summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramw <none@none>2007-10-25 16:34:29 -0700
committeramw <none@none>2007-10-25 16:34:29 -0700
commitda6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch)
tree65be91fb78a6a66183197595333f2e8aafb4640a
parente845e33dd0d1aea22db7edaa8c7d43955d24609b (diff)
downloadillumos-joyent-da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0.tar.gz
PSARC/2007/218 caller_context_t in all VOPs
PSARC/2007/227 VFS Feature Registration and ACL on Create PSARC/2007/244 ZFS Case-insensitive support PSARC/2007/315 Extensible Attribute Interfaces PSARC/2007/394 ls(1) new command line options '-/' and '-%': CIFS system attributes support PSARC/2007/403 Modified Access Checks for CIFS PSARC/2007/410 Add system attribute support to chmod(1) PSARC/2007/432 CIFS system attributes support for cp(1), pack(1), unpack(1), compress(1) and uncompress(1) PSARC/2007/444 Rescind SETTABLE Attribute PSARC/2007/459 CIFS system attributes support for cpio(1), pax(1), tar(1) PSARC/2007/546 Update utilities to match CIFS system attributes changes. PSARC/2007/560 ZFS sharesmb property 4890717 want append-only files 6417428 Case-insensitive file system name lookup to support CIFS 6417435 DOS attributes and additional timestamps to support for CIFS 6417442 File system quarantined and modified attributes to support an integrated Anti-Virus service 6417453 FS boolean property for rejecting/allowing invalid UTF-8 sequences in file names 6473733 RFE: Need support for open-deny modes 6473755 RFE: Need ability to reconcile oplock and delegation conflicts 6494624 sharemgr needs to support CIFS shares better 6546705 All vnode operations need to pass caller_context_t 6546706 Need VOP_SETATTR/VOP_GETATTR to support new, optional attributes 6546893 Solaris system attribute support 6550962 ZFS ACL inheritance needs to be enhanced to support Automatic Inheritance 6553589 RFE: VFS Feature Registration facility 6553770 RFE: ZFS support for ACL-on-CREATE (PSARC 2007/227) 6565581 ls(1) should support file system attributes proposed in PSARC/2007/315 6566784 NTFS streams are not copied along with the files. 6576205 cp(1), pack(1) and compress(1) should support file system attributes proposed in PSARC/2007/315 6578875 RFE: kernel interfaces for nbmand need improvement 6578883 RFE: VOP_SHRLOCK needs additional access types 6578885 chmod(1) should support file system attributes proposed in PSARC/2007/315 6578886 RFE: disallow nbmand state to change on remount 6583349 ACL parser needs to support audit/alarm ACE types 6590347 tar(1) should support filesystem attributes proposed in PSARC/2007/315 6597357 *tar* xv@ doesn't show the hidden directory even though it is restored 6597360 *tar* should re-init xattr info if openat() fails during extraction of and extended attribute 6597368 *tar* cannot restore hard linked extended attributes 6597374 *tar* doesn't display "x " when hard linked attributes are restored 6597375 *tar* extended attribute header off by one 6614861 *cpio* incorrectly archives extended system attributes with -@ 6614896 *pax* incorrectly archives extended system attributes with -@ 6615225 *tar* incorrectly archives extended system attributes with -@ 6617183 CIFS Service - PSARC 2006/715
-rw-r--r--usr/src/Makefile.lint2
-rw-r--r--usr/src/Targetdirs6
-rw-r--r--usr/src/cmd/Adm/sun/Makefile23
-rw-r--r--usr/src/cmd/Makefile1
-rw-r--r--usr/src/cmd/Makefile.cmd5
-rw-r--r--usr/src/cmd/bnu/in.uucpd.c2
-rw-r--r--usr/src/cmd/chmod/Makefile9
-rw-r--r--usr/src/cmd/chmod/chmod.c892
-rw-r--r--usr/src/cmd/cmd-inet/etc/services2
-rw-r--r--usr/src/cmd/compress/Makefile2
-rw-r--r--usr/src/cmd/compress/compress.c165
-rw-r--r--usr/src/cmd/cpio/cpio.c82
-rw-r--r--usr/src/cmd/cpio/cpio.h23
-rw-r--r--usr/src/cmd/dfs.cmds/sharemgr/commands.c2116
-rw-r--r--usr/src/cmd/dfs.cmds/sharemgr/group.xml11
-rw-r--r--usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h1
-rw-r--r--usr/src/cmd/filesync/main.c2
-rw-r--r--usr/src/cmd/idmap/idmap/idmap.c4
-rw-r--r--usr/src/cmd/idmap/idmapd/server.c2
-rw-r--r--usr/src/cmd/login/login.c2
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/disp1.c2
-rw-r--r--usr/src/cmd/ls/Makefile.com9
-rw-r--r--usr/src/cmd/ls/ls.c500
-rw-r--r--usr/src/cmd/mdb/Makefile.common1
-rw-r--r--usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c1194
-rw-r--r--usr/src/cmd/mdb/intel/amd64/smbsrv/Makefile35
-rw-r--r--usr/src/cmd/mdb/intel/ia32/smbsrv/Makefile34
-rw-r--r--usr/src/cmd/mdb/sparc/v9/smbsrv/Makefile35
-rw-r--r--usr/src/cmd/mv/Makefile6
-rw-r--r--usr/src/cmd/mv/mv.c919
-rw-r--r--usr/src/cmd/pack/Makefile11
-rw-r--r--usr/src/cmd/pack/pack.c326
-rw-r--r--usr/src/cmd/rpcbind/rpcb_svc_com.c2
-rw-r--r--usr/src/cmd/smbsrv/Makefile32
-rw-r--r--usr/src/cmd/smbsrv/Makefile.smbsrv.defs41
-rw-r--r--usr/src/cmd/smbsrv/Makefile.smbsrv.targ44
-rw-r--r--usr/src/cmd/smbsrv/Makefile.subdirs45
-rw-r--r--usr/src/cmd/smbsrv/dtrace/Makefile51
-rwxr-xr-xusr/src/cmd/smbsrv/dtrace/msrpc.d300
-rw-r--r--usr/src/cmd/smbsrv/dtrace/smbnode.d127
-rw-r--r--usr/src/cmd/smbsrv/dtrace/smbvfs.d77
-rwxr-xr-xusr/src/cmd/smbsrv/dtrace/stype.d151
-rw-r--r--usr/src/cmd/smbsrv/smbadm/Makefile47
-rw-r--r--usr/src/cmd/smbsrv/smbadm/smbadm.c1374
-rw-r--r--usr/src/cmd/smbsrv/smbd/Makefile78
-rw-r--r--usr/src/cmd/smbsrv/smbd/server.xml250
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd.h75
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_door_ops.c916
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_door_server.c290
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c200
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_join.c395
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_logon.c289
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_main.c758
-rwxr-xr-xusr/src/cmd/smbsrv/smbd/smbd_mlsvc_doorsvc.c423
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_nicmon.c275
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c371
-rw-r--r--usr/src/cmd/smbsrv/smbstat/Makefile39
-rw-r--r--usr/src/cmd/smbsrv/smbstat/smbstat.c283
-rw-r--r--usr/src/cmd/svc/configd/rc_node.c2
-rw-r--r--usr/src/cmd/tar/Makefile2
-rw-r--r--usr/src/cmd/tar/tar.c1462
-rw-r--r--usr/src/cmd/truss/systable.c3
-rw-r--r--usr/src/cmd/unpack/Makefile11
-rw-r--r--usr/src/cmd/unpack/unpack.c265
-rw-r--r--usr/src/cmd/wbem/provider/c/wbem_disk/common/disk_descriptors.c9
-rw-r--r--usr/src/cmd/wbem/provider/c/wbem_disk/common/drive_descriptors.c9
-rw-r--r--usr/src/cmd/wbem/provider/c/wbem_disk/common/methods.c19
-rw-r--r--usr/src/cmd/zdb/zdb.c8
-rw-r--r--usr/src/cmd/zdb/zdb_il.c39
-rw-r--r--usr/src/cmd/zfs/zfs_main.c183
-rw-r--r--usr/src/cmd/zpool/zpool_main.c4
-rw-r--r--usr/src/common/acl/acl_common.c1538
-rw-r--r--usr/src/common/acl/acl_common.h27
-rw-r--r--usr/src/common/smbsrv/smb_common_door_decode.c387
-rw-r--r--usr/src/common/smbsrv/smb_match.c241
-rw-r--r--usr/src/common/smbsrv/smb_msgbuf.c709
-rw-r--r--usr/src/common/smbsrv/smb_native.c231
-rw-r--r--usr/src/common/smbsrv/smb_netbios_util.c394
-rw-r--r--usr/src/common/smbsrv/smb_oem.c762
-rw-r--r--usr/src/common/smbsrv/smb_opmlang.c127
-rw-r--r--usr/src/common/smbsrv/smb_share_door_decode.c156
-rw-r--r--usr/src/common/smbsrv/smb_sid.c587
-rw-r--r--usr/src/common/smbsrv/smb_status_xlat.c597
-rw-r--r--usr/src/common/smbsrv/smb_strcase.c388
-rw-r--r--usr/src/common/smbsrv/smb_string.c103
-rw-r--r--usr/src/common/smbsrv/smb_token.c383
-rw-r--r--usr/src/common/smbsrv/smb_token_xdr.c395
-rw-r--r--usr/src/common/smbsrv/smb_utf8.c418
-rw-r--r--usr/src/common/smbsrv/smb_xdr_utils.c165
-rw-r--r--usr/src/common/util/string.c56
-rw-r--r--usr/src/common/xattr/xattr_common.c135
-rw-r--r--usr/src/common/zfs/zfs_prop.c62
-rw-r--r--usr/src/common/zfs/zfs_prop.h9
-rw-r--r--usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h3
-rw-r--r--usr/src/grub/grub-0.95/stage2/zfs-include/zfs_acl.h27
-rw-r--r--usr/src/head/Makefile1
-rw-r--r--usr/src/head/attr.h59
-rw-r--r--usr/src/lib/Makefile8
-rw-r--r--usr/src/lib/common/inc/c_synonyms.h1
-rw-r--r--usr/src/lib/libbc/inc/include/tzfile.h139
-rw-r--r--usr/src/lib/libbsm/audit_event.txt2
-rw-r--r--usr/src/lib/libbsm/common/adt.xml55
-rw-r--r--usr/src/lib/libc/Makefile.targ4
-rw-r--r--usr/src/lib/libc/amd64/Makefile5
-rw-r--r--usr/src/lib/libc/i386/Makefile.com6
-rw-r--r--usr/src/lib/libc/port/gen/attrat.c273
-rw-r--r--usr/src/lib/libc/port/gen/privlib.c2
-rw-r--r--usr/src/lib/libc/port/llib-lc1
-rw-r--r--usr/src/lib/libc/port/mapfile-vers12
-rw-r--r--usr/src/lib/libc/port/sys/fsmisc.c13
-rw-r--r--usr/src/lib/libc/sparc/Makefile6
-rw-r--r--usr/src/lib/libc/sparcv9/Makefile6
-rw-r--r--usr/src/lib/libcmdutils/Makefile.com8
-rw-r--r--usr/src/lib/libcmdutils/common/mapfile-vers8
-rw-r--r--usr/src/lib/libcmdutils/common/process_xattrs.c334
-rw-r--r--usr/src/lib/libcmdutils/common/sysattrs.c128
-rw-r--r--usr/src/lib/libcmdutils/common/writefile.c230
-rw-r--r--usr/src/lib/libcmdutils/libcmdutils.h57
-rw-r--r--usr/src/lib/libsec/common/acl.y4
-rw-r--r--usr/src/lib/libsec/common/acl_lex.l73
-rw-r--r--usr/src/lib/libsec/common/acltext.c55
-rw-r--r--usr/src/lib/libsec/common/aclutils.c1388
-rw-r--r--usr/src/lib/libsec/common/aclutils.h24
-rw-r--r--usr/src/lib/libsecdb/auth_attr.txt3
-rwxr-xr-xusr/src/lib/libsecdb/help/auths/AuthReadSMB.html38
-rw-r--r--usr/src/lib/libsecdb/help/auths/Makefile3
-rw-r--r--usr/src/lib/libsecdb/help/auths/SmfSMBStates.html40
-rw-r--r--usr/src/lib/libsecdb/help/auths/SmfValueSMB.html40
-rw-r--r--usr/src/lib/libsecdb/help/profiles/Makefile1
-rw-r--r--usr/src/lib/libsecdb/help/profiles/RtSMBMngmnt.html40
-rw-r--r--usr/src/lib/libsecdb/prof_attr.txt3
-rw-r--r--usr/src/lib/libshare/Makefile2
-rw-r--r--usr/src/lib/libshare/common/libshare.c1194
-rw-r--r--usr/src/lib/libshare/common/libshare.h48
-rw-r--r--usr/src/lib/libshare/common/libshare_impl.h13
-rw-r--r--usr/src/lib/libshare/common/libshare_zfs.c388
-rw-r--r--usr/src/lib/libshare/common/libsharecore.c236
-rw-r--r--usr/src/lib/libshare/common/mapfile-vers19
-rw-r--r--usr/src/lib/libshare/common/plugin.c175
-rw-r--r--usr/src/lib/libshare/common/scfutil.c418
-rw-r--r--usr/src/lib/libshare/nfs/libshare_nfs.c47
-rw-r--r--usr/src/lib/libshare/smb/Makefile51
-rw-r--r--usr/src/lib/libshare/smb/Makefile.com88
-rw-r--r--usr/src/lib/libshare/smb/amd64/Makefile31
-rw-r--r--usr/src/lib/libshare/smb/i386/Makefile30
-rw-r--r--usr/src/lib/libshare/smb/libshare_smb.c1641
-rw-r--r--usr/src/lib/libshare/smb/libshare_smb.h75
-rw-r--r--usr/src/lib/libshare/smb/mapfile-vers34
-rw-r--r--usr/src/lib/libshare/smb/smb_share_doorclnt.c951
-rw-r--r--usr/src/lib/libshare/smb/sparc/Makefile30
-rw-r--r--usr/src/lib/libshare/smb/sparcv9/Makefile31
-rw-r--r--usr/src/lib/libsldap/common/ns_writes.c2
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h12
-rw-r--r--usr/src/lib/libzfs/common/libzfs_changelist.c62
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c80
-rw-r--r--usr/src/lib/libzfs/common/libzfs_impl.h23
-rw-r--r--usr/src/lib/libzfs/common/libzfs_mount.c313
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c4
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers7
-rw-r--r--usr/src/lib/libzpool/common/kernel.c15
-rw-r--r--usr/src/lib/libzpool/common/sys/zfs_context.h115
-rw-r--r--usr/src/lib/pam_modules/Makefile3
-rw-r--r--usr/src/lib/pam_modules/smb/Makefile56
-rw-r--r--usr/src/lib/pam_modules/smb/Makefile.com42
-rw-r--r--usr/src/lib/pam_modules/smb/amd64/Makefile35
-rw-r--r--usr/src/lib/pam_modules/smb/i386/Makefile34
-rw-r--r--usr/src/lib/pam_modules/smb/mapfile-vers33
-rw-r--r--usr/src/lib/pam_modules/smb/smb_passwd.c202
-rw-r--r--usr/src/lib/pam_modules/smb/sparc/Makefile34
-rw-r--r--usr/src/lib/pam_modules/smb/sparcv9/Makefile35
-rw-r--r--usr/src/lib/smbsrv/Makefile43
-rw-r--r--usr/src/lib/smbsrv/Makefile.lib50
-rw-r--r--usr/src/lib/smbsrv/Makefile.smbsrv65
-rw-r--r--usr/src/lib/smbsrv/Makefile.subdirs42
-rw-r--r--usr/src/lib/smbsrv/Makefile.targ42
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/Makefile.com57
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/amd64/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h41
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/llib-lmlrpc31
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers57
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mlndo.c534
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mlndr.c1965
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mlrpc_client.c369
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mlrpc_encdec.c349
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mlrpc_heap.c236
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mlrpc_server.c836
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mlrpc_svc.c286
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/i386/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/sparc/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/sparcv9/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/Makefile.com86
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/amd64/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h237
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/llib-lmlsvc31
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lmshare.c1233
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lsalib.c637
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c875
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lsar_open.c298
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers97
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c306
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_dssetup.c168
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_handle.c179
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c65
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_logr.c574
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c1385
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_netr.c202
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c1463
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_spoolss.c139
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_srvsvc.c1684
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_svcctl.c485
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c752
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_winreg.c454
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_wkssvc.c142
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/netdfs.c519
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c502
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c584
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samlib.c512
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c565
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samr_open.c684
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/secdb.c932
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c413
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/smb_share_util.c106
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/srvsvc_client.c554
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/i386/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/sparc/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libsmb/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmb/Makefile.com86
-rw-r--r--usr/src/lib/smbsrv/libsmb/amd64/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/libsmb.h778
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/llib-lsmb31
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/mapfile-vers325
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c864
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_auth.c706
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_cfg.c1090
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_crypt.c204
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_ctxbuf.c120
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_domain.c394
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_door_client.c411
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c313
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c148
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_downcalls.c195
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_group_door_encdec.c337
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_group_xdr.c158
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_ht.c639
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_idmap.c382
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_info.c382
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_mac.c207
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_privilege.c361
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c529
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c1035
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_util.c336
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_wins.c210
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_wksids.c350
-rw-r--r--usr/src/lib/smbsrv/libsmb/i386/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmb/sparc/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmb/sparcv9/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libsmbns/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmbns/Makefile.com62
-rw-r--r--usr/src/lib/smbsrv/libsmbns/amd64/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/libsmbns.h184
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/llib-lsmbns31
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/mapfile-vers81
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c2304
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h87
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c1410
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_browser.h190
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c1894
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.h205
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_krb.c543
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h64
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c242
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c300
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.h1617
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_cache.c776
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c1061
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c4738
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c643
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_nicconfig.c1163
-rw-r--r--usr/src/lib/smbsrv/libsmbns/i386/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmbns/sparc/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmbns/sparcv9/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/Makefile.com53
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/amd64/Makefile31
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h97
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/llib-lsmbrdr31
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers63
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h241
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.c382
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.h85
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_lib.c592
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c710
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netbios.c457
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netuse.c458
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_read_andx.c210
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_rpcpipe.c518
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c889
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_transact.c254
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/i386/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/sparc/Makefile30
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/sparcv9/Makefile31
-rw-r--r--usr/src/pkgdefs/Makefile3
-rw-r--r--usr/src/pkgdefs/SUNW0on/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWcsu/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWsmbskr/Makefile38
-rw-r--r--usr/src/pkgdefs/SUNWsmbskr/pkginfo.tmpl51
-rw-r--r--usr/src/pkgdefs/SUNWsmbskr/postinstall62
-rw-r--r--usr/src/pkgdefs/SUNWsmbskr/preremove48
-rw-r--r--usr/src/pkgdefs/SUNWsmbskr/prototype_com40
-rw-r--r--usr/src/pkgdefs/SUNWsmbskr/prototype_i38636
-rw-r--r--usr/src/pkgdefs/SUNWsmbskr/prototype_sparc34
-rw-r--r--usr/src/pkgdefs/SUNWsmbsr/Makefile38
-rw-r--r--usr/src/pkgdefs/SUNWsmbsr/depend54
-rw-r--r--usr/src/pkgdefs/SUNWsmbsr/pkginfo.tmpl51
-rw-r--r--usr/src/pkgdefs/SUNWsmbsr/prototype_com44
-rw-r--r--usr/src/pkgdefs/SUNWsmbsr/prototype_i38633
-rw-r--r--usr/src/pkgdefs/SUNWsmbsr/prototype_sparc33
-rw-r--r--usr/src/pkgdefs/SUNWsmbsu/Makefile36
-rw-r--r--usr/src/pkgdefs/SUNWsmbsu/depend55
-rw-r--r--usr/src/pkgdefs/SUNWsmbsu/pkginfo.tmpl46
-rw-r--r--usr/src/pkgdefs/SUNWsmbsu/preremove44
-rw-r--r--usr/src/pkgdefs/SUNWsmbsu/prototype_com70
-rw-r--r--usr/src/pkgdefs/SUNWsmbsu/prototype_i38633
-rw-r--r--usr/src/pkgdefs/SUNWsmbsu/prototype_sparc32
-rw-r--r--usr/src/pkgdefs/common_files/i.minorperm_i3861
-rw-r--r--usr/src/pkgdefs/common_files/i.minorperm_sparc1
-rw-r--r--usr/src/pkgdefs/etc/exception_list_i386107
-rw-r--r--usr/src/pkgdefs/etc/exception_list_sparc107
-rw-r--r--usr/src/tools/scripts/bfu.sh1
-rw-r--r--usr/src/uts/Makefile2
-rw-r--r--usr/src/uts/common/Makefile.files121
-rw-r--r--usr/src/uts/common/Makefile.rules21
-rw-r--r--usr/src/uts/common/brand/lx/autofs/lx_autofs.c74
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prvnops.c71
-rw-r--r--usr/src/uts/common/c2/audit.c29
-rw-r--r--usr/src/uts/common/c2/audit_event.c9
-rw-r--r--usr/src/uts/common/cpr/cpr_dump.c5
-rw-r--r--usr/src/uts/common/cpr/cpr_main.c10
-rw-r--r--usr/src/uts/common/cpr/cpr_misc.c18
-rw-r--r--usr/src/uts/common/fs/autofs/auto_vnops.c177
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_cnode.c26
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_cod.c15
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_dir.c25
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_dlog.c25
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_filegrp.c57
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_fscache.c38
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_ioctl.c85
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_log.c20
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_noopc.c13
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_resource.c19
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_strict.c17
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_subr.c54
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_vfsops.c13
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_vnops.c311
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_all.c14
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_cdir.c9
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_ctl.c39
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_event.c69
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_latest.c30
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_root.c40
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_sym.c11
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_tdir.c14
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_tmpl.c21
-rw-r--r--usr/src/uts/common/fs/dev/sdev_profile.c20
-rw-r--r--usr/src/uts/common/fs/dev/sdev_ptsops.c16
-rw-r--r--usr/src/uts/common/fs/dev/sdev_subr.c48
-rw-r--r--usr/src/uts/common/fs/dev/sdev_vfsops.c2
-rw-r--r--usr/src/uts/common/fs/dev/sdev_vnops.c173
-rw-r--r--usr/src/uts/common/fs/devfs/devfs_subr.c35
-rw-r--r--usr/src/uts/common/fs/devfs/devfs_vfsops.c2
-rw-r--r--usr/src/uts/common/fs/devfs/devfs_vnops.c71
-rw-r--r--usr/src/uts/common/fs/doorfs/door_sys.c26
-rw-r--r--usr/src/uts/common/fs/doorfs/door_vnops.c31
-rw-r--r--usr/src/uts/common/fs/fd/fdops.c21
-rw-r--r--usr/src/uts/common/fs/fem.c432
-rw-r--r--usr/src/uts/common/fs/fifofs/fifosubr.c17
-rw-r--r--usr/src/uts/common/fs/fifofs/fifovnops.c129
-rw-r--r--usr/src/uts/common/fs/fs_subr.c245
-rw-r--r--usr/src/uts/common/fs/fs_subr.h46
-rw-r--r--usr/src/uts/common/fs/fsflush.c6
-rw-r--r--usr/src/uts/common/fs/gfs.c74
-rw-r--r--usr/src/uts/common/fs/hsfs/hsfs_vfsops.c14
-rw-r--r--usr/src/uts/common/fs/hsfs/hsfs_vnops.c97
-rw-r--r--usr/src/uts/common/fs/lofs/lofs_vfsops.c2
-rw-r--r--usr/src/uts/common/fs/lofs/lofs_vnops.c242
-rw-r--r--usr/src/uts/common/fs/lookup.c75
-rw-r--r--usr/src/uts/common/fs/mntfs/mntvnops.c27
-rw-r--r--usr/src/uts/common/fs/namefs/namevfs.c8
-rw-r--r--usr/src/uts/common/fs/namefs/namevno.c57
-rw-r--r--usr/src/uts/common/fs/nbmlock.c18
-rw-r--r--usr/src/uts/common/fs/nfs/nfs3_srv.c297
-rw-r--r--usr/src/uts/common/fs/nfs/nfs3_vnops.c274
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_acl.c8
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_callback.c8
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_client.c12
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c54
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_rnode.c6
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv.c368
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_attr.c38
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c81
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_ns.c17
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c29
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_state.c59
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c133
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_subr.c4
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vnops.c319
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_xdr.c5
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_acl_srv.c36
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_client.c23
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_common.c8
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_dump.c10
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_export.c26
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_log.c10
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_server.c10
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_srv.c127
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_subr.c10
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_vnops.c332
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_common.c18
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_data.c14
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_odir.c3
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_root.c15
-rw-r--r--usr/src/uts/common/fs/pathname.c9
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_dir.c20
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_node.c3
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_vfsops.c8
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_vnops.c147
-rw-r--r--usr/src/uts/common/fs/portfs/port_fd.c6
-rw-r--r--usr/src/uts/common/fs/portfs/port_fop.c119
-rw-r--r--usr/src/uts/common/fs/portfs/port_vnops.c34
-rw-r--r--usr/src/uts/common/fs/proc/prcontrol.c2
-rw-r--r--usr/src/uts/common/fs/proc/prioctl.c51
-rw-r--r--usr/src/uts/common/fs/proc/prsubr.c16
-rw-r--r--usr/src/uts/common/fs/proc/prvnops.c83
-rw-r--r--usr/src/uts/common/fs/sharefs/sharefs_vnops.c12
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_acl.c1310
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_alloc.c117
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_books.c170
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_check_directory.c126
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_close.c148
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_lock.c424
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c982
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_search.c344
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_transact.c2485
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_tree.c397
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_copy.c121
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create.c224
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create_directory.c272
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete.c354
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete_directory.c114
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dispatch.c1574
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_echo.c132
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fem.c285
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find.c440
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find_notify_close.c78
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find_unique.c286
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_flush.c129
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_forward.c148
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsd.c276
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsops.c2595
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_init.c796
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_kdoor_clnt.c137
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_kdoor_encdec.c266
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c159
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c217
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c100
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_lock_svc.c709
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_locking_andx.c378
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_logoff_andx.c78
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mangle_name.c777
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c1659
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c334
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_memory_manager.c107
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_move.c114
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_negotiate.c478
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_net.c281
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_node.c770
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c77
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c373
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c255
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c110
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c613
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c213
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_odir.c456
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_ofile.c726
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_open_andx.c431
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c539
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_print.c253
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_process_exit.c84
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information.c128
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information2.c111
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information_disk.c129
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_read.c456
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_rename.c347
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_rpc.c532
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_sd.c862
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_search.c289
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_seek.c129
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session.c1252
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c516
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information.c128
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information2.c123
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_share_kdoor_client.c730
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_signing.c418
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_svc_sm.c1301
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_create_directory.c97
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c205
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_find.c1142
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_open2.c137
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c559
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c434
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c588
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c163
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c414
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c179
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree.c733
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree_connect.c107
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree_connect_andx.c213
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree_disconnect.c110
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c87
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_upcalls.c104
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_user.c619
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_util.c2172
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vfs.c161
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vops.c1878
-rwxr-xr-xusr/src/uts/common/fs/smbsrv/smb_winpipe.c431
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write.c565
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write_raw.c606
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_xlate.c250
-rw-r--r--usr/src/uts/common/fs/smbsrv/smbsrv.conf27
-rw-r--r--usr/src/uts/common/fs/sockfs/nl7c.c26
-rw-r--r--usr/src/uts/common/fs/sockfs/nl7clogd.c25
-rw-r--r--usr/src/uts/common/fs/sockfs/socksctp.c8
-rw-r--r--usr/src/uts/common/fs/sockfs/socksctpvnops.c38
-rwxr-xr-xusr/src/uts/common/fs/sockfs/socksdp.c4
-rwxr-xr-xusr/src/uts/common/fs/sockfs/socksdpvnops.c38
-rw-r--r--usr/src/uts/common/fs/sockfs/socksubr.c2
-rw-r--r--usr/src/uts/common/fs/sockfs/socksyscalls.c35
-rw-r--r--usr/src/uts/common/fs/sockfs/socktpi.c10
-rw-r--r--usr/src/uts/common/fs/sockfs/sockvnops.c65
-rw-r--r--usr/src/uts/common/fs/specfs/specsubr.c6
-rw-r--r--usr/src/uts/common/fs/specfs/specvfsops.c12
-rw-r--r--usr/src/uts/common/fs/specfs/specvnops.c226
-rw-r--r--usr/src/uts/common/fs/swapfs/swap_subr.c2
-rw-r--r--usr/src/uts/common/fs/swapfs/swap_vnops.c40
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_dir.c5
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vfsops.c5
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vnops.c190
-rw-r--r--usr/src/uts/common/fs/udfs/udf_dir.c32
-rw-r--r--usr/src/uts/common/fs/udfs/udf_subr.c129
-rw-r--r--usr/src/uts/common/fs/udfs/udf_vfsops.c19
-rw-r--r--usr/src/uts/common/fs/udfs/udf_vnops.c383
-rw-r--r--usr/src/uts/common/fs/ufs/quotacalls.c4
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_directio.c8
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_extvnops.c11
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_filio.c4
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_lockfs.c2
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_subr.c3
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_vfsops.c30
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_vnops.c233
-rw-r--r--usr/src/uts/common/fs/vfs.c180
-rw-r--r--usr/src/uts/common/fs/vnode.c724
-rw-r--r--usr/src/uts/common/fs/xattr.c1428
-rw-r--r--usr/src/uts/common/fs/zfs/dmu.c8
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_deleg.c4
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_prop.c20
-rw-r--r--usr/src/uts/common/fs/zfs/spa_config.c4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu.h9
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_deleg.h1
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zap.h51
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zap_impl.h38
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zap_leaf.h20
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_acl.h148
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h3
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_dir.h12
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_fuid.h131
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_i18n.h71
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h9
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h10
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_znode.h88
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zil.h122
-rw-r--r--usr/src/uts/common/fs/zfs/vdev_file.c10
-rw-r--r--usr/src/uts/common/fs/zfs/zap.c95
-rw-r--r--usr/src/uts/common/fs/zfs/zap_leaf.c176
-rw-r--r--usr/src/uts/common/fs/zfs/zap_micro.c357
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_acl.c2291
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_byteswap.c98
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ctldir.c60
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_dir.c210
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_fuid.c724
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c414
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_log.c359
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_replay.c544
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c174
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c923
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_znode.c126
-rw-r--r--usr/src/uts/common/fs/zfs/zil.c10
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c3
-rw-r--r--usr/src/uts/common/idmap/idmap_cache.c6
-rw-r--r--usr/src/uts/common/io/cons.c10
-rw-r--r--usr/src/uts/common/io/devinfo.c6
-rw-r--r--usr/src/uts/common/io/devpoll.c12
-rw-r--r--usr/src/uts/common/io/fssnap.c10
-rw-r--r--usr/src/uts/common/io/gentty.c8
-rw-r--r--usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c2
-rw-r--r--usr/src/uts/common/io/iwscons.c19
-rw-r--r--usr/src/uts/common/io/l_strplumb.c6
-rw-r--r--usr/src/uts/common/io/lofi.c11
-rw-r--r--usr/src/uts/common/io/lvm/trans/trans_ioctl.c17
-rw-r--r--usr/src/uts/common/io/physmem.c18
-rw-r--r--usr/src/uts/common/io/rsm/rsmops.c11
-rw-r--r--usr/src/uts/common/io/sysmsg.c19
-rw-r--r--usr/src/uts/common/ipp/ipgpc/classifier.c2
-rw-r--r--usr/src/uts/common/ipp/ipgpc/filters.c8
-rw-r--r--usr/src/uts/common/krtld/kobj.c12
-rw-r--r--usr/src/uts/common/ktli/t_kopen.c10
-rw-r--r--usr/src/uts/common/nfs/nfs.h8
-rw-r--r--usr/src/uts/common/nfs/nfs4.h13
-rw-r--r--usr/src/uts/common/nfs/rnode.h4
-rw-r--r--usr/src/uts/common/os/acct.c14
-rw-r--r--usr/src/uts/common/os/core.c17
-rw-r--r--usr/src/uts/common/os/cred.c53
-rw-r--r--usr/src/uts/common/os/devcache.c7
-rw-r--r--usr/src/uts/common/os/driver.c6
-rw-r--r--usr/src/uts/common/os/driver_lyr.c14
-rw-r--r--usr/src/uts/common/os/dumpsubr.c29
-rw-r--r--usr/src/uts/common/os/exacct.c2
-rw-r--r--usr/src/uts/common/os/exec.c12
-rw-r--r--usr/src/uts/common/os/fio.c11
-rw-r--r--usr/src/uts/common/os/flock.c39
-rw-r--r--usr/src/uts/common/os/grow.c31
-rw-r--r--usr/src/uts/common/os/inst_sync.c11
-rw-r--r--usr/src/uts/common/os/mem_config.c6
-rw-r--r--usr/src/uts/common/os/modctl.c4
-rw-r--r--usr/src/uts/common/os/policy.c153
-rw-r--r--usr/src/uts/common/os/priv_defs12
-rw-r--r--usr/src/uts/common/os/session.c20
-rw-r--r--usr/src/uts/common/os/share.c194
-rw-r--r--usr/src/uts/common/os/sid.c2
-rw-r--r--usr/src/uts/common/os/tlabel.c2
-rw-r--r--usr/src/uts/common/os/urw.c11
-rw-r--r--usr/src/uts/common/os/vm_pageout.c4
-rw-r--r--usr/src/uts/common/os/zone.c7
-rw-r--r--usr/src/uts/common/smbsrv/Makefile131
-rw-r--r--usr/src/uts/common/smbsrv/alloc.h89
-rw-r--r--usr/src/uts/common/smbsrv/cifs.h1161
-rw-r--r--usr/src/uts/common/smbsrv/codepage.h85
-rw-r--r--usr/src/uts/common/smbsrv/cp_cyrillic.h312
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin1.h317
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin2.h314
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin3.h311
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin4.h312
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin5.h311
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin6.h309
-rw-r--r--usr/src/uts/common/smbsrv/cp_unicode.h6639
-rw-r--r--usr/src/uts/common/smbsrv/cp_usascii.h310
-rw-r--r--usr/src/uts/common/smbsrv/crypt.h45
-rw-r--r--usr/src/uts/common/smbsrv/ctype.h76
-rw-r--r--usr/src/uts/common/smbsrv/doserror.h145
-rwxr-xr-xusr/src/uts/common/smbsrv/hash_table.h192
-rw-r--r--usr/src/uts/common/smbsrv/lm.h47
-rw-r--r--usr/src/uts/common/smbsrv/lmdfs.h67
-rw-r--r--usr/src/uts/common/smbsrv/lmerr.h536
-rw-r--r--usr/src/uts/common/smbsrv/lmshare.h195
-rw-r--r--usr/src/uts/common/smbsrv/lmshare_door.h116
-rw-r--r--usr/src/uts/common/smbsrv/lsalib.h164
-rw-r--r--usr/src/uts/common/smbsrv/mac_cifs.h112
-rw-r--r--usr/src/uts/common/smbsrv/mailslot.h76
-rw-r--r--usr/src/uts/common/smbsrv/mbuf.h269
-rw-r--r--usr/src/uts/common/smbsrv/mlrpc.h414
-rw-r--r--usr/src/uts/common/smbsrv/mlsvc.h233
-rw-r--r--usr/src/uts/common/smbsrv/mlsvc_util.h244
-rw-r--r--usr/src/uts/common/smbsrv/msgbuf.h124
-rw-r--r--usr/src/uts/common/smbsrv/ndl/dssetup.ndl168
-rw-r--r--usr/src/uts/common/smbsrv/ndl/eventlog.ndl204
-rw-r--r--usr/src/uts/common/smbsrv/ndl/llsrpc.ndl110
-rw-r--r--usr/src/uts/common/smbsrv/ndl/lsarpc.ndl801
-rw-r--r--usr/src/uts/common/smbsrv/ndl/ndrtypes.ndl166
-rw-r--r--usr/src/uts/common/smbsrv/ndl/netdfs.ndl493
-rw-r--r--usr/src/uts/common/smbsrv/ndl/netlogon.ndl395
-rw-r--r--usr/src/uts/common/smbsrv/ndl/rpcpdu.ndl552
-rw-r--r--usr/src/uts/common/smbsrv/ndl/samrpc.ndl1314
-rw-r--r--usr/src/uts/common/smbsrv/ndl/spoolss.ndl489
-rw-r--r--usr/src/uts/common/smbsrv/ndl/srvsvc.ndl1331
-rw-r--r--usr/src/uts/common/smbsrv/ndl/svcctl.ndl287
-rw-r--r--usr/src/uts/common/smbsrv/ndl/winreg.ndl288
-rw-r--r--usr/src/uts/common/smbsrv/ndr.h468
-rw-r--r--usr/src/uts/common/smbsrv/netbios.h147
-rw-r--r--usr/src/uts/common/smbsrv/netrauth.h162
-rw-r--r--usr/src/uts/common/smbsrv/nmpipes.h165
-rw-r--r--usr/src/uts/common/smbsrv/ntaccess.h237
-rw-r--r--usr/src/uts/common/smbsrv/nterror.h941
-rw-r--r--usr/src/uts/common/smbsrv/ntifs.h216
-rw-r--r--usr/src/uts/common/smbsrv/ntlocale.h330
-rw-r--r--usr/src/uts/common/smbsrv/ntsid.h304
-rw-r--r--usr/src/uts/common/smbsrv/ntstatus.h595
-rw-r--r--usr/src/uts/common/smbsrv/oem.h106
-rw-r--r--usr/src/uts/common/smbsrv/samlib.h159
-rw-r--r--usr/src/uts/common/smbsrv/smb.h272
-rw-r--r--usr/src/uts/common/smbsrv/smb_common_door.h130
-rw-r--r--usr/src/uts/common/smbsrv/smb_door_svc.h202
-rw-r--r--usr/src/uts/common/smbsrv/smb_fsd.h90
-rw-r--r--usr/src/uts/common/smbsrv/smb_fsops.h153
-rw-r--r--usr/src/uts/common/smbsrv/smb_i18n.h41
-rw-r--r--usr/src/uts/common/smbsrv/smb_idmap.h100
-rw-r--r--usr/src/uts/common/smbsrv/smb_incl.h121
-rwxr-xr-xusr/src/uts/common/smbsrv/smb_ioctl.h45
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h602
-rw-r--r--usr/src/uts/common/smbsrv/smb_privilege.h197
-rw-r--r--usr/src/uts/common/smbsrv/smb_secdesc.h397
-rw-r--r--usr/src/uts/common/smbsrv/smb_svc_sm.h162
-rw-r--r--usr/src/uts/common/smbsrv/smb_token.h224
-rw-r--r--usr/src/uts/common/smbsrv/smb_vops.h386
-rwxr-xr-xusr/src/uts/common/smbsrv/smb_winpipe.h84
-rw-r--r--usr/src/uts/common/smbsrv/smb_xdr.h111
-rw-r--r--usr/src/uts/common/smbsrv/smbfmt.h56
-rw-r--r--usr/src/uts/common/smbsrv/smbinfo.h181
-rw-r--r--usr/src/uts/common/smbsrv/smbtrans.h70
-rw-r--r--usr/src/uts/common/smbsrv/smbvar.h1402
-rw-r--r--usr/src/uts/common/smbsrv/string.h75
-rw-r--r--usr/src/uts/common/smbsrv/svrapi.h263
-rw-r--r--usr/src/uts/common/smbsrv/winioctl.h475
-rw-r--r--usr/src/uts/common/smbsrv/winsvc.h217
-rw-r--r--usr/src/uts/common/smbsrv/wintypes.h62
-rw-r--r--usr/src/uts/common/sys/Makefile4
-rw-r--r--usr/src/uts/common/sys/acl.h49
-rw-r--r--usr/src/uts/common/sys/acl_impl.h61
-rw-r--r--usr/src/uts/common/sys/attr.h148
-rw-r--r--usr/src/uts/common/sys/byteorder.h64
-rw-r--r--usr/src/uts/common/sys/cred.h2
-rw-r--r--usr/src/uts/common/sys/ctfs_impl.h22
-rw-r--r--usr/src/uts/common/sys/epm.h13
-rw-r--r--usr/src/uts/common/sys/extdirent.h77
-rw-r--r--usr/src/uts/common/sys/fcntl.h3
-rw-r--r--usr/src/uts/common/sys/fem.h208
-rw-r--r--usr/src/uts/common/sys/file.h14
-rw-r--r--usr/src/uts/common/sys/fs/fifonode.h11
-rw-r--r--usr/src/uts/common/sys/fs/pc_node.h6
-rw-r--r--usr/src/uts/common/sys/fs/snode.h3
-rw-r--r--usr/src/uts/common/sys/fs/tmp.h9
-rw-r--r--usr/src/uts/common/sys/fs/udf_inode.h11
-rw-r--r--usr/src/uts/common/sys/fs/zfs.h30
-rw-r--r--usr/src/uts/common/sys/gfs.h24
-rw-r--r--usr/src/uts/common/sys/modctl.h2
-rw-r--r--usr/src/uts/common/sys/nbmlock.h17
-rw-r--r--usr/src/uts/common/sys/objfs_impl.h15
-rw-r--r--usr/src/uts/common/sys/policy.h2
-rw-r--r--usr/src/uts/common/sys/sid.h2
-rw-r--r--usr/src/uts/common/sys/socketvar.h25
-rw-r--r--usr/src/uts/common/sys/tzfile.h166
-rw-r--r--usr/src/uts/common/sys/unistd.h10
-rw-r--r--usr/src/uts/common/sys/vfs.h68
-rw-r--r--usr/src/uts/common/sys/vnode.h681
-rw-r--r--usr/src/uts/common/syscall/access.c2
-rw-r--r--usr/src/uts/common/syscall/acctctl.c14
-rw-r--r--usr/src/uts/common/syscall/acl.c28
-rw-r--r--usr/src/uts/common/syscall/chdir.c8
-rw-r--r--usr/src/uts/common/syscall/fcntl.c21
-rw-r--r--usr/src/uts/common/syscall/fdsync.c11
-rw-r--r--usr/src/uts/common/syscall/fsat.c36
-rw-r--r--usr/src/uts/common/syscall/getdents.c11
-rw-r--r--usr/src/uts/common/syscall/ioctl.c11
-rw-r--r--usr/src/uts/common/syscall/lseek.c31
-rw-r--r--usr/src/uts/common/syscall/open.c77
-rw-r--r--usr/src/uts/common/syscall/pathconf.c8
-rw-r--r--usr/src/uts/common/syscall/pipe.c9
-rw-r--r--usr/src/uts/common/syscall/poll.c8
-rw-r--r--usr/src/uts/common/syscall/readlink.c6
-rw-r--r--usr/src/uts/common/syscall/rw.c32
-rw-r--r--usr/src/uts/common/syscall/sendfile.c2
-rw-r--r--usr/src/uts/common/syscall/stat.c9
-rw-r--r--usr/src/uts/common/syscall/symlink.c4
-rw-r--r--usr/src/uts/common/syscall/ucredsys.c4
-rw-r--r--usr/src/uts/common/vm/seg_dev.c14
-rw-r--r--usr/src/uts/common/vm/seg_kp.c8
-rw-r--r--usr/src/uts/common/vm/seg_map.c16
-rw-r--r--usr/src/uts/common/vm/seg_vn.c56
-rw-r--r--usr/src/uts/common/vm/vm_anon.c19
-rw-r--r--usr/src/uts/common/vm/vm_as.c4
-rw-r--r--usr/src/uts/common/vm/vm_page.c32
-rw-r--r--usr/src/uts/common/vm/vm_rm.c10
-rw-r--r--usr/src/uts/common/vm/vm_swap.c25
-rw-r--r--usr/src/uts/common/vm/vpm.c8
-rw-r--r--usr/src/uts/i86xpv/vm/seg_mf.c6
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared1
-rw-r--r--usr/src/uts/intel/os/minor_perm1
-rw-r--r--usr/src/uts/intel/os/name_to_major1
-rw-r--r--usr/src/uts/intel/smbsrv/Makefile100
-rw-r--r--usr/src/uts/intel/zfs/Makefile4
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared1
-rw-r--r--usr/src/uts/sparc/os/minor_perm1
-rw-r--r--usr/src/uts/sparc/os/name_to_major1
-rw-r--r--usr/src/uts/sparc/smbsrv/Makefile99
-rw-r--r--usr/src/uts/sparc/zfs/Makefile4
-rw-r--r--usr/src/uts/sun4u/montecarlo/io/ttymux_dacf/ttymux_dacf.c19
-rw-r--r--usr/src/uts/sun4u/os/cpr_impl.c6
-rw-r--r--usr/src/uts/sun4v/io/vds.c12
800 files changed, 176226 insertions, 9293 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index 07be457327..9cf1c1b209 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -246,6 +246,7 @@ COMMON_SUBDIRS = \
cmd/sdpadm \
cmd/setpgrp \
cmd/smbios \
+ cmd/smbsrv \
cmd/smserverd \
cmd/sort \
cmd/split \
@@ -400,6 +401,7 @@ COMMON_SUBDIRS = \
lib/pkcs11 \
lib/print \
lib/raidcfg_plugins \
+ lib/smbsrv \
lib/fm \
lib/udapl \
lib/watchmalloc \
diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs
index b7d74fa7f7..1e2d094be2 100644
--- a/usr/src/Targetdirs
+++ b/usr/src/Targetdirs
@@ -153,6 +153,7 @@ ROOT.SYS= \
/var/sadm \
/var/opt \
/var/run \
+ /var/smb \
/var/svc \
/var/svc/log \
/var/svc/manifest \
@@ -282,6 +283,7 @@ ROOT.BIN= \
/usr/lib/sasl \
/usr/lib/secure \
/usr/lib/security \
+ /usr/lib/smbsrv \
/usr/lib/term \
/usr/lib/zones \
/usr/old \
@@ -363,6 +365,7 @@ ROOT.SYS2= \
/usr/lib/fs \
/usr/lib/fs/nfs \
/usr/lib/fs/proc \
+ /usr/lib/fs/smb \
/usr/lib/fs/zfs \
/usr/lib/mdb \
/usr/lib/mdb/kvm \
@@ -390,7 +393,8 @@ ROOT.SYS64.2 = \
$($(MACH64)_ROOT.SYS64.2) \
/usr/lib/mdb/kvm/$(MACH64) \
/usr/lib/mdb/proc/$(MACH64) \
- /usr/lib/fs/nfs/$(MACH64)
+ /usr/lib/fs/nfs/$(MACH64) \
+ /usr/lib/fs/smb/$(MACH64)
UUCP.UUCP= \
/var/spool/uucp \
diff --git a/usr/src/cmd/Adm/sun/Makefile b/usr/src/cmd/Adm/sun/Makefile
index 017f4ff8d4..817aafbf61 100644
--- a/usr/src/cmd/Adm/sun/Makefile
+++ b/usr/src/cmd/Adm/sun/Makefile
@@ -2,9 +2,8 @@
# 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.
+# 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.
@@ -20,31 +19,34 @@
# CDDL HEADER END
#
#
-#ident "%Z%%M% %I% %E% SMI"
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
#
-# Copyright (c) 1989, 1995, 1997 by Sun Microsystems, Inc.
-# All Rights Reserved
+# ident "%Z%%M% %I% %E% SMI"
#
ETCFILES= ioctl.syscon passwd shadow motd
KVMFILES= README
+SMBFILES= smbpasswd
include ../../Makefile.cmd
ROOTETCFILES= $(ETCFILES:%=$(ROOTETC)/%)
ROOTUSRKVMFILES= $(KVMFILES:%=$(ROOTUSRKVM)/%)
+ROOTVARSMBFILES= $(SMBFILES:%=$(ROOTVARSMB)/%)
FILEMODE= 0644
OWNER= root
GROUP= sys
$(ROOTETC)/shadow := FILEMODE = 400
+$(ROOTVARSMB)/smbpasswd := FILEMODE = 0400
.KEEP_STATE:
-all: $(ETCFILES) $(KVMFILES)
+all: $(ETCFILES) $(KVMFILES) $(SMBFILES)
-install: all $(ROOTETCFILES) $(ROOTUSRKVMFILES)
+install: all $(ROOTETCFILES) $(ROOTUSRKVMFILES) $(ROOTVARSMBFILES)
clean:
@@ -59,11 +61,14 @@ motd: FRC
@$(NOT_RELEASE_BUILD)-$(ECHO) $(DEV_CM) | sed -e "s/@(#)//" >> motd
@-$(CAT) release_info >> motd
+smbpasswd:
+ $(TOUCH) smbpasswd
+
clean:
lint:
clobber:
- $(RM) motd
+ $(RM) motd smbpasswd
FRC:
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index b3173b0190..f6c720e4f7 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -349,6 +349,7 @@ COMMON_SUBDIRS= \
sh \
sleep \
smbios \
+ smbsrv \
smserverd \
soelim \
sort \
diff --git a/usr/src/cmd/Makefile.cmd b/usr/src/cmd/Makefile.cmd
index 89d085da4d..09e3e1d378 100644
--- a/usr/src/cmd/Makefile.cmd
+++ b/usr/src/cmd/Makefile.cmd
@@ -92,6 +92,7 @@ ROOTUSRSBIN64= $(ROOTUSRSBIN)/$(MACH64)
ROOTMAN1= $(ROOT)/usr/share/man/man1
ROOTMAN1M= $(ROOT)/usr/share/man/man1m
ROOTMAN3= $(ROOT)/usr/share/man/man3
+ROOTVARSMB= $(ROOT)/var/smb
#
@@ -246,6 +247,7 @@ ROOTSVCNETWORKSECURITY= $(ROOTSVCNETWORK)/security
ROOTSVCNETWORKSSL= $(ROOTSVCNETWORK)/ssl
ROOTSVCNETWORKIPSEC= $(ROOTSVCNETWORK)/ipsec
ROOTSVCNETWORKSHARES= $(ROOTSVCNETWORK)/shares
+ROOTSVCSMB= $(ROOTSVCNETWORK)/smb
ROOTSVCPLATFORM= $(ROOTVARSVCMANIFEST)/platform
ROOTSVCPLATFORMSUN4U= $(ROOTSVCPLATFORM)/sun4u
ROOTSVCPLATFORMSUN4V= $(ROOTSVCPLATFORM)/sun4v
@@ -460,6 +462,9 @@ $(ROOTMAN1M)/%: %.sunman
$(ROOTMAN3)/%: %.sunman
$(INS.rename)
+$(ROOTVARSMB)/%: %
+ $(INS.file)
+
# build rule for statically linked programs with single source file.
%.static: %.c
$(LINK.c) -o $@ $< $(LDLIBS)
diff --git a/usr/src/cmd/bnu/in.uucpd.c b/usr/src/cmd/bnu/in.uucpd.c
index d8ae4b02c6..bc0b372f3e 100644
--- a/usr/src/cmd/bnu/in.uucpd.c
+++ b/usr/src/cmd/bnu/in.uucpd.c
@@ -466,7 +466,7 @@ struct sockaddr_in *sin;
* there is no way to do the "pam_close_session()".
*
* Processes like "init" can do a pam_close_session()
- * because they can use the utmp entry to retrive
+ * because they can use the utmp entry to retrieve
* the proper username, ttyname, etc. --
* uucpd only writes to the wtmp file.
*
diff --git a/usr/src/cmd/chmod/Makefile b/usr/src/cmd/chmod/Makefile
index fad270c1b0..5e6b3fe6c4 100644
--- a/usr/src/cmd/chmod/Makefile
+++ b/usr/src/cmd/chmod/Makefile
@@ -2,9 +2,8 @@
# 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.
+# 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.
@@ -22,7 +21,7 @@
#
#ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/chmod/Makefile
@@ -42,7 +41,7 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64
LINTFLAGS += -erroff=E_NAME_DEF_NOT_USED2
-LDLIBS += -lsec
+LDLIBS += -lsec -lnvpair -lcmdutils
POFILE= chmod_cmd.po
XGETFLAGS= -a -x chmod.xcl
diff --git a/usr/src/cmd/chmod/chmod.c b/usr/src/cmd/chmod/chmod.c
index 29813f7d09..531c4bf3d2 100644
--- a/usr/src/cmd/chmod/chmod.c
+++ b/usr/src/cmd/chmod/chmod.c
@@ -44,7 +44,8 @@
* where
* mode is [ugoa][+-=][rwxXlstugo] or an octal number
* mode is [<+|->A[# <number] ]<aclspec>
- * option is -R and -f
+ * mode is S<attrspec>
+ * option is -R, -f, and -@
*/
/*
@@ -58,6 +59,7 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include <dirent.h>
#include <locale.h>
#include <string.h> /* strerror() */
@@ -67,6 +69,10 @@
#include <errno.h>
#include <sys/acl.h>
#include <aclutils.h>
+#include <libnvpair.h>
+#include <libcmdutils.h>
+#include <libgen.h>
+#include <attr.h>
static int rflag;
static int fflag;
@@ -79,11 +85,37 @@ static char **mav; /* Alternate to argv (for parseargs) */
static char *ms; /* Points to the mode argument */
-#define ACL_ADD 1
-#define ACL_DELETE 2
-#define ACL_SLOT_DELETE 3
-#define ACL_REPLACE 4
-#define ACL_STRIP 5
+#define ACL_ADD 1
+#define ACL_DELETE 2
+#define ACL_SLOT_DELETE 3
+#define ACL_REPLACE 4
+#define ACL_STRIP 5
+
+#define LEFTBRACE '{'
+#define RIGHTBRACE '}'
+#define A_SEP ','
+#define A_SEP_TOK ","
+
+#define A_COMPACT_TYPE 'c'
+#define A_VERBOSE_TYPE 'v'
+#define A_ALLATTRS_TYPE 'a'
+
+#define A_SET_OP '+'
+#define A_INVERSE_OP '-'
+#define A_REPLACE_OP '='
+#define A_UNDEF_OP '\0'
+
+#define A_SET_TEXT "set"
+#define A_INVERSE_TEXT "clear"
+
+#define A_SET_VAL B_TRUE
+#define A_CLEAR_VAL B_FALSE
+
+#define ATTR_OPTS 0
+#define ATTR_NAMES 1
+
+#define sec_acls secptr.acls
+#define sec_attrs secptr.attrs
typedef struct acl_args {
acl_t *acl_aclp;
@@ -91,34 +123,55 @@ typedef struct acl_args {
int acl_action;
} acl_args_t;
-extern mode_t
-newmode_common(char *ms, mode_t new_mode, mode_t umsk, char *file, char *path,
- o_mode_t *group_clear_bits, o_mode_t *group_set_bits);
+typedef enum {
+ SEC_ACL,
+ SEC_ATTR
+} chmod_sec_t;
-static int
-dochmod(char *name, char *path, mode_t umsk, acl_args_t *aclp),
-chmodr(char *dir, char *path, mode_t mode, mode_t umsk, acl_args_t *aclp);
-static int doacl(char *file, struct stat *st, acl_args_t *aclp);
+typedef struct {
+ chmod_sec_t sec_type;
+ union {
+ acl_args_t *acls;
+ nvlist_t *attrs;
+ } secptr;
+} sec_args_t;
-static void handle_acl(char *name, o_mode_t group_clear_bits,
- o_mode_t group_set_bits);
+typedef struct attr_name {
+ char *name;
+ struct attr_name *next;
+} attr_name_t;
-static void usage(void);
-void errmsg(int severity, int code, char *format, ...);
+extern mode_t newmode_common(char *ms, mode_t new_mode, mode_t umsk,
+ char *file, char *path, o_mode_t *group_clear_bits,
+ o_mode_t *group_set_bits);
+static int chmodr(char *dir, char *path, mode_t mode, mode_t umsk,
+ sec_args_t *secp, attr_name_t *attrname);
+static int doacl(char *file, struct stat *st, acl_args_t *aclp);
+static int dochmod(char *name, char *path, mode_t umsk, sec_args_t *secp,
+ attr_name_t *attrnames);
+static void handle_acl(char *name, o_mode_t group_clear_bits,
+ o_mode_t group_set_bits);
+void errmsg(int severity, int code, char *format, ...);
+static void free_attr_names(attr_name_t *attrnames);
static void parseargs(int ac, char *av[]);
-
-int
-parse_acl_args(char *arg, acl_args_t **acl_args);
+static int parse_acl_args(char *arg, sec_args_t **sec_args);
+static int parse_attr_args(char *arg, sec_args_t **sec_args);
+static void print_attrs(int flag);
+static int set_attrs(char *file, attr_name_t *attrnames, nvlist_t *attr_nvlist);
+static void usage(void);
int
main(int argc, char *argv[])
{
- int i, c;
- int status = 0;
- mode_t umsk;
- acl_args_t *acl_args = NULL;
+ int i, c;
+ int status = 0;
+ mode_t umsk;
+ sec_args_t *sec_args = NULL;
+ attr_name_t *attrnames = NULL;
+ attr_name_t *attrend = NULL;
+ attr_name_t *tattr;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
@@ -128,7 +181,7 @@ main(int argc, char *argv[])
parseargs(argc, argv);
- while ((c = getopt(mac, mav, "Rf")) != EOF) {
+ while ((c = getopt(mac, mav, "Rf@:")) != EOF) {
switch (c) {
case 'R':
rflag++;
@@ -136,6 +189,20 @@ main(int argc, char *argv[])
case 'f':
fflag++;
break;
+ case '@':
+ if (((tattr = malloc(sizeof (attr_name_t))) == NULL) ||
+ ((tattr->name = strdup(optarg)) == NULL)) {
+ perror("chmod");
+ exit(2);
+ }
+ if (attrnames == NULL) {
+ attrnames = tattr;
+ attrnames->next = NULL;
+ } else {
+ attrend->next = tattr;
+ }
+ attrend = tattr;
+ break;
case '?':
usage();
exit(2);
@@ -149,16 +216,33 @@ main(int argc, char *argv[])
mac -= optind;
mav += optind;
- if (mac >= 2 && (mav[0][0] == 'A')) {
- if (parse_acl_args(*mav, &acl_args)) {
+ if ((mac >= 2) && (mav[0][0] == 'A')) {
+ if (attrnames != NULL) {
+ free_attr_names(attrnames);
+ attrnames = NULL;
+ }
+ if (parse_acl_args(*mav, &sec_args)) {
usage();
exit(2);
}
+ } else if ((mac >= 2) && (mav[0][0] == 'S')) {
+ if (parse_attr_args(*mav, &sec_args)) {
+ usage();
+ exit(2);
+
+ /* A no-op attribute operation was specified. */
+ } else if (sec_args->sec_attrs == NULL) {
+ exit(0);
+ }
} else {
if (mac < 2) {
usage();
exit(2);
}
+ if (attrnames != NULL) {
+ free_attr_names(attrnames);
+ attrnames = NULL;
+ }
}
ms = mav[0];
@@ -167,14 +251,30 @@ main(int argc, char *argv[])
(void) umask(umsk);
for (i = 1; i < mac; i++) {
- status += dochmod(mav[i], mav[i], umsk, acl_args);
+ status += dochmod(mav[i], mav[i], umsk, sec_args, attrnames);
}
return (fflag ? 0 : status);
}
+static void
+free_attr_names(attr_name_t *attrnames)
+{
+ attr_name_t *attrnamesptr = attrnames;
+ attr_name_t *tptr;
+
+ while (attrnamesptr != NULL) {
+ tptr = attrnamesptr->next;
+ if (attrnamesptr->name != NULL) {
+ free(attrnamesptr->name);
+ }
+ attrnamesptr = tptr;
+ }
+}
+
static int
-dochmod(char *name, char *path, mode_t umsk, acl_args_t *aclp)
+dochmod(char *name, char *path, mode_t umsk, sec_args_t *secp,
+ attr_name_t *attrnames)
{
static struct stat st;
int linkflg = 0;
@@ -194,15 +294,24 @@ dochmod(char *name, char *path, mode_t umsk, acl_args_t *aclp)
}
/* Do not recurse if directory is object of symbolic link */
- if (rflag && ((st.st_mode & S_IFMT) == S_IFDIR) && !linkflg)
- return (chmodr(name, path, st.st_mode, umsk, aclp));
+ if (rflag && ((st.st_mode & S_IFMT) == S_IFDIR) && !linkflg) {
+ return (chmodr(name, path, st.st_mode, umsk, secp, attrnames));
+ }
- if (aclp) {
- return (doacl(name, &st, aclp));
- } else if (chmod(name, newmode_common(ms, st.st_mode, umsk, name, path,
- &group_clear_bits, &group_set_bits)) == -1) {
- errmsg(2, 0, gettext("can't change %s\n"), path);
- return (1);
+ if (secp != NULL) {
+ if (secp->sec_type == SEC_ACL) {
+ return (doacl(name, &st, secp->sec_acls));
+ } else if (secp->sec_type == SEC_ATTR) {
+ return (set_attrs(name, attrnames, secp->sec_attrs));
+ } else {
+ return (1);
+ }
+ } else {
+ if (chmod(name, newmode_common(ms, st.st_mode, umsk, name, path,
+ &group_clear_bits, &group_set_bits)) == -1) {
+ errmsg(2, 0, gettext("can't change %s\n"), path);
+ return (1);
+ }
}
/*
@@ -218,9 +327,9 @@ dochmod(char *name, char *path, mode_t umsk, acl_args_t *aclp)
return (0);
}
-
static int
-chmodr(char *dir, char *path, mode_t mode, mode_t umsk, acl_args_t *aclp)
+chmodr(char *dir, char *path, mode_t mode, mode_t umsk, sec_args_t *secp,
+ attr_name_t *attrnames)
{
DIR *dirp;
@@ -239,13 +348,21 @@ chmodr(char *dir, char *path, mode_t mode, mode_t umsk, acl_args_t *aclp)
/*
* Change what we are given before doing it's contents
*/
- if (aclp) {
+ if (secp != NULL) {
if (lstat(dir, &st) < 0) {
errmsg(2, 0, gettext("can't access %s\n"), path);
return (1);
}
- if (doacl(dir, &st, aclp) != 0)
+ if (secp->sec_type == SEC_ACL) {
+ if (doacl(dir, &st, secp->sec_acls) != 0)
+ return (1);
+ } else if (secp->sec_type == SEC_ATTR) {
+ if (set_attrs(dir, attrnames, secp->sec_attrs) != 0) {
+ return (1);
+ }
+ } else {
return (1);
+ }
} else if (chmod(dir, newmode_common(ms, mode, umsk, dir, path,
&group_clear_bits, &group_set_bits)) < 0) {
errmsg(2, 0, gettext("can't change %s\n"), path);
@@ -260,7 +377,8 @@ chmodr(char *dir, char *path, mode_t mode, mode_t umsk, acl_args_t *aclp)
* general group permissions.
*/
- if (aclp == NULL) { /* only necessary when not setting ACL */
+ if (secp != NULL) {
+ /* only necessary when not setting ACL or system attributes */
if (group_clear_bits || group_set_bits)
handle_acl(dir, group_clear_bits, group_set_bits);
}
@@ -315,7 +433,7 @@ chmodr(char *dir, char *path, mode_t mode, mode_t umsk, acl_args_t *aclp)
currdir, dp->d_name);
return (1);
}
- ecode += dochmod(dp->d_name, currdir, umsk, aclp);
+ ecode += dochmod(dp->d_name, currdir, umsk, secp, attrnames);
}
(void) closedir(dirp);
if (chdir(savedir) < 0) {
@@ -344,7 +462,7 @@ errmsg(int severity, int code, char *format, ...)
*/
if (!fflag || (code != 0)) {
(void) fprintf(stderr,
- "chmod: %s: ", gettext(msg[severity]));
+ "chmod: %s: ", gettext(msg[severity]));
(void) vfprintf(stderr, format, ap);
}
@@ -361,17 +479,36 @@ usage(void)
"usage:\tchmod [-fR] <absolute-mode> file ...\n"));
(void) fprintf(stderr, gettext(
- "\tchmod [-fR] <ACL-operation> file ...\n"));
+ "\tchmod [-fR] [-@ attribute] ... "
+ "S<attribute-operation> file ...\n"));
(void) fprintf(stderr, gettext(
- "\tchmod [-fR] <symbolic-mode-list> file ...\n"));
+ "\tchmod [-fR] <ACL-operation> file ...\n"));
+ (void) fprintf(stderr, gettext(
+ "\tchmod [-fR] <symbolic-mode-list> file ...\n\n"));
(void) fprintf(stderr, gettext(
"where \t<symbolic-mode-list> is a comma-separated list of\n"));
+ (void) fprintf(stderr, gettext(
+ "\t[ugoa]{+|-|=}[rwxXlstugo]\n\n"));
(void) fprintf(stderr, gettext(
- "\t[ugoa]{+|-|=}[rwxXlstugo]\n"));
+ "where \t<attribute-operation> is a comma-separated list of\n"
+ "\tone or more of the following\n"));
+ (void) fprintf(stderr, gettext(
+ "\t[+|-|=]c[<compact-attribute-list>|{<compact-attribute-list>}]\n"
+ "\t[+|-|=]v[<verbose-attribute-setting>|"
+ "\'{\'<verbose-attribute-setting-list>\'}\']\n"
+ "\t[+|-|=]a\n"));
+ (void) fprintf(stderr, gettext(
+ "where \t<compact-attribute-list> is a list of zero or more of\n"));
+ print_attrs(ATTR_OPTS);
+ (void) fprintf(stderr, gettext(
+ "where \t<verbose-attribute-setting> is one of\n"));
+ print_attrs(ATTR_NAMES);
+ (void) fprintf(stderr, gettext(
+ "\tand can be, optionally, immediately preceded by \"no\"\n\n"));
(void) fprintf(stderr, gettext(
"where \t<ACL-operation> is one of the following\n"));
@@ -416,7 +553,7 @@ parseargs(int ac, char *av[])
for (fflag = i = 0; i < ac; i ++) {
if (strcmp(av[i], "--") == 0)
- fflag = 1;
+ fflag = 1;
}
/* process the arguments */
@@ -435,19 +572,26 @@ parseargs(int ac, char *av[])
*/
if ((strchr(av[i], 'R') == NULL &&
- strchr(av[i], 'f') == NULL)) {
- mav[mac++] = strdup("--");
+ strchr(av[i], 'f') == NULL) &&
+ strchr(av[i], '@') == NULL) {
+ if ((mav[mac++] = strdup("--")) == NULL) {
+ perror("chmod");
+ exit(2);
+ }
}
}
- mav[mac++] = strdup(av[i]);
+ if ((mav[mac++] = strdup(av[i])) == NULL) {
+ perror("chmod");
+ exit(2);
+ }
}
mav[mac] = (char *)NULL;
}
-int
-parse_acl_args(char *arg, acl_args_t **acl_args)
+static int
+parse_acl_args(char *arg, sec_args_t **sec_args)
{
acl_t *new_acl = NULL;
int slot;
@@ -512,7 +656,12 @@ parse_acl_args(char *arg, acl_args_t **acl_args)
new_acl_args->acl_slot = slot;
new_acl_args->acl_action = action;
- *acl_args = new_acl_args;
+ if ((*sec_args = malloc(sizeof (sec_args_t))) == NULL) {
+ perror("chmod");
+ exit(2);
+ }
+ (*sec_args)->sec_type = SEC_ACL;
+ (*sec_args)->sec_acls = new_acl_args;
return (0);
}
@@ -593,10 +742,10 @@ doacl(char *file, struct stat *st, acl_args_t *acl_args)
switch (acl_args->acl_action) {
case ACL_ADD:
if ((error = acl_addentries(aclp,
- acl_args->acl_aclp, acl_args->acl_slot)) != 0) {
- errmsg(1, 1, "%s\n", acl_strerror(error));
- acl_free(aclp);
- return (1);
+ acl_args->acl_aclp, acl_args->acl_slot)) != 0) {
+ errmsg(1, 1, "%s\n", acl_strerror(error));
+ acl_free(aclp);
+ return (1);
}
set_aclp = aclp;
break;
@@ -699,3 +848,630 @@ doacl(char *file, struct stat *st, acl_args_t *acl_args)
acl_free(aclp);
return (0);
}
+
+/*
+ * Prints out the attributes in their verbose form:
+ * '{'[["no"]<attribute-name>][,["no"]<attribute-name>]...'}'
+ * similar to output of ls -/v.
+ */
+static void
+print_nvlist(nvlist_t *attr_nvlist)
+{
+ int firsttime = 1;
+ boolean_t value;
+ nvlist_t *lptr = attr_nvlist;
+ nvpair_t *pair = NULL;
+
+ (void) fprintf(stderr, "\t%c", LEFTBRACE);
+ while (pair = nvlist_next_nvpair(lptr, pair)) {
+ if (nvpair_value_boolean_value(pair, &value) == 0) {
+ (void) fprintf(stderr, "%s%s%s",
+ firsttime ? "" : A_SEP_TOK,
+ (value == A_SET_VAL) ? "" : "no",
+ nvpair_name(pair));
+ firsttime = 0;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "<error retrieving attributes: %s>"),
+ strerror(errno));
+ break;
+ }
+ }
+ (void) fprintf(stderr, "%c\n", RIGHTBRACE);
+}
+
+/*
+ * Add an attribute name and boolean value to an nvlist if an action is to be
+ * performed for that attribute. The nvlist will be used later to set all the
+ * attributes in the nvlist in one operation through a call to setattrat().
+ *
+ * If a set operation ('+') was specified, then a boolean representation of the
+ * attribute's value will be added to the nvlist for that attribute name. If an
+ * inverse operation ('-') was specified, then a boolean representation of the
+ * inverse of the attribute's value will be added to the nvlist for that
+ * attribute name.
+ *
+ * Returns an nvlist of attribute name and boolean value pairs if there are
+ * attribute actions to be performed, otherwise returns NULL.
+ */
+static nvlist_t *
+set_attrs_nvlist(char *attractptr, int numofattrs)
+{
+ int attribute_set = 0;
+ f_attr_t i;
+ nvlist_t *attr_nvlist;
+
+ if (nvlist_alloc(&attr_nvlist, NV_UNIQUE_NAME, 0) != 0) {
+ perror("chmod");
+ exit(2);
+ }
+
+ for (i = 0; i < numofattrs; i++) {
+ if (attractptr[i] != '\0') {
+ if ((nvlist_add_boolean_value(attr_nvlist,
+ attr_to_name(i),
+ (attractptr[i] == A_SET_OP))) != 0) {
+ errmsg(1, 2, gettext(
+ "unable to propagate attribute names and"
+ "values: %s\n"), strerror(errno));
+ } else {
+ attribute_set = 1;
+ }
+ }
+ }
+ return (attribute_set ? attr_nvlist : NULL);
+}
+
+/*
+ * Set the attributes of file, or if specified, of the named attribute file,
+ * attrname. Build an nvlist of attribute names and values and call setattrat()
+ * to set the attributes in one operation.
+ *
+ * Returns 0 if successful, otherwise returns 1.
+ */
+static int
+set_file_attrs(char *file, char *attrname, nvlist_t *attr_nvlist)
+{
+ int rc;
+ char *filename;
+
+ if (attrname != NULL) {
+ filename = attrname;
+ } else {
+ filename = basename(file);
+ }
+
+ if ((rc = setattrat(AT_FDCWD, XATTR_VIEW_READWRITE, filename,
+ attr_nvlist)) != 0) {
+ char *emsg;
+ switch (errno) {
+ case EINVAL:
+ emsg = gettext("not supported");
+ break;
+ case EPERM:
+ emsg = gettext("not privileged");
+ break;
+ default:
+ emsg = strerror(rc);
+ }
+ errmsg(1, 0, gettext(
+ "cannot set the following attributes on "
+ "%s%s%s%s: %s\n"),
+ (attrname == NULL) ? "" : gettext("attribute "),
+ (attrname == NULL) ? "" : attrname,
+ (attrname == NULL) ? "" : gettext(" of "),
+ file, emsg);
+ print_nvlist(attr_nvlist);
+ }
+
+ return (rc);
+}
+
+static int
+save_cwd(void)
+{
+ return (open(".", O_RDONLY));
+}
+
+static void
+rest_cwd(int cwd)
+{
+ if (cwd != -1) {
+ if (fchdir(cwd) != 0) {
+ errmsg(1, 1, gettext(
+ "can't change to current working directory\n"));
+ }
+ (void) close(cwd);
+ }
+}
+
+/*
+ * Returns 1 if filename is a system attribute file, otherwise
+ * returns 0.
+ */
+static int
+is_sattr(char *filename)
+{
+ return (sysattr_type(filename) != _NOT_SATTR);
+}
+
+/*
+ * Perform the action on the specified named attribute file for the file
+ * associated with the input file descriptor. If the named attribute file
+ * is "*", then the action is to be performed on all the named attribute files
+ * of the file associated with the input file descriptor.
+ */
+static int
+set_named_attrs(char *file, int parentfd, char *attrname, nvlist_t *attr_nvlist)
+{
+ int dirfd;
+ int error = 0;
+ DIR *dirp = NULL;
+ struct dirent *dp;
+ struct stat st;
+
+ if ((attrname == NULL) || (strcmp(attrname, "*") != 0)) {
+ /*
+ * Make sure the named attribute exists and extended system
+ * attributes are supported on the underlying file system.
+ */
+ if (attrname != NULL) {
+ if (fstatat(parentfd, attrname, &st,
+ AT_SYMLINK_NOFOLLOW) < 0) {
+ errmsg(2, 0, gettext(
+ "can't access attribute %s of %s\n"),
+ attrname, file);
+ return (1);
+ }
+ if (sysattr_support(attrname, _PC_SATTR_ENABLED) != 1) {
+ errmsg(1, 0, gettext(
+ "extended system attributes not supported "
+ "for attribute %s of %s\n"),
+ attrname, file);
+ return (1);
+ }
+ }
+
+ error = set_file_attrs(file, attrname, attr_nvlist);
+
+ } else {
+ if (((dirfd = dup(parentfd)) == -1) ||
+ ((dirp = fdopendir(dirfd)) == NULL)) {
+ errmsg(1, 0, gettext(
+ "cannot open dir pointer of file %s\n"), file);
+ if (dirfd > 0) {
+ (void) close(dirfd);
+ }
+ return (1);
+ }
+
+ while (dp = readdir(dirp)) {
+ /*
+ * Process all extended attribute files except
+ * ".", "..", and extended system attribute files.
+ */
+ if ((strcmp(dp->d_name, ".") == 0) ||
+ (strcmp(dp->d_name, "..") == 0) ||
+ is_sattr(dp->d_name)) {
+ continue;
+ }
+
+ if (set_named_attrs(file, parentfd, dp->d_name,
+ attr_nvlist) != 0) {
+ error++;
+ }
+ }
+ if (dirp != NULL) {
+ (void) closedir(dirp);
+ }
+ }
+
+ return ((error == 0) ? 0 : 1);
+}
+
+/*
+ * Set the attributes of the specified file, or if specified with -@ on the
+ * command line, the specified named attributes of the specified file.
+ *
+ * Returns 0 if successful, otherwise returns 1.
+ */
+static int
+set_attrs(char *file, attr_name_t *attrnames, nvlist_t *attr_nvlist)
+{
+ char *parentd;
+ char *tpath = NULL;
+ int cwd;
+ int error = 0;
+ int parentfd;
+ attr_name_t *tattr = attrnames;
+
+ if (attr_nvlist == NULL) {
+ return (0);
+ }
+
+ if (sysattr_support(file, _PC_SATTR_ENABLED) != 1) {
+ errmsg(1, 0, gettext(
+ "extended system attributes not supported for %s\n"), file);
+ return (1);
+ }
+
+ /*
+ * Open the parent directory and change into it before attempting
+ * to set the attributes of the file.
+ */
+ if (attrnames == NULL) {
+ tpath = strdup(file);
+ parentd = dirname(tpath);
+ parentfd = open(parentd, O_RDONLY);
+ } else {
+ parentfd = attropen(file, ".", O_RDONLY);
+ }
+ if (parentfd == -1) {
+ errmsg(1, 0, gettext(
+ "cannot open attribute directory of %s\n"), file);
+ if (tpath != NULL) {
+ free(tpath);
+ }
+ return (1);
+ }
+
+ if ((cwd = save_cwd()) < 0) {
+ errmsg(1, 1, gettext(
+ "can't get current working directory\n"));
+ }
+ if (fchdir(parentfd) != 0) {
+ errmsg(1, 0, gettext(
+ "can't change to parent %sdirectory of %s\n"),
+ (attrnames == NULL) ? "" : gettext("attribute "), file);
+ (void) close(cwd);
+ (void) close(parentfd);
+ if (tpath != NULL) {
+ free(tpath);
+ }
+ return (1);
+ }
+
+ /*
+ * If no named attribute file names were provided on the command line
+ * then set the attributes of the base file, otherwise, set the
+ * attributes for each of the named attribute files specified.
+ */
+ if (attrnames == NULL) {
+ error = set_named_attrs(file, parentfd, NULL, attr_nvlist);
+ free(tpath);
+ } else {
+ while (tattr != NULL) {
+ if (set_named_attrs(file, parentfd, tattr->name,
+ attr_nvlist) != 0) {
+ error++;
+ }
+ tattr = tattr->next;
+ }
+ }
+ (void) close(parentfd);
+ rest_cwd(cwd);
+
+ return ((error == 0) ? 0 : 1);
+}
+
+/*
+ * Prints the attributes in either the compact or verbose form indicated
+ * by flag.
+ */
+static void
+print_attrs(int flag)
+{
+ f_attr_t i;
+ static int numofattrs;
+ int firsttime = 1;
+
+ numofattrs = attr_count();
+
+ (void) fprintf(stderr, gettext("\t["));
+ for (i = 0; i < numofattrs; i++) {
+ if ((attr_to_xattr_view(i) != XATTR_VIEW_READWRITE) ||
+ (attr_to_data_type(i) != DATA_TYPE_BOOLEAN_VALUE)) {
+ continue;
+ }
+ (void) fprintf(stderr, "%s%s",
+ (firsttime == 1) ? "" : gettext("|"),
+ (flag == ATTR_OPTS) ? attr_to_option(i) : attr_to_name(i));
+ firsttime = 0;
+ }
+ (void) fprintf(stderr, gettext("]\n"));
+}
+
+/*
+ * Record what action should be taken on the specified attribute. Only boolean
+ * read-write attributes can be manipulated.
+ *
+ * Returns 0 if successful, otherwise returns 1.
+ */
+static int
+set_attr_args(f_attr_t attr, char action, char *attractptr)
+{
+ if ((attr_to_xattr_view(attr) == XATTR_VIEW_READWRITE) &&
+ (attr_to_data_type(attr) == DATA_TYPE_BOOLEAN_VALUE)) {
+ attractptr[attr] = action;
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Parses the entry and assigns the appropriate action (either '+' or '-' in
+ * attribute's position in the character array pointed to by attractptr, where
+ * upon exit, attractptr is positional and the value of each character specifies
+ * whether to set (a '+'), clear (a '-'), or leave untouched (a '\0') the
+ * attribute value.
+ *
+ * If the entry is an attribute name, then the A_SET_OP action is to be
+ * performed for this attribute. If the entry is an attribute name proceeded
+ * with "no", then the A_INVERSE_OP action is to be performed for this
+ * attribute. If the entry is one or more attribute option letters, then step
+ * through each of the option letters marking the action to be performed for
+ * each of the attributes associated with the letter as A_SET_OP.
+ *
+ * Returns 0 if the entry was a valid attribute(s) and the action to be
+ * performed on that attribute(s) has been recorded, otherwise returns 1.
+ */
+static int
+parse_entry(char *entry, char action, char atype, int len, char *attractptr)
+{
+ char aopt[2] = {'\0', '\0'};
+ char *aptr;
+ f_attr_t attr;
+
+ if (atype == A_VERBOSE_TYPE) {
+ if ((attr = name_to_attr(entry)) != F_ATTR_INVAL) {
+ return (set_attr_args(attr,
+ (action == A_REPLACE_OP) ? A_SET_OP : action,
+ attractptr));
+ } else if ((len > 2) && (strncmp(entry, "no", 2) == 0) &&
+ ((attr = name_to_attr(entry + 2)) != F_ATTR_INVAL)) {
+ return (set_attr_args(attr, ((action == A_REPLACE_OP) ||
+ (action == A_SET_OP)) ? A_INVERSE_OP : A_SET_OP,
+ attractptr));
+ } else {
+ return (1);
+ }
+ } else if (atype == A_COMPACT_TYPE) {
+ for (aptr = entry; *aptr != '\0'; aptr++) {
+ *aopt = *aptr;
+ /*
+ * The output of 'ls' can be used as the attribute mode
+ * specification for chmod. This output can contain a
+ * hypen ('-') for each attribute that is not set. If
+ * so, ignore them. If a replace action is being
+ * performed, then all attributes that don't have an
+ * action set here, will be cleared down the line.
+ */
+ if (*aptr == '-') {
+ continue;
+ }
+ if (set_attr_args(option_to_attr(aopt),
+ (action == A_REPLACE_OP) ? A_SET_OP : action,
+ attractptr) != 0) {
+ return (1);
+ }
+ }
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Parse the attribute specification, aoptsstr. Upon completion, attr_nvlist
+ * will point to an nvlist which contains pairs of attribute names and values
+ * to be set; attr_nvlist will be NULL if it is a no-op.
+ *
+ * The attribute specification format is
+ * S[oper]attr_type[attribute_list]
+ * where oper is
+ * + set operation of specified attributes in attribute list.
+ * This is the default operation.
+ * - inverse operation of specified attributes in attribute list
+ * = replace operation of all attributes. All attribute operations
+ * depend on those specified in the attribute list. Attributes
+ * not specified in the attribute list will be cleared.
+ * where attr_type is
+ * c compact type. Each entry in the attribute list is a character
+ * option representing an associated attribute name.
+ * v verbose type. Each entry in the attribute list is an
+ * an attribute name which can optionally be preceeded with "no"
+ * (to imply the attribute should be cleared).
+ * a all attributes type. The oper should be applied to all
+ * read-write boolean system attributes. No attribute list should
+ * be specified after an 'a' attribute type.
+ *
+ * Returns 0 if aoptsstr contained a valid attribute specification,
+ * otherwise, returns 1.
+ */
+static int
+parse_attr_args(char *aoptsstr, sec_args_t **sec_args)
+{
+ char action;
+ char *attractptr;
+ char atype;
+ char *entry;
+ char *eptr;
+ char *nextattr;
+ char *nextentry;
+ char *subentry;
+ char *teptr;
+ char tok[] = {'\0', '\0'};
+ int len;
+ f_attr_t i;
+ int numofattrs;
+
+ if ((*aoptsstr != 'S') || (*(aoptsstr + 1) == '\0')) {
+ return (1);
+ }
+
+ if ((eptr = strdup(aoptsstr + 1)) == NULL) {
+ perror("chmod");
+ exit(2);
+ }
+ entry = eptr;
+
+ /*
+ * Create a positional character array to determine a single attribute
+ * operation to be performed, where each index represents the system
+ * attribute affected, and it's value in the array represents the action
+ * to be performed, i.e., a value of '+' means to set the attribute, a
+ * value of '-' means to clear the attribute, and a value of '\0' means
+ * to leave the attribute untouched. Initially, this positional
+ * character array is all '\0's, representing a no-op.
+ */
+ if ((numofattrs = attr_count()) < 1) {
+ errmsg(1, 1, gettext("system attributes not supported\n"));
+ }
+
+ if ((attractptr = calloc(numofattrs, sizeof (char))) == NULL) {
+ perror("chmod");
+ exit(2);
+ }
+
+ if ((*sec_args = malloc(sizeof (sec_args_t))) == NULL) {
+ perror("chmod");
+ exit(2);
+ }
+ (*sec_args)->sec_type = SEC_ATTR;
+ (*sec_args)->sec_attrs = NULL;
+
+ /* Parse each attribute operation within the attribute specification. */
+ while ((entry != NULL) && (*entry != '\0')) {
+ action = A_SET_OP;
+ atype = '\0';
+
+ /* Get the operator. */
+ switch (*entry) {
+ case A_SET_OP:
+ case A_INVERSE_OP:
+ case A_REPLACE_OP:
+ action = *entry++;
+ break;
+ case A_COMPACT_TYPE:
+ case A_VERBOSE_TYPE:
+ case A_ALLATTRS_TYPE:
+ atype = *entry++;
+ action = A_SET_OP;
+ break;
+ default:
+ break;
+ }
+
+ /* An attribute type must be specified. */
+ if (atype == '\0') {
+ if ((*entry == A_COMPACT_TYPE) ||
+ (*entry == A_VERBOSE_TYPE) ||
+ (*entry == A_ALLATTRS_TYPE)) {
+ atype = *entry++;
+ } else {
+ return (1);
+ }
+ }
+
+ /* Get the attribute specification separator. */
+ if (*entry == LEFTBRACE) {
+ *tok = RIGHTBRACE;
+ entry++;
+ } else {
+ *tok = A_SEP;
+ }
+
+ /* Get the attribute operation */
+ if ((nextentry = strpbrk(entry, tok)) != NULL) {
+ *nextentry = '\0';
+ nextentry++;
+ }
+
+ /* Check for a no-op */
+ if ((*entry == '\0') && (atype != A_ALLATTRS_TYPE) &&
+ (action != A_REPLACE_OP)) {
+ entry = nextentry;
+ continue;
+ }
+
+ /*
+ * Step through the attribute operation, setting the
+ * appropriate values for the specified attributes in the
+ * character array, attractptr. A value of '+' will mean the
+ * attribute is to be set, and a value of '-' will mean the
+ * attribute is to be cleared. If the value of an attribute
+ * remains '\0', then no action is to be taken on that
+ * attribute. As multiple operations specified are
+ * accumulated, a single attribute setting operation is
+ * represented in attractptr.
+ */
+ len = strlen(entry);
+ if ((*tok == RIGHTBRACE) || (action == A_REPLACE_OP) ||
+ (atype == A_ALLATTRS_TYPE)) {
+
+ if ((action == A_REPLACE_OP) ||
+ (atype == A_ALLATTRS_TYPE)) {
+ (void) memset(attractptr, '\0', numofattrs);
+ }
+
+ if (len > 0) {
+ if ((teptr = strdup(entry)) == NULL) {
+ perror("chmod");
+ exit(2);
+ }
+ subentry = teptr;
+ while (subentry != NULL) {
+ if ((nextattr = strpbrk(subentry,
+ A_SEP_TOK)) != NULL) {
+ *nextattr = '\0';
+ nextattr++;
+ }
+ if (parse_entry(subentry, action,
+ atype, len, attractptr) != 0) {
+ return (1);
+ }
+ subentry = nextattr;
+ }
+ free(teptr);
+ }
+
+ /*
+ * If performing the replace action, record the
+ * attributes and values for the rest of the
+ * attributes that have not already been recorded,
+ * otherwise record the specified action for all
+ * attributes. Note: set_attr_args() will only record
+ * the attribute and action if it is a boolean
+ * read-write attribute so we don't need to worry
+ * about checking it here.
+ */
+ if ((action == A_REPLACE_OP) ||
+ (atype == A_ALLATTRS_TYPE)) {
+ for (i = 0; i < numofattrs; i++) {
+ if (attractptr[i] == A_UNDEF_OP) {
+ (void) set_attr_args(i,
+ (action == A_SET_OP) ?
+ A_SET_OP : A_INVERSE_OP,
+ attractptr);
+ }
+ }
+ }
+
+ } else {
+ if (parse_entry(entry, action, atype, len,
+ attractptr) != 0) {
+ return (1);
+ }
+ }
+ entry = nextentry;
+ }
+
+ /*
+ * Populate an nvlist with attribute name and boolean value pairs
+ * using the single attribute operation.
+ */
+ (*sec_args)->sec_attrs = set_attrs_nvlist(attractptr, numofattrs);
+ free(attractptr);
+ free(eptr);
+
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-inet/etc/services b/usr/src/cmd/cmd-inet/etc/services
index a4862b5bbe..edb0bb6c5d 100644
--- a/usr/src/cmd/cmd-inet/etc/services
+++ b/usr/src/cmd/cmd-inet/etc/services
@@ -93,6 +93,8 @@ slp 427/tcp slp # Service Location Protocol, V2
slp 427/udp slp # Service Location Protocol, V2
mobile-ip 434/udp mobile-ip # Mobile-IP
cvc_hostd 442/tcp # Network Console
+microsoft-ds 445/tcp # Microsoft Directory Services
+microsoft-ds 445/udp # Microsoft Directory Services
ike 500/udp ike # Internet Key Exchange
uuidgen 697/tcp # UUID Generator
uuidgen 697/udp # UUID Generator
diff --git a/usr/src/cmd/compress/Makefile b/usr/src/cmd/compress/Makefile
index 5fc1e35e42..ea306d8cc2 100644
--- a/usr/src/cmd/compress/Makefile
+++ b/usr/src/cmd/compress/Makefile
@@ -39,7 +39,7 @@ CFLAGS += $(CCVERBOSE)
CPPFLAGS += -D_FILE_OFFSET_BITS=64 -I $(SRC)/common/util
LINTFLAGS += -u
-LDLIBS += -lsec
+LDLIBS += -lcmdutils -lsec
all: $(PROG)
diff --git a/usr/src/cmd/compress/compress.c b/usr/src/cmd/compress/compress.c
index fd08c406b9..de8e62b704 100644
--- a/usr/src/cmd/compress/compress.c
+++ b/usr/src/cmd/compress/compress.c
@@ -116,30 +116,20 @@ static char_type magic_header[] = { "\037\235" }; /* 1F 9D */
static char rcs_ident[] =
"$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $";
-#include <stdio.h>
#include <ctype.h>
#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
#include <sys/param.h>
-#include <stdlib.h> /* XCU4 */
-#include <limits.h>
-#include <libintl.h>
#include <locale.h>
#include <langinfo.h>
-#include <string.h>
#include <sys/acl.h>
#include <utime.h>
#include <libgen.h>
#include <setjmp.h>
-#include <strings.h>
-#include <fcntl.h>
-#include <dirent.h>
#include <aclutils.h>
-#include <errno.h>
+#include <libcmdutils.h>
#include "getresponse.h"
+
static int n_bits; /* number of bits/code */
static int maxbits = BITS; /* user settable max # bits/code */
static code_int maxcode; /* maximum code, given n_bits */
@@ -246,7 +236,6 @@ static void oops();
static void output(code_int);
static void prratio(FILE *, count_long, count_long);
static void version(void);
-static int mv_xattrs(char *, char *, int);
#ifdef DEBUG
static int in_stack(int, int);
@@ -287,6 +276,10 @@ static count_long bytes_out; /* length of compressed output */
code_int sorttab[1<<BITS]; /* sorted pointers into htab */
#endif
+/* Extended system attribute support */
+
+static int saflg = 0;
+
/*
* *************************************************************
* TAG( main )
@@ -294,7 +287,7 @@ code_int sorttab[1<<BITS]; /* sorted pointers into htab */
* Algorithm from "A Technique for High Performance Data Compression",
* Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
*
- * Usage: compress [-dfvc] [-b bits] [file ...]
+ * Usage: compress [-dfvc/] [-b bits] [file ...]
* Inputs:
* -d: If given, decompression is done instead.
*
@@ -307,6 +300,8 @@ code_int sorttab[1<<BITS]; /* sorted pointers into htab */
* If -f is not used, the user will be prompted if stdin is
* a tty, otherwise, the output file will not be overwritten.
*
+ * -/ Copies extended attributes and extended system attributes.
+ *
* -v: Write compression statistics
*
* file ...: Files to be compressed. If none specified, stdin
@@ -397,9 +392,9 @@ main(int argc, char *argv[])
* if a string is left, must be an input filename.
*/
#ifdef DEBUG
- optstr = "b:cCdDfFnqvV";
+ optstr = "b:cCdDfFnqvV/";
#else
- optstr = "b:cCdfFnqvV";
+ optstr = "b:cCdfFnqvV/";
#endif
while ((ch = getopt(argc, argv, optstr)) != EOF) {
@@ -466,6 +461,9 @@ main(int argc, char *argv[])
qflg++;
quiet = 1;
break;
+ case '/':
+ saflg++;
+ break;
default:
(void) fprintf(stderr, gettext(
"Unknown flag: '%c'\n"), optopt);
@@ -797,7 +795,9 @@ main(int argc, char *argv[])
}
}
if (!use_stdout) {
- if (pathconf(ofname, _PC_XATTR_EXISTS) == 1) {
+ if ((pathconf(ofname, _PC_XATTR_EXISTS) == 1) ||
+ (saflg && sysattr_support(ofname,
+ _PC_SATTR_EXISTS) == 1)) {
(void) unlink(ofname);
}
/* Open output file */
@@ -1582,6 +1582,13 @@ copystat(char *ifname, struct stat *ifstat, char *ofname)
struct utimbuf timep;
acl_t *aclp = NULL;
int error;
+ int sattr_exist = 0;
+ int xattr_exist = 0;
+
+ if (pathconf(ifname, _PC_XATTR_EXISTS) == 1)
+ xattr_exist = 1;
+ if (saflg && sysattr_support(ifname, _PC_SATTR_EXISTS) == 1)
+ sattr_exist = 1;
if (fclose(outp)) {
perror(ofname);
@@ -1618,20 +1625,34 @@ copystat(char *ifname, struct stat *ifstat, char *ofname)
" -- file unchanged"));
newline_needed = 1;
}
- } else if ((pathconf(ifname, _PC_XATTR_EXISTS) == 1) &&
- (mv_xattrs(ifname, ofname, 0) < 0)) {
+ } else if ((xattr_exist || sattr_exist) &&
+ (mv_xattrs(progname, ifname, ofname, sattr_exist, 0)
+ != 0)) {
(void) fprintf(stderr, gettext(
- "%s: -- cannot preserve extended attributes, "
- "file unchanged"), ifname);
+ "%s: -- cannot preserve extended attributes or "
+ "system attributes, file unchanged"), ifname);
newline_needed = 1;
/* Move attributes back ... */
- (void) mv_xattrs(ofname, ifname, 1);
+ xattr_exist = 0;
+ sattr_exist = 0;
+ if (pathconf(ofname, _PC_XATTR_EXISTS) == 1)
+ xattr_exist = 1;
+ if (saflg && sysattr_support(ofname, _PC_SATTR_EXISTS) == 1)
+ sattr_exist = 1;
+ if (sattr_exist || xattr_exist)
+ (void) mv_xattrs(progname, ofname, ifname,
+ sattr_exist, 1);
perm_stat = 1;
- } else { /* ***** Successful Compression ***** */
+ } else { /* ***** Successful Compression ***** */
mode = ifstat->st_mode & 07777;
- if (chmod(ofname, mode)) /* Copy modes */
+ if (chmod(ofname, mode)) { /* Copy modes */
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ gettext("failed to chmod %s"
+ "- permisssion denied\n"), ofname);
+ }
perror(ofname);
-
+ }
error = acl_get(ifname, ACL_NO_TRIVIAL, &aclp);
if (error != 0) {
(void) fprintf(stderr, gettext(
@@ -1640,7 +1661,8 @@ copystat(char *ifname, struct stat *ifstat, char *ofname)
perm_stat = 1;
}
if (aclp && (acl_set(ofname, aclp) < 0)) {
- (void) fprintf(stderr, gettext("%s: failed to set acl "
+ (void) fprintf(stderr,
+ gettext("%s: failed to set acl "
"entries\n"), ofname);
perm_stat = 1;
}
@@ -1655,8 +1677,14 @@ copystat(char *ifname, struct stat *ifstat, char *ofname)
timep.modtime = ifstat->st_mtime;
/* Update last accessed and modified times */
(void) utime(ofname, &timep);
- if (unlink(ifname)) /* Remove input file */
+ if (unlink(ifname)) { /* Remove input file */
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ gettext("failed to remove %s"
+ "- permisssion denied\n"), ifname);
+ }
perror(ifname);
+ }
if (!quiet) {
(void) fprintf(stderr, gettext(
" -- replaced with %s"), ofname);
@@ -1668,6 +1696,11 @@ copystat(char *ifname, struct stat *ifstat, char *ofname)
/* Unsuccessful return -- one of the tests failed */
if (ofname[0] != '\0') {
if (unlink(ofname)) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ gettext("failed to remove %s"
+ "- permisssion denied\n"), ifname);
+ }
perror(ofname);
}
@@ -1804,16 +1837,16 @@ Usage()
{
#ifdef DEBUG
(void) fprintf(stderr,
- "Usage: compress [-dDVfc] [-b maxbits] [file ...]\n");
+ "Usage: compress [-dDVfc/] [-b maxbits] [file ...]\n");
#else
if (strcmp(progname, "compress") == 0) {
(void) fprintf(stderr,
gettext(
- "Usage: compress [-fv] [-b maxbits] [file ...]\n"\
- " compress [-cfv] [-b maxbits] [file]\n"));
+ "Usage: compress [-fv/] [-b maxbits] [file ...]\n"\
+ " compress c [-fv] [-b maxbits] [file]\n"));
} else if (strcmp(progname, "uncompress") == 0)
(void) fprintf(stderr, gettext(
- "Usage: uncompress [-cfv] [file ...]\n"));
+ "Usage: uncompress [-fv] [-c || -/] [file ...]\n"));
else if (strcmp(progname, "zcat") == 0)
(void) fprintf(stderr, gettext("Usage: zcat [file ...]\n"));
@@ -1872,73 +1905,3 @@ addDotZ(char *fn, size_t fnsize)
return (0);
}
-
-/*
- * mv_xattrs - move (via renameat) all of the extended attributes
- * associated with the file infile to the file outfile.
- * This function returns 0 on success and -1 on error.
- */
-static int
-mv_xattrs(char *infile, char *outfile, int silent)
-{
- int indfd, outdfd, tmpfd;
- DIR *dirp = NULL;
- struct dirent *dp = NULL;
- int error = 0;
- char *etext;
-
- indfd = outdfd = tmpfd = -1;
-
- if ((indfd = attropen(infile, ".", O_RDONLY)) == -1) {
- etext = gettext("cannot open source");
- error = -1;
- goto out;
- }
-
- if ((outdfd = attropen(outfile, ".", O_RDONLY)) == -1) {
- etext = gettext("cannot open target");
- error = -1;
- goto out;
- }
-
- if ((tmpfd = dup(indfd)) == -1) {
- etext = gettext("cannot dup descriptor");
- error = -1;
- goto out;
-
- }
- if ((dirp = fdopendir(tmpfd)) == NULL) {
- etext = gettext("cannot access source");
- error = -1;
- goto out;
- }
-
- while (dp = readdir(dirp)) {
- if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
- (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
- dp->d_name[2] == '\0'))
- continue;
- if ((renameat(indfd, dp->d_name, outdfd, dp->d_name)) == -1) {
- etext = dp->d_name;
- error = -1;
- goto out;
- }
- }
-out:
- if (error == -1 && silent == 0) {
- if (quiet) {
- (void) fprintf(stderr, "%s: ", infile);
- } else {
- (void) fprintf(stderr, ", ");
- }
- (void) fprintf(stderr, gettext("extended attribute error: "));
- perror(etext);
- }
- if (dirp)
- (void) closedir(dirp);
- if (indfd != -1)
- (void) close(indfd);
- if (outdfd != -1)
- (void) close(outdfd);
- return (error);
-}
diff --git a/usr/src/cmd/cpio/cpio.c b/usr/src/cmd/cpio/cpio.c
index 7e12c2ef29..2a3dade1b6 100644
--- a/usr/src/cmd/cpio/cpio.c
+++ b/usr/src/cmd/cpio/cpio.c
@@ -418,7 +418,7 @@ char Adir, /* Flags object as a directory */
static
int Append = 0, /* Flag set while searching to end of archive */
Archive, /* File descriptor of the archive */
- Buf_error = 0, /* I/O error occured during buffer fill */
+ Buf_error = 0, /* I/O error occurred during buffer fill */
Def_mode = 0777, /* Default file/directory protection modes */
Device, /* Device type being accessed (used with libgenIO) */
Error_cnt = 0, /* Cumulative count of I/O errors */
@@ -1986,7 +1986,7 @@ creat_tmp(char *nam_p)
/*
* If it's a regular file, write to the temporary file, and then rename
- * in order to accomodate potential executables.
+ * in order to accommodate potential executables.
*
* Note: g_typeflag is only defined (set) for USTAR archive types. It
* defaults to 0 in the cpio-format-regular file case, so this test
@@ -3269,6 +3269,15 @@ flush_lnks(void)
} /* l_p != &Lnk_hd */
}
+#if defined(O_XATTR)
+static int
+is_sysattr(char *name)
+{
+ return ((strcmp(name, VIEW_READONLY) == 0) ||
+ (strcmp(name, VIEW_READWRITE) == 0));
+}
+#endif
+
/*
* gethdr: Get a header from the archive, validate it and check for the trailer.
* Any user specified Hdr_type is ignored (set to NONE in main). Hdr_type is
@@ -3548,6 +3557,8 @@ gethdr(void)
if (((Gen.g_mode & S_IFMT) == _XATTR_CPIO_MODE) ||
((Hdr_type == USTAR || Hdr_type == TAR) &&
Thdr_p->tbuf.t_typeflag == _XATTR_HDRTYPE)) {
+ char *tapath;
+
if (xattrp != (struct xattr_buf *)NULL) {
if (xattrbadhead) {
free(xattrhead);
@@ -3556,7 +3567,18 @@ gethdr(void)
xattrhead = NULL;
return (1);
}
- if (Atflag == 0 && ((Args & OCt) == 0)) {
+
+ /*
+ * Skip processing of an attribute if -@ wasn't
+ * specified, or if -@ was specified and the attribute
+ * is either an extended system attribute or if the
+ * attribute name is not a file name, but a path name
+ * (-@ should only process extended attributes).
+ */
+ tapath = xattrp->h_names + strlen(xattrp->h_names) + 1;
+ if (((Args & OCt) == 0) && ((Atflag == 0) ||
+ (is_sysattr(tapath) ||
+ (strpbrk(tapath, "/") != NULL)))) {
data_in(P_SKIP);
free(xattrhead);
xattrhead = NULL;
@@ -3581,8 +3603,7 @@ gethdr(void)
xattrp->h_names);
}
- Gen.g_attrnam_p = e_strdup(E_EXIT,
- xattrp->h_names + strlen(xattrp->h_names) + 1);
+ Gen.g_attrnam_p = e_strdup(E_EXIT, tapath);
if (Hdr_type != USTAR && Hdr_type != TAR) {
Gen.g_mode = Gen.g_mode & (~_XATTR_CPIO_MODE);
@@ -3602,8 +3623,7 @@ gethdr(void)
Gen.g_linktoattrfnam_p = e_strdup(E_EXIT,
xattr_linkp->h_names);
Gen.g_linktoattrnam_p = e_strdup(E_EXIT,
- xattr_linkp->h_names +
- strlen(xattr_linkp->h_names) + 1);
+ tapath);
xattr_linkp = NULL;
}
ftype = Gen.g_mode & Ftype;
@@ -3738,7 +3758,7 @@ gethdr(void)
* getname: Get file names for inclusion in the archive. When end of file
* on the input stream of file names is reached, flush the link buffer out.
* For each filename, remove leading "./"s and multiple "/"s, and remove
- * any trailing newline "\n". Finally, verify the existance of the file,
+ * any trailing newline "\n". Finally, verify the existence of the file,
* and call creat_hdr() to fill in the gen_hdr structure.
*/
@@ -4065,7 +4085,7 @@ matched(void)
if ((result == 0 && ! negatep) ||
(result == FNM_NOMATCH && negatep)) {
- /* match occured */
+ /* match occurred */
return (!(Args & OCf));
}
}
@@ -4760,7 +4780,7 @@ setpasswd(char *nam)
*
* Note that if Do_rename is set, then the roles of original and temporary
* file are reversed. If all went well, we will rename() the temporary file
- * over the original in order to accomodate potentially executing files.
+ * over the original in order to accommodate potentially executing files.
*/
static void
rstfiles(int over, int dirfd)
@@ -5567,7 +5587,12 @@ verbose(char *nam_p)
* Translation note:
* 'attribute' is a noun.
*/
- name_fmt = gettext("%s attribute %s");
+
+ if (is_sysattr(basename(Gen.g_attrnam_p))) {
+ name_fmt = gettext("%s system attribute %s");
+ } else {
+ name_fmt = gettext("%s attribute %s");
+ }
name = (Args & OCp) ? nam_p : Gen.g_attrfnam_p;
attribute = Gen.g_attrnam_p;
@@ -6890,7 +6915,8 @@ xattrs_out(int (*func)())
}
while ((dp = readdir(dirp)) != (struct dirent *)NULL) {
- if (strcmp(dp->d_name, "..") == 0) {
+ if ((strcmp(dp->d_name, "..") == 0) ||
+ is_sysattr(dp->d_name)) {
continue;
}
@@ -7200,9 +7226,12 @@ read_xattr_hdr()
off_t bytes;
int comp_len, link_len;
int namelen;
+ int asz;
int cnt;
char *tp;
+ char *xattrapath;
int pad;
+ int parentfilelen;
/*
* Include any padding in the read. We need to be positioned
@@ -7259,6 +7288,32 @@ read_xattr_hdr()
xattr_linkp = NULL;
}
+ /*
+ * Gather the attribute path from the filename and attrnames section.
+ * The filename and attrnames section can be composed of two or more
+ * path segments separated by a null character. The first segment
+ * is the path to the parent file that roots the entire sequence in
+ * the normal name space. The remaining segments describes a path
+ * rooted at the hidden extended attribute directory of the leaf file of
+ * the previous segment, making it possible to name attributes on
+ * attributes.
+ */
+ parentfilelen = strlen(xattrp->h_names);
+ xattrapath = xattrp->h_names + parentfilelen + 1;
+ asz = strlen(xattrapath);
+ if ((asz + parentfilelen + 2) < namelen) {
+ /*
+ * The attrnames section contains a system attribute on an
+ * attribute. Save the name of the attribute for use later,
+ * and replace the null separating the attribute name from
+ * the system attribute name with a '/' so that xattrapath can
+ * be used to display messages with the full attribute path name
+ * rooted at the hidden attribute directory of the base file
+ * in normal name space.
+ */
+ xattrapath[asz] = '/';
+ }
+
return (0);
}
#endif
@@ -7885,7 +7940,8 @@ sl_preview_synonyms(void)
dp->d_name[1] == '\0') ||
(dp->d_name[0] == '.' &&
dp->d_name[1] == '.' &&
- dp->d_name[2] == '\0'))
+ dp->d_name[2] == '\0') ||
+ is_sysattr(dp->d_name))
continue;
if (fstatat(dirfd, dp->d_name, &sb,
diff --git a/usr/src/cmd/cpio/cpio.h b/usr/src/cmd/cpio/cpio.h
index e4ad5912ba..d34ee049a4 100644
--- a/usr/src/cmd/cpio/cpio.h
+++ b/usr/src/cmd/cpio/cpio.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -19,15 +18,14 @@
*
* CDDL HEADER END
*/
-/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
-
-
/*
- * Copyright 1988-2002 Sun Microsystems, Inc. All rights reserved.
+ * 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 */
+
#ifndef _CPIO_H
#define _CPIO_H
@@ -152,6 +150,15 @@ extern "C" {
#define FORMAT "%b %e %H:%M %Y"
+/* Extended system attributes */
+#ifndef VIEW_READONLY
+#define VIEW_READONLY "SUNWattr_ro"
+#endif
+
+#ifndef VIEW_READWRITE
+#define VIEW_READWRITE "SUNWattr_rw"
+#endif
+
/* Values used in typeflag field */
#define REGTYPE '0' /* Regular File */
#define LNKTYPE '1' /* Link */
diff --git a/usr/src/cmd/dfs.cmds/sharemgr/commands.c b/usr/src/cmd/dfs.cmds/sharemgr/commands.c
index 6140b03e1e..0f75ef7ebf 100644
--- a/usr/src/cmd/dfs.cmds/sharemgr/commands.c
+++ b/usr/src/cmd/dfs.cmds/sharemgr/commands.c
@@ -48,6 +48,10 @@
#include <libscf.h>
#include <libxml/tree.h>
#include <libintl.h>
+#include <assert.h>
+#include <iconv.h>
+#include <langinfo.h>
+#include <dirent.h>
static char *sa_get_usage(sa_usage_t);
@@ -75,13 +79,175 @@ has_protocol(sa_group_t group, char *protocol)
}
/*
- * add_list(list, item)
- * Adds a new list member that points to item to the list.
+ * validresource(name)
+ *
+ * Check that name only has valid characters in it. The current valid
+ * set are the printable characters but not including:
+ * " / \ [ ] : | < > + ; , ? * = \t
+ * Note that space is included and there is a maximum length.
+ */
+static int
+validresource(const char *name)
+{
+ const char *cp;
+ size_t len;
+
+ if (name == NULL)
+ return (B_FALSE);
+
+ len = strlen(name);
+ if (len == 0 || len > SA_MAX_RESOURCE_NAME)
+ return (B_FALSE);
+
+ if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
+ return (B_FALSE);
+ }
+
+ for (cp = name; *cp != '\0'; cp++)
+ if (iscntrl(*cp))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * conv_to_utf8(input)
+ *
+ * Convert the input string to utf8 from the current locale. If the
+ * conversion fails, use the current locale, it is likely close
+ * enough. For example, the "C" locale is a subset of utf-8. The
+ * return value may be a new string or the original input string.
+ */
+
+static char *
+conv_to_utf8(char *input)
+{
+ iconv_t cd;
+ char *output = input;
+ char *outleft;
+ char *curlocale;
+ size_t bytesleft;
+ size_t size;
+ size_t osize;
+ static int warned = 0;
+
+ curlocale = nl_langinfo(CODESET);
+ if (curlocale == NULL)
+ curlocale = "C";
+ cd = iconv_open("UTF-8", curlocale);
+ if (cd != NULL && cd != (iconv_t)-1) {
+ size = strlen(input);
+ /* Assume worst case of characters expanding to 4 bytes. */
+ bytesleft = size * 4;
+ output = calloc(bytesleft, 1);
+ if (output != NULL) {
+ outleft = output;
+ osize = iconv(cd, (const char **)&input, &size,
+ &outleft, &bytesleft);
+ if (osize == (size_t)-1 || size != 0) {
+ free(output);
+ output = input;
+ }
+ }
+ (void) iconv_close(cd);
+ } else {
+ if (!warned)
+ (void) fprintf(stderr,
+ gettext("Cannot convert to UTF-8 from %s\n"),
+ curlocale ? curlocale : gettext("unknown"));
+ warned = 1;
+ }
+ return (output);
+}
+
+/*
+ * conv_from(input)
+ *
+ * Convert the input string from utf8 to current locale. If the
+ * conversion isn't supported, just use as is. The return value may be
+ * a new string or the original input string.
+ */
+
+static char *
+conv_from_utf8(char *input)
+{
+ iconv_t cd;
+ char *output = input;
+ char *outleft;
+ char *curlocale;
+ size_t bytesleft;
+ size_t size;
+ size_t osize;
+ static int warned = 0;
+
+ curlocale = nl_langinfo(CODESET);
+ if (curlocale == NULL)
+ curlocale = "C";
+ cd = iconv_open(curlocale, "UTF-8");
+ if (cd != NULL && cd != (iconv_t)-1) {
+ size = strlen(input);
+ /* Assume worst case of characters expanding to 4 bytes. */
+ bytesleft = size * 4;
+ output = calloc(bytesleft, 1);
+ if (output != NULL) {
+ outleft = output;
+ osize = iconv(cd, (const char **)&input, &size,
+ &outleft, &bytesleft);
+ if (osize == (size_t)-1 || size != 0) {
+ free(output);
+ output = input;
+ }
+ }
+ (void) iconv_close(cd);
+ } else {
+ if (!warned)
+ (void) fprintf(stderr,
+ gettext("Cannot convert to %s from UTF-8\n"),
+ curlocale ? curlocale : gettext("unknown"));
+ warned = 1;
+ }
+ return (output);
+}
+
+static void
+print_rsrc_desc(char *resource)
+{
+ char *description;
+ char *desc;
+
+ description = sa_get_resource_description(resource);
+ if (description != NULL) {
+ desc = conv_from_utf8(description);
+ if (desc != description) {
+ sa_free_share_description(description);
+ description = desc;
+ }
+ (void) printf("\t\"%s\"", description);
+ sa_free_share_description(description);
+ }
+}
+
+static int
+set_share_desc(sa_share_t share, char *description)
+{
+ char *desc;
+ int ret;
+
+ desc = conv_to_utf8(description);
+ ret = sa_set_share_description(share, desc);
+ if (description != desc)
+ sa_free_share_description(desc);
+ return (ret);
+}
+
+/*
+ * add_list(list, item, data, proto)
+ * Adds a new list member that points holds item in the list.
* If list is NULL, it starts a new list. The function returns
* the first member of the list.
*/
struct list *
-add_list(struct list *listp, void *item, void *data)
+add_list(struct list *listp, void *item, void *data, char *proto)
{
struct list *new, *tmp;
@@ -90,6 +256,7 @@ add_list(struct list *listp, void *item, void *data)
new->next = NULL;
new->item = item;
new->itemdata = data;
+ new->proto = proto;
} else {
return (listp);
}
@@ -229,15 +396,92 @@ check_authorizations(char *instname, int flags)
}
/*
- * enable_group(group, updateproto)
+ * notify_or_enable_share(share, protocol)
+ *
+ * Since some protocols don't want an "enable" when properties change,
+ * this function will use the protocol specific notify function
+ * first. If that fails, it will then attempt to use the
+ * sa_enable_share(). "protocol" is the protocol that was specified
+ * on the command line.
+ */
+static void
+notify_or_enable_share(sa_share_t share, char *protocol)
+{
+ sa_group_t group;
+ sa_optionset_t opt;
+ int ret = SA_OK;
+ char *path;
+ char *groupproto;
+ sa_share_t parent = share;
+
+ /* If really a resource, get parent share */
+ if (!sa_is_share(share)) {
+ parent = sa_get_resource_parent((sa_resource_t)share);
+ }
+
+ /*
+ * Now that we've got a share in "parent", make sure it has a path.
+ */
+ path = sa_get_share_attr(parent, "path");
+ if (path == NULL)
+ return;
+
+ group = sa_get_parent_group(parent);
+
+ if (group == NULL) {
+ sa_free_attr_string(path);
+ return;
+ }
+ for (opt = sa_get_optionset(group, NULL);
+ opt != NULL;
+ opt = sa_get_next_optionset(opt)) {
+ groupproto = sa_get_optionset_attr(opt, "type");
+ if (groupproto == NULL ||
+ (protocol != NULL && strcmp(groupproto, protocol) != 0)) {
+ sa_free_attr_string(groupproto);
+ continue;
+ }
+ if (sa_is_share(share)) {
+ if ((ret = sa_proto_change_notify(share,
+ groupproto)) != SA_OK) {
+ ret = sa_enable_share(share, groupproto);
+ if (ret != SA_OK) {
+ (void) printf(
+ gettext("Could not reenable"
+ " share %s: %s\n"),
+ path, sa_errorstr(ret));
+ }
+ }
+ } else {
+ /* Must be a resource */
+ if ((ret = sa_proto_notify_resource(share,
+ groupproto)) != SA_OK) {
+ ret = sa_enable_resource(share, groupproto);
+ if (ret != SA_OK) {
+ (void) printf(
+ gettext("Could not "
+ "reenable resource %s: "
+ "%s\n"), path,
+ sa_errorstr(ret));
+ }
+ }
+ }
+ sa_free_attr_string(groupproto);
+ }
+ sa_free_attr_string(path);
+}
+
+/*
+ * enable_group(group, updateproto, notify, proto)
*
* enable all the shares in the specified group. This is a helper for
* enable_all_groups in order to simplify regular and subgroup (zfs)
- * disabling. Group has already been checked for non-NULL.
+ * enabling. Group has already been checked for non-NULL. If notify
+ * is non-zero, attempt to use the notify interface rather than
+ * enable.
*/
-
static void
-enable_group(sa_group_t group, char *updateproto)
+enable_group(sa_group_t group, char *updateproto, int notify, char *proto)
{
sa_share_t share;
@@ -246,7 +490,10 @@ enable_group(sa_group_t group, char *updateproto)
share = sa_get_next_share(share)) {
if (updateproto != NULL)
(void) sa_update_legacy(share, updateproto);
- (void) sa_enable_share(share, NULL);
+ if (notify)
+ notify_or_enable_share(share, proto);
+ else
+ (void) sa_enable_share(share, proto);
}
}
@@ -266,6 +513,7 @@ isenabled(sa_group_t group)
if (group != NULL) {
state = sa_get_group_attr(group, "state");
if (state != NULL) {
+
if (strcmp(state, "enabled") == 0)
ret = B_TRUE;
sa_free_attr_string(state);
@@ -276,13 +524,15 @@ isenabled(sa_group_t group)
/*
* enable_all_groups(list, setstate, online, updateproto)
- * Given a list of groups, enable each one found. If updateproto
- * is not NULL, then update all the shares for the protocol that
- * was passed in.
+ *
+ * Given a list of groups, enable each one found. If updateproto is
+ * not NULL, then update all the shares for the protocol that was
+ * passed in. If enable is non-zero, tell enable_group to try the
+ * notify interface since this is a property change.
*/
static int
enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
- int online, char *updateproto)
+ int online, char *updateproto, int enable)
{
int ret;
char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
@@ -319,7 +569,23 @@ enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
/* if itemdata != NULL then a single share */
if (work->itemdata != NULL) {
- ret = sa_enable_share((sa_share_t)work->itemdata, NULL);
+ if (enable) {
+ if (work->itemdata != NULL)
+ notify_or_enable_share(work->itemdata,
+ updateproto);
+ else
+ ret = SA_CONFIG_ERR;
+ } else {
+ if (sa_is_share(work->itemdata)) {
+ ret = sa_enable_share(
+ (sa_share_t)work->itemdata,
+ updateproto);
+ } else {
+ ret = sa_enable_resource(
+ (sa_resource_t)work->itemdata,
+ updateproto);
+ }
+ }
}
if (ret != SA_OK)
break;
@@ -328,18 +594,20 @@ enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
if (work->itemdata == NULL) {
zfs = sa_get_group_attr(group, "zfs");
/*
- * if the share is managed by ZFS, don't
+ * If the share is managed by ZFS, don't
* update any of the protocols since ZFS is
- * handling this. updateproto will contain
+ * handling this. Updateproto will contain
* the name of the protocol that we want to
* update legacy files for.
*/
- enable_group(group, zfs == NULL ? updateproto : NULL);
+ enable_group(group, zfs == NULL ? updateproto : NULL,
+ enable, work->proto);
for (subgroup = sa_get_sub_group(group);
subgroup != NULL;
subgroup = sa_get_next_group(subgroup)) {
/* never update legacy for ZFS subgroups */
- enable_group(subgroup, NULL);
+ enable_group(subgroup, NULL, enable,
+ work->proto);
}
}
if (online) {
@@ -497,12 +765,14 @@ add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
{
sa_optionset_t optionset;
int ret = SA_OK;
- int result = 0;
+ int result = B_FALSE;
optionset = sa_get_optionset(group, proto);
if (optionset == NULL) {
optionset = sa_create_optionset(group, proto);
- result = 1; /* adding a protocol is a change */
+ if (optionset == NULL)
+ ret = SA_NO_MEMORY;
+ result = B_TRUE; /* adding a protocol is a change */
}
if (optionset == NULL) {
ret = SA_NO_MEMORY;
@@ -541,7 +811,7 @@ add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
sa_errorstr(ret));
} else {
/* there was a change */
- result = 1;
+ result = B_TRUE;
}
}
}
@@ -553,7 +823,7 @@ add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
"property %s: %s\n"), optlist->optname,
sa_errorstr(ret));
} else {
- result = 1;
+ result = B_TRUE;
}
}
optlist = optlist->next;
@@ -567,6 +837,160 @@ out:
}
/*
+ * resource_compliant(group)
+ *
+ * Go through all the shares in the group. Assume compliant, but if
+ * any share doesn't have at least one resource name, it isn't
+ * compliant.
+ */
+static int
+resource_compliant(sa_group_t group)
+{
+ sa_share_t share;
+
+ for (share = sa_get_share(group, NULL); share != NULL;
+ share = sa_get_next_share(share)) {
+ if (sa_get_share_resource(share, NULL) == NULL) {
+ return (B_FALSE);
+ }
+ }
+ return (B_TRUE);
+}
+
+/*
+ * fix_path(path)
+ *
+ * change all illegal characters to something else. For now, all get
+ * converted to '_' and the leading '/' is stripped off. This is used
+ * to construct an resource name (SMB share name) that is valid.
+ * Caller must pass a valid path.
+ */
+static void
+fix_path(char *path)
+{
+ char *cp;
+ size_t len;
+
+ assert(path != NULL);
+
+ /* make sure we are appropriate length */
+ cp = path + 1; /* skip leading slash */
+ while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) {
+ cp = strchr(cp, '/');
+ if (cp != NULL)
+ cp++;
+ }
+ /* two cases - cp == NULL and cp is substring of path */
+ if (cp == NULL) {
+ /* just take last SA_MAX_RESOURCE_NAME chars */
+ len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME;
+ (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME);
+ path[SA_MAX_RESOURCE_NAME] = '\0';
+ } else {
+ len = strlen(cp) + 1;
+ (void) memmove(path, cp, len);
+ }
+
+ /*
+ * Don't want any of the characters that are not allowed
+ * in and SMB share name. Replace them with '_'.
+ */
+ while (*path) {
+ switch (*path) {
+ case '/':
+ case '"':
+ case '\\':
+ case '[':
+ case ']':
+ case ':':
+ case '|':
+ case '<':
+ case '>':
+ case '+':
+ case ';':
+ case ',':
+ case '?':
+ case '*':
+ case '=':
+ case '\t':
+ *path = '_';
+ break;
+ }
+ path++;
+ }
+}
+
+/*
+ * name_adjust(path, count)
+ *
+ * Add a ~<count> in place of last few characters. The total number of
+ * characters is dependent on count.
+ */
+#define MAX_MANGLE_NUMBER 10000
+
+static int
+name_adjust(char *path, int count)
+{
+ size_t len;
+
+ len = strlen(path) - 2;
+ if (count > 10)
+ len--;
+ if (count > 100)
+ len--;
+ if (count > 1000)
+ len--;
+ if (len > 0)
+ (void) sprintf(path + len, "~%d", count);
+ else
+ return (SA_BAD_VALUE);
+
+ return (SA_OK);
+}
+
+/*
+ * make_resources(group)
+ *
+ * Go through all the shares in the group and make them have resource
+ * names.
+ */
+static void
+make_resources(sa_group_t group)
+{
+ sa_share_t share;
+ int count;
+ int err = SA_OK;
+
+ for (share = sa_get_share(group, NULL); share != NULL;
+ share = sa_get_next_share(share)) {
+ /* Skip those with resources */
+ if (sa_get_share_resource(share, NULL) == NULL) {
+ char *path;
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ continue;
+ fix_path(path);
+ count = 0; /* reset for next resource */
+ while (sa_add_resource(share, path,
+ SA_SHARE_PERMANENT, &err) == NULL &&
+ err == SA_DUPLICATE_NAME) {
+ int ret;
+ ret = name_adjust(path, count);
+ count++;
+ if (ret != SA_OK ||
+ count >= MAX_MANGLE_NUMBER) {
+ (void) printf(gettext(
+ "Cannot create resource name for"
+ " path: %s\n"), path);
+ break;
+ }
+ }
+ sa_free_attr_string(path);
+ }
+ }
+}
+
+/*
* sa_create(flags, argc, argv)
* create a new group
* this may or may not have a protocol associated with it.
@@ -578,6 +1002,7 @@ sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
char *groupname;
sa_group_t group;
+ int force = 0;
int verbose = 0;
int dryrun = 0;
int c;
@@ -587,8 +1012,11 @@ sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
int err = 0;
int auth;
- while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) {
+ while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) {
switch (c) {
+ case 'f':
+ force++;
+ break;
case 'v':
verbose++;
break;
@@ -596,6 +1024,12 @@ sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
dryrun++;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext("Specifying "
+ "multiple protocols "
+ "not supported: %s\n"), protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (sa_valid_protocol(protocol))
break;
@@ -714,6 +1148,31 @@ sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
}
if (group != NULL) {
sa_optionset_t optionset;
+ /*
+ * First check to see if the new protocol is one that
+ * requires resource names and make sure we are
+ * compliant before proceeding.
+ */
+ if (protocol != NULL) {
+ uint64_t features;
+
+ features = sa_proto_get_featureset(protocol);
+ if ((features & SA_FEATURE_RESOURCE) &&
+ !resource_compliant(group)) {
+ if (force) {
+ make_resources(group);
+ } else {
+ ret = SA_RESOURCE_REQUIRED;
+ (void) printf(
+ gettext("Protocol "
+ "requires resource "
+ "names to be "
+ "set: %s\n"),
+ protocol);
+ goto err;
+ }
+ }
+ }
if (optlist != NULL) {
(void) add_optionset(group, optlist, protocol,
&ret);
@@ -760,6 +1219,7 @@ sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
sa_errorstr(SA_NO_PERMISSION));
ret = SA_NO_PERMISSION;
}
+err:
free_opt(optlist);
return (ret);
}
@@ -816,14 +1276,26 @@ sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
dryrun++;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext("Specifying "
+ "multiple protocols "
+ "not supported: %s\n"), protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext("Invalid protocol "
- "specified: %s\n"), protocol);
+ "specified: %s\n"), protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'S':
+ if (sectype != NULL) {
+ (void) printf(gettext("Specifying "
+ "multiple property "
+ "spaces not supported: %s\n"), sectype);
+ return (SA_SYNTAX_ERR);
+ }
sectype = optarg;
break;
case 'f':
@@ -909,7 +1381,7 @@ sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
/* a protocol delete */
sa_optionset_t optionset;
sa_security_t security;
- if (sectype != NULL) {
+ if (sectype != NULL) {
/* only delete specified security */
security = sa_get_security(group, sectype, protocol);
if (security != NULL && !dryrun)
@@ -949,6 +1421,16 @@ sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
ret = SA_INVALID_PROTOCOL;
}
}
+ /*
+ * With the protocol items removed, make sure that all
+ * the shares are updated in the legacy files, if
+ * necessary.
+ */
+ for (share = sa_get_share(group, NULL);
+ share != NULL;
+ share = sa_get_next_share(share)) {
+ (void) sa_delete_legacy(share, protocol);
+ }
}
done:
@@ -1045,7 +1527,6 @@ group_proto(sa_group_t group)
* their state and protocols.
*/
-/*ARGSUSED*/
static int
sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
{
@@ -1053,6 +1534,9 @@ sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
int verbose = 0;
int c;
char *protocol = NULL;
+#ifdef lint
+ flags = flags;
+#endif
while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
switch (c) {
@@ -1060,6 +1544,13 @@ sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
verbose++;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple protocols "
+ "not supported: %s\n"),
+ protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext(
@@ -1227,6 +1718,229 @@ show_properties(sa_group_t group, char *protocol, char *prefix)
}
/*
+ * get_resource(share)
+ *
+ * Get the first resource name, if any, and fix string to be in
+ * current locale and have quotes if it has embedded spaces. Return
+ * an attr string that must be freed.
+ */
+
+static char *
+get_resource(sa_share_t share)
+{
+ sa_resource_t resource;
+ char *resstring = NULL;
+ char *retstring;
+
+ if ((resource = sa_get_share_resource(share, NULL)) != NULL) {
+ resstring = sa_get_resource_attr(resource, "name");
+ if (resstring != NULL) {
+ char *cp;
+ int len;
+
+ retstring = conv_from_utf8(resstring);
+ if (retstring != resstring) {
+ sa_free_attr_string(resstring);
+ resstring = retstring;
+ }
+ if (strpbrk(resstring, " ") != NULL) {
+ /* account for quotes */
+ len = strlen(resstring) + 3;
+ cp = calloc(len, sizeof (char));
+ if (cp != NULL) {
+ (void) snprintf(cp, len,
+ "\"%s\"", resstring);
+ sa_free_attr_string(resstring);
+ resstring = cp;
+ } else {
+ sa_free_attr_string(resstring);
+ resstring = NULL;
+ }
+ }
+ }
+ }
+ return (resstring);
+}
+
+/*
+ * has_resource_with_opt(share)
+ *
+ * Check to see if the share has any resource names with optionsets
+ * set. Also indicate if multiple resource names since the syntax
+ * would be about the same.
+ */
+static int
+has_resource_with_opt(sa_share_t share)
+{
+ sa_resource_t resource;
+ int ret = B_FALSE;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+
+ if (sa_get_optionset(resource, NULL) != NULL) {
+ ret = B_TRUE;
+ break;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * has_multiple_resource(share)
+ *
+ * Check to see if the share has any resource names with optionsets
+ * set. Also indicate if multiple resource names since the syntax
+ * would be about the same.
+ */
+static int
+has_multiple_resource(sa_share_t share)
+{
+ sa_resource_t resource;
+ int num;
+
+ for (num = 0, resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ num++;
+ if (num > 1)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * show_share(share, verbose, properties, proto, iszfs, sharepath)
+ *
+ * print out the share information. With the addition of resource as a
+ * full object that can have multiple instances below the share, we
+ * need to display that as well.
+ */
+
+static void
+show_share(sa_share_t share, int verbose, int properties, char *proto,
+ int iszfs, char *sharepath)
+{
+ char *drive;
+ char *exclude;
+ sa_resource_t resource = NULL;
+ char *description;
+ char *desc;
+ char *rsrcname;
+ int rsrcwithopt;
+ int multiple;
+ char *type;
+
+ rsrcwithopt = has_resource_with_opt(share);
+
+ if (verbose || (properties && rsrcwithopt)) {
+ /* First, indicate if transient */
+ type = sa_get_share_attr(share, "type");
+ if (type != NULL && !iszfs && verbose &&
+ strcmp(type, "transient") == 0)
+ (void) printf("\t* ");
+ else
+ (void) printf("\t ");
+
+ if (type != NULL)
+ sa_free_attr_string(type);
+
+ /*
+ * If we came in with verbose, we want to handle the case of
+ * multiple resources as though they had properties set.
+ */
+ multiple = has_multiple_resource(share);
+
+ /* Next, if not multiple follow old model */
+ if (!multiple && !rsrcwithopt) {
+ rsrcname = get_resource(share);
+ if (rsrcname != NULL && strlen(rsrcname) > 0) {
+ (void) printf("%s=%s", rsrcname, sharepath);
+ } else {
+ (void) printf("%s", sharepath);
+ }
+ if (rsrcname != NULL)
+ sa_free_attr_string(rsrcname);
+ } else {
+ /* Treat as simple and then resources come later */
+ (void) printf("%s", sharepath);
+ }
+ drive = sa_get_share_attr(share, "drive-letter");
+ if (drive != NULL) {
+ if (strlen(drive) > 0)
+ (void) printf(gettext("\tdrive-letter=\"%s:\""),
+ drive);
+ sa_free_attr_string(drive);
+ }
+ if (properties)
+ show_properties(share, proto, "\t");
+ exclude = sa_get_share_attr(share, "exclude");
+ if (exclude != NULL) {
+ (void) printf(gettext("\tnot-shared-with=[%s]"),
+ exclude);
+ sa_free_attr_string(exclude);
+ }
+ description = sa_get_share_description(share);
+ if (description != NULL) {
+ if (strlen(description) > 0) {
+ desc = conv_from_utf8(description);
+ if (desc != description) {
+ sa_free_share_description(description);
+ description = desc;
+ }
+ (void) printf("\t\"%s\"", description);
+ }
+ sa_free_share_description(description);
+ }
+
+ /*
+ * If there are resource names with options, show them
+ * here, with one line per resource. Resource specific
+ * options are at the end of the line followed by
+ * description, if any.
+ */
+ if (rsrcwithopt || multiple) {
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ int has_space;
+ char *rsrc;
+
+ (void) printf("\n\t\t ");
+ rsrcname = sa_get_resource_attr(resource,
+ "name");
+ if (rsrcname == NULL)
+ continue;
+
+ rsrc = conv_from_utf8(rsrcname);
+ has_space = strpbrk(rsrc, " ") != NULL;
+
+ if (has_space)
+ (void) printf("\"%s\"=%s", rsrc,
+ sharepath);
+ else
+ (void) printf("%s=%s", rsrc,
+ sharepath);
+ if (rsrc != rsrcname)
+ sa_free_attr_string(rsrc);
+ sa_free_attr_string(rsrcname);
+ if (properties || rsrcwithopt)
+ show_properties(resource, proto, "\t");
+
+ /* Get description string if any */
+ print_rsrc_desc(resource);
+ }
+ }
+ } else {
+ (void) printf("\t %s", sharepath);
+ if (properties)
+ show_properties(share, proto, "\t");
+ }
+ (void) printf("\n");
+}
+
+/*
* show_group(group, verbose, properties, proto, subgroup)
*
* helper function to show the contents of a group.
@@ -1234,16 +1948,13 @@ show_properties(sa_group_t group, char *protocol, char *prefix)
static void
show_group(sa_group_t group, int verbose, int properties, char *proto,
- char *subgroup)
+ char *subgroup)
{
sa_share_t share;
char *groupname;
- char *sharepath;
- char *resource;
- char *description;
- char *type;
char *zfs = NULL;
int iszfs = 0;
+ char *sharepath;
groupname = sa_get_group_attr(group, "name");
if (groupname != NULL) {
@@ -1292,48 +2003,8 @@ show_group(sa_group_t group, int verbose, int properties, char *proto,
share = sa_get_next_share(share)) {
sharepath = sa_get_share_attr(share, "path");
if (sharepath != NULL) {
- if (verbose) {
- resource = sa_get_share_attr(share,
- "resource");
- description =
- sa_get_share_description(share);
- type = sa_get_share_attr(share,
- "type");
- if (type != NULL && !iszfs &&
- strcmp(type, "transient") == 0)
- (void) printf("\t* ");
- else
- (void) printf("\t ");
- if (resource != NULL &&
- strlen(resource) > 0) {
- (void) printf("%s=%s",
- resource, sharepath);
- } else {
- (void) printf("%s", sharepath);
- }
- if (resource != NULL)
- sa_free_attr_string(resource);
- if (properties)
- show_properties(share, NULL,
- "\t");
- if (description != NULL) {
- if (strlen(description) > 0) {
- (void) printf(
- "\t\"%s\"",
- description);
- }
- sa_free_share_description(
- description);
- }
- if (type != NULL)
- sa_free_attr_string(type);
- } else {
- (void) printf("\t%s", sharepath);
- if (properties)
- show_properties(share, NULL,
- "\t");
- }
- (void) printf("\n");
+ show_share(share, verbose, properties, proto,
+ iszfs, sharepath);
sa_free_attr_string(sharepath);
}
}
@@ -1395,7 +2066,6 @@ show_group_xml(xmlDocPtr doc, sa_group_t group)
* Implements the show subcommand.
*/
-/*ARGSUSED*/
int
sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
{
@@ -1407,6 +2077,9 @@ sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
char *protocol = NULL;
int xml = 0;
xmlDocPtr doc;
+#ifdef lint
+ flags = flags;
+#endif
while ((c = getopt(argc, argv, "?hvP:px")) != EOF) {
switch (c) {
@@ -1417,6 +2090,13 @@ sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
properties++;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple protocols "
+ "not supported: %s\n"),
+ protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext(
@@ -1491,14 +2171,16 @@ sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
static int
enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
- int update_legacy)
+ int update_legacy)
{
char *value;
int enabled;
sa_optionset_t optionset;
+ int err;
int ret = SA_OK;
char *zfs = NULL;
int iszfs = 0;
+ int isshare;
/*
* need to enable this share if the group is enabled but not
@@ -1511,7 +2193,7 @@ enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
sa_free_attr_string(value);
/* remove legacy config if necessary */
if (update_legacy)
- ret = sa_delete_legacy(share);
+ ret = sa_delete_legacy(share, NULL);
zfs = sa_get_group_attr(group, "zfs");
if (zfs != NULL) {
iszfs++;
@@ -1524,15 +2206,47 @@ enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
* works because protocols must be set on the group
* for the protocol to be enabled.
*/
+ isshare = sa_is_share(share);
for (optionset = sa_get_optionset(group, NULL);
optionset != NULL && ret == SA_OK;
optionset = sa_get_next_optionset(optionset)) {
value = sa_get_optionset_attr(optionset, "type");
if (value != NULL) {
- if (enabled)
- ret = sa_enable_share(share, value);
- if (update_legacy && !iszfs)
- (void) sa_update_legacy(share, value);
+ if (enabled) {
+ if (isshare) {
+ err = sa_enable_share(share, value);
+ } else {
+ err = sa_enable_resource(share, value);
+ if (err == SA_NOT_SUPPORTED) {
+ sa_share_t parent;
+ parent = sa_get_resource_parent(
+ share);
+ if (parent != NULL)
+ err = sa_enable_share(
+ parent, value);
+ }
+ }
+ if (err != SA_OK) {
+ ret = err;
+ (void) printf(gettext(
+ "Failed to enable share for "
+ "\"%s\": %s\n"),
+ value, sa_errorstr(ret));
+ }
+ }
+ /*
+ * If we want to update the legacy, use a copy of
+ * share so we can avoid breaking the loop we are in
+ * since we might also need to go up the tree to the
+ * parent.
+ */
+ if (update_legacy && !iszfs) {
+ sa_share_t update = share;
+ if (!sa_is_share(share)) {
+ update = sa_get_resource_parent(share);
+ }
+ (void) sa_update_legacy(update, value);
+ }
sa_free_attr_string(value);
}
}
@@ -1542,12 +2256,44 @@ enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
}
/*
+ * sa_require_resource(group)
+ *
+ * if any of the defined protocols on the group require resource
+ * names, then all shares must have them.
+ */
+
+static int
+sa_require_resource(sa_group_t group)
+{
+ sa_optionset_t optionset;
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *proto;
+
+ proto = sa_get_optionset_attr(optionset, "type");
+ if (proto != NULL) {
+ uint64_t features;
+
+ features = sa_proto_get_featureset(proto);
+ if (features & SA_FEATURE_RESOURCE) {
+ sa_free_attr_string(proto);
+ return (B_TRUE);
+ }
+ sa_free_attr_string(proto);
+ }
+ }
+ return (B_FALSE);
+}
+
+/*
* sa_addshare(flags, argc, argv)
*
* implements add-share subcommand.
*/
-int
+static int
sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
{
int verbose = 0;
@@ -1556,9 +2302,11 @@ sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
int ret = SA_OK;
sa_group_t group;
sa_share_t share;
+ sa_resource_t resource = NULL;
char *sharepath = NULL;
char *description = NULL;
- char *resource = NULL;
+ char *rsrcname = NULL;
+ char *rsrc = NULL;
int persist = SA_SHARE_PERMANENT; /* default to persist */
int auth;
char dir[MAXPATHLEN];
@@ -1575,7 +2323,13 @@ sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
description = optarg;
break;
case 'r':
- resource = optarg;
+ if (rsrcname != NULL) {
+ (void) printf(gettext("Adding multiple "
+ "resource names not"
+ " supported\n"));
+ return (SA_SYNTAX_ERR);
+ }
+ rsrcname = optarg;
break;
case 's':
/*
@@ -1585,7 +2339,7 @@ sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
if (sharepath != NULL) {
(void) printf(gettext(
"Adding multiple shares not supported\n"));
- return (1);
+ return (SA_SYNTAX_ERR);
}
sharepath = optarg;
break;
@@ -1605,7 +2359,7 @@ sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
(void) printf(gettext("usage: %s\n"),
sa_get_usage(USAGE_ADD_SHARE));
if (dryrun || sharepath != NULL || description != NULL ||
- resource != NULL || verbose || persist) {
+ rsrcname != NULL || verbose || persist) {
(void) printf(gettext("\tgroup must be specified\n"));
ret = SA_NO_SUCH_GROUP;
} else {
@@ -1617,116 +2371,174 @@ sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
sa_get_usage(USAGE_ADD_SHARE));
(void) printf(gettext(
"\t-s sharepath must be specified\n"));
- return (SA_BAD_PATH);
+ ret = SA_BAD_PATH;
}
- if (realpath(sharepath, dir) == NULL) {
- (void) printf(gettext(
- "Path is not valid: %s\n"), sharepath);
- return (SA_BAD_PATH);
- } else {
- sharepath = dir;
+ if (ret == SA_OK) {
+ if (realpath(sharepath, dir) == NULL) {
+ ret = SA_BAD_PATH;
+ (void) printf(gettext("Path "
+ "is not valid: %s\n"),
+ sharepath);
+ } else {
+ sharepath = dir;
+ }
}
-
- /* Check for valid syntax */
- if (resource != NULL && strpbrk(resource, " \t/") != NULL) {
- (void) printf(gettext("usage: %s\n"),
- sa_get_usage(USAGE_ADD_SHARE));
- (void) printf(gettext(
- "\tresource must not contain white"
- "space or '/' characters\n"));
- return (SA_BAD_PATH);
+ if (ret == SA_OK && rsrcname != NULL) {
+ /* check for valid syntax */
+ if (validresource(rsrcname)) {
+ rsrc = conv_to_utf8(rsrcname);
+ resource = sa_find_resource(handle, rsrc);
+ if (resource != NULL) {
+ /*
+ * Resource names must be
+ * unique in the system
+ */
+ ret = SA_DUPLICATE_NAME;
+ (void) printf(gettext("usage: %s\n"),
+ sa_get_usage(USAGE_ADD_SHARE));
+ (void) printf(gettext(
+ "\tresource names must be unique "
+ "in the system\n"));
+ }
+ } else {
+ (void) printf(gettext("usage: %s\n"),
+ sa_get_usage(USAGE_ADD_SHARE));
+ (void) printf(gettext(
+ "\tresource names use restricted "
+ "character set\n"));
+ ret = SA_INVALID_NAME;
+ }
}
- group = sa_get_group(handle, argv[optind]);
- if (group == NULL) {
- (void) printf(gettext("Group \"%s\" not found\n"),
- argv[optind]);
- return (SA_NO_SUCH_GROUP);
+
+ if (ret != SA_OK) {
+ if (rsrc != NULL && rsrcname != rsrc)
+ sa_free_attr_string(rsrc);
+ return (ret);
}
- auth = check_authorizations(argv[optind], flags);
+
share = sa_find_share(handle, sharepath);
if (share != NULL) {
- group = sa_get_parent_group(share);
- if (group != NULL) {
- char *groupname;
- groupname = sa_get_group_attr(
- group, "name");
- if (groupname != NULL) {
- (void) printf(gettext(
- "Share path already "
- "shared in group "
- "\"%s\": %s\n"),
- groupname, sharepath);
- sa_free_attr_string(groupname);
- } else {
- (void) printf(gettext(
- "Share path already"
- "shared: %s\n"),
- groupname, sharepath);
- }
- } else {
+ if (rsrcname == NULL) {
+ /*
+ * Can only have a duplicate share if a new
+ * resource name is being added.
+ */
+ ret = SA_DUPLICATE_NAME;
+ (void) printf(gettext("Share path already "
+ "shared: %s\n"), sharepath);
+ }
+ }
+ if (ret != SA_OK)
+ return (ret);
+
+ group = sa_get_group(handle, argv[optind]);
+ if (group != NULL) {
+ if (sa_require_resource(group) == B_TRUE &&
+ rsrcname == NULL) {
(void) printf(gettext(
- "Share path %s already shared\n"),
- sharepath);
+ "Resource name is required "
+ "by at least one enabled protocol "
+ "in group\n"));
+ return (SA_RESOURCE_REQUIRED);
+ }
+ if (share == NULL && ret == SA_OK) {
+ if (dryrun)
+ ret = sa_check_path(group, sharepath,
+ SA_CHECK_NORMAL);
+ else
+ share = sa_add_share(group, sharepath,
+ persist, &ret);
}
- return (SA_DUPLICATE_NAME);
- } else {
/*
- * Need to check that resource name is
- * unique at some point. Path checking
- * should use the "normal" rules which
- * don't check the repository.
+ * Make sure this isn't an attempt to put a resourced
+ * share into a different group than it already is in.
*/
- if (dryrun)
- ret = sa_check_path(group, sharepath,
- SA_CHECK_NORMAL);
- else
- share = sa_add_share(group, sharepath,
- persist, &ret);
+ if (share != NULL) {
+ sa_group_t parent;
+ parent = sa_get_parent_group(share);
+ if (parent != group) {
+ ret = SA_DUPLICATE_NAME;
+ (void) printf(gettext(
+ "Share path already "
+ "shared: %s\n"), sharepath);
+ }
+ }
if (!dryrun && share == NULL) {
(void) printf(gettext(
"Could not add share: %s\n"),
sa_errorstr(ret));
} else {
+ auth = check_authorizations(argv[optind],
+ flags);
if (!dryrun && ret == SA_OK) {
- if (resource != NULL &&
- strpbrk(resource, " \t/") == NULL) {
- ret = sa_set_share_attr(share,
- "resource", resource);
+ if (rsrcname != NULL) {
+ resource = sa_add_resource(
+ share,
+ rsrc,
+ SA_SHARE_PERMANENT,
+ &ret);
}
if (ret == SA_OK &&
description != NULL) {
- ret = sa_set_share_description(
- share, description);
+ if (description != NULL) {
+ ret =
+ set_share_desc(
+ share,
+ description);
+ }
}
if (ret == SA_OK) {
- /* Now enable the share(s) */
- ret = enable_share(handle,
- group, share, 1);
+ /* now enable the share(s) */
+ if (resource != NULL) {
+ ret = enable_share(
+ handle,
+ group,
+ resource,
+ 1);
+ } else {
+ ret = enable_share(
+ handle,
+ group,
+ share,
+ 1);
+ }
ret = sa_update_config(handle);
}
switch (ret) {
case SA_DUPLICATE_NAME:
(void) printf(gettext(
"Resource name in"
- "use: %s\n"), resource);
+ "use: %s\n"),
+ rsrcname);
break;
default:
- (void) printf(
- gettext("Could not set "
+ (void) printf(gettext(
+ "Could not set "
"attribute: %s\n"),
sa_errorstr(ret));
break;
case SA_OK:
break;
}
- } else if (dryrun && ret == SA_OK && !auth &&
- verbose) {
+ } else if (dryrun && ret == SA_OK &&
+ !auth && verbose) {
(void) printf(gettext(
"Command would fail: %s\n"),
sa_errorstr(SA_NO_PERMISSION));
ret = SA_NO_PERMISSION;
}
}
+ } else {
+ switch (ret) {
+ default:
+ (void) printf(gettext(
+ "Group \"%s\" not found\n"), argv[optind]);
+ ret = SA_NO_SUCH_GROUP;
+ break;
+ case SA_BAD_PATH:
+ case SA_DUPLICATE_NAME:
+ break;
+ }
}
}
return (ret);
@@ -1747,10 +2559,11 @@ sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
int ret = SA_OK;
sa_group_t group;
sa_share_t share;
+ char *rsrcname = NULL;
char *sharepath = NULL;
int authsrc = 0, authdst = 0;
- while ((c = getopt(argc, argv, "?hvns:")) != EOF) {
+ while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) {
switch (c) {
case 'n':
dryrun++;
@@ -1758,6 +2571,15 @@ sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
case 'v':
verbose++;
break;
+ case 'r':
+ if (rsrcname != NULL) {
+ (void) printf(gettext(
+ "Moving multiple resource names not"
+ " supported\n"));
+ return (SA_SYNTAX_ERR);
+ }
+ rsrcname = optarg;
+ break;
case 's':
/*
* Remove share path from group. Currently limit
@@ -1765,8 +2587,8 @@ sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
*/
if (sharepath != NULL) {
(void) printf(gettext("Moving multiple shares"
- "not supported\n"));
- return (SA_BAD_PATH);
+ " not supported\n"));
+ return (SA_SYNTAX_ERR);
}
sharepath = optarg;
break;
@@ -1780,21 +2602,20 @@ sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
}
if (optind >= argc || sharepath == NULL) {
- (void) printf(gettext("usage: %s\n"),
- sa_get_usage(USAGE_MOVE_SHARE));
- if (dryrun || verbose || sharepath != NULL) {
+ (void) printf(gettext("usage: %s\n"),
+ sa_get_usage(USAGE_MOVE_SHARE));
+ if (dryrun || verbose || sharepath != NULL) {
+ (void) printf(gettext("\tgroup must be specified\n"));
+ ret = SA_NO_SUCH_GROUP;
+ } else {
+ if (sharepath == NULL) {
+ ret = SA_SYNTAX_ERR;
(void) printf(gettext(
- "\tgroup must be specified\n"));
- ret = SA_NO_SUCH_GROUP;
+ "\tsharepath must be specified\n"));
} else {
- if (sharepath == NULL) {
- ret = SA_SYNTAX_ERR;
- (void) printf(gettext(
- "\tsharepath must be specified\n"));
- } else {
- ret = SA_OK;
- }
+ ret = SA_OK;
}
+ }
} else {
sa_group_t parent;
char *zfsold;
@@ -1839,30 +2660,41 @@ sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
if (zfsnew != NULL)
sa_free_attr_string(zfsnew);
}
- if (!dryrun && ret == SA_OK)
- ret = sa_move_share(group, share);
if (ret == SA_OK && parent != group && !dryrun) {
char *oldstate;
- ret = sa_update_config(handle);
/*
* Note that the share may need to be
- * "unshared" if the new group is
- * disabled and the old was enabled or
- * it may need to be share to update
- * if the new group is enabled.
+ * "unshared" if the new group is disabled and
+ * the old was enabled or it may need to be
+ * share to update if the new group is
+ * enabled. We disable before the move and
+ * will have to enable after the move in order
+ * to cleanup entries for protocols that
+ * aren't in the new group.
*/
oldstate = sa_get_group_attr(parent, "state");
/* enable_share determines what to do */
- if (strcmp(oldstate, "enabled") == 0) {
+ if (strcmp(oldstate, "enabled") == 0)
(void) sa_disable_share(share, NULL);
- }
- (void) enable_share(handle, group, share, 1);
+
if (oldstate != NULL)
sa_free_attr_string(oldstate);
}
+ if (!dryrun && ret == SA_OK)
+ ret = sa_move_share(group, share);
+
+ /*
+ * Reenable and update any config information.
+ */
+ if (ret == SA_OK && parent != group && !dryrun) {
+ ret = sa_update_config(handle);
+
+ (void) enable_share(handle, group, share, 1);
+ }
+
if (ret != SA_OK)
(void) printf(gettext("Could not move share: %s\n"),
sa_errorstr(ret));
@@ -1891,12 +2723,14 @@ sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
int c;
int ret = SA_OK;
sa_group_t group;
- sa_share_t share;
+ sa_resource_t resource = NULL;
+ sa_share_t share = NULL;
+ char *rsrcname = NULL;
char *sharepath = NULL;
char dir[MAXPATHLEN];
int auth;
- while ((c = getopt(argc, argv, "?hfns:v")) != EOF) {
+ while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) {
switch (c) {
case 'n':
dryrun++;
@@ -1920,6 +2754,19 @@ sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
}
sharepath = optarg;
break;
+ case 'r':
+ /*
+ * Remove share from group if last resource or remove
+ * resource from share if multiple resources.
+ */
+ if (rsrcname != NULL) {
+ (void) printf(gettext(
+ "Removing multiple resource names not "
+ "supported\n"));
+ return (SA_SYNTAX_ERR);
+ }
+ rsrcname = optarg;
+ break;
default:
case 'h':
case '?':
@@ -1929,12 +2776,12 @@ sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
}
}
- if (optind >= argc || sharepath == NULL) {
- if (sharepath == NULL) {
+ if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) {
+ if (sharepath == NULL && rsrcname == NULL) {
(void) printf(gettext("usage: %s\n"),
sa_get_usage(USAGE_REMOVE_SHARE));
- (void) printf(gettext(
- "\t-s sharepath must be specified\n"));
+ (void) printf(gettext("\t-s sharepath or -r resource"
+ " must be specified\n"));
ret = SA_BAD_PATH;
} else {
ret = SA_OK;
@@ -1961,6 +2808,16 @@ sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
group = NULL;
}
+ if (rsrcname != NULL) {
+ resource = sa_find_resource(handle, rsrcname);
+ if (resource == NULL) {
+ ret = SA_NO_SUCH_RESOURCE;
+ (void) printf(gettext(
+ "Resource name not found for share: %s\n"),
+ rsrcname);
+ }
+ }
+
/*
* Lookup the path in the internal configuration. Care
* must be taken to handle the case where the
@@ -1968,10 +2825,27 @@ sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
* be able to deal with that as well.
*/
if (ret == SA_OK) {
- if (group != NULL)
- share = sa_get_share(group, sharepath);
- else
- share = sa_find_share(handle, sharepath);
+ if (sharepath != NULL) {
+ if (group != NULL)
+ share = sa_get_share(group, sharepath);
+ else
+ share = sa_find_share(handle, sharepath);
+ }
+
+ if (resource != NULL) {
+ sa_share_t rsrcshare;
+ rsrcshare = sa_get_resource_parent(resource);
+ if (share == NULL)
+ share = rsrcshare;
+ else if (share != rsrcshare) {
+ ret = SA_NO_SUCH_RESOURCE;
+ (void) printf(gettext(
+ "Bad resource name for share: %s\n"),
+ rsrcname);
+ share = NULL;
+ }
+ }
+
/*
* If we didn't find the share with the provided path,
* it may be a symlink so attempt to resolve it using
@@ -2013,13 +2887,17 @@ sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
else
(void) printf(gettext("Share not found: %s\n"),
sharepath);
- ret = SA_NO_SUCH_PATH;
+ ret = SA_NO_SUCH_PATH;
} else {
if (group == NULL)
group = sa_get_parent_group(share);
if (!dryrun) {
if (ret == SA_OK) {
- ret = sa_disable_share(share, NULL);
+ if (resource != NULL)
+ ret = sa_disable_resource(resource,
+ NULL);
+ else
+ ret = sa_disable_share(share, NULL);
/*
* We don't care if it fails since it
* could be disabled already. Some
@@ -2027,19 +2905,37 @@ sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
* prevent removal, so also check for
* force being set.
*/
- if (ret == SA_OK || ret == SA_NO_SUCH_PATH ||
+ if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
ret == SA_NOT_SUPPORTED ||
- ret == SA_SYSTEM_ERR || force) {
+ ret == SA_SYSTEM_ERR || force) &&
+ resource == NULL)
ret = sa_remove_share(share);
+
+ if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
+ ret == SA_NOT_SUPPORTED ||
+ ret == SA_SYSTEM_ERR || force) &&
+ resource != NULL) {
+ ret = sa_remove_resource(resource);
+ if (ret == SA_OK) {
+ /*
+ * If this was the
+ * last one, remove
+ * the share as well.
+ */
+ resource =
+ sa_get_share_resource(
+ share, NULL);
+ if (resource == NULL)
+ ret = sa_remove_share(
+ share);
+ }
}
if (ret == SA_OK)
ret = sa_update_config(handle);
}
if (ret != SA_OK)
- (void) printf(gettext(
- "Could not remove share: %s\n"),
- sa_errorstr(ret));
-
+ (void) printf(gettext("Could not remove share:"
+ " %s\n"), sa_errorstr(ret));
} else if (ret == SA_OK) {
char *pname;
pname = sa_get_group_attr(group, "name");
@@ -2071,12 +2967,17 @@ sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
int ret = SA_OK;
sa_group_t group, sharegroup;
sa_share_t share;
+ sa_resource_t resource = NULL;
char *sharepath = NULL;
char *description = NULL;
- char *resource = NULL;
+ char *desc;
+ char *rsrcname = NULL;
+ char *rsrc = NULL;
+ char *newname = NULL;
+ char *newrsrc;
+ char *groupname = NULL;
int auth;
int verbose = 0;
- char *groupname;
while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
switch (c) {
@@ -2086,12 +2987,21 @@ sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
case 'd':
description = optarg;
break;
- case 'r':
- resource = optarg;
- break;
case 'v':
verbose++;
break;
+ case 'r':
+ /*
+ * Update share by resource name
+ */
+ if (rsrcname != NULL) {
+ (void) printf(gettext(
+ "Updating multiple resource names not "
+ "supported\n"));
+ return (SA_SYNTAX_ERR);
+ }
+ rsrcname = optarg;
+ break;
case 's':
/*
* Save share path into group. Currently limit
@@ -2101,7 +3011,7 @@ sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
(void) printf(gettext(
"Updating multiple shares not "
"supported\n"));
- return (SA_BAD_PATH);
+ return (SA_SYNTAX_ERR);
}
sharepath = optarg;
break;
@@ -2114,7 +3024,7 @@ sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
}
}
- if (optind >= argc || sharepath == NULL) {
+ if (optind >= argc && sharepath == NULL && rsrcname == NULL) {
if (sharepath == NULL) {
(void) printf(gettext("usage: %s\n"),
sa_get_usage(USAGE_SET_SHARE));
@@ -2131,6 +3041,16 @@ sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
ret = SA_SYNTAX_ERR;
}
+ /*
+ * Must have at least one of sharepath and rsrcrname.
+ * It is a syntax error to be missing both.
+ */
+ if (sharepath == NULL && rsrcname == NULL) {
+ (void) printf(gettext("usage: %s\n"),
+ sa_get_usage(USAGE_SET_SHARE));
+ ret = SA_SYNTAX_ERR;
+ }
+
if (ret != SA_OK)
return (ret);
@@ -2141,70 +3061,132 @@ sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
group = NULL;
groupname = NULL;
}
- share = sa_find_share(handle, sharepath);
- if (share == NULL) {
- (void) printf(gettext("Share path \"%s\" not found\n"),
- sharepath);
- return (SA_NO_SUCH_PATH);
- }
- sharegroup = sa_get_parent_group(share);
- if (group != NULL && group != sharegroup) {
- (void) printf(gettext("Group \"%s\" does not contain "
- "share %s\n"), argv[optind], sharepath);
- ret = SA_BAD_PATH;
- } else {
- int delgroupname = 0;
- if (groupname == NULL) {
- groupname = sa_get_group_attr(sharegroup, "name");
- delgroupname = 1;
- }
- if (groupname != NULL) {
- auth = check_authorizations(groupname, flags);
- if (delgroupname) {
- sa_free_attr_string(groupname);
- groupname = NULL;
- }
+ if (rsrcname != NULL) {
+ /*
+ * If rsrcname exists, split rename syntax and then
+ * convert to utf 8 if no errors.
+ */
+ newname = strchr(rsrcname, '=');
+ if (newname != NULL) {
+ *newname++ = '\0';
+ }
+ if (!validresource(rsrcname)) {
+ ret = SA_INVALID_NAME;
+ (void) printf(gettext("Invalid resource name: "
+ "\"%s\"\n"), rsrcname);
} else {
- ret = SA_NO_MEMORY;
+ rsrc = conv_to_utf8(rsrcname);
}
- if (resource != NULL) {
- if (strpbrk(resource, " \t/") == NULL) {
- if (!dryrun) {
- ret = sa_set_share_attr(share,
- "resource", resource);
- } else {
- sa_share_t resshare;
- resshare = sa_get_resource(sharegroup,
- resource);
- if (resshare != NULL &&
- resshare != share)
- ret = SA_DUPLICATE_NAME;
- }
+ if (newname != NULL) {
+ if (!validresource(newname)) {
+ ret = SA_INVALID_NAME;
+ (void) printf(gettext("Invalid resource name: "
+ "%s\n"), newname);
} else {
- ret = SA_BAD_PATH;
- (void) printf(gettext("Resource must not "
- "contain white space or '/'\n"));
+ newrsrc = conv_to_utf8(newname);
}
}
- if (ret == SA_OK && description != NULL)
- ret = sa_set_share_description(share, description);
}
- if (!dryrun && ret == SA_OK)
- ret = sa_update_config(handle);
- switch (ret) {
- case SA_DUPLICATE_NAME:
- (void) printf(gettext("Resource name in use: %s\n"), resource);
- break;
- default:
- (void) printf(gettext("Could not set attribute: %s\n"),
- sa_errorstr(ret));
- break;
- case SA_OK:
- if (dryrun && !auth && verbose)
- (void) printf(gettext("Command would fail: %s\n"),
- sa_errorstr(SA_NO_PERMISSION));
- break;
+ if (ret != SA_OK) {
+ if (rsrcname != NULL && rsrcname != rsrc)
+ sa_free_attr_string(rsrc);
+ if (newname != NULL && newname != newrsrc)
+ sa_free_attr_string(newrsrc);
+ return (ret);
+ }
+
+ if (sharepath != NULL) {
+ share = sa_find_share(handle, sharepath);
+ } else if (rsrcname != NULL) {
+ resource = sa_find_resource(handle, rsrc);
+ if (resource != NULL) {
+ share = sa_get_resource_parent(resource);
+ }
+ }
+ if (share != NULL) {
+ sharegroup = sa_get_parent_group(share);
+ if (group != NULL && group != sharegroup) {
+ (void) printf(gettext("Group \"%s\" does not contain "
+ "share %s\n"),
+ argv[optind], sharepath);
+ ret = SA_BAD_PATH;
+ } else {
+ int delgroupname = 0;
+ if (groupname == NULL) {
+ groupname = sa_get_group_attr(sharegroup,
+ "name");
+ delgroupname = 1;
+ }
+ if (groupname != NULL) {
+ auth = check_authorizations(groupname, flags);
+ if (delgroupname) {
+ sa_free_attr_string(groupname);
+ groupname = NULL;
+ }
+ } else {
+ ret = SA_NO_MEMORY;
+ }
+ if (rsrcname != NULL) {
+ resource = sa_find_resource(handle, rsrc);
+ if (!dryrun) {
+ if (newname != NULL &&
+ resource != NULL)
+ ret = sa_rename_resource(
+ resource, newrsrc);
+ else if (newname != NULL)
+ ret = SA_NO_SUCH_RESOURCE;
+ if (newname != NULL &&
+ newname != newrsrc)
+ sa_free_attr_string(newrsrc);
+ }
+ if (rsrc != rsrcname)
+ sa_free_attr_string(rsrc);
+ }
+
+ /*
+ * If the user has set a description, it will be
+ * on the resource if -r was used otherwise it
+ * must be on the share.
+ */
+ if (ret == SA_OK && description != NULL) {
+ desc = conv_to_utf8(description);
+ if (resource != NULL)
+ ret = sa_set_resource_description(
+ resource, desc);
+ else
+ ret = sa_set_share_description(share,
+ desc);
+ if (desc != description)
+ sa_free_share_description(desc);
+ }
+ }
+ if (!dryrun && ret == SA_OK) {
+ if (resource != NULL)
+ (void) sa_enable_resource(resource, NULL);
+ ret = sa_update_config(handle);
+ }
+ switch (ret) {
+ case SA_DUPLICATE_NAME:
+ (void) printf(gettext("Resource name in use: %s\n"),
+ rsrcname);
+ break;
+ default:
+ (void) printf(gettext("Could not set: %s\n"),
+ sa_errorstr(ret));
+ break;
+ case SA_OK:
+ if (dryrun && !auth && verbose) {
+ (void) printf(gettext(
+ "Command would fail: %s\n"),
+ sa_errorstr(SA_NO_PERMISSION));
+ }
+ break;
+ }
+ } else {
+ (void) printf(gettext("Share path \"%s\" not found\n"),
+ sharepath);
+ ret = SA_NO_SUCH_PATH;
}
return (ret);
@@ -2219,7 +3201,7 @@ sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
static int
add_security(sa_group_t group, char *sectype,
- struct options *optlist, char *proto, int *err)
+ struct options *optlist, char *proto, int *err)
{
sa_security_t security;
int ret = SA_OK;
@@ -2248,8 +3230,8 @@ add_security(sa_group_t group, char *sectype,
prop = sa_create_property(optlist->optname,
optlist->optvalue);
if (prop != NULL) {
- ret = sa_valid_property(security, proto,
- prop);
+ ret = sa_valid_property(security,
+ proto, prop);
if (ret != SA_OK) {
(void) sa_remove_property(prop);
(void) printf(gettext(
@@ -2264,8 +3246,8 @@ add_security(sa_group_t group, char *sectype,
if (ret != SA_OK) {
(void) printf(gettext(
"Could not add "
- "property (%s=%s): "
- "%s\n"),
+ "property (%s=%s):"
+ " %s\n"),
optlist->optname,
optlist->optvalue,
sa_errorstr(ret));
@@ -2334,16 +3316,24 @@ zfscheck(sa_group_t group, sa_share_t share)
}
/*
- * basic_set(groupname, optlist, protocol, sharepath, dryrun)
+ * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
*
* This function implements "set" when a name space (-S) is not
* specified. It is a basic set. Options and other CLI parsing has
* already been done.
+ *
+ * "rsrcname" is a "resource name". If it is non-NULL, it must match
+ * the sharepath if present or group if present, otherwise it is used
+ * to set options.
+ *
+ * Resource names may take options if the protocol supports it. If the
+ * protocol doesn't support resource level options, rsrcname is just
+ * an alias for the share.
*/
static int
basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
- char *protocol, char *sharepath, int dryrun)
+ char *protocol, char *sharepath, char *rsrcname, int dryrun)
{
sa_group_t group;
int ret = SA_OK;
@@ -2353,6 +3343,12 @@ basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
group = sa_get_group(handle, groupname);
if (group != NULL) {
sa_share_t share = NULL;
+ sa_resource_t resource = NULL;
+
+ /*
+ * If there is a sharepath, make sure it belongs to
+ * the group.
+ */
if (sharepath != NULL) {
share = sa_get_share(group, sharepath);
if (share == NULL) {
@@ -2372,6 +3368,41 @@ basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
"not supported: %s\n"), sharepath);
}
}
+
+ /*
+ * If a resource name exists, make sure it belongs to
+ * the share if present else it belongs to the
+ * group. Also check the protocol to see if it
+ * supports resource level properties or not. If not,
+ * use share only.
+ */
+ if (rsrcname != NULL) {
+ if (share != NULL) {
+ resource = sa_get_share_resource(share,
+ rsrcname);
+ if (resource == NULL)
+ ret = SA_NO_SUCH_RESOURCE;
+ } else {
+ resource = sa_get_resource(group, rsrcname);
+ if (resource != NULL)
+ share = sa_get_resource_parent(
+ resource);
+ else
+ ret = SA_NO_SUCH_RESOURCE;
+ }
+ if (ret == SA_OK && resource != NULL) {
+ uint64_t features;
+ /*
+ * Check to see if the resource can take
+ * properties. If so, stick the resource into
+ * "share" so it will all just work.
+ */
+ features = sa_proto_get_featureset(protocol);
+ if (features & SA_FEATURE_RESOURCE)
+ share = (sa_share_t)resource;
+ }
+ }
+
if (ret == SA_OK) {
/* group must exist */
ret = valid_options(optlist, protocol,
@@ -2385,7 +3416,7 @@ basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
protocol, &ret);
if (ret == SA_OK && change)
worklist = add_list(worklist, group,
- share);
+ share, protocol);
}
}
free_opt(optlist);
@@ -2403,7 +3434,8 @@ basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
*/
if (!dryrun && ret == SA_OK && change && worklist != NULL)
/* properties changed, so update all shares */
- (void) enable_all_groups(handle, worklist, 0, 0, protocol);
+ (void) enable_all_groups(handle, worklist, 0, 0, protocol,
+ B_TRUE);
if (worklist != NULL)
free_list(worklist);
@@ -2420,7 +3452,7 @@ basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
static int
space_set(sa_handle_t handle, char *groupname, struct options *optlist,
- char *protocol, char *sharepath, int dryrun, char *sectype)
+ char *protocol, char *sharepath, int dryrun, char *sectype)
{
sa_group_t group;
int ret = SA_OK;
@@ -2476,15 +3508,17 @@ space_set(sa_handle_t handle, char *groupname, struct options *optlist,
sa_errorstr(ret));
}
if (ret == SA_OK && change)
- worklist = add_list(worklist, group, share);
+ worklist = add_list(worklist, group, share,
+ protocol);
}
free_opt(optlist);
} else {
(void) printf(gettext("Group \"%s\" not found\n"), groupname);
ret = SA_NO_SUCH_GROUP;
}
+
/*
- * we have a group and potentially legal additions
+ * We have a group and potentially legal additions.
*/
/* Commit to configuration if not a dryrun */
@@ -2492,7 +3526,7 @@ space_set(sa_handle_t handle, char *groupname, struct options *optlist,
if (change && worklist != NULL) {
/* properties changed, so update all shares */
(void) enable_all_groups(handle, worklist, 0, 0,
- protocol);
+ protocol, B_TRUE);
}
ret = sa_update_config(handle);
}
@@ -2518,11 +3552,12 @@ sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
char *protocol = NULL;
int ret = SA_OK;
struct options *optlist = NULL;
+ char *rsrcname = NULL;
char *sharepath = NULL;
char *optset = NULL;
int auth;
- while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
+ while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
switch (c) {
case 'v':
verbose++;
@@ -2531,6 +3566,12 @@ sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
dryrun++;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple protocols "
+ "not supported: %s\n"), protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext(
@@ -2554,10 +3595,30 @@ sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
break;
}
break;
+ case 'r':
+ if (rsrcname != NULL) {
+ (void) printf(gettext(
+ "Setting multiple resource names not"
+ " supported\n"));
+ return (SA_SYNTAX_ERR);
+ }
+ rsrcname = optarg;
+ break;
case 's':
+ if (sharepath != NULL) {
+ (void) printf(gettext(
+ "Setting multiple shares not supported\n"));
+ return (SA_SYNTAX_ERR);
+ }
sharepath = optarg;
break;
case 'S':
+ if (optset != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple property "
+ "spaces not supported: %s\n"), optset);
+ return (SA_SYNTAX_ERR);
+ }
optset = optarg;
break;
default:
@@ -2610,7 +3671,7 @@ sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
auth = check_authorizations(groupname, flags);
if (optset == NULL)
ret = basic_set(handle, groupname, optlist, protocol,
- sharepath, dryrun);
+ sharepath, rsrcname, dryrun);
else
ret = space_set(handle, groupname, optlist, protocol,
sharepath, dryrun, optset);
@@ -2631,7 +3692,7 @@ sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
static int
remove_options(sa_group_t group, struct options *optlist,
- char *proto, int *err)
+ char *proto, int *err)
{
struct options *cur;
sa_optionset_t optionset;
@@ -2698,7 +3759,7 @@ valid_unset(sa_group_t group, struct options *optlist, char *proto)
static int
valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
- char *sectype)
+ char *sectype)
{
struct options *cur;
sa_security_t security;
@@ -2736,7 +3797,7 @@ valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
static int
remove_security(sa_group_t group, char *sectype,
- struct options *optlist, char *proto, int *err)
+ struct options *optlist, char *proto, int *err)
{
sa_security_t security;
int ret = SA_OK;
@@ -2775,25 +3836,30 @@ remove_security(sa_group_t group, char *sectype,
}
/*
- * basic_unset(groupname, optlist, protocol, sharepath, dryrun)
+ * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
*
* Unset non-named optionset properties.
*/
static int
basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
- char *protocol, char *sharepath, int dryrun)
+ char *protocol, char *sharepath, char *rsrcname, int dryrun)
{
sa_group_t group;
int ret = SA_OK;
int change = 0;
struct list *worklist = NULL;
sa_share_t share = NULL;
+ sa_resource_t resource = NULL;
group = sa_get_group(handle, groupname);
if (group == NULL)
return (ret);
+ /*
+ * If there is a sharepath, make sure it belongs to
+ * the group.
+ */
if (sharepath != NULL) {
share = sa_get_share(group, sharepath);
if (share == NULL) {
@@ -2803,6 +3869,39 @@ basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
ret = SA_NO_SUCH_PATH;
}
}
+ /*
+ * If a resource name exists, make sure it belongs to
+ * the share if present else it belongs to the
+ * group. Also check the protocol to see if it
+ * supports resource level properties or not. If not,
+ * use share only.
+ */
+ if (rsrcname != NULL) {
+ if (share != NULL) {
+ resource = sa_get_share_resource(share, rsrcname);
+ if (resource == NULL)
+ ret = SA_NO_SUCH_RESOURCE;
+ } else {
+ resource = sa_get_resource(group, rsrcname);
+ if (resource != NULL) {
+ share = sa_get_resource_parent(resource);
+ } else {
+ ret = SA_NO_SUCH_RESOURCE;
+ }
+ }
+ if (ret == SA_OK && resource != NULL) {
+ uint64_t features;
+ /*
+ * Check to see if the resource can take
+ * properties. If so, stick the resource into
+ * "share" so it will all just work.
+ */
+ features = sa_proto_get_featureset(protocol);
+ if (features & SA_FEATURE_RESOURCE)
+ share = (sa_share_t)resource;
+ }
+ }
+
if (ret == SA_OK) {
/* group must exist */
ret = valid_unset(share != NULL ? share : group,
@@ -2830,16 +3929,15 @@ basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
optlist, protocol, &ret);
}
if (ret == SA_OK && change)
- worklist = add_list(worklist, group,
- share);
+ worklist = add_list(worklist, group, share,
+ protocol);
if (ret != SA_OK)
(void) printf(gettext(
"Could not remove properties: "
"%s\n"), sa_errorstr(ret));
}
} else {
- (void) printf(gettext("Group \"%s\" not found\n"),
- groupname);
+ (void) printf(gettext("Group \"%s\" not found\n"), groupname);
ret = SA_NO_SUCH_GROUP;
}
free_opt(optlist);
@@ -2853,7 +3951,7 @@ basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
if (change && worklist != NULL) {
/* properties changed, so update all shares */
(void) enable_all_groups(handle, worklist, 0, 0,
- protocol);
+ protocol, B_TRUE);
}
}
if (worklist != NULL)
@@ -2868,7 +3966,7 @@ basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
*/
static int
space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
- char *protocol, char *sharepath, int dryrun, char *sectype)
+ char *protocol, char *sharepath, int dryrun, char *sectype)
{
sa_group_t group;
int ret = SA_OK;
@@ -2890,8 +3988,8 @@ space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
return (SA_NO_SUCH_PATH);
}
}
- ret = valid_unset_security(share != NULL ? share : group, optlist,
- protocol, sectype);
+ ret = valid_unset_security(share != NULL ? share : group,
+ optlist, protocol, sectype);
if (ret == SA_OK && !dryrun) {
if (optlist != NULL) {
@@ -2936,7 +4034,7 @@ space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
}
if (ret == SA_OK && change)
- worklist = add_list(worklist, group, 0);
+ worklist = add_list(worklist, group, 0, protocol);
free_opt(optlist);
/*
@@ -2948,7 +4046,7 @@ space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
/* properties changed, so update all shares */
if (change && worklist != NULL)
(void) enable_all_groups(handle, worklist, 0, 0,
- protocol);
+ protocol, B_TRUE);
ret = sa_update_config(handle);
}
if (worklist != NULL)
@@ -2973,11 +4071,12 @@ sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
char *protocol = NULL;
int ret = SA_OK;
struct options *optlist = NULL;
+ char *rsrcname = NULL;
char *sharepath = NULL;
char *optset = NULL;
int auth;
- while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
+ while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
switch (c) {
case 'v':
verbose++;
@@ -2986,6 +4085,12 @@ sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
dryrun++;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple protocols "
+ "not supported: %s\n"), protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext(
@@ -3011,10 +4116,35 @@ sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
break;
}
break;
+ case 'r':
+ /*
+ * Unset properties on resource if applicable or on
+ * share if resource for this protocol doesn't use
+ * resources.
+ */
+ if (rsrcname != NULL) {
+ (void) printf(gettext(
+ "Unsetting multiple resource "
+ "names not supported\n"));
+ return (SA_SYNTAX_ERR);
+ }
+ rsrcname = optarg;
+ break;
case 's':
+ if (sharepath != NULL) {
+ (void) printf(gettext(
+ "Adding multiple shares not supported\n"));
+ return (SA_SYNTAX_ERR);
+ }
sharepath = optarg;
break;
case 'S':
+ if (optset != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple property "
+ "spaces not supported: %s\n"), optset);
+ return (SA_SYNTAX_ERR);
+ }
optset = optarg;
break;
default:
@@ -3063,7 +4193,7 @@ sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
auth = check_authorizations(groupname, flags);
if (optset == NULL)
ret = basic_unset(handle, groupname, optlist, protocol,
- sharepath, dryrun);
+ sharepath, rsrcname, dryrun);
else
ret = space_unset(handle, groupname, optlist, protocol,
sharepath, dryrun, optset);
@@ -3104,6 +4234,12 @@ sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
dryrun++;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple protocols "
+ "not supported: %s\n"), protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext(
@@ -3148,7 +4284,7 @@ sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
ret = SA_BUSY; /* already enabled */
} else {
worklist = add_list(worklist, group,
- 0);
+ 0, protocol);
if (verbose)
(void) printf(gettext(
"Enabling group \"%s\"\n"),
@@ -3165,11 +4301,11 @@ sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
for (group = sa_get_group(handle, NULL);
group != NULL;
group = sa_get_next_group(group)) {
- worklist = add_list(worklist, group, 0);
+ worklist = add_list(worklist, group, 0, protocol);
}
}
if (!dryrun && ret == SA_OK)
- ret = enable_all_groups(handle, worklist, 1, 0, NULL);
+ ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE);
if (ret != SA_OK && ret != SA_BUSY)
(void) printf(gettext("Could not enable group: %s\n"),
@@ -3187,24 +4323,30 @@ sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
}
/*
- * disable_group(group, setstate)
+ * disable_group(group, proto)
*
- * Disable all the shares in the specified group honoring the setstate
- * argument. This is a helper for disable_all_groups in order to
- * simplify regular and subgroup (zfs) disabling. Group has already
- * been checked for non-NULL.
+ * Disable all the shares in the specified group.. This is a helper
+ * for disable_all_groups in order to simplify regular and subgroup
+ * (zfs) disabling. Group has already been checked for non-NULL.
*/
static int
-disable_group(sa_group_t group)
+disable_group(sa_group_t group, char *proto)
{
sa_share_t share;
int ret = SA_OK;
+ /*
+ * If the protocol isn't enabled, skip it and treat as
+ * successful.
+ */
+ if (!has_protocol(group, proto))
+ return (ret);
+
for (share = sa_get_share(group, NULL);
share != NULL && ret == SA_OK;
share = sa_get_next_share(share)) {
- ret = sa_disable_share(share, NULL);
+ ret = sa_disable_share(share, proto);
if (ret == SA_NO_SUCH_PATH) {
/*
* this is OK since the path is gone. we can't
@@ -3216,7 +4358,6 @@ disable_group(sa_group_t group)
return (ret);
}
-
/*
* disable_all_groups(work, setstate)
*
@@ -3243,10 +4384,11 @@ disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
for (subgroup = sa_get_sub_group(group);
subgroup != NULL;
subgroup = sa_get_next_group(subgroup)) {
- ret = disable_group(subgroup);
+ ret = disable_group(subgroup,
+ work->proto);
}
} else {
- ret = disable_group(group);
+ ret = disable_group(group, work->proto);
}
/*
* We don't want to "disable" since it won't come
@@ -3276,7 +4418,7 @@ sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
int all = 0;
int c;
int ret = SA_OK;
- char *protocol;
+ char *protocol = NULL;
char *state;
struct list *worklist = NULL;
sa_group_t group;
@@ -3291,6 +4433,12 @@ sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
dryrun++;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple protocols "
+ "not supported: %s\n"), protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext(
@@ -3332,9 +4480,10 @@ sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
"Group \"%s\" is "
"already disabled\n"),
argv[optind]);
- ret = SA_BUSY; /* already disable */
+ ret = SA_BUSY; /* already disabled */
} else {
- worklist = add_list(worklist, group, 0);
+ worklist = add_list(worklist, group, 0,
+ protocol);
if (verbose)
(void) printf(gettext(
"Disabling group "
@@ -3351,7 +4500,7 @@ sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
for (group = sa_get_group(handle, NULL);
group != NULL;
group = sa_get_next_group(group))
- worklist = add_list(worklist, group, 0);
+ worklist = add_list(worklist, group, 0, protocol);
}
if (ret == SA_OK && !dryrun)
@@ -3377,7 +4526,7 @@ sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
* of the group(s) and only enables shares if the group is already
* enabled.
*/
-/*ARGSUSED*/
+
int
sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
{
@@ -3389,6 +4538,9 @@ sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
char *state;
struct list *worklist = NULL;
sa_group_t group;
+#ifdef lint
+ flags = flags;
+#endif
while ((c = getopt(argc, argv, "?havP:")) != EOF) {
switch (c) {
@@ -3396,6 +4548,12 @@ sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
all = 1;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple protocols "
+ "not supported: %s\n"), protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext(
@@ -3429,7 +4587,8 @@ sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
state = sa_get_group_attr(group, "state");
if (state == NULL ||
strcmp(state, "enabled") == 0) {
- worklist = add_list(worklist, group, 0);
+ worklist = add_list(worklist, group, 0,
+ protocol);
if (verbose)
(void) printf(gettext(
"Starting group \"%s\"\n"),
@@ -3437,7 +4596,7 @@ sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
} else {
/*
* Determine if there are any
- * protocols. if there aren't any,
+ * protocols. If there aren't any,
* then there isn't anything to do in
* any case so no error.
*/
@@ -3452,17 +4611,19 @@ sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
optind++;
}
} else {
- for (group = sa_get_group(handle, NULL); group != NULL;
+ for (group = sa_get_group(handle, NULL);
+ group != NULL;
group = sa_get_next_group(group)) {
state = sa_get_group_attr(group, "state");
if (state == NULL || strcmp(state, "enabled") == 0)
- worklist = add_list(worklist, group, 0);
+ worklist = add_list(worklist, group, 0,
+ protocol);
if (state != NULL)
sa_free_attr_string(state);
}
}
- (void) enable_all_groups(handle, worklist, 0, 1, NULL);
+ (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE);
if (worklist != NULL)
free_list(worklist);
@@ -3477,7 +4638,6 @@ sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
* of the group(s) and only disables shares if the group is already
* enabled.
*/
-/*ARGSUSED*/
int
sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
{
@@ -3489,6 +4649,9 @@ sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
char *state;
struct list *worklist = NULL;
sa_group_t group;
+#ifdef lint
+ flags = flags;
+#endif
while ((c = getopt(argc, argv, "?havP:")) != EOF) {
switch (c) {
@@ -3496,6 +4659,12 @@ sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
all = 1;
break;
case 'P':
+ if (protocol != NULL) {
+ (void) printf(gettext(
+ "Specifying multiple protocols "
+ "not supported: %s\n"), protocol);
+ return (SA_SYNTAX_ERR);
+ }
protocol = optarg;
if (!sa_valid_protocol(protocol)) {
(void) printf(gettext(
@@ -3527,7 +4696,8 @@ sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
state = sa_get_group_attr(group, "state");
if (state == NULL ||
strcmp(state, "enabled") == 0) {
- worklist = add_list(worklist, group, 0);
+ worklist = add_list(worklist, group, 0,
+ protocol);
if (verbose)
(void) printf(gettext(
"Stopping group \"%s\"\n"),
@@ -3541,16 +4711,17 @@ sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
optind++;
}
} else {
- for (group = sa_get_group(handle, NULL); group != NULL;
+ for (group = sa_get_group(handle, NULL);
+ group != NULL;
group = sa_get_next_group(group)) {
state = sa_get_group_attr(group, "state");
if (state == NULL || strcmp(state, "enabled") == 0)
- worklist = add_list(worklist, group, 0);
+ worklist = add_list(worklist, group, 0,
+ protocol);
if (state != NULL)
sa_free_attr_string(state);
}
}
-
(void) disable_all_groups(handle, worklist, 0);
ret = sa_update_config(handle);
@@ -3686,6 +4857,27 @@ out_share(FILE *out, sa_group_t group, char *proto)
{
sa_share_t share;
char resfmt[128];
+ char *defprop;
+
+ /*
+ * The original share command defaulted to displaying NFS
+ * shares or allowed a protocol to be specified. We want to
+ * skip those shares that are not the specified protocol.
+ */
+ if (proto != NULL && sa_get_optionset(group, proto) == NULL)
+ return;
+
+ if (proto == NULL)
+ proto = "nfs";
+
+ /*
+ * get the default property string. NFS uses "rw" but
+ * everything else will use "".
+ */
+ if (proto != NULL && strcmp(proto, "nfs") != 0)
+ defprop = "\"\"";
+ else
+ defprop = "rw";
for (share = sa_get_share(group, NULL);
share != NULL;
@@ -3698,11 +4890,12 @@ out_share(FILE *out, sa_group_t group, char *proto)
char *sharedstate;
int shared = 1;
char *soptions;
+ char shareopts[MAXNAMLEN];
sharedstate = sa_get_share_attr(share, "shared");
path = sa_get_share_attr(share, "path");
type = sa_get_share_attr(share, "type");
- resource = sa_get_share_attr(share, "resource");
+ resource = get_resource(share);
groupname = sa_get_group_attr(group, "name");
if (groupname != NULL && strcmp(groupname, "default") == 0) {
@@ -3711,8 +4904,12 @@ out_share(FILE *out, sa_group_t group, char *proto)
}
description = sa_get_share_description(share);
- /* Want the sharetab version if it exists */
- soptions = sa_get_share_attr(share, "shareopts");
+ /*
+ * Want the sharetab version if it exists, defaulting
+ * to NFS if no protocol specified.
+ */
+ (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto);
+ soptions = sa_get_share_attr(share, shareopts);
if (sharedstate == NULL)
shared = 0;
@@ -3729,7 +4926,7 @@ out_share(FILE *out, sa_group_t group, char *proto)
(void) fprintf(out, "%-14.14s %s %s \"%s\" \n",
resfmt, path,
(soptions != NULL && strlen(soptions) > 0) ?
- soptions : "rw",
+ soptions : defprop,
(description != NULL) ? description : "");
}
@@ -3763,22 +4960,21 @@ output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
{
sa_group_t group;
- for (group = sa_get_group(handle, NULL); group != NULL;
+ for (group = sa_get_group(handle, NULL);
+ group != NULL;
group = sa_get_next_group(group)) {
- char *options;
char *zfs;
/*
- * Get default options preformated, being careful to
- * handle legacy shares differently from new style
- * shares. Legacy share have options on the share.
+ * Go through all the groups and ZFS
+ * sub-groups. out_share() will format the shares in
+ * the group appropriately.
*/
zfs = sa_get_group_attr(group, "zfs");
if (zfs != NULL) {
sa_group_t zgroup;
sa_free_attr_string(zfs);
- options = sa_proto_legacy_format(proto, group, 1);
for (zgroup = sa_get_sub_group(group);
zgroup != NULL;
zgroup = sa_get_next_group(zgroup)) {
@@ -3787,15 +4983,11 @@ output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
out_share(out, zgroup, proto);
}
} else {
- options = sa_proto_legacy_format(proto, group, 1);
out_share(out, group, proto);
}
- if (options != NULL)
- free(options);
}
}
-/*ARGSUSED*/
int
sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
{
@@ -3815,8 +5007,13 @@ sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
int curtype = SA_SHARE_TRANSIENT;
char cmd[MAXPATHLEN];
sa_group_t group = NULL;
+ sa_resource_t rsrc = NULL;
sa_share_t share;
char dir[MAXPATHLEN];
+ uint64_t features;
+#ifdef lint
+ flags = flags;
+#endif
while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
switch (c) {
@@ -3859,7 +5056,7 @@ sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
/* Have the info so construct what is needed */
if (!argsused && optind == argc) {
/* display current info in share format */
- (void) output_legacy_file(stdout, "nfs", handle);
+ (void) output_legacy_file(stdout, protocol, handle);
return (ret);
}
@@ -3891,79 +5088,130 @@ sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
else
share = NULL;
+ features = sa_proto_get_featureset(protocol);
+
if (groupname != NULL) {
ret = SA_NOT_ALLOWED;
} else if (ret == SA_OK) {
- char *legacygroup = "default";
+ char *legacygroup;
/*
* The legacy group is always present and zfs groups
* come and go. zfs shares may be in sub-groups and
* the zfs share will already be in that group so it
- * isn't an error.
+ * isn't an error. If the protocol is "smb", the group
+ * "smb" is used when "default" would otherwise be
+ * used. "default" is NFS only and "smb" is SMB only.
*/
+ if (strcmp(protocol, "smb") == 0)
+ legacygroup = "smb";
+ else
+ legacygroup = "default";
+
/*
* If the share exists (not NULL), then make sure it
* is one we want to handle by getting the parent
* group.
*/
- if (share != NULL)
+ if (share != NULL) {
group = sa_get_parent_group(share);
- else
+ } else {
group = sa_get_group(handle, legacygroup);
+ if (group == NULL && strcmp(legacygroup, "smb") == 0) {
+ /*
+ * This group may not exist, so create
+ * as necessary. It only contains the
+ * "smb" protocol.
+ */
+ group = sa_create_group(handle, legacygroup,
+ &ret);
+ if (group != NULL)
+ (void) sa_create_optionset(group,
+ protocol);
+ }
+ }
- if (group != NULL) {
- groupstatus = group_status(group);
- if (share == NULL) {
- share = sa_add_share(group, sharepath,
- persist, &ret);
- if (share == NULL &&
- ret == SA_DUPLICATE_NAME) {
- /*
- * Could be a ZFS path being started
- */
- if (sa_zfs_is_shared(handle,
- sharepath)) {
- ret = SA_OK;
- group = sa_get_group(handle,
- "zfs");
- if (group == NULL) {
- /*
- * This shouldn't
- * happen.
- */
- ret = SA_CONFIG_ERR;
- } else {
- share = sa_add_share(
- group, sharepath,
- persist, &ret);
- }
- }
- }
- } else {
- char *type;
+ if (group == NULL) {
+ ret = SA_SYSTEM_ERR;
+ goto err;
+ }
+
+ groupstatus = group_status(group);
+ if (share == NULL) {
+ share = sa_add_share(group, sharepath,
+ persist, &ret);
+ if (share == NULL &&
+ ret == SA_DUPLICATE_NAME) {
/*
- * May want to change persist state, but the
- * important thing is to change options. We
- * need to change them regardless of the
- * source.
+ * Could be a ZFS path being started
*/
- if (sa_zfs_is_shared(handle, sharepath)) {
- zfs = 1;
- }
- remove_all_options(share, protocol);
- type = sa_get_share_attr(share, "type");
- if (type != NULL &&
- strcmp(type, "transient") != 0) {
- curtype = SA_SHARE_PERMANENT;
+ if (sa_zfs_is_shared(handle,
+ sharepath)) {
+ ret = SA_OK;
+ group = sa_get_group(handle,
+ "zfs");
+ if (group == NULL) {
+ /*
+ * This shouldn't
+ * happen.
+ */
+ ret = SA_CONFIG_ERR;
+ } else {
+ share = sa_add_share(
+ group, sharepath,
+ persist, &ret);
+ }
}
- if (type != NULL)
- sa_free_attr_string(type);
- if (curtype != persist) {
- (void) sa_set_share_attr(share, "type",
- persist == SA_SHARE_PERMANENT ?
- "persist" : "transient");
+ }
+ } else {
+ char *type;
+ /*
+ * May want to change persist state, but the
+ * important thing is to change options. We
+ * need to change them regardless of the
+ * source.
+ */
+
+ if (sa_zfs_is_shared(handle, sharepath)) {
+ zfs = 1;
+ }
+ remove_all_options(share, protocol);
+ type = sa_get_share_attr(share, "type");
+ if (type != NULL &&
+ strcmp(type, "transient") != 0) {
+ curtype = SA_SHARE_PERMANENT;
+ }
+ if (type != NULL)
+ sa_free_attr_string(type);
+ if (curtype != persist) {
+ (void) sa_set_share_attr(share, "type",
+ persist == SA_SHARE_PERMANENT ?
+ "persist" : "transient");
+ }
+ }
+
+ /*
+ * If there is a resource name, we may
+ * actually care about it if this is share for
+ * a protocol that uses resource level sharing
+ * (SMB). We need to find the resource and, if
+ * it exists, make sure it belongs to the
+ * current share. If it doesn't exist, attempt
+ * to create it.
+ */
+
+ if (ret == SA_OK && resource != NULL) {
+ rsrc = sa_find_resource(handle, resource);
+ if (rsrc != NULL) {
+ if (share != sa_get_resource_parent(rsrc))
+ ret = SA_DUPLICATE_NAME;
+ } else {
+ rsrc = sa_add_resource(share, resource,
+ persist, &ret);
}
+ if (features & SA_FEATURE_RESOURCE)
+ share = rsrc;
}
+
/* Have a group to hold this share path */
if (ret == SA_OK && options != NULL &&
strlen(options) > 0) {
@@ -3973,20 +5221,21 @@ sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
}
if (!zfs) {
/*
- * ZFS shares never have resource or
- * description and we can't store the values
- * so don't try.
+ * ZFS shares never have a description
+ * and we can't store the values so
+ * don't try.
*/
if (ret == SA_OK && description != NULL)
ret = sa_set_share_description(share,
description);
- if (ret == SA_OK && resource != NULL)
- ret = sa_set_share_attr(share,
- "resource", resource);
}
- if (ret == SA_OK) {
- if (strcmp(groupstatus, "enabled") == 0)
+ if (ret == SA_OK &&
+ strcmp(groupstatus, "enabled") == 0) {
+ if (rsrc != share)
ret = sa_enable_share(share, protocol);
+ else
+ ret = sa_enable_resource(rsrc,
+ protocol);
if (ret == SA_OK &&
persist == SA_SHARE_PERMANENT) {
(void) sa_update_legacy(share,
@@ -3995,15 +5244,12 @@ sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
if (ret == SA_OK)
ret = sa_update_config(handle);
}
- } else {
- ret = SA_SYSTEM_ERR;
- }
}
+err:
if (ret != SA_OK) {
(void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
sharepath, sa_errorstr(ret));
ret = SA_LEGACY_ERR;
-
}
return (ret);
}
@@ -4013,7 +5259,6 @@ sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
*
* Implements the original unshare command.
*/
-/*ARGSUSED*/
int
sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
{
@@ -4025,7 +5270,13 @@ sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
int c;
int ret = SA_OK;
int true_legacy = 0;
+ uint64_t features = 0;
+ sa_resource_t resource = NULL;
char cmd[MAXPATHLEN];
+#ifdef lint
+ flags = flags;
+ options = options;
+#endif
while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
switch (c) {
@@ -4086,7 +5337,37 @@ sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
share = sa_find_share(handle, dir);
}
}
- if (share != NULL) {
+ if (share == NULL) {
+ /* Could be a resource name so check that next */
+ features = sa_proto_get_featureset(protocol);
+ resource = sa_find_resource(handle, sharepath);
+ if (resource != NULL) {
+ share = sa_get_resource_parent(resource);
+ if (features & SA_FEATURE_RESOURCE)
+ (void) sa_disable_resource(resource,
+ protocol);
+ if (persist == SA_SHARE_PERMANENT) {
+ ret = sa_remove_resource(resource);
+ if (ret == SA_OK)
+ ret = sa_update_config(handle);
+ }
+ /*
+ * If we still have a resource on the
+ * share, we don't disable the share
+ * itself. IF there aren't anymore, we
+ * need to remove the share. The
+ * removal will be done in the next
+ * section if appropriate.
+ */
+ resource = sa_get_share_resource(share, NULL);
+ if (resource != NULL)
+ share = NULL;
+ } else if (ret == SA_OK) {
+ /* Didn't find path and no resource */
+ ret = SA_BAD_PATH;
+ }
+ }
+ if (share != NULL && resource == NULL) {
ret = sa_disable_share(share, protocol);
/*
* Errors are ok and removal should still occur. The
@@ -4101,7 +5382,13 @@ sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
if (ret == SA_OK)
ret = sa_update_config(handle);
}
- } else {
+ } else if (ret == SA_OK && share == NULL && resource == NULL) {
+ /*
+ * If both share and resource are NULL, then
+ * share not found. If one or the other was
+ * found or there was an earlier error, we
+ * assume it was handled earlier.
+ */
ret = SA_NOT_SHARED;
}
}
@@ -4122,7 +5409,7 @@ sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
/*
* Common commands that implement the sub-commands used by all
- * protcols. The entries are found via the lookup command
+ * protocols. The entries are found via the lookup command
*/
static sa_command_t commands[] = {
@@ -4139,7 +5426,7 @@ static sa_command_t commands[] = {
{"show", 0, sa_show, USAGE_SHOW},
{"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
{"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
- SVC_SET|SVC_ACTION},
+ SVC_SET|SVC_ACTION},
{"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
{"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
{"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
@@ -4176,11 +5463,14 @@ sa_get_usage(sa_usage_t index)
"move-share [-nvh] -s sharepath destination-group");
break;
case USAGE_REMOVE_SHARE:
- ret = gettext("remove-share [-fnvh] -s sharepath group");
+ ret = gettext(
+ "remove-share [-fnvh] {-s sharepath | -r resource} "
+ "group");
break;
case USAGE_SET:
ret = gettext("set [-nvh] -P proto [-S optspace] "
- "[-p property=value]* [-s sharepath] group");
+ "[-p property=value]* [-s sharepath] [-r resource]] "
+ "group");
break;
case USAGE_SET_SECURITY:
ret = gettext("set-security [-nvh] -P proto -S security-type "
@@ -4208,12 +5498,12 @@ sa_get_usage(sa_usage_t index)
"[-p property]* group");
break;
case USAGE_UNSET_SECURITY:
- ret = gettext("unset-security [-nvh] -P proto -S security-type"
- " [-p property]* group");
+ ret = gettext("unset-security [-nvh] -P proto "
+ "-S security-type [-p property]* group");
break;
case USAGE_UNSHARE:
ret = gettext(
- "unshare [-F fstype] [-p] sharepath");
+ "unshare [-F fstype] [-p] [-o optionlist] sharepath");
break;
}
return (ret);
@@ -4225,12 +5515,14 @@ sa_get_usage(sa_usage_t index)
* Lookup the sub-command. proto isn't currently used, but it may
* eventually provide a way to provide protocol specific sub-commands.
*/
-/*ARGSUSED*/
sa_command_t *
sa_lookup(char *cmd, char *proto)
{
int i;
size_t len;
+#ifdef lint
+ proto = proto;
+#endif
len = strlen(cmd);
for (i = 0; commands[i].cmdname != NULL; i++) {
@@ -4240,11 +5532,13 @@ sa_lookup(char *cmd, char *proto)
return (NULL);
}
-/*ARGSUSED*/
void
sub_command_help(char *proto)
{
int i;
+#ifdef lint
+ proto = proto;
+#endif
(void) printf(gettext("\tsub-commands:\n"));
for (i = 0; commands[i].cmdname != NULL; i++) {
diff --git a/usr/src/cmd/dfs.cmds/sharemgr/group.xml b/usr/src/cmd/dfs.cmds/sharemgr/group.xml
index 628338f896..3b6a4eb210 100644
--- a/usr/src/cmd/dfs.cmds/sharemgr/group.xml
+++ b/usr/src/cmd/dfs.cmds/sharemgr/group.xml
@@ -56,6 +56,17 @@
type='service'>
<service_fmri value='svc:/milestone/network' />
</dependency>
+ <!--
+ SMB is optional_all so that we don't have to have SMB
+ enabled to work, but if it is, we want to run "after" the
+ smb/service starts.
+ -->
+ <dependency name='smb'
+ grouping='optional_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/network/smb/server' />
+ </dependency>
<!--
The start method will cause each share group to be
diff --git a/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h b/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h
index 0c6648cf16..a7c9dedafd 100644
--- a/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h
+++ b/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h
@@ -105,6 +105,7 @@ struct list {
struct list *next;
void *item;
void *itemdata;
+ char *proto;
};
/* shareutil entry points */
diff --git a/usr/src/cmd/filesync/main.c b/usr/src/cmd/filesync/main.c
index 22099f6acb..3af9bf6d81 100644
--- a/usr/src/cmd/filesync/main.c
+++ b/usr/src/cmd/filesync/main.c
@@ -634,7 +634,7 @@ check_access(char *name, int *newflag)
return (0);
}
- /* if the problem is isn't non-existance, lose */
+ /* if the problem is isn't non-existence, lose */
if (errno != ENOENT) {
*newflag = 0;
fprintf(stderr, gettext(ERR_rdwri), name);
diff --git a/usr/src/cmd/idmap/idmap/idmap.c b/usr/src/cmd/idmap/idmap/idmap.c
index efd9dbe5e2..b5ca5dabf5 100644
--- a/usr/src/cmd/idmap/idmap/idmap.c
+++ b/usr/src/cmd/idmap/idmap/idmap.c
@@ -166,10 +166,10 @@ static char *pnm_last_unixname;
* idmap_api batch related variables:
*
* idmap can operate in two modes. It the batch mode, the idmap_api
- * batch is commited at the end of a batch of several
+ * batch is committed at the end of a batch of several
* commands. At the end of input file, typically. This mode is used
* for processing input from a file.
- * In the non-batch mode, each command is commited immediately. This
+ * In the non-batch mode, each command is committed immediately. This
* mode is used for tty input.
*/
diff --git a/usr/src/cmd/idmap/idmapd/server.c b/usr/src/cmd/idmap/idmapd/server.c
index 09feccb512..cb7cb83fde 100644
--- a/usr/src/cmd/idmap/idmapd/server.c
+++ b/usr/src/cmd/idmap/idmapd/server.c
@@ -251,7 +251,7 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch,
}
}
- /* Commit if we have atleast one successful update */
+ /* Commit if we have at least one successful update */
if (state.sid2pid_done == FALSE || state.pid2sid_done == FALSE)
(void) sql_exec_no_cb(cache, "COMMIT TRANSACTION;");
else
diff --git a/usr/src/cmd/login/login.c b/usr/src/cmd/login/login.c
index 4ad71d0d56..f86e186092 100644
--- a/usr/src/cmd/login/login.c
+++ b/usr/src/cmd/login/login.c
@@ -60,7 +60,7 @@
* -z <zonename>: This flag is passed to login when zlogin(1) executes a
* zone login. This tells login(1) to skip it's normal CONSOLE check
* (i.e. that the root login must be on /dev/console) and tells us the
- * name of the zone from which the login is occuring.
+ * name of the zone from which the login is occurring.
*/
#include <sys/types.h>
diff --git a/usr/src/cmd/lp/cmd/lpsched/disp1.c b/usr/src/cmd/lp/cmd/lpsched/disp1.c
index 3f5ac73450..b933a3519c 100644
--- a/usr/src/cmd/lp/cmd/lpsched/disp1.c
+++ b/usr/src/cmd/lp/cmd/lpsched/disp1.c
@@ -1040,7 +1040,7 @@ reqpath(char *file, char **idnumber)
}
/*
- * The client is sending a peer connection to retreive label information
+ * The client is sending a peer connection to retrieve label information
* from. This is used in the event that the client is an intermediary for
* the actual requestor in a Trusted environment.
*/
diff --git a/usr/src/cmd/ls/Makefile.com b/usr/src/cmd/ls/Makefile.com
index 6d695f3cd5..fc97bafcf6 100644
--- a/usr/src/cmd/ls/Makefile.com
+++ b/usr/src/cmd/ls/Makefile.com
@@ -2,9 +2,8 @@
# 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.
+# 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.
@@ -20,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -36,7 +35,7 @@ SRCS= $(OBJS:%.o=../%.c)
include ../../Makefile.cmd
-LDLIBS += -lsec
+LDLIBS += -lsec -lnvpair -lcmdutils
CFLAGS += $(CCVERBOSE)
$(XPG4) := CFLAGS += -DXPG4
diff --git a/usr/src/cmd/ls/ls.c b/usr/src/cmd/ls/ls.c
index 1287dd9280..2ea223e719 100644
--- a/usr/src/cmd/ls/ls.c
+++ b/usr/src/cmd/ls/ls.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -61,6 +61,9 @@
#include <libgen.h>
#include <errno.h>
#include <aclutils.h>
+#include <libnvpair.h>
+#include <libcmdutils.h>
+#include <attr.h>
#ifndef STANDALONE
#define TERMINFO
@@ -69,7 +72,7 @@
/*
* -DNOTERMINFO can be defined on the cc command line to prevent
* the use of terminfo. This should be done on systems not having
- * the terminfo feature(pre 6.0 sytems ?).
+ * the terminfo feature(pre 6.0 systems ?).
* As a result, columnar listings assume 80 columns for output,
* unless told otherwise via the COLUMNS environment variable.
*/
@@ -119,6 +122,16 @@ struct ditem {
ino_t ino; /* directory items inode number */
struct ditem *parent; /* dir items ptr to its parent's info */
};
+/* Holds boolean extended system attributes */
+struct attrb {
+ char *name;
+};
+/* Holds timestamp extended system attributes */
+struct attrtm {
+ char *name;
+ uint64_t stm;
+ uint64_t nstm;
+};
struct lbuf {
union {
@@ -134,11 +147,16 @@ struct lbuf {
off_t lsize; /* filesize or major/minor dev numbers */
blkcnt_t lblocks; /* number of file blocks */
timestruc_t lmtime;
+ timestruc_t lat;
+ timestruc_t lct;
+ timestruc_t lmt;
char *flinkto; /* symbolic link contents */
char acl; /* indicate there are additional acl entries */
int cycle; /* cycle detected flag */
struct ditem *ancinfo; /* maintains ancestor info */
acl_t *aclp; /* ACL if present */
+ struct attrb *exttr; /* boolean extended system attributes */
+ struct attrtm *extm; /* timestamp extended system attributes */
};
struct dchain {
@@ -221,6 +239,16 @@ static int Rflg;
static int Sflg;
static int vflg;
static int Vflg;
+static int saflg; /* boolean extended system attr. */
+static int sacnt; /* number of extended system attr. */
+static int copt;
+static int vopt;
+static int tmflg; /* create time ext. system attr. */
+static int ctm;
+static int atm;
+static int mtm;
+static int crtm;
+static int alltm;
static long hscale;
static mode_t flags;
static int err = 0; /* Contains return code */
@@ -247,13 +275,25 @@ static int curcol;
static struct winsize win;
-static char time_buf[50]; /* array to hold day and time */
+static char time_buf[FMTSIZE]; /* array to hold day and time */
#define NOTWORKINGDIR(d, l) (((l) < 2) || \
(strcmp((d) + (l) - 2, "/.") != 0))
#define NOTPARENTDIR(d, l) (((l) < 3) || \
(strcmp((d) + (l) - 3, "/..") != 0))
+/* Extended system attributes support */
+static int get_sysxattr(char *, struct lbuf *);
+static void set_sysattrb_display(char *, boolean_t, struct lbuf *);
+static void set_sysattrtm_display(char *, struct lbuf *);
+static void format_time(const char *, time_t);
+static void format_etime(const char *, time_t, time_t);
+static void print_time(struct lbuf *);
+static void format_attrtime(struct lbuf *);
+static void *xmalloc(size_t, struct lbuf *);
+static void free_sysattr(struct lbuf *);
+static nvpair_t *pair;
+static nvlist_t *response;
int
main(int argc, char *argv[])
@@ -287,7 +327,7 @@ main(int argc, char *argv[])
}
while ((c = getopt(argc, argv,
- "aAbcCdeEfFghHilLmnopqrRsStux1@vV")) != EOF)
+ "aAbcCdeEfFghHilLmnopqrRsStux1@vV/:%:")) != EOF)
switch (c) {
case 'a':
aflg++;
@@ -301,6 +341,10 @@ main(int argc, char *argv[])
continue;
case 'c':
uflg = 0;
+ atm = 0;
+ ctm = 0;
+ mtm = 0;
+ crtm = 0;
cflg++;
continue;
case 'C':
@@ -414,6 +458,10 @@ main(int argc, char *argv[])
continue;
case 'u':
cflg = 0;
+ atm = 0;
+ ctm = 0;
+ mtm = 0;
+ crtm = 0;
uflg++;
continue;
case 'V':
@@ -457,13 +505,78 @@ main(int argc, char *argv[])
xflg = 0;
mflg = 0;
continue;
+ case '/':
+ saflg++;
+ if (optarg != NULL) {
+ if (strcmp(optarg, "c") == 0) {
+ copt++;
+ vopt = 0;
+ } else if (strcmp(optarg, "v") == 0) {
+ vopt++;
+ copt = 0;
+ } else
+ opterr++;
+ } else
+ opterr++;
+ lflg++;
+ statreq++;
+ Cflg = 0;
+ xflg = 0;
+ mflg = 0;
+ continue;
+ case '%':
+ tmflg++;
+ if (optarg != NULL) {
+ if (strcmp(optarg, "ctime") == 0) {
+ ctm++;
+ atm = 0;
+ mtm = 0;
+ crtm = 0;
+ } else if (strcmp(optarg, "atime") == 0) {
+ atm++;
+ ctm = 0;
+ mtm = 0;
+ crtm = 0;
+ uflg = 0;
+ cflg = 0;
+ } else if (strcmp(optarg, "mtime") == 0) {
+ mtm++;
+ atm = 0;
+ ctm = 0;
+ crtm = 0;
+ uflg = 0;
+ cflg = 0;
+ } else if (strcmp(optarg, "crtime") == 0) {
+ crtm++;
+ atm = 0;
+ ctm = 0;
+ mtm = 0;
+ uflg = 0;
+ cflg = 0;
+ } else if (strcmp(optarg, "all") == 0) {
+ alltm++;
+ atm = 0;
+ ctm = 0;
+ mtm = 0;
+ crtm = 0;
+ } else
+ opterr++;
+ } else
+ opterr++;
+
+ Sflg = 0;
+ statreq++;
+ mflg = 0;
+ continue;
case '?':
opterr++;
continue;
}
if (opterr) {
(void) fprintf(stderr, gettext(
- "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxvV1@ [files]\n"));
+ "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxvV1@/%[c | v]"
+ "%%[atime | crtime | ctime | mtime | all]"
+ " [files]\n"));
exit(2);
}
@@ -745,7 +858,6 @@ pentry(struct lbuf *ap)
struct lbuf *p;
numbuf_t hbuf;
char buf[BUFSIZ];
- char fmt_buf[FMTSIZE];
char *dmark = ""; /* Used if -p or -F option active */
char *cp;
@@ -758,9 +870,9 @@ pentry(struct lbuf *ap)
curcol += printf("%10llu ", (long long)p->lnum);
if (sflg)
curcol += printf((mflg && !lflg) ? "%lld " :
- (p->lblocks < 10000) ? "%4lld " : "%lld ",
- (p->ltype != 'b' && p->ltype != 'c') ?
- p->lblocks : 0LL);
+ (p->lblocks < 10000) ? "%4lld " : "%lld ",
+ (p->ltype != 'b' && p->ltype != 'c') ?
+ p->lblocks : 0LL);
if (lflg) {
(void) putchar(p->ltype);
curcol++;
@@ -794,31 +906,26 @@ pentry(struct lbuf *ap)
curcol += printf((p->lsize < (off_t)10000000) ?
"%7lld" : "%lld", p->lsize);
}
- if (eflg) {
- (void) strftime(time_buf, sizeof (time_buf),
- dcgettext(NULL, FORMAT3, LC_TIME),
- localtime(&p->lmtime.tv_sec));
- } else if (Eflg) {
+ if (eflg)
+ format_time(FORMAT3, p->lmtime.tv_sec);
+ else if (Eflg)
/* fill in nanoseconds first */
- (void) snprintf(fmt_buf, sizeof (fmt_buf),
- FORMAT4, p->lmtime.tv_nsec);
- (void) strftime(time_buf, sizeof (time_buf),
- fmt_buf, localtime(&p->lmtime.tv_sec));
- } else {
+ format_etime(FORMAT4, p->lmtime.tv_sec,
+ p->lmtime.tv_nsec);
+ else {
if ((p->lmtime.tv_sec < year) ||
- (p->lmtime.tv_sec > now)) {
- (void) strftime(time_buf, sizeof (time_buf),
- dcgettext(NULL, FORMAT1, LC_TIME),
- localtime(&p->lmtime.tv_sec));
- } else {
- (void) strftime(time_buf, sizeof (time_buf),
- dcgettext(NULL, FORMAT2, LC_TIME),
- localtime(&p->lmtime.tv_sec));
- }
+ (p->lmtime.tv_sec > now))
+ format_time(FORMAT1, p->lmtime.tv_sec);
+ else
+ format_time(FORMAT2, p->lmtime.tv_sec);
}
+ /* format extended system attribute time */
+ if (tmflg && crtm)
+ format_attrtime(p);
+
curcol += printf("%s", time_buf);
- }
+ }
/*
* prevent both "->" and trailing marks
* from appearing
@@ -868,12 +975,44 @@ pentry(struct lbuf *ap)
}
}
+ /* Display extended system attributes */
+ if (saflg) {
+ int i;
+
+ new_line();
+ (void) printf(" \t{");
+ if (p->exttr != NULL) {
+ int k = 0;
+ for (i = 0; i < sacnt; i++) {
+ if (p->exttr[i].name != NULL)
+ k++;
+ }
+ for (i = 0; i < sacnt; i++) {
+ if (p->exttr[i].name != NULL) {
+ (void) printf("%s", p->exttr[i].name);
+ k--;
+ if (vopt && (k != 0))
+ (void) printf(",");
+ }
+ }
+ }
+ (void) printf("}\n");
+ }
+ /* Display file timestamps and extended system attribute timestamps */
+ if (tmflg && alltm) {
+ new_line();
+ print_time(p);
+ new_line();
+ }
if (vflg) {
new_line();
if (p->aclp) {
acl_printacl(p->aclp, num_cols, Vflg);
}
}
+ /* Free extended system attribute lists */
+ if (saflg || tmflg)
+ free_sysattr(p);
}
/* print various r,w,x permissions */
@@ -1016,7 +1155,7 @@ rddir(char *dir, struct ditem *myinfo)
ep = gstat(makename(dir, dentry->d_name), 0, myinfo);
if (ep == NULL) {
if (nomocore)
- return;
+ exit(2);
continue;
} else {
ep->lnum = dentry->d_ino;
@@ -1394,6 +1533,7 @@ gstat(char *file, int argfl, struct ditem *myparent)
if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1)
rep->acl = '@';
+
} else
rep->acl = ' ';
@@ -1402,15 +1542,48 @@ gstat(char *file, int argfl, struct ditem *myparent)
rep->luid = statb.st_uid;
rep->lgid = statb.st_gid;
rep->lnl = statb.st_nlink;
- if (uflg)
+ if (uflg || (tmflg && atm))
rep->lmtime = statb.st_atim;
- else if (cflg)
+ else if (cflg || (tmflg && ctm))
rep->lmtime = statb.st_ctim;
else
rep->lmtime = statb.st_mtim;
+ rep->lat = statb.st_atim;
+ rep->lct = statb.st_ctim;
+ rep->lmt = statb.st_mtim;
if (rep->ltype != 'b' && rep->ltype != 'c')
tblocks += rep->lblocks;
+
+ /* Get extended system attributes */
+
+ rep->exttr = NULL;
+ rep->extm = NULL;
+ if ((saflg || (tmflg && crtm) || (tmflg && alltm)) &&
+ (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) {
+ int i;
+
+ sacnt = attr_count();
+ /*
+ * Allocate 'sacnt' size array to hold extended
+ * system attribute name (verbose) or respective
+ * symbol represenation (compact).
+ */
+ rep->exttr = xmalloc(sacnt * sizeof (struct attrb),
+ rep);
+
+ /* initialize boolean attribute list */
+ for (i = 0; i < sacnt; i++)
+ rep->exttr[i].name = NULL;
+ if (get_sysxattr(file, rep) != 0) {
+ (void) fprintf(stderr,
+ gettext("ls:Failed to retrieve "
+ "extended system attribute from "
+ "%s\n"), file);
+ rep->exttr[0].name = xmalloc(2, rep);
+ (void) strlcpy(rep->exttr[0].name, "?", 2);
+ }
+ }
}
return (rep);
}
@@ -1595,9 +1768,9 @@ compar(struct lbuf **pp1, struct lbuf **pp2)
* sort by name.
*/
off_t p1size = (p1->ltype == 'b') ||
- (p1->ltype == 'c') ? 0 : p1->lsize;
+ (p1->ltype == 'c') ? 0 : p1->lsize;
off_t p2size = (p2->ltype == 'b') ||
- (p2->ltype == 'c') ? 0 : p2->lsize;
+ (p2->ltype == 'c') ? 0 : p2->lsize;
if (p2size > p1size) {
return (rflg);
} else if (p2size < p1size) {
@@ -1796,3 +1969,262 @@ number_to_scaled_string(
}
return (buf);
}
+
+/* Get extended system attributes and set the display */
+
+int
+get_sysxattr(char *fname, struct lbuf *rep)
+{
+ boolean_t value;
+ data_type_t type;
+ int error;
+ char *name;
+ int i;
+
+ if ((error = nvlist_alloc(&response, NV_UNIQUE_NAME, 0)) != 0) {
+ perror("ls:nvlist_alloc");
+ return (error);
+ }
+ if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname,
+ &response)) != 0) {
+ perror("ls:getattrat");
+ nvlist_free(response);
+ return (error);
+ }
+
+ /*
+ * Allocate 'sacnt' size array to hold extended timestamp
+ * system attributes and initialize the array.
+ */
+ rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep);
+ for (i = 0; i < sacnt; i++) {
+ rep->extm[i].stm = 0;
+ rep->extm[i].nstm = 0;
+ rep->extm[i].name = NULL;
+ }
+ while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
+ name = nvpair_name(pair);
+ type = nvpair_type(pair);
+ if (type == DATA_TYPE_BOOLEAN_VALUE) {
+ error = nvpair_value_boolean_value(pair, &value);
+ if (error) {
+ (void) fprintf(stderr,
+ gettext("nvpair_value_boolean_value "
+ "failed: error = %d\n"), error);
+ continue;
+ }
+ if (name != NULL)
+ set_sysattrb_display(name, value, rep);
+ continue;
+ } else if (type == DATA_TYPE_UINT64_ARRAY) {
+ if (name != NULL)
+ set_sysattrtm_display(name, rep);
+ continue;
+ }
+ }
+ nvlist_free(response);
+ return (0);
+}
+
+/* Set extended system attribute boolean display */
+
+void
+set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep)
+{
+ f_attr_t fattr;
+ const char *opt;
+ size_t len;
+
+ fattr = name_to_attr(name);
+ if (fattr != F_ATTR_INVAL && fattr < sacnt) {
+ if (vopt) {
+ len = strlen(name);
+ if (val) {
+ rep->exttr[fattr].name = xmalloc(len + 1, rep);
+ (void) strlcpy(rep->exttr[fattr].name, name,
+ len + 1);
+ } else {
+ rep->exttr[fattr].name = xmalloc(len + 3, rep);
+ (void) snprintf(rep->exttr[fattr].name, len + 3,
+ "no%s", name);
+ }
+ } else {
+ opt = attr_to_option(fattr);
+ if (opt != NULL) {
+ len = strlen(opt);
+ rep->exttr[fattr].name = xmalloc(len + 1, rep);
+ if (val)
+ (void) strlcpy(rep->exttr[fattr].name,
+ opt, len + 1);
+ else
+ (void) strlcpy(rep->exttr[fattr].name,
+ "-", len + 1);
+ }
+ }
+ }
+}
+
+/* Set extended system attribute timestamp display */
+
+void
+set_sysattrtm_display(char *name, struct lbuf *rep)
+{
+ uint_t nelem;
+ uint64_t *value;
+ int i;
+ size_t len;
+
+ if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) {
+ if (*value != NULL) {
+ len = strlen(name);
+ i = 0;
+ while (rep->extm[i].stm != 0 && i < sacnt)
+ i++;
+ rep->extm[i].stm = value[0];
+ rep->extm[i].nstm = value[1];
+ rep->extm[i].name = xmalloc(len + 1, rep);
+ (void) strlcpy(rep->extm[i].name, name, len + 1);
+ }
+ }
+}
+
+void
+format_time(const char *format, time_t sec)
+{
+
+ (void) strftime(time_buf, sizeof (time_buf),
+ dcgettext(NULL, format, LC_TIME),
+ localtime(&sec));
+}
+
+void
+format_etime(const char *format, time_t sec, time_t nsec)
+{
+ char fmt_buf[FMTSIZE];
+
+ (void) snprintf(fmt_buf, FMTSIZE,
+ format, nsec);
+ (void) strftime(time_buf, sizeof (time_buf),
+ fmt_buf, localtime(&sec));
+}
+
+/* Format timestamp extended system attributes */
+
+void
+format_attrtime(struct lbuf *p)
+{
+ int tmattr = 0;
+ int i;
+
+ if (p->extm != NULL) {
+ for (i = 0; i < sacnt; i++) {
+ if (p->extm[i].name != NULL) {
+ tmattr = 1;
+ break;
+ }
+ }
+ }
+ if (tmattr) {
+ if (Eflg)
+ format_etime(FORMAT4, (time_t)p->extm[i].stm,
+ (time_t)p->extm[i].nstm);
+ else {
+ if ((p->lmtime.tv_sec < year) ||
+ (p->lmtime.tv_sec > now))
+ format_time(FORMAT1,
+ (time_t)p->extm[i].stm);
+ else
+ format_time(FORMAT2,
+ (time_t)p->extm[i].stm);
+ }
+ }
+}
+
+void
+print_time(struct lbuf *p)
+{
+ int i = 0;
+
+ new_line();
+ if (Eflg) {
+ format_etime(FORMAT4, p->lat.tv_sec, p->lat.tv_nsec);
+ (void) printf(" timestamp: atime %s\n",
+ time_buf);
+ format_etime(FORMAT4, p->lct.tv_sec, p->lct.tv_nsec);
+ (void) printf(" timestamp: ctime %s\n",
+ time_buf);
+ format_etime(FORMAT4, p->lmt.tv_sec, p->lmt.tv_nsec);
+ (void) printf(" timestamp: mtime %s\n",
+ time_buf);
+ if (p->extm != NULL) {
+ while (p->extm[i].nstm != 0 && i < sacnt) {
+ format_etime(FORMAT4, p->extm[i].stm,
+ p->extm[i].nstm);
+ if (p->extm[i].name != NULL) {
+ (void) printf(" timestamp:"
+ " %s %s\n",
+ p->extm[i].name, time_buf);
+ }
+ i++;
+ }
+ }
+ } else {
+ format_time(FORMAT3, p->lat.tv_sec);
+ (void) printf(" timestamp: atime %s\n",
+ time_buf);
+ format_time(FORMAT3, p->lct.tv_sec);
+ (void) printf(" timestamp: ctime %s\n",
+ time_buf);
+ format_time(FORMAT3, p->lmt.tv_sec);
+ (void) printf(" timestamp: mtime %s\n",
+ time_buf);
+ if (p->extm != NULL) {
+ while (p->extm[i].stm != 0 && i < sacnt) {
+ format_time(FORMAT3, p->extm[i].stm);
+ if (p->extm[i].name != NULL) {
+ (void) printf(" timestamp:"
+ " %s %s\n",
+ p->extm[i].name, time_buf);
+ }
+ i++;
+ }
+ }
+ }
+}
+
+/* Free extended system attribute lists */
+
+void
+free_sysattr(struct lbuf *p)
+{
+ int i;
+
+ if (p->exttr != NULL) {
+ for (i = 0; i < sacnt; i++) {
+ if (p->exttr[i].name != NULL)
+ free(p->exttr[i].name);
+ }
+ free(p->exttr);
+ }
+ if (p->extm != NULL) {
+ for (i = 0; i < sacnt; i++) {
+ if (p->extm[i].name != NULL)
+ free(p->extm[i].name);
+ }
+ free(p->extm);
+ }
+}
+
+/* Allocate extended system attribute list */
+
+void *
+xmalloc(size_t size, struct lbuf *p)
+{
+ if ((p = malloc(size)) == NULL) {
+ perror("ls");
+ free_sysattr(p);
+ nvlist_free(response);
+ exit(2);
+ }
+ return (p);
+}
diff --git a/usr/src/cmd/mdb/Makefile.common b/usr/src/cmd/mdb/Makefile.common
index add8318269..56746f40de 100644
--- a/usr/src/cmd/mdb/Makefile.common
+++ b/usr/src/cmd/mdb/Makefile.common
@@ -73,6 +73,7 @@ COMMON_MODULES_KVM = \
s1394 \
scsi_vhci \
sctp \
+ smbsrv \
specfs \
sppp \
ufs \
diff --git a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
new file mode 100644
index 0000000000..d8cca22f4f
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
@@ -0,0 +1,1194 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/mdb_modapi.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smbvar.h>
+
+#define SMB_DCMD_INDENT 4
+
+static void smb_lookup_svc_state_str(smb_svcstate_t state, char *dst_str,
+ int slen);
+
+/*
+ * Initialize the smb_session_t walker by reading the value of smb_info
+ * object in the kernel's symbol table. Only global walk supported.
+ */
+static int
+smb_session_walk_init(mdb_walk_state_t *wsp)
+{
+ GElf_Sym sym;
+ uintptr_t svcsm_addr;
+
+ if (wsp->walk_addr == NULL) {
+ if (mdb_lookup_by_name("smb_info", &sym) == -1) {
+ mdb_warn("failed to find 'smb_info'");
+ return (WALK_ERR);
+ }
+ svcsm_addr = (uintptr_t)(sym.st_value +
+ offsetof(struct smb_info, si_svc_sm_ctx));
+ wsp->walk_addr = svcsm_addr +
+ offsetof(smb_svc_sm_ctx_t, ssc_active_sessions);
+ } else {
+ mdb_printf("smb_session walk only supports global walks\n");
+ return (WALK_ERR);
+ }
+
+ if (mdb_layered_walk("list", wsp) == -1) {
+ mdb_warn("failed to walk 'list'");
+ return (WALK_ERR);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+smb_session_walk_step(mdb_walk_state_t *wsp)
+{
+ return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
+ wsp->walk_cbdata));
+}
+
+/*
+ * Initialize the smb_node_t walker by reading the value of smb_info
+ * object in the kernel's symbol table. Only global walk supported.
+ */
+static int
+smb_node_walk_init(mdb_walk_state_t *wsp)
+{
+ GElf_Sym sym;
+ int i;
+ uintptr_t node_hash_table_addr;
+
+ if (wsp->walk_addr == NULL) {
+ if (mdb_lookup_by_name("smb_info", &sym) == -1) {
+ mdb_warn("failed to find 'smb_info'");
+ return (WALK_ERR);
+ }
+ node_hash_table_addr = (uintptr_t)(sym.st_value +
+ offsetof(struct smb_info, node_hash_table));
+ } else {
+ mdb_printf("smb_node walk only supports global walks\n");
+ return (WALK_ERR);
+ }
+
+ for (i = 0; i < SMBND_HASH_MASK + 1; i++) {
+ wsp->walk_addr = node_hash_table_addr +
+ (i * sizeof (smb_llist_t)) +
+ offsetof(smb_llist_t, ll_list);
+ if (mdb_layered_walk("list", wsp) == -1) {
+ mdb_warn("failed to walk 'list'");
+ return (WALK_ERR);
+ }
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+smb_node_walk_step(mdb_walk_state_t *wsp)
+{
+ return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
+ wsp->walk_cbdata));
+}
+
+/*
+ * ::smb_info
+ *
+ * smb_info dcmd - Print out the smb_info structure.
+ */
+/*ARGSUSED*/
+static int
+smb_information(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ int print_config = FALSE;
+ struct smb_info smb_info;
+ GElf_Sym smb_info_sym;
+ char state_name[40];
+ char last_state_name[40];
+
+ if (mdb_getopts(argc, argv,
+ 'c', MDB_OPT_SETBITS, TRUE, &print_config,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ if (flags & DCMD_ADDRSPEC)
+ return (DCMD_USAGE);
+
+ if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "smb_info", &smb_info_sym)) {
+ mdb_warn("failed to find symbol smb_info");
+ return (DCMD_ERR);
+ }
+
+ if (mdb_readvar(&smb_info, "smb_info") == -1) {
+ mdb_warn("failed to read smb_info structure");
+ return (DCMD_ERR);
+ }
+
+ /* Lookup state string */
+ smb_lookup_svc_state_str(smb_info.si_svc_sm_ctx.ssc_state,
+ state_name, 40);
+ smb_lookup_svc_state_str(smb_info.si_svc_sm_ctx.ssc_last_state,
+ last_state_name, 40);
+
+ mdb_printf("SMB information:\n\n");
+ mdb_printf(" SMB state :\t%s (%d)\n", state_name,
+ smb_info.si_svc_sm_ctx.ssc_state);
+ mdb_printf(" SMB last state :\t%s (%d)\n", last_state_name,
+ smb_info.si_svc_sm_ctx.ssc_last_state);
+ mdb_printf(" Active Sessions :\t%d\n",
+ smb_info.si_svc_sm_ctx.ssc_active_session_count);
+ mdb_printf("Deferred Sessions :\t%d\n",
+ smb_info.si_svc_sm_ctx.ssc_deferred_session_count);
+ mdb_printf(" SMB Open Files :\t%d\n", smb_info.open_files);
+ mdb_printf(" SMB Open Trees :\t%d\n", smb_info.open_trees);
+ mdb_printf(" SMB Open Users :\t%d\n\n", smb_info.open_users);
+
+ if (print_config) {
+ mdb_printf("Configuration:\n\n");
+ (void) mdb_inc_indent(SMB_DCMD_INDENT);
+ mdb_printf("Max Buffer Size %d\n",
+ smb_info.si.skc_maxbufsize);
+ mdb_printf("Max Worker Thread %d\n",
+ smb_info.si.skc_maxworkers);
+ mdb_printf("Max Connections %d\n",
+ smb_info.si.skc_maxconnections);
+ mdb_printf("Keep Alive Timeout %d\n",
+ smb_info.si.skc_keepalive);
+ mdb_printf("%sRestrict Anonymous Access\n",
+ (smb_info.si.skc_restrict_anon) ? "" : "Do Not ");
+ mdb_printf("Signing %s\n",
+ (smb_info.si.skc_signing_enable) ? "Enabled" : "Disabled");
+ mdb_printf("Signing %sRequired\n",
+ (smb_info.si.skc_signing_required) ? "" : "Not ");
+ mdb_printf("Signing Check %s\n",
+ (smb_info.si.skc_signing_check) ? "Enabled" : "Disabled");
+ mdb_printf("Oplocks %s\n",
+ (smb_info.si.skc_oplock_enable) ? "Enabled" : "Disabled");
+ mdb_printf("Oplock Timeout %d millisec\n",
+ smb_info.si.skc_oplock_timeout);
+ mdb_printf("Flush %sRequired\n",
+ (smb_info.si.skc_flush_required) ? "" : "Not ");
+ mdb_printf("Sync %s\n",
+ (smb_info.si.skc_sync_enable) ? "Enabled" : "Disabled");
+ mdb_printf("Dir Symlink %s\n",
+ (smb_info.si.skc_dirsymlink_enable) ?
+ "Enabled" : "Disabled");
+ mdb_printf("%sAnnounce Quota\n",
+ (smb_info.si.skc_announce_quota) ? "" : "Do Not ");
+ mdb_printf("Security Mode %d\n", smb_info.si.skc_secmode);
+ mdb_printf("LM Level %d\n", smb_info.si.skc_lmlevel);
+ mdb_printf("Domain %s\n", smb_info.si.skc_resource_domain);
+ mdb_printf("Hostname %s\n", smb_info.si.skc_hostname);
+ mdb_printf("Comment %s\n", smb_info.si.skc_system_comment);
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ mdb_printf("\n");
+ }
+
+ return (DCMD_OK);
+}
+
+static void
+smb_lookup_svc_state_str(smb_svcstate_t state, char *dst_str, int slen)
+{
+ GElf_Sym smb_statename_table_sym;
+ uintptr_t statename_addr_addr, statename_addr;
+
+ if (mdb_lookup_by_name("smb_svcstate_state_name",
+ &smb_statename_table_sym)) {
+ (void) mdb_snprintf(dst_str, slen, "UNKNOWN");
+ return;
+ }
+
+ /* Lookup state string */
+ statename_addr_addr = smb_statename_table_sym.st_value +
+ (state * sizeof (uintptr_t));
+ if (mdb_vread(&statename_addr, sizeof (uintptr_t),
+ statename_addr_addr) == -1) {
+ (void) mdb_snprintf(dst_str, slen, "UNKNOWN");
+ return;
+ } else {
+ if (mdb_readstr(dst_str, slen, statename_addr) == -1) {
+ (void) mdb_snprintf(dst_str, slen, "UNKNOWN");
+ return;
+ }
+ }
+}
+
+static void
+smb_node_help(void)
+{
+ mdb_printf(
+ "Display the contents of smb_node_t, with optional filtering.\n\n");
+ mdb_dec_indent(2);
+ mdb_printf("%<b>OPTIONS%</b>\n");
+ mdb_inc_indent(2);
+ mdb_printf(
+ "-v\tDisplay verbose smb_node information\n"
+ "-p\tDisplay the full path of the vnode associated\n"
+ "-s\tDisplay the stack of the last 16 calls that modified the "
+ "reference\n\tcount\n");
+}
+
+/*
+ * ::smb_node
+ *
+ * smb_node dcmd - Print out smb_node structure.
+ */
+/*ARGSUSED*/
+static int
+smb_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ smb_node_t node;
+ int verbose = FALSE;
+ int print_full_path = FALSE;
+ int stack_trace = FALSE;
+ vnode_t vnode;
+ char od_name[MAXNAMELEN];
+ char path_name[1024];
+ uintptr_t list_addr;
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, TRUE, &verbose,
+ 'p', MDB_OPT_SETBITS, TRUE, &print_full_path,
+ 's', MDB_OPT_SETBITS, TRUE, &stack_trace,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ /*
+ * If no smb_node address was specified on the command line, we can
+ * print out all smb nodes by invoking the smb_node walker, using
+ * this dcmd itself as the callback.
+ */
+ if (!(flags & DCMD_ADDRSPEC)) {
+ if (mdb_walk_dcmd("smb_node", "smb_node",
+ argc, argv) == -1) {
+ mdb_warn("failed to walk 'smb_node'");
+ return (DCMD_ERR);
+ }
+ return (DCMD_OK);
+ }
+
+ /*
+ * If this is the first invocation of the command, print a nice
+ * header line for the output that will follow.
+ */
+ if (DCMD_HDRSPEC(flags)) {
+ if (verbose)
+ mdb_printf("SMB node information:\n\n");
+ else
+ mdb_printf("%<u>%?s %?s %18s %6s %5s %4s%</u>\n",
+ "SMB Nodes:", "VP", "NODE NAME",
+ "OFILES", "LOCKS", "REF");
+ }
+
+ /*
+ * For each smb_node, we just need to read the smb_node_t struct,
+ * read and then print out the following fields.
+ */
+ if (mdb_vread(&node, sizeof (node), addr) == sizeof (node)) {
+ (void) mdb_snprintf(od_name, MAXNAMELEN, "%s", node.od_name);
+ if (print_full_path) {
+ if (mdb_vread(&vnode, sizeof (vnode_t),
+ (uintptr_t)node.vp) ==
+ sizeof (vnode_t)) {
+ if (mdb_readstr(path_name, 1024,
+ (uintptr_t)vnode.v_path) != 0) {
+ (void) mdb_snprintf(od_name,
+ MAXNAMELEN, "N/A");
+ }
+ }
+ }
+ if (verbose) {
+ mdb_printf("VP :\t%p\n",
+ node.vp);
+ mdb_printf("Name :\t%s\n",
+ od_name);
+ if (print_full_path) {
+ mdb_printf("V-node Path :\t%s\n",
+ path_name);
+ }
+ mdb_printf("Ofiles :\t%u\n",
+ node.n_ofile_list.ll_count);
+ mdb_printf("Range Locks :\t%u\n",
+ node.n_lock_list.ll_count);
+ if (node.n_lock_list.ll_count != 0) {
+ (void) mdb_inc_indent(SMB_DCMD_INDENT);
+ list_addr = addr +
+ offsetof(smb_node_t, n_lock_list) +
+ offsetof(smb_llist_t, ll_list);
+ if (mdb_pwalk_dcmd("list", "smb_lock",
+ 0, NULL, list_addr)) {
+ mdb_warn("failed to walk node's active"
+ " locks");
+ }
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ }
+ mdb_printf("Reference Count :\t%u\n",
+ node.n_refcnt);
+ mdb_printf("\n");
+ } else {
+ mdb_printf("%?p %?p %18s %5d %5d %4d\n",
+ addr, node.vp, od_name, node.n_ofile_list.ll_count,
+ node.n_lock_list.ll_count, node.n_refcnt);
+ if (print_full_path) {
+ if (mdb_vread(&vnode, sizeof (vnode_t),
+ (uintptr_t)node.vp) ==
+ sizeof (vnode_t)) {
+ if (mdb_readstr(path_name, 1024,
+ (uintptr_t)vnode.v_path)) {
+ mdb_printf("\t%s\n",
+ path_name);
+ }
+ }
+ }
+ }
+ if (stack_trace && node.n_audit_buf) {
+ int ctr;
+ smb_audit_buf_node_t *anb;
+
+ anb = mdb_alloc(sizeof (smb_audit_buf_node_t),
+ UM_SLEEP);
+
+ if (mdb_vread(anb, sizeof (*anb),
+ (uintptr_t)node.n_audit_buf) != sizeof (*anb)) {
+ mdb_free(anb, sizeof (smb_audit_buf_node_t));
+ mdb_warn("failed to read audit buffer");
+ return (DCMD_ERR);
+ }
+ ctr = anb->anb_max_index + 1;
+ anb->anb_index--;
+ anb->anb_index &= anb->anb_max_index;
+
+ while (ctr) {
+ smb_audit_record_node_t *anr;
+
+ anr = anb->anb_records + anb->anb_index;
+
+ if (anr->anr_depth) {
+ char c[MDB_SYM_NAMLEN];
+ GElf_Sym sym;
+ int i;
+
+ mdb_printf("\nRefCnt: %u\t",
+ anr->anr_refcnt);
+
+ for (i = 0;
+ i < anr->anr_depth;
+ i++) {
+ if (mdb_lookup_by_addr(
+ anr->anr_stack[i],
+ MDB_SYM_FUZZY,
+ c, sizeof (c),
+ &sym) == -1) {
+ continue;
+ }
+ mdb_printf("%s+0x%1x",
+ c,
+ anr->anr_stack[i] -
+ (uintptr_t)sym.st_value);
+ ++i;
+ break;
+ }
+
+ while (i < anr->anr_depth) {
+ if (mdb_lookup_by_addr(
+ anr->anr_stack[i],
+ MDB_SYM_FUZZY,
+ c, sizeof (c),
+ &sym) == -1) {
+ ++i;
+ continue;
+ }
+ mdb_printf("\n\t\t%s+0x%1x",
+ c,
+ anr->anr_stack[i] -
+ (uintptr_t)sym.st_value);
+ ++i;
+ }
+ mdb_printf("\n");
+ }
+ anb->anb_index--;
+ anb->anb_index &= anb->anb_max_index;
+ ctr--;
+ }
+ mdb_free(anb, sizeof (smb_audit_buf_node_t));
+ }
+ } else {
+ mdb_warn("failed to read struct smb_node at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+static void
+smb_session_help(void)
+{
+ mdb_printf(
+ "Display the contents of smb_session_t, with optional"
+ " filtering.\n\n");
+ mdb_dec_indent(2);
+ mdb_printf("%<b>OPTIONS%</b>\n");
+ mdb_inc_indent(2);
+ mdb_printf(
+ "-v\tDisplay verbose smb_session information\n"
+ "-r\tDisplay the list of smb requests attached\n"
+ "-u\tDisplay the list of users attached\n");
+}
+
+/*
+ * ::smb_session
+ *
+ * smb_session dcmd - Print out the smb_session structure.
+ */
+/*ARGSUSED*/
+static int
+smb_session(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ smb_session_t session;
+ int print_requests = FALSE;
+ int print_users = FALSE;
+ int verbose = FALSE;
+ uintptr_t list_addr;
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, TRUE, &verbose,
+ 'r', MDB_OPT_SETBITS, TRUE, &print_requests,
+ 'u', MDB_OPT_SETBITS, TRUE, &print_users,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ /*
+ * If no smb_session address was specified on the command line, we can
+ * print out all smb sessions by invoking the smb_session walker, using
+ * this dcmd itself as the callback.
+ */
+ if (!(flags & DCMD_ADDRSPEC)) {
+ if (mdb_walk_dcmd("smb_session", "smb_session",
+ argc, argv) == -1) {
+ mdb_warn("failed to walk 'smb_session'");
+ return (DCMD_ERR);
+ }
+ return (DCMD_OK);
+ }
+
+ /*
+ * If this is the first invocation of the command, print a nice
+ * header line for the output that will follow.
+ */
+ if (DCMD_HDRSPEC(flags)) {
+ if (verbose)
+ mdb_printf("SMB session information:\n\n");
+ else
+ mdb_printf("%<u>%-?s %16s %16s %5s %10s%</u>\n",
+ "Sessions:", "CLIENT_IP_ADDR", "LOCAL_IP_ADDR",
+ "KID", "STATE");
+ }
+
+ /*
+ * For each smb_session, we just need to read the smb_session_t struct,
+ * read and then print out the following fields.
+ */
+ if (mdb_vread(&session, sizeof (session), addr) == sizeof (session)) {
+ if (verbose) {
+ mdb_printf("IP address :\t%I\n",
+ session.ipaddr);
+ mdb_printf("Local IP Address:\t%I\n",
+ session.local_ipaddr);
+ mdb_printf("Session KID :\t%u\n",
+ session.s_kid);
+ mdb_printf("Workstation Name:\t%s\n",
+ session.workstation);
+ mdb_printf("Session state :\t%u\n",
+ session.s_state);
+ mdb_printf("users :\t%u\n",
+ session.s_user_list.ll_count);
+ mdb_printf("trees :\t%u\n",
+ session.s_tree_cnt);
+ mdb_printf("files :\t%u\n",
+ session.s_file_cnt);
+ mdb_printf("shares :\t%u\n",
+ session.s_dir_cnt);
+ mdb_printf("xa count :\t%u\n\n",
+ session.s_xa_list.ll_count);
+ mdb_printf("\n");
+ } else {
+ mdb_printf("%?p %16I %16I %5u %10u\n", addr,
+ session.ipaddr, session.local_ipaddr,
+ session.s_kid, session.s_state);
+ }
+ } else {
+ mdb_warn("failed to read struct smb_session at %p", &session);
+ return (DCMD_ERR);
+ }
+
+ if (print_requests) {
+ (void) mdb_inc_indent(SMB_DCMD_INDENT);
+ list_addr = addr + offsetof(smb_session_t, s_req_list) +
+ offsetof(smb_slist_t, sl_list);
+ if (mdb_pwalk_dcmd("list", "smb_request", 0, NULL, list_addr)) {
+ mdb_warn("failed to walk request list\n");
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ return (DCMD_ERR);
+ }
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ }
+
+ if (print_users) {
+ (void) mdb_inc_indent(SMB_DCMD_INDENT);
+ list_addr = addr + offsetof(smb_session_t, s_user_list) +
+ offsetof(smb_llist_t, ll_list);
+ if (mdb_pwalk_dcmd("list", "smb_user", 0, NULL, list_addr)) {
+ mdb_warn("failed to walk user list\n");
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ return (DCMD_ERR);
+ }
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ }
+
+ return (DCMD_OK);
+}
+
+static int
+smb_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ smb_request_t request;
+ int verbose = FALSE;
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, TRUE, &verbose,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ /*
+ * An smb_requets_t address must be specified.
+ */
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ /*
+ * If this is the first invocation of the command, print a nice
+ * header line for the output that will follow.
+ */
+ if (DCMD_HDRSPEC(flags)) {
+ if (verbose)
+ mdb_printf("SMB request information:\n\n");
+ else
+ mdb_printf("%<u>%-?s %4s %6s %4s %4s %4s %4s%</u>\n",
+ "Requests: ", "COM", "STATE",
+ "TID", "PID", "UID", "MID");
+ }
+
+ if (mdb_vread(&request, sizeof (request), addr) == sizeof (request)) {
+ if (verbose) {
+ mdb_printf("First SMB COM :\t%I\n",
+ request.first_smb_com);
+ mdb_printf("State :\t%I\n",
+ request.sr_state);
+ mdb_printf("Tree ID :\t%u\n",
+ request.smb_tid);
+ mdb_printf("Process ID :\t%u\n",
+ request.smb_pid);
+ mdb_printf("User ID :\t%u\n",
+ request.smb_uid);
+ mdb_printf("Multiplex ID :\t%u\n",
+ request.smb_mid);
+ mdb_printf("\n");
+ } else {
+ mdb_printf("%?p %04x %6x %04x %04x %04x"
+ " %04x\n", addr,
+ request.first_smb_com, request.sr_state,
+ request.smb_tid, request.smb_pid,
+ request.smb_uid, request.smb_mid);
+ }
+ } else {
+ mdb_warn("failed to read struct smb_request at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+static int
+smb_lock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ smb_lock_t lock;
+ int verbose = FALSE;
+ uintptr_t list_addr;
+ char *lock_type;
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, TRUE, &verbose,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ /*
+ * An smb_lock_t address must be specified.
+ */
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ /*
+ * If this is the first invocation of the command, print a nice
+ * header line for the output that will follow.
+ */
+ if (DCMD_HDRSPEC(flags)) {
+ if (verbose)
+ mdb_printf("SMB lock information:\n\n");
+ else
+ mdb_printf("%<u>%-?s %4s %16s %8s %9s%</u>\n",
+ "Locks: ", "TYPE", "START", "LENGTH",
+ "CONFLICTS");
+ }
+
+ if (mdb_vread(&lock, sizeof (lock), addr) == sizeof (lock)) {
+ switch (lock.l_type) {
+ case SMB_LOCK_TYPE_READWRITE:
+ lock_type = "RW";
+ break;
+ case SMB_LOCK_TYPE_READONLY:
+ lock_type = "RO";
+ break;
+ default:
+ lock_type = "N/A";
+ break;
+ }
+ if (verbose) {
+ mdb_printf("Type :\t%s (%u)\n",
+ lock_type, lock.l_type);
+ mdb_printf("Start :\t%llx\n",
+ lock.l_start);
+ mdb_printf("Length :\t%lx\n",
+ lock.l_length);
+ mdb_printf("Session :\t%p\n",
+ lock.l_session);
+ mdb_printf("File :\t%p\n",
+ lock.l_file);
+ mdb_printf("User ID :\t%u\n",
+ lock.l_uid);
+ mdb_printf("Process ID :\t%u\n",
+ lock.l_pid);
+ mdb_printf("Conflicts :\t%u\n",
+ lock.l_conflict_list.sl_count);
+ if (lock.l_conflict_list.sl_count != 0) {
+ (void) mdb_inc_indent(SMB_DCMD_INDENT);
+ list_addr = addr +
+ offsetof(smb_lock_t, l_conflict_list) +
+ offsetof(smb_slist_t, sl_list);
+ if (mdb_pwalk_dcmd("list", "smb_lock",
+ 0, NULL, list_addr)) {
+ mdb_warn("failed to walk conflict "
+ "locks ");
+ }
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ }
+ mdb_printf("Blocked by :\t%p\n",
+ lock.l_blocked_by);
+ mdb_printf("Flags :\t0x%x\n",
+ lock.l_flags);
+ mdb_printf("\n");
+ } else {
+ mdb_printf("%?p %4s %16llx %08lx %9x", addr,
+ lock_type, lock.l_start, lock.l_length,
+ lock.l_conflict_list.sl_count);
+ }
+ } else {
+ mdb_warn("failed to read struct smb_request at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+static void
+smb_user_help(void)
+{
+ mdb_printf(
+ "Display the contents of smb_user_t, with optional filtering.\n\n");
+ mdb_dec_indent(2);
+ mdb_printf("%<b>OPTIONS%</b>\n");
+ mdb_inc_indent(2);
+ mdb_printf(
+ "-v\tDisplay verbose smb_user information\n"
+ "-q\tDon't Display the contents of the smb_user. This option "
+ "should be\n\tused in conjunction with -d or -f\n"
+ "-d\tDisplay the list of smb_odirs attached\n"
+ "-f\tDisplay the list of smb_ofiles attached\n"
+ "-t\tDisplay the list of smb_trees attached\n");
+}
+
+static int
+smb_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ smb_user_t user;
+ int print_odir = FALSE;
+ int print_ofile = FALSE;
+ int print_tree = FALSE;
+ int verbose = FALSE;
+ int quiet = FALSE;
+ uintptr_t list_addr;
+ int new_argc;
+ mdb_arg_t new_argv[3];
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, TRUE, &verbose,
+ 'q', MDB_OPT_SETBITS, TRUE, &quiet,
+ 'd', MDB_OPT_SETBITS, TRUE, &print_odir,
+ 'f', MDB_OPT_SETBITS, TRUE, &print_ofile,
+ 't', MDB_OPT_SETBITS, TRUE, &print_tree,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ /*
+ * An smb_user address must be specified on the command line.
+ */
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ /*
+ * If this is the first invocation of the command, print a nice
+ * header line for the output that will follow.
+ */
+ if (DCMD_HDRSPEC(flags) && !quiet) {
+ if (verbose)
+ mdb_printf("SMB user information:\n\n");
+ else
+ mdb_printf("%<u>%-?s %4s %6s %8s %16s %8s %s%</u>\n",
+ "Users:", "UID", "STATE", "FLAGS", "CRED",
+ "REFCNT", "ACCOUNT");
+ }
+
+ if (mdb_vread(&user, sizeof (user), addr) != sizeof (user)) {
+ mdb_warn("failed to read struct smb_user at %?p", addr);
+ return (DCMD_ERR);
+ }
+
+ if (!quiet) {
+ char domain[SMB_PI_MAX_DOMAIN];
+ char account[SMB_PI_MAX_USERNAME];
+ int valid_domain = 0, valid_account = 0;
+
+ if (mdb_vread(domain, user.u_domain_len,
+ (uintptr_t)user.u_domain) == user.u_domain_len)
+ valid_domain = 1;
+ if (mdb_vread(account, user.u_name_len,
+ (uintptr_t)user.u_name) == user.u_name_len)
+ valid_account = 1;
+
+ if (verbose) {
+ mdb_printf("User ID :\t%04x\n",
+ user.u_uid);
+ mdb_printf("State :\t%d\n",
+ user.u_state);
+ mdb_printf("Flags :\t%08x\n",
+ user.u_flags);
+ mdb_printf("Privileges :\t%08x\n",
+ user.u_privileges);
+ mdb_printf("Credential :\t%llx\n",
+ user.u_cred);
+ mdb_printf("Reference Count :\t%d\n",
+ user.u_refcnt);
+ if (valid_domain && valid_account)
+ mdb_printf("User Account :\t%s\\%s\n",
+ domain, account);
+ mdb_printf("\n");
+ } else {
+ mdb_printf("%?p %04x %6d %08x %?p %8d %s\\%s\n",
+ addr, user.u_uid, user.u_state, user.u_flags,
+ user.u_cred, user.u_refcnt,
+ valid_domain ? domain : "UNKNOWN",
+ valid_account ? account : "UNKNOWN");
+ }
+ }
+
+ new_argc = 0;
+ if (!print_tree) {
+ new_argv[new_argc].a_type = MDB_TYPE_STRING;
+ new_argv[new_argc].a_un.a_str = "-q";
+ new_argc++;
+ }
+ if (print_ofile) {
+ new_argv[new_argc].a_type = MDB_TYPE_STRING;
+ new_argv[new_argc].a_un.a_str = "-f";
+ new_argc++;
+ }
+ if (print_odir) {
+ new_argv[new_argc].a_type = MDB_TYPE_STRING;
+ new_argv[new_argc].a_un.a_str = "-d";
+ new_argc++;
+ }
+
+ if (print_tree || print_ofile || print_odir) {
+ (void) mdb_inc_indent(SMB_DCMD_INDENT);
+ list_addr = addr + offsetof(smb_user_t, u_tree_list) +
+ offsetof(smb_llist_t, ll_list);
+ if (mdb_pwalk_dcmd("list", "smb_tree", new_argc, new_argv,
+ list_addr)) {
+ mdb_warn("failed to walk tree list\n");
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ return (DCMD_ERR);
+ }
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ }
+
+ return (DCMD_OK);
+}
+
+static void
+smb_tree_help(void)
+{
+ mdb_printf(
+ "Display the contents of smb_tree_t, with optional filtering.\n\n");
+ mdb_dec_indent(2);
+ mdb_printf("%<b>OPTIONS%</b>\n");
+ mdb_inc_indent(2);
+ mdb_printf(
+ "-v\tDisplay verbose smb_tree information\n"
+ "-q\tDon't Display the contents of the smb_tree. This option "
+ "should be\n\tused in conjunction with -d or -f\n"
+ "-d\tDisplay the list of smb_odirs attached\n"
+ "-f\tDisplay the list of smb_ofiles attached\n");
+}
+
+static int
+smb_tree(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ smb_tree_t tree;
+ int print_odir = FALSE;
+ int print_ofile = FALSE;
+ int verbose = FALSE;
+ int quiet = FALSE;
+ uintptr_t list_addr;
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, TRUE, &verbose,
+ 'd', MDB_OPT_SETBITS, TRUE, &print_odir,
+ 'f', MDB_OPT_SETBITS, TRUE, &print_ofile,
+ 'q', MDB_OPT_SETBITS, TRUE, &quiet,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ /*
+ * If no smb_session address was specified on the command line, we can
+ * print out all smb sessions by invoking the smb_session walker, using
+ * this dcmd itself as the callback.
+ */
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ /*
+ * If this is the first invocation of the command, print a nice
+ * header line for the output that will follow.
+ */
+ if (DCMD_HDRSPEC(flags)) {
+ if (verbose)
+ mdb_printf("SMB tree information:\n\n");
+ else
+ mdb_printf("%<u>%-?s %4s %6s %16s %10s%</u>\n",
+ "Trees:", "TID", "STATE", "SMB NODE",
+ "SHARE NAME");
+ }
+
+ /*
+ * Read tree and print some of the fields
+ */
+ if (mdb_vread(&tree, sizeof (tree), addr) != sizeof (tree)) {
+ mdb_warn("failed to read struct smb_tree at %p", addr);
+ return (DCMD_ERR);
+ }
+ if (!quiet) {
+ if (verbose) {
+ mdb_printf("Tree ID :\t%04x\n",
+ tree.t_tid);
+ mdb_printf("State :\t%d\n",
+ tree.t_state);
+ mdb_printf("Share name :\t%s\n",
+ tree.t_sharename);
+ mdb_printf("Resource :\t%s\n",
+ tree.t_resource);
+ mdb_printf("Umask :\t%04x\n",
+ tree.t_umask);
+ mdb_printf("Access :\t%04x\n",
+ tree.t_access);
+ mdb_printf("Flags :\t%08x\n",
+ tree.t_flags);
+ mdb_printf("SMB Node :\t%llx\n",
+ tree.t_snode);
+ mdb_printf("Reference Count :\t%d\n",
+ tree.t_refcnt);
+ mdb_printf("\n");
+ } else {
+ mdb_printf("%?p %04x %6d %16llx %s\n", addr,
+ tree.t_tid, tree.t_state, tree.t_snode,
+ tree.t_sharename);
+ }
+ }
+
+ if (print_odir) {
+ (void) mdb_inc_indent(SMB_DCMD_INDENT);
+ list_addr = addr + offsetof(smb_tree_t, t_odir_list) +
+ offsetof(smb_llist_t, ll_list);
+ if (mdb_pwalk_dcmd("list", "smb_odir", 0, NULL, list_addr)) {
+ mdb_warn("failed to walk odir list\n");
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ return (DCMD_ERR);
+ }
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ }
+
+ if (print_ofile) {
+ (void) mdb_inc_indent(SMB_DCMD_INDENT);
+ list_addr = addr + offsetof(smb_tree_t, t_ofile_list) +
+ offsetof(smb_llist_t, ll_list);
+ if (mdb_pwalk_dcmd("list", "smb_ofile", 0, NULL, list_addr)) {
+ mdb_warn("failed to walk ofile list\n");
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ return (DCMD_ERR);
+ }
+ (void) mdb_dec_indent(SMB_DCMD_INDENT);
+ }
+
+ return (DCMD_OK);
+}
+
+static int
+smb_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ smb_odir_t odir;
+ int verbose = FALSE;
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, TRUE, &verbose,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ /*
+ * If no smb_session address was specified on the command line, we can
+ * print out all smb sessions by invoking the smb_session walker, using
+ * this dcmd itself as the callback.
+ */
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ /*
+ * If this is the first invocation of the command, print a nice
+ * header line for the output that will follow.
+ */
+ if (DCMD_HDRSPEC(flags)) {
+ if (verbose)
+ mdb_printf("SMB odir information:\n\n");
+ else
+ mdb_printf("%<u>%-?s %8s %?s %10s%</u>\n",
+ "odir:", "STATE", "SMB NODE", "PATTERN");
+ }
+
+ /*
+ * For each smb_session, we just need to read the smb_session_t struct,
+ * read and then print out the following fields.
+ */
+ if (mdb_vread(&odir, sizeof (odir), addr) == sizeof (odir)) {
+ if (verbose) {
+ mdb_printf("State :\t%d\n",
+ odir.d_state);
+ mdb_printf("Pattern :\t%s\n",
+ odir.d_pattern);
+ mdb_printf("SMB Node :\t%s\n",
+ odir.d_dir_snode);
+ mdb_printf("\n");
+ } else {
+ mdb_printf("%?p %8d %16llx %s\n", addr,
+ odir.d_state, odir.d_dir_snode, odir.d_pattern);
+ }
+ } else {
+ mdb_warn("failed to read struct smb_odir at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+static int
+smb_ofile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ smb_ofile_t ofile;
+ int verbose = FALSE;
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, TRUE, &verbose,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ /*
+ * If no smb_session address was specified on the command line, we can
+ * print out all smb sessions by invoking the smb_session walker, using
+ * this dcmd itself as the callback.
+ */
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ /*
+ * If this is the first invocation of the command, print a nice
+ * header line for the output that will follow.
+ */
+ if (DCMD_HDRSPEC(flags)) {
+ if (verbose)
+ mdb_printf("SMB ofile information:\n\n");
+ else
+ mdb_printf("%<u>%-?s %04s %8s %?s %8s %?s%</u>\n",
+ "ofiles:", "FID", "STATE", "SMB NODE", "FLAGS",
+ "CRED");
+ }
+
+ /*
+ * For each smb_session, we just need to read the smb_session_t struct,
+ * read and then print out the following fields.
+ */
+ if (mdb_vread(&ofile, sizeof (ofile), addr) == sizeof (ofile)) {
+ if (verbose) {
+ mdb_printf("Ofile ID :\t%04x\n",
+ ofile.f_fid);
+ mdb_printf("State :\t%d\n",
+ ofile.f_state);
+ mdb_printf("SMB Node :\t%llx\n",
+ ofile.f_node);
+ mdb_printf("LLF Offset :\t%llx (%s)\n",
+ ofile.f_llf_pos,
+ ((ofile.f_flags & SMB_OFLAGS_LLF_POS_VALID) ?
+ "Valid" : "Invalid"));
+ mdb_printf("FLAGS :\t%08x\n",
+ ofile.f_flags);
+ mdb_printf("Credential :\t%llx\n",
+ ofile.f_cr);
+ mdb_printf("\n");
+ } else {
+ mdb_printf("%?p %04x %8d %16llx %08x %?\n", addr,
+ ofile.f_fid, ofile.f_state, ofile.f_node,
+ ofile.f_flags, ofile.f_cr);
+ }
+ } else {
+ mdb_warn("failed to read struct smb_odir at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+
+/*
+ * ::smb_dispatch_stats
+ *
+ * smb_dispatch_stats dcmd - Prints all dispatched SMB requests statistics.
+ */
+/*ARGSUSED*/
+static int
+smb_stats(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ smb_dispatch_table_t *disp;
+ GElf_Sym sym;
+ int nstats = 0, i;
+
+ if ((flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "dispatch", &sym)) {
+ mdb_warn("failed to find dispatch object");
+ return (DCMD_ERR);
+ }
+
+ disp = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
+ if (mdb_vread(disp, sym.st_size, sym.st_value) == -1) {
+ mdb_warn("failed to read from dispatch object");
+ return (DCMD_ERR);
+ }
+
+ nstats = sym.st_size / sizeof (smb_dispatch_table_t);
+
+ mdb_printf("All dispatched SMB requests statistics:\n\n");
+ for (i = 0; i < nstats; i++) {
+ if (disp[i].sdt_function)
+ mdb_printf(" %40s\t: %lld\n",
+ disp[i].sdt_dispatch_stats.name,
+ disp[i].sdt_dispatch_stats.value.ui64);
+ }
+ return (DCMD_OK);
+}
+
+/*
+ * MDB module linkage information:
+ *
+ * We declare a list of structures describing our dcmds, a list of structures
+ * describing our walkers and a function named _mdb_init to return a pointer
+ * to our module information.
+ */
+static const mdb_dcmd_t dcmds[] = {
+ { "smb_info", "[-c]",
+ "print smb_info information", smb_information },
+ { "smb_node", "?[-vps]",
+ "print smb_node_t information", smb_node, smb_node_help },
+ { "smb_session", "?[-vru]",
+ "print smb_session_t information", smb_session, smb_session_help},
+ { "smb_request", ":[-v]",
+ "print smb_request_t information", smb_request },
+ { "smb_lock", ":[-v]",
+ "print smb_lock_t information", smb_lock },
+ { "smb_user", ":[-vdftq]",
+ "print smb_user_t information", smb_user, smb_user_help },
+ { "smb_tree", ":[-vdfq]",
+ "print smb_tree_t information", smb_tree, smb_tree_help },
+ { "smb_odir", ":[-v]",
+ "print smb_odir_t information", smb_odir },
+ { "smb_ofile", "[-v]",
+ "print smb_odir_t information", smb_ofile },
+ { "smb_stats", NULL,
+ "print all smb dispatched requests statistics",
+ smb_stats },
+ { NULL }
+};
+
+static const mdb_walker_t walkers[] = {
+ { "smb_session", "walk list of smb_session_t structures",
+ smb_session_walk_init, smb_session_walk_step,
+ NULL },
+ { "smb_node", "walk list of smb_node_t structures",
+ smb_node_walk_init, smb_node_walk_step,
+ NULL },
+ { NULL }
+};
+
+static const mdb_modinfo_t modinfo = {
+ MDB_API_VERSION, dcmds, walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+ return (&modinfo);
+}
diff --git a/usr/src/cmd/mdb/intel/amd64/smbsrv/Makefile b/usr/src/cmd/mdb/intel/amd64/smbsrv/Makefile
new file mode 100644
index 0000000000..88449863b2
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/amd64/smbsrv/Makefile
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+MODULE = smbsrv.so
+MDBTGT = kvm
+
+MODSRCS = smbsrv.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
diff --git a/usr/src/cmd/mdb/intel/ia32/smbsrv/Makefile b/usr/src/cmd/mdb/intel/ia32/smbsrv/Makefile
new file mode 100644
index 0000000000..c98245d4e1
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/ia32/smbsrv/Makefile
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+MODULE = smbsrv.so
+MDBTGT = kvm
+
+MODSRCS = smbsrv.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
diff --git a/usr/src/cmd/mdb/sparc/v9/smbsrv/Makefile b/usr/src/cmd/mdb/sparc/v9/smbsrv/Makefile
new file mode 100644
index 0000000000..3fe1397e49
--- /dev/null
+++ b/usr/src/cmd/mdb/sparc/v9/smbsrv/Makefile
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+MODULE = smbsrv.so
+MDBTGT = kvm
+
+MODSRCS = smbsrv.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.sparcv9
+include ../../../Makefile.module
diff --git a/usr/src/cmd/mv/Makefile b/usr/src/cmd/mv/Makefile
index 277d5b1bd1..fa86f295c2 100644
--- a/usr/src/cmd/mv/Makefile
+++ b/usr/src/cmd/mv/Makefile
@@ -47,9 +47,9 @@ LINTFLAGS += -DXPG4 -u
XGETFLAGS += -a -x mv.xcl
CPPFLAGS += -D_FILE_OFFSET_BITS=64 -I $(SRC)/common/util
-lint := LDLIBS += -lcmdutils -lavl -lsec
-$(PROG) := LDLIBS += $(ZLAZYLOAD) -lcmdutils -lavl -lsec $(ZNOLAZYLOAD)
-$(XPG4) := LDLIBS += $(ZLAZYLOAD) -lcmdutils -lavl -lsec $(ZNOLAZYLOAD)
+lint := LDLIBS += -lcmdutils -lavl -lsec -lnvpair
+$(PROG) := LDLIBS += $(ZLAZYLOAD) -lcmdutils -lavl -lsec -lnvpair $(ZNOLAZYLOAD)
+$(XPG4) := LDLIBS += $(ZLAZYLOAD) -lcmdutils -lavl -lsec -lnvpair $(ZNOLAZYLOAD)
.KEEP_STATE:
diff --git a/usr/src/cmd/mv/mv.c b/usr/src/cmd/mv/mv.c
index 1f4d4fb23c..8558125312 100644
--- a/usr/src/cmd/mv/mv.c
+++ b/usr/src/cmd/mv/mv.c
@@ -44,22 +44,10 @@
* mv dir1 dir2
* mv file1 ... filen dir1
*/
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/avl.h>
-#include <sys/mman.h>
-#include <fcntl.h>
#include <sys/time.h>
#include <signal.h>
-#include <errno.h>
-#include <dirent.h>
-#include <stdlib.h>
#include <locale.h>
#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <limits.h>
#include <sys/acl.h>
#include <libcmdutils.h>
#include <aclutils.h>
@@ -107,14 +95,13 @@ static int getrealpath(char *, char *);
static void usage(void);
static void Perror(char *);
static void Perror2(char *, char *);
-static int writefile(int, int, char *, char *,
- struct stat *, struct stat *);
static int use_stdin(void);
static int copyattributes(char *, char *);
+static int copy_sysattr(char *, char *);
static void timestruc_to_timeval(timestruc_t *, struct timeval *);
static tree_node_t *create_tnode(dev_t, ino_t);
-static struct stat s1, s2;
+static struct stat s1, s2, s3, s4;
static int cpy = FALSE;
static int mve = FALSE;
static int lnk = FALSE;
@@ -135,6 +122,25 @@ static int targetexists = 0;
static int cmdarg; /* command line argument */
static avl_tree_t *stree = NULL; /* source file inode search tree */
static acl_t *s1acl;
+static int saflg = 0; /* 'cp' extended system attr. */
+static int srcfd;
+static int targfd;
+static int sourcedirfd;
+static int targetdirfd;
+static DIR *srcdirp;
+static int srcattrfd;
+static int targattrfd;
+static struct stat attrdir;
+
+/* Extended system attributes support */
+
+static int open_source(char *);
+static int open_target_srctarg_attrdirs(char *, char *);
+static int open_attrdirp(char *);
+static int traverse_attrfile(struct dirent *, char *, char *, int);
+static void rewind_attrdir(DIR *);
+static void close_all();
+
int
main(int argc, char *argv[])
@@ -182,8 +188,8 @@ main(int argc, char *argv[])
/*
* Check for options:
- * cp -r|-R [-H|-L|-P] [-fip@] file1 [file2 ...] target
- * cp [-fiprR@] file1 [file2 ...] target
+ * cp -r|-R [-H|-L|-P] [-fip@/] file1 [file2 ...] target
+ * cp [-fiprR@/] file1 [file2 ...] target
* ln [-f] [-n] [-s] file1 [file2 ...] target
* ln [-f] [-n] [-s] file1 [file2 ...]
* mv [-f|i] file1 [file2 ...] target
@@ -191,7 +197,7 @@ main(int argc, char *argv[])
*/
if (cpy) {
- while ((c = getopt(argc, argv, "fHiLpPrR@")) != EOF)
+ while ((c = getopt(argc, argv, "fHiLpPrR@/")) != EOF)
switch (c) {
case 'f':
fflg++;
@@ -204,8 +210,9 @@ main(int argc, char *argv[])
#ifdef XPG4
attrsilent = 1;
atflg = 0;
+ saflg = 0;
#else
- if (atflg == 0)
+ if ((atflg == 0) && (saflg == 0))
attrsilent = 1;
#endif
break;
@@ -244,6 +251,13 @@ main(int argc, char *argv[])
pflg = 0;
#endif
break;
+ case '/':
+ saflg++;
+ attrsilent = 0;
+#ifdef XPG4
+ pflg = 0;
+#endif
+ break;
default:
errflg++;
}
@@ -491,6 +505,7 @@ cpymve(char *source, char *target)
int fi, fo;
int ret = 0;
int attret = 0;
+ int sattret = 0;
int errno_save;
switch (chkfiles(source, &target)) {
@@ -831,8 +846,8 @@ copy:
return (1);
}
- if (writefile(fi, fo, source, target,
- &s1, &s2) != 0) {
+ if (writefile(fi, fo, source, target, NULL,
+ NULL, &s1, &s2) != 0) {
return (1);
}
@@ -842,8 +857,8 @@ copy:
return (1);
}
}
-
- if (pflg || atflg || mve) {
+ /* Copy regular extended attributes */
+ if (pflg || atflg || mve || saflg) {
attret = copyattributes(source, target);
if (attret != 0 && !attrsilent) {
(void) fprintf(stderr, gettext(
@@ -851,14 +866,25 @@ copy:
" extended attributes of file"
" %s\n"), cmd, source);
}
-
+ /* Copy extended system attributes */
+ if (pflg || mve || saflg) {
+ sattret = copy_sysattr(source, target);
+ if (sattret != 0 && !attrsilent) {
+ (void) fprintf(stderr, gettext(
+ "%s: Failed to preserve "
+ "extended system "
+ "attributes of file "
+ "%s\n"), cmd, source);
+ }
+ }
if (mve && attret != 0) {
(void) unlink(target);
return (1);
}
-
- if (attrsilent)
+ if (attrsilent) {
attret = 0;
+ sattret = 0;
+ }
}
/*
@@ -920,132 +946,6 @@ cleanup:
return (ret);
}
-static int
-writefile(int fi, int fo, char *source, char *target,
- struct stat *s1p, struct stat *s2p)
-{
- int mapsize, munmapsize;
- caddr_t cp;
- off_t filesize = s1p->st_size;
- off_t offset;
- int nbytes;
- int remains;
- int n;
-
- if (ISREG(*s1p) && s1p->st_size > SMALLFILESIZE) {
- /*
- * Determine size of initial mapping. This will determine the
- * size of the address space chunk we work with. This initial
- * mapping size will be used to perform munmap() in the future.
- */
- mapsize = MAXMAPSIZE;
- if (s1p->st_size < mapsize) mapsize = s1p->st_size;
- munmapsize = mapsize;
-
- /*
- * Mmap time!
- */
- if ((cp = mmap((caddr_t)NULL, mapsize, PROT_READ,
- MAP_SHARED, fi, (off_t)0)) == MAP_FAILED)
- mapsize = 0; /* can't mmap today */
- } else
- mapsize = 0;
-
- if (mapsize != 0) {
- offset = 0;
-
- for (;;) {
- nbytes = write(fo, cp, mapsize);
- /*
- * if we write less than the mmaped size it's due to a
- * media error on the input file or out of space on
- * the output file. So, try again, and look for errno.
- */
- if ((nbytes >= 0) && (nbytes != (int)mapsize)) {
- remains = mapsize - nbytes;
- while (remains > 0) {
- nbytes = write(fo,
- cp + mapsize - remains, remains);
- if (nbytes < 0) {
- if (errno == ENOSPC)
- Perror(target);
- else
- Perror(source);
- (void) close(fi);
- (void) close(fo);
- (void) munmap(cp, munmapsize);
- if (ISREG(*s2p))
- (void) unlink(target);
- return (1);
- }
- remains -= nbytes;
- if (remains == 0)
- nbytes = mapsize;
- }
- }
- /*
- * although the write manual page doesn't specify this
- * as a possible errno, it is set when the nfs read
- * via the mmap'ed file is accessed, so report the
- * problem as a source access problem, not a target file
- * problem
- */
- if (nbytes < 0) {
- if (errno == EACCES)
- Perror(source);
- else
- Perror(target);
- (void) close(fi);
- (void) close(fo);
- (void) munmap(cp, munmapsize);
- if (ISREG(*s2p))
- (void) unlink(target);
- return (1);
- }
- filesize -= nbytes;
- if (filesize == 0)
- break;
- offset += nbytes;
- if (filesize < mapsize)
- mapsize = filesize;
- if (mmap(cp, mapsize, PROT_READ, MAP_SHARED | MAP_FIXED,
- fi, offset) == MAP_FAILED) {
- Perror(source);
- (void) close(fi);
- (void) close(fo);
- (void) munmap(cp, munmapsize);
- if (ISREG(*s2p))
- (void) unlink(target);
- return (1);
- }
- }
- (void) munmap(cp, munmapsize);
- } else {
- char buf[SMALLFILESIZE];
- for (;;) {
- n = read(fi, buf, sizeof (buf));
- if (n == 0) {
- return (0);
- } else if (n < 0) {
- Perror2(source, "read");
- (void) close(fi);
- (void) close(fo);
- if (ISREG(*s2p))
- (void) unlink(target);
- return (1);
- } else if (write(fo, buf, n) != n) {
- Perror2(target, "write");
- (void) close(fi);
- (void) close(fo);
- if (ISREG(*s2p))
- (void) unlink(target);
- return (1);
- }
- }
- }
- return (0);
-}
-
/*
* create_tnode()
*
@@ -1415,9 +1315,9 @@ usage(void)
#endif
} else if (cpy) {
(void) fprintf(stderr, gettext(
- "Usage: cp [-f] [-i] [-p] [-@] f1 f2\n"
- " cp [-f] [-i] [-p] [-@] f1 ... fn d1\n"
- " cp -r|-R [-H|-L|-P] [-f] [-i] [-p] [-@] "
+ "Usage: cp [-f] [-i] [-p] [-@] [-/] f1 f2\n"
+ " cp [-f] [-i] [-p] [-@] [-/] f1 ... fn d1\n"
+ " cp -r|-R [-H|-L|-P] [-f] [-i] [-p] [-@] [-/] "
"d1 ... dn-1 dn\n"));
}
exit(2);
@@ -1644,7 +1544,7 @@ copydir(char *source, char *target)
} else if (fixmode != (mode_t)0)
(void) chmod(target, fixmode & MODEBITS);
- if (pflg || atflg || mve) {
+ if (pflg || atflg || mve || saflg) {
attret = copyattributes(source, target);
if (!attrsilent && attret != 0) {
(void) fprintf(stderr, gettext("%s: Failed to preserve"
@@ -1656,6 +1556,18 @@ copydir(char *source, char *target)
*/
attret = 0;
}
+ /* Copy extended system attributes */
+ if (pflg || mve || saflg) {
+ attret = copy_sysattr(source, target);
+ if (attret != 0 && !attrsilent) {
+ (void) fprintf(stderr, gettext(
+ "%s: Failed to preserve "
+ "extended system attributes "
+ "of directory %s\n"), cmd, source);
+ } else {
+ attret = 0;
+ }
+ }
}
if (attret != 0)
return (attret);
@@ -1692,34 +1604,25 @@ use_stdin(void)
#endif
}
+/* Copy non-system extended attributes */
+
static int
copyattributes(char *source, char *target)
{
- int sourcedirfd, targetdirfd;
- int srcfd, targfd;
- int tmpfd;
- DIR *srcdirp;
- int srcattrfd, targattrfd;
struct dirent *dp;
- char *attrstr;
char *srcbuf, *targbuf;
- size_t src_size, targ_size;
int error = 0;
int aclerror;
mode_t mode;
int clearflg = 0;
acl_t *xacl = NULL;
acl_t *attrdiracl = NULL;
- struct stat attrdir, s3, s4;
struct timeval times[2];
- mode_t targmode;
- srcdirp = NULL;
- srcfd = targfd = tmpfd = -1;
- sourcedirfd = targetdirfd = srcattrfd = targattrfd = -1;
srcbuf = targbuf = NULL;
- if (pathconf(source, _PC_XATTR_EXISTS) != 1)
+
+ if (pathconf(source, _PC_XATTR_EXISTS) != 1)
return (0);
if (pathconf(target, _PC_XATTR_ENABLED) != 1) {
@@ -1732,135 +1635,12 @@ copyattributes(char *source, char *target)
}
return (1);
}
-
-
- if ((srcfd = open(source, O_RDONLY)) == -1) {
- if (pflg && attrsilent) {
- error = 0;
- goto out;
- }
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: cannot open file"
- " %s: "), cmd, source);
- perror("");
- }
- ++error;
- goto out;
- }
- if ((targfd = open(target, O_RDONLY)) == -1) {
-
- if (pflg && attrsilent) {
- error = 0;
- goto out;
- }
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: cannot open file"
- " %s: "), cmd, source);
- perror("");
- }
- ++error;
- goto out;
- }
-
- if ((sourcedirfd = openat(srcfd, ".", O_RDONLY|O_XATTR)) == -1) {
- if (pflg && attrsilent) {
- error = 0;
- goto out;
- }
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: cannot open attribute"
- " directory for %s: "), cmd, source);
- perror("");
- ++error;
- }
- goto out;
- }
-
- if (fstat(sourcedirfd, &attrdir) == -1) {
- if (pflg && attrsilent) {
- error = 0;
- goto out;
- }
-
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: could not retrieve stat"
- " information for attribute directory"
- "of file %s: "), cmd, source);
- perror("");
- ++error;
- }
- goto out;
- }
- if ((targetdirfd = openat(targfd, ".", O_RDONLY|O_XATTR)) == -1) {
- /*
- * We couldn't create the attribute directory
- *
- * Lets see if we can add write support to the mode
- * and create the directory and then put the mode back
- * to way it should be.
- */
-
- targmode = FMODE(s1) | S_IWUSR;
- if (fchmod(targfd, targmode) == 0) {
- targetdirfd = openat(targfd, ".", O_RDONLY|O_XATTR);
- /*
- * Put mode back to what it was
- */
- targmode = FMODE(s1) & MODEBITS;
- if (fchmod(targfd, targmode) == -1) {
- if (pflg && attrsilent) {
- error = 0;
- goto out;
- }
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: failed to set"
- " mode correctly on file"
- " %s: "), cmd, target);
- perror("");
- ++error;
- goto out;
- }
- }
- } else {
- if (pflg && attrsilent) {
- error = 0;
- goto out;
- }
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: cannot open attribute"
- " directory for %s: "), cmd, target);
- perror("");
- ++error;
- }
- goto out;
- }
- }
-
- if (targetdirfd == -1) {
- if (pflg && attrsilent) {
- error = 0;
- goto out;
- }
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: cannot open attribute directory"
- " for %s: "), cmd, target);
- perror("");
- ++error;
- }
- goto out;
- }
-
- /*
- * Set mode of attribute directory same as on source,
- * if pflg set or this is a move.
- */
+ if (open_source(source) != 0)
+ return (1);
+ if (open_target_srctarg_attrdirs(source, target) != 0)
+ return (1);
+ if (open_attrdirp(source) != 0)
+ return (1);
if (pflg || mve) {
if (fchmod(targetdirfd, attrdir.st_mode) == -1) {
@@ -1933,71 +1713,15 @@ copyattributes(char *source, char *target)
}
}
- /*
- * dup sourcedirfd for use by fdopendir().
- * fdopendir will take ownership of given fd and will close
- * it when closedir() is called.
- */
+ while ((dp = readdir(srcdirp)) != NULL) {
+ int ret;
- if ((tmpfd = dup(sourcedirfd)) == -1) {
- if (pflg && attrsilent) {
- error = 0;
- goto out;
- }
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext(
- "%s: unable to dup attribute directory"
- " file descriptor for %s: "), cmd, source);
- perror("");
+ if ((ret = traverse_attrfile(dp, source, target, 1)) == -1)
+ continue;
+ else if (ret > 0) {
++error;
- }
- goto out;
- }
- if ((srcdirp = fdopendir(tmpfd)) == NULL) {
- if (pflg && attrsilent) {
- error = 0;
goto out;
}
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: failed to open attribute"
- " directory for %s: "), cmd, source);
- perror("");
- ++error;
- }
- goto out;
- }
-
- while (dp = readdir(srcdirp)) {
- if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
- (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
- dp->d_name[2] == '\0'))
- continue;
-
- if ((srcattrfd = openat(sourcedirfd, dp->d_name,
- O_RDONLY)) == -1) {
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: cannot open attribute %s on"
- " file %s: "), cmd, dp->d_name, source);
- perror("");
- ++error;
- goto next;
- }
- }
-
- if (fstat(srcattrfd, &s3) < 0) {
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: could not stat attribute"
- " %s on file"
- " %s: "), cmd, dp->d_name, source);
- perror("");
- ++error;
- }
- goto next;
- }
if (pflg || mve) {
if ((aclerror = facl_get(srcattrfd,
@@ -2013,20 +1737,6 @@ copyattributes(char *source, char *target)
}
}
- (void) unlinkat(targetdirfd, dp->d_name, 0);
- if ((targattrfd = openat(targetdirfd, dp->d_name,
- O_RDWR|O_CREAT|O_TRUNC, s3.st_mode & MODEBITS)) == -1) {
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: could not create attribute"
- " %s on file"
- " %s: "), cmd, dp->d_name, target);
- perror("");
- ++error;
- }
- goto next;
- }
-
/*
* preserve ACL
*/
@@ -2044,60 +1754,8 @@ copyattributes(char *source, char *target)
}
}
- if (fstat(targattrfd, &s4) < 0) {
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: could not stat attribute"
- " %s on file"
- " %s: "), cmd, dp->d_name, source);
- perror("");
- ++error;
- }
- goto next;
- }
-
-/*
- * setup path string to be passed to writefile
- *
- * We need to include attribute in the string so that
- * a useful error message can be printed in the case of a failure.
- */
- attrstr = gettext(" attribute ");
- src_size = strlen(source) +
- strlen(dp->d_name) + strlen(attrstr) + 1;
- srcbuf = malloc(src_size);
-
- if (srcbuf == NULL) {
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: could not allocate memory"
- " for path buffer: "), cmd);
- perror("");
- ++error;
- }
- goto next;
- }
- targ_size = strlen(target) +
- strlen(dp->d_name) + strlen(attrstr) + 1;
- targbuf = malloc(targ_size);
- if (targbuf == NULL) {
- if (!attrsilent) {
- (void) fprintf(stderr,
- gettext("%s: could not allocate memory"
- " for path buffer: "), cmd);
- perror("");
- ++error;
- }
- goto next;
- }
-
- (void) snprintf(srcbuf, src_size, "%s%s%s",
- source, attrstr, dp->d_name);
- (void) snprintf(targbuf, targ_size, "%s%s%s",
- target, attrstr, dp->d_name);
-
- if (writefile(srcattrfd, targattrfd,
- srcbuf, targbuf, &s3, &s4) != 0) {
+ if (writefile(srcattrfd, targattrfd, source, target,
+ dp->d_name, dp->d_name, &s3, &s4) != 0) {
if (!attrsilent) {
++error;
}
@@ -2194,16 +1852,138 @@ out:
free(srcbuf);
if (targbuf)
free(targbuf);
- if (sourcedirfd != -1)
- (void) close(sourcedirfd);
- if (targetdirfd != -1)
- (void) close(targetdirfd);
- if (srcdirp != NULL)
- (void) closedir(srcdirp);
- if (srcfd != -1)
- (void) close(srcfd);
- if (targfd != -1)
- (void) close(targfd);
+
+ if (!saflg && !pflg && !mve)
+ close_all();
+ return (error == 0 ? 0 : 1);
+}
+
+/* Copy extended system attributes from source to target */
+
+static int
+copy_sysattr(char *source, char *target)
+{
+ struct dirent *dp;
+ nvlist_t *response;
+ int error = 0;
+ int chk_support = 0;
+ int sa_support = 1;
+
+ if (sysattr_support(source, _PC_SATTR_EXISTS) != 1)
+ return (0);
+
+ if (open_source(source) != 0)
+ return (1);
+
+ /*
+ * Gets non default extended system attributes from the
+ * source file to copy to the target. The target has
+ * the defaults set when its created and thus no need
+ * to copy the defaults.
+ */
+ response = sysattr_list(cmd, srcfd, source);
+
+ if (response != NULL &&
+ sysattr_support(target, _PC_SATTR_ENABLED) != 1) {
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext(
+ "%s: cannot preserve extended system "
+ "attribute, operation not supported on file"
+ " %s\n"), cmd, target);
+ }
+ error++;
+ goto out;
+ }
+
+ if (srcdirp == NULL) {
+ if (open_target_srctarg_attrdirs(source, target) != 0) {
+ error++;
+ goto out;
+ }
+ if (open_attrdirp(source) != 0) {
+ error++;
+ goto out;
+ }
+ } else {
+ rewind_attrdir(srcdirp);
+ }
+ while (sa_support && (dp = readdir(srcdirp)) != NULL) {
+ nvlist_t *res;
+ int ret;
+
+ if ((ret = traverse_attrfile(dp, source, target, 0)) == -1)
+ continue;
+ else if (ret > 0) {
+ ++error;
+ goto out;
+ }
+ /*
+ * Gets non default extended system attributes from the
+ * attribute file to copy to the target. The target has
+ * the defaults set when its created and thus no need
+ * to copy the defaults.
+ */
+ if (dp->d_name != NULL) {
+ res = sysattr_list(cmd, srcattrfd, dp->d_name);
+ if (res == NULL)
+ goto next;
+
+ if (!chk_support &&
+ sysattr_support(target, _PC_SATTR_ENABLED) != 1) {
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext(
+ "%s: cannot preserve extended "
+ "system attribute, operation not "
+ " %s\n"), cmd, target);
+ }
+ error++;
+ sa_support = 0;
+ } else {
+ chk_support = 1;
+ }
+
+ /*
+ * Copy non default extended system attributes of named
+ * attribute file.
+ */
+ if (sa_support && fsetattr(targattrfd,
+ XATTR_VIEW_READWRITE, res) != 0) {
+ ++error;
+ if (!attrsilent) {
+ (void) fprintf(stderr, gettext("%s: "
+ "Failed to copy extended system "
+ "attributes from attribute file "
+ "%s of %s to %s\n"), cmd,
+ dp->d_name, source, target);
+ }
+ }
+ }
+next:
+ if (srcattrfd != -1)
+ (void) close(srcattrfd);
+ if (targattrfd != -1)
+ (void) close(targattrfd);
+ srcattrfd = targattrfd = -1;
+ if (res != NULL)
+ nvlist_free(res);
+ }
+
+ /* Copy source file non default extended system attributes to target */
+ if ((response != NULL) &&
+ (fsetattr(targfd, XATTR_VIEW_READWRITE, response)) != 0) {
+ ++error;
+ if (!attrsilent) {
+ (void) fprintf(stderr, gettext("%s: Failed to "
+ "copy extended system attributes from "
+ "%s to %s\n"), cmd, source, target);
+ }
+ }
+out:
+ if (response != NULL)
+ nvlist_free(response);
+ close_all();
return (error == 0 ? 0 : 1);
}
@@ -2216,3 +1996,268 @@ timestruc_to_timeval(timestruc_t *ts, struct timeval *tv)
tv->tv_sec = ts->tv_sec;
tv->tv_usec = ts->tv_nsec / 1000;
}
+
+/* Open the source file */
+
+int
+open_source(char *src)
+{
+ int error = 0;
+
+ srcfd = -1;
+ if ((srcfd = open(src, O_RDONLY)) == -1) {
+ if (pflg && attrsilent) {
+ error++;
+ goto out;
+ }
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: cannot open file"
+ " %s: "), cmd, src);
+ perror("");
+ }
+ ++error;
+ }
+out:
+ if (error)
+ close_all();
+ return (error == 0 ? 0 : 1);
+}
+
+/* Open source attribute dir, target and target attribute dir. */
+
+int
+open_target_srctarg_attrdirs(char *src, char *targ)
+{
+ int error = 0;
+
+ targfd = sourcedirfd = targetdirfd = -1;
+
+ if ((targfd = open(targ, O_RDONLY)) == -1) {
+ if (pflg && attrsilent) {
+ error++;
+ goto out;
+ }
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: cannot open file"
+ " %s: "), cmd, targ);
+ perror("");
+ }
+ ++error;
+ goto out;
+ }
+
+ if ((sourcedirfd = openat(srcfd, ".", O_RDONLY|O_XATTR)) == -1) {
+ if (pflg && attrsilent) {
+ error++;
+ goto out;
+ }
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: cannot open attribute"
+ " directory for %s: "), cmd, src);
+ perror("");
+ }
+ ++error;
+ goto out;
+ }
+
+ if (fstat(sourcedirfd, &attrdir) == -1) {
+ if (pflg && attrsilent) {
+ error++;
+ goto out;
+ }
+
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: could not retrieve stat"
+ " information for attribute directory"
+ "of file %s: "), cmd, src);
+ perror("");
+ }
+ ++error;
+ goto out;
+ }
+ if ((targetdirfd = openat(targfd, ".", O_RDONLY|O_XATTR)) == -1) {
+ if (pflg && attrsilent) {
+ error++;
+ goto out;
+ }
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: cannot open attribute"
+ " directory for %s: "), cmd, targ);
+ perror("");
+ }
+ ++error;
+ }
+out:
+ if (error)
+ close_all();
+ return (error == 0 ? 0 : 1);
+}
+
+int
+open_attrdirp(char *source)
+{
+ int tmpfd = -1;
+ int error = 0;
+
+ /*
+ * dup sourcedirfd for use by fdopendir().
+ * fdopendir will take ownership of given fd and will close
+ * it when closedir() is called.
+ */
+
+ if ((tmpfd = dup(sourcedirfd)) == -1) {
+ if (pflg && attrsilent) {
+ error++;
+ goto out;
+ }
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext(
+ "%s: unable to dup attribute directory"
+ " file descriptor for %s: "), cmd, source);
+ perror("");
+ ++error;
+ }
+ goto out;
+ }
+ if ((srcdirp = fdopendir(tmpfd)) == NULL) {
+ if (pflg && attrsilent) {
+ error++;
+ goto out;
+ }
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: failed to open attribute"
+ " directory for %s: "), cmd, source);
+ perror("");
+ ++error;
+ }
+ }
+out:
+ if (error)
+ close_all();
+ return (error == 0 ? 0 : 1);
+}
+
+/* Skips through ., .., and system attribute 'view' files */
+int
+traverse_attrfile(struct dirent *dp, char *source, char *target, int first)
+{
+ int error = 0;
+
+ if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
+ (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
+ dp->d_name[2] == '\0') ||
+ (sysattr_type(dp->d_name) == _RO_SATTR) ||
+ (sysattr_type(dp->d_name) == _RW_SATTR))
+ return (-1);
+
+ if ((srcattrfd = openat(sourcedirfd, dp->d_name,
+ O_RDONLY)) == -1) {
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: cannot open attribute %s on"
+ " file %s: "), cmd, dp->d_name, source);
+ perror("");
+ ++error;
+ goto out;
+ }
+ }
+
+ if (fstat(srcattrfd, &s3) < 0) {
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: could not stat attribute"
+ " %s on file"
+ " %s: "), cmd, dp->d_name, source);
+ perror("");
+ ++error;
+ }
+ goto out;
+ }
+
+ if (first) {
+ (void) unlinkat(targetdirfd, dp->d_name, 0);
+ targattrfd = openat(targetdirfd, dp->d_name,
+ O_RDWR|O_CREAT|O_TRUNC, s3.st_mode & MODEBITS);
+ } else {
+ targattrfd = openat(targetdirfd, dp->d_name, O_RDWR);
+ }
+
+ if (targattrfd == -1) {
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: could not create attribute"
+ " %s on file %s: "), cmd, dp->d_name,
+ target);
+ perror("");
+ ++error;
+ }
+ goto out;
+ }
+
+ if (fstat(targattrfd, &s4) < 0) {
+ if (!attrsilent) {
+ (void) fprintf(stderr,
+ gettext("%s: could not stat attribute"
+ " %s on file"
+ " %s: "), cmd, dp->d_name, target);
+ perror("");
+ ++error;
+ }
+ }
+
+out:
+ if (error) {
+ if (srcattrfd != -1)
+ (void) close(srcattrfd);
+ if (targattrfd != -1)
+ (void) close(targattrfd);
+ }
+ return (error == 0 ? 0 :1);
+}
+
+void
+rewind_attrdir(DIR * sdp)
+{
+ int pwdfd;
+
+ pwdfd = open(".", O_RDONLY);
+ if ((pwdfd != -1) && (fchdir(sourcedirfd) == 0)) {
+ rewinddir(sdp);
+ (void) fchdir(pwdfd);
+ (void) close(pwdfd);
+ } else {
+ if (!attrsilent) {
+ (void) fprintf(stderr, gettext("%s: "
+ "failed to rewind attribute dir\n"),
+ cmd);
+ }
+ }
+}
+
+void
+close_all()
+{
+ if (srcattrfd != -1)
+ (void) close(srcattrfd);
+ if (targattrfd != -1)
+ (void) close(targattrfd);
+ if (sourcedirfd != -1)
+ (void) close(sourcedirfd);
+ if (targetdirfd != -1)
+ (void) close(targetdirfd);
+ if (srcdirp != NULL) {
+ (void) closedir(srcdirp);
+ srcdirp = NULL;
+ }
+ if (srcfd != -1)
+ (void) close(srcfd);
+ if (targfd != -1)
+ (void) close(targfd);
+}
diff --git a/usr/src/cmd/pack/Makefile b/usr/src/cmd/pack/Makefile
index 49dd679511..365475cb39 100644
--- a/usr/src/cmd/pack/Makefile
+++ b/usr/src/cmd/pack/Makefile
@@ -2,9 +2,8 @@
# 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.
+# 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.
@@ -22,7 +21,7 @@
#
#ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -32,7 +31,9 @@ include ../Makefile.cmd
CFLAGS += $(CCVERBOSE)
XGETFLAGS += -a -x $(PROG).xcl
-LDLIBS += -lsec
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+
+LDLIBS += -lcmdutils -lsec
.KEEP_STATE:
diff --git a/usr/src/cmd/pack/pack.c b/usr/src/cmd/pack/pack.c
index 181e6a61db..67e4814986 100644
--- a/usr/src/cmd/pack/pack.c
+++ b/usr/src/cmd/pack/pack.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,28 +30,18 @@
/*
* Huffman encoding program
- * Usage: pack [[ -f ] [ - ] filename ... ] filename ...
+ * Usage: pack [[ -f ] [ - ] [-/] filename ... ] filename ...
* - option: enable/disable listing of statistics
*/
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
#include <locale.h>
#include <stdarg.h>
-#include <errno.h>
#include <sys/isa_defs.h>
-#include <stdlib.h>
-#include <limits.h>
#include <sys/param.h>
-#include <fcntl.h>
#include <utime.h>
-#include <string.h>
-#include <dirent.h>
-#include <unistd.h>
#include <sys/acl.h>
#include <aclutils.h>
+#include <libcmdutils.h>
#undef lint
@@ -82,7 +72,6 @@ int force = 0; /* allow forced packing for consistency in directory */
static char filename [MAXPATHLEN];
static int max_name;
-static int max_path = MAXPATHLEN;
int infile; /* unpacked file */
int outfile; /* packed file */
@@ -123,7 +112,11 @@ struct heap {
#define hmove(a, b) {(b).count = (a).count; (b).node = (a).node; }
static void heapify(int i);
-static int mv_xattrs(int, int, char *, int);
+
+/* Extended system attribute support */
+
+static int saflg = 0;
+
/* gather character frequency statistics */
/* return 1 if successful, 0 otherwise */
@@ -138,8 +131,8 @@ input(char *source)
count[inbuff[--i]&0377] += 2;
if (i == 0)
return (1);
- fprintf(stderr, gettext(
- "pack: %s: read error - file unchanged: "), source);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: read error - file unchanged: "), source);
perror("");
return (0);
}
@@ -176,7 +169,7 @@ output(char *source)
dictsize = outp-&outbuff[0];
/* output the text */
- lseek(infile, 0L, 0);
+ (void) lseek(infile, 0L, 0);
outsize = 0;
bitsleft = 8;
inleft = 0;
@@ -184,9 +177,9 @@ output(char *source)
if (inleft <= 0) {
inleft = read(infile, inp = &inbuff[0], BUFSIZ);
if (inleft < 0) {
- fprintf(stderr, gettext(
+ (void) fprintf(stderr, gettext(
"pack: %s: read error - file unchanged: "),
- source);
+ source);
perror("");
return (0);
}
@@ -205,14 +198,14 @@ output(char *source)
}
if (outp >= &outbuff[BUFSIZ]) {
if (write(outfile, outbuff, BUFSIZ) != BUFSIZ) {
-wrerr: fprintf(stderr, gettext(
- "pack: %s.z: write error - file unchanged: "),
- source);
+wrerr: (void) fprintf(stderr, gettext(
+ "pack: %s.z: write error - "
+ "file unchanged: "), source);
perror("");
return (0);
}
((union FOUR *)outbuff)->lint.lng =
- ((union FOUR *)&outbuff[BUFSIZ])->lint.lng;
+ ((union FOUR *)&outbuff[BUFSIZ])->lint.lng;
outp -= BUFSIZ;
outsize += BUFSIZ;
}
@@ -272,8 +265,8 @@ packfile(char *source)
}
}
if (diffbytes == 1) {
- fprintf(stderr, gettext(
- "pack: %s: trivial file - file unchanged\n"), source);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: trivial file - file unchanged\n"), source);
return (0);
}
insize.lint.lng >>= 1;
@@ -311,18 +304,18 @@ packfile(char *source)
}
if (maxlev > 24) {
/* can't occur unless insize.lint.lng >= 2**24 */
- fprintf(stderr, gettext(
- "pack: %s: Huffman tree has too many levels - file unchanged\n"),
- source);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: Huffman tree has too many levels - "
+ "file unchanged\n"), source);
return (0);
}
/* don't bother if no compression results */
outsize = ((bitsout+7)>>3)+6+maxlev+diffbytes;
if ((insize.lint.lng+BUFSIZ-1)/BUFSIZ <=
- (outsize+BUFSIZ-1)/BUFSIZ && !force) {
- printf(gettext(
- "pack: %s: no saving - file unchanged\n"), source);
+ (outsize+BUFSIZ-1)/BUFSIZ && !force) {
+ (void) printf(gettext(
+ "pack: %s: no saving - file unchanged\n"), source);
return (0);
}
@@ -354,6 +347,9 @@ main(int argc, char *argv[])
int error;
int fcount = 0; /* count failures */
acl_t *aclp = NULL;
+ char *progname;
+ int sattr_exist = 0;
+ int xattr_exist = 0;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
@@ -361,9 +357,16 @@ main(int argc, char *argv[])
#endif
(void) textdomain(TEXT_DOMAIN);
- while ((c = getopt(argc, argv, "f-")) != EOF) {
+ if (progname = strrchr(argv[0], '/'))
+ ++progname;
+ else
+ progname = argv[0];
+
+ while ((c = getopt(argc, argv, "f-/")) != EOF) {
if (c == 'f')
force++;
+ else if (c == '/')
+ saflg++;
else
++errflg;
}
@@ -374,18 +377,20 @@ main(int argc, char *argv[])
argc -= optind;
argv = &argv[optind];
if (errflg || argc < 1 ||
- (argc == 1 && argv[0][0] == '-' && argv[0][1] == '\0')) {
- fprintf(stderr, gettext(
- "usage: pack [-f] [-] file...\n"));
+ (argc == 1 && (argv[0][0] == '-' || argv[0][0] == '/' &&
+ argv[0][1] == '\0'))) {
+ (void) fprintf(stderr, gettext(
+ "usage: pack [-f] [-] [-/] file...\n"));
if (argc < 1 ||
- (argc == 1 && argv[0][0] == '-' &&
- argv[0][1] == '\0')) {
+ (argc == 1 && (argv[0][0] == '-' || argv[0][0] == '/') &&
+ argv[0][1] == '\0')) {
/*
* return 1 for usage error when no file was specified
*/
return (1);
}
}
+
/* loop through the file names */
for (k = 0; k < argc; k++) {
if (argv[k][0] == '-' && argv[k][1] == '\0') {
@@ -416,45 +421,45 @@ main(int argc, char *argv[])
for (i = 0; i < (MAXPATHLEN-3) && (*cp = argv[k][i]); i++)
if (*cp++ == '/') sep = i;
if ((infile = open(filename, 0)) < 0) {
- fprintf(stderr, gettext(
- "pack: %s: cannot open: "), filename);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: cannot open: "), filename);
perror("");
continue;
}
if (i >= (MAXPATHLEN-3) || (i-sep) > (max_name - 1)) {
- fprintf(stderr, gettext(
- "pack: %s: file name too long\n"), argv[k]);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: file name too long\n"), argv[k]);
continue;
}
- fstat(infile, &status);
+ (void) fstat(infile, &status);
if (S_ISDIR(status.st_mode)) {
- fprintf(stderr, gettext(
- "pack: %s: cannot pack a directory\n"),
- argv[k]);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: cannot pack a directory\n"),
+ argv[k]);
goto closein;
}
if (status.st_size == 0) {
- fprintf(stderr, gettext(
- "pack: %s: cannot pack a zero length file\n"),
- argv[k]);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: cannot pack a zero length file\n"),
+ argv[k]);
goto closein;
}
if (status.st_nlink != 1) {
- fprintf(stderr, gettext(
- "pack: %s: has links\n"),
- argv[k]);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: has links\n"),
+ argv[k]);
goto closein;
}
*cp++ = SUF0; *cp++ = SUF1; *cp = '\0';
if (stat(filename, &ostatus) != -1) {
- fprintf(stderr, gettext(
- "pack: %s: already exists\n"), filename);
+ (void) fprintf(stderr, gettext(
+ "pack: %s: already exists\n"), filename);
goto closein;
}
-
- if ((outfile = creat(filename, status.st_mode)) < 0) {
- fprintf(stderr, gettext(
- "pack: %s: cannot create: "), filename);
+ if ((outfile = creat(filename, status.st_mode | O_RDONLY))
+ < 0) {
+ (void) fprintf(stderr, gettext(
+ "pack: %s: cannot create: "), filename);
perror("");
goto closein;
}
@@ -462,155 +467,126 @@ main(int argc, char *argv[])
error = facl_get(infile, ACL_NO_TRIVIAL, &aclp);
if (error != 0) {
- fprintf(stderr, gettext(
+ (void) fprintf(stderr, gettext(
"pack: %s: cannot retrieve ACL: %s\n"), argv[k],
acl_strerror(error));
}
- if (packfile(argv[k]) &&
- ((pathconf(argv[k], _PC_XATTR_EXISTS) != 1) ||
- (mv_xattrs(infile, outfile,
- argv[k], 0) == 0))) {
- if (unlink(argv[k]) != 0) {
- fprintf(stderr, gettext(
- "pack: %s: cannot unlink: "),
- argv[k]);
- perror("");
+
+ if (packfile(argv[k])) {
+ if (pathconf(argv[k], _PC_XATTR_EXISTS) == 1)
+ xattr_exist = 1;
+ if (saflg && sysattr_support(argv[k],
+ _PC_SATTR_EXISTS) == 1)
+ sattr_exist = 1;
+ if (sattr_exist || xattr_exist) {
+ if (mv_xattrs(progname, argv[k], filename,
+ sattr_exist, 0) != 0) {
+ /* Move attributes back ... */
+ xattr_exist = 0;
+ sattr_exist = 0;
+ if (pathconf(filename,
+ _PC_XATTR_EXISTS) == 1)
+ xattr_exist = 1;
+ if (saflg && sysattr_support(filename,
+ _PC_SATTR_EXISTS) == 1)
+ sattr_exist = 1;
+ if (xattr_exist || sattr_exist) {
+ (void) mv_xattrs(progname,
+ filename, argv[k],
+ sattr_exist, 1);
+ (void) unlink(filename);
+ goto out;
+ }
+ } else {
+ errno = 0;
+ if (unlink(argv[k]) != 0) {
+ (void) fprintf(stderr, gettext(
+ "pack: %s :cannot unlink:"),
+ argv[k]);
+ if (errno == EPERM)
+ perror("No permission");
+ else
+ perror("");
+ }
+ }
+ } else {
+ errno = 0;
+ if (unlink(argv[k]) != 0) {
+ (void) fprintf(stderr, gettext(
+ "pack: %s :cannot unlink"),
+ argv[k]);
+ if (errno == EPERM)
+ perror("No permission");
+ else
+ perror("");
+ }
}
- printf(gettext(
- "pack: %s: %.1f%% Compression\n"),
- argv[k],
- ((double)(-outsize+(insize.lint.lng))/(double)insize.lint.lng)*100);
+ (void) printf(gettext(
+ "pack: %s: %.1f%% Compression\n"),
+ argv[k],
+ ((double)(-outsize+(insize.lint.lng))/
+ (double)insize.lint.lng)*100);
/* output statistics */
if (vflag) {
- printf(gettext("\tfrom %ld to %ld bytes\n"),
- insize.lint.lng, outsize);
- printf(gettext(
- "\tHuffman tree has %d levels below root\n"),
- maxlev);
- printf(gettext(
- "\t%d distinct bytes in input\n"),
- diffbytes);
- printf(gettext(
- "\tdictionary overhead = %ld bytes\n"),
- dictsize);
- printf(gettext(
+ (void) printf(gettext(
+ "\tfrom %ld to %ld bytes\n"),
+ insize.lint.lng, outsize);
+ (void) printf(gettext(
+ "\tHuffman tree has %d levels below "
+ "root\n"), maxlev);
+ (void) printf(gettext(
+ "\t%d distinct bytes in input\n"),
+ diffbytes);
+ (void) printf(gettext(
+ "\tdictionary overhead = %ld bytes\n"),
+ dictsize);
+ (void) printf(gettext(
"\teffective entropy = %.2f bits/byte\n"),
- ((double)outsize / (double)insize.lint.lng) * 8);
- printf(gettext(
+ ((double)outsize / (double)insize.lint.lng)
+ * 8);
+ (void) printf(gettext(
"\tasymptotic entropy = %.2f bits/byte\n"),
- ((double)(outsize-dictsize) /
- (double)insize.lint.lng) * 8);
+ ((double)(outsize-dictsize) /
+ (double)insize.lint.lng) * 8);
}
+
u_times.actime = status.st_atime;
u_times.modtime = status.st_mtime;
if (utime(filename, &u_times) != 0) {
errflg++;
- fprintf(stderr,
- gettext(
- "pack: cannot change times on %s: "),
- filename);
+ (void) fprintf(stderr,
+ gettext(
+ "pack: cannot change times on %s: "),
+ filename);
perror("");
}
if (chmod(filename, status.st_mode) != 0) {
errflg++;
- fprintf(stderr,
- gettext(
- "pack: can't change mode to %o on %s: "),
- status.st_mode, filename);
+ (void) fprintf(stderr,
+ gettext(
+ "pack: can't change mode to %o on %s: "),
+ status.st_mode, filename);
perror("");
}
- chown(filename, status.st_uid, status.st_gid);
+ (void) chown(filename, status.st_uid, status.st_gid);
if (aclp && (facl_set(outfile, aclp) < 0)) {
- fprintf(stderr, gettext(
+ (void) fprintf(stderr, gettext(
"pack: %s: failed to set acl entries\n"),
filename);
perror("");
}
if (!errflg)
fcount--; /* success after all */
- } else {
- if (pathconf(filename, _PC_XATTR_EXISTS) == 1) {
- (void) mv_xattrs(outfile, infile, filename, 1);
- }
- unlink(filename);
- }
+ }
+out:
if (aclp) {
acl_free(aclp);
aclp = NULL;
}
-closein: close(outfile);
- close(infile);
+closein: (void) close(outfile);
+ (void) close(infile);
}
return (fcount);
}
-
-/*
- * mv_xattrs - move (via renameat) all of the extended attributes
- * associated with the file referenced by infd to the file
- * referenced by outfd. The infile and silent arguments are
- * provided for error message processing. This function
- * returns 0 on success and -1 on error.
- */
-static int
-mv_xattrs(int infd, int outfd, char *infile, int silent)
-{
- int indfd, outdfd, tmpfd;
- DIR *dirp = NULL;
- struct dirent *dp = NULL;
- int error = 0;
- char *etext;
-
- indfd = outdfd = tmpfd = -1;
-
- if ((indfd = openat(infd, ".", O_RDONLY|O_XATTR)) == -1) {
- etext = gettext("cannot open source");
- error = -1;
- goto out;
- }
-
- if ((outdfd = openat(outfd, ".", O_RDONLY|O_XATTR)) == -1) {
- etext = gettext("cannot open target");
- error = -1;
- goto out;
- }
-
- if ((tmpfd = dup(indfd)) == -1) {
- etext = gettext("cannot dup descriptor");
- error = -1;
- goto out;
-
- }
- if ((dirp = fdopendir(tmpfd)) == NULL) {
- etext = gettext("cannot access source");
- error = -1;
- goto out;
- }
-
- while (dp = readdir(dirp)) {
- if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
- (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
- dp->d_name[2] == '\0'))
- continue;
- if ((renameat(indfd, dp->d_name, outdfd, dp->d_name)) == -1) {
- etext = dp->d_name;
- error = -1;
- goto out;
- }
- }
-out:
- if (error == -1 && silent == 0) {
- fprintf(stderr, gettext(
- "pack: %s: cannot move extended attributes, "),
- infile);
- perror(etext);
- }
- if (dirp)
- closedir(dirp);
- if (indfd != -1)
- close(indfd);
- if (outdfd != -1)
- close(outdfd);
- return (error);
-}
diff --git a/usr/src/cmd/rpcbind/rpcb_svc_com.c b/usr/src/cmd/rpcbind/rpcb_svc_com.c
index cef47619b5..03844d4b48 100644
--- a/usr/src/cmd/rpcbind/rpcb_svc_com.c
+++ b/usr/src/cmd/rpcbind/rpcb_svc_com.c
@@ -266,7 +266,7 @@ map_unset(regp, owner)
/*
* We return 1 either when the entry was not there or it
* was able to unset it. It can come to this point only if
- * atleast one of the conditions is true.
+ * at least one of the conditions is true.
*/
return (1);
}
diff --git a/usr/src/cmd/smbsrv/Makefile b/usr/src/cmd/smbsrv/Makefile
new file mode 100644
index 0000000000..86716aa460
--- /dev/null
+++ b/usr/src/cmd/smbsrv/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+SUBDIRS = smbadm smbd smbstat dtrace
+MSGSUBDIRS = smbadm smbstat
+
+include ../Makefile.cmd
+include ./Makefile.subdirs
diff --git a/usr/src/cmd/smbsrv/Makefile.smbsrv.defs b/usr/src/cmd/smbsrv/Makefile.smbsrv.defs
new file mode 100644
index 0000000000..b8d8d6694f
--- /dev/null
+++ b/usr/src/cmd/smbsrv/Makefile.smbsrv.defs
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Common definitions for all smbsrv commands
+#
+
+OBJS= $(SRCS:%.c=%.o)
+
+LDLIBS += -lumem
+LDLIBS += -L$(ROOT)/usr/lib/smbsrv -lsmb
+LDFLAGS += -R/usr/lib/smbsrv
+
+CFLAGS += $(CCVERBOSE)
+
+C99MODE = -xc99=%all
+C99LMODE = -Xc99=%all
diff --git a/usr/src/cmd/smbsrv/Makefile.smbsrv.targ b/usr/src/cmd/smbsrv/Makefile.smbsrv.targ
new file mode 100644
index 0000000000..f8a12200ac
--- /dev/null
+++ b/usr/src/cmd/smbsrv/Makefile.smbsrv.targ
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# Common targets for all smbsrv commands
+#
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all .WAIT $(ROOTUSRSBINPROG)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_SRCS
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
diff --git a/usr/src/cmd/smbsrv/Makefile.subdirs b/usr/src/cmd/smbsrv/Makefile.subdirs
new file mode 100644
index 0000000000..eec8722036
--- /dev/null
+++ b/usr/src/cmd/smbsrv/Makefile.subdirs
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+.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
+_msg := TARGET = _msg
+
+all check clean clobber install install_h lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET)
+
+_msg: $(MSGSUBDIRS)
+
+FRC:
diff --git a/usr/src/cmd/smbsrv/dtrace/Makefile b/usr/src/cmd/smbsrv/dtrace/Makefile
new file mode 100644
index 0000000000..17db7fe24b
--- /dev/null
+++ b/usr/src/cmd/smbsrv/dtrace/Makefile
@@ -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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SRCS= stype.d msrpc.d smbvfs.d smbnode.d
+
+include ../../Makefile.cmd
+
+ROOTSMBDTRACEDIR = $(ROOTLIB)/smbsrv/dtrace
+ROOTSMBDTRACEFILE = $(SRCS:%=$(ROOTSMBDTRACEDIR)/%)
+
+$(ROOTSMBDTRACEFILE):= FILEMODE = 0555
+
+$(ROOTSMBDTRACEDIR):
+ $(INS.dir)
+
+$(ROOTSMBDTRACEDIR)/%: %
+ $(INS.file)
+
+all:
+
+clean:
+
+lint:
+
+include ../../Makefile.targ
+
+install: all $(ROOTSMBDTRACEDIR) .WAIT $(ROOTSMBDTRACEFILE)
diff --git a/usr/src/cmd/smbsrv/dtrace/msrpc.d b/usr/src/cmd/smbsrv/dtrace/msrpc.d
new file mode 100755
index 0000000000..1869ae59bf
--- /dev/null
+++ b/usr/src/cmd/smbsrv/dtrace/msrpc.d
@@ -0,0 +1,300 @@
+#!/usr/sbin/dtrace -s
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Usage: ./msrpc.d -p `pgrep smbd`
+ *
+ * On multi-processor systems, it may be easier to follow the output
+ * if run on a single processor: see psradm. For example, to disable
+ * the second processor on a dual-processor system: psradm -f 1
+ */
+
+/*
+ * SmbSessionSetupX, SmbLogoffX
+ * SmbTreeConnect, SmbTreeDisconnect
+ */
+smb_session*:entry,
+smb_tree*:entry,
+smb_com_*:entry,
+smb_com_*:return,
+smb_com_session_setup_andx:entry,
+smb_com_logoff_andx:entry,
+smb_tree_connect:return,
+smb_tree_disconnect:entry,
+smb_tree_disconnect:return
+{
+}
+
+smb_com_session_setup_andx:return,
+smb_session*:return,
+smb_user*:return,
+smb_tree*:return
+{
+ printf("rc=%d", arg1);
+}
+
+sdt:smbsrv::smb-sessionsetup-clntinfo
+{
+ clnt = (netr_client_t *)arg0;
+
+ printf("domain=%s\n\n", stringof(clnt->domain));
+ printf("username=%s\n\n", stringof(clnt->username));
+}
+
+smb_tree_connect:entry
+{
+ printf("share=%s service=%s",
+ stringof(arg3), stringof(arg4));
+}
+
+smb_com_logoff_andx:return
+{
+ exit(0);
+}
+
+/*
+ * Raise error functions (no return).
+ */
+smbsr_raise_error:entry
+{
+ printf("class=%d code=%d", arg1, arg2);
+}
+
+smbsr_raise_cifs_error:entry
+{
+ printf("status=0x%08x class=%d, code=%d", arg1, arg2, arg3);
+}
+
+smbsr_raise_nt_error:entry
+{
+ printf("error=0x%08x", arg1);
+}
+
+smbsr_raise_errno:entry
+{
+ printf("errno=%d", arg1);
+}
+
+/*
+ * MSRPC activity.
+ */
+pid$target::mlrpc_s_bind:entry,
+pid$target::mlrpc_s_bind:return,
+pid$target::mlrpc_s_request:entry,
+pid$target::mlrpc_s_request:return
+{
+}
+
+pid$target::smb_trace:entry,
+pid$target::mlndo_trace:entry
+{
+ printf("%s", copyinstr(arg0));
+}
+
+/*
+ * LSARPC
+ */
+pid$target::lsarpc_s_CloseHandle:entry,
+pid$target::lsarpc_s_QuerySecurityObject:entry,
+pid$target::lsarpc_s_EnumAccounts:entry,
+pid$target::lsarpc_s_EnumTrustedDomain:entry,
+pid$target::lsarpc_s_OpenAccount:entry,
+pid$target::lsarpc_s_EnumPrivsAccount:entry,
+pid$target::lsarpc_s_LookupPrivValue:entry,
+pid$target::lsarpc_s_LookupPrivName:entry,
+pid$target::lsarpc_s_LookupPrivDisplayName:entry,
+pid$target::lsarpc_s_Discovery:entry,
+pid$target::lsarpc_s_QueryInfoPolicy:entry,
+pid$target::lsarpc_s_OpenDomainHandle:entry,
+pid$target::lsarpc_s_OpenDomainHandle:entry,
+pid$target::lsarpc_s_LookupSids:entry,
+pid$target::lsarpc_s_LookupNames:entry,
+pid$target::lsarpc_s_GetConnectedUser:entry,
+pid$target::lsarpc_s_LookupSids2:entry,
+pid$target::lsarpc_s_LookupNames2:entry
+{
+}
+
+pid$target::lsarpc_s_CloseHandle:return,
+pid$target::lsarpc_s_QuerySecurityObject:return,
+pid$target::lsarpc_s_EnumAccounts:return,
+pid$target::lsarpc_s_EnumTrustedDomain:return,
+pid$target::lsarpc_s_OpenAccount:return,
+pid$target::lsarpc_s_EnumPrivsAccount:return,
+pid$target::lsarpc_s_LookupPrivValue:return,
+pid$target::lsarpc_s_LookupPrivName:return,
+pid$target::lsarpc_s_LookupPrivDisplayName:return,
+pid$target::lsarpc_s_Discovery:return,
+pid$target::lsarpc_s_QueryInfoPolicy:return,
+pid$target::lsarpc_s_OpenDomainHandle:return,
+pid$target::lsarpc_s_OpenDomainHandle:return,
+pid$target::lsarpc_s_LookupSids:return,
+pid$target::lsarpc_s_LookupNames:return,
+pid$target::lsarpc_s_GetConnectedUser:return,
+pid$target::lsarpc_s_LookupSids2:return,
+pid$target::lsarpc_s_LookupNames2:return
+{
+}
+
+/*
+ * NetLogon
+ */
+pid$target::netr_s_*:entry,
+pid$target::netr_s_*:return
+{
+}
+
+/*
+ * SAMR
+ */
+pid$target::samr_s_ConnectAnon:entry,
+pid$target::samr_s_CloseHandle:entry,
+pid$target::samr_s_LookupDomain:entry,
+pid$target::samr_s_EnumLocalDomains:entry,
+pid$target::samr_s_OpenDomain:entry,
+pid$target::samr_s_QueryDomainInfo:entry,
+pid$target::samr_s_LookupNames:entry,
+pid$target::samr_s_OpenUser:entry,
+pid$target::samr_s_DeleteUser:entry,
+pid$target::samr_s_QueryUserInfo:entry,
+pid$target::samr_s_QueryUserGroups:entry,
+pid$target::samr_s_OpenGroup:entry,
+pid$target::samr_s_Connect:entry,
+pid$target::samr_s_GetUserPwInfo:entry,
+pid$target::samr_s_CreateUser:entry,
+pid$target::samr_s_ChangeUserPasswd:entry,
+pid$target::samr_s_GetDomainPwInfo:entry,
+pid$target::samr_s_SetUserInfo:entry,
+pid$target::samr_s_Connect3:entry,
+pid$target::samr_s_Connect4:entry,
+pid$target::samr_s_QueryDispInfo:entry,
+pid$target::samr_s_OpenAlias:entry,
+pid$target::samr_s_CreateDomainAlias:entry,
+pid$target::samr_s_SetAliasInfo:entry,
+pid$target::samr_s_QueryAliasInfo:entry,
+pid$target::samr_s_DeleteDomainAlias:entry,
+pid$target::samr_s_EnumDomainAliases:entry,
+pid$target::samr_s_EnumDomainGroups:entry
+{
+}
+
+pid$target::samr_s_ConnectAnon:return,
+pid$target::samr_s_CloseHandle:return,
+pid$target::samr_s_LookupDomain:return,
+pid$target::samr_s_EnumLocalDomains:return,
+pid$target::samr_s_OpenDomain:return,
+pid$target::samr_s_QueryDomainInfo:return,
+pid$target::samr_s_LookupNames:return,
+pid$target::samr_s_OpenUser:return,
+pid$target::samr_s_DeleteUser:return,
+pid$target::samr_s_QueryUserInfo:return,
+pid$target::samr_s_QueryUserGroups:return,
+pid$target::samr_s_OpenGroup:return,
+pid$target::samr_s_Connect:return,
+pid$target::samr_s_GetUserPwInfo:return,
+pid$target::samr_s_CreateUser:return,
+pid$target::samr_s_ChangeUserPasswd:return,
+pid$target::samr_s_GetDomainPwInfo:return,
+pid$target::samr_s_SetUserInfo:return,
+pid$target::samr_s_Connect3:return,
+pid$target::samr_s_Connect4:return,
+pid$target::samr_s_QueryDispInfo:return,
+pid$target::samr_s_OpenAlias:return,
+pid$target::samr_s_CreateDomainAlias:return,
+pid$target::samr_s_SetAliasInfo:return,
+pid$target::samr_s_QueryAliasInfo:return,
+pid$target::samr_s_DeleteDomainAlias:return,
+pid$target::samr_s_EnumDomainAliases:return,
+pid$target::samr_s_EnumDomainGroups:return
+{
+}
+
+/*
+ * SVCCTL
+ */
+pid$target::svcctl_s_*:entry,
+pid$target::svcctl_s_*:return
+{
+}
+
+/*
+ * SRVSVC
+ */
+pid$target::srvsvc_s_NetConnectEnum:entry,
+pid$target::srvsvc_s_NetFileEnum:entry,
+pid$target::srvsvc_s_NetFileClose:entry,
+pid$target::srvsvc_s_NetShareGetInfo:entry,
+pid$target::srvsvc_s_NetShareSetInfo:entry,
+pid$target::srvsvc_s_NetSessionEnum:entry,
+pid$target::srvsvc_s_NetSessionDel:entry,
+pid$target::srvsvc_s_NetServerGetInfo:entry,
+pid$target::srvsvc_s_NetRemoteTOD:entry,
+pid$target::srvsvc_s_NetNameValidate:entry,
+pid$target::srvsvc_s_NetShareAdd:entry,
+pid$target::srvsvc_s_NetShareDel:entry,
+pid$target::srvsvc_s_NetShareEnum:entry,
+pid$target::srvsvc_s_NetShareEnumSticky:entry,
+pid$target::srvsvc_s_NetGetFileSecurity:entry,
+pid$target::srvsvc_s_NetSetFileSecurity:entry
+{
+}
+
+pid$target::srvsvc_s_NetConnectEnum:return,
+pid$target::srvsvc_s_NetFileEnum:return,
+pid$target::srvsvc_s_NetFileClose:return,
+pid$target::srvsvc_s_NetShareGetInfo:return,
+pid$target::srvsvc_s_NetShareSetInfo:return,
+pid$target::srvsvc_s_NetSessionEnum:return,
+pid$target::srvsvc_s_NetSessionDel:return,
+pid$target::srvsvc_s_NetServerGetInfo:return,
+pid$target::srvsvc_s_NetRemoteTOD:return,
+pid$target::srvsvc_s_NetNameValidate:return,
+pid$target::srvsvc_s_NetShareAdd:return,
+pid$target::srvsvc_s_NetShareDel:return,
+pid$target::srvsvc_s_NetShareEnum:return,
+pid$target::srvsvc_s_NetShareEnumSticky:return,
+pid$target::srvsvc_s_NetGetFileSecurity:return,
+pid$target::srvsvc_s_NetSetFileSecurity:return
+{
+}
+
+/*
+ * WinReg
+ */
+pid$target::winreg_s_*:entry,
+pid$target::winreg_s_*:return
+{
+}
+
+/*
+ * Workstation
+ */
+pid$target::wkssvc_s_*:entry,
+pid$target::wkssvc_s_*:return
+{
+}
diff --git a/usr/src/cmd/smbsrv/dtrace/smbnode.d b/usr/src/cmd/smbsrv/dtrace/smbnode.d
new file mode 100644
index 0000000000..1e4bdc8cb4
--- /dev/null
+++ b/usr/src/cmd/smbsrv/dtrace/smbnode.d
@@ -0,0 +1,127 @@
+#!/usr/sbin/dtrace -qs
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ printf("-->SMB Server Node Trace Started");
+ printf("\n\n");
+}
+
+END
+{
+ printf("<--SMB Server Node Trace Ended");
+ printf("\n\n");
+}
+
+sdt:smbsrv:smb_node_lookup:smb_node_lookup_hit
+/((smb_node_t *)arg0)->n_state == SMB_NODE_STATE_AVAILABLE/
+{
+ printf("\nSMB Node lookup hit/SMB_NODE_STATE_AVAILABLE");
+ printf("\n\tNode: %p", arg0);
+ printf("\n\tRefCnt: %d", ((smb_node_t *)arg0)->n_refcnt);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg0)->vp)->v_path);
+ stack();
+}
+
+sdt:smbsrv:smb_node_lookup:smb_node_lookup_hit
+/((smb_node_t *)arg0)->n_state == SMB_NODE_STATE_DESTROYING/
+{
+ printf("\nSMB Node lookup hit/SMB_NODE_STATE_DESTROYING");
+ printf("\n\tNode: %p", arg0);
+ printf("\n\tRefCnt: %d", ((smb_node_t *)arg0)->n_refcnt);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg0)->vp)->v_path);
+ stack();
+}
+
+sdt:smbsrv:smb_node_lookup:smb_node_lookup_hit
+/(((smb_node_t *)arg0)->n_state != SMB_NODE_STATE_DESTROYING) &&
+ (((smb_node_t *)arg0)->n_state != SMB_NODE_STATE_AVAILABLE)/
+{
+ printf("\nSMB Node lookup hit/Unknown State");
+ printf("\n\tNode: %p", arg0);
+ printf("\n\tRefCnt: %d", ((smb_node_t *)arg0)->n_refcnt);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg0)->vp)->v_path);
+ stack();
+}
+
+sdt:smbsrv:smb_node_lookup:smb_node_lookup_miss
+{
+ printf("\nSMB Node lookup miss");
+ printf("\n\tNode: %p", arg0);
+ printf("\n\tRefCnt: %d", ((smb_node_t *)arg0)->n_refcnt);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg0)->vp)->v_path);
+ stack();
+}
+
+sdt:smbsrv:smb_node_ref:smb_node_ref_exit
+{
+ printf("\nSMB Node reference taken");
+ printf("\n\tNode: %p", arg0);
+ printf("\n\tRefCnt: %d", ((smb_node_t *)arg0)->n_refcnt);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg0)->vp)->v_path);
+ stack();
+}
+
+sdt:smbsrv:smb_node_release:smb_node_release
+/((smb_node_t *)arg0)->n_refcnt == 1/
+{
+ printf("\nSMB Node release(will be destroyed)");
+ printf("\n\tNode: %p", arg0);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg0)->vp)->v_path);
+ stack();
+}
+
+sdt:smbsrv:smb_node_release:smb_node_release
+/((smb_node_t *)arg0)->n_refcnt > 1/
+{
+ printf("\nSMB Node release");
+ printf("\n\tNode: %p", arg0);
+ printf("\n\tRefCnt: %d", ((smb_node_t *)arg0)->n_refcnt);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg0)->vp)->v_path);
+ stack();
+}
+
+sdt:smbsrv:smb_node_delete_on_close:smb_node_delete_on_close
+/(int)arg0 == 0/
+{
+ printf("\nSMB Node delete on close successful");
+ printf("\n\tNode: %p", arg1);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg1)->vp)->v_path);
+ stack();
+}
+
+sdt:smbsrv:smb_node_delete_on_close:smb_node_delete_on_close
+/(int)arg0 == 0/
+{
+ printf("\nSMB Node delete on close failed (%d)", (int)arg0);
+ printf("\n\tNode: %p", arg1);
+ printf("\n\tName: %s", (string)((vnode_t *)((smb_node_t *)arg1)->vp)->v_path);
+ stack();
+}
+
+
diff --git a/usr/src/cmd/smbsrv/dtrace/smbvfs.d b/usr/src/cmd/smbsrv/dtrace/smbvfs.d
new file mode 100644
index 0000000000..23fa589109
--- /dev/null
+++ b/usr/src/cmd/smbsrv/dtrace/smbvfs.d
@@ -0,0 +1,77 @@
+#!/usr/sbin/dtrace -qs
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ printf("\n-->SMB Server VFS Trace Started");
+ printf("\n\n");
+}
+
+END
+{
+ printf("\n<--SMB Server VFS Trace Ended");
+ printf("\n\n");
+}
+
+sdt:smbsrv:smb_vfs_hold:smb_vfs_hold_hit
+{
+ printf("\nSMB VFS lookup hit");
+ printf("\n Path: %s", (string)((smb_vfs_t *)arg0)->sv_rootvp->v_path);
+ printf("\n RefCount: %d", ((smb_vfs_t *)arg0)->sv_refcnt);
+}
+
+sdt:smbsrv:smb_vfs_hold:smb_vfs_hold_miss
+{
+ printf("\nSMB VFS lookup miss");
+ printf("\n Path: %s", (string)((smb_vfs_t *)arg0)->sv_rootvp->v_path);
+ printf("\n RefCount: %d", ((smb_vfs_t *)arg0)->sv_refcnt);
+}
+
+sdt:smbsrv:smb_vfs_rele:smb_vfs_release
+/(smb_vfs_t *)arg0 != 0/
+{
+ printf("\nSMB VFS release hit");
+ printf("\n Path: %s", (string)((smb_vfs_t *)arg0)->sv_rootvp->v_path);
+ printf("\n RefCount: %d", ((smb_vfs_t *)arg0)->sv_refcnt - 2);
+}
+
+sdt:smbsrv:smb_vfs_rele:smb_vfs_release
+/(smb_vfs_t *)arg0 == 0/
+{
+ printf("\nSMB VFS release miss");
+ printf("\n Path: %s", (string)((vnode_t *)arg1)->v_path);
+}
+
+sdt:smbsrv:smb_vfs_rele_all:smb_vfs_rele_all_hit
+{
+ printf("\nSMB VFS free");
+ printf("\n Path: %s", (string)((smb_vfs_t *)arg0)->sv_rootvp->v_path);
+ printf("\n RefCount: %d", ((smb_vfs_t *)arg0)->sv_refcnt);
+}
+
+
diff --git a/usr/src/cmd/smbsrv/dtrace/stype.d b/usr/src/cmd/smbsrv/dtrace/stype.d
new file mode 100755
index 0000000000..19fef52dbe
--- /dev/null
+++ b/usr/src/cmd/smbsrv/dtrace/stype.d
@@ -0,0 +1,151 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option flowindent
+
+/*
+ * SmbSessionSetupX, SmbLogoffX and dispatcher
+ */
+smb_com_session_setup_andx:entry,
+smb_com_logoff_andx:entry,
+smb_com_session_setup_andx:return
+{
+}
+
+sdt:smbsrv::smb-dispatch-com
+{
+ printf("command=%d", ((smb_request_t *)arg0)->smb_com);
+}
+
+sdt:smbsrv::smb-sessionsetup-clntinfo
+{
+ clnt = (netr_client_t *)arg0;
+
+ printf("domain=%s\n\n", stringof(clnt->domain));
+ printf("username=%s\n\n", stringof(clnt->username));
+}
+
+smb_com_logoff_andx:return
+{
+ exit(0);
+}
+
+/*
+ * Raise error functions (no return).
+ */
+smbsr_raise_error:entry
+{
+ printf("class=%d code=%d", arg1, arg2);
+}
+
+smbsr_raise_cifs_error:entry
+{
+ printf("status=0x%08x class=%d, code=%d", arg1, arg2, arg3);
+}
+
+smbsr_raise_nt_error:entry
+{
+ printf("error=0x%08x", arg1);
+}
+
+smbsr_raise_errno:entry
+{
+ printf("errno=%d", arg1);
+}
+
+/*
+ * Share/tree connect.
+ */
+smbsr_setup_share:entry
+{
+ printf("sharename=%s stype=%d", stringof(arg1), arg2);
+ self->stype = arg2;
+}
+
+smbsr_setup_share:return
+{
+ self->stype = 0;
+}
+
+smbsr_connect_tree:entry
+{
+}
+
+smbsr_share_report:entry
+{
+ printf("%s: %s %s", stringof(arg1), stringof(arg2), stringof(arg3));
+}
+
+smbsr_connect_tree:return,
+smbsr_share_report:return,
+smb_pathname_reduce:return
+{
+ printf("rc=%d", arg1);
+}
+
+smb_get_stype:entry
+{
+ printf("share=%s service=%s", stringof(arg0), stringof(arg1));
+}
+
+smb_get_stype:return
+{
+ printf("%d", arg1);
+}
+
+smb_tree_connect:entry
+/self->stype == 0/
+{
+ printf("share=%s service=%s volname=%s",
+ stringof(arg3),
+ stringof(arg4),
+ stringof(((fsvol_attr_t *)arg7)->name));
+}
+
+smb_tree_connect:return
+/self->stype == 0/
+{
+ printf("FS=%s", stringof(((smb_tree_t *)arg1)->t_typename));
+}
+
+smb_pathname_reduce:entry
+{
+ printf("path=%s", stringof(arg2));
+}
+
+sdt:smbsrv::smb-vfs-volume
+{
+ printf("mntpnt=%s volname=%s", stringof(arg0), stringof(arg1));
+}
+
+sdt:smbsrv::smb-vfs-getflags
+{
+ printf("flags=0x%08x", arg0);
+}
diff --git a/usr/src/cmd/smbsrv/smbadm/Makefile b/usr/src/cmd/smbsrv/smbadm/Makefile
new file mode 100644
index 0000000000..9bf78a75c2
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbadm/Makefile
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG= smbadm
+SRCS= smbadm.c
+
+include ../../Makefile.cmd
+include ../Makefile.smbsrv.defs
+
+all: $(PROG)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_SRCS
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+include ../../Makefile.targ
+
+install: all .WAIT $(ROOTUSRSBINPROG)
diff --git a/usr/src/cmd/smbsrv/smbadm/smbadm.c b/usr/src/cmd/smbsrv/smbadm/smbadm.c
new file mode 100644
index 0000000000..98f61b2b9b
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbadm/smbadm.c
@@ -0,0 +1,1374 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module contains smbadm CLI which offers smb configuration
+ * functionalities.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <strings.h>
+#include <limits.h>
+#include <getopt.h>
+#include <libintl.h>
+#include <zone.h>
+#include <grp.h>
+#include <libgen.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+
+typedef enum {
+ HELP_ADD_MEMBER,
+ HELP_CREATE,
+ HELP_DELETE,
+ HELP_DEL_MEMBER,
+ HELP_GET,
+ HELP_JOIN,
+ HELP_LIST,
+ HELP_RENAME,
+ HELP_SET,
+ HELP_SHOW,
+ HELP_UDISABLE,
+ HELP_UENABLE
+} smbadm_help_t;
+
+typedef struct smbadm_cmdinfo {
+ char *name;
+ int (*func)(int, char **);
+ smbadm_help_t usage;
+} smbadm_cmdinfo_t;
+
+smbadm_cmdinfo_t *curcmd;
+static char *progname;
+
+static int smbadm_join(int, char **);
+static int smbadm_list(int, char **);
+static int smbadm_group_create(int, char **);
+static int smbadm_group_delete(int, char **);
+static int smbadm_group_rename(int, char **);
+static int smbadm_group_show(int, char **);
+static int smbadm_group_getprop(int, char **);
+static int smbadm_group_setprop(int, char **);
+static int smbadm_group_addmember(int, char **);
+static int smbadm_group_delmember(int, char **);
+static int smbadm_user_disable(int, char **);
+static int smbadm_user_enable(int, char **);
+
+static smbadm_cmdinfo_t smbadm_cmdtable[] =
+{
+ { "add-member", smbadm_group_addmember, HELP_ADD_MEMBER },
+ { "create", smbadm_group_create, HELP_CREATE },
+ { "delete", smbadm_group_delete, HELP_DELETE },
+ { "disable-user", smbadm_user_disable, HELP_UDISABLE },
+ { "enable-user", smbadm_user_enable, HELP_UENABLE },
+ { "get", smbadm_group_getprop, HELP_GET },
+ { "join", smbadm_join, HELP_JOIN },
+ { "list", smbadm_list, HELP_LIST },
+ { "remove-member", smbadm_group_delmember, HELP_DEL_MEMBER },
+ { "rename", smbadm_group_rename, HELP_RENAME },
+ { "set", smbadm_group_setprop, HELP_SET },
+ { "show", smbadm_group_show, HELP_SHOW },
+};
+
+#define SMBADM_NCMD (sizeof (smbadm_cmdtable) / sizeof (smbadm_cmdtable[0]))
+
+typedef struct smbadm_prop {
+ char *p_name;
+ char *p_value;
+} smbadm_prop_t;
+
+typedef struct smbadm_prop_handle {
+ char *p_name;
+ char *p_dispvalue;
+ int (*p_setfn)(char *, smbadm_prop_t *);
+ int (*p_getfn)(char *, smbadm_prop_t *);
+ boolean_t (*p_chkfn)(smbadm_prop_t *);
+} smbadm_prop_handle_t;
+
+static boolean_t smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval);
+static int smbadm_prop_parse(char *arg, smbadm_prop_t *prop);
+static smbadm_prop_handle_t *smbadm_prop_gethandle(char *pname);
+
+static boolean_t smbadm_chkprop_priv(smbadm_prop_t *prop);
+static int smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop);
+static int smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop);
+static int smbadm_setprop_backup(char *gname, smbadm_prop_t *prop);
+static int smbadm_getprop_backup(char *gname, smbadm_prop_t *prop);
+static int smbadm_setprop_restore(char *gname, smbadm_prop_t *prop);
+static int smbadm_getprop_restore(char *gname, smbadm_prop_t *prop);
+static int smbadm_setprop_desc(char *gname, smbadm_prop_t *prop);
+static int smbadm_getprop_desc(char *gname, smbadm_prop_t *prop);
+
+static smbadm_prop_handle_t smbadm_ptable[] = {
+ {"backup", "on | off", smbadm_setprop_backup,
+ smbadm_getprop_backup, smbadm_chkprop_priv },
+ {"restore", "on | off", smbadm_setprop_restore,
+ smbadm_getprop_restore, smbadm_chkprop_priv },
+ {"take-ownership", "on | off", smbadm_setprop_tkowner,
+ smbadm_getprop_tkowner, smbadm_chkprop_priv },
+ {"description", "<string>", smbadm_setprop_desc,
+ smbadm_getprop_desc, NULL },
+};
+
+static const char *smbadm_pwd_strerror(int error);
+
+/*
+ * Number of supported properties
+ */
+#define SMBADM_NPROP (sizeof (smbadm_ptable) / sizeof (smbadm_ptable[0]))
+
+static void
+smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd)
+{
+ switch (cmd->usage) {
+ case HELP_ADD_MEMBER:
+ (void) fprintf(fp,
+ gettext("\t%s -m member [[-m member] ...] group\n"),
+ cmd->name);
+ return;
+
+ case HELP_CREATE:
+ (void) fprintf(fp, gettext("\t%s [-d description] group\n"),
+ cmd->name);
+ return;
+
+ case HELP_DELETE:
+ (void) fprintf(fp, gettext("\t%s group\n"), cmd->name);
+ return;
+
+ case HELP_UDISABLE:
+ case HELP_UENABLE:
+ (void) fprintf(fp, gettext("\t%s user\n"), cmd->name);
+ return;
+
+ case HELP_GET:
+ (void) fprintf(fp, gettext("\t%s [[-p property] ...] group\n"),
+ cmd->name);
+ return;
+
+ case HELP_JOIN:
+ (void) fprintf(fp, gettext("\t%s -u username domain\n"
+ "\t%s -w workgroup\n"), cmd->name, cmd->name);
+ return;
+
+ case HELP_LIST:
+ (void) fprintf(fp, gettext("\t%s\n"), cmd->name);
+ return;
+
+ case HELP_DEL_MEMBER:
+ (void) fprintf(fp,
+ gettext("\t%s -m member [[-m member] ...] group\n"),
+ cmd->name);
+ return;
+
+ case HELP_RENAME:
+ (void) fprintf(fp, gettext("\t%s group new-group\n"),
+ cmd->name);
+ return;
+
+ case HELP_SET:
+ (void) fprintf(fp, gettext("\t%s -p property=value "
+ "[[-p property=value] ...] group\n"), cmd->name);
+ return;
+
+ case HELP_SHOW:
+ (void) fprintf(fp, gettext("\t%s [-m] [-p] [group]\n"),
+ cmd->name);
+ return;
+
+ }
+
+ abort();
+ /* NOTREACHED */
+}
+
+static void
+smbadm_usage(boolean_t requested)
+{
+ FILE *fp = requested ? stdout : stderr;
+ boolean_t show_props = B_FALSE;
+ int i;
+
+ if (curcmd == NULL) {
+ (void) fprintf(fp,
+ gettext("usage: %s [-h | <command> [options]]\n"),
+ progname);
+ (void) fprintf(fp,
+ gettext("where 'command' is one of the following:\n\n"));
+
+ for (i = 0; i < SMBADM_NCMD; i++)
+ smbadm_cmdusage(fp, &smbadm_cmdtable[i]);
+
+ (void) fprintf(fp,
+ gettext("\nFor property list, run %s %s|%s\n"),
+ progname, "get", "set");
+
+ exit(requested ? 0 : 2);
+ }
+
+ (void) fprintf(fp, gettext("usage:\n"));
+ smbadm_cmdusage(fp, curcmd);
+
+ if (strcmp(curcmd->name, "get") == 0 ||
+ strcmp(curcmd->name, "set") == 0)
+ show_props = B_TRUE;
+
+ if (show_props) {
+ (void) fprintf(fp,
+ gettext("\nThe following properties are supported:\n"));
+
+ (void) fprintf(fp, "\n\t%-16s %s\n\n",
+ "PROPERTY", "VALUES");
+
+ for (i = 0; i < SMBADM_NPROP; i++) {
+ (void) fprintf(fp, "\t%-16s %s\n",
+ smbadm_ptable[i].p_name,
+ smbadm_ptable[i].p_dispvalue);
+ }
+ }
+
+ exit(requested ? 0 : 2);
+}
+
+/*
+ * smbadm_join
+ *
+ * Join the given domain/workgroup
+ */
+static int
+smbadm_join(int argc, char **argv)
+{
+ char option;
+ smb_joininfo_t jdi;
+ boolean_t join_w = B_FALSE;
+ boolean_t join_d = B_FALSE;
+ uint32_t status;
+
+ bzero(&jdi, sizeof (jdi));
+
+ while ((option = getopt(argc, argv, "u:w:")) != -1) {
+ switch (option) {
+ case 'w':
+ (void) strlcpy(jdi.domain_name, optarg,
+ sizeof (jdi.domain_name));
+ jdi.mode = SMB_SECMODE_WORKGRP;
+ join_w = B_TRUE;
+ break;
+
+ case 'u':
+ /* admin username */
+ (void) strlcpy(jdi.domain_username, optarg,
+ sizeof (jdi.domain_username));
+ jdi.mode = SMB_SECMODE_DOMAIN;
+ join_d = B_TRUE;
+ break;
+
+ default:
+ smbadm_usage(B_FALSE);
+ }
+ }
+
+ if (join_w && join_d) {
+ (void) fprintf(stderr,
+ gettext("domain and workgroup "
+ "can not be specified together\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ if (join_d && (argv[optind] != NULL)) {
+ (void) strlcpy(jdi.domain_name, argv[optind],
+ sizeof (jdi.domain_name));
+ }
+
+ if (*jdi.domain_name == '\0') {
+ (void) fprintf(stderr, gettext("missing %s name\n"),
+ (join_d) ? "domain" : "workgroup");
+ smbadm_usage(B_FALSE);
+ }
+
+ if (join_d && *jdi.domain_username == '\0') {
+ (void) fprintf(stderr, gettext("missing username\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ if (join_w) {
+ status = smb_join(&jdi);
+ if (status == NT_STATUS_SUCCESS) {
+ (void) printf(
+ gettext("Successfully joined workgroup '%s'\n"),
+ jdi.domain_name);
+ return (0);
+ }
+
+ (void) fprintf(stderr,
+ gettext("failed to join workgroup '%s' (%s)\n"),
+ jdi.domain_name, xlate_nt_status(status));
+
+ return (1);
+ }
+
+ /* Join the domain */
+ if (*jdi.domain_passwd == '\0') {
+ char *p = NULL;
+ char *prompt = gettext("Enter domain password: ");
+ p = getpassphrase(prompt);
+ if (!p) {
+ (void) fprintf(stderr, gettext("missing password\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ (void) strlcpy(jdi.domain_passwd, p,
+ sizeof (jdi.domain_passwd));
+ }
+
+ (void) printf(gettext("Joining '%s' ... this may take a minute ...\n"),
+ jdi.domain_name);
+
+ status = smb_join(&jdi);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ (void) printf(gettext("Successfully joined domain '%s'\n"),
+ jdi.domain_name);
+ return (0);
+
+ case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
+ (void) fprintf(stderr, gettext("failed to find "
+ "any domain controllers for '%s'\n"),
+ jdi.domain_name);
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ gettext("failed to join domain '%s' (%s)\n"),
+ jdi.domain_name, xlate_nt_status(status));
+ }
+
+ return (1);
+}
+
+/*
+ * smbadm_list
+ *
+ * Displays current security mode and domain/workgroup name.
+ */
+/*ARGSUSED*/
+static int
+smbadm_list(int argc, char **argv)
+{
+ char resource_domain[SMB_PI_MAX_DOMAIN];
+ int sec_mode;
+ char *modename;
+
+ if (smbd_get_security_mode(&sec_mode)) {
+ (void) fprintf(stderr,
+ gettext("failed to get the security mode\n"));
+ return (1);
+ }
+
+ modename = (sec_mode == SMB_SECMODE_DOMAIN) ? "domain" : "workgroup";
+
+ (void) printf(gettext("security mode: %s\n"),
+ smb_config_secmode_tostr(sec_mode));
+
+ if (smbd_get_param(SMB_CI_DOMAIN_NAME, resource_domain) != 0) {
+ (void) fprintf(stderr,
+ gettext("failed to get the %s name\n"), modename);
+ return (1);
+ }
+
+ (void) printf(gettext("%s name: %s\n"),
+ modename, resource_domain);
+
+ return (0);
+}
+
+/*
+ * smbadm_group_create
+ *
+ * Creates a local SMB group
+ */
+static int
+smbadm_group_create(int argc, char **argv)
+{
+ char *gname = NULL;
+ char *desc = NULL;
+ char option;
+ uint32_t status;
+
+ while ((option = getopt(argc, argv, "d:")) != -1) {
+ switch (option) {
+ case 'd':
+ desc = optarg;
+ break;
+
+ default:
+ smbadm_usage(B_FALSE);
+ }
+ }
+
+ gname = argv[optind];
+ if (optind >= argc || gname == NULL || *gname == '\0') {
+ (void) fprintf(stderr, gettext("missing group name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ if (getgrnam(gname) == NULL) {
+ (void) fprintf(stderr,
+ gettext("failed to get the Solaris group\n"));
+ (void) fprintf(stderr,
+ gettext("use 'groupadd' to add the Solaris group\n"));
+ return (1);
+ }
+
+ status = smb_group_add(gname, desc);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to create the group (%s)\n"),
+ xlate_nt_status(status));
+ } else {
+ (void) printf(gettext("Successfully created group '%s'\n"),
+ gname);
+ }
+
+ return (status);
+}
+
+/*
+ * smbadm_group_dump_members
+ *
+ * Dump group members details.
+ */
+static void
+smbadm_group_dump_members(char *gname)
+{
+ ntgrp_member_list_t *members = NULL;
+ int mem_cnt = 0;
+ int offset = 0;
+ uint32_t status;
+ int i;
+
+ status = smb_group_member_count(gname, &mem_cnt);
+ if (mem_cnt < 0) {
+ (void) fprintf(stderr,
+ gettext("failed to get the group members (%s)\n"),
+ xlate_nt_status(status));
+ }
+
+ if (mem_cnt == 0) {
+ (void) printf(gettext("\tNo members\n"));
+ return;
+ }
+
+ (void) printf(gettext("\tMembers:\n"));
+ while (smb_group_member_list(gname, offset, &members) == 0) {
+ if (members == NULL)
+ break;
+
+ for (i = 0; i < members->cnt; i++)
+ (void) printf(gettext("\t\t%s\n"), members->members[i]);
+
+ offset += members->cnt;
+ smb_group_free_memberlist(members, 0);
+ if (offset >= mem_cnt)
+ break;
+ }
+}
+
+/*
+ * smbadm_group_dump_privs
+ *
+ * Dump group privilege details.
+ */
+static void
+smbadm_group_dump_privs(char *gname, ntpriv_list_t *privs)
+{
+ int privcnt = 0;
+ uint32_t privval;
+ char *name = NULL;
+ int i;
+
+ (void) printf(gettext("\tPrivileges: \n"));
+
+ for (i = 0; i < privs->cnt; i++) {
+ name = privs->privs[i]->name;
+ if (name == NULL)
+ continue;
+
+ if (smb_group_priv_get(gname, privs->privs[i]->id,
+ &privval) != 0) {
+ continue;
+ }
+
+ if (privval == SE_PRIVILEGE_ENABLED) {
+ (void) printf(gettext("\t\t%s: On\n"), name);
+ } else if (privval == SE_PRIVILEGE_DISABLED) {
+ (void) printf(gettext("\t\t%s: Off\n"), name);
+ } else {
+ (void) printf(gettext("\t\t%s: %d\n"),
+ name, privval);
+ }
+
+ name = NULL;
+ privcnt++;
+ }
+
+ if (privcnt == 0)
+ (void) printf(gettext("\t\tNo privileges\n"));
+}
+
+/*
+ * smbadm_group_dump
+ *
+ * Dump group details.
+ */
+static int
+smbadm_group_dump(ntgrp_list_t *list, boolean_t show_mem, boolean_t show_privs)
+{
+ ntpriv_list_t *privs = NULL;
+ char *gname;
+ uint32_t status;
+ int i;
+
+ if (show_privs) {
+ if ((status = smb_group_priv_list(&privs)) != 0) {
+ (void) fprintf(stderr,
+ gettext("failed to get privileges (%s)\n"),
+ xlate_nt_status(status));
+ return (1);
+ }
+ }
+
+ for (i = 0; i < list->cnt; i++) {
+ gname = list->groups[i].name;
+
+ (void) printf(gettext("%s (%s)\n"), gname,
+ list->groups[i].desc);
+ (void) printf(gettext("\tType: %s, Attr: %X\n"),
+ list->groups[i].type, list->groups[i].attr);
+ (void) printf(gettext("\tSID: %s\n"),
+ list->groups[i].sid);
+
+ if (show_privs)
+ smbadm_group_dump_privs(gname, privs);
+
+ if (show_mem)
+ smbadm_group_dump_members(list->groups[i].name);
+ }
+
+ return (0);
+}
+
+/*
+ * smbadm_group_show
+ *
+ */
+static int
+smbadm_group_show(int argc, char **argv)
+{
+ char *gname = NULL;
+ int cnt = 0;
+ int offset = 0;
+ boolean_t show_privs;
+ boolean_t show_members;
+ char option;
+ uint32_t status;
+ ntgrp_list_t *list = NULL;
+ int ret = 0;
+
+ show_privs = show_members = B_FALSE;
+
+ while ((option = getopt(argc, argv, "mp")) != -1) {
+ switch (option) {
+ case 'm':
+ show_members = B_TRUE;
+ break;
+ case 'p':
+ show_privs = B_TRUE;
+ break;
+
+ default:
+ smbadm_usage(B_FALSE);
+ }
+ }
+
+ gname = argv[optind];
+ if (optind >= argc || gname == NULL || *gname == '\0')
+ gname = "*";
+
+ status = smb_group_count(&cnt);
+ if ((status != NT_STATUS_SUCCESS) || (cnt < 0)) {
+ (void) fprintf(stderr,
+ gettext("failed to get the number of group(s) (%s)\n"),
+ xlate_nt_status(status));
+ return (1);
+ }
+
+ while ((offset < cnt)) {
+ status = smb_group_list(offset, &list, gname, 0);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to get the group(s) (%s)\n"),
+ xlate_nt_status(status));
+ return (1);
+ }
+
+ if ((list == NULL) || (list->cnt <= 0))
+ break;
+
+ ret = smbadm_group_dump(list, show_members, show_privs);
+ if (ret)
+ break;
+
+ offset += list->cnt;
+ smb_group_free_list(list, 0);
+ list = NULL;
+ }
+
+ return (ret);
+}
+
+/*
+ * smbadm_group_delete
+ *
+ */
+static int
+smbadm_group_delete(int argc, char **argv)
+{
+ uint32_t status;
+ char *gname = NULL;
+
+ gname = argv[optind];
+ if (optind >= argc || gname == NULL || *gname == '\0') {
+ (void) fprintf(stderr, gettext("missing group name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ status = smb_group_delete(gname);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to delete the group (%s)\n"),
+ xlate_nt_status(status));
+ } else {
+ (void) printf(gettext("Successfully deleted group '%s'\n"),
+ gname);
+ }
+
+ return (status);
+}
+
+/*
+ * smbadm_group_rename
+ *
+ */
+static int
+smbadm_group_rename(int argc, char **argv)
+{
+ char *gname = NULL;
+ char *ngname = NULL;
+ uint32_t status;
+
+ gname = argv[optind];
+ if (optind++ >= argc || gname == NULL || *gname == '\0') {
+ (void) fprintf(stderr, gettext("missing group name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ ngname = argv[optind];
+ if (optind >= argc || ngname == NULL || *ngname == '\0') {
+ (void) fprintf(stderr, gettext("missing new group name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ if (getgrnam(gname) == NULL) {
+ (void) fprintf(stderr,
+ gettext("failed to get the Solaris group\n"));
+ (void) fprintf(stderr,
+ gettext("use 'groupadd' to add the Solaris group\n"));
+ return (1);
+ }
+
+ status = smb_group_modify(gname, ngname, NULL);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to modify the group (%s)\n"),
+ xlate_nt_status(status));
+ } else {
+ (void) printf(gettext("Successfully modified "
+ "group '%s'\n"), gname);
+ }
+
+ return (status);
+}
+
+/*
+ * smbadm_group_setprop
+ *
+ * Set the group properties.
+ */
+static int
+smbadm_group_setprop(int argc, char **argv)
+{
+ char *gname = NULL;
+ smbadm_prop_t props[SMBADM_NPROP];
+ smbadm_prop_handle_t *phandle;
+ char option;
+ int pcnt = 0;
+ int ret;
+ int p;
+
+ bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t));
+
+ while ((option = getopt(argc, argv, "p:")) != -1) {
+ switch (option) {
+ case 'p':
+ if (pcnt >= SMBADM_NPROP) {
+ (void) fprintf(stderr,
+ gettext("exceeded number of supported"
+ " properties\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ ret = smbadm_prop_parse(optarg, &props[pcnt++]);
+ if (ret) {
+ if (ret == 1)
+ exit(1);
+
+ if (ret == 2)
+ smbadm_usage(B_FALSE);
+ }
+ break;
+
+ default:
+ smbadm_usage(B_FALSE);
+ }
+ }
+
+ if (pcnt == 0) {
+ (void) fprintf(stderr,
+ gettext("missing property=value argument\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ gname = argv[optind];
+ if (optind >= argc || gname == NULL || *gname == '\0') {
+ (void) fprintf(stderr, gettext("missing group name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ for (p = 0; p < pcnt; p++) {
+ phandle = smbadm_prop_gethandle(props[p].p_name);
+ if (phandle) {
+ if (phandle->p_setfn(gname, &props[p]) != 0)
+ ret = 1;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * smbadm_group_getprop
+ *
+ * Get the group properties.
+ */
+static int
+smbadm_group_getprop(int argc, char **argv)
+{
+ char *gname = NULL;
+ smbadm_prop_t props[SMBADM_NPROP];
+ smbadm_prop_handle_t *phandle;
+ char option;
+ int pcnt = 0;
+ int ret;
+ int p;
+
+ bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t));
+
+ while ((option = getopt(argc, argv, "p:")) != -1) {
+ switch (option) {
+ case 'p':
+ if (pcnt >= SMBADM_NPROP) {
+ (void) fprintf(stderr,
+ gettext("exceeded number of supported"
+ " properties\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ ret = smbadm_prop_parse(optarg, &props[pcnt++]);
+ if (ret) {
+ if (ret == 1)
+ exit(1);
+
+ if (ret == 2)
+ smbadm_usage(B_FALSE);
+ }
+ break;
+
+ default:
+ smbadm_usage(B_FALSE);
+ }
+ }
+
+ gname = argv[optind];
+ if (optind >= argc || gname == NULL || *gname == '\0') {
+ (void) fprintf(stderr, gettext("missing group name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ if (pcnt == 0) {
+ /*
+ * If no property has be specified then get
+ * all the properties.
+ */
+ pcnt = SMBADM_NPROP;
+ for (p = 0; p < pcnt; p++)
+ props[p].p_name = smbadm_ptable[p].p_name;
+ }
+
+ for (p = 0; p < pcnt; p++) {
+ phandle = smbadm_prop_gethandle(props[p].p_name);
+ if (phandle) {
+ if (phandle->p_getfn(gname, &props[p]) != 0)
+ ret = 1;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * smbadm_group_addmember
+ *
+ */
+static int
+smbadm_group_addmember(int argc, char **argv)
+{
+ char *gname = NULL;
+ char **mname;
+ char option;
+ uint32_t status;
+ int mcnt = 0;
+ int ret = 0;
+ int i;
+
+
+ mname = (char **)malloc(argc * sizeof (char *));
+ if (mname == NULL) {
+ (void) fprintf(stderr, gettext("out of memory\n"));
+ return (1);
+ }
+ bzero(mname, argc * sizeof (char *));
+
+ while ((option = getopt(argc, argv, "m:")) != -1) {
+ switch (option) {
+ case 'm':
+ mname[mcnt++] = optarg;
+ break;
+
+ default:
+ free(mname);
+ smbadm_usage(B_FALSE);
+ }
+ }
+
+ if (mcnt == 0) {
+ (void) fprintf(stderr, gettext("missing member name\n"));
+ free(mname);
+ smbadm_usage(B_FALSE);
+ }
+
+ gname = argv[optind];
+ if (optind >= argc || gname == NULL || *gname == 0) {
+ (void) fprintf(stderr, gettext("missing group name\n"));
+ free(mname);
+ smbadm_usage(B_FALSE);
+ }
+
+
+ for (i = 0; i < mcnt; i++) {
+ if (mname[i] == NULL)
+ continue;
+
+ status = smb_group_member_add(gname, mname[i]);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to add %s (%s)\n"),
+ mname[i], xlate_nt_status(status));
+ ret = 1;
+ }
+ else
+ (void) printf(gettext("Successfully added %s to %s\n"),
+ mname[i], gname);
+ }
+
+ free(mname);
+ return (ret);
+}
+
+/*
+ * smbadm_group_delmember
+ */
+static int
+smbadm_group_delmember(int argc, char **argv)
+{
+ char *gname = NULL;
+ char **mname;
+ char option;
+ uint32_t status;
+ int mcnt = 0;
+ int ret = 0;
+ int i;
+
+ mname = (char **)malloc(argc * sizeof (char *));
+ if (mname == NULL) {
+ (void) fprintf(stderr, gettext("out of memory\n"));
+ return (1);
+ }
+ bzero(mname, argc * sizeof (char *));
+
+ while ((option = getopt(argc, argv, "m:")) != -1) {
+ switch (option) {
+ case 'm':
+ mname[mcnt++] = optarg;
+ break;
+
+ default:
+ free(mname);
+ smbadm_usage(B_FALSE);
+ }
+ }
+
+ if (mcnt == 0) {
+ (void) fprintf(stderr, gettext("missing member name\n"));
+ free(mname);
+ smbadm_usage(B_FALSE);
+ }
+
+ gname = argv[optind];
+ if (optind >= argc || gname == NULL || *gname == 0) {
+ (void) fprintf(stderr, gettext("missing group name\n"));
+ free(mname);
+ smbadm_usage(B_FALSE);
+ }
+
+
+ for (i = 0; i < mcnt; i++) {
+ if (mname[i] == NULL)
+ continue;
+
+ status = smb_group_member_remove(gname, mname[i]);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to remove %s (%s)\n"),
+ mname[i], xlate_nt_status(status));
+ ret = 1;
+ } else {
+ (void) printf(
+ gettext("Successfully removed %s from %s\n"),
+ mname[i], gname);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+smbadm_user_disable(int argc, char **argv)
+{
+ int error;
+ char *user = NULL;
+
+ user = argv[optind];
+ if (optind >= argc || user == NULL || *user == '\0') {
+ (void) fprintf(stderr, gettext("missing user name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ error = smb_pwd_setcntl(user, SMB_PWC_DISABLE);
+ if (error == SMB_PWE_SUCCESS)
+ (void) printf(gettext("%s is disabled.\n"), user);
+ else
+ (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
+
+ return (error);
+}
+
+static int
+smbadm_user_enable(int argc, char **argv)
+{
+ int error;
+ char *user = NULL;
+
+ user = argv[optind];
+ if (optind >= argc || user == NULL || *user == '\0') {
+ (void) fprintf(stderr, gettext("missing user name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ error = smb_pwd_setcntl(user, SMB_PWC_ENABLE);
+ if (error == SMB_PWE_SUCCESS)
+ (void) printf(gettext("%s is enabled.\n"), user);
+ else
+ (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
+
+ return (error);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ (void) malloc(0); /* satisfy libumem dependency */
+
+ progname = basename(argv[0]);
+
+ if (getzoneid() != GLOBAL_ZONEID) {
+ (void) fprintf(stderr,
+ gettext("cannot execute in non-global zone\n"));
+ return (0);
+ }
+
+ if (is_system_labeled()) {
+ (void) fprintf(stderr,
+ gettext("Trusted Extensions not supported\n"));
+ return (0);
+ }
+
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing command\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ /*
+ * Special case "cmd --help/-?"
+ */
+ if (strcmp(argv[1], "-?") == 0 ||
+ strcmp(argv[1], "--help") == 0 ||
+ strcmp(argv[1], "-h") == 0)
+ smbadm_usage(B_TRUE);
+
+ for (i = 0; i < SMBADM_NCMD; ++i) {
+ curcmd = &smbadm_cmdtable[i];
+ if (strcasecmp(argv[1], curcmd->name) == 0) {
+ if (argc > 2) {
+ /* cmd subcmd --help/-? */
+ if (strcmp(argv[2], "-?") == 0 ||
+ strcmp(argv[2], "--help") == 0 ||
+ strcmp(argv[2], "-h") == 0)
+ smbadm_usage(B_TRUE);
+ }
+
+ return (curcmd->func(argc - 1, &argv[1]));
+ }
+ }
+
+ curcmd = NULL;
+ (void) fprintf(stderr, gettext("unknown subcommand (%s)\n"), argv[1]);
+ smbadm_usage(B_FALSE);
+ return (2);
+}
+
+static boolean_t
+smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval)
+{
+ smbadm_prop_handle_t *pinfo;
+ int i;
+
+ for (i = 0; i < SMBADM_NPROP; i++) {
+ pinfo = &smbadm_ptable[i];
+ if (strcmp(pinfo->p_name, prop->p_name) == 0) {
+ if (pinfo->p_chkfn && chkval)
+ return (pinfo->p_chkfn(prop));
+
+ return (B_TRUE);
+ }
+ }
+
+ (void) fprintf(stderr,
+ gettext("unrecognized property '%s'\n"), prop->p_name);
+
+ return (B_FALSE);
+}
+
+static int
+smbadm_prop_parse(char *arg, smbadm_prop_t *prop)
+{
+ boolean_t parse_value;
+ char *equal;
+
+ if (arg == NULL)
+ return (2);
+
+ prop->p_name = prop->p_value = NULL;
+
+ if (strcmp(curcmd->name, "set") == 0)
+ parse_value = B_TRUE;
+ else
+ parse_value = B_FALSE;
+
+ prop->p_name = arg;
+
+ if (parse_value) {
+ equal = strchr(arg, '=');
+ if (equal == NULL)
+ return (2);
+
+ *equal++ = '\0';
+ prop->p_value = equal;
+ }
+
+ if (smbadm_prop_validate(prop, parse_value) == B_FALSE)
+ return (2);
+
+ return (0);
+}
+
+static smbadm_prop_handle_t *
+smbadm_prop_gethandle(char *pname)
+{
+ int i;
+
+ for (i = 0; i < SMBADM_NPROP; i++)
+ if (strcmp(pname, smbadm_ptable[i].p_name) == 0)
+ return (&smbadm_ptable[i]);
+
+ return (NULL);
+}
+
+static int
+smbadm_setprop_desc(char *gname, smbadm_prop_t *prop)
+{
+ uint32_t status;
+
+ status = smb_group_modify(gname, gname, prop->p_value);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to modify the group description (%s)\n"),
+ xlate_nt_status(status));
+ return (1);
+ }
+
+ (void) printf(gettext("Successfully modified "
+ "'%s' description\n"), gname);
+
+ return (0);
+}
+
+static int
+smbadm_getprop_desc(char *gname, smbadm_prop_t *prop)
+{
+ uint32_t status;
+ ntgrp_list_t *list = NULL;
+
+ status = smb_group_list(0, &list, gname, 0);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to get the %s (%s)\n"),
+ prop->p_name, xlate_nt_status(status));
+ return (1);
+ }
+
+ if ((list == NULL) || (list->cnt <= 0)) {
+ (void) fprintf(stderr, gettext("%s: no such group\n"), gname);
+ return (1);
+ }
+
+ (void) printf(gettext("\t%s: %s\n"), prop->p_name,
+ list->groups[0].desc);
+ smb_group_free_list(list, 0);
+ return (0);
+}
+
+static int
+smbadm_group_setpriv(char *gname, uint32_t priv_id, smbadm_prop_t *prop)
+{
+ uint32_t priv_attr;
+ uint32_t status;
+ int ret;
+
+ if (strcasecmp(prop->p_value, "on") == 0) {
+ (void) printf(gettext("Enabling %s privilege "), prop->p_name);
+ priv_attr = SE_PRIVILEGE_ENABLED;
+ } else {
+ (void) printf(gettext("Disabling %s privilege "), prop->p_name);
+ priv_attr = SE_PRIVILEGE_DISABLED;
+ }
+
+ status = smb_group_priv_set(gname, priv_id, priv_attr);
+
+ if (status == NT_STATUS_SUCCESS) {
+ (void) printf(gettext("succeeded\n"));
+ ret = 0;
+ } else {
+ (void) printf(gettext("failed: %s\n"), xlate_nt_status(status));
+ ret = 1;
+ }
+
+ return (ret);
+}
+
+static int
+smbadm_group_getpriv(char *gname, uint32_t priv_id, smbadm_prop_t *prop)
+{
+ uint32_t priv_attr;
+ uint32_t status;
+
+ status = smb_group_priv_get(gname, priv_id, &priv_attr);
+ if (status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr, gettext("failed to get %s (%s)\n"),
+ prop->p_name, xlate_nt_status(status));
+ return (1);
+ }
+
+ if (priv_attr == SE_PRIVILEGE_ENABLED)
+ (void) printf(gettext("\t%s: %s\n"), prop->p_name, "On");
+ else if (priv_attr == SE_PRIVILEGE_DISABLED)
+ (void) printf(gettext("\t%s: %s\n"), prop->p_name, "Off");
+ else
+ (void) printf(gettext("\t%s: %s\n"), prop->p_name, "Unknown");
+
+ return (0);
+}
+
+static int
+smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop)
+{
+ return (smbadm_group_setpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop));
+}
+
+static int
+smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop)
+{
+ return (smbadm_group_getpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop));
+}
+
+static int
+smbadm_setprop_backup(char *gname, smbadm_prop_t *prop)
+{
+ return (smbadm_group_setpriv(gname, SE_BACKUP_LUID, prop));
+}
+
+static int
+smbadm_getprop_backup(char *gname, smbadm_prop_t *prop)
+{
+ return (smbadm_group_getpriv(gname, SE_BACKUP_LUID, prop));
+}
+
+static int
+smbadm_setprop_restore(char *gname, smbadm_prop_t *prop)
+{
+ return (smbadm_group_setpriv(gname, SE_RESTORE_LUID, prop));
+}
+
+static int
+smbadm_getprop_restore(char *gname, smbadm_prop_t *prop)
+{
+ return (smbadm_group_getpriv(gname, SE_RESTORE_LUID, prop));
+}
+
+static boolean_t
+smbadm_chkprop_priv(smbadm_prop_t *prop)
+{
+ if (prop->p_value == NULL || *prop->p_value == '\0') {
+ (void) fprintf(stderr,
+ gettext("missing value for '%s'\n"), prop->p_name);
+ return (B_FALSE);
+ }
+
+ if (strcasecmp(prop->p_value, "on") == 0)
+ return (B_TRUE);
+
+ if (strcasecmp(prop->p_value, "off") == 0)
+ return (B_TRUE);
+
+ (void) fprintf(stderr,
+ gettext("%s: unrecognized value for '%s' property\n"),
+ prop->p_value, prop->p_name);
+
+ return (B_FALSE);
+}
+
+static const char *
+smbadm_pwd_strerror(int error)
+{
+ switch (error) {
+ case SMB_PWE_SUCCESS:
+ return (gettext("Success."));
+
+ case SMB_PWE_USER_UNKNOWN:
+ return (gettext("User does not exist."));
+
+ case SMB_PWE_USER_DISABLE:
+ return (gettext("User is disable."));
+
+ case SMB_PWE_CLOSE_FAILED:
+ case SMB_PWE_OPEN_FAILED:
+ case SMB_PWE_WRITE_FAILED:
+ case SMB_PWE_UPDATE_FAILED:
+ return (gettext("Unexpected failure. "
+ "SMB password database unchanged."));
+
+ case SMB_PWE_STAT_FAILED:
+ return (gettext("stat of SMB password file failed."));
+
+ case SMB_PWE_BUSY:
+ return (gettext("SMB password database busy. "
+ "Try again later."));
+
+ case SMB_PWE_DENIED:
+ return (gettext("Operation not permitted."));
+
+ case SMB_PWE_SYSTEM_ERROR:
+ return (gettext("System error."));
+ }
+
+ return (gettext("Unknown error code."));
+}
+
+/*
+ * Enable libumem debugging by default on DEBUG builds.
+ */
+#ifdef DEBUG
+/* LINTED - external libumem symbol */
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+/* LINTED - external libumem symbol */
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+#endif
diff --git a/usr/src/cmd/smbsrv/smbd/Makefile b/usr/src/cmd/smbsrv/smbd/Makefile
new file mode 100644
index 0000000000..725ebf7a63
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/Makefile
@@ -0,0 +1,78 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG= smbd
+SRCS= \
+ smbd_door_ops.c \
+ smbd_door_server.c \
+ smbd_doorsvc.c \
+ smbd_join.c \
+ smbd_logon.c \
+ smbd_main.c \
+ smbd_mlsvc_doorsvc.c \
+ smbd_nicmon.c \
+ smbd_share_doorsvc.c
+
+include ../../Makefile.cmd
+
+MANIFEST = server.xml
+
+ROOTMANIFESTDIR = $(ROOTSVCSMB)
+$(ROOTMANIFEST):= FILEMODE = 0444
+
+include ../Makefile.smbsrv.defs
+
+LDLIBS += -lmlsvc -lmlrpc -lsmbrdr -lsmbns -lbsm -lnsl -lsocket
+
+ROOTSMBDDIR = $(ROOTLIB)/smbsrv
+ROOTSMBDFILE = $(PROG:%=$(ROOTSMBDDIR)/%)
+
+FILEMODE = 0444
+$(ROOTSMBDFILE):= FILEMODE = 0555
+
+$(ROOTSMBDDIR)/%: %
+ $(INS.file)
+
+all: $(PROG)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_SRCS
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+check: $(CHKMANIFEST)
+
+_msg:
+
+include ../../Makefile.targ
+
+install: all .WAIT $(ROOTETCDEFAULTFILES) $(ROOTMANIFEST) \
+ $(ROOTSMBDFILE)
diff --git a/usr/src/cmd/smbsrv/smbd/server.xml b/usr/src/cmd/smbsrv/smbd/server.xml
new file mode 100644
index 0000000000..879ca260a8
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/server.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+
+ 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.
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+
+-->
+
+<service_bundle type='manifest' name='SUNWsmbsr:smb-server'>
+
+<!-- 1. Name the service to 'network/smb/server' -->
+<service
+ name='network/smb/server'
+ type='service'
+ version='1'>
+
+ <!-- 2. Create default service instance. -->
+ <create_default_instance enabled='false' />
+
+ <!-- 3. Service has single instance -->
+ <single_instance/>
+
+ <!-- 4. Identify dependencies -->
+
+ <dependency name='network'
+ grouping='require_any'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/milestone/network'/>
+ </dependency>
+
+ <!-- Must have all local filesystems mounted before we share them -->
+ <dependency name='filesystem-local'
+ grouping='require_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/local'/>
+ </dependency>
+
+ <!-- Must have idmap service started -->
+ <dependency name='idmap'
+ grouping='require_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/system/idmap:default'/>
+ </dependency>
+
+ <!--
+ Want to make sure that the network/shares/group service
+ starts after the smb/server service. It needs to be
+ optional in order to not cause failure if smb is
+ disabled.
+ -->
+ <dependent name='groups'
+ grouping="optional_all"
+ restart_on='error' >
+ <service_fmri value='svc:/network/shares/group'/>
+ </dependent>
+
+ <!-- 5. Identify start/stop/refresh methods -->
+ <exec_method
+ type='method'
+ name='start'
+ exec='/usr/lib/smbsrv/smbd %m'
+ timeout_seconds='60' >
+ <method_context>
+ <method_credential
+ user='root'
+ group='sys'
+ privileges='basic,net_mac_aware,net_privaddr,proc_audit,sys_devices,sys_smb' />
+ </method_context>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <exec_method
+ type='method'
+ name='refresh'
+ exec=':kill -HUP'
+ timeout_seconds='60' />
+
+ <property_group name='general' type='framework'>
+ <!-- To Start/Stop/Refresh the service -->
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.smb' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.manage.smb' />
+ </property_group>
+
+ <property_group name='read' type='application'>
+ <!-- To read protected parameters -->
+ <propval name='read_authorization' type='astring'
+ value='solaris.smf.read.smb' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.smb' />
+ <propval name='rdr_ipcuser' type='astring' value='' />
+ <propval name='rdr_ipcpasswd' type='astring' value='' />
+ <propval name='ads_user' type='astring' value='' />
+ <propval name='ads_passwd' type='astring' value='' />
+ <propval name='machine_passwd' type='astring' value='' />
+ </property_group>
+
+ <!-- SMB service-specific general configuration defaults -->
+ <property_group name='smbd' type='application'>
+ <stability value='Evolving' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.smb' />
+ <propval name='rdr_ipcmode' type='astring'
+ value='auth' override='true'/>
+ <propval name='oplock_enable' type='boolean'
+ value='false' override='true'/>
+ <propval name='oplock_timeout' type='integer'
+ value='15000' override='true'/>
+ <propval name='autohome_map' type='astring'
+ value='/etc' override='true'/>
+ <propval name='domain_sid' type='astring'
+ value='' override='true'/>
+ <propval name='domain_member' type='boolean'
+ value='false' override='true'/>
+ <propval name='domain_name' type='astring'
+ value='WORKGROUP' override='true'/>
+ <propval name='pdc' type='astring'
+ value='' override='true'/>
+ <propval name='wins_server_1' type='astring'
+ value='' override='true'/>
+ <propval name='wins_server_2' type='astring'
+ value='' override='true'/>
+ <propval name='wins_exclude' type='astring'
+ value='' override='true'/>
+ <propval name='srvsvc_sharesetinfo_enable' type='boolean'
+ value='false' override='true'/>
+ <propval name='logr_enable' type='boolean'
+ value='false' override='true'/>
+ <propval name='mlrpc_keep_alive_interval' type='integer'
+ value='30' override='true'/>
+ <propval name='max_bufsize' type='integer'
+ value='37' override='true'/>
+ <propval name='max_workers' type='integer'
+ value='64' override='true'/>
+ <propval name='max_connections' type='integer'
+ value='-1' override='true'/>
+ <propval name='keep_alive' type='integer'
+ value='5400' override='true'/>
+ <propval name='restrict_anonymous' type='boolean'
+ value='false' override='true'/>
+ <propval name='signing_enabled' type='boolean'
+ value='false' override='true'/>
+ <propval name='signing_required' type='boolean'
+ value='false' override='true'/>
+ <propval name='signing_check' type='boolean'
+ value='false' override='true'/>
+ <propval name='flush_required' type='boolean'
+ value='false' override='true'/>
+ <propval name='sync_enable' type='boolean'
+ value='false' override='true'/>
+ <propval name='dir_symlink_disable' type='boolean'
+ value='false' override='true'/>
+ <propval name='announce_quota' type='boolean'
+ value='false' override='true'/>
+ <propval name='security' type='astring'
+ value='workgroup' override='true'/>
+ <propval name='netbios_scope' type='astring'
+ value='' override='true'/>
+ <propval name='system_comment' type='astring'
+ value='' override='true'/>
+ <propval name='lmauth_level' type='integer'
+ value='4' override='true'/>
+ <propval name='msdcs_disable' type='boolean'
+ value='false' override='true'/>
+ <propval name='ads_enable' type='boolean'
+ value='false' override='true'/>
+ <propval name='ads_domain' type='astring'
+ value='' override='true'/>
+ <propval name='ads_site' type='astring'
+ value='' override='true'/>
+ <propval name='ads_user_container' type='astring'
+ value='cn=Users' override='true'/>
+ <propval name='ads_ip_lookup' type='boolean'
+ value='false' override='true'/>
+ <propval name='ddns_enable' type='boolean'
+ value='false' override='true'/>
+ <propval name='ddns_retry_cnt' type='integer'
+ value='3' override='true'/>
+ <propval name='ddns_retry_sec' type='integer'
+ value='2' override='true'/>
+ </property_group>
+
+ <!-- 6. Identify faults to be ignored. -->
+ <!-- 7. Identify service model. Default service model is 'contract' -->
+ <!-- 8. Identify dependents.
+ For Solaris NAS, we may want to have the smbd service start,
+ before it reaches the svc:/milestone/multi-user-server
+ milestone.
+ <dependent
+ name='smb-server_multi-user-server'
+ grouping='optional_all'
+ restart_on='none'>
+ <service_fmri value=
+ 'svc:/milestone/multi-user-server'/>
+ </dependent>
+ -->
+ <!-- 9. Insert service milestones. None. -->
+
+ <stability value='Evolving' />
+
+ <!-- 10. Create Service Template information -->
+ <template>
+ <common_name>
+ <loctext xml:lang='C'> smbd daemon</loctext>
+ </common_name>
+ <documentation>
+ <manpage title='smbd' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/smbsrv/smbd/smbd.h b/usr/src/cmd/smbsrv/smbd/smbd.h
new file mode 100644
index 0000000000..27cd6f02e6
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBD_H
+#define _SMBD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <smbsrv/smb_token.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+
+extern int smb_nicmon_start(void);
+extern void smb_nicmon_stop(void);
+extern int smb_mlsvc_srv_start(void);
+extern void smb_mlsvc_srv_stop(void);
+extern int smb_lmshrd_srv_start(void);
+extern void smb_lmshrd_srv_stop(void);
+
+extern int smb_doorsrv_start(void);
+extern void smb_doorsrv_stop(void);
+extern int smb_ntgroup_doorsrv_start(void);
+extern void smb_ntgroup_doorsrv_stop(void);
+
+extern int smb_netlogon_init(void);
+
+extern smb_token_t *smbd_user_auth_logon(netr_client_t *);
+extern void smbd_user_nonauth_logon(uint32_t);
+extern void smbd_user_auth_logoff(uint32_t);
+
+typedef struct smbd {
+ const char *s_version; /* smbd version string */
+ const char *s_pname; /* basename to use for messages */
+ pid_t s_pid; /* process-ID of current daemon */
+ uid_t s_uid; /* UID of current daemon */
+ gid_t s_gid; /* GID of current daemon */
+ int s_fg; /* Run in foreground */
+ int s_drv_fd; /* Handle for SMB kernel driver */
+ int s_shutdown_flag; /* Fields for shutdown control */
+ int s_sigval;
+} smbd_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBD_H */
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_door_ops.c b/usr/src/cmd/smbsrv/smbd/smbd_door_ops.c
new file mode 100644
index 0000000000..5b1634a719
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_door_ops.c
@@ -0,0 +1,916 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMBd door operations
+ */
+#include <stdlib.h>
+#include <synch.h>
+#include <strings.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/libmlsvc.h>
+#include "smbd.h"
+
+static int smb_set_downcall_desc(int desc);
+static int smb_get_downcall_desc(void);
+
+static char *smb_dop_set_dwncall_desc(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_user_auth_logon(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_user_nonauth_logon(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_user_auth_logoff(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+
+static char *smb_dop_user_list(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+
+static char *smb_dop_group_add(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_delete(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_member_add(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_member_remove(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_count(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_cachesize(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_modify(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_priv_num(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_priv_list(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_priv_get(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_priv_set(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_list(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_member_list(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_group_member_count(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+
+/* SMB daemon's door operation table */
+smb_dr_op_t smb_doorsrv_optab[] =
+{
+ smb_dop_user_auth_logon,
+ smb_dop_set_dwncall_desc,
+ smb_dop_user_nonauth_logon,
+ smb_dop_user_auth_logoff,
+ smb_dop_user_list,
+ smb_dop_group_add,
+ smb_dop_group_delete,
+ smb_dop_group_member_add,
+ smb_dop_group_member_remove,
+ smb_dop_group_count,
+ smb_dop_group_cachesize,
+ smb_dop_group_modify,
+ smb_dop_group_priv_num,
+ smb_dop_group_priv_list,
+ smb_dop_group_priv_get,
+ smb_dop_group_priv_set,
+ smb_dop_group_list,
+ smb_dop_group_member_list,
+ smb_dop_group_member_count
+};
+
+/*ARGSUSED*/
+static char *
+smb_dop_user_nonauth_logon(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *buf;
+ uint32_t sid;
+
+ if (smb_dr_decode_common(argp, arg_size, xdr_uint32_t, &sid) != 0) {
+ *rbufsize = 0;
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ smbd_user_nonauth_logon(sid);
+
+ if ((buf = smb_dr_set_res_stat(SMB_DR_OP_SUCCESS, rbufsize)) == NULL) {
+ *rbufsize = 0;
+ *err = SMB_DR_OP_ERR_ENCODE;
+ return (NULL);
+ }
+
+ *err = SMB_DR_OP_SUCCESS;
+ return (buf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_user_auth_logoff(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *buf;
+ uint32_t sid;
+
+ if (smb_dr_decode_common(argp, arg_size, xdr_uint32_t, &sid) != 0) {
+ *rbufsize = 0;
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ smbd_user_auth_logoff(sid);
+
+ if ((buf = smb_dr_set_res_stat(SMB_DR_OP_SUCCESS, rbufsize)) == NULL) {
+ *rbufsize = 0;
+ *err = SMB_DR_OP_ERR_ENCODE;
+ return (NULL);
+ }
+
+ *err = SMB_DR_OP_SUCCESS;
+ return (buf);
+}
+
+/*
+ * smb_downcall_desc
+ *
+ * This downcall descriptor will be initialized when the SMB Kmod
+ * makes a upcall for the SMBD_DOOR_SET_DOWNCALL_DESC.
+ * This descriptor should be passed as the 1st argument to the
+ * door_call() whenever the SMBD is making a downcall to SMB Kmod.
+ */
+static int smb_downcall_desc = -1;
+static mutex_t smb_downcall_mutex;
+
+/*
+ * Get and set the smb downcall descriptor.
+ */
+static int
+smb_set_downcall_desc(int desc)
+{
+ (void) mutex_lock(&smb_downcall_mutex);
+ smb_downcall_desc = desc;
+ (void) mutex_unlock(&smb_downcall_mutex);
+ return (0);
+}
+
+/*
+ * smb_get_downcall_desc
+ *
+ * Returns the downcall descriptor.
+ */
+static int
+smb_get_downcall_desc(void)
+{
+ int rc;
+
+ (void) mutex_lock(&smb_downcall_mutex);
+ rc = smb_downcall_desc;
+ (void) mutex_unlock(&smb_downcall_mutex);
+ return (rc);
+}
+
+/*
+ * smb_dr_is_valid_opcode
+ *
+ * Validates the given door opcode.
+ */
+int
+smb_dr_is_valid_opcode(int opcode)
+{
+ if (opcode < 0 ||
+ opcode > (sizeof (smb_doorsrv_optab) / sizeof (smb_dr_op_t)))
+ return (-1);
+ else
+ return (0);
+}
+
+/*
+ * Obtains an access token on successful user authentication.
+ */
+/*ARGSUSED*/
+static char *
+smb_dop_user_auth_logon(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t n_desc, size_t *rbufsize, int *err)
+{
+ netr_client_t *clnt_info;
+ smb_token_t *token;
+ char *buf;
+
+ *rbufsize = 0;
+ *err = 0;
+ clnt_info = smb_dr_decode_arg_get_token(argp, arg_size);
+ if (clnt_info == NULL) {
+ syslog(LOG_ERR, "smbd: clnt_info is NULL");
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ token = smbd_user_auth_logon(clnt_info);
+
+ free(clnt_info);
+
+ if (!token) {
+ *err = SMB_DR_OP_ERR_EMPTYBUF;
+ return (NULL);
+ }
+
+ if ((buf = smb_dr_encode_res_token(token, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ }
+
+ smb_token_destroy(token);
+ return (buf);
+}
+
+/*
+ * smb_dop_set_dwncall_desc
+ *
+ * Set the downcall descriptor.
+ */
+/*ARGSUSED*/
+static char *
+smb_dop_set_dwncall_desc(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *buf = NULL;
+ uint32_t stat;
+
+ *rbufsize = 0;
+ *err = 0;
+
+ if (n_desc != 1 ||
+ smb_set_downcall_desc(dp->d_data.d_desc.d_descriptor) != 0) {
+ stat = SMB_DR_OP_ERR;
+ } else {
+ /* install get downcall descriptor callback */
+ (void) smb_dwncall_install_callback(smb_get_downcall_desc);
+ stat = SMB_DR_OP_SUCCESS;
+ }
+ if ((buf = smb_dr_set_res_stat(stat, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ return (buf);
+}
+
+/*
+ * smb_dr_op_users
+ *
+ * This function will obtain information on the connected users
+ * starting at the given offset by making a door down-call. The
+ * information will then be returned to the user-space door client.
+ *
+ * At most 50 users (i.e. SMB_DR_MAX_USER) will be returned via this
+ * function. The user-space door client might need to make multiple
+ * calls to retrieve information on all connected users.
+ */
+/*ARGSUSED*/
+char *
+smb_dop_user_list(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ smb_dr_ulist_t *ulist;
+ uint32_t offset;
+ char *rbuf = NULL;
+ int cnt = 0;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+ if (smb_dr_decode_common(argp, arg_size, xdr_uint32_t, &offset) != 0) {
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ ulist = malloc(sizeof (smb_dr_ulist_t));
+ if (!ulist) {
+ *err = SMB_DR_OP_ERR_EMPTYBUF;
+ return (NULL);
+ }
+
+ cnt = smb_dwncall_get_users(offset, ulist);
+ if (cnt < 0) {
+ *err = SMB_DR_OP_ERR_EMPTYBUF;
+ free(ulist);
+ return (NULL);
+ }
+
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, ulist,
+ xdr_smb_dr_ulist_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ smb_dr_ulist_free(ulist);
+ return (rbuf);
+}
+
+/* NT Group door operations start from here */
+/*ARGSUSED*/
+static char *
+smb_dop_group_add(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ ntgrp_dr_arg_t *args;
+ uint32_t ntstatus = NT_STATUS_UNSUCCESSFUL;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_dop_group_add: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ if (smb_dr_decode_common(argp, arg_size,
+ xdr_ntgrp_dr_arg_t, args) != 0) {
+ free(args);
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ ntstatus = nt_group_add(args->gname, args->desc);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &ntstatus,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ free(args);
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_delete(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *gname = NULL;
+ char *rbuf = NULL;
+ uint32_t ntstatus = NT_STATUS_UNSUCCESSFUL;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((gname = smb_dr_decode_string(argp, arg_size)) == 0) {
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ ntstatus = nt_group_delete(gname);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &ntstatus,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_member_add(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ ntgrp_dr_arg_t *args;
+ nt_group_t *grp = NULL;
+ uint32_t ntstatus = NT_STATUS_UNSUCCESSFUL;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_dop_group_member_add: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ if (smb_dr_decode_common(argp, arg_size,
+ xdr_ntgrp_dr_arg_t, args) != 0) {
+ free(args);
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ grp = nt_group_getinfo(args->gname, RWLOCK_WRITER);
+ if (grp) {
+ ntstatus = nt_group_add_member_byname(args->gname,
+ args->member);
+ } else {
+ ntstatus = NT_STATUS_NO_SUCH_GROUP;
+ }
+ nt_group_putinfo(grp);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &ntstatus,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+ free(args);
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_member_remove(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ ntgrp_dr_arg_t *args;
+ nt_group_t *grp = NULL;
+ uint32_t ntstatus = NT_STATUS_UNSUCCESSFUL;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_dop_group_member_add: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ if (smb_dr_decode_common(argp, arg_size,
+ xdr_ntgrp_dr_arg_t, args) != 0) {
+ free(args);
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ grp = nt_group_getinfo(args->gname, RWLOCK_WRITER);
+ if (grp) {
+ ntstatus = nt_group_del_member_byname(grp, args->member);
+ } else {
+ ntstatus = NT_STATUS_NO_SUCH_GROUP;
+ }
+ nt_group_putinfo(grp);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &ntstatus,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ free(args);
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_count(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ int num = 0;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ num = nt_group_num_groups();
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &num,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_cachesize(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ int num = 0;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ num = nt_group_cache_size();
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &num,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_modify(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ ntgrp_dr_arg_t *args;
+ nt_group_t *grp = NULL;
+ uint32_t ntstatus = NT_STATUS_UNSUCCESSFUL;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_dop_group_modify: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ if (smb_dr_decode_common(argp, arg_size,
+ xdr_ntgrp_dr_arg_t, args) != 0) {
+ free(args);
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ grp = nt_group_getinfo(args->gname, RWLOCK_WRITER);
+ if (grp) {
+ if (!args->desc)
+ args->desc = grp->comment;
+ ntstatus = nt_group_modify(args->gname,
+ args->newgname, args->desc);
+ } else {
+ ntstatus = NT_STATUS_NO_SUCH_GROUP;
+ }
+ nt_group_putinfo(grp);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &ntstatus,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+ free(args);
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_priv_num(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ int num = 0;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ num = smb_priv_presentable_num();
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &num,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_priv_list(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ int num = 0, i, len = 0;
+ uint32_t *ids = NULL;
+ smb_privinfo_t *priv = NULL;
+ ntpriv_list_t *list;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ num = smb_priv_presentable_num();
+ if (num > 0) {
+ len = sizeof (int) + (num * sizeof (privs_t *));
+ if ((ids = malloc(num * sizeof (uint32_t))) == 0) {
+ syslog(LOG_ERR, "smb_dop_group_priv_list:"
+ "cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+
+ if ((list = (ntpriv_list_t *)malloc(len)) == 0) {
+ syslog(LOG_ERR, "smb_dop_group_priv_list:"
+ "cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ free(ids);
+ return (NULL);
+ }
+
+ list->cnt = num;
+ (void) smb_priv_presentable_ids(ids, num);
+ for (i = 0; i < num; i++) {
+ if ((list->privs[i] = malloc(sizeof (ntpriv_t))) == 0) {
+ *err = SMB_DR_OP_ERR;
+ free(ids);
+ smb_group_free_privlist(list, 1);
+ return (NULL);
+ }
+ bzero(list->privs[i], sizeof (ntpriv_t));
+ priv = smb_priv_getbyvalue(ids[i]);
+ list->privs[i]->id = priv->id;
+ list->privs[i]->name = strdup(priv->name);
+ }
+ free(ids);
+ }
+
+ if ((rbuf = smb_dr_encode_grp_privlist(SMB_DR_OP_SUCCESS, list,
+ rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ smb_group_free_privlist(list, 1);
+
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_priv_get(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ ntgrp_dr_arg_t *args;
+ uint32_t priv_attr;
+ nt_group_t *grp;
+ uint32_t retval;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_dop_group_priv_get: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ if (smb_dr_decode_common(argp, arg_size,
+ xdr_ntgrp_dr_arg_t, args) != 0) {
+ free(args);
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ grp = nt_group_getinfo(args->gname, RWLOCK_READER);
+ if (grp) {
+ priv_attr = nt_group_getpriv(grp, args->privid);
+ retval = priv_attr;
+ } else {
+ retval = NT_STATUS_NO_SUCH_GROUP;
+ *err = SMB_DR_OP_ERR;
+ }
+ nt_group_putinfo(grp);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &retval,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+ free(args);
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_priv_set(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ ntgrp_dr_arg_t *args;
+ uint32_t ntstatus = NT_STATUS_UNSUCCESSFUL;
+ nt_group_t *grp;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_dop_group_priv_set: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ if (smb_dr_decode_common(argp, arg_size,
+ xdr_ntgrp_dr_arg_t, args) != 0) {
+ free(args);
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ grp = nt_group_getinfo(args->gname, RWLOCK_WRITER);
+ if (grp) {
+ ntstatus = nt_group_setpriv(grp,
+ args->privid, args->priv_attr);
+ } else {
+ ntstatus = NT_STATUS_NO_SUCH_GROUP;
+ *err = SMB_DR_OP_ERR;
+ }
+ nt_group_putinfo(grp);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &ntstatus,
+ xdr_uint32_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ free(args);
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_list(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL, *scope = NULL;
+ ntgrp_dr_arg_t *args;
+ ntgrp_list_t list;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_dop_group_list: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ if (smb_dr_decode_common(argp, arg_size,
+ xdr_ntgrp_dr_arg_t, args) != 0) {
+ free(args);
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ bzero(&list, sizeof (ntgrp_list_t));
+ scope = args->scope;
+ if (scope == NULL)
+ scope = "*";
+ nt_group_list(args->offset, scope, &list);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_grp_list(SMB_DR_OP_SUCCESS, &list,
+ rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ smb_group_free_list(&list, 1);
+ free(args);
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_member_list(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL;
+ ntgrp_dr_arg_t *args;
+ nt_group_t *grp = NULL;
+ ntgrp_member_list_t members;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_group_dr_listmember: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ if (smb_dr_decode_common(argp, arg_size,
+ xdr_ntgrp_dr_arg_t, args) != 0) {
+ free(args);
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ bzero(&members, sizeof (ntgrp_member_list_t));
+ bzero(&members.members, SMB_GROUP_PER_LIST * sizeof (members_list));
+ if ((!args->gname) || (strlen(args->gname) == 0)) {
+ free(args);
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ grp = nt_group_getinfo(args->gname, RWLOCK_READER);
+ if (grp) {
+ (void) nt_group_member_list(args->offset, grp, &members);
+ }
+ nt_group_putinfo(grp);
+
+ /* Encode the result and return */
+ if ((rbuf = smb_dr_encode_grp_memberlist(SMB_DR_OP_SUCCESS, &members,
+ rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ smb_group_free_memberlist(&members, 1);
+ free(args);
+ return (rbuf);
+}
+
+/*ARGSUSED*/
+static char *
+smb_dop_group_member_count(char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+ char *rbuf = NULL, *gname = NULL;
+ ntgrp_dr_arg_t *enc_args;
+ nt_group_t *grp = NULL;
+ int num = 0;
+ uint32_t ntstatus = NT_STATUS_UNSUCCESSFUL;
+
+ *err = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ /* Decode */
+ if ((gname = smb_dr_decode_string(argp, arg_size)) == 0) {
+ *err = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ grp = nt_group_getinfo(gname, RWLOCK_READER);
+ if (grp) {
+ num = nt_group_num_members(grp);
+ ntstatus = NT_STATUS_SUCCESS;
+ } else {
+ ntstatus = NT_STATUS_NO_SUCH_GROUP;
+ }
+ nt_group_putinfo(grp);
+
+ /* Encode the result and return */
+ if ((enc_args = (ntgrp_dr_arg_t *)
+ malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR,
+ "smb_dop_group_member_count: cannot allocate memory");
+ *err = SMB_DR_OP_ERR;
+ return (NULL);
+ }
+ bzero(enc_args, sizeof (ntgrp_dr_arg_t));
+ enc_args->count = num;
+ enc_args->ntstatus = ntstatus;
+ if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, enc_args,
+ xdr_ntgrp_dr_arg_t, rbufsize)) == NULL) {
+ *err = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+ free(enc_args);
+ return (rbuf);
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_door_server.c b/usr/src/cmd/smbsrv/smbd/smbd_door_server.c
new file mode 100644
index 0000000000..30f3e91e13
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_door_server.c
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMBd door server
+ */
+
+#include <door.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <varargs.h>
+#include <stdio.h>
+#include <synch.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <assert.h>
+#include <alloca.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbns.h>
+#include <smbsrv/libsmbrdr.h>
+
+#include <smbsrv/smb_common_door.h>
+
+static int smb_door_fildes = -1;
+static mutex_t smb_doorsrv_mutex;
+
+void smb_srv_door(void *, char *, size_t, door_desc_t *, uint_t);
+
+extern uint32_t smbd_join(smb_joininfo_t *);
+
+/*
+ * smb_doorsrv_start
+ *
+ * Start the SMBd door service.
+ * Returns 0 on success. Otherwise, -1.
+ */
+int
+smb_doorsrv_start()
+{
+ int newfd;
+
+ (void) mutex_lock(&smb_doorsrv_mutex);
+
+ if (smb_door_fildes != -1) {
+ syslog(LOG_ERR, "smb_doorsrv_start: duplicate");
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (0);
+ }
+
+ if ((smb_door_fildes = door_create(smb_srv_door,
+ SMBD_DOOR_COOKIE, DOOR_UNREF)) < 0) {
+ syslog(LOG_ERR, "smb_doorsrv_start: door_create failed %s",
+ strerror(errno));
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (-1);
+ }
+
+ (void) unlink(SMBD_DOOR_NAME);
+
+ if ((newfd = creat(SMBD_DOOR_NAME, 0644)) < 0) {
+ syslog(LOG_ERR, "smb_doorsrv_start: open failed %s",
+ strerror(errno));
+ (void) door_revoke(smb_door_fildes);
+ smb_door_fildes = -1;
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (-1);
+ }
+
+ (void) close(newfd);
+ (void) fdetach(SMBD_DOOR_NAME);
+
+ if (fattach(smb_door_fildes, SMBD_DOOR_NAME) < 0) {
+ syslog(LOG_ERR, "smb_doorsrv_start: fattach failed %s",
+ strerror(errno));
+ (void) door_revoke(smb_door_fildes);
+ smb_door_fildes = -1;
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (-1);
+ }
+
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (0);
+}
+
+
+/*
+ * smb_doorsrv_stop
+ *
+ * Stop the smbd door service.
+ */
+void
+smb_doorsrv_stop(void)
+{
+ (void) mutex_lock(&smb_doorsrv_mutex);
+
+ if (smb_door_fildes != -1) {
+ (void) fdetach(SMBD_DOOR_NAME);
+ (void) door_revoke(smb_door_fildes);
+ smb_door_fildes = -1;
+ }
+
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+}
+
+
+/*
+ * smb_srv_door
+ *
+ */
+/*ARGSUSED*/
+void
+smb_srv_door(void *cookie, char *ptr, size_t size, door_desc_t *dp,
+ uint_t n_desc)
+{
+ int req_type, rc;
+ char *buf;
+ int buflen;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int dec_status;
+ unsigned int enc_status;
+ char *domain;
+ char *user;
+ char *passwd;
+ smb_joininfo_t jdi;
+
+
+ dec_ctx = smb_dr_decode_start(ptr, size);
+
+ if (dec_ctx == 0)
+ return;
+
+ req_type = smb_dr_get_uint32(dec_ctx);
+ buflen = SMBD_DOOR_SIZE;
+
+ if ((buf = alloca(buflen)) == NULL) {
+ syslog(LOG_ERR, "SmbdDoorSrv: resource shortage");
+ (void) smb_dr_decode_finish(dec_ctx);
+ return;
+ }
+
+ enc_ctx = smb_dr_encode_start(buf, buflen);
+ if (enc_ctx == 0) {
+ syslog(LOG_ERR, "SmbdDoorSrv: encode start failed");
+ (void) smb_dr_decode_finish(dec_ctx);
+ return;
+ }
+
+ switch (req_type) {
+ case SMBD_DOOR_PARAM_GET: {
+ smb_cfg_id_t id;
+ char *value = NULL;
+ char *empty = "";
+
+ id = smb_dr_get_uint32(dec_ctx);
+
+ dec_status = smb_dr_decode_finish(dec_ctx);
+ if (dec_status != 0) {
+ goto decode_error;
+ }
+
+ smb_config_rdlock();
+ value = smb_config_getstr(id);
+ smb_dr_put_int32(enc_ctx, SMBD_DOOR_SRV_SUCCESS);
+
+ if (value)
+ smb_dr_put_string(enc_ctx, value);
+ else
+ smb_dr_put_string(enc_ctx, empty);
+ smb_config_unlock();
+ break;
+ }
+
+ case SMBD_DOOR_PARAM_SET: {
+ smb_cfg_id_t id;
+ char *value = NULL;
+
+ id = smb_dr_get_uint32(dec_ctx);
+ value = smb_dr_get_string(dec_ctx);
+
+ dec_status = smb_dr_decode_finish(dec_ctx);
+ if (dec_status != 0) {
+ smb_dr_free_string(value);
+ goto decode_error;
+ }
+
+ smb_config_wrlock();
+ if (smb_config_set(id, value) == 0) {
+ smb_dr_put_int32(enc_ctx, SMBD_DOOR_SRV_SUCCESS);
+ } else {
+ smb_dr_put_int32(enc_ctx, SMBD_DOOR_SRV_ERROR);
+ }
+ smb_config_unlock();
+ smb_dr_free_string(value);
+ break;
+ }
+
+ case SMBD_DOOR_NETBIOS_RECONFIG: {
+ smb_netbios_name_reconfig();
+ smb_dr_put_int32(enc_ctx, SMBD_DOOR_SRV_SUCCESS);
+ break;
+ }
+
+ case SMBD_DOOR_JOIN:
+ jdi.mode = smb_dr_get_uint32(dec_ctx);
+ domain = smb_dr_get_string(dec_ctx);
+ user = smb_dr_get_string(dec_ctx);
+ passwd = smb_dr_get_string(dec_ctx);
+
+ dec_status = smb_dr_decode_finish(dec_ctx);
+ if (dec_status != 0 ||
+ domain == 0 || user == 0 || passwd == 0) {
+ smb_dr_free_string(domain);
+ smb_dr_free_string(user);
+ smb_dr_free_string(passwd);
+ goto decode_error;
+ }
+
+ (void) strlcpy(jdi.domain_name, domain,
+ sizeof (jdi.domain_name));
+ (void) strlcpy(jdi.domain_username, user,
+ sizeof (jdi.domain_username));
+ (void) strlcpy(jdi.domain_passwd, passwd,
+ sizeof (jdi.domain_passwd));
+
+ smb_dr_free_string(domain);
+ smb_dr_free_string(user);
+ smb_dr_free_string(passwd);
+
+ rc = smbd_join(&jdi);
+ smb_dr_put_int32(enc_ctx, SMBD_DOOR_SRV_SUCCESS);
+ smb_dr_put_int32(enc_ctx, rc);
+ break;
+
+ default:
+ goto decode_error;
+ }
+
+ if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0)
+ goto encode_error;
+
+ (void) door_return(buf, used, NULL, 0);
+
+ return;
+
+decode_error:
+ (void) smb_dr_put_int32(enc_ctx, SMBD_DOOR_SRV_ERROR);
+ (void) smb_dr_put_uint32(enc_ctx, dec_status);
+ (void) smb_dr_encode_finish(enc_ctx, &used);
+ (void) door_return(buf, used, NULL, 0);
+ return;
+
+encode_error:
+ enc_ctx = smb_dr_encode_start(buf, buflen);
+ (void) smb_dr_put_int32(enc_ctx, SMBD_DOOR_SRV_ERROR);
+ (void) smb_dr_put_uint32(enc_ctx, enc_status);
+ (void) smb_dr_encode_finish(enc_ctx, &used);
+
+ (void) door_return(buf, used, NULL, 0);
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c
new file mode 100644
index 0000000000..d564c789b5
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMBd door server
+ */
+
+#include <alloca.h>
+#include <door.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <varargs.h>
+#include <stdio.h>
+#include <synch.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <strings.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+
+
+static int smb_doorsrv_fildes = -1;
+static mutex_t smb_doorsrv_mutex;
+
+static void smb_door_srv_func(void *cookie, char *ptr, size_t size,
+ door_desc_t *dp, uint_t n_odesc);
+
+/*
+ * smb_door_srv_start
+ *
+ * Start the smbd door service. Create and bind to a door.
+ * Returns 0 on success. Otherwise, -1.
+ */
+int
+smb_door_srv_start()
+{
+ int newfd;
+
+ (void) mutex_lock(&smb_doorsrv_mutex);
+
+ if (smb_doorsrv_fildes != -1) {
+ (void) fprintf(stderr, "smb_doorsrv_start: already started");
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (-1);
+ }
+
+ if ((smb_doorsrv_fildes = door_create(smb_door_srv_func,
+ SMB_DR_SVC_COOKIE, DOOR_UNREF)) < 0) {
+ (void) fprintf(stderr, "smb_doorsrv_start: door_create: %s",
+ strerror(errno));
+ smb_doorsrv_fildes = -1;
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (-1);
+ }
+
+ (void) unlink(SMB_DR_SVC_NAME);
+
+ if ((newfd = creat(SMB_DR_SVC_NAME, 0644)) < 0) {
+ (void) fprintf(stderr, "smb_doorsrv_start: open: %s",
+ strerror(errno));
+ (void) door_revoke(smb_doorsrv_fildes);
+ smb_doorsrv_fildes = -1;
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (-1);
+ }
+
+ (void) close(newfd);
+ (void) fdetach(SMB_DR_SVC_NAME);
+
+ if (fattach(smb_doorsrv_fildes, SMB_DR_SVC_NAME) < 0) {
+ (void) fprintf(stderr, "smb_doorsrv_start: fattach: %s",
+ strerror(errno));
+ (void) door_revoke(smb_doorsrv_fildes);
+ smb_doorsrv_fildes = -1;
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (-1);
+ }
+
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+ return (0);
+}
+
+
+/*
+ * smb_door_srv_stop
+ *
+ * Stop the smbd door service.
+ */
+void
+smb_door_srv_stop(void)
+{
+ (void) mutex_lock(&smb_doorsrv_mutex);
+
+ if (smb_doorsrv_fildes != -1) {
+ (void) fdetach(SMB_DR_SVC_NAME);
+ (void) door_revoke(smb_doorsrv_fildes);
+ smb_doorsrv_fildes = -1;
+ }
+
+ (void) mutex_unlock(&smb_doorsrv_mutex);
+}
+
+/*
+ * smb_door_err_hdlr
+ *
+ * Encode the appropriate error code to the first 4-byte of the result
+ * buffer upon any door operation failure.
+ */
+static char *
+smb_door_srv_err_hdlr(int stat, size_t *rbufsize)
+{
+ char *rbuf;
+
+ if ((rbuf = smb_dr_set_res_stat(stat, rbufsize)) == NULL) {
+ *rbufsize = 0;
+ return (NULL);
+ }
+
+ return (rbuf);
+}
+
+/*
+ * smb_door_srv_func
+ *
+ * This function will determine the opcode by decoding the first 4-byte of
+ * the argument buffer passed by a door client. The corresponding door
+ * operation will be looked up from the optab and get invoked.
+ * Basically, any door operation will takes the argument buffer as its
+ * parameter, and generates the result buffer.
+ */
+/*ARGSUSED*/
+void
+smb_door_srv_func(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t n_desc)
+{
+ char *resbuf = NULL, *tmpbuf = NULL;
+ size_t rbufsize = 0;
+ int opcode;
+ int err;
+ smb_dr_op_t smbop;
+
+ if ((opcode = smb_dr_get_opcode(argp, arg_size)) < 0) {
+ tmpbuf = smb_door_srv_err_hdlr(SMB_DR_OP_ERR_DECODE,
+ &rbufsize);
+ goto door_return;
+ }
+
+ syslog(LOG_DEBUG, "smb_door_srv_func: execute server routine"
+ "(opcode=%d)", opcode);
+ if (smb_dr_is_valid_opcode(opcode) != 0) {
+ tmpbuf = smb_door_srv_err_hdlr(SMB_DR_OP_ERR_INVALID_OPCODE,
+ &rbufsize);
+ } else {
+ smbop = smb_doorsrv_optab[opcode];
+ if ((tmpbuf = smbop(argp + sizeof (opcode),
+ arg_size - sizeof (opcode), dp, n_desc,
+ &rbufsize, &err)) == NULL)
+ tmpbuf = smb_door_srv_err_hdlr(err, &rbufsize);
+ }
+
+door_return:
+ if (tmpbuf) {
+ if ((resbuf = (char *)alloca(rbufsize)) == NULL)
+ rbufsize = 0;
+ else
+ (void) memcpy(resbuf, tmpbuf, rbufsize);
+ free(tmpbuf);
+ }
+
+ (void) door_return(resbuf, rbufsize, NULL, 0);
+ /*NOTREACHED*/
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_join.c b/usr/src/cmd/smbsrv/smbd/smbd_join.c
new file mode 100644
index 0000000000..425df10df8
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_join.c
@@ -0,0 +1,395 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <syslog.h>
+#include <synch.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/errno.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbrdr.h>
+#include <smbsrv/libsmbns.h>
+#include <smbsrv/libmlsvc.h>
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/lsalib.h>
+
+/*
+ * Local protocol flags used to indicate which version of the
+ * netlogon protocol to use when attempting to find the PDC.
+ */
+#define NETLOGON_PROTO_NETLOGON 0x01
+#define NETLOGON_PROTO_SAMLOGON 0x02
+
+/*
+ * Maximum time to wait for a domain controller (30 seconds).
+ */
+#define SMB_NETLOGON_TIMEOUT 30
+
+/*
+ * Flags used in conjunction with the location and query condition
+ * variables.
+ */
+#define SMB_NETLF_LOCATE_DC 0x00000001
+#define SMB_NETLF_LSA_QUERY 0x00000002
+
+typedef struct smb_netlogon_info {
+ char snli_domain[SMB_PI_MAX_DOMAIN];
+ unsigned snli_flags;
+ mutex_t snli_locate_mtx;
+ cond_t snli_locate_cv;
+ mutex_t snli_query_mtx;
+ cond_t snli_query_cv;
+ uint32_t snli_status;
+} smb_netlogon_info_t;
+
+static smb_netlogon_info_t smb_netlogon_info;
+
+static pthread_t lsa_monitor_thr;
+static pthread_t dc_browser_thr;
+
+static void *smb_netlogon_lsa_monitor(void *arg);
+static void *smb_netlogon_dc_browser(void *arg);
+
+/*
+ * Inline convenience function to find out if the domain information is
+ * valid. The caller can decide whether or not to wait.
+ */
+static boolean_t
+smb_ntdomain_is_valid(uint32_t timeout)
+{
+ smb_ntdomain_t *info;
+
+ if ((info = smb_getdomaininfo(timeout)) != 0) {
+ if (info->ipaddr != 0)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * smbd_join
+ *
+ * Joins the specified domain/workgroup
+ */
+uint32_t
+smbd_join(smb_joininfo_t *info)
+{
+ smb_ntdomain_t *pi;
+ uint32_t status;
+ unsigned char passwd_hash[SMBAUTH_HASH_SZ];
+ char plain_passwd[PASS_LEN + 1];
+ char plain_user[PASS_LEN + 1];
+
+ if (info->mode == SMB_SECMODE_WORKGRP) {
+ smb_config_wrlock();
+ (void) smb_config_set_secmode(info->mode);
+ (void) smb_config_set(SMB_CI_DOMAIN_NAME, info->domain_name);
+ smb_config_unlock();
+ return (NT_STATUS_SUCCESS);
+ }
+
+ /*
+ * Ensure that any previous membership of this domain has
+ * been cleared from the environment before we start. This
+ * will ensure that we don't attempt a NETLOGON_SAMLOGON
+ * when attempting to find the PDC.
+ */
+ smb_set_domain_member(0);
+
+ (void) strcpy(plain_user, info->domain_username);
+ (void) strcpy(plain_passwd, info->domain_passwd);
+
+ if (smb_auth_ntlm_hash(plain_passwd, passwd_hash) != SMBAUTH_SUCCESS) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ syslog(LOG_ERR, "smbd: could not compute ntlm hash for '%s'",
+ plain_user);
+ return (status);
+ }
+
+ smbrdr_ipc_set(plain_user, passwd_hash);
+
+ if (locate_resource_pdc(info->domain_name)) {
+ if ((pi = smb_getdomaininfo(0)) == 0) {
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ syslog(LOG_ERR, "smbd: could not get domain controller"
+ "information for '%s'", info->domain_name);
+ return (status);
+ }
+
+ /*
+ * Temporary delay before creating
+ * the workstation trust account.
+ */
+ (void) sleep(2);
+ status = mlsvc_validate_user(pi->server, pi->domain,
+ plain_user, plain_passwd);
+
+ if (status == NT_STATUS_SUCCESS) {
+ smb_config_wrlock();
+ (void) smb_config_set_secmode(SMB_SECMODE_DOMAIN);
+ (void) smb_config_set(SMB_CI_DOMAIN_NAME,
+ info->domain_name);
+ smb_config_unlock();
+ smbrdr_ipc_commit();
+ return (status);
+ }
+
+ smbrdr_ipc_rollback();
+ syslog(LOG_ERR, "smbd: failed joining %s (%s)",
+ info->domain_name, xlate_nt_status(status));
+ return (status);
+ }
+
+ smbrdr_ipc_rollback();
+ syslog(LOG_ERR, "smbd: failed locating domain controller for %s",
+ info->domain_name);
+ return (NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND);
+}
+
+/*
+ * locate_resource_pdc
+ *
+ * This is the entry point for discovering a domain controller for the
+ * specified domain. The caller may block here for around 30 seconds if
+ * the system has to go to the network and find a domain controller.
+ * Sometime it would be good to change this to smb_locate_pdc and allow
+ * the caller to specify whether or not he wants to wait for a response.
+ *
+ * The actual work of discovering a DC is handled by other threads.
+ * All we do here is signal the request and wait for a DC or a timeout.
+ *
+ * Returns B_TRUE if a domain controller is available.
+ */
+boolean_t
+locate_resource_pdc(char *domain)
+{
+ int rc;
+ timestruc_t to;
+
+ if (domain == NULL || *domain == '\0')
+ return (B_FALSE);
+
+ (void) mutex_lock(&smb_netlogon_info.snli_locate_mtx);
+
+ if ((smb_netlogon_info.snli_flags & SMB_NETLF_LOCATE_DC) == 0) {
+ smb_netlogon_info.snli_flags |= SMB_NETLF_LOCATE_DC;
+ (void) strlcpy(smb_netlogon_info.snli_domain, domain,
+ SMB_PI_MAX_DOMAIN);
+ (void) cond_broadcast(&smb_netlogon_info.snli_locate_cv);
+ }
+
+ while (smb_netlogon_info.snli_flags & SMB_NETLF_LOCATE_DC) {
+ to.tv_sec = SMB_NETLOGON_TIMEOUT;
+ to.tv_nsec = 0;
+ rc = cond_reltimedwait(&smb_netlogon_info.snli_locate_cv,
+ &smb_netlogon_info.snli_locate_mtx, &to);
+
+ if (rc == ETIME)
+ break;
+ }
+
+ (void) mutex_unlock(&smb_netlogon_info.snli_locate_mtx);
+
+ return (smb_ntdomain_is_valid(0));
+}
+
+/*
+ * smb_netlogon_init
+ *
+ * Initialization of the DC browser and LSA monitor threads.
+ * Returns 0 on success, an error number if thread creation fails.
+ */
+int
+smb_netlogon_init(void)
+{
+ pthread_attr_t tattr;
+ int rc;
+
+ (void) pthread_attr_init(&tattr);
+ (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+ rc = pthread_create(&lsa_monitor_thr, &tattr,
+ smb_netlogon_lsa_monitor, 0);
+ if (rc != 0)
+ goto nli_exit;
+ rc = pthread_create(&dc_browser_thr, &tattr,
+ smb_netlogon_dc_browser, 0);
+ if (rc != 0) {
+ (void) pthread_cancel(lsa_monitor_thr);
+ (void) pthread_join(lsa_monitor_thr, NULL);
+ }
+
+nli_exit:
+ (void) pthread_attr_destroy(&tattr);
+ return (rc);
+}
+
+/*
+ * smb_netlogon_dc_browser
+ *
+ * This is the DC browser thread: it gets woken up whenever someone
+ * wants to locate a domain controller.
+ *
+ * With the introduction of Windows 2000, NetBIOS is no longer a
+ * requirement for NT domains. If NetBIOS has been disabled on the
+ * network there will be no browsers and we won't get any response
+ * to netlogon requests. So we try to find a DC controller via ADS
+ * first. If ADS is disabled or the DNS query fails, we drop back
+ * to the netlogon protocol.
+ *
+ * This function will block for up to 30 seconds waiting for the PDC
+ * to be discovered. Sometime it would be good to change this to
+ * smb_locate_pdc and allow the caller to specify whether or not he
+ * wants to wait for a response.
+ *
+ */
+/*ARGSUSED*/
+static void *
+smb_netlogon_dc_browser(void *arg)
+{
+ boolean_t rc;
+ char resource_domain[SMB_PI_MAX_DOMAIN];
+ int net, smb_nc_cnt;
+ int protocol;
+
+ for (;;) {
+ (void) mutex_lock(&smb_netlogon_info.snli_locate_mtx);
+
+ while ((smb_netlogon_info.snli_flags & SMB_NETLF_LOCATE_DC) ==
+ 0) {
+ (void) cond_wait(&smb_netlogon_info.snli_locate_cv,
+ &smb_netlogon_info.snli_locate_mtx);
+ }
+
+ (void) mutex_unlock(&smb_netlogon_info.snli_locate_mtx);
+
+ (void) strlcpy(resource_domain, smb_netlogon_info.snli_domain,
+ SMB_PI_MAX_DOMAIN);
+
+ smb_setdomaininfo(NULL, NULL, 0);
+ if (msdcs_lookup_ads() == 0) {
+ if (smb_is_domain_member())
+ protocol = NETLOGON_PROTO_SAMLOGON;
+ else
+ protocol = NETLOGON_PROTO_NETLOGON;
+
+ smb_nc_cnt = smb_nic_get_num();
+ for (net = 0; net < smb_nc_cnt; net++) {
+ smb_netlogon_request(net, protocol,
+ resource_domain);
+ }
+ }
+
+ rc = smb_ntdomain_is_valid(SMB_NETLOGON_TIMEOUT);
+
+ (void) mutex_lock(&smb_netlogon_info.snli_locate_mtx);
+ smb_netlogon_info.snli_flags &= ~SMB_NETLF_LOCATE_DC;
+ (void) cond_broadcast(&smb_netlogon_info.snli_locate_cv);
+ (void) mutex_unlock(&smb_netlogon_info.snli_locate_mtx);
+
+ if (rc != B_TRUE) {
+ /*
+ * Notify the LSA monitor to update the
+ * primary and trusted domain information.
+ */
+ (void) mutex_lock(&smb_netlogon_info.snli_query_mtx);
+ smb_netlogon_info.snli_flags |= SMB_NETLF_LSA_QUERY;
+ (void) cond_broadcast(&smb_netlogon_info.snli_query_cv);
+ (void) mutex_unlock(&smb_netlogon_info.snli_query_mtx);
+ }
+ }
+
+ /*NOTREACHED*/
+ return (NULL);
+}
+
+/*
+ * smb_netlogon_lsa_monitor
+ *
+ * This monitor should run as a separate thread. It waits on a condition
+ * variable until someone indicates that the LSA domain information needs
+ * to be refreshed. It then queries the DC for the NT domain information:
+ * primary, account and trusted domains. The condition variable should be
+ * signaled whenever a DC is selected.
+ *
+ * Note that the LSA query calls require the DC information and this task
+ * may end up blocked on the DC location protocol, which is why this
+ * monitor is run as a separate thread. This should only happen if the DC
+ * goes down immediately after we located it.
+ */
+/*ARGSUSED*/
+static void *
+smb_netlogon_lsa_monitor(void *arg)
+{
+ uint32_t status;
+
+ for (;;) {
+ (void) mutex_lock(&smb_netlogon_info.snli_query_mtx);
+
+ while ((smb_netlogon_info.snli_flags & SMB_NETLF_LSA_QUERY) ==
+ 0) {
+ (void) cond_wait(&smb_netlogon_info.snli_query_cv,
+ &smb_netlogon_info.snli_query_mtx);
+ }
+
+ smb_netlogon_info.snli_flags &= ~SMB_NETLF_LSA_QUERY;
+ (void) mutex_unlock(&smb_netlogon_info.snli_query_mtx);
+
+ /*
+ * Skip the LSA query if Authenticated IPC is supported
+ * and the credential is not yet set.
+ */
+ if (smbrdr_ipc_skip_lsa_query() == 0) {
+ status = lsa_query_primary_domain_info();
+ if (status == NT_STATUS_SUCCESS) {
+ if (lsa_query_account_domain_info()
+ != NT_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "NetlogonLSAMonitor: query "
+ "account info failed");
+ }
+ if (lsa_enum_trusted_domains()
+ != NT_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "NetlogonLSAMonitor: enum "
+ "trusted domain failed");
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "NetlogonLSAMonitor: update failed");
+ }
+ }
+ }
+
+ /*NOTREACHED*/
+ return (NULL);
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_logon.c b/usr/src/cmd/smbsrv/smbd/smbd_logon.c
new file mode 100644
index 0000000000..3fa0443789
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_logon.c
@@ -0,0 +1,289 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <errno.h>
+#include <synch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <bsm/adt.h>
+#include <bsm/adt_event.h>
+#include <bsm/audit_uevents.h>
+#include "smbd.h"
+
+
+/*
+ * An audit session is established at user logon and terminated at user
+ * logoff.
+ *
+ * SMB audit handles are allocated when users logon (SmbSessionSetupX)
+ * and deallocted when a user logs off (SmbLogoffX). Each time an SMB
+ * audit handle is allocated it is added to a global list.
+ */
+typedef struct smb_audit {
+ struct smb_audit *sa_next;
+ adt_session_data_t *sa_handle;
+ uid_t sa_uid;
+ gid_t sa_gid;
+ uint32_t sa_audit_sid;
+ uint32_t sa_refcnt;
+ char *sa_domain;
+ char *sa_username;
+} smb_audit_t;
+
+static smb_audit_t *smbd_audit_list;
+static mutex_t smbd_audit_lock;
+
+/*
+ * Unique identifier for audit sessions in the audit list.
+ * Used to lookup an audit session on logoff.
+ */
+static uint32_t smbd_audit_sid;
+
+static void smbd_audit_link(smb_audit_t *);
+static smb_audit_t *smbd_audit_unlink(uint32_t);
+
+
+/*
+ * Invoked at user logon due to SmbSessionSetupX. Authenticate the
+ * user, start an audit session and audit the event.
+ */
+smb_token_t *
+smbd_user_auth_logon(netr_client_t *clnt)
+{
+ smb_token_t *token;
+ smb_audit_t *entry;
+ adt_session_data_t *ah;
+ adt_event_data_t *event;
+ au_tid_addr_t termid;
+ uid_t uid;
+ gid_t gid;
+ char *sid;
+ int status;
+ int retval;
+
+ if ((token = smb_logon(clnt)) == NULL) {
+ uid = ADT_NO_ATTRIB;
+ gid = ADT_NO_ATTRIB;
+ sid = strdup(NT_NULL_SIDSTR);
+ status = ADT_FAILURE;
+ retval = ADT_FAIL_VALUE_AUTH;
+ } else {
+ uid = token->tkn_user->i_id;
+ gid = token->tkn_primary_grp->i_id;
+ sid = nt_sid_format(token->tkn_user->i_sidattr.sid);
+ status = ADT_SUCCESS;
+ retval = ADT_SUCCESS;
+ }
+
+ if (adt_start_session(&ah, NULL, 0)) {
+ syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m");
+ free(sid);
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ if ((event = adt_alloc_event(ah, ADT_smbd_session)) == NULL) {
+ syslog(LOG_AUTH | LOG_ALERT,
+ "adt_alloc_event(ADT_smbd_session): %m");
+ (void) adt_end_session(ah);
+ free(sid);
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ (void) memset(&termid, 0, sizeof (au_tid_addr_t));
+ termid.at_port = clnt->local_port;
+ termid.at_type = AU_IPv4;
+ termid.at_addr[0] = clnt->ipaddr;
+ adt_set_termid(ah, &termid);
+
+ if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) {
+ syslog(LOG_AUTH | LOG_ALERT, "adt_set_user: %m");
+ adt_free_event(event);
+ (void) adt_end_session(ah);
+ free(sid);
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ event->adt_smbd_session.domain = clnt->domain;
+ event->adt_smbd_session.username = clnt->username;
+ event->adt_smbd_session.sid = sid;
+
+ if (adt_put_event(event, status, retval))
+ syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m");
+
+ adt_free_event(event);
+ free(sid);
+
+ if (token) {
+ if ((entry = malloc(sizeof (smb_audit_t))) == NULL) {
+ syslog(LOG_ERR, "smbd_user_auth_logon: %m");
+ (void) adt_end_session(ah);
+ free(sid);
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ entry->sa_handle = ah;
+ entry->sa_uid = uid;
+ entry->sa_gid = gid;
+ entry->sa_username = strdup(clnt->username);
+ entry->sa_domain = strdup(clnt->domain);
+
+ (void) smb_autohome_add(entry->sa_username);
+ smbd_audit_link(entry);
+ token->tkn_audit_sid = entry->sa_audit_sid;
+ }
+
+ return (token);
+}
+
+/*
+ * Logon due to a subsequent SmbSessionSetupX on an existing session.
+ * The user was authenticated during the initial session setup.
+ */
+void
+smbd_user_nonauth_logon(uint32_t audit_sid)
+{
+ smb_audit_t *entry;
+
+ (void) mutex_lock(&smbd_audit_lock);
+ entry = smbd_audit_list;
+
+ while (entry) {
+ if (entry->sa_audit_sid == audit_sid) {
+ ++entry->sa_refcnt;
+ break;
+ }
+
+ entry = entry->sa_next;
+ }
+
+ (void) mutex_unlock(&smbd_audit_lock);
+}
+
+/*
+ * Invoked at user logoff due to SmbLogoffX. If this is the final
+ * logoff for this user on the session, audit the event and terminate
+ * the audit session.
+ */
+void
+smbd_user_auth_logoff(uint32_t audit_sid)
+{
+ smb_audit_t *entry;
+ adt_session_data_t *ah;
+ adt_event_data_t *event;
+
+ if ((entry = smbd_audit_unlink(audit_sid)) == NULL)
+ return;
+
+ (void) smb_autohome_remove(entry->sa_username);
+
+ ah = entry->sa_handle;
+
+ if ((event = adt_alloc_event(ah, ADT_smbd_logoff)) == NULL) {
+ syslog(LOG_AUTH | LOG_ALERT,
+ "adt_alloc_event(ADT_smbd_logoff): %m");
+ } else {
+ event->adt_smbd_logoff.domain = entry->sa_domain;
+ event->adt_smbd_logoff.username = entry->sa_username;
+
+ if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS))
+ syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m");
+
+ adt_free_event(event);
+ }
+
+ (void) adt_end_session(ah);
+
+ free(entry->sa_username);
+ free(entry->sa_domain);
+ free(entry);
+}
+
+/*
+ * Allocate an id and link an audit handle onto the global list.
+ */
+static void
+smbd_audit_link(smb_audit_t *entry)
+{
+ (void) mutex_lock(&smbd_audit_lock);
+
+ do {
+ ++smbd_audit_sid;
+ } while ((smbd_audit_sid == 0) || (smbd_audit_sid == (uint32_t)-1));
+
+ entry->sa_audit_sid = smbd_audit_sid;
+ entry->sa_refcnt = 1;
+ entry->sa_next = smbd_audit_list;
+ smbd_audit_list = entry;
+
+ (void) mutex_unlock(&smbd_audit_lock);
+}
+
+/*
+ * Unlink an audit handle. If the reference count reaches 0, the entry
+ * is removed from the list and returned. Otherwise the entry remains
+ * on the list and a null pointer is returned.
+ */
+static smb_audit_t *
+smbd_audit_unlink(uint32_t audit_sid)
+{
+ smb_audit_t *entry;
+ smb_audit_t **ppe;
+
+ (void) mutex_lock(&smbd_audit_lock);
+ ppe = &smbd_audit_list;
+
+ while (*ppe) {
+ entry = *ppe;
+
+ if (entry->sa_audit_sid == audit_sid) {
+ if (entry->sa_refcnt == 0)
+ break;
+
+ if ((--entry->sa_refcnt) != 0)
+ break;
+
+ *ppe = entry->sa_next;
+ (void) mutex_unlock(&smbd_audit_lock);
+ return (entry);
+ }
+
+ ppe = &(*ppe)->sa_next;
+ }
+
+ (void) mutex_unlock(&smbd_audit_lock);
+ return (NULL);
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_main.c b/usr/src/cmd/smbsrv/smbd/smbd_main.c
new file mode 100644
index 0000000000..740cc73837
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c
@@ -0,0 +1,758 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioccom.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <wait.h>
+#include <signal.h>
+#include <libscf.h>
+#include <limits.h>
+#include <priv_utils.h>
+#include <door.h>
+#include <errno.h>
+#include <syslog.h>
+#include <pthread.h>
+#include <time.h>
+#include <libscf.h>
+#include <zone.h>
+#include <tzfile.h>
+#include <libgen.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_ioctl.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbns.h>
+#include <smbsrv/libsmbrdr.h>
+#include <smbsrv/libmlsvc.h>
+
+#include "smbd.h"
+
+#define DRV_DEVICE_PATH "/devices/pseudo/smbsrv@0:smbsrv"
+#define SMB_CACHEDIR "/var/run/smb"
+#define SMB_DBDIR "/var/smb"
+
+extern void smb_netbios_name_reconfig();
+extern void smb_browser_config();
+
+static int smbd_daemonize_init(void);
+static void smbd_daemonize_fini(int, int);
+
+static int smbd_kernel_bind(void);
+static void smbd_kernel_unbind(void);
+static int smbd_already_running(void);
+
+static int smbd_service_init(void);
+static void smbd_service_fini(void);
+
+static int smbd_setup_options(int argc, char *argv[]);
+static void smbd_usage(FILE *fp);
+static void smbd_report(const char *fmt, ...);
+
+static void smbd_sig_handler(int sig);
+
+static int smbd_localtime_init(void);
+static void *smbd_localtime_monitor(void *arg);
+
+extern time_t altzone;
+
+static pthread_t localtime_thr;
+
+static int smbd_refresh_init(void);
+static void smbd_refresh_fini(void);
+static void *smbd_refresh_monitor(void *);
+static pthread_t refresh_thr;
+static pthread_cond_t refresh_cond;
+static pthread_mutex_t refresh_mutex;
+
+static smbd_t smbd;
+
+/*
+ * smbd user land daemon
+ *
+ * Use SMF error codes only on return or exit.
+ */
+int
+main(int argc, char *argv[])
+{
+ struct sigaction act;
+ sigset_t set;
+ uid_t uid;
+ int pfd = -1;
+
+ smbd.s_pname = basename(argv[0]);
+ openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
+
+ if (smbd_setup_options(argc, argv) != 0)
+ return (SMF_EXIT_ERR_FATAL);
+
+ if ((uid = getuid()) != smbd.s_uid) {
+ smbd_report("user %d: %s", uid, strerror(EPERM));
+ return (SMF_EXIT_ERR_FATAL);
+ }
+
+ if (getzoneid() != GLOBAL_ZONEID) {
+ smbd_report("non-global zones are not supported");
+ return (SMF_EXIT_ERR_FATAL);
+ }
+
+ if (is_system_labeled()) {
+ smbd_report("Trusted Extensions not supported");
+ return (SMF_EXIT_ERR_FATAL);
+ }
+
+ if (smbd_already_running())
+ return (SMF_EXIT_OK);
+
+ (void) sigfillset(&set);
+ (void) sigdelset(&set, SIGABRT);
+
+ (void) sigfillset(&act.sa_mask);
+ act.sa_handler = smbd_sig_handler;
+ act.sa_flags = 0;
+
+ (void) sigaction(SIGTERM, &act, NULL);
+ (void) sigaction(SIGHUP, &act, NULL);
+ (void) sigaction(SIGINT, &act, NULL);
+ (void) sigaction(SIGPIPE, &act, NULL);
+
+ (void) sigdelset(&set, SIGTERM);
+ (void) sigdelset(&set, SIGHUP);
+ (void) sigdelset(&set, SIGINT);
+ (void) sigdelset(&set, SIGPIPE);
+
+ if (smbd.s_fg) {
+ (void) sigdelset(&set, SIGTSTP);
+ (void) sigdelset(&set, SIGTTIN);
+ (void) sigdelset(&set, SIGTTOU);
+
+ if (smbd_service_init() != 0) {
+ smbd_report("service initialization failed");
+ exit(SMF_EXIT_ERR_FATAL);
+ }
+ } else {
+ /*
+ * "pfd" is a pipe descriptor -- any fatal errors
+ * during subsequent initialization of the child
+ * process should be written to this pipe and the
+ * parent will report this error as the exit status.
+ */
+ pfd = smbd_daemonize_init();
+
+ if (smbd_service_init() != 0) {
+ smbd_report("daemon initialization failed");
+ exit(SMF_EXIT_ERR_FATAL);
+ }
+
+ smbd_daemonize_fini(pfd, SMF_EXIT_OK);
+ }
+
+ (void) atexit(smbd_service_fini);
+
+ while (!smbd.s_shutdown_flag) {
+ (void) sigsuspend(&set);
+
+ switch (smbd.s_sigval) {
+ case 0:
+ break;
+
+ case SIGPIPE:
+ break;
+
+ case SIGHUP:
+ /* Refresh config was triggered */
+ if (smbd.s_fg)
+ smbd_report("reconfiguration requested");
+ (void) pthread_cond_signal(&refresh_cond);
+ break;
+
+ default:
+ /*
+ * Typically SIGINT or SIGTERM.
+ */
+ smbd.s_shutdown_flag = 1;
+ break;
+ }
+
+ smbd.s_sigval = 0;
+ }
+
+ smbd_service_fini();
+ closelog();
+ return (SMF_EXIT_OK);
+}
+
+/*
+ * This function will fork off a child process,
+ * from which only the child will return.
+ *
+ * Use SMF error codes only on exit.
+ */
+static int
+smbd_daemonize_init(void)
+{
+ int status, pfds[2];
+ sigset_t set, oset;
+ pid_t pid;
+ int rc;
+
+ /*
+ * Reset privileges to the minimum set required. We continue
+ * to run as root to create and access files in /var.
+ */
+ rc = __init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS,
+ smbd.s_uid, smbd.s_gid,
+ PRIV_NET_MAC_AWARE, PRIV_NET_PRIVADDR, PRIV_PROC_AUDIT,
+ PRIV_SYS_DEVICES, PRIV_SYS_SMB, NULL);
+
+ if (rc != 0) {
+ smbd_report("insufficient privileges");
+ exit(SMF_EXIT_ERR_FATAL);
+ }
+
+ /*
+ * Block all signals prior to the fork and leave them blocked in the
+ * parent so we don't get in a situation where the parent gets SIGINT
+ * and returns non-zero exit status and the child is actually running.
+ * In the child, restore the signal mask once we've done our setsid().
+ */
+ (void) sigfillset(&set);
+ (void) sigdelset(&set, SIGABRT);
+ (void) sigprocmask(SIG_BLOCK, &set, &oset);
+
+ if (pipe(pfds) == -1) {
+ smbd_report("unable to create pipe");
+ exit(SMF_EXIT_ERR_FATAL);
+ }
+
+ closelog();
+
+ if ((pid = fork()) == -1) {
+ openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
+ smbd_report("unable to fork");
+ closelog();
+ exit(SMF_EXIT_ERR_FATAL);
+ }
+
+ /*
+ * If we're the parent process, wait for either the child to send us
+ * the appropriate exit status over the pipe or for the read to fail
+ * (presumably with 0 for EOF if our child terminated abnormally).
+ * If the read fails, exit with either the child's exit status if it
+ * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
+ */
+ if (pid != 0) {
+ (void) close(pfds[1]);
+
+ if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
+ _exit(status);
+
+ if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
+ _exit(WEXITSTATUS(status));
+
+ _exit(SMF_EXIT_ERR_FATAL);
+ }
+
+ openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
+ smbd.s_pid = getpid();
+ (void) setsid();
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+ (void) chdir("/");
+ (void) umask(022);
+ (void) close(pfds[0]);
+
+ return (pfds[1]);
+}
+
+static void
+smbd_daemonize_fini(int fd, int exit_status)
+{
+ /*
+ * Now that we're running, if a pipe fd was specified, write an exit
+ * status to it to indicate that our parent process can safely detach.
+ * Then proceed to loading the remaining non-built-in modules.
+ */
+ if (fd >= 0)
+ (void) write(fd, &exit_status, sizeof (exit_status));
+
+ (void) close(fd);
+
+ if ((fd = open("/dev/null", O_RDWR)) >= 0) {
+ (void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
+ (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
+ (void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
+ (void) close(fd);
+ }
+
+ __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
+ PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL);
+}
+
+static int
+smbd_service_init(void)
+{
+ static char *dir[] = {
+ SMB_DBDIR, /* smbpasswd */
+ SMB_CACHEDIR /* KRB credential cache */
+ };
+
+ int rc;
+ int ddns_enabled;
+ uint32_t mode;
+ char resource_domain[SMB_PI_MAX_DOMAIN];
+ int i;
+
+ smbd.s_drv_fd = -1;
+
+ for (i = 0; i < (sizeof (dir)/sizeof (dir[0])); ++i) {
+ errno = 0;
+
+ if ((mkdir(dir[i], 0700) < 0) && (errno != EEXIST)) {
+ smbd_report("mkdir %s: %s", dir[i], strerror(errno));
+ return (1);
+ }
+ }
+
+ /*
+ * Set KRB5CCNAME (for the SMB credential cache) in the environment.
+ */
+ if (putenv("KRB5CCNAME=" SMB_CACHEDIR "/ccache") != 0) {
+ smbd_report("unable to set KRB5CCNAME");
+ return (1);
+ }
+
+ (void) oem_language_set("english");
+
+ if (!nt_builtin_init()) {
+ smbd_report("out of memory");
+ return (1);
+ }
+
+ /*
+ * Need to load the configuration data prior to getting the
+ * interface information.
+ */
+ if (smb_config_load() != 0) {
+ smbd_report("failed to load configuration data");
+ return (1);
+ }
+
+ smb_resolver_init();
+ (void) smb_nicmon_start();
+
+ smbrdr_init();
+
+ smb_netbios_start();
+ if (smb_netlogon_init() != 0) {
+ smbd_report("netlogon initialization failed");
+ return (1);
+ }
+
+ smb_config_rdlock();
+ resource_domain[0] = '\0';
+ (void) strlcpy(resource_domain,
+ smb_config_getstr(SMB_CI_DOMAIN_NAME), SMB_PI_MAX_DOMAIN);
+ (void) utf8_strupr(resource_domain);
+ smb_config_unlock();
+
+ mode = smb_get_security_mode();
+
+ if (mode == SMB_SECMODE_DOMAIN)
+ (void) locate_resource_pdc(resource_domain);
+
+ /* Get the ID map client handle */
+ if ((rc = smb_idmap_start()) != 0) {
+ smbd_report("no idmap handle");
+ return (rc);
+ }
+
+ if ((rc = nt_domain_init(resource_domain, mode)) != 0) {
+ if (rc == SMB_DOMAIN_NOMACHINE_SID)
+ smbd_report("No Security Identifier (SID) has been "
+ "generated for this system.\n"
+ "Check idmap service configuration.");
+
+ if (rc == SMB_DOMAIN_NODOMAIN_SID) {
+ /* Get the domain sid from domain controller */
+ if ((rc = lsa_query_primary_domain_info()) != 0)
+ smbd_report("Failed to get the Security "
+ "Identifier (SID) of domain %s",
+ resource_domain);
+ }
+ return (rc);
+ }
+
+ if ((rc = mlsvc_init()) != 0) {
+ smbd_report("msrpc initialization failed");
+ return (rc);
+ }
+
+ if (rc = smb_mlsvc_srv_start()) {
+ smbd_report("msrpc door initialization failed: %d", rc);
+ return (rc);
+ }
+
+ if (smb_lmshrd_srv_start() != 0) {
+ smbd_report("share initialization failed");
+ }
+
+ /* XXX following will get removed */
+ (void) smb_doorsrv_start();
+ if ((rc = smb_door_srv_start()) != 0)
+ return (rc);
+
+ if ((rc = smbd_refresh_init()) != 0)
+ return (rc);
+
+ /* Call dyndns update - Just in case its configured to refresh DNS */
+ smb_config_rdlock();
+ ddns_enabled = smb_config_getyorn(SMB_CI_DYNDNS_ENABLE);
+ smb_config_unlock();
+ if (ddns_enabled) {
+ (void) dyndns_update();
+ }
+
+ if ((rc = smbd_kernel_bind()) != 0)
+ smbd_report("kernel bind error: %s", strerror(errno));
+
+ (void) smbd_localtime_init();
+
+ return (lmshare_start());
+}
+
+/*
+ * Close the kernel service and shutdown smbd services.
+ * This function is registered with atexit(): ensure that anything
+ * called from here is safe to be called multiple times.
+ */
+static void
+smbd_service_fini(void)
+{
+ nt_builtin_fini();
+ smbd_refresh_fini();
+ smbd_kernel_unbind();
+ smb_door_srv_stop();
+ smb_doorsrv_stop();
+ smb_lmshrd_srv_stop();
+ lmshare_stop();
+ smb_mlsvc_srv_stop();
+ smb_nicmon_stop();
+ smb_resolver_close();
+ smb_idmap_stop();
+}
+
+/*
+ * smbd_refresh_init()
+ *
+ * SMB service refresh thread initialization. This thread waits for a
+ * refresh event and updates the daemon's view of the configuration
+ * before going back to sleep.
+ */
+static int
+smbd_refresh_init()
+{
+ pthread_attr_t tattr;
+ pthread_condattr_t cattr;
+ int rc;
+
+ (void) pthread_condattr_init(&cattr);
+ (void) pthread_cond_init(&refresh_cond, &cattr);
+ (void) pthread_condattr_destroy(&cattr);
+
+ (void) pthread_mutex_init(&refresh_mutex, NULL);
+
+ (void) pthread_attr_init(&tattr);
+ (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+ rc = pthread_create(&refresh_thr, &tattr, smbd_refresh_monitor, 0);
+ (void) pthread_attr_destroy(&tattr);
+ return (rc);
+
+}
+
+/*
+ * smbd_refresh_fini()
+ *
+ * Stop the refresh thread.
+ */
+static void
+smbd_refresh_fini()
+{
+ (void) pthread_cancel(refresh_thr);
+
+ (void) pthread_cond_destroy(&refresh_cond);
+ (void) pthread_mutex_destroy(&refresh_mutex);
+}
+
+/*
+ * smbd_refresh_monitor()
+ *
+ * Wait for a refresh event. When this thread wakes up, update the
+ * smbd configuration from the SMF config information then go back to
+ * wait for the next refresh.
+ */
+/*ARGSUSED*/
+static void *
+smbd_refresh_monitor(void *arg)
+{
+ int dummy = 0;
+
+ (void) pthread_mutex_lock(&refresh_mutex);
+ while (pthread_cond_wait(&refresh_cond, &refresh_mutex) == 0) {
+ /*
+ * We've been woken up by a refresh event so go do
+ * what is necessary.
+ */
+ (void) smb_config_load();
+ smb_nic_build_info();
+ (void) smb_netbios_name_reconfig();
+ (void) smb_browser_config();
+ if (ioctl(smbd.s_drv_fd, SMB_IOC_CONFIG_REFRESH, &dummy) < 0) {
+ smbd_report("configuration update ioctl: %s",
+ strerror(errno));
+ }
+ }
+ return (NULL);
+}
+
+
+/*
+ * If the door has already been opened by another process (non-zero pid
+ * in target), we assume that another smbd is already running. If there
+ * is a race here, it will be caught later when smbsrv is opened because
+ * only one process is allowed to open the device at a time.
+ */
+static int
+smbd_already_running(void)
+{
+ door_info_t info;
+ int door;
+
+ if ((door = open(SMBD_DOOR_NAME, O_RDONLY)) < 0)
+ return (0);
+
+ if (door_info(door, &info) < 0)
+ return (0);
+
+ if (info.di_target > 0) {
+ smbd_report("already running: pid %ld\n", info.di_target);
+ (void) close(door);
+ return (1);
+ }
+
+ (void) close(door);
+ return (0);
+}
+
+static int
+smbd_kernel_bind(void)
+{
+ if (smbd.s_drv_fd != -1)
+ (void) close(smbd.s_drv_fd);
+
+ if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) {
+ smbd.s_drv_fd = -1;
+ return (1);
+ }
+ return (0);
+}
+
+
+/*
+ * Initialization of the localtime thread.
+ * Returns 0 on success, an error number if thread creation fails.
+ */
+
+int
+smbd_localtime_init(void)
+{
+ pthread_attr_t tattr;
+ int rc;
+
+ (void) pthread_attr_init(&tattr);
+ (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+ rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0);
+ (void) pthread_attr_destroy(&tattr);
+ return (rc);
+}
+
+/*
+ * Local time thread to kernel land.
+ * Send local gmtoff to kernel module one time at startup
+ * and each time it changes (up to twice a year).
+ * Local gmtoff is checked once every 15 minutes and
+ * since some timezones are aligned on half and qtr hour boundaries,
+ * once an hour would likely suffice.
+ */
+
+/*ARGSUSED*/
+static void *
+smbd_localtime_monitor(void *arg)
+{
+ struct tm local_tm;
+ time_t secs, gmtoff;
+ time_t last_gmtoff = -1;
+ int timeout;
+
+ for (;;) {
+ gmtoff = -altzone;
+
+ if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) {
+ if (ioctl(smbd.s_drv_fd, SMB_IOC_GMTOFF, &gmtoff) < 0) {
+ smbd_report("localtime ioctl: %s",
+ strerror(errno));
+ }
+ }
+
+ /*
+ * Align the next iteration on a fifteen minute boundary.
+ */
+ secs = time(0);
+ (void) localtime_r(&secs, &local_tm);
+ timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN);
+ (void) sleep(timeout);
+
+ last_gmtoff = gmtoff;
+ }
+
+ /*NOTREACHED*/
+ return (NULL);
+}
+
+
+static void
+smbd_kernel_unbind(void)
+{
+ if (smbd.s_drv_fd != -1) {
+ (void) close(smbd.s_drv_fd);
+ smbd.s_drv_fd = -1;
+ }
+}
+
+static void
+smbd_sig_handler(int sigval)
+{
+ if (smbd.s_sigval == 0)
+ smbd.s_sigval = sigval;
+}
+
+/*
+ * Set up configuration options and parse the command line.
+ * This function will determine if we will run as a daemon
+ * or in the foreground.
+ *
+ * Failure to find a uid or gid results in using the default (0).
+ */
+static int
+smbd_setup_options(int argc, char *argv[])
+{
+ struct passwd *pwd;
+ struct group *grp;
+ int c;
+
+ if ((pwd = getpwnam("root")) != NULL)
+ smbd.s_uid = pwd->pw_uid;
+
+ if ((grp = getgrnam("sys")) != NULL)
+ smbd.s_gid = grp->gr_gid;
+
+ smbd.s_fg = smb_get_fg_flag();
+
+ while ((c = getopt(argc, argv, ":f")) != -1) {
+ switch (c) {
+ case 'f':
+ smbd.s_fg = 1;
+ break;
+
+ case ':':
+ case '?':
+ default:
+ smbd_usage(stderr);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+static void
+smbd_usage(FILE *fp)
+{
+ static char *help[] = {
+ "-f run program in foreground"
+ };
+
+ int i;
+
+ (void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname);
+
+ for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i)
+ (void) fprintf(fp, " %s\n", help[i]);
+}
+
+static void
+smbd_report(const char *fmt, ...)
+{
+ char buf[128];
+ va_list ap;
+
+ if (fmt == NULL)
+ return;
+
+ va_start(ap, fmt);
+ (void) vsnprintf(buf, 128, fmt, ap);
+ va_end(ap);
+
+ (void) fprintf(stderr, "smbd: %s\n", buf);
+}
+
+/*
+ * Enable libumem debugging by default on DEBUG builds.
+ */
+#ifdef DEBUG
+/* LINTED - external libumem symbol */
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+/* LINTED - external libumem symbol */
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+#endif
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_mlsvc_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_mlsvc_doorsvc.c
new file mode 100755
index 0000000000..da39ac33c7
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_mlsvc_doorsvc.c
@@ -0,0 +1,423 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <door.h>
+#include <errno.h>
+#include <syslog.h>
+#include <pthread.h>
+
+#include <smbsrv/libsmb.h>
+
+#include <smbsrv/ntsid.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/smb_winpipe.h>
+
+static int smb_updoor_id = -1;
+static pthread_mutex_t smb_winpipe_user_mutex;
+
+#define START_OUTDOOR_SIZE 65536
+#define MAX_INPIPE_LEN 65536
+
+static smb_dr_user_ctx_t *
+smb_user_ctx_mkabsolute(uint8_t *buf, uint32_t len)
+{
+ smb_dr_user_ctx_t *obj;
+ XDR xdrs;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
+ obj = (smb_dr_user_ctx_t *)malloc(sizeof (smb_dr_user_ctx_t));
+ if (!obj) {
+ xdr_destroy(&xdrs);
+ syslog(LOG_ERR, "smb_user_ctx_mkabsolute: resource shortage");
+ return (NULL);
+ }
+
+ bzero(obj, sizeof (smb_dr_user_ctx_t));
+ if (!xdr_smb_dr_user_ctx_t(&xdrs, obj)) {
+ syslog(LOG_ERR, "smb_user_ctx_mkabsolute: XDR decode error");
+ free(obj);
+ obj = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (obj);
+}
+
+static void
+smb_user_ctx_free(smb_dr_user_ctx_t *user_ctx)
+{
+ if (user_ctx) {
+ xdr_free(xdr_smb_dr_user_ctx_t, (char *)user_ctx);
+ free(user_ctx);
+ }
+}
+
+/*
+ * Function: smb_mlsvc_door_server
+ *
+ * This is the userland winpipe door entry point.
+ * Door arg data is a previously marshalled in to flat buffer
+ * that contains no pointers. This data is first unmarshalled into
+ * common structures. The data from the door *argp contains a header structure,
+ * mlsvc_door_hdr_t. Following are its members.
+ * thread_id - kernel thread id
+ * version number - possible use at a leter point
+ * call_type - rpc_transact, rpc_read or rpc_write
+ * length - max number of bytes that can be returned
+ * rpc_ctx - some rpc context info such as domain, user account, ...
+ * smb_pipe_t - pipeid, pipename, pipelen and data
+ *
+ * After converting the data, mlsvc_rpc_process is called
+ * The returning outpipe contains the relevant data to be
+ * returned to the windows client.
+ *
+ * Outgoing data must be marshalled again before returning.
+ */
+
+/*ARGSUSED*/
+void
+smb_mlsvc_door_server(void *cookie, char *argp, size_t arg_size,
+ door_desc_t *dd, uint_t n_desc)
+{
+ smb_pipe_t *inpipe = NULL;
+ smb_pipe_t *outpipe = NULL;
+ smb_pipe_t tmp_pipe;
+ smb_dr_user_ctx_t *user_ctx = NULL;
+ uchar_t *bufp;
+ int bplen = 0;
+ int total_pipelen;
+ mlsvc_door_hdr_t mdhin, mdhout;
+ int tbytes = 0;
+ int bytes_off = 0;
+ struct mlsvc_rpc_context *context;
+ uchar_t *obuf = NULL;
+ int current_out_len;
+ uint32_t adj_len;
+ char lfp[START_OUTDOOR_SIZE];
+
+ bufp = (uchar_t *)argp;
+ bcopy(bufp, &mdhin.md_tid, sizeof (uint64_t));
+ bytes_off = sizeof (uint64_t);
+ bcopy(bufp+bytes_off, &mdhin.md_version, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(bufp+bytes_off, &mdhin.md_call_type, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(bufp+bytes_off, &mdhin.md_length, sizeof (uint32_t));
+ bytes_off += sizeof (uint32_t);
+ bcopy(bufp+bytes_off, &mdhin.md_reserved, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+
+ /* flush is a special case, just free the buffers and return */
+ if (mdhin.md_call_type == SMB_RPC_FLUSH) {
+ bcopy(bufp + bytes_off, &tmp_pipe.sp_pipeid, sizeof (uint32_t));
+ context = mlsvc_lookup_context(tmp_pipe.sp_pipeid);
+ if (!context) {
+ syslog(LOG_ERR, "mds: Cannot lookup mlsvc context");
+ goto zero_exit;
+ }
+ if (context->inpipe) {
+ free(context->inpipe);
+ context->inpipe = NULL;
+ }
+ if (context->outpipe) {
+ free(context->outpipe);
+ context->outpipe = NULL;
+ }
+ mlsvc_rpc_release(tmp_pipe.sp_pipeid);
+ goto zero_exit;
+ }
+
+ user_ctx = smb_user_ctx_mkabsolute(bufp + bytes_off,
+ arg_size - bytes_off);
+ if (!user_ctx) {
+ syslog(LOG_ERR, "mds: user_ctx_mkabsolute failed");
+ goto zero_exit;
+ }
+
+ tbytes += xdr_sizeof(xdr_smb_dr_user_ctx_t, user_ctx) + bytes_off;
+
+ bzero(tmp_pipe.sp_pipename, SMB_MAX_PIPENAMELEN);
+ bcopy(bufp + tbytes, tmp_pipe.sp_pipename, SMB_MAX_PIPENAMELEN);
+ bplen = SMB_MAX_PIPENAMELEN;
+ bcopy(bufp + tbytes + bplen, &tmp_pipe.sp_pipeid, sizeof (uint32_t));
+ bplen += sizeof (uint32_t);
+ bcopy(bufp + tbytes + bplen, &tmp_pipe.sp_datalen, sizeof (uint32_t));
+ bplen += sizeof (uint32_t);
+
+ total_pipelen = bplen + tmp_pipe.sp_datalen;
+ inpipe = malloc(total_pipelen);
+ if (! inpipe) {
+ syslog(LOG_ERR, "mds: resource shortage");
+ goto zero_exit;
+ }
+ (void) strlcpy(inpipe->sp_pipename, tmp_pipe.sp_pipename,
+ SMB_MAX_PIPENAMELEN);
+ inpipe->sp_pipeid = tmp_pipe.sp_pipeid;
+ inpipe->sp_datalen = tmp_pipe.sp_datalen;
+ bcopy(bufp + tbytes + bplen, inpipe->sp_data, inpipe->sp_datalen);
+
+ context = mlsvc_lookup_context(inpipe->sp_pipeid);
+ if (!context) {
+ syslog(LOG_ERR, "mds: Cannot lookup mlsvc context");
+ goto zero_exit;
+ }
+ adj_len = mdhin.md_length;
+ /*
+ * If RPC_TRANSACT, save len, set cookie to 0 and store
+ * outpipe pointer into rpc_context. This will be used later
+ * by RPC_READ. See if we have pending writes.
+ * Clear the in context if we do.
+ */
+ if ((mdhin.md_call_type == SMB_RPC_READ) && (context->inlen)) {
+ context->inpipe->sp_datalen = context->inlen;
+ if (context->inpipe->sp_pipeid != inpipe->sp_pipeid) {
+ syslog(LOG_DEBUG, "mds: RPC_READ pipeid mismatch !!");
+ goto zero_exit;
+ }
+ (void) mlsvc_rpc_process(context->inpipe, &outpipe, user_ctx);
+ context->inlen = 0;
+ free(context->inpipe);
+ context->inpipe = NULL;
+ /*
+ * if no outpipe yet, initialize it
+ */
+ if (!context->outpipe) {
+ context->outpipe = outpipe;
+ context->outcookie = 0;
+ context->outlen = outpipe->sp_datalen;
+ }
+ }
+ if (mdhin.md_call_type == SMB_RPC_TRANSACT) {
+ (void) mlsvc_rpc_process(inpipe, &outpipe, user_ctx);
+ /*
+ * init pipe context for subsequent calls
+ */
+ context->outpipe = outpipe;
+ context->outcookie = 0;
+ context->outlen = outpipe->sp_datalen;
+ if (outpipe->sp_datalen < mdhin.md_length)
+ adj_len = outpipe->sp_datalen;
+ }
+ if (mdhin.md_call_type == SMB_RPC_WRITE) {
+ /*
+ * the first write we need to allocate
+ * the maximum inpipe len
+ */
+ if (context->inlen == 0) {
+ context->inpipe = malloc(MAX_INPIPE_LEN);
+ }
+ if (! context->inpipe) {
+ syslog(LOG_ERR, "mds: ctx resource shortage");
+ goto zero_exit;
+ }
+ bcopy(inpipe->sp_data, context->inpipe->sp_data +
+ context->inlen, inpipe->sp_datalen);
+ /*
+ * if we get another RPC_WRITE then we need to append
+ */
+ context->inlen += inpipe->sp_datalen;
+ context->inpipe->sp_pipeid = inpipe->sp_pipeid;
+ context->inpipe->sp_datalen = context->inlen;
+ (void) strlcpy(context->inpipe->sp_pipename,
+ inpipe->sp_pipename, SMB_MAX_PIPENAMELEN);
+ goto zero_exit;
+ }
+ obuf = malloc(START_OUTDOOR_SIZE);
+ if (! obuf) {
+ syslog(LOG_ERR, "mds: obuf resource shortage");
+ goto zero_exit;
+ }
+ /*
+ * check if this is the first transfer
+ * pipe and cookie management
+ */
+ if (context->outcookie > 0) {
+ if (context->outcookie >= context->outlen) {
+ goto zero_exit;
+ } else {
+ if (adj_len < (context->outlen - context->outcookie)) {
+ bcopy(context->outpipe->sp_data +
+ context->outcookie, obuf, adj_len);
+ context->outcookie += adj_len;
+ current_out_len = adj_len;
+ } else {
+ bcopy(context->outpipe->sp_data +
+ context->outcookie, obuf, (context->outlen -
+ context->outcookie));
+ current_out_len = context->outlen -
+ context->outcookie;
+ context->outcookie = 0;
+ free(context->outpipe);
+ context->outpipe = NULL;
+ }
+ }
+ outpipe = malloc(START_OUTDOOR_SIZE);
+ if (! outpipe) {
+ syslog(LOG_ERR, "mds: outpipe resource shortage");
+ goto zero_exit;
+ }
+ } else {
+ if (adj_len < context->outlen) {
+ bcopy(context->outpipe->sp_data, obuf, adj_len);
+ context->outcookie += adj_len;
+ current_out_len = adj_len;
+ } else {
+ bcopy(context->outpipe->sp_data, obuf, context->outlen);
+ current_out_len = context->outlen;
+ context->outcookie = 0;
+ free(context->outpipe);
+ context->outpipe = NULL;
+ }
+ }
+ mdhout = mdhin;
+ mdhout.md_tid = (uint64_t)getpid(); /* user process pid */
+ bytes_off = 0;
+ bcopy(&mdhout.md_tid, lfp, sizeof (uint64_t));
+ bytes_off = sizeof (uint64_t);
+ bcopy(&mdhout.md_version, lfp + bytes_off, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(&mdhout.md_call_type, lfp + bytes_off, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(&adj_len, lfp + bytes_off, sizeof (uint32_t));
+ bytes_off += sizeof (uint32_t);
+ bcopy(&mdhout.md_reserved, lfp + bytes_off, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ tbytes = 0;
+ tbytes = bytes_off;
+ bzero(outpipe->sp_pipename, SMB_MAX_PIPENAMELEN);
+ (void) strcpy(outpipe->sp_pipename, "OUTPIPE");
+ outpipe->sp_pipeid = inpipe->sp_pipeid;
+ bcopy(outpipe->sp_pipename, lfp + tbytes, SMB_MAX_PIPENAMELEN);
+ bplen = SMB_MAX_PIPENAMELEN;
+ bcopy(&(outpipe->sp_pipeid), lfp + tbytes + bplen, sizeof (uint32_t));
+ bplen += sizeof (uint32_t);
+
+ bcopy(&(current_out_len), lfp + tbytes + bplen, sizeof (uint32_t));
+ bplen += sizeof (uint32_t);
+
+ bcopy(obuf, lfp + tbytes + bplen, current_out_len);
+ tbytes += bplen + current_out_len;
+ smb_user_ctx_free(user_ctx);
+ free(obuf);
+ free(inpipe);
+ (void) door_return((char *)lfp, tbytes, NULL, 0);
+ /*NOTREACHED*/
+
+zero_exit:
+ smb_user_ctx_free(user_ctx);
+
+ if (obuf)
+ free(obuf);
+ if (inpipe)
+ free(inpipe);
+
+ (void) door_return(0, 0, NULL, 0);
+}
+
+/*
+ * smb_mlsvc_srv_start
+ *
+ * Start the mlsvc door service.
+ */
+int
+smb_mlsvc_srv_start()
+{
+ int newfd;
+
+ (void) pthread_mutex_lock(&smb_winpipe_user_mutex);
+
+ if (smb_updoor_id != -1) {
+ (void) fprintf(stderr, "smb_mlsvc_srv_start: duplicate");
+ (void) pthread_mutex_unlock(&smb_winpipe_user_mutex);
+ return (-1);
+ }
+
+ errno = 0;
+ if ((smb_updoor_id = door_create(smb_mlsvc_door_server, 0, 0)) < 0) {
+ (void) fprintf(stderr, "smb_mlsvc_srv_start: door_create: %s",
+ strerror(errno));
+ smb_updoor_id = -1;
+ (void) pthread_mutex_unlock(&smb_winpipe_user_mutex);
+ return (-1);
+ }
+
+ (void) unlink(SMB_WINPIPE_DOOR_UP_PATH);
+
+ if ((newfd = creat(SMB_WINPIPE_DOOR_UP_PATH, 0644)) < 0) {
+ (void) fprintf(stderr, "smb_mlsvc_srv_start: open: %s",
+ strerror(errno));
+ (void) door_revoke(smb_updoor_id);
+ smb_updoor_id = -1;
+ (void) pthread_mutex_unlock(&smb_winpipe_user_mutex);
+ return (-1);
+ }
+
+ (void) close(newfd);
+ (void) fdetach(SMB_WINPIPE_DOOR_UP_PATH);
+
+ if (fattach(smb_updoor_id, SMB_WINPIPE_DOOR_UP_PATH) < 0) {
+ (void) fprintf(stderr, "smb_mlsvc_srv_start: fattach: %s",
+ strerror(errno));
+ (void) door_revoke(smb_updoor_id);
+ smb_updoor_id = -1;
+ (void) pthread_mutex_unlock(&smb_winpipe_user_mutex);
+ return (-1);
+ }
+
+ (void) pthread_mutex_unlock(&smb_winpipe_user_mutex);
+ return (0);
+}
+
+/*
+ * smb_mlsvc_srv_stop
+ *
+ * Stop the mlsvc door service.
+ * We will eventually call this based on some signals
+ * No one calls this just yet, if the process dies all this stuff happens
+ * by default
+ */
+void
+smb_mlsvc_srv_stop()
+{
+ (void) pthread_mutex_lock(&smb_winpipe_user_mutex);
+
+ if (smb_updoor_id != -1) {
+ (void) fdetach(SMB_WINPIPE_DOOR_UP_PATH);
+ (void) door_revoke(smb_updoor_id);
+ smb_updoor_id = -1;
+ }
+
+ (void) pthread_mutex_unlock(&smb_winpipe_user_mutex);
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_nicmon.c b/usr/src/cmd/smbsrv/smbd/smbd_nicmon.c
new file mode 100644
index 0000000000..e13f7c457d
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_nicmon.c
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is the SMB NIC monitoring module.
+ */
+#include <sys/types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbns.h>
+
+static pthread_t smb_nicmon_thread;
+
+static void smb_setup_rtsock(int, int *);
+static int smb_nics_changed(int);
+static void *smb_nicmonitor(void *);
+static int smb_setup_eventpipe(int *, int *);
+static void smb_process_nic_change();
+
+/* Use this to stop monitoring */
+static int eventpipe_write = -1;
+
+/*
+ * Start the nic monitor thread.
+ */
+int
+smb_nicmon_start(void)
+{
+ int rc = 0;
+
+ smb_nic_build_info();
+ rc = pthread_create(&smb_nicmon_thread, NULL, smb_nicmonitor, 0);
+ if (rc != 0) {
+ syslog(LOG_ERR, "smb_nicmonitor: "
+ "NIC monitoring failed to start: %s", strerror(errno));
+ return (rc);
+ }
+ return (rc);
+}
+
+/*
+ * Stop the nic monitor.
+ */
+void
+smb_nicmon_stop(void)
+{
+ uchar_t buf = 1;
+
+ if (eventpipe_write < 0)
+ return;
+
+ (void) write(eventpipe_write, &buf, sizeof (buf));
+}
+
+/*
+ * Setup routing socket for getting RTM messages.
+ */
+static void
+smb_setup_rtsock(int af, int *s)
+{
+ int flags;
+
+ *s = socket(PF_ROUTE, SOCK_RAW, af);
+ if (*s == -1) {
+ syslog(LOG_ERR, "smb_setup_rtsock: failed to "
+ "create routing socket");
+ return;
+ }
+ if ((flags = fcntl(*s, F_GETFL, 0)) < 0) {
+ syslog(LOG_ERR, "smb_setup_rtsock: failed to fcntl F_GETFL");
+ (void) close(*s);
+ *s = -1;
+ return;
+ }
+ if ((fcntl(*s, F_SETFL, flags | O_NONBLOCK)) < 0) {
+ syslog(LOG_ERR, "smb_setup_rtsock: failed to fcntl F_SETFL");
+ (void) close(*s);
+ *s = -1;
+ return;
+ }
+}
+
+static int
+smb_nics_changed(int sock)
+{
+ int nbytes;
+ int64_t msg[2048 / 8];
+ struct rt_msghdr *rtm;
+ int need_if_scan = 0;
+
+ /* Read as many messages as possible and try to empty the sockets */
+ for (;;) {
+ nbytes = read(sock, msg, sizeof (msg));
+ if (nbytes <= 0) {
+ break;
+ }
+ rtm = (struct rt_msghdr *)msg;
+ if (rtm->rtm_version != RTM_VERSION) {
+ continue;
+ }
+ if (nbytes < rtm->rtm_msglen) {
+ syslog(LOG_DEBUG, "smb_nicmonitor: short read: %d "
+ "of %d", nbytes, rtm->rtm_msglen);
+ continue;
+ }
+
+ switch (rtm->rtm_type) {
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ case RTM_IFINFO:
+ need_if_scan = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return (need_if_scan);
+}
+
+/*
+ * Create pipe for signal delivery and set up signal handlers.
+ */
+static int
+smb_setup_eventpipe(int *read_pipe, int *write_pipe)
+{
+ int fds[2];
+
+ if ((pipe(fds)) < 0) {
+ syslog(LOG_ERR, "smb_nicmonitor: failed to open pipe");
+ return (1);
+ }
+ *read_pipe = fds[0];
+ *write_pipe = fds[1];
+ return (0);
+}
+
+/*
+ * Call this to do stuff after ifs changed.
+ */
+static void
+smb_process_nic_change()
+{
+ int ddns_enabled;
+
+ smb_config_rdlock();
+ ddns_enabled = smb_config_getyorn(SMB_CI_DYNDNS_ENABLE);
+ smb_config_unlock();
+
+ /* Clear rev zone before creating if list */
+ if (ddns_enabled) {
+ if (dyndns_clear_rev_zone() != 0) {
+ syslog(LOG_ERR, "smb_nicmonitor: "
+ "failed to clear DNS reverse lookup zone");
+ }
+ }
+
+ /* re-initialize NIC table */
+ smb_nic_build_info();
+
+ smb_netbios_name_reconfig();
+
+ if (ddns_enabled) {
+ if (dyndns_update() != 0) {
+ syslog(LOG_ERR, "smb_nicmonitor: "
+ "failed to update dynamic DNS");
+ }
+ }
+}
+
+/*ARGSUSED*/
+static void *
+smb_nicmonitor(void *args)
+{
+ struct pollfd pollfds[2];
+ int pollfd_num = 2;
+ int i, nic_changed;
+ /* AF_INET routing socket add AF_INET6 when we support IPv6 */
+ static int rtsock_v4;
+ static int eventpipe_read = -1;
+
+ /*
+ * Create the global routing socket. We use this to
+ * monitor changes in NIC interfaces. We are only interested
+ * in new inerface addition/deletion and change in UP/DOWN status.
+ */
+ smb_setup_rtsock(AF_INET, &rtsock_v4);
+ if (rtsock_v4 == -1) {
+ syslog(LOG_ERR, "smb_nicmonitor: cannot open routing socket");
+ return (NULL);
+ }
+ if (smb_setup_eventpipe(&eventpipe_read, &eventpipe_write) != 0) {
+ syslog(LOG_ERR, "smb_nicmonitor: cannot open event pipes");
+ return (NULL);
+ }
+
+ /*
+ * Keep listening for activity on any of the sockets.
+ */
+ for (;;) {
+ nic_changed = 0;
+ pollfds[0].fd = rtsock_v4;
+ pollfds[0].events = POLLIN;
+ pollfds[1].fd = eventpipe_read;
+ pollfds[1].events = POLLIN;
+ if (poll(pollfds, pollfd_num, -1) < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "smb_nicmonitor: "
+ "poll failed with errno %d", errno);
+ break;
+ }
+ for (i = 0; i < pollfd_num; i++) {
+ if ((pollfds[i].fd < 0) ||
+ !(pollfds[i].revents & POLLIN))
+ continue;
+ if (pollfds[i].fd == rtsock_v4)
+ nic_changed = smb_nics_changed(rtsock_v4);
+ if (pollfds[i].fd == eventpipe_read)
+ goto done;
+ }
+
+ /*
+ * If anything changed do refresh our
+ * nic list and other configs.
+ */
+ if (nic_changed)
+ smb_process_nic_change();
+ }
+done:
+ /* Close sockets */
+ (void) close(rtsock_v4);
+ (void) close(eventpipe_read);
+ (void) close(eventpipe_write);
+ eventpipe_write = -1;
+ return (NULL);
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c
new file mode 100644
index 0000000000..342ac7b4e5
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c
@@ -0,0 +1,371 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * LanMan share door server
+ */
+
+#include <door.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <smbsrv/libsmb.h>
+
+#include <smbsrv/lmshare.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/smbinfo.h>
+
+static smb_kmod_cfg_t smb_kcfg;
+
+static int smb_lmshrd_fildes = -1;
+static pthread_mutex_t smb_lmshrd_srv_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* forward declaration */
+static void smb_lmshrd_srv_door(void *cookie, char *ptr, size_t size,
+ door_desc_t *dp, uint_t n_desc);
+static int smb_lmshrd_srv_check(int opcode, char *sharename);
+
+/*
+ * smb_lmshrd_srv_start
+ *
+ * Start the LanMan share door service.
+ * Returns 0 on success. Otherwise, -1.
+ */
+int
+smb_lmshrd_srv_start()
+{
+ int newfd;
+
+ (void) pthread_mutex_lock(&smb_lmshrd_srv_mutex);
+
+ if (smb_lmshrd_fildes != -1) {
+ syslog(LOG_ERR, "smb_lmshrd_srv_start: duplicate");
+ (void) pthread_mutex_unlock(&smb_lmshrd_srv_mutex);
+ return (0);
+ }
+
+ if ((smb_lmshrd_fildes = door_create(smb_lmshrd_srv_door,
+ LMSHR_DOOR_COOKIE, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) {
+ syslog(LOG_ERR, "smb_lmshrd_srv_start: door_create: %s",
+ strerror(errno));
+ (void) pthread_mutex_unlock(&smb_lmshrd_srv_mutex);
+ return (-1);
+ }
+
+ (void) unlink(LMSHR_DOOR_NAME);
+
+ if ((newfd = creat(LMSHR_DOOR_NAME, 0644)) < 0) {
+ syslog(LOG_ERR, "smb_lmshrd_srv_start: open: %s",
+ strerror(errno));
+ (void) door_revoke(smb_lmshrd_fildes);
+ smb_lmshrd_fildes = -1;
+ (void) pthread_mutex_unlock(&smb_lmshrd_srv_mutex);
+ return (-1);
+ }
+
+ (void) close(newfd);
+ (void) fdetach(LMSHR_DOOR_NAME);
+
+ if (fattach(smb_lmshrd_fildes, LMSHR_DOOR_NAME) < 0) {
+ syslog(LOG_ERR, "smb_lmshrd_srv_start: fattach: %s",
+ strerror(errno));
+ (void) door_revoke(smb_lmshrd_fildes);
+ smb_lmshrd_fildes = -1;
+ (void) pthread_mutex_unlock(&smb_lmshrd_srv_mutex);
+ return (-1);
+ }
+
+ (void) pthread_mutex_unlock(&smb_lmshrd_srv_mutex);
+ return (0);
+}
+
+
+/*
+ * smb_lmshrd_srv_stop
+ *
+ * Stop the LanMan share door service.
+ */
+void
+smb_lmshrd_srv_stop(void)
+{
+ (void) pthread_mutex_lock(&smb_lmshrd_srv_mutex);
+
+ if (smb_lmshrd_fildes != -1) {
+ (void) fdetach(LMSHR_DOOR_NAME);
+ (void) door_revoke(smb_lmshrd_fildes);
+ smb_lmshrd_fildes = -1;
+ }
+
+ (void) pthread_mutex_unlock(&smb_lmshrd_srv_mutex);
+}
+
+
+/*
+ * smb_lmshrd_srv_door
+ *
+ * This function with which the LMSHARE door is associated
+ * will invoke the appropriate CIFS share management function
+ * based on the request type of the door call.
+ */
+/*ARGSUSED*/
+void
+smb_lmshrd_srv_door(void *cookie, char *ptr, size_t size, door_desc_t *dp,
+ uint_t n_desc)
+{
+ DWORD rc;
+ int req_type, mode, rc2;
+ char buf[LMSHR_DOOR_SIZE];
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx = smb_dr_decode_start(ptr, size);
+ smb_dr_ctx_t *enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
+ unsigned int dec_status;
+ unsigned int enc_status;
+ char *sharename, *sharename2;
+ lmshare_info_t lmshr_info;
+ lmshare_info_t *lmshr_infop;
+ lmshare_iterator_t *lmshr_iter;
+ int offset;
+ lmshare_list_t lmshr_list;
+
+ req_type = smb_dr_get_uint32(dec_ctx);
+
+ switch (req_type) {
+ case LMSHR_DOOR_OPEN_ITERATOR:
+ mode = smb_dr_get_int32(dec_ctx);
+
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
+ goto decode_error;
+
+ lmshr_iter = lmshare_open_iterator(mode);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_lmshr_iterator(enc_ctx,
+ (uint64_t)(uintptr_t)lmshr_iter);
+
+ break;
+
+ case LMSHR_DOOR_CLOSE_ITERATOR:
+ lmshr_iter = (lmshare_iterator_t *)(uintptr_t)
+ smb_dr_get_lmshr_iterator(dec_ctx);
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
+ goto decode_error;
+
+ lmshare_close_iterator(lmshr_iter);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ break;
+
+ case LMSHR_DOOR_ITERATE:
+ lmshr_iter = (lmshare_iterator_t *)(uintptr_t)
+ smb_dr_get_lmshr_iterator(dec_ctx);
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
+ goto decode_error;
+
+ lmshr_infop = lmshare_iterate(lmshr_iter);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_lmshare(enc_ctx, lmshr_infop);
+ break;
+
+ case LMSHR_DOOR_NUM_SHARES:
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
+ goto decode_error;
+
+ rc = lmshare_num_shares();
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_uint32(enc_ctx, rc);
+ break;
+
+ case LMSHR_DOOR_DELETE:
+ sharename = smb_dr_get_string(dec_ctx);
+
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ smb_dr_free_string(sharename);
+ goto decode_error;
+ }
+
+ rc = lmshare_delete(sharename, 0);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_uint32(enc_ctx, rc);
+ smb_dr_free_string(sharename);
+ break;
+
+ case LMSHR_DOOR_RENAME:
+ sharename = smb_dr_get_string(dec_ctx);
+ sharename2 = smb_dr_get_string(dec_ctx);
+
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ smb_dr_free_string(sharename);
+ smb_dr_free_string(sharename2);
+ goto decode_error;
+ }
+
+ rc = lmshare_rename(sharename, sharename2, 0);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_uint32(enc_ctx, rc);
+ smb_dr_free_string(sharename);
+ smb_dr_free_string(sharename2);
+ break;
+
+ case LMSHR_DOOR_GETINFO:
+ sharename = smb_dr_get_string(dec_ctx);
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ smb_dr_free_string(sharename);
+ goto decode_error;
+ }
+
+ rc = lmshare_getinfo(sharename, &lmshr_info);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_uint32(enc_ctx, rc);
+ smb_dr_put_lmshare(enc_ctx, &lmshr_info);
+ smb_dr_free_string(sharename);
+ break;
+
+ case LMSHR_DOOR_ADD:
+ smb_dr_get_lmshare(dec_ctx, &lmshr_info);
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
+ goto decode_error;
+
+ rc = lmshare_add(&lmshr_info, 0);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_uint32(enc_ctx, rc);
+ smb_dr_put_lmshare(enc_ctx, &lmshr_info);
+ break;
+
+ case LMSHR_DOOR_SETINFO:
+ smb_dr_get_lmshare(dec_ctx, &lmshr_info);
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
+ goto decode_error;
+
+ rc = lmshare_setinfo(&lmshr_info, 0);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_uint32(enc_ctx, rc);
+ break;
+
+ case LMSHR_DOOR_EXISTS:
+ case LMSHR_DOOR_IS_SPECIAL:
+ case LMSHR_DOOR_IS_RESTRICTED:
+ case LMSHR_DOOR_IS_ADMIN:
+ case LMSHR_DOOR_IS_VALID:
+ case LMSHR_DOOR_IS_DIR:
+ sharename = smb_dr_get_string(dec_ctx);
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ smb_dr_free_string(sharename);
+ goto decode_error;
+ }
+
+ rc2 = smb_lmshrd_srv_check(req_type, sharename);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_uint32(enc_ctx, rc2);
+ smb_dr_free_string(sharename);
+ break;
+
+ case LMSHR_DOOR_LIST:
+ offset = smb_dr_get_int32(dec_ctx);
+ if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
+ goto decode_error;
+
+ rc = lmshare_list(offset, &lmshr_list);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_uint32(enc_ctx, rc);
+ smb_dr_put_lmshr_list(enc_ctx, &lmshr_list);
+ break;
+
+ case SMB_GET_KCONFIG:
+ smb_load_kconfig(&smb_kcfg);
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_SUCCESS);
+ smb_dr_put_kconfig(enc_ctx, &smb_kcfg);
+ break;
+
+ default:
+ goto decode_error;
+ }
+
+ if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0)
+ goto encode_error;
+
+ (void) door_return(buf, used, NULL, 0);
+
+ return;
+
+decode_error:
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_ERROR);
+ smb_dr_put_uint32(enc_ctx, dec_status);
+ (void) smb_dr_encode_finish(enc_ctx, &used);
+ (void) door_return(buf, used, NULL, 0);
+ return;
+
+encode_error:
+ enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
+ smb_dr_put_int32(enc_ctx, LMSHR_DOOR_SRV_ERROR);
+ smb_dr_put_uint32(enc_ctx, enc_status);
+ (void) smb_dr_encode_finish(enc_ctx, &used);
+ (void) door_return(buf, used, NULL, 0);
+}
+
+/*
+ * smb_lmshrd_srv_check
+ *
+ * Depending upon the opcode, this function will
+ * either check the existence of a share/dir or
+ * the the type of the specified share.
+ */
+static int
+smb_lmshrd_srv_check(int opcode, char *sharename)
+{
+ int rc;
+
+ switch (opcode) {
+ case LMSHR_DOOR_EXISTS:
+ rc = lmshare_exists(sharename);
+ break;
+
+ case LMSHR_DOOR_IS_SPECIAL:
+ rc = lmshare_is_special(sharename);
+ break;
+
+ case LMSHR_DOOR_IS_RESTRICTED:
+ rc = lmshare_is_restricted(sharename);
+ break;
+
+ case LMSHR_DOOR_IS_ADMIN:
+ rc = lmshare_is_admin(sharename);
+ break;
+
+ case LMSHR_DOOR_IS_VALID:
+ rc = lmshare_is_valid(sharename);
+ break;
+
+ case LMSHR_DOOR_IS_DIR:
+ rc = lmshare_is_dir(sharename);
+ }
+
+ return (rc);
+}
diff --git a/usr/src/cmd/smbsrv/smbstat/Makefile b/usr/src/cmd/smbsrv/smbstat/Makefile
new file mode 100644
index 0000000000..1bb8b73737
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbstat/Makefile
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG= smbstat
+SRCS= smbstat.c
+
+include ../../Makefile.cmd
+
+OBJS= $(SRCS:%.c=%.o)
+
+include ../Makefile.smbsrv.defs
+
+LDLIBS = -lumem -lkstat
+include ../Makefile.smbsrv.targ
+include ../../Makefile.targ
diff --git a/usr/src/cmd/smbsrv/smbstat/smbstat.c b/usr/src/cmd/smbsrv/smbstat/smbstat.c
new file mode 100644
index 0000000000..b2c4bab4a7
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbstat/smbstat.c
@@ -0,0 +1,283 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * smbstat: Server Message Block File System statistics
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <kstat.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <strings.h>
+#include <utility.h>
+#include <libintl.h>
+#include <zone.h>
+
+static kstat_ctl_t *kc; /* libkstat cookie */
+static kstat_t *smb_info;
+static kstat_t *smb_dispatch;
+static kstat_t *ksmb_kstat;
+
+static int get_smbinfo_stat(void);
+static int get_smbdispatch_stat(void);
+static void smbstat_setup(void);
+static void smbstat_smb_info_print();
+static void smbstat_smb_dispatch_print();
+static void smbstat_print(const char *, kstat_t *, int);
+static int smbstat_width(kstat_t *, int);
+static void smbstat_fail(int, char *, ...);
+static kid_t smbstat_kstat_read(kstat_ctl_t *, kstat_t *, void *);
+static void smbstat_usage(void);
+
+#define MAX_COLUMNS 80
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int iflag = 0; /* smb_info stats */
+ int dflag = 0; /* smb_dispatch_all stats */
+
+ if (getzoneid() != GLOBAL_ZONEID) {
+ (void) fprintf(stderr,
+ gettext("%s: Cannot execute in non-global zone.\n"),
+ argv[0]);
+ return (0);
+ }
+
+ if (is_system_labeled()) {
+ (void) fprintf(stderr,
+ gettext("%s: Trusted Extensions not supported.\n"),
+ argv[0]);
+ return (0);
+ }
+
+ while ((c = getopt(argc, argv, "id")) != EOF) {
+ switch (c) {
+ case 'i':
+ iflag++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case '?':
+ default:
+ smbstat_usage();
+ }
+ }
+
+ if ((argc - optind) > 0) {
+ smbstat_usage();
+ }
+
+ smbstat_setup();
+
+ if (iflag) {
+ smbstat_smb_info_print();
+ } else if (dflag) {
+ smbstat_smb_dispatch_print();
+ } else {
+ smbstat_smb_info_print();
+ smbstat_smb_dispatch_print();
+ }
+
+ (void) kstat_close(kc);
+ free(ksmb_kstat);
+ return (0);
+}
+
+
+static int
+get_smbinfo_stat(void)
+{
+ (void) smbstat_kstat_read(kc, smb_info, NULL);
+ return (smbstat_width(smb_info, 0));
+}
+
+static int
+get_smbdispatch_stat(void)
+{
+ (void) smbstat_kstat_read(kc, smb_dispatch, NULL);
+ return (smbstat_width(smb_dispatch, 0));
+}
+
+static void
+smbstat_smb_info_print()
+{
+ int field_width;
+
+ field_width = get_smbinfo_stat();
+ if (field_width == 0)
+ return;
+
+ smbstat_print(gettext("\nSMB Info:\n"), smb_info, field_width);
+}
+
+static void
+smbstat_smb_dispatch_print()
+{
+ int field_width;
+
+ field_width = get_smbdispatch_stat();
+ if (field_width == 0)
+ return;
+
+ smbstat_print(gettext("\nAll dispatched SMB requests statistics:\n"),
+ smb_dispatch, field_width);
+}
+
+static void
+smbstat_setup(void)
+{
+ if ((kc = kstat_open()) == NULL)
+ smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
+
+ if ((ksmb_kstat = malloc(sizeof (kstat_t))) == NULL) {
+ (void) kstat_close(kc);
+ smbstat_fail(1, gettext("Out of memory"));
+ }
+
+ smb_info = kstat_lookup(kc, "smb", 0, "smb_info");
+ smb_dispatch = kstat_lookup(kc, "smb", 0, "smb_dispatch_all");
+ if ((smb_info == NULL) || (smb_dispatch == NULL))
+ smbstat_fail(0, gettext("kstat lookups failed for smb. "
+ "Your kernel module may not be loaded\n"));
+}
+
+static int
+smbstat_width(kstat_t *req, int field_width)
+{
+ int i, nreq, len;
+ char fixlen[128];
+ kstat_named_t *knp;
+
+ knp = KSTAT_NAMED_PTR(req);
+ nreq = req->ks_ndata;
+
+ for (i = 0; i < nreq; i++) {
+ len = strlen(knp[i].name) + 1;
+ if (field_width < len)
+ field_width = len;
+ (void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64);
+ len = strlen(fixlen) + 1;
+ if (field_width < len)
+ field_width = len;
+ }
+ return (field_width);
+}
+
+static void
+smbstat_print(const char *title_string, kstat_t *req, int field_width)
+{
+ int i, j, nreq, ncolumns;
+ char fixlen[128];
+ kstat_named_t *knp;
+
+ if (req == NULL)
+ return;
+
+ if (field_width == 0)
+ return;
+
+ (void) printf("%s\n", title_string);
+ ncolumns = (MAX_COLUMNS -1)/field_width;
+
+ knp = KSTAT_NAMED_PTR(req);
+ nreq = req->ks_ndata;
+
+ for (i = 0; i < nreq; i += ncolumns) {
+ /* prints out the titles of the columns */
+ for (j = i; j < MIN(i + ncolumns, nreq); j++) {
+ (void) printf("%-*s", field_width, knp[j].name);
+ }
+ (void) printf("\n");
+ /* prints out the stat numbers */
+ for (j = i; j < MIN(i + ncolumns, nreq); j++) {
+ (void) sprintf(fixlen, "%" PRIu64 " ",
+ knp[j].value.ui64);
+ (void) printf("%-*s", field_width, fixlen);
+ }
+ (void) printf("\n");
+
+ }
+}
+
+static void
+smbstat_usage(void)
+{
+ (void) fprintf(stderr, gettext("Usage: smbstat [-id]\n"));
+ exit(1);
+}
+
+static void
+smbstat_fail(int do_perror, char *message, ...)
+{
+ va_list args;
+
+ va_start(args, message);
+ (void) fprintf(stderr, gettext("smbstat: "));
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) vfprintf(stderr, message, args);
+ va_end(args);
+ if (do_perror)
+ (void) fprintf(stderr, ": %s", strerror(errno));
+ (void) fprintf(stderr, "\n");
+ exit(1);
+}
+
+static kid_t
+smbstat_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data)
+{
+ kid_t kstat_chain_id = kstat_read(kc, ksp, data);
+
+ if (kstat_chain_id == -1)
+ smbstat_fail(1, gettext("kstat_read('%s') failed"),
+ ksp->ks_name);
+ return (kstat_chain_id);
+}
+
+/*
+ * Enable libumem debugging by default on DEBUG builds.
+ */
+#ifdef DEBUG
+/* LINTED - external libumem symbol */
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+/* LINTED - external libumem symbol */
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+#endif
diff --git a/usr/src/cmd/svc/configd/rc_node.c b/usr/src/cmd/svc/configd/rc_node.c
index 4ef49a0b05..bed6c9ed3f 100644
--- a/usr/src/cmd/svc/configd/rc_node.c
+++ b/usr/src/cmd/svc/configd/rc_node.c
@@ -900,7 +900,7 @@ perm_add_enabling(permcheck_t *pcp, const char *auth)
* perm_granted() returns 1 if the current door caller has one of the enabling
* authorizations in pcp, 0 if it doesn't, and -1 if an error (usually lack of
* memory) occurs. check_auth_list() checks an RBAC_AUTH_SEP-separated list
- * of authorizations for existance in pcp, and check_prof_list() checks the
+ * of authorizations for existence in pcp, and check_prof_list() checks the
* authorizations granted to an RBAC_AUTH_SEP-separated list of profiles.
*/
static int
diff --git a/usr/src/cmd/tar/Makefile b/usr/src/cmd/tar/Makefile
index a8053fb33d..8d8157c5c5 100644
--- a/usr/src/cmd/tar/Makefile
+++ b/usr/src/cmd/tar/Makefile
@@ -40,7 +40,7 @@ DCFILE= $(PROG).dc
LINTFLAGS += -u
LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
lint := LAZYLIBS = -ltsol
-LDLIBS += -lsec $(LAZYLIBS)
+LDLIBS += -lsec -lcmdutils -lnvpair $(LAZYLIBS)
CFLAGS += $(CCVERBOSE)
diff --git a/usr/src/cmd/tar/tar.c b/usr/src/cmd/tar/tar.c
index d68c4e0e34..80e72adb35 100644
--- a/usr/src/cmd/tar/tar.c
+++ b/usr/src/cmd/tar/tar.c
@@ -61,26 +61,32 @@
#include <stdarg.h>
#include <widec.h>
#include <sys/mtio.h>
-#include <libintl.h>
#include <sys/acl.h>
#include <strings.h>
#include <deflt.h>
#include <limits.h>
#include <iconv.h>
#include <assert.h>
+#include <libgen.h>
+#include <libintl.h>
#include <aclutils.h>
-#include "getresponse.h"
+#include <libnvpair.h>
+#include <archives.h>
#if defined(__SunOS_5_6) || defined(__SunOS_5_7)
extern int defcntl();
#endif
-#include <archives.h>
+#if defined(_PC_SATTR_ENABLED)
+#include <attr.h>
+#include <libcmdutils.h>
+#endif
/* Trusted Extensions */
#include <zone.h>
#include <tsol/label.h>
#include <sys/tsol/label_macro.h>
+#include "getresponse.h"
/*
* Source compatibility
*/
@@ -180,6 +186,14 @@ int utimes(const char *path, const struct timeval timeval_ptr[]);
#define PUT_AS_LINK 1
#define PUT_NOTAS_LINK 0
+#ifndef VIEW_READONLY
+#define VIEW_READONLY "SUNWattr_ro"
+#endif
+
+#ifndef VIEW_READWRITE
+#define VIEW_READWRITE "SUNWattr_rw"
+#endif
+
#if _FILE_OFFSET_BITS == 64
#define FMT_off_t "lld"
#define FMT_off_t_o "llo"
@@ -199,6 +213,31 @@ struct sec_attr {
char attr_info[1];
} *attr;
+#if defined(O_XATTR)
+typedef enum {
+ ATTR_OK,
+ ATTR_SKIP,
+ ATTR_CHDIR_ERR,
+ ATTR_OPEN_ERR,
+ ATTR_XATTR_ERR,
+ ATTR_SATTR_ERR
+} attr_status_t;
+#endif
+
+#if defined(O_XATTR)
+typedef enum {
+ ARC_CREATE,
+ ARC_RESTORE
+} arc_action_t;
+#endif
+
+typedef struct attr_data {
+ char *attr_parent;
+ char *attr_path;
+ int attr_parentfd;
+ int attr_rw_sysattr;
+} attr_data_t;
+
/*
*
* Tar has been changed to support extended attributes.
@@ -306,7 +345,7 @@ struct sec_attr {
static struct xattr_hdr *xattrhead;
static struct xattr_buf *xattrp;
static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
-static char *xattraname; /* attribute name */
+static char *xattrapath; /* attribute name */
static char *xattr_linkaname; /* attribute attribute is linked to */
static char Hiddendir; /* are we processing hidden xattr dir */
static char xattrbadhead;
@@ -394,7 +433,7 @@ static void assert_string(char *s, char *msg);
static int istape(int fd, int type);
static void backtape(void);
static void build_table(struct file_list *table[], char *file);
-static void check_prefix(char **namep, char **dirp, char **compp);
+static int check_prefix(char **namep, char **dirp, char **compp);
static void closevol(void);
static void copy(void *dst, void *src);
static int convtoreg(off_t);
@@ -421,7 +460,7 @@ static void newvol(void);
static void passtape(void);
static void putempty(blkcnt_t n);
static int putfile(char *longname, char *shortname, char *parent,
- int filetype, int lev, int symlink_lev);
+ attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
static void readtape(char *buffer);
static void seekdisk(blkcnt_t blocks);
static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
@@ -429,8 +468,8 @@ static void splitfile(char *longname, int ifd, char *name,
char *prefix, int filetype);
static void tomodes(struct stat *sp);
static void usage(void);
-static void xblocks(off_t bytes, int ofile);
-static void xsfile(int ofd);
+static int xblocks(int issysattr, off_t bytes, int ofile);
+static int xsfile(int issysattr, int ofd);
static void resugname(int dirfd, char *name, int symflag);
static int bcheck(char *bstr);
static int checkdir(char *name);
@@ -466,7 +505,8 @@ static char *getname(gid_t);
static char *getgroup(gid_t);
static int checkf(char *name, int mode, int howmuch);
static int writetbuf(char *buffer, int n);
-static int wantit(char *argv[], char **namep, char **dirp, char **comp);
+static int wantit(char *argv[], char **namep, char **dirp, char **comp,
+ attr_data_t **attrinfo);
static void append_ext_attr(char *shortname, char **secinfo, int *len);
static int get_xdata(void);
static void gen_num(const char *keyword, const u_longlong_t number);
@@ -481,17 +521,18 @@ static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
iconv_t iconv_cd, int xhdrflg, int max_val);
static int c_utf8(char *target, const char *source);
-static int getstat(int dirfd, char *longname, char *shortname);
-static void xattrs_put(char *, char *, char *);
+static int getstat(int dirfd, char *longname, char *shortname,
+ char *attrparent);
+static void xattrs_put(char *, char *, char *, char *);
static void prepare_xattr(char **, char *, char *,
char, struct linkbuf *, int *);
-static int put_link(char *name, char *longname, char *component, char *prefix,
- int filetype, char typeflag);
+static int put_link(char *name, char *longname, char *component,
+ char *longattrname, char *prefix, int filetype, char typeflag);
static int put_extra_attributes(char *longname, char *shortname,
- char *prefix, int filetype, char typeflag);
-static int put_xattr_hdr(char *longname, char *shortname, char *prefix,
- int typeflag, int filetype, struct linkbuf *lp);
-static int read_xattr_hdr();
+ char *longattrname, char *prefix, int filetype, char typeflag);
+static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
+ char *prefix, int typeflag, int filetype, struct linkbuf *lp);
+static int read_xattr_hdr(attr_data_t **attrinfo);
/* Trusted Extensions */
#define AUTO_ZONE "/zone"
@@ -503,12 +544,14 @@ static int rebuild_lk_comp_path(char *str, char **namep);
static void get_parent(char *path, char *dir);
static char *get_component(char *path);
-static int retry_attrdir_open(char *name);
+static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
+ char *name, int oflag, mode_t mode);
static char *skipslashes(char *string, char *start);
static void chop_endslashes(char *path);
static struct stat stbuf;
+static char *myname;
static int checkflag = 0;
#ifdef _iBCS2
static int Fileflag;
@@ -523,6 +566,7 @@ static int bflag, kflag, Aflag;
static int Pflag; /* POSIX conformant archive */
static int Eflag; /* Allow files greater than 8GB */
static int atflag; /* traverse extended attributes */
+static int saflag; /* traverse extended sys attributes */
static int Dflag; /* Data change flag */
/* Trusted Extensions */
static int Tflag; /* Trusted Extensions attr flags */
@@ -657,6 +701,11 @@ main(int argc, char *argv[])
usage();
tfile = NULL;
+ if ((myname = strdup(argv[0])) == NULL) {
+ (void) fprintf(stderr, gettext(
+ "tar: cannot allocate program name\n"));
+ exit(1);
+ }
if (init_yes() < 0) {
(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
@@ -737,7 +786,12 @@ main(int argc, char *argv[])
case '@':
atflag++;
break;
-#endif
+#endif /* O_XATTR */
+#if defined(_PC_SATTR_ENABLED)
+ case '/':
+ saflag++;
+ break;
+#endif /* _PC_SATTR_ENABLED */
case 'u':
uflag++; /* moved code after signals caught */
rflag++;
@@ -1047,10 +1101,14 @@ usage(void)
if (sysv3_env) {
(void) fprintf(stderr, gettext(
#if defined(O_XATTR)
+#if defined(_PC_SATTR_ENABLED)
+ "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@/[0-7]][bfFk][X...] "
+#else
"Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@[0-7]][bfFk][X...] "
+#endif /* _PC_SATTR_ENABLED */
#else
"Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw[0-7]][bfFk][X...] "
-#endif
+#endif /* O_XATTR */
"[blocksize] [tarfile] [filename] [size] [exclude-file...] "
"{file | -I include-file | -C directory file}...\n"));
} else
@@ -1058,10 +1116,14 @@ usage(void)
{
(void) fprintf(stderr, gettext(
#if defined(O_XATTR)
+#if defined(_PC_SATTR_ENABLED)
+ "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@/[0-7]][bfk][X...] "
+#else
"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@[0-7]][bfk][X...] "
+#endif /* _PC_SATTR_ENABLED */
#else
"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw[0-7]][bfk][X...] "
-#endif
+#endif /* O_XATTR */
"[blocksize] [tarfile] [size] [exclude-file...] "
"{file | -I include-file | -C directory file}...\n"));
}
@@ -1196,7 +1258,7 @@ dorep(char *argv[])
if (chdir(*++argv) < 0)
vperror(0, gettext(
- "can't change directories to %s"), *argv);
+ "can't change directories to %s"), *argv);
else
(void) getcwd(wdir, (sizeof (wdir)));
argv++;
@@ -1235,7 +1297,7 @@ dorep(char *argv[])
*cp2 = '\0';
if (chdir(file) < 0) {
vperror(0, gettext(
- "can't change directories to %s"), file);
+ "can't change directories to %s"), file);
continue;
}
*cp2 = '/';
@@ -1243,13 +1305,15 @@ dorep(char *argv[])
}
parent = getcwd(tempdir, (sizeof (tempdir)));
- archtype = putfile(file, cp2, parent, NORMAL_FILE,
+
+ archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
LEV0, SYMLINK_LEV0);
#if defined(O_XATTR)
if (!exitflag) {
- if (atflag && archtype == PUT_NOTAS_LINK) {
- xattrs_put(file, cp2, parent);
+ if ((atflag || saflag) &&
+ (archtype == PUT_NOTAS_LINK)) {
+ xattrs_put(file, cp2, parent, NULL);
}
}
#endif
@@ -1447,7 +1511,11 @@ top:
xattr_linkp = NULL;
xattrhead = NULL;
} else {
- if (xattraname[0] == '.' && xattraname[1] == '\0' &&
+ char *aname = basename(xattrapath);
+ size_t xindex = aname - xattrapath;
+
+ if (xattrapath[xindex] == '.' &&
+ xattrapath[xindex + 1] == '\0' &&
xattrp->h_typeflag == '5') {
Hiddendir = 1;
sp->st_mode =
@@ -1495,9 +1563,102 @@ passtape(void)
readtape(buf);
}
+#if defined(O_XATTR)
+static int
+is_sysattr(char *name)
+{
+ return ((strcmp(name, VIEW_READONLY) == 0) ||
+ (strcmp(name, VIEW_READWRITE) == 0));
+}
+#endif
+
+#if defined(O_XATTR)
+/*
+ * Verify the attribute, attrname, is an attribute we want to restore.
+ * Never restore read-only system attribute files. Only restore read-write
+ * system attributes files when -/ was specified, and only traverse into
+ * the 2nd level attribute directory containing only system attributes if
+ * -@ was specified. This keeps us from archiving
+ * <attribute name>/<read-write system attribute file>
+ * when -/ was specified without -@.
+ *
+ * attrname - attribute file name
+ * attrparent - attribute's parent name within the base file's attribute
+ * directory hierarchy
+ */
+static attr_status_t
+verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
+ int *rw_sysattr)
+{
+#if defined(_PC_SATTR_ENABLED)
+ int attr_supported;
+
+ /* Never restore read-only system attribute files */
+ if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
+ *rw_sysattr = 0;
+ return (ATTR_SKIP);
+ } else {
+ *rw_sysattr = (attr_supported == _RW_SATTR);
+ }
+#else
+ /*
+ * Only need to check if this attribute is an extended system
+ * attribute.
+ */
+ if (*rw_sysattr = is_sysattr(attrname)) {
+ return (ATTR_SKIP);
+ } else {
+ return (ATTR_OK);
+ }
+#endif /* _PC_SATTR_ENABLED */
+
+ /*
+ * If the extended system attribute file is specified with the
+ * arc_rwsysattr flag, as being transient (default extended
+ * attributes), then don't archive it.
+ */
+ if (*rw_sysattr && !arc_rwsysattr) {
+ return (ATTR_SKIP);
+ }
+
+ /*
+ * Only restore read-write system attribute files
+ * when -/ was specified. Only restore extended
+ * attributes when -@ was specified.
+ */
+ if (atflag) {
+ if (!saflag) {
+ /*
+ * Only archive/restore the hidden directory "." if
+ * we're processing the top level hidden attribute
+ * directory. We don't want to process the
+ * hidden attribute directory of the attribute
+ * directory that contains only extended system
+ * attributes.
+ */
+ if (*rw_sysattr || (Hiddendir &&
+ (attrparent != NULL))) {
+ return (ATTR_SKIP);
+ }
+ }
+ } else if (saflag) {
+ /*
+ * Only archive/restore read-write extended system attribute
+ * files of the base file.
+ */
+ if (!*rw_sysattr || (attrparent != NULL)) {
+ return (ATTR_SKIP);
+ }
+ } else {
+ return (ATTR_SKIP);
+ }
+
+ return (ATTR_OK);
+}
+#endif
static int
-putfile(char *longname, char *shortname, char *parent,
+putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
int filetype, int lev, int symlink_lev)
{
int infile = -1; /* deliberately invalid */
@@ -1509,6 +1670,8 @@ putfile(char *longname, char *shortname, char *parent,
char filetmp[PATH_MAX + 1];
char *cp;
char *name;
+ char *attrparent = NULL;
+ char *longattrname = NULL;
struct dirent *dp;
DIR *dirp;
int i;
@@ -1517,6 +1680,7 @@ putfile(char *longname, char *shortname, char *parent,
int dirfd = -1;
int rc = PUT_NOTAS_LINK;
int archtype = 0;
+ int rw_sysattr = 0;
char newparent[PATH_MAX + MAXNAMLEN + 1];
char *prefix = "";
char *tmpbuf;
@@ -1533,28 +1697,24 @@ putfile(char *longname, char *shortname, char *parent,
xhdr_flgs = 0;
if (filetype == XATTR_FILE) {
- dirfd = attropen(get_component(longname), ".", O_RDONLY);
+ attrparent = attrinfo->attr_parent;
+ longattrname = attrinfo->attr_path;
+ dirfd = attrinfo->attr_parentfd;
} else {
dirfd = open(".", O_RDONLY);
}
if (dirfd == -1) {
(void) fprintf(stderr, gettext(
- "tar: unable to open%sdirectory %s\n"),
+ "tar: unable to open%sdirectory %s%s%s%s\n"),
(filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
+ (attrparent == NULL) ? "" : gettext("of attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
(filetype == XATTR_FILE) ? longname : parent);
goto out;
}
- if (filetype == XATTR_FILE) {
- if (fchdir(dirfd) < 0) {
- (void) fprintf(stderr, gettext(
- "tar: unable to fchdir into attribute directory"
- " of file %s\n"), longname);
- goto out;
- }
- }
-
if (lev > MAXLEV) {
(void) fprintf(stderr,
gettext("tar: directory nesting too deep, %s not dumped\n"),
@@ -1562,7 +1722,7 @@ putfile(char *longname, char *shortname, char *parent,
goto out;
}
- if (getstat(dirfd, longname, shortname))
+ if (getstat(dirfd, longname, shortname, attrparent))
goto out;
if (hflag) {
@@ -1588,7 +1748,12 @@ putfile(char *longname, char *shortname, char *parent,
*/
if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
(void) fprintf(stderr, gettext(
- "tar: %s same as archive file\n"), longname);
+ "tar: %s%s%s%s%s same as archive file\n"),
+ rw_sysattr ? gettext("system ") : "",
+ (longattrname == NULL) ? "" : gettext("attribute "),
+ (longattrname == NULL) ? "" : longattrname,
+ (longattrname == NULL) ? "" : gettext(" of "),
+ longname);
Errflg = 1;
goto out;
}
@@ -1605,8 +1770,13 @@ putfile(char *longname, char *shortname, char *parent,
!S_ISBLK(stbuf.st_mode) &&
(Eflag == 0)) {
(void) fprintf(stderr, gettext(
- "tar: %s too large to archive. "
- "Use E function modifier.\n"), longname);
+ "tar: %s%s%s%s%s too large to archive. "
+ "Use E function modifier.\n"),
+ rw_sysattr ? gettext("system ") : "",
+ (longattrname == NULL) ? "" : gettext("attribute "),
+ (longattrname == NULL) ? "" : longattrname,
+ (longattrname == NULL) ? "" : gettext(" of "),
+ longname);
if (errflag)
exitflag = 1;
Errflg = 1;
@@ -1787,8 +1957,8 @@ putfile(char *longname, char *shortname, char *parent,
}
}
- if (put_extra_attributes(longname, shortname, prefix,
- filetype, '5') != 0)
+ if (put_extra_attributes(longname, shortname,
+ longattrname, prefix, filetype, '5') != 0)
goto out;
#if defined(O_XATTR)
@@ -1817,8 +1987,8 @@ putfile(char *longname, char *shortname, char *parent,
0);
#endif
if (filetype == XATTR_FILE && Hiddendir) {
- (void) fprintf(vfile, "a %s attribute . ",
- longname);
+ (void) fprintf(vfile, "a %s attribute %s ",
+ longname, longattrname);
} else {
(void) fprintf(vfile, "a %s/ ", longname);
@@ -1835,9 +2005,9 @@ putfile(char *longname, char *shortname, char *parent,
* If hidden dir then break now since xattrs_put() will do
* the iterating of the directory.
*
- * At the moment, there can't be attributes on attributes
- * or directories within the attributes hidden directory
- * hierarchy.
+ * At the moment, there can only be system attributes on
+ * attributes. There can be no attributes on attributes or
+ * directories within the attributes hidden directory hierarchy.
*/
if (filetype == XATTR_FILE)
break;
@@ -1854,7 +2024,7 @@ putfile(char *longname, char *shortname, char *parent,
if ((dirp = opendir(".")) == NULL) {
vperror(0, gettext(
- "can't open directory %s"), longname);
+ "can't open directory %s"), longname);
if (chdir(parent) < 0)
vperror(0, gettext("cannot change back?: %s"),
parent);
@@ -1873,12 +2043,13 @@ putfile(char *longname, char *shortname, char *parent,
} else
l = -1;
- archtype = putfile(buf, cp, newparent,
+ archtype = putfile(buf, cp, newparent, NULL,
NORMAL_FILE, lev + 1, symlink_lev);
if (!exitflag) {
- if (atflag && archtype == PUT_NOTAS_LINK) {
- xattrs_put(buf, cp, newparent);
+ if ((atflag || saflag) &&
+ (archtype == PUT_NOTAS_LINK)) {
+ xattrs_put(buf, cp, newparent, NULL);
}
}
if (exitflag)
@@ -1962,17 +2133,18 @@ putfile(char *longname, char *shortname, char *parent,
break;
case S_IFREG:
if ((infile = openat(dirfd, shortname, 0)) < 0) {
- vperror(0, "%s%s%s", longname,
+ vperror(0, "unable to open %s%s%s%s", longname,
+ rw_sysattr ? gettext(" system") : "",
(filetype == XATTR_FILE) ?
gettext(" attribute ") : "",
- (filetype == XATTR_FILE) ?
- shortname : "");
+ (filetype == XATTR_FILE) ? (longattrname == NULL) ?
+ shortname : longattrname : "");
goto out;
}
blocks = TBLOCKS(stbuf.st_size);
- if (put_link(name, longname, shortname,
+ if (put_link(name, longname, shortname, longattrname,
prefix, filetype, '1') == 0) {
(void) close(infile);
rc = PUT_AS_LINK;
@@ -2018,11 +2190,12 @@ putfile(char *longname, char *shortname, char *parent,
DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
0);
#endif
- (void) fprintf(vfile, "a %s%s%s ", longname,
- (filetype == XATTR_FILE) ?
- gettext(" attribute ") : "",
+ (void) fprintf(vfile, "a %s%s%s%s ", longname,
+ rw_sysattr ? gettext(" system") : "",
+ (filetype == XATTR_FILE) ? gettext(
+ " attribute ") : "",
(filetype == XATTR_FILE) ?
- shortname : "");
+ longattrname : "");
if (NotTape)
(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
K(blocks));
@@ -2032,8 +2205,8 @@ putfile(char *longname, char *shortname, char *parent,
blocks);
}
- if (put_extra_attributes(longname, shortname, prefix,
- filetype, '0') != 0)
+ if (put_extra_attributes(longname, shortname, longattrname,
+ prefix, filetype, '0') != 0)
goto out;
/*
@@ -2082,7 +2255,7 @@ putfile(char *longname, char *shortname, char *parent,
blocks = TBLOCKS(stbuf.st_size);
stbuf.st_size = (off_t)0;
- if (put_link(name, longname, shortname,
+ if (put_link(name, longname, shortname, longattrname,
prefix, filetype, '6') == 0) {
rc = PUT_AS_LINK;
goto out;
@@ -2132,8 +2305,8 @@ putfile(char *longname, char *shortname, char *parent,
&stbuf, stbuf.st_dev, prefix) != 0)
goto out;
- if (put_extra_attributes(longname, shortname, prefix,
- filetype, '6') != 0)
+ if (put_extra_attributes(longname, shortname, longattrname,
+ prefix, filetype, '6') != 0)
goto out;
(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
@@ -2144,8 +2317,8 @@ putfile(char *longname, char *shortname, char *parent,
case S_IFCHR:
stbuf.st_size = (off_t)0;
blocks = TBLOCKS(stbuf.st_size);
- if (put_link(name, longname,
- shortname, prefix, filetype, '3') == 0) {
+ if (put_link(name, longname, shortname, longattrname,
+ prefix, filetype, '3') == 0) {
rc = PUT_AS_LINK;
goto out;
}
@@ -2193,7 +2366,7 @@ putfile(char *longname, char *shortname, char *parent,
filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
goto out;
- if (put_extra_attributes(longname, shortname,
+ if (put_extra_attributes(longname, shortname, longattrname,
prefix, filetype, '3') != 0)
goto out;
@@ -2205,8 +2378,8 @@ putfile(char *longname, char *shortname, char *parent,
case S_IFBLK:
stbuf.st_size = (off_t)0;
blocks = TBLOCKS(stbuf.st_size);
- if (put_link(name, longname,
- shortname, prefix, filetype, '4') == 0) {
+ if (put_link(name, longname, shortname, longattrname,
+ prefix, filetype, '4') == 0) {
rc = PUT_AS_LINK;
goto out;
}
@@ -2254,7 +2427,7 @@ putfile(char *longname, char *shortname, char *parent,
filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
goto out;
- if (put_extra_attributes(longname, shortname,
+ if (put_extra_attributes(longname, shortname, longattrname,
prefix, filetype, '4') != 0)
goto out;
@@ -2273,9 +2446,7 @@ putfile(char *longname, char *shortname, char *parent,
}
out:
- if (dirfd != -1) {
- if (filetype == XATTR_FILE)
- (void) chdir(parent);
+ if ((dirfd != -1) && (filetype != XATTR_FILE)) {
(void) close(dirfd);
}
return (rc);
@@ -2417,6 +2588,210 @@ convtoreg(off_t size)
return (0);
}
+#if defined(O_XATTR)
+static int
+save_cwd(void)
+{
+ return (open(".", O_RDONLY));
+}
+#endif
+
+#if defined(O_XATTR)
+static void
+rest_cwd(int *cwd)
+{
+ if (*cwd != -1) {
+ if (fchdir(*cwd) < 0) {
+ vperror(0, gettext(
+ "Cannot fchdir to attribute directory"));
+ exit(1);
+ }
+ (void) close(*cwd);
+ *cwd = -1;
+ }
+}
+#endif
+
+/*
+ * Verify the underlying file system supports the attribute type.
+ * Only archive extended attribute files when '-@' was specified.
+ * Only archive system extended attribute files if '-/' was specified.
+ */
+#if defined(O_XATTR)
+static attr_status_t
+verify_attr_support(char *filename, arc_action_t actflag)
+{
+ /*
+ */
+ if (atflag) {
+ /* Verify extended attributes are supported */
+ if (pathconf(filename, (actflag == ARC_CREATE) ?
+ _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) != 1) {
+#if defined(_PC_SATTR_ENABLED)
+ if (saflag) {
+ /* Verify system attributes are supported */
+ if (sysattr_support(filename,
+ (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
+ _PC_SATTR_ENABLED) != 1) {
+ return (ATTR_SATTR_ERR);
+ }
+ } else
+ return (ATTR_XATTR_ERR);
+#else
+ return (ATTR_XATTR_ERR);
+#endif /* _PC_SATTR_ENABLED */
+ }
+
+#if defined(_PC_SATTR_ENABLED)
+ } else if (saflag) {
+ /* Verify system attributes are supported */
+ if (sysattr_support(filename, (actflag == ARC_CREATE) ?
+ _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
+ return (ATTR_SATTR_ERR);
+ }
+#endif /* _PC_SATTR_ENABLED */
+ } else {
+ return (ATTR_SKIP);
+ }
+
+ return (ATTR_OK);
+}
+#endif
+
+#if defined(O_XATTR)
+/*
+ * Recursively open attribute directories until the attribute directory
+ * containing the specified attribute, attrname, is opened.
+ *
+ * Currently, only 2 directory levels of attributes are supported, (i.e.,
+ * extended system attributes on extended attributes). The following are
+ * the possible input combinations:
+ * 1. Open the attribute directory of the base file (don't change
+ * into it).
+ * attrinfo->parent = NULL
+ * attrname = '.'
+ * 2. Open the attribute directory of the base file and change into it.
+ * attrinfo->parent = NULL
+ * attrname = <attr> | <sys_attr>
+ * 3. Open the attribute directory of the base file, change into it,
+ * then recursively call open_attr_dir() to open the attribute's
+ * parent directory (don't change into it).
+ * attrinfo->parent = <attr>
+ * attrname = '.'
+ * 4. Open the attribute directory of the base file, change into it,
+ * then recursively call open_attr_dir() to open the attribute's
+ * parent directory and change into it.
+ * attrinfo->parent = <attr>
+ * attrname = <attr> | <sys_attr>
+ *
+ * An attribute directory will be opened only if the underlying file system
+ * supports the attribute type, and if the command line specifications (atflag
+ * and saflag) enable the processing of the attribute type.
+ *
+ * On succesful return, attrinfo->parentfd will be the file descriptor of the
+ * opened attribute directory. In addition, if the attribute is a read-write
+ * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
+ * it will be set to 0.
+ *
+ * Possible return values:
+ * ATTR_OK Successfully opened and, if needed, changed into the
+ * attribute directory containing attrname.
+ * ATTR_SKIP The command line specifications don't enable the
+ * processing of the attribute type.
+ * ATTR_CHDIR_ERR An error occurred while trying to change into an
+ * attribute directory.
+ * ATTR_OPEN_ERR An error occurred while trying to open an
+ * attribute directory.
+ * ATTR_XATTR_ERR The underlying file system doesn't support extended
+ * attributes.
+ * ATTR_SATTR_ERR The underlying file system doesn't support extended
+ * system attributes.
+ */
+static int
+open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
+{
+ attr_status_t rc;
+ int firsttime = (attrinfo->attr_parentfd == -1);
+ int saveerrno;
+
+ /*
+ * open_attr_dir() was recursively called (input combination number 4),
+ * close the previously opened file descriptor as we've already changed
+ * into it.
+ */
+ if (!firsttime) {
+ (void) close(attrinfo->attr_parentfd);
+ attrinfo->attr_parentfd = -1;
+ }
+
+ /*
+ * Verify that the underlying file system supports the restoration
+ * of the attribute.
+ */
+ if ((rc = verify_attr_support(dirp, ARC_RESTORE)) != ATTR_OK) {
+ return (rc);
+ }
+
+ /* Open the base file's attribute directory */
+ if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
+ /*
+ * Save the errno from the attropen so it can be reported
+ * if the retry of the attropen fails.
+ */
+ saveerrno = errno;
+ if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
+ NULL, ".", O_RDONLY, 0)) == -1) {
+ /*
+ * Reset typeflag back to real value so passtape
+ * will skip ahead correctly.
+ */
+ dblock.dbuf.typeflag = _XATTR_HDRTYPE;
+ (void) close(attrinfo->attr_parentfd);
+ attrinfo->attr_parentfd = -1;
+ errno = saveerrno;
+ return (ATTR_OPEN_ERR);
+ }
+ }
+
+ /*
+ * Change into the parent attribute's directory unless we are
+ * processing the hidden attribute directory of the base file itself.
+ */
+ if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
+ if (fchdir(attrinfo->attr_parentfd) != 0) {
+ saveerrno = errno;
+ (void) close(attrinfo->attr_parentfd);
+ attrinfo->attr_parentfd = -1;
+ errno = saveerrno;
+ return (ATTR_CHDIR_ERR);
+ }
+ }
+
+ /* Determine if the attribute should be processed */
+ if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
+ &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
+ saveerrno = errno;
+ (void) close(attrinfo->attr_parentfd);
+ attrinfo->attr_parentfd = -1;
+ errno = saveerrno;
+ return (rc);
+ }
+
+ /*
+ * If the attribute is an extended attribute, or extended system
+ * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
+ * recursively call open_attr_dir() to open the attribute directory
+ * of the parent attribute.
+ */
+ if (firsttime && (attrinfo->attr_parent != NULL)) {
+ return (open_attr_dir(attrname, attrinfo->attr_parent,
+ attrinfo->attr_parentfd, attrinfo));
+ }
+
+ return (ATTR_OK);
+}
+#endif
+
static void
#ifdef _iBCS2
doxtract(char *argv[], int tbl_cnt)
@@ -2433,15 +2808,18 @@ doxtract(char *argv[])
int fcnt = 0; /* count # files in argv list */
int dir;
int dirfd = -1;
+ int cwd = -1;
+ int rw_sysattr = 0;
+ int saveerrno;
uid_t Uid;
char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
char dirname[PATH_MAX+1];
char templink[PATH_MAX+1]; /* temp link with terminating NULL */
- char origdir[PATH_MAX+1];
int once = 1;
int error;
int symflag;
int want;
+ attr_data_t *attrinfo = NULL; /* attribute info */
acl_t *aclp = NULL; /* acl info */
char dot[] = "."; /* dirp for using realpath */
timestruc_t time_zero; /* used for call to doDirTimes */
@@ -2480,10 +2858,26 @@ doxtract(char *argv[])
dir = 0;
ofile = -1;
+ if (dirfd != -1) {
+ (void) close(dirfd);
+ dirfd = -1;
+ }
+ if (ofile != -1) {
+ if (close(ofile) != 0)
+ vperror(2, gettext("close error"));
+ }
+
+#if defined(O_XATTR)
+ if (cwd != -1) {
+ rest_cwd(&cwd);
+ }
+#endif
+
/* namep is set by wantit to point to the full name */
- if ((want = wantit(argv, &namep, &dirp, &comp)) == 0) {
+ if ((want = wantit(argv, &namep, &dirp, &comp,
+ &attrinfo)) == 0) {
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
free(xattrhead);
xattrp = NULL;
xattr_linkp = NULL;
@@ -2522,51 +2916,49 @@ doxtract(char *argv[])
dircreate = checkdir(&dirname[0]);
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
- dirfd = attropen(dirp, ".", O_RDONLY);
- } else {
- dirfd = open(dirp, O_RDONLY);
- }
-#else
- dirfd = open(dirp, O_RDONLY);
-#endif
+ if (xattrp != NULL) {
+ int rc;
- if (dirfd == -1) {
-#if defined(O_XATTR)
- if (xattrp) {
- dirfd = retry_attrdir_open(dirp);
- }
-#endif
- if (dirfd == -1) {
-#if defined(O_XATTR)
- if (xattrp) {
+ if (((cwd = save_cwd()) == -1) ||
+ ((rc = open_attr_dir(comp, dirp, cwd,
+ attrinfo)) != ATTR_OK)) {
+ if (cwd == -1) {
+ vperror(0, gettext(
+ "unable to save current working "
+ "directory while processing "
+ "attribute %s of %s"),
+ dirp, attrinfo->attr_path);
+ } else if (rc != ATTR_SKIP) {
(void) fprintf(vfile,
gettext("tar: cannot open "
- "attribute %s of file %s: %s\n"),
- xattraname, dirp, strerror(errno));
- /*
- * Reset typeflag back to real
- * value so passtape will skip
- * ahead correctly.
- */
- dblock.dbuf.typeflag = _XATTR_HDRTYPE;
- free(xattrhead);
- xattrp = NULL;
- xattr_linkp = NULL;
- xattrhead = NULL;
- } else {
- (void) fprintf(vfile,
- gettext("tar: cannot open %s %s\n"),
- dirp, strerror(errno));
+ "%sattribute %s of file %s: %s\n"),
+ attrinfo->attr_rw_sysattr ? gettext(
+ "system ") : "",
+ comp, dirp, strerror(errno));
}
-#else
- (void) fprintf(vfile,
- gettext("tar: cannot open %s %s\n"),
- dirp, strerror(errno));
-#endif
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+
passtape();
continue;
+ } else {
+ dirfd = attrinfo->attr_parentfd;
+ rw_sysattr = attrinfo->attr_rw_sysattr;
}
+ } else {
+ dirfd = open(dirp, O_RDONLY);
+ }
+#else
+ dirfd = open(dirp, O_RDONLY);
+#endif
+ if (dirfd == -1) {
+ (void) fprintf(vfile, gettext(
+ "tar: cannot open %s: %s\n"),
+ dirp, strerror(errno));
+ passtape();
+ continue;
}
if (xhdr_flgs & _X_LINKPATH)
@@ -2635,18 +3027,51 @@ doxtract(char *argv[])
* Dir is automatically created, we only
* need to update mode and perm's.
*/
- if ((xattrp != (struct xattr_buf *)NULL) && Hiddendir == 1) {
- if (fchownat(dirfd, ".", stbuf.st_uid,
- stbuf.st_gid, 0) != 0) {
- vperror(0, gettext(
- "%s: failed to set ownership of attribute"
- " directory"), namep);
+ if ((xattrp != NULL) && Hiddendir == 1) {
+ bytes = stbuf.st_size;
+ blocks = TBLOCKS(bytes);
+ if (vflag) {
+ (void) fprintf(vfile,
+ "x %s%s%s, %" FMT_off_t " bytes, ", namep,
+ gettext(" attribute "),
+ xattrapath, bytes);
+ if (NotTape)
+ (void) fprintf(vfile,
+ "%" FMT_blkcnt_t "K\n", K(blocks));
+ else
+ (void) fprintf(vfile, gettext("%"
+ FMT_blkcnt_t " tape blocks\n"),
+ blocks);
}
- if (fchmod(dirfd, stbuf.st_mode) != 0) {
- vperror(0, gettext(
- "%s: failed to set permissions of"
- " attribute directory"), namep);
+ /*
+ * Set the permissions and mode of the attribute
+ * unless the attribute is a system attribute (can't
+ * successfully do this) or the hidden attribute
+ * directory (".") of an attribute (when the attribute
+ * is restored, the hidden attribute directory of an
+ * attribute is transient). Note: when the permissions
+ * and mode are set for the hidden attribute directory
+ * of a file on a system supporting extended system
+ * attributes, even though it returns successfully, it
+ * will not have any affect since the attribute
+ * directory is transient.
+ */
+ if (attrinfo->attr_parent == NULL) {
+ if (fchownat(dirfd, ".", stbuf.st_uid,
+ stbuf.st_gid, 0) != 0) {
+ vperror(0, gettext(
+ "%s%s%s: failed to set ownership "
+ "of attribute directory"), namep,
+ gettext(" attribute "), xattrapath);
+ }
+
+ if (fchmod(dirfd, stbuf.st_mode) != 0) {
+ vperror(0, gettext(
+ "%s%s%s: failed to set permissions "
+ "of attribute directory"), namep,
+ gettext(" attribute "), xattrapath);
+ }
}
goto filedone;
}
@@ -2683,7 +3108,8 @@ doxtract(char *argv[])
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s linked to %s\n"), namep, linkp);
+ "x %s linked to %s\n"), namep,
+ linkp);
xcnt++; /* increment # files extracted */
continue;
}
@@ -2723,14 +3149,15 @@ doxtract(char *argv[])
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s linked to %s\n"), namep, linkp);
+ "x %s linked to %s\n"), namep,
+ linkp);
xcnt++; /* increment # files extracted */
continue;
}
if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
(int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
vperror(0, gettext(
- "%s: mknod failed"), namep);
+ "%s: mknod failed"), namep);
continue;
}
bytes = stbuf.st_size;
@@ -2771,7 +3198,8 @@ doxtract(char *argv[])
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s linked to %s\n"), namep, linkp);
+ "x %s linked to %s\n"), namep,
+ linkp);
xcnt++; /* increment # files extracted */
continue;
}
@@ -2833,28 +3261,16 @@ doxtract(char *argv[])
}
#if defined(O_XATTR)
if (xattrp && xattr_linkp) {
- if (getcwd(origdir, (PATH_MAX+1)) ==
- (char *)NULL) {
- vperror(0, gettext(
- "A parent directory cannot"
- " be read"));
- exit(1);
- }
-
if (fchdir(dirfd) < 0) {
vperror(0, gettext(
"Cannot fchdir to attribute "
- "directory"));
+ "directory %s"),
+ (attrinfo->attr_parent == NULL) ?
+ dirp : attrinfo->attr_parent);
exit(1);
}
- error = link(xattr_linkaname, xattraname);
- if (chdir(origdir) < 0) {
- vperror(0, gettext(
- "Cannot chdir out of attribute "
- "directory"));
- exit(1);
- }
+ error = link(xattr_linkaname, xattrapath);
} else {
error = link(linkp, namep);
}
@@ -2868,23 +3284,23 @@ doxtract(char *argv[])
namep, (xattr_linkp != NULL) ?
gettext(" attribute ") : "",
(xattr_linkp != NULL) ?
- xattraname : "");
+ xattrapath : "");
continue;
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s%s%s linked to %s%s%s\n"), namep,
+ "x %s%s%s linked to %s%s%s\n"), namep,
(xattr_linkp != NULL) ?
gettext(" attribute ") : "",
(xattr_linkp != NULL) ?
xattr_linkaname : "",
- linkp, (xattr_linkp != NULL) ?
- gettext(" attribute ") : "",
+ linkp,
(xattr_linkp != NULL) ?
- xattraname : "");
+ gettext(" attribute ") : "",
+ (xattr_linkp != NULL) ? xattrapath : "");
xcnt++; /* increment # files extracted */
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
free(xattrhead);
xattrp = NULL;
xattr_linkp = NULL;
@@ -2925,20 +3341,58 @@ doxtract(char *argv[])
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s linked to %s\n"), comp, linkp);
+ "x %s linked to %s\n"), comp,
+ linkp);
xcnt++; /* increment # files extracted */
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+ }
+#endif
continue;
}
newfile = ((fstatat(dirfd, comp,
&xtractbuf, 0) == -1) ? TRUE : FALSE);
- if ((ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
- stbuf.st_mode & MODEMASK)) < 0) {
+ ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
+ stbuf.st_mode & MODEMASK);
+ saveerrno = errno;
+
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ if (ofile < 0) {
+ ofile = retry_open_attr(dirfd, cwd,
+ dirp, attrinfo->attr_parent, comp,
+ O_RDWR|O_CREAT|O_TRUNC,
+ stbuf.st_mode & MODEMASK);
+ }
+ }
+#endif
+ if (ofile < 0) {
+ errno = saveerrno;
(void) fprintf(stderr, gettext(
- "tar: %s - cannot create\n"), comp);
+ "tar: %s%s%s%s - cannot create\n"),
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext("system attribure ") :
+ gettext("attribute ")),
+ (xattrp == NULL) ? "" : xattrapath,
+ (xattrp == NULL) ? "" : gettext(" of "),
+ (xattrp == NULL) ? comp : namep);
if (errflag)
done(1);
else
Errflg = 1;
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ dblock.dbuf.typeflag = _XATTR_HDRTYPE;
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+ }
+#endif
passtape();
continue;
}
@@ -2955,11 +3409,17 @@ doxtract(char *argv[])
if (extno != 0) { /* file is in pieces */
if (extotal < 1 || extotal > MAXEXT)
(void) fprintf(stderr, gettext(
- "tar: ignoring bad extent info for %s\n"),
- comp);
+ "tar: ignoring bad extent info for "
+ "%s%s%s%s\n"),
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext("system attribute ") :
+ gettext("attribute ")),
+ (xattrp == NULL) ? "" : xattrapath,
+ (xattrp == NULL) ? "" : gettext(" of "),
+ (xattrp == NULL) ? comp : namep);
else {
- xsfile(ofile); /* extract it */
- goto filedone;
+ /* extract it */
+ (void) xsfile(rw_sysattr, ofile);
}
}
extno = 0; /* let everyone know file is not split */
@@ -2969,8 +3429,10 @@ doxtract(char *argv[])
(void) fprintf(vfile,
"x %s%s%s, %" FMT_off_t " bytes, ",
(xattrp == NULL) ? "" : dirp,
- (xattrp == NULL) ? "" : gettext(" attribute "),
- (xattrp == NULL) ? namep : comp, bytes);
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext(" system attribute ") :
+ gettext(" attribute ")),
+ (xattrp == NULL) ? namep : xattrapath, bytes);
if (NotTape)
(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
K(blocks));
@@ -2979,18 +3441,50 @@ doxtract(char *argv[])
FMT_blkcnt_t " tape blocks\n"), blocks);
}
- xblocks(bytes, ofile);
+ if (xblocks(rw_sysattr, bytes, ofile) != 0) {
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+ }
+#endif
+ continue;
+ }
filedone:
if (mflag == 0 && !symflag) {
if (dir)
doDirTimes(namep, stbuf.st_mtim);
+
else
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ /*
+ * Set the time on the attribute unless
+ * the attribute is a system attribute
+ * (can't successfully do this) or the
+ * hidden attribute directory, "." (the
+ * time on the hidden attribute
+ * directory will be updated when
+ * attributes are restored, otherwise
+ * it's transient).
+ */
+ if (!rw_sysattr && (Hiddendir == 0)) {
+ setPathTimes(dirfd, comp,
+ stbuf.st_mtim);
+ }
+ } else
+ setPathTimes(dirfd, comp,
+ stbuf.st_mtim);
+#else
setPathTimes(dirfd, comp, stbuf.st_mtim);
+#endif
}
/* moved this code from above */
if (pflag && !symflag && Hiddendir == 0) {
- if (xattrp != (struct xattr_buf *)NULL)
+ if (xattrp != NULL)
(void) fchmod(ofile, stbuf.st_mode & MODEMASK);
else
(void) chmod(namep, stbuf.st_mode & MODEMASK);
@@ -3007,7 +3501,7 @@ filedone:
int ret;
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
if (Hiddendir)
ret = facl_set(dirfd, aclp);
else
@@ -3021,8 +3515,14 @@ filedone:
if (ret < 0) {
if (pflag) {
(void) fprintf(stderr, gettext(
- "%s: failed to set acl entries\n"),
- namep);
+ "%s%s%s%s: failed to set acl "
+ "entries\n"), namep,
+ (xattrp == NULL) ? "" :
+ (rw_sysattr ? gettext(
+ " system attribute ") :
+ gettext(" attribute ")),
+ (xattrp == NULL) ? "" :
+ xattrapath);
}
/* else: silent and continue */
}
@@ -3031,7 +3531,7 @@ filedone:
}
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
free(xattrhead);
xattrp = NULL;
xattr_linkp = NULL;
@@ -3048,15 +3548,29 @@ filedone:
convflag || dblock.dbuf.typeflag == '1')) {
if (fstat(ofile, &xtractbuf) == -1)
(void) fprintf(stderr, gettext(
- "tar: cannot stat extracted file %s\n"),
- namep);
+ "tar: cannot stat extracted file "
+ "%s%s%s%s\n"),
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext("system attribute ") :
+ gettext("attribute ")),
+ (xattrp == NULL) ? "" : xattrapath,
+ (xattrp == NULL) ? "" :
+ gettext(" of "), namep);
+
else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
!= (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
(void) fprintf(stderr, gettext(
"tar: warning - file permissions have "
- "changed for %s (are 0%o, should be "
+ "changed for %s%s%s%s (are 0%o, should be "
"0%o)\n"),
- namep, xtractbuf.st_mode, stbuf.st_mode);
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext("system attribute ") :
+ gettext("attribute ")),
+ (xattrp == NULL) ? "" : xattrapath,
+ (xattrp == NULL) ? "" :
+ gettext(" of "), namep,
+ xtractbuf.st_mode, stbuf.st_mode);
+
}
}
if (ofile != -1) {
@@ -3064,6 +3578,7 @@ filedone:
dirfd = -1;
if (close(ofile) != 0)
vperror(2, gettext("close error"));
+ ofile = -1;
}
xcnt++; /* increment # files extracted */
}
@@ -3188,8 +3703,9 @@ filedone:
tp += attrsize;
} while (bytes != 0);
free(secp);
- } else
+ } else {
passtape();
+ }
} /* acl */
} /* for */
@@ -3202,6 +3718,15 @@ filedone:
doDirTimes(NULL, time_zero);
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+ }
+#endif
+
/*
* Check if the number of files extracted is different from the
* number of files listed on the command line
@@ -3223,8 +3748,8 @@ filedone:
* called by doxtract() and xsfile()
*/
-static void
-xblocks(off_t bytes, int ofile)
+static int
+xblocks(int issysattr, off_t bytes, int ofile)
{
blkcnt_t blocks;
char buf[TBLOCK];
@@ -3239,17 +3764,36 @@ xblocks(off_t bytes, int ofile)
else
write_count = bytes;
if (write(ofile, buf, write_count) < 0) {
+ int saveerrno = errno;
+
if (xhdr_flgs & _X_PATH)
(void) strcpy(tempname, Xtarhdr.x_path);
else
(void) sprintf(tempname, "%.*s", NAMSIZ,
dblock.dbuf.name);
- (void) fprintf(stderr, gettext(
- "tar: %s: HELP - extract write error\n"), tempname);
- done(2);
+ /*
+ * If the extended system attribute being extracted
+ * contains attributes that the user needs privileges
+ * for, then just display a warning message, skip
+ * the extraction of this file, and return.
+ */
+ if ((saveerrno == EPERM) && issysattr) {
+ (void) fprintf(stderr, gettext(
+ "tar: unable to extract system attribute "
+ "%s: insufficient privileges\n"), tempname);
+ Errflg = 1;
+ return (1);
+ } else {
+ (void) fprintf(stderr, gettext(
+ "tar: %s: HELP - extract write error\n"),
+ tempname);
+ done(2);
+ }
}
bytes -= TBLOCK;
}
+
+ return (0);
}
@@ -3265,10 +3809,11 @@ xblocks(off_t bytes, int ofile)
static union hblock savedblock; /* to ensure same file across volumes */
-static void
-xsfile(int ofd)
+static int
+xsfile(int issysattr, int ofd)
{
int i, c;
+ int sysattrerr = 0;
char name[PATH_MAX+1]; /* holds name for diagnostics */
int extents, totalext;
off_t bytes, totalbytes;
@@ -3295,7 +3840,11 @@ canit:
passtape();
if (close(ofd) != 0)
vperror(2, gettext("close error"));
- return;
+ if (sysattrerr) {
+ return (1);
+ } else {
+ return (0);
+ }
}
}
extents = extotal;
@@ -3312,7 +3861,10 @@ canit:
(void) fprintf(vfile, "+++ x %s [extent #%d], %"
FMT_off_t " bytes, %ldK\n", name, extno, bytes,
(long)K(TBLOCKS(bytes)));
- xblocks(bytes, ofd);
+ if (xblocks(issysattr, bytes, ofd) != 0) {
+ sysattrerr = 1;
+ goto canit;
+ }
totalbytes += bytes;
totalext++;
@@ -3361,6 +3913,8 @@ asknicely:
(void) fprintf(vfile, gettext(
"x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
+
+ return (0);
}
@@ -3394,7 +3948,6 @@ notsame(void)
(strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
}
-
static void
#ifdef _iBCS2
dotable(char *argv[], int tbl_cnt)
@@ -3409,7 +3962,7 @@ dotable(char *argv[])
int want;
char aclchar = ' '; /* either blank or '+' */
char templink[PATH_MAX+1];
- char *np;
+ attr_data_t *attrinfo = NULL;
dumping = 0;
@@ -3436,7 +3989,7 @@ dotable(char *argv[])
for (;;) {
/* namep is set by wantit to point to the full name */
- if ((want = wantit(argv, &namep, &dirp, &comp)) == 0)
+ if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
continue;
if (want == -1)
break;
@@ -3460,11 +4013,27 @@ dotable(char *argv[])
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
- np = xattrp->h_names + strlen(xattrp->h_names) + 1;
- (void) printf(gettext("%s attribute %s"),
- xattrp->h_names, np);
+ if (xattrp != NULL) {
+ int issysattr;
+ char *bn = basename(attrinfo->attr_path);
+
+ /*
+ * We could use sysattr_type() to test whether or not
+ * the attribute we are processing is really an
+ * extended system attribute, which as of this writing
+ * just does a strcmp(), however, sysattr_type() may
+ * be changed to issue a pathconf() call instead, which
+ * would require being changed into the parent attribute
+ * directory. So instead, just do simple string
+ * comparisons to see if we are processing an extended
+ * system attribute.
+ */
+ issysattr = is_sysattr(bn);
+ (void) printf(gettext("%s %sattribute %s"),
+ xattrp->h_names,
+ issysattr ? gettext("system ") : "",
+ attrinfo->attr_path);
} else {
(void) printf("%s", namep);
}
@@ -3486,7 +4055,7 @@ dotable(char *argv[])
(void) strcpy(templink, Xtarhdr.x_linkpath);
} else {
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
(void) sprintf(templink,
"file %.*s", NAMSIZ, xattrp->h_names);
} else {
@@ -3507,7 +4076,7 @@ dotable(char *argv[])
* <subject> linked to %s
*/
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
(void) printf(
gettext(" linked to attribute %s"),
xattr_linkp->h_names +
@@ -3533,7 +4102,7 @@ dotable(char *argv[])
" symbolic link to %s"), templink);
(void) printf("\n");
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
free(xattrhead);
xattrp = NULL;
xattrhead = NULL;
@@ -5027,7 +5596,8 @@ mterr(char *operation, int i, int exitcode)
}
static int
-wantit(char *argv[], char **namep, char **dirp, char **component)
+wantit(char *argv[], char **namep, char **dirp, char **component,
+ attr_data_t **attrinfo)
{
char **cp;
int gotit; /* true if we've found a match */
@@ -5044,17 +5614,29 @@ top:
#if defined(O_XATTR)
if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
- if (atflag || tflag) {
- (void) read_xattr_hdr();
- } else {
- passtape();
- }
+ /*
+ * Always needs to read the extended header. If atflag, saflag,
+ * or tflag isn't set, then we'll have the correct info for
+ * passtape() later.
+ */
+ (void) read_xattr_hdr(attrinfo);
goto top;
}
+ /*
+ * Now that we've read the extended header, call passtape() if we aren't
+ * processing extended attributes.
+ */
+ if ((xattrp != NULL) && !atflag && !saflag && !tflag) {
+ passtape();
+ return (0);
+ }
#endif
/* sets *namep to point at the proper name */
- check_prefix(namep, dirp, component);
+ if (check_prefix(namep, dirp, component) != 0) {
+ passtape();
+ return (0);
+ }
if (endtape()) {
if (Bflag) {
@@ -5104,13 +5686,96 @@ top:
return (1);
}
+static int
+fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
+ int rw_sysattr, attr_data_t **attrinfo)
+{
+ size_t pathlen;
+ char *tpath;
+ char *tparent;
+
+ /* parent info */
+ if (attrparent != NULL) {
+ if ((tparent = strdup(attrparent)) == NULL) {
+ vperror(0, gettext(
+ "unable to allocate memory for attribute parent "
+ "name for %sattribute %s/%s of %s"),
+ rw_sysattr ? gettext("system ") : "",
+ attrparent, attr, longname);
+ return (1);
+ }
+ } else {
+ tparent = NULL;
+ }
+
+ /* path info */
+ pathlen = strlen(attr) + 1;
+ if (attrparent != NULL) {
+ pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
+ }
+ if ((tpath = calloc(1, pathlen)) == NULL) {
+ vperror(0, gettext(
+ "unable to allocate memory for full "
+ "attribute path name for %sattribute %s%s%s of %s"),
+ rw_sysattr ? gettext("system ") : "",
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : "/",
+ attr, longname);
+ if (tparent != NULL) {
+ free(tparent);
+ }
+ return (1);
+ }
+ (void) snprintf(tpath, pathlen, "%s%s%s",
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : "/",
+ attr);
+
+ /* fill in the attribute info */
+ if (*attrinfo == NULL) {
+ if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
+ vperror(0, gettext(
+ "unable to allocate memory for attribute "
+ "information for %sattribute %s%s%s of %s"),
+ rw_sysattr ? gettext("system ") : "",
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext("/"),
+ attr, longname);
+ if (tparent != NULL) {
+ free(tparent);
+ }
+ free(tpath);
+ return (1);
+ }
+ } else {
+ if ((*attrinfo)->attr_parent != NULL) {
+ free((*attrinfo)->attr_parent);
+ }
+ if ((*attrinfo)->attr_path != NULL) {
+ free((*attrinfo)->attr_path);
+ }
+ /*
+ * The parent file descriptor is passed in, so don't
+ * close it here as it should be closed by the function
+ * that opened it.
+ */
+ }
+ (*attrinfo)->attr_parent = tparent;
+ (*attrinfo)->attr_path = tpath;
+ (*attrinfo)->attr_rw_sysattr = rw_sysattr;
+ (*attrinfo)->attr_parentfd = atparentfd;
+
+ return (0);
+}
/*
* Return through *namep a pointer to the proper fullname (i.e "<name> |
* <prefix>/<name>"), as represented in the header entry dblock.dbuf.
+ *
+ * Returns 0 if successful, otherwise returns 1.
*/
-static void
+static int
check_prefix(char **namep, char **dirp, char **compp)
{
static char fullname[PATH_MAX + 1];
@@ -5140,7 +5805,7 @@ check_prefix(char **namep, char **dirp, char **compp)
get_parent(fullname, dir);
#if defined(O_XATTR)
- if (xattrp == (struct xattr_buf *)NULL) {
+ if (xattrp == NULL) {
#endif
/*
* Save of real name since were going to chop off the
@@ -5158,13 +5823,15 @@ check_prefix(char **namep, char **dirp, char **compp)
} else {
(void) strcpy(fullname, xattrp->h_names);
(void) strcpy(dir, fullname);
- (void) strcpy(component, xattrp->h_names +
- strlen(xattrp->h_names) + 1);
+ (void) strcpy(component, basename(xattrp->h_names +
+ strlen(xattrp->h_names) + 1));
}
#endif
*namep = fullname;
*dirp = dir;
*compp = component;
+
+ return (0);
}
/*
@@ -6540,12 +7207,13 @@ static void
prepare_xattr(
char **attrbuf,
char *filename,
- char *attrname,
+ char *attrpath,
char typeflag,
struct linkbuf *linkinfo,
int *rlen)
{
char *bufhead; /* ptr to full buffer */
+ char *aptr;
struct xattr_hdr *hptr; /* ptr to header in bufhead */
struct xattr_buf *tptr; /* ptr to pathing pieces */
int totalen; /* total buffer length */
@@ -6558,6 +7226,7 @@ prepare_xattr(
int linkstringlen;
int complen; /* length of pathing section */
int linklen; /* length of link section */
+ int attrnames_index; /* attrnames starting index */
/*
* Release previous buffer
@@ -6576,7 +7245,7 @@ prepare_xattr(
/*
* Add space for two nulls
*/
- stringlen = strlen(attrname) + strlen(filename) + 2;
+ stringlen = strlen(attrpath) + strlen(filename) + 2;
complen = stringlen + sizeof (struct xattr_buf);
len += stringlen;
@@ -6591,7 +7260,10 @@ prepare_xattr(
*/
linkstringlen = strlen(linkinfo->pathname) +
strlen(linkinfo->attrname) + 2;
- len += linkstringlen;
+ linklen = linkstringlen + sizeof (struct xattr_buf);
+ len += linklen;
+ } else {
+ linklen = 0;
}
/*
@@ -6611,12 +7283,6 @@ prepare_xattr(
* Now we can fill in the necessary pieces
*/
- if (linkinfo != (struct linkbuf *)NULL) {
- linklen = linkstringlen + (sizeof (struct xattr_buf));
- } else {
- linklen = 0;
- }
-
/*
* first fill in the fixed header
*/
@@ -6630,16 +7296,39 @@ prepare_xattr(
/*
* Now fill in the filename + attrnames section
+ * The filename and attrnames section can be composed of two or more
+ * path segments separated by a null character. The first segment
+ * is the path to the parent file that roots the entire sequence in
+ * the normal name space. The remaining segments describes a path
+ * rooted at the hidden extended attribute directory of the leaf file of
+ * the previous segment, making it possible to name attributes on
+ * attributes. Thus, if we are just archiving an extended attribute,
+ * the second segment will contain the attribute name. If we are
+ * archiving a system attribute of an extended attribute, then the
+ * second segment will contain the attribute name, and a third segment
+ * will contain the system attribute name. The attribute pathing
+ * information is obtained from 'attrpath'.
*/
tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
(void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
stringlen);
(void) strcpy(tptr->h_names, filename);
- (void) strcpy(&tptr->h_names[strlen(filename) + 1], attrname);
+ attrnames_index = strlen(filename) + 1;
+ (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
tptr->h_typeflag = typeflag;
/*
+ * Split the attrnames section into two segments if 'attrpath'
+ * contains pathing information for a system attribute of an
+ * extended attribute. We split them by replacing the '/' with
+ * a '\0'.
+ */
+ if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
+ *aptr = '\0';
+ }
+
+ /*
* Now fill in the optional link section if we have one
*/
@@ -6675,7 +7364,7 @@ prepare_xattr(
#endif
int
-getstat(int dirfd, char *longname, char *shortname)
+getstat(int dirfd, char *longname, char *shortname, char *attrparent)
{
int i, j;
@@ -6722,7 +7411,11 @@ getstat(int dirfd, char *longname, char *shortname)
if (printerr) {
(void) fprintf(stderr, gettext(
- "tar: %s: %s\n"), longname, strerror(errno));
+ "tar: %s%s%s%s: %s\n"),
+ (attrparent == NULL) ? "" : gettext("attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
+ longname, strerror(errno));
Errflg = 1;
}
return (1);
@@ -6730,60 +7423,208 @@ getstat(int dirfd, char *longname, char *shortname)
return (0);
}
+/*
+ * Recursively archive the extended attributes and/or extended system attributes
+ * of the base file, longname. Note: extended system attribute files will be
+ * archived only if the extended system attributes are not transient (i.e. the
+ * extended system attributes are other than the default values).
+ *
+ * If -@ was specified and the underlying file system supports it, archive the
+ * extended attributes, and if there is a system attribute associated with the
+ * extended attribute, then recursively call xattrs_put() to archive the
+ * hidden attribute directory and the extended system attribute. If -/ was
+ * specified and the underlying file system supports it, archive the extended
+ * system attributes. Read-only extended system attributes are never archived.
+ *
+ * Currently, there cannot be attributes on attributes; only system
+ * attributes on attributes. In addition, there cannot be attributes on
+ * system attributes. A file and it's attribute directory hierarchy looks as
+ * follows:
+ * longname ----> . ("." is the hidden attribute directory)
+ * |
+ * ----------------------------
+ * | |
+ * <sys_attr_name> <attr_name> ----> .
+ * |
+ * <sys_attr_name>
+ *
+ */
#if defined(O_XATTR)
static void
-xattrs_put(char *longname, char *shortname, char *parent)
+xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
{
+ char *filename = (attrparent == NULL) ? shortname : attrparent;
+ int arc_rwsysattr = 0;
int dirfd;
+ int fd = -1;
+ int rw_sysattr = 0;
+ int rc;
DIR *dirp;
struct dirent *dp;
+ attr_data_t *attrinfo = NULL;
- if (pathconf(shortname, _PC_XATTR_EXISTS) != 1) {
+ /*
+ * If the underlying file system supports it, then archive the extended
+ * attributes if -@ was specified, and the extended system attributes
+ * if -/ was specified.
+ */
+ if (verify_attr_support(filename, ARC_CREATE) != ATTR_OK) {
return;
}
- if ((dirfd = attropen(shortname, ".", O_RDONLY)) < 0) {
- (void) fprintf(stderr, gettext(
- "tar: unable to open attribute directory for file %s\n"),
+ /*
+ * Only want to archive a read-write extended system attribute file
+ * if it contains extended system attribute settings that are not the
+ * default values.
+ */
+#if defined(_PC_SATTR_ENABLED)
+ if (saflag) {
+ int filefd;
+ nvlist_t *slist = NULL;
+
+ /* Determine if there are non-transient system attributes */
+ errno = 0;
+ if ((filefd = open(filename, O_RDONLY)) == -1) {
+ if (attrparent == NULL) {
+ vperror(0, gettext(
+ "unable to open file %s"), longname);
+ }
+ return;
+ }
+ if (((slist = sysattr_list(basename(myname), filefd,
+ filename)) != NULL) || (errno != 0)) {
+ arc_rwsysattr = 1;
+ }
+ if (slist != NULL) {
+ (void) nvlist_free(slist);
+ slist = NULL;
+ }
+ (void) close(filefd);
+ }
+#endif /* _PC_SATTR_ENABLED */
+
+ /* open the parent attribute directory */
+ fd = attropen(filename, ".", O_RDONLY);
+ if (fd < 0) {
+ vperror(0, gettext(
+ "unable to open attribute directory for %s%s%sfile %s"),
+ (attrparent == NULL) ? "" : gettext("attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
longname);
return;
}
- if ((dirp = fdopendir(dirfd)) == NULL) {
+ /*
+ * We need to change into the parent's attribute directory to determine
+ * if each of the attributes should be archived.
+ */
+ if (fchdir(fd) < 0) {
+ vperror(0, gettext(
+ "cannot change to attribute directory of %s%s%sfile %s"),
+ (attrparent == NULL) ? "" : gettext("attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
+ longname);
+ (void) close(fd);
+ return;
+ }
+
+ if (((dirfd = dup(fd)) == -1) ||
+ ((dirp = fdopendir(dirfd)) == NULL)) {
(void) fprintf(stderr, gettext(
- "tar: unable to open dir pointer for file %s\n"), longname);
+ "tar: unable to open dir pointer for %s%s%sfile %s\n"),
+ (attrparent == NULL) ? "" : gettext("attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
+ longname);
+ if (fd > 0) {
+ (void) close(fd);
+ }
return;
}
while (dp = readdir(dirp)) {
- if (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
- dp->d_name[2] == '\0')
+ if (strcmp(dp->d_name, "..") == 0) {
continue;
-
- if (dp->d_name[0] == '.' && dp->d_name[1] == '\0')
+ } else if (strcmp(dp->d_name, ".") == 0) {
Hiddendir = 1;
- else
+ } else {
Hiddendir = 0;
+ }
+
+ /* Determine if this attribute should be archived */
+ if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
+ &rw_sysattr) != ATTR_OK) {
+ continue;
+ }
+
+ /* gather the attribute's information to pass to putfile() */
+ if ((fill_in_attr_info(dp->d_name, longname, attrparent,
+ fd, rw_sysattr, &attrinfo)) == 1) {
+ continue;
+ }
- (void) putfile(longname, dp->d_name, parent,
+ /* add the attribute to the archive */
+ rc = putfile(longname, dp->d_name, parent, attrinfo,
XATTR_FILE, LEV0, SYMLINK_LEV0);
- if (exitflag)
+ if (exitflag) {
break;
+ }
+
+#if defined(_PC_SATTR_ENABLED)
+ /*
+ * If both -/ and -@ were specified, then archive the
+ * attribute's extended system attributes and hidden directory
+ * by making a recursive call to xattrs_put().
+ */
+ if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
+ (Hiddendir == 0)) {
+
+ xattrs_put(longname, shortname, parent, dp->d_name);
+
+ /*
+ * Change back to the parent's attribute directory
+ * to process any further attributes.
+ */
+ if (fchdir(fd) < 0) {
+ vperror(0, gettext(
+ "cannot change back to attribute directory "
+ "of file %s"), longname);
+ break;
+ }
+ }
+#endif /* _PC_SATTR_ENABLED */
}
+ if (attrinfo != NULL) {
+ if (attrinfo->attr_parent != NULL) {
+ free(attrinfo->attr_parent);
+ }
+ free(attrinfo->attr_path);
+ free(attrinfo);
+ }
(void) closedir(dirp);
+ if (fd != -1) {
+ (void) close(fd);
+ }
+
+ /* Change back to the parent directory of the base file */
+ if (attrparent == NULL) {
+ (void) chdir(parent);
+ }
}
#else
static void
-xattrs_put(char *longname, char *shortname, char *parent)
+xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
{
}
#endif /* O_XATTR */
static int
-put_link(char *name, char *longname, char *component,
- char *prefix, int filetype, char type)
+put_link(char *name, char *longname, char *component, char *longattrname,
+ char *prefix, int filetype, char type)
{
if (stbuf.st_nlink > 1) {
@@ -6799,8 +7640,8 @@ put_link(char *name, char *longname, char *component,
if (found) {
#if defined(O_XATTR)
if (filetype == XATTR_FILE)
- if (put_xattr_hdr(longname, component, prefix,
- type, filetype, lp)) {
+ if (put_xattr_hdr(longname, component,
+ longattrname, prefix, type, filetype, lp)) {
goto out;
}
#endif
@@ -6833,8 +7674,9 @@ put_link(char *name, char *longname, char *component,
if (filetype == XATTR_FILE) {
(void) fprintf(vfile, gettext(
"a %s attribute %s link to "
- "attribute %s\n"),
- name, component, lp->attrname);
+ "%s attribute %s\n"),
+ name, component, name,
+ lp->attrname);
} else {
(void) fprintf(vfile, gettext(
"a %s link to %s\n"),
@@ -6853,7 +7695,8 @@ put_link(char *name, char *longname, char *component,
lp->count = stbuf.st_nlink - 1;
if (filetype == XATTR_FILE) {
(void) strcpy(lp->pathname, longname);
- (void) strcpy(lp->attrname, component);
+ (void) strcpy(lp->attrname,
+ component);
} else {
(void) strcpy(lp->pathname, longname);
(void) strcpy(lp->attrname, "");
@@ -6867,8 +7710,8 @@ out:
}
static int
-put_extra_attributes(char *longname, char *shortname, char *prefix,
- int filetype, char typeflag)
+put_extra_attributes(char *longname, char *shortname, char *longattrname,
+ char *prefix, int filetype, char typeflag)
{
static acl_t *aclp = NULL;
int error;
@@ -6878,8 +7721,8 @@ put_extra_attributes(char *longname, char *shortname, char *prefix,
aclp = NULL;
}
#if defined(O_XATTR)
- if (atflag && filetype == XATTR_FILE) {
- if (put_xattr_hdr(longname, shortname, prefix,
+ if ((atflag || saflag) && (filetype == XATTR_FILE)) {
+ if (put_xattr_hdr(longname, shortname, longattrname, prefix,
typeflag, filetype, NULL)) {
return (1);
}
@@ -6927,7 +7770,7 @@ put_extra_attributes(char *longname, char *shortname, char *prefix,
#if defined(O_XATTR)
static int
-put_xattr_hdr(char *longname, char *shortname, char *prefix,
+put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
int typeflag, int filetype, struct linkbuf *lp)
{
char *lname = NULL;
@@ -6943,7 +7786,7 @@ put_xattr_hdr(char *longname, char *shortname, char *prefix,
fatal(gettext("Out of Memory."));
}
sname = malloc(sizeof (char) * strlen(shortname) +
- strlen(".hdr"));
+ strlen(".hdr") + 1);
if (sname == NULL) {
fatal(gettext("Out of Memory."));
}
@@ -6960,7 +7803,7 @@ put_xattr_hdr(char *longname, char *shortname, char *prefix,
/*
* dump extended attr lookup info
*/
- prepare_xattr(&attrbuf, longname, shortname, typeflag, lp, &attrlen);
+ prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
(void) sprintf(lname, "/dev/null/%s", shortname);
@@ -6981,15 +7824,17 @@ put_xattr_hdr(char *longname, char *shortname, char *prefix,
#if defined(O_XATTR)
static int
-read_xattr_hdr()
+read_xattr_hdr(attr_data_t **attrinfo)
{
char buf[TBLOCK];
+ char *attrparent = NULL;
blkcnt_t blocks;
char *tp;
off_t bytes;
int comp_len, link_len;
int namelen;
-
+ int attrparentlen;
+ int parentfilelen;
if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
return (1);
@@ -7037,7 +7882,40 @@ read_xattr_hdr()
else
xattr_linkp = NULL;
- xattraname = xattrp->h_names + strlen(xattrp->h_names) + 1;
+ /*
+ * Gather the attribute path from the filename and attrnames section.
+ * The filename and attrnames section can be composed of two or more
+ * path segments separated by a null character. The first segment
+ * is the path to the parent file that roots the entire sequence in
+ * the normal name space. The remaining segments describes a path
+ * rooted at the hidden extended attribute directory of the leaf file of
+ * the previous segment, making it possible to name attributes on
+ * attributes.
+ */
+ parentfilelen = strlen(xattrp->h_names);
+ xattrapath = xattrp->h_names + parentfilelen + 1;
+ if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
+ /*
+ * The attrnames section contains a system attribute on an
+ * attribute. Save the name of the attribute for use later,
+ * and replace the null separating the attribute name from
+ * the system attribute name with a '/' so that xattrapath can
+ * be used to display messages with the full attribute path name
+ * rooted at the hidden attribute directory of the base file
+ * in normal name space.
+ */
+ attrparent = strdup(xattrapath);
+ attrparentlen = strlen(attrparent);
+ xattrapath[attrparentlen] = '/';
+ }
+ if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
+ xattrapath + attrparentlen + 1, xattrapath, attrparent,
+ -1, 0, attrinfo)) == 1) {
+ free(attrparent);
+ return (1);
+ }
+
+ /* Gather link info */
if (xattr_linkp) {
xattr_linkaname = xattr_linkp->h_names +
strlen(xattr_linkp->h_names) + 1;
@@ -7049,7 +7927,7 @@ read_xattr_hdr()
}
#else
static int
-read_xattr_hdr()
+read_xattr_hdr(attr_data_t **attrinfo)
{
return (0);
}
@@ -7138,10 +8016,13 @@ get_component(char *path)
}
#endif
+#if defined(O_XATTR)
static int
-retry_attrdir_open(char *name)
+retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
+ int oflag, mode_t mode)
{
- int dirfd = -1;
+ int dirfd;
+ int ofilefd = -1;
struct timeval times[2];
mode_t newmode;
struct stat parentstat;
@@ -7152,57 +8033,82 @@ retry_attrdir_open(char *name)
* We couldn't get to attrdir. See if its
* just a mode problem on the parent file.
* for example: a mode such as r-xr--r--
- * won't let us create an attribute dir
- * if it doesn't already exist.
+ * on a ufs file system without extended
+ * system attribute support won't let us
+ * create an attribute dir if it doesn't
+ * already exist, and on a ufs file system
+ * with extended system attribute support
+ * won't let us open the attribute for
+ * write.
*
* If file has a non-trivial ACL, then save it
* off so that we can place it back on after doing
* chmod's.
*/
-
- if (stat(name, &parentstat) == -1) {
- (void) fprintf(stderr, gettext("tar: cannot stat file %s %s\n"),
- name, strerror(errno));
+ if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
+ O_RDONLY)) == -1) {
+ return (-1);
+ }
+ if (fstat(dirfd, &parentstat) == -1) {
+ (void) fprintf(stderr, gettext(
+ "tar: cannot stat %sfile %s: %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name, strerror(errno));
return (-1);
}
- if ((error = acl_get(name, ACL_NO_TRIVIAL, &aclp)) != 0) {
- (void) fprintf(stderr, gettext("tar: failed to retrieve ACL on"
- " %s %s\n"), name, strerror(errno));
+ if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
+ (void) fprintf(stderr, gettext(
+ "tar: failed to retrieve ACL on %sfile %s: %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name, strerror(errno));
return (-1);
}
newmode = S_IWUSR | parentstat.st_mode;
- if (chmod(name, newmode) == -1) {
+ if (fchmod(dirfd, newmode) == -1) {
(void) fprintf(stderr,
- gettext("tar: cannot chmod file %s to %o %s\n"),
- name, newmode, strerror(errno));
+ gettext(
+ "tar: cannot fchmod %sfile %s to %o: %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
if (aclp)
acl_free(aclp);
return (-1);
}
- dirfd = attropen(name, ".", O_RDONLY);
- /*
- * Don't print error message if attropen() failed,
- * caller will print message.
- */
+ if (pdirfd == -1) {
+ /*
+ * We weren't able to create the attribute directory before.
+ * Now try again.
+ */
+ ofilefd = attropen(dirp, ".", oflag);
+ } else {
+ /*
+ * We weren't able to create open the attribute before.
+ * Now try again.
+ */
+ ofilefd = openat(pdirfd, name, oflag, mode);
+ }
/*
* Put mode back to original
*/
- if (chmod(name, parentstat.st_mode) == -1) {
+ if (fchmod(dirfd, parentstat.st_mode) == -1) {
(void) fprintf(stderr,
- gettext("tar: cannot chmod file %s to %o %s\n"),
- name, newmode, strerror(errno));
+ gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
}
if (aclp) {
- error = acl_set(name, aclp);
+ error = facl_set(dirfd, aclp);
if (error) {
(void) fprintf(stderr,
- gettext("tar: %s: failed to set acl entries\n"),
- name);
+ gettext("tar: failed to set acl entries on "
+ "%sfile %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name);
}
acl_free(aclp);
}
@@ -7215,10 +8121,14 @@ retry_attrdir_open(char *name)
times[0].tv_usec = 0;
times[1].tv_sec = parentstat.st_mtime;
times[1].tv_usec = 0;
- (void) utimes(name, times);
- return (dirfd);
+ (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
+
+ (void) close(dirfd);
+
+ return (ofilefd);
}
+#endif
#if !defined(O_XATTR)
static int
diff --git a/usr/src/cmd/truss/systable.c b/usr/src/cmd/truss/systable.c
index 58b8065178..623a367e38 100644
--- a/usr/src/cmd/truss/systable.c
+++ b/usr/src/cmd/truss/systable.c
@@ -720,6 +720,7 @@ static const struct systable fsatsystable[] = {
{"futimesat", 4, DEC, NOV, HID, ATC, STG, HEX}, /* 6 */
{"renameat", 5, DEC, NOV, HID, ATC, STG, DEC, STG}, /* 7 */
{"__accessat", 5, DEC, NOV, HID, ATC, STG, ACC}, /* 8 */
+{"__openattrdirat", 3, DEC, NOV, HID, ATC, STG}, /* 9 */
{"openat", 4, DEC, NOV, HID, ATC, STG, OPN}, /* N - 2 */
{"openat64", 4, DEC, NOV, HID, ATC, STG, OPN}, /* N - 1 */
};
@@ -955,6 +956,7 @@ const struct sysalias sysalias[] = {
{ "futimesat", SYS_fsat },
{ "renameat", SYS_fsat },
{ "__accessat", SYS_fsat },
+ { "__openattrdirat", SYS_fsat },
{ "lgrpsys", SYS_lgrpsys },
{ "getrusage", SYS_rusagesys },
{ "getrusage_chld", SYS_rusagesys },
@@ -1248,6 +1250,7 @@ getsubcode(private_t *pri)
case 6:
case 7:
case 8:
+ case 9:
subcode = arg0;
}
break;
diff --git a/usr/src/cmd/unpack/Makefile b/usr/src/cmd/unpack/Makefile
index 076a2013e8..31e0e24556 100644
--- a/usr/src/cmd/unpack/Makefile
+++ b/usr/src/cmd/unpack/Makefile
@@ -2,9 +2,8 @@
# 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.
+# 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.
@@ -22,7 +21,7 @@
#
#ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -30,7 +29,9 @@ PROG= unpack
include ../Makefile.cmd
CFLAGS += $(CCVERBOSE)
-LDLIBS += -lsec
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+
+LDLIBS += -lcmdutils -lsec
XGETFLAGS += -a -x unpack.xcl
.KEEP_STATE:
diff --git a/usr/src/cmd/unpack/unpack.c b/usr/src/cmd/unpack/unpack.c
index 44f70ac51b..b95909d4a3 100644
--- a/usr/src/cmd/unpack/unpack.c
+++ b/usr/src/cmd/unpack/unpack.c
@@ -23,11 +23,11 @@
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.21 */
+#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Huffman decompressor
@@ -35,24 +35,16 @@
* or unpack filename...
*/
-#include <stdio.h>
-#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
#include <locale.h>
#include <utime.h>
-#include <stdlib.h>
-#include <limits.h>
#include <sys/param.h>
-#include <dirent.h>
#include <sys/acl.h>
#include <aclutils.h>
+#include <libcmdutils.h>
static struct utimbuf u_times;
-
static jmp_buf env;
static struct stat status;
static char *argv0, *argvk;
@@ -91,7 +83,11 @@ static int decode();
static int getwdsize();
static int getch();
static int getdict();
-static int mv_xattrs();
+
+/* Extended system attribute support */
+
+static int saflg = 0;
+
/* read in the dictionary portion and build decoding structures */
/* return 1 if successful, 0 otherwise */
@@ -113,7 +109,7 @@ getdict()
inleft = read(infile, &inbuff[0], BUFSIZ);
if (inleft < 0) {
(void) fprintf(stderr, gettext(
- "%s: %s: read error: "), argv0, filename);
+ "%s: %s: read error: "), argv0, filename);
perror("");
return (0);
}
@@ -135,7 +131,7 @@ getdict()
maxlev = *inp++ & 0377;
if (maxlev > 24) {
goof: (void) fprintf(stderr, gettext(
- "%s: %s: not in packed format\n"), argv0, filename);
+ "%s: %s: not in packed format\n"), argv0, filename);
return (0);
}
for (i = 1; i <= maxlev; i++)
@@ -185,16 +181,16 @@ decode()
inleft = read(infile, inp = &inbuff[0], BUFSIZ);
if (inleft < 0) {
(void) fprintf(stderr, gettext(
- "%s: %s: read error: "),
- argv0, filename);
+ "%s: %s: read error: "),
+ argv0, filename);
perror("");
return (0);
}
}
if (--inleft < 0) {
uggh: (void) fprintf(stderr, gettext(
- "%s: %s: unpacking error\n"),
- argv0, filename);
+ "%s: %s: unpacking error\n"),
+ argv0, filename);
return (0);
}
c = *inp++;
@@ -208,10 +204,12 @@ uggh: (void) fprintf(stderr, gettext(
p = &tree[lev][j];
if (p == eof) {
c = outp - &outbuff[0];
- if (write(outfile, &outbuff[0], c) != c) {
-wrerr: (void) fprintf(stderr, gettext(
- "%s: %s: write error: "),
- argv0, argvk);
+ if (write(outfile, &outbuff[0], c)
+ != c) {
+wrerr: (void) fprintf(stderr,
+ gettext(
+ "%s: %s: write error: "),
+ argv0, argvk);
perror("");
return (0);
}
@@ -223,7 +221,7 @@ wrerr: (void) fprintf(stderr, gettext(
*outp++ = *p;
if (outp == &outbuff[BUFSIZ]) {
if (write(outfile, outp = &outbuff[0],
- BUFSIZ) != BUFSIZ)
+ BUFSIZ) != BUFSIZ)
goto wrerr;
origsize -= BUFSIZ;
}
@@ -248,25 +246,28 @@ main(int argc, char *argv[])
int max_name;
void onsig(int);
acl_t *aclp = NULL;
-
+ int c;
+ char *progname;
+ int sattr_exist = 0;
+ int xattr_exist = 0;
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
#ifdef __STDC__
- signal((int)SIGHUP, onsig);
+ (void) signal((int)SIGHUP, onsig);
#else
- signal((int)SIGHUP, onsig);
+ (void) signal((int)SIGHUP, onsig);
#endif
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
#ifdef __STDC__
- signal((int)SIGINT, onsig);
+ (void) signal((int)SIGINT, onsig);
#else
- signal((int)SIGINT, onsig);
+ (void) signal((int)SIGINT, onsig);
#endif
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
#ifdef __STDC__
- signal((int)SIGTERM, onsig);
+ (void) signal((int)SIGTERM, onsig);
#else
- signal(SIGTERM, onsig);
+ (void) signal(SIGTERM, onsig);
#endif
(void) setlocale(LC_ALL, "");
@@ -275,16 +276,28 @@ main(int argc, char *argv[])
#endif
(void) textdomain(TEXT_DOMAIN);
+ if (progname = strrchr(argv[0], '/'))
+ ++progname;
+ else
+ progname = argv[0];
+
p1 = *argv;
- while (*p1++); /* Point p1 to end of argv[0] string */
+ while (*p1++) { }; /* Point p1 to end of argv[0] string */
while (--p1 >= *argv)
if (*p1 == '/')break;
*argv = p1 + 1;
argv0 = argv[0];
if (**argv == 'p')pcat++; /* User entered pcat (or /xx/xx/pcat) */
- while (getopt(argc, argv, "") != EOF)
- ++errflg;
+ while ((c = getopt(argc, argv, "/")) != EOF) {
+ if (c == '/') {
+ if (pcat)
+ ++errflg;
+ else
+ saflg++;
+ } else
+ ++errflg;
+ }
/*
* Check for invalid option. Also check for missing
* file operand, ie: "unpack" or "pcat".
@@ -292,7 +305,13 @@ main(int argc, char *argv[])
argc -= optind;
argv = &argv[optind];
if (errflg || argc < 1) {
- (void) fprintf(stderr, gettext("usage: %s file...\n"), argv0);
+ if (!pcat)
+ (void) fprintf(stderr,
+ gettext("usage: %s [-/] file...\n"), argv0);
+ else
+ (void) fprintf(stderr, gettext("usage: %s file...\n"),
+ argv0);
+
if (argc < 1) {
/*
* return 1 for usage error when no file was specified
@@ -329,8 +348,8 @@ main(int argc, char *argv[])
*cp = '\0';
if ((infile = open(filename, O_RDONLY)) == -1) {
(void) fprintf(stderr, gettext(
- "%s: %s: cannot open: "),
- argv0, filename);
+ "%s: %s: cannot open: "),
+ argv0, filename);
perror("");
goto done;
}
@@ -342,7 +361,7 @@ main(int argc, char *argv[])
if (error != 0) {
(void) printf(gettext(
"%s: %s: cannot retrieve ACL : %s\n"),
- argv0, filename, acl_strerror(error));
+ argv0, filename, acl_strerror(error));
}
max_name = pathconf(filename, _PC_NAME_MAX);
@@ -352,38 +371,69 @@ main(int argc, char *argv[])
}
if (i >= (MAXPATHLEN-1) || (i - sep - 1) > max_name) {
(void) fprintf(stderr, gettext(
- "%s: %s: file name too long\n"),
- argv0, argvk);
+ "%s: %s: file name too long\n"),
+ argv0, argvk);
goto done;
}
if (stat(argvk, &status) != -1) {
(void) fprintf(stderr, gettext(
- "%s: %s: already exists\n"),
- argv0, argvk);
+ "%s: %s: already exists\n"),
+ argv0, argvk);
goto done;
}
(void) fstat(infile, &status);
if (status.st_nlink != 1) {
(void) printf(gettext(
- "%s: %s: Warning: file has links\n"),
- argv0, filename);
+ "%s: %s: Warning: file has links\n"),
+ argv0, filename);
}
if ((outfile = creat(argvk, status.st_mode)) == -1) {
(void) fprintf(stderr, gettext(
- "%s: %s: cannot create: "),
- argv0, argvk);
+ "%s: %s: cannot create: "),
+ argv0, argvk);
perror("");
goto done;
}
rmflg = 1;
}
- if (getdict() && /* unpack */
- (pcat ||
- (pathconf(filename, _PC_XATTR_EXISTS) != 1) ||
- (mv_xattrs(infile, outfile,
- filename, 0) == 0))) {
+ if (getdict()) { /* unpack */
+ if (pathconf(filename, _PC_XATTR_EXISTS) == 1)
+ xattr_exist = 1;
+ if (saflg && sysattr_support(filename,
+ _PC_SATTR_EXISTS) == 1)
+ sattr_exist = 1;
+ if (pcat || xattr_exist || sattr_exist) {
+ if (mv_xattrs(progname, filename, argv[k],
+ sattr_exist, 0)
+ != 0) {
+ /* Move attributes back ... */
+ xattr_exist = 0;
+ sattr_exist = 0;
+ if (pathconf(argvk, _PC_XATTR_EXISTS)
+ == 1)
+ xattr_exist = 1;
+ if (saflg && sysattr_support(argvk,
+ _PC_SATTR_EXISTS) == 1)
+ sattr_exist = 1;
+ if (!pcat && (xattr_exist ||
+ sattr_exist)) {
+ (void) mv_xattrs(progname,
+ argv[k], filename,
+ sattr_exist, 1);
+ (void) unlink(argvk);
+ goto done;
+ }
+ } else {
+ if (!pcat)
+ (void) unlink(filename);
+ }
+ } else if (!pcat)
+ (void) unlink(filename);
+
if (!pcat) {
+ (void) printf(gettext("%s: %s: unpacked\n"),
+ argv0, argvk);
/*
* preserve acc & mod dates
*/
@@ -392,8 +442,8 @@ main(int argc, char *argv[])
if (utime(argvk, &u_times) != 0) {
errflg++;
(void) fprintf(stderr, gettext(
- "%s: cannot change times on %s: "),
- argv0, argvk);
+ "%s: cannot change times on %s: "),
+ argv0, argvk);
perror("");
}
if (chmod(argvk, status.st_mode) != 0) {
@@ -405,7 +455,7 @@ main(int argc, char *argv[])
perror("");
}
(void) chown(argvk,
- status.st_uid, status.st_gid);
+ status.st_uid, status.st_gid);
if (aclp && (facl_set(outfile, aclp) < 0)) {
(void) printf(gettext("%s: cannot "
"set ACL on %s: "), argv0, argvk);
@@ -413,22 +463,10 @@ main(int argc, char *argv[])
}
rmflg = 0;
- (void) printf(gettext("%s: %s: unpacked\n"),
- argv0, argvk);
- (void) unlink(filename);
-
}
if (!errflg)
fcount--; /* success after all */
}
- else
- if (!pcat) {
- if (pathconf(argvk, _PC_XATTR_EXISTS) == 1) {
- (void) mv_xattrs(outfile, infile,
- argvk, 1);
- }
- (void) unlink(argvk);
- }
done: (void) close(infile);
if (!pcat)
(void) close(outfile);
@@ -465,8 +503,8 @@ expand()
origsize += (unsigned)getwdsize();
if (origsize == 0 || is_eof) {
(void) fprintf(stderr, gettext(
- "%s: %s: not in packed format\n"),
- argv0, filename);
+ "%s: %s: not in packed format\n"),
+ argv0, filename);
return (0);
}
t = Tree;
@@ -479,8 +517,8 @@ expand()
*/
if (is_eof) {
(void) fprintf(stderr, gettext(
- "%s: %s: not in packed format\n"),
- argv0, filename);
+ "%s: %s: not in packed format\n"),
+ argv0, filename);
return (0);
}
*t++ = i & 0377;
@@ -491,8 +529,8 @@ expand()
*/
if (is_eof) {
(void) fprintf(stderr, gettext(
- "%s: %s: not in packed format\n"),
- argv0, filename);
+ "%s: %s: not in packed format\n"),
+ argv0, filename);
return (0);
}
@@ -506,8 +544,8 @@ expand()
*/
if (word == 0 && is_eof && origsize > 0) {
(void) fprintf(stderr, gettext(
- "%s: %s: not in packed format\n"),
- argv0, filename);
+ "%s: %s: not in packed format\n"),
+ argv0, filename);
return (0);
}
bit = 16;
@@ -533,8 +571,8 @@ getch()
inleft = read(infile, inp = inbuff, BUFSIZ);
if (inleft < 0) {
(void) fprintf(stderr, gettext(
- "%s: %s: read error: "),
- argv0, filename);
+ "%s: %s: read error: "),
+ argv0, filename);
perror("");
longjmp(env, 1);
} else { /* reached EOF, report it */
@@ -572,7 +610,9 @@ onsig(int sig)
/* created by unpack and not yet done */
if (rmflg == 1)
(void) unlink(argvk);
- exit(1);
+ /* To quiet lint noise */
+ if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT)
+ exit(1);
}
void
@@ -585,79 +625,10 @@ putch(char c)
n = write(outfile, outp = outbuff, BUFSIZ);
if (n < BUFSIZ) {
(void) fprintf(stderr, gettext(
- "%s: %s: write error: "),
- argv0, argvk);
+ "%s: %s: write error: "),
+ argv0, argvk);
perror("");
longjmp(env, 2);
}
}
}
-
-/*
- * mv_xattrs - move (via renameat) all of the extended attributes
- * associated with the file referenced by infd to the file
- * referenced by outfd. The infile and silent arguments are
- * provided for error message processing. This function
- * returns 0 on success and -1 on error.
- */
-static int
-mv_xattrs(int infd, int outfd, char *infile, int silent)
-{
- int indfd, outdfd, tmpfd;
- DIR *dirp = NULL;
- struct dirent *dp = NULL;
- int error = 0;
- char *etext;
-
- indfd = outdfd = tmpfd = -1;
-
- if ((indfd = openat(infd, ".", O_RDONLY|O_XATTR)) == -1) {
- etext = gettext("cannot open source");
- error = -1;
- goto out;
- }
-
- if ((outdfd = openat(outfd, ".", O_RDONLY|O_XATTR)) == -1) {
- etext = gettext("cannot open target");
- error = -1;
- goto out;
- }
-
- if ((tmpfd = dup(indfd)) == -1) {
- etext = gettext("cannot dup descriptor");
- error = -1;
- goto out;
-
- }
- if ((dirp = fdopendir(tmpfd)) == NULL) {
- etext = gettext("cannot access source");
- error = -1;
- goto out;
- }
-
- while (dp = readdir(dirp)) {
- if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
- (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
- dp->d_name[2] == '\0'))
- continue;
- if ((renameat(indfd, dp->d_name, outdfd, dp->d_name)) == -1) {
- etext = dp->d_name;
- error = -1;
- goto out;
- }
- }
-out:
- if (error == -1 && silent == 0) {
- fprintf(stderr, gettext(
- "unpack: %s: cannot move extended attributes, "),
- infile);
- perror(etext);
- }
- if (dirp)
- closedir(dirp);
- if (indfd != -1)
- close(indfd);
- if (outdfd != -1)
- close(outdfd);
- return (error);
-}
diff --git a/usr/src/cmd/wbem/provider/c/wbem_disk/common/disk_descriptors.c b/usr/src/cmd/wbem/provider/c/wbem_disk/common/disk_descriptors.c
index d962c94291..c59d9f9543 100644
--- a/usr/src/cmd/wbem/provider/c/wbem_disk/common/disk_descriptors.c
+++ b/usr/src/cmd/wbem/provider/c/wbem_disk/common/disk_descriptors.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -285,7 +284,7 @@ disk_descriptor_toCCIMInstance(char *hostname, dm_descriptor_t desc,
return ((CCIMInstance *)NULL);
}
- nvlist_lookup_uint32(nvlp, DM_BLOCKSIZE, &blocksize);
+ (void) nvlist_lookup_uint32(nvlp, DM_BLOCKSIZE, &blocksize);
error = snprintf(buf, sizeof (buf), "%llu", ui64 * blocksize);
if (error < 0) {
diff --git a/usr/src/cmd/wbem/provider/c/wbem_disk/common/drive_descriptors.c b/usr/src/cmd/wbem/provider/c/wbem_disk/common/drive_descriptors.c
index 37c38e5282..200aa2ed4e 100644
--- a/usr/src/cmd/wbem/provider/c/wbem_disk/common/drive_descriptors.c
+++ b/usr/src/cmd/wbem/provider/c/wbem_disk/common/drive_descriptors.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -724,7 +723,7 @@ drive_descriptors_toCCIMObjPathInstList(char *providerName, dm_descriptor_t *dp,
}
drvtype = DM_DT_UNKNOWN;
- nvlist_lookup_uint32(attrs, DM_DRVTYPE, &drvtype);
+ (void) nvlist_lookup_uint32(attrs, DM_DRVTYPE, &drvtype);
nvlist_free(attrs);
switch (drvtype) {
diff --git a/usr/src/cmd/wbem/provider/c/wbem_disk/common/methods.c b/usr/src/cmd/wbem/provider/c/wbem_disk/common/methods.c
index 9f94fc99c1..72489a3dbe 100644
--- a/usr/src/cmd/wbem/provider/c/wbem_disk/common/methods.c
+++ b/usr/src/cmd/wbem/provider/c/wbem_disk/common/methods.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -824,23 +823,23 @@ disk_geometry(char *media_name, ulong_t *geometry)
geometry[0] = val32;
val32 = 0;
- nvlist_lookup_uint32(attrs, DM_NHEADS, &val32);
+ (void) nvlist_lookup_uint32(attrs, DM_NHEADS, &val32);
geometry[1] = val32;
val32 = 0;
- nvlist_lookup_uint32(attrs, DM_BLOCKSIZE, &val32);
+ (void) nvlist_lookup_uint32(attrs, DM_BLOCKSIZE, &val32);
geometry[2] = (geometry[1] * geometry[0]) * val32;
val32 = 0;
- nvlist_lookup_uint32(attrs, DM_NPHYSCYLINDERS, &val32);
+ (void) nvlist_lookup_uint32(attrs, DM_NPHYSCYLINDERS, &val32);
geometry[3] = val32;
val32 = 0;
- nvlist_lookup_uint32(attrs, DM_NCYLINDERS, &val32);
+ (void) nvlist_lookup_uint32(attrs, DM_NCYLINDERS, &val32);
geometry[4] = val32;
val32 = 0;
- nvlist_lookup_uint32(attrs, DM_NALTCYLINDERS, &val32);
+ (void) nvlist_lookup_uint32(attrs, DM_NALTCYLINDERS, &val32);
geometry[5] = val32;
val32 = 0;
/* This one is probably there only in x86 machines. */
- nvlist_lookup_uint32(attrs, DM_NACTUALCYLINDERS, &val32);
+ (void) nvlist_lookup_uint32(attrs, DM_NACTUALCYLINDERS, &val32);
geometry[6] = val32;
nvlist_free(attrs);
diff --git a/usr/src/cmd/zdb/zdb.c b/usr/src/cmd/zdb/zdb.c
index 86278f1d8b..055c283c1f 100644
--- a/usr/src/cmd/zdb/zdb.c
+++ b/usr/src/cmd/zdb/zdb.c
@@ -720,7 +720,7 @@ dump_dsl_dir(objset_t *os, uint64_t object, void *data, size_t size)
if (dd == NULL)
return;
- ASSERT(size == sizeof (*dd));
+ ASSERT3U(size, >=, sizeof (dsl_dir_phys_t));
crtime = dd->dd_creation_time;
nicenum(dd->dd_used_bytes, used);
@@ -925,7 +925,7 @@ static object_viewer_t *object_viewer[DMU_OT_NUMTYPES] = {
dump_zap, /* DSL props */
dump_dsl_dataset, /* DSL dataset */
dump_znode, /* ZFS znode */
- dump_acl, /* ZFS ACL */
+ dump_acl, /* ZFS V0 ACL */
dump_uint8, /* ZFS plain file */
dump_zpldir, /* ZFS directory */
dump_zap, /* ZFS master node */
@@ -940,6 +940,10 @@ static object_viewer_t *object_viewer[DMU_OT_NUMTYPES] = {
dump_uint64, /* SPA history offsets */
dump_zap, /* Pool properties */
dump_zap, /* DSL permissions */
+ dump_acl, /* ZFS ACL */
+ dump_uint8, /* ZFS SYSACL */
+ dump_none, /* FUID nvlist */
+ dump_packed_nvlist, /* FUID nvlist size */
};
static void
diff --git a/usr/src/cmd/zdb/zdb_il.c b/usr/src/cmd/zdb/zdb_il.c
index 10dfe20eda..02d35a0503 100644
--- a/usr/src/cmd/zdb/zdb_il.c
+++ b/usr/src/cmd/zdb/zdb_il.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -233,19 +233,26 @@ typedef struct zil_rec_info {
} zil_rec_info_t;
static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
- { NULL, "Total " },
- { zil_prt_rec_create, "TX_CREATE " },
- { zil_prt_rec_create, "TX_MKDIR " },
- { zil_prt_rec_create, "TX_MKXATTR " },
- { zil_prt_rec_create, "TX_SYMLINK " },
- { zil_prt_rec_remove, "TX_REMOVE " },
- { zil_prt_rec_remove, "TX_RMDIR " },
- { zil_prt_rec_link, "TX_LINK " },
- { zil_prt_rec_rename, "TX_RENAME " },
- { zil_prt_rec_write, "TX_WRITE " },
- { zil_prt_rec_truncate, "TX_TRUNCATE" },
- { zil_prt_rec_setattr, "TX_SETATTR " },
- { zil_prt_rec_acl, "TX_ACL " },
+ { NULL, "Total " },
+ { zil_prt_rec_create, "TX_CREATE " },
+ { zil_prt_rec_create, "TX_MKDIR " },
+ { zil_prt_rec_create, "TX_MKXATTR " },
+ { zil_prt_rec_create, "TX_SYMLINK " },
+ { zil_prt_rec_remove, "TX_REMOVE " },
+ { zil_prt_rec_remove, "TX_RMDIR " },
+ { zil_prt_rec_link, "TX_LINK " },
+ { zil_prt_rec_rename, "TX_RENAME " },
+ { zil_prt_rec_write, "TX_WRITE " },
+ { zil_prt_rec_truncate, "TX_TRUNCATE " },
+ { zil_prt_rec_setattr, "TX_SETATTR " },
+ { zil_prt_rec_acl, "TX_ACL_V0 " },
+ { zil_prt_rec_acl, "TX_ACL_ACL " },
+ { zil_prt_rec_create, "TX_CREATE_ACL " },
+ { zil_prt_rec_create, "TX_CREATE_ATTR " },
+ { zil_prt_rec_create, "TX_CREATE_ACL_ATTR " },
+ { zil_prt_rec_create, "TX_MKDIR_ACL " },
+ { zil_prt_rec_create, "TX_MKDIR_ATTR " },
+ { zil_prt_rec_create, "TX_MKDIR_ACL_ATTR " },
};
/* ARGSUSED */
@@ -255,12 +262,14 @@ print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
int txtype;
int verbose = MAX(dump_opt['d'], dump_opt['i']);
+ /* reduce size of txtype to strip off TX_CI bit */
txtype = lr->lrc_txtype;
ASSERT(txtype != 0 && (uint_t)txtype < TX_MAX_TYPE);
ASSERT(lr->lrc_txg);
- (void) printf("\t\t%s len %6llu, txg %llu, seq %llu\n",
+ (void) printf("\t\t%s%s len %6llu, txg %llu, seq %llu\n",
+ (lr->lrc_txtype & TX_CI) ? "CI-" : "",
zil_rec_info[txtype].zri_name,
(u_longlong_t)lr->lrc_reclen,
(u_longlong_t)lr->lrc_txg,
diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c
index 3fe2cd1705..e7ea903595 100644
--- a/usr/src/cmd/zfs/zfs_main.c
+++ b/usr/src/cmd/zfs/zfs_main.c
@@ -283,7 +283,9 @@ usage_prop_cb(int prop, void *cb)
(void) fprintf(fp, "\t%-13s ", zfs_prop_to_name(prop));
- if (zfs_prop_readonly(prop))
+ if (prop == ZFS_PROP_CASE)
+ (void) fprintf(fp, "NO ");
+ else if (zfs_prop_readonly(prop))
(void) fprintf(fp, " NO ");
else
(void) fprintf(fp, " YES ");
@@ -1348,6 +1350,35 @@ upgrade_set_callback(zfs_handle_t *zhp, void *data)
upgrade_cbdata_t *cb = data;
int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+ if (cb->cb_version >= ZPL_VERSION_FUID) {
+ char pool_name[MAXPATHLEN];
+ zpool_handle_t *zpool_handle;
+ int spa_version;
+ char *p;
+
+ if (zfs_prop_get(zhp, ZFS_PROP_NAME, pool_name,
+ sizeof (pool_name), NULL, NULL, 0, B_FALSE) != 0)
+ return (-1);
+
+ if (p = strchr(pool_name, '/'))
+ *p = '\0';
+ if ((zpool_handle = zpool_open(g_zfs, pool_name)) == NULL)
+ return (-1);
+
+ spa_version = zpool_get_prop_int(zpool_handle,
+ ZPOOL_PROP_VERSION, NULL);
+ zpool_close(zpool_handle);
+ if (spa_version < SPA_VERSION_FUID) {
+ /* can't upgrade */
+ (void) printf(gettext("%s: can not be upgraded; "
+ "the pool version needs to first be upgraded\nto "
+ "version %d\n\n"),
+ zfs_get_name(zhp), SPA_VERSION_FUID);
+ cb->cb_numfailed++;
+ return (0);
+ }
+ }
+
/* upgrade */
if (version < cb->cb_version) {
char verstr[16];
@@ -1442,6 +1473,8 @@ zfs_do_upgrade(int argc, char **argv)
"---------------\n");
(void) printf(gettext(" 1 Initial ZFS filesystem version\n"));
(void) printf(gettext(" 2 Enhanced directory entries\n"));
+ (void) printf(gettext(" 3 Case insensitive and File system "
+ "unique identifer (FUID)\n"));
(void) printf(gettext("\nFor more information on a particular "
"version, including supported releases, see:\n\n"));
(void) printf("http://www.opensolaris.org/os/community/zfs/"
@@ -1494,7 +1527,7 @@ zfs_do_upgrade(int argc, char **argv)
* <dataset> ...
*
* -r Recurse over all children
- * -H Scripted mode; elide headers and separate colums by tabs
+ * -H Scripted mode; elide headers and separate columns by tabs
* -o Control which fields to display.
* -t Control which object types to display.
* -s Specify sort columns, descending order.
@@ -2121,7 +2154,7 @@ zfs_do_set(int argc, char **argv)
* zfs snapshot [-r] <fs@snap>
*
* Creates a snapshot with the given name. While functionally equivalent to
- * 'zfs create', it is a separate command to diffferentiate intent.
+ * 'zfs create', it is a separate command to differentiate intent.
*/
static int
zfs_do_snapshot(int argc, char **argv)
@@ -2828,15 +2861,17 @@ dataset_cmp(const void *a, const void *b)
* Share or mount a dataset.
*/
static int
-share_mount_one(zfs_handle_t *zhp, int op, int flags, boolean_t explicit,
- const char *options)
+share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
+ boolean_t explicit, const char *options)
{
char mountpoint[ZFS_MAXPROPLEN];
char shareopts[ZFS_MAXPROPLEN];
+ char smbshareopts[ZFS_MAXPROPLEN];
const char *cmdname = op == OP_SHARE ? "share" : "mount";
struct mnttab mnt;
uint64_t zoned, canmount;
zfs_type_t type = zfs_get_type(zhp);
+ boolean_t shared_nfs, shared_smb;
assert(type & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME));
@@ -2877,9 +2912,12 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, boolean_t explicit,
sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts,
+ sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0);
canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
- if (op == OP_SHARE && strcmp(shareopts, "off") == 0) {
+ if (op == OP_SHARE && strcmp(shareopts, "off") == 0 &&
+ strcmp(smbshareopts, "off") == 0) {
if (!explicit)
return (0);
@@ -2935,7 +2973,15 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, boolean_t explicit,
*/
switch (op) {
case OP_SHARE:
- if (zfs_is_shared_nfs(zhp, NULL)) {
+
+ shared_nfs = zfs_is_shared_nfs(zhp, NULL);
+ shared_smb = zfs_is_shared_smb(zhp, NULL);
+
+ if (shared_nfs && shared_smb ||
+ (shared_nfs && strcmp(shareopts, "on") == 0 &&
+ strcmp(smbshareopts, "off") == 0) ||
+ (shared_smb && strcmp(smbshareopts, "on") == 0 &&
+ strcmp(shareopts, "off") == 0)) {
if (!explicit)
return (0);
@@ -2949,8 +2995,23 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, boolean_t explicit,
zfs_mount(zhp, NULL, 0) != 0)
return (1);
- if (zfs_share_nfs(zhp) != 0)
+ if (protocol == NULL) {
+ if (zfs_shareall(zhp) != 0)
+ return (1);
+ } else if (strcmp(protocol, "nfs") == 0) {
+ if (zfs_share_nfs(zhp))
+ return (1);
+ } else if (strcmp(protocol, "smb") == 0) {
+ if (zfs_share_smb(zhp))
+ return (1);
+ } else {
+ (void) fprintf(stderr, gettext("cannot share "
+ "'%s': invalid share type '%s' "
+ "specified\n"),
+ zfs_get_name(zhp), protocol);
return (1);
+ }
+
break;
case OP_MOUNT:
@@ -3098,20 +3159,22 @@ share_mount(int op, int argc, char **argv)
if (do_all) {
zfs_handle_t **dslist = NULL;
size_t i, count = 0;
+ char *protocol = NULL;
if (op == OP_MOUNT) {
types = ZFS_TYPE_FILESYSTEM;
} else if (argc > 0) {
- if (strcmp(argv[0], "nfs") == 0) {
+ if (strcmp(argv[0], "nfs") == 0 ||
+ strcmp(argv[0], "smb") == 0) {
types = ZFS_TYPE_FILESYSTEM;
} else if (strcmp(argv[0], "iscsi") == 0) {
types = ZFS_TYPE_VOLUME;
} else {
(void) fprintf(stderr, gettext("share type "
- "must be 'nfs' or 'iscsi'\n"));
+ "must be 'nfs', 'smb' or 'iscsi'\n"));
usage(B_FALSE);
}
-
+ protocol = argv[0];
argc--;
argv++;
} else {
@@ -3134,8 +3197,8 @@ share_mount(int op, int argc, char **argv)
if (verbose)
report_mount_progress(i, count);
- if (share_mount_one(dslist[i], op, flags, B_FALSE,
- options) != 0)
+ if (share_mount_one(dslist[i], op, flags, protocol,
+ B_FALSE, options) != 0)
ret = 1;
zfs_close(dslist[i]);
}
@@ -3181,7 +3244,7 @@ share_mount(int op, int argc, char **argv)
if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) {
ret = 1;
} else {
- ret = share_mount_one(zhp, op, flags, B_TRUE,
+ ret = share_mount_one(zhp, op, flags, NULL, B_TRUE,
options);
zfs_close(zhp);
}
@@ -3203,7 +3266,7 @@ zfs_do_mount(int argc, char **argv)
}
/*
- * zfs share -a [nfs | iscsi]
+ * zfs share -a [nfs | iscsi | smb]
* zfs share filesystem
*
* Share all filesystems, or share the given filesystem.
@@ -3243,7 +3306,8 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
struct stat64 statbuf;
struct extmnttab entry;
const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount";
- char property[ZFS_MAXPROPLEN];
+ char nfs_mnt_prop[ZFS_MAXPROPLEN];
+ char smbshare_prop[ZFS_MAXPROPLEN];
/*
* Search for the path in /etc/mnttab. Rather than looking for the
@@ -3283,27 +3347,31 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
return (1);
verify(zfs_prop_get(zhp, op == OP_SHARE ?
- ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property,
- sizeof (property), NULL, NULL, 0, B_FALSE) == 0);
+ ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, nfs_mnt_prop,
+ sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, op == OP_SHARE ?
+ ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, smbshare_prop,
+ sizeof (smbshare_prop), NULL, NULL, 0, B_FALSE) == 0);
if (op == OP_SHARE) {
- if (strcmp(property, "off") == 0) {
+ if (strcmp(nfs_mnt_prop, "off") == 0 &&
+ strcmp(smbshare_prop, "off") == 0) {
(void) fprintf(stderr, gettext("cannot unshare "
"'%s': legacy share\n"), path);
(void) fprintf(stderr, gettext("use "
"unshare(1M) to unshare this filesystem\n"));
ret = 1;
- } else if (!zfs_is_shared_nfs(zhp, NULL)) {
+ } else if (!zfs_is_shared(zhp)) {
(void) fprintf(stderr, gettext("cannot unshare '%s': "
"not currently shared\n"), path);
ret = 1;
} else {
- ret = zfs_unshareall_nfs(zhp);
+ ret = zfs_unshareall_bypath(zhp, path);
}
} else {
if (is_manual) {
ret = zfs_unmount(zhp, NULL, flags);
- } else if (strcmp(property, "legacy") == 0) {
+ } else if (strcmp(nfs_mnt_prop, "legacy") == 0) {
(void) fprintf(stderr, gettext("cannot unmount "
"'%s': legacy mountpoint\n"),
zfs_get_name(zhp));
@@ -3331,7 +3399,8 @@ unshare_unmount(int op, int argc, char **argv)
int ret = 0;
int types, c;
zfs_handle_t *zhp;
- char property[ZFS_MAXPROPLEN];
+ char nfsiscsi_mnt_prop[ZFS_MAXPROPLEN];
+ char sharesmb[ZFS_MAXPROPLEN];
/* check options */
while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) {
@@ -3412,18 +3481,31 @@ unshare_unmount(int op, int argc, char **argv)
continue;
}
- verify(zfs_prop_get(zhp, op == OP_SHARE ?
- ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
- property, sizeof (property), NULL, NULL,
- 0, B_FALSE) == 0);
-
- /* Ignore legacy mounts and shares */
- if ((op == OP_SHARE &&
- strcmp(property, "off") == 0) ||
- (op == OP_MOUNT &&
- strcmp(property, "legacy") == 0)) {
- zfs_close(zhp);
- continue;
+ switch (op) {
+ case OP_SHARE:
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
+ nfsiscsi_mnt_prop,
+ sizeof (nfsiscsi_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ if (strcmp(nfsiscsi_mnt_prop, "off") != 0)
+ break;
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
+ nfsiscsi_mnt_prop,
+ sizeof (nfsiscsi_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ if (strcmp(nfsiscsi_mnt_prop, "off") == 0)
+ continue;
+ break;
+ case OP_MOUNT:
+ /* Ignore legacy mounts */
+ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
+ nfsiscsi_mnt_prop,
+ sizeof (nfsiscsi_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0)
+ continue;
+ default:
+ break;
}
node = safe_malloc(sizeof (unshare_unmount_node_t));
@@ -3463,7 +3545,7 @@ unshare_unmount(int op, int argc, char **argv)
switch (op) {
case OP_SHARE:
- if (zfs_unshare_nfs(node->un_zhp,
+ if (zfs_unshareall_bypath(node->un_zhp,
node->un_mountp) != 0)
ret = 1;
break;
@@ -3537,12 +3619,22 @@ unshare_unmount(int op, int argc, char **argv)
if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
verify(zfs_prop_get(zhp, op == OP_SHARE ?
- ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property,
- sizeof (property), NULL, NULL, 0, B_FALSE) == 0);
+ ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
+ nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop), NULL,
+ NULL, 0, B_FALSE) == 0);
switch (op) {
case OP_SHARE:
- if (strcmp(property, "off") == 0) {
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
+ nfsiscsi_mnt_prop,
+ sizeof (nfsiscsi_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
+ sharesmb, sizeof (sharesmb), NULL, NULL,
+ 0, B_FALSE) == 0);
+
+ if (strcmp(nfsiscsi_mnt_prop, "off") == 0 &&
+ strcmp(sharesmb, "off") == 0) {
(void) fprintf(stderr, gettext("cannot "
"unshare '%s': legacy share\n"),
zfs_get_name(zhp));
@@ -3550,18 +3642,18 @@ unshare_unmount(int op, int argc, char **argv)
"unshare(1M) to unshare this "
"filesystem\n"));
ret = 1;
- } else if (!zfs_is_shared_nfs(zhp, NULL)) {
+ } else if (!zfs_is_shared(zhp)) {
(void) fprintf(stderr, gettext("cannot "
"unshare '%s': not currently "
"shared\n"), zfs_get_name(zhp));
ret = 1;
- } else if (zfs_unshareall_nfs(zhp) != 0) {
+ } else if (zfs_unshareall(zhp) != 0) {
ret = 1;
}
break;
case OP_MOUNT:
- if (strcmp(property, "legacy") == 0) {
+ if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0) {
(void) fprintf(stderr, gettext("cannot "
"unmount '%s': legacy "
"mountpoint\n"), zfs_get_name(zhp));
@@ -3583,10 +3675,11 @@ unshare_unmount(int op, int argc, char **argv)
} else {
assert(op == OP_SHARE);
- verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, property,
- sizeof (property), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI,
+ nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
- if (strcmp(property, "off") == 0) {
+ if (strcmp(nfsiscsi_mnt_prop, "off") == 0) {
(void) fprintf(stderr, gettext("cannot unshare "
"'%s': 'shareiscsi' property not set\n"),
zfs_get_name(zhp));
diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c
index 7b4d0f6f06..0025c3a81c 100644
--- a/usr/src/cmd/zpool/zpool_main.c
+++ b/usr/src/cmd/zpool/zpool_main.c
@@ -731,7 +731,7 @@ zpool_do_create(int argc, char **argv)
ZFS_PROP_MOUNTPOINT),
mountpoint) == 0);
if (zfs_mount(pool, NULL, 0) == 0)
- ret = zfs_share_nfs(pool);
+ ret = zfs_shareall(pool);
zfs_close(pool);
}
} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
@@ -3277,6 +3277,8 @@ zpool_do_upgrade(int argc, char **argv)
(void) printf(gettext(" 6 bootfs pool property\n"));
(void) printf(gettext(" 7 Separate intent log devices\n"));
(void) printf(gettext(" 8 Delegated administration\n"));
+ (void) printf(gettext(" 9 Case insensitive support and "
+ "File system unique identifiers (FUID)\n"));
(void) printf(gettext("For more information on a particular "
"version, including supported releases, see:\n\n"));
(void) printf("http://www.opensolaris.org/os/community/zfs/"
diff --git a/usr/src/common/acl/acl_common.c b/usr/src/common/acl/acl_common.c
index f93446045f..2f8f6bd409 100644
--- a/usr/src/common/acl/acl_common.c
+++ b/usr/src/common/acl/acl_common.c
@@ -26,18 +26,128 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
-#include <sys/acl.h>
#include <sys/stat.h>
+#include <sys/avl.h>
#if defined(_KERNEL)
#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <acl/acl_common.h>
#else
#include <errno.h>
#include <stdlib.h>
+#include <stddef.h>
#include <strings.h>
+#include <unistd.h>
#include <assert.h>
+#include <grp.h>
+#include <pwd.h>
+#include <acl_common.h>
#define ASSERT assert
#endif
+#define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \
+ ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \
+ ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL)
+
+
+#define ACL_SYNCHRONIZE_SET_DENY 0x0000001
+#define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002
+#define ACL_SYNCHRONIZE_ERR_DENY 0x0000004
+#define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008
+
+#define ACL_WRITE_OWNER_SET_DENY 0x0000010
+#define ACL_WRITE_OWNER_SET_ALLOW 0x0000020
+#define ACL_WRITE_OWNER_ERR_DENY 0x0000040
+#define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080
+
+#define ACL_DELETE_SET_DENY 0x0000100
+#define ACL_DELETE_SET_ALLOW 0x0000200
+#define ACL_DELETE_ERR_DENY 0x0000400
+#define ACL_DELETE_ERR_ALLOW 0x0000800
+
+#define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000
+#define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000
+#define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000
+#define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000
+
+#define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000
+#define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000
+#define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000
+#define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000
+
+#define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000
+#define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000
+#define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000
+#define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000
+
+#define ACL_READ_NAMED_READER_SET_DENY 0x1000000
+#define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000
+#define ACL_READ_NAMED_READER_ERR_DENY 0x4000000
+#define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000
+
+
+#define ACE_VALID_MASK_BITS (\
+ ACE_READ_DATA | \
+ ACE_LIST_DIRECTORY | \
+ ACE_WRITE_DATA | \
+ ACE_ADD_FILE | \
+ ACE_APPEND_DATA | \
+ ACE_ADD_SUBDIRECTORY | \
+ ACE_READ_NAMED_ATTRS | \
+ ACE_WRITE_NAMED_ATTRS | \
+ ACE_EXECUTE | \
+ ACE_DELETE_CHILD | \
+ ACE_READ_ATTRIBUTES | \
+ ACE_WRITE_ATTRIBUTES | \
+ ACE_DELETE | \
+ ACE_READ_ACL | \
+ ACE_WRITE_ACL | \
+ ACE_WRITE_OWNER | \
+ ACE_SYNCHRONIZE)
+
+#define ACE_MASK_UNDEFINED 0x80000000
+
+#define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \
+ ACE_DIRECTORY_INHERIT_ACE | \
+ ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \
+ ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
+ ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
+
+/*
+ * ACL conversion helpers
+ */
+
+typedef enum {
+ ace_unused,
+ ace_user_obj,
+ ace_user,
+ ace_group, /* includes GROUP and GROUP_OBJ */
+ ace_other_obj
+} ace_to_aent_state_t;
+
+typedef struct acevals {
+ uid_t key;
+ avl_node_t avl;
+ uint32_t mask;
+ uint32_t allowed;
+ uint32_t denied;
+ int aent_type;
+} acevals_t;
+
+typedef struct ace_list {
+ acevals_t user_obj;
+ avl_tree_t user;
+ int numusers;
+ acevals_t group_obj;
+ avl_tree_t group;
+ int numgroups;
+ acevals_t other_obj;
+ uint32_t acl_mask;
+ int hasmask;
+ int dfacl_flag;
+ ace_to_aent_state_t state;
+ int seen; /* bitmask of all aclent_t a_type values seen */
+} ace_list_t;
ace_t trivial_acl[] = {
{(uid_t)-1, 0, ACE_OWNER, ACE_ACCESS_DENIED_ACE_TYPE},
@@ -55,43 +165,58 @@ ace_t trivial_acl[] = {
void
-adjust_ace_pair(ace_t *pair, mode_t mode)
+adjust_ace_pair_common(void *pair, size_t access_off,
+ size_t pairsize, mode_t mode)
{
+ char *datap = (char *)pair;
+ uint32_t *amask0 = (uint32_t *)(uintptr_t)(datap + access_off);
+ uint32_t *amask1 = (uint32_t *)(uintptr_t)(datap + pairsize +
+ access_off);
if (mode & S_IROTH)
- pair[1].a_access_mask |= ACE_READ_DATA;
+ *amask1 |= ACE_READ_DATA;
else
- pair[0].a_access_mask |= ACE_READ_DATA;
+ *amask0 |= ACE_READ_DATA;
if (mode & S_IWOTH)
- pair[1].a_access_mask |=
- ACE_WRITE_DATA|ACE_APPEND_DATA;
+ *amask1 |= ACE_WRITE_DATA|ACE_APPEND_DATA;
else
- pair[0].a_access_mask |=
- ACE_WRITE_DATA|ACE_APPEND_DATA;
+ *amask0 |= ACE_WRITE_DATA|ACE_APPEND_DATA;
if (mode & S_IXOTH)
- pair[1].a_access_mask |= ACE_EXECUTE;
+ *amask1 |= ACE_EXECUTE;
else
- pair[0].a_access_mask |= ACE_EXECUTE;
+ *amask0 |= ACE_EXECUTE;
+}
+
+void
+adjust_ace_pair(ace_t *pair, mode_t mode)
+{
+ adjust_ace_pair_common(pair, offsetof(ace_t, a_access_mask),
+ sizeof (ace_t), mode);
}
/*
* ace_trivial:
* determine whether an ace_t acl is trivial
*
- * Trivialness implys that the acl is composed of only
+ * Trivialness implies that the acl is composed of only
* owner, group, everyone entries. ACL can't
* have read_acl denied, and write_owner/write_acl/write_attributes
* can only be owner@ entry.
*/
int
-ace_trivial(ace_t *acep, int aclcnt)
+ace_trivial_common(void *acep, int aclcnt,
+ uint64_t (*walk)(void *, uint64_t, int aclcnt,
+ uint16_t *, uint16_t *, uint32_t *))
{
- int i;
int owner_seen = 0;
int group_seen = 0;
int everyone_seen = 0;
+ uint16_t flags;
+ uint32_t mask;
+ uint16_t type;
+ uint64_t cookie = 0;
- for (i = 0; i != aclcnt; i++) {
- switch (acep[i].a_flags & 0xf040) {
+ while (cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask)) {
+ switch (flags & ACE_TYPE_FLAGS) {
case ACE_OWNER:
if (group_seen || everyone_seen)
return (1);
@@ -113,7 +238,7 @@ ace_trivial(ace_t *acep, int aclcnt)
}
- if (acep[i].a_flags & (ACE_FILE_INHERIT_ACE|
+ if (flags & (ACE_FILE_INHERIT_ACE|
ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
ACE_INHERIT_ONLY_ACE))
return (1);
@@ -124,27 +249,48 @@ ace_trivial(ace_t *acep, int aclcnt)
* Don't allow anybody to deny reading basic
* attributes or a files ACL.
*/
- if ((acep[i].a_access_mask &
- (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
- (acep[i].a_type == ACE_ACCESS_DENIED_ACE_TYPE))
+ if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
+ (type == ACE_ACCESS_DENIED_ACE_TYPE))
return (1);
/*
* Allow on owner@ to allow
* write_acl/write_owner/write_attributes
*/
- if (acep[i].a_type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
- (!(acep[i].a_flags & ACE_OWNER) && (acep[i].a_access_mask &
+ if (type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
+ (!(flags & ACE_OWNER) && (mask &
(ACE_WRITE_OWNER|ACE_WRITE_ACL|ACE_WRITE_ATTRIBUTES))))
return (1);
+
}
if ((owner_seen == 0) || (group_seen == 0) || (everyone_seen == 0))
- return (1);
+ return (1);
return (0);
}
+uint64_t
+ace_walk(void *datap, uint64_t cookie, int aclcnt, uint16_t *flags,
+ uint16_t *type, uint32_t *mask)
+{
+ ace_t *acep = datap;
+
+ *flags = acep[cookie].a_flags;
+ *type = acep[cookie].a_type;
+ *mask = acep[cookie++].a_access_mask;
+
+ if (cookie > aclcnt)
+ return (0);
+ else
+ return (cookie);
+}
+
+int
+ace_trivial(ace_t *acep, int aclcnt)
+{
+ return (ace_trivial_common(acep, aclcnt, ace_walk));
+}
/*
* Generic shellsort, from K&R (1st ed, p 58.), somewhat modified.
@@ -171,8 +317,8 @@ ksort(caddr_t v, int n, int s, int (*f)())
for (g = n / 2; g > 0; g /= 2) {
for (i = g; i < n; i++) {
for (j = i - g; j >= 0 &&
- (*f)(v + j * s, v + (j + g) * s) == 1;
- j -= g) {
+ (*f)(v + j * s, v + (j + g) * s) == 1;
+ j -= g) {
p1 = (void *)(v + j * s);
p2 = (void *)(v + (j + g) * s);
for (ii = 0; ii < s / 4; ii++) {
@@ -215,3 +361,1347 @@ cmp2acls(void *a, void *b)
/* Totally equal */
return (0);
}
+
+/*ARGSUSED*/
+static void *
+cacl_realloc(void *ptr, size_t size, size_t new_size)
+{
+#if defined(_KERNEL)
+ void *tmp;
+
+ tmp = kmem_alloc(new_size, KM_SLEEP);
+ (void) memcpy(tmp, ptr, (size < new_size) ? size : new_size);
+ kmem_free(ptr, size);
+ return (tmp);
+#else
+ return (realloc(ptr, new_size));
+#endif
+}
+
+static int
+cacl_malloc(void **ptr, size_t size)
+{
+#if defined(_KERNEL)
+ *ptr = kmem_zalloc(size, KM_SLEEP);
+ return (0);
+#else
+ *ptr = calloc(1, size);
+ if (*ptr == NULL)
+ return (errno);
+
+ return (0);
+#endif
+}
+
+/*ARGSUSED*/
+static void
+cacl_free(void *ptr, size_t size)
+{
+#if defined(_KERNEL)
+ kmem_free(ptr, size);
+#else
+ free(ptr);
+#endif
+}
+
+acl_t *
+acl_alloc(enum acl_type type)
+{
+ acl_t *aclp;
+
+ if (cacl_malloc((void **)&aclp, sizeof (acl_t)) != 0)
+ return (NULL);
+
+ aclp->acl_aclp = NULL;
+ aclp->acl_cnt = 0;
+
+ switch (type) {
+ case ACE_T:
+ aclp->acl_type = ACE_T;
+ aclp->acl_entry_size = sizeof (ace_t);
+ break;
+ case ACLENT_T:
+ aclp->acl_type = ACLENT_T;
+ aclp->acl_entry_size = sizeof (aclent_t);
+ break;
+ default:
+ acl_free(aclp);
+ aclp = NULL;
+ }
+ return (aclp);
+}
+
+/*
+ * Free acl_t structure
+ */
+void
+acl_free(acl_t *aclp)
+{
+ int acl_size;
+
+ if (aclp == NULL)
+ return;
+
+ if (aclp->acl_aclp) {
+ acl_size = aclp->acl_cnt * aclp->acl_entry_size;
+ cacl_free(aclp->acl_aclp, acl_size);
+ }
+
+ cacl_free(aclp, sizeof (acl_t));
+}
+
+static uint32_t
+access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
+{
+ uint32_t access_mask = 0;
+ int acl_produce;
+ int synchronize_set = 0, write_owner_set = 0;
+ int delete_set = 0, write_attrs_set = 0;
+ int read_named_set = 0, write_named_set = 0;
+
+ acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
+ ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
+ ACL_WRITE_ATTRS_WRITER_SET_DENY);
+
+ if (isallow) {
+ synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
+ write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
+ delete_set = ACL_DELETE_SET_ALLOW;
+ if (hasreadperm)
+ read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
+ if (haswriteperm)
+ write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
+ if (isowner)
+ write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
+ else if (haswriteperm)
+ write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
+ } else {
+
+ synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
+ write_owner_set = ACL_WRITE_OWNER_SET_DENY;
+ delete_set = ACL_DELETE_SET_DENY;
+ if (hasreadperm)
+ read_named_set = ACL_READ_NAMED_READER_SET_DENY;
+ if (haswriteperm)
+ write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
+ if (isowner)
+ write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
+ else if (haswriteperm)
+ write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
+ else
+ /*
+ * If the entity is not the owner and does not
+ * have write permissions ACE_WRITE_ATTRIBUTES will
+ * always go in the DENY ACE.
+ */
+ access_mask |= ACE_WRITE_ATTRIBUTES;
+ }
+
+ if (acl_produce & synchronize_set)
+ access_mask |= ACE_SYNCHRONIZE;
+ if (acl_produce & write_owner_set)
+ access_mask |= ACE_WRITE_OWNER;
+ if (acl_produce & delete_set)
+ access_mask |= ACE_DELETE;
+ if (acl_produce & write_attrs_set)
+ access_mask |= ACE_WRITE_ATTRIBUTES;
+ if (acl_produce & read_named_set)
+ access_mask |= ACE_READ_NAMED_ATTRS;
+ if (acl_produce & write_named_set)
+ access_mask |= ACE_WRITE_NAMED_ATTRS;
+
+ return (access_mask);
+}
+
+/*
+ * Given an mode_t, convert it into an access_mask as used
+ * by nfsace, assuming aclent_t -> nfsace semantics.
+ */
+static uint32_t
+mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
+{
+ uint32_t access = 0;
+ int haswriteperm = 0;
+ int hasreadperm = 0;
+
+ if (isallow) {
+ haswriteperm = (mode & S_IWOTH);
+ hasreadperm = (mode & S_IROTH);
+ } else {
+ haswriteperm = !(mode & S_IWOTH);
+ hasreadperm = !(mode & S_IROTH);
+ }
+
+ /*
+ * The following call takes care of correctly setting the following
+ * mask bits in the access_mask:
+ * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
+ * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
+ */
+ access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
+
+ if (isallow) {
+ access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
+ if (isowner)
+ access |= ACE_WRITE_ACL;
+ } else {
+ if (! isowner)
+ access |= ACE_WRITE_ACL;
+ }
+
+ /* read */
+ if (mode & S_IROTH) {
+ access |= ACE_READ_DATA;
+ }
+ /* write */
+ if (mode & S_IWOTH) {
+ access |= ACE_WRITE_DATA |
+ ACE_APPEND_DATA;
+ if (isdir)
+ access |= ACE_DELETE_CHILD;
+ }
+ /* exec */
+ if (mode & 01) {
+ access |= ACE_EXECUTE;
+ }
+
+ return (access);
+}
+
+/*
+ * Given an nfsace (presumably an ALLOW entry), make a
+ * corresponding DENY entry at the address given.
+ */
+static void
+ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
+{
+ (void) memcpy(deny, allow, sizeof (ace_t));
+
+ deny->a_who = allow->a_who;
+
+ deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
+ deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
+ if (isdir)
+ deny->a_access_mask ^= ACE_DELETE_CHILD;
+
+ deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
+ ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
+ ACE_WRITE_NAMED_ATTRS);
+ deny->a_access_mask |= access_mask_set((allow->a_access_mask &
+ ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
+ B_FALSE);
+}
+/*
+ * Make an initial pass over an array of aclent_t's. Gather
+ * information such as an ACL_MASK (if any), number of users,
+ * number of groups, and whether the array needs to be sorted.
+ */
+static int
+ln_aent_preprocess(aclent_t *aclent, int n,
+ int *hasmask, mode_t *mask,
+ int *numuser, int *numgroup, int *needsort)
+{
+ int error = 0;
+ int i;
+ int curtype = 0;
+
+ *hasmask = 0;
+ *mask = 07;
+ *needsort = 0;
+ *numuser = 0;
+ *numgroup = 0;
+
+ for (i = 0; i < n; i++) {
+ if (aclent[i].a_type < curtype)
+ *needsort = 1;
+ else if (aclent[i].a_type > curtype)
+ curtype = aclent[i].a_type;
+ if (aclent[i].a_type & USER)
+ (*numuser)++;
+ if (aclent[i].a_type & (GROUP | GROUP_OBJ))
+ (*numgroup)++;
+ if (aclent[i].a_type & CLASS_OBJ) {
+ if (*hasmask) {
+ error = EINVAL;
+ goto out;
+ } else {
+ *hasmask = 1;
+ *mask = aclent[i].a_perm;
+ }
+ }
+ }
+
+ if ((! *hasmask) && (*numuser + *numgroup > 1)) {
+ error = EINVAL;
+ goto out;
+ }
+
+out:
+ return (error);
+}
+
+/*
+ * Convert an array of aclent_t into an array of nfsace entries,
+ * following POSIX draft -> nfsv4 conversion semantics as outlined in
+ * the IETF draft.
+ */
+static int
+ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
+{
+ int error = 0;
+ mode_t mask;
+ int numuser, numgroup, needsort;
+ int resultsize = 0;
+ int i, groupi = 0, skip;
+ ace_t *acep, *result = NULL;
+ int hasmask;
+
+ error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
+ &numuser, &numgroup, &needsort);
+ if (error != 0)
+ goto out;
+
+ /* allow + deny for each aclent */
+ resultsize = n * 2;
+ if (hasmask) {
+ /*
+ * stick extra deny on the group_obj and on each
+ * user|group for the mask (the group_obj was added
+ * into the count for numgroup)
+ */
+ resultsize += numuser + numgroup;
+ /* ... and don't count the mask itself */
+ resultsize -= 2;
+ }
+
+ /* sort the source if necessary */
+ if (needsort)
+ ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
+
+ if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0)
+ goto out;
+
+ acep = result;
+
+ for (i = 0; i < n; i++) {
+ /*
+ * don't process CLASS_OBJ (mask); mask was grabbed in
+ * ln_aent_preprocess()
+ */
+ if (aclent[i].a_type & CLASS_OBJ)
+ continue;
+
+ /* If we need an ACL_MASK emulator, prepend it now */
+ if ((hasmask) &&
+ (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
+ acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
+ acep->a_flags = 0;
+ if (aclent[i].a_type & GROUP_OBJ) {
+ acep->a_who = (uid_t)-1;
+ acep->a_flags |=
+ (ACE_IDENTIFIER_GROUP|ACE_GROUP);
+ } else if (aclent[i].a_type & USER) {
+ acep->a_who = aclent[i].a_id;
+ } else {
+ acep->a_who = aclent[i].a_id;
+ acep->a_flags |= ACE_IDENTIFIER_GROUP;
+ }
+ if (aclent[i].a_type & ACL_DEFAULT) {
+ acep->a_flags |= ACE_INHERIT_ONLY_ACE |
+ ACE_FILE_INHERIT_ACE |
+ ACE_DIRECTORY_INHERIT_ACE;
+ }
+ /*
+ * Set the access mask for the prepended deny
+ * ace. To do this, we invert the mask (found
+ * in ln_aent_preprocess()) then convert it to an
+ * DENY ace access_mask.
+ */
+ acep->a_access_mask = mode_to_ace_access((mask ^ 07),
+ isdir, 0, 0);
+ acep += 1;
+ }
+
+ /* handle a_perm -> access_mask */
+ acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
+ isdir, aclent[i].a_type & USER_OBJ, 1);
+
+ /* emulate a default aclent */
+ if (aclent[i].a_type & ACL_DEFAULT) {
+ acep->a_flags |= ACE_INHERIT_ONLY_ACE |
+ ACE_FILE_INHERIT_ACE |
+ ACE_DIRECTORY_INHERIT_ACE;
+ }
+
+ /*
+ * handle a_perm and a_id
+ *
+ * this must be done last, since it involves the
+ * corresponding deny aces, which are handled
+ * differently for each different a_type.
+ */
+ if (aclent[i].a_type & USER_OBJ) {
+ acep->a_who = (uid_t)-1;
+ acep->a_flags |= ACE_OWNER;
+ ace_make_deny(acep, acep + 1, isdir, B_TRUE);
+ acep += 2;
+ } else if (aclent[i].a_type & USER) {
+ acep->a_who = aclent[i].a_id;
+ ace_make_deny(acep, acep + 1, isdir, B_FALSE);
+ acep += 2;
+ } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
+ if (aclent[i].a_type & GROUP_OBJ) {
+ acep->a_who = (uid_t)-1;
+ acep->a_flags |= ACE_GROUP;
+ } else {
+ acep->a_who = aclent[i].a_id;
+ }
+ acep->a_flags |= ACE_IDENTIFIER_GROUP;
+ /*
+ * Set the corresponding deny for the group ace.
+ *
+ * The deny aces go after all of the groups, unlike
+ * everything else, where they immediately follow
+ * the allow ace.
+ *
+ * We calculate "skip", the number of slots to
+ * skip ahead for the deny ace, here.
+ *
+ * The pattern is:
+ * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
+ * thus, skip is
+ * (2 * numgroup) - 1 - groupi
+ * (2 * numgroup) to account for MD + A
+ * - 1 to account for the fact that we're on the
+ * access (A), not the mask (MD)
+ * - groupi to account for the fact that we have
+ * passed up groupi number of MD's.
+ */
+ skip = (2 * numgroup) - 1 - groupi;
+ ace_make_deny(acep, acep + skip, isdir, B_FALSE);
+ /*
+ * If we just did the last group, skip acep past
+ * all of the denies; else, just move ahead one.
+ */
+ if (++groupi >= numgroup)
+ acep += numgroup + 1;
+ else
+ acep += 1;
+ } else if (aclent[i].a_type & OTHER_OBJ) {
+ acep->a_who = (uid_t)-1;
+ acep->a_flags |= ACE_EVERYONE;
+ ace_make_deny(acep, acep + 1, isdir, B_FALSE);
+ acep += 2;
+ } else {
+ error = EINVAL;
+ goto out;
+ }
+ }
+
+ *acepp = result;
+ *rescount = resultsize;
+
+out:
+ if (error != 0) {
+ if ((result != NULL) && (resultsize > 0)) {
+ cacl_free(result, resultsize * sizeof (ace_t));
+ }
+ }
+
+ return (error);
+}
+
+static int
+convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
+ ace_t **retacep, int *retacecnt)
+{
+ ace_t *acep;
+ ace_t *dfacep;
+ int acecnt = 0;
+ int dfacecnt = 0;
+ int dfaclstart = 0;
+ int dfaclcnt = 0;
+ aclent_t *aclp;
+ int i;
+ int error;
+ int acesz, dfacesz;
+
+ ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
+
+ for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
+ if (aclp->a_type & ACL_DEFAULT)
+ break;
+ }
+
+ if (i < aclcnt) {
+ dfaclstart = i;
+ dfaclcnt = aclcnt - i;
+ }
+
+ if (dfaclcnt && isdir == 0) {
+ return (EINVAL);
+ }
+
+ error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
+ if (error)
+ return (error);
+
+ if (dfaclcnt) {
+ error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
+ &dfacep, &dfacecnt, isdir);
+ if (error) {
+ if (acep) {
+ cacl_free(acep, acecnt * sizeof (ace_t));
+ }
+ return (error);
+ }
+ }
+
+ if (dfacecnt != 0) {
+ acesz = sizeof (ace_t) * acecnt;
+ dfacesz = sizeof (ace_t) * dfacecnt;
+ acep = cacl_realloc(acep, acesz, acesz + dfacesz);
+ if (acep == NULL)
+ return (ENOMEM);
+ if (dfaclcnt) {
+ (void) memcpy(acep + acecnt, dfacep, dfacesz);
+ }
+ }
+ if (dfaclcnt)
+ cacl_free(dfacep, dfacecnt * sizeof (ace_t));
+
+ *retacecnt = acecnt + dfacecnt;
+ *retacep = acep;
+ return (0);
+}
+
+static int
+ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
+{
+ int error = 0;
+ o_mode_t mode = 0;
+ uint32_t bits, wantbits;
+
+ /* read */
+ if (mask & ACE_READ_DATA)
+ mode |= S_IROTH;
+
+ /* write */
+ wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
+ if (isdir)
+ wantbits |= ACE_DELETE_CHILD;
+ bits = mask & wantbits;
+ if (bits != 0) {
+ if (bits != wantbits) {
+ error = ENOTSUP;
+ goto out;
+ }
+ mode |= S_IWOTH;
+ }
+
+ /* exec */
+ if (mask & ACE_EXECUTE) {
+ mode |= S_IXOTH;
+ }
+
+ *modep = mode;
+
+out:
+ return (error);
+}
+
+static void
+acevals_init(acevals_t *vals, uid_t key)
+{
+ bzero(vals, sizeof (*vals));
+ vals->allowed = ACE_MASK_UNDEFINED;
+ vals->denied = ACE_MASK_UNDEFINED;
+ vals->mask = ACE_MASK_UNDEFINED;
+ vals->key = key;
+}
+
+static void
+ace_list_init(ace_list_t *al, int dfacl_flag)
+{
+ acevals_init(&al->user_obj, NULL);
+ acevals_init(&al->group_obj, NULL);
+ acevals_init(&al->other_obj, NULL);
+ al->numusers = 0;
+ al->numgroups = 0;
+ al->acl_mask = 0;
+ al->hasmask = 0;
+ al->state = ace_unused;
+ al->seen = 0;
+ al->dfacl_flag = dfacl_flag;
+}
+
+/*
+ * Find or create an acevals holder for a given id and avl tree.
+ *
+ * Note that only one thread will ever touch these avl trees, so
+ * there is no need for locking.
+ */
+static acevals_t *
+acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
+{
+ acevals_t key, *rc;
+ avl_index_t where;
+
+ key.key = ace->a_who;
+ rc = avl_find(avl, &key, &where);
+ if (rc != NULL)
+ return (rc);
+
+ /* this memory is freed by ln_ace_to_aent()->ace_list_free() */
+ if (cacl_malloc((void **)&rc, sizeof (acevals_t)) != 0)
+ return (NULL);
+
+ acevals_init(rc, ace->a_who);
+ avl_insert(avl, rc, where);
+ (*num)++;
+
+ return (rc);
+}
+
+static int
+access_mask_check(ace_t *acep, int mask_bit, int isowner)
+{
+ int set_deny, err_deny;
+ int set_allow, err_allow;
+ int acl_consume;
+ int haswriteperm, hasreadperm;
+
+ if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
+ haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
+ hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
+ } else {
+ haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
+ hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
+ }
+
+ acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
+ ACL_DELETE_ERR_DENY |
+ ACL_WRITE_OWNER_ERR_DENY |
+ ACL_WRITE_OWNER_ERR_ALLOW |
+ ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
+ ACL_WRITE_ATTRS_OWNER_ERR_DENY |
+ ACL_WRITE_ATTRS_WRITER_SET_DENY |
+ ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
+ ACL_WRITE_NAMED_WRITER_ERR_DENY |
+ ACL_READ_NAMED_READER_ERR_DENY);
+
+ if (mask_bit == ACE_SYNCHRONIZE) {
+ set_deny = ACL_SYNCHRONIZE_SET_DENY;
+ err_deny = ACL_SYNCHRONIZE_ERR_DENY;
+ set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
+ err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
+ } else if (mask_bit == ACE_WRITE_OWNER) {
+ set_deny = ACL_WRITE_OWNER_SET_DENY;
+ err_deny = ACL_WRITE_OWNER_ERR_DENY;
+ set_allow = ACL_WRITE_OWNER_SET_ALLOW;
+ err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
+ } else if (mask_bit == ACE_DELETE) {
+ set_deny = ACL_DELETE_SET_DENY;
+ err_deny = ACL_DELETE_ERR_DENY;
+ set_allow = ACL_DELETE_SET_ALLOW;
+ err_allow = ACL_DELETE_ERR_ALLOW;
+ } else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
+ if (isowner) {
+ set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
+ err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY;
+ set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
+ err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
+ } else if (haswriteperm) {
+ set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
+ err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY;
+ set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
+ err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
+ } else {
+ if ((acep->a_access_mask & mask_bit) &&
+ (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
+ return (ENOTSUP);
+ }
+ return (0);
+ }
+ } else if (mask_bit == ACE_READ_NAMED_ATTRS) {
+ if (!hasreadperm)
+ return (0);
+
+ set_deny = ACL_READ_NAMED_READER_SET_DENY;
+ err_deny = ACL_READ_NAMED_READER_ERR_DENY;
+ set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
+ err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
+ } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
+ if (!haswriteperm)
+ return (0);
+
+ set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
+ err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
+ set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
+ err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
+ } else {
+ return (EINVAL);
+ }
+
+ if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
+ if (acl_consume & set_deny) {
+ if (!(acep->a_access_mask & mask_bit)) {
+ return (ENOTSUP);
+ }
+ } else if (acl_consume & err_deny) {
+ if (acep->a_access_mask & mask_bit) {
+ return (ENOTSUP);
+ }
+ }
+ } else {
+ /* ACE_ACCESS_ALLOWED_ACE_TYPE */
+ if (acl_consume & set_allow) {
+ if (!(acep->a_access_mask & mask_bit)) {
+ return (ENOTSUP);
+ }
+ } else if (acl_consume & err_allow) {
+ if (acep->a_access_mask & mask_bit) {
+ return (ENOTSUP);
+ }
+ }
+ }
+ return (0);
+}
+
+static int
+ace_to_aent_legal(ace_t *acep)
+{
+ int error = 0;
+ int isowner;
+
+ /* only ALLOW or DENY */
+ if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
+ (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /* check for invalid flags */
+ if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ /* some flags are illegal */
+ if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
+ ACE_FAILED_ACCESS_ACE_FLAG |
+ ACE_NO_PROPAGATE_INHERIT_ACE)) {
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /* check for invalid masks */
+ if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ if ((acep->a_flags & ACE_OWNER)) {
+ isowner = 1;
+ } else {
+ isowner = 0;
+ }
+
+ error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
+ if (error)
+ goto out;
+
+ error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
+ if (error)
+ goto out;
+
+ error = access_mask_check(acep, ACE_DELETE, isowner);
+ if (error)
+ goto out;
+
+ error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
+ if (error)
+ goto out;
+
+ error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
+ if (error)
+ goto out;
+
+ error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
+ if (error)
+ goto out;
+
+ /* more detailed checking of masks */
+ if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
+ error = ENOTSUP;
+ goto out;
+ }
+ if ((acep->a_access_mask & ACE_WRITE_DATA) &&
+ (! (acep->a_access_mask & ACE_APPEND_DATA))) {
+ error = ENOTSUP;
+ goto out;
+ }
+ if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
+ (acep->a_access_mask & ACE_APPEND_DATA)) {
+ error = ENOTSUP;
+ goto out;
+ }
+ }
+
+ /* ACL enforcement */
+ if ((acep->a_access_mask & ACE_READ_ACL) &&
+ (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
+ error = ENOTSUP;
+ goto out;
+ }
+ if (acep->a_access_mask & ACE_WRITE_ACL) {
+ if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
+ (isowner)) {
+ error = ENOTSUP;
+ goto out;
+ }
+ if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
+ (! isowner)) {
+ error = ENOTSUP;
+ goto out;
+ }
+ }
+
+out:
+ return (error);
+}
+
+static int
+ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
+{
+ /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
+ if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
+ (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
+ return (ENOTSUP);
+ }
+
+ return (ace_mask_to_mode(mask, modep, isdir));
+}
+
+static int
+acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
+ uid_t owner, gid_t group, int isdir)
+{
+ int error;
+ uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
+
+ if (isdir)
+ flips |= ACE_DELETE_CHILD;
+ if (vals->allowed != (vals->denied ^ flips)) {
+ error = ENOTSUP;
+ goto out;
+ }
+ if ((list->hasmask) && (list->acl_mask != vals->mask) &&
+ (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
+ error = ENOTSUP;
+ goto out;
+ }
+ error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
+ if (error != 0)
+ goto out;
+ dest->a_type = vals->aent_type;
+ if (dest->a_type & (USER | GROUP)) {
+ dest->a_id = vals->key;
+ } else if (dest->a_type & USER_OBJ) {
+ dest->a_id = owner;
+ } else if (dest->a_type & GROUP_OBJ) {
+ dest->a_id = group;
+ } else if (dest->a_type & OTHER_OBJ) {
+ dest->a_id = 0;
+ } else {
+ error = EINVAL;
+ goto out;
+ }
+
+out:
+ return (error);
+}
+
+
+static int
+ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
+ uid_t owner, gid_t group, int isdir)
+{
+ int error = 0;
+ aclent_t *aent, *result = NULL;
+ acevals_t *vals;
+ int resultcount;
+
+ if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
+ (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
+ error = ENOTSUP;
+ goto out;
+ }
+ if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
+ error = ENOTSUP;
+ goto out;
+ }
+
+ resultcount = 3 + list->numusers + list->numgroups;
+ /*
+ * This must be the same condition as below, when we add the CLASS_OBJ
+ * (aka ACL mask)
+ */
+ if ((list->hasmask) || (! list->dfacl_flag))
+ resultcount += 1;
+
+ if (cacl_malloc((void **)&result,
+ resultcount * sizeof (aclent_t)) != 0) {
+ error = ENOMEM;
+ goto out;
+ }
+ aent = result;
+
+ /* USER_OBJ */
+ if (!(list->user_obj.aent_type & USER_OBJ)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
+ isdir);
+
+ if (error != 0)
+ goto out;
+ ++aent;
+ /* USER */
+ vals = NULL;
+ for (vals = avl_first(&list->user); vals != NULL;
+ vals = AVL_NEXT(&list->user, vals)) {
+ if (!(vals->aent_type & USER)) {
+ error = EINVAL;
+ goto out;
+ }
+ error = acevals_to_aent(vals, aent, list, owner, group,
+ isdir);
+ if (error != 0)
+ goto out;
+ ++aent;
+ }
+ /* GROUP_OBJ */
+ if (!(list->group_obj.aent_type & GROUP_OBJ)) {
+ error = EINVAL;
+ goto out;
+ }
+ error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
+ isdir);
+ if (error != 0)
+ goto out;
+ ++aent;
+ /* GROUP */
+ vals = NULL;
+ for (vals = avl_first(&list->group); vals != NULL;
+ vals = AVL_NEXT(&list->group, vals)) {
+ if (!(vals->aent_type & GROUP)) {
+ error = EINVAL;
+ goto out;
+ }
+ error = acevals_to_aent(vals, aent, list, owner, group,
+ isdir);
+ if (error != 0)
+ goto out;
+ ++aent;
+ }
+ /*
+ * CLASS_OBJ (aka ACL_MASK)
+ *
+ * An ACL_MASK is not fabricated if the ACL is a default ACL.
+ * This is to follow UFS's behavior.
+ */
+ if ((list->hasmask) || (! list->dfacl_flag)) {
+ if (list->hasmask) {
+ uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
+ if (isdir)
+ flips |= ACE_DELETE_CHILD;
+ error = ace_mask_to_mode(list->acl_mask ^ flips,
+ &aent->a_perm, isdir);
+ if (error != 0)
+ goto out;
+ } else {
+ /* fabricate the ACL_MASK from the group permissions */
+ error = ace_mask_to_mode(list->group_obj.allowed,
+ &aent->a_perm, isdir);
+ if (error != 0)
+ goto out;
+ }
+ aent->a_id = 0;
+ aent->a_type = CLASS_OBJ | list->dfacl_flag;
+ ++aent;
+ }
+ /* OTHER_OBJ */
+ if (!(list->other_obj.aent_type & OTHER_OBJ)) {
+ error = EINVAL;
+ goto out;
+ }
+ error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
+ isdir);
+ if (error != 0)
+ goto out;
+ ++aent;
+
+ *aclentp = result;
+ *aclcnt = resultcount;
+
+out:
+ if (error != 0) {
+ if (result != NULL)
+ cacl_free(result, resultcount * sizeof (aclent_t));
+ }
+
+ return (error);
+}
+
+
+/*
+ * free all data associated with an ace_list
+ */
+static void
+ace_list_free(ace_list_t *al)
+{
+ acevals_t *node;
+ void *cookie;
+
+ if (al == NULL)
+ return;
+
+ cookie = NULL;
+ while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
+ cacl_free(node, sizeof (acevals_t));
+ cookie = NULL;
+ while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
+ cacl_free(node, sizeof (acevals_t));
+
+ avl_destroy(&al->user);
+ avl_destroy(&al->group);
+
+ /* free the container itself */
+ cacl_free(al, sizeof (ace_list_t));
+}
+
+static int
+acevals_compare(const void *va, const void *vb)
+{
+ const acevals_t *a = va, *b = vb;
+
+ if (a->key == b->key)
+ return (0);
+
+ if (a->key > b->key)
+ return (1);
+
+ else
+ return (-1);
+}
+
+/*
+ * Convert a list of ace_t entries to equivalent regular and default
+ * aclent_t lists. Return error (ENOTSUP) when conversion is not possible.
+ */
+static int
+ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
+ aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
+ int isdir)
+{
+ int error = 0;
+ ace_t *acep;
+ uint32_t bits;
+ int i;
+ ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
+ acevals_t *vals;
+
+ *aclentp = NULL;
+ *aclcnt = 0;
+ *dfaclentp = NULL;
+ *dfaclcnt = 0;
+
+ /* we need at least user_obj, group_obj, and other_obj */
+ if (n < 6) {
+ error = ENOTSUP;
+ goto out;
+ }
+ if (ace == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ error = cacl_malloc((void **)&normacl, sizeof (ace_list_t));
+ if (error != 0)
+ goto out;
+
+ avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
+ offsetof(acevals_t, avl));
+ avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
+ offsetof(acevals_t, avl));
+
+ ace_list_init(normacl, 0);
+
+ error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t));
+ if (error != 0)
+ goto out;
+
+ avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
+ offsetof(acevals_t, avl));
+ avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
+ offsetof(acevals_t, avl));
+ ace_list_init(dfacl, ACL_DEFAULT);
+
+ /* process every ace_t... */
+ for (i = 0; i < n; i++) {
+ acep = &ace[i];
+
+ /* rule out certain cases quickly */
+ error = ace_to_aent_legal(acep);
+ if (error != 0)
+ goto out;
+
+ /*
+ * Turn off these bits in order to not have to worry about
+ * them when doing the checks for compliments.
+ */
+ acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
+ ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
+ ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
+
+ /* see if this should be a regular or default acl */
+ bits = acep->a_flags &
+ (ACE_INHERIT_ONLY_ACE |
+ ACE_FILE_INHERIT_ACE |
+ ACE_DIRECTORY_INHERIT_ACE);
+ if (bits != 0) {
+ /* all or nothing on these inherit bits */
+ if (bits != (ACE_INHERIT_ONLY_ACE |
+ ACE_FILE_INHERIT_ACE |
+ ACE_DIRECTORY_INHERIT_ACE)) {
+ error = ENOTSUP;
+ goto out;
+ }
+ acl = dfacl;
+ } else {
+ acl = normacl;
+ }
+
+ if ((acep->a_flags & ACE_OWNER)) {
+ if (acl->state > ace_user_obj) {
+ error = ENOTSUP;
+ goto out;
+ }
+ acl->state = ace_user_obj;
+ acl->seen |= USER_OBJ;
+ vals = &acl->user_obj;
+ vals->aent_type = USER_OBJ | acl->dfacl_flag;
+ } else if ((acep->a_flags & ACE_EVERYONE)) {
+ acl->state = ace_other_obj;
+ acl->seen |= OTHER_OBJ;
+ vals = &acl->other_obj;
+ vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
+ } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
+ if (acl->state > ace_group) {
+ error = ENOTSUP;
+ goto out;
+ }
+ if ((acep->a_flags & ACE_GROUP)) {
+ acl->seen |= GROUP_OBJ;
+ vals = &acl->group_obj;
+ vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
+ } else {
+ acl->seen |= GROUP;
+ vals = acevals_find(acep, &acl->group,
+ &acl->numgroups);
+ if (vals == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ vals->aent_type = GROUP | acl->dfacl_flag;
+ }
+ acl->state = ace_group;
+ } else {
+ if (acl->state > ace_user) {
+ error = ENOTSUP;
+ goto out;
+ }
+ acl->state = ace_user;
+ acl->seen |= USER;
+ vals = acevals_find(acep, &acl->user,
+ &acl->numusers);
+ if (vals == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ vals->aent_type = USER | acl->dfacl_flag;
+ }
+
+ if (!(acl->state > ace_unused)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ /* no more than one allowed per aclent_t */
+ if (vals->allowed != ACE_MASK_UNDEFINED) {
+ error = ENOTSUP;
+ goto out;
+ }
+ vals->allowed = acep->a_access_mask;
+ } else {
+ /*
+ * it's a DENY; if there was a previous DENY, it
+ * must have been an ACL_MASK.
+ */
+ if (vals->denied != ACE_MASK_UNDEFINED) {
+ /* ACL_MASK is for USER and GROUP only */
+ if ((acl->state != ace_user) &&
+ (acl->state != ace_group)) {
+ error = ENOTSUP;
+ goto out;
+ }
+
+ if (! acl->hasmask) {
+ acl->hasmask = 1;
+ acl->acl_mask = vals->denied;
+ /* check for mismatched ACL_MASK emulations */
+ } else if (acl->acl_mask != vals->denied) {
+ error = ENOTSUP;
+ goto out;
+ }
+ vals->mask = vals->denied;
+ }
+ vals->denied = acep->a_access_mask;
+ }
+ }
+
+ /* done collating; produce the aclent_t lists */
+ if (normacl->state != ace_unused) {
+ error = ace_list_to_aent(normacl, aclentp, aclcnt,
+ owner, group, isdir);
+ if (error != 0) {
+ goto out;
+ }
+ }
+ if (dfacl->state != ace_unused) {
+ error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
+ owner, group, isdir);
+ if (error != 0) {
+ goto out;
+ }
+ }
+
+out:
+ if (normacl != NULL)
+ ace_list_free(normacl);
+ if (dfacl != NULL)
+ ace_list_free(dfacl);
+
+ return (error);
+}
+
+static int
+convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir,
+ uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
+{
+ int error = 0;
+ aclent_t *aclentp, *dfaclentp;
+ int aclcnt, dfaclcnt;
+ int aclsz, dfaclsz;
+
+ error = ln_ace_to_aent(acebufp, acecnt, owner, group,
+ &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
+
+ if (error)
+ return (error);
+
+
+ if (dfaclcnt != 0) {
+ /*
+ * Slap aclentp and dfaclentp into a single array.
+ */
+ aclsz = sizeof (aclent_t) * aclcnt;
+ dfaclsz = sizeof (aclent_t) * dfaclcnt;
+ aclentp = cacl_realloc(aclentp, aclsz, aclsz + dfaclsz);
+ if (aclentp != NULL) {
+ (void) memcpy(aclentp + aclcnt, dfaclentp, dfaclsz);
+ } else {
+ error = ENOMEM;
+ }
+ }
+
+ if (aclentp) {
+ *retaclentp = aclentp;
+ *retaclcnt = aclcnt + dfaclcnt;
+ }
+
+ if (dfaclentp)
+ cacl_free(dfaclentp, dfaclsz);
+
+ return (error);
+}
+
+
+int
+acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner,
+ gid_t group)
+{
+ int aclcnt;
+ void *acldata;
+ int error;
+
+ /*
+ * See if we need to translate
+ */
+ if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
+ (target_flavor == _ACL_ACLENT_ENABLED &&
+ aclp->acl_type == ACLENT_T))
+ return (0);
+
+ if (target_flavor == -1) {
+ error = EINVAL;
+ goto out;
+ }
+
+ if (target_flavor == _ACL_ACE_ENABLED &&
+ aclp->acl_type == ACLENT_T) {
+ error = convert_aent_to_ace(aclp->acl_aclp,
+ aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
+ if (error)
+ goto out;
+
+ } else if (target_flavor == _ACL_ACLENT_ENABLED &&
+ aclp->acl_type == ACE_T) {
+ error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
+ isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
+ if (error)
+ goto out;
+ } else {
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /*
+ * replace old acl with newly translated acl
+ */
+ cacl_free(aclp->acl_aclp, aclp->acl_cnt * aclp->acl_entry_size);
+ aclp->acl_aclp = acldata;
+ aclp->acl_cnt = aclcnt;
+ if (target_flavor == _ACL_ACE_ENABLED) {
+ aclp->acl_type = ACE_T;
+ aclp->acl_entry_size = sizeof (ace_t);
+ } else {
+ aclp->acl_type = ACLENT_T;
+ aclp->acl_entry_size = sizeof (aclent_t);
+ }
+ return (0);
+
+out:
+
+#if !defined(_KERNEL)
+ errno = error;
+ return (-1);
+#else
+ return (error);
+#endif
+}
diff --git a/usr/src/common/acl/acl_common.h b/usr/src/common/acl/acl_common.h
index 2227ad77ea..84bd04f52f 100644
--- a/usr/src/common/acl/acl_common.h
+++ b/usr/src/common/acl/acl_common.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,12 +19,12 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#ifndef _ACL_ACL_UTILS_H
-#define _ACL_ACL_UTILS_H
+#ifndef _ACL_COMMON_H
+#define _ACL_COMMON_H
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -34,7 +33,7 @@
#include <sys/acl.h>
#include <sys/stat.h>
-#ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
#endif
@@ -42,15 +41,21 @@ extern ace_t trivial_acl[6];
extern int acltrivial(const char *);
extern void adjust_ace_pair(ace_t *pair, mode_t mode);
+extern void adjust_ace_pair_common(void *, size_t, size_t, mode_t);
extern int ace_trivial(ace_t *acep, int aclcnt);
+extern int ace_trivial_common(void *, int,
+ uint64_t (*walk)(void *, uint64_t, int aclcnt, uint16_t *, uint16_t *,
+ uint32_t *mask));
+extern acl_t *acl_alloc(acl_type_t);
+extern void acl_free(acl_t *aclp);
+extern int acl_translate(acl_t *aclp, int target_flavor,
+ int isdir, uid_t owner, gid_t group);
void ksort(caddr_t v, int n, int s, int (*f)());
int cmp2acls(void *a, void *b);
-
-
-#ifdef __cplusplus
+#ifdef __cplusplus
}
#endif
-#endif /* _ACL_ACL_UTILS_H */
+#endif /* _ACL_COMMON_H */
diff --git a/usr/src/common/smbsrv/smb_common_door_decode.c b/usr/src/common/smbsrv/smb_common_door_decode.c
new file mode 100644
index 0000000000..907c29bd23
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_common_door_decode.c
@@ -0,0 +1,387 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Provides encode/decode routines for all door servers/clients.
+ */
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#else
+#include <string.h>
+#endif
+#include <sys/errno.h>
+#ifndef _KERNEL
+#include <errno.h>
+#endif
+
+#include <smbsrv/alloc.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/wintypes.h>
+
+
+smb_dr_ctx_t *
+smb_dr_decode_start(char *ptr, int size)
+{
+ smb_dr_ctx_t *ctx = MEM_MALLOC("CommonDoor", sizeof (smb_dr_ctx_t));
+ if (ctx) {
+ ctx->start_ptr = ctx->ptr = ptr;
+ ctx->end_ptr = ptr + size;
+ ctx->status = 0;
+ }
+ return (ctx);
+}
+
+int
+smb_dr_decode_finish(smb_dr_ctx_t *ctx)
+{
+ int status = ctx->status;
+ if (status == 0 && ctx->ptr != ctx->end_ptr) {
+ status = ENOTEMPTY;
+ }
+ MEM_FREE("CommonDoor", ctx);
+ return (status);
+}
+
+smb_dr_ctx_t *
+smb_dr_encode_start(char *ptr, int size)
+{
+ smb_dr_ctx_t *ctx = MEM_MALLOC("CommonDoor", sizeof (smb_dr_ctx_t));
+ if (ctx) {
+ ctx->start_ptr = ctx->ptr = ptr;
+ ctx->end_ptr = ptr + size;
+ ctx->status = 0;
+ }
+ return (ctx);
+}
+
+int
+smb_dr_encode_finish(smb_dr_ctx_t *ctx, unsigned int *used)
+{
+ int status = ctx->status;
+ if (status == 0) {
+ if (ctx->ptr < ctx->end_ptr) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ *used = ctx->ptr - ctx->start_ptr;
+ }
+ else
+ status = ENOSPC;
+ }
+
+ MEM_FREE("CommonDoor", ctx);
+ return (status);
+}
+
+DWORD
+smb_dr_get_dword(smb_dr_ctx_t *ctx)
+{
+ DWORD num = 0;
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (DWORD) <= ctx->end_ptr) {
+ (void) memcpy(&num, ctx->ptr, sizeof (DWORD));
+ ctx->ptr += sizeof (DWORD);
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+ return (num);
+}
+
+int32_t
+smb_dr_get_int32(smb_dr_ctx_t *ctx)
+{
+ int32_t num = 0;
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (int32_t) <= ctx->end_ptr) {
+ (void) memcpy(&num, ctx->ptr, sizeof (int32_t));
+ ctx->ptr += sizeof (int32_t);
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+ return (num);
+}
+
+uint32_t
+smb_dr_get_uint32(smb_dr_ctx_t *ctx)
+{
+ return ((uint32_t)smb_dr_get_int32(ctx));
+}
+
+char *
+smb_dr_get_string(smb_dr_ctx_t *ctx)
+{
+ char *buf = NULL;
+ int len = smb_dr_get_int32(ctx);
+
+ if (ctx->status == 0) {
+ if (len == -1)
+ return (buf);
+
+ if (ctx->ptr + len <= ctx->end_ptr) {
+ buf = MEM_MALLOC("CommonDoor", len +1);
+ if (buf) {
+ if (len == 0)
+ (void) strcpy(buf, "");
+ else {
+ (void) memcpy(buf, ctx->ptr, len);
+ ctx->ptr += len;
+ *(buf + len) = '\0';
+ }
+ }
+ else
+#ifndef _KERNEL
+ ctx->status = errno;
+#else
+ ctx->status = ENOMEM;
+#endif
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+ return (buf);
+}
+
+void
+smb_dr_put_dword(smb_dr_ctx_t *ctx, DWORD num)
+{
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (DWORD) <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, &num, sizeof (DWORD));
+ ctx->ptr += sizeof (DWORD);
+ } else
+ ctx->status = ENOSPC;
+ }
+}
+
+void
+smb_dr_put_int32(smb_dr_ctx_t *ctx, int32_t num)
+{
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (int32_t) <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, &num, sizeof (int32_t));
+ ctx->ptr += sizeof (int32_t);
+ } else
+ ctx->status = ENOSPC;
+ }
+}
+
+void
+smb_dr_put_uint32(smb_dr_ctx_t *ctx, uint32_t num)
+{
+ smb_dr_put_int32(ctx, (int32_t)num);
+}
+
+void
+smb_dr_put_string(smb_dr_ctx_t *ctx, char *buf)
+{
+ int len;
+
+ if (!buf)
+ len = -1;
+ else
+ len = strlen(buf);
+
+ if (ctx->status == 0) {
+ smb_dr_put_int32(ctx, len);
+ if (len <= 0)
+ return;
+
+ if (ctx->ptr + len <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, buf, len);
+ ctx->ptr += len;
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+}
+
+void
+smb_dr_free_string(char *buf)
+{
+ if (buf)
+ MEM_FREE("CommonDoor", buf);
+}
+
+int64_t
+smb_dr_get_int64(smb_dr_ctx_t *ctx)
+{
+ int64_t num = 0;
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (int64_t) <= ctx->end_ptr) {
+ (void) memcpy(&num, ctx->ptr, sizeof (int64_t));
+ ctx->ptr += sizeof (int64_t);
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+ return (num);
+}
+
+uint64_t
+smb_dr_get_uint64(smb_dr_ctx_t *ctx)
+{
+ return ((uint64_t)smb_dr_get_int64(ctx));
+}
+
+
+void
+smb_dr_put_int64(smb_dr_ctx_t *ctx, int64_t num)
+{
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (int64_t) <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, &num, sizeof (int64_t));
+ ctx->ptr += sizeof (int64_t);
+ } else
+ ctx->status = ENOSPC;
+ }
+}
+
+void
+smb_dr_put_uint64(smb_dr_ctx_t *ctx, uint64_t num)
+{
+ smb_dr_put_int64(ctx, (int64_t)num);
+}
+
+void
+smb_dr_put_short(smb_dr_ctx_t *ctx, short num)
+{
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (short) <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, &num, sizeof (short));
+ ctx->ptr += sizeof (short);
+ } else
+ ctx->status = ENOSPC;
+ }
+}
+
+short
+smb_dr_get_short(smb_dr_ctx_t *ctx)
+{
+ short num = 0;
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (short) <= ctx->end_ptr) {
+ (void) memcpy(&num, ctx->ptr, sizeof (short));
+ ctx->ptr += sizeof (short);
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+ return (num);
+}
+
+void
+smb_dr_put_ushort(smb_dr_ctx_t *ctx, unsigned short num)
+{
+ smb_dr_put_short(ctx, (short)num);
+}
+
+unsigned short
+smb_dr_get_ushort(smb_dr_ctx_t *ctx)
+{
+ return ((unsigned short)smb_dr_get_short(ctx));
+}
+
+void
+smb_dr_put_word(smb_dr_ctx_t *ctx, WORD num)
+{
+ smb_dr_put_ushort(ctx, num);
+}
+
+WORD
+smb_dr_get_word(smb_dr_ctx_t *ctx)
+{
+ return (smb_dr_get_ushort(ctx));
+}
+
+void
+smb_dr_put_BYTE(smb_dr_ctx_t *ctx, BYTE byte)
+{
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (BYTE) <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, &byte, sizeof (BYTE));
+ ctx->ptr += sizeof (BYTE);
+ } else
+ ctx->status = ENOSPC;
+ }
+}
+
+BYTE
+smb_dr_get_BYTE(smb_dr_ctx_t *ctx)
+{
+ BYTE byte = 0;
+ if (ctx->status == 0) {
+ if (ctx->ptr + sizeof (BYTE) <= ctx->end_ptr) {
+ (void) memcpy(&byte, ctx->ptr, sizeof (BYTE));
+ ctx->ptr += sizeof (BYTE);
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+ return (byte);
+}
+
+void
+smb_dr_put_buf(smb_dr_ctx_t *ctx, unsigned char *start, int len)
+{
+ smb_dr_put_int32(ctx, len);
+ if (ctx->status == 0) {
+ if (ctx->ptr + len <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, start, len);
+ ctx->ptr += len;
+ } else
+ ctx->status = ENOSPC;
+ }
+}
+
+int
+smb_dr_get_buf(smb_dr_ctx_t *ctx, unsigned char *buf, int bufsize)
+{
+ int len = -1;
+
+ if (!buf)
+ return (-1);
+
+ len = smb_dr_get_int32(ctx);
+ if (ctx->status == 0) {
+ if (bufsize < len) {
+ ctx->status = ENOSPC;
+ return (-2);
+ }
+
+ if (ctx->ptr + len <= ctx->end_ptr) {
+ (void) memcpy(buf, ctx->ptr, len);
+ ctx->ptr += len;
+ } else {
+ ctx->status = ENOSPC;
+ return (-3);
+ }
+ }
+
+ return (len);
+}
diff --git a/usr/src/common/smbsrv/smb_match.c b/usr/src/common/smbsrv/smb_match.c
new file mode 100644
index 0000000000..8edf565e1b
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_match.c
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <string.h>
+#else
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#endif
+#include <smbsrv/ctype.h>
+
+
+/*
+ * c Any non-special character matches itslef
+ * ? Match any character
+ * ab character 'a' followed by character 'b'
+ * S Any string of non-special characters
+ * AB String 'A' followed by string 'B'
+ * * Any String, including the empty string
+ */
+int
+smb_match(char *patn, char *str)
+{
+ for (;;) {
+ switch (*patn) {
+ case 0:
+ return (*str == 0);
+
+ case '?':
+ if (*str != 0) {
+ str++;
+ patn++;
+ continue;
+ } else {
+ return (0);
+ }
+ /*NOTREACHED*/
+
+#if 0
+ case '[':
+ int invert = 0, clower, cupper;
+
+ patn++;
+ if (*patn == '!') {
+ invert = 1;
+ patn++;
+ }
+ for (;;) {
+ clower = *patn;
+ if (clower == 0)
+ break;
+ if (clower == ']') {
+ patn++;
+ break;
+ }
+ patn++;
+ if (*patn == '-') {
+ /* range */
+ patn++;
+ cupper = *patn;
+ if (cupper == 0)
+ break;
+ patn++;
+ } else {
+ cupper = clower;
+ }
+ if (*str < clower || cupper < *str)
+ continue;
+
+ /* match */
+ if (invert)
+ return (0);
+
+ while (*patn && *patn++ != ']')
+ ;
+ str++;
+ continue; /* THIS WON`T WORK */
+ }
+ if (invert) {
+ str++;
+ continue;
+ }
+ return (0);
+
+#endif
+
+ case '*':
+ patn++;
+ if (*patn == 0)
+ return (1);
+
+#if 0
+ if (*patn != '?' && *patn != '*' && *patn != '[') {
+ /* accelerate */
+ while (*str) {
+ if (*str == *patn &&
+ match(patn+1, str+1))
+ return (1);
+ str++;
+ }
+ return (0);
+ }
+#endif
+
+ while (*str) {
+ if (smb_match(patn, str))
+ return (1);
+ str++;
+ }
+ return (0);
+
+ default:
+ if (*str != *patn)
+ return (0);
+ str++;
+ patn++;
+ continue;
+ }
+ }
+}
+
+int
+smb_match83(char *patn, char *str83)
+{
+ int avail;
+ char *ptr;
+ char name83[14];
+
+ ptr = name83;
+ for (avail = 8; (avail > 0) && (*patn != '.') && (*patn != 0);
+ avail--) {
+ *(ptr++) = *(patn++);
+ }
+ while (avail--)
+ *(ptr++) = ' ';
+ *(ptr++) = '.';
+
+ if (*patn == '.')
+ patn++;
+ else if (*patn != 0)
+ return (0);
+
+ for (avail = 3; (avail > 0) && (*patn != 0); avail--) {
+ *(ptr++) = *(patn++);
+ }
+ if (*patn != 0)
+ return (0);
+
+ while (avail--)
+ *(ptr++) = ' ';
+ *ptr = 0;
+
+ return (smb_match_ci(name83, str83));
+}
+
+
+
+int
+smb_match_ci(char *patn, char *str)
+{
+ /*
+ * "<" is a special pattern that matches only those names that do
+ * NOT have an extension. "." and ".." are ok.
+ */
+ if (strcmp(patn, "<") == 0) {
+ if ((strcmp(str, ".") == 0) || (strcmp(str, "..") == 0))
+ return (1);
+ if (strchr(str, '.') == 0)
+ return (1);
+ return (0);
+ }
+ for (;;) {
+ switch (*patn) {
+ case 0:
+ return (*str == 0);
+
+ case '?':
+ if (*str != 0) {
+ str++;
+ patn++;
+ continue;
+ } else {
+ return (0);
+ }
+ /*NOTREACHED*/
+
+
+ case '*':
+ patn++;
+ if (*patn == 0)
+ return (1);
+
+ while (*str) {
+ if (smb_match_ci(patn, str))
+ return (1);
+ str++;
+ }
+ return (0);
+
+ default:
+ if (*str != *patn) {
+ int c1 = *str;
+ int c2 = *patn;
+
+ c1 = mts_tolower(c1);
+ c2 = mts_tolower(c2);
+ if (c1 != c2)
+ return (0);
+ }
+ str++;
+ patn++;
+ continue;
+ }
+ }
+ /* NOT REACHED */
+}
diff --git a/usr/src/common/smbsrv/smb_msgbuf.c b/usr/src/common/smbsrv/smb_msgbuf.c
new file mode 100644
index 0000000000..d456dac683
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_msgbuf.c
@@ -0,0 +1,709 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Msgbuf buffer management implementation. The smb_msgbuf interface is
+ * typically used to encode or decode SMB data using sprintf/scanf
+ * style operations. It contains special handling for the SMB header.
+ * It can also be used for general purpose encoding and decoding.
+ */
+
+#include <sys/types.h>
+#include <sys/varargs.h>
+#include <sys/byteorder.h>
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#else
+#include <sys/sunddi.h>
+#include <sys/kmem.h>
+#endif
+#include <smbsrv/string.h>
+#include <smbsrv/msgbuf.h>
+#include <smbsrv/smb.h>
+
+static int buf_decode(smb_msgbuf_t *, char *, va_list ap);
+static int buf_encode(smb_msgbuf_t *, char *, va_list ap);
+static void *smb_msgbuf_malloc(smb_msgbuf_t *, size_t);
+static int smb_msgbuf_chkerc(char *text, int erc);
+static void buf_decode_wcs(mts_wchar_t *, mts_wchar_t *, int wcstrlen);
+
+/*
+ * Returns the offset or number of bytes used within the buffer.
+ */
+size_t
+smb_msgbuf_used(smb_msgbuf_t *mb)
+{
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (mb->scan - mb->base);
+}
+
+/*
+ * Returns the actual buffer size.
+ */
+size_t
+smb_msgbuf_size(smb_msgbuf_t *mb)
+{
+ return (mb->max);
+}
+
+uint8_t *
+smb_msgbuf_base(smb_msgbuf_t *mb)
+{
+ return (mb->base);
+}
+
+/*
+ * Ensure that the scan is aligned on a word (16-bit) boundary.
+ */
+void
+smb_msgbuf_word_align(smb_msgbuf_t *mb)
+{
+ mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 1) & ~1);
+}
+
+/*
+ * Ensure that the scan is aligned on a dword (32-bit) boundary.
+ */
+void
+smb_msgbuf_dword_align(smb_msgbuf_t *mb)
+{
+ mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 3) & ~3);
+}
+
+/*
+ * Checks whether or not the buffer has space for the amount of data
+ * specified. Returns 1 if there is space, otherwise returns 0.
+ */
+int
+smb_msgbuf_has_space(smb_msgbuf_t *mb, size_t size)
+{
+ if (size > mb->max || (mb->scan + size) > mb->end)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * Set flags the smb_msgbuf.
+ */
+void
+smb_msgbuf_fset(smb_msgbuf_t *mb, uint32_t flags)
+{
+ mb->flags |= flags;
+}
+
+/*
+ * Clear flags the smb_msgbuf.
+ */
+void
+smb_msgbuf_fclear(smb_msgbuf_t *mb, uint32_t flags)
+{
+ mb->flags &= ~flags;
+}
+
+/*
+ * smb_msgbuf_init
+ *
+ * Initialize a smb_msgbuf_t structure based on the buffer and size
+ * specified. Both scan and base initially point to the beginning
+ * of the buffer and end points to the limit of the buffer. As
+ * data is added scan should be incremented to point to the next
+ * offset at which data will be written. Max and count are set
+ * to the actual buffer size.
+ */
+void
+smb_msgbuf_init(smb_msgbuf_t *mb, uint8_t *buf, size_t size, uint32_t flags)
+{
+ mb->scan = mb->base = buf;
+ mb->max = mb->count = size;
+ mb->end = &buf[size];
+ mb->flags = flags;
+ mb->mlist.next = 0;
+}
+
+
+/*
+ * smb_msgbuf_term
+ *
+ * Destruct a smb_msgbuf_t. Free any memory hanging off the mlist.
+ */
+void
+smb_msgbuf_term(smb_msgbuf_t *mb)
+{
+ smb_msgbuf_mlist_t *item = mb->mlist.next;
+ smb_msgbuf_mlist_t *tmp;
+
+ while (item) {
+ tmp = item;
+ item = item->next;
+#ifndef _KERNEL
+ free(tmp);
+#else
+ kmem_free(tmp, tmp->size);
+#endif
+ }
+}
+
+
+/*
+ * smb_msgbuf_decode
+ *
+ * Decode a smb_msgbuf buffer as indicated by the format string into
+ * the variable arg list. This is similar to a scanf operation.
+ *
+ * On success, returns the number of bytes encoded. Otherwise
+ * returns a -ve error code.
+ */
+int
+smb_msgbuf_decode(smb_msgbuf_t *mb, char *fmt, ...)
+{
+ int rc;
+ uint8_t *orig_scan;
+ va_list ap;
+
+ va_start(ap, fmt);
+ orig_scan = mb->scan;
+ rc = buf_decode(mb, fmt, ap);
+ va_end(ap);
+
+ if (rc != SMB_MSGBUF_SUCCESS) {
+ (void) smb_msgbuf_chkerc("smb_msgbuf_decode", rc);
+ mb->scan = orig_scan;
+ return (rc);
+ }
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (mb->scan - orig_scan);
+}
+
+
+/*
+ * buf_decode
+ *
+ * Private decode function, where the real work of decoding the smb_msgbuf
+ * is done. This function should only be called via smb_msgbuf_decode to
+ * ensure correct behaviour and error handling.
+ */
+static int
+buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
+{
+ uint32_t ival;
+ uint8_t c;
+ uint8_t *cvalp;
+ uint8_t **cvalpp;
+ uint16_t *wvalp;
+ uint32_t *lvalp;
+ uint64_t *llvalp;
+ mts_wchar_t *wcs;
+ int repc;
+ int rc;
+
+ while ((c = *fmt++) != 0) {
+ repc = 1;
+
+ if (c == ' ' || c == '\t')
+ continue;
+
+ if (c == '(') {
+ while (((c = *fmt++) != 0) && c != ')')
+ ;
+
+ if (!c)
+ return (SMB_MSGBUF_SUCCESS);
+
+ continue;
+ }
+
+ if ('0' <= c && c <= '9') {
+ repc = 0;
+ do {
+ repc = repc * 10 + c - '0';
+ c = *fmt++;
+ } while ('0' <= c && c <= '9');
+ } else if (c == '#') {
+ repc = va_arg(ap, int);
+ c = *fmt++;
+ }
+
+ switch (c) {
+ case '.':
+ if (smb_msgbuf_has_space(mb, repc) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ mb->scan += repc;
+ break;
+
+ case 'c':
+ if (smb_msgbuf_has_space(mb, repc) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ cvalp = va_arg(ap, uint8_t *);
+ bcopy(mb->scan, cvalp, repc);
+ mb->scan += repc;
+ break;
+
+ case 'b':
+ if (smb_msgbuf_has_space(mb, repc) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ cvalp = va_arg(ap, uint8_t *);
+ while (repc-- > 0) {
+ *cvalp++ = *mb->scan++;
+ }
+ break;
+
+ case 'w':
+ rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t));
+ if (rc == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ wvalp = va_arg(ap, uint16_t *);
+ while (repc-- > 0) {
+ *wvalp++ = LE_IN16(mb->scan);
+ mb->scan += sizeof (uint16_t);
+ }
+ break;
+
+ case 'l':
+ rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t));
+ if (rc == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ lvalp = va_arg(ap, uint32_t *);
+ while (repc-- > 0) {
+ *lvalp++ = LE_IN32(mb->scan);
+ mb->scan += sizeof (int32_t);
+ }
+ break;
+
+ case 'q':
+ rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t));
+ if (rc == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ llvalp = va_arg(ap, uint64_t *);
+ while (repc-- > 0) {
+ *llvalp++ = LE_IN64(mb->scan);
+ mb->scan += sizeof (int64_t);
+ }
+ break;
+
+ case 'u': /* Convert from unicode if flags are set */
+ if (mb->flags & SMB_MSGBUF_UNICODE)
+ goto unicode_translation;
+ /*FALLTHROUGH*/
+
+ case 's':
+ ival = strlen((const char *)mb->scan) + 1;
+ if (smb_msgbuf_has_space(mb, ival) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ if ((cvalp = smb_msgbuf_malloc(mb, ival * 2)) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ if ((ival = mts_stombs((char *)cvalp,
+ (char *)mb->scan, ival * 2)) ==
+ (uint32_t)-1) {
+ return (SMB_MSGBUF_DATA_ERROR);
+ }
+
+ cvalpp = va_arg(ap, uint8_t **);
+ *cvalpp = cvalp;
+ mb->scan += (ival+1);
+ break;
+
+ case 'U': /* Convert from unicode */
+unicode_translation:
+ /*
+ * Unicode strings are always word aligned.
+ * The malloc'd area is larger than the
+ * original string because the UTF-8 chars
+ * may be longer than the wide-chars.
+ */
+ smb_msgbuf_word_align(mb);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ wcs = (mts_wchar_t *)mb->scan;
+
+ /* count the null wchar */
+ repc = sizeof (mts_wchar_t);
+ while (*wcs++)
+ repc += sizeof (mts_wchar_t);
+
+ if (smb_msgbuf_has_space(mb, repc) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ /* Decode wchar string into host byte-order */
+ if ((wcs = smb_msgbuf_malloc(mb, repc)) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ buf_decode_wcs(wcs, (mts_wchar_t *)mb->scan,
+ repc / sizeof (mts_wchar_t));
+
+ /* Get space for translated string */
+ if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ /* Translate string */
+ (void) mts_wcstombs((char *)cvalp, wcs, repc * 2);
+
+ cvalpp = va_arg(ap, uint8_t **);
+ *cvalpp = cvalp;
+ mb->scan += repc;
+ break;
+
+ case 'M':
+ if (smb_msgbuf_has_space(mb, 4) == 0)
+ return (SMB_MSGBUF_UNDERFLOW);
+
+ if (mb->scan[0] != 0xFF ||
+ mb->scan[1] != 'S' ||
+ mb->scan[2] != 'M' ||
+ mb->scan[3] != 'B') {
+ return (SMB_MSGBUF_INVALID_HEADER);
+ }
+ mb->scan += 4;
+ break;
+
+ default:
+ return (SMB_MSGBUF_INVALID_FORMAT);
+ }
+ }
+
+ return (SMB_MSGBUF_SUCCESS);
+}
+
+
+/*
+ * smb_msgbuf_encode
+ *
+ * Encode a smb_msgbuf buffer as indicated by the format string using
+ * the variable arg list. This is similar to a sprintf operation.
+ *
+ * On success, returns the number of bytes encoded. Otherwise
+ * returns a -ve error code.
+ */
+int
+smb_msgbuf_encode(smb_msgbuf_t *mb, char *fmt, ...)
+{
+ int rc;
+ uint8_t *orig_scan;
+ va_list ap;
+
+ va_start(ap, fmt);
+ orig_scan = mb->scan;
+ rc = buf_encode(mb, fmt, ap);
+ va_end(ap);
+
+ if (rc != SMB_MSGBUF_SUCCESS) {
+ (void) smb_msgbuf_chkerc("smb_msgbuf_encode", rc);
+ mb->scan = orig_scan;
+ return (rc);
+ }
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (mb->scan - orig_scan);
+}
+
+
+/*
+ * buf_encode
+ *
+ * Private encode function, where the real work of encoding the smb_msgbuf
+ * is done. This function should only be called via smb_msgbuf_encode to
+ * ensure correct behaviour and error handling.
+ */
+static int
+buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
+{
+ uint8_t cval;
+ uint16_t wval;
+ uint32_t lval;
+ uint64_t llval;
+ uint32_t ival;
+ uint8_t *cvalp;
+ uint8_t c;
+ mts_wchar_t wcval;
+ int count;
+ int repc = 1;
+ int rc;
+
+ while ((c = *fmt++) != 0) {
+ repc = 1;
+
+ if (c == ' ' || c == '\t')
+ continue;
+
+ if (c == '(') {
+ while (((c = *fmt++) != 0) && c != ')')
+ ;
+
+ if (!c)
+ return (SMB_MSGBUF_SUCCESS);
+
+ continue;
+ }
+
+ if ('0' <= c && c <= '9') {
+ repc = 0;
+ do {
+ repc = repc * 10 + c - '0';
+ c = *fmt++;
+ } while ('0' <= c && c <= '9');
+ } else if (c == '#') {
+ repc = va_arg(ap, int);
+ c = *fmt++;
+ }
+
+ switch (c) {
+ case '.':
+ if (smb_msgbuf_has_space(mb, repc) == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ while (repc-- > 0)
+ *mb->scan++ = 0;
+ break;
+
+ case 'c':
+ if (smb_msgbuf_has_space(mb, repc) == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ cvalp = va_arg(ap, uint8_t *);
+ bcopy(cvalp, mb->scan, repc);
+ mb->scan += repc;
+ break;
+
+ case 'b':
+ if (smb_msgbuf_has_space(mb, repc) == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ while (repc-- > 0) {
+ cval = va_arg(ap, int);
+ *mb->scan++ = cval;
+ }
+ break;
+
+ case 'w':
+ rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t));
+ if (rc == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ while (repc-- > 0) {
+ wval = va_arg(ap, int);
+ LE_OUT16(mb->scan, wval);
+ mb->scan += sizeof (uint16_t);
+ }
+ break;
+
+ case 'l':
+ rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t));
+ if (rc == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ while (repc-- > 0) {
+ lval = va_arg(ap, uint32_t);
+ LE_OUT32(mb->scan, lval);
+ mb->scan += sizeof (int32_t);
+ }
+ break;
+
+ case 'q':
+ rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t));
+ if (rc == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ while (repc-- > 0) {
+ llval = va_arg(ap, uint64_t);
+ LE_OUT64(mb->scan, llval);
+ mb->scan += sizeof (uint64_t);
+ }
+ break;
+
+ case 'u': /* conditional unicode */
+ if (mb->flags & SMB_MSGBUF_UNICODE)
+ goto unicode_translation;
+ /* FALLTHROUGH */
+
+ case 's':
+ cvalp = va_arg(ap, uint8_t *);
+ ival = strlen((const char *)cvalp) + 1;
+
+ if (smb_msgbuf_has_space(mb, ival) == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ ival =
+ mts_mbstos((char *)mb->scan, (const char *)cvalp);
+ mb->scan += ival + 1;
+ break;
+
+ case 'U': /* unicode */
+unicode_translation:
+ /*
+ * Unicode strings are always word aligned.
+ */
+ smb_msgbuf_word_align(mb);
+ cvalp = va_arg(ap, uint8_t *);
+
+ for (;;) {
+ rc = smb_msgbuf_has_space(mb,
+ sizeof (mts_wchar_t));
+ if (rc == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ count = mts_mbtowc(&wcval, (const char *)cvalp,
+ MTS_MB_CHAR_MAX);
+
+ if (count < 0) {
+ return (SMB_MSGBUF_DATA_ERROR);
+ } else if (count == 0) {
+ /*
+ * No longer need to do this now that
+ * mbtowc correctly writes the null
+ * before returning zero but paranoia
+ * wins.
+ */
+ wcval = 0;
+ count = 1;
+ }
+
+ /* Write wchar in wire-format */
+ LE_OUT16(mb->scan, wcval);
+
+ if (*cvalp == 0) {
+ /*
+ * End of string. Check to see whether
+ * or not to include the null
+ * terminator.
+ */
+ if ((mb->flags & SMB_MSGBUF_NOTERM) ==
+ 0)
+ mb->scan +=
+ sizeof (mts_wchar_t);
+ break;
+ }
+
+ mb->scan += sizeof (mts_wchar_t);
+ cvalp += count;
+ }
+ break;
+
+ case 'M':
+ if (smb_msgbuf_has_space(mb, 4) == 0)
+ return (SMB_MSGBUF_OVERFLOW);
+
+ *mb->scan++ = 0xFF;
+ *mb->scan++ = 'S';
+ *mb->scan++ = 'M';
+ *mb->scan++ = 'B';
+ break;
+
+ default:
+ return (SMB_MSGBUF_INVALID_FORMAT);
+ }
+ }
+
+ return (SMB_MSGBUF_SUCCESS);
+}
+
+
+/*
+ * smb_msgbuf_malloc
+ *
+ * Allocate some memory for use with this smb_msgbuf. We increase the
+ * requested size to hold the list pointer and return a pointer
+ * to the area for use by the caller.
+ */
+static void *
+smb_msgbuf_malloc(smb_msgbuf_t *mb, size_t size)
+{
+ smb_msgbuf_mlist_t *item;
+
+ size += sizeof (smb_msgbuf_mlist_t);
+
+#ifndef _KERNEL
+ if ((item = malloc(size)) == NULL)
+ return (NULL);
+#else
+ item = kmem_alloc(size, KM_SLEEP);
+#endif
+ item->next = mb->mlist.next;
+ item->size = size;
+ mb->mlist.next = item;
+
+ /*
+ * The caller gets a pointer to the address
+ * immediately after the smb_msgbuf_mlist_t.
+ */
+ return ((void *)(item + 1));
+}
+
+
+/*
+ * smb_msgbuf_chkerc
+ *
+ * Diagnostic function to write an appropriate message to the system log.
+ */
+static int
+smb_msgbuf_chkerc(char *text, int erc)
+{
+ static struct {
+ int erc;
+ char *name;
+ } etable[] = {
+ { SMB_MSGBUF_SUCCESS, "success" },
+ { SMB_MSGBUF_UNDERFLOW, "overflow/underflow" },
+ { SMB_MSGBUF_INVALID_FORMAT, "invalid format" },
+ { SMB_MSGBUF_INVALID_HEADER, "invalid header" },
+ { SMB_MSGBUF_DATA_ERROR, "data error" }
+ };
+
+ int i;
+
+ for (i = 0; i < sizeof (etable)/sizeof (etable[0]); ++i) {
+ if (etable[i].erc == erc) {
+ if (text == 0)
+ text = "smb_msgbuf_chkerc";
+ break;
+ }
+ }
+ return (erc);
+}
+
+static void
+buf_decode_wcs(mts_wchar_t *dst_wcstr, mts_wchar_t *src_wcstr, int wcstrlen)
+{
+ int i;
+
+ for (i = 0; i < wcstrlen; i++) {
+ *dst_wcstr = LE_IN16(src_wcstr);
+ dst_wcstr++;
+ src_wcstr++;
+ }
+}
diff --git a/usr/src/common/smbsrv/smb_native.c b/usr/src/common/smbsrv/smb_native.c
new file mode 100644
index 0000000000..bd88cc5427
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_native.c
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module defines generic functions to map Native OS and Native
+ * LanMan names to values.
+ */
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#else
+#include <string.h>
+#endif
+#include <smbsrv/string.h>
+#include <smbsrv/smbinfo.h>
+
+/*
+ * smbnative_os_value
+ *
+ * Return the appropriate native OS value for the specified native OS name.
+ *
+ * Windows 2000 server: "Windows 2000 2195"
+ * Windows XP Professional client: "Windows 2002 2543"
+ * Windows XP PDC server: "Windows 5.1"
+ * Windows .Net: "Windows .NET 3621"
+ * Windows .Net: "Windows .NET 3718"
+ *
+ * DAVE (Thursby Software: CIFS for MacOS) uses "MacOS", sometimes with a
+ * version number appended, i.e. "MacOS 8.5.1". We treat DAVE like NT 4.0
+ * except for the cases that DAVE clients set 'watch tree' flag in notify
+ * change requests.
+ *
+ * Samba reports UNIX as its Native OS, which we can map to NT 4.0.
+ */
+int
+smbnative_os_value(char *native_os)
+{
+ typedef struct native_os_table {
+ int os_value;
+ char *os_name;
+ } native_os_table_t;
+
+ static native_os_table_t os_table[] = {
+ { NATIVE_OS_WINNT, "Windows NT 4.0" },
+ { NATIVE_OS_WINNT, "Windows NT" },
+ { NATIVE_OS_WIN95, "Windows 4.0" },
+ { NATIVE_OS_WIN2000, "Windows 5.0" },
+ { NATIVE_OS_WIN2000, "Windows 5.1" },
+ { NATIVE_OS_WIN2000, "Windows 2000 5.0" },
+ { NATIVE_OS_NT5_1, "Windows 2000 5.1" },
+ { NATIVE_OS_WIN2000, "Windows 2000" },
+ { NATIVE_OS_WIN2000, "Windows 2002" },
+ { NATIVE_OS_WIN2000, "Windows .NET" },
+ { NATIVE_OS_WIN2000, "Windows Server 2003" },
+ { NATIVE_OS_WIN2000, "Windows XP" },
+ { NATIVE_OS_WINNT, "UNIX" },
+ { NATIVE_OS_MACOS, "MacOS" }
+ };
+
+ int i;
+ int len;
+ char *os_name;
+
+ if (native_os == NULL) {
+ return (NATIVE_OS_UNKNOWN);
+ }
+
+ for (i = 0; i < sizeof (os_table)/sizeof (os_table[0]); ++i) {
+ os_name = os_table[i].os_name;
+ len = strlen(os_name);
+
+ if (utf8_strncasecmp(os_name, native_os, len) == 0) {
+ return (os_table[i].os_value);
+ }
+ }
+ return (NATIVE_OS_UNKNOWN);
+}
+
+
+/*
+ * smbnative_lm_value
+ *
+ * Return the appropriate native LanMan value for the specified native
+ * LanMan name. There's an alignment problem in some packets from some
+ * clients that means we can miss the first character, so we do an
+ * additional check starting from the second character.
+ *
+ * DAVE (Thursby Software: CIFS for MacOS) sometimes uses a Unicode
+ * character in the LanMan name. Variations seen so far are:
+ *
+ * 44 00 41 00 56 00 45 00 00 00 D.A.V.E...
+ *
+ * 44 00 41 00 56 00 45 00 22 21 20 00 56 00 32 00
+ * 2E 00 35 00 2E 00 31 00 00 00 D.A.V.E."!..V.2...5...1...
+ *
+ * Samba reports its own name (Samba) as its Native LM, which we can
+ * map to NT LM 4.0.
+ */
+int
+smbnative_lm_value(char *native_lm)
+{
+ typedef struct native_lm_table {
+ int lm_value;
+ char *lm_name;
+ } native_lm_table_t;
+
+ static native_lm_table_t lm_table[] = {
+ { NATIVE_LM_NT, "NT LAN Manager 4.0" },
+ { NATIVE_LM_NT, "Windows NT 4.0" },
+ { NATIVE_LM_NT, "Windows NT" },
+ { NATIVE_LM_NT, "Windows 4.0" },
+ { NATIVE_LM_WIN2000, "Windows 2000 LAN Manager" },
+ { NATIVE_LM_WIN2000, "Windows 2000 5.0" },
+ { NATIVE_LM_WIN2000, "Windows 2000 5.1" },
+ { NATIVE_LM_WIN2000, "Windows 2000", },
+ { NATIVE_LM_WIN2000, "Windows 2002 5.1" },
+ { NATIVE_LM_WIN2000, "Windows 2002" },
+ { NATIVE_LM_WIN2000, "Windows .NET 5.2" },
+ { NATIVE_LM_WIN2000, "Windows .NET" },
+ { NATIVE_LM_WIN2000, "Windows Server 2003" },
+ { NATIVE_LM_WIN2000, "Windows XP" },
+ { NATIVE_LM_NT, "Samba" },
+ { NATIVE_LM_NT, "DAVE" }
+ };
+
+ int i;
+ int len;
+ char *lm_name;
+
+ if (native_lm == NULL) {
+ return (NATIVE_LM_NONE);
+ }
+
+ for (i = 0; i < sizeof (lm_table)/sizeof (lm_table[0]); ++i) {
+ lm_name = lm_table[i].lm_name;
+ len = strlen(lm_name);
+
+ if ((utf8_strncasecmp(lm_name, native_lm, len) == 0) ||
+ (utf8_strncasecmp(&lm_name[1], native_lm, len - 1) == 0)) {
+ return (lm_table[i].lm_value);
+ }
+ }
+ return (NATIVE_LM_NONE);
+}
+
+/*
+ * smbnative_pdc_value
+ *
+ * This function is used when NetFORCE contacting a PDC
+ * to authenticate a connected user to determine and keep
+ * the PDC type.
+ *
+ * The reason for adding this functionality is that NetFORCE
+ * doesn't support Samba PDC but code didn't check the PDC type
+ * and do authentication agains any PDC. This behaviour could
+ * cause problem in some circumstances.
+ * Now that we determine the PDC type the authentication code
+ * can be configured (by smb.samba.pdc env var) to return access
+ * denied to authentication attempts when PDC is Samba.
+ */
+int
+smbnative_pdc_value(char *native_lm)
+{
+ typedef struct pdc_table {
+ int pdc_value;
+ char *pdc_lmname;
+ } pdc_table_t;
+
+ static pdc_table_t pdc_table[] = {
+ { PDC_WINNT, "NT LAN Manager 4.0" },
+ { PDC_WINNT, "Windows NT 4.0" },
+ { PDC_WINNT, "Windows NT" },
+ { PDC_WINNT, "Windows 4.0" },
+ { PDC_WIN2000, "Windows 2000 LAN Manager" },
+ { PDC_WIN2000, "Windows 2000 5.0" },
+ { PDC_WIN2000, "Windows 2000 5.1" },
+ { PDC_WIN2000, "Windows 2000", },
+ { PDC_WIN2000, "Windows 2002 5.1" },
+ { PDC_WIN2000, "Windows 2002" },
+ { PDC_WIN2000, "Windows .NET 5.2" },
+ { PDC_WIN2000, "Windows .NET" },
+ { PDC_SAMBA, "Samba" },
+ { PDC_WINNT, "DAVE" }
+ };
+
+ int i;
+ int len;
+ char *pdc_lmname;
+
+ if (native_lm == 0) {
+ return (PDC_UNKNOWN);
+ }
+
+ for (i = 0; i < sizeof (pdc_table)/sizeof (pdc_table[0]); ++i) {
+ pdc_lmname = pdc_table[i].pdc_lmname;
+ len = strlen(pdc_lmname);
+
+ if ((utf8_strncasecmp(pdc_lmname, native_lm, len) == 0) ||
+ (utf8_strncasecmp(&pdc_lmname[1], native_lm, len - 1)
+ == 0)) {
+ return (pdc_table[i].pdc_value);
+ }
+ }
+
+ return (PDC_UNKNOWN);
+}
diff --git a/usr/src/common/smbsrv/smb_netbios_util.c b/usr/src/common/smbsrv/smb_netbios_util.c
new file mode 100644
index 0000000000..1bd47f80bc
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_netbios_util.c
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#else
+#include <string.h>
+#endif
+#include <smbsrv/string.h>
+#include <smbsrv/ctype.h>
+#include <smbsrv/netbios.h>
+
+static int domainname_is_valid(char *domain_name);
+
+/*
+ * Routines than support name compression.
+ *
+ * The NetBIOS name representation in all NetBIOS packets (for NAME,
+ * SESSION, and DATAGRAM services) is defined in the Domain Name
+ * Service RFC 883[3] as "compressed" name messages. This format is
+ * called "second-level encoding" in the section entitled
+ * "Representation of NetBIOS Names" in the Concepts and Methods
+ * document.
+ *
+ * For ease of description, the first two paragraphs from page 31,
+ * the section titled "Domain name representation and compression",
+ * of RFC 883 are replicated here:
+ *
+ * Domain names messages are expressed in terms of a sequence
+ * of labels. Each label is represented as a one octet length
+ * field followed by that number of octets. Since every domain
+ * name ends with the null label of the root, a compressed
+ * domain name is terminated by a length byte of zero. The
+ * high order two bits of the length field must be zero, and
+ * the remaining six bits of the length field limit the label
+ * to 63 octets or less.
+ *
+ * To simplify implementations, the total length of label
+ * octets and label length octets that make up a domain name is
+ * restricted to 255 octets or less.
+ *
+ * The following is the uncompressed representation of the NetBIOS name
+ * "FRED ", which is the 4 ASCII characters, F, R, E, D, followed by 12
+ * space characters (0x20). This name has the SCOPE_ID: "NETBIOS.COM"
+ *
+ * EGFCEFEECACACACACACACACACACACACA.NETBIOS.COM
+ *
+ * This uncompressed representation of names is called "first-level
+ * encoding" in the section entitled "Representation of NetBIOS Names"
+ * in the Concepts and Methods document.
+ *
+ * The following is a pictographic representation of the compressed
+ * representation of the previous uncompressed Domain Name
+ * representation.
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x20 | E (0x45) | G (0x47) | F (0x46) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | C (0x43) | E (0x45) | F (0x46) | E (0x45) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | E (0x45) | C (0x43) | A (0x41) | C (0x43) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | A (0x41) | C (0x43) | A (0x41) | C (0x43) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | A (0x41) | C (0x43) | A (0x41) | C (0x43) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | A (0x41) | C (0x43) | A (0x41) | C (0x43) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | A (0x41) | C (0x43) | A (0x41) | C (0x43) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | A (0x41) | C (0x43) | A (0x41) | C (0x43) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | A (0X41) | 0x07 | N (0x4E) | E (0x45) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | T (0x54) | B (0x42) | I (0x49) | O (0x4F) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | S (0x53) | 0x03 | C (0x43) | O (0x4F) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | M (0x4D) | 0x00 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Each section of a domain name is called a label [7 (page 31)]. A
+ * label can be a maximum of 63 bytes. The first byte of a label in
+ * compressed representation is the number of bytes in the label. For
+ * the above example, the first 0x20 is the number of bytes in the
+ * left-most label, EGFCEFEECACACACACACACACACACACACA, of the domain
+ * name. The bytes following the label length count are the characters
+ * of the label. The following labels are in sequence after the first
+ * label, which is the encoded NetBIOS name, until a zero (0x00) length
+ * count. The zero length count represents the root label, which is
+ * always null.
+ *
+ * A label length count is actually a 6-bit field in the label length
+ * field. The most significant 2 bits of the field, bits 7 and 6, are
+ * flags allowing an escape from the above compressed representation.
+ * If bits 7 and 6 are both set (11), the following 14 bits are an
+ * offset pointer into the full message to the actual label string from
+ * another domain name that belongs in this name. This label pointer
+ * allows for a further compression of a domain name in a packet.
+ *
+ * NetBIOS implementations can only use label string pointers in Name
+ * Service packets. They cannot be used in Session or Datagram Service
+ * packets.
+ *
+ * The other two possible values for bits 7 and 6 (01 and 10) of a label
+ * length field are reserved for future use by RFC 883[2 (page 32)].
+ *
+ * Note that the first octet of a compressed name must contain one of
+ * the following bit patterns. (An "x" indicates a bit whose value may
+ * be either 0 or 1.):
+ *
+ * 00100000 - Netbios name, length must be 32 (decimal)
+ * 11xxxxxx - Label string pointer
+ * 10xxxxxx - Reserved
+ * 01xxxxxx - Reserved
+ */
+
+/*
+ * netbios_first_level_name_encode
+ *
+ * Put test description here.
+ *
+ * Inputs:
+ * char * in -> Name to encode
+ * char * out -> Buffer to encode into.
+ * int length -> # of bytes to encode.
+ *
+ * Returns:
+ * Nothing
+ */
+int
+netbios_first_level_name_encode(unsigned char *name, unsigned char *scope,
+ unsigned char *out, int max_out)
+{
+ unsigned char ch, len;
+ unsigned char *in;
+ unsigned char *lp;
+ unsigned char *op = out;
+
+ if (max_out < 0x21)
+ return (-1);
+
+ in = name;
+ *op++ = 0x20;
+ for (len = 0; len < NETBIOS_NAME_SZ; len++) {
+ ch = *in++;
+ *op++ = 'A' + ((ch >> 4) & 0xF);
+ *op++ = 'A' + ((ch) & 0xF);
+ }
+
+ max_out -= 0x21;
+
+ in = scope;
+ len = 0;
+ lp = op++;
+ while (((ch = *in++) != 0) && (max_out-- > 1)) {
+ if (ch == 0) {
+ if ((*lp = len) != 0)
+ *op++ = 0;
+ break;
+ }
+ if (ch == '.') {
+ *lp = len;
+ lp = op++;
+ len = 0;
+ } else {
+ *op++ = ch;
+ len++;
+ }
+ }
+ *lp = len;
+ if (len != 0)
+ *op = 0;
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (op - out);
+}
+
+/*
+ * smb_first_level_name_decode
+ *
+ * The null terminated string "in" is the name to decode. The output
+ * is placed in the name_entry structure "name".
+ *
+ * The scope field is a series of length designated labels as described
+ * in the "Domain name representation and compression" section of RFC883.
+ * The two high order two bits of the length field must be zero, the
+ * remaining six bits contain the field length. The total length of the
+ * domain name is restricted to 255 octets but note that the trailing
+ * root label and its dot are not printed. When converting the labels,
+ * the length fields are replaced by dots.
+ *
+ * Returns the number of bytes scanned or -1 to indicate an error.
+ */
+int
+netbios_first_level_name_decode(char *in, char *name, char *scope)
+{
+ unsigned int length, bytes;
+ char c1, c2;
+ char *cp;
+ char *out;
+
+ cp = in;
+
+ if ((length = *cp++) != 0x20) {
+ return (-1);
+ }
+
+ out = name;
+ while (length > 0) {
+ c1 = *cp++;
+ c2 = *cp++;
+
+ if ('A' <= c1 && c1 <= 'P' && 'A' <= c2 && c2 <= 'P') {
+ c1 -= 'A';
+ c2 -= 'A';
+ *out++ = (c1 << 4) | (c2);
+ } else {
+ return (-1); /* conversion error */
+ }
+ length -= 2;
+ }
+
+ out = scope;
+ bytes = 0;
+ for (length = *cp++; length != 0; length = *cp++) {
+ if ((length & 0xc0) != 0x00) {
+ /*
+ * This is a pointer or a reserved field. If it's
+ * a pointer (16-bits) we have to skip the next byte.
+ */
+ if ((length & 0xc0) == 0xc0) {
+ cp++;
+ continue;
+ }
+ }
+
+ /*
+ * Replace the length with a '.', except for the first one.
+ */
+ if (out != scope) {
+ *out++ = '.';
+ bytes++;
+ }
+
+ while (length-- > 0) {
+ if (bytes++ >= (NETBIOS_DOMAIN_NAME_MAX - 1)) {
+ return (-1);
+ }
+ *out++ = *cp++;
+ }
+ }
+ *out = 0;
+
+ /*
+ * We are supposed to preserve all 8-bits of the domain name
+ * but due to the single byte representation in the name cache
+ * and UTF-8 encoding everywhere else, we restrict domain names
+ * to Appendix 1 - Domain Name Syntax Specification in RFC883.
+ */
+ if (domainname_is_valid(scope)) {
+ (void) utf8_strupr(scope);
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (cp - in);
+ }
+
+ scope[0] = '\0';
+ return (-1);
+}
+
+/*
+ * smb_netbios_name_isvalid
+ *
+ * This function is provided to be used by session service
+ * which runs in kernel in order to hide name_entry definition.
+ *
+ * It returns the decoded name in the provided buffer as 'out'
+ * if it's not null.
+ *
+ * Returns 0 if decode fails, 1 if it succeeds.
+ */
+int
+netbios_name_isvalid(char *in, char *out)
+{
+ char name[NETBIOS_NAME_SZ];
+ char scope[NETBIOS_DOMAIN_NAME_MAX];
+
+ if (netbios_first_level_name_decode(in, name, scope) < 0)
+ return (0);
+
+ if (out)
+ (void) strlcpy(out, name, NETBIOS_NAME_SZ);
+
+ return (1);
+}
+
+/*
+ * Characters that we allow in DNS domain names, in addition to
+ * alphanumeric characters. This is not quite consistent with
+ * RFC883. This is global so that it can be patched if there is
+ * a need to change the valid characters in the field.
+ */
+unsigned char *dns_allowed = (unsigned char *)"-_";
+
+/*
+ * dns_is_allowed
+ *
+ * Check the dns_allowed characters and return true (1) if the character
+ * is in the table. Otherwise return false (0).
+ */
+static int
+dns_is_allowed(unsigned char c)
+{
+ unsigned char *p = dns_allowed;
+
+ while (*p) {
+ if (c == *p++)
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * domainname_is_valid
+ *
+ * Check the specified domain name for mostly compliance with RFC883
+ * Appendix 1. Names may contain alphanumeric characters, hyphens,
+ * underscores and dots. The first character after a dot must be an
+ * alphabetic character. RFC883 doesn't mention underscores but we
+ * allow it due to common use, and we don't check that labels end
+ * with an alphanumeric character.
+ *
+ * Returns true (1) if the name is valid. Otherwise returns false (0).
+ */
+static int
+domainname_is_valid(char *domain_name)
+{
+ char *name;
+ int first_char = 1;
+
+ if (domain_name == 0)
+ return (0);
+
+ for (name = domain_name; *name != 0; ++name) {
+ if (*name == '.') {
+ first_char = 1;
+ continue;
+ }
+
+ if (first_char) {
+ if (mts_isalpha_ascii(*name) == 0)
+ return (0);
+
+ first_char = 0;
+ continue;
+ }
+
+ if (mts_isalnum_ascii(*name) || dns_is_allowed(*name))
+ continue;
+
+ return (0);
+ }
+
+ return (1);
+}
diff --git a/usr/src/common/smbsrv/smb_oem.c b/usr/src/common/smbsrv/smb_oem.c
new file mode 100644
index 0000000000..4dca80402b
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_oem.c
@@ -0,0 +1,762 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Support for oem <-> unicode translations.
+ */
+
+#ifndef _KERNEL
+#include <stdio.h>
+#include <stdlib.h>
+#include <thread.h>
+#include <synch.h>
+#include <string.h>
+#endif /* _KERNEL */
+#include <smbsrv/alloc.h>
+#include <smbsrv/string.h>
+#include <smbsrv/oem.h>
+#include <sys/byteorder.h>
+/*
+ * name: Name used to show on the telnet/GUI.
+ * filename: The actual filename contains the codepage.
+ * doublebytes: The codepage is double or single byte.
+ * oempage: The oempage is used to convert Unicode to OEM chars.
+ * Memory needs to be allocated for value field of oempage
+ * to store the entire table.
+ * unipage: The unipage is used to convert OEM to Unicode chars.
+ * Memory needs to be allocated for value field of unipage
+ * to store the entire table.
+ * valid: This field indicates if the page is valid or not.
+ * ref: This ref count is used to keep track of the usage of BOTH
+ * oempage and unipage.
+ * Note: If the cpid of the table is changed, please change the
+ * codepage_id in oem.h as well.
+ */
+typedef struct oem_codepage {
+ char *filename;
+ unsigned int bytesperchar;
+ oempage_t oempage;
+ oempage_t unicodepage;
+ unsigned int valid;
+ unsigned int ref;
+} oem_codepage_t;
+
+static oem_codepage_t oemcp_table[] = {
+ {"850.cpg", 1, {0, 0}, {0, 0}, 0, 0}, /* Multilingual Latin1 */
+ {"950.cpg", 2, {1, 0}, {1, 0}, 0, 0}, /* Chinese Traditional */
+ {"1252.cpg", 1, {2, 0}, {2, 0}, 0, 0}, /* MS Latin1 */
+ {"949.cpg", 2, {3, 0}, {3, 0}, 0, 0}, /* Korean */
+ {"936.cpg", 2, {4, 0}, {4, 0}, 0, 0}, /* Chinese Simplified */
+ {"932.cpg", 2, {5, 0}, {5, 0}, 0, 0}, /* Japanese */
+ {"852.cpg", 1, {6, 0}, {6, 0}, 0, 0}, /* Multilingual Latin2 */
+ {"1250.cpg", 1, {7, 0}, {7, 0}, 0, 0}, /* MS Latin2 */
+ {"1253.cpg", 1, {8, 0}, {8, 0}, 0, 0}, /* MS Greek */
+ {"737.cpg", 1, {9, 0}, {9, 0}, 0, 0}, /* Greek */
+ {"1254.cpg", 1, {10, 0}, {10, 0}, 0, 0}, /* MS Turkish */
+ {"857.cpg", 1, {11, 0}, {11, 0}, 0, 0}, /* Multilingual Latin5 */
+ {"1251.cpg", 1, {12, 0}, {12, 0}, 0, 0}, /* MS Cyrillic */
+ {"866.cpg", 1, {13, 0}, {13, 0}, 0, 0}, /* Cyrillic II */
+ {"1255.cpg", 1, {14, 0}, {14, 0}, 0, 0}, /* MS Hebrew */
+ {"862.cpg", 1, {15, 0}, {15, 0}, 0, 0}, /* Hebrew */
+ {"1256.cpg", 1, {16, 0}, {16, 0}, 0, 0}, /* MS Arabic */
+ {"720.cpg", 1, {17, 0}, {17, 0}, 0, 0} /* Arabic */
+};
+
+static language lang_table[] = {
+ {"Arabic", OEM_CP_IND_720, OEM_CP_IND_1256},
+ {"Brazilian", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"Chinese Traditional", OEM_CP_IND_950, OEM_CP_IND_950},
+ {"Chinese Simplified", OEM_CP_IND_936, OEM_CP_IND_936},
+ {"Czech", OEM_CP_IND_852, OEM_CP_IND_1250},
+ {"Danish", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"Dutch", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"English", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"Finnish", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"French", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"German", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"Greek", OEM_CP_IND_737, OEM_CP_IND_1253},
+ {"Hebrew", OEM_CP_IND_862, OEM_CP_IND_1255},
+ {"Hungarian", OEM_CP_IND_852, OEM_CP_IND_1250},
+ {"Italian", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"Japanese", OEM_CP_IND_932, OEM_CP_IND_932},
+ {"Korean", OEM_CP_IND_949, OEM_CP_IND_949},
+ {"Norwegian", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"Polish", OEM_CP_IND_852, OEM_CP_IND_1250},
+ {"Russian", OEM_CP_IND_866, OEM_CP_IND_1251},
+ {"Slovak", OEM_CP_IND_852, OEM_CP_IND_1250},
+ {"Slovenian", OEM_CP_IND_852, OEM_CP_IND_1250},
+ {"Spanish", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"Swedish", OEM_CP_IND_850, OEM_CP_IND_1252},
+ {"Turkish", OEM_CP_IND_857, OEM_CP_IND_1254}
+};
+
+
+
+/*
+ * The oem_default_smb_cp is the default smb codepage for English.
+ * It is actually codepage 850.
+ */
+mts_wchar_t oem_default_smb_cp[256] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+ 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+
+
+/*
+ * The oem_default_telnet_cp is the default telnet codepage for English.
+ * It is actually codepage 1252.
+ */
+mts_wchar_t oem_default_telnet_cp[256] = {
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
+ 0x9, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x30,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x40,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x60,
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x70,
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x20AC,
+ 0x81, 0x201A, 0x192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6,
+ 0x2030, 0x160, 0x2039, 0x152, 0x8D, 0x017D, 0x8F, 0x90,
+ 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC,
+ 0x2122, 0x161, 0x203A, 0x153, 0x9D, 0x017E, 0x178, 0x00A0,
+ 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8,
+ 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0,
+ 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8,
+ 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0,
+ 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8,
+ 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0,
+ 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8,
+ 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0,
+ 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8,
+ 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0,
+ 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8,
+ 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+
+#define MAX_OEMPAGES (sizeof (oemcp_table) / sizeof (oemcp_table[0]))
+#define MAX_UNI_IDX 65536
+
+
+
+/*
+ * oem_codepage_bytesperchar
+ *
+ * This function returns the max bytes per oem char for the specified
+ * oem table. This basically shows if the oem codepage is single or
+ * double bytes.
+ */
+static unsigned int
+oem_codepage_bytesperchar(unsigned int cpid)
+{
+ if (cpid >= MAX_OEMPAGES)
+ return (0);
+ else
+ return (oemcp_table[cpid].bytesperchar);
+}
+
+
+
+/*
+ * oem_get_codepage_path
+ *
+ * This function will get the codepage path.
+ */
+const char *
+oem_get_codepage_path(void)
+{
+#ifdef PBSHORTCUT /* */
+ const char *path = getenv("codepage.oem.directory");
+ if (path == 0)
+ return ("/");
+ else
+ return (path);
+#else /* PBSHORTCUT */
+ return ("/");
+#endif /* PBSHORTCUT */
+}
+
+/*
+ * oem_codepage_init
+ *
+ * This function will init oem page via the cpid of the oem table.
+ * The function oem_codepage_free must be called when the oempage is
+ * no longer needed to free up the allocated memory. If the codepage is
+ * successfully initialized, zero will be the return value; otherwise
+ * -1 will be the return value.
+ */
+int
+oem_codepage_init(unsigned int cpid)
+{
+#ifndef _KERNEL
+ FILE *fp;
+ static mutex_t mutex;
+ char buf[32];
+ char filePath[100];
+#endif /* _KERNEL */
+ unsigned int max_oem_index;
+ const char *codepagePath = oem_get_codepage_path();
+ mts_wchar_t *default_oem_cp = 0;
+ oem_codepage_t *oemcp;
+
+ /*
+ * The OEM codepages 850 and 1252 are stored in kernel; therefore,
+ * no need for codepagePath to be defined to work.
+ */
+ if (cpid >= MAX_OEMPAGES ||
+ (codepagePath == 0 &&
+ cpid != oem_default_smb_cpid && cpid != oem_default_telnet_cpid))
+ return (-1);
+
+ max_oem_index = 1 << oem_codepage_bytesperchar(cpid) * 8;
+ /*
+ * Use mutex so no two same index can be initialize
+ * at the same time.
+ */
+#ifndef _KERNEL
+ (void) mutex_lock(&mutex);
+#endif /* _KERNEL */
+
+ oemcp = &oemcp_table[cpid];
+ if (oemcp->valid) {
+ oemcp->valid++;
+#ifndef _KERNEL
+ (void) mutex_unlock(&mutex);
+#endif /* _KERNEL */
+ return (0);
+ }
+
+ oemcp->oempage.value =
+ MEM_ZALLOC("oem", max_oem_index * sizeof (mts_wchar_t));
+ if (oemcp->oempage.value == 0) {
+#ifndef _KERNEL
+ (void) mutex_unlock(&mutex);
+#endif /* _KERNEL */
+ return (-1);
+ }
+
+ oemcp->unicodepage.value =
+ MEM_ZALLOC("oem", MAX_UNI_IDX * sizeof (mts_wchar_t));
+ if (oemcp->unicodepage.value == 0) {
+ MEM_FREE("oem", oemcp->oempage.value);
+ oemcp->oempage.value = 0;
+#ifndef _KERNEL
+ (void) mutex_unlock(&mutex);
+#endif /* _KERNEL */
+ return (-1);
+ }
+
+ /*
+ * The default English page is stored in kernel.
+ * Therefore, no need to go to codepage files.
+ */
+#ifndef _KERNEL
+ if (cpid == oem_default_smb_cpid)
+ default_oem_cp = oem_default_smb_cp;
+ else if (cpid == oem_default_telnet_cpid)
+ default_oem_cp = oem_default_telnet_cp;
+ else
+ default_oem_cp = 0;
+#else /* _KERNEL */
+ default_oem_cp = oem_default_smb_cp;
+#endif /* _KERNEL */
+
+ if (default_oem_cp) {
+ int i;
+
+ for (i = 0; i < max_oem_index; i++) {
+ oemcp->oempage.value[i] = default_oem_cp[i];
+ oemcp->unicodepage.value[default_oem_cp[i]] =
+ (mts_wchar_t)i;
+ }
+#ifdef _KERNEL
+ }
+ /*
+ * XXX This doesn't seem right. How do we handle the situation
+ * where default_oem_cp == 0 in the kernel?
+ * Is this a PBSHORTCUT?
+ */
+#else
+ } else {
+
+ /*
+ * The codepage is not one of the default that stores
+ * in the include
+ * file; therefore, we need to read from the file.
+ */
+ (void) snprintf(filePath, sizeof (filePath),
+ "%s/%s", codepagePath, oemcp->filename);
+ fp = fopen(filePath, "r");
+
+ if (fp == 0) {
+ MEM_FREE("oem", oemcp->oempage.value);
+ MEM_FREE("oem", oemcp->unicodepage.value);
+#ifndef _KERNEL
+ (void) mutex_unlock(&mutex);
+#endif /* _KERNEL */
+ return (-1);
+ }
+
+ while (fgets(buf, 32, fp) != 0) {
+ char *endptr;
+ unsigned int oemval, unival;
+
+ endptr = (char *)strchr(buf, ' ');
+ if (endptr == 0) {
+ continue;
+ }
+
+ oemval = strtol(buf, &endptr, 0);
+ unival = strtol(endptr+1, 0, 0);
+
+ if (oemval >= max_oem_index || unival >= MAX_UNI_IDX) {
+ continue;
+ }
+
+ oemcp->oempage.value[oemval] = unival;
+ oemcp->unicodepage.value[unival] = oemval;
+ }
+ (void) fclose(fp);
+ }
+#endif /* _KERNEL */
+
+ oemcp->valid = 1;
+#ifndef _KERNEL
+ (void) mutex_unlock(&mutex);
+#endif /* _KERNEL */
+ return (0);
+}
+
+
+
+
+/*
+ * oem_codepage_free
+ *
+ * This function will clear the valid bit and free the memory
+ * allocated to the oem/unipage by oem_codepage_init if the ref count
+ * is zero.
+ */
+void
+oem_codepage_free(unsigned int cpid)
+{
+ oem_codepage_t *oemcp;
+
+ if (cpid >= MAX_OEMPAGES || !oemcp_table[cpid].valid)
+ return;
+
+ oemcp = &oemcp_table[cpid];
+ oemcp->valid--;
+
+ if (oemcp->ref != 0 || oemcp->valid != 0)
+ return;
+
+ if (oemcp->oempage.value != 0) {
+ MEM_FREE("oem", oemcp->oempage.value);
+ oemcp->oempage.value = 0;
+ }
+
+ if (oemcp->unicodepage.value != 0) {
+ MEM_FREE("oem", oemcp->unicodepage.value);
+ oemcp->unicodepage.value = 0;
+ }
+}
+
+
+
+/*
+ * oem_get_oempage
+ *
+ * This function will return the current oempage and increment
+ * the ref count. The function oem_release_page should always
+ * be called when finish using the oempage to decrement the
+ * ref count.
+ */
+static oempage_t *
+oem_get_oempage(unsigned int cpid)
+{
+ if (cpid >= MAX_OEMPAGES)
+ return (0);
+
+ if (oemcp_table[cpid].valid) {
+ oemcp_table[cpid].ref++;
+ return (&oemcp_table[cpid].oempage);
+ }
+ return (0);
+}
+
+
+
+/*
+ * oem_get_unipage
+ *
+ * This function will return the current unipage and increment
+ * the ref count. The function oem_release_page should always
+ * be called when finish using the unipage to decrement the
+ * ref count.
+ */
+static oempage_t *
+oem_get_unipage(unsigned int cpid)
+{
+ if (cpid >= MAX_OEMPAGES)
+ return (0);
+
+ if (oemcp_table[cpid].valid) {
+ oemcp_table[cpid].ref++;
+ return (&oemcp_table[cpid].unicodepage);
+ }
+ return (0);
+}
+
+
+
+/*
+ * oem_release_page
+ *
+ * This function will decrement the ref count and check the valid
+ * bit. It will free the memory allocated for the pages
+ * if the
+ * valid bit is not set, ref count is zero and the page is not
+ * already freed.
+ */
+static void
+oem_release_page(oempage_t *page)
+{
+ oem_codepage_t *oemcp = &oemcp_table[page->cpid];
+
+ page = 0;
+
+ if (oemcp->ref > 0)
+ oemcp->ref--;
+
+ if (oemcp->ref != 0 || oemcp->valid)
+ return;
+
+ if (oemcp->oempage.value != 0) {
+ MEM_FREE("oem", oemcp->oempage.value);
+ oemcp->oempage.value = 0;
+ }
+
+ if (oemcp->unicodepage.value != 0) {
+ MEM_FREE("oem", oemcp->unicodepage.value);
+ oemcp->unicodepage.value = 0;
+ }
+}
+
+
+
+/*
+ * unicodestooems
+ *
+ * Convert unicode string to oem string. The function will stop
+ * converting the unicode string when size nbytes - 1 is reached
+ * or when there is not enough room to store another unicode.
+ * If the function is called when the codepage is not initialized
+ * or when the codepage initialize failed, it will return 0.
+ * Otherwise, the total # of the converted unicode is returned.
+ */
+size_t
+unicodestooems(
+ char *oemstring,
+ const mts_wchar_t *unicodestring,
+ size_t nbytes,
+ unsigned int cpid)
+{
+ oempage_t *unipage;
+ unsigned int count = 0;
+ mts_wchar_t oemchar;
+
+ if (cpid >= MAX_OEMPAGES)
+ return (0);
+
+ if (unicodestring == 0 || oemstring == 0)
+ return (0);
+
+ if ((unipage = oem_get_unipage(cpid)) == 0)
+ return (0);
+
+ while ((oemchar = unipage->value[*unicodestring]) != 0) {
+ if (oemchar & 0xff00 && nbytes >= MTS_MB_CHAR_MAX) {
+ *oemstring++ = oemchar >> 8;
+ *oemstring++ = (char)oemchar;
+ nbytes -= 2;
+ } else if (nbytes > 1) {
+ *oemstring++ = (char)oemchar;
+ nbytes--;
+ } else
+ break;
+
+ count++;
+ unicodestring++;
+ }
+
+ *oemstring = 0;
+
+ oem_release_page(unipage);
+
+ return (count);
+}
+
+
+
+/*
+ * oemstounicodes
+ *
+ * Convert oem string to unicode string. The function will stop
+ * converting the oem string when unicodestring len reaches nwchars - 1.
+ * or when there is not enough room to store another oem char.
+ * If the function is called when the codepage is not initialized
+ * or when the codepage initialize failed, it will return 0.
+ * Otherwise, the total # of the converted oem chars is returned.
+ * The oem char can be either 1 or 2 bytes.
+ */
+size_t
+oemstounicodes(
+ mts_wchar_t *unicodestring,
+ const char *oemstring,
+ size_t nwchars,
+ unsigned int cpid)
+{
+ oempage_t *oempage;
+ size_t count = nwchars;
+ mts_wchar_t oemchar;
+
+ if (cpid >= MAX_OEMPAGES)
+ return (0);
+
+ if (unicodestring == 0 || oemstring == 0)
+ return (0);
+
+ if ((oempage = oem_get_oempage(cpid)) == 0)
+ return (0);
+
+ while ((oemchar = (mts_wchar_t)*oemstring++ & 0xff) != 0) {
+ /*
+ * Cannot find one byte oemchar in table. Must be
+ * a lead byte. Try two bytes.
+ */
+
+ if ((oempage->value[oemchar] == 0) && (oemchar != 0)) {
+ oemchar = oemchar << 8 | (*oemstring++ & 0xff);
+ if (oempage->value[oemchar] == 0) {
+ *unicodestring = 0;
+ break;
+ }
+ }
+#ifdef _BIG_ENDIAN
+ *unicodestring = LE_IN16(&oempage->value[oemchar]);
+#else
+ *unicodestring = oempage->value[oemchar];
+#endif
+ count--;
+ unicodestring++;
+ }
+
+ *unicodestring = 0;
+
+ oem_release_page(oempage);
+
+ return (nwchars - count);
+}
+
+/*
+ * oem_get_lang_table
+ *
+ * This function returns a pointer to the language table.
+ */
+language *
+oem_get_lang_table(void)
+{
+ return (lang_table);
+}
+
+/*
+ * oem_no_of_languages
+ *
+ * This function returns total languages support in the system.
+ */
+int
+oem_no_of_languages(void)
+{
+ return (sizeof (lang_table)/sizeof (lang_table[0]));
+}
+
+
+#ifndef _KERNEL
+#if 1
+/*
+ * TESTING Functions
+ */
+void
+oemcp_print(unsigned int cpid)
+{
+ unsigned int bytesperchar, max_index, i;
+ oempage_t *oempage, *unipage;
+ unsigned int counter = 0;
+
+ if (cpid >= MAX_OEMPAGES) {
+ (void) printf("oemcp cpid %d is invalid\n", cpid);
+ return;
+ }
+
+ if ((oempage = oem_get_oempage(cpid)) == 0) {
+ (void) printf("oemcp of cpid %d is invalid\n", cpid);
+ return;
+ }
+
+ if ((unipage = oem_get_unipage(cpid)) == 0) {
+ (void) printf("unicp of cpid %d is invalid\n", cpid);
+ return;
+ }
+
+ if ((bytesperchar = oem_codepage_bytesperchar(cpid)) == 0) {
+ (void) printf("bytesperchar of cpid %d is not correct\n", cpid);
+ return;
+ }
+
+ max_index = 1 << bytesperchar * 8;
+
+ (void) printf("OEMPAGE:\n");
+ for (i = 0; i < max_index; i++) {
+ if ((counter + 1) % 4 == 0 &&
+ (oempage->value[i] != 0 || i == 0)) {
+ (void) printf("%x %x\n", i, oempage->value[i]);
+ counter++;
+ } else if (oempage->value[i] != 0 || i == 0) {
+ (void) printf("%x %x, ", i, oempage->value[i]);
+ counter++;
+ }
+ }
+ counter = 0;
+ (void) printf("\n\nUNIPAGE:\n");
+ for (i = 0; i < 65536; i++) {
+ if ((counter + 1) % 8 == 0 &&
+ (unipage->value[i] != 0 || i == 0)) {
+ (void) printf("%x %x\n", i, unipage->value[i]);
+ counter++;
+ } else if (unipage->value[i] != 0 || i == 0) {
+ (void) printf("%x %x, ", i, unipage->value[i]);
+ counter++;
+ }
+ }
+ (void) printf("\n");
+ oem_release_page(oempage);
+ oem_release_page(unipage);
+}
+
+
+
+void
+oemstringtest(unsigned int cpid)
+{
+ unsigned char *c, *cbuf;
+ unsigned char cbuf1[100] = {0xfe, 0xfd, 0xf2, 0xe9,
+ 0x63, 0xce, 0xdb, 0x8c, 0x9c, 0x21, 0};
+ unsigned char cbuf2[100] = {0xfe, 0xfc, 0x63, 0x81, 0x42,
+ 0x91, 0x40, 0x24, 0xff, 0x49};
+ mts_wchar_t buf[100], *wc;
+
+ if (cpid == 1)
+ cbuf = cbuf1;
+ else if (cpid == 2)
+ cbuf = cbuf2;
+
+ /*
+ * Before oem->uni conversion.
+ */
+ (void) printf("Before oem->uni conversion: ");
+ for (c = cbuf; *c != 0; c++)
+ (void) printf("%x ", *c);
+ (void) printf("\n");
+
+ /*
+ * oem->uni conversion
+ */
+ (void) oemstounicodes(buf, (const char *)cbuf, 100, cpid);
+
+ /*
+ * After oem->uni conversion.
+ */
+ (void) printf("After oem->uni conversion: ");
+ for (wc = buf; *wc != 0; wc++)
+ (void) printf("%x ", *wc);
+ (void) printf("\n");
+
+ /*
+ * uni->oem conversion
+ */
+ (void) unicodestooems((char *)cbuf, buf, 100, cpid);
+
+ /*
+ * After uni->oem conversion.
+ */
+ (void) printf("After uni->oem conversion: ");
+ for (c = cbuf; *c != 0; c++)
+ (void) printf("%x ", *c);
+ (void) printf("\n");
+}
+#endif
+#endif /* _KERNEL */
diff --git a/usr/src/common/smbsrv/smb_opmlang.c b/usr/src/common/smbsrv/smb_opmlang.c
new file mode 100644
index 0000000000..af7ee73cb1
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_opmlang.c
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/string.h>
+#include <smbsrv/codepage.h>
+#include <smbsrv/oem.h>
+
+static unsigned int smb_cpid = NO_OF_OEM_CP_INDS;
+static unsigned int telnet_cpid = NO_OF_OEM_CP_INDS;
+
+/*
+ * oem_get_smb_cpid
+ *
+ * This function returns the cpid for current smb codepage.
+ */
+unsigned int
+oem_get_smb_cpid(void)
+{
+ return (smb_cpid);
+}
+
+/*
+ * oem_get_telnet_cpid
+ *
+ * This function returns the cpid for current telnet codepage.
+ */
+unsigned int
+oem_get_telnet_cpid(void)
+{
+ return (telnet_cpid);
+}
+
+/*
+ * oem_current_language
+ *
+ * This function will return the current language setting.
+ * The current language is stored in env "codepage.oem.language".
+ * If the env does not exist, "None Selected" will be returned.
+ */
+char *
+oem_current_language()
+{
+#ifdef PBSHORTCUT
+ char *p = getenv("codepage.oem.language");
+
+ if (p)
+ return (p);
+#endif
+ return ("None Selected");
+}
+
+
+/*
+ * oem_language_set
+ *
+ * This function will set the oem language and correct
+ * env variables.
+ */
+int
+oem_language_set(char *lang_name)
+{
+ int i;
+ language *lang_table = oem_get_lang_table();
+
+ for (i = 0; i < NO_OF_LANGUAGES; i++) {
+ if (utf8_strcasecmp(lang_name, lang_table[i].language) == 0) {
+ unsigned int oldSmbIndex = smb_cpid;
+ unsigned int oldTelnetIndex = telnet_cpid;
+ if (oem_codepage_init(lang_table[i].smbIndex) < 0 ||
+ oem_codepage_init(lang_table[i].telnetIndex) < 0) {
+ oem_codepage_free(lang_table[i].smbIndex);
+ oem_codepage_free(lang_table[i].telnetIndex);
+ (void) oem_codepage_init(oem_default_smb_cpid);
+ (void) oem_codepage_init(
+ oem_default_telnet_cpid);
+ smb_cpid = oem_default_smb_cpid;
+ telnet_cpid = oem_default_telnet_cpid;
+#ifdef PBSHORTCUT
+ setenv("codepage.oem.language",
+ oem_default_language);
+#endif
+ } else {
+ smb_cpid = lang_table[i].smbIndex;
+ telnet_cpid = lang_table[i].telnetIndex;
+#ifdef PBSHORTCUT
+ setenv("codepage.oem.language",
+ lang_table[i].language);
+#endif
+ }
+#ifdef PBSHORTCUT
+ saveenv();
+#endif
+
+ if (oldSmbIndex < NO_OF_OEM_CP_INDS)
+ oem_codepage_free(oldSmbIndex);
+ if (oldTelnetIndex < NO_OF_OEM_CP_INDS)
+ oem_codepage_free(oldTelnetIndex);
+ return (0);
+ }
+ }
+
+ return (-1);
+}
diff --git a/usr/src/common/smbsrv/smb_share_door_decode.c b/usr/src/common/smbsrv/smb_share_door_decode.c
new file mode 100644
index 0000000000..cc3f2884e8
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_share_door_decode.c
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Encode/decode functions used by both lmshare door server and client.
+ */
+
+#ifndef _KERNEL
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#else
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/errno.h>
+#endif
+
+#include <smbsrv/lmshare.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/smbinfo.h>
+
+void
+smb_dr_get_kconfig(smb_dr_ctx_t *ctx, smb_kmod_cfg_t *cfg)
+{
+ if (ctx->status == 0) {
+ (void) memcpy(cfg, ctx->ptr, sizeof (smb_kmod_cfg_t));
+ ctx->ptr += sizeof (smb_kmod_cfg_t);
+ }
+ else
+ bzero(cfg, sizeof (smb_kmod_cfg_t));
+}
+
+void
+smb_dr_put_kconfig(smb_dr_ctx_t *ctx, smb_kmod_cfg_t *cfg)
+{
+ if (ctx->ptr + sizeof (smb_kmod_cfg_t) <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, cfg, sizeof (smb_kmod_cfg_t));
+ ctx->ptr += sizeof (smb_kmod_cfg_t);
+ }
+ else
+ ctx->status = ENOSPC;
+}
+
+void
+smb_dr_get_lmshare(smb_dr_ctx_t *ctx, lmshare_info_t *si)
+{
+ if (ctx->status == 0) {
+ if (smb_dr_get_int32(ctx)) {
+ (void) memcpy(si, ctx->ptr, sizeof (lmshare_info_t));
+ ctx->ptr += sizeof (lmshare_info_t);
+ }
+ else
+ bzero(si, sizeof (lmshare_info_t));
+ }
+ else
+ bzero(si, sizeof (lmshare_info_t));
+}
+
+void
+smb_dr_put_lmshare(smb_dr_ctx_t *ctx, lmshare_info_t *si)
+{
+ if (si) {
+ smb_dr_put_int32(ctx, 1);
+ if (ctx->ptr + sizeof (lmshare_info_t) <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr, si, sizeof (lmshare_info_t));
+ ctx->ptr += sizeof (lmshare_info_t);
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+ else
+ smb_dr_put_int32(ctx, 0);
+}
+
+uint64_t
+smb_dr_get_lmshr_iterator(smb_dr_ctx_t *ctx)
+{
+ uint64_t lmshr_iter;
+
+ if (smb_dr_get_int32(ctx))
+ lmshr_iter = smb_dr_get_uint64(ctx);
+ else
+ lmshr_iter = 0;
+
+ return (lmshr_iter);
+}
+
+void
+smb_dr_put_lmshr_iterator(smb_dr_ctx_t *ctx, uint64_t lmshr_iter)
+{
+ if (lmshr_iter) {
+ smb_dr_put_int32(ctx, 1);
+ smb_dr_put_uint64(ctx, lmshr_iter);
+ }
+ else
+ smb_dr_put_int32(ctx, 0);
+}
+
+void
+smb_dr_get_lmshr_list(smb_dr_ctx_t *ctx, lmshare_list_t *shrlist)
+{
+ if (ctx->status == 0) {
+ if (smb_dr_get_int32(ctx)) {
+ (void) memcpy(shrlist,
+ ctx->ptr, sizeof (lmshare_list_t));
+ ctx->ptr += sizeof (lmshare_list_t);
+ }
+ else
+ bzero(shrlist, sizeof (lmshare_list_t));
+ }
+ else
+ bzero(shrlist, sizeof (lmshare_list_t));
+}
+
+void
+smb_dr_put_lmshr_list(smb_dr_ctx_t *ctx, lmshare_list_t *shrlist)
+{
+ if (shrlist) {
+ smb_dr_put_int32(ctx, 1);
+ if (ctx->ptr + sizeof (lmshare_list_t) <= ctx->end_ptr) {
+ (void) memcpy(ctx->ptr,
+ shrlist, sizeof (lmshare_list_t));
+ ctx->ptr += sizeof (lmshare_list_t);
+ }
+ else
+ ctx->status = ENOSPC;
+ }
+ else
+ smb_dr_put_int32(ctx, 0);
+}
diff --git a/usr/src/common/smbsrv/smb_sid.c b/usr/src/common/smbsrv/smb_sid.c
new file mode 100644
index 0000000000..ffbb3048ed
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_sid.c
@@ -0,0 +1,587 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Security Identifier (SID) library functions.
+ */
+
+#ifndef _KERNEL
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <smbsrv/libsmb.h>
+#else /* _KERNEL */
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#endif /* _KERNEL */
+
+#include <smbsrv/alloc.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smbinfo.h>
+
+
+/*
+ * nt_sid_is_valid
+ *
+ * Check that a sid is valid. The checking is minimal: check the pointer
+ * is valid and that the revision and sub-authority count is legal.
+ * Returns 1 if the sid appears to be valid. Otherwise 0.
+ */
+int
+nt_sid_is_valid(nt_sid_t *sid)
+{
+ if (sid == 0)
+ return (0);
+
+ return (sid->Revision == NT_SID_REVISION &&
+ sid->SubAuthCount < NT_SID_SUBAUTH_MAX) ? 1 : 0;
+}
+
+
+/*
+ * nt_sid_length
+ *
+ * Returns the number of bytes required to hold the sid.
+ */
+int
+nt_sid_length(nt_sid_t *sid)
+{
+ if (sid == 0)
+ return (0);
+
+ return (sizeof (nt_sid_t) - sizeof (DWORD)
+ + (sid->SubAuthCount * sizeof (DWORD)));
+}
+
+
+/*
+ * nt_sid_dup
+ *
+ * Make a duplicate of the specified sid. The memory for the new sid is
+ * allocated using malloc so the caller should call free when it is no
+ * longer required. A pointer to the new sid is returned.
+ */
+nt_sid_t *
+nt_sid_dup(nt_sid_t *sid)
+{
+ nt_sid_t *new_sid;
+ int size;
+ int i;
+
+ if (sid == 0)
+ return (0);
+
+ size = sizeof (nt_sid_t)
+ + (sid->SubAuthCount * sizeof (DWORD))
+ + sizeof (DWORD);
+
+ if ((new_sid = MEM_MALLOC("libnt", size)) == 0)
+ return (0);
+
+ (void) memcpy(new_sid, sid, sizeof (nt_sid_t));
+
+ for (i = 0; i < sid->SubAuthCount && i < NT_SID_SUBAUTH_MAX; ++i)
+ new_sid->SubAuthority[i] = sid->SubAuthority[i];
+
+ return (new_sid);
+}
+
+
+/*
+ * nt_sid_splice
+ *
+ * Make a full user sid from the domain sid and the user relative id
+ * (rid). The memory for the new sid is allocated using malloc so the
+ * caller should call free when it is no longer required. A pointer
+ * to the new sid is returned.
+ */
+nt_sid_t *
+nt_sid_splice(nt_sid_t *domain_sid, DWORD rid)
+{
+ nt_sid_t *sid;
+ int size;
+ int i;
+
+ if (domain_sid == 0)
+ return (0);
+
+ size = sizeof (nt_sid_t)
+ + (domain_sid->SubAuthCount * sizeof (DWORD))
+ + sizeof (DWORD);
+
+ if ((sid = MEM_MALLOC("libnt", size)) == 0)
+ return (0);
+
+ (void) memcpy(sid, domain_sid, sizeof (nt_sid_t));
+
+ for (i = 0; i < sid->SubAuthCount && i < NT_SID_SUBAUTH_MAX; ++i)
+ sid->SubAuthority[i] = domain_sid->SubAuthority[i];
+
+ sid->SubAuthority[i] = rid;
+ ++sid->SubAuthCount;
+ return (sid);
+}
+
+
+/*
+ * nt_sid_get_rid
+ *
+ * Return the Relative Id (RID) from the specified SID. It is the
+ * caller's responsibility to ensure that this is an appropriate SID.
+ * All we do here is return the last sub-authority from the SID.
+ */
+int
+nt_sid_get_rid(nt_sid_t *sid, DWORD *rid)
+{
+ if (!nt_sid_is_valid(sid))
+ return (-1);
+
+ if (sid->SubAuthCount == 0) {
+ return (-1);
+ }
+
+ if (rid)
+ *rid = sid->SubAuthority[sid->SubAuthCount - 1];
+ return (0);
+}
+
+
+/*
+ * nt_sid_split
+ *
+ * Take a full user sid and split it into the domain sid and the user
+ * relative id (rid). The original sid is modified in place - use
+ * nt_sid_dup before calling this function to preserve the original SID.
+ */
+int
+nt_sid_split(nt_sid_t *sid, DWORD *rid)
+{
+ if (!nt_sid_is_valid(sid)) {
+ return (-1);
+ }
+
+ if (sid->SubAuthCount == 0) {
+ return (-1);
+ }
+
+ --sid->SubAuthCount;
+ if (rid)
+ *rid = sid->SubAuthority[sid->SubAuthCount];
+ return (0);
+}
+
+
+/*
+ * nt_sid_gen_null_sid
+ *
+ * This function allocates a SID structure and initializes it as the
+ * well-known Null SID (S-1-0-0). A pointer to the SID is returned.
+ * As the memory for this structure is obtained via malloc, it is the
+ * caller's responsibility to free the memory when it is no longer
+ * required. If malloc fails, a null pointer is returned.
+ */
+nt_sid_t *
+nt_sid_gen_null_sid(void)
+{
+ nt_sid_t *sid;
+ int size;
+
+ size = sizeof (nt_sid_t) + sizeof (DWORD);
+
+ if ((sid = MEM_MALLOC("libnt", size)) == 0) {
+ return (0);
+ }
+
+ sid->Revision = 1;
+ sid->SubAuthCount = 1;
+ return (sid);
+}
+
+
+/*
+ * nt_sid_is_equal
+ *
+ * Compare two SIDs and return a boolean result. The checks are ordered
+ * such that components that are more likely to differ are checked
+ * first. For example, after checking that the SIDs contain the same
+ * SubAuthCount, we check the sub-authorities in reverse order because
+ * the RID is the most likely differentiator between two SIDs, i.e.
+ * they are probably going to be in the same domain.
+ *
+ * Returns 1 if the SIDs are equal. Otherwise returns 0.
+ */
+int
+nt_sid_is_equal(nt_sid_t *sid1, nt_sid_t *sid2)
+{
+ int i;
+
+ if (sid1 == 0 || sid2 == 0)
+ return (0);
+
+ if (sid1->SubAuthCount != sid2->SubAuthCount ||
+ sid1->Revision != sid2->Revision)
+ return (0);
+
+ for (i = sid1->SubAuthCount - 1; i >= 0; --i)
+ if (sid1->SubAuthority[i] != sid2->SubAuthority[i])
+ return (0);
+
+ if (bcmp(&sid1->Authority, &sid2->Authority, NT_SID_AUTH_MAX))
+ return (0);
+
+ return (1);
+}
+
+/*
+ * nt_sid_is_indomain
+ *
+ * Check if given SID is in given domain.
+ * Returns 1 on success. Otherwise returns 0.
+ */
+int
+nt_sid_is_indomain(nt_sid_t *domain_sid, nt_sid_t *sid)
+{
+ int i;
+
+ if (sid == 0 || domain_sid == 0) {
+ return (0);
+ }
+
+ if (domain_sid->Revision != sid->Revision ||
+ sid->SubAuthCount < domain_sid->SubAuthCount)
+ return (0);
+
+ for (i = domain_sid->SubAuthCount - 1; i >= 0; --i)
+ if (domain_sid->SubAuthority[i] != sid->SubAuthority[i])
+ return (0);
+
+ if (bcmp(&domain_sid->Authority, &sid->Authority, NT_SID_AUTH_MAX))
+ return (0);
+
+ return (1);
+}
+
+#ifndef _KERNEL
+/*
+ * nt_sid_is_local
+ *
+ * Check a SID to see if it belongs to the local domain. This is almost
+ * the same as checking that two SIDs are equal except that we don't
+ * care if the specified SID contains extra sub-authorities. We're only
+ * interested in the domain part.
+ *
+ * Returns 1 if the SIDs are equal. Otherwise returns 0.
+ */
+int
+nt_sid_is_local(nt_sid_t *sid)
+{
+ nt_sid_t *local_sid;
+
+ local_sid = nt_domain_local_sid();
+ return (nt_sid_is_indomain(local_sid, sid));
+}
+
+/*
+ * nt_sid_is_builtin
+ *
+ * Check a SID to see if it belongs to the builtin domain.
+ * Returns 1 if the SID is a builtin SID. Otherwise returns 0.
+ */
+int
+nt_sid_is_builtin(nt_sid_t *sid)
+{
+ nt_domain_t *domain;
+
+ domain = nt_domain_lookupbytype(NT_DOMAIN_BUILTIN);
+ if (domain == 0)
+ return (0);
+ return (nt_sid_is_indomain(domain->sid, sid));
+}
+#endif /* _KERNEL */
+
+/*
+ * nt_sid_is_domain_equal
+ *
+ * Compare two SIDs's domain and return a boolean result.
+ *
+ * Returns 1 if the domain SID are the same. Otherwise returns 0.
+ */
+int
+nt_sid_is_domain_equal(nt_sid_t *pSid1, nt_sid_t *pSid2)
+{
+ int i, n;
+
+ if (pSid1->Revision != pSid2->Revision)
+ return (0);
+
+ if (pSid1->SubAuthCount != pSid2->SubAuthCount)
+ return (0);
+
+ if (bcmp(pSid1->Authority, pSid2->Authority, NT_SID_AUTH_MAX) != 0)
+ return (0);
+
+ n = pSid1->SubAuthCount;
+
+ n -= 1; /* don't compare last SubAuthority[] (aka RID) */
+
+ for (i = 0; i < n; i++)
+ if (pSid1->SubAuthority[i] != pSid2->SubAuthority[i])
+ return (0);
+
+ return (1);
+}
+
+/*
+ * nt_sid_logf
+ *
+ * Format a sid and write it to the system log. See nt_sid_format
+ * for format information.
+ */
+void
+nt_sid_logf(nt_sid_t *sid)
+{
+ char *s;
+
+ if ((s = nt_sid_format(sid)) == 0)
+ return;
+
+ MEM_FREE("libnt", s);
+}
+
+
+/*
+ * nt_sid_format
+ *
+ * Format a sid and return it as a string. The memory for the string is
+ * allocated using malloc so the caller should call free when it is no
+ * longer required. A pointer to the string is returned.
+ */
+char *
+nt_sid_format(nt_sid_t *sid)
+{
+ int i;
+ char *fmtbuf;
+ char *p;
+
+ if (sid == 0)
+ return (0);
+
+ if ((fmtbuf = MEM_MALLOC("libnt", NT_SID_FMTBUF_SIZE)) == 0)
+ return (0);
+
+ p = fmtbuf;
+ (void) sprintf(p, "S-%d-", sid->Revision);
+ while (*p)
+ ++p;
+
+ for (i = 0; i < NT_SID_AUTH_MAX; ++i) {
+ if (sid->Authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) {
+ (void) sprintf(p, "%d", sid->Authority[i]);
+ while (*p)
+ ++p;
+ }
+ }
+
+ for (i = 0; i < sid->SubAuthCount && i < NT_SID_SUBAUTH_MAX; ++i) {
+ (void) sprintf(p, "-%u", sid->SubAuthority[i]);
+ while (*p)
+ ++p;
+ }
+
+ return (fmtbuf);
+}
+
+/*
+ * nt_sid_format2
+ *
+ * Format a sid and return it in the passed buffer.
+ */
+void
+nt_sid_format2(nt_sid_t *sid, char *fmtbuf)
+{
+ int i;
+ char *p;
+
+ if (sid == 0 || fmtbuf == 0)
+ return;
+
+ p = fmtbuf;
+ (void) sprintf(p, "S-%d-", sid->Revision);
+ while (*p)
+ ++p;
+
+ for (i = 0; i < NT_SID_AUTH_MAX; ++i) {
+ if (sid->Authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) {
+ (void) sprintf(p, "%d", sid->Authority[i]);
+ while (*p)
+ ++p;
+ }
+ }
+
+ for (i = 0; i < sid->SubAuthCount && i < NT_SID_SUBAUTH_MAX; ++i) {
+ (void) sprintf(p, "-%u", sid->SubAuthority[i]);
+ while (*p)
+ ++p;
+ }
+}
+
+/*
+ * nt_sid_strtosid
+ *
+ * Converts a SID in string form to a SID structure. There are lots of
+ * simplifying assumptions in here. The memory for the SID is allocated
+ * as if it was the largest possible SID; the caller is responsible for
+ * freeing the memory when it is no longer required. We assume that the
+ * string starts with "S-1-" and that the authority is held in the last
+ * byte, which should be okay for most situations. It also assumes the
+ * sub-authorities are in decimal format.
+ *
+ * On success, a pointer to a SID is returned. Otherwise a null pointer
+ * is returned.
+ *
+ * XXX this function may have endian issues
+ */
+nt_sid_t *
+nt_sid_strtosid(char *sidstr)
+{
+ nt_sid_t *sid;
+ char *p;
+ int size;
+ BYTE i;
+#ifdef _KERNEL
+ long sua;
+#endif /* _KERNEL */
+
+ if (sidstr == 0) {
+ return (0);
+ }
+
+ if (strncmp(sidstr, "S-1-", 4) != 0) {
+ return (0);
+ }
+
+ size = sizeof (nt_sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (DWORD));
+
+ if ((sid = MEM_MALLOC("libnt", size)) == 0) {
+ return (0);
+ }
+
+ bzero(sid, size);
+ sid->Revision = NT_SID_REVISION;
+#ifndef _KERNEL
+ sid->Authority[5] = atoi(&sidstr[4]);
+#else /* _KERNEL */
+ sua = 0;
+ /* XXX Why are we treating sua as a long/unsigned long? */
+ (void) ddi_strtoul(&sidstr[4], 0, 10, (unsigned long *)&sua);
+ sid->Authority[5] = (BYTE)sua;
+#endif /* _KERNEL */
+
+ for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) {
+ while (*p && *p == '-')
+ ++p;
+
+ if (*p < '0' || *p > '9') {
+ MEM_FREE("libnt", sid);
+ return (0);
+ }
+
+#ifndef _KERNEL
+ sid->SubAuthority[i] = strtoul(p, 0, 10);
+#else /* _KERNEL */
+ sua = 0;
+ (void) ddi_strtoul(p, 0, 10, (unsigned long *)&sua);
+ sid->SubAuthority[i] = (DWORD)sua;
+#endif /* _KERNEL */
+
+ while (*p && *p != '-')
+ ++p;
+ }
+
+ sid->SubAuthCount = i;
+ return (sid);
+}
+
+
+/*
+ * nt_sid_name_use
+ *
+ * Returns the text name for a SID_NAME_USE value. The SID_NAME_USE
+ * provides the context for a SID, i.e. the type of resource to which
+ * it refers.
+ */
+char *
+nt_sid_name_use(unsigned int snu_id)
+{
+ static char *snu_name[] = {
+ "SidTypeSidPrefix",
+ "SidTypeUser",
+ "SidTypeGroup",
+ "SidTypeDomain",
+ "SidTypeAlias",
+ "SidTypeWellKnownGroup",
+ "SidTypeDeletedAccount",
+ "SidTypeInvalid",
+ "SidTypeUnknown"
+ };
+
+ if (snu_id < ((sizeof (snu_name)/sizeof (snu_name[0]))))
+ return (snu_name[snu_id]);
+ else {
+ return (snu_name[SidTypeUnknown]);
+ }
+}
+
+
+/*
+ * nt_sid_copy
+ *
+ * Copy information of srcsid to dessid. The buffer should be allocated
+ * for dessid before passing to this function. The size of buffer for
+ * dessid should be specified in the buflen.
+ *
+ * Returns total bytes of information copied. If there is an error, 0
+ * will be returned.
+ */
+int
+nt_sid_copy(nt_sid_t *dessid, nt_sid_t *srcsid, unsigned buflen)
+{
+ unsigned n_bytes;
+
+ if (!dessid || !srcsid)
+ return (0);
+
+ n_bytes = nt_sid_length(srcsid);
+ if (n_bytes > buflen)
+ return (0);
+
+ bcopy((char *)srcsid, (char *)dessid, n_bytes);
+
+ return (n_bytes);
+}
diff --git a/usr/src/common/smbsrv/smb_status_xlat.c b/usr/src/common/smbsrv/smb_status_xlat.c
new file mode 100644
index 0000000000..987a154403
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_status_xlat.c
@@ -0,0 +1,597 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides a text translation service for NT status codes.
+ */
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#else
+#include <syslog.h>
+#include <stdio.h>
+#endif /* _KERNEL */
+#include <smbsrv/ntstatus.h>
+
+typedef struct xlate_table {
+ DWORD value;
+ char *name;
+} xlate_table_t;
+
+
+static xlate_table_t ntx_table[] = {
+ { NT_STATUS_SUCCESS, "SUCCESS" },
+ { NT_STATUS_UNSUCCESSFUL, "UNSUCCESSFUL" },
+ { NT_STATUS_NOT_IMPLEMENTED, "NOT_IMPLEMENTED" },
+ { NT_STATUS_INVALID_INFO_CLASS, "INVALID_INFO_CLASS" },
+ { NT_STATUS_INFO_LENGTH_MISMATCH, "INFO_LENGTH_MISMATCH" },
+ { NT_STATUS_BUFFER_OVERFLOW, "BUFFER_OVERFLOW" },
+ /*
+ * There seems to be some overloading of status codes.
+ * NT_STATUS_IN_PAGE_ERROR is NT_STATUS_NO_MORE_FILES
+ */
+ { NT_STATUS_NO_MORE_FILES, "NO MORE FILES" },
+ { NT_STATUS_PAGEFILE_QUOTA, "PAGEFILE_QUOTA" },
+ { NT_STATUS_INVALID_HANDLE, "INVALID_HANDLE" },
+ { NT_STATUS_BAD_INITIAL_STACK, "BAD_INITIAL_STACK" },
+ { NT_STATUS_BAD_INITIAL_PC, "BAD_INITIAL_PC" },
+ { NT_STATUS_INVALID_CID, "INVALID_CID" },
+ { NT_STATUS_TIMER_NOT_CANCELED, "TIMER_NOT_CANCELED" },
+ { NT_STATUS_INVALID_PARAMETER, "INVALID_PARAMETER" },
+ { NT_STATUS_NO_SUCH_DEVICE, "NO_SUCH_DEVICE" },
+ { NT_STATUS_NO_SUCH_FILE, "NO_SUCH_FILE" },
+ { NT_STATUS_INVALID_DEVICE_REQUEST, "INVALID_DEVICE_REQUEST" },
+ { NT_STATUS_END_OF_FILE, "END_OF_FILE" },
+ { NT_STATUS_WRONG_VOLUME, "WRONG_VOLUME" },
+ { NT_STATUS_NO_MEDIA_IN_DEVICE, "NO_MEDIA_IN_DEVICE" },
+ { NT_STATUS_UNRECOGNIZED_MEDIA, "UNRECOGNIZED_MEDIA" },
+ { NT_STATUS_NONEXISTENT_SECTOR, "NONEXISTENT_SECTOR" },
+ { NT_STATUS_MORE_PROCESSING_REQUIRED, "MORE_PROCESSING_REQUIRED" },
+ { NT_STATUS_NO_MEMORY, "NO_MEMORY" },
+ { NT_STATUS_CONFLICTING_ADDRESSES, "CONFLICTING_ADDRESSES" },
+ { NT_STATUS_NOT_MAPPED_VIEW, "NOT_MAPPED_VIEW" },
+
+ /*
+ * There seems to be some overloading of status codes.
+ * When we get NT_STATUS_UNABLE_TO_FREE_VM it really
+ * means NT_STATUS_NO_MORE_DATA.
+ */
+ { NT_STATUS_UNABLE_TO_FREE_VM, "NO_MORE_DATA" },
+
+ { NT_STATUS_UNABLE_TO_DELETE_SECTION, "UNABLE_TO_DELETE_SECTION" },
+ { NT_STATUS_INVALID_SYSTEM_SERVICE, "INVALID_SYSTEM_SERVICE" },
+ { NT_STATUS_ILLEGAL_INSTRUCTION, "ILLEGAL_INSTRUCTION" },
+ { NT_STATUS_INVALID_LOCK_SEQUENCE, "INVALID_LOCK_SEQUENCE" },
+ { NT_STATUS_INVALID_VIEW_SIZE, "INVALID_VIEW_SIZE" },
+ { NT_STATUS_INVALID_FILE_FOR_SECTION, "INVALID_FILE_FOR_SECTION" },
+ { NT_STATUS_ALREADY_COMMITTED, "ALREADY_COMMITTED" },
+ { NT_STATUS_ACCESS_DENIED, "ACCESS_DENIED" },
+ { NT_STATUS_BUFFER_TOO_SMALL, "BUFFER_TOO_SMALL" },
+ { NT_STATUS_OBJECT_TYPE_MISMATCH, "OBJECT_TYPE_MISMATCH" },
+ { NT_STATUS_NONCONTINUABLE_EXCEPTION, "NONCONTINUABLE_EXCEPTION" },
+ { NT_STATUS_INVALID_DISPOSITION, "INVALID_DISPOSITION" },
+ { NT_STATUS_UNWIND, "UNWIND" },
+ { NT_STATUS_BAD_STACK, "BAD_STACK" },
+ { NT_STATUS_INVALID_UNWIND_TARGET, "INVALID_UNWIND_TARGET" },
+ { NT_STATUS_NOT_LOCKED, "NOT_LOCKED" },
+ { NT_STATUS_PARITY_ERROR, "PARITY_ERROR" },
+ { NT_STATUS_UNABLE_TO_DECOMMIT_VM, "UNABLE_TO_DECOMMIT_VM" },
+ { NT_STATUS_NOT_COMMITTED, "NOT_COMMITTED" },
+ { NT_STATUS_INVALID_PORT_ATTRIBUTES, "INVALID_PORT_ATTRIBUTES" },
+ { NT_STATUS_PORT_MESSAGE_TOO_LONG, "PORT_MESSAGE_TOO_LONG" },
+ { NT_STATUS_INVALID_PARAMETER_MIX, "INVALID_PARAMETER_MIX" },
+ { NT_STATUS_INVALID_QUOTA_LOWER, "INVALID_QUOTA_LOWER" },
+ { NT_STATUS_DISK_CORRUPT_ERROR, "DISK_CORRUPT_ERROR" },
+ { NT_STATUS_OBJECT_NAME_INVALID, "OBJECT_NAME_INVALID" },
+ { NT_STATUS_OBJECT_NAME_NOT_FOUND, "OBJECT_NAME_NOT_FOUND" },
+ { NT_STATUS_OBJECT_NAME_COLLISION, "OBJECT_NAME_COLLISION" },
+ { NT_STATUS_HANDLE_NOT_WAITABLE, "HANDLE_NOT_WAITABLE" },
+ { NT_STATUS_PORT_DISCONNECTED, "PORT_DISCONNECTED" },
+ { NT_STATUS_DEVICE_ALREADY_ATTACHED, "DEVICE_ALREADY_ATTACHED" },
+ { NT_STATUS_OBJECT_PATH_INVALID, "OBJECT_PATH_INVALID" },
+ { NT_STATUS_OBJECT_PATH_NOT_FOUND, "OBJECT_PATH_NOT_FOUND" },
+ { NT_STATUS_OBJECT_PATH_SYNTAX_BAD, "OBJECT_PATH_SYNTAX_BAD" },
+ { NT_STATUS_DATA_OVERRUN, "DATA_OVERRUN" },
+ { NT_STATUS_DATA_LATE_ERROR, "DATA_LATE_ERROR" },
+ { NT_STATUS_DATA_ERROR, "DATA_ERROR" },
+ { NT_STATUS_CRC_ERROR, "CRC_ERROR" },
+ { NT_STATUS_SECTION_TOO_BIG, "SECTION_TOO_BIG" },
+ { NT_STATUS_PORT_CONNECTION_REFUSED, "PORT_CONNECTION_REFUSED" },
+ { NT_STATUS_INVALID_PORT_HANDLE, "INVALID_PORT_HANDLE" },
+ { NT_STATUS_SHARING_VIOLATION, "SHARING_VIOLATION" },
+ { NT_STATUS_QUOTA_EXCEEDED, "QUOTA_EXCEEDED" },
+ { NT_STATUS_INVALID_PAGE_PROTECTION, "INVALID_PAGE_PROTECTION" },
+ { NT_STATUS_MUTANT_NOT_OWNED, "MUTANT_NOT_OWNED" },
+ { NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED, "SEMAPHORE_LIMIT_EXCEEDED" },
+ { NT_STATUS_PORT_ALREADY_SET, "PORT_ALREADY_SET" },
+ { NT_STATUS_SECTION_NOT_IMAGE, "SECTION_NOT_IMAGE" },
+ { NT_STATUS_SUSPEND_COUNT_EXCEEDED, "SUSPEND_COUNT_EXCEEDED" },
+ { NT_STATUS_THREAD_IS_TERMINATING, "THREAD_IS_TERMINATING" },
+ { NT_STATUS_BAD_WORKING_SET_LIMIT, "BAD_WORKING_SET_LIMIT" },
+ { NT_STATUS_INCOMPATIBLE_FILE_MAP, "INCOMPATIBLE_FILE_MAP" },
+ { NT_STATUS_SECTION_PROTECTION, "SECTION_PROTECTION" },
+ { NT_STATUS_EAS_NOT_SUPPORTED, "EAS_NOT_SUPPORTED" },
+ { NT_STATUS_EA_TOO_LARGE, "EA_TOO_LARGE" },
+ { NT_STATUS_NONEXISTENT_EA_ENTRY, "NONEXISTENT_EA_ENTRY" },
+ { NT_STATUS_NO_EAS_ON_FILE, "NO_EAS_ON_FILE" },
+ { NT_STATUS_EA_CORRUPT_ERROR, "EA_CORRUPT_ERROR" },
+ { NT_STATUS_FILE_LOCK_CONFLICT, "FILE_LOCK_CONFLICT" },
+ { NT_STATUS_LOCK_NOT_GRANTED, "LOCK_NOT_GRANTED" },
+ { NT_STATUS_DELETE_PENDING, "DELETE_PENDING" },
+ { NT_STATUS_CTL_FILE_NOT_SUPPORTED, "CTL_FILE_NOT_SUPPORTED" },
+ { NT_STATUS_UNKNOWN_REVISION, "UNKNOWN_REVISION" },
+ { NT_STATUS_REVISION_MISMATCH, "REVISION_MISMATCH" },
+ { NT_STATUS_INVALID_OWNER, "INVALID_OWNER" },
+ { NT_STATUS_INVALID_PRIMARY_GROUP, "INVALID_PRIMARY_GROUP" },
+ { NT_STATUS_NO_IMPERSONATION_TOKEN, "NO_IMPERSONATION_TOKEN" },
+ { NT_STATUS_CANT_DISABLE_MANDATORY, "CANT_DISABLE_MANDATORY" },
+ { NT_STATUS_NO_LOGON_SERVERS, "NO_LOGON_SERVERS" },
+ { NT_STATUS_NO_SUCH_LOGON_SESSION, "NO_SUCH_LOGON_SESSION" },
+ { NT_STATUS_NO_SUCH_PRIVILEGE, "NO_SUCH_PRIVILEGE" },
+ { NT_STATUS_PRIVILEGE_NOT_HELD, "PRIVILEGE_NOT_HELD" },
+ { NT_STATUS_INVALID_ACCOUNT_NAME, "INVALID_ACCOUNT_NAME" },
+ { NT_STATUS_USER_EXISTS, "USER_EXISTS" },
+ { NT_STATUS_NO_SUCH_USER, "NO_SUCH_USER" },
+ { NT_STATUS_GROUP_EXISTS, "GROUP_EXISTS" },
+ { NT_STATUS_NO_SUCH_GROUP, "NO_SUCH_GROUP" },
+ { NT_STATUS_MEMBER_IN_GROUP, "MEMBER_IN_GROUP" },
+ { NT_STATUS_MEMBER_NOT_IN_GROUP, "MEMBER_NOT_IN_GROUP" },
+ { NT_STATUS_LAST_ADMIN, "LAST_ADMIN" },
+ { NT_STATUS_WRONG_PASSWORD, "WRONG_PASSWORD" },
+ { NT_STATUS_ILL_FORMED_PASSWORD, "ILL_FORMED_PASSWORD" },
+ { NT_STATUS_PASSWORD_RESTRICTION, "PASSWORD_RESTRICTION" },
+ { NT_STATUS_LOGON_FAILURE, "LOGON_FAILURE" },
+ { NT_STATUS_ACCOUNT_RESTRICTION, "ACCOUNT_RESTRICTION" },
+ { NT_STATUS_INVALID_LOGON_HOURS, "INVALID_LOGON_HOURS" },
+ { NT_STATUS_INVALID_WORKSTATION, "INVALID_WORKSTATION" },
+ { NT_STATUS_PASSWORD_EXPIRED, "PASSWORD_EXPIRED" },
+ { NT_STATUS_ACCOUNT_DISABLED, "ACCOUNT_DISABLED" },
+ { NT_STATUS_NONE_MAPPED, "NONE_MAPPED" },
+ { NT_STATUS_TOO_MANY_LUIDS_REQUESTED, "TOO_MANY_LUIDS_REQUESTED" },
+ { NT_STATUS_LUIDS_EXHAUSTED, "LUIDS_EXHAUSTED" },
+ { NT_STATUS_INVALID_SUB_AUTHORITY, "INVALID_SUB_AUTHORITY" },
+ { NT_STATUS_INVALID_ACL, "INVALID_ACL" },
+ { NT_STATUS_INVALID_SID, "INVALID_SID" },
+ { NT_STATUS_INVALID_SECURITY_DESCR, "INVALID_SECURITY_DESCR" },
+ { NT_STATUS_PROCEDURE_NOT_FOUND, "PROCEDURE_NOT_FOUND" },
+ { NT_STATUS_INVALID_IMAGE_FORMAT, "INVALID_IMAGE_FORMAT" },
+ { NT_STATUS_NO_TOKEN, "NO_TOKEN" },
+ { NT_STATUS_BAD_INHERITANCE_ACL, "BAD_INHERITANCE_ACL" },
+ { NT_STATUS_RANGE_NOT_LOCKED, "RANGE_NOT_LOCKED" },
+ { NT_STATUS_DISK_FULL, "DISK_FULL" },
+ { NT_STATUS_SERVER_DISABLED, "SERVER_DISABLED" },
+ { NT_STATUS_SERVER_NOT_DISABLED, "SERVER_NOT_DISABLED" },
+ { NT_STATUS_TOO_MANY_GUIDS_REQUESTED, "TOO_MANY_GUIDS_REQUESTED" },
+ { NT_STATUS_GUIDS_EXHAUSTED, "GUIDS_EXHAUSTED" },
+ { NT_STATUS_INVALID_ID_AUTHORITY, "INVALID_ID_AUTHORITY" },
+ { NT_STATUS_AGENTS_EXHAUSTED, "AGENTS_EXHAUSTED" },
+ { NT_STATUS_INVALID_VOLUME_LABEL, "INVALID_VOLUME_LABEL" },
+ { NT_STATUS_SECTION_NOT_EXTENDED, "SECTION_NOT_EXTENDED" },
+ { NT_STATUS_NOT_MAPPED_DATA, "NOT_MAPPED_DATA" },
+ { NT_STATUS_RESOURCE_DATA_NOT_FOUND, "RESOURCE_DATA_NOT_FOUND" },
+ { NT_STATUS_RESOURCE_TYPE_NOT_FOUND, "RESOURCE_TYPE_NOT_FOUND" },
+ { NT_STATUS_RESOURCE_NAME_NOT_FOUND, "RESOURCE_NAME_NOT_FOUND" },
+ { NT_STATUS_ARRAY_BOUNDS_EXCEEDED, "ARRAY_BOUNDS_EXCEEDED" },
+ { NT_STATUS_FLOAT_DENORMAL_OPERAND, "FLOAT_DENORMAL_OPERAND" },
+ { NT_STATUS_FLOAT_DIVIDE_BY_ZERO, "FLOAT_DIVIDE_BY_ZERO" },
+ { NT_STATUS_FLOAT_INEXACT_RESULT, "FLOAT_INEXACT_RESULT" },
+ { NT_STATUS_FLOAT_INVALID_OPERATION, "FLOAT_INVALID_OPERATION" },
+ { NT_STATUS_FLOAT_OVERFLOW, "FLOAT_OVERFLOW" },
+ { NT_STATUS_FLOAT_STACK_CHECK, "FLOAT_STACK_CHECK" },
+ { NT_STATUS_FLOAT_UNDERFLOW, "FLOAT_UNDERFLOW" },
+ { NT_STATUS_INTEGER_DIVIDE_BY_ZERO, "INTEGER_DIVIDE_BY_ZERO" },
+ { NT_STATUS_INTEGER_OVERFLOW, "INTEGER_OVERFLOW" },
+ { NT_STATUS_PRIVILEGED_INSTRUCTION, "PRIVILEGED_INSTRUCTION" },
+ { NT_STATUS_TOO_MANY_PAGING_FILES, "TOO_MANY_PAGING_FILES" },
+ { NT_STATUS_FILE_INVALID, "FILE_INVALID" },
+ { NT_STATUS_ALLOTTED_SPACE_EXCEEDED, "ALLOTTED_SPACE_EXCEEDED" },
+ { NT_STATUS_INSUFFICIENT_RESOURCES, "INSUFFICIENT_RESOURCES" },
+ { NT_STATUS_DFS_EXIT_PATH_FOUND, "DFS_EXIT_PATH_FOUND" },
+ { NT_STATUS_DEVICE_DATA_ERROR, "DEVICE_DATA_ERROR" },
+ { NT_STATUS_DEVICE_NOT_CONNECTED, "DEVICE_NOT_CONNECTED" },
+ { NT_STATUS_DEVICE_POWER_FAILURE, "DEVICE_POWER_FAILURE" },
+ { NT_STATUS_FREE_VM_NOT_AT_BASE, "FREE_VM_NOT_AT_BASE" },
+ { NT_STATUS_MEMORY_NOT_ALLOCATED, "MEMORY_NOT_ALLOCATED" },
+ { NT_STATUS_WORKING_SET_QUOTA, "WORKING_SET_QUOTA" },
+ { NT_STATUS_MEDIA_WRITE_PROTECTED, "MEDIA_WRITE_PROTECTED" },
+ { NT_STATUS_DEVICE_NOT_READY, "DEVICE_NOT_READY" },
+ { NT_STATUS_INVALID_GROUP_ATTRIBUTES, "INVALID_GROUP_ATTRIBUTES" },
+ { NT_STATUS_BAD_IMPERSONATION_LEVEL, "BAD_IMPERSONATION_LEVEL" },
+ { NT_STATUS_CANT_OPEN_ANONYMOUS, "CANT_OPEN_ANONYMOUS" },
+ { NT_STATUS_BAD_VALIDATION_CLASS, "BAD_VALIDATION_CLASS" },
+ { NT_STATUS_BAD_TOKEN_TYPE, "BAD_TOKEN_TYPE" },
+ { NT_STATUS_BAD_MASTER_BOOT_RECORD, "BAD_MASTER_BOOT_RECORD" },
+ { NT_STATUS_INSTRUCTION_MISALIGNMENT, "INSTRUCTION_MISALIGNMENT" },
+ { NT_STATUS_INSTANCE_NOT_AVAILABLE, "INSTANCE_NOT_AVAILABLE" },
+ { NT_STATUS_PIPE_NOT_AVAILABLE, "PIPE_NOT_AVAILABLE" },
+ { NT_STATUS_INVALID_PIPE_STATE, "INVALID_PIPE_STATE" },
+ { NT_STATUS_PIPE_BUSY, "PIPE_BUSY" },
+ { NT_STATUS_ILLEGAL_FUNCTION, "ILLEGAL_FUNCTION" },
+ { NT_STATUS_PIPE_DISCONNECTED, "PIPE_DISCONNECTED" },
+ { NT_STATUS_PIPE_CLOSING, "PIPE_CLOSING" },
+ { NT_STATUS_PIPE_CONNECTED, "PIPE_CONNECTED" },
+ { NT_STATUS_PIPE_LISTENING, "PIPE_LISTENING" },
+ { NT_STATUS_INVALID_READ_MODE, "INVALID_READ_MODE" },
+ { NT_STATUS_IO_TIMEOUT, "IO_TIMEOUT" },
+ { NT_STATUS_FILE_FORCED_CLOSED, "FILE_FORCED_CLOSED" },
+ { NT_STATUS_PROFILING_NOT_STARTED, "PROFILING_NOT_STARTED" },
+ { NT_STATUS_PROFILING_NOT_STOPPED, "PROFILING_NOT_STOPPED" },
+ { NT_STATUS_COULD_NOT_INTERPRET, "COULD_NOT_INTERPRET" },
+ { NT_STATUS_FILE_IS_A_DIRECTORY, "FILE_IS_A_DIRECTORY" },
+ { NT_STATUS_NOT_SUPPORTED, "NOT_SUPPORTED" },
+ { NT_STATUS_REMOTE_NOT_LISTENING, "REMOTE_NOT_LISTENING" },
+ { NT_STATUS_DUPLICATE_NAME, "DUPLICATE_NAME" },
+ { NT_STATUS_BAD_NETWORK_PATH, "BAD_NETWORK_PATH" },
+ { NT_STATUS_NETWORK_BUSY, "NETWORK_BUSY" },
+ { NT_STATUS_DEVICE_DOES_NOT_EXIST, "DEVICE_DOES_NOT_EXIST" },
+ { NT_STATUS_TOO_MANY_COMMANDS, "TOO_MANY_COMMANDS" },
+ { NT_STATUS_ADAPTER_HARDWARE_ERROR, "ADAPTER_HARDWARE_ERROR" },
+ { NT_STATUS_INVALID_NETWORK_RESPONSE, "INVALID_NETWORK_RESPONSE" },
+ { NT_STATUS_UNEXPECTED_NETWORK_ERROR, "UNEXPECTED_NETWORK_ERROR" },
+ { NT_STATUS_BAD_REMOTE_ADAPTER, "BAD_REMOTE_ADAPTER" },
+ { NT_STATUS_PRINT_QUEUE_FULL, "PRINT_QUEUE_FULL" },
+ { NT_STATUS_NO_SPOOL_SPACE, "NO_SPOOL_SPACE" },
+ { NT_STATUS_PRINT_CANCELLED, "PRINT_CANCELLED" },
+ { NT_STATUS_NETWORK_NAME_DELETED, "NETWORK_NAME_DELETED" },
+ { NT_STATUS_NETWORK_ACCESS_DENIED, "NETWORK_ACCESS_DENIED" },
+ { NT_STATUS_BAD_DEVICE_TYPE, "BAD_DEVICE_TYPE" },
+ { NT_STATUS_BAD_NETWORK_NAME, "BAD_NETWORK_NAME" },
+ { NT_STATUS_TOO_MANY_NAMES, "TOO_MANY_NAMES" },
+ { NT_STATUS_TOO_MANY_SESSIONS, "TOO_MANY_SESSIONS" },
+ { NT_STATUS_SHARING_PAUSED, "SHARING_PAUSED" },
+ { NT_STATUS_REQUEST_NOT_ACCEPTED, "REQUEST_NOT_ACCEPTED" },
+ { NT_STATUS_REDIRECTOR_PAUSED, "REDIRECTOR_PAUSED" },
+ { NT_STATUS_NET_WRITE_FAULT, "NET_WRITE_FAULT" },
+ { NT_STATUS_PROFILING_AT_LIMIT, "PROFILING_AT_LIMIT" },
+ { NT_STATUS_NOT_SAME_DEVICE, "NOT_SAME_DEVICE" },
+ { NT_STATUS_FILE_RENAMED, "FILE_RENAMED" },
+ { NT_STATUS_VIRTUAL_CIRCUIT_CLOSED, "VIRTUAL_CIRCUIT_CLOSED" },
+ { NT_STATUS_NO_SECURITY_ON_OBJECT, "NO_SECURITY_ON_OBJECT" },
+ { NT_STATUS_CANT_WAIT, "CANT_WAIT" },
+ { NT_STATUS_PIPE_EMPTY, "PIPE_EMPTY" },
+ { NT_STATUS_CANT_ACCESS_DOMAIN_INFO, "CANT_ACCESS_DOMAIN_INFO" },
+ { NT_STATUS_CANT_TERMINATE_SELF, "CANT_TERMINATE_SELF" },
+ { NT_STATUS_INVALID_SERVER_STATE, "INVALID_SERVER_STATE" },
+ { NT_STATUS_INVALID_DOMAIN_STATE, "INVALID_DOMAIN_STATE" },
+ { NT_STATUS_INVALID_DOMAIN_ROLE, "INVALID_DOMAIN_ROLE" },
+ { NT_STATUS_NO_SUCH_DOMAIN, "NO_SUCH_DOMAIN" },
+ { NT_STATUS_DOMAIN_EXISTS, "DOMAIN_EXISTS" },
+ { NT_STATUS_DOMAIN_LIMIT_EXCEEDED, "DOMAIN_LIMIT_EXCEEDED" },
+ { NT_STATUS_OPLOCK_NOT_GRANTED, "OPLOCK_NOT_GRANTED" },
+ { NT_STATUS_INVALID_OPLOCK_PROTOCOL, "INVALID_OPLOCK_PROTOCOL" },
+ { NT_STATUS_INTERNAL_DB_CORRUPTION, "INTERNAL_DB_CORRUPTION" },
+ { NT_STATUS_INTERNAL_ERROR, "INTERNAL_ERROR" },
+ { NT_STATUS_GENERIC_NOT_MAPPED, "GENERIC_NOT_MAPPED" },
+ { NT_STATUS_BAD_DESCRIPTOR_FORMAT, "BAD_DESCRIPTOR_FORMAT" },
+ { NT_STATUS_INVALID_USER_BUFFER, "INVALID_USER_BUFFER" },
+ { NT_STATUS_UNEXPECTED_IO_ERROR, "UNEXPECTED_IO_ERROR" },
+ { NT_STATUS_UNEXPECTED_MM_CREATE_ERR, "UNEXPECTED_MM_CREATE_ERR" },
+ { NT_STATUS_UNEXPECTED_MM_MAP_ERROR, "UNEXPECTED_MM_MAP_ERROR" },
+ { NT_STATUS_UNEXPECTED_MM_EXTEND_ERR, "UNEXPECTED_MM_EXTEND_ERR" },
+ { NT_STATUS_NOT_LOGON_PROCESS, "NOT_LOGON_PROCESS" },
+ { NT_STATUS_LOGON_SESSION_EXISTS, "LOGON_SESSION_EXISTS" },
+ { NT_STATUS_INVALID_PARAMETER_1, "INVALID_PARAMETER_1" },
+ { NT_STATUS_INVALID_PARAMETER_2, "INVALID_PARAMETER_2" },
+ { NT_STATUS_INVALID_PARAMETER_3, "INVALID_PARAMETER_3" },
+ { NT_STATUS_INVALID_PARAMETER_4, "INVALID_PARAMETER_4" },
+ { NT_STATUS_INVALID_PARAMETER_5, "INVALID_PARAMETER_5" },
+ { NT_STATUS_INVALID_PARAMETER_6, "INVALID_PARAMETER_6" },
+ { NT_STATUS_INVALID_PARAMETER_7, "INVALID_PARAMETER_7" },
+ { NT_STATUS_INVALID_PARAMETER_8, "INVALID_PARAMETER_8" },
+ { NT_STATUS_INVALID_PARAMETER_9, "INVALID_PARAMETER_9" },
+ { NT_STATUS_INVALID_PARAMETER_10, "INVALID_PARAMETER_10" },
+ { NT_STATUS_INVALID_PARAMETER_11, "INVALID_PARAMETER_11" },
+ { NT_STATUS_INVALID_PARAMETER_12, "INVALID_PARAMETER_12" },
+ { NT_STATUS_REDIRECTOR_NOT_STARTED, "REDIRECTOR_NOT_STARTED" },
+ { NT_STATUS_REDIRECTOR_STARTED, "REDIRECTOR_STARTED" },
+ { NT_STATUS_STACK_OVERFLOW, "STACK_OVERFLOW" },
+ { NT_STATUS_NO_SUCH_PACKAGE, "NO_SUCH_PACKAGE" },
+ { NT_STATUS_BAD_FUNCTION_TABLE, "BAD_FUNCTION_TABLE" },
+ { NT_STATUS_DIRECTORY_NOT_EMPTY, "DIRECTORY_NOT_EMPTY" },
+ { NT_STATUS_FILE_CORRUPT_ERROR, "FILE_CORRUPT_ERROR" },
+ { NT_STATUS_NOT_A_DIRECTORY, "NOT_A_DIRECTORY" },
+ { NT_STATUS_BAD_LOGON_SESSION_STATE, "BAD_LOGON_SESSION_STATE" },
+ { NT_STATUS_LOGON_SESSION_COLLISION, "LOGON_SESSION_COLLISION" },
+ { NT_STATUS_NAME_TOO_LONG, "NAME_TOO_LONG" },
+ { NT_STATUS_FILES_OPEN, "FILES_OPEN" },
+ { NT_STATUS_CONNECTION_IN_USE, "CONNECTION_IN_USE" },
+ { NT_STATUS_MESSAGE_NOT_FOUND, "MESSAGE_NOT_FOUND" },
+ { NT_STATUS_PROCESS_IS_TERMINATING, "PROCESS_IS_TERMINATING" },
+ { NT_STATUS_INVALID_LOGON_TYPE, "INVALID_LOGON_TYPE" },
+ { NT_STATUS_NO_GUID_TRANSLATION, "NO_GUID_TRANSLATION" },
+ { NT_STATUS_CANNOT_IMPERSONATE, "CANNOT_IMPERSONATE" },
+ { NT_STATUS_IMAGE_ALREADY_LOADED, "IMAGE_ALREADY_LOADED" },
+ { NT_STATUS_ABIOS_NOT_PRESENT, "ABIOS_NOT_PRESENT" },
+ { NT_STATUS_ABIOS_LID_NOT_EXIST, "ABIOS_LID_NOT_EXIST" },
+ { NT_STATUS_ABIOS_LID_ALREADY_OWNED, "ABIOS_LID_ALREADY_OWNED" },
+ { NT_STATUS_ABIOS_NOT_LID_OWNER, "ABIOS_NOT_LID_OWNER" },
+ { NT_STATUS_ABIOS_INVALID_COMMAND, "ABIOS_INVALID_COMMAND" },
+ { NT_STATUS_ABIOS_INVALID_LID, "ABIOS_INVALID_LID" },
+ { NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE,
+ "ABIOS_SELECTOR_NOT_AVAILABLE" },
+ { NT_STATUS_ABIOS_INVALID_SELECTOR, "ABIOS_INVALID_SELECTOR" },
+ { NT_STATUS_NO_LDT, "NO_LDT" },
+ { NT_STATUS_INVALID_LDT_SIZE, "INVALID_LDT_SIZE" },
+ { NT_STATUS_INVALID_LDT_OFFSET, "INVALID_LDT_OFFSET" },
+ { NT_STATUS_INVALID_LDT_DESCRIPTOR, "INVALID_LDT_DESCRIPTOR" },
+ { NT_STATUS_INVALID_IMAGE_NE_FORMAT, "INVALID_IMAGE_NE_FORMAT" },
+ { NT_STATUS_RXACT_INVALID_STATE, "RXACT_INVALID_STATE" },
+ { NT_STATUS_RXACT_COMMIT_FAILURE, "RXACT_COMMIT_FAILURE" },
+ { NT_STATUS_MAPPED_FILE_SIZE_ZERO, "MAPPED_FILE_SIZE_ZERO" },
+ { NT_STATUS_TOO_MANY_OPENED_FILES, "TOO_MANY_OPENED_FILES" },
+ { NT_STATUS_CANCELLED, "CANCELLED" },
+ { NT_STATUS_CANNOT_DELETE, "CANNOT_DELETE" },
+ { NT_STATUS_INVALID_COMPUTER_NAME, "INVALID_COMPUTER_NAME" },
+ { NT_STATUS_FILE_DELETED, "FILE_DELETED" },
+ { NT_STATUS_SPECIAL_ACCOUNT, "SPECIAL_ACCOUNT" },
+ { NT_STATUS_SPECIAL_GROUP, "SPECIAL_GROUP" },
+ { NT_STATUS_SPECIAL_USER, "SPECIAL_USER" },
+ { NT_STATUS_MEMBERS_PRIMARY_GROUP, "MEMBERS_PRIMARY_GROUP" },
+ { NT_STATUS_FILE_CLOSED, "FILE_CLOSED" },
+ { NT_STATUS_TOO_MANY_THREADS, "TOO_MANY_THREADS" },
+ { NT_STATUS_THREAD_NOT_IN_PROCESS, "THREAD_NOT_IN_PROCESS" },
+ { NT_STATUS_TOKEN_ALREADY_IN_USE, "TOKEN_ALREADY_IN_USE" },
+ { NT_STATUS_PAGEFILE_QUOTA_EXCEEDED, "PAGEFILE_QUOTA_EXCEEDED" },
+ { NT_STATUS_COMMITMENT_LIMIT, "COMMITMENT_LIMIT" },
+ { NT_STATUS_INVALID_IMAGE_LE_FORMAT, "INVALID_IMAGE_LE_FORMAT" },
+ { NT_STATUS_INVALID_IMAGE_NOT_MZ, "INVALID_IMAGE_NOT_MZ" },
+ { NT_STATUS_INVALID_IMAGE_PROTECT, "INVALID_IMAGE_PROTECT" },
+ { NT_STATUS_INVALID_IMAGE_WIN_16, "INVALID_IMAGE_WIN_16" },
+ { NT_STATUS_LOGON_SERVER_CONFLICT, "LOGON_SERVER_CONFLICT" },
+ { NT_STATUS_TIME_DIFFERENCE_AT_DC, "TIME_DIFFERENCE_AT_DC" },
+ { NT_STATUS_SYNCHRONIZATION_REQUIRED, "SYNCHRONIZATION_REQUIRED" },
+ { NT_STATUS_DLL_NOT_FOUND, "DLL_NOT_FOUND" },
+ { NT_STATUS_OPEN_FAILED, "OPEN_FAILED" },
+ { NT_STATUS_IO_PRIVILEGE_FAILED, "IO_PRIVILEGE_FAILED" },
+ { NT_STATUS_ORDINAL_NOT_FOUND, "ORDINAL_NOT_FOUND" },
+ { NT_STATUS_ENTRYPOINT_NOT_FOUND, "ENTRYPOINT_NOT_FOUND" },
+ { NT_STATUS_CONTROL_C_EXIT, "CONTROL_C_EXIT" },
+ { NT_STATUS_LOCAL_DISCONNECT, "LOCAL_DISCONNECT" },
+ { NT_STATUS_REMOTE_DISCONNECT, "REMOTE_DISCONNECT" },
+ { NT_STATUS_REMOTE_RESOURCES, "REMOTE_RESOURCES" },
+ { NT_STATUS_LINK_FAILED, "LINK_FAILED" },
+ { NT_STATUS_LINK_TIMEOUT, "LINK_TIMEOUT" },
+ { NT_STATUS_INVALID_CONNECTION, "INVALID_CONNECTION" },
+ { NT_STATUS_INVALID_ADDRESS, "INVALID_ADDRESS" },
+ { NT_STATUS_DLL_INIT_FAILED, "DLL_INIT_FAILED" },
+ { NT_STATUS_MISSING_SYSTEMFILE, "MISSING_SYSTEMFILE" },
+ { NT_STATUS_UNHANDLED_EXCEPTION, "UNHANDLED_EXCEPTION" },
+ { NT_STATUS_APP_INIT_FAILURE, "APP_INIT_FAILURE" },
+ { NT_STATUS_PAGEFILE_CREATE_FAILED, "PAGEFILE_CREATE_FAILED" },
+ { NT_STATUS_NO_PAGEFILE, "NO_PAGEFILE" },
+ { NT_STATUS_INVALID_LEVEL, "INVALID_LEVEL" },
+ { NT_STATUS_WRONG_PASSWORD_CORE, "WRONG_PASSWORD_CORE" },
+ { NT_STATUS_ILLEGAL_FLOAT_CONTEXT, "ILLEGAL_FLOAT_CONTEXT" },
+ { NT_STATUS_PIPE_BROKEN, "PIPE_BROKEN" },
+ { NT_STATUS_REGISTRY_CORRUPT, "REGISTRY_CORRUPT" },
+ { NT_STATUS_REGISTRY_IO_FAILED, "REGISTRY_IO_FAILED" },
+ { NT_STATUS_NO_EVENT_PAIR, "NO_EVENT_PAIR" },
+ { NT_STATUS_UNRECOGNIZED_VOLUME, "UNRECOGNIZED_VOLUME" },
+ { NT_STATUS_SERIAL_NO_DEVICE_INITED, "SERIAL_NO_DEVICE_INITED" },
+ { NT_STATUS_NO_SUCH_ALIAS, "NO SUCH ALIAS" },
+ { NT_STATUS_MEMBER_NOT_IN_ALIAS, "MEMBER NOT IN ALIAS" },
+ { NT_STATUS_MEMBER_IN_ALIAS, "MEMBER IN ALIAS" },
+ { NT_STATUS_ALIAS_EXISTS, "ALIAS EXISTS" },
+ { NT_STATUS_LOGON_NOT_GRANTED, "LOGON_NOT_GRANTED" },
+ { NT_STATUS_TOO_MANY_SECRETS, "TOO_MANY_SECRETS" },
+ { NT_STATUS_SECRET_TOO_LONG, "SECRET_TOO_LONG" },
+ { NT_STATUS_INTERNAL_DB_ERROR, "INTERNAL_DB_ERROR" },
+ { NT_STATUS_FULLSCREEN_MODE, "FULLSCREEN_MODE" },
+ { NT_STATUS_TOO_MANY_CONTEXT_IDS, "TOO_MANY_CONTEXT_IDS" },
+ { NT_STATUS_LOGON_TYPE_NOT_GRANTED, "LOGON_TYPE_NOT_GRANTED" },
+ { NT_STATUS_NOT_REGISTRY_FILE, "NOT_REGISTRY_FILE" },
+ { NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED,
+ "NT_CROSS_ENCRYPTION_REQUIRED" },
+ { NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR, "DOMAIN_CTRLR_CONFIG_ERROR" },
+ { NT_STATUS_FT_MISSING_MEMBER, "FT_MISSING_MEMBER" },
+ { NT_STATUS_ILL_FORMED_SERVICE_ENTRY, "ILL_FORMED_SERVICE_ENTRY" },
+ { NT_STATUS_ILLEGAL_CHARACTER, "ILLEGAL_CHARACTER" },
+ { NT_STATUS_UNMAPPABLE_CHARACTER, "UNMAPPABLE_CHARACTER" },
+ { NT_STATUS_UNDEFINED_CHARACTER, "UNDEFINED_CHARACTER" },
+ { NT_STATUS_FLOPPY_VOLUME, "FLOPPY_VOLUME" },
+ { NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND, "FLOPPY_ID_MARK_NOT_FOUND" },
+ { NT_STATUS_FLOPPY_WRONG_CYLINDER, "FLOPPY_WRONG_CYLINDER" },
+ { NT_STATUS_FLOPPY_UNKNOWN_ERROR, "FLOPPY_UNKNOWN_ERROR" },
+ { NT_STATUS_FLOPPY_BAD_REGISTERS, "FLOPPY_BAD_REGISTERS" },
+ { NT_STATUS_DISK_RECALIBRATE_FAILED, "DISK_RECALIBRATE_FAILED" },
+ { NT_STATUS_DISK_OPERATION_FAILED, "DISK_OPERATION_FAILED" },
+ { NT_STATUS_DISK_RESET_FAILED, "DISK_RESET_FAILED" },
+ { NT_STATUS_SHARED_IRQ_BUSY, "SHARED_IRQ_BUSY" },
+ { NT_STATUS_FT_ORPHANING, "FT_ORPHANING" },
+ { NT_STATUS_PARTITION_FAILURE, "PARTITION_FAILURE" },
+ { NT_STATUS_INVALID_BLOCK_LENGTH, "INVALID_BLOCK_LENGTH" },
+ { NT_STATUS_DEVICE_NOT_PARTITIONED, "DEVICE_NOT_PARTITIONED" },
+ { NT_STATUS_UNABLE_TO_LOCK_MEDIA, "UNABLE_TO_LOCK_MEDIA" },
+ { NT_STATUS_UNABLE_TO_UNLOAD_MEDIA, "UNABLE_TO_UNLOAD_MEDIA" },
+ { NT_STATUS_EOM_OVERFLOW, "EOM_OVERFLOW" },
+ { NT_STATUS_NO_MEDIA, "NO_MEDIA" },
+ { NT_STATUS_NO_SUCH_MEMBER, "NO SUCH MEMBER" },
+ { NT_STATUS_INVALID_MEMBER, "INVALID MEMBER" },
+ { NT_STATUS_KEY_DELETED, "KEY_DELETED" },
+ { NT_STATUS_NO_LOG_SPACE, "NO_LOG_SPACE" },
+ { NT_STATUS_TOO_MANY_SIDS, "TOO MANY SIDS" },
+ { NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED,
+ "LM_CROSS_ENCRYPTION_REQUIRED" },
+ { NT_STATUS_KEY_HAS_CHILDREN, "KEY_HAS_CHILDREN" },
+ { NT_STATUS_CHILD_MUST_BE_VOLATILE, "CHILD_MUST_BE_VOLATILE" },
+ { NT_STATUS_DEVICE_CONFIGURATION_ERROR, "DEVICE_CONFIGURATION_ERROR" },
+ { NT_STATUS_DRIVER_INTERNAL_ERROR, "DRIVER_INTERNAL_ERROR" },
+ { NT_STATUS_INVALID_DEVICE_STATE, "INVALID_DEVICE_STATE" },
+ { NT_STATUS_IO_DEVICE_ERROR, "IO_DEVICE_ERROR" },
+ { NT_STATUS_DEVICE_PROTOCOL_ERROR, "DEVICE_PROTOCOL_ERROR" },
+ { NT_STATUS_BACKUP_CONTROLLER, "BACKUP_CONTROLLER" },
+ { NT_STATUS_LOG_FILE_FULL, "LOG_FILE_FULL" },
+ { NT_STATUS_TOO_LATE, "TOO_LATE" },
+ { NT_STATUS_NO_TRUST_LSA_SECRET, "NO_TRUST_LSA_SECRET" },
+ { NT_STATUS_NO_TRUST_SAM_ACCOUNT, "NO_TRUST_SAM_ACCOUNT" },
+ { NT_STATUS_TRUSTED_DOMAIN_FAILURE, "TRUSTED_DOMAIN_FAILURE" },
+ { NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE,
+ "TRUSTED_RELATIONSHIP_FAILURE" },
+ { NT_STATUS_EVENTLOG_FILE_CORRUPT, "EVENTLOG_FILE_CORRUPT" },
+ { NT_STATUS_EVENTLOG_CANT_START, "EVENTLOG_CANT_START" },
+ { NT_STATUS_TRUST_FAILURE, "TRUST_FAILURE" },
+ { NT_STATUS_MUTANT_LIMIT_EXCEEDED, "MUTANT_LIMIT_EXCEEDED" },
+ { NT_STATUS_NETLOGON_NOT_STARTED, "NETLOGON_NOT_STARTED" },
+ { NT_STATUS_ACCOUNT_EXPIRED, "ACCOUNT_EXPIRED" },
+ { NT_STATUS_POSSIBLE_DEADLOCK, "POSSIBLE_DEADLOCK" },
+ { NT_STATUS_NETWORK_CREDENTIAL_CONFLICT,
+ "NETWORK_CREDENTIAL_CONFLICT" },
+ { NT_STATUS_REMOTE_SESSION_LIMIT, "REMOTE_SESSION_LIMIT" },
+ { NT_STATUS_EVENTLOG_FILE_CHANGED, "EVENTLOG_FILE_CHANGED" },
+ { NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT,
+ "NOLOGON_INTERDOMAIN_TRUST_ACCOUNT" },
+ { NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT,
+ "NOLOGON_WORKSTATION_TRUST_ACCOUNT" },
+ { NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT,
+ "NOLOGON_SERVER_TRUST_ACCOUNT" },
+ { NT_STATUS_DOMAIN_TRUST_INCONSISTENT, "DOMAIN_TRUST_INCONSISTENT" },
+ { NT_STATUS_FS_DRIVER_REQUIRED, "FS_DRIVER_REQUIRED" },
+ { NT_STATUS_NO_USER_SESSION_KEY, "NO_USER_SESSION_KEY" },
+ { NT_STATUS_USER_SESSION_DELETED, "USER_SESSION_DELETED" },
+ { NT_STATUS_RESOURCE_LANG_NOT_FOUND, "RESOURCE_LANG_NOT_FOUND" },
+ { NT_STATUS_INSUFF_SERVER_RESOURCES, "INSUFF_SERVER_RESOURCES" },
+ { NT_STATUS_INVALID_BUFFER_SIZE, "INVALID_BUFFER_SIZE" },
+ { NT_STATUS_INVALID_ADDRESS_COMPONENT, "INVALID_ADDRESS_COMPONENT" },
+ { NT_STATUS_INVALID_ADDRESS_WILDCARD, "INVALID_ADDRESS_WILDCARD" },
+ { NT_STATUS_TOO_MANY_ADDRESSES, "TOO_MANY_ADDRESSES" },
+ { NT_STATUS_ADDRESS_ALREADY_EXISTS, "ADDRESS_ALREADY_EXISTS" },
+ { NT_STATUS_ADDRESS_CLOSED, "ADDRESS_CLOSED" },
+ { NT_STATUS_CONNECTION_DISCONNECTED, "CONNECTION_DISCONNECTED" },
+ { NT_STATUS_CONNECTION_RESET, "CONNECTION_RESET" },
+ { NT_STATUS_TOO_MANY_NODES, "TOO_MANY_NODES" },
+ { NT_STATUS_TRANSACTION_ABORTED, "TRANSACTION_ABORTED" },
+ { NT_STATUS_TRANSACTION_TIMED_OUT, "TRANSACTION_TIMED_OUT" },
+ { NT_STATUS_TRANSACTION_NO_RELEASE, "TRANSACTION_NO_RELEASE" },
+ { NT_STATUS_TRANSACTION_NO_MATCH, "TRANSACTION_NO_MATCH" },
+ { NT_STATUS_TRANSACTION_RESPONDED, "TRANSACTION_RESPONDED" },
+ { NT_STATUS_TRANSACTION_INVALID_ID, "TRANSACTION_INVALID_ID" },
+ { NT_STATUS_TRANSACTION_INVALID_TYPE, "TRANSACTION_INVALID_TYPE" },
+ { NT_STATUS_NOT_SERVER_SESSION, "NOT_SERVER_SESSION" },
+ { NT_STATUS_NOT_CLIENT_SESSION, "NOT_CLIENT_SESSION" },
+ { NT_STATUS_CANNOT_LOAD_REGISTRY_FILE, "CANNOT_LOAD_REGISTRY_FILE" },
+ { NT_STATUS_DEBUG_ATTACH_FAILED, "DEBUG_ATTACH_FAILED" },
+ { NT_STATUS_SYSTEM_PROCESS_TERMINATED, "SYSTEM_PROCESS_TERMINATED" },
+ { NT_STATUS_DATA_NOT_ACCEPTED, "DATA_NOT_ACCEPTED" },
+ { NT_STATUS_NO_BROWSER_SERVERS_FOUND, "NO_BROWSER_SERVERS_FOUND" },
+ { NT_STATUS_VDM_HARD_ERROR, "VDM_HARD_ERROR" },
+ { NT_STATUS_DRIVER_CANCEL_TIMEOUT, "DRIVER_CANCEL_TIMEOUT" },
+ { NT_STATUS_REPLY_MESSAGE_MISMATCH, "REPLY_MESSAGE_MISMATCH" },
+ { NT_STATUS_MAPPED_ALIGNMENT, "MAPPED_ALIGNMENT" },
+ { NT_STATUS_IMAGE_CHECKSUM_MISMATCH, "IMAGE_CHECKSUM_MISMATCH" },
+ { NT_STATUS_LOST_WRITEBEHIND_DATA, "LOST_WRITEBEHIND_DATA" },
+ { NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID,
+ "CLIENT_SERVER_PARAMETERS_INVALID" },
+ { NT_STATUS_PASSWORD_MUST_CHANGE, "PASSWORD_MUST_CHANGE" },
+ { NT_STATUS_NOT_FOUND, "NOT_FOUND" },
+ { NT_STATUS_NOT_TINY_STREAM, "NOT_TINY_STREAM" },
+ { NT_STATUS_RECOVERY_FAILURE, "RECOVERY_FAILURE" },
+ { NT_STATUS_STACK_OVERFLOW_READ, "STACK_OVERFLOW_READ" },
+ { NT_STATUS_FAIL_CHECK, "FAIL_CHECK" },
+ { NT_STATUS_DUPLICATE_OBJECTID, "DUPLICATE_OBJECTID" },
+ { NT_STATUS_OBJECTID_EXISTS, "OBJECTID_EXISTS" },
+ { NT_STATUS_CONVERT_TO_LARGE, "CONVERT_TO_LARGE" },
+ { NT_STATUS_RETRY, "RETRY" },
+ { NT_STATUS_FOUND_OUT_OF_SCOPE, "FOUND_OUT_OF_SCOPE" },
+ { NT_STATUS_ALLOCATE_BUCKET, "ALLOCATE_BUCKET" },
+ { NT_STATUS_PROPSET_NOT_FOUND, "PROPSET_NOT_FOUND" },
+ { NT_STATUS_MARSHALL_OVERFLOW, "MARSHALL_OVERFLOW" },
+ { NT_STATUS_INVALID_VARIANT, "INVALID_VARIANT" },
+ { NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND,
+ "DOMAIN_CONTROLLER_NOT_FOUND" },
+ { NT_STATUS_ACCOUNT_LOCKED_OUT, "ACCOUNT_LOCKED_OUT" },
+ { NT_STATUS_HANDLE_NOT_CLOSABLE, "HANDLE_NOT_CLOSABLE" },
+ { NT_STATUS_CONNECTION_REFUSED, "CONNECTION_REFUSED" },
+ { NT_STATUS_GRACEFUL_DISCONNECT, "GRACEFUL_DISCONNECT" },
+ { NT_STATUS_ADDRESS_ALREADY_ASSOCIATED, "ADDRESS_ALREADY_ASSOCIATED" },
+ { NT_STATUS_ADDRESS_NOT_ASSOCIATED, "ADDRESS_NOT_ASSOCIATED" },
+ { NT_STATUS_CONNECTION_INVALID, "CONNECTION_INVALID" },
+ { NT_STATUS_CONNECTION_ACTIVE, "CONNECTION_ACTIVE" },
+ { NT_STATUS_NETWORK_UNREACHABLE, "NETWORK_UNREACHABLE" },
+ { NT_STATUS_HOST_UNREACHABLE, "HOST/PARTNER UNREACHABLE" },
+ { NT_STATUS_PROTOCOL_UNREACHABLE, "PROTOCOL_UNREACHABLE" },
+ { NT_STATUS_PORT_UNREACHABLE, "PORT_UNREACHABLE" },
+ { NT_STATUS_REQUEST_ABORTED, "REQUEST_ABORTED" },
+ { NT_STATUS_CONNECTION_ABORTED, "CONNECTION_ABORTED" },
+ { NT_STATUS_BAD_COMPRESSION_BUFFER, "BAD_COMPRESSION_BUFFER" },
+ { NT_STATUS_USER_MAPPED_FILE, "USER_MAPPED_FILE" },
+ { NT_STATUS_AUDIT_FAILED, "AUDIT_FAILED" },
+ { NT_STATUS_TIMER_RESOLUTION_NOT_SET, "TIMER_RESOLUTION_NOT_SET" },
+ { NT_STATUS_CONNECTION_COUNT_LIMIT, "CONNECTION_COUNT_LIMIT" },
+ { NT_STATUS_LOGIN_TIME_RESTRICTION, "LOGIN_TIME_RESTRICTION" },
+ { NT_STATUS_LOGIN_WKSTA_RESTRICTION, "LOGIN_WKSTA_RESTRICTION" },
+ { NT_STATUS_IMAGE_MP_UP_MISMATCH, "IMAGE_MP_UP_MISMATCH" },
+ { NT_STATUS_INSUFFICIENT_LOGON_INFO, "INSUFFICIENT_LOGON_INFO" },
+ { NT_STATUS_BAD_DLL_ENTRYPOINT, "BAD_DLL_ENTRYPOINT" },
+ { NT_STATUS_BAD_SERVICE_ENTRYPOINT, "BAD_SERVICE_ENTRYPOINT" },
+ { NT_STATUS_LPC_REPLY_LOST, "LPC_REPLY_LOST" },
+ { NT_STATUS_IP_ADDRESS_CONFLICT1, "IP_ADDRESS_CONFLICT1" },
+ { NT_STATUS_IP_ADDRESS_CONFLICT2, "IP_ADDRESS_CONFLICT2" },
+ { NT_STATUS_REGISTRY_QUOTA_LIMIT, "REGISTRY_QUOTA_LIMIT" },
+ { NT_STATUS_PATH_NOT_COVERED, "PATH_NOT_COVERED" },
+ { NT_STATUS_NO_CALLBACK_ACTIVE, "NO_CALLBACK_ACTIVE" },
+ { NT_STATUS_LICENSE_QUOTA_EXCEEDED, "LICENSE_QUOTA_EXCEEDED" },
+ { NT_STATUS_PWD_TOO_SHORT, "PWD_TOO_SHORT" },
+ { NT_STATUS_PWD_TOO_RECENT, "PWD_TOO_RECENT" },
+ { NT_STATUS_PWD_HISTORY_CONFLICT, "PWD_HISTORY_CONFLICT" },
+ { NT_STATUS_PLUGPLAY_NO_DEVICE, "PLUGPLAY_NO_DEVICE" },
+ { NT_STATUS_UNSUPPORTED_COMPRESSION, "UNSUPPORTED_COMPRESSION" },
+ { NT_STATUS_INVALID_HW_PROFILE, "INVALID_HW_PROFILE" },
+ { NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH,
+ "INVALID_PLUGPLAY_DEVICE_PATH" },
+ { NT_STATUS_DRIVER_ORDINAL_NOT_FOUND, "DRIVER_ORDINAL_NOT_FOUND" },
+ { NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND,
+ "DRIVER_ENTRYPOINT_NOT_FOUND" },
+ { NT_STATUS_RESOURCE_NOT_OWNED, "RESOURCE_NOT_OWNED" },
+ { NT_STATUS_TOO_MANY_LINKS, "TOO_MANY_LINKS" },
+ { NT_STATUS_QUOTA_LIST_INCONSISTENT, "QUOTA_LIST_INCONSISTENT" },
+ { NT_STATUS_FILE_IS_OFFLINE, "FILE_IS_OFFLINE" },
+};
+
+
+/*
+ * Translate an ntstatus value to a meaningful text string. If there isn't
+ * a corresponding text string in the table, the text representation of the
+ * status value is returned. This uses a static buffer so there is a
+ * possible concurrency issue if the caller hangs on to this pointer for a
+ * while but it should be harmless and really remote since the value will
+ * almost always be found in the table.
+ */
+char *
+xlate_nt_status(DWORD ntstatus)
+{
+ static char unknown[16];
+ int i;
+
+ for (i = 0; i < sizeof (ntx_table)/sizeof (ntx_table[0]); ++i) {
+ if (ntx_table[i].value == NT_SC_VALUE(ntstatus))
+ return (ntx_table[i].name);
+ }
+
+ (void) sprintf(unknown, "0x%08x", ntstatus);
+ return (unknown);
+}
diff --git a/usr/src/common/smbsrv/smb_strcase.c b/usr/src/common/smbsrv/smb_strcase.c
new file mode 100644
index 0000000000..e1de2cdd32
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_strcase.c
@@ -0,0 +1,388 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Case conversion functions for strings. Originally this module only
+ * dealt with ASCII strings. It has been updated to support European
+ * character set characters. The current implementation is based on
+ * code page table lookup rather than simple character range checks.
+ */
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#else
+#include <stdio.h>
+#include <string.h>
+#endif
+#include <smbsrv/ctype.h>
+#include <smbsrv/codepage.h>
+#include <smbsrv/cp_cyrillic.h>
+#include <smbsrv/cp_latin1.h>
+#include <smbsrv/cp_latin2.h>
+#include <smbsrv/cp_latin3.h>
+#include <smbsrv/cp_latin4.h>
+#include <smbsrv/cp_latin5.h>
+#include <smbsrv/cp_latin6.h>
+#include <smbsrv/cp_usascii.h>
+
+/*
+ * Global pointer to the current code page. This is
+ * defaulted to a standard ASCII table.
+ */
+static codepage_t *current_codepage = usascii_codepage;
+
+/*
+ * A flag indicating whether the codepage being used is ASCII
+ * When this flag is set, string opeartions can go faster.
+ */
+static int is_unicode = 0;
+
+/*
+ * codepage_isupper
+ *
+ * Determine whether or not a character is an uppercase character.
+ * This function operates on the current codepage table. Returns
+ * non-zero if the character is uppercase. Otherwise returns zero.
+ */
+int
+codepage_isupper(int c)
+{
+ unsigned short mask = is_unicode ? 0xffff : 0xff;
+
+ return (current_codepage[c & mask].ctype & CODEPAGE_ISUPPER);
+}
+
+
+/*
+ * codepage_islower
+ *
+ * Determine whether or not a character is an lowercase character.
+ * This function operates on the current codepage table. Returns
+ * non-zero if the character is lowercase. Otherwise returns zero.
+ */
+int
+codepage_islower(int c)
+{
+ unsigned short mask = is_unicode ? 0xffff : 0xff;
+
+ return (current_codepage[c & mask].ctype & CODEPAGE_ISLOWER);
+}
+
+
+/*
+ * codepage_toupper
+ *
+ * Convert individual characters to their uppercase equivalent value.
+ * If the specified character is lowercase, the uppercase value will
+ * be returned. Otherwise the original value will be returned.
+ */
+int
+codepage_toupper(int c)
+{
+ unsigned short mask = is_unicode ? 0xffff : 0xff;
+
+ return (current_codepage[c & mask].upper);
+}
+
+
+/*
+ * codepage_tolower
+ *
+ * Convert individual characters to their lowercase equivalent value.
+ * If the specified character is uppercase, the lowercase value will
+ * be returned. Otherwise the original value will be returned.
+ */
+int
+codepage_tolower(int c)
+{
+ unsigned short mask = is_unicode ? 0xffff : 0xff;
+
+ return (current_codepage[c & mask].lower);
+}
+
+
+/*
+ * strupr
+ *
+ * Convert a string to uppercase using the appropriate codepage. The
+ * string is converted in place. A pointer to the string is returned.
+ * There is an assumption here that uppercase and lowercase values
+ * always result encode to the same length.
+ */
+char *
+utf8_strupr(char *s)
+{
+ mts_wchar_t c;
+ char *p = s;
+
+ while (*p) {
+ if (mts_isascii(*p)) {
+ *p = codepage_toupper(*p);
+ p++;
+ } else {
+ if (mts_mbtowc(&c, p, MTS_MB_CHAR_MAX) < 0)
+ return (0);
+
+ if (c == 0)
+ break;
+
+ c = codepage_toupper(c);
+ p += mts_wctomb(p, c);
+ }
+ }
+
+ return (s);
+}
+
+
+/*
+ * strlwr
+ *
+ * Convert a string to lowercase using the appropriate codepage. The
+ * string is converted in place. A pointer to the string is returned.
+ * There is an assumption here that uppercase and lowercase values
+ * always result encode to the same length.
+ */
+char *
+utf8_strlwr(char *s)
+{
+ mts_wchar_t c;
+ char *p = s;
+
+ while (*p) {
+ if (mts_isascii(*p)) {
+ *p = codepage_tolower(*p);
+ p++;
+ } else {
+ if (mts_mbtowc(&c, p, MTS_MB_CHAR_MAX) < 0)
+ return (0);
+
+ if (c == 0)
+ break;
+
+ c = codepage_tolower(c);
+ p += mts_wctomb(p, c);
+ }
+ }
+
+ return (s);
+}
+
+
+/*
+ * isstrlwr
+ *
+ * Returns 1 if string contains NO uppercase chars 0 otherwise. However,
+ * -1 is returned if "s" is not a valid multi-byte string.
+ */
+int
+utf8_isstrlwr(const char *s)
+{
+ mts_wchar_t c;
+ int n;
+ const char *p = s;
+
+ while (*p) {
+ if (mts_isascii(*p) && codepage_isupper(*p))
+ return (0);
+ else {
+ if ((n = mts_mbtowc(&c, p, MTS_MB_CHAR_MAX)) < 0)
+ return (-1);
+
+ if (c == 0)
+ break;
+
+ if (codepage_isupper(c))
+ return (0);
+
+ p += n;
+ }
+ }
+
+ return (1);
+}
+
+
+/*
+ * isstrupr
+ *
+ * Returns 1 if string contains NO lowercase chars 0 otherwise. However,
+ * -1 is returned if "s" is not a valid multi-byte string.
+ */
+int
+utf8_isstrupr(const char *s)
+{
+ mts_wchar_t c;
+ int n;
+ const char *p = s;
+
+ while (*p) {
+ if (mts_isascii(*p) && codepage_islower(*p))
+ return (0);
+ else {
+ if ((n = mts_mbtowc(&c, p, MTS_MB_CHAR_MAX)) < 0)
+ return (-1);
+
+ if (c == 0)
+ break;
+
+ if (codepage_islower(c))
+ return (0);
+
+ p += n;
+ }
+ }
+
+ return (1);
+}
+
+
+/*
+ * strcasecmp
+ *
+ * Compare the null-terminated strings s1 and s2 and return an integer
+ * greater than, equal to, or less than 0, according as s1 is lexico
+ * graphically greater than, equal to, or less than s2 after translation
+ * of each corresponding character to lowercase. The strings themselves
+ * are not modified.
+ *
+ * Out: 0 if strings are equal
+ * < 0 if first string < second string
+ * > 0 if first string > second string
+ */
+int
+utf8_strcasecmp(const char *s1, const char *s2)
+{
+ mts_wchar_t c1, c2;
+ int n1, n2;
+ const char *p1 = s1;
+ const char *p2 = s2;
+
+ for (;;) {
+ if (mts_isascii(*p1))
+ c1 = *p1++;
+ else {
+ if ((n1 = mts_mbtowc(&c1, p1, MTS_MB_CHAR_MAX)) < 0)
+ return (-1);
+ p1 += n1;
+ }
+
+ if (mts_isascii(*p2))
+ c2 = *p2++;
+ else {
+ if ((n2 = mts_mbtowc(&c2, p2, MTS_MB_CHAR_MAX)) < 0)
+ return (1);
+ p2 += n2;
+ }
+
+ if (c1 == 0 || c2 == 0)
+ break;
+
+ if (c1 == c2)
+ continue;
+
+ c1 = codepage_tolower(c1);
+ c2 = codepage_tolower(c2);
+
+ if (c1 != c2)
+ break;
+ }
+
+ return ((int)c1 - (int)c2);
+}
+
+
+/*
+ * strncasecmp
+ *
+ * Compare two null-terminated strings, s1 and s2, of at most len
+ * characters and return an int greater than, equal to, or less than 0,
+ * dependent on whether s1 is lexicographically greater than, equal to,
+ * or less than s2 after translation of each corresponding character to
+ * lowercase. The original strings are not modified.
+ *
+ * Out: 0 if strings are equal
+ * < 0 if first string < second string
+ * > 0 if first string > second string
+ */
+int
+utf8_strncasecmp(const char *s1, const char *s2, int len)
+{
+ mts_wchar_t c1, c2;
+ int n1, n2;
+ const char *p1 = s1;
+ const char *p2 = s2;
+
+ if (len <= 0)
+ return (0);
+
+ while (len--) {
+ if (mts_isascii(*p1))
+ c1 = *p1++;
+ else {
+ if ((n1 = mts_mbtowc(&c1, p1, MTS_MB_CHAR_MAX)) < 0)
+ return (-1);
+ p1 += n1;
+ }
+
+ if (mts_isascii(*p2))
+ c2 = *p2++;
+ else {
+ if ((n2 = mts_mbtowc(&c2, p2, MTS_MB_CHAR_MAX)) < 0)
+ return (1);
+ p2 += n2;
+ }
+
+ if (c1 == 0 || c2 == 0)
+ break;
+
+ if (c1 == c2)
+ continue;
+
+ c1 = codepage_tolower(c1);
+ c2 = codepage_tolower(c2);
+
+ if (c1 != c2)
+ break;
+ }
+
+ return ((int)c1 - (int)c2);
+}
+
+
+
+int
+utf8_isstrascii(const char *s)
+{
+ while (*s) {
+ if (mts_isascii(*s) == 0)
+ return (0);
+ s++;
+ }
+ return (1);
+}
diff --git a/usr/src/common/smbsrv/smb_string.c b/usr/src/common/smbsrv/smb_string.c
new file mode 100644
index 0000000000..0ff4f1e8a6
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_string.c
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+/*
+ * Implementation of some of the string functions.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#endif
+#include <smbsrv/alloc.h>
+#include <smbsrv/string.h>
+#include <smbsrv/ctype.h>
+
+
+/*
+ * strsubst
+ *
+ * Scan a string replacing all occurrences of orgchar with newchar.
+ * Returns a pointer to s, or null of s is null.
+ */
+char *
+strsubst(char *s, char orgchar, char newchar)
+{
+ char *p = s;
+
+ if (p == 0)
+ return (0);
+
+ while (*p) {
+ if (*p == orgchar)
+ *p = newchar;
+ ++p;
+ }
+
+ return (s);
+}
+
+/*
+ * strcanon
+ *
+ * Normalize a string by reducing all the repeated characters in
+ * buf as defined by class. For example;
+ *
+ * char *buf = strdup("/d1//d2//d3\\\\d4\\\\f1.txt");
+ * strcanon(buf, "/\\");
+ *
+ * Would result in buf containing the following string:
+ *
+ * /d1/d2/d3\d4\f1.txt
+ *
+ * This function modifies the contents of buf in place and returns
+ * a pointer to buf.
+ */
+char *
+strcanon(char *buf, const char *class)
+{
+ char *p = buf;
+ char *q = buf;
+ char *r;
+
+ while (*p) {
+ *q++ = *p;
+
+ if ((r = strchr(class, *p)) != 0) {
+ while (*p == *r)
+ ++p;
+ } else
+ ++p;
+ }
+
+ *q = '\0';
+ return (buf);
+}
diff --git a/usr/src/common/smbsrv/smb_token.c b/usr/src/common/smbsrv/smb_token.c
new file mode 100644
index 0000000000..1e71bf673f
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_token.c
@@ -0,0 +1,383 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * NT Token library (kernel/user)
+ */
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+#include <sys/cmn_err.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+#else /* _KERNEL */
+#include <stdlib.h>
+#include <strings.h>
+#include <thread.h>
+#include <synch.h>
+#include <syslog.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <sys/varargs.h>
+#include <smbsrv/alloc.h>
+#endif /* _KERNEL */
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <smbsrv/alloc.h>
+#include <smbsrv/string.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_token.h>
+#include <smbsrv/smb_xdr.h>
+
+#ifndef _KERNEL
+#include <assert.h>
+#define ASSERT assert
+void (*smb_token_logfunc)(int, const char *, ...) = syslog;
+int smb_token_errlog = LOG_ERR;
+int smb_token_infolog = LOG_INFO;
+#else /* _KERNEL */
+void (*smb_token_logfunc)(int, const char *, ...) = cmn_err;
+int smb_token_errlog = CE_WARN;
+int smb_token_infolog = CE_NOTE;
+#endif /* _KERNEL */
+
+int smb_token_debug = 0;
+
+#ifdef _KERNEL
+extern char *inet_ntop(int, const void *, char *, int);
+#endif /* _KERNEL */
+
+/*
+ * Returns -1 on error. Otherwise, returns 0.
+ */
+int
+smb_token_tobuf(smb_dr_user_ctx_t *usr, char *buf, int len)
+{
+ char ipaddr_buf[INET_ADDRSTRLEN];
+
+ if (!usr) {
+ (void) strcpy(buf, "N/A");
+ return (-1);
+ }
+
+ (void) inet_ntop(AF_INET, (char *)&usr->du_ipaddr, ipaddr_buf,
+ sizeof (ipaddr_buf));
+ (void) snprintf(buf, len, "%s\\%s %s (%s)",
+ usr->du_domain ? usr->du_domain : "",
+ usr->du_account ? usr->du_account : "",
+ usr->du_workstation ? usr->du_workstation : "",
+ ipaddr_buf);
+
+ return (0);
+}
+
+/*PRINTFLIKE3*/
+void
+smb_token_log(int level, smb_dr_user_ctx_t *usr, char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+ int len;
+ char tokenbuf[NTTOKEN_BASIC_INFO_MAXLEN];
+
+ msg = MEM_MALLOC("nttoken", 1024);
+ if (!msg) {
+ smb_token_logfunc(smb_token_errlog, "smb_token_log: "
+ "resource shortage");
+ return;
+ }
+
+ if (usr)
+ (void) smb_token_tobuf(usr, tokenbuf, sizeof (tokenbuf));
+ else
+ (void) strcpy(tokenbuf, "UNKNOWN");
+
+ va_start(ap, fmt);
+ (void) snprintf(msg, 1024, "Token[%s]: ", tokenbuf);
+ len = strlen(msg);
+ (void) vsnprintf(msg + len, 1024 - len, fmt, ap);
+ va_end(ap);
+#ifdef _KERNEL
+ cmn_err(level, "%s", msg);
+#else
+ syslog(level, "%s", msg);
+#endif /* _KERNEL */
+
+ MEM_FREE("nttoken", msg);
+}
+
+#ifndef _KERNEL
+/*
+ * smb_token_print
+ *
+ * Diagnostic routine to write the contents of a token to the log.
+ */
+void
+smb_token_print(smb_token_t *token)
+{
+ smb_win_grps_t *w_grps;
+ smb_posix_grps_t *x_grps;
+ smb_sid_attrs_t *grp;
+ char sidstr[128];
+ int i;
+
+ if (token == NULL)
+ return;
+
+ smb_token_logfunc(smb_token_infolog, "Token for %s\\%s",
+ (token->tkn_domain_name) ? token->tkn_domain_name : "-NULL-",
+ (token->tkn_account_name) ? token->tkn_account_name : "-NULL-");
+
+ smb_token_logfunc(smb_token_infolog, " User->Attr: %d",
+ token->tkn_user->i_sidattr.attrs);
+ nt_sid_format2((nt_sid_t *)token->tkn_user->i_sidattr.sid, sidstr);
+ smb_token_logfunc(smb_token_infolog, " User->Sid: %s (id=%u)",
+ sidstr, token->tkn_user->i_id);
+
+ nt_sid_format2((nt_sid_t *)token->tkn_owner->i_sidattr.sid, sidstr);
+ smb_token_logfunc(smb_token_infolog, " Ownr->Sid: %s (id=%u)",
+ sidstr, token->tkn_owner->i_id);
+
+ nt_sid_format2((nt_sid_t *)token->tkn_primary_grp->i_sidattr.sid,
+ sidstr);
+ smb_token_logfunc(smb_token_infolog, " PGrp->Sid: %s (id=%u)",
+ sidstr, token->tkn_primary_grp->i_id);
+
+ w_grps = token->tkn_win_grps;
+ if (w_grps) {
+ smb_token_logfunc(smb_token_infolog, " Windows groups: %d",
+ w_grps->wg_count);
+
+ for (i = 0; i < w_grps->wg_count; ++i) {
+ grp = &w_grps->wg_groups[i].i_sidattr;
+ smb_token_logfunc(smb_token_infolog,
+ " Grp[%d].Attr:%d", i, grp->attrs);
+ if (w_grps->wg_groups[i].i_sidattr.sid) {
+ nt_sid_format2((nt_sid_t *)grp->sid, sidstr);
+ smb_token_logfunc(smb_token_infolog,
+ " Grp[%d].Sid: %s (id=%u)", i, sidstr,
+ w_grps->wg_groups[i].i_id);
+ }
+ }
+ }
+ else
+ smb_token_logfunc(smb_token_infolog, " No Windows groups");
+
+ x_grps = token->tkn_posix_grps;
+ if (x_grps) {
+ smb_token_logfunc(smb_token_infolog, " Solaris groups: %d",
+ x_grps->pg_ngrps);
+ for (i = 0; i < x_grps->pg_ngrps; i++)
+ smb_token_logfunc(smb_token_infolog, " %u",
+ x_grps->pg_grps[i]);
+ }
+ else
+ smb_token_logfunc(smb_token_infolog, " No Solaris groups");
+
+ if (token->tkn_privileges)
+ smb_privset_log(token->tkn_privileges);
+ else
+ smb_token_logfunc(smb_token_infolog, " No privileges");
+}
+#endif /* _KERNEL */
+
+/*
+ * smb_token_query_privilege
+ *
+ * Find out if the specified privilege is enable in the given
+ * access token.
+ */
+int
+smb_token_query_privilege(smb_token_t *token, int priv_id)
+{
+ smb_privset_t *privset;
+ int i;
+
+ if ((token == NULL) || (token->tkn_privileges == NULL))
+ return (0);
+
+ privset = token->tkn_privileges;
+ for (i = 0; privset->priv_cnt; i++) {
+ if (privset->priv[i].luid.lo_part == priv_id) {
+ if (privset->priv[i].attrs == SE_PRIVILEGE_ENABLED)
+ return (1);
+ else
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+#ifndef _KERNEL
+/*
+ * smb_token_mkselfrel
+ *
+ * encode: structure -> flat buffer (buffer size)
+ * Pre-condition: obj is non-null.
+ */
+uint8_t *
+smb_token_mkselfrel(smb_token_t *obj, uint32_t *len)
+{
+ uint8_t *buf;
+ XDR xdrs;
+
+ if (!obj) {
+ smb_token_logfunc(smb_token_errlog,
+ "smb_token_mkselfrel: invalid parameter");
+ return (NULL);
+ }
+
+ *len = xdr_sizeof(xdr_smb_token_t, obj);
+ buf = (uint8_t *)malloc(*len);
+ if (!buf) {
+ smb_token_logfunc(smb_token_errlog,
+ "smb_token_mkselfrel: resource shortage");
+ return (NULL);
+ }
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, *len, XDR_ENCODE);
+
+ if (!xdr_smb_token_t(&xdrs, obj)) {
+ smb_token_logfunc(smb_token_errlog,
+ "smb_token_mkselfrel: XDR encode error");
+ *len = 0;
+ free(buf);
+ buf = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+/*
+ * netr_client_mkabsolute
+ *
+ * decode: flat buffer -> structure
+ */
+netr_client_t *
+netr_client_mkabsolute(uint8_t *buf, uint32_t len)
+{
+ netr_client_t *obj;
+ XDR xdrs;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
+ obj = (netr_client_t *)malloc(sizeof (netr_client_t));
+ if (!obj) {
+ smb_token_logfunc(smb_token_errlog, "netr_client_mkabsolute: "
+ "resource shortage");
+ xdr_destroy(&xdrs);
+ return (NULL);
+ }
+
+ bzero(obj, sizeof (netr_client_t));
+ if (!xdr_netr_client_t(&xdrs, obj)) {
+ smb_token_logfunc(smb_token_errlog, "netr_client_mkabsolute: "
+ "XDR decode error");
+ free(obj);
+ obj = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (obj);
+}
+#else /* _KERNEL */
+/*
+ * smb_token_mkabsolute
+ *
+ * decode: flat buffer -> structure
+ */
+smb_token_t *
+smb_token_mkabsolute(uint8_t *buf, uint32_t len)
+{
+ smb_token_t *obj;
+ XDR xdrs;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
+ obj = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
+
+ if (!xdr_smb_token_t(&xdrs, obj)) {
+ smb_token_logfunc(smb_token_errlog, "smb_token_mkabsolute: XDR "
+ "decode error");
+ kmem_free(obj, sizeof (smb_token_t));
+ obj = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (obj);
+}
+
+/*
+ * netr_client_mkselfrel
+ *
+ * encode: structure -> flat buffer (buffer size)
+ * Pre-condition: obj is non-null.
+ */
+uint8_t *
+netr_client_mkselfrel(netr_client_t *obj, uint32_t *len)
+{
+ uint8_t *buf;
+ XDR xdrs;
+
+ *len = xdr_sizeof(xdr_netr_client_t, obj);
+ buf = kmem_alloc(*len, KM_SLEEP);
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, *len, XDR_ENCODE);
+
+ if (!xdr_netr_client_t(&xdrs, obj)) {
+ smb_token_logfunc(smb_token_errlog, "netr_client_mkselfrel: "
+ "XDR encode error");
+ kmem_free(buf, *len);
+ *len = 0;
+ buf = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+void
+smb_token_free(smb_token_t *token)
+{
+ if (!token)
+ return;
+
+ /*
+ * deallocate any pointer field of an access token object
+ * using xdr_free since they are created by the XDR decode
+ * operation.
+ */
+ xdr_free(xdr_smb_token_t, (char *)token);
+ kmem_free(token, sizeof (smb_token_t));
+}
+#endif /* _KERNEL */
diff --git a/usr/src/common/smbsrv/smb_token_xdr.c b/usr/src/common/smbsrv/smb_token_xdr.c
new file mode 100644
index 0000000000..14870b29c6
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_token_xdr.c
@@ -0,0 +1,395 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file was originally generated using rpcgen.
+ */
+
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif /* !_KERNEL */
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_token.h>
+
+bool_t
+xdr_ntsid_helper(xdrs, sid)
+ XDR *xdrs;
+ char **sid;
+{
+ uint32_t pos, len;
+ uint8_t dummy, cnt;
+ bool_t rc;
+
+ switch (xdrs->x_op) {
+ case XDR_DECODE:
+ /*
+ * chicken-and-egg: Can't use nt_sid_length() since it takes
+ * SID as its parameter while sid is yet to be decoded.
+ */
+ pos = xdr_getpos(xdrs);
+
+ if (!xdr_bool(xdrs, &rc))
+ return (FALSE);
+
+ if (!xdr_uint8_t(xdrs, &dummy))
+ return (FALSE);
+
+ if (!xdr_uint8_t(xdrs, &cnt))
+ return (FALSE);
+
+ rc = xdr_setpos(xdrs, pos);
+
+ if (rc == FALSE)
+ return (FALSE);
+
+ len = sizeof (nt_sid_t) - sizeof (uint32_t) +
+ (cnt * sizeof (uint32_t));
+
+ if (!xdr_pointer(xdrs, sid, len, (xdrproc_t)xdr_nt_sid_t))
+ return (FALSE);
+ break;
+
+ case XDR_ENCODE:
+ case XDR_FREE:
+ if (*sid == NULL)
+ return (FALSE);
+
+ len = nt_sid_length((nt_sid_t *)(uintptr_t)*sid);
+ if (!xdr_pointer(xdrs, sid, len, (xdrproc_t)xdr_nt_sid_t))
+ return (FALSE);
+ break;
+ }
+
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_privset_helper(xdrs, privs)
+ XDR *xdrs;
+ char **privs;
+{
+ uint32_t pos, len;
+ uint32_t cnt;
+ bool_t rc;
+ smb_privset_t *p;
+
+ if (xdrs->x_op == XDR_DECODE) {
+ pos = xdr_getpos(xdrs);
+
+ if (!xdr_bool(xdrs, &rc))
+ return (FALSE);
+
+ if (!xdr_uint32_t(xdrs, &cnt))
+ return (FALSE);
+
+ rc = xdr_setpos(xdrs, pos);
+
+ if (rc == FALSE)
+ return (FALSE);
+ } else {
+ if (*privs == NULL)
+ return (FALSE);
+
+ p = (smb_privset_t *)(uintptr_t)*privs;
+ cnt = p->priv_cnt;
+ }
+
+ len = sizeof (smb_privset_t)
+ - sizeof (smb_luid_attrs_t)
+ + (cnt * sizeof (smb_luid_attrs_t));
+
+ if (!xdr_pointer(xdrs, privs, len, (xdrproc_t)xdr_smb_privset_t))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_win_grps_helper(xdrs, grps)
+ XDR *xdrs;
+ char **grps;
+{
+ uint32_t pos, len;
+ uint16_t cnt;
+ bool_t rc;
+
+ if (xdrs->x_op == XDR_DECODE) {
+ pos = xdr_getpos(xdrs);
+
+ if (!xdr_bool(xdrs, &rc))
+ return (FALSE);
+
+ if (!xdr_uint16_t(xdrs, &cnt))
+ return (FALSE);
+
+ rc = xdr_setpos(xdrs, pos);
+ if (rc == FALSE)
+ return (FALSE);
+ } else {
+ if (*grps == NULL)
+ return (FALSE);
+
+ cnt = ((smb_win_grps_t *)(uintptr_t)*grps)->wg_count;
+ }
+
+ len = cnt * sizeof (smb_id_t) + sizeof (smb_win_grps_t);
+
+ if (!xdr_pointer(xdrs, grps, len, (xdrproc_t)xdr_smb_win_grps_t))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_id_t(xdrs, objp)
+ XDR *xdrs;
+ smb_id_t *objp;
+{
+ if (!xdr_smb_sid_attrs_t(xdrs, &objp->i_sidattr))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, (uint32_t *)&objp->i_id))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_win_grps_t(xdrs, objp)
+ XDR *xdrs;
+ smb_win_grps_t *objp;
+{
+ if (!xdr_uint16_t(xdrs, &objp->wg_count))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->wg_groups, objp->wg_count,
+ sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_posix_grps_t(xdrs, objp)
+ XDR *xdrs;
+ smb_posix_grps_t *objp;
+{
+ if (!xdr_uint32_t(xdrs, &objp->pg_ngrps))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->pg_grps, objp->pg_ngrps,
+ sizeof (uint32_t), (xdrproc_t)xdr_uint32_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_posix_grps_helper(xdrs, identity)
+ XDR *xdrs;
+ char **identity;
+{
+ uint32_t pos, len;
+ uint32_t cnt;
+ bool_t rc;
+
+ if (xdrs->x_op == XDR_DECODE) {
+ pos = xdr_getpos(xdrs);
+
+ if (!xdr_bool(xdrs, &rc))
+ return (FALSE);
+
+ if (!xdr_uint32_t(xdrs, &cnt))
+ return (FALSE);
+
+ rc = xdr_setpos(xdrs, pos);
+ if (rc == FALSE)
+ return (FALSE);
+ } else {
+ if (*identity == NULL)
+ return (FALSE);
+ cnt = ((smb_posix_grps_t *)(uintptr_t)*identity)->pg_ngrps;
+ }
+
+ len = SMB_POSIX_GRPS_SIZE(cnt);
+
+ if (!xdr_pointer(xdrs, identity, len, (xdrproc_t)xdr_smb_posix_grps_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_session_key_t(xdrs, objp)
+ XDR *xdrs;
+ smb_session_key_t *objp;
+{
+ if (!xdr_vector(xdrs, (char *)objp->data, 16,
+ sizeof (uint8_t), (xdrproc_t)xdr_uint8_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_netr_client_t(xdrs, objp)
+ XDR *xdrs;
+ netr_client_t *objp;
+{
+ if (!xdr_uint16_t(xdrs, &objp->logon_level))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->username, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->domain, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->workstation, ~0))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ipaddr))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->challenge_key.challenge_key_val,
+ (uint32_t *)&objp->challenge_key.challenge_key_len, ~0,
+ sizeof (uint8_t), (xdrproc_t)xdr_uint8_t))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->nt_password.nt_password_val,
+ (uint32_t *)&objp->nt_password.nt_password_len, ~0,
+ sizeof (uint8_t), (xdrproc_t)xdr_uint8_t))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->lm_password.lm_password_val,
+ (uint32_t *)&objp->lm_password.lm_password_len, ~0,
+ sizeof (uint8_t), (xdrproc_t)xdr_uint8_t))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->logon_id))
+ return (FALSE);
+ if (!xdr_int(xdrs, &objp->native_os))
+ return (FALSE);
+ if (!xdr_int(xdrs, &objp->native_lm))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->local_ipaddr))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->local_port))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->flags))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_nt_sid_t(xdrs, objp)
+ XDR *xdrs;
+ nt_sid_t *objp;
+{
+ if (!xdr_uint8_t(xdrs, &objp->Revision))
+ return (FALSE);
+ if (!xdr_uint8_t(xdrs, &objp->SubAuthCount))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->Authority, NT_SID_AUTH_MAX,
+ sizeof (uint8_t), (xdrproc_t)xdr_uint8_t))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->SubAuthority, objp->SubAuthCount,
+ sizeof (uint32_t), (xdrproc_t)xdr_uint32_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_luid_t(xdrs, objp)
+ XDR *xdrs;
+ smb_luid_t *objp;
+{
+ if (!xdr_uint32_t(xdrs, &objp->lo_part))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->hi_part))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_luid_attrs_t(xdrs, objp)
+ XDR *xdrs;
+ smb_luid_attrs_t *objp;
+{
+ if (!xdr_smb_luid_t(xdrs, &objp->luid))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->attrs))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_privset_t(xdrs, objp)
+ XDR *xdrs;
+ smb_privset_t *objp;
+{
+ if (!xdr_uint32_t(xdrs, &objp->priv_cnt))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->control))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->priv, objp->priv_cnt,
+ sizeof (smb_luid_attrs_t),
+ (xdrproc_t)xdr_smb_luid_attrs_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_sid_attrs_t(xdrs, objp)
+ XDR *xdrs;
+ smb_sid_attrs_t *objp;
+{
+ if (!xdr_uint32_t(xdrs, &objp->attrs))
+ return (FALSE);
+ return (xdr_ntsid_helper(xdrs, (char **)&objp->sid));
+}
+
+bool_t
+xdr_smb_token_t(xdrs, objp)
+ XDR *xdrs;
+ smb_token_t *objp;
+{
+ if (!xdr_pointer(xdrs, (char **)&objp->tkn_user,
+ sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
+ return (FALSE);
+ if (!xdr_pointer(xdrs, (char **)&objp->tkn_owner,
+ sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
+ return (FALSE);
+ if (!xdr_pointer(xdrs, (char **)&objp->tkn_primary_grp,
+ sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
+ return (FALSE);
+ if (!xdr_smb_win_grps_helper(xdrs, (char **)&objp->tkn_win_grps))
+ return (FALSE);
+ if (!xdr_smb_privset_helper(xdrs, (char **)&objp->tkn_privileges))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->tkn_account_name, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->tkn_domain_name, ~0))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->tkn_flags))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->tkn_audit_sid))
+ return (FALSE);
+ if (!xdr_pointer(xdrs, (char **)&objp->tkn_session_key,
+ sizeof (smb_session_key_t), (xdrproc_t)xdr_smb_session_key_t))
+ return (FALSE);
+ if (!xdr_smb_posix_grps_helper(xdrs, (char **)&objp->tkn_posix_grps))
+ return (FALSE);
+ return (TRUE);
+}
diff --git a/usr/src/common/smbsrv/smb_utf8.c b/usr/src/common/smbsrv/smb_utf8.c
new file mode 100644
index 0000000000..704f01877e
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_utf8.c
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+/*
+ * Multibyte/wide-char conversion routines. Wide-char encoding provides
+ * a fixed size character encoding that maps to the Unicode 16-bit
+ * (UCS-2) character set standard. Multibyte or UCS transformation
+ * format (UTF) encoding is a variable length character encoding scheme
+ * that s compatible with existing ASCII characters and guarantees that
+ * the resultant strings do not contain embedded null characters. Both
+ * types of encoding provide a null terminator: single byte for UTF-8
+ * and a wide-char null for Unicode. See RFC 2044.
+ *
+ * The table below illustrates the UTF-8 encoding scheme. The letter x
+ * indicates bits available for encoding the character value.
+ *
+ * UCS-2 UTF-8 octet sequence (binary)
+ * 0x0000-0x007F 0xxxxxxx
+ * 0x0080-0x07FF 110xxxxx 10xxxxxx
+ * 0x0800-0xFFFF 1110xxxx 10xxxxxx 10xxxxxx
+ *
+ * RFC 2044
+ * UTF-8,a transformation format of UNICODE and ISO 10646
+ * F. Yergeau
+ * Alis Technologies
+ * October 1996
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <strings.h>
+#endif
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/string.h>
+
+int mbtowc_verbose = 0;
+int mbtowc_announce = 0;
+
+/*
+ * mbstowcs
+ *
+ * The mbstowcs() function converts a multibyte character string
+ * mbstring into a wide character string wcstring. No more than
+ * nwchars wide characters are stored. A terminating null wide
+ * character is appended if there is room.
+ *
+ * Returns the number of wide characters converted, not counting
+ * any terminating null wide character. Returns -1 if an invalid
+ * multibyte character is encountered.
+ */
+size_t
+mts_mbstowcs(mts_wchar_t *wcstring, const char *mbstring, size_t nwchars)
+{
+ int len;
+ mts_wchar_t *start = wcstring;
+
+ while (nwchars--) {
+ len = mts_mbtowc(wcstring, mbstring, MTS_MB_CHAR_MAX);
+ if (len < 0) {
+ *wcstring = 0;
+ return ((size_t)-1);
+ }
+
+ if (*mbstring == 0)
+ break;
+
+ ++wcstring;
+ mbstring += len;
+ }
+
+ return (wcstring - start);
+}
+
+
+/*
+ * mbtowc
+ *
+ * The mbtowc() function converts a multibyte character mbchar into
+ * a wide character and stores the result in the object pointed to
+ * by wcharp. Up to nbytes bytes are examined.
+ *
+ * If mbchar is NULL, mbtowc() returns zero to indicate that shift
+ * states are not supported. If mbchar is valid, returns the number
+ * of bytes processed in mbchar. If mbchar is invalid, returns -1.
+ */
+int /*ARGSUSED*/
+mts_mbtowc(mts_wchar_t *wcharp, const char *mbchar, size_t nbytes)
+{
+ unsigned char mbyte;
+ mts_wchar_t wide_char;
+ int count;
+ int bytes_left;
+
+ if (mbchar == 0)
+ return (0); /* shift states not supported */
+
+ /* 0xxxxxxx -> 1 byte ASCII encoding */
+ if (((mbyte = *mbchar++) & 0x80) == 0) {
+ if (wcharp)
+ *wcharp = (mts_wchar_t)mbyte;
+
+ return (mbyte ? 1 : 0);
+ }
+
+ /* 10xxxxxx -> invalid first byte */
+ if ((mbyte & 0x40) == 0) {
+ if (mbtowc_verbose || mbtowc_announce == 0) {
+ mbtowc_announce = 1;
+ }
+ return (-1);
+ }
+
+ wide_char = mbyte;
+ if ((mbyte & 0x20) == 0) {
+ wide_char &= 0x1f;
+ bytes_left = 1;
+ } else if ((mbyte & 0x10) == 0) {
+ wide_char &= 0x0f;
+ bytes_left = 2;
+ } else {
+ if (mbtowc_verbose || mbtowc_announce == 0) {
+ mbtowc_announce = 1;
+ }
+ return (-1);
+ }
+
+ count = 1;
+ while (bytes_left--) {
+ if (((mbyte = *mbchar++) & 0xc0) != 0x80) {
+ if (mbtowc_verbose || mbtowc_announce == 0) {
+ mbtowc_announce = 1;
+ }
+ return (-1);
+ }
+
+ count++;
+ wide_char = (wide_char << 6) | (mbyte & 0x3f);
+ }
+
+ if (wcharp)
+ *wcharp = wide_char;
+
+ return (count);
+}
+
+
+/*
+ * wctomb
+ *
+ * The wctomb() function converts a wide character wchar into a multibyte
+ * character and stores the result in mbchar. The object pointed to by
+ * mbchar must be large enough to accommodate the multibyte character.
+ *
+ * Returns the numberof bytes written to mbchar.
+ */
+int
+mts_wctomb(char *mbchar, mts_wchar_t wchar)
+{
+#ifdef UTF8_DEBUG
+ char *start = mbchar;
+#endif
+
+ if ((wchar & ~0x7f) == 0) {
+ *mbchar = (char)wchar;
+ return (1);
+ }
+
+ if ((wchar & ~0x7ff) == 0) {
+ *mbchar++ = (wchar >> 6) | 0xc0;
+ *mbchar = (wchar & 0x3f) | 0x80;
+ return (2);
+ }
+
+ *mbchar++ = (wchar >> 12) | 0xe0;
+ *mbchar++ = ((wchar >> 6) & 0x3f) | 0x80;
+ *mbchar = (wchar & 0x3f) | 0x80;
+ return (3);
+}
+
+
+/*
+ * wcstombs
+ *
+ * The wcstombs() function converts a wide character string wcstring
+ * into a multibyte character string mbstring. Up to nbytes bytes are
+ * stored in mbstring. Partial multibyte characters at the end of the
+ * string are not stored. The multibyte character string is null
+ * terminated if there is room.
+ *
+ * Returns the number of bytes converted, not counting the terminating
+ * null byte.
+ */
+size_t
+mts_wcstombs(char *mbstring, const mts_wchar_t *wcstring, size_t nbytes)
+{
+ char *start = mbstring;
+ const mts_wchar_t *wcp = wcstring;
+ mts_wchar_t wide_char;
+ char buf[4];
+ size_t len;
+
+ if ((mbstring == 0) || (wcstring == 0))
+ return (0);
+
+ while (nbytes > MTS_MB_CHAR_MAX) {
+ wide_char = *wcp++;
+ len = mts_wctomb(mbstring, wide_char);
+
+ if (wide_char == 0)
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (mbstring - start);
+
+ mbstring += len;
+ nbytes -= len;
+ }
+
+ while (wide_char && nbytes) {
+ wide_char = *wcp++;
+ if ((len = mts_wctomb(buf, wide_char)) > nbytes) {
+ *mbstring = 0;
+ break;
+ }
+
+ bcopy(buf, mbstring, len);
+ mbstring += len;
+ nbytes -= len;
+ }
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (mbstring - start);
+}
+
+
+/*
+ * Returns the number of bytes that would be written if the multi-
+ * byte string mbs was converted to a wide character string, not
+ * counting the terminating null wide character.
+ */
+size_t
+mts_wcequiv_strlen(const char *mbs)
+{
+ mts_wchar_t wide_char;
+ size_t bytes;
+ size_t len = 0;
+
+ while (*mbs) {
+ bytes = mts_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
+ if (bytes == ((size_t)-1))
+ return ((size_t)-1);
+
+ len += sizeof (mts_wchar_t);
+ mbs += bytes;
+ }
+
+ return (len);
+}
+
+
+/*
+ * Returns the number of bytes that would be written if the multi-
+ * byte string mbs was converted to a single byte character string,
+ * not counting the terminating null character.
+ */
+size_t
+mts_sbequiv_strlen(const char *mbs)
+{
+ mts_wchar_t wide_char;
+ size_t nbytes;
+ size_t len = 0;
+
+ while (*mbs) {
+ nbytes = mts_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
+ if (nbytes == ((size_t)-1))
+ return ((size_t)-1);
+
+ if (wide_char & 0xFF00)
+ len += sizeof (mts_wchar_t);
+ else
+ ++len;
+
+ mbs += nbytes;
+ }
+
+ return (len);
+}
+
+
+/*
+ * stombs
+ *
+ * Convert a regular null terminated string 'string' to a UTF-8 encoded
+ * null terminated multi-byte string 'mbstring'. Only full converted
+ * UTF-8 characters will be written 'mbstring'. If a character will not
+ * fit within the remaining buffer space or 'mbstring' will overflow
+ * max_mblen, the conversion process will be terminated and 'mbstring'
+ * will be null terminated.
+ *
+ * Returns the number of bytes written to 'mbstring', excluding the
+ * terminating null character.
+ *
+ * If either mbstring or string is a null pointer, -1 is returned.
+ */
+int
+mts_stombs(char *mbstring, char *string, int max_mblen)
+{
+ char *start = mbstring;
+ unsigned char *p = (unsigned char *)string;
+ int space_left = max_mblen;
+ int len;
+ mts_wchar_t wide_char;
+ char buf[4];
+
+ if (!mbstring || !string)
+ return (-1);
+
+ while (*p && space_left > 2) {
+ wide_char = *p++;
+ len = mts_wctomb(mbstring, wide_char);
+ mbstring += len;
+ space_left -= len;
+ }
+
+ if (*p) {
+ wide_char = *p;
+ if ((len = mts_wctomb(buf, wide_char)) < 2) {
+ *mbstring = *buf;
+ mbstring += len;
+ space_left -= len;
+ }
+ }
+
+ *mbstring = '\0';
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (mbstring - start);
+}
+
+
+/*
+ * mbstos
+ *
+ * Convert a null terminated multi-byte string 'mbstring' to a regular
+ * null terminated string 'string'. A 1-byte character in 'mbstring'
+ * maps to a 1-byte character in 'string'. A 2-byte character in
+ * 'mbstring' will be mapped to 2-bytes, if the upper byte is non-null.
+ * Otherwise the upper byte null will be discarded to ensure that the
+ * output stream does not contain embedded null characters.
+ *
+ * If the input stream contains invalid multi-byte characters, a value
+ * of -1 will be returned. Otherwise the length of 'string', excluding
+ * the terminating null character, is returned.
+ *
+ * If either mbstring or string is a null pointer, -1 is returned.
+ */
+int
+mts_mbstos(char *string, const char *mbstring)
+{
+ mts_wchar_t wc;
+ unsigned char *start = (unsigned char *)string;
+ int len;
+
+ if (string == 0 || mbstring == 0)
+ return (-1);
+
+ while (*mbstring) {
+ if ((len = mts_mbtowc(&wc, mbstring, MTS_MB_CHAR_MAX)) < 0) {
+ *string = 0;
+ return (-1);
+ }
+
+ if (wc & 0xFF00) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ *((mts_wchar_t *)string) = wc;
+ string += sizeof (mts_wchar_t);
+ }
+ else
+ {
+ *string = (unsigned char)wc;
+ string++;
+ }
+
+ mbstring += len;
+ }
+
+ *string = 0;
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return ((unsigned char *)string - start);
+}
diff --git a/usr/src/common/smbsrv/smb_xdr_utils.c b/usr/src/common/smbsrv/smb_xdr_utils.c
new file mode 100644
index 0000000000..1293eb34c1
--- /dev/null
+++ b/usr/src/common/smbsrv/smb_xdr_utils.c
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef _KERNEL
+#include <string.h>
+#endif /* _KERNEL */
+#include <smbsrv/smb_xdr.h>
+
+#ifdef _KERNEL
+/*
+ * xdr_vector():
+ *
+ * XDR a fixed length array. Unlike variable-length arrays,
+ * the storage of fixed length arrays is static and unfreeable.
+ * > basep: base of the array
+ * > size: size of the array
+ * > elemsize: size of each element
+ * > xdr_elem: routine to XDR each element
+ */
+#define LASTUNSIGNED ((uint_t)0-1)
+bool_t
+xdr_vector(XDR *xdrs, char *basep, uint_t nelem,
+ uint_t elemsize, xdrproc_t xdr_elem)
+{
+ uint_t i;
+ char *elptr;
+
+ elptr = basep;
+ for (i = 0; i < nelem; i++) {
+ if (!(*xdr_elem)(xdrs, elptr, LASTUNSIGNED))
+ return (FALSE);
+ elptr += elemsize;
+ }
+ return (TRUE);
+}
+
+/*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char(XDR *xdrs, uchar_t *cp)
+{
+ int i;
+
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ i = (*cp);
+ return (XDR_PUTINT32(xdrs, &i));
+ case XDR_DECODE:
+ if (!XDR_GETINT32(xdrs, &i))
+ return (FALSE);
+ *cp = (uchar_t)i;
+ return (TRUE);
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+#endif /* _KERNEL */
+
+bool_t
+xdr_smb_dr_string_t(xdrs, objp)
+ XDR *xdrs;
+ smb_dr_string_t *objp;
+{
+ if (!xdr_string(xdrs, &objp->buf, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_dr_bytes_t(xdrs, objp)
+ XDR *xdrs;
+ smb_dr_bytes_t *objp;
+{
+ if (!xdr_array(xdrs, (char **)&objp->bytes_val,
+ (uint32_t *)&objp->bytes_len, ~0, sizeof (uint8_t),
+ (xdrproc_t)xdr_uint8_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_dr_user_ctx_t(xdrs, objp)
+ XDR *xdrs;
+ smb_dr_user_ctx_t *objp;
+{
+ if (!xdr_uint64_t(xdrs, &objp->du_session_id))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->du_uid))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->du_domain_len))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->du_domain, ~0))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->du_account_len))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->du_account, ~0))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->du_workstation_len))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->du_workstation, ~0))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->du_ipaddr))
+ return (FALSE);
+ if (!xdr_int32_t(xdrs, &objp->du_native_os))
+ return (FALSE);
+ if (!xdr_int64_t(xdrs, &objp->du_logon_time))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->du_flags))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+bool_t
+xdr_smb_dr_ulist_t(xdrs, objp)
+ XDR *xdrs;
+ smb_dr_ulist_t *objp;
+{
+ if (!xdr_uint32_t(xdrs, &objp->dul_cnt))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->dul_users, SMB_DR_MAX_USERS,
+ sizeof (smb_dr_user_ctx_t), (xdrproc_t)xdr_smb_dr_user_ctx_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_smb_dr_kshare_t(xdrs, objp)
+ XDR *xdrs;
+ smb_dr_kshare_t *objp;
+{
+ if (!xdr_int32_t(xdrs, &objp->k_op))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->k_path, MAXPATHLEN))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->k_sharename, MAXNAMELEN))
+ return (FALSE);
+ return (TRUE);
+}
diff --git a/usr/src/common/util/string.c b/usr/src/common/util/string.c
index 94153d2db2..73063ead61 100644
--- a/usr/src/common/util/string.c
+++ b/usr/src/common/util/string.c
@@ -622,6 +622,62 @@ strspn(const char *string, const char *charset)
return ((size_t)(q - string));
}
+size_t
+strcspn(const char *string, const char *charset)
+{
+ const char *p, *q;
+
+ for (q = string; *q != '\0'; ++q) {
+ for (p = charset; *p != '\0' && *p != *q; ++p)
+ ;
+ if (*p != '\0')
+ break;
+ }
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return ((size_t)(q - string));
+}
+
+/*
+ * strsep
+ *
+ * The strsep() function locates, in the string referenced by *stringp, the
+ * first occurrence of any character in the string delim (or the terminating
+ * `\0' character) and replaces it with a `\0'. The location of the next
+ * character after the delimiter character (or NULL, if the end of the
+ * string was reached) is stored in *stringp. The original value of
+ * *stringp is returned.
+ *
+ * If *stringp is initially NULL, strsep() returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+
+ for (tok = s; ; ) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
/*
* Unless mentioned otherwise, all of the routines below should be added to
* the Solaris DDI as necessary. For now, only provide them to standalone.
diff --git a/usr/src/common/xattr/xattr_common.c b/usr/src/common/xattr/xattr_common.c
new file mode 100644
index 0000000000..55902162ea
--- /dev/null
+++ b/usr/src/common/xattr/xattr_common.c
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/attr.h>
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * This table maps each system attribute to its option and its view.
+ * All new system attrs must be added to this table. To add a new view,
+ * add another entry to xattr_dirents[] and update xattr_view_t in sys/attr.h.
+ * Also, xattr_file_pathconf() and sys/unistd.h should be updated to add
+ * return values for the new view.
+ */
+
+static xattr_entry_t xattrs[F_ATTR_ALL] = {
+ { A_ARCHIVE, O_ARCHIVE, XATTR_VIEW_READWRITE, DATA_TYPE_BOOLEAN_VALUE },
+ { A_HIDDEN, O_HIDDEN, XATTR_VIEW_READWRITE, DATA_TYPE_BOOLEAN_VALUE },
+ { A_READONLY, O_READONLY, XATTR_VIEW_READWRITE,
+ DATA_TYPE_BOOLEAN_VALUE },
+ { A_SYSTEM, O_SYSTEM, XATTR_VIEW_READWRITE, DATA_TYPE_BOOLEAN_VALUE },
+ { A_APPENDONLY, O_APPENDONLY, XATTR_VIEW_READWRITE,
+ DATA_TYPE_BOOLEAN_VALUE },
+ { A_NODUMP, O_NODUMP, XATTR_VIEW_READWRITE, DATA_TYPE_BOOLEAN_VALUE },
+ { A_IMMUTABLE, O_IMMUTABLE, XATTR_VIEW_READWRITE,
+ DATA_TYPE_BOOLEAN_VALUE },
+ { A_AV_MODIFIED, O_AV_MODIFIED, XATTR_VIEW_READWRITE,
+ DATA_TYPE_BOOLEAN_VALUE },
+ { A_OPAQUE, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_BOOLEAN_VALUE },
+ { A_AV_SCANSTAMP, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_UINT8_ARRAY },
+ { A_AV_QUARANTINED, O_AV_QUARANTINED, XATTR_VIEW_READWRITE,
+ DATA_TYPE_BOOLEAN_VALUE },
+ { A_NOUNLINK, O_NOUNLINK, XATTR_VIEW_READWRITE,
+ DATA_TYPE_BOOLEAN_VALUE },
+ { A_CRTIME, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_UINT64_ARRAY },
+ { A_OWNERSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST },
+ { A_GROUPSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST },
+ { A_FSID, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_UINT64 },
+ { A_MDEV, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_UINT16 },
+};
+
+const char *
+attr_to_name(f_attr_t attr)
+{
+ if (attr >= F_ATTR_ALL || attr < 0)
+ return (NULL);
+
+ return (xattrs[attr].x_name);
+}
+
+const char *
+attr_to_option(f_attr_t attr)
+{
+ if (attr >= F_ATTR_ALL || attr < 0)
+ return (NULL);
+
+ return (xattrs[attr].x_option);
+}
+
+f_attr_t
+name_to_attr(const char *name)
+{
+ int i;
+
+ for (i = 0; i < F_ATTR_ALL; i++) {
+ if (strcmp(name, xattrs[i].x_name) == 0)
+ return (i);
+ }
+
+ return (F_ATTR_INVAL);
+}
+
+f_attr_t
+option_to_attr(const char *option)
+{
+ int i;
+
+ for (i = 0; i < F_ATTR_ALL; i++) {
+ if (strcmp(option, xattrs[i].x_option) == 0)
+ return (i);
+ }
+
+ return (F_ATTR_INVAL);
+}
+
+xattr_view_t
+attr_to_xattr_view(f_attr_t attr)
+{
+ if (attr >= F_ATTR_ALL || attr < 0)
+ return (NULL);
+
+ return (xattrs[attr].x_xattr_view);
+}
+
+int
+attr_count(void)
+{
+ return (F_ATTR_ALL);
+}
+
+data_type_t
+attr_to_data_type(f_attr_t attr)
+{
+ if (attr >= F_ATTR_ALL || attr < 0)
+ return (DATA_TYPE_UNKNOWN);
+
+ return (xattrs[attr].x_data_type);
+}
diff --git a/usr/src/common/zfs/zfs_prop.c b/usr/src/common/zfs/zfs_prop.c
index 19b6774b6e..2d04ce5fb0 100644
--- a/usr/src/common/zfs/zfs_prop.c
+++ b/usr/src/common/zfs/zfs_prop.c
@@ -30,6 +30,7 @@
#include <sys/zfs_acl.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_znode.h>
+#include <sys/zfs_i18n.h>
#include "zfs_prop.h"
#include "zfs_deleg.h"
@@ -100,6 +101,13 @@ zfs_prop_init(void)
{ NULL }
};
+ static zprop_index_t case_table[] = {
+ { "sensitive", ZFS_CASE_SENSITIVE },
+ { "insensitive", ZFS_CASE_INSENSITIVE },
+ { "mixed", ZFS_CASE_MIXED },
+ { NULL }
+ };
+
static zprop_index_t copies_table[] = {
{ "1", 1 },
{ "2", 2 },
@@ -107,9 +115,19 @@ zfs_prop_init(void)
{ NULL }
};
+ static zprop_index_t normalize_table[] = {
+ { "none", ZFS_NORMALIZE_NONE },
+ { "formD", ZFS_NORMALIZE_D },
+ { "formKC", ZFS_NORMALIZE_KC },
+ { "formC", ZFS_NORMALIZE_C },
+ { "formKD", ZFS_NORMALIZE_KD },
+ { NULL }
+ };
+
static zprop_index_t version_table[] = {
{ "1", 1 },
{ "2", 2 },
+ { "3", 3 },
{ "current", ZPL_VERSION },
{ NULL }
};
@@ -163,11 +181,17 @@ zfs_prop_init(void)
register_index(ZFS_PROP_XATTR, "xattr", 1, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "XATTR",
boolean_table);
+ register_index(ZFS_PROP_VSCAN, "vscan", 0, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM, "on | off", "VSCAN",
+ boolean_table);
+ register_index(ZFS_PROP_NBMAND, "nbmand", 0, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "NBMAND",
+ boolean_table);
/* default index properties */
register_index(ZFS_PROP_VERSION, "version", 0, PROP_DEFAULT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
- "1 | 2 | current", "VERSION", version_table);
+ "1 | 2 | 3 | current", "VERSION", version_table);
/* default index (boolean) properties */
register_index(ZFS_PROP_CANMOUNT, "canmount", 1, PROP_DEFAULT,
@@ -177,6 +201,20 @@ zfs_prop_init(void)
register_index(ZFS_PROP_MOUNTED, "mounted", 0, PROP_READONLY,
ZFS_TYPE_FILESYSTEM, "yes | no", "MOUNTED", boolean_table);
+ /* set once index properties */
+ register_index(ZFS_PROP_NORMALIZE, "normalization", ZFS_NORMALIZE_NONE,
+ PROP_ONETIME, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
+ "none | formC | formD | formKC | formKD", "NORMALIZATION",
+ normalize_table);
+ register_index(ZFS_PROP_CASE, "casesensitivity", ZFS_CASE_SENSITIVE,
+ PROP_ONETIME, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
+ "sensitive | insensitive | mixed", "CASE", case_table);
+
+ /* set once index (boolean) properties */
+ register_index(ZFS_PROP_UTF8ONLY, "utf8only", 0, PROP_ONETIME,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
+ "on | off", "UTF8ONLY", boolean_table);
+
/* string properties */
register_string(ZFS_PROP_ORIGIN, "origin", NULL, PROP_READONLY,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN");
@@ -188,6 +226,8 @@ zfs_prop_init(void)
ZFS_TYPE_DATASET, "on | off | type=<type>", "SHAREISCSI");
register_string(ZFS_PROP_TYPE, "type", NULL, PROP_READONLY,
ZFS_TYPE_DATASET, "filesystem | volume | snapshot", "TYPE");
+ register_string(ZFS_PROP_SHARESMB, "sharesmb", "off", PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM, "on | off | sharemgr(1M) options", "SHARESMB");
/* readonly number properties */
register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,
@@ -200,8 +240,8 @@ zfs_prop_init(void)
PROP_READONLY, ZFS_TYPE_DATASET,
"<1.00x or higher if compressed>", "RATIO");
register_number(ZFS_PROP_VOLBLOCKSIZE, "volblocksize", 8192,
- PROP_READONLY, ZFS_TYPE_VOLUME,
- "512 to 128k, power of 2", "VOLBLOCK");
+ PROP_ONETIME,
+ ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK");
/* default number properties */
register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT,
@@ -322,7 +362,17 @@ zfs_prop_get_type(zfs_prop_t prop)
boolean_t
zfs_prop_readonly(zfs_prop_t prop)
{
- return (zfs_prop_table[prop].pd_attr == PROP_READONLY);
+ return (zfs_prop_table[prop].pd_attr == PROP_READONLY ||
+ zfs_prop_table[prop].pd_attr == PROP_ONETIME);
+}
+
+/*
+ * Returns TRUE if the property is only allowed to be set once.
+ */
+boolean_t
+zfs_prop_setonce(zfs_prop_t prop)
+{
+ return (zfs_prop_table[prop].pd_attr == PROP_ONETIME);
}
const char *
@@ -353,7 +403,8 @@ zfs_prop_to_name(zfs_prop_t prop)
boolean_t
zfs_prop_inheritable(zfs_prop_t prop)
{
- return (zfs_prop_table[prop].pd_attr == PROP_INHERIT);
+ return (zfs_prop_table[prop].pd_attr == PROP_INHERIT ||
+ zfs_prop_table[prop].pd_attr == PROP_ONETIME);
}
#ifndef _KERNEL
@@ -399,4 +450,5 @@ zfs_prop_align_right(zfs_prop_t prop)
{
return (zfs_prop_table[prop].pd_rightalign);
}
+
#endif
diff --git a/usr/src/common/zfs/zfs_prop.h b/usr/src/common/zfs/zfs_prop.h
index e2f1186285..08af3f4090 100644
--- a/usr/src/common/zfs/zfs_prop.h
+++ b/usr/src/common/zfs/zfs_prop.h
@@ -48,7 +48,14 @@ typedef enum {
typedef enum {
PROP_DEFAULT,
PROP_READONLY,
- PROP_INHERIT
+ PROP_INHERIT,
+ /*
+ * ONETIME properties are a sort of conglomeration of READONLY
+ * and INHERIT. They can be set only during object creation,
+ * after that they are READONLY. If not explicitly set during
+ * creation, they can be inherited.
+ */
+ PROP_ONETIME
} zprop_attr_t;
typedef struct zfs_index {
diff --git a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h
index 8af94bc497..9619d5bfc2 100644
--- a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h
+++ b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h
@@ -37,7 +37,8 @@
#define SPA_VERSION_6 6ULL
#define SPA_VERSION_7 7ULL
#define SPA_VERSION_8 8ULL
-#define SPA_VERSION SPA_VERSION_8
+#define SPA_VERSION_9 9ULL
+#define SPA_VERSION SPA_VERSION_9
/*
* The following are configuration names used in the nvlist describing a pool's
diff --git a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs_acl.h b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs_acl.h
index eb51b9baa8..77ebb8dc77 100644
--- a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs_acl.h
+++ b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs_acl.h
@@ -31,21 +31,32 @@
typedef unsigned int uid_t; /* UID type */
#endif /* _UID_T */
-typedef struct ace {
- uid_t a_who; /* uid or gid */
- uint32_t a_access_mask; /* read,write,... */
- uint16_t a_flags; /* see below */
- uint16_t a_type; /* allow or deny */
-} ace_t;
+typedef struct zfs_oldace {
+ uint32_t z_fuid; /* "who" */
+ uint32_t z_access_mask; /* access mask */
+ uint16_t z_flags; /* flags, i.e inheritance */
+ uint16_t z_type; /* type of entry allow/deny */
+} zfs_oldace_t;
#define ACE_SLOT_CNT 6
-typedef struct zfs_znode_acl {
+typedef struct zfs_znode_acl_v0 {
uint64_t z_acl_extern_obj; /* ext acl pieces */
uint32_t z_acl_count; /* Number of ACEs */
uint16_t z_acl_version; /* acl version */
uint16_t z_acl_pad; /* pad */
- ace_t z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */
+ zfs_oldace_t z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */
+} zfs_znode_acl_v0_t;
+
+#define ZFS_ACE_SPACE (sizeof (zfs_oldace_t) * ACE_SLOT_CNT)
+
+typedef struct zfs_znode_acl {
+ uint64_t z_acl_extern_obj; /* ext acl pieces */
+ uint32_t z_acl_size; /* Number of bytes in ACL */
+ uint16_t z_acl_version; /* acl version */
+ uint16_t z_acl_count; /* ace count */
+ uint8_t z_ace_data[ZFS_ACE_SPACE]; /* space for embedded ACEs */
} zfs_znode_acl_t;
+
#endif /* _SYS_FS_ZFS_ACL_H */
diff --git a/usr/src/head/Makefile b/usr/src/head/Makefile
index 5183a40513..d63931a8a4 100644
--- a/usr/src/head/Makefile
+++ b/usr/src/head/Makefile
@@ -48,6 +48,7 @@ HDRS= $($(MACH)_HDRS) $(ATTRDB_HDRS) \
archives.h \
assert.h \
atomic.h \
+ attr.h \
config_admin.h \
cpio.h \
crypt.h \
diff --git a/usr/src/head/attr.h b/usr/src/head/attr.h
new file mode 100644
index 0000000000..9c394412a1
--- /dev/null
+++ b/usr/src/head/attr.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef _ATTR_H
+#define _ATTR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6.1.7 */
+
+#include <sys/types.h>
+#include <sys/nvpair.h>
+#include <sys/attr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__STDC__)
+
+extern int getattrat(int, xattr_view_t, const char *, nvlist_t **);
+extern int fgetattr(int, xattr_view_t, nvlist_t **);
+extern int setattrat(int, xattr_view_t, const char *, nvlist_t *);
+extern int fsetattr(int, xattr_view_t, nvlist_t *);
+
+#else /* defined(__STDC__) */
+
+extern int getattrat();
+extern int fgetattr();
+extern int setattrat();
+extern int fsetattr();
+
+#endif /* defined(__STDC__) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ATTR_H */
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 68613f9412..ab96c6624e 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -234,6 +234,7 @@ SUBDIRS += \
libidmap \
libipmi \
libexacct/demo \
+ smbsrv \
$($(MACH)_SUBDIRS)
sparc_SUBDIRS= .WAIT \
@@ -421,6 +422,7 @@ HDRSUBDIRS= \
libkrb5 \
libshare \
libidmap \
+ smbsrv \
$($(MACH)_HDRSUBDIRS)
$(CLOSED_BUILD)HDRSUBDIRS += \
@@ -506,7 +508,7 @@ libinetcfg: libnsl libsocket libdevinfo
libkmf: libcryptoutil pkcs11 openssl
libnsl: libmd5 libscf
libmapid: libresolv
-libuuid: libdlpi libdladm
+libuuid: libdlpi libdladm
libinetutil: libsocket
libsecdb: libnsl
libsasl: libgss libsocket pkcs11 libmd
@@ -528,7 +530,7 @@ libwrap: libnsl libsocket
libwanboot: libnvpair libresolv libnsl libsocket libdevinfo libinetutil \
libdhcputil openssl
libwanbootutil: libnsl
-pam_modules: libproject passwdutil $(SMARTCARD)
+pam_modules: libproject passwdutil $(SMARTCARD) smbsrv
libscf: libuutil libmd libgen
libinetsvc: libscf
librestart: libuutil libscf
@@ -545,6 +547,8 @@ brand: libc libsocket
libshare: libscf libzfs libuuid libfsmgt libsecdb
libexacct/demo: libexacct libproject libsocket libnsl
libtsalarm: libpcp
+smbsrv: libsocket libnsl libmd libxnet libpthread librt \
+ libshare libidmap pkcs11
#
# The reason this rule checks for the existence of the
diff --git a/usr/src/lib/common/inc/c_synonyms.h b/usr/src/lib/common/inc/c_synonyms.h
index 50bb091a58..8b8a610531 100644
--- a/usr/src/lib/common/inc/c_synonyms.h
+++ b/usr/src/lib/common/inc/c_synonyms.h
@@ -744,6 +744,7 @@ extern "C" {
#define readv _readv
#define realpath _realpath
#define remque _remque
+#define renameat _renameat
#define resolvepath _resolvepath
#define rmdir _rmdir
#define rwlock_destroy _rwlock_destroy
diff --git a/usr/src/lib/libbc/inc/include/tzfile.h b/usr/src/lib/libbc/inc/include/tzfile.h
index d6e43f03c2..b094236256 100644
--- a/usr/src/lib/libbc/inc/include/tzfile.h
+++ b/usr/src/lib/libbc/inc/include/tzfile.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,139 +19,17 @@
* CDDL HEADER END
*/
/*
- * Copyright 1989 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* from Arthur Olson's 6.1 */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#ifndef TZFILE_H
-
-#define TZFILE_H
-
-/*
-** Information about time zone files.
-*/
-
-#define TZDIR "/usr/share/lib/zoneinfo" /* Time zone object file directory */
-
-#define TZDEFAULT (getenv("TZ"))
-
-#define TZDEFRULES "posixrules"
-
-/*
-** Each file begins with. . .
-*/
-
-struct tzhead {
- char tzh_reserved[24]; /* reserved for future use */
- char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
- char tzh_leapcnt[4]; /* coded number of leap seconds */
- char tzh_timecnt[4]; /* coded number of transition times */
- char tzh_typecnt[4]; /* coded number of local time types */
- char tzh_charcnt[4]; /* coded number of abbr. chars */
-};
-
-/*
-** . . .followed by. . .
-**
-** tzh_timecnt (char [4])s coded transition times a la time(2)
-** tzh_timecnt (unsigned char)s types of local time starting at above
-** tzh_typecnt repetitions of
-** one (char [4]) coded GMT offset in seconds
-** one (unsigned char) used to set tm_isdst
-** one (unsigned char) that's an abbreviation list index
-** tzh_charcnt (char)s '\0'-terminated zone abbreviations
-** tzh_leapcnt repetitions of
-** one (char [4]) coded leap second transition times
-** one (char [4]) total correction after above
-** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
-** time is standard time, if FALSE,
-** transition time is wall clock time
-** if absent, transition times are
-** assumed to be wall clock time
-*/
-
-/*
-** In the current implementation, "tzset()" refuses to deal with files that
-** exceed any of the limits below.
-*/
+#ifndef _TZFILE_H
+#define _TZFILE_H
-/*
-** The TZ_MAX_TIMES value below is enough to handle a bit more than a
-** year's worth of solar time (corrected daily to the nearest second) or
-** 138 years of Pacific Presidential Election time
-** (where there are three time zone transitions every fourth year).
-*/
-#define TZ_MAX_TIMES 370
-
-#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
-
-#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
-
-#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
-
-#define SECSPERMIN 60
-#define MINSPERHOUR 60
-#define HOURSPERDAY 24
-#define DAYSPERWEEK 7
-#define DAYSPERNYEAR 365
-#define DAYSPERLYEAR 366
-#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
-#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
-#define MONSPERYEAR 12
-
-#define TM_SUNDAY 0
-#define TM_MONDAY 1
-#define TM_TUESDAY 2
-#define TM_WEDNESDAY 3
-#define TM_THURSDAY 4
-#define TM_FRIDAY 5
-#define TM_SATURDAY 6
-
-#define TM_JANUARY 0
-#define TM_FEBRUARY 1
-#define TM_MARCH 2
-#define TM_APRIL 3
-#define TM_MAY 4
-#define TM_JUNE 5
-#define TM_JULY 6
-#define TM_AUGUST 7
-#define TM_SEPTEMBER 8
-#define TM_OCTOBER 9
-#define TM_NOVEMBER 10
-#define TM_DECEMBER 11
-
-#define TM_YEAR_BASE 1900
-
-#define EPOCH_YEAR 1970
-#define EPOCH_WDAY TM_THURSDAY
-
-/*
-** Accurate only for the past couple of centuries;
-** that will probably do.
-*/
-
-#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
-
-/*
-** Use of the underscored variants may cause problems if you move your code to
-** certain System-V-based systems; for maximum portability, use the
-** underscore-free variants. The underscored variants are provided for
-** backward compatibility only; they may disappear from future versions of
-** this file.
-*/
+#pragma ident "%Z%%M% %I% %E% SMI"
-#define SECS_PER_MIN SECSPERMIN
-#define MINS_PER_HOUR MINSPERHOUR
-#define HOURS_PER_DAY HOURSPERDAY
-#define DAYS_PER_WEEK DAYSPERWEEK
-#define DAYS_PER_NYEAR DAYSPERNYEAR
-#define DAYS_PER_LYEAR DAYSPERLYEAR
-#define SECS_PER_HOUR SECSPERHOUR
-#define SECS_PER_DAY SECSPERDAY
-#define MONS_PER_YEAR MONSPERYEAR
+#include <sys/tzfile.h>
-#endif /* !defined TZFILE_H */
+#endif /* _TZFILE_H */
diff --git a/usr/src/lib/libbsm/audit_event.txt b/usr/src/lib/libbsm/audit_event.txt
index 8192080da3..125ef50174 100644
--- a/usr/src/lib/libbsm/audit_event.txt
+++ b/usr/src/lib/libbsm/audit_event.txt
@@ -444,6 +444,8 @@
6241:AUE_uadmin_remount:uadmin(1m) - remount:ss
6242:AUE_uadmin_ftrace:uadmin(1m) - ftrace:ss
6243:AUE_uadmin_swapctl:uadmin(1m) - swapctl:ss
+6237:AUE_smbd_session:smbd(1m) session setup:lo
+6238:AUE_smbd_logoff:smbd(1m) session logoff:lo
#
# Trusted Extensions events:
#
diff --git a/usr/src/lib/libbsm/common/adt.xml b/usr/src/lib/libbsm/common/adt.xml
index 3ae2957188..a91361e402 100644
--- a/usr/src/lib/libbsm/common/adt.xml
+++ b/usr/src/lib/libbsm/common/adt.xml
@@ -1231,8 +1231,61 @@ Use is subject to license terms.
<see>uadmin(1M)</see>
</event>
+<!-- smbd service event; smbd session setup -->
+ <event id="AUE_smbd_session" header="0" idNo="58" omit="JNI">
+ <title>smbd</title>
+ <program>/usr/lib/smbsrv/smbd</program>
+ <entry id="subject">
+ <internal token="subject"/>
+ <external opt="none"/>
+ </entry>
+ <entry id="domain">
+ <internal token="text"/>
+ <external opt="required" type="char*"/>
+ <comment>domain</comment>
+ </entry>
+ <entry id="username">
+ <internal token="text"/>
+ <external opt="required" type="char*"/>
+ <comment>username</comment>
+ </entry>
+ <entry id="sid">
+ <internal token="text"/>
+ <external opt="optional" type="char*"/>
+ <comment>sid</comment>
+ </entry>
+ <entry id="return">
+ <internal token="return"/>
+ <external opt="none"/>
+ </entry>
+ </event>
+
+<!-- smbd service event; smbd session logoff -->
+ <event id="AUE_smbd_logoff" header="0" idNo="59" omit="JNI">
+ <title>smbd</title>
+ <program>/usr/lib/smbsrv/smbd</program>
+ <entry id="subject">
+ <internal token="subject"/>
+ <external opt="none"/>
+ </entry>
+ <entry id="domain">
+ <internal token="text"/>
+ <external opt="required" type="char*"/>
+ <comment>domain</comment>
+ </entry>
+ <entry id="username">
+ <internal token="text"/>
+ <external opt="required" type="char*"/>
+ <comment>username</comment>
+ </entry>
+ <entry id="return">
+ <internal token="return"/>
+ <external opt="none"/>
+ </entry>
+ </event>
+
<!-- add new events here with the next higher idNo -->
-<!-- Highest idNo is 57, so next is 58, then fix this comment -->
+<!-- Highest idNo is 59, so next is 60, then fix this comment -->
<!-- end of C Only events -->
diff --git a/usr/src/lib/libc/Makefile.targ b/usr/src/lib/libc/Makefile.targ
index b8237246a4..95a0a3b0e3 100644
--- a/usr/src/lib/libc/Makefile.targ
+++ b/usr/src/lib/libc/Makefile.targ
@@ -272,6 +272,10 @@ $(COMOBJS:%=pics/%): $(SRC)/common/util/$$(@F:.o=.c)
$(COMPILE.c) -o $@ $(SRC)/common/util/$(@F:.o=.c)
$(POST_PROCESS_O)
+$(XATTROBJS:%=pics/%): $(SRC)/common/xattr/$$(@F:.o=.c)
+ $(COMPILE.c) -o $@ $(SRC)/common/xattr/$(@F:.o=.c)
+ $(POST_PROCESS_O)
+
$(DTRACEOBJS:%=pics/%): $(SRC)/common/dtrace/$$(@F:.o=.c)
$(COMPILE.c) -o $@ $(SRC)/common/dtrace/$(@F:.o=.c)
$(POST_PROCESS_O)
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile
index 0e2d924805..0539645b34 100644
--- a/usr/src/lib/libc/amd64/Makefile
+++ b/usr/src/lib/libc/amd64/Makefile
@@ -85,6 +85,8 @@ FPASMOBJS= \
ATOMICOBJS= \
atomic.o
+XATTROBJS= \
+ xattr_common.o
COMOBJS= \
bcmp.o \
bcopy.o \
@@ -99,6 +101,7 @@ GENOBJS= \
_getsp.o \
abs.o \
alloca.o \
+ attrat.o \
byteorder.o \
cache.o \
cuexit.o \
@@ -849,6 +852,7 @@ MOSTOBJS= \
$(I386FPOBJS) \
$(FPASMOBJS) \
$(ATOMICOBJS) \
+ $(XATTROBJS) \
$(COMOBJS) \
$(GENOBJS) \
$(PORTFP) \
@@ -966,6 +970,7 @@ CLOBBERFILES += $(LIB_PIC)
# list of C source for lint
SRCS= \
$(ATOMICOBJS:%.o=$(SRC)/common/atomic/%.c) \
+ $(XATTROBJS:%.o=$(SRC)/common/xattr/%.c) \
$(COMOBJS:%.o=$(SRC)/common/util/%.c) \
$(PORTFP:%.o=../port/fp/%.c) \
$(PORTGEN:%.o=../port/gen/%.c) \
diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com
index 6fe1a1c5cc..5fb4ffea84 100644
--- a/usr/src/lib/libc/i386/Makefile.com
+++ b/usr/src/lib/libc/i386/Makefile.com
@@ -83,6 +83,9 @@ FPASMOBJS= \
ATOMICOBJS= \
atomic.o
+XATTROBJS= \
+ xattr_common.o
+
COMOBJS= \
bcmp.o \
bcopy.o \
@@ -389,6 +392,7 @@ PORTGEN= \
atoi.o \
atol.o \
atoll.o \
+ attrat.o \
attropen.o \
atexit.o \
atfork.o \
@@ -884,6 +888,7 @@ MOSTOBJS= \
$(FPOBJS) \
$(FPASMOBJS) \
$(ATOMICOBJS) \
+ $(XATTROBJS) \
$(COMOBJS) \
$(DTRACEOBJS) \
$(GENOBJS) \
@@ -1026,6 +1031,7 @@ CLOBBERFILES += $(LIB_PIC)
# list of C source for lint
SRCS= \
$(ATOMICOBJS:%.o=$(SRC)/common/atomic/%.c) \
+ $(XATTROBJS:%.o=$(SRC)/common/xattr/%.c) \
$(COMOBJS:%.o=$(SRC)/common/util/%.c) \
$(DTRACEOBJS:%.o=$(SRC)/common/dtrace/%.c) \
$(PORTFP:%.o=../port/fp/%.c) \
diff --git a/usr/src/lib/libc/port/gen/attrat.c b/usr/src/lib/libc/port/gen/attrat.c
new file mode 100644
index 0000000000..f2a26d17cd
--- /dev/null
+++ b/usr/src/lib/libc/port/gen/attrat.c
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "synonyms.h"
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <mtlib.h>
+#include <attr.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/filio.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
+static int (*nvsize)(nvlist_t *, size_t *, int);
+static int (*nvunpacker)(char *, size_t, nvlist_t **);
+static mutex_t attrlock = DEFAULTMUTEX;
+static int initialized;
+extern int __openattrdirat(int basefd, const char *name);
+
+static char *xattr_view_name[XATTR_VIEW_LAST] = {
+ VIEW_READONLY,
+ VIEW_READWRITE
+};
+
+static int
+attrat_init()
+{
+ if (initialized == 0) {
+ lmutex_lock(&attrlock);
+ if (initialized == 1) {
+ lmutex_unlock(&attrlock);
+ return (0);
+ }
+
+ void *libnvhandle = dlopen("libnvpair.so.1", RTLD_LAZY);
+ if (libnvhandle == NULL || (nvpacker = (int (*)(nvlist_t *,
+ char **, size_t *, int, int)) dlsym(libnvhandle,
+ "nvlist_pack")) == NULL ||
+ (nvsize = (int (*)(nvlist_t *,
+ size_t *, int)) dlsym(libnvhandle,
+ "nvlist_size")) == NULL ||
+ (nvunpacker = (int (*)(char *, size_t,
+ nvlist_t **)) dlsym(libnvhandle,
+ "nvlist_unpack")) == NULL) {
+ if (libnvhandle)
+ dlclose(libnvhandle);
+ lmutex_unlock(&attrlock);
+ return (EINVAL);
+ }
+
+ initialized = 1;
+ lmutex_unlock(&attrlock);
+ }
+ return (0);
+}
+
+static int
+attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
+{
+ size_t bufsize;
+ char *packbuf = NULL;
+
+ if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
+ return (EINVAL);
+ }
+
+ packbuf = malloc(bufsize);
+ if (packbuf == NULL)
+ return (EINVAL);
+ if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
+ free(packbuf);
+ } else {
+ *nv_request = (void *)packbuf;
+ *nv_requestlen = bufsize;
+ }
+ return (0);
+}
+
+static const char *
+view_to_name(xattr_view_t view)
+{
+ if (view >= XATTR_VIEW_LAST || view < 0)
+ return (NULL);
+ return (xattr_view_name[view]);
+}
+
+static int
+xattr_openat(int basefd, xattr_view_t view, int mode)
+{
+ const char *xattrname;
+ int xattrfd;
+ int oflag;
+
+ switch (view) {
+ case XATTR_VIEW_READONLY:
+ oflag = O_RDONLY;
+ break;
+ case XATTR_VIEW_READWRITE:
+ oflag = mode & O_RDWR;
+ break;
+ default:
+ (void) __set_errno(EINVAL);
+ return (-1);
+ }
+ if (mode & O_XATTR)
+ oflag |= O_XATTR;
+
+ xattrname = view_to_name(view);
+ xattrfd = openat(basefd, xattrname, oflag);
+ if (xattrfd < 0)
+ return (xattrfd);
+ /* Don't cache sysattr info (advisory) */
+ (void) directio(xattrfd, DIRECTIO_ON);
+ return (xattrfd);
+}
+
+static int
+cgetattr(int fd, nvlist_t **response)
+{
+ int error;
+ int bytesread;
+ void *nv_response;
+ size_t nv_responselen;
+ struct stat buf;
+
+ if (error = attrat_init())
+ return (__set_errno(error));
+ if ((error = fstat(fd, &buf)) != 0)
+ return (__set_errno(error));
+ nv_responselen = buf.st_size;
+
+ if ((nv_response = malloc(nv_responselen)) == NULL)
+ return (__set_errno(ENOMEM));
+ bytesread = read(fd, nv_response, nv_responselen);
+ if (bytesread != nv_responselen)
+ return (__set_errno(EFAULT));
+
+ error = nvunpacker(nv_response, nv_responselen, response);
+ free(nv_response);
+ return (error);
+}
+
+static int
+csetattr(int fd, nvlist_t *request)
+{
+ int error, saveerrno;
+ int byteswritten;
+ void *nv_request;
+ size_t nv_requestlen;
+
+ if (error = attrat_init())
+ return (__set_errno(error));
+
+ if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0)
+ return (__set_errno(error));
+
+ (void) __set_errno(0);
+ byteswritten = write(fd, nv_request, nv_requestlen);
+ if (byteswritten != nv_requestlen) {
+ saveerrno = errno;
+ free(nv_request);
+ errno = saveerrno;
+ return (__set_errno(errno));
+ }
+
+ free(nv_request);
+ return (0);
+}
+
+int
+fgetattr(int basefd, xattr_view_t view, nvlist_t **response)
+{
+ int error, saveerrno, xattrfd;
+
+ if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0)
+ return (xattrfd);
+
+ error = cgetattr(xattrfd, response);
+ saveerrno = errno;
+ (void) close(xattrfd);
+ errno = saveerrno;
+ return (error);
+}
+
+int
+fsetattr(int basefd, xattr_view_t view, nvlist_t *request)
+{
+ int error, saveerrno, xattrfd;
+
+ if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0)
+ return (xattrfd);
+ error = csetattr(xattrfd, request);
+ saveerrno = errno;
+ (void) close(xattrfd);
+ errno = saveerrno;
+ return (error);
+}
+
+int
+getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response)
+{
+ int error, saveerrno, namefd, xattrfd;
+
+ if ((namefd = __openattrdirat(basefd, name)) < 0)
+ return (namefd);
+
+ if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) {
+ saveerrno = errno;
+ (void) close(namefd);
+ errno = saveerrno;
+ return (xattrfd);
+ }
+
+ error = cgetattr(xattrfd, response);
+ saveerrno = errno;
+ (void) close(namefd);
+ (void) close(xattrfd);
+ errno = saveerrno;
+ return (error);
+}
+
+int
+setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request)
+{
+ int error, saveerrno, namefd, xattrfd;
+
+ if ((namefd = __openattrdirat(basefd, name)) < 0)
+ return (namefd);
+
+ if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) {
+ saveerrno = errno;
+ (void) close(namefd);
+ errno = saveerrno;
+ return (xattrfd);
+ }
+
+ error = csetattr(xattrfd, request);
+ saveerrno = errno;
+ (void) close(namefd);
+ (void) close(xattrfd);
+ errno = saveerrno;
+ return (error);
+}
diff --git a/usr/src/lib/libc/port/gen/privlib.c b/usr/src/lib/libc/port/gen/privlib.c
index 1968f7eaa4..57218876bc 100644
--- a/usr/src/lib/libc/port/gen/privlib.c
+++ b/usr/src/lib/libc/port/gen/privlib.c
@@ -442,7 +442,7 @@ priv_set(priv_op_t op, priv_ptype_t setname, ...)
/*
* priv_ineffect(privilege).
- * tests the existance of a privilege against the effective set.
+ * tests the existence of a privilege against the effective set.
*/
boolean_t
priv_ineffect(const char *priv)
diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc
index 3e3bba59ca..e74313a424 100644
--- a/usr/src/lib/libc/port/llib-lc
+++ b/usr/src/lib/libc/port/llib-lc
@@ -31,6 +31,7 @@
#include <aio.h>
#include <alloca.h>
+#include <attr.h>
#include <atomic.h>
#include <ctype.h>
#include <deflt.h>
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index 3e658f68e6..717c4d9186 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -64,8 +64,11 @@ SUNW_1.23 { # SunOS 5.11 (Solaris 11)
err;
errx;
fdatasync;
+ fgetattr;
forkallx;
forkx;
+ fsetattr;
+ getattrat;
htonl;
htons;
lio_listio;
@@ -111,6 +114,7 @@ SUNW_1.23 { # SunOS 5.11 (Solaris 11)
sem_trywait;
sem_unlink;
sem_wait;
+ setattrat;
_sharefs;
shm_open;
shm_unlink;
@@ -1408,6 +1412,11 @@ SUNWprivate_1.1 {
_atomic_swap_uint = NODYNSORT;
_atomic_swap_ulong = NODYNSORT;
_atomic_swap_ushort = NODYNSORT;
+ attr_count;
+ attr_to_data_type;
+ attr_to_name;
+ attr_to_option;
+ attr_to_xattr_view;
_autofssys;
_brk;
__btowc_dense;
@@ -1762,6 +1771,7 @@ SUNWprivate_1.1 {
__mutex_trylock;
_mutex_unlock = NODYNSORT;
__mutex_unlock;
+ name_to_attr;
_nanosleep;
__nan_read;
__nan_written;
@@ -1807,6 +1817,8 @@ SUNWprivate_1.1 {
__nsw_getconfig_v1;
__nthreads;
__numeric_init;
+ __openattrdirat;
+ option_to_attr;
_openlog;
_plock;
_port_alert;
diff --git a/usr/src/lib/libc/port/sys/fsmisc.c b/usr/src/lib/libc/port/sys/fsmisc.c
index 88415c5363..491cc73732 100644
--- a/usr/src/lib/libc/port/sys/fsmisc.c
+++ b/usr/src/lib/libc/port/sys/fsmisc.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -60,3 +59,9 @@ renameat(int fromfd, const char *fromname, int tofd, const char *toname)
{
return (syscall(SYS_fsat, 7, fromfd, fromname, tofd, toname));
}
+
+int
+__openattrdirat(int fd, const char *name)
+{
+ return (syscall(SYS_fsat, 9, fd, name));
+}
diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile
index c67463652b..37e0818dc6 100644
--- a/usr/src/lib/libc/sparc/Makefile
+++ b/usr/src/lib/libc/sparc/Makefile
@@ -102,6 +102,9 @@ FPASMOBJS= \
ATOMICOBJS= \
atomic.o
+XATTROBJS= \
+ xattr_common.o
+
COMOBJS= \
bcmp.o \
bcopy.o \
@@ -413,6 +416,7 @@ PORTGEN= \
atoi.o \
atol.o \
atoll.o \
+ attrat.o \
attropen.o \
atexit.o \
atfork.o \
@@ -912,6 +916,7 @@ MOSTOBJS= \
$(FPOBJS) \
$(FPASMOBJS) \
$(ATOMICOBJS) \
+ $(XATTROBJS) \
$(COMOBJS) \
$(DTRACEOBJS) \
$(GENOBJS) \
@@ -1044,6 +1049,7 @@ CLOBBERFILES += $(LIB_PIC)
# list of C source for lint
SRCS= \
$(ATOMICOBJS:%.o=$(SRC)/common/atomic/%.c) \
+ $(XATTROBJS:%.o=$(SRC)/common/xattr/%.c) \
$(COMOBJS:%.o=$(SRC)/common/util/%.c) \
$(DTRACEOBJS:%.o=$(SRC)/common/dtrace/%.c) \
$(PORTFP:%.o=../port/fp/%.c) \
diff --git a/usr/src/lib/libc/sparcv9/Makefile b/usr/src/lib/libc/sparcv9/Makefile
index c114126bfe..c837e39361 100644
--- a/usr/src/lib/libc/sparcv9/Makefile
+++ b/usr/src/lib/libc/sparcv9/Makefile
@@ -107,6 +107,9 @@ $(__GNUC)FPASMOBJS += \
ATOMICOBJS= \
atomic.o
+XATTROBJS= \
+ xattr_common.o
+
COMOBJS= \
bcmp.o \
bcopy.o \
@@ -371,6 +374,7 @@ PORTGEN= \
abort.o \
addsev.o \
assert.o \
+ attrat.o \
atof.o \
atoi.o \
atol.o \
@@ -858,6 +862,7 @@ MOSTOBJS= \
$(FPOBJS64) \
$(FPASMOBJS) \
$(ATOMICOBJS) \
+ $(XATTROBJS) \
$(COMOBJS) \
$(GENOBJS) \
$(PORTFP) \
@@ -978,6 +983,7 @@ CLOBBERFILES += $(LIB_PIC)
# list of C source for lint
SRCS= \
$(ATOMICOBJS:%.o=$(SRC)/common/atomic/%.c) \
+ $(XATTROBJS:%.o=$(SRC)/common/xattr/%.c) \
$(COMOBJS:%.o=$(SRC)/common/util/%.c) \
$(PORTFP:%.o=../port/fp/%.c) \
$(PORTGEN:%.o=../port/gen/%.c) \
diff --git a/usr/src/lib/libcmdutils/Makefile.com b/usr/src/lib/libcmdutils/Makefile.com
index 50ca57cedf..e12e5b07c5 100644
--- a/usr/src/lib/libcmdutils/Makefile.com
+++ b/usr/src/lib/libcmdutils/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -27,14 +27,14 @@
LIBRARY= libcmdutils.a
VERS= .1
-OBJECTS= avltree.o
+OBJECTS= avltree.o sysattrs.o writefile.o process_xattrs.o
include ../../Makefile.lib
include ../../Makefile.rootfs
LIBS = $(DYNLIB) $(LINTLIB)
-LDLIBS += -lc -lavl
+LDLIBS += -lc -lavl -lnvpair
SRCDIR = ../common
$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
@@ -43,7 +43,7 @@ CFLAGS += $(CCVERBOSE)
# All commands using the common avltree interfaces must
# be largefile aware.
-CPPFLAGS += -I.. -D_REENTRANT -D_FILE_OFFSET_BITS=64
+CPPFLAGS += -I.. -I../../common/inc -D_REENTRANT -D_FILE_OFFSET_BITS=64
.KEEP_STATE:
diff --git a/usr/src/lib/libcmdutils/common/mapfile-vers b/usr/src/lib/libcmdutils/common/mapfile-vers
index 48d26ca9af..295493845b 100644
--- a/usr/src/lib/libcmdutils/common/mapfile-vers
+++ b/usr/src/lib/libcmdutils/common/mapfile-vers
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -30,6 +30,12 @@ SUNWprivate_1.1 {
add_tnode;
destroy_tree;
tnode_compare;
+ sysattr_type;
+ sysattr_support;
+ writefile;
+ get_attrdirs;
+ mv_xattrs;
+ sysattr_list;
local:
*;
};
diff --git a/usr/src/lib/libcmdutils/common/process_xattrs.c b/usr/src/lib/libcmdutils/common/process_xattrs.c
new file mode 100644
index 0000000000..5c8df946a1
--- /dev/null
+++ b/usr/src/lib/libcmdutils/common/process_xattrs.c
@@ -0,0 +1,334 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <c_synonyms.h>
+#include "libcmdutils.h"
+
+
+/*
+ * Gets file descriptors of attribute directories for source and target
+ * attribute files
+ */
+int
+get_attrdirs(int indfd, int outdfd, char *attrfile, int *sfd, int *tfd)
+{
+ int pwdfd;
+ int fd1;
+ int fd2;
+
+ pwdfd = open(".", O_RDONLY);
+ if ((pwdfd != -1) && (fchdir(indfd) == 0)) {
+ if ((fd1 = attropen(attrfile, ".", O_RDONLY)) == -1) {
+ (void) fchdir(pwdfd);
+ (void) close(pwdfd);
+ return (1);
+ }
+ *sfd = fd1;
+ } else {
+ (void) fchdir(pwdfd);
+ (void) close(pwdfd);
+ return (1);
+ }
+ if (fchdir(outdfd) == 0) {
+ if ((fd2 = attropen(attrfile, ".", O_RDONLY)) == -1) {
+ (void) fchdir(pwdfd);
+ (void) close(pwdfd);
+ return (1);
+ }
+ *tfd = fd2;
+ } else {
+ (void) fchdir(pwdfd);
+ (void) close(pwdfd);
+ return (1);
+ }
+ (void) fchdir(pwdfd);
+ return (0);
+}
+
+/*
+ * mv_xattrs - Copies the content of the extended attribute files. Then
+ * moves the extended system attributes from the input attribute files
+ * to the target attribute files. Moves the extended system attributes
+ * from source to the target file. This function returns 0 on success
+ * and nonzero on error.
+ */
+int
+mv_xattrs(char *cmd, char *infile, char *outfile, int sattr, int silent)
+{
+ int srcfd = -1;
+ int indfd = -1;
+ int outdfd = -1;
+ int tmpfd = -1;
+ int sattrfd = -1;
+ int tattrfd = -1;
+ int asfd = -1;
+ int atfd = -1;
+ DIR *dirp = NULL;
+ struct dirent *dp = NULL;
+ char *etext = NULL;
+ struct stat st1;
+ struct stat st2;
+ nvlist_t *response = NULL;
+ nvlist_t *res = NULL;
+
+ if ((srcfd = open(infile, O_RDONLY)) == -1) {
+ etext = dgettext(TEXT_DOMAIN, "cannot open source");
+ goto error;
+ }
+ if (sattr)
+ response = sysattr_list(cmd, srcfd, infile);
+
+ if ((indfd = openat(srcfd, ".", O_RDONLY|O_XATTR)) == -1) {
+ etext = dgettext(TEXT_DOMAIN, "cannot openat source");
+ goto error;
+ }
+ if ((outdfd = attropen(outfile, ".", O_RDONLY)) == -1) {
+ etext = dgettext(TEXT_DOMAIN, "cannot attropen target");
+ goto error;
+ }
+ if ((tmpfd = dup(indfd)) == -1) {
+ etext = dgettext(TEXT_DOMAIN, "cannot dup descriptor");
+ goto error;
+
+ }
+ if ((dirp = fdopendir(tmpfd)) == NULL) {
+ etext = dgettext(TEXT_DOMAIN, "cannot access source");
+ goto error;
+ }
+ while ((dp = readdir(dirp)) != NULL) {
+ if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
+ (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
+ dp->d_name[2] == '\0') ||
+ (sysattr_type(dp->d_name) == _RO_SATTR) ||
+ (sysattr_type(dp->d_name) == _RW_SATTR))
+ continue;
+
+ if ((sattrfd = openat(indfd, dp->d_name,
+ O_RDONLY)) == -1) {
+ etext = dgettext(TEXT_DOMAIN,
+ "cannot open src attribute file");
+ goto error;
+ }
+ if (fstat(sattrfd, &st1) < 0) {
+ etext = dgettext(TEXT_DOMAIN,
+ "could not stat attribute file");
+ goto error;
+ }
+ if ((tattrfd = openat(outdfd, dp->d_name,
+ O_RDWR|O_CREAT|O_TRUNC, st1.st_mode)) == -1) {
+ etext = dgettext(TEXT_DOMAIN,
+ "cannot open target attribute file");
+ goto error;
+ }
+ if (fstat(tattrfd, &st2) < 0) {
+ etext = dgettext(TEXT_DOMAIN,
+ "could not stat attribute file");
+ goto error;
+ }
+ if (writefile(sattrfd, tattrfd, infile, outfile, dp->d_name,
+ dp->d_name, &st1, &st2) != 0) {
+ etext = dgettext(TEXT_DOMAIN,
+ "failed to copy extended attribute "
+ "from source to target");
+ goto error;
+ }
+
+ errno = 0;
+ if (sattr) {
+ /*
+ * Gets non default extended system attributes from
+ * source to copy to target.
+ */
+ if (dp->d_name != NULL)
+ res = sysattr_list(cmd, sattrfd, dp->d_name);
+
+ if (res != NULL &&
+ get_attrdirs(indfd, outdfd, dp->d_name, &asfd,
+ &atfd) != 0) {
+ etext = dgettext(TEXT_DOMAIN,
+ "Failed to open attribute files");
+ goto error;
+ }
+ /*
+ * Copy extended system attribute from source
+ * attribute file to target attribute file
+ */
+ if (res != NULL &&
+ (renameat(asfd, VIEW_READWRITE, atfd,
+ VIEW_READWRITE) != 0)) {
+ if (errno == EPERM)
+ etext = dgettext(TEXT_DOMAIN,
+ "Permission denied -"
+ "failed to move system attribute");
+ else
+ etext = dgettext(TEXT_DOMAIN,
+ "failed to move extended "
+ "system attribute");
+ goto error;
+ }
+ }
+ if (sattrfd != -1)
+ (void) close(sattrfd);
+ if (tattrfd != -1)
+ (void) close(tattrfd);
+ if (asfd != -1)
+ (void) close(asfd);
+ if (atfd != -1)
+ (void) close(atfd);
+ if (res != NULL) {
+ nvlist_free(res);
+ res = NULL;
+ }
+ }
+ errno = 0;
+ /* Copy extended system attribute from source to target */
+
+ if (response != NULL) {
+ if (renameat(indfd, VIEW_READWRITE, outdfd,
+ VIEW_READWRITE) == 0)
+ goto done;
+
+ if (errno == EPERM)
+ etext = dgettext(TEXT_DOMAIN, "Permission denied");
+ else
+ etext = dgettext(TEXT_DOMAIN,
+ "failed to move system attribute");
+ }
+error:
+ if (res != NULL)
+ nvlist_free(res);
+ if (silent == 0 && etext != NULL) {
+ if (!sattr)
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: %s: cannot move extended attributes, "),
+ cmd, infile);
+ else
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: %s: cannot move extended system "
+ "attributes, "), cmd, infile);
+ perror(etext);
+ }
+done:
+ if (dirp)
+ (void) closedir(dirp);
+ if (sattrfd != -1)
+ (void) close(sattrfd);
+ if (tattrfd != -1)
+ (void) close(tattrfd);
+ if (asfd != -1)
+ (void) close(asfd);
+ if (atfd != -1)
+ (void) close(atfd);
+ if (indfd != -1)
+ (void) close(indfd);
+ if (outdfd != -1)
+ (void) close(outdfd);
+ if (response != NULL)
+ nvlist_free(response);
+ if (etext != NULL)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * The function returns non default extended system attribute list
+ * associated with 'fname' and returns NULL when an error has occured
+ * or when only extended system attributes other than archive,
+ * av_modified or crtime are set.
+ *
+ * The function returns system attribute list for the following cases:
+ *
+ * - any extended system attribute other than the default attributes
+ * ('archive', 'av_modified' and 'crtime') is set
+ * - nvlist has NULL name string
+ * - nvpair has data type of 'nvlist'
+ * - default data type.
+ */
+
+nvlist_t *
+sysattr_list(char *cmd, int fd, char *fname)
+{
+ boolean_t value;
+ data_type_t type;
+ nvlist_t *response;
+ nvpair_t *pair;
+ f_attr_t fattr;
+ char *name;
+
+ if (nvlist_alloc(&response, NV_UNIQUE_NAME, 0) != 0) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: %s: nvlist_alloc failed\n"),
+ cmd, fname);
+ return (NULL);
+ }
+ if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: %s: fgetattr failed\n"),
+ cmd, fname);
+ nvlist_free(response);
+ return (NULL);
+ }
+ pair = NULL;
+ while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
+
+ name = nvpair_name(pair);
+
+ if (name != NULL)
+ fattr = name_to_attr(name);
+ else
+ return (response);
+
+ type = nvpair_type(pair);
+ switch (type) {
+ case DATA_TYPE_BOOLEAN_VALUE:
+ if (nvpair_value_boolean_value(pair,
+ &value) != 0) {
+ (void) fprintf(stderr,
+ dgettext(TEXT_DOMAIN, "%s "
+ "nvpair_value_boolean_value "
+ "failed\n"), cmd);
+ continue;
+ }
+ if (value && fattr != F_ARCHIVE &&
+ fattr != F_AV_MODIFIED)
+ return (response);
+ break;
+ case DATA_TYPE_UINT64_ARRAY:
+ if (fattr != F_CRTIME)
+ return (response);
+ break;
+ case DATA_TYPE_NVLIST:
+ default:
+ return (response);
+ break;
+ }
+ }
+ if (response != NULL)
+ nvlist_free(response);
+ return (NULL);
+}
diff --git a/usr/src/lib/libcmdutils/common/sysattrs.c b/usr/src/lib/libcmdutils/common/sysattrs.c
new file mode 100644
index 0000000000..a22e8e5e21
--- /dev/null
+++ b/usr/src/lib/libcmdutils/common/sysattrs.c
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <c_synonyms.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <attr.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "libcmdutils.h"
+
+/*
+ * Returns the status of attempting to obtain the extended system
+ * attributes in the specified view.
+ *
+ * Note: If obtaining status for an extended attribute file, the caller must
+ * chdir into the hidden directory prior to calling sysattr_status().
+ *
+ * Returns 1 if the extended system attributes were obtained, otherwise
+ * returns 0.
+ */
+int
+sysattr_status(char *file, xattr_view_t view)
+{
+ nvlist_t *response;
+ int saveerrno;
+ int status;
+
+ if (nvlist_alloc(&response, NV_UNIQUE_NAME, 0) != 0) {
+ return (0);
+ }
+
+ status = getattrat(AT_FDCWD, view, file, &response);
+
+ saveerrno = errno;
+ (void) nvlist_free(response);
+ errno = saveerrno;
+
+ return (status == 0);
+}
+
+/*
+ * Returns the type of the specified in file. If the file name matches
+ * the name of either a read-only or read-write extended system attribute
+ * file then sysattr_type() returns the type of file:
+ * return value file type
+ * ------------ ---------
+ * _RO_SATTR read-only extended system attribute file
+ * _RW_SATTR read-write extended system attribute file
+ * _NOT_SATTR neither a read-only or read-write extended system
+ * attribute file.
+ */
+int
+sysattr_type(char *file)
+{
+ if (file == NULL) {
+ errno = ENOENT;
+ return (_NOT_SATTR);
+ }
+
+ if (strcmp(basename(file), file) != 0) {
+ errno = EINVAL;
+ return (_NOT_SATTR);
+ }
+
+ errno = 0;
+ if (strcmp(file, VIEW_READONLY) == 0) {
+ return (_RO_SATTR);
+ } else if (strcmp(file, VIEW_READWRITE) == 0) {
+ return (_RW_SATTR);
+ } else {
+ return (_NOT_SATTR);
+ }
+}
+
+/*
+ * Call sysattr_support() instead of pathconf(file, _PC_SATTR_ENABLED) or
+ * pathconf(file, _PC_SATTR_EXISTS) so that if pathconf() fails over NFS, we
+ * can still try to figure out if extended system attributes are supported by
+ * testing for a valid extended system attribute file.
+ *
+ * 'name' can have the values _PC_SATTR_ENABLED or _PC_SATTR_EXISTS.
+ *
+ * Returns 1 if the underlying file system supports extended system attributes,
+ * otherwise, returns -1.
+ */
+int
+sysattr_support(char *file, int name)
+{
+ int rc;
+
+ errno = 0;
+ if ((name != _PC_SATTR_ENABLED) &&
+ (name != _PC_SATTR_EXISTS)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (((rc = pathconf(file, name)) == 1) || (errno != EINVAL)) {
+ return (rc);
+ }
+ return (sysattr_status(file, XATTR_VIEW_READONLY));
+}
diff --git a/usr/src/lib/libcmdutils/common/writefile.c b/usr/src/lib/libcmdutils/common/writefile.c
new file mode 100644
index 0000000000..3e36f90c61
--- /dev/null
+++ b/usr/src/lib/libcmdutils/common/writefile.c
@@ -0,0 +1,230 @@
+/*
+ * 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 */
+
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <c_synonyms.h>
+#include "libcmdutils.h"
+
+
+int
+writefile(int fi, int fo, char *infile, char *outfile, char *asfile,
+ char *atfile, struct stat *s1p, struct stat *s2p)
+{
+ int mapsize, munmapsize;
+ caddr_t cp;
+ off_t filesize = s1p->st_size;
+ off_t offset;
+ int nbytes;
+ int remains;
+ int n;
+ size_t src_size;
+ size_t targ_size;
+ char *srcbuf;
+ char *targbuf;
+
+ if (asfile != NULL) {
+ src_size = strlen(infile) + strlen(asfile) +
+ strlen(dgettext(TEXT_DOMAIN, " attribute ")) + 1;
+ } else {
+ src_size = strlen(infile) + 1;
+ }
+ srcbuf = malloc(src_size);
+ if (srcbuf == NULL) {
+ (void) fprintf(stderr,
+ dgettext(TEXT_DOMAIN, "could not allocate memory"
+ " for path buffer: "));
+ return (1);
+ }
+ if (asfile != NULL) {
+ (void) snprintf(srcbuf, src_size, "%s%s%s",
+ infile, dgettext(TEXT_DOMAIN, " attribute "), asfile);
+ } else {
+ (void) snprintf(srcbuf, src_size, "%s", infile);
+ }
+
+ if (atfile != NULL) {
+ targ_size = strlen(outfile) + strlen(atfile) +
+ strlen(dgettext(TEXT_DOMAIN, " attribute ")) + 1;
+ } else {
+ targ_size = strlen(outfile) + 1;
+ }
+ targbuf = malloc(targ_size);
+ if (targbuf == NULL) {
+ (void) fprintf(stderr,
+ dgettext(TEXT_DOMAIN, "could not allocate memory"
+ " for path buffer: "));
+ return (1);
+ }
+ if (atfile != NULL) {
+ (void) snprintf(targbuf, targ_size, "%s%s%s",
+ outfile, dgettext(TEXT_DOMAIN, " attribute "), atfile);
+ } else {
+ (void) snprintf(targbuf, targ_size, "%s", outfile);
+ }
+
+ if (ISREG(*s1p) && s1p->st_size > SMALLFILESIZE) {
+ /*
+ * Determine size of initial mapping. This will determine the
+ * size of the address space chunk we work with. This initial
+ * mapping size will be used to perform munmap() in the future.
+ */
+ mapsize = MAXMAPSIZE;
+ if (s1p->st_size < mapsize) mapsize = s1p->st_size;
+ munmapsize = mapsize;
+
+ /*
+ * Mmap time!
+ */
+ if ((cp = mmap((caddr_t)NULL, mapsize, PROT_READ,
+ MAP_SHARED, fi, (off_t)0)) == MAP_FAILED)
+ mapsize = 0; /* can't mmap today */
+ } else
+ mapsize = 0;
+
+ if (mapsize != 0) {
+ offset = 0;
+
+ for (;;) {
+ nbytes = write(fo, cp, mapsize);
+ /*
+ * if we write less than the mmaped size it's due to a
+ * media error on the input file or out of space on
+ * the output file. So, try again, and look for errno.
+ */
+ if ((nbytes >= 0) && (nbytes != (int)mapsize)) {
+ remains = mapsize - nbytes;
+ while (remains > 0) {
+ nbytes = write(fo,
+ cp + mapsize - remains, remains);
+ if (nbytes < 0) {
+ if (errno == ENOSPC)
+ perror(targbuf);
+ else
+ perror(srcbuf);
+ (void) close(fi);
+ (void) close(fo);
+ (void) munmap(cp, munmapsize);
+ if (ISREG(*s2p))
+ (void) unlink(targbuf);
+ return (1);
+ }
+ remains -= nbytes;
+ if (remains == 0)
+ nbytes = mapsize;
+ }
+ }
+ /*
+ * although the write manual page doesn't specify this
+ * as a possible errno, it is set when the nfs read
+ * via the mmap'ed file is accessed, so report the
+ * problem as a source access problem, not a target file
+ * problem
+ */
+ if (nbytes < 0) {
+ if (errno == EACCES)
+ perror(srcbuf);
+ else
+ perror(targbuf);
+ (void) close(fi);
+ (void) close(fo);
+ (void) munmap(cp, munmapsize);
+ if (ISREG(*s2p))
+ (void) unlink(targbuf);
+ if (srcbuf != NULL)
+ free(srcbuf);
+ if (targbuf != NULL)
+ free(targbuf);
+ return (1);
+ }
+ filesize -= nbytes;
+ if (filesize == 0)
+ break;
+ offset += nbytes;
+ if (filesize < mapsize)
+ mapsize = filesize;
+ if (mmap(cp, mapsize, PROT_READ, MAP_SHARED |
+ MAP_FIXED, fi, offset) == MAP_FAILED) {
+ perror(srcbuf);
+ (void) close(fi);
+ (void) close(fo);
+ (void) munmap(cp, munmapsize);
+ if (ISREG(*s2p))
+ (void) unlink(targbuf);
+ if (srcbuf != NULL)
+ free(srcbuf);
+ if (targbuf != NULL)
+ free(targbuf);
+ return (1);
+ }
+ }
+ (void) munmap(cp, munmapsize);
+ } else {
+ char buf[SMALLFILESIZE];
+ for (;;) {
+ n = read(fi, buf, sizeof (buf));
+ if (n == 0) {
+ return (0);
+ } else if (n < 0) {
+ (void) close(fi);
+ (void) close(fo);
+ if (ISREG(*s2p))
+ (void) unlink(targbuf);
+ if (srcbuf != NULL)
+ free(srcbuf);
+ if (targbuf != NULL)
+ free(targbuf);
+ return (1);
+ } else if (write(fo, buf, n) != n) {
+ (void) close(fi);
+ (void) close(fo);
+ if (ISREG(*s2p))
+ (void) unlink(targbuf);
+ if (srcbuf != NULL)
+ free(srcbuf);
+ if (targbuf != NULL)
+ free(targbuf);
+ return (1);
+ }
+ }
+ }
+ if (srcbuf != NULL)
+ free(srcbuf);
+ if (targbuf != NULL)
+ free(targbuf);
+ return (0);
+}
diff --git a/usr/src/lib/libcmdutils/libcmdutils.h b/usr/src/lib/libcmdutils/libcmdutils.h
index 28a9e996d4..d1c3a0b193 100644
--- a/usr/src/lib/libcmdutils/libcmdutils.h
+++ b/usr/src/lib/libcmdutils/libcmdutils.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -38,14 +37,35 @@
* this file.
*/
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <libintl.h>
+#include <string.h>
+#include <dirent.h>
+#include <attr.h>
#include <sys/avl.h>
#include <sys/types.h>
-#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <libnvpair.h>
#ifdef __cplusplus
extern "C" {
#endif
+/* extended system attribute support */
+#define _NOT_SATTR 0
+#define _RO_SATTR 1
+#define _RW_SATTR 2
+
+#define MAXMAPSIZE (1024*1024*8) /* map at most 8MB */
+#define SMALLFILESIZE (32*1024) /* don't use mmap on little file */
+#define ISREG(A) (((A).st_mode & S_IFMT) == S_IFREG)
+
/* avltree */
#define OFFSETOF(s, m) ((size_t)(&(((s *)0)->m)))
@@ -56,11 +76,38 @@ typedef struct tree_node {
avl_node_t avl_link;
} tree_node_t;
+
+ /* extended system attribute support */
+
+/* Determine if a file is the name of an extended system attribute file */
+extern int sysattr_type(char *);
+
+/* Determine if the underlying file system supports system attributes */
+extern int sysattr_support(char *, int);
+
+/* Copies the content of the source file to the target file */
+extern int writefile(int, int, char *, char *, char *, char *,
+struct stat *, struct stat *);
+
+/* Gets file descriptors of the source and target attribute files */
+extern int get_attrdirs(int, int, char *, int *, int *);
+
+/* Move extended attribute and extended system attribute */
+extern int mv_xattrs(char *, char *, char *, int, int);
+
+/* Returns non default extended system attribute list */
+extern nvlist_t *sysattr_list(char *, int, char *);
+
+
+
+ /* avltree */
+
/*
* Used to compare two nodes. We are attempting to match the 1st
* argument (node) against the 2nd argument (a node which
* is already in the search tree).
*/
+
extern int tnode_compare(const void *, const void *);
/*
diff --git a/usr/src/lib/libsec/common/acl.y b/usr/src/lib/libsec/common/acl.y
index 684ab0ba3d..8b5d29509e 100644
--- a/usr/src/lib/libsec/common/acl.y
+++ b/usr/src/lib/libsec/common/acl.y
@@ -19,13 +19,13 @@
*
* CDDL HEADER END
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
-#include <sys/acl.h>
+#include <acl_common.h>
#include <aclutils.h>
extern int yyinteractive;
diff --git a/usr/src/lib/libsec/common/acl_lex.l b/usr/src/lib/libsec/common/acl_lex.l
index ce08a1da28..890c063cc7 100644
--- a/usr/src/lib/libsec/common/acl_lex.l
+++ b/usr/src/lib/libsec/common/acl_lex.l
@@ -59,6 +59,7 @@ int yybufpos;
%}
+%e 1500
%s TS NS PS AIS AS US ES
/*
* TS = type state
@@ -73,7 +74,7 @@ int yybufpos;
ID [0-9]+
LOGNAME [^:]+:
PERM_STR [rRwWxpdDaAcCos-]+
-INHERIT_STR [fdinFS-]+
+INHERIT_STR [fdinFSI-]+
%%
@@ -398,6 +399,32 @@ INHERIT_STR [fdinFS-]+
yylval.val = ACE_ACCESS_DENIED_ACE_TYPE;
return (ACCESS_TYPE);
}
+<AS>audit/[:,\n] {
+ int c;
+
+ c = input();
+ unput(c);
+ if (c == ',' || c == '\n')
+ BEGIN ES;
+ else
+ BEGIN US;
+
+ yylval.val = ACE_SYSTEM_AUDIT_ACE_TYPE;
+ return (ACCESS_TYPE);
+ }
+<AS>alarm/[:,\n] {
+ int c;
+
+ c = input();
+ unput(c);
+ if (c == ',' || c == '\n')
+ BEGIN ES;
+ else
+ BEGIN US;
+
+ yylval.val = ACE_SYSTEM_ALARM_ACE_TYPE;
+ return (ACCESS_TYPE);
+ }
<AS>: {
acl_error(dgettext(TEXT_DOMAIN,
@@ -466,6 +493,33 @@ INHERIT_STR [fdinFS-]+
yylval.val = ACE_ACCESS_DENIED_ACE_TYPE;
return (ACCESS_TYPE);
}
+<AIS>audit/[:,\n] {
+ int c;
+
+ c = input();
+ unput(c);
+ if (c == ',' || c == '\n')
+ BEGIN ES;
+ else
+ BEGIN US;
+
+ yylval.val = ACE_SYSTEM_AUDIT_ACE_TYPE;
+ return (ACCESS_TYPE);
+ }
+<AIS>alarm/[:,\n] {
+
+ int c;
+
+ c = input();
+ unput(c);
+ if (c == ',' || c == '\n')
+ BEGIN ES;
+ else
+ BEGIN US;
+
+ yylval.val = ACE_SYSTEM_ALARM_ACE_TYPE;
+ return (ACCESS_TYPE);
+ }
<AIS>file_inherit/[:/,] {
yylval.val = ACE_FILE_INHERIT_ACE;
return (ACE_INHERIT);
@@ -482,6 +536,19 @@ INHERIT_STR [fdinFS-]+
yylval.val = ACE_INHERIT_ONLY_ACE;
return (ACE_INHERIT);
}
+
+<AIS>successful_access/[/:,] {
+ yylval.val = ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
+ return (ACE_INHERIT);
+ }
+<AIS>failed_access/[/:,] {
+ yylval.val = ACE_FAILED_ACCESS_ACE_FLAG;
+ return (ACE_INHERIT);
+ }
+<AIS>inherited/[/:,] {
+ yylval.val = ACE_INHERITED_ACE;
+ return (ACE_INHERIT);
+ }
<AIS>{INHERIT_STR}/[:] {
yylval.str = strdup(yytext);
if (yylval.str == NULL) {
@@ -625,7 +692,7 @@ INHERIT_STR [fdinFS-]+
* used for retrieving illegal data in ACL specification.
*
* The first set of characters is retrieved from yytext.
- * subseequent characters are pulled from the input stream,
+ * subsequent characters are pulled from the input stream,
* until either EOF or one of the requested terminators is scene.
* Result is returned in yylval.str which is malloced.
*/
@@ -783,7 +850,7 @@ acl_str_to_id(char *str, int *id)
uid_t value;
errno = 0;
- value = strtol(str, &end, 10);
+ value = strtoul(str, &end, 10);
if (errno != 0 || *end != '\0')
return (EACL_INVALID_USER_GROUP);
diff --git a/usr/src/lib/libsec/common/acltext.c b/usr/src/lib/libsec/common/acltext.c
index cdfd171c82..c0e1bb1e58 100644
--- a/usr/src/lib/libsec/common/acltext.c
+++ b/usr/src/lib/libsec/common/acltext.c
@@ -540,8 +540,12 @@ ace_inherit_txt(char *buf, char **endp, uint32_t iflags, int flags)
buf[5] = 'F';
else
buf[5] = '-';
- buf[6] = '\0';
- *endp = buf + 6;
+ if (iflags & ACE_INHERITED_ACE)
+ buf[6] = 'I';
+ else
+ buf[6] = '-';
+ buf[7] = '\0';
+ *endp = buf + 7;
} else {
if (iflags & ACE_FILE_INHERIT_ACE) {
strcpy(lend, "file_inherit/");
@@ -559,6 +563,18 @@ ace_inherit_txt(char *buf, char **endp, uint32_t iflags, int flags)
strcpy(lend, "inherit_only/");
lend += sizeof ("inherit_only/") - 1;
}
+ if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) {
+ strcpy(lend, "successful_access/");
+ lend += sizeof ("successful_access/") - 1;
+ }
+ if (iflags & ACE_FAILED_ACCESS_ACE_FLAG) {
+ strcpy(lend, "failed_access/");
+ lend += sizeof ("failed_access/") - 1;
+ }
+ if (iflags & ACE_INHERITED_ACE) {
+ strcpy(lend, "inherited/");
+ lend += sizeof ("inherited/") - 1;
+ }
if (*(lend - 1) == '/')
*--lend = '\0';
@@ -829,16 +845,19 @@ increase_length(struct dynaclstr *dacl, size_t increase)
* The length of a perms entry is 144 i.e read_data/write_data...
* to each acl entry.
*
- * iflags: file_inherit/dir_inherit/inherit_only/no_propagate
+ * iflags: file_inherit/dir_inherit/inherit_only/no_propagate/successful_access
+ * /failed_access
*
*/
#define ACE_ENTRYTYPLEN 6
-#define IFLAGS_SIZE 51
+#define IFLAGS_STR "file_inherit/dir_inherit/inherit_only/no_propagate/" \
+ "successful_access/failed_access/inherited"
+#define IFLAGS_SIZE (sizeof (IFLAGS_STR) - 1)
#define ACCESS_TYPE_SIZE 7 /* if unknown */
#define COLON_CNT 3
#define PERMS_LEN 216
-#define ACE_ENTRY_SIZE (ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN +\
+#define ACE_ENTRY_SIZE (ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN + \
ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
static char *
@@ -871,7 +890,9 @@ ace_acltotext(acl_t *aceaclp, int flags)
(void) ace_inherit_txt(endp, &endp, aclp->a_flags, flags);
if (flags & ACL_COMPACT_FMT || aclp->a_flags &
(ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE |
- (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE))) {
+ (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE |
+ ACE_INHERITED_ACE | ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
+ ACE_FAILED_ACCESS_ACE_FLAG))) {
*endp++ = ':';
*endp = '\0';
}
@@ -972,7 +993,7 @@ ace_compact_printacl(acl_t *aclp)
aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT));
(void) printf("%s:",
ace_inherit_txt(endp, &endp, acep->a_flags,
- ACL_COMPACT_FMT));
+ ACL_COMPACT_FMT));
(void) printf("%s\n", ace_access_txt(endp, &endp,
acep->a_type));
}
@@ -1038,16 +1059,14 @@ typedef struct value_table {
uint32_t p_value; /* value for perm when pletter found */
} value_table_t;
-#define ACE_PERM_COUNT 14
-
/*
- * The permission tables are layed out in positional order
+ * The permission tables are laid out in positional order
* a '-' character will indicate a permission at a given
* position is not specified. The '-' is not part of the
* table, but will be checked for in the permission computation
* routine.
*/
-value_table_t ace_perm_table[ACE_PERM_COUNT] = {
+value_table_t ace_perm_table[] = {
{ 'r', ACE_READ_DATA},
{ 'w', ACE_WRITE_DATA},
{ 'x', ACE_EXECUTE},
@@ -1064,24 +1083,28 @@ value_table_t ace_perm_table[ACE_PERM_COUNT] = {
{ 's', ACE_SYNCHRONIZE}
};
-#define ACLENT_PERM_COUNT 3
+#define ACE_PERM_COUNT (sizeof (ace_perm_table) / sizeof (value_table_t))
-value_table_t aclent_perm_table[ACLENT_PERM_COUNT] = {
+value_table_t aclent_perm_table[] = {
{ 'r', S_IROTH},
{ 'w', S_IWOTH},
{ 'x', S_IXOTH}
};
-#define IFLAG_COUNT 6
-value_table_t inherit_table[IFLAG_COUNT] = {
+#define ACLENT_PERM_COUNT (sizeof (aclent_perm_table) / sizeof (value_table_t))
+
+value_table_t inherit_table[] = {
{'f', ACE_FILE_INHERIT_ACE},
{'d', ACE_DIRECTORY_INHERIT_ACE},
{'i', ACE_INHERIT_ONLY_ACE},
{'n', ACE_NO_PROPAGATE_INHERIT_ACE},
{'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
- {'F', ACE_FAILED_ACCESS_ACE_FLAG}
+ {'F', ACE_FAILED_ACCESS_ACE_FLAG},
+ {'I', ACE_INHERITED_ACE}
};
+#define IFLAG_COUNT (sizeof (inherit_table) / sizeof (value_table_t))
+
/*
* compute value from a permission table or inheritance table
* based on string passed in. If positional is set then
diff --git a/usr/src/lib/libsec/common/aclutils.c b/usr/src/lib/libsec/common/aclutils.c
index d90ad4b171..0200db6c66 100644
--- a/usr/src/lib/libsec/common/aclutils.c
+++ b/usr/src/lib/libsec/common/aclutils.c
@@ -33,171 +33,23 @@
#include <pwd.h>
#include <strings.h>
#include <sys/types.h>
-#include <sys/acl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/varargs.h>
#include <locale.h>
#include <aclutils.h>
-#include <acl_common.h>
#include <sys/avl.h>
-
-#define offsetof(s, m) ((size_t)(&(((s *)0)->m)))
+#include <acl_common.h>
#define ACL_PATH 0
#define ACL_FD 1
-#define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \
- ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \
- ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL)
-
-
-#define ACL_SYNCHRONIZE_SET_DENY 0x0000001
-#define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002
-#define ACL_SYNCHRONIZE_ERR_DENY 0x0000004
-#define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008
-
-#define ACL_WRITE_OWNER_SET_DENY 0x0000010
-#define ACL_WRITE_OWNER_SET_ALLOW 0x0000020
-#define ACL_WRITE_OWNER_ERR_DENY 0x0000040
-#define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080
-
-#define ACL_DELETE_SET_DENY 0x0000100
-#define ACL_DELETE_SET_ALLOW 0x0000200
-#define ACL_DELETE_ERR_DENY 0x0000400
-#define ACL_DELETE_ERR_ALLOW 0x0000800
-
-#define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000
-#define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000
-#define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000
-#define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000
-
-#define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000
-#define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000
-#define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000
-#define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000
-
-#define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000
-#define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000
-#define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000
-#define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000
-
-#define ACL_READ_NAMED_READER_SET_DENY 0x1000000
-#define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000
-#define ACL_READ_NAMED_READER_ERR_DENY 0x4000000
-#define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000
-
-
-#define ACE_VALID_MASK_BITS (\
- ACE_READ_DATA | \
- ACE_LIST_DIRECTORY | \
- ACE_WRITE_DATA | \
- ACE_ADD_FILE | \
- ACE_APPEND_DATA | \
- ACE_ADD_SUBDIRECTORY | \
- ACE_READ_NAMED_ATTRS | \
- ACE_WRITE_NAMED_ATTRS | \
- ACE_EXECUTE | \
- ACE_DELETE_CHILD | \
- ACE_READ_ATTRIBUTES | \
- ACE_WRITE_ATTRIBUTES | \
- ACE_DELETE | \
- ACE_READ_ACL | \
- ACE_WRITE_ACL | \
- ACE_WRITE_OWNER | \
- ACE_SYNCHRONIZE)
-
-#define ACE_MASK_UNDEFINED 0x80000000
-
-#define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \
- ACE_DIRECTORY_INHERIT_ACE | \
- ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \
- ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
- ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
-
-/*
- * ACL conversion helpers
- */
-
-typedef enum {
- ace_unused,
- ace_user_obj,
- ace_user,
- ace_group, /* includes GROUP and GROUP_OBJ */
- ace_other_obj
-} ace_to_aent_state_t;
-
-typedef struct acevals {
- uid_t key;
- avl_node_t avl;
- uint32_t mask;
- uint32_t allowed;
- uint32_t denied;
- int aent_type;
-} acevals_t;
-
-typedef struct ace_list {
- acevals_t user_obj;
- avl_tree_t user;
- int numusers;
- acevals_t group_obj;
- avl_tree_t group;
- int numgroups;
- acevals_t other_obj;
- uint32_t acl_mask;
- int hasmask;
- int dfacl_flag;
- ace_to_aent_state_t state;
- int seen; /* bitmask of all aclent_t a_type values seen */
-} ace_list_t;
typedef union {
const char *file;
int fd;
} acl_inp;
-acl_t *
-acl_alloc(enum acl_type type)
-{
- acl_t *aclp;
-
- aclp = malloc(sizeof (acl_t));
-
- if (aclp == NULL)
- return (NULL);
-
- aclp->acl_aclp = NULL;
- aclp->acl_cnt = 0;
-
- switch (type) {
- case ACE_T:
- aclp->acl_type = ACE_T;
- aclp->acl_entry_size = sizeof (ace_t);
- break;
- case ACLENT_T:
- aclp->acl_type = ACLENT_T;
- aclp->acl_entry_size = sizeof (aclent_t);
- break;
- default:
- acl_free(aclp);
- aclp = NULL;
- }
- return (aclp);
-}
-
-/*
- * Free acl_t structure
- */
-void
-acl_free(acl_t *aclp)
-{
- if (aclp == NULL)
- return;
-
- if (aclp->acl_aclp)
- free(aclp->acl_aclp);
- free(aclp);
-}
/*
* Determine whether a file has a trivial ACL
@@ -242,1194 +94,6 @@ acl_trivial(const char *filename)
return (val);
}
-static uint32_t
-access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
-{
- uint32_t access_mask = 0;
- int acl_produce;
- int synchronize_set = 0, write_owner_set = 0;
- int delete_set = 0, write_attrs_set = 0;
- int read_named_set = 0, write_named_set = 0;
-
- acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
- ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
- ACL_WRITE_ATTRS_WRITER_SET_DENY);
-
- if (isallow) {
- synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
- write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
- delete_set = ACL_DELETE_SET_ALLOW;
- if (hasreadperm)
- read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
- if (haswriteperm)
- write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
- if (isowner)
- write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
- else if (haswriteperm)
- write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
- } else {
-
- synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
- write_owner_set = ACL_WRITE_OWNER_SET_DENY;
- delete_set = ACL_DELETE_SET_DENY;
- if (hasreadperm)
- read_named_set = ACL_READ_NAMED_READER_SET_DENY;
- if (haswriteperm)
- write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
- if (isowner)
- write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
- else if (haswriteperm)
- write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
- else
- /*
- * If the entity is not the owner and does not
- * have write permissions ACE_WRITE_ATTRIBUTES will
- * always go in the DENY ACE.
- */
- access_mask |= ACE_WRITE_ATTRIBUTES;
- }
-
- if (acl_produce & synchronize_set)
- access_mask |= ACE_SYNCHRONIZE;
- if (acl_produce & write_owner_set)
- access_mask |= ACE_WRITE_OWNER;
- if (acl_produce & delete_set)
- access_mask |= ACE_DELETE;
- if (acl_produce & write_attrs_set)
- access_mask |= ACE_WRITE_ATTRIBUTES;
- if (acl_produce & read_named_set)
- access_mask |= ACE_READ_NAMED_ATTRS;
- if (acl_produce & write_named_set)
- access_mask |= ACE_WRITE_NAMED_ATTRS;
-
- return (access_mask);
-}
-
-/*
- * Given an mode_t, convert it into an access_mask as used
- * by nfsace, assuming aclent_t -> nfsace semantics.
- */
-static uint32_t
-mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
-{
- uint32_t access = 0;
- int haswriteperm = 0;
- int hasreadperm = 0;
-
- if (isallow) {
- haswriteperm = (mode & 02);
- hasreadperm = (mode & 04);
- } else {
- haswriteperm = !(mode & 02);
- hasreadperm = !(mode & 04);
- }
-
- /*
- * The following call takes care of correctly setting the following
- * mask bits in the access_mask:
- * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
- * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
- */
- access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
-
- if (isallow) {
- access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
- if (isowner)
- access |= ACE_WRITE_ACL;
- } else {
- if (! isowner)
- access |= ACE_WRITE_ACL;
- }
-
- /* read */
- if (mode & 04) {
- access |= ACE_READ_DATA;
- }
- /* write */
- if (mode & 02) {
- access |= ACE_WRITE_DATA |
- ACE_APPEND_DATA;
- if (isdir)
- access |= ACE_DELETE_CHILD;
- }
- /* exec */
- if (mode & 01) {
- access |= ACE_EXECUTE;
- }
-
- return (access);
-}
-
-/*
- * Given an nfsace (presumably an ALLOW entry), make a
- * corresponding DENY entry at the address given.
- */
-static void
-ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
-{
- (void) memcpy(deny, allow, sizeof (ace_t));
-
- deny->a_who = allow->a_who;
-
- deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
- deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
- if (isdir)
- deny->a_access_mask ^= ACE_DELETE_CHILD;
-
- deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
- ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
- ACE_WRITE_NAMED_ATTRS);
- deny->a_access_mask |= access_mask_set((allow->a_access_mask &
- ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
- B_FALSE);
-}
-/*
- * Make an initial pass over an array of aclent_t's. Gather
- * information such as an ACL_MASK (if any), number of users,
- * number of groups, and whether the array needs to be sorted.
- */
-static int
-ln_aent_preprocess(aclent_t *aclent, int n,
- int *hasmask, mode_t *mask,
- int *numuser, int *numgroup, int *needsort)
-{
- int error = 0;
- int i;
- int curtype = 0;
-
- *hasmask = 0;
- *mask = 07;
- *needsort = 0;
- *numuser = 0;
- *numgroup = 0;
-
- for (i = 0; i < n; i++) {
- if (aclent[i].a_type < curtype)
- *needsort = 1;
- else if (aclent[i].a_type > curtype)
- curtype = aclent[i].a_type;
- if (aclent[i].a_type & USER)
- (*numuser)++;
- if (aclent[i].a_type & (GROUP | GROUP_OBJ))
- (*numgroup)++;
- if (aclent[i].a_type & CLASS_OBJ) {
- if (*hasmask) {
- error = EINVAL;
- goto out;
- } else {
- *hasmask = 1;
- *mask = aclent[i].a_perm;
- }
- }
- }
-
- if ((! *hasmask) && (*numuser + *numgroup > 1)) {
- error = EINVAL;
- goto out;
- }
-
-out:
- return (error);
-}
-
-/*
- * Convert an array of aclent_t into an array of nfsace entries,
- * following POSIX draft -> nfsv4 conversion semantics as outlined in
- * the IETF draft.
- */
-static int
-ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
-{
- int error = 0;
- mode_t mask;
- int numuser, numgroup, needsort;
- int resultsize = 0;
- int i, groupi = 0, skip;
- ace_t *acep, *result = NULL;
- int hasmask;
-
- error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
- &numuser, &numgroup, &needsort);
- if (error != 0)
- goto out;
-
- /* allow + deny for each aclent */
- resultsize = n * 2;
- if (hasmask) {
- /*
- * stick extra deny on the group_obj and on each
- * user|group for the mask (the group_obj was added
- * into the count for numgroup)
- */
- resultsize += numuser + numgroup;
- /* ... and don't count the mask itself */
- resultsize -= 2;
- }
-
- /* sort the source if necessary */
- if (needsort)
- ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
-
- result = acep = calloc(1, resultsize * sizeof (ace_t));
- if (result == NULL)
- goto out;
-
- for (i = 0; i < n; i++) {
- /*
- * don't process CLASS_OBJ (mask); mask was grabbed in
- * ln_aent_preprocess()
- */
- if (aclent[i].a_type & CLASS_OBJ)
- continue;
-
- /* If we need an ACL_MASK emulator, prepend it now */
- if ((hasmask) &&
- (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
- acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
- acep->a_flags = 0;
- if (aclent[i].a_type & GROUP_OBJ) {
- acep->a_who = (uid_t)-1;
- acep->a_flags |=
- (ACE_IDENTIFIER_GROUP|ACE_GROUP);
- } else if (aclent[i].a_type & USER) {
- acep->a_who = aclent[i].a_id;
- } else {
- acep->a_who = aclent[i].a_id;
- acep->a_flags |= ACE_IDENTIFIER_GROUP;
- }
- if (aclent[i].a_type & ACL_DEFAULT) {
- acep->a_flags |= ACE_INHERIT_ONLY_ACE |
- ACE_FILE_INHERIT_ACE |
- ACE_DIRECTORY_INHERIT_ACE;
- }
- /*
- * Set the access mask for the prepended deny
- * ace. To do this, we invert the mask (found
- * in ln_aent_preprocess()) then convert it to an
- * DENY ace access_mask.
- */
- acep->a_access_mask = mode_to_ace_access((mask ^ 07),
- isdir, 0, 0);
- acep += 1;
- }
-
- /* handle a_perm -> access_mask */
- acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
- isdir, aclent[i].a_type & USER_OBJ, 1);
-
- /* emulate a default aclent */
- if (aclent[i].a_type & ACL_DEFAULT) {
- acep->a_flags |= ACE_INHERIT_ONLY_ACE |
- ACE_FILE_INHERIT_ACE |
- ACE_DIRECTORY_INHERIT_ACE;
- }
-
- /*
- * handle a_perm and a_id
- *
- * this must be done last, since it involves the
- * corresponding deny aces, which are handled
- * differently for each different a_type.
- */
- if (aclent[i].a_type & USER_OBJ) {
- acep->a_who = (uid_t)-1;
- acep->a_flags |= ACE_OWNER;
- ace_make_deny(acep, acep + 1, isdir, B_TRUE);
- acep += 2;
- } else if (aclent[i].a_type & USER) {
- acep->a_who = aclent[i].a_id;
- ace_make_deny(acep, acep + 1, isdir, B_FALSE);
- acep += 2;
- } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
- if (aclent[i].a_type & GROUP_OBJ) {
- acep->a_who = (uid_t)-1;
- acep->a_flags |= ACE_GROUP;
- } else {
- acep->a_who = aclent[i].a_id;
- }
- acep->a_flags |= ACE_IDENTIFIER_GROUP;
- /*
- * Set the corresponding deny for the group ace.
- *
- * The deny aces go after all of the groups, unlike
- * everything else, where they immediately follow
- * the allow ace.
- *
- * We calculate "skip", the number of slots to
- * skip ahead for the deny ace, here.
- *
- * The pattern is:
- * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
- * thus, skip is
- * (2 * numgroup) - 1 - groupi
- * (2 * numgroup) to account for MD + A
- * - 1 to account for the fact that we're on the
- * access (A), not the mask (MD)
- * - groupi to account for the fact that we have
- * passed up groupi number of MD's.
- */
- skip = (2 * numgroup) - 1 - groupi;
- ace_make_deny(acep, acep + skip, isdir, B_FALSE);
- /*
- * If we just did the last group, skip acep past
- * all of the denies; else, just move ahead one.
- */
- if (++groupi >= numgroup)
- acep += numgroup + 1;
- else
- acep += 1;
- } else if (aclent[i].a_type & OTHER_OBJ) {
- acep->a_who = (uid_t)-1;
- acep->a_flags |= ACE_EVERYONE;
- ace_make_deny(acep, acep + 1, isdir, B_FALSE);
- acep += 2;
- } else {
- error = EINVAL;
- goto out;
- }
- }
-
- *acepp = result;
- *rescount = resultsize;
-
-out:
- if (error != 0) {
- if ((result != NULL) && (resultsize > 0)) {
- free(result);
- }
- }
-
- return (error);
-}
-
-static int
-convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
- ace_t **retacep, int *retacecnt)
-{
- ace_t *acep;
- ace_t *dfacep;
- int acecnt = 0;
- int dfacecnt = 0;
- int dfaclstart = 0;
- int dfaclcnt = 0;
- aclent_t *aclp;
- int i;
- int error;
-
- ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
-
- for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
- if (aclp->a_type & ACL_DEFAULT)
- break;
- }
-
- if (i < aclcnt) {
- dfaclstart = i;
- dfaclcnt = aclcnt - i;
- }
-
- if (dfaclcnt && isdir == 0) {
- return (-1);
- }
-
- error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
- if (error)
- return (-1);
-
- if (dfaclcnt) {
- error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
- &dfacep, &dfacecnt, isdir);
- if (error) {
- if (acep) {
- free(acep);
- }
- return (-1);
- }
- }
-
- if (dfacecnt != 0) {
- acep = realloc(acep, sizeof (ace_t) * (acecnt + dfacecnt));
- if (acep == NULL)
- return (-1);
- if (dfaclcnt) {
- (void) memcpy(acep + acecnt, dfacep,
- sizeof (ace_t) * dfacecnt);
- }
- }
- if (dfaclcnt)
- free(dfacep);
-
- *retacecnt = acecnt + dfacecnt;
- *retacep = acep;
- return (0);
-}
-
-static void
-acevals_init(acevals_t *vals, uid_t key)
-{
- bzero(vals, sizeof (*vals));
- vals->allowed = ACE_MASK_UNDEFINED;
- vals->denied = ACE_MASK_UNDEFINED;
- vals->mask = ACE_MASK_UNDEFINED;
- vals->key = key;
-}
-
-static void
-ace_list_init(ace_list_t *al, int dfacl_flag)
-{
- acevals_init(&al->user_obj, NULL);
- acevals_init(&al->group_obj, NULL);
- acevals_init(&al->other_obj, NULL);
- al->numusers = 0;
- al->numgroups = 0;
- al->acl_mask = 0;
- al->hasmask = 0;
- al->state = ace_unused;
- al->seen = 0;
- al->dfacl_flag = dfacl_flag;
-}
-
-/*
- * Find or create an acevals holder for a given id and avl tree.
- *
- * Note that only one thread will ever touch these avl trees, so
- * there is no need for locking.
- */
-static acevals_t *
-acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
-{
- acevals_t key, *rc;
- avl_index_t where;
-
- key.key = ace->a_who;
- rc = avl_find(avl, &key, &where);
- if (rc != NULL)
- return (rc);
-
- /* this memory is freed by ln_ace_to_aent()->ace_list_free() */
- rc = calloc(1, sizeof (acevals_t));
- if (rc == NULL)
- return (rc);
- acevals_init(rc, ace->a_who);
- avl_insert(avl, rc, where);
- (*num)++;
-
- return (rc);
-}
-
-static int
-access_mask_check(ace_t *acep, int mask_bit, int isowner)
-{
- int set_deny, err_deny;
- int set_allow, err_allow;
- int acl_consume;
- int haswriteperm, hasreadperm;
-
- if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
- haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
- hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
- } else {
- haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
- hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
- }
-
- acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
- ACL_DELETE_ERR_DENY |
- ACL_WRITE_OWNER_ERR_DENY |
- ACL_WRITE_OWNER_ERR_ALLOW |
- ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
- ACL_WRITE_ATTRS_OWNER_ERR_DENY |
- ACL_WRITE_ATTRS_WRITER_SET_DENY |
- ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
- ACL_WRITE_NAMED_WRITER_ERR_DENY |
- ACL_READ_NAMED_READER_ERR_DENY);
-
- if (mask_bit == ACE_SYNCHRONIZE) {
- set_deny = ACL_SYNCHRONIZE_SET_DENY;
- err_deny = ACL_SYNCHRONIZE_ERR_DENY;
- set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
- err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
- } else if (mask_bit == ACE_WRITE_OWNER) {
- set_deny = ACL_WRITE_OWNER_SET_DENY;
- err_deny = ACL_WRITE_OWNER_ERR_DENY;
- set_allow = ACL_WRITE_OWNER_SET_ALLOW;
- err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
- } else if (mask_bit == ACE_DELETE) {
- set_deny = ACL_DELETE_SET_DENY;
- err_deny = ACL_DELETE_ERR_DENY;
- set_allow = ACL_DELETE_SET_ALLOW;
- err_allow = ACL_DELETE_ERR_ALLOW;
- } else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
- if (isowner) {
- set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
- err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY;
- set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
- err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
- } else if (haswriteperm) {
- set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
- err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY;
- set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
- err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
- } else {
- if ((acep->a_access_mask & mask_bit) &&
- (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
- return (ENOTSUP);
- }
- return (0);
- }
- } else if (mask_bit == ACE_READ_NAMED_ATTRS) {
- if (!hasreadperm)
- return (0);
-
- set_deny = ACL_READ_NAMED_READER_SET_DENY;
- err_deny = ACL_READ_NAMED_READER_ERR_DENY;
- set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
- err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
- } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
- if (!haswriteperm)
- return (0);
-
- set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
- err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
- set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
- err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
- } else {
- return (EINVAL);
- }
-
- if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
- if (acl_consume & set_deny) {
- if (!(acep->a_access_mask & mask_bit)) {
- return (ENOTSUP);
- }
- } else if (acl_consume & err_deny) {
- if (acep->a_access_mask & mask_bit) {
- return (ENOTSUP);
- }
- }
- } else {
- /* ACE_ACCESS_ALLOWED_ACE_TYPE */
- if (acl_consume & set_allow) {
- if (!(acep->a_access_mask & mask_bit)) {
- return (ENOTSUP);
- }
- } else if (acl_consume & err_allow) {
- if (acep->a_access_mask & mask_bit) {
- return (ENOTSUP);
- }
- }
- }
- return (0);
-}
-
-static int
-ace_to_aent_legal(ace_t *acep)
-{
- int error = 0;
- int isowner;
-
- /* only ALLOW or DENY */
- if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
- (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
- error = ENOTSUP;
- goto out;
- }
-
- /* check for invalid flags */
- if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
- error = EINVAL;
- goto out;
- }
-
- /* some flags are illegal */
- if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
- ACE_FAILED_ACCESS_ACE_FLAG |
- ACE_NO_PROPAGATE_INHERIT_ACE)) {
- error = ENOTSUP;
- goto out;
- }
-
- /* check for invalid masks */
- if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
- error = EINVAL;
- goto out;
- }
-
- if ((acep->a_flags & ACE_OWNER)) {
- isowner = 1;
- } else {
- isowner = 0;
- }
-
- error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
- if (error)
- goto out;
-
- error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
- if (error)
- goto out;
-
- error = access_mask_check(acep, ACE_DELETE, isowner);
- if (error)
- goto out;
-
- error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
- if (error)
- goto out;
-
- error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
- if (error)
- goto out;
-
- error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
- if (error)
- goto out;
-
- /* more detailed checking of masks */
- if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
- if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
- error = ENOTSUP;
- goto out;
- }
- if ((acep->a_access_mask & ACE_WRITE_DATA) &&
- (! (acep->a_access_mask & ACE_APPEND_DATA))) {
- error = ENOTSUP;
- goto out;
- }
- if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
- (acep->a_access_mask & ACE_APPEND_DATA)) {
- error = ENOTSUP;
- goto out;
- }
- }
-
- /* ACL enforcement */
- if ((acep->a_access_mask & ACE_READ_ACL) &&
- (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
- error = ENOTSUP;
- goto out;
- }
- if (acep->a_access_mask & ACE_WRITE_ACL) {
- if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
- (isowner)) {
- error = ENOTSUP;
- goto out;
- }
- if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
- (! isowner)) {
- error = ENOTSUP;
- goto out;
- }
- }
-
-out:
- return (error);
-}
-
-static int
-ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
-{
- int error = 0;
- o_mode_t mode = 0;
- uint32_t bits, wantbits;
-
- /* read */
- if (mask & ACE_READ_DATA)
- mode |= 04;
-
- /* write */
- wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
- if (isdir)
- wantbits |= ACE_DELETE_CHILD;
- bits = mask & wantbits;
- if (bits != 0) {
- if (bits != wantbits) {
- error = ENOTSUP;
- goto out;
- }
- mode |= 02;
- }
-
- /* exec */
- if (mask & ACE_EXECUTE) {
- mode |= 01;
- }
-
- *modep = mode;
-
-out:
- return (error);
-}
-
-static int
-ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
-{
- /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
- if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
- (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
- return (ENOTSUP);
- }
-
- return (ace_mask_to_mode(mask, modep, isdir));
-}
-
-static int
-acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
- uid_t owner, gid_t group, int isdir)
-{
- int error;
- uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
-
- if (isdir)
- flips |= ACE_DELETE_CHILD;
- if (vals->allowed != (vals->denied ^ flips)) {
- error = ENOTSUP;
- goto out;
- }
- if ((list->hasmask) && (list->acl_mask != vals->mask) &&
- (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
- error = ENOTSUP;
- goto out;
- }
- error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
- if (error != 0)
- goto out;
- dest->a_type = vals->aent_type;
- if (dest->a_type & (USER | GROUP)) {
- dest->a_id = vals->key;
- } else if (dest->a_type & USER_OBJ) {
- dest->a_id = owner;
- } else if (dest->a_type & GROUP_OBJ) {
- dest->a_id = group;
- } else if (dest->a_type & OTHER_OBJ) {
- dest->a_id = 0;
- } else {
- error = EINVAL;
- goto out;
- }
-
-out:
- return (error);
-}
-
-static int
-ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
- uid_t owner, gid_t group, int isdir)
-{
- int error = 0;
- aclent_t *aent, *result = NULL;
- acevals_t *vals;
- int resultcount;
-
- if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
- (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
- error = ENOTSUP;
- goto out;
- }
- if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
- error = ENOTSUP;
- goto out;
- }
-
- resultcount = 3 + list->numusers + list->numgroups;
- /*
- * This must be the same condition as below, when we add the CLASS_OBJ
- * (aka ACL mask)
- */
- if ((list->hasmask) || (! list->dfacl_flag))
- resultcount += 1;
-
- result = aent = calloc(1, resultcount * sizeof (aclent_t));
-
- if (result == NULL) {
- error = ENOMEM;
- goto out;
- }
-
- /* USER_OBJ */
- if (!(list->user_obj.aent_type & USER_OBJ)) {
- error = EINVAL;
- goto out;
- }
-
- error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
- isdir);
-
- if (error != 0)
- goto out;
- ++aent;
- /* USER */
- vals = NULL;
- for (vals = avl_first(&list->user); vals != NULL;
- vals = AVL_NEXT(&list->user, vals)) {
- if (!(vals->aent_type & USER)) {
- error = EINVAL;
- goto out;
- }
- error = acevals_to_aent(vals, aent, list, owner, group,
- isdir);
- if (error != 0)
- goto out;
- ++aent;
- }
- /* GROUP_OBJ */
- if (!(list->group_obj.aent_type & GROUP_OBJ)) {
- error = EINVAL;
- goto out;
- }
- error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
- isdir);
- if (error != 0)
- goto out;
- ++aent;
- /* GROUP */
- vals = NULL;
- for (vals = avl_first(&list->group); vals != NULL;
- vals = AVL_NEXT(&list->group, vals)) {
- if (!(vals->aent_type & GROUP)) {
- error = EINVAL;
- goto out;
- }
- error = acevals_to_aent(vals, aent, list, owner, group,
- isdir);
- if (error != 0)
- goto out;
- ++aent;
- }
- /*
- * CLASS_OBJ (aka ACL_MASK)
- *
- * An ACL_MASK is not fabricated if the ACL is a default ACL.
- * This is to follow UFS's behavior.
- */
- if ((list->hasmask) || (! list->dfacl_flag)) {
- if (list->hasmask) {
- uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
- if (isdir)
- flips |= ACE_DELETE_CHILD;
- error = ace_mask_to_mode(list->acl_mask ^ flips,
- &aent->a_perm, isdir);
- if (error != 0)
- goto out;
- } else {
- /* fabricate the ACL_MASK from the group permissions */
- error = ace_mask_to_mode(list->group_obj.allowed,
- &aent->a_perm, isdir);
- if (error != 0)
- goto out;
- }
- aent->a_id = 0;
- aent->a_type = CLASS_OBJ | list->dfacl_flag;
- ++aent;
- }
- /* OTHER_OBJ */
- if (!(list->other_obj.aent_type & OTHER_OBJ)) {
- error = EINVAL;
- goto out;
- }
- error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
- isdir);
- if (error != 0)
- goto out;
- ++aent;
-
- *aclentp = result;
- *aclcnt = resultcount;
-
-out:
- if (error != 0) {
- if (result != NULL)
- free(result);
- }
-
- return (error);
-}
-
-/*
- * free all data associated with an ace_list
- */
-static void
-ace_list_free(ace_list_t *al)
-{
- acevals_t *node;
- void *cookie;
-
- if (al == NULL)
- return;
-
- cookie = NULL;
- while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
- free(node);
- cookie = NULL;
- while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
- free(node);
-
- avl_destroy(&al->user);
- avl_destroy(&al->group);
-
- /* free the container itself */
- free(al);
-}
-
-static int
-acevals_compare(const void *va, const void *vb)
-{
- const acevals_t *a = va, *b = vb;
-
- if (a->key == b->key)
- return (0);
-
- if (a->key > b->key)
- return (1);
-
- else
- return (-1);
-}
-
-/*
- * Convert a list of ace_t entries to equivalent regular and default
- * aclent_t lists. Return error (ENOTSUP) when conversion is not possible.
- */
-static int
-ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
- aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
- int isdir)
-{
- int error = 0;
- ace_t *acep;
- uint32_t bits;
- int i;
- ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
- acevals_t *vals;
-
- *aclentp = NULL;
- *aclcnt = 0;
- *dfaclentp = NULL;
- *dfaclcnt = 0;
-
- /* we need at least user_obj, group_obj, and other_obj */
- if (n < 6) {
- error = ENOTSUP;
- goto out;
- }
- if (ace == NULL) {
- error = EINVAL;
- goto out;
- }
-
- normacl = calloc(1, sizeof (ace_list_t));
-
- if (normacl == NULL) {
- error = errno;
- goto out;
- }
-
- avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
- offsetof(acevals_t, avl));
- avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
- offsetof(acevals_t, avl));
-
- ace_list_init(normacl, 0);
-
- dfacl = calloc(1, sizeof (ace_list_t));
- if (dfacl == NULL) {
- error = errno;
- goto out;
- }
- avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
- offsetof(acevals_t, avl));
- avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
- offsetof(acevals_t, avl));
- ace_list_init(dfacl, ACL_DEFAULT);
-
- /* process every ace_t... */
- for (i = 0; i < n; i++) {
- acep = &ace[i];
-
- /* rule out certain cases quickly */
- error = ace_to_aent_legal(acep);
- if (error != 0)
- goto out;
-
- /*
- * Turn off these bits in order to not have to worry about
- * them when doing the checks for compliments.
- */
- acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
- ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
- ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
-
- /* see if this should be a regular or default acl */
- bits = acep->a_flags &
- (ACE_INHERIT_ONLY_ACE |
- ACE_FILE_INHERIT_ACE |
- ACE_DIRECTORY_INHERIT_ACE);
- if (bits != 0) {
- /* all or nothing on these inherit bits */
- if (bits != (ACE_INHERIT_ONLY_ACE |
- ACE_FILE_INHERIT_ACE |
- ACE_DIRECTORY_INHERIT_ACE)) {
- error = ENOTSUP;
- goto out;
- }
- acl = dfacl;
- } else {
- acl = normacl;
- }
-
- if ((acep->a_flags & ACE_OWNER)) {
- if (acl->state > ace_user_obj) {
- error = ENOTSUP;
- goto out;
- }
- acl->state = ace_user_obj;
- acl->seen |= USER_OBJ;
- vals = &acl->user_obj;
- vals->aent_type = USER_OBJ | acl->dfacl_flag;
- } else if ((acep->a_flags & ACE_EVERYONE)) {
- acl->state = ace_other_obj;
- acl->seen |= OTHER_OBJ;
- vals = &acl->other_obj;
- vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
- } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
- if (acl->state > ace_group) {
- error = ENOTSUP;
- goto out;
- }
- if ((acep->a_flags & ACE_GROUP)) {
- acl->seen |= GROUP_OBJ;
- vals = &acl->group_obj;
- vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
- } else {
- acl->seen |= GROUP;
- vals = acevals_find(acep, &acl->group,
- &acl->numgroups);
- if (vals == NULL) {
- error = ENOMEM;
- goto out;
- }
- vals->aent_type = GROUP | acl->dfacl_flag;
- }
- acl->state = ace_group;
- } else {
- if (acl->state > ace_user) {
- error = ENOTSUP;
- goto out;
- }
- acl->state = ace_user;
- acl->seen |= USER;
- vals = acevals_find(acep, &acl->user,
- &acl->numusers);
- if (vals == NULL) {
- error = ENOMEM;
- goto out;
- }
- vals->aent_type = USER | acl->dfacl_flag;
- }
-
- if (!(acl->state > ace_unused)) {
- error = EINVAL;
- goto out;
- }
-
- if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
- /* no more than one allowed per aclent_t */
- if (vals->allowed != ACE_MASK_UNDEFINED) {
- error = ENOTSUP;
- goto out;
- }
- vals->allowed = acep->a_access_mask;
- } else {
- /*
- * it's a DENY; if there was a previous DENY, it
- * must have been an ACL_MASK.
- */
- if (vals->denied != ACE_MASK_UNDEFINED) {
- /* ACL_MASK is for USER and GROUP only */
- if ((acl->state != ace_user) &&
- (acl->state != ace_group)) {
- error = ENOTSUP;
- goto out;
- }
-
- if (! acl->hasmask) {
- acl->hasmask = 1;
- acl->acl_mask = vals->denied;
- /* check for mismatched ACL_MASK emulations */
- } else if (acl->acl_mask != vals->denied) {
- error = ENOTSUP;
- goto out;
- }
- vals->mask = vals->denied;
- }
- vals->denied = acep->a_access_mask;
- }
- }
-
- /* done collating; produce the aclent_t lists */
- if (normacl->state != ace_unused) {
- error = ace_list_to_aent(normacl, aclentp, aclcnt,
- owner, group, isdir);
- if (error != 0) {
- goto out;
- }
- }
- if (dfacl->state != ace_unused) {
- error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
- owner, group, isdir);
- if (error != 0) {
- goto out;
- }
- }
-
-out:
- if (normacl != NULL)
- ace_list_free(normacl);
- if (dfacl != NULL)
- ace_list_free(dfacl);
-
- return (error);
-}
-
-static int
-convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir,
- uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
-{
- int error;
- aclent_t *aclentp, *dfaclentp;
- int aclcnt, dfaclcnt;
-
- error = ln_ace_to_aent(acebufp, acecnt, owner, group,
- &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
-
- if (error)
- return (error);
-
-
- if (dfaclcnt != 0) {
- /*
- * Slap aclentp and dfaclentp into a single array.
- */
- aclentp = realloc(aclentp, (sizeof (aclent_t) * aclcnt) +
- (sizeof (aclent_t) * dfaclcnt));
- if (aclentp != NULL) {
- (void) memcpy(aclentp + aclcnt,
- dfaclentp, sizeof (aclent_t) * dfaclcnt);
- } else {
- error = -1;
- }
- }
-
- if (aclentp) {
- *retaclentp = aclentp;
- *retaclcnt = aclcnt + dfaclcnt;
- }
-
- if (dfaclentp)
- free(dfaclentp);
-
- return (error);
-}
static int
cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp)
@@ -1576,56 +240,6 @@ facl_get(int fd, int get_flag, acl_t **aclp)
return (cacl_get(acl_inp, get_flag, ACL_FD, aclp));
}
-static int
-acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner,
- gid_t group)
-{
- int aclcnt;
- void *acldata;
- int error;
-
- /*
- * See if we need to translate
- */
- if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
- (target_flavor == _ACL_ACLENT_ENABLED &&
- aclp->acl_type == ACLENT_T))
- return (0);
-
- if (target_flavor == -1)
- return (-1);
-
- if (target_flavor == _ACL_ACE_ENABLED &&
- aclp->acl_type == ACLENT_T) {
- error = convert_aent_to_ace(aclp->acl_aclp,
- aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
- if (error) {
- errno = error;
- return (-1);
- }
- } else if (target_flavor == _ACL_ACLENT_ENABLED &&
- aclp->acl_type == ACE_T) {
- error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
- isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
- if (error) {
- errno = error;
- return (-1);
- }
- } else {
- errno = ENOTSUP;
- return (-1);
- }
-
- /*
- * replace old acl with newly translated acl
- */
- free(aclp->acl_aclp);
- aclp->acl_aclp = acldata;
- aclp->acl_cnt = aclcnt;
- aclp->acl_type = (target_flavor == _ACL_ACE_ENABLED) ? ACE_T : ACLENT_T;
- return (0);
-}
-
/*
* Set an ACL, translates acl to ace_t when appropriate.
*/
diff --git a/usr/src/lib/libsec/common/aclutils.h b/usr/src/lib/libsec/common/aclutils.h
index e5c34347bf..1db0aa4752 100644
--- a/usr/src/lib/libsec/common/aclutils.h
+++ b/usr/src/lib/libsec/common/aclutils.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,6 +29,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
+#include <sys/acl.h>
#include <strings.h>
#include <locale.h>
#include <ctype.h>
@@ -50,26 +51,6 @@ extern "C" {
* append_data/add_subdirectory
* when object of ACL is known.
*/
-#define ACL_IS_DIR 0x2
-
-typedef enum acl_type {
- ACLENT_T = 0,
- ACE_T = 1
-} acl_type_t;
-
-/*
- * acl flags
- */
-#define ACL_IS_TRIVIAL 0x1
-
-struct acl_info {
- acl_type_t acl_type; /* style of acl */
- int acl_cnt; /* number of acl entries */
- int acl_entry_size; /* sizeof acl entry */
- int acl_flags; /* special flags about acl */
- void *acl_aclp; /* the acl */
-};
-
#define PERM_TYPE_ACE 0x1 /* permissions are of ACE type */
#define PERM_TYPE_UNKNOWN 0x2 /* permission type not yet known */
@@ -105,7 +86,6 @@ extern void acl_error(const char *, ...);
extern int acl_parse(const char *, acl_t **);
extern int yyparse(void);
extern void yyreset(void);
-extern acl_t *acl_alloc(enum acl_type);
extern acl_t *acl_to_aclp(enum acl_type, void *, int);
#ifdef __cplusplus
diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt
index afb8349e40..0b81cd20f0 100644
--- a/usr/src/lib/libsecdb/auth_attr.txt
+++ b/usr/src/lib/libsecdb/auth_attr.txt
@@ -121,6 +121,7 @@ solaris.smf.manage.mdns:::Manage Multicast DNS Service States::help=SmfMDNSState
solaris.smf.manage.name-service-cache:::Manage Name Service Cache Daemon Service States::help=SmfNscdStates.html
solaris.smf.manage.nwam:::Manage Network Auto-Magic Service States::help=SmfNWAMStates.html
solaris.smf.manage.power:::Manage Power Management Service States::help=SmfPowerStates.html
+solaris.smf.manage.smb:::Manage SMB Service States::help=SmfSMBStates.html
solaris.smf.manage.rmvolmgr:::Manage Rmvolmgr Service States::help=SmfRmvolmgrStates.html
solaris.smf.manage.routing:::Manage Routing Service States::help=SmfRoutingStates.html
solaris.smf.manage.rpc.bind:::Manage RPC Program number mapper::help=SmfRPCBind.html
@@ -137,6 +138,8 @@ solaris.smf.value.inetd:::Change values of SMF Inetd configuration paramaters::h
solaris.smf.value.ipsec:::Change Values of SMF IPsec Properties::help=SmfValueIPsec.html
solaris.smf.value.mdns:::Change Values of MDNS Service Properties::help=SmfValueMDNS.html
solaris.smf.value.nwam:::Change Values of SMF Network Auto-Magic Properties::help=SmfValueNWAM.html
+solaris.smf.value.smb:::Change Values of SMB Service Properties::help=SmfValueSMB.html
+solaris.smf.read.smb:::Read permission for protected SMF SMB Service Properties::help=AuthReadSMB.html
solaris.smf.value.routing:::Change Values of SMF Routing Properties::help=SmfValueRouting.html
solaris.smf.value.tnd:::Change Trusted Network Daemon Service Property Values::help=ValueTND.html
#
diff --git a/usr/src/lib/libsecdb/help/auths/AuthReadSMB.html b/usr/src/lib/libsecdb/help/auths/AuthReadSMB.html
new file mode 100755
index 0000000000..aec2ed97e8
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/AuthReadSMB.html
@@ -0,0 +1,38 @@
+<HTML>
+<!--
+ 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.
+-->
+<HEAD>
+ <TITLE> </TITLE>
+
+
+</HEAD>
+<BODY>
+<!-- ident "%Z%%M% %I% %E% SMI" -->
+
+When View Rights is in the Authorizations Included column, it grants the authorization to list and read rights, in the Users tools of the Solaris Management Console.
+<p>
+If View Rights is grayed, then you are not entitled to Add or Remove this authorization.
+<p>
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile
index 1bdd12e0ce..d28be1d4c5 100644
--- a/usr/src/lib/libsecdb/help/auths/Makefile
+++ b/usr/src/lib/libsecdb/help/auths/Makefile
@@ -93,6 +93,9 @@ HTMLENTS = \
SmfValueNADD.html \
SmfValueNWAM.html \
SmfValueRouting.html \
+ SmfValueSMB.html \
+ AuthReadSMB.html \
+ SmfSMBStates.html \
SmfWpaStates.html \
NetworkHeader.html \
WifiConfig.html \
diff --git a/usr/src/lib/libsecdb/help/auths/SmfSMBStates.html b/usr/src/lib/libsecdb/help/auths/SmfSMBStates.html
new file mode 100644
index 0000000000..baa85f002d
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/SmfSMBStates.html
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+ 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.
+-->
+<!-- SCCS keyword
+#pragma ident "%Z%%M% %I% %E% SMI"
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Manage SMB Service States is in the Authorizations Include
+column, it grants the authorization to enable, disable, or restart
+the SMB service.
+<p>
+If Manage SMB Service States is grayed, then you are not entitled
+to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/auths/SmfValueSMB.html b/usr/src/lib/libsecdb/help/auths/SmfValueSMB.html
new file mode 100644
index 0000000000..0e5c3bc277
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/SmfValueSMB.html
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+ 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.
+-->
+<!-- SCCS keyword
+#pragma ident "%Z%%M% %I% %E% SMI"
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Value SMB Properties is in the Authorizations Include
+column, it grants the authorization to change SMB service
+property values.
+<P>
+If Value SMB Properties is grayed, then you are not entitled to
+Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/profiles/Makefile b/usr/src/lib/libsecdb/help/profiles/Makefile
index 9ad6ede803..e0300d339b 100644
--- a/usr/src/lib/libsecdb/help/profiles/Makefile
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile
@@ -62,6 +62,7 @@ HTMLENTS = \
RtPrntAdmin.html \
RtProcManagement.html \
RtRightsDelegate.html \
+ RtSMBMngmnt.html \
RtSoftwareInstall.html \
RtSysEvMngmnt.html \
RtUserMngmnt.html \
diff --git a/usr/src/lib/libsecdb/help/profiles/RtSMBMngmnt.html b/usr/src/lib/libsecdb/help/profiles/RtSMBMngmnt.html
new file mode 100644
index 0000000000..bbfef648ab
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/profiles/RtSMBMngmnt.html
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+ 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.
+-->
+<HEAD>
+ <TITLE> </TITLE>
+
+
+</HEAD>
+<BODY>
+<!-- ident "%Z%%M% %I% %E% SMI" -->
+
+When SMB Service Management is in the Rights Included column, it grants
+the right to administer the SMB service.
+<p>
+If SMB Service Management is grayed, then you are not entitled to Add or
+Remove this right.
+<p>
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt
index 96107e01f4..1c171d427b 100644
--- a/usr/src/lib/libsecdb/prof_attr.txt
+++ b/usr/src/lib/libsecdb/prof_attr.txt
@@ -42,7 +42,7 @@ Log Management:::Manage log files:help=RtLogMngmnt.html
Basic Solaris User:::Automatically assigned rights:auths=solaris.profmgr.read,solaris.jobs.user,solaris.mail.mailq,solaris.device.mount.removable;profiles=All;help=RtDefault.html
Device Security:::Manage devices and Volume Manager:auths=solaris.device.*;help=RtDeviceSecurity.html
DHCP Management:::Manage the DHCP service:auths=solaris.dhcpmgr.*;help=RtDHCPMngmnt.html
-File System Management:::Manage, mount, share file systems:auths=solaris.smf.manage.autofs,solaris.smf.manage.shares.*,solaris.smf.value.shares.*;help=RtFileSysMngmnt.html
+File System Management:::Manage, mount, share file systems:profiles=SMB Management;auths=solaris.smf.manage.autofs,solaris.smf.manage.shares.*,solaris.smf.value.shares.*;help=RtFileSysMngmnt.html
File System Security:::Manage file system security attributes:help=RtFileSysSecurity.html
HAL Management:::Manage HAL SMF service:auths=solaris.smf.manage.hal;help=RtHALMngmnt.html
Idmap Name Mapping Management:::Manage Name-based Mapping Rules of Identity Mapping Service:auths=solaris.admin.idmap.rules;help=RtIdmapNameRulesMngmnt.html
@@ -75,6 +75,7 @@ Crypto Management:::Cryptographic Framework Administration:help=RtCryptoMngmnt.h
Kerberos Client Management:::Maintain and Administer Kerberos excluding the servers:help=RtKerberosClntMngmnt.html
Kerberos Server Management:::Maintain and Administer Kerberos Servers:profiles=Kerberos Client Management;help=RtKerberosSrvrMngmnt.html
DAT Administration:::Manage the DAT configuration:help=RtDatAdmin.html
+SMB Management:::Manage the SMB service:auths=solaris.smf.manage.smb,solaris.smf.value.smb,solaris.smf.read.smb;help=RtSMBMngmnt.html
ZFS File System Management:::Create and Manage ZFS File Systems:help=RtZFSFileSysMngmnt.html
ZFS Storage Management:::Create and Manage ZFS Storage Pools:help=RtZFSStorageMngmnt.html
Zone Management:::Zones Virtual Application Environment Administration:help=RtZoneMngmnt.html
diff --git a/usr/src/lib/libshare/Makefile b/usr/src/lib/libshare/Makefile
index fb19160065..0c333e4459 100644
--- a/usr/src/lib/libshare/Makefile
+++ b/usr/src/lib/libshare/Makefile
@@ -35,7 +35,7 @@ $(BUILD64)MACHS += $(MACH64)
# Add plugin module directories here. They need to build after the libshare
# objects are built.
-PLUGINS = nfs
+PLUGINS = smb nfs
$(PLUGINS): $(MACHS)
SUBDIRS = $(MACHS) $(PLUGINS)
diff --git a/usr/src/lib/libshare/common/libshare.c b/usr/src/lib/libshare/common/libshare.c
index 25213e97a4..49104b2abe 100644
--- a/usr/src/lib/libshare/common/libshare.c
+++ b/usr/src/lib/libshare/common/libshare.c
@@ -58,6 +58,16 @@
#define SA_STRSIZE 256 /* max string size for names */
/*
+ * internal object type values returned by sa_get_object_type()
+ */
+#define SA_TYPE_UNKNOWN 0
+#define SA_TYPE_GROUP 1
+#define SA_TYPE_SHARE 2
+#define SA_TYPE_RESOURCE 3
+#define SA_TYPE_OPTIONSET 4
+#define SA_TYPE_ALTSPACE 5
+
+/*
* internal data structures
*/
@@ -69,16 +79,20 @@ extern int gettransients(sa_handle_impl_t, xmlNodePtr *);
extern int sa_valid_property(void *, char *, sa_property_t);
extern char *sa_fstype(char *);
extern int sa_is_share(void *);
+extern int sa_is_resource(void *);
extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */
extern int sa_group_is_zfs(sa_group_t);
extern int sa_path_is_zfs(char *);
extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
+extern int sa_zfs_set_sharesmb(sa_group_t, char *, int);
extern void update_legacy_config(sa_handle_t);
extern int issubdir(char *, char *);
extern int sa_zfs_init(sa_handle_impl_t);
extern void sa_zfs_fini(sa_handle_impl_t);
extern void sablocksigs(sigset_t *);
extern void saunblocksigs(sigset_t *);
+static sa_group_t sa_get_optionset_parent(sa_optionset_t);
+static char *get_node_attr(void *, char *);
/*
* Data structures for finding/managing the document root to access
@@ -188,6 +202,21 @@ sa_errorstr(int err)
case SA_NOT_SHARED:
ret = dgettext(TEXT_DOMAIN, "not shared");
break;
+ case SA_NO_SUCH_RESOURCE:
+ ret = dgettext(TEXT_DOMAIN, "no such resource");
+ break;
+ case SA_RESOURCE_REQUIRED:
+ ret = dgettext(TEXT_DOMAIN, "resource name required");
+ break;
+ case SA_MULTIPLE_ERROR:
+ ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
+ break;
+ case SA_PATH_IS_SUBDIR:
+ ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
+ break;
+ case SA_PATH_IS_PARENTDIR:
+ ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
+ break;
default:
(void) snprintf(errstr, sizeof (errstr),
dgettext(TEXT_DOMAIN, "unknown %d"), err);
@@ -376,6 +405,36 @@ is_shared(sa_share_t share)
}
/*
+ * excluded_protocol(share, proto)
+ *
+ * Returns B_TRUE if the specified protocol appears in the "exclude"
+ * property. This is used to prevent sharing special case shares
+ * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is
+ * returned if the protocol isn't in the list.
+ */
+static boolean_t
+excluded_protocol(sa_share_t share, char *proto)
+{
+ char *protolist;
+ char *str;
+ char *token;
+
+ protolist = sa_get_share_attr(share, "exclude");
+ if (protolist != NULL) {
+ str = protolist;
+ while ((token = strtok(str, ",")) != NULL) {
+ if (strcmp(token, proto) == 0) {
+ sa_free_attr_string(protolist);
+ return (B_TRUE);
+ }
+ str = NULL;
+ }
+ sa_free_attr_string(protolist);
+ }
+ return (B_FALSE);
+}
+
+/*
* checksubdirgroup(group, newpath, strictness)
*
* check all the specified newpath against all the paths in the
@@ -392,6 +451,11 @@ checksubdirgroup(sa_group_t group, char *newpath, int strictness)
sa_share_t share;
char *path;
int issub = SA_OK;
+ int subdir;
+ int parent;
+
+ if (newpath == NULL)
+ return (SA_INVALID_PATH);
for (share = sa_get_share(group, NULL); share != NULL;
share = sa_get_next_share(share)) {
@@ -417,13 +481,18 @@ checksubdirgroup(sa_group_t group, char *newpath, int strictness)
*/
if (path == NULL)
continue;
- if (newpath != NULL &&
- (strcmp(path, newpath) == 0 || issubdir(newpath, path) ||
- issubdir(path, newpath))) {
- sa_free_attr_string(path);
- path = NULL;
+
+ if (strcmp(path, newpath) == 0) {
issub = SA_INVALID_PATH;
- break;
+ } else {
+ subdir = issubdir(newpath, path);
+ parent = issubdir(path, newpath);
+ if (subdir || parent) {
+ sa_free_attr_string(path);
+ path = NULL;
+ return (subdir ?
+ SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR);
+ }
}
sa_free_attr_string(path);
path = NULL;
@@ -446,15 +515,16 @@ static int
checksubdir(sa_handle_t handle, char *newpath, int strictness)
{
sa_group_t group;
- int issub;
+ int issub = SA_OK;
char *path = NULL;
- for (issub = 0, group = sa_get_group(handle, NULL);
- group != NULL && !issub; group = sa_get_next_group(group)) {
+ for (group = sa_get_group(handle, NULL);
+ group != NULL && issub == SA_OK;
+ group = sa_get_next_group(group)) {
if (sa_group_is_zfs(group)) {
sa_group_t subgroup;
for (subgroup = sa_get_sub_group(group);
- subgroup != NULL && !issub;
+ subgroup != NULL && issub == SA_OK;
subgroup = sa_get_next_group(subgroup))
issub = checksubdirgroup(subgroup, newpath,
strictness);
@@ -517,14 +587,17 @@ validpath(sa_handle_t handle, char *path, int strictness)
/*
* check to see if group/share is persistent.
+ *
+ * "group" can be either an sa_group_t or an sa_share_t. (void *)
+ * works since both thse types are also void *.
*/
-static int
-is_persistent(sa_group_t group)
+int
+sa_is_persistent(void *group)
{
char *type;
int persist = 1;
- type = sa_get_group_attr(group, "type");
+ type = sa_get_group_attr((sa_group_t)group, "type");
if (type != NULL && strcmp(type, "transient") == 0)
persist = 0;
if (type != NULL)
@@ -590,6 +663,35 @@ is_zfs_group(sa_group_t group)
}
/*
+ * sa_get_object_type(object)
+ *
+ * This function returns a numeric value representing the object
+ * type. This allows using simpler checks when doing type specific
+ * operations.
+ */
+
+static int
+sa_get_object_type(void *object)
+{
+ xmlNodePtr node = (xmlNodePtr)object;
+ int type;
+
+ if (xmlStrcmp(node->name, (xmlChar *)"group") == 0)
+ type = SA_TYPE_GROUP;
+ else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0)
+ type = SA_TYPE_SHARE;
+ else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
+ type = SA_TYPE_RESOURCE;
+ else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0)
+ type = SA_TYPE_OPTIONSET;
+ else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0)
+ type = SA_TYPE_ALTSPACE;
+ else
+ assert(0);
+ return (type);
+}
+
+/*
* sa_optionset_name(optionset, oname, len, id)
* return the SMF name for the optionset. If id is not NULL, it
* will have the GUID value for a share and should be used
@@ -605,15 +707,34 @@ static int
sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id)
{
char *proto;
+ void *parent;
+ int ptype;
if (id == NULL)
id = "optionset";
- proto = sa_get_optionset_attr(optionset, "type");
- len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default");
+ parent = sa_get_optionset_parent(optionset);
+ if (parent != NULL) {
+ ptype = sa_get_object_type(parent);
+ proto = sa_get_optionset_attr(optionset, "type");
+ if (ptype != SA_TYPE_RESOURCE) {
+ len = snprintf(oname, len, "%s_%s", id,
+ proto ? proto : "default");
+ } else {
+ char *index;
+ index = get_node_attr((void *)parent, "id");
+ if (index != NULL)
+ len = snprintf(oname, len, "%s_%s_%s", id,
+ proto ? proto : "default", index);
+ else
+ len = 0;
+ }
- if (proto != NULL)
- sa_free_attr_string(proto);
+ if (proto != NULL)
+ sa_free_attr_string(proto);
+ } else {
+ len = 0;
+ }
return (len);
}
@@ -660,6 +781,7 @@ verifydefgroupopts(sa_handle_t handle)
{
sa_group_t defgrp;
sa_optionset_t opt;
+
defgrp = sa_get_group(handle, "default");
if (defgrp != NULL) {
opt = sa_get_optionset(defgrp, NULL);
@@ -1187,7 +1309,7 @@ sa_find_share(sa_handle_t handle, char *sharepath)
/*
* sa_check_path(group, path, strictness)
*
- * check that path is a valid path relative to the group. Currently,
+ * Check that path is a valid path relative to the group. Currently,
* we are ignoring the group and checking only the NFS rules. Later,
* we may want to use the group to then check against the protocols
* enabled on the group. The strictness values mean:
@@ -1206,16 +1328,84 @@ sa_check_path(sa_group_t group, char *path, int strictness)
}
/*
- * _sa_add_share(group, sharepath, persist, *error)
+ * mark_excluded_protos(group, share, flags)
+ *
+ * Walk through all the protocols enabled for the group and check to
+ * see if the share has any of them should be in the exclude list
+ * based on the featureset of the protocol. If there are any, add the
+ * "exclude" property to the share.
+ */
+static void
+mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags)
+{
+ sa_optionset_t optionset;
+ char exclude_list[SA_STRSIZE];
+ char *sep = "";
+
+ exclude_list[0] = '\0';
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *value;
+ uint64_t features;
+ value = sa_get_optionset_attr(optionset, "type");
+ if (value == NULL)
+ continue;
+ features = sa_proto_get_featureset(value);
+ sa_free_attr_string(value);
+ if (!(features & flags)) {
+ (void) strlcat(exclude_list, sep,
+ sizeof (exclude_list));
+ (void) strlcat(exclude_list, value,
+ sizeof (exclude_list));
+ sep = ",";
+ }
+ }
+ if (exclude_list[0] != '\0')
+ xmlSetProp(share, (xmlChar *)"exclude",
+ (xmlChar *)exclude_list);
+}
+
+/*
+ * get_all_features(group)
*
- * common code for all types of add_share. sa_add_share() is the
+ * Walk through all the protocols on the group and collect all
+ * possible enabled features. This is the OR of all the featuresets.
+ */
+static uint64_t
+get_all_features(sa_group_t group)
+{
+ sa_optionset_t optionset;
+ uint64_t features = 0;
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *value;
+ value = sa_get_optionset_attr(optionset, "type");
+ if (value == NULL)
+ continue;
+ features |= sa_proto_get_featureset(value);
+ sa_free_attr_string(value);
+ }
+ return (features);
+}
+
+
+/*
+ * _sa_add_share(group, sharepath, persist, *error, flags)
+ *
+ * Common code for all types of add_share. sa_add_share() is the
* public API, we also need to be able to do this when parsing legacy
* files and construction of the internal configuration while
- * extracting config info from SMF.
+ * extracting config info from SMF. "flags" indicates if some
+ * protocols need relaxed rules while other don't. These values are
+ * the featureset values defined in libshare.h.
*/
sa_share_t
-_sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
+_sa_add_share(sa_group_t group, char *sharepath, int persist, int *error,
+ uint64_t flags)
{
xmlNodePtr node = NULL;
int err;
@@ -1223,52 +1413,60 @@ _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
err = SA_OK; /* assume success */
node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL);
- if (node != NULL) {
- xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
- xmlSetProp(node, (xmlChar *)"type",
- persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
- if (persist != SA_SHARE_TRANSIENT) {
- /*
- * persistent shares come in two flavors: SMF and
- * ZFS. Sort this one out based on target group and
- * path type. Currently, only NFS is supported in the
- * ZFS group and it is always on.
- */
- if (sa_group_is_zfs(group) &&
- sa_path_is_zfs(sharepath)) {
+ if (node == NULL) {
+ if (error != NULL)
+ *error = SA_NO_MEMORY;
+ return (node);
+ }
+
+ xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
+ xmlSetProp(node, (xmlChar *)"type",
+ persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
+ if (flags != 0)
+ mark_excluded_protos(group, node, flags);
+ if (persist != SA_SHARE_TRANSIENT) {
+ /*
+ * persistent shares come in two flavors: SMF and
+ * ZFS. Sort this one out based on target group and
+ * path type. Both NFS and SMB are supported. First,
+ * check to see if the protocol is enabled on the
+ * subgroup and then setup the share appropriately.
+ */
+ if (sa_group_is_zfs(group) &&
+ sa_path_is_zfs(sharepath)) {
+ if (sa_get_optionset(group, "nfs") != NULL)
err = sa_zfs_set_sharenfs(group, sharepath, 1);
+ else if (sa_get_optionset(group, "smb") != NULL)
+ err = sa_zfs_set_sharesmb(group, sharepath, 1);
+ } else {
+ sa_handle_impl_t impl_handle;
+ impl_handle =
+ (sa_handle_impl_t)sa_find_group_handle(group);
+ if (impl_handle != NULL) {
+ err = sa_commit_share(impl_handle->scfhandle,
+ group, (sa_share_t)node);
} else {
- sa_handle_impl_t impl_handle;
- impl_handle =
- (sa_handle_impl_t)sa_find_group_handle(
- group);
- if (impl_handle != NULL) {
- err = sa_commit_share(
- impl_handle->scfhandle, group,
- (sa_share_t)node);
- } else {
- err = SA_SYSTEM_ERR;
- }
+ err = SA_SYSTEM_ERR;
}
}
- if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) {
- /* called by the dfstab parser so could be a show */
- err = SA_OK;
- }
- if (err != SA_OK) {
- /*
- * we couldn't commit to the repository so undo
- * our internal state to reflect reality.
- */
- xmlUnlinkNode(node);
- xmlFreeNode(node);
- node = NULL;
- }
- } else {
- err = SA_NO_MEMORY;
}
+ if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER)
+ /* called by the dfstab parser so could be a show */
+ err = SA_OK;
+
+ if (err != SA_OK) {
+ /*
+ * we couldn't commit to the repository so undo
+ * our internal state to reflect reality.
+ */
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+ node = NULL;
+ }
+
if (error != NULL)
*error = err;
+
return (node);
}
@@ -1285,9 +1483,10 @@ sa_share_t
sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
{
xmlNodePtr node = NULL;
- sa_share_t dup;
int strictness = SA_CHECK_NORMAL;
sa_handle_t handle;
+ uint64_t special = 0;
+ uint64_t features;
/*
* If the share is to be permanent, use strict checking so a
@@ -1304,12 +1503,33 @@ sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
handle = sa_find_group_handle(group);
- if ((dup = sa_find_share(handle, sharepath)) == NULL &&
- (*error = sa_check_path(group, sharepath, strictness)) == SA_OK) {
- node = _sa_add_share(group, sharepath, persist, error);
- }
- if (dup != NULL)
+ /*
+ * need to determine if the share is valid. The rules are:
+ * - The path must not already exist
+ * - The path must not be a subdir or parent dir of an
+ * existing path unless at least one protocol allows it.
+ * The sub/parent check is done in sa_check_path().
+ */
+
+ if (sa_find_share(handle, sharepath) == NULL) {
+ *error = sa_check_path(group, sharepath, strictness);
+ features = get_all_features(group);
+ switch (*error) {
+ case SA_PATH_IS_SUBDIR:
+ if (features & SA_FEATURE_ALLOWSUBDIRS)
+ special |= SA_FEATURE_ALLOWSUBDIRS;
+ break;
+ case SA_PATH_IS_PARENTDIR:
+ if (features & SA_FEATURE_ALLOWPARDIRS)
+ special |= SA_FEATURE_ALLOWPARDIRS;
+ break;
+ }
+ if (*error == SA_OK || special != SA_FEATURE_NONE)
+ node = _sa_add_share(group, sharepath, persist,
+ error, special);
+ } else {
*error = SA_DUPLICATE_NAME;
+ }
return ((sa_share_t)node);
}
@@ -1324,28 +1544,52 @@ sa_enable_share(sa_share_t share, char *protocol)
{
char *sharepath;
struct stat st;
- int err = 0;
+ int err = SA_OK;
+ int ret;
sharepath = sa_get_share_attr(share, "path");
+ if (sharepath == NULL)
+ return (SA_NO_MEMORY);
if (stat(sharepath, &st) < 0) {
err = SA_NO_SUCH_PATH;
} else {
/* tell the server about the share */
if (protocol != NULL) {
+ if (excluded_protocol(share, protocol))
+ goto done;
+
/* lookup protocol specific handler */
err = sa_proto_share(protocol, share);
if (err == SA_OK)
- (void) sa_set_share_attr(share, "shared",
- "true");
+ (void) sa_set_share_attr(share,
+ "shared", "true");
} else {
- /*
- * Tell all protocols. Only NFS for now but
- * SMB is coming.
- */
- err = sa_proto_share("nfs", share);
+ /* Tell all protocols about the share */
+ sa_group_t group;
+ sa_optionset_t optionset;
+
+ group = sa_get_parent_group(share);
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *proto;
+ proto = sa_get_optionset_attr(optionset,
+ "type");
+ if (proto != NULL) {
+ if (!excluded_protocol(share, proto)) {
+ ret = sa_proto_share(proto,
+ share);
+ if (ret != SA_OK)
+ err = ret;
+ }
+ sa_free_attr_string(proto);
+ }
+ }
(void) sa_set_share_attr(share, "shared", "true");
}
}
+done:
if (sharepath != NULL)
sa_free_attr_string(sharepath);
return (err);
@@ -1353,31 +1597,47 @@ sa_enable_share(sa_share_t share, char *protocol)
/*
* sa_disable_share(share, protocol)
- * Disable the specified share to the specified protocol.
- * If protocol is NULL, then all protocols.
+ * Disable the specified share to the specified protocol. If
+ * protocol is NULL, then all protocols that are enabled for the
+ * share should be disabled.
*/
int
sa_disable_share(sa_share_t share, char *protocol)
{
char *path;
- char *shared;
+ int err = SA_OK;
int ret = SA_OK;
path = sa_get_share_attr(share, "path");
- shared = sa_get_share_attr(share, "shared");
if (protocol != NULL) {
ret = sa_proto_unshare(share, protocol, path);
} else {
/* need to do all protocols */
- ret = sa_proto_unshare(share, "nfs", path);
+ sa_group_t group;
+ sa_optionset_t optionset;
+
+ group = sa_get_parent_group(share);
+
+ /* Tell all protocols about the share */
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *proto;
+
+ proto = sa_get_optionset_attr(optionset, "type");
+ if (proto != NULL) {
+ err = sa_proto_unshare(share, proto, path);
+ if (err != SA_OK)
+ ret = err;
+ sa_free_attr_string(proto);
+ }
+ }
}
if (ret == SA_OK)
(void) sa_set_share_attr(share, "shared", NULL);
if (path != NULL)
sa_free_attr_string(path);
- if (shared != NULL)
- sa_free_attr_string(shared);
return (ret);
}
@@ -1415,7 +1675,7 @@ sa_remove_share(sa_share_t share)
/* only do SMF action if permanent */
if (!transient || zfs != NULL) {
/* remove from legacy dfstab as well as possible SMF */
- ret = sa_delete_legacy(share);
+ ret = sa_delete_legacy(share, NULL);
if (ret == SA_OK) {
if (!sa_group_is_zfs(group)) {
sa_handle_impl_t impl_handle;
@@ -1497,7 +1757,7 @@ sa_move_share(sa_group_t group, sa_share_t share)
/*
* sa_get_parent_group(share)
*
- * Return the containg group for the share. If a group was actually
+ * Return the containing group for the share. If a group was actually
* passed in, we don't want a parent so return NULL.
*/
@@ -1728,7 +1988,7 @@ sa_update_config(sa_handle_t handle)
/*
* get_node_attr(node, tag)
*
- * Get the speficied tag(attribute) if it exists on the node. This is
+ * Get the specified tag(attribute) if it exists on the node. This is
* used internally by a number of attribute oriented functions.
*/
@@ -1746,7 +2006,7 @@ get_node_attr(void *nodehdl, char *tag)
/*
* get_node_attr(node, tag)
*
- * Set the speficied tag(attribute) to the specified value This is
+ * Set the specified tag(attribute) to the specified value This is
* used internally by a number of attribute oriented functions. It
* doesn't update the repository, only the internal document state.
*/
@@ -1792,6 +2052,14 @@ sa_set_group_attr(sa_group_t group, char *tag, char *value)
char *groupname;
sa_handle_impl_t impl_handle;
+ /*
+ * ZFS group/subgroup doesn't need the handle so shortcut.
+ */
+ if (sa_group_is_zfs(group)) {
+ set_node_attr((void *)group, tag, value);
+ return (SA_OK);
+ }
+
impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
if (impl_handle != NULL) {
groupname = sa_get_group_attr(group, "name");
@@ -1833,47 +2101,15 @@ sa_get_share_attr(sa_share_t share, char *tag)
}
/*
- * sa_get_resource(group, resource)
- *
- * Search all the shares in the speified group for a share with a
- * resource name matching the one specified.
- *
- * In the future, it may be advantageous to allow group to be NULL and
- * search all groups but that isn't needed at present.
- */
-
-sa_share_t
-sa_get_resource(sa_group_t group, char *resource)
-{
- sa_share_t share = NULL;
- char *name = NULL;
-
- if (resource != NULL) {
- for (share = sa_get_share(group, NULL); share != NULL;
- share = sa_get_next_share(share)) {
- name = sa_get_share_attr(share, "resource");
- if (name != NULL) {
- if (strcmp(name, resource) == 0)
- break;
- sa_free_attr_string(name);
- name = NULL;
- }
- }
- if (name != NULL)
- sa_free_attr_string(name);
- }
- return ((sa_share_t)share);
-}
-
-/*
* _sa_set_share_description(share, description)
*
- * Add a description tag with text contents to the specified share.
- * A separate XML tag is used rather than a property.
+ * Add a description tag with text contents to the specified share. A
+ * separate XML tag is used rather than a property. This can also be
+ * used with resources.
*/
xmlNodePtr
-_sa_set_share_description(sa_share_t share, char *content)
+_sa_set_share_description(void *share, char *content)
{
xmlNodePtr node;
node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description",
@@ -2205,7 +2441,6 @@ sa_set_share_description(sa_share_t share, char *content)
break;
}
}
- group = sa_get_parent_group(share);
/* no existing description but want to add */
if (node == NULL && content != NULL) {
/* add a description */
@@ -2218,7 +2453,8 @@ sa_set_share_description(sa_share_t share, char *content)
xmlUnlinkNode(node);
xmlFreeNode(node);
}
- if (group != NULL && is_persistent((sa_group_t)share)) {
+ group = sa_get_parent_group(share);
+ if (group != NULL && sa_is_persistent(share)) {
sa_handle_impl_t impl_handle;
impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
if (impl_handle != NULL) {
@@ -2269,7 +2505,7 @@ sa_get_share_description(sa_share_t share)
}
}
if (node != NULL) {
- description = xmlNodeGetContent((xmlNodePtr)share);
+ description = xmlNodeGetContent(node);
fixproblemchars((char *)description);
}
return ((char *)description);
@@ -2299,12 +2535,44 @@ sa_create_optionset(sa_group_t group, char *proto)
{
sa_optionset_t optionset;
sa_group_t parent = group;
+ sa_share_t share = NULL;
+ int err = SA_OK;
+ char *id = NULL;
optionset = sa_get_optionset(group, proto);
if (optionset != NULL) {
/* can't have a duplicate protocol */
optionset = NULL;
} else {
+ /*
+ * Account for resource names being slightly
+ * different.
+ */
+ if (sa_is_share(group)) {
+ /*
+ * Transient shares do not have an "id" so not an
+ * error to not find one.
+ */
+ id = sa_get_share_attr((sa_share_t)group, "id");
+ } else if (sa_is_resource(group)) {
+ share = sa_get_resource_parent(
+ (sa_resource_t)group);
+ id = sa_get_resource_attr(share, "id");
+
+ /* id can be NULL if the group is transient (ZFS) */
+ if (id == NULL && sa_is_persistent(group))
+ err = SA_NO_MEMORY;
+ }
+ if (err == SA_NO_MEMORY) {
+ /*
+ * Couldn't get the id for the share or
+ * resource. While this could be a
+ * configuration issue, it is most likely an
+ * out of memory. In any case, fail the create.
+ */
+ return (NULL);
+ }
+
optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group,
NULL, (xmlChar *)"optionset", NULL);
/*
@@ -2314,38 +2582,44 @@ sa_create_optionset(sa_group_t group, char *proto)
if (optionset != NULL) {
char oname[SA_STRSIZE];
char *groupname;
- char *id = NULL;
- if (sa_is_share(group))
+ /*
+ * Need to get parent group in all cases, but also get
+ * the share if this is a resource.
+ */
+ if (sa_is_share(group)) {
parent = sa_get_parent_group((sa_share_t)group);
+ } else if (sa_is_resource(group)) {
+ share = sa_get_resource_parent(
+ (sa_resource_t)group);
+ parent = sa_get_parent_group(share);
+ }
sa_set_optionset_attr(optionset, "type", proto);
- if (sa_is_share(group)) {
- id = sa_get_share_attr((sa_share_t)group, "id");
- }
(void) sa_optionset_name(optionset, oname,
sizeof (oname), id);
groupname = sa_get_group_attr(parent, "name");
- if (groupname != NULL && is_persistent(group)) {
+ if (groupname != NULL && sa_is_persistent(group)) {
sa_handle_impl_t impl_handle;
- impl_handle = (sa_handle_impl_t)
- sa_find_group_handle(group);
+ impl_handle =
+ (sa_handle_impl_t)sa_find_group_handle(
+ group);
assert(impl_handle != NULL);
if (impl_handle != NULL) {
(void) sa_get_instance(
- impl_handle->scfhandle,
- groupname);
+ impl_handle->scfhandle, groupname);
(void) sa_create_pgroup(
impl_handle->scfhandle, oname);
}
}
if (groupname != NULL)
sa_free_attr_string(groupname);
- if (id != NULL)
- sa_free_attr_string(id);
}
}
+
+ if (id != NULL)
+ sa_free_attr_string(id);
return (optionset);
}
@@ -2388,7 +2662,7 @@ sa_get_optionset_parent(sa_optionset_t optionset)
*
* In order to avoid making multiple updates to a ZFS share when
* setting properties, the share attribute "changed" will be set to
- * true when a property is added or modifed. When done adding
+ * true when a property is added or modified. When done adding
* properties, we can then detect that an update is needed. We then
* clear the state here to detect additional changes.
*/
@@ -2470,7 +2744,7 @@ sa_commit_properties(sa_optionset_t optionset, int clear)
/*
* sa_destroy_optionset(optionset)
*
- * Remove the optionset from its group. Update the repostory to
+ * Remove the optionset from its group. Update the repository to
* reflect this change.
*/
@@ -2486,9 +2760,16 @@ sa_destroy_optionset(sa_optionset_t optionset)
/* now delete the prop group */
group = sa_get_optionset_parent(optionset);
- if (group != NULL && sa_is_share(group)) {
- ispersist = is_persistent(group);
- id = sa_get_share_attr((sa_share_t)group, "id");
+ if (group != NULL) {
+ if (sa_is_resource(group)) {
+ sa_resource_t resource = group;
+ sa_share_t share = sa_get_resource_parent(resource);
+ group = sa_get_parent_group(share);
+ id = sa_get_share_attr(share, "id");
+ } else if (sa_is_share(group)) {
+ id = sa_get_share_attr((sa_share_t)group, "id");
+ }
+ ispersist = sa_is_persistent(group);
}
if (ispersist) {
sa_handle_impl_t impl_handle;
@@ -2559,7 +2840,7 @@ sa_create_security(sa_group_t group, char *sectype, char *proto)
sa_set_security_attr(security, "sectype", sectype);
(void) sa_security_name(security, oname,
sizeof (oname), id);
- if (groupname != NULL && is_persistent(group)) {
+ if (groupname != NULL && sa_is_persistent(group)) {
sa_handle_impl_t impl_handle;
impl_handle =
(sa_handle_impl_t)sa_find_group_handle(
@@ -2603,7 +2884,7 @@ sa_destroy_security(sa_security_t security)
if (group != NULL && !iszfs) {
if (sa_is_share(group))
- ispersist = is_persistent(group);
+ ispersist = sa_is_persistent(group);
id = sa_get_share_attr((sa_share_t)group, "id");
}
if (ispersist) {
@@ -2666,7 +2947,6 @@ is_nodetype(void *node, char *type)
return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0);
}
-
/*
* add_or_update()
*
@@ -2721,12 +3001,12 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
int opttype; /* 1 == optionset, 0 == security */
char *id = NULL;
int iszfs = 0;
- int isshare = 0;
sa_group_t parent = NULL;
+ sa_share_t share = NULL;
sa_handle_impl_t impl_handle;
scfutilhandle_t *scf_handle;
- if (!is_persistent(group)) {
+ if (!sa_is_persistent(group)) {
/*
* if the group/share is not persistent we don't need
* to do anything here
@@ -2742,12 +3022,20 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
entry = scf_entry_create(scf_handle->handle);
opttype = is_nodetype((void *)optionset, "optionset");
+ /*
+ * Check for share vs. resource since they need slightly
+ * different treatment given the hierarchy.
+ */
if (valstr != NULL && entry != NULL) {
if (sa_is_share(group)) {
- isshare = 1;
parent = sa_get_parent_group(group);
+ share = (sa_share_t)group;
if (parent != NULL)
iszfs = is_zfs_group(parent);
+ } else if (sa_is_resource(group)) {
+ share = sa_get_parent_group(group);
+ if (share != NULL)
+ parent = sa_get_parent_group(share);
} else {
iszfs = is_zfs_group(group);
}
@@ -2755,15 +3043,13 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
if (scf_handle->trans == NULL) {
char oname[SA_STRSIZE];
char *groupname = NULL;
- if (isshare) {
- if (parent != NULL) {
+ if (share != NULL) {
+ if (parent != NULL)
groupname =
sa_get_group_attr(parent,
"name");
- }
- id =
- sa_get_share_attr((sa_share_t)group,
- "id");
+ id = sa_get_share_attr(
+ (sa_share_t)share, "id");
} else {
groupname = sa_get_group_attr(group,
"name");
@@ -2870,14 +3156,22 @@ sa_add_property(void *object, sa_property_t property)
sa_free_attr_string(proto);
parent = sa_get_parent_group(object);
- if (!is_persistent(parent)) {
+ if (!sa_is_persistent(parent))
return (ret);
- }
- if (sa_is_share(parent))
+ if (sa_is_resource(parent)) {
+ /*
+ * Resources are children of share. Need to go up two
+ * levels to find the group but the parent needs to be
+ * the share at this point in order to get the "id".
+ */
+ parent = sa_get_parent_group(parent);
group = sa_get_parent_group(parent);
- else
+ } else if (sa_is_share(parent)) {
+ group = sa_get_parent_group(parent);
+ } else {
group = parent;
+ }
if (property == NULL) {
ret = SA_NO_MEMORY;
@@ -3110,7 +3404,7 @@ sa_set_protocol_property(sa_property_t prop, char *value)
/*
* sa_add_protocol_property(propset, prop)
*
- * Add a new property to the protocol sepcific property set.
+ * Add a new property to the protocol specific property set.
*/
int
@@ -3128,7 +3422,7 @@ sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop)
/*
* sa_create_protocol_properties(proto)
*
- * Create a protocol specifity property set.
+ * Create a protocol specific property set.
*/
sa_protocol_properties_t
@@ -3141,3 +3435,583 @@ sa_create_protocol_properties(char *proto)
xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
return (node);
}
+
+/*
+ * sa_get_share_resource(share, resource)
+ *
+ * Get the named resource from the share, if it exists. If resource is
+ * NULL, get the first resource.
+ */
+
+sa_resource_t
+sa_get_share_resource(sa_share_t share, char *resource)
+{
+ xmlNodePtr node = NULL;
+ xmlChar *name;
+
+ if (share != NULL) {
+ for (node = ((xmlNodePtr)share)->children; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) {
+ if (resource == NULL) {
+ /*
+ * We are looking for the first
+ * resource node and not a names
+ * resource.
+ */
+ break;
+ } else {
+ /* is it the correct share? */
+ name = xmlGetProp(node,
+ (xmlChar *)"name");
+ if (name != NULL &&
+ xmlStrcasecmp(name,
+ (xmlChar *)resource) == 0) {
+ xmlFree(name);
+ break;
+ }
+ xmlFree(name);
+ }
+ }
+ }
+ }
+ return ((sa_resource_t)node);
+}
+
+/*
+ * sa_get_next_resource(resource)
+ * Return the next share following the specified share
+ * from the internal list of shares. Returns NULL if there
+ * are no more shares. The list is relative to the same
+ * group.
+ */
+sa_share_t
+sa_get_next_resource(sa_resource_t resource)
+{
+ xmlNodePtr node = NULL;
+
+ if (resource != NULL) {
+ for (node = ((xmlNodePtr)resource)->next; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
+ break;
+ }
+ }
+ return ((sa_share_t)node);
+}
+
+/*
+ * _sa_get_next_resource_index(share)
+ *
+ * get the next resource index number (one greater then current largest)
+ */
+
+static int
+_sa_get_next_resource_index(sa_share_t share)
+{
+ sa_resource_t resource;
+ int index = 0;
+ char *id;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ id = get_node_attr((void *)resource, "id");
+ if (id != NULL) {
+ int val;
+ val = atoi(id);
+ if (val > index)
+ index = val;
+ sa_free_attr_string(id);
+ }
+ }
+ return (index + 1);
+}
+
+
+/*
+ * sa_add_resource(share, resource, persist, &err)
+ *
+ * Adds a new resource name associated with share. The resource name
+ * must be unique in the system and will be case insensitive (eventually).
+ */
+
+sa_resource_t
+sa_add_resource(sa_share_t share, char *resource, int persist, int *error)
+{
+ xmlNodePtr node;
+ int err = SA_OK;
+ sa_resource_t res;
+ sa_group_t group;
+ sa_handle_t handle;
+ char istring[8]; /* just big enough for an integer value */
+ int index;
+
+ group = sa_get_parent_group(share);
+ handle = sa_find_group_handle(group);
+ res = sa_find_resource(handle, resource);
+ if (res != NULL) {
+ err = SA_DUPLICATE_NAME;
+ res = NULL;
+ } else {
+ node = xmlNewChild((xmlNodePtr)share, NULL,
+ (xmlChar *)"resource", NULL);
+ if (node != NULL) {
+ xmlSetProp(node, (xmlChar *)"name",
+ (xmlChar *)resource);
+ xmlSetProp(node, (xmlChar *)"type", persist ?
+ (xmlChar *)"persist" : (xmlChar *)"transient");
+ if (persist != SA_SHARE_TRANSIENT) {
+ index = _sa_get_next_resource_index(share);
+ (void) snprintf(istring, sizeof (istring), "%d",
+ index);
+ xmlSetProp(node, (xmlChar *)"id",
+ (xmlChar *)istring);
+ if (!sa_group_is_zfs(group) &&
+ sa_is_persistent((sa_group_t)share)) {
+ /* ZFS doesn't use resource names */
+ sa_handle_impl_t ihandle;
+ ihandle = (sa_handle_impl_t)
+ sa_find_group_handle(
+ group);
+ if (ihandle != NULL)
+ err = sa_commit_share(
+ ihandle->scfhandle, group,
+ share);
+ else
+ err = SA_SYSTEM_ERR;
+ }
+ }
+ }
+ }
+ if (error != NULL)
+ *error = err;
+ return ((sa_resource_t)node);
+}
+
+/*
+ * sa_remove_resource(resource)
+ *
+ * Remove the resource name from the share (and the system)
+ */
+
+int
+sa_remove_resource(sa_resource_t resource)
+{
+ sa_share_t share;
+ sa_group_t group;
+ char *type;
+ int ret = SA_OK;
+ int transient = 0;
+
+ share = sa_get_resource_parent(resource);
+ type = sa_get_share_attr(share, "type");
+ group = sa_get_parent_group(share);
+
+
+ if (type != NULL) {
+ if (strcmp(type, "persist") != 0)
+ transient = 1;
+ sa_free_attr_string(type);
+ }
+
+ /* Remove from the share */
+ xmlUnlinkNode((xmlNode *)resource);
+ xmlFreeNode((xmlNode *)resource);
+
+ /* only do SMF action if permanent and not ZFS */
+ if (!transient && !sa_group_is_zfs(group)) {
+ sa_handle_impl_t ihandle;
+ ihandle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (ihandle != NULL)
+ ret = sa_commit_share(ihandle->scfhandle, group, share);
+ else
+ ret = SA_SYSTEM_ERR;
+ }
+ return (ret);
+}
+
+/*
+ * proto_resource_rename(handle, group, resource, newname)
+ *
+ * Helper function for sa_rename_resource that notifies the protocol
+ * of a resource name change prior to a config repository update.
+ */
+static int
+proto_rename_resource(sa_handle_t handle, sa_group_t group,
+ sa_resource_t resource, char *newname)
+{
+ sa_optionset_t optionset;
+ int ret = SA_OK;
+ int err;
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *type;
+ type = sa_get_optionset_attr(optionset, "type");
+ if (type != NULL) {
+ err = sa_proto_rename_resource(handle, type, resource,
+ newname);
+ if (err != SA_OK)
+ ret = err;
+ sa_free_attr_string(type);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_rename_resource(resource, newname)
+ *
+ * Rename the resource to the new name, if it is unique.
+ */
+
+int
+sa_rename_resource(sa_resource_t resource, char *newname)
+{
+ sa_share_t share;
+ sa_group_t group = NULL;
+ sa_resource_t target;
+ int ret = SA_CONFIG_ERR;
+ sa_handle_t handle = NULL;
+
+ share = sa_get_resource_parent(resource);
+ if (share == NULL)
+ return (ret);
+
+ group = sa_get_parent_group(share);
+ if (group == NULL)
+ return (ret);
+
+ handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (handle == NULL)
+ return (ret);
+
+ target = sa_find_resource(handle, newname);
+ if (target != NULL) {
+ ret = SA_DUPLICATE_NAME;
+ } else {
+ /*
+ * Everything appears to be valid at this
+ * point. Change the name of the active share and then
+ * update the share in the appropriate repository.
+ */
+ ret = proto_rename_resource(handle, group, resource, newname);
+ set_node_attr(resource, "name", newname);
+ if (!sa_group_is_zfs(group) &&
+ sa_is_persistent((sa_group_t)share)) {
+ sa_handle_impl_t ihandle = (sa_handle_impl_t)handle;
+ ret = sa_commit_share(ihandle->scfhandle, group,
+ share);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_get_resource_attr(resource, tag)
+ *
+ * Get the named attribute of the resource. "name" and "id" are
+ * currently defined. NULL if tag not defined.
+ */
+
+char *
+sa_get_resource_attr(sa_resource_t resource, char *tag)
+{
+ return (get_node_attr((void *)resource, tag));
+}
+
+/*
+ * sa_set_resource_attr(resource, tag, value)
+ *
+ * Get the named attribute of the resource. "name" and "id" are
+ * currently defined. NULL if tag not defined. Currently we don't do
+ * much, but additional checking may be needed in the future.
+ */
+
+int
+sa_set_resource_attr(sa_resource_t resource, char *tag, char *value)
+{
+ set_node_attr((void *)resource, tag, value);
+ return (SA_OK);
+}
+
+/*
+ * sa_get_resource_parent(resource_t)
+ *
+ * Returns the share associated with the resource.
+ */
+
+sa_share_t
+sa_get_resource_parent(sa_resource_t resource)
+{
+ sa_share_t share = NULL;
+
+ if (resource != NULL)
+ share = (sa_share_t)((xmlNodePtr)resource)->parent;
+ return (share);
+}
+
+/*
+ * find_resource(group, name)
+ *
+ * Find the resource within the group.
+ */
+
+static sa_resource_t
+find_resource(sa_group_t group, char *resname)
+{
+ sa_share_t share;
+ sa_resource_t resource = NULL;
+ char *name;
+
+ /* Iterate over all the shares and resources in the group. */
+ for (share = sa_get_share(group, NULL);
+ share != NULL && resource == NULL;
+ share = sa_get_next_share(share)) {
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ name = sa_get_resource_attr(resource, "name");
+ if (name != NULL && xmlStrcasecmp((xmlChar*)name,
+ (xmlChar*)resname) == 0) {
+ sa_free_attr_string(name);
+ break;
+ }
+ if (name != NULL) {
+ sa_free_attr_string(name);
+ }
+ }
+ }
+ return (resource);
+}
+
+/*
+ * sa_find_resource(name)
+ *
+ * Find the named resource in the system.
+ */
+
+sa_resource_t
+sa_find_resource(sa_handle_t handle, char *name)
+{
+ sa_group_t group;
+ sa_group_t zgroup;
+ sa_resource_t resource = NULL;
+
+ /*
+ * Iterate over all groups and zfs subgroups and check for
+ * resource name in them.
+ */
+ for (group = sa_get_group(handle, NULL); group != NULL;
+ group = sa_get_next_group(group)) {
+
+ if (is_zfs_group(group)) {
+ for (zgroup =
+ (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
+ (xmlChar *)"group");
+ zgroup != NULL && resource == NULL;
+ zgroup = sa_get_next_group(zgroup)) {
+ resource = find_resource(zgroup, name);
+ }
+ } else {
+ resource = find_resource(group, name);
+ }
+ if (resource != NULL)
+ break;
+ }
+ return (resource);
+}
+
+/*
+ * sa_get_resource(group, resource)
+ *
+ * Search all the shares in the specified group for a share with a
+ * resource name matching the one specified.
+ *
+ * In the future, it may be advantageous to allow group to be NULL and
+ * search all groups but that isn't needed at present.
+ */
+
+sa_resource_t
+sa_get_resource(sa_group_t group, char *resource)
+{
+ sa_share_t share = NULL;
+ sa_resource_t res = NULL;
+
+ if (resource != NULL) {
+ for (share = sa_get_share(group, NULL);
+ share != NULL && res == NULL;
+ share = sa_get_next_share(share)) {
+ res = sa_get_share_resource(share, resource);
+ }
+ }
+ return (res);
+}
+
+/*
+ * sa_enable_resource, protocol)
+ * Disable the specified share to the specified protocol.
+ * If protocol is NULL, then all protocols.
+ */
+int
+sa_enable_resource(sa_resource_t resource, char *protocol)
+{
+ int ret = SA_OK;
+ char **protocols;
+ int numproto;
+
+ if (protocol != NULL) {
+ ret = sa_proto_share_resource(protocol, resource);
+ } else {
+ /* need to do all protocols */
+ if ((numproto = sa_get_protocols(&protocols)) >= 0) {
+ int i, err;
+ for (i = 0; i < numproto; i++) {
+ err = sa_proto_share_resource(
+ protocols[i], resource);
+ if (err != SA_OK)
+ ret = err;
+ }
+ free(protocols);
+ }
+ }
+ if (ret == SA_OK)
+ (void) sa_set_resource_attr(resource, "shared", NULL);
+
+ return (ret);
+}
+
+/*
+ * sa_disable_resource(resource, protocol)
+ *
+ * Disable the specified share for the specified protocol. If
+ * protocol is NULL, then all protocols. If the underlying
+ * protocol doesn't implement disable at the resource level, we
+ * disable at the share level.
+ */
+int
+sa_disable_resource(sa_resource_t resource, char *protocol)
+{
+ int ret = SA_OK;
+ char **protocols;
+ int numproto;
+
+ if (protocol != NULL) {
+ ret = sa_proto_unshare_resource(protocol, resource);
+ if (ret == SA_NOT_IMPLEMENTED) {
+ sa_share_t parent;
+ /*
+ * The protocol doesn't implement unshare
+ * resource. That implies that resource names are
+ * simple aliases for this protocol so we need to
+ * unshare the share.
+ */
+ parent = sa_get_resource_parent(resource);
+ if (parent != NULL)
+ ret = sa_disable_share(parent, protocol);
+ else
+ ret = SA_CONFIG_ERR;
+ }
+ } else {
+ /* need to do all protocols */
+ if ((numproto = sa_get_protocols(&protocols)) >= 0) {
+ int i, err;
+ for (i = 0; i < numproto; i++) {
+ err = sa_proto_unshare_resource(protocols[i],
+ resource);
+ if (err == SA_NOT_SUPPORTED) {
+ sa_share_t parent;
+ parent = sa_get_resource_parent(
+ resource);
+ if (parent != NULL)
+ err = sa_disable_share(parent,
+ protocols[i]);
+ else
+ err = SA_CONFIG_ERR;
+ }
+ if (err != SA_OK)
+ ret = err;
+ }
+ free(protocols);
+ }
+ }
+ if (ret == SA_OK)
+ (void) sa_set_resource_attr(resource, "shared", NULL);
+
+ return (ret);
+}
+
+/*
+ * sa_set_resource_description(resource, content)
+ *
+ * Set the description of share to content.
+ */
+
+int
+sa_set_resource_description(sa_resource_t resource, char *content)
+{
+ xmlNodePtr node;
+ sa_group_t group;
+ sa_share_t share;
+ int ret = SA_OK;
+
+ for (node = ((xmlNodePtr)resource)->children;
+ node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
+ break;
+ }
+ }
+
+ /* no existing description but want to add */
+ if (node == NULL && content != NULL) {
+ /* add a description */
+ node = _sa_set_share_description(resource, content);
+ } else if (node != NULL && content != NULL) {
+ /* update a description */
+ xmlNodeSetContent(node, (xmlChar *)content);
+ } else if (node != NULL && content == NULL) {
+ /* remove an existing description */
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+ }
+ share = sa_get_resource_parent(resource);
+ group = sa_get_parent_group(share);
+ if (group != NULL && sa_is_persistent(share)) {
+ sa_handle_impl_t impl_handle;
+ impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (impl_handle != NULL)
+ ret = sa_commit_share(impl_handle->scfhandle,
+ group, share);
+ else
+ ret = SA_SYSTEM_ERR;
+ }
+ return (ret);
+}
+
+/*
+ * sa_get_resource_description(share)
+ *
+ * Return the description text for the specified share if it
+ * exists. NULL if no description exists.
+ */
+
+char *
+sa_get_resource_description(sa_resource_t resource)
+{
+ xmlChar *description = NULL;
+ xmlNodePtr node;
+
+ for (node = ((xmlNodePtr)resource)->children; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"description") == 0)
+ break;
+ }
+ if (node != NULL) {
+ description = xmlNodeGetContent(node);
+ fixproblemchars((char *)description);
+ }
+ return ((char *)description);
+}
diff --git a/usr/src/lib/libshare/common/libshare.h b/usr/src/lib/libshare/common/libshare.h
index c78b0822c6..bdac6a6d64 100644
--- a/usr/src/lib/libshare/common/libshare.h
+++ b/usr/src/lib/libshare/common/libshare.h
@@ -37,6 +37,8 @@
extern "C" {
#endif
+#include <sys/types.h>
+
/*
* Basic datatypes for most functions
*/
@@ -46,6 +48,7 @@ typedef void *sa_property_t;
typedef void *sa_optionset_t;
typedef void *sa_security_t;
typedef void *sa_protocol_properties_t;
+typedef void *sa_resource_t;
typedef void *sa_handle_t; /* opaque handle to access core functions */
@@ -77,6 +80,11 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
#define SA_NOT_SUPPORTED 21 /* operation not supported for proto */
#define SA_PROP_SHARE_ONLY 22 /* property valid on share only */
#define SA_NOT_SHARED 23 /* path is not shared */
+#define SA_NO_SUCH_RESOURCE 24 /* resource not found */
+#define SA_RESOURCE_REQUIRED 25 /* resource name is required */
+#define SA_MULTIPLE_ERROR 26 /* multiple protocols reported error */
+#define SA_PATH_IS_SUBDIR 27 /* check_path found path is subdir */
+#define SA_PATH_IS_PARENTDIR 28 /* check_path found path is parent */
/* API Initialization */
#define SA_INIT_SHARE_API 0x0001 /* init share specific interface */
@@ -90,8 +98,9 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
*/
#define SA_MAX_NAME_LEN 100 /* must fit service instance name */
+#define SA_MAX_RESOURCE_NAME 255 /* Maximum length of resource name */
-/* Used in calls to sa_add_share() */
+/* Used in calls to sa_add_share() and sa_add_resource() */
#define SA_SHARE_TRANSIENT 0 /* shared but not across reboot */
#define SA_SHARE_LEGACY 1 /* share is in dfstab only */
#define SA_SHARE_PERMANENT 2 /* share goes to repository */
@@ -105,6 +114,16 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
#define SA_RBAC_VALUE "solaris.smf.value.shares"
/*
+ * Feature set bit definitions
+ */
+
+#define SA_FEATURE_NONE 0x0000 /* no feature flags set */
+#define SA_FEATURE_RESOURCE 0x0001 /* resource names are required */
+#define SA_FEATURE_DFSTAB 0x0002 /* need to manage in dfstab */
+#define SA_FEATURE_ALLOWSUBDIRS 0x0004 /* allow subdirs to be shared */
+#define SA_FEATURE_ALLOWPARDIRS 0x0008 /* allow parent dirs to be shared */
+
+/*
* legacy files
*/
@@ -143,7 +162,6 @@ extern int sa_check_path(sa_group_t, char *, int);
extern int sa_move_share(sa_group_t, sa_share_t);
extern int sa_remove_share(sa_share_t);
extern sa_share_t sa_get_share(sa_group_t, char *);
-extern sa_share_t sa_get_resource(sa_group_t, char *);
extern sa_share_t sa_find_share(sa_handle_t, char *);
extern sa_share_t sa_get_next_share(sa_share_t);
extern char *sa_get_share_attr(sa_share_t, char *);
@@ -152,9 +170,26 @@ extern sa_group_t sa_get_parent_group(sa_share_t);
extern int sa_set_share_attr(sa_share_t, char *, char *);
extern int sa_set_share_description(sa_share_t, char *);
extern int sa_enable_share(sa_group_t, char *);
-extern int sa_disable_share(sa_group_t, char *);
+extern int sa_disable_share(sa_share_t, char *);
extern int sa_is_share(void *);
+/* resource name related */
+extern sa_resource_t sa_find_resource(sa_handle_t, char *);
+extern sa_resource_t sa_get_resource(sa_group_t, char *);
+extern sa_resource_t sa_get_next_resource(sa_resource_t);
+extern sa_share_t sa_get_resource_parent(sa_resource_t);
+extern sa_resource_t sa_get_share_resource(sa_share_t, char *);
+extern sa_resource_t sa_add_resource(sa_share_t, char *, int, int *);
+extern int sa_remove_resource(sa_resource_t);
+extern char *sa_get_resource_attr(sa_resource_t, char *);
+extern int sa_set_resource_attr(sa_resource_t, char *, char *);
+extern int sa_set_resource_description(sa_resource_t, char *);
+extern char *sa_get_resource_description(sa_resource_t);
+extern int sa_enable_resource(sa_resource_t, char *);
+extern int sa_disable_resource(sa_resource_t, char *);
+extern int sa_rename_resource(sa_resource_t, char *);
+extern void sa_fix_resource_name(char *);
+
/* data structure free calls */
extern void sa_free_attr_string(char *);
extern void sa_free_share_description(char *);
@@ -179,6 +214,7 @@ extern int sa_update_property(sa_property_t, char *);
extern int sa_remove_property(sa_property_t);
extern int sa_commit_properties(sa_optionset_t, int);
extern int sa_valid_property(void *, char *, sa_property_t);
+extern int sa_is_persistent(void *);
/* security control */
extern sa_security_t sa_get_security(sa_group_t, char *, char *);
@@ -196,6 +232,7 @@ extern int sa_parse_legacy_options(sa_group_t, char *, char *);
extern char *sa_proto_legacy_format(char *, sa_group_t, int);
extern int sa_is_security(char *, char *);
extern sa_protocol_properties_t sa_proto_get_properties(char *);
+extern uint64_t sa_proto_get_featureset(char *);
extern sa_property_t sa_get_protocol_property(sa_protocol_properties_t, char *);
extern sa_property_t sa_get_next_protocol_property(sa_property_t);
extern int sa_set_protocol_property(sa_property_t, char *);
@@ -206,9 +243,12 @@ extern int sa_add_protocol_property(sa_protocol_properties_t, sa_property_t);
extern int sa_proto_valid_prop(char *, sa_property_t, sa_optionset_t);
extern int sa_proto_valid_space(char *, char *);
extern char *sa_proto_space_alias(char *, char *);
+extern int sa_proto_get_transients(sa_handle_t, char *);
+extern int sa_proto_notify_resource(sa_resource_t, char *);
+extern int sa_proto_change_notify(sa_share_t, char *);
/* handle legacy (dfstab/sharetab) files */
-extern int sa_delete_legacy(sa_share_t);
+extern int sa_delete_legacy(sa_share_t, char *);
extern int sa_update_legacy(sa_share_t, char *);
extern int sa_update_sharetab(sa_share_t, char *);
extern int sa_delete_sharetab(char *, char *);
diff --git a/usr/src/lib/libshare/common/libshare_impl.h b/usr/src/lib/libshare/common/libshare_impl.h
index a454e3ef75..ab661e432f 100644
--- a/usr/src/lib/libshare/common/libshare_impl.h
+++ b/usr/src/lib/libshare/common/libshare_impl.h
@@ -72,6 +72,13 @@ struct sa_plugin_ops {
char *(*sa_space_alias)(char *);
int (*sa_update_legacy)(sa_share_t);
int (*sa_delete_legacy)(sa_share_t);
+ int (*sa_change_notify)(sa_share_t);
+ int (*sa_enable_resource)(sa_resource_t);
+ int (*sa_disable_resource)(sa_resource_t);
+ uint64_t (*sa_features)(void);
+ int (*sa_get_transient_shares)(sa_handle_t); /* add transients */
+ int (*sa_notify_resource)(sa_resource_t);
+ int (*sa_rename_resource)(sa_handle_t, sa_resource_t, char *);
int (*sa_run_command)(int, int, char **); /* proto specific */
int (*sa_command_help)();
};
@@ -97,6 +104,8 @@ extern int sa_proto_unshare(sa_share_t, char *, char *);
extern int sa_proto_valid_prop(char *, sa_property_t, sa_optionset_t);
extern int sa_proto_security_prop(char *, char *);
extern int sa_proto_legacy_opts(char *, sa_group_t, char *);
+extern int sa_proto_share_resource(char *, sa_resource_t);
+extern int sa_proto_unshare_resource(char *, sa_resource_t);
/* internal utility functions */
extern sa_optionset_t sa_get_derived_optionset(sa_group_t, char *, int);
@@ -121,7 +130,7 @@ extern void sa_emptyshare(struct share *sh);
/* ZFS functions */
extern int sa_get_zfs_shares(sa_handle_t, char *);
extern int sa_zfs_update(sa_share_t);
-extern int sa_share_zfs(sa_share_t, char *, share_t *, void *, boolean_t);
+extern int sa_share_zfs(sa_share_t, char *, share_t *, void *, zfs_share_op_t);
extern int sa_sharetab_fill_zfs(sa_share_t share, struct share *sh,
char *proto);
@@ -131,6 +140,8 @@ extern void proto_plugin_fini();
extern int sa_proto_set_property(char *, sa_property_t);
extern int sa_proto_delete_legacy(char *, sa_share_t);
extern int sa_proto_update_legacy(char *, sa_share_t);
+extern int sa_proto_rename_resource(sa_handle_t, char *,
+ sa_resource_t, char *);
#define PL_TYPE_PROPERTY 0
#define PL_TYPE_SECURITY 1
diff --git a/usr/src/lib/libshare/common/libshare_zfs.c b/usr/src/lib/libshare/common/libshare_zfs.c
index 1cfbcbe72a..e0ee84ef8a 100644
--- a/usr/src/lib/libshare/common/libshare_zfs.c
+++ b/usr/src/lib/libshare/common/libshare_zfs.c
@@ -36,7 +36,7 @@
#include <sys/mnttab.h>
#include <sys/mntent.h>
-extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *);
+extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
extern char *sa_fstype(char *);
extern void set_node_attr(void *, char *, char *);
@@ -109,7 +109,7 @@ sa_zfs_fini(sa_handle_impl_t impl_handle)
/*
* get_one_filesystem(zfs_handle_t, data)
*
- * an interator function called while iterating through the ZFS
+ * an iterator function called while iterating through the ZFS
* root. It accumulates into an array of file system handles that can
* be used to derive info about those file systems.
*
@@ -390,7 +390,7 @@ sa_zfs_is_shared(sa_handle_t sahandle, char *path)
}
/*
- * find_or_create_group(groupname, proto, *err)
+ * find_or_create_group(handle, groupname, proto, *err)
*
* While walking the ZFS tree, we need to add shares to a defined
* group. If the group doesn't exist, create it first, making sure it
@@ -424,19 +424,8 @@ find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
if (group != NULL) {
if (proto != NULL) {
optionset = sa_get_optionset(group, proto);
- if (optionset == NULL) {
+ if (optionset == NULL)
optionset = sa_create_optionset(group, proto);
- } else {
- char **protolist;
- int numprotos, i;
- numprotos = sa_get_protocols(&protolist);
- for (i = 0; i < numprotos; i++) {
- optionset = sa_create_optionset(group,
- protolist[i]);
- }
- if (protolist != NULL)
- free(protolist);
- }
}
}
if (err != NULL)
@@ -457,8 +446,8 @@ find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
*/
static sa_group_t
-find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname,
- char *optstring, int *err)
+find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto,
+ char *optstring, int *err)
{
sa_group_t group = NULL;
sa_group_t zfs;
@@ -494,30 +483,58 @@ find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname,
options = strdup(optstring);
if (options != NULL) {
*err = sa_parse_legacy_options(group,
- options, "nfs");
+ options, proto);
+
+ /* If no optionset, add one */
+ if (sa_get_optionset(group, proto) ==
+ NULL)
+ (void) sa_create_optionset(
+ group, proto);
free(options);
} else {
*err = SA_NO_MEMORY;
}
}
+ } else if (proto != NULL && strcmp(proto, "smb") == 0) {
+ *err = SA_PROP_SHARE_ONLY;
}
}
return (group);
}
/*
+ * zfs_construct_resource(share, name, base, dataset)
+ *
+ * Add a resource to the share using name as a template. If name ==
+ * NULL, then construct a name based on the dataset value.
+ * name.
+ */
+static void
+zfs_construct_resource(sa_share_t share, char *dataset)
+{
+ char buff[SA_MAX_RESOURCE_NAME + 1];
+ int ret = SA_OK;
+
+ (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset);
+ sa_fix_resource_name(buff);
+ (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret);
+}
+
+/*
* zfs_inherited(handle, source, sourcestr)
*
- * handle case of inherited sharenfs. Pulled out of sa_get_zfs_shares
+ * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares
* for readability.
*/
static int
zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
- char *shareopts, char *mountpoint)
+ char *shareopts, char *mountpoint, char *proto, char *dataset)
{
int doshopt = 0;
int err = SA_OK;
sa_group_t group;
+ sa_resource_t resource;
+ uint64_t features;
/*
* Need to find the "real" parent sub-group. It may not be
@@ -525,11 +542,18 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
* variable. The real parent not mounted can occur if
* "canmount=off and sharenfs=on".
*/
- group = find_or_create_zfs_subgroup(handle, sourcestr, shareopts,
- &doshopt);
+ group = find_or_create_zfs_subgroup(handle, sourcestr, proto,
+ shareopts, &doshopt);
if (group != NULL) {
- share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
- &err);
+ /*
+ * We may need the first share for resource
+ * prototype. We only care about it if it has a
+ * resource that sets a prefix value.
+ */
+ if (share == NULL)
+ share = _sa_add_share(group, mountpoint,
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
/*
* some options may only be on shares. If the opt
* string contains one of those, we put it just on the
@@ -539,10 +563,27 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
char *options;
options = strdup(shareopts);
if (options != NULL) {
+ set_node_attr(share, "dataset", dataset);
err = sa_parse_legacy_options(share, options,
- "nfs");
+ proto);
+ set_node_attr(share, "dataset", NULL);
free(options);
}
+ if (sa_get_optionset(group, proto) == NULL)
+ (void) sa_create_optionset(group, proto);
+ }
+ features = sa_proto_get_featureset(proto);
+ if (share != NULL && features & SA_FEATURE_RESOURCE) {
+ /*
+ * We have a share and the protocol requires
+ * that at least one resource exist (probably
+ * SMB). We need to make sure that there is at
+ * least one.
+ */
+ resource = sa_get_share_resource(share, NULL);
+ if (resource == NULL) {
+ zfs_construct_resource(share, dataset);
+ }
}
} else {
err = SA_NO_MEMORY;
@@ -557,45 +598,60 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
* of sa_get_zfs_shares for readability.
*/
static int
-zfs_notinherited(sa_group_t group, char *mountpoint, char *shareopts)
+zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint,
+ char *shareopts, char *proto, char *dataset)
{
int err = SA_OK;
- sa_share_t share;
- char *options;
+ sa_resource_t resource;
+ uint64_t features;
set_node_attr(group, "zfs", "true");
- share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, &err);
+ if (share == NULL)
+ share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
+ &err, (uint64_t)SA_FEATURE_NONE);
if (err == SA_OK) {
if (strcmp(shareopts, "on") == 0)
- shareopts = "rw";
-
- options = strdup(shareopts);
- if (options != NULL) {
- err = sa_parse_legacy_options(group, options,
- "nfs");
- free(options);
- }
- if (err == SA_PROP_SHARE_ONLY) {
- /*
- * Same as above, some properties may
- * only be on shares, but due to the
- * ZFS sub-groups being artificial, we
- * sometimes get this and have to deal
- * with it. We do it by attempting to
- * put it on the share.
- */
+ shareopts = "";
+ if (shareopts != NULL) {
+ char *options;
options = strdup(shareopts);
if (options != NULL) {
- err = sa_parse_legacy_options(share,
- options, "nfs");
+ err = sa_parse_legacy_options(group, options,
+ proto);
free(options);
}
+ if (err == SA_PROP_SHARE_ONLY) {
+ /*
+ * Same as above, some properties may
+ * only be on shares, but due to the
+ * ZFS sub-groups being artificial, we
+ * sometimes get this and have to deal
+ * with it. We do it by attempting to
+ * put it on the share.
+ */
+ options = strdup(shareopts);
+ if (options != NULL) {
+ err = sa_parse_legacy_options(share,
+ options, proto);
+ free(options);
+ }
+ }
+ /* unmark the share's changed state */
+ set_node_attr(share, "changed", NULL);
+ }
+ features = sa_proto_get_featureset(proto);
+ if (share != NULL && features & SA_FEATURE_RESOURCE) {
+ /*
+ * We have a share and the protocol requires
+ * that at least one resource exist (probably
+ * SMB). We need to make sure that there is at
+ * least one.
+ */
+ resource = sa_get_share_resource(share, NULL);
+ if (resource == NULL) {
+ zfs_construct_resource(share, dataset);
+ }
}
- /* Mark as the defining node of the subgroup */
- set_node_attr(share, "subgroup", "true");
-
- /* unmark the share's changed state */
- set_node_attr(share, "changed", NULL);
}
return (err);
}
@@ -619,6 +675,46 @@ zfs_grp_error(int err)
}
/*
+ * zfs_process_share(handle, share, mountpoint, proto, source,
+ * shareopts, sourcestr)
+ *
+ * Creates the subgroup, if necessary and adds shares and adds shares
+ * and properties.
+ */
+static int
+zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
+ char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
+ char *sourcestr, char *dataset)
+{
+ int err = SA_OK;
+
+ if (source & ZPROP_SRC_INHERITED) {
+ err = zfs_inherited(handle, share, sourcestr, shareopts,
+ mountpoint, proto, dataset);
+ } else {
+ group = find_or_create_zfs_subgroup(handle, dataset, proto,
+ shareopts, &err);
+ if (group == NULL) {
+ static int err = 0;
+ /*
+ * there is a problem, but we can't do
+ * anything about it at this point so we issue
+ * a warning an move on.
+ */
+ zfs_grp_error(err);
+ err = 1;
+ }
+ set_node_attr(group, "zfs", "true");
+ /*
+ * Add share with local opts via zfs_notinherited.
+ */
+ err = zfs_notinherited(group, share, mountpoint, shareopts,
+ proto, dataset);
+ }
+ return (err);
+}
+
+/*
* sa_get_zfs_shares(handle, groupname)
*
* Walk the mnttab for all zfs mounts and determine which are
@@ -652,7 +748,7 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
if (zfs_libhandle == NULL)
return (SA_SYSTEM_ERR);
- zfsgroup = find_or_create_group(handle, groupname, "nfs", &err);
+ zfsgroup = find_or_create_group(handle, groupname, NULL, &err);
if (zfsgroup == NULL)
return (legacy);
@@ -666,6 +762,7 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
group = zfsgroup;
for (i = 0; i < count; i++) {
char *dataset;
+ int foundnfs = 0;
source = ZPROP_SRC_ALL;
/* If no mountpoint, skip. */
@@ -694,8 +791,9 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
ZFS_MAXPROPLEN, B_FALSE) == 0 &&
strcmp(shareopts, "off") != 0) {
/* it is shared so add to list */
- share = sa_find_share(handle, mountpoint);
err = SA_OK;
+ foundnfs = 1;
+ share = sa_find_share(handle, mountpoint);
if (share != NULL) {
/*
* A zfs file system had been shared
@@ -711,36 +809,36 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
share = NULL;
}
if (err == SA_OK) {
- if (source & ZPROP_SRC_INHERITED) {
- err = zfs_inherited(handle,
- share, sourcestr,
- shareopts, mountpoint);
- } else {
- group = _sa_create_zfs_group(
- zfsgroup, dataset);
- if (group == NULL) {
- static int err = 0;
- /*
- * there is a problem,
- * but we can't do
- * anything about it
- * at this point so we
- * issue a warning an
- * move on.
- */
- zfs_grp_error(err);
- err = 1;
- continue;
- }
- set_node_attr(group, "zfs",
- "true");
- /*
- * Add share with local opts via
- * zfs_notinherited.
- */
- err = zfs_notinherited(group,
- mountpoint, shareopts);
- }
+ err = zfs_process_share(handle, group,
+ share, mountpoint, "nfs", source,
+ shareopts, sourcestr, dataset);
+ }
+ }
+ if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, shareopts,
+ sizeof (shareopts), &source, sourcestr,
+ ZFS_MAXPROPLEN, B_FALSE) == 0 &&
+ strcmp(shareopts, "off") != 0) {
+ /* it is shared so add to list */
+ err = SA_OK;
+ share = sa_find_share(handle, mountpoint);
+ if (share != NULL && !foundnfs) {
+ /*
+ * A zfs file system had been shared
+ * through traditional methods
+ * (share/dfstab or added to a non-zfs
+ * group. Now it has been added to a
+ * ZFS group via the zfs
+ * command. Remove from previous
+ * config and setup with current
+ * options.
+ */
+ err = sa_remove_share(share);
+ share = NULL;
+ }
+ if (err == SA_OK) {
+ err = zfs_process_share(handle, group,
+ share, mountpoint, "smb", source,
+ shareopts, sourcestr, dataset);
}
}
}
@@ -811,6 +909,122 @@ sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
}
/*
+ * add_resources(share, opt)
+ *
+ * Add resource properties to those in "opt". Resources are prefixed
+ * with name=resourcename.
+ */
+static char *
+add_resources(sa_share_t share, char *opt)
+{
+ char *newopt = NULL;
+ char *propstr;
+ sa_resource_t resource;
+
+ newopt = strdup(opt);
+ if (newopt == NULL)
+ return (newopt);
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ char *name;
+ size_t size;
+
+ name = sa_get_resource_attr(resource, "name");
+ if (name == NULL) {
+ free(newopt);
+ return (NULL);
+ }
+ size = strlen(name) + strlen(opt) + sizeof ("name=") + 1;
+ newopt = calloc(1, size);
+ if (newopt != NULL)
+ (void) snprintf(newopt, size, "%s,name=%s", opt, name);
+ free(opt);
+ opt = newopt;
+ propstr = sa_proto_legacy_format("smb", resource, 0);
+ if (propstr == NULL) {
+ free(opt);
+ return (NULL);
+ }
+ size = strlen(propstr) + strlen(opt) + 2;
+ newopt = calloc(1, size);
+ if (newopt != NULL)
+ (void) snprintf(newopt, size, "%s,%s", opt, propstr);
+ free(opt);
+ opt = newopt;
+ }
+ return (opt);
+}
+
+/*
+ * sa_zfs_set_sharesmb(group, path, on)
+ *
+ * Update the "sharesmb" property on the path. If on is true, then set
+ * to the properties on the group or "on" if no properties are
+ * defined. Set to "off" if on is false.
+ */
+
+int
+sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
+{
+ int ret = SA_NOT_IMPLEMENTED;
+ char *command;
+ sa_share_t share;
+
+ /* In case SMB not enabled */
+ if (sa_get_optionset(group, "smb") == NULL)
+ return (SA_NOT_SUPPORTED);
+
+ command = malloc(ZFS_MAXPROPLEN * 2);
+ if (command != NULL) {
+ char *opts = NULL;
+ char *dataset = NULL;
+ FILE *pfile;
+ sa_handle_impl_t impl_handle;
+
+ if (on) {
+ char *newopt;
+
+ share = sa_get_share(group, NULL);
+ opts = sa_proto_legacy_format("smb", share, 1);
+ if (opts != NULL && strlen(opts) == 0) {
+ free(opts);
+ opts = strdup("on");
+ }
+ newopt = add_resources(opts, share);
+ free(opts);
+ opts = newopt;
+ }
+
+ impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ assert(impl_handle != NULL);
+ if (impl_handle != NULL)
+ dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
+ else
+ ret = SA_SYSTEM_ERR;
+
+ if (dataset != NULL) {
+ (void) snprintf(command, ZFS_MAXPROPLEN * 2,
+ "echo %s set sharesmb=\"%s\" %s", COMMAND,
+ opts != NULL ? opts : "off", dataset);
+ pfile = popen(command, "r");
+ if (pfile != NULL) {
+ ret = pclose(pfile);
+ if (ret != 0)
+ ret = SA_SYSTEM_ERR;
+ }
+ }
+ if (opts != NULL)
+ free(opts);
+ if (dataset != NULL)
+ free(dataset);
+ free(command);
+ }
+ return (ret);
+}
+
+/*
* sa_zfs_update(group)
*
* call back to ZFS to update the share if necessary.
@@ -986,7 +1200,7 @@ sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
int
sa_share_zfs(sa_share_t share, char *path, share_t *sh,
- void *exportdata, boolean_t on)
+ void *exportdata, zfs_share_op_t operation)
{
libzfs_handle_t *libhandle;
sa_group_t group;
@@ -1057,7 +1271,7 @@ sa_share_zfs(sa_share_t share, char *path, share_t *sh,
sh->sh_size += j;
SMAX(i, j);
err = zfs_deleg_share_nfs(libhandle, dataset, path,
- exportdata, sh, i, on);
+ exportdata, sh, i, operation);
libzfs_fini(libhandle);
}
free(dataset);
diff --git a/usr/src/lib/libshare/common/libsharecore.c b/usr/src/lib/libshare/common/libsharecore.c
index 503a424cc6..2e39594fc3 100644
--- a/usr/src/lib/libshare/common/libsharecore.c
+++ b/usr/src/lib/libshare/common/libsharecore.c
@@ -51,6 +51,7 @@
#include <sys/param.h>
#include <signal.h>
#include <libintl.h>
+#include <dirent.h>
#include <sharefs/share.h>
#include "sharetab.h"
@@ -88,7 +89,7 @@ extern char *get_token(char *);
static void dfs_free_list(xfs_sharelist_t *);
/* prototypes */
void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
-extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *);
+extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
extern sa_group_t _sa_create_group(sa_handle_impl_t, char *);
static void outdfstab(FILE *, xfs_sharelist_t *);
extern int _sa_remove_optionset(sa_optionset_t);
@@ -563,13 +564,13 @@ sa_comment_line(char *line, char *err)
}
/*
- * sa_delete_legacy(share)
+ * sa_delete_legacy(share, protocol)
*
* Delete the specified share from the legacy config file.
*/
int
-sa_delete_legacy(sa_share_t share)
+sa_delete_legacy(sa_share_t share, char *protocol)
{
FILE *dfstab;
int err;
@@ -580,39 +581,54 @@ sa_delete_legacy(sa_share_t share)
sa_group_t parent;
sigset_t old;
+ /*
+ * Protect against shares that don't have paths. This is not
+ * really an error at this point.
+ */
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (ret);
+
dfstab = open_dfstab(SA_LEGACY_DFSTAB);
if (dfstab != NULL) {
(void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8);
sablocksigs(&old);
- path = sa_get_share_attr(share, "path");
parent = sa_get_parent_group(share);
if (parent != NULL) {
(void) lockf(fileno(dfstab), F_LOCK, 0);
list = getdfstab(dfstab);
rewind(dfstab);
- for (optionset = sa_get_optionset(parent, NULL);
- optionset != NULL;
- optionset = sa_get_next_optionset(optionset)) {
- char *proto = sa_get_optionset_attr(optionset,
- "type");
- if (list != NULL && proto != NULL)
+ if (protocol != NULL) {
+ if (list != NULL)
list = remdfsentry(list, path,
- proto);
- if (proto == NULL)
- ret = SA_NO_MEMORY;
- /*
- * May want to only do the dfstab if
- * this call returns NOT IMPLEMENTED
- * but it shouldn't hurt.
- */
- if (ret == SA_OK) {
- err = sa_proto_delete_legacy(proto,
- share);
- if (err != SA_NOT_IMPLEMENTED)
- ret = err;
+ protocol);
+ } else {
+ for (optionset = sa_get_optionset(parent, NULL);
+ optionset != NULL;
+ optionset =
+ sa_get_next_optionset(optionset)) {
+ char *proto = sa_get_optionset_attr(
+ optionset, "type");
+
+ if (list != NULL && proto != NULL)
+ list = remdfsentry(list, path,
+ proto);
+ if (proto == NULL)
+ ret = SA_NO_MEMORY;
+ /*
+ * may want to only do the dfstab if
+ * this call returns NOT IMPLEMENTED
+ * but it shouldn't hurt.
+ */
+ if (ret == SA_OK) {
+ err = sa_proto_delete_legacy(
+ proto, share);
+ if (err != SA_NOT_IMPLEMENTED)
+ ret = err;
+ }
+ if (proto != NULL)
+ sa_free_attr_string(proto);
}
- if (proto != NULL)
- sa_free_attr_string(proto);
}
outdfstab(dfstab, list);
if (list != NULL)
@@ -623,13 +639,16 @@ sa_delete_legacy(sa_share_t share)
(void) fsync(fileno(dfstab));
saunblocksigs(&old);
(void) fclose(dfstab);
- sa_free_attr_string(path);
} else {
if (errno == EACCES || errno == EPERM)
ret = SA_NO_PERMISSION;
else
ret = SA_CONFIG_ERR;
}
+
+ if (path != NULL)
+ sa_free_attr_string(path);
+
return (ret);
}
@@ -639,7 +658,7 @@ sa_delete_legacy(sa_share_t share)
* There is an assumption that dfstab will be the most common form of
* legacy configuration file for shares, but not the only one. Because
* of that, dfstab handling is done in the main code with calls to
- * this function and protocol specific calls to deal with formating
+ * this function and protocol specific calls to deal with formatting
* options into dfstab/share compatible syntax. Since not everything
* will be dfstab, there is a provision for calling a protocol
* specific plugin interface that allows the protocol plugin to do its
@@ -655,10 +674,16 @@ sa_update_legacy(sa_share_t share, char *proto)
char *path;
sigset_t old;
char *persist;
+ uint64_t features;
ret = sa_proto_update_legacy(proto, share);
if (ret != SA_NOT_IMPLEMENTED)
return (ret);
+
+ features = sa_proto_get_featureset(proto);
+ if (!(features & SA_FEATURE_DFSTAB))
+ return (ret);
+
/* do the dfstab format */
persist = sa_get_share_attr(share, "type");
/*
@@ -748,6 +773,21 @@ sa_is_share(void *object)
}
return (0);
}
+/*
+ * sa_is_resource(object)
+ *
+ * returns true of the object is of type "share".
+ */
+
+int
+sa_is_resource(void *object)
+{
+ if (object != NULL) {
+ if (strcmp((char *)((xmlNodePtr)object)->name, "resource") == 0)
+ return (1);
+ }
+ return (0);
+}
/*
* _sa_remove_property(property)
@@ -1392,6 +1432,7 @@ parse_sharetab(sa_handle_t handle)
sa_group_t lgroup;
char *groupname;
int legacy = 0;
+ char shareopts[MAXNAMLEN];
list = get_share_list(&err);
if (list == NULL)
@@ -1410,7 +1451,9 @@ parse_sharetab(sa_handle_t handle)
* share with no arguments.
*/
set_node_attr(share, "shared", "true");
- set_node_attr(share, "shareopts", tmplist->options);
+ (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s",
+ tmplist->fstype);
+ set_node_attr(share, shareopts, tmplist->options);
continue;
}
@@ -1426,9 +1469,9 @@ parse_sharetab(sa_handle_t handle)
*groupname++ = '\0';
group = sa_get_group(handle, groupname);
if (group != NULL) {
- share = _sa_add_share(group,
- tmplist->path,
- SA_SHARE_TRANSIENT, &err);
+ share = _sa_add_share(group, tmplist->path,
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
} else {
/*
* While this case shouldn't
@@ -1447,7 +1490,7 @@ parse_sharetab(sa_handle_t handle)
*/
share = _sa_add_share(lgroup,
tmplist->path, SA_SHARE_TRANSIENT,
- &err);
+ &err, (uint64_t)SA_FEATURE_NONE);
}
} else {
if (sa_zfs_is_shared(handle, tmplist->path)) {
@@ -1472,11 +1515,12 @@ parse_sharetab(sa_handle_t handle)
if (group != NULL) {
share = _sa_add_share(group,
tmplist->path, SA_SHARE_TRANSIENT,
- &err);
+ &err, (uint64_t)SA_FEATURE_NONE);
}
} else {
share = _sa_add_share(lgroup, tmplist->path,
- SA_SHARE_TRANSIENT, &err);
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
}
}
if (share == NULL)
@@ -1517,12 +1561,22 @@ int
gettransients(sa_handle_impl_t ihandle, xmlNodePtr *root)
{
int legacy = 0;
+ int numproto;
+ char **protocols = NULL;
+ int i;
if (root != NULL) {
if (*root == NULL)
*root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
- if (*root != NULL)
+ if (*root != NULL) {
legacy = parse_sharetab(ihandle);
+ numproto = sa_get_protocols(&protocols);
+ for (i = 0; i < numproto; i++)
+ legacy |= sa_proto_get_transients(
+ (sa_handle_t)ihandle, protocols[i]);
+ if (protocols != NULL)
+ free(protocols);
+ }
}
return (legacy);
}
@@ -1630,7 +1684,7 @@ sa_free_fstype(char *type)
* Work backward to the top of the share object tree and start
* copying protocol specific optionsets into a newly created
* optionset that doesn't have a parent (it will be freed
- * later). This provides for the property inheritence model. That
+ * later). This provides for the property inheritance model. That
* is, properties closer to the share take precedence over group
* level. This also provides for groups of groups in the future.
*/
@@ -1719,7 +1773,7 @@ sa_free_derived_optionset(sa_optionset_t optionset)
* Find all the security types set for this object. This is
* preliminary to getting a derived security set. The return value is an
* optionset containg properties which are the sectype values found by
- * walking up the XML document struture. The returned optionset
+ * walking up the XML document structure. The returned optionset
* is a derived optionset.
*
* If hier is 0, only look at object. If non-zero, walk up the tree.
@@ -1885,6 +1939,19 @@ sa_fillshare(sa_share_t share, char *proto, struct share *sh)
sa_group_t group;
char *buff;
char *zfs;
+ sa_resource_t resource;
+ char *rsrcname = NULL;
+ char *defprop;
+
+ /*
+ * We only want to deal with the path level shares for the
+ * sharetab file. If a resource, get the parent.
+ */
+ if (sa_is_resource(share)) {
+ resource = (sa_resource_t)share;
+ share = sa_get_resource_parent(resource);
+ rsrcname = sa_get_resource_attr(resource, "name");
+ }
group = sa_get_parent_group(share);
if (group != NULL) {
@@ -1912,41 +1979,48 @@ sa_fillshare(sa_share_t share, char *proto, struct share *sh)
sa_free_attr_string(value);
}
- value = sa_get_share_attr(share, "resource");
- if (value != NULL || groupname != NULL) {
+ if (rsrcname != NULL || groupname != NULL) {
int len = 0;
- if (value != NULL)
- len += strlen(value);
+ if (rsrcname != NULL)
+ len += strlen(rsrcname);
if (groupname != NULL)
len += strlen(groupname);
len += 3; /* worst case */
buff = malloc(len);
(void) snprintf(buff, len, "%s%s%s",
- (value != NULL && strlen(value) > 0) ? value : "-",
+ (rsrcname != NULL &&
+ strlen(rsrcname) > 0) ? rsrcname : "-",
groupname != NULL ? "@" : "",
groupname != NULL ? groupname : "");
sh->sh_res = buff;
- if (value != NULL)
- sa_free_attr_string(value);
- if (groupname != NULL) {
+ if (rsrcname != NULL)
+ sa_free_attr_string(rsrcname);
+ if (groupname != NULL)
sa_free_attr_string(groupname);
- groupname = NULL;
- }
} else {
sh->sh_res = strdup("-");
}
+ /*
+ * Get correct default prop string. NFS uses "rw", others use
+ * "".
+ */
+ if (strcmp(proto, "nfs") != 0)
+ defprop = "\"\"";
+ else
+ defprop = "rw";
+
sh->sh_fstype = strdup(proto);
value = sa_proto_legacy_format(proto, share, 1);
if (value != NULL) {
if (strlen(value) > 0)
sh->sh_opts = strdup(value);
else
- sh->sh_opts = strdup("rw");
+ sh->sh_opts = strdup(defprop);
free(value);
} else {
- sh->sh_opts = strdup("rw");
+ sh->sh_opts = strdup(defprop);
}
value = sa_get_share_description(share);
@@ -2041,3 +2115,67 @@ sa_delete_sharetab(char *path, char *proto)
return (ret);
}
+/*
+ * sa_fix_resource_name(path)
+ *
+ * change all illegal characters to something else. For now, all get
+ * converted to '_' and the leading '/' is stripped off. This is used
+ * to construct an resource name (SMB share name) that is valid.
+ * Caller must pass a valid path.
+ */
+void
+sa_fix_resource_name(char *path)
+{
+ char *cp;
+ size_t len;
+
+ assert(path != NULL);
+
+ /* make sure we are appropriate length */
+ cp = path;
+ if (*cp == '/')
+ cp++; /* skip leading slash */
+ while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) {
+ cp = strchr(cp, '/');
+ if (cp != NULL)
+ cp++;
+ }
+ /* two cases - cp == NULL and cp is substring of path */
+ if (cp == NULL) {
+ /* just take last SA_MAX_RESOURCE_NAME chars */
+ len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME;
+ (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME);
+ path[SA_MAX_RESOURCE_NAME] = '\0';
+ } else {
+ len = strlen(cp) + 1;
+ (void) memmove(path, cp, len);
+ }
+
+ /*
+ * Don't want any of the characters that are not allowed
+ * in an SMB share name. Replace them with '_'.
+ */
+ while (*path) {
+ switch (*path) {
+ case '/':
+ case '"':
+ case '\\':
+ case '[':
+ case ']':
+ case ':':
+ case '|':
+ case '<':
+ case '>':
+ case '+':
+ case ';':
+ case ',':
+ case '?':
+ case '*':
+ case '=':
+ case '\t':
+ *path = '_';
+ break;
+ }
+ path++;
+ }
+}
diff --git a/usr/src/lib/libshare/common/mapfile-vers b/usr/src/lib/libshare/common/mapfile-vers
index 317623b3b4..f7dfde5730 100644
--- a/usr/src/lib/libshare/common/mapfile-vers
+++ b/usr/src/lib/libshare/common/mapfile-vers
@@ -106,9 +106,28 @@ SUNWprivate {
sa_delete_legacy;
sa_free_derived_security;
sa_enable_share;
+ sa_enable_resource;
sa_create_group;
sa_valid_protocol;
sa_find_group_handle;
+ sa_add_resource;
+ sa_remove_resource;
+ sa_rename_resource;
+ sa_get_resource;
+ sa_get_next_resource;
+ sa_get_resource_attr;
+ sa_set_resource_attr;
+ sa_get_share_resource;
+ sa_get_resource_parent;
+ sa_find_resource;
+ sa_proto_change_notify;
+ sa_proto_notify_resource;
+ sa_disable_resource;
+ sa_proto_get_featureset;
+ sa_is_persistent;
+ sa_set_resource_description;
+ sa_get_resource_description;
+ sa_fix_resource_name;
local:
*;
};
diff --git a/usr/src/lib/libshare/common/plugin.c b/usr/src/lib/libshare/common/plugin.c
index 4079e24ff7..08856a8951 100644
--- a/usr/src/lib/libshare/common/plugin.c
+++ b/usr/src/lib/libshare/common/plugin.c
@@ -64,7 +64,7 @@ void proto_plugin_fini();
* /usr/lib/fs/nfs/libshare_nfs.so. The protocol specific directory
* would have a modules with name libshare_<proto>.so. If one is
* found, initialize it and add to the internal list of
- * protocols. These are used for protocol specifici operations.
+ * protocols. These are used for protocol specific operations.
*/
int
@@ -242,9 +242,9 @@ sa_proto_share(char *proto, sa_share_t share)
}
/*
- * sa_proto_unshare(proto, path)
+ * sa_proto_unshare(proto, share)
*
- * Deactivate (unshare) the path for this protocol.
+ * Deactivate (unshare) the share for this protocol.
*/
int
@@ -259,6 +259,52 @@ sa_proto_unshare(sa_share_t share, char *proto, char *path)
}
/*
+ * sa_proto_share_resource(char *proto, sa_resource_t resource)
+ *
+ * For protocols that actually enable at the resource level, do the
+ * protocol specific resource enable. If it doesn't, return an error.
+ * Note that the resource functions are optional so can return
+ * SA_NOT_SUPPORTED.
+ */
+
+int
+sa_proto_share_resource(char *proto, sa_resource_t resource)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_INVALID_PROTOCOL;
+
+ if (ops != NULL) {
+ if (ops->sa_enable_resource != NULL)
+ ret = ops->sa_enable_resource(resource);
+ else
+ ret = SA_NOT_SUPPORTED;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_unshare_resource(char *proto, sa_resource_t resource)
+ *
+ * For protocols that actually disable at the resource level, do the
+ * protocol specific resource disable. If it doesn't, return an error.
+ */
+
+int
+sa_proto_unshare_resource(char *proto, sa_resource_t resource)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_INVALID_PROTOCOL;
+
+ if (ops != NULL) {
+ if (ops->sa_disable_resource != NULL)
+ ret = ops->sa_disable_resource(resource);
+ else
+ ret = SA_NOT_SUPPORTED;
+ }
+ return (ret);
+}
+
+/*
* sa_proto_valid_prop(proto, prop, opt)
*
* Check to see if the specified prop is valid for this protocol.
@@ -395,7 +441,7 @@ sa_proto_get_properties(char *proto)
/*
* sa_proto_set_property(proto, prop)
*
- * Update the protocol specifiec property.
+ * Update the protocol specific property.
*/
int
@@ -467,16 +513,127 @@ int
sa_proto_delete_legacy(char *proto, sa_share_t share)
{
struct sa_plugin_ops *ops = find_protocol(proto);
- int ret = SA_OK;
+ int ret = SA_NOT_IMPLEMENTED;
if (ops != NULL) {
if (ops->sa_delete_legacy != NULL)
ret = ops->sa_delete_legacy(share);
- } else {
- if (proto != NULL)
- ret = SA_NOT_IMPLEMENTED;
- else
+ } else if (proto == NULL) {
+ ret = SA_INVALID_PROTOCOL;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_change_notify(share, char *protocol)
+ *
+ * Notify the protocol that a change has been made to the share
+ */
+
+int
+sa_proto_change_notify(sa_share_t share, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_NOT_IMPLEMENTED;
+
+ if (ops != NULL) {
+ if (ops->sa_change_notify != NULL)
+ ret = ops->sa_change_notify(share);
+ } else if (proto == NULL) {
ret = SA_INVALID_PROTOCOL;
}
return (ret);
}
+
+/*
+ * sa_proto_notify_resource(resource, char *protocol)
+ *
+ * Notify the protocol that a change has been made to the share
+ */
+
+int
+sa_proto_notify_resource(sa_resource_t resource, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_NOT_IMPLEMENTED;
+
+ if (ops != NULL) {
+ if (ops->sa_notify_resource != NULL)
+ ret = ops->sa_notify_resource(resource);
+ } else if (proto == NULL) {
+ ret = SA_INVALID_PROTOCOL;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_get_featureset(protocol)
+ *
+ * Get bitmask of defined features of the protocol. These are
+ * primarily things like SA_FEATURE_RESOURCE (shares are by resource
+ * name rather than path) and other operational features that affect
+ * behavior.
+ */
+
+uint64_t
+sa_proto_get_featureset(char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ uint64_t ret = 0;
+
+ if (ops != NULL) {
+ if (ops->sa_features != NULL)
+ ret = ops->sa_features();
+ }
+ /* if not implemented, zero is valid */
+ return (ret);
+}
+
+/*
+ * sa_proto_get_transients(sa_handle_t)
+ *
+ * Called to get any protocol specific transient shares. NFS doesn't
+ * use this since the info is in sharetab which is processed as a
+ * common transient store.
+ *
+ * The protocol plugin should verify that the share isn't in the
+ * repository and then add it as a transient.
+ *
+ * Not having an entry is not a problem. It returns 0 in that case.
+ */
+
+int
+sa_proto_get_transients(sa_handle_t handle, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = 0;
+
+ if (ops != NULL) {
+ if (ops->sa_get_transient_shares != NULL)
+ ret = ops->sa_get_transient_shares(handle);
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_rename_resource(sa_handle_t, proto, sa_resource_t, newname)
+ *
+ * Protocols may need to know when a resource has changed names in
+ * order to notify clients. This must be done "before" the name in the
+ * resource has been changed. Not being implemented is not a problem.
+ */
+
+int
+sa_proto_rename_resource(sa_handle_t handle, char *proto,
+ sa_resource_t resource, char *newname)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_OK;
+
+ if (ops != NULL) {
+ if (ops->sa_rename_resource != NULL)
+ ret = ops->sa_rename_resource(handle, resource,
+ newname);
+ }
+ return (ret);
+}
diff --git a/usr/src/lib/libshare/common/scfutil.c b/usr/src/lib/libshare/common/scfutil.c
index 05421d605b..344d3729bb 100644
--- a/usr/src/lib/libshare/common/scfutil.c
+++ b/usr/src/lib/libshare/common/scfutil.c
@@ -35,6 +35,7 @@
#include "libshare_impl.h"
#include "scfutil.h"
#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include <uuid/uuid.h>
#include <sys/param.h>
@@ -396,7 +397,8 @@ out:
static char *share_attr[] = {
"path",
"id",
- "resource",
+ "drive-letter",
+ "exclude",
NULL,
};
@@ -411,6 +413,52 @@ is_share_attr(char *name)
}
/*
+ * _sa_make_resource(node, valuestr)
+ *
+ * Make a resource node on the share node. The valusestr will either
+ * be old format (SMF acceptable string) or new format (pretty much an
+ * arbitrary string with "nnn:" prefixing in order to persist
+ * mapping). The input valuestr will get modified in place. This is
+ * only used in SMF repository parsing. A possible third field will be
+ * a "description" string.
+ */
+
+static void
+_sa_make_resource(xmlNodePtr node, char *valuestr)
+{
+ char *idx;
+ char *name;
+ char *description = NULL;
+
+ idx = valuestr;
+ name = strchr(valuestr, ':');
+ if (name == NULL) {
+ /* this is old form so give an index of "0" */
+ idx = "0";
+ name = valuestr;
+ } else {
+ /* NUL the ':' and move past it */
+ *name++ = '\0';
+ /* There could also be a description string */
+ description = strchr(name, ':');
+ if (description != NULL)
+ *description++ = '\0';
+ }
+ node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
+ if (node != NULL) {
+ xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
+ xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
+ /* SMF values are always persistent */
+ xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
+ if (description != NULL && strlen(description) > 0) {
+ (void) xmlNewChild(node, NULL, (xmlChar *)"description",
+ (xmlChar *)description);
+ }
+ }
+}
+
+
+/*
* sa_share_from_pgroup
*
* Extract the share definition from the share property group. We do
@@ -490,34 +538,70 @@ sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
vallen) >= 0) {
ret = SA_OK;
}
+ } else if (strcmp(name, "resource") == 0) {
+ ret = SA_OK;
}
}
- if (ret == SA_OK) {
+ if (ret != SA_OK)
+ continue;
+ /*
+ * Check that we have the "path" property in
+ * name. The string in name will always be nul
+ * terminated if scf_property_get_name()
+ * succeeded.
+ */
+ if (strcmp(name, "path") == 0)
+ have_path = 1;
+ if (is_share_attr(name)) {
/*
- * Check that we have the "path" property in
- * name. The string in name will always be nul
- * terminated if scf_property_get_name()
- * succeeded.
+ * If a share attr, then simple -
+ * usually path and id name
*/
- if (strcmp(name, "path") == 0)
- have_path = 1;
- if (is_share_attr(name)) {
- /*
- * If a share attr, then simple -
- * usually path and resource name
- */
- xmlSetProp(node, (xmlChar *)name,
- (xmlChar *)valuestr);
- } else {
- if (strcmp(name, "description") == 0) {
- /* We have a description node */
- xmlNodePtr desc;
- desc = xmlNewChild(node, NULL,
- (xmlChar *)"description", NULL);
- if (desc != NULL)
- xmlNodeSetContent(desc,
- (xmlChar *)valuestr);
+ xmlSetProp(node, (xmlChar *)name,
+ (xmlChar *)valuestr);
+ } else if (strcmp(name, "resource") == 0) {
+ /*
+ * Resource names handled differently since
+ * there can be multiple on each share. The
+ * "resource" id must be preserved since this
+ * will be used by some protocols in mapping
+ * "property spaces" to names and is always
+ * used to create SMF property groups specific
+ * to resources. CIFS needs this. The first
+ * value is present so add and then loop for
+ * any additional. Since this is new and
+ * previous values may exist, handle
+ * conversions.
+ */
+ scf_iter_t *viter;
+ viter = scf_iter_create(handle->handle);
+ if (viter != NULL &&
+ scf_iter_property_values(viter, prop) == 0) {
+ while (scf_iter_next_value(viter, value) > 0) {
+ /* Have a value so process it */
+ if (scf_value_get_ustring(value,
+ valuestr, vallen) >= 0) {
+ /* have a ustring */
+ _sa_make_resource(node,
+ valuestr);
+ } else if (scf_value_get_astring(value,
+ valuestr, vallen) >= 0) {
+ /* have an astring */
+ _sa_make_resource(node,
+ valuestr);
+ }
}
+ scf_iter_destroy(viter);
+ }
+ } else {
+ if (strcmp(name, "description") == 0) {
+ /* We have a description node */
+ xmlNodePtr desc;
+ desc = xmlNewChild(node, NULL,
+ (xmlChar *)"description", NULL);
+ if (desc != NULL)
+ xmlNodeSetContent(desc,
+ (xmlChar *)valuestr);
}
}
}
@@ -583,7 +667,34 @@ find_share_by_id(sa_handle_t handle, char *shareid)
}
/*
- * sa_share_props_from_pgroup(root, handle, pg, id)
+ * find_resource_by_index(share, index)
+ *
+ * Search the resource records on the share for the id index.
+ */
+static sa_resource_t
+find_resource_by_index(sa_share_t share, char *index)
+{
+ sa_resource_t resource;
+ sa_resource_t found = NULL;
+ char *id;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL && found == NULL;
+ resource = sa_get_next_resource(resource)) {
+ id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
+ if (id != NULL) {
+ if (strcmp(id, index) == 0) {
+ /* found it so save in "found" */
+ found = resource;
+ }
+ sa_free_attr_string(id);
+ }
+ }
+ return (found);
+}
+
+/*
+ * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
*
* Extract share properties from the SMF property group. More sanity
* checks are done and the share object is created. We ignore some
@@ -639,6 +750,7 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
/* not a valid proto (null) */
return (ret);
}
+
sectype = strchr(proto, '_');
if (sectype != NULL)
*sectype++ = '\0';
@@ -664,10 +776,35 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
if (sectype == NULL)
node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
else {
- node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL);
- if (node != NULL)
- xmlSetProp(node, (xmlChar *)"sectype",
- (xmlChar *)sectype);
+ if (isdigit((int)*sectype)) {
+ sa_resource_t resource;
+ /*
+ * If sectype[0] is a digit, then it is an index into
+ * the resource names. We need to find a resource
+ * record and then get the properties into an
+ * optionset. The optionset becomes the "node" and the
+ * rest is hung off of the share.
+ */
+ resource = find_resource_by_index(share, sectype);
+ if (resource != NULL) {
+ node = xmlNewChild(resource, NULL,
+ (xmlChar *)"optionset", NULL);
+ } else {
+ /* this shouldn't happen */
+ ret = SA_SYSTEM_ERR;
+ }
+ } else {
+ /*
+ * If not a digit, then it is a security type
+ * (alternate option space). Security types start with
+ * an alphabetic.
+ */
+ node = xmlNewChild(root, NULL, (xmlChar *)"security",
+ NULL);
+ if (node != NULL)
+ xmlSetProp(node, (xmlChar *)"sectype",
+ (xmlChar *)sectype);
+ }
}
if (node == NULL) {
ret = SA_NO_MEMORY;
@@ -685,7 +822,7 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
if (iter == NULL || value == NULL || prop == NULL || name == NULL)
goto out;
- /* Iterate over the share pg properties */
+ /* iterate over the share pg properties */
if (scf_iter_pg_properties(iter, pg) == 0) {
while (scf_iter_next_property(iter, prop) > 0) {
ret = SA_SYSTEM_ERR; /* assume the worst */
@@ -897,7 +1034,7 @@ out:
* sa_extract_defaults(root, handle, instance)
*
* Local function to find the default properties that live in the
- * default instance's "operation" proprerty group.
+ * default instance's "operation" property group.
*/
static void
@@ -946,7 +1083,7 @@ out:
/*
- * sa_get_config(handle, root, doc, sahandlec)
+ * sa_get_config(handle, root, doc, sahandle)
*
* Walk the SMF repository for /network/shares/group and find all the
* instances. These become group names. Then add the XML structure
@@ -1276,6 +1413,147 @@ sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
}
/*
+ * check_resource(share)
+ *
+ * Check to see if share has any persistent resources. We don't want
+ * to save if they are all transient.
+ */
+static int
+check_resource(sa_share_t share)
+{
+ sa_resource_t resource;
+ int ret = B_FALSE;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL && ret == B_FALSE;
+ resource = sa_get_next_resource(resource)) {
+ char *type;
+ type = sa_get_resource_attr(resource, "type");
+ if (type != NULL) {
+ if (strcmp(type, "transient") != 0) {
+ ret = B_TRUE;
+ }
+ sa_free_attr_string(type);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_set_resource_property(handle, prop, value)
+ *
+ * set a property transaction entry into the pending SMF
+ * transaction. We don't want to include any transient resources
+ */
+
+static int
+sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
+{
+ int ret = SA_OK;
+ scf_value_t *value;
+ scf_transaction_entry_t *entry;
+ sa_resource_t resource;
+ char *valstr;
+ char *idstr;
+ char *description;
+ char *propstr = NULL;
+ size_t strsize;
+
+ /* don't bother if no persistent resources */
+ if (check_resource(share) == B_FALSE)
+ return (ret);
+
+ /*
+ * properties must be set in transactions and don't take
+ * effect until the transaction has been ended/committed.
+ */
+ entry = scf_entry_create(handle->handle);
+ if (entry == NULL)
+ return (SA_SYSTEM_ERR);
+
+ if (scf_transaction_property_change(handle->trans, entry,
+ "resource", SCF_TYPE_ASTRING) != 0 &&
+ scf_transaction_property_new(handle->trans, entry,
+ "resource", SCF_TYPE_ASTRING) != 0) {
+ scf_entry_destroy(entry);
+ return (SA_SYSTEM_ERR);
+
+ }
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ value = scf_value_create(handle->handle);
+ if (value == NULL) {
+ ret = SA_NO_MEMORY;
+ break;
+ }
+ /* Get size of complete string */
+ valstr = sa_get_resource_attr(resource, "name");
+ idstr = sa_get_resource_attr(resource, "id");
+ description = sa_get_resource_description(resource);
+ strsize = (valstr != NULL) ? strlen(valstr) : 0;
+ strsize += (idstr != NULL) ? strlen(idstr) : 0;
+ strsize += (description != NULL) ? strlen(description) : 0;
+ if (strsize > 0) {
+ strsize += 3; /* add nul and ':' */
+ propstr = (char *)malloc(strsize);
+ if (propstr == NULL) {
+ scf_value_destroy(value);
+ ret = SA_NO_MEMORY;
+ goto err;
+ }
+ if (idstr == NULL)
+ (void) snprintf(propstr, strsize, "%s",
+ valstr ? valstr : "");
+ else
+ (void) snprintf(propstr, strsize, "%s:%s:%s",
+ idstr ? idstr : "", valstr ? valstr : "",
+ description ? description : "");
+ if (scf_value_set_astring(value, propstr) != 0) {
+ ret = SA_SYSTEM_ERR;
+ free(propstr);
+ scf_value_destroy(value);
+ break;
+ }
+ if (scf_entry_add_value(entry, value) != 0) {
+ ret = SA_SYSTEM_ERR;
+ free(propstr);
+ scf_value_destroy(value);
+ break;
+ }
+ /* the value is in the transaction */
+ value = NULL;
+ free(propstr);
+ }
+err:
+ if (valstr != NULL)
+ sa_free_attr_string(valstr);
+ if (idstr != NULL)
+ sa_free_attr_string(idstr);
+ if (description != NULL)
+ sa_free_share_description(description);
+ }
+ /* the entry is in the transaction */
+ entry = NULL;
+
+ if (ret == SA_SYSTEM_ERR) {
+ switch (scf_error()) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SA_NO_PERMISSION;
+ break;
+ }
+ }
+ /*
+ * cleanup if there were any errors that didn't leave
+ * these values where they would be cleaned up later.
+ */
+ if (entry != NULL)
+ scf_entry_destroy(entry);
+
+ return (ret);
+}
+
+/*
* sa_commit_share(handle, group, share)
*
* Commit this share to the repository.
@@ -1288,7 +1566,6 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
int ret = SA_OK;
char *groupname;
char *name;
- char *resource;
char *description;
char *sharename;
ssize_t proplen;
@@ -1371,15 +1648,35 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
}
if (ret == SA_OK) {
- resource = sa_get_share_attr(share,
- "resource");
- if (resource != NULL) {
+ name = sa_get_share_attr(share, "drive-letter");
+ if (name != NULL) {
+ /* A drive letter may exist for SMB */
+ ret = sa_set_property(handle,
+ "drive-letter", name);
+ sa_free_attr_string(name);
+ }
+ }
+ if (ret == SA_OK) {
+ name = sa_get_share_attr(share, "exclude");
+ if (name != NULL) {
+ /*
+ * In special cases need to
+ * exclude proto enable.
+ */
ret = sa_set_property(handle,
- "resource", resource);
- sa_free_attr_string(resource);
+ "exclude", name);
+ sa_free_attr_string(name);
}
}
if (ret == SA_OK) {
+ /*
+ * If there are resource names, bundle them up
+ * and save appropriately.
+ */
+ ret = sa_set_resource_property(handle, share);
+ }
+
+ if (ret == SA_OK) {
description = sa_get_share_description(share);
if (description != NULL) {
ret = sa_set_property(handle,
@@ -1414,6 +1711,49 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
/*
+ * remove_resources(handle, share, shareid)
+ *
+ * If the share has resources, remove all of them and their
+ * optionsets.
+ */
+static int
+remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
+{
+ sa_resource_t resource;
+ sa_optionset_t opt;
+ char *proto;
+ char *id;
+ ssize_t proplen;
+ char *propstring;
+ int ret = SA_OK;
+
+ proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
+ propstring = malloc(proplen);
+ if (propstring == NULL)
+ return (SA_NO_MEMORY);
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL; resource = sa_get_next_resource(resource)) {
+ id = sa_get_resource_attr(resource, "id");
+ if (id == NULL)
+ continue;
+ for (opt = sa_get_optionset(resource, NULL);
+ opt != NULL; opt = sa_get_next_optionset(resource)) {
+ proto = sa_get_optionset_attr(opt, "type");
+ if (proto != NULL) {
+ (void) snprintf(propstring, proplen,
+ "%s_%s_%s", shareid, proto, id);
+ ret = sa_delete_pgroup(handle, propstring);
+ sa_free_attr_string(proto);
+ }
+ }
+ sa_free_attr_string(id);
+ }
+ free(propstring);
+ return (ret);
+}
+
+/*
* sa_delete_share(handle, group, share)
*
* Remove the specified share from the group (and service instance).
@@ -1444,6 +1784,8 @@ sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
ret = sa_get_instance(handle, groupname);
if (ret == SA_OK) {
+ /* If a share has resources, remove them */
+ ret = remove_resources(handle, share, shareid);
/* If a share has properties, remove them */
ret = sa_delete_pgroup(handle, shareid);
for (opt = sa_get_optionset(share, NULL);
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c
index a7426ab841..0a3175de70 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c
@@ -73,6 +73,7 @@ static int nfs_set_proto_prop(sa_property_t);
static sa_protocol_properties_t nfs_get_proto_set();
static char *nfs_get_status();
static char *nfs_space_alias(char *);
+static uint64_t nfs_features();
/*
* ops vector that provides the protocol specific info and operations
@@ -95,7 +96,14 @@ struct sa_plugin_ops sa_plugin_ops = {
nfs_get_proto_set,
nfs_get_status,
nfs_space_alias,
- NULL,
+ NULL, /* update_legacy */
+ NULL, /* delete_legacy */
+ NULL, /* change_notify */
+ NULL, /* enable_resource */
+ NULL, /* disable_resource */
+ nfs_features,
+ NULL, /* transient shares */
+ NULL, /* notify resource */
NULL
};
@@ -543,13 +551,16 @@ nfs_parse_legacy_options(sa_group_t group, char *options)
optionset = sa_create_optionset(group, "nfs");
} else {
/*
- * have an existing optionset so we need to compare
- * options in order to detect errors. For now, we
- * assume that the first optionset is the correct one
- * and the others will be the same. This needs to be
- * fixed before the final code is ready.
+ * Have an existing optionset . Ideally, we would need
+ * to compare options in order to detect errors. For
+ * now, we assume that the first optionset is the
+ * correct one and the others will be the same. An
+ * empty optionset is the same as no optionset so we
+ * don't want to exit in that case. Getting an empty
+ * optionset can occur with ZFS property checking.
*/
- return (ret);
+ if (sa_get_property(optionset, NULL) != NULL)
+ return (ret);
}
if (strcmp(options, SHOPT_RW) == 0) {
@@ -839,7 +850,7 @@ fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset)
/*
* since options may be set/reset multiple times, always do an
* explicit set or clear of the option. This allows defaults
- * to be set and then the protocol specifici to override.
+ * to be set and then the protocol specific to override.
*/
name = sa_get_property_attr(option, "type");
@@ -1804,7 +1815,8 @@ nfs_enable_share(sa_share_t share)
ea.uex = &export;
sa_sharetab_fill_zfs(share, &sh, "nfs");
- err = sa_share_zfs(share, path, &sh, &ea, B_TRUE);
+ err = sa_share_zfs(share, path, &sh,
+ &ea, ZFS_SHARE_NFS);
sa_emptyshare(&sh);
}
} else {
@@ -1909,7 +1921,8 @@ nfs_disable_share(sa_share_t share, char *path)
sh.sh_path = path;
sh.sh_fstype = "nfs";
- err = sa_share_zfs(share, path, &sh, &ea, B_FALSE);
+ err = sa_share_zfs(share, path, &sh,
+ &ea, ZFS_UNSHARE_NFS);
} else
err = exportfs(path, NULL);
if (err < 0) {
@@ -2802,7 +2815,7 @@ nfs_minmax_check(int index, int value)
/*
* nfs_validate_proto_prop(index, name, value)
*
- * Verify that the property specifed by name can take the new
+ * Verify that the property specified by name can take the new
* value. This is a sanity check to prevent bad values getting into
* the default files. All values need to be checked against what is
* allowed by their defined type. If a type isn't explicitly defined
@@ -2967,3 +2980,15 @@ nfs_space_alias(char *space)
}
return (strdup(name));
}
+
+/*
+ * nfs_features()
+ *
+ * Return a mask of the features required.
+ */
+
+static uint64_t
+nfs_features()
+{
+ return ((uint64_t)SA_FEATURE_DFSTAB);
+}
diff --git a/usr/src/lib/libshare/smb/Makefile b/usr/src/lib/libshare/smb/Makefile
new file mode 100644
index 0000000000..d5f3df5233
--- /dev/null
+++ b/usr/src/lib/libshare/smb/Makefile
@@ -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
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+MSGFILES = libshare_smb.c
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
+include ../../../Makefile.msg.targ
diff --git a/usr/src/lib/libshare/smb/Makefile.com b/usr/src/lib/libshare/smb/Makefile.com
new file mode 100644
index 0000000000..997f47daef
--- /dev/null
+++ b/usr/src/lib/libshare/smb/Makefile.com
@@ -0,0 +1,88 @@
+#
+# 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
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = libshare_smb.a
+VERS = .1
+SMBMLSVC_DIR = $(SRC)/lib/smbsrv/libmlsvc/common
+SMBBASE_DIR = $(SRC)/lib/smbsrv/libsmb/common
+SMBCOMMON_DIR = $(SRC)/common/smbsrv
+
+LIBOBJS = libshare_smb.o smb_share_doorclnt.o
+SMBCOMMON_OBJ = smb_share_door_decode.o smb_common_door_decode.o
+SMBBASE_OBJ = smb_cfg.o smb_scfutil.o smb_door_client.o
+SMBMLSVC_OBJ = smb_share_util.o
+OBJECTS = $(LIBOBJS) $(SMBCOMMON_OBJ) $(SMBBASE_OBJ) $(SMBMLSVC_OBJ)
+
+include ../../../Makefile.lib
+
+ROOTLIBDIR = $(ROOT)/usr/lib/fs/smb
+ROOTLIBDIR64 = $(ROOT)/usr/lib/fs/smb/$(MACH64)
+
+LIBSRCS = $(LIBOBJS:%.o=$(SRCDIR)/%.c)
+lintcheck := SRCS = $(LIBSRCS)
+
+LIBS = $(DYNLIB)
+LDLIBS += -lshare -lnsl -lscf -lumem -lc
+all install := LDLIBS += -lxml2
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I/usr/include/libxml2 \
+ -I$(SRCDIR)/../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: all
+
+lint: lintcheck
+
+pics/smb_door_client.o: $(SMBBASE_DIR)/smb_door_client.c
+ $(COMPILE.c) -o $@ $(SMBBASE_DIR)/smb_door_client.c
+ $(POST_PROCESS_O)
+
+pics/smb_share_door_decode.o: $(SMBCOMMON_DIR)/smb_share_door_decode.c
+ $(COMPILE.c) -o $@ $(SMBCOMMON_DIR)/smb_share_door_decode.c
+ $(POST_PROCESS_O)
+
+pics/smb_common_door_decode.o: $(SMBCOMMON_DIR)/smb_common_door_decode.c
+ $(COMPILE.c) -o $@ $(SMBCOMMON_DIR)/smb_common_door_decode.c
+ $(POST_PROCESS_O)
+
+pics/smb_cfg.o: $(SMBBASE_DIR)/smb_cfg.c
+ $(COMPILE.c) -o $@ $(SMBBASE_DIR)/smb_cfg.c
+ $(POST_PROCESS_O)
+
+pics/smb_scfutil.o: $(SMBBASE_DIR)/smb_scfutil.c
+ $(COMPILE.c) -o $@ $(SMBBASE_DIR)/smb_scfutil.c
+ $(POST_PROCESS_O)
+
+pics/smb_share_util.o: $(SMBMLSVC_DIR)/smb_share_util.c
+ $(COMPILE.c) -o $@ $(SMBMLSVC_DIR)/smb_share_util.c
+ $(POST_PROCESS_O)
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/libshare/smb/amd64/Makefile b/usr/src/lib/libshare/smb/amd64/Makefile
new file mode 100644
index 0000000000..90b1730d23
--- /dev/null
+++ b/usr/src/lib/libshare/smb/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# 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
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libshare/smb/i386/Makefile b/usr/src/lib/libshare/smb/i386/Makefile
new file mode 100644
index 0000000000..543238473c
--- /dev/null
+++ b/usr/src/lib/libshare/smb/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libshare/smb/libshare_smb.c b/usr/src/lib/libshare/smb/libshare_smb.c
new file mode 100644
index 0000000000..7d705e0369
--- /dev/null
+++ b/usr/src/lib/libshare/smb/libshare_smb.c
@@ -0,0 +1,1641 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB specific functions
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <zone.h>
+#include <errno.h>
+#include <locale.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include "libshare.h"
+#include "libshare_impl.h"
+#include <pwd.h>
+#include <limits.h>
+#include <libscf.h>
+#include <strings.h>
+#include "libshare_smb.h"
+#include <rpcsvc/daemon_utils.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/libsmb.h>
+
+/* internal functions */
+static int smb_share_init(void);
+static void smb_share_fini(void);
+static int smb_enable_share(sa_share_t);
+static int smb_share_changed(sa_share_t);
+static int smb_resource_changed(sa_resource_t);
+static int smb_rename_resource(sa_handle_t, sa_resource_t, char *);
+static int smb_disable_share(sa_share_t share, char *);
+static int smb_validate_property(sa_property_t, sa_optionset_t);
+static int smb_set_proto_prop(sa_property_t);
+static sa_protocol_properties_t smb_get_proto_set(void);
+static char *smb_get_status(void);
+static int smb_parse_optstring(sa_group_t, char *);
+static char *smb_format_options(sa_group_t, int);
+
+static int smb_enable_service(void);
+
+static int range_check_validator(int, char *);
+static int range_check_validator_zero_ok(int, char *);
+static int string_length_check_validator(int, char *);
+static int true_false_validator(int, char *);
+static int ip_address_validator_empty_ok(int, char *);
+static int ip_address_csv_list_validator_empty_ok(int, char *);
+static int ipc_mode_validator(int, char *);
+static int path_validator(int, char *);
+
+static int smb_enable_resource(sa_resource_t);
+static int smb_disable_resource(sa_resource_t);
+static uint64_t smb_share_features(void);
+static int smb_list_transient(sa_handle_t);
+
+/* size of basic format allocation */
+#define OPT_CHUNK 1024
+
+/*
+ * Indexes of entries in smb_proto_options table.
+ * Changes to smb_proto_options table may require
+ * an update to these values.
+ */
+#define PROTO_OPT_WINS1 6
+#define PROTO_OPT_WINS_EXCLUDE 8
+
+
+/*
+ * ops vector that provides the protocol specific info and operations
+ * for share management.
+ */
+
+struct sa_plugin_ops sa_plugin_ops = {
+ SA_PLUGIN_VERSION,
+ SMB_PROTOCOL_NAME,
+ smb_share_init,
+ smb_share_fini,
+ smb_enable_share,
+ smb_disable_share,
+ smb_validate_property,
+ NULL,
+ NULL,
+ smb_parse_optstring,
+ smb_format_options,
+ smb_set_proto_prop,
+ smb_get_proto_set,
+ smb_get_status,
+ NULL,
+ NULL,
+ NULL,
+ smb_share_changed,
+ smb_enable_resource,
+ smb_disable_resource,
+ smb_share_features,
+ smb_list_transient,
+ smb_resource_changed,
+ smb_rename_resource,
+ NULL,
+ NULL
+};
+
+/*
+ * option definitions. Make sure to keep the #define for the option
+ * index just before the entry it is the index for. Changing the order
+ * can cause breakage.
+ */
+
+struct option_defs optdefs[] = {
+ {SHOPT_AD_CONTAINER, OPT_TYPE_STRING},
+ {SHOPT_NAME, OPT_TYPE_NAME},
+ {NULL, NULL},
+};
+
+/*
+ * findopt(name)
+ *
+ * Lookup option "name" in the option table and return the table
+ * index.
+ */
+
+static int
+findopt(char *name)
+{
+ int i;
+ if (name != NULL) {
+ for (i = 0; optdefs[i].tag != NULL; i++) {
+ if (strcmp(optdefs[i].tag, name) == 0)
+ return (i);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * is_a_number(number)
+ *
+ * is the string a number in one of the forms we want to use?
+ */
+
+static int
+is_a_number(char *number)
+{
+ int ret = 1;
+ int hex = 0;
+
+ if (strncmp(number, "0x", 2) == 0) {
+ number += 2;
+ hex = 1;
+ } else if (*number == '-') {
+ number++; /* skip the minus */
+ }
+
+ while (ret == 1 && *number != '\0') {
+ if (hex) {
+ ret = isxdigit(*number++);
+ } else {
+ ret = isdigit(*number++);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * validresource(name)
+ *
+ * Check that name only has valid characters in it. The current valid
+ * set are the printable characters but not including:
+ * " / \ [ ] : | < > + ; , ? * = \t
+ * Note that space is included and there is a maximum length.
+ */
+static int
+validresource(const char *name)
+{
+ const char *cp;
+ size_t len;
+
+ if (name == NULL)
+ return (B_FALSE);
+
+ len = strlen(name);
+ if (len == 0 || len > SA_MAX_RESOURCE_NAME)
+ return (B_FALSE);
+
+ if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
+ return (B_FALSE);
+ }
+
+ for (cp = name; *cp != '\0'; cp++)
+ if (iscntrl(*cp))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * smb_isonline()
+ *
+ * Determine if the SMF service instance is in the online state or
+ * not. A number of operations depend on this state.
+ */
+static boolean_t
+smb_isonline(void)
+{
+ char *str;
+ boolean_t ret = B_FALSE;
+
+ if ((str = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI)) != NULL) {
+ ret = (strcmp(str, SCF_STATE_STRING_ONLINE) == 0);
+ free(str);
+ }
+ return (ret);
+}
+
+/*
+ * smb_enable_share tells the implementation that it is to enable the share.
+ * This entails converting the path and options into the appropriate ioctl
+ * calls. It is assumed that all error checking of paths, etc. were
+ * done earlier.
+ */
+static int
+smb_enable_share(sa_share_t share)
+{
+ char *path;
+ char *rname;
+ lmshare_info_t si;
+ sa_resource_t resource;
+ boolean_t iszfs;
+ boolean_t privileged;
+ int err = SA_OK;
+ priv_set_t *priv_effective;
+ boolean_t online;
+
+ priv_effective = priv_allocset();
+ (void) getppriv(PRIV_EFFECTIVE, priv_effective);
+ privileged = (priv_isfullset(priv_effective) == B_TRUE);
+ priv_freeset(priv_effective);
+
+ /* get the path since it is important in several places */
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (SA_NO_SUCH_PATH);
+
+ online = smb_isonline();
+
+ iszfs = sa_path_is_zfs(path);
+
+ if (iszfs) {
+
+ if (privileged == B_FALSE && !online) {
+
+ if (!online) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "SMB: Cannot share remove "
+ "file system: %s\n"), path);
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "SMB: Service needs to be enabled "
+ "by a privileged user\n"));
+ err = SA_NO_PERMISSION;
+ errno = EPERM;
+ }
+ if (err) {
+ sa_free_attr_string(path);
+ return (err);
+ }
+
+ }
+ }
+
+ if (privileged == B_TRUE && !online) {
+ err = smb_enable_service();
+ if (err != SA_OK) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "SMB: Unable to enable service\n"));
+ /*
+ * For now, it is OK to not be able to enable
+ * the service.
+ */
+ if (err == SA_BUSY)
+ err = SA_OK;
+ } else {
+ online = B_TRUE;
+ }
+ }
+
+ /*
+ * Don't bother trying to start shares if the service isn't
+ * running.
+ */
+ if (!online)
+ goto done;
+
+ /* Each share can have multiple resources */
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ sa_optionset_t opts;
+ bzero(&si, sizeof (lmshare_info_t));
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL) {
+ sa_free_attr_string(path);
+ return (SA_NO_SUCH_RESOURCE);
+ }
+
+ opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
+ smb_build_lmshare_info(rname, path, opts, &si);
+ sa_free_attr_string(rname);
+
+ sa_free_derived_optionset(opts);
+ if (!iszfs) {
+ err = lmshrd_add(&si);
+ } else {
+ share_t sh;
+
+ sa_sharetab_fill_zfs(share, &sh, "smb");
+ err = sa_share_zfs(share, (char *)path, &sh,
+ &si, ZFS_SHARE_SMB);
+
+ sa_emptyshare(&sh);
+ }
+ }
+ if (!iszfs)
+ (void) sa_update_sharetab(share, "smb");
+done:
+ sa_free_attr_string(path);
+
+ return (err == NERR_DuplicateShare ? 0 : err);
+}
+
+/*
+ * This is the share for CIFS all shares have resource names.
+ * Enable tells the smb server to update its hash. If it fails
+ * because smb server is down, we just ignore as smb server loads
+ * the resources from sharemanager at startup.
+ */
+
+static int
+smb_enable_resource(sa_resource_t resource)
+{
+ char *path;
+ char *rname;
+ sa_optionset_t opts;
+ sa_share_t share;
+ lmshare_info_t si;
+ int ret;
+
+ share = sa_get_resource_parent(resource);
+ if (share == NULL)
+ return (SA_NO_SUCH_PATH);
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (SA_SYSTEM_ERR);
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL) {
+ sa_free_attr_string(path);
+ return (SA_NO_SUCH_RESOURCE);
+ }
+
+ ret = smb_enable_service();
+
+ if (!smb_isonline()) {
+ ret = SA_OK;
+ goto done;
+ }
+
+ opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
+ smb_build_lmshare_info(rname, path, opts, &si);
+ sa_free_attr_string(path);
+ sa_free_attr_string(rname);
+ sa_free_derived_optionset(opts);
+ if (lmshrd_add(&si) != NERR_Success)
+ return (SA_NOT_SHARED);
+ (void) sa_update_sharetab(share, "smb");
+
+done:
+ return (ret);
+}
+
+/*
+ * Remove it from smb server hash.
+ */
+static int
+smb_disable_resource(sa_resource_t resource)
+{
+ char *rname;
+ DWORD res;
+ sa_share_t share;
+
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL)
+ return (SA_NO_SUCH_RESOURCE);
+
+ if (smb_isonline()) {
+ res = lmshrd_delete(rname);
+ if (res != NERR_Success) {
+ sa_free_attr_string(rname);
+ return (SA_CONFIG_ERR);
+ }
+ sa_free_attr_string(rname);
+ rname = NULL;
+ }
+ share = sa_get_resource_parent(resource);
+ if (share != NULL) {
+ rname = sa_get_share_attr(share, "path");
+ if (rname != NULL) {
+ (void) sa_delete_sharetab(rname, "smb");
+ sa_free_attr_string(rname);
+ rname = NULL;
+ }
+ }
+ if (rname != NULL)
+ sa_free_attr_string(rname);
+ /*
+ * Always return OK as smb/server may be down and
+ * Shares will be picked up when loaded.
+ */
+ return (SA_OK);
+}
+
+/*
+ * smb_share_changed(sa_share_t share)
+ *
+ * The specified share has changed.
+ */
+static int
+smb_share_changed(sa_share_t share)
+{
+ char *path;
+ sa_resource_t resource;
+
+ /* get the path since it is important in several places */
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (SA_NO_SUCH_PATH);
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource))
+ (void) smb_resource_changed(resource);
+
+ sa_free_attr_string(path);
+
+ return (SA_OK);
+}
+
+/*
+ * smb_resource_changed(sa_resource_t resource)
+ *
+ * The specified resource has changed.
+ */
+static int
+smb_resource_changed(sa_resource_t resource)
+{
+ DWORD res;
+ lmshare_info_t si;
+ lmshare_info_t new_si;
+ char *rname, *path;
+ sa_optionset_t opts;
+ sa_share_t share;
+
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL)
+ return (SA_NO_SUCH_RESOURCE);
+
+ share = sa_get_resource_parent(resource);
+ if (share == NULL) {
+ sa_free_attr_string(rname);
+ return (SA_CONFIG_ERR);
+ }
+
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL) {
+ sa_free_attr_string(rname);
+ return (SA_NO_SUCH_PATH);
+ }
+
+ if (!smb_isonline()) {
+ sa_free_attr_string(rname);
+ return (SA_OK);
+ }
+
+ /* Update the share cache in smb/server */
+ res = lmshrd_getinfo(rname, &si);
+ if (res != NERR_Success) {
+ sa_free_attr_string(path);
+ sa_free_attr_string(rname);
+ return (SA_CONFIG_ERR);
+ }
+
+ opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
+ smb_build_lmshare_info(rname, path, opts, &new_si);
+ sa_free_derived_optionset(opts);
+ sa_free_attr_string(path);
+ sa_free_attr_string(rname);
+
+ /*
+ * Update all fields from sa_share_t
+ * Get derived values.
+ */
+ if (lmshrd_setinfo(&new_si) != LMSHR_DOOR_SRV_SUCCESS)
+ return (SA_CONFIG_ERR);
+ return (smb_enable_service());
+}
+
+/*
+ * smb_disable_share(sa_share_t share)
+ *
+ * Unshare the specified share.
+ */
+static int
+smb_disable_share(sa_share_t share, char *path)
+{
+ char *rname;
+ sa_resource_t resource;
+ boolean_t iszfs;
+ int err = SA_OK;
+
+ iszfs = sa_path_is_zfs(path);
+ if (!smb_isonline())
+ goto done;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL) {
+ continue;
+ }
+ if (!iszfs) {
+ err = lmshrd_delete(rname);
+ switch (err) {
+ case NERR_NetNameNotFound:
+ case NERR_Success:
+ err = SA_OK;
+ break;
+ default:
+ err = SA_CONFIG_ERR;
+ break;
+ }
+ } else {
+ share_t sh;
+
+ sa_sharetab_fill_zfs(share, &sh, "smb");
+ err = sa_share_zfs(share, (char *)path, &sh,
+ rname, ZFS_UNSHARE_SMB);
+ sa_emptyshare(&sh);
+ }
+ sa_free_attr_string(rname);
+ }
+done:
+ if (!iszfs)
+ (void) sa_delete_sharetab(path, "smb");
+ return (err);
+}
+
+/*
+ * smb_validate_property(property, parent)
+ *
+ * Check that the property has a legitimate value for its type.
+ */
+
+static int
+smb_validate_property(sa_property_t property, sa_optionset_t parent)
+{
+ int ret = SA_OK;
+ char *propname;
+ int optindex;
+ sa_group_t parent_group;
+ char *value;
+
+ propname = sa_get_property_attr(property, "type");
+
+ if ((optindex = findopt(propname)) < 0)
+ ret = SA_NO_SUCH_PROP;
+
+ /* need to validate value range here as well */
+ if (ret == SA_OK) {
+ parent_group = sa_get_parent_group((sa_share_t)parent);
+ if (optdefs[optindex].share && !sa_is_share(parent_group))
+ ret = SA_PROP_SHARE_ONLY;
+ }
+ if (ret != SA_OK) {
+ if (propname != NULL)
+ sa_free_attr_string(propname);
+ return (ret);
+ }
+
+ value = sa_get_property_attr(property, "value");
+ if (value != NULL) {
+ /* first basic type checking */
+ switch (optdefs[optindex].type) {
+ case OPT_TYPE_NUMBER:
+ /* check that the value is all digits */
+ if (!is_a_number(value))
+ ret = SA_BAD_VALUE;
+ break;
+ case OPT_TYPE_BOOLEAN:
+ if (strlen(value) == 0 ||
+ strcasecmp(value, "true") == 0 ||
+ strcmp(value, "1") == 0 ||
+ strcasecmp(value, "false") == 0 ||
+ strcmp(value, "0") == 0) {
+ ret = SA_OK;
+ } else {
+ ret = SA_BAD_VALUE;
+ }
+ break;
+ case OPT_TYPE_NAME:
+ /*
+ * Make sure no invalid characters
+ */
+ if (validresource(value) == B_FALSE)
+ ret = SA_BAD_VALUE;
+ break;
+ case OPT_TYPE_STRING:
+ /* whatever is here should be ok */
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (value != NULL)
+ sa_free_attr_string(value);
+ if (ret == SA_OK && optdefs[optindex].check != NULL)
+ /* do the property specific check */
+ ret = optdefs[optindex].check(property);
+
+ if (propname != NULL)
+ sa_free_attr_string(propname);
+ return (ret);
+}
+
+/*
+ * Protocol management functions
+ *
+ * properties defined in the default files are defined in
+ * proto_option_defs for parsing and validation.
+ */
+
+struct smb_proto_option_defs {
+ char *name; /* display name -- remove protocol identifier */
+ int smb_index;
+ int32_t minval;
+ int32_t maxval; /* In case of length of string this should be max */
+ int (*validator)(int, char *);
+ int32_t refresh;
+} smb_proto_options[] = {
+ { SMB_CD_SYS_CMNT,
+ SMB_CI_SYS_CMNT, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_MAX_WORKERS,
+ SMB_CI_MAX_WORKERS, 64, 1024, range_check_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_NBSCOPE,
+ SMB_CI_NBSCOPE, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_RDR_IPCMODE,
+ SMB_CI_RDR_IPCMODE, 0, 0, ipc_mode_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_LM_LEVEL,
+ SMB_CI_LM_LEVEL, 2, 5, range_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_KEEPALIVE,
+ SMB_CI_KEEPALIVE, 20, 5400, range_check_validator_zero_ok,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_WINS_SRV1,
+ SMB_CI_WINS_SRV1, 0, MAX_VALUE_BUFLEN,
+ ip_address_validator_empty_ok, SMB_REFRESH_REFRESH},
+ { SMB_CD_WINS_SRV2,
+ SMB_CI_WINS_SRV2, 0, MAX_VALUE_BUFLEN,
+ ip_address_validator_empty_ok, SMB_REFRESH_REFRESH},
+ { SMB_CD_WINS_EXCL,
+ SMB_CI_WINS_EXCL, 0, MAX_VALUE_BUFLEN,
+ ip_address_csv_list_validator_empty_ok, SMB_REFRESH_REFRESH},
+ { SMB_CD_SIGNING_ENABLE,
+ SMB_CI_SIGNING_ENABLE, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_SIGNING_REQD,
+ SMB_CI_SIGNING_REQD, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_RESTRICT_ANON,
+ SMB_CI_RESTRICT_ANON, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_DOMAIN_SRV,
+ SMB_CI_DOMAIN_SRV, 0, MAX_VALUE_BUFLEN,
+ ip_address_validator_empty_ok, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_ENABLE,
+ SMB_CI_ADS_ENABLE, 0, 0, true_false_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_USER,
+ SMB_CI_ADS_USER, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_USER_CONTAINER,
+ SMB_CI_ADS_USER_CONTAINER, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_DOMAIN,
+ SMB_CI_ADS_DOMAIN, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_PASSWD,
+ SMB_CI_ADS_PASSWD, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_IPLOOKUP,
+ SMB_CI_ADS_IPLOOKUP, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_ADS_SITE,
+ SMB_CI_ADS_SITE, 0, MAX_VALUE_BUFLEN,
+ string_length_check_validator, SMB_REFRESH_REFRESH},
+ { SMB_CD_DYNDNS_ENABLE,
+ SMB_CI_DYNDNS_ENABLE, 0, 0, true_false_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_DYNDNS_RETRY_SEC,
+ SMB_CI_DYNDNS_RETRY_SEC, 0, 20, range_check_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_DYNDNS_RETRY_COUNT,
+ SMB_CI_DYNDNS_RETRY_COUNT, 3, 5, range_check_validator,
+ SMB_REFRESH_REFRESH},
+ { SMB_CD_AUTOHOME_MAP,
+ SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN,
+ path_validator},
+ {NULL, -1, 0, 0, NULL}
+};
+
+/*
+ * Check the range of value as int range.
+ */
+static int
+range_check_validator(int index, char *value)
+{
+ int ret = SA_OK;
+
+ if (!is_a_number(value)) {
+ ret = SA_BAD_VALUE;
+ } else {
+ int val;
+ val = strtoul(value, NULL, 0);
+ if (val < smb_proto_options[index].minval ||
+ val > smb_proto_options[index].maxval)
+ ret = SA_BAD_VALUE;
+ }
+ return (ret);
+}
+
+/*
+ * Check the range of value as int range.
+ */
+static int
+range_check_validator_zero_ok(int index, char *value)
+{
+ int ret = SA_OK;
+
+ if (!is_a_number(value)) {
+ ret = SA_BAD_VALUE;
+ } else {
+ int val;
+ val = strtoul(value, NULL, 0);
+ if (val == 0)
+ ret = SA_OK;
+ else {
+ if (val < smb_proto_options[index].minval ||
+ val > smb_proto_options[index].maxval)
+ ret = SA_BAD_VALUE;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * Check the length of the string
+ */
+static int
+string_length_check_validator(int index, char *value)
+{
+ int ret = SA_OK;
+
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ if (strlen(value) > smb_proto_options[index].maxval)
+ ret = SA_BAD_VALUE;
+ return (ret);
+}
+
+/*
+ * Check yes/no
+ */
+/*ARGSUSED*/
+static int
+true_false_validator(int index, char *value)
+{
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ if ((strcasecmp(value, "true") == 0) ||
+ (strcasecmp(value, "false") == 0))
+ return (SA_OK);
+ return (SA_BAD_VALUE);
+}
+
+/*
+ * Check IP address.
+ */
+/*ARGSUSED*/
+static int
+ip_address_validator_empty_ok(int index, char *value)
+{
+ char sbytes[16];
+ int len;
+
+ if (value == NULL)
+ return (SA_OK);
+ len = strlen(value);
+ if (len == 0)
+ return (SA_OK);
+ if (inet_pton(AF_INET, value, (void *)sbytes) != 1)
+ return (SA_BAD_VALUE);
+
+ return (SA_OK);
+}
+
+/*
+ * Check IP address list
+ */
+/*ARGSUSED*/
+static int
+ip_address_csv_list_validator_empty_ok(int index, char *value)
+{
+ char sbytes[16];
+ char *ip, *tmp, *ctx;
+
+ if (value == NULL || *value == '\0')
+ return (SA_OK);
+
+ if (strlen(value) > MAX_VALUE_BUFLEN)
+ return (SA_BAD_VALUE);
+
+ if ((tmp = strdup(value)) == NULL)
+ return (SA_NO_MEMORY);
+
+ ip = strtok_r(tmp, ",", &ctx);
+ while (ip) {
+ if (strlen(ip) == 0) {
+ free(tmp);
+ return (SA_BAD_VALUE);
+ }
+ if (*ip != 0) {
+ if (inet_pton(AF_INET, ip,
+ (void *)sbytes) != 1) {
+ free(tmp);
+ return (SA_BAD_VALUE);
+ }
+ }
+ ip = strtok_r(0, ",", &ctx);
+ }
+
+ free(tmp);
+ return (SA_OK);
+}
+
+/*
+ * Check IPC mode
+ */
+/*ARGSUSED*/
+static int
+ipc_mode_validator(int index, char *value)
+{
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ if (strcasecmp(value, "anon") == 0)
+ return (SA_OK);
+ if (strcasecmp(value, "auth") == 0)
+ return (SA_OK);
+ return (SA_BAD_VALUE);
+}
+
+/*
+ * Check path
+ */
+/*ARGSUSED*/
+static int
+path_validator(int index, char *value)
+{
+ struct stat buffer;
+ int fd, status;
+
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+
+ fd = open(value, O_RDONLY);
+ if (fd < 0)
+ return (SA_BAD_VALUE);
+
+ status = fstat(fd, &buffer);
+ (void) close(fd);
+
+ if (status < 0)
+ return (SA_BAD_VALUE);
+
+ if (buffer.st_mode & S_IFDIR)
+ return (SA_OK);
+ return (SA_BAD_VALUE);
+}
+
+/*
+ * the protoset holds the defined options so we don't have to read
+ * them multiple times
+ */
+static sa_protocol_properties_t protoset;
+
+static int
+findprotoopt(char *name)
+{
+ int i;
+ for (i = 0; smb_proto_options[i].name != NULL; i++) {
+ if (strcasecmp(smb_proto_options[i].name, name) == 0)
+ return (i);
+ }
+ return (-1);
+}
+
+/*
+ * smb_load_proto_properties()
+ *
+ * read the smb config values from SMF.
+ */
+
+static int
+smb_load_proto_properties()
+{
+ sa_property_t prop;
+ int index;
+ char *value;
+
+ protoset = sa_create_protocol_properties(SMB_PROTOCOL_NAME);
+ if (protoset == NULL)
+ return (SA_NO_MEMORY);
+
+ if (smb_config_load() != 0)
+ return (SA_CONFIG_ERR);
+ for (index = 0; smb_proto_options[index].name != NULL; index++) {
+ value = smb_config_getenv(smb_proto_options[index].smb_index);
+ prop = sa_create_property(
+ smb_proto_options[index].name, value);
+ (void) sa_add_protocol_property(protoset, prop);
+ }
+ return (SA_OK);
+}
+
+/*
+ * smb_share_init()
+ *
+ * Initialize the smb plugin.
+ */
+
+static int
+smb_share_init(void)
+{
+ int ret = SA_OK;
+
+ if (sa_plugin_ops.sa_init != smb_share_init)
+ return (SA_SYSTEM_ERR);
+
+ if (smb_load_proto_properties() != SA_OK)
+ return (SA_SYSTEM_ERR);
+
+ return (ret);
+}
+
+/*
+ * smb_share_fini()
+ *
+ */
+static void
+smb_share_fini(void)
+{
+ xmlFreeNode(protoset);
+ protoset = NULL;
+}
+
+/*
+ * smb_get_proto_set()
+ *
+ * Return an optionset with all the protocol specific properties in
+ * it.
+ */
+static sa_protocol_properties_t
+smb_get_proto_set(void)
+{
+ return (protoset);
+}
+
+/*
+ * How long to wait for service to come online
+ */
+#define WAIT_FOR_SERVICE 15
+
+/*
+ * smb_enable_service()
+ *
+ */
+static int
+smb_enable_service(void)
+{
+ int i;
+ int ret = SA_OK;
+
+ if (!smb_isonline()) {
+ if (smf_enable_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0) != 0) {
+ (void) fprintf(stderr,
+ dgettext(TEXT_DOMAIN,
+ "%s failed to restart: %s\n"),
+ scf_strerror(scf_error()));
+ return (SA_CONFIG_ERR);
+ }
+
+ /* Wait for service to come online */
+ for (i = 0; i < WAIT_FOR_SERVICE; i++) {
+ if (smb_isonline()) {
+ ret = SA_OK;
+ break;
+ } else {
+ ret = SA_BUSY;
+ (void) sleep(1);
+ }
+ }
+ }
+ return (ret);
+}
+
+/*
+ * smb_validate_proto_prop(index, name, value)
+ *
+ * Verify that the property specified by name can take the new
+ * value. This is a sanity check to prevent bad values getting into
+ * the default files.
+ */
+static int
+smb_validate_proto_prop(int index, char *name, char *value)
+{
+ if ((name == NULL) || (index < 0))
+ return (SA_BAD_VALUE);
+
+ if (smb_proto_options[index].validator == NULL)
+ return (SA_OK);
+
+ if (smb_proto_options[index].validator(index, value) == SA_OK)
+ return (SA_OK);
+ return (SA_BAD_VALUE);
+}
+
+/*
+ * smb_set_proto_prop(prop)
+ *
+ * check that prop is valid.
+ */
+/*ARGSUSED*/
+static int
+smb_set_proto_prop(sa_property_t prop)
+{
+ int ret = SA_OK;
+ char *name;
+ char *value;
+ int index = -1;
+
+ name = sa_get_property_attr(prop, "type");
+ value = sa_get_property_attr(prop, "value");
+ if (name != NULL && value != NULL) {
+ index = findprotoopt(name);
+ if (index >= 0) {
+ /* should test for valid value */
+ ret = smb_validate_proto_prop(index, name, value);
+ if (ret == SA_OK) {
+ /* Save to SMF */
+ smb_config_setenv(
+ smb_proto_options[index].smb_index, value);
+ /*
+ * Specialized refresh mechanisms can
+ * be flagged in the proto_options and
+ * processed here.
+ */
+ if (smb_proto_options[index].refresh &
+ SMB_REFRESH_REFRESH)
+ (void) smf_refresh_instance(
+ SMBD_DEFAULT_INSTANCE_FMRI);
+ else if (smb_proto_options[index].refresh &
+ SMB_REFRESH_RESTART)
+ (void) smf_restart_instance(
+ SMBD_DEFAULT_INSTANCE_FMRI);
+ }
+ }
+ }
+ if (name != NULL)
+ sa_free_attr_string(name);
+ if (value != NULL)
+ sa_free_attr_string(value);
+
+ return (ret);
+}
+
+/*
+ * smb_get_status()
+ *
+ * What is the current status of the smbd? We use the SMF state here.
+ * Caller must free the returned value.
+ */
+
+static char *
+smb_get_status(void)
+{
+ char *state = NULL;
+ state = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI);
+ return (state != NULL ? state : "-");
+}
+
+/*
+ * This protocol plugin require resource names
+ */
+static uint64_t
+smb_share_features(void)
+{
+ return (SA_FEATURE_RESOURCE | SA_FEATURE_ALLOWSUBDIRS |
+ SA_FEATURE_ALLOWPARDIRS);
+}
+
+/*
+ * This should be used to convert lmshare_info to sa_resource_t
+ * Should only be needed to build temp shares/resources to be
+ * supplied to sharemanager to display temp shares.
+ */
+static int
+smb_build_tmp_sa_resource(sa_handle_t handle, lmshare_info_t *si)
+{
+ int err;
+ sa_share_t share;
+ sa_group_t group;
+ sa_resource_t resource;
+
+ if (si == NULL)
+ return (SA_INVALID_NAME);
+
+ /*
+ * First determine if the "share path" is already shared
+ * somewhere. If it is, we have to use it as the authority on
+ * where the transient share lives so will use it's parent
+ * group. If it doesn't exist, it needs to land in "smb".
+ */
+
+ share = sa_find_share(handle, si->directory);
+ if (share != NULL) {
+ group = sa_get_parent_group(share);
+ } else {
+ group = smb_get_smb_share_group(handle);
+ if (group == NULL)
+ return (SA_NO_SUCH_GROUP);
+ share = sa_get_share(group, si->directory);
+ if (share == NULL) {
+ share = sa_add_share(group, si->directory,
+ SA_SHARE_TRANSIENT, &err);
+ if (share == NULL)
+ return (SA_NO_SUCH_PATH);
+ }
+ }
+
+ /*
+ * Now handle the resource. Make sure that the resource is
+ * transient and added to the share.
+ */
+ resource = sa_get_share_resource(share, si->share_name);
+ if (resource == NULL) {
+ resource = sa_add_resource(share,
+ si->share_name, SA_SHARE_TRANSIENT, &err);
+ if (resource == NULL)
+ return (SA_NO_SUCH_RESOURCE);
+ }
+
+ /* set resource attributes now */
+ (void) sa_set_resource_attr(resource, "description", si->comment);
+ (void) sa_set_resource_attr(resource, SHOPT_AD_CONTAINER,
+ si->container);
+
+ return (SA_OK);
+}
+
+/*
+ * Return smb transient shares. Note that we really want to look at
+ * all current shares from SMB in order to determine this. Transient
+ * shares should be those that don't appear in either the SMF or ZFS
+ * configurations. Those that are in the repositories will be
+ * filtered out by smb_build_tmp_sa_resource.
+ */
+static int
+smb_list_transient(sa_handle_t handle)
+{
+ int i, offset, num;
+ lmshare_list_t list;
+ int res;
+
+ num = lmshrd_num_shares();
+ if (num <= 0)
+ return (SA_OK);
+ offset = 0;
+ while (lmshrd_list(offset, &list) != NERR_InternalError) {
+ if (list.no == 0)
+ break;
+ for (i = 0; i < list.no; i++) {
+ res = smb_build_tmp_sa_resource(handle,
+ &(list.smbshr[i]));
+ if (res != SA_OK)
+ return (res);
+ }
+ offset += list.no;
+ }
+
+ return (SA_OK);
+}
+
+/*
+ * fix_resource_name(share, name, prefix)
+ *
+ * Construct a name where the ZFS dataset has the prefix replaced with "name".
+ */
+static char *
+fix_resource_name(sa_share_t share, char *name, char *prefix)
+{
+ char *dataset = NULL;
+ char *newname = NULL;
+ size_t psize;
+ size_t nsize;
+
+ dataset = sa_get_share_attr(share, "dataset");
+
+ if (dataset != NULL && strcmp(dataset, prefix) != 0) {
+ psize = strlen(prefix);
+ if (strncmp(dataset, prefix, psize) == 0) {
+ /* need string plus ',' and NULL */
+ nsize = (strlen(dataset) - psize) + strlen(name) + 2;
+ newname = calloc(nsize, 1);
+ if (newname != NULL) {
+ (void) snprintf(newname, nsize, "%s%s", name,
+ dataset + psize);
+ sa_fix_resource_name(newname);
+ }
+ sa_free_attr_string(dataset);
+ return (newname);
+ }
+ }
+ if (dataset != NULL)
+ sa_free_attr_string(dataset);
+ return (strdup(name));
+}
+
+/*
+ * smb_parse_optstring(group, options)
+ *
+ * parse a compact option string into individual options. This allows
+ * ZFS sharesmb and sharemgr "share" command to work. group can be a
+ * group, a share or a resource.
+ */
+static int
+smb_parse_optstring(sa_group_t group, char *options)
+{
+ char *dup;
+ char *base;
+ char *lasts;
+ char *token;
+ sa_optionset_t optionset;
+ sa_group_t parent = NULL;
+ sa_resource_t resource = NULL;
+ int iszfs = 0;
+ int persist = 0;
+ int need_optionset = 0;
+ int ret = SA_OK;
+ sa_property_t prop;
+
+ /*
+ * In order to not attempt to change ZFS properties unless
+ * absolutely necessary, we never do it in the legacy parsing
+ * so we need to keep track of this.
+ */
+ if (sa_is_share(group)) {
+ char *zfs;
+
+ parent = sa_get_parent_group(group);
+ if (parent != NULL) {
+ zfs = sa_get_group_attr(parent, "zfs");
+ if (zfs != NULL) {
+ sa_free_attr_string(zfs);
+ iszfs = 1;
+ }
+ }
+ } else {
+ iszfs = sa_group_is_zfs(group);
+ /*
+ * If a ZFS group, then we need to see if a resource
+ * name is being set. If so, bail with
+ * SA_PROP_SHARE_ONLY, so we come back in with a share
+ * instead of a group.
+ */
+ if (strncmp(options, "name=", sizeof ("name=") - 1) == 0 ||
+ strstr(options, ",name=") != NULL) {
+ return (SA_PROP_SHARE_ONLY);
+ }
+ }
+
+ /* do we have an existing optionset? */
+ optionset = sa_get_optionset(group, "smb");
+ if (optionset == NULL) {
+ /* didn't find existing optionset so create one */
+ optionset = sa_create_optionset(group, "smb");
+ if (optionset == NULL)
+ return (SA_NO_MEMORY);
+ } else {
+ /*
+ * If an optionset already exists, we've come through
+ * twice so ignore the second time.
+ */
+ return (ret);
+ }
+
+ /* We need a copy of options for the next part. */
+ dup = strdup(options);
+ if (dup == NULL)
+ return (SA_NO_MEMORY);
+
+ /*
+ * SMB properties are straightforward and are strings,
+ * integers or booleans. Properties are separated by
+ * commas. It will be necessary to parse quotes due to some
+ * strings not having a restricted characters set.
+ *
+ * Note that names will create a resource. For now, if there
+ * is a set of properties "before" the first name="", those
+ * properties will be placed on the group.
+ */
+ persist = sa_is_persistent(group);
+ base = dup;
+ token = dup;
+ lasts = NULL;
+ while (token != NULL && ret == SA_OK) {
+ ret = SA_OK;
+ token = strtok_r(base, ",", &lasts);
+ base = NULL;
+ if (token != NULL) {
+ char *value;
+ /*
+ * All SMB properties have values so there
+ * MUST be an '=' character. If it doesn't,
+ * it is a syntax error.
+ */
+ value = strchr(token, '=');
+ if (value != NULL) {
+ *value++ = '\0';
+ } else {
+ ret = SA_SYNTAX_ERR;
+ break;
+ }
+ /*
+ * We may need to handle a "name" property
+ * that is a ZFS imposed resource name. Each
+ * name would trigger getting a new "resource"
+ * to put properties on. For now, assume no
+ * "name" property for special handling.
+ */
+
+ if (strcmp(token, "name") == 0) {
+ char *prefix;
+ char *name = NULL;
+ /*
+ * We have a name, so now work on the
+ * resource level. We have a "share"
+ * in "group" due to the caller having
+ * added it. If we are called with a
+ * group, the check for group/share
+ * at the beginning of this function
+ * will bail out the parse if there is a
+ * "name" but no share.
+ */
+ if (!iszfs) {
+ ret = SA_SYNTAX_ERR;
+ break;
+ }
+ /*
+ * Make sure the parent group has the
+ * "prefix" property since we will
+ * need to use this for constructing
+ * inherited name= values.
+ */
+ prefix = sa_get_group_attr(parent, "prefix");
+ if (prefix == NULL) {
+ prefix = sa_get_group_attr(parent,
+ "name");
+ if (prefix != NULL) {
+ (void) sa_set_group_attr(parent,
+ "prefix", prefix);
+ }
+ }
+ name = fix_resource_name((sa_share_t)group,
+ value, prefix);
+ if (name != NULL) {
+ resource = sa_add_resource(
+ (sa_share_t)group, name,
+ SA_SHARE_TRANSIENT, &ret);
+ sa_free_attr_string(name);
+ } else {
+ ret = SA_NO_MEMORY;
+ }
+ if (prefix != NULL)
+ sa_free_attr_string(prefix);
+
+ /* A resource level optionset is needed */
+
+ need_optionset = 1;
+ if (resource == NULL) {
+ ret = SA_NO_MEMORY;
+ break;
+ }
+ continue;
+ }
+
+ if (need_optionset) {
+ optionset = sa_create_optionset(resource,
+ "smb");
+ need_optionset = 0;
+ }
+
+ prop = sa_create_property(token, value);
+ if (prop == NULL)
+ ret = SA_NO_MEMORY;
+ else
+ ret = sa_add_property(optionset, prop);
+ if (ret != SA_OK)
+ break;
+ if (!iszfs)
+ ret = sa_commit_properties(optionset, !persist);
+ }
+ }
+ free(dup);
+ return (ret);
+}
+
+/*
+ * smb_sprint_option(rbuff, rbuffsize, incr, prop, sep)
+ *
+ * provides a mechanism to format SMB properties into legacy output
+ * format. If the buffer would overflow, it is reallocated and grown
+ * as appropriate. Special cases of converting internal form of values
+ * to those used by "share" are done. this function does one property
+ * at a time.
+ */
+
+static void
+smb_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr,
+ sa_property_t prop, int sep)
+{
+ char *name;
+ char *value;
+ int curlen;
+ char *buff = *rbuff;
+ size_t buffsize = *rbuffsize;
+
+ name = sa_get_property_attr(prop, "type");
+ value = sa_get_property_attr(prop, "value");
+ if (buff != NULL)
+ curlen = strlen(buff);
+ else
+ curlen = 0;
+ if (name != NULL) {
+ int len;
+ len = strlen(name) + sep;
+
+ /*
+ * A future RFE would be to replace this with more
+ * generic code and to possibly handle more types.
+ *
+ * For now, everything else is treated as a string. If
+ * we get any properties that aren't exactly
+ * name/value pairs, we may need to
+ * interpret/transform.
+ */
+ if (value != NULL)
+ len += 1 + strlen(value);
+
+ while (buffsize <= (curlen + len)) {
+ /* need more room */
+ buffsize += incr;
+ buff = realloc(buff, buffsize);
+ *rbuff = buff;
+ *rbuffsize = buffsize;
+ if (buff == NULL) {
+ /* realloc failed so free everything */
+ if (*rbuff != NULL)
+ free(*rbuff);
+ goto err;
+ }
+ }
+ if (buff == NULL)
+ goto err;
+ (void) snprintf(buff + curlen, buffsize - curlen,
+ "%s%s=%s", sep ? "," : "",
+ name, value != NULL ? value : "\"\"");
+
+ }
+err:
+ if (name != NULL)
+ sa_free_attr_string(name);
+ if (value != NULL)
+ sa_free_attr_string(value);
+}
+
+/*
+ * smb_format_resource_options(resource, hier)
+ *
+ * format all the options on the group into a flattened option
+ * string. If hier is non-zero, walk up the tree to get inherited
+ * options.
+ */
+
+static char *
+smb_format_options(sa_group_t group, int hier)
+{
+ sa_optionset_t options = NULL;
+ sa_property_t prop;
+ int sep = 0;
+ char *buff;
+ size_t buffsize;
+
+
+ buff = malloc(OPT_CHUNK);
+ if (buff == NULL)
+ return (NULL);
+
+ buff[0] = '\0';
+ buffsize = OPT_CHUNK;
+
+ /*
+ * We may have a an optionset relative to this item. format
+ * these if we find them and then add any security definitions.
+ */
+
+ options = sa_get_derived_optionset(group, "smb", hier);
+
+ /*
+ * do the default set first but skip any option that is also
+ * in the protocol specific optionset.
+ */
+ if (options != NULL) {
+ for (prop = sa_get_property(options, NULL);
+ prop != NULL; prop = sa_get_next_property(prop)) {
+ /*
+ * use this one since we skipped any
+ * of these that were also in
+ * optdefault
+ */
+ smb_sprint_option(&buff, &buffsize, OPT_CHUNK,
+ prop, sep);
+ if (buff == NULL) {
+ /*
+ * buff could become NULL if there
+ * isn't enough memory for
+ * smb_sprint_option to realloc()
+ * as necessary. We can't really
+ * do anything about it at this
+ * point so we return NULL. The
+ * caller should handle the
+ * failure.
+ */
+ if (options != NULL)
+ sa_free_derived_optionset(
+ options);
+ return (buff);
+ }
+ sep = 1;
+ }
+ }
+
+ if (options != NULL)
+ sa_free_derived_optionset(options);
+ return (buff);
+}
+
+/*
+ * smb_rename_resource(resource, newname)
+ *
+ * Change the current exported name of the resource to newname.
+ */
+/*ARGSUSED*/
+int
+smb_rename_resource(sa_handle_t handle, sa_resource_t resource, char *newname)
+{
+ int ret = SA_OK;
+ int err;
+ char *oldname;
+
+ oldname = sa_get_resource_attr(resource, "name");
+ if (oldname == NULL)
+ return (SA_NO_SUCH_RESOURCE);
+
+ err = lmshrd_rename(oldname, newname);
+
+ /* improve error values somewhat */
+ switch (err) {
+ case NERR_Success:
+ break;
+ case NERR_InternalError:
+ ret = SA_SYSTEM_ERR;
+ break;
+ case NERR_DuplicateShare:
+ ret = SA_DUPLICATE_NAME;
+ break;
+ default:
+ ret = SA_CONFIG_ERR;
+ break;
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libshare/smb/libshare_smb.h b/usr/src/lib/libshare/smb/libshare_smb.h
new file mode 100644
index 0000000000..2d86c9ed32
--- /dev/null
+++ b/usr/src/lib/libshare/smb/libshare_smb.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * basic API declarations for share management
+ */
+
+#ifndef _LIBSHARE_SMB_H
+#define _LIBSHARE_SMB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <smbsrv/lmshare.h>
+
+/*
+ * defined options types. These should be in a file rather than
+ * compiled in. Until there is a plugin mechanism to add new types,
+ * this is sufficient.
+ */
+#define OPT_TYPE_ANY 0
+#define OPT_TYPE_STRING 1
+#define OPT_TYPE_BOOLEAN 2
+#define OPT_TYPE_NUMBER 3
+#define OPT_TYPE_PATH 4
+#define OPT_TYPE_PROTOCOL 5
+#define OPT_TYPE_NAME 6
+
+struct option_defs {
+ char *tag;
+ int type;
+ int share; /* share only option */
+ int (*check)(char *);
+};
+
+/*
+ * Sharectl property refresh types. Bit mask to indicate which type(s)
+ * of refresh might be needed on the service(s).
+ */
+
+#define SMB_REFRESH_RESTART 0x0001 /* restart smb/server */
+#define SMB_REFRESH_REFRESH 0x0002 /* refresh smb/server */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSHARE_SMB_H */
diff --git a/usr/src/lib/libshare/smb/mapfile-vers b/usr/src/lib/libshare/smb/mapfile-vers
new file mode 100644
index 0000000000..18c216bf6b
--- /dev/null
+++ b/usr/src/lib/libshare/smb/mapfile-vers
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ sa_plugin_ops;
+ local:
+ *;
+};
+
diff --git a/usr/src/lib/libshare/smb/smb_share_doorclnt.c b/usr/src/lib/libshare/smb/smb_share_doorclnt.c
new file mode 100644
index 0000000000..0ebf61b7a9
--- /dev/null
+++ b/usr/src/lib/libshare/smb/smb_share_doorclnt.c
@@ -0,0 +1,951 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * User-space door client for LanMan share management.
+ */
+
+#include <syslog.h>
+#include <door.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+
+#include <smbsrv/lmshare.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/cifs.h>
+
+int lmshrd_fildes = -1;
+
+char *lmshrd_desc[] = {
+ "",
+ "LmshrdOpenIter",
+ "LmshrdCloseIter",
+ "LmshrdIterate",
+ "LmshrdNumShares",
+ "LmshrdDelete",
+ "LmshrdRename",
+ "LmshrdGetinfo",
+ "LmshrdAdd",
+ "LmshrdSetinfo",
+ "LmshrdExists",
+ "LmshrdIsSpecial",
+ "LmshrdIsRestricted",
+ "LmshrdIsAdmin",
+ "LmshrdIsValid",
+ "LmshrdIsDir",
+ "LmshrdList",
+ "LmshrdListTrans",
+ "LmshrdNumTrans",
+ "N/A",
+ 0
+};
+
+/*
+ * Returns 0 on success. Otherwise, -1.
+ */
+static int
+lmshrd_door_open(int opcode)
+{
+ int rc = 0;
+
+ if (lmshrd_fildes == -1 &&
+ (lmshrd_fildes = open(LMSHR_DOOR_NAME, O_RDONLY)) < 0) {
+ syslog(LOG_DEBUG, "%s: open %s failed %s", lmshrd_desc[opcode],
+ LMSHR_DOOR_NAME, strerror(errno));
+ rc = -1;
+ }
+ return (rc);
+}
+
+/*
+ * Return 0 upon success. Otherwise, -1.
+ */
+static int
+lmshrd_door_check_srv_status(int opcode, smb_dr_ctx_t *dec_ctx)
+{
+ int status = smb_dr_get_int32(dec_ctx);
+ int err;
+ int rc = -1;
+
+ switch (status) {
+ case LMSHR_DOOR_SRV_SUCCESS:
+ rc = 0;
+ break;
+
+ case LMSHR_DOOR_SRV_ERROR:
+ err = smb_dr_get_uint32(dec_ctx);
+ syslog(LOG_ERR, "%s: Encountered door server error %s",
+ lmshrd_desc[opcode], strerror(err));
+ break;
+
+ default:
+ syslog(LOG_ERR, "%s: Unknown door server status",
+ lmshrd_desc[opcode]);
+ }
+
+ if (rc != 0) {
+ if ((err = smb_dr_decode_finish(dec_ctx)) != 0)
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(err));
+ }
+
+ return (rc);
+}
+
+uint64_t
+lmshrd_open_iterator(int mode)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ uint64_t lmshr_iter = 0;
+ int opcode = LMSHR_DOOR_OPEN_ITERATOR;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (lmshr_iter);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (lmshr_iter);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_int32(enc_ctx, mode);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (lmshr_iter);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (lmshr_iter);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (lmshr_iter);
+ }
+
+ lmshr_iter = smb_dr_get_lmshr_iterator(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (lmshr_iter);
+ }
+
+ (void) free(buf);
+ return (lmshr_iter);
+}
+
+
+DWORD
+lmshrd_close_iterator(uint64_t iterator)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ int opcode = LMSHR_DOOR_CLOSE_ITERATOR;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshr_iterator(enc_ctx, iterator);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (NERR_Success);
+}
+
+DWORD
+lmshrd_iterate(uint64_t iterator, lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ int opcode = LMSHR_DOOR_ITERATE;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ bzero(si, sizeof (lmshare_info_t));
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshr_iterator(enc_ctx, iterator);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (NERR_Success);
+}
+
+DWORD
+lmshrd_list(int offset, lmshare_list_t *list)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_LIST;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_int32(enc_ctx, offset);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ smb_dr_get_lmshr_list(dec_ctx, list);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+
+ return (rc);
+}
+
+int
+lmshrd_num_shares(void)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ DWORD num_shares;
+ int opcode = LMSHR_DOOR_NUM_SHARES;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (-1);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (-1);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_NUM_SHARES);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (-1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (-1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (-1);
+ }
+
+ num_shares = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (-1);
+ }
+
+ (void) free(buf);
+ return (num_shares);
+}
+
+DWORD
+lmshrd_delete(char *share_name)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_DELETE;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_DELETE);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+
+}
+
+DWORD
+lmshrd_rename(char *from, char *to)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_RENAME;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_RENAME);
+ smb_dr_put_string(enc_ctx, from);
+ smb_dr_put_string(enc_ctx, to);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+DWORD
+lmshrd_getinfo(char *share_name, lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_GETINFO;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_GETINFO);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+DWORD
+lmshrd_add(lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_ADD;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshare(enc_ctx, si);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+DWORD
+lmshrd_setinfo(lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_SETINFO;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshare(enc_ctx, si);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+static int
+lmshrd_check(char *share_name, int opcode)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status, rc;
+
+ if (lmshrd_door_open(opcode) == -1)
+ return (NERR_InternalError);
+
+ buf = malloc(LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_call(lmshrd_fildes, &arg) < 0) {
+ syslog(LOG_DEBUG, "%s: Door call failed %s",
+ lmshrd_desc[opcode], strerror(errno));
+ (void) free(buf);
+ lmshrd_fildes = -1;
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_int32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ lmshrd_desc[opcode], strerror(status));
+ (void) free(buf);
+ return (NERR_InternalError);
+ }
+
+ (void) free(buf);
+ return (rc);
+}
+
+int
+lmshrd_exists(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_EXISTS));
+}
+
+int
+lmshrd_is_special(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_SPECIAL));
+}
+
+int
+lmshrd_is_restricted(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_RESTRICTED));
+}
+
+int
+lmshrd_is_admin(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_ADMIN));
+}
+
+int
+lmshrd_is_valid(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_VALID));
+}
+
+int
+lmshrd_is_dir(char *path)
+{
+ return (lmshrd_check(path, LMSHR_DOOR_IS_DIR));
+}
+
+static char *
+lmshare_decode_type(unsigned int stype)
+{
+ switch (stype) {
+ case STYPE_DISKTREE:
+ return ("Disk");
+ case STYPE_PRINTQ:
+ return ("Print Queue");
+ case STYPE_DEVICE:
+ return ("Device");
+ case STYPE_IPC:
+ return ("IPC");
+ case STYPE_DFS:
+ return ("DFS");
+ case STYPE_SPECIAL:
+ return ("Special");
+ default:
+ return ("Unknown");
+ };
+}
+
+
+static void
+lmshare_loginfo(FILE *fp, lmshare_info_t *si)
+{
+ if (!si) {
+ return;
+ }
+
+ (void) fprintf(fp, "\n%s Information:\n", si->share_name);
+ (void) fprintf(fp, "\tFolder: %s\n", si->directory);
+ (void) fprintf(fp, "\tType: %s\n", lmshare_decode_type(si->stype));
+ (void) fprintf(fp, "\tComment: %s\n", si->comment);
+
+ (void) fprintf(fp, "\tStatus: %s\n",
+ ((si->mode & LMSHRM_TRANS) ? "Transient" : "Permanent"));
+
+ (void) fprintf(fp, "\tContainer: %s\n", si->container);
+}
+
+int
+lmshrd_dump_hash(char *logfname)
+{
+ lmshare_info_t si;
+ uint64_t it;
+ FILE *fp;
+
+ if ((logfname == 0) || (*logfname == 0))
+ fp = stdout;
+ else {
+ fp = fopen(logfname, "w");
+ if (fp == 0) {
+ syslog(LOG_WARNING, "LmshareDump [%s]:"
+ " cannot create logfile", logfname);
+ syslog(LOG_WARNING, "LmshareDump:"
+ " output will be written on screen");
+ }
+ }
+
+ it = lmshrd_open_iterator(LMSHRM_PERM);
+ if (it == NULL) {
+ syslog(LOG_ERR, "LmshareDump: resource shortage");
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (1);
+ }
+
+ if (lmshrd_iterate(it, &si) != NERR_Success) {
+ syslog(LOG_ERR, "LmshareDump: Iterator iterate failed");
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (1);
+ }
+ while (*si.share_name != 0) {
+ lmshare_loginfo(fp, &si);
+ if (lmshrd_iterate(it, &si) != NERR_Success) {
+ syslog(LOG_ERR, "LmshareDump: Iterator iterate failed");
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (1);
+ }
+ }
+
+ if (lmshrd_close_iterator(it) != NERR_Success) {
+ syslog(LOG_ERR, "LmshareDump: Iterator close failed");
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (1);
+ }
+ if (fp && fp != stdout) {
+ (void) fclose(fp);
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libshare/smb/sparc/Makefile b/usr/src/lib/libshare/smb/sparc/Makefile
new file mode 100644
index 0000000000..543238473c
--- /dev/null
+++ b/usr/src/lib/libshare/smb/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libshare/smb/sparcv9/Makefile b/usr/src/lib/libshare/smb/sparcv9/Makefile
new file mode 100644
index 0000000000..90b1730d23
--- /dev/null
+++ b/usr/src/lib/libshare/smb/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# 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
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libsldap/common/ns_writes.c b/usr/src/lib/libsldap/common/ns_writes.c
index 6c39272eba..4ac8c16c13 100644
--- a/usr/src/lib/libsldap/common/ns_writes.c
+++ b/usr/src/lib/libsldap/common/ns_writes.c
@@ -86,7 +86,7 @@ replace_mapped_attr_in_dn(
*new_dn = NULL;
/*
- * seperate dn into individual componets
+ * separate dn into individual componets
* e.g.
* "automountKey=user_01" , "automountMapName_test=auto_home", ...
*/
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 73bd80d201..265d22e66b 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -110,6 +110,8 @@ enum {
EZFS_BADPERMSET, /* invalid permission set name */
EZFS_NODELEGATION, /* delegated administration is disabled */
EZFS_PERMRDONLY, /* pemissions are readonly */
+ EZFS_UNSHARESMBFAILED, /* failed to unshare over smb */
+ EZFS_SHARESMBFAILED, /* failed to share over smb */
EZFS_UNKNOWN
};
@@ -320,7 +322,6 @@ extern const char *zfs_get_name(const zfs_handle_t *);
/*
* zfs dataset property management
*/
-extern int zfs_prop_valid_for_type(zfs_prop_t, int);
extern const char *zfs_prop_default_string(zfs_prop_t);
extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
extern const char *zfs_prop_column_name(zfs_prop_t);
@@ -459,15 +460,22 @@ extern int zfs_unshare(zfs_handle_t *);
* Protocol-specific share support functions.
*/
extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
+extern boolean_t zfs_is_shared_smb(zfs_handle_t *, char **);
extern int zfs_share_nfs(zfs_handle_t *);
+extern int zfs_share_smb(zfs_handle_t *);
+extern int zfs_shareall(zfs_handle_t *);
extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
+extern int zfs_unshare_smb(zfs_handle_t *, const char *);
extern int zfs_unshareall_nfs(zfs_handle_t *);
+extern int zfs_unshareall_smb(zfs_handle_t *);
+extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
+extern int zfs_unshareall(zfs_handle_t *);
extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *);
extern int zfs_share_iscsi(zfs_handle_t *);
extern int zfs_unshare_iscsi(zfs_handle_t *);
extern int zfs_iscsi_perm_check(libzfs_handle_t *, char *, ucred_t *);
extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *,
- void *, void *, int, boolean_t);
+ void *, void *, int, zfs_share_op_t);
/*
* When dealing with nvlists, verify() is extremely useful
diff --git a/usr/src/lib/libzfs/common/libzfs_changelist.c b/usr/src/lib/libzfs/common/libzfs_changelist.c
index 9ceefdc3b1..2b53f7d983 100644
--- a/usr/src/lib/libzfs/common/libzfs_changelist.c
+++ b/usr/src/lib/libzfs/common/libzfs_changelist.c
@@ -71,6 +71,7 @@ typedef struct prop_changenode {
struct prop_changelist {
zfs_prop_t cl_prop;
zfs_prop_t cl_realprop;
+ zfs_prop_t cl_shareprop; /* used with sharenfs/sharesmb */
uu_list_pool_t *cl_pool;
uu_list_t *cl_list;
boolean_t cl_waslegacy;
@@ -185,6 +186,7 @@ changelist_postfix(prop_changelist_t *clp)
cn = uu_list_prev(clp->cl_list, cn)) {
boolean_t sharenfs;
+ boolean_t sharesmb;
/*
* If we are in the global zone, but this dataset is exported
@@ -222,14 +224,18 @@ changelist_postfix(prop_changelist_t *clp)
/*
* Remount if previously mounted or mountpoint was legacy,
- * or sharenfs property is set.
+ * or sharenfs or sharesmb property is set.
*/
sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
shareopts, sizeof (shareopts), NULL, NULL, 0,
B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
- if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs) &&
- !zfs_is_mounted(cn->cn_handle, NULL) &&
+ sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB,
+ shareopts, sizeof (shareopts), NULL, NULL, 0,
+ B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
+
+ if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs ||
+ sharesmb) && !zfs_is_mounted(cn->cn_handle, NULL) &&
zfs_mount(cn->cn_handle, NULL, 0) != 0)
ret = -1;
@@ -237,11 +243,16 @@ changelist_postfix(prop_changelist_t *clp)
* We always re-share even if the filesystem is currently
* shared, so that we can adopt any new options.
*/
- if (cn->cn_shared || clp->cl_waslegacy || sharenfs) {
+ if (cn->cn_shared || clp->cl_waslegacy ||
+ sharenfs || sharesmb) {
if (sharenfs)
ret = zfs_share_nfs(cn->cn_handle);
else
ret = zfs_unshare_nfs(cn->cn_handle, NULL);
+ if (sharesmb)
+ ret = zfs_share_smb(cn->cn_handle);
+ else
+ ret = zfs_unshare_smb(cn->cn_handle, NULL);
}
}
@@ -302,21 +313,22 @@ changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
}
/*
- * Given a gathered changelist for the 'sharenfs' property, unshare all the
- * datasets in the list.
+ * Given a gathered changelist for the 'sharenfs' or 'sharesmb' property,
+ * unshare all the datasets in the list.
*/
int
-changelist_unshare(prop_changelist_t *clp)
+changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto)
{
prop_changenode_t *cn;
int ret = 0;
- if (clp->cl_prop != ZFS_PROP_SHARENFS)
+ if (clp->cl_prop != ZFS_PROP_SHARENFS &&
+ clp->cl_prop != ZFS_PROP_SHARESMB)
return (0);
for (cn = uu_list_first(clp->cl_list); cn != NULL;
cn = uu_list_next(clp->cl_list, cn)) {
- if (zfs_unshare_nfs(cn->cn_handle, NULL) != 0)
+ if (zfs_unshare_proto(cn->cn_handle, NULL, proto) != 0)
ret = -1;
}
@@ -386,6 +398,7 @@ change_one(zfs_handle_t *zhp, void *data)
char where[64];
prop_changenode_t *cn;
zprop_source_t sourcetype;
+ zprop_source_t share_sourcetype;
/*
* We only want to unmount/unshare those filesystems that may inherit
@@ -405,9 +418,25 @@ change_one(zfs_handle_t *zhp, void *data)
return (0);
}
+ /*
+ * If we are "watching" sharenfs or sharesmb
+ * then check out the companion property which is tracked
+ * in cl_shareprop
+ */
+ if (clp->cl_shareprop != ZPROP_INVAL &&
+ zfs_prop_get(zhp, clp->cl_shareprop, property,
+ sizeof (property), &share_sourcetype, where, sizeof (where),
+ B_FALSE) != 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
if (clp->cl_alldependents || clp->cl_allchildren ||
sourcetype == ZPROP_SRC_DEFAULT ||
- sourcetype == ZPROP_SRC_INHERITED) {
+ sourcetype == ZPROP_SRC_INHERITED ||
+ (clp->cl_shareprop != ZPROP_INVAL &&
+ (share_sourcetype == ZPROP_SRC_DEFAULT ||
+ share_sourcetype == ZPROP_SRC_INHERITED))) {
if ((cn = zfs_alloc(zfs_get_handle(zhp),
sizeof (prop_changenode_t))) == NULL) {
zfs_close(zhp);
@@ -507,7 +536,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
* order, regardless of their position in the hierarchy.
*/
if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
- prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
+ prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) {
compare = compare_mountpoints;
clp->cl_sorted = B_TRUE;
}
@@ -561,9 +591,19 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
clp->cl_prop != ZFS_PROP_SHARENFS &&
+ clp->cl_prop != ZFS_PROP_SHARESMB &&
clp->cl_prop != ZFS_PROP_SHAREISCSI)
return (clp);
+ /*
+ * If watching SHARENFS or SHARESMB then
+ * also watch its companion property.
+ */
+ if (clp->cl_prop == ZFS_PROP_SHARENFS)
+ clp->cl_shareprop = ZFS_PROP_SHARESMB;
+ else if (clp->cl_prop == ZFS_PROP_SHARESMB)
+ clp->cl_shareprop = ZFS_PROP_SHARENFS;
+
if (clp->cl_alldependents) {
if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
changelist_free(clp);
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index 04a37032ea..db912e7f20 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -51,6 +51,7 @@
#include <sys/spa.h>
#include <sys/zio.h>
#include <sys/zap.h>
+#include <sys/zfs_i18n.h>
#include <libzfs.h>
#include "zfs_namecheck.h"
@@ -376,7 +377,7 @@ top:
if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0)
goto top;
/*
- * If we can sucessfully destroy it, pretend that it
+ * If we can successfully destroy it, pretend that it
* never existed.
*/
if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) {
@@ -481,6 +482,8 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
char *strval;
zfs_prop_t prop;
nvlist_t *ret;
+ int chosen_normal = -1;
+ int chosen_utf = -1;
if (type == ZFS_TYPE_SNAPSHOT) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -545,7 +548,7 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
}
if (zfs_prop_readonly(prop) &&
- (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) {
+ (!zfs_prop_setonce(prop) || zhp != NULL)) {
zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "'%s' is readonly"),
propname);
@@ -636,19 +639,23 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
/*FALLTHRU*/
+ case ZFS_PROP_SHARESMB:
case ZFS_PROP_SHARENFS:
/*
- * For the mountpoint and sharenfs properties, check if
- * it can be set in a global/non-global zone based on
+ * For the mountpoint and sharenfs or sharesmb
+ * properties, check if it can be set in a
+ * global/non-global zone based on
* the zoned property value:
*
* global zone non-global zone
* --------------------------------------------------
* zoned=on mountpoint (no) mountpoint (yes)
* sharenfs (no) sharenfs (no)
+ * sharesmb (no) sharesmb (no)
*
* zoned=off mountpoint (yes) N/A
* sharenfs (yes)
+ * sharesmb (yes)
*/
if (zoned) {
if (getzoneid() == GLOBAL_ZONEID) {
@@ -659,7 +666,8 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
(void) zfs_error(hdl, EZFS_ZONED,
errbuf);
goto error;
- } else if (prop == ZFS_PROP_SHARENFS) {
+ } else if (prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"'%s' cannot be set in "
"a non-global zone"), propname);
@@ -684,17 +692,24 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
* property. Now we want to make sure that the
* property value is valid if it is sharenfs.
*/
- if (prop == ZFS_PROP_SHARENFS &&
+ if ((prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) &&
strcmp(strval, "on") != 0 &&
strcmp(strval, "off") != 0) {
+ zfs_share_proto_t proto;
+
+ if (prop == ZFS_PROP_SHARESMB)
+ proto = PROTO_SMB;
+ else
+ proto = PROTO_NFS;
/*
- * Must be an NFS option string so
- * init the libshare in order to
- * enable the parser and then parse
- * the options. We use the control API
- * since we don't care about the
- * current configuration and don't
+ * Must be an valid sharing protocol
+ * option string so init the libshare
+ * in order to enable the parser and
+ * then parse the options. We use the
+ * control API since we don't care about
+ * the current configuration and don't
* want the overhead of loading it
* until we actually do something.
*/
@@ -714,7 +729,7 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
goto error;
}
- if (zfs_parse_options(strval, "nfs") != SA_OK) {
+ if (zfs_parse_options(strval, proto) != SA_OK) {
/*
* There was an error in parsing so
* deal with it by issuing an error
@@ -734,6 +749,12 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
}
break;
+ case ZFS_PROP_UTF8ONLY:
+ chosen_utf = (int)intval;
+ break;
+ case ZFS_PROP_NORMALIZE:
+ chosen_normal = (int)intval;
+ break;
}
/*
@@ -786,6 +807,27 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
}
/*
+ * If normalization was chosen, but no UTF8 choice was made,
+ * enforce rejection of non-UTF8 names.
+ *
+ * If normalization was chosen, but rejecting non-UTF8 names
+ * was explicitly not chosen, it is an error.
+ */
+ if (chosen_normal > ZFS_NORMALIZE_NONE && chosen_utf < 0) {
+ if (nvlist_add_uint64(ret,
+ zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ } else if (chosen_normal > ZFS_NORMALIZE_NONE && chosen_utf == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be set 'on' if normalization chosen"),
+ zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ /*
* If this is an existing volume, and someone is setting the volsize,
* make sure that it matches the reservation, or add it if necessary.
*/
@@ -941,7 +983,7 @@ zfs_perms_add_who_nvlist(nvlist_t *who_nvp, uint64_t whoid, void *whostr,
* whostr may be null for everyone or create perms.
* who_type: is the type of entry in whostr. Typically this will be
* ZFS_DELEG_WHO_UNKNOWN.
- * perms: comman separated list of permissions. May be null if user
+ * perms: common separated list of permissions. May be null if user
* is requested to remove permissions by who.
* inherit: Specifies the inheritance of the permissions. Will be either
* ZFS_DELEG_PERM_LOCAL and/or ZFS_DELEG_PERM_DESCENDENT.
@@ -1833,6 +1875,11 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
mntopt_on = MNTOPT_XATTR;
mntopt_off = MNTOPT_NOXATTR;
break;
+
+ case ZFS_PROP_NBMAND:
+ mntopt_on = MNTOPT_NBMAND;
+ mntopt_off = MNTOPT_NONBMAND;
+ break;
}
/*
@@ -1871,6 +1918,7 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
case ZFS_PROP_READONLY:
case ZFS_PROP_SETUID:
case ZFS_PROP_XATTR:
+ case ZFS_PROP_NBMAND:
*val = getprop_uint64(zhp, prop, source);
if (hasmntopt(&mnt, mntopt_on) && !*val) {
@@ -4177,7 +4225,7 @@ zfs_iscsi_perm_check(libzfs_handle_t *hdl, char *dataset, ucred_t *cred)
int
zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
- void *export, void *sharetab, int sharemax, boolean_t share_on)
+ void *export, void *sharetab, int sharemax, zfs_share_op_t operation)
{
zfs_cmd_t zc = { 0 };
int error;
@@ -4186,7 +4234,7 @@ zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
(void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
- zc.zc_share.z_sharetype = share_on;
+ zc.zc_share.z_sharetype = operation;
zc.zc_share.z_sharemax = sharemax;
error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h
index 19a7590cee..cfc03791dd 100644
--- a/usr/src/lib/libzfs/common/libzfs_impl.h
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h
@@ -90,6 +90,23 @@ struct zpool_handle {
diskaddr_t zpool_start_block;
};
+typedef enum {
+ PROTO_NFS = 0,
+ PROTO_SMB = 1,
+ PROTO_END = 2
+} zfs_share_proto_t;
+
+/*
+ * The following can be used as a bitmask and any new values
+ * added must preserve that capability.
+ */
+typedef enum {
+ SHARED_NOT_SHARED = 0x0,
+ SHARED_ISCSI = 0x1,
+ SHARED_NFS = 0x2,
+ SHARED_SMB = 0x4
+} zfs_share_type_t;
+
int zfs_error(libzfs_handle_t *, int, const char *);
int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
void zfs_error_aux(libzfs_handle_t *, const char *, ...);
@@ -127,7 +144,7 @@ void changelist_rename(prop_changelist_t *, const char *, const char *);
void changelist_remove(zfs_handle_t *, prop_changelist_t *);
void changelist_free(prop_changelist_t *);
prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int);
-int changelist_unshare(prop_changelist_t *);
+int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *);
int changelist_haszonedchild(prop_changelist_t *);
void remove_mountpoint(zfs_handle_t *);
@@ -148,8 +165,10 @@ void namespace_clear(libzfs_handle_t *);
extern int zfs_init_libshare(libzfs_handle_t *, int);
extern void zfs_uninit_libshare(libzfs_handle_t *);
-extern int zfs_parse_options(char *, char *);
+extern int zfs_parse_options(char *, zfs_share_proto_t);
+extern int zfs_unshare_proto(zfs_handle_t *zhp,
+ const char *, zfs_share_proto_t *);
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c
index d7dd227bc8..6810f7efdc 100644
--- a/usr/src/lib/libzfs/common/libzfs_mount.c
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c
@@ -45,11 +45,17 @@
* zfs_unshare()
*
* zfs_is_shared_nfs()
- * zfs_share_nfs()
- * zfs_unshare_nfs()
- * zfs_unshareall_nfs()
+ * zfs_is_shared_smb()
* zfs_is_shared_iscsi()
+ * zfs_share_proto()
+ * zfs_shareall();
* zfs_share_iscsi()
+ * zfs_unshare_nfs()
+ * zfs_unshare_smb()
+ * zfs_unshareall_nfs()
+ * zfs_unshareall_smb()
+ * zfs_unshareall()
+ * zfs_unshareall_bypath()
* zfs_unshare_iscsi()
*
* The following functions are available for pool consumers, and will
@@ -82,11 +88,46 @@
#include <sys/systeminfo.h>
#define MAXISALEN 257 /* based on sysinfo(2) man page */
+static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
+zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
+ zfs_share_proto_t);
+
static int (*iscsitgt_zfs_share)(const char *);
static int (*iscsitgt_zfs_unshare)(const char *);
static int (*iscsitgt_zfs_is_shared)(const char *);
static int (*iscsitgt_svc_online)();
+/*
+ * The share protocols table must be in the same order as the zfs_share_prot_t
+ * enum in libzfs_impl.h
+ */
+typedef struct {
+ zfs_prop_t p_prop;
+ char *p_name;
+ int p_share_err;
+ int p_unshare_err;
+} proto_table_t;
+
+proto_table_t proto_table[PROTO_END] = {
+ {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
+ {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
+};
+
+zfs_share_proto_t nfs_only[] = {
+ PROTO_NFS,
+ PROTO_END
+};
+
+zfs_share_proto_t smb_only[] = {
+ PROTO_SMB,
+ PROTO_END
+};
+zfs_share_proto_t share_all_proto[] = {
+ PROTO_NFS,
+ PROTO_SMB,
+ PROTO_END
+};
+
#pragma init(zfs_iscsi_init)
static void
zfs_iscsi_init(void)
@@ -111,29 +152,54 @@ zfs_iscsi_init(void)
}
/*
- * Search the sharetab for the given mountpoint, returning true if it is found.
+ * Search the sharetab for the given mountpoint and protocol, returning
+ * a zfs_share_type_t value.
*/
-static boolean_t
-is_shared(libzfs_handle_t *hdl, const char *mountpoint)
+static zfs_share_type_t
+is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
{
char buf[MAXPATHLEN], *tab;
+ char *ptr;
if (hdl->libzfs_sharetab == NULL)
- return (0);
+ return (SHARED_NOT_SHARED);
(void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
/* the mountpoint is the first entry on each line */
- if ((tab = strchr(buf, '\t')) != NULL) {
+ if ((tab = strchr(buf, '\t')) == NULL)
+ continue;
+
+ *tab = '\0';
+ if (strcmp(buf, mountpoint) == 0) {
+ /*
+ * the protocol field is the third field
+ * skip over second field
+ */
+ ptr = ++tab;
+ if ((tab = strchr(ptr, '\t')) == NULL)
+ continue;
+ ptr = ++tab;
+ if ((tab = strchr(ptr, '\t')) == NULL)
+ continue;
*tab = '\0';
- if (strcmp(buf, mountpoint) == 0)
- return (B_TRUE);
+ if (strcmp(ptr,
+ proto_table[proto].p_name) == 0) {
+ switch (proto) {
+ case PROTO_NFS:
+ return (SHARED_NFS);
+ case PROTO_SMB:
+ return (SHARED_SMB);
+ default:
+ return (0);
+ }
+ }
}
}
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
}
/*
@@ -349,12 +415,12 @@ zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
/*
* Unshare and unmount the filesystem
*/
- if (zfs_unshare_nfs(zhp, mntpt) != 0)
+ if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
return (-1);
if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) {
free(mntpt);
- (void) zfs_share_nfs(zhp);
+ (void) zfs_shareall(zhp);
return (-1);
}
free(mntpt);
@@ -387,10 +453,17 @@ zfs_unmountall(zfs_handle_t *zhp, int flags)
boolean_t
zfs_is_shared(zfs_handle_t *zhp)
{
+ zfs_share_type_t rc = 0;
+ zfs_share_proto_t *curr_proto;
+
if (ZFS_IS_VOLUME(zhp))
return (zfs_is_shared_iscsi(zhp));
- return (zfs_is_shared_nfs(zhp, NULL));
+ for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+ curr_proto++)
+ rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto);
+
+ return (rc ? B_TRUE : B_FALSE);
}
int
@@ -399,7 +472,7 @@ zfs_share(zfs_handle_t *zhp)
if (ZFS_IS_VOLUME(zhp))
return (zfs_share_iscsi(zhp));
- return (zfs_share_nfs(zhp));
+ return (zfs_share_proto(zhp, share_all_proto));
}
int
@@ -408,32 +481,47 @@ zfs_unshare(zfs_handle_t *zhp)
if (ZFS_IS_VOLUME(zhp))
return (zfs_unshare_iscsi(zhp));
- return (zfs_unshare_nfs(zhp, NULL));
+ return (zfs_unshareall(zhp));
}
/*
* Check to see if the filesystem is currently shared.
*/
-boolean_t
-zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
+zfs_share_type_t
+zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
{
char *mountpoint;
+ zfs_share_type_t rc;
if (!zfs_is_mounted(zhp, &mountpoint))
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
- if (is_shared(zhp->zfs_hdl, mountpoint)) {
+ if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) {
if (where != NULL)
*where = mountpoint;
else
free(mountpoint);
- return (B_TRUE);
+ return (rc);
} else {
free(mountpoint);
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
}
}
+boolean_t
+zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
+{
+ return (zfs_is_shared_proto(zhp, where,
+ PROTO_NFS) != SHARED_NOT_SHARED);
+}
+
+boolean_t
+zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
+{
+ return (zfs_is_shared_proto(zhp, where,
+ PROTO_SMB) != SHARED_NOT_SHARED);
+}
+
/*
* Make sure things will work if libshare isn't installed by using
* wrapper functions that check to see that the pointers to functions
@@ -552,12 +640,13 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle)
*/
int
-zfs_parse_options(char *options, char *proto)
+zfs_parse_options(char *options, zfs_share_proto_t proto)
{
int ret;
if (_sa_parse_legacy_options != NULL)
- ret = _sa_parse_legacy_options(NULL, options, proto);
+ ret = _sa_parse_legacy_options(NULL, options,
+ proto_table[proto].p_name);
else
ret = SA_CONFIG_ERR;
return (ret);
@@ -609,74 +698,102 @@ zfs_sa_disable_share(sa_share_t share, char *proto)
}
/*
- * Share the given filesystem according to the options in 'sharenfs'. We rely
+ * Share the given filesystem according to the options in the specified
+ * protocol specific properties (sharenfs, sharesmb). We rely
* on "libshare" to the dirty work for us.
*/
-int
-zfs_share_nfs(zfs_handle_t *zhp)
+static int
+zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
char mountpoint[ZFS_MAXPROPLEN];
char shareopts[ZFS_MAXPROPLEN];
libzfs_handle_t *hdl = zhp->zfs_hdl;
sa_share_t share;
+ zfs_share_proto_t *curr_proto;
int ret;
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
return (0);
- /*
- * Return success if there are no share options.
- */
- if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts),
- NULL, NULL, 0, B_FALSE) != 0 ||
- strcmp(shareopts, "off") == 0)
- return (0);
-
- /*
- * If the 'zoned' property is set, then zfs_is_mountable() will have
- * already bailed out if we are in the global zone. But local
- * zones cannot be NFS servers, so we ignore it for local zones as well.
- */
- if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
- return (0);
-
if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
zfs_get_name(zhp), _sa_errorstr(ret));
return (-1);
}
- share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
- if (share != NULL) {
- int err;
- err = zfs_sa_enable_share(share, "nfs");
- if (err != SA_OK) {
- (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
+
+ for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
+ /*
+ * Return success if there are no share options.
+ */
+ if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
+ shareopts, sizeof (shareopts), NULL, NULL,
+ 0, B_FALSE) != 0 || strcmp(shareopts, "off") == 0)
+ continue;
+
+ /*
+ * If the 'zoned' property is set, then zfs_is_mountable()
+ * will have already bailed out if we are in the global zone.
+ * But local zones cannot be NFS servers, so we ignore it for
+ * local zones as well.
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
+ continue;
+
+ share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
+ if (share != NULL) {
+ int err;
+ err = zfs_sa_enable_share(share,
+ proto_table[*curr_proto].p_name);
+ if (err != SA_OK) {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
+ dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+ zfs_get_name(zhp));
+ return (-1);
+ }
+ } else {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
zfs_get_name(zhp));
return (-1);
}
- } else {
- (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
- dgettext(TEXT_DOMAIN, "cannot share '%s'"),
- zfs_get_name(zhp));
- return (-1);
- }
+ }
return (0);
}
+
+int
+zfs_share_nfs(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, nfs_only));
+}
+
+int
+zfs_share_smb(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, smb_only));
+}
+
+int
+zfs_shareall(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, share_all_proto));
+}
+
/*
* Unshare a filesystem by mountpoint.
*/
static int
-unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
+unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
+ zfs_share_proto_t proto)
{
sa_share_t share;
int err;
char *mntpt;
-
/*
* Mountpoint could get trashed if libshare calls getmntany
* which id does during API initialization, so strdup the
@@ -696,7 +813,7 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
free(mntpt); /* don't need the copy anymore */
if (share != NULL) {
- err = zfs_sa_disable_share(share, "nfs");
+ err = zfs_sa_disable_share(share, proto_table[proto].p_name);
if (err != SA_OK) {
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
@@ -714,7 +831,8 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
* Unshare the given filesystem.
*/
int
-zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
+zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
+ zfs_share_proto_t *proto)
{
struct mnttab search = { 0 }, entry;
char *mntpt = NULL;
@@ -724,19 +842,25 @@ zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
search.mnt_fstype = MNTTYPE_ZFS;
rewind(zhp->zfs_hdl->libzfs_mnttab);
if (mountpoint != NULL)
- mountpoint = mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);
+ mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
+ zfs_share_proto_t *curr_proto;
if (mountpoint == NULL)
- mountpoint = entry.mnt_mountp;
+ mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
- if (is_shared(zhp->zfs_hdl, mountpoint) &&
- unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0) {
- if (mntpt != NULL)
- free(mntpt);
- return (-1);
+ for (curr_proto = proto; *curr_proto != PROTO_END;
+ curr_proto++) {
+
+ if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) &&
+ unshare_one(zhp->zfs_hdl, zhp->zfs_name,
+ mntpt, *curr_proto) != 0) {
+ if (mntpt != NULL)
+ free(mntpt);
+ return (-1);
+ }
}
}
if (mntpt != NULL)
@@ -745,11 +869,23 @@ zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
return (0);
}
+int
+zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
+}
+
+int
+zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, smb_only));
+}
+
/*
- * Same as zfs_unmountall(), but for NFS unshares.
+ * Same as zfs_unmountall(), but for NFS and SMB unshares.
*/
int
-zfs_unshareall_nfs(zfs_handle_t *zhp)
+zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
prop_changelist_t *clp;
int ret;
@@ -758,12 +894,36 @@ zfs_unshareall_nfs(zfs_handle_t *zhp)
if (clp == NULL)
return (-1);
- ret = changelist_unshare(clp);
+ ret = changelist_unshare(clp, proto);
changelist_free(clp);
return (ret);
}
+int
+zfs_unshareall_nfs(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, nfs_only));
+}
+
+int
+zfs_unshareall_smb(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, smb_only));
+}
+
+int
+zfs_unshareall(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, share_all_proto));
+}
+
+int
+zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
+}
+
/*
* Remove the mountpoint associated with the current dataset, if necessary.
* We only remove the underlying directory if:
@@ -805,7 +965,7 @@ zfs_is_shared_iscsi(zfs_handle_t *zhp)
* If iscsi deamon isn't running then we aren't shared
*/
if (iscsitgt_svc_online && iscsitgt_svc_online() == 1)
- return (0);
+ return (B_FALSE);
else
return (iscsitgt_zfs_is_shared != NULL &&
iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
@@ -853,7 +1013,7 @@ zfs_unshare_iscsi(zfs_handle_t *zhp)
/*
* Return if the volume is not shared
*/
- if (!zfs_is_shared_iscsi(zhp))
+ if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI)
return (0);
/*
@@ -1143,9 +1303,14 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
* Walk through and first unshare everything.
*/
for (i = 0; i < used; i++) {
- if (is_shared(hdl, mountpoints[i]) &&
- unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0)
- goto out;
+ zfs_share_proto_t *curr_proto;
+ for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+ curr_proto++) {
+ if (is_shared(hdl, mountpoints[i], *curr_proto) &&
+ unshare_one(hdl, mountpoints[i],
+ mountpoints[i], *curr_proto) != 0)
+ goto out;
+ }
}
/*
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index d446b32091..8a1ad6d656 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -136,6 +136,10 @@ libzfs_error_description(libzfs_handle_t *hdl)
return (dgettext(TEXT_DOMAIN, "unshare(1M) failed"));
case EZFS_SHARENFSFAILED:
return (dgettext(TEXT_DOMAIN, "share(1M) failed"));
+ case EZFS_UNSHARESMBFAILED:
+ return (dgettext(TEXT_DOMAIN, "smb remove share failed"));
+ case EZFS_SHARESMBFAILED:
+ return (dgettext(TEXT_DOMAIN, "smb add share failed"));
case EZFS_ISCSISVCUNAVAIL:
return (dgettext(TEXT_DOMAIN,
"iscsitgt service need to be enabled by "
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index 1ca0da3453..d7d68f8708 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -53,6 +53,7 @@ SUNWprivate_1.1 {
zfs_is_shared;
zfs_is_shared_iscsi;
zfs_is_shared_nfs;
+ zfs_is_shared_smb;
zfs_iter_children;
zfs_iter_dependents;
zfs_iter_filesystems;
@@ -92,7 +93,9 @@ SUNWprivate_1.1 {
zfs_rollback;
zfs_send;
zfs_share;
+ zfs_shareall;
zfs_share_nfs;
+ zfs_share_smb;
zfs_share_iscsi;
zfs_snapshot;
zfs_type_to_name;
@@ -101,7 +104,11 @@ SUNWprivate_1.1 {
zfs_unshare;
zfs_unshare_iscsi;
zfs_unshare_nfs;
+ zfs_unshare_smb;
+ zfs_unshareall;
+ zfs_unshareall_bypath;
zfs_unshareall_nfs;
+ zfs_unshareall_smb;
zpool_add;
zpool_clear;
zpool_close;
diff --git a/usr/src/lib/libzpool/common/kernel.c b/usr/src/lib/libzpool/common/kernel.c
index 12219b72a9..e8ce11b2a5 100644
--- a/usr/src/lib/libzpool/common/kernel.c
+++ b/usr/src/lib/libzpool/common/kernel.c
@@ -389,9 +389,10 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
return (0);
}
+/*ARGSUSED*/
int
vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
- int x3, vnode_t *startvp)
+ int x3, vnode_t *startvp, int fd)
{
char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL);
int ret;
@@ -399,6 +400,7 @@ vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
ASSERT(startvp == rootdir);
(void) sprintf(realpath, "/%s", path);
+ /* fd ignored for now, need if want to simulate nbmand support */
ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3);
umem_free(realpath, strlen(path) + 2);
@@ -622,7 +624,8 @@ kobj_open_file(char *name)
vnode_t *vp;
/* set vp as the _fd field of the file */
- if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir) != 0)
+ if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir,
+ -1) != 0)
return ((void *)-1UL);
file = umem_zalloc(sizeof (struct _buf), UMEM_NOFAIL);
@@ -814,6 +817,14 @@ z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen,
return (ret);
}
+/*ARGSUSED*/
+size_t u8_textprep_str(char *i, size_t *il, char *o, size_t *ol, int nf,
+ size_t vers, int *err)
+{
+ *err = EINVAL;
+ return ((size_t)-1);
+}
+
uid_t
crgetuid(cred_t *cr)
{
diff --git a/usr/src/lib/libzpool/common/sys/zfs_context.h b/usr/src/lib/libzpool/common/sys/zfs_context.h
index 628a9c25a4..7825bfcb08 100644
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h
@@ -322,6 +322,9 @@ extern void taskq_destroy(taskq_t *);
extern void taskq_wait(taskq_t *);
extern int taskq_member(taskq_t *, void *);
+#define XVA_MAPSIZE 3
+#define XVA_MAGIC 0x78766174
+
/*
* vnodes
*/
@@ -331,41 +334,79 @@ typedef struct vnode {
char *v_path;
} vnode_t;
+
+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_settable;
+ uint8_t xoa_opaque;
+ uint8_t xoa_av_quarantined;
+ uint8_t xoa_av_modified;
+} xoptattr_t;
+
typedef struct vattr {
uint_t va_mask; /* bit-mask of attributes */
u_offset_t va_size; /* file size in bytes */
} vattr_t;
-#define AT_TYPE 0x0001
-#define AT_MODE 0x0002
-#define AT_UID 0x0004
-#define AT_GID 0x0008
-#define AT_FSID 0x0010
-#define AT_NODEID 0x0020
-#define AT_NLINK 0x0040
-#define AT_SIZE 0x0080
-#define AT_ATIME 0x0100
-#define AT_MTIME 0x0200
-#define AT_CTIME 0x0400
-#define AT_RDEV 0x0800
-#define AT_BLKSIZE 0x1000
-#define AT_NBLOCKS 0x2000
-#define AT_SEQ 0x8000
+
+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;
+
+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 */
+} vsecattr_t;
+
+#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
+#define AT_SEQ 0x08000
+#define AT_XVATTR 0x10000
#define CRCREAT 0
-#define VOP_CLOSE(vp, f, c, o, cr) 0
-#define VOP_PUTPAGE(vp, of, sz, fl, cr) 0
-#define VOP_GETATTR(vp, vap, fl, cr) ((vap)->va_size = (vp)->v_size, 0)
+#define VOP_CLOSE(vp, f, c, o, cr, ct) 0
+#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) 0
+#define VOP_GETATTR(vp, vap, fl, cr, ct) ((vap)->va_size = (vp)->v_size, 0)
-#define VOP_FSYNC(vp, f, cr) fsync((vp)->v_fd)
+#define VOP_FSYNC(vp, f, cr, ct) fsync((vp)->v_fd)
#define VN_RELE(vp) vn_close(vp)
extern int vn_open(char *path, int x1, int oflags, int mode, vnode_t **vpp,
int x2, int x3);
extern int vn_openat(char *path, int x1, int oflags, int mode, vnode_t **vpp,
- int x2, int x3, vnode_t *vp);
+ int x2, int x3, vnode_t *vp, int fd);
extern int vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len,
offset_t offset, int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp);
extern void vn_close(vnode_t *vp);
@@ -453,6 +494,21 @@ struct bootstat {
uint64_t st_size;
};
+typedef struct ace_object {
+ uid_t a_who;
+ uint32_t a_access_mask;
+ uint16_t a_flags;
+ uint16_t a_type;
+ uint8_t a_obj_type[16];
+ uint8_t a_inherit_obj_type[16];
+} ace_object_t;
+
+
+#define ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05
+#define ACE_ACCESS_DENIED_OBJECT_ACE_TYPE 0x06
+#define ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07
+#define ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08
+
extern struct _buf *kobj_open_file(char *name);
extern int kobj_read_file(struct _buf *file, char *buf, unsigned size,
unsigned off);
@@ -464,6 +520,25 @@ extern int zfs_secpolicy_rename_perms(const char *from, const char *to,
extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
extern zoneid_t getzoneid(void);
+/*
+ * UTF-8 text preparation functions and their macros.
+ * (sunddi.h)
+ */
+#define U8_STRCMP_CS 0x00000001
+#define U8_STRCMP_CI_UPPER 0x00000002
+#define U8_STRCMP_CI_LOWER 0x00000004
+
+#define U8_TEXTPREP_TOUPPER U8_STRCMP_CI_UPPER
+#define U8_TEXTPREP_TOLOWER U8_STRCMP_CI_LOWER
+#define U8_TEXTPREP_IGNORE_NULL 0x00010000
+
+#define U8_UNICODE_320 (0)
+#define U8_UNICODE_500 (1)
+#define U8_UNICODE_LATEST U8_UNICODE_500
+
+extern size_t u8_textprep_str(char *, size_t *, char *, size_t *, int, size_t,
+ int *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/pam_modules/Makefile b/usr/src/lib/pam_modules/Makefile
index c5692283be..0dce8eb7b1 100644
--- a/usr/src/lib/pam_modules/Makefile
+++ b/usr/src/lib/pam_modules/Makefile
@@ -49,7 +49,8 @@ SUBDIRS = \
unix_auth \
unix_account \
unix_cred \
- unix_session
+ unix_session \
+ smb
$(CLOSED_BUILD)SUBDIRS += \
$(CLOSED)/lib/pam_modules/smartcard
diff --git a/usr/src/lib/pam_modules/smb/Makefile b/usr/src/lib/pam_modules/smb/Makefile
new file mode 100644
index 0000000000..ea50c3ae1f
--- /dev/null
+++ b/usr/src/lib/pam_modules/smb/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 (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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+TEXT_DOMAIN= SUNW_OST_SYSOSPAM
+POFILE= smb_passwd.po
+MSGFILES= smb_passwd.c
+
+SUBDIRS= $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+include ../../Makefile.targ
diff --git a/usr/src/lib/pam_modules/smb/Makefile.com b/usr/src/lib/pam_modules/smb/Makefile.com
new file mode 100644
index 0000000000..8afe5b8232
--- /dev/null
+++ b/usr/src/lib/pam_modules/smb/Makefile.com
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY= pam_smb_passwd.a
+VERS= .1
+OBJECTS= smb_passwd.o
+
+include ../../Makefile.pam_modules
+
+LDLIBS += -lpam -lc
+LDLIBS += -L$(ROOT)/usr/lib/smbsrv -lsmb
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/pam_modules/smb/amd64/Makefile b/usr/src/lib/pam_modules/smb/amd64/Makefile
new file mode 100644
index 0000000000..8b0fed8b9f
--- /dev/null
+++ b/usr/src/lib/pam_modules/smb/amd64/Makefile
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/smbsrv/$(MACH64)
+DYNFLAGS += $(ROOT)/usr/lib/$(MACH64)/passwdutil.so.1
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/pam_modules/smb/i386/Makefile b/usr/src/lib/pam_modules/smb/i386/Makefile
new file mode 100644
index 0000000000..5be2ca90df
--- /dev/null
+++ b/usr/src/lib/pam_modules/smb/i386/Makefile
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+DYNFLAGS += -R/usr/lib/smbsrv
+DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/pam_modules/smb/mapfile-vers b/usr/src/lib/pam_modules/smb/mapfile-vers
new file mode 100644
index 0000000000..2a7c980a33
--- /dev/null
+++ b/usr/src/lib/pam_modules/smb/mapfile-vers
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNW_1.1 {
+ global:
+ pam_sm_chauthtok;
+ local:
+ *;
+};
diff --git a/usr/src/lib/pam_modules/smb/smb_passwd.c b/usr/src/lib/pam_modules/smb/smb_passwd.c
new file mode 100644
index 0000000000..9167d093a6
--- /dev/null
+++ b/usr/src/lib/pam_modules/smb/smb_passwd.c
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/varargs.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdlib.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_impl.h>
+
+#include <libintl.h>
+#include <passwdutil.h>
+
+#include <smbsrv/libsmb.h>
+
+/*PRINTFLIKE3*/
+static void
+error(boolean_t nowarn, pam_handle_t *pamh, char *fmt, ...)
+{
+ va_list ap;
+ char message[PAM_MAX_MSG_SIZE];
+
+ if (nowarn)
+ return;
+
+ va_start(ap, fmt);
+ (void) vsnprintf(message, sizeof (message), fmt, ap);
+ (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, &message,
+ NULL);
+ va_end(ap);
+}
+
+/*PRINTFLIKE3*/
+static void
+info(boolean_t nowarn, pam_handle_t *pamh, char *fmt, ...)
+{
+ va_list ap;
+ char message[PAM_MAX_MSG_SIZE];
+
+ if (nowarn)
+ return;
+
+ va_start(ap, fmt);
+ (void) vsnprintf(message, sizeof (message), fmt, ap);
+ (void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, &message,
+ NULL);
+ va_end(ap);
+}
+
+int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ boolean_t debug = B_FALSE;
+ boolean_t nowarn = B_FALSE;
+ pwu_repository_t files_rep;
+ char *user, *local_user;
+ char *newpw;
+ char *service;
+ int privileged;
+ int res;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = B_TRUE;
+ else if (strcmp(argv[i], "nowarn") == 0)
+ nowarn = B_TRUE;
+ }
+
+ if ((flags & PAM_PRELIM_CHECK) != 0)
+ return (PAM_IGNORE);
+
+ if ((flags & PAM_UPDATE_AUTHTOK) == 0)
+ return (PAM_SYSTEM_ERR);
+
+ if ((flags & PAM_SILENT) != 0)
+ nowarn = B_TRUE;
+
+ if (debug)
+ __pam_log(LOG_AUTH | LOG_DEBUG,
+ "pam_smb_passwd: storing authtok");
+
+ (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
+ (void) pam_get_item(pamh, PAM_USER, (void **)&user);
+
+ if (user == NULL || *user == '\0') {
+ __pam_log(LOG_AUTH | LOG_ERR,
+ "pam_smb_passwd: username is empty");
+ return (PAM_USER_UNKNOWN);
+ }
+
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&newpw);
+ if (newpw == NULL) {
+ /*
+ * A module on the stack has removed PAM_AUTHTOK. We fail
+ */
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ /* Check to see if this is a local user */
+ files_rep.type = "files";
+ files_rep.scope = NULL;
+ files_rep.scope_len = 0;
+ res = __user_to_authenticate(user, &files_rep, &local_user,
+ &privileged);
+ if (res != PWU_SUCCESS) {
+ switch (res) {
+ case PWU_NOT_FOUND:
+ /* if not a local user, ignore */
+ if (debug) {
+ __pam_log(LOG_AUTH | LOG_DEBUG,
+ "pam_smb_passwd: %s is not local", user);
+ }
+ return (PAM_IGNORE);
+ case PWU_DENIED:
+ return (PAM_PERM_DENIED);
+ }
+ return (PAM_SYSTEM_ERR);
+ }
+
+ res = smb_pwd_setpasswd(user, newpw);
+
+ /*
+ * now map the various return states to user messages
+ * and PAM return codes.
+ */
+ switch (res) {
+ case SMB_PWE_SUCCESS:
+ info(nowarn, pamh, dgettext(TEXT_DOMAIN,
+ "%s: SMB password successfully changed for %s"),
+ service, user);
+ return (PAM_SUCCESS);
+
+ case SMB_PWE_STAT_FAILED:
+ __pam_log(LOG_AUTH | LOG_ERR,
+ "%s: stat of SMB password file failed", service);
+ return (PAM_SYSTEM_ERR);
+
+ case SMB_PWE_OPEN_FAILED:
+ case SMB_PWE_WRITE_FAILED:
+ case SMB_PWE_CLOSE_FAILED:
+ case SMB_PWE_UPDATE_FAILED:
+ error(nowarn, pamh, dgettext(TEXT_DOMAIN,
+ "%s: Unexpected failure. SMB password database unchanged."),
+ service);
+ return (PAM_SYSTEM_ERR);
+
+ case SMB_PWE_BUSY:
+ error(nowarn, pamh, dgettext(TEXT_DOMAIN,
+ "%s: SMB password database busy. Try again later."),
+ service);
+
+ return (PAM_AUTHTOK_LOCK_BUSY);
+
+ case SMB_PWE_USER_UNKNOWN:
+ error(nowarn, pamh, dgettext(TEXT_DOMAIN,
+ "%s: %s does not exist."), service, user);
+ return (PAM_USER_UNKNOWN);
+
+ case SMB_PWE_USER_DISABLE:
+ error(nowarn, pamh, dgettext(TEXT_DOMAIN,
+ "%s: %s is disable. SMB password database unchanged."),
+ service, user);
+ return (PAM_IGNORE);
+
+ case SMB_PWE_DENIED:
+ return (PAM_PERM_DENIED);
+
+ default:
+ res = PAM_SYSTEM_ERR;
+ break;
+ }
+
+ return (res);
+}
diff --git a/usr/src/lib/pam_modules/smb/sparc/Makefile b/usr/src/lib/pam_modules/smb/sparc/Makefile
new file mode 100644
index 0000000000..5be2ca90df
--- /dev/null
+++ b/usr/src/lib/pam_modules/smb/sparc/Makefile
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+DYNFLAGS += -R/usr/lib/smbsrv
+DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/pam_modules/smb/sparcv9/Makefile b/usr/src/lib/pam_modules/smb/sparcv9/Makefile
new file mode 100644
index 0000000000..8b0fed8b9f
--- /dev/null
+++ b/usr/src/lib/pam_modules/smb/sparcv9/Makefile
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/smbsrv/$(MACH64)
+DYNFLAGS += $(ROOT)/usr/lib/$(MACH64)/passwdutil.so.1
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/smbsrv/Makefile b/usr/src/lib/smbsrv/Makefile
new file mode 100644
index 0000000000..a57e621ffe
--- /dev/null
+++ b/usr/src/lib/smbsrv/Makefile
@@ -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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.lib
+
+SUBDIRS = \
+ libmlsvc \
+ libmlrpc \
+ libsmb \
+ libsmbns \
+ libsmbrdr
+
+libmlrpc: libsmb
+libsmbrdr: libsmb
+libsmbns: libsmb
+libmlsvc: libsmb libmlrpc libsmbrdr libsmbns
+
+include ./Makefile.subdirs
diff --git a/usr/src/lib/smbsrv/Makefile.lib b/usr/src/lib/smbsrv/Makefile.lib
new file mode 100644
index 0000000000..abd5776bc9
--- /dev/null
+++ b/usr/src/lib/smbsrv/Makefile.lib
@@ -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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# Common Makefile definitions for smbsrv.
+#
+
+# We reset the Makefile.lib macros ROOTLIBDIR to refer to usr/lib/smbsrv
+# We also install the userland library header files under /usr/include/smbsrv
+ROOTSMBHDRDIR= $(ROOTHDRDIR)/smbsrv
+ROOTSMBHDRS= $(HDRS:%=$(ROOTSMBHDRDIR)/%)
+
+ROOTLIBDIR = $(ROOT)/usr/lib/smbsrv
+
+SRCDIR= ../common
+NDLDIR= $(ROOT)/usr/include/smbsrv/ndl
+LIBS= $(DYNLIB) $(LINTLIB)
+C99MODE = -xc99=%all
+C99LMODE = -Xc99=%all
+CPPFLAGS += -I$(SRCDIR) -I.
+DYNFLAGS += -R/usr/lib/smbsrv
+DYNFLAGS64 += -R/usr/lib/smbsrv/$(MACH64)
+LDLIBS32 += -L$(ROOT)/usr/lib/smbsrv
+LDLIBS64 += -L$(ROOT)/usr/lib/smbsrv/$(MACH64)
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+CLEANFILES += $(OBJECTS:%_ndr.o=%_ndr.c)
diff --git a/usr/src/lib/smbsrv/Makefile.smbsrv b/usr/src/lib/smbsrv/Makefile.smbsrv
new file mode 100644
index 0000000000..16d6ddfed1
--- /dev/null
+++ b/usr/src/lib/smbsrv/Makefile.smbsrv
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# 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/smbsrv/Makefile.subdirs b/usr/src/lib/smbsrv/Makefile.subdirs
new file mode 100644
index 0000000000..928a4e2167
--- /dev/null
+++ b/usr/src/lib/smbsrv/Makefile.subdirs
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+.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/smbsrv/Makefile.targ b/usr/src/lib/smbsrv/Makefile.targ
new file mode 100644
index 0000000000..92a05ef243
--- /dev/null
+++ b/usr/src/lib/smbsrv/Makefile.targ
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# Common targets for smbsrv Makefiles
+#
+
+%_ndr.c: $(NDLDIR)/%.ndl
+ $(NDRGEN) -Y $(CC) $<
+
+pics/%.o: $(SRC)/common/smbsrv/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
diff --git a/usr/src/lib/smbsrv/libmlrpc/Makefile b/usr/src/lib/smbsrv/libmlrpc/Makefile
new file mode 100644
index 0000000000..c5a61203cd
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+HDRS= libmlrpc.h
+
+include ../Makefile.smbsrv
diff --git a/usr/src/lib/smbsrv/libmlrpc/Makefile.com b/usr/src/lib/smbsrv/libmlrpc/Makefile.com
new file mode 100644
index 0000000000..86c7672546
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/Makefile.com
@@ -0,0 +1,57 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libmlrpc.a
+VERS = .1
+
+OBJS_COMMON = \
+ mlndo.o \
+ mlndr.o \
+ mlrpc_client.o \
+ mlrpc_encdec.o \
+ mlrpc_heap.o \
+ mlrpc_server.o \
+ mlrpc_svc.o
+
+NDLLIST = rpcpdu
+
+OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED) $(NDLLIST:%=%_ndr.o)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+INCS += -I$(SRC)/common/smbsrv
+
+LDLIBS += -lsmb -lc
+
+CPPFLAGS += $(INCS) -D_REENTRANT
+
+SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_SHARED:%.o=$(SRC)/common/smbsrv/%.c)
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbsrv/libmlrpc/amd64/Makefile b/usr/src/lib/smbsrv/libmlrpc/amd64/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h
new file mode 100644
index 0000000000..9a20054d8f
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBMLRPC_H
+#define _LIBMLRPC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBMLRPC_H */
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/llib-lmlrpc b/usr/src/lib/smbsrv/libmlrpc/common/llib-lmlrpc
new file mode 100644
index 0000000000..1621e3c2f6
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/llib-lmlrpc
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <smbsrv/libmlrpc.h>
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers b/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers
new file mode 100644
index 0000000000..6858b4cea0
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers
@@ -0,0 +1,57 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate {
+ global:
+ mlndr_inner;
+ mlndr_params;
+ mlndr_topmost;
+ mlnds_destruct;
+ mlnds_initialize;
+ mlrpc_binding_pool_initialize;
+ mlrpc_c_bind;
+ mlrpc_c_call;
+ mlrpc_c_free_heap;
+ mlrpc_heap_avail;
+ mlrpc_heap_create;
+ mlrpc_heap_destroy;
+ mlrpc_heap_malloc;
+ mlrpc_heap_mkvcs;
+ mlrpc_heap_strsave;
+ mlrpc_heap_used;
+ mlrpc_register_service;
+ mlsvc_lookup_context;
+ mlsvc_rpc_process;
+ mlsvc_rpc_release;
+ ndt__char;
+ ndt_s_wchar;
+ ndt__uchar;
+ ndt__ulong;
+ ndt__ushort;
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mlndo.c b/usr/src/lib/smbsrv/libmlrpc/common/mlndo.c
new file mode 100644
index 0000000000..c469223c4d
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mlndo.c
@@ -0,0 +1,534 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MLRPC server-side NDR stream (PDU) operations. Stream operations
+ * should return TRUE (non-zero) on success or FALSE (zero or a null
+ * pointer) on failure. When an operation returns FALSE, including
+ * mlndo_malloc() returning NULL, it should set the mlnds->error to
+ * indicate what went wrong.
+ *
+ * When available, the relevant ndr_reference is passed to the
+ * operation but keep in mind that it may be a null pointer.
+ *
+ * Functions mlndo_get_pdu(), mlndo_put_pdu(), and mlndo_pad_pdu()
+ * must never grow the PDU data. A request for out-of-bounds data is
+ * an error. The swap_bytes flag is 1 if NDR knows that the byte-
+ * order in the PDU is different from the local system.
+ */
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <assert.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/ndr.h>
+#include <smbsrv/ntstatus.h>
+
+#define NDOBUFSZ 128
+
+#define NDR_PDU_BLOCK_SIZE (4*1024)
+#define NDR_PDU_BLOCK_MASK (NDR_PDU_BLOCK_SIZE - 1)
+#define NDR_PDU_ALIGN(N) \
+ (((N) + NDR_PDU_BLOCK_SIZE) & ~NDR_PDU_BLOCK_MASK)
+#define NDR_PDU_MAX_SIZE (64*1024*1024)
+
+static char *mlndo_malloc(struct mlndr_stream *, unsigned,
+ struct ndr_reference *);
+static int mlndo_free(struct mlndr_stream *, char *, struct ndr_reference *);
+static int mlndo_grow_pdu(struct mlndr_stream *, unsigned long,
+ struct ndr_reference *);
+static int mlndo_pad_pdu(struct mlndr_stream *, unsigned long, unsigned long,
+ struct ndr_reference *);
+static int mlndo_get_pdu(struct mlndr_stream *, unsigned long, unsigned long,
+ char *, int, struct ndr_reference *);
+static int mlndo_put_pdu(struct mlndr_stream *, unsigned long, unsigned long,
+ char *, int, struct ndr_reference *);
+static void mlndo_tattle(struct mlndr_stream *, char *, struct ndr_reference *);
+static void mlndo_tattle_error(struct mlndr_stream *, struct ndr_reference *);
+static int mlndo_reset(struct mlndr_stream *);
+static void mlndo_destruct(struct mlndr_stream *);
+static void mlndo_hexfmt(uint8_t *, int, int, char *, int);
+
+/*
+ * The mlndr stream operations table.
+ */
+static struct mlndr_stream_ops mlnds_ops = {
+ mlndo_malloc,
+ mlndo_free,
+ mlndo_grow_pdu,
+ mlndo_pad_pdu,
+ mlndo_get_pdu,
+ mlndo_put_pdu,
+ mlndo_tattle,
+ mlndo_tattle_error,
+ mlndo_reset,
+ mlndo_destruct
+};
+
+/*
+ * mlnds_bswap
+ *
+ * Copies len bytes from src to dst such that dst contains the bytes
+ * from src in reverse order.
+ *
+ * We expect to be dealing with bytes, words, dwords etc. So the
+ * length must be non-zero and a power of 2.
+ */
+void
+mlnds_bswap(void *srcbuf, void *dstbuf, size_t len)
+{
+ uint8_t *src = (uint8_t *)srcbuf;
+ uint8_t *dst = (uint8_t *)dstbuf;
+
+ if ((len != 0) && ((len & (len - 1)) == 0)) {
+ src += len;
+
+ while (len--)
+ *dst++ = *(--src);
+ }
+}
+
+/*
+ * mlnds_initialize
+ *
+ * Initialize a stream. Sets up the PDU parameters and assigns the stream
+ * operations and the reference to the heap. An external heap is provided
+ * to the stream, rather than each stream creating its own heap.
+ */
+int
+mlnds_initialize(struct mlndr_stream *mlnds, unsigned pdu_size_hint,
+ int composite_op, mlrpc_heap_t *heap)
+{
+ unsigned size;
+
+ assert(mlnds);
+ assert(heap);
+
+ bzero(mlnds, sizeof (*mlnds));
+
+ if (pdu_size_hint > NDR_PDU_MAX_SIZE)
+ return (0);
+
+ size = (pdu_size_hint == 0) ? NDR_PDU_BLOCK_SIZE : pdu_size_hint;
+ mlnds->pdu_base_addr = malloc(size);
+ assert(mlnds->pdu_base_addr);
+
+ mlnds->pdu_max_size = size;
+ mlnds->pdu_size = 0;
+ mlnds->pdu_base_offset = (unsigned long)mlnds->pdu_base_addr;
+
+ mlnds->mlndo = &mlnds_ops;
+ mlnds->heap = (struct mlrpc_heap *)heap;
+
+ mlnds->m_op = composite_op & 0x0F;
+ mlnds->dir = composite_op & 0xF0;
+
+ mlnds->outer_queue_tailp = &mlnds->outer_queue_head;
+ return (1);
+}
+
+/*
+ * mlnds_destruct
+ *
+ * Destroy a stream. This is an external interface to provide access to
+ * the stream's destruct operation.
+ */
+void
+mlnds_destruct(struct mlndr_stream *mlnds)
+{
+ MLNDS_DESTRUCT(mlnds);
+}
+
+/*
+ * mlndo_malloc
+ *
+ * Allocate memory from the stream heap.
+ */
+/*ARGSUSED*/
+static char *
+mlndo_malloc(struct mlndr_stream *mlnds, unsigned len,
+ struct ndr_reference *ref)
+{
+ return (mlrpc_heap_malloc((mlrpc_heap_t *)mlnds->heap, len));
+}
+
+/*
+ * mlndo_free
+ *
+ * Always succeeds: cannot free individual stream allocations.
+ */
+/*ARGSUSED*/
+static int
+mlndo_free(struct mlndr_stream *mlnds, char *p, struct ndr_reference *ref)
+{
+ return (1);
+}
+
+/*
+ * mlndo_grow_pdu
+ *
+ * This is the only place that should change the size of the PDU. If the
+ * desired offset is beyond the current PDU size, we realloc the PDU
+ * buffer to accommodate the request. For efficiency, the PDU is always
+ * extended to a NDR_PDU_BLOCK_SIZE boundary. Requests to grow the PDU
+ * beyond NDR_PDU_MAX_SIZE are rejected.
+ *
+ * Returns 1 to indicate success. Otherwise 0 to indicate failure.
+ */
+static int
+mlndo_grow_pdu(struct mlndr_stream *mlnds, unsigned long want_end_offset,
+ struct ndr_reference *ref)
+{
+ unsigned char *pdu_addr;
+ unsigned pdu_max_size;
+
+ mlndo_printf(mlnds, ref, "grow %d", want_end_offset);
+
+ pdu_max_size = mlnds->pdu_max_size;
+
+ if (want_end_offset > pdu_max_size) {
+ pdu_max_size = NDR_PDU_ALIGN(want_end_offset);
+
+ if (pdu_max_size >= NDR_PDU_MAX_SIZE)
+ return (0);
+
+ pdu_addr = realloc(mlnds->pdu_base_addr, pdu_max_size);
+ if (pdu_addr == 0)
+ return (0);
+
+ mlnds->pdu_max_size = pdu_max_size;
+ mlnds->pdu_base_addr = pdu_addr;
+ mlnds->pdu_base_offset = (unsigned long)pdu_addr;
+ }
+
+ mlnds->pdu_size = want_end_offset;
+ return (1);
+}
+
+static int
+mlndo_pad_pdu(struct mlndr_stream *mlnds, unsigned long pdu_offset,
+ unsigned long n_bytes, struct ndr_reference *ref)
+{
+ unsigned char *data;
+
+ data = (unsigned char *)mlnds->pdu_base_offset;
+ data += pdu_offset;
+
+ mlndo_printf(mlnds, ref, "pad %d@%-3d", n_bytes, pdu_offset);
+
+ bzero(data, n_bytes);
+ return (1);
+}
+
+/*
+ * mlndo_get_pdu
+ *
+ * The swap flag is 1 if NDR knows that the byte-order in the PDU
+ * is different from the local system.
+ *
+ * Returns 1 on success or 0 to indicate failure.
+ */
+static int
+mlndo_get_pdu(struct mlndr_stream *mlnds, unsigned long pdu_offset,
+ unsigned long n_bytes, char *buf, int swap_bytes,
+ struct ndr_reference *ref)
+{
+ unsigned char *data;
+ char hexbuf[NDOBUFSZ];
+
+ data = (unsigned char *)mlnds->pdu_base_offset;
+ data += pdu_offset;
+
+ mlndo_hexfmt(data, n_bytes, swap_bytes, hexbuf, NDOBUFSZ);
+
+ mlndo_printf(mlnds, ref, "get %d@%-3d = %s",
+ n_bytes, pdu_offset, hexbuf);
+
+ if (!swap_bytes)
+ bcopy(data, buf, n_bytes);
+ else
+ mlnds_bswap(data, (unsigned char *)buf, n_bytes);
+
+ return (1);
+}
+
+/*
+ * mlndo_put_pdu
+ *
+ * This is a receiver makes right protocol. So we do not need
+ * to be concerned about the byte-order of an outgoing PDU.
+ */
+/*ARGSUSED*/
+static int
+mlndo_put_pdu(struct mlndr_stream *mlnds, unsigned long pdu_offset,
+ unsigned long n_bytes, char *buf, int swap_bytes,
+ struct ndr_reference *ref)
+{
+ unsigned char *data;
+ char hexbuf[NDOBUFSZ];
+
+ data = (unsigned char *)mlnds->pdu_base_offset;
+ data += pdu_offset;
+
+ mlndo_hexfmt((uint8_t *)buf, n_bytes, 0, hexbuf, NDOBUFSZ);
+
+ mlndo_printf(mlnds, ref, "put %d@%-3d = %s",
+ n_bytes, pdu_offset, hexbuf);
+
+ bcopy(buf, data, n_bytes);
+ return (1);
+}
+
+static void
+mlndo_tattle(struct mlndr_stream *mlnds, char *what,
+ struct ndr_reference *ref)
+{
+ mlndo_printf(mlnds, ref, what);
+}
+
+static void
+mlndo_tattle_error(struct mlndr_stream *mlnds, struct ndr_reference *ref)
+{
+ unsigned char *data;
+ char hexbuf[NDOBUFSZ];
+
+ data = (unsigned char *)mlnds->pdu_base_offset;
+ if (ref)
+ data += ref->pdu_offset;
+ else
+ data += mlnds->pdu_scan_offset;
+
+ mlndo_hexfmt(data, 16, 0, hexbuf, NDOBUFSZ);
+
+ mlndo_printf(mlnds, ref, "ERROR=%d REF=%d OFFSET=%d SIZE=%d/%d",
+ mlnds->error, mlnds->error_ref, mlnds->pdu_scan_offset,
+ mlnds->pdu_size, mlnds->pdu_max_size);
+ mlndo_printf(mlnds, ref, " %s", hexbuf);
+}
+
+/*
+ * mlndo_reset
+ *
+ * Reset a stream: zap the outer_queue. We don't need to tamper
+ * with the stream heap: it's handled externally to the stream.
+ */
+static int
+mlndo_reset(struct mlndr_stream *mlnds)
+{
+ mlndo_printf(mlnds, 0, "reset");
+
+ mlnds->pdu_size = 0;
+ mlnds->pdu_scan_offset = 0;
+ mlnds->outer_queue_head = 0;
+ mlnds->outer_current = 0;
+ mlnds->outer_queue_tailp = &mlnds->outer_queue_head;
+
+ return (1);
+}
+
+/*
+ * mlndo_destruct
+ *
+ * Destruct a stream: zap the outer_queue. Currently, this operation isn't
+ * required because the heap management (creation/destruction) is external
+ * to the stream but it provides a place-holder for stream cleanup.
+ */
+static void
+mlndo_destruct(struct mlndr_stream *mlnds)
+{
+ mlndo_printf(mlnds, 0, "destruct");
+
+ if (mlnds->pdu_base_addr != 0) {
+ free(mlnds->pdu_base_addr);
+ mlnds->pdu_base_addr = 0;
+ mlnds->pdu_base_offset = 0;
+ }
+
+ mlnds->outer_queue_head = 0;
+ mlnds->outer_current = 0;
+ mlnds->outer_queue_tailp = &mlnds->outer_queue_head;
+}
+
+/*
+ * Printf style formatting for NDR operations.
+ */
+void
+mlndo_printf(struct mlndr_stream *mlnds, struct ndr_reference *ref,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char buf[NDOBUFSZ];
+
+ va_start(ap, fmt);
+ (void) vsnprintf(buf, NDOBUFSZ, fmt, ap);
+ va_end(ap);
+
+ if (mlnds)
+ mlndo_fmt(mlnds, ref, buf);
+ else
+ mlndo_trace(buf);
+}
+
+/*
+ * Main output formatter for NDR operations.
+ *
+ * UI 03 ... rpc_vers get 1@0 = 5 {05}
+ * UI 03 ... rpc_vers_minor get 1@1 = 0 {00}
+ *
+ * U Marshalling flag (M=marshal, U=unmarshal)
+ * I Direction flag (I=in, O=out)
+ * ... Field name
+ * get PDU operation (get or put)
+ * 1@0 Bytes @ offset (i.e. 1 byte at offset 0)
+ * {05} Value
+ */
+void
+mlndo_fmt(struct mlndr_stream *mlnds, struct ndr_reference *ref, char *note)
+{
+ struct ndr_reference *p;
+ int indent;
+ char ref_name[NDOBUFSZ];
+ char buf[NDOBUFSZ];
+ int m_op_c = '?', dir_c = '?';
+
+ switch (mlnds->m_op) {
+ case 0: m_op_c = '-'; break;
+ case NDR_M_OP_MARSHALL: m_op_c = 'M'; break;
+ case NDR_M_OP_UNMARSHALL: m_op_c = 'U'; break;
+ default: m_op_c = '?'; break;
+ }
+
+ switch (mlnds->dir) {
+ case 0: dir_c = '-'; break;
+ case NDR_DIR_IN: dir_c = 'I'; break;
+ case NDR_DIR_OUT: dir_c = 'O'; break;
+ default: dir_c = '?'; break;
+ }
+
+ for (indent = 0, p = ref; p; p = p->enclosing)
+ indent++;
+
+ if (ref && ref->name) {
+ if (*ref->name == '[' && ref->enclosing) {
+ indent--;
+ (void) snprintf(ref_name, NDOBUFSZ, "%s%s",
+ ref->enclosing->name, ref->name);
+ } else {
+ (void) strlcpy(ref_name, ref->name, NDOBUFSZ);
+ }
+ } else {
+ (void) strlcpy(ref_name, "----", NDOBUFSZ);
+ }
+
+ (void) snprintf(buf, NDOBUFSZ, "%c%c %02d %-.*s %-*s %s",
+ m_op_c, dir_c, indent, indent,
+ "....+....+....+....+....+....",
+ 20 - indent, ref_name, note);
+
+ mlndo_trace(buf);
+}
+
+/*ARGSUSED*/
+void
+mlndo_trace(const char *s)
+{
+ /*
+ * Temporary fbt for dtrace until user space sdt enabled.
+ */
+}
+
+/*
+ * Format data as hex bytes (limit is 10 bytes):
+ *
+ * 1188689424 {10 f6 d9 46}
+ *
+ * If the input data is greater than 10 bytes, an ellipsis will
+ * be inserted before the closing brace.
+ */
+static void
+mlndo_hexfmt(uint8_t *data, int size, int swap_bytes, char *buf, int len)
+{
+ char *p = buf;
+ int interp = 1;
+ uint32_t c;
+ int n;
+ int i;
+
+ n = (size > 10) ? 10 : size;
+ if (n > len-1)
+ n = len-1;
+
+ switch (size) {
+ case 1:
+ c = *(uint8_t *)data;
+ break;
+ case 2:
+ if (swap_bytes == 0) /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ c = *(uint16_t *)data;
+ else
+ c = (data[0] << 8) | data[1];
+ break;
+ case 4:
+ if (swap_bytes == 0) { /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ c = *(uint32_t *)data;
+ } else {
+ c = (data[0] << 24) | (data[1] << 16)
+ | (data[2] << 8) | data[3];
+ }
+ break;
+ default:
+ c = 0;
+ interp = 0;
+ break;
+ }
+
+ if (interp)
+ p += sprintf(p, "%4u {", c);
+ else
+ p += sprintf(p, " {");
+
+ p += sprintf(p, "%02x", data[0]);
+ for (i = 1; i < n; i++)
+ p += sprintf(p, " %02x", data[i]);
+ if (size > 10)
+ p += sprintf(p, " ...}");
+ else
+ p += sprintf(p, "}");
+
+ /*
+ * Show c if it's a printable character or wide-char.
+ */
+ if (size < 4 && isprint((uint8_t)c))
+ (void) sprintf(p, " %c", (uint8_t)c);
+}
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mlndr.c b/usr/src/lib/smbsrv/libmlrpc/common/mlndr.c
new file mode 100644
index 0000000000..6d13d459b3
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mlndr.c
@@ -0,0 +1,1965 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Network Data Representation (NDR) is a compatible subset of the DCE RPC
+ * and MSRPC NDR. NDR is used to move parameters consisting of
+ * complicated trees of data constructs between an RPC client and server.
+ */
+
+#include <strings.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/string.h>
+#include <smbsrv/ndr.h>
+
+#define NDR_STRING_MAX 256
+
+#define NDR_IS_UNION(T) \
+ (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
+#define NDR_IS_STRING(T) \
+ (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
+
+extern struct ndr_typeinfo ndt_s_wchar;
+
+/*
+ * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
+ *
+ * Each parameter (call arguments and return values) is a TOP-MOST item.
+ * A TOP-MOST item consists of one or more OUTER items. An OUTER item
+ * consists of one or more INNER items. There are important differences
+ * between each kind, which, primarily, have to do with the allocation
+ * of memory to contain data structures and the order of processing.
+ *
+ * This is most easily demonstrated with a short example.
+ * Consider these structures:
+ *
+ * struct top_param {
+ * long level;
+ * struct list * head;
+ * long count;
+ * };
+ *
+ * struct list {
+ * struct list * next;
+ * char * str; // a string
+ * };
+ *
+ * Now, consider an instance tree like this:
+ *
+ * +---------+ +-------+ +-------+
+ * |top_param| +--->|list #1| +--->|list #2|
+ * +---------+ | +-------+ | +-------+
+ * | level | | | next ----+ | next --->(NULL)
+ * | head ----+ | str -->"foo" | str -->"bar"
+ * | count | | flag | | flag |
+ * +---------+ +-------+ +-------+
+ *
+ * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
+ * The vertical bars (|) indicate OUTER construct boundaries.
+ *
+ * +-----+----------------------+----------------------+-----+-----+-----+
+ * |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count|
+ * +-----+----------------------+----------------------+-----+-----+-----+
+ * level |<----------------------- head -------------------------->|count
+ * TOP TOP TOP
+ *
+ * Here's what to notice:
+ *
+ * - The members of the TOP-MOST construct are scattered through the Stub
+ * Data in the order they occur. This example shows a TOP-MOST construct
+ * consisting of atomic types (pointers and integers). A construct
+ * (struct) within the TOP-MOST construct would be contiguous and not
+ * scattered.
+ *
+ * - The members of OUTER constructs are contiguous, which allows for
+ * non-copied relocated (fixed-up) data structures at the packet's
+ * destination. We don't do fix-ups here. The pointers within the
+ * OUTER constructs are processed depth-first in the order that they
+ * occur. If they were processed breadth first, the sequence would
+ * be #1,"foo",#2,"bar". This is tricky because OUTER constructs may
+ * be variable length, and pointers are often encountered before the
+ * size(s) is known.
+ *
+ * - The INNER constructs are simply the members of an OUTER construct.
+ *
+ * For comparison, consider how ONC RPC would handle the same tree of
+ * data. ONC requires very little buffering, while DCE requires enough
+ * buffer space for the entire message. ONC does atom-by-atom depth-first
+ * (de)serialization and copy, while DCE allows for constructs to be
+ * "fixed-up" (relocated) in place at the destination. The packet data
+ * for the same tree processed by ONC RPC would look like this:
+ *
+ * +---------------------------------------------------------------------+
+ * |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count|
+ * +---------------------------------------------------------------------+
+ * TOP #1 #2 #2 bar #2 #1 foo #1 TOP
+ *
+ * More details about each TOP-MOST, OUTER, and INNER constructs appear
+ * throughout this source file near where such constructs are processed.
+ *
+ * NDR_REFERENCE
+ *
+ * The primary object for NDR is the struct ndr_reference.
+ *
+ * An ndr_reference indicates the local datum (i.e. native "C" data
+ * format), and the element within the Stub Data (contained within the
+ * RPC PDU (protocol data unit). An ndr_reference also indicates,
+ * largely as a debugging aid, something about the type of the
+ * element/datum, and the enclosing construct for the element. The
+ * ndr_reference's are typically allocated on the stack as locals,
+ * and the chain of ndr_reference.enclosing references is in reverse
+ * order of the call graph.
+ *
+ * The ndr_reference.datum is a pointer to the local memory that
+ * contains/receives the value. The ndr_reference.pdu_offset indicates
+ * where in the Stub Data the value is to be stored/retrieved.
+ *
+ * The ndr_reference also contains various parameters to the NDR
+ * process, such as ndr_reference.size_is, which indicates the size
+ * of variable length data, or ndr_reference.switch_is, which
+ * indicates the arm of a union to use.
+ *
+ * QUEUE OF OUTER REFERENCES
+ *
+ * Some OUTER constructs are variable size. Sometimes (often) we don't
+ * know the size of the OUTER construct until after pointers have been
+ * encountered. Hence, we can not begin processing the referent of the
+ * pointer until after the referring OUTER construct is completely
+ * processed, i.e. we don't know where to find/put the referent in the
+ * Stub Data until we know the size of all its predecessors.
+ *
+ * This is managed using the queue of OUTER references. The queue is
+ * anchored in mlndr_stream.outer_queue_head. At any time,
+ * mlndr_stream.outer_queue_tailp indicates where to put the
+ * ndr_reference for the next encountered pointer.
+ *
+ * Refer to the example above as we illustrate the queue here. In these
+ * illustrations, the queue entries are not the data structures themselves.
+ * Rather, they are ndr_reference entries which **refer** to the data
+ * structures in both the PDU and local memory.
+ *
+ * During some point in the processing, the queue looks like this:
+ *
+ * outer_current -------v
+ * outer_queue_head --> list#1 --0
+ * outer_queue_tailp ---------&
+ *
+ * When the pointer #1.next is encountered, and entry is added to the
+ * queue,
+ *
+ * outer_current -------v
+ * outer_queue_head --> list#1 --> list#2 --0
+ * outer_queue_tailp --------------------&
+ *
+ * and the members of #1 continue to be processed, which encounters
+ * #1.str:
+ *
+ * outer_current -------v
+ * outer_queue_head --> list#1 --> list#2 --> "foo" --0
+ * outer_queue_tailp ------------------------------&
+ *
+ * Upon the completion of list#1, the processing continues by moving
+ * to mlndr_stream.outer_current->next, and the tail is set to this
+ * outer member:
+ *
+ * outer_current ------------------v
+ * outer_queue_head --> list#1 --> list#2 --> "foo" --0
+ * outer_queue_tailp --------------------&
+ *
+ * Space for list#2 is allocated, either in the Stub Data or of local
+ * memory. When #2.next is encountered, it is found to be the null
+ * pointer and no reference is added to the queue. When #2.str is
+ * encountered, it is found to be valid, and a reference is added:
+ *
+ * outer_current ------------------v
+ * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
+ * outer_queue_tailp ------------------------------&
+ *
+ * Processing continues in a similar fashion with the string "bar",
+ * which is variable-length. At this point, memory for "bar" may be
+ * malloc()ed during NDR_M_OP_UNMARSHALL:
+ *
+ * outer_current -----------------------------v
+ * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
+ * outer_queue_tailp ------------------------------&
+ *
+ * And finishes on string "foo". Notice that because "bar" is a
+ * variable length string, and we don't know the PDU offset for "foo"
+ * until we reach this point.
+ *
+ * When the queue is drained (current->next==0), processing continues
+ * with the next TOP-MOST member.
+ *
+ * The queue of OUTER constructs manages the variable-length semantics
+ * of OUTER constructs and satisfies the depth-first requirement.
+ * We allow the queue to linger until the entire TOP-MOST structure is
+ * processed as an aid to debugging.
+ */
+
+static struct ndr_reference *mlndr_enter_outer_queue(struct ndr_reference *);
+extern int mlndr__ulong(struct ndr_reference *);
+
+/*
+ * TOP-MOST ELEMENTS
+ *
+ * This is fundamentally the first OUTER construct of the parameter,
+ * possibly followed by more OUTER constructs due to pointers. The
+ * datum (local memory) for TOP-MOST constructs (structs) is allocated
+ * by the caller of NDR.
+ *
+ * After the element is transferred, the outer_queue is drained.
+ *
+ * All we have to do is add an entry to the outer_queue for this
+ * top-most member, and commence the outer_queue processing.
+ */
+int
+mlndo_process(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti,
+ char *datum)
+{
+ struct ndr_reference myref;
+
+ bzero(&myref, sizeof (myref));
+ myref.stream = mlnds;
+ myref.datum = datum;
+ myref.name = "PROCESS";
+ myref.ti = ti;
+
+ return (mlndr_topmost(&myref));
+}
+
+int
+mlndo_operation(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti,
+ int opnum, char *datum)
+{
+ struct ndr_reference myref;
+
+ bzero(&myref, sizeof (myref));
+ myref.stream = mlnds;
+ myref.datum = datum;
+ myref.name = "OPERATION";
+ myref.ti = ti;
+ myref.inner_flags = NDR_F_SWITCH_IS;
+ myref.switch_is = opnum;
+
+ if (ti->type_flags != NDR_F_INTERFACE) {
+ NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
+ return (0);
+ }
+
+ return ((*ti->ndr_func)(&myref));
+}
+
+int
+mlndr_params(struct ndr_reference *params_ref)
+{
+ struct ndr_typeinfo *ti = params_ref->ti;
+
+ if (ti->type_flags == NDR_F_OPERATION)
+ return (*ti->ndr_func) (params_ref);
+ else
+ return (mlndr_topmost(params_ref));
+}
+
+int
+mlndr_topmost(struct ndr_reference *top_ref)
+{
+ struct mlndr_stream *mlnds;
+ struct ndr_typeinfo *ti;
+ struct ndr_reference *outer_ref = 0;
+ int is_varlen;
+ int is_string;
+ int error;
+ int rc;
+ unsigned n_fixed;
+ int params;
+
+ assert(top_ref);
+ assert(top_ref->stream);
+ assert(top_ref->ti);
+
+ mlnds = top_ref->stream;
+ ti = top_ref->ti;
+
+ is_varlen = ti->pdu_size_variable_part;
+ is_string = NDR_IS_STRING(ti);
+
+ assert(mlnds->outer_queue_tailp && !*mlnds->outer_queue_tailp);
+ assert(!mlnds->outer_current);
+
+ params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
+
+ switch (params) {
+ case NDR_F_NONE:
+ case NDR_F_SWITCH_IS:
+ if (is_string || is_varlen) {
+ error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
+ NDR_SET_ERROR(outer_ref, error);
+ return (0);
+ }
+ n_fixed = ti->pdu_size_fixed_part;
+ break;
+
+ case NDR_F_SIZE_IS:
+ error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
+ NDR_SET_ERROR(outer_ref, error);
+ return (0);
+
+ case NDR_F_DIMENSION_IS:
+ if (is_varlen) {
+ error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
+ NDR_SET_ERROR(outer_ref, error);
+ return (0);
+ }
+ n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
+ break;
+
+ case NDR_F_IS_POINTER:
+ case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
+ n_fixed = 4;
+ break;
+
+ case NDR_F_IS_REFERENCE:
+ case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
+ n_fixed = 0;
+ break;
+
+ default:
+ error = NDR_ERR_OUTER_PARAMS_BAD;
+ NDR_SET_ERROR(outer_ref, error);
+ return (0);
+ }
+
+ outer_ref = mlndr_enter_outer_queue(top_ref);
+ if (!outer_ref)
+ return (0); /* error already set */
+
+ /*
+ * Hand-craft the first OUTER construct and directly call
+ * mlndr_inner(). Then, run the outer_queue. We do this
+ * because mlndr_outer() wants to malloc() memory for
+ * the construct, and we already have the memory.
+ */
+
+ /* move the flags, etc, around again, undoes enter_outer_queue() */
+ outer_ref->inner_flags = top_ref->inner_flags;
+ outer_ref->outer_flags = 0;
+ outer_ref->datum = top_ref->datum;
+
+ /* All outer constructs start on a mod4 (longword) boundary */
+ if (!mlndr_outer_align(outer_ref))
+ return (0); /* error already set */
+
+ /* Regardless of what it is, this is where it starts */
+ outer_ref->pdu_offset = mlnds->pdu_scan_offset;
+
+ rc = mlndr_outer_grow(outer_ref, n_fixed);
+ if (!rc)
+ return (0); /* error already set */
+
+ outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
+
+ /* set-up outer_current, as though run_outer_queue() was doing it */
+ mlnds->outer_current = outer_ref;
+ mlnds->outer_queue_tailp = &mlnds->outer_current->next;
+ mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
+
+ /* do the topmost member */
+ rc = mlndr_inner(outer_ref);
+ if (!rc)
+ return (0); /* error already set */
+
+ mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
+
+ /* advance, as though run_outer_queue() was doing it */
+ mlnds->outer_current = mlnds->outer_current->next;
+ return (mlndr_run_outer_queue(mlnds));
+}
+
+static struct ndr_reference *
+mlndr_enter_outer_queue(struct ndr_reference *arg_ref)
+{
+ struct mlndr_stream *mlnds = arg_ref->stream;
+ struct ndr_reference *outer_ref;
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ outer_ref = (struct ndr_reference *)
+ MLNDS_MALLOC(mlnds, sizeof (*outer_ref), arg_ref);
+ if (!outer_ref) {
+ NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED);
+ return (0);
+ }
+
+ *outer_ref = *arg_ref;
+
+ /* move advice in inner_flags to outer_flags */
+ outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
+ outer_ref->inner_flags = 0;
+ outer_ref->enclosing = mlnds->outer_current;
+ outer_ref->backptr = 0;
+ outer_ref->datum = 0;
+
+ assert(mlnds->outer_queue_tailp);
+
+ outer_ref->next = *mlnds->outer_queue_tailp;
+ *mlnds->outer_queue_tailp = outer_ref;
+ mlnds->outer_queue_tailp = &outer_ref->next;
+ return (outer_ref);
+}
+
+int
+mlndr_run_outer_queue(struct mlndr_stream *mlnds)
+{
+ while (mlnds->outer_current) {
+ mlnds->outer_queue_tailp = &mlnds->outer_current->next;
+
+ if (!mlndr_outer(mlnds->outer_current))
+ return (0);
+
+ mlnds->outer_current = mlnds->outer_current->next;
+ }
+
+ return (1);
+}
+
+/*
+ * OUTER CONSTRUCTS
+ *
+ * OUTER constructs are where the real work is, which stems from the
+ * variable-length potential.
+ *
+ * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT
+ *
+ * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT,
+ * VARYING, and VARYING/CONFORMANT.
+ *
+ * What makes this so tough is that the variable-length array may be well
+ * encapsulated within the outer construct. Further, because DCE(MS)/RPC
+ * tries to keep the constructs contiguous in the data stream, the sizing
+ * information precedes the entire OUTER construct. The sizing information
+ * must be used at the appropriate time, which can be after many, many,
+ * many fixed-length elements. During IDL type analysis, we know in
+ * advance constructs that encapsulate variable-length constructs. So,
+ * we know when we have a sizing header and when we don't. The actual
+ * semantics of the header are largely deferred.
+ *
+ * Currently, VARYING constructs are not implemented but they are described
+ * here in case they have to be implemented in the future. Similarly,
+ * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently
+ * not implemented. Only one-dimensional, variable-length arrays are
+ * supported.
+ *
+ * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW
+ *
+ * All variable-length values are arrays. These arrays may be embedded
+ * well within another construct. However, a variable-length construct
+ * may ONLY appear as the last member of an enclosing construct. Example:
+ *
+ * struct credentials {
+ * ulong uid, gid;
+ * ulong n_gids;
+ * [size_is(n_gids)]
+ * ulong gids[*]; // variable-length.
+ * };
+ *
+ * CONFORMANT constructs have a dynamic size in local memory and in the
+ * PDU. The CONFORMANT quality is indicated by the [size_is()] advice.
+ * CONFORMANT constructs have the following header:
+ *
+ * struct conformant_header {
+ * ulong size_is;
+ * };
+ *
+ * (Multi-dimensional CONFORMANT arrays have a similar header for each
+ * dimension - not implemented).
+ *
+ * Example CONFORMANT construct:
+ *
+ * struct user {
+ * char * name;
+ * struct credentials cred; // see above
+ * };
+ *
+ * Consider the data tree:
+ *
+ * +--------+
+ * | user |
+ * +--------+
+ * | name ----> "fred" (the string is a different OUTER)
+ * | uid |
+ * | gid |
+ * | n_gids | for example, 3
+ * | gids[0]|
+ * | gids[1]|
+ * | gids[2]|
+ * +--------+
+ *
+ * The OUTER construct in the Stub Data would be:
+ *
+ * +---+---------+---------------------------------------------+
+ * |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]|
+ * +---+---------+---------------------------------------------+
+ * szing hdr|user |<-------------- user.cred ------------>|
+ * |<--- fixed-size ---->|<----- conformant ---->|
+ *
+ * The ndr_typeinfo for struct user will have:
+ * pdu_fixed_size_part = 16 four long words (name uid gid n_gids)
+ * pdu_variable_size_part = 4 per element, sizeof gids[0]
+ *
+ * VARYING CONSTRUCTS -- NOT IMPLEMENTED
+ *
+ * VARYING constructs have the following header:
+ *
+ * struct varying_header {
+ * ulong first_is;
+ * ulong length_is;
+ * };
+ *
+ * This indicates which interval of an array is significant.
+ * Non-intersecting elements of the array are undefined and usually
+ * zero-filled. The first_is parameter for C arrays is always 0 for
+ * the first element.
+ *
+ * N.B. Constructs may contain one CONFORMANT element, which is always
+ * last, but may contain many VARYING elements, which can be anywhere.
+ *
+ * VARYING CONFORMANT constructs have the sizing headers arranged like
+ * this:
+ *
+ * struct conformant_header all_conformant[N_CONFORMANT_DIM];
+ * struct varying_header all_varying[N_VARYING_ELEMS_AND_DIMS];
+ *
+ * The sizing header is immediately followed by the values for the
+ * construct. Again, we don't support more than one dimension and
+ * we don't support VARYING constructs at this time.
+ *
+ * A good example of a VARYING/CONFORMANT data structure is the UNIX
+ * directory entry:
+ *
+ * struct dirent {
+ * ushort reclen;
+ * ushort namlen;
+ * ulong inum;
+ * [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL
+ * uchar name[*];
+ * };
+ *
+ *
+ * STRINGS ARE A SPECIAL CASE
+ *
+ * Strings are handled specially. MS/RPC uses VARYING/CONFORMANT structures
+ * for strings. This is a simple one-dimensional variable-length array,
+ * typically with its last element all zeroes. We handle strings with the
+ * header:
+ *
+ * struct string_header {
+ * ulong size_is;
+ * ulong first_is; // always 0
+ * ulong length_is; // always same as size_is
+ * };
+ *
+ * If general support for VARYING and VARYING/CONFORMANT mechanisms is
+ * implemented, we probably won't need the strings special case.
+ */
+int
+mlndr_outer(struct ndr_reference *outer_ref)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ struct ndr_typeinfo *ti = outer_ref->ti;
+ int is_varlen = ti->pdu_size_variable_part;
+ int is_union = NDR_IS_UNION(ti);
+ int is_string = NDR_IS_STRING(ti);
+ int error = NDR_ERR_OUTER_PARAMS_BAD;
+ int params;
+
+ params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
+
+ NDR_TATTLE(outer_ref, "--OUTER--");
+
+ /* All outer constructs start on a mod4 (longword) boundary */
+ if (!mlndr_outer_align(outer_ref))
+ return (0); /* error already set */
+
+ /* Regardless of what it is, this is where it starts */
+ outer_ref->pdu_offset = mlnds->pdu_scan_offset;
+
+ if (is_union) {
+ error = NDR_ERR_OUTER_UNION_ILLEGAL;
+ NDR_SET_ERROR(outer_ref, error);
+ return (0);
+ }
+
+ switch (params) {
+ case NDR_F_NONE:
+ if (is_string)
+ return (mlndr_outer_string(outer_ref));
+ if (is_varlen)
+ return (mlndr_outer_conformant_construct(outer_ref));
+
+ return (mlndr_outer_fixed(outer_ref));
+ break;
+
+ case NDR_F_SIZE_IS:
+ case NDR_F_DIMENSION_IS:
+ if (is_varlen) {
+ error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
+ break;
+ }
+
+ if (params == NDR_F_SIZE_IS)
+ return (mlndr_outer_conformant_array(outer_ref));
+ else
+ return (mlndr_outer_fixed_array(outer_ref));
+ break;
+
+ default:
+ error = NDR_ERR_OUTER_PARAMS_BAD;
+ break;
+ }
+
+ /*
+ * If we get here, something is wrong. Most likely,
+ * the params flags do not match.
+ */
+ NDR_SET_ERROR(outer_ref, error);
+ return (0);
+}
+
+int
+mlndr_outer_fixed(struct ndr_reference *outer_ref)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ struct ndr_typeinfo *ti = outer_ref->ti;
+ struct ndr_reference myref;
+ char *valp = NULL;
+ int is_varlen = ti->pdu_size_variable_part;
+ int is_union = NDR_IS_UNION(ti);
+ int is_string = NDR_IS_STRING(ti);
+ int rc;
+ unsigned n_hdr;
+ unsigned n_fixed;
+ unsigned n_variable;
+ unsigned n_alloc;
+ unsigned n_pdu_total;
+ int params;
+
+ params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
+
+ assert(!is_varlen && !is_string && !is_union);
+ assert(params == NDR_F_NONE);
+
+ /* no header for this */
+ n_hdr = 0;
+
+ /* fixed part -- exactly one of these */
+ n_fixed = ti->pdu_size_fixed_part;
+ assert(n_fixed > 0);
+
+ /* variable part -- exactly none of these */
+ n_variable = 0;
+
+ /* sum them up to determine the PDU space required */
+ n_pdu_total = n_hdr + n_fixed + n_variable;
+
+ /* similar sum to determine how much local memory is required */
+ n_alloc = n_fixed + n_variable;
+
+ rc = mlndr_outer_grow(outer_ref, n_pdu_total);
+ if (!rc)
+ return (rc); /* error already set */
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ valp = outer_ref->datum;
+ assert(valp);
+ if (outer_ref->backptr) {
+ assert(valp == *outer_ref->backptr);
+ }
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
+ if (!valp) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
+ return (0);
+ }
+ if (outer_ref->backptr)
+ *outer_ref->backptr = valp;
+ outer_ref->datum = valp;
+ break;
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ bzero(&myref, sizeof (myref));
+ myref.stream = mlnds;
+ myref.enclosing = outer_ref;
+ myref.ti = outer_ref->ti;
+ myref.datum = outer_ref->datum;
+ myref.name = "FIXED-VALUE";
+ myref.outer_flags = NDR_F_NONE;
+ myref.inner_flags = NDR_F_NONE;
+
+ myref.pdu_offset = outer_ref->pdu_offset;
+ outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
+
+ rc = mlndr_inner(&myref);
+ if (!rc)
+ return (rc); /* error already set */
+
+ mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
+ return (1);
+}
+
+int
+mlndr_outer_fixed_array(struct ndr_reference *outer_ref)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ struct ndr_typeinfo *ti = outer_ref->ti;
+ struct ndr_reference myref;
+ char *valp = NULL;
+ int is_varlen = ti->pdu_size_variable_part;
+ int is_union = NDR_IS_UNION(ti);
+ int is_string = NDR_IS_STRING(ti);
+ int rc;
+ unsigned n_hdr;
+ unsigned n_fixed;
+ unsigned n_variable;
+ unsigned n_alloc;
+ unsigned n_pdu_total;
+ int params;
+
+ params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
+
+ assert(!is_varlen && !is_string && !is_union);
+ assert(params == NDR_F_DIMENSION_IS);
+
+ /* no header for this */
+ n_hdr = 0;
+
+ /* fixed part -- exactly dimension_is of these */
+ n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
+ assert(n_fixed > 0);
+
+ /* variable part -- exactly none of these */
+ n_variable = 0;
+
+ /* sum them up to determine the PDU space required */
+ n_pdu_total = n_hdr + n_fixed + n_variable;
+
+ /* similar sum to determine how much local memory is required */
+ n_alloc = n_fixed + n_variable;
+
+ rc = mlndr_outer_grow(outer_ref, n_pdu_total);
+ if (!rc)
+ return (rc); /* error already set */
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ valp = outer_ref->datum;
+ assert(valp);
+ if (outer_ref->backptr) {
+ assert(valp == *outer_ref->backptr);
+ }
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
+ if (!valp) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
+ return (0);
+ }
+ if (outer_ref->backptr)
+ *outer_ref->backptr = valp;
+ outer_ref->datum = valp;
+ break;
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ bzero(&myref, sizeof (myref));
+ myref.stream = mlnds;
+ myref.enclosing = outer_ref;
+ myref.ti = outer_ref->ti;
+ myref.datum = outer_ref->datum;
+ myref.name = "FIXED-ARRAY";
+ myref.outer_flags = NDR_F_NONE;
+ myref.inner_flags = NDR_F_DIMENSION_IS;
+ myref.dimension_is = outer_ref->dimension_is;
+
+ myref.pdu_offset = outer_ref->pdu_offset;
+ outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
+
+ rc = mlndr_inner(&myref);
+ if (!rc)
+ return (rc); /* error already set */
+
+ mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
+ return (1);
+}
+
+int
+mlndr_outer_conformant_array(struct ndr_reference *outer_ref)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ struct ndr_typeinfo *ti = outer_ref->ti;
+ struct ndr_reference myref;
+ char *valp = NULL;
+ int is_varlen = ti->pdu_size_variable_part;
+ int is_union = NDR_IS_UNION(ti);
+ int is_string = NDR_IS_STRING(ti);
+ unsigned long size_is;
+ int rc;
+ unsigned n_hdr;
+ unsigned n_fixed;
+ unsigned n_variable;
+ unsigned n_alloc;
+ unsigned n_pdu_total;
+ int params;
+
+ params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
+
+ assert(!is_varlen && !is_string && !is_union);
+ assert(params == NDR_F_SIZE_IS);
+
+ /* conformant header for this */
+ n_hdr = 4;
+
+ /* fixed part -- exactly none of these */
+ n_fixed = 0;
+
+ /* variable part -- exactly size_of of these */
+ /* notice that it is the **fixed** size of the ti */
+ n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
+
+ /* sum them up to determine the PDU space required */
+ n_pdu_total = n_hdr + n_fixed + n_variable;
+
+ /* similar sum to determine how much local memory is required */
+ n_alloc = n_fixed + n_variable;
+
+ rc = mlndr_outer_grow(outer_ref, n_pdu_total);
+ if (!rc)
+ return (rc); /* error already set */
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ size_is = outer_ref->size_is;
+ rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is);
+ if (!rc)
+ return (0); /* error already set */
+
+ valp = outer_ref->datum;
+ assert(valp);
+ if (outer_ref->backptr) {
+ assert(valp == *outer_ref->backptr);
+ }
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ rc = mlndr_outer_peek_sizing(outer_ref, 0, &size_is);
+ if (!rc)
+ return (0); /* error already set */
+
+ if (size_is != outer_ref->size_is) {
+ NDR_SET_ERROR(outer_ref,
+ NDR_ERR_SIZE_IS_MISMATCH_PDU);
+ return (0);
+ }
+
+ valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
+ if (!valp) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
+ return (0);
+ }
+ if (outer_ref->backptr)
+ *outer_ref->backptr = valp;
+ outer_ref->datum = valp;
+ break;
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ bzero(&myref, sizeof (myref));
+ myref.stream = mlnds;
+ myref.enclosing = outer_ref;
+ myref.ti = outer_ref->ti;
+ myref.datum = outer_ref->datum;
+ myref.name = "CONFORMANT-ARRAY";
+ myref.outer_flags = NDR_F_NONE;
+ myref.inner_flags = NDR_F_SIZE_IS;
+ myref.size_is = outer_ref->size_is;
+
+ myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */
+ myref.dimension_is = outer_ref->size_is; /* convenient */
+
+ myref.pdu_offset = outer_ref->pdu_offset + 4;
+ outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
+
+ outer_ref->type_flags = NDR_F_NONE;
+ outer_ref->inner_flags = NDR_F_NONE;
+
+ rc = mlndr_inner(&myref);
+ if (!rc)
+ return (rc); /* error already set */
+
+ mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
+ return (1);
+}
+
+int
+mlndr_outer_conformant_construct(struct ndr_reference *outer_ref)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ struct ndr_typeinfo *ti = outer_ref->ti;
+ struct ndr_reference myref;
+ char *valp = NULL;
+ int is_varlen = ti->pdu_size_variable_part;
+ int is_union = NDR_IS_UNION(ti);
+ int is_string = NDR_IS_STRING(ti);
+ unsigned long size_is;
+ int rc;
+ unsigned n_hdr;
+ unsigned n_fixed;
+ unsigned n_variable;
+ unsigned n_alloc;
+ unsigned n_pdu_total;
+ int params;
+
+ params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
+
+ assert(is_varlen && !is_string && !is_union);
+ assert(params == NDR_F_NONE);
+
+ /* conformant header for this */
+ n_hdr = 4;
+
+ /* fixed part -- exactly one of these */
+ n_fixed = ti->pdu_size_fixed_part;
+
+ /* variable part -- exactly size_of of these */
+ n_variable = 0; /* 0 for the moment */
+
+ /* sum them up to determine the PDU space required */
+ n_pdu_total = n_hdr + n_fixed + n_variable;
+
+ /* similar sum to determine how much local memory is required */
+ n_alloc = n_fixed + n_variable;
+
+ /* For the moment, grow enough for the fixed-size part */
+ rc = mlndr_outer_grow(outer_ref, n_pdu_total);
+ if (!rc)
+ return (rc); /* error already set */
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ /*
+ * We don't know the size yet. We have to wait for
+ * it. Proceed with the fixed-size part, and await
+ * the call to mlndr_size_is().
+ */
+ size_is = 0;
+ rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is);
+ if (!rc)
+ return (0); /* error already set */
+
+ valp = outer_ref->datum;
+ assert(valp);
+ if (outer_ref->backptr) {
+ assert(valp == *outer_ref->backptr);
+ }
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ /*
+ * We know the size of the variable part because
+ * of the CONFORMANT header. We will verify
+ * the header against the [size_is(X)] advice
+ * later when mlndr_size_is() is called.
+ */
+ rc = mlndr_outer_peek_sizing(outer_ref, 0, &size_is);
+ if (!rc)
+ return (0); /* error already set */
+
+ /* recalculate metrics */
+ n_variable = size_is * ti->pdu_size_variable_part;
+ n_pdu_total = n_hdr + n_fixed + n_variable;
+ n_alloc = n_fixed + n_variable;
+
+ rc = mlndr_outer_grow(outer_ref, n_pdu_total);
+ if (!rc)
+ return (rc); /* error already set */
+
+ outer_ref->size_is = size_is; /* verified later */
+
+ valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
+ if (!valp) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
+ return (0);
+ }
+ if (outer_ref->backptr)
+ *outer_ref->backptr = valp;
+ outer_ref->datum = valp;
+ break;
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ bzero(&myref, sizeof (myref));
+ myref.stream = mlnds;
+ myref.enclosing = outer_ref;
+ myref.ti = outer_ref->ti;
+ myref.datum = outer_ref->datum;
+ myref.name = "CONFORMANT-CONSTRUCT";
+ myref.outer_flags = NDR_F_NONE;
+ myref.inner_flags = NDR_F_NONE;
+ myref.size_is = outer_ref->size_is;
+
+ myref.pdu_offset = outer_ref->pdu_offset + 4;
+ outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
+
+ outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */
+ outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */
+
+ rc = mlndr_inner(&myref);
+ if (!rc)
+ return (rc); /* error already set */
+
+ mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
+
+ if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
+ NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+mlndr_size_is(struct ndr_reference *ref)
+{
+ struct mlndr_stream *mlnds = ref->stream;
+ struct ndr_reference *outer_ref = mlnds->outer_current;
+ struct ndr_typeinfo *ti = outer_ref->ti;
+ unsigned long size_is;
+ int rc;
+ unsigned n_hdr;
+ unsigned n_fixed;
+ unsigned n_variable;
+ unsigned n_pdu_total;
+
+ assert(ref->inner_flags & NDR_F_SIZE_IS);
+ size_is = ref->size_is;
+
+ if (outer_ref->type_flags != NDR_F_SIZE_IS) {
+ NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
+ return (0);
+ }
+
+ if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
+ NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
+ return (0);
+ }
+
+ /* repeat metrics, see mlndr_conformant_construct() above */
+ n_hdr = 4;
+ n_fixed = ti->pdu_size_fixed_part;
+ n_variable = size_is * ti->pdu_size_variable_part;
+ n_pdu_total = n_hdr + n_fixed + n_variable;
+
+ rc = mlndr_outer_grow(outer_ref, n_pdu_total);
+ if (!rc)
+ return (rc); /* error already set */
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ /*
+ * We have to set the sizing header and extend
+ * the size of the PDU (already done).
+ */
+ rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is);
+ if (!rc)
+ return (0); /* error already set */
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ /*
+ * Allocation done during mlndr_conformant_construct().
+ * All we are doing here is verifying that the
+ * intended size (ref->size_is) matches the sizing header.
+ */
+ if (size_is != outer_ref->size_is) {
+ NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
+ return (0);
+ }
+ break;
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ outer_ref->inner_flags |= NDR_F_SIZE_IS;
+ outer_ref->size_is = ref->size_is;
+ return (1);
+}
+
+int
+mlndr_outer_string(struct ndr_reference *outer_ref)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ struct ndr_typeinfo *ti = outer_ref->ti;
+ struct ndr_reference myref;
+ char *valp = NULL;
+ unsigned is_varlen = ti->pdu_size_variable_part;
+ int is_union = NDR_IS_UNION(ti);
+ int is_string = NDR_IS_STRING(ti);
+ int rc;
+ unsigned n_zeroes;
+ unsigned ix;
+ unsigned long size_is;
+ unsigned long first_is;
+ unsigned long length_is;
+ unsigned n_hdr;
+ unsigned n_fixed;
+ unsigned n_variable;
+ unsigned n_alloc;
+ unsigned n_pdu_total;
+ int params;
+
+ params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
+
+ assert(is_varlen && is_string && !is_union);
+ assert(params == NDR_F_NONE);
+
+ /* string header for this: size_is first_is length_is */
+ n_hdr = 12;
+
+ /* fixed part -- exactly none of these */
+ n_fixed = 0;
+
+ if (!mlndr_outer_grow(outer_ref, n_hdr))
+ return (0); /* error already set */
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ valp = outer_ref->datum;
+ assert(valp);
+
+ if (outer_ref->backptr)
+ assert(valp == *outer_ref->backptr);
+
+ if (ti == &ndt_s_wchar) {
+ /*
+ * size_is is the number of characters in the string,
+ * including the null. We assume valp is UTF-8 encoded.
+ * We can use mts_wcequiv_strlen for ASCII, extended
+ * ASCII or Unicode (UCS-2).
+ */
+ size_is = (mts_wcequiv_strlen(valp) /
+ sizeof (mts_wchar_t)) + 1;
+
+ if (size_is > NDR_STRING_MAX) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
+ return (0);
+ }
+ } else {
+ valp = outer_ref->datum;
+ n_zeroes = 0;
+ for (ix = 0; ix < 1024; ix++) {
+ if (valp[ix] == 0) {
+ n_zeroes++;
+ if (n_zeroes >= is_varlen &&
+ ix % is_varlen == 0) {
+ break;
+ }
+ } else {
+ n_zeroes = 0;
+ }
+ }
+ if (ix >= 1024) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
+ return (0);
+ }
+ size_is = ix+1;
+ }
+
+ first_is = 0;
+ length_is = size_is;
+
+ if (!mlndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
+ !mlndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
+ !mlndr_outer_poke_sizing(outer_ref, 8, &length_is))
+ return (0); /* error already set */
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ if (!mlndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
+ !mlndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
+ !mlndr_outer_peek_sizing(outer_ref, 8, &length_is))
+ return (0); /* error already set */
+
+ /*
+ * In addition to the first_is check, we used to check that
+ * size_is or size_is-1 was equal to length_is but Windows95
+ * doesn't conform to this "rule" (see variable part below).
+ * The srvmgr tool for Windows95 sent the following values
+ * for a path string:
+ *
+ * size_is = 261 (0x105)
+ * first_is = 0
+ * length_is = 53 (0x35)
+ *
+ * The length_is was correct (for the given path) but the
+ * size_is was the maximum path length rather than being
+ * related to length_is.
+ */
+ if (first_is != 0) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
+ return (0);
+ }
+
+ if (ti == &ndt_s_wchar) {
+ /*
+ * Decoding Unicode to UTF-8; we need to allow
+ * for the maximum possible char size. It would
+ * be nice to use mbequiv_strlen but the string
+ * may not be null terminated.
+ */
+ n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX;
+ } else {
+ n_alloc = (size_is + 1) * is_varlen;
+ }
+
+ valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
+ if (!valp) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
+ return (0);
+ }
+
+ bzero(valp, (size_is+1) * is_varlen);
+
+ if (outer_ref->backptr)
+ *outer_ref->backptr = valp;
+ outer_ref->datum = valp;
+ break;
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ /*
+ * Variable part - exactly length_is of these.
+ *
+ * Usually, length_is is same as size_is and includes nul.
+ * Some protocols use length_is = size_is-1, and length_is does
+ * not include the nul (which is more consistent with DCE spec).
+ * If the length_is is 0, there is no data following the
+ * sizing header, regardless of size_is.
+ */
+ n_variable = length_is * is_varlen;
+
+ /* sum them up to determine the PDU space required */
+ n_pdu_total = n_hdr + n_fixed + n_variable;
+
+ /* similar sum to determine how much local memory is required */
+ n_alloc = n_fixed + n_variable;
+
+ rc = mlndr_outer_grow(outer_ref, n_pdu_total);
+ if (!rc)
+ return (rc); /* error already set */
+
+ if (length_is > 0) {
+ bzero(&myref, sizeof (myref));
+ myref.stream = mlnds;
+ myref.enclosing = outer_ref;
+ myref.ti = outer_ref->ti;
+ myref.datum = outer_ref->datum;
+ myref.name = "OUTER-STRING";
+ myref.outer_flags = NDR_F_IS_STRING;
+ myref.inner_flags = NDR_F_NONE;
+
+ /*
+ * Set up strlen_is so that we know what to
+ * expect later (see mlndr_s_wchar).
+ */
+ myref.strlen_is = length_is;
+ }
+
+ myref.pdu_offset = outer_ref->pdu_offset + 12;
+
+ /*
+ * Don't try to decode empty strings.
+ */
+ if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
+ mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
+ return (1);
+ }
+
+ if ((size_is != 0) && (length_is != 0)) {
+ rc = mlndr_inner(&myref);
+ if (!rc)
+ return (rc); /* error already set */
+ }
+
+ mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
+ return (1);
+}
+
+int
+mlndr_outer_peek_sizing(struct ndr_reference *outer_ref, unsigned offset,
+ unsigned long *sizing_p)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ unsigned long pdu_offset;
+ int rc;
+
+ pdu_offset = outer_ref->pdu_offset + offset;
+
+ if (pdu_offset < mlnds->outer_current->pdu_offset ||
+ pdu_offset > mlnds->outer_current->pdu_end_offset ||
+ pdu_offset+4 > mlnds->outer_current->pdu_end_offset) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
+ return (0);
+ }
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
+ return (0);
+
+ case NDR_M_OP_UNMARSHALL:
+ rc = MLNDS_GET_PDU(mlnds, pdu_offset, 4, (char *)sizing_p,
+ mlnds->swap, outer_ref);
+ break;
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ return (rc);
+}
+
+int
+mlndr_outer_poke_sizing(struct ndr_reference *outer_ref, unsigned offset,
+ unsigned long *sizing_p)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ unsigned long pdu_offset;
+ int rc;
+
+ pdu_offset = outer_ref->pdu_offset + offset;
+
+ if (pdu_offset < mlnds->outer_current->pdu_offset ||
+ pdu_offset > mlnds->outer_current->pdu_end_offset ||
+ pdu_offset+4 > mlnds->outer_current->pdu_end_offset) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
+ return (0);
+ }
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ rc = MLNDS_PUT_PDU(mlnds, pdu_offset, 4, (char *)sizing_p,
+ mlnds->swap, outer_ref);
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
+ return (0);
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ return (rc);
+}
+
+/*
+ * All OUTER constructs begin on a mod4 (dword) boundary - except
+ * for the ones that don't: some MSRPC calls appear to use word or
+ * packed alignment. Strings appear to be dword aligned.
+ */
+int
+mlndr_outer_align(struct ndr_reference *outer_ref)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ int rc;
+ unsigned n_pad;
+ unsigned align;
+
+ if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
+ align = outer_ref->ti->alignment;
+ n_pad = ((align + 1) - mlnds->pdu_scan_offset) & align;
+ } else {
+ n_pad = (4 - mlnds->pdu_scan_offset) & 3;
+ }
+
+ if (n_pad == 0)
+ return (1); /* already aligned, often the case */
+
+ if (!mlndr_outer_grow(outer_ref, n_pad))
+ return (0); /* error already set */
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ rc = MLNDS_PAD_PDU(mlnds,
+ mlnds->pdu_scan_offset, n_pad, outer_ref);
+ if (!rc) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
+ return (0);
+ }
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ break;
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ mlnds->pdu_scan_offset += n_pad;
+ return (1);
+}
+
+int
+mlndr_outer_grow(struct ndr_reference *outer_ref, unsigned n_total)
+{
+ struct mlndr_stream *mlnds = outer_ref->stream;
+ unsigned long pdu_want_size;
+ int rc, is_ok = 0;
+
+ pdu_want_size = mlnds->pdu_scan_offset + n_total;
+
+ if (pdu_want_size <= mlnds->pdu_max_size) {
+ is_ok = 1;
+ }
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ if (is_ok)
+ break;
+ rc = MLNDS_GROW_PDU(mlnds, pdu_want_size, outer_ref);
+ if (!rc) {
+ NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
+ return (0);
+ }
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ if (is_ok)
+ break;
+ NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
+ return (0);
+
+ default:
+ NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ if (mlnds->pdu_size < pdu_want_size)
+ mlnds->pdu_size = pdu_want_size;
+
+ outer_ref->pdu_end_offset = pdu_want_size;
+ return (1);
+}
+
+/*
+ * INNER ELEMENTS
+ *
+ * The local datum (arg_ref->datum) already exists, there is no need to
+ * malloc() it. The datum should point at a member of a structure.
+ *
+ * For the most part, mlndr_inner() and its helpers are just a sanity
+ * check. The underlying ti->ndr_func() could be called immediately
+ * for non-pointer elements. For the sake of robustness, we detect
+ * run-time errors here. Most of the situations this protects against
+ * have already been checked by the IDL compiler. This is also a
+ * common point for processing of all data, and so is a convenient
+ * place to work from for debugging.
+ */
+int
+mlndr_inner(struct ndr_reference *arg_ref)
+{
+ struct ndr_typeinfo *ti = arg_ref->ti;
+ int is_varlen = ti->pdu_size_variable_part;
+ int is_union = NDR_IS_UNION(ti);
+ int error = NDR_ERR_INNER_PARAMS_BAD;
+ int params;
+
+ params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
+
+ switch (params) {
+ case NDR_F_NONE:
+ if (is_union) {
+ error = NDR_ERR_SWITCH_VALUE_MISSING;
+ break;
+ }
+ return (*ti->ndr_func)(arg_ref);
+ break;
+
+ case NDR_F_SIZE_IS:
+ case NDR_F_DIMENSION_IS:
+ case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */
+ case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
+ if (is_varlen) {
+ error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
+ break;
+ }
+ if (is_union) {
+ error = NDR_ERR_ARRAY_UNION_ILLEGAL;
+ break;
+ }
+ if (params & NDR_F_IS_POINTER)
+ return (mlndr_inner_pointer(arg_ref));
+ else if (params & NDR_F_IS_REFERENCE)
+ return (mlndr_inner_reference(arg_ref));
+ else
+ return (mlndr_inner_array(arg_ref));
+ break;
+
+ case NDR_F_IS_POINTER: /* type is pointer to one something */
+ if (is_union) {
+ error = NDR_ERR_ARRAY_UNION_ILLEGAL;
+ break;
+ }
+ return (mlndr_inner_pointer(arg_ref));
+ break;
+
+ case NDR_F_IS_REFERENCE: /* type is pointer to one something */
+ if (is_union) {
+ error = NDR_ERR_ARRAY_UNION_ILLEGAL;
+ break;
+ }
+ return (mlndr_inner_reference(arg_ref));
+ break;
+
+ case NDR_F_SWITCH_IS:
+ if (!is_union) {
+ error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
+ break;
+ }
+ return (*ti->ndr_func)(arg_ref);
+ break;
+
+ default:
+ error = NDR_ERR_INNER_PARAMS_BAD;
+ break;
+ }
+
+ /*
+ * If we get here, something is wrong. Most likely,
+ * the params flags do not match
+ */
+ NDR_SET_ERROR(arg_ref, error);
+ return (0);
+}
+
+int
+mlndr_inner_pointer(struct ndr_reference *arg_ref)
+{
+ struct mlndr_stream *mlnds = arg_ref->stream;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ char **valpp = (char **)arg_ref->datum;
+ struct ndr_reference *outer_ref;
+
+ if (!mlndr__ulong(arg_ref))
+ return (0); /* error */
+ if (!*valpp)
+ return (1); /* NULL pointer */
+
+ outer_ref = mlndr_enter_outer_queue(arg_ref);
+ if (!outer_ref)
+ return (0); /* error already set */
+
+ /* move advice in inner_flags to outer_flags sans pointer */
+ outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
+ outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
+#ifdef NDR_INNER_NOT_YET
+ outer_ref->outer_flags |= NDR_F_BACKPTR;
+ if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
+ outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
+ }
+#endif /* NDR_INNER_NOT_YET */
+
+ outer_ref->backptr = valpp;
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ outer_ref->datum = *valpp;
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ /*
+ * This is probably wrong if the application allocated
+ * memory in advance. Indicate no value for now.
+ * ONC RPC handles this case.
+ */
+ *valpp = 0;
+ outer_ref->datum = 0;
+ break;
+ }
+
+ return (1); /* pointer dereference scheduled */
+}
+
+int
+mlndr_inner_reference(struct ndr_reference *arg_ref)
+{
+ struct mlndr_stream *mlnds = arg_ref->stream;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ char **valpp = (char **)arg_ref->datum;
+ struct ndr_reference *outer_ref;
+
+ outer_ref = mlndr_enter_outer_queue(arg_ref);
+ if (!outer_ref)
+ return (0); /* error already set */
+
+ /* move advice in inner_flags to outer_flags sans pointer */
+ outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
+ outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
+#ifdef NDR_INNER_REF_NOT_YET
+ outer_ref->outer_flags |= NDR_F_BACKPTR;
+ if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
+ outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
+ }
+#endif /* NDR_INNER_REF_NOT_YET */
+
+ outer_ref->backptr = valpp;
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ outer_ref->datum = *valpp;
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ /*
+ * This is probably wrong if the application allocated
+ * memory in advance. Indicate no value for now.
+ * ONC RPC handles this case.
+ */
+ *valpp = 0;
+ outer_ref->datum = 0;
+ break;
+ }
+
+ return (1); /* pointer dereference scheduled */
+}
+
+int
+mlndr_inner_array(struct ndr_reference *encl_ref)
+{
+ struct ndr_typeinfo *ti = encl_ref->ti;
+ struct ndr_reference myref;
+ unsigned long pdu_offset = encl_ref->pdu_offset;
+ unsigned long n_elem;
+ unsigned long i;
+ char name[30];
+
+ if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
+ /* now is the time to check/set size */
+ if (!mlndr_size_is(encl_ref))
+ return (0); /* error already set */
+ n_elem = encl_ref->size_is;
+ } else {
+ assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
+ n_elem = encl_ref->dimension_is;
+ }
+
+ bzero(&myref, sizeof (myref));
+ myref.enclosing = encl_ref;
+ myref.stream = encl_ref->stream;
+ myref.packed_alignment = 0;
+ myref.ti = ti;
+ myref.inner_flags = NDR_F_NONE;
+
+ for (i = 0; i < n_elem; i++) {
+ (void) sprintf(name, "[%lu]", i);
+ myref.name = name;
+ myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
+ myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
+
+ if (!mlndr_inner(&myref))
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * BASIC TYPES
+ */
+#define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
+ extern int mlndr_##TYPE(struct ndr_reference *encl_ref); \
+ struct ndr_typeinfo ndt_##TYPE = { \
+ 1, /* NDR version */ \
+ (SIZE)-1, /* alignment */ \
+ NDR_F_NONE, /* flags */ \
+ mlndr_##TYPE, /* ndr_func */ \
+ SIZE, /* pdu_size_fixed_part */ \
+ 0, /* pdu_size_variable_part */ \
+ SIZE, /* c_size_fixed_part */ \
+ 0, /* c_size_variable_part */ \
+ }; \
+ int mlndr_##TYPE(struct ndr_reference *ref) { \
+ return (mlndr_basic_integer(ref, SIZE)); \
+}
+
+#define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
+ extern int mlndr_s##TYPE(struct ndr_reference *encl_ref); \
+ struct ndr_typeinfo ndt_s##TYPE = { \
+ 1, /* NDR version */ \
+ (SIZE)-1, /* alignment */ \
+ NDR_F_STRING, /* flags */ \
+ mlndr_s##TYPE, /* ndr_func */ \
+ 0, /* pdu_size_fixed_part */ \
+ SIZE, /* pdu_size_variable_part */ \
+ 0, /* c_size_fixed_part */ \
+ SIZE, /* c_size_variable_part */ \
+ }; \
+ int mlndr_s##TYPE(struct ndr_reference *ref) { \
+ return (mlndr_string_basic_integer(ref, &ndt_##TYPE)); \
+}
+
+#define MAKE_BASIC_TYPE(TYPE, SIZE) \
+ MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
+ MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
+
+extern int
+mlndr_basic_integer(struct ndr_reference *ref, unsigned size);
+
+extern int
+mlndr_string_basic_integer(struct ndr_reference *encl_ref,
+ struct ndr_typeinfo *type_under);
+
+
+MAKE_BASIC_TYPE(_char, 1)
+MAKE_BASIC_TYPE(_uchar, 1)
+MAKE_BASIC_TYPE(_short, 2)
+MAKE_BASIC_TYPE(_ushort, 2)
+MAKE_BASIC_TYPE(_long, 4)
+MAKE_BASIC_TYPE(_ulong, 4)
+
+MAKE_BASIC_TYPE_BASE(_wchar, 2)
+
+int
+mlndr_basic_integer(struct ndr_reference *ref, unsigned size)
+{
+ struct mlndr_stream *mlnds = ref->stream;
+ char *valp = (char *)ref->datum;
+ int rc;
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ rc = MLNDS_PUT_PDU(mlnds, ref->pdu_offset, size,
+ valp, mlnds->swap, ref);
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ rc = MLNDS_GET_PDU(mlnds, ref->pdu_offset, size,
+ valp, mlnds->swap, ref);
+ break;
+
+ default:
+ NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ return (rc);
+}
+
+int
+mlndr_string_basic_integer(struct ndr_reference *encl_ref,
+ struct ndr_typeinfo *type_under)
+{
+ unsigned long pdu_offset = encl_ref->pdu_offset;
+ unsigned size = type_under->pdu_size_fixed_part;
+ char *valp;
+ struct ndr_reference myref;
+ unsigned long i;
+ long sense = 0;
+ char name[30];
+
+ assert(size != 0);
+
+ bzero(&myref, sizeof (myref));
+ myref.enclosing = encl_ref;
+ myref.stream = encl_ref->stream;
+ myref.packed_alignment = 0;
+ myref.ti = type_under;
+ myref.inner_flags = NDR_F_NONE;
+ myref.name = name;
+
+ for (i = 0; i < NDR_STRING_MAX; i++) {
+ (void) sprintf(name, "[%lu]", i);
+ myref.pdu_offset = pdu_offset + i * size;
+ valp = encl_ref->datum + i * size;
+ myref.datum = valp;
+
+ if (!mlndr_inner(&myref))
+ return (0);
+
+ switch (size) {
+ case 1: sense = *valp; break;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ case 2: sense = *(short *)valp; break;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ case 4: sense = *(long *)valp; break;
+ }
+
+ if (!sense)
+ break;
+ }
+
+ return (1);
+}
+
+
+extern int mlndr_s_wchar(struct ndr_reference *encl_ref);
+struct ndr_typeinfo ndt_s_wchar = {
+ 1, /* NDR version */
+ 2-1, /* alignment */
+ NDR_F_STRING, /* flags */
+ mlndr_s_wchar, /* ndr_func */
+ 0, /* pdu_size_fixed_part */
+ 2, /* pdu_size_variable_part */
+ 0, /* c_size_fixed_part */
+ 1, /* c_size_variable_part */
+};
+
+
+/*
+ * Hand coded wchar function because all strings are transported
+ * as wide characters. During NDR_M_OP_MARSHALL, we convert from
+ * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
+ * convert from wide characters to multi-byte.
+ *
+ * It appeared that NT would sometimes leave a spurious character
+ * in the data stream before the null wide_char, which would get
+ * included in the string decode because we processed until the
+ * null character. It now looks like NT does not always terminate
+ * RPC Unicode strings and the terminating null is a side effect
+ * of field alignment. So now we rely on the strlen_is (set up in
+ * mlndr_outer_string) of the enclosing reference. This may or may
+ * not include the null but it doesn't matter, the algorithm will
+ * get it right.
+ */
+int
+mlndr_s_wchar(struct ndr_reference *encl_ref)
+{
+ struct mlndr_stream *mlnds = encl_ref->stream;
+ unsigned short wide_char;
+ char *valp;
+ struct ndr_reference myref;
+ unsigned long i;
+ char name[30];
+ int count;
+ int char_count = 0;
+
+ if (mlnds->m_op == NDR_M_OP_UNMARSHALL) {
+ /*
+ * To avoid problems with zero length strings
+ * we can just null terminate here and be done.
+ */
+ if (encl_ref->strlen_is == 0) {
+ encl_ref->datum[0] = '\0';
+ return (1);
+ }
+ }
+
+ bzero(&myref, sizeof (myref));
+ myref.enclosing = encl_ref;
+ myref.stream = encl_ref->stream;
+ myref.packed_alignment = 0;
+ myref.ti = &ndt__wchar;
+ myref.inner_flags = NDR_F_NONE;
+ myref.datum = (char *)&wide_char;
+ myref.name = name;
+ myref.pdu_offset = encl_ref->pdu_offset;
+
+ valp = encl_ref->datum;
+ count = 0;
+
+ for (i = 0; i < NDR_STRING_MAX; i++) {
+ (void) sprintf(name, "[%lu]", i);
+
+ if (mlnds->m_op == NDR_M_OP_MARSHALL) {
+ count = mts_mbtowc((mts_wchar_t *)&wide_char, valp,
+ MTS_MB_CHAR_MAX);
+ if (count < 0) {
+ return (0);
+ } else if (count == 0) {
+ /*
+ * If the input char is 0, mts_mbtowc
+ * returns 0 without setting wide_char.
+ * I'm not sure if this is the correct
+ * behaviour for mts_mbtowc but for
+ * now we need to set wide_char to 0
+ * and assume a count of 1.
+ */
+ wide_char = *valp;
+ count = 1;
+ }
+ }
+
+ if (!mlndr_inner(&myref))
+ return (0);
+
+ if (mlnds->m_op == NDR_M_OP_UNMARSHALL) {
+ count = mts_wctomb(valp, wide_char);
+
+ if ((++char_count) == encl_ref->strlen_is) {
+ valp += count;
+ *valp = '\0';
+ break;
+ }
+ }
+
+ if (!wide_char)
+ break;
+
+ myref.pdu_offset += sizeof (wide_char);
+ valp += count;
+ }
+
+ return (1);
+}
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_client.c b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_client.c
new file mode 100644
index 0000000000..9bce9469ea
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_client.c
@@ -0,0 +1,369 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/errno.h>
+#include <string.h>
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ndr.h>
+#include <smbsrv/mlrpc.h>
+
+#define MLRPC_IS_LAST_FRAG(F) ((F) & MLRPC_PFC_LAST_FRAG)
+#define MLRPC_DEFAULT_FRAGSZ 8192
+
+static void mlrpc_c_init_hdr(struct mlrpc_client *, struct mlrpc_xaction *);
+static int mlrpc_c_get_frags(struct mlrpc_client *, struct mlrpc_xaction *);
+static void mlrpc_c_remove_hdr(struct mlndr_stream *, int *);
+
+int
+mlrpc_c_bind(struct mlrpc_client *mcli, char *service_name,
+ struct mlrpc_binding **ret_binding_p)
+{
+ struct mlrpc_service *msvc;
+ struct mlrpc_binding *mbind;
+ struct mlrpc_xaction mxa;
+ mlrpcconn_bind_hdr_t *bhdr;
+ mlrpc_p_cont_elem_t *pce;
+ mlrpcconn_bind_ack_hdr_t *bahdr;
+ mlrpc_p_result_t *pre;
+ int rc;
+
+ bzero(&mxa, sizeof (mxa));
+
+ msvc = mlrpc_find_service_by_name(service_name);
+ if (msvc == NULL)
+ return (MLRPC_DRC_FAULT_API_SERVICE_INVALID);
+
+ mxa.binding_list = mcli->binding_list;
+ if ((mbind = mlrpc_new_binding(&mxa)) == NULL)
+ return (MLRPC_DRC_FAULT_API_BIND_NO_SLOTS);
+
+ mlrpc_c_init_hdr(mcli, &mxa);
+
+ bhdr = &mxa.send_hdr.bind_hdr;
+ bhdr->common_hdr.ptype = MLRPC_PTYPE_BIND;
+ bhdr->common_hdr.frag_length = sizeof (*bhdr);
+ bhdr->max_xmit_frag = MLRPC_DEFAULT_FRAGSZ;
+ bhdr->max_recv_frag = MLRPC_DEFAULT_FRAGSZ;
+ bhdr->assoc_group_id = 0;
+ bhdr->p_context_elem.n_context_elem = 1;
+
+ /* Assign presentation context id */
+ pce = &bhdr->p_context_elem.p_cont_elem[0];
+ pce->p_cont_id = mcli->next_p_cont_id++;
+ pce->n_transfer_syn = 1;
+
+ /* Set up UUIDs and versions from the service */
+ pce->abstract_syntax.if_version = msvc->abstract_syntax_version;
+ rc = mlrpc_str_to_uuid(msvc->abstract_syntax_uuid,
+ &pce->abstract_syntax.if_uuid);
+ if (!rc)
+ return (MLRPC_DRC_FAULT_API_SERVICE_INVALID);
+
+ pce->transfer_syntaxes[0].if_version = msvc->transfer_syntax_version;
+ rc = mlrpc_str_to_uuid(msvc->transfer_syntax_uuid,
+ &pce->transfer_syntaxes[0].if_uuid);
+ if (!rc)
+ return (MLRPC_DRC_FAULT_API_SERVICE_INVALID);
+
+ /* Format and exchange the PDU */
+
+ rc = (*mcli->xa_init)(mcli, &mxa, 0);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ return (rc);
+
+ rc = mlrpc_encode_pdu_hdr(&mxa);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ goto fault_exit;
+
+ rc = (*mcli->xa_exchange)(mcli, &mxa);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ goto fault_exit;
+
+ rc = mlrpc_decode_pdu_hdr(&mxa);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ goto fault_exit;
+
+ /* done with buffers */
+ (*mcli->xa_destruct)(mcli, &mxa);
+
+ bahdr = &mxa.recv_hdr.bind_ack_hdr;
+
+ if (mxa.ptype != MLRPC_PTYPE_BIND_ACK)
+ return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED);
+
+ if (bahdr->p_result_list.n_results != 1)
+ return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED);
+
+ pre = &bahdr->p_result_list.p_results[0];
+
+ if (pre->result != MLRPC_PCDR_ACCEPTANCE)
+ return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED);
+
+ mbind->p_cont_id = pce->p_cont_id;
+ mbind->which_side = MLRPC_BIND_SIDE_CLIENT;
+ mbind->context = mcli;
+ mbind->service = msvc;
+ mbind->instance_specific = 0;
+
+ *ret_binding_p = mbind;
+ return (MLRPC_DRC_OK);
+
+fault_exit:
+ (*mcli->xa_destruct)(mcli, &mxa);
+ return (rc);
+}
+
+int
+mlrpc_c_call(struct mlrpc_binding *mbind, int opnum, void *params,
+ mlrpc_heapref_t *heapref)
+{
+ struct mlrpc_client *mcli = mbind->context;
+ struct mlrpc_service *msvc = mbind->service;
+ struct mlrpc_xaction mxa;
+ mlrpcconn_request_hdr_t *reqhdr;
+ mlrpcconn_common_header_t *rsphdr;
+ unsigned long recv_pdu_scan_offset;
+ int rc;
+
+ if (mlrpc_find_stub_in_svc(msvc, opnum) == NULL)
+ return (MLRPC_DRC_FAULT_API_OPNUM_INVALID);
+
+ bzero(&mxa, sizeof (mxa));
+ mxa.ptype = MLRPC_PTYPE_REQUEST;
+ mxa.opnum = opnum;
+ mxa.binding = mbind;
+
+ mlrpc_c_init_hdr(mcli, &mxa);
+
+ reqhdr = &mxa.send_hdr.request_hdr;
+ reqhdr->common_hdr.ptype = MLRPC_PTYPE_REQUEST;
+ reqhdr->p_cont_id = mbind->p_cont_id;
+ reqhdr->opnum = opnum;
+
+ rc = (*mcli->xa_init)(mcli, &mxa, heapref->heap);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ return (rc);
+
+ /* Reserve room for hdr */
+ mxa.send_mlnds.pdu_scan_offset = sizeof (*reqhdr);
+
+ rc = mlrpc_encode_call(&mxa, params);
+ if (!MLRPC_DRC_IS_OK(rc))
+ goto fault_exit;
+
+ mxa.send_mlnds.pdu_scan_offset = 0;
+
+ /*
+ * Now we have the PDU size, we need to set up the
+ * frag_length and calculate the alloc_hint.
+ */
+ mxa.send_hdr.common_hdr.frag_length = mxa.send_mlnds.pdu_size;
+ reqhdr->alloc_hint = mxa.send_mlnds.pdu_size -
+ sizeof (mlrpcconn_request_hdr_t);
+
+ rc = mlrpc_encode_pdu_hdr(&mxa);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ goto fault_exit;
+
+ rc = (*mcli->xa_exchange)(mcli, &mxa);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ goto fault_exit;
+
+ rc = mlrpc_decode_pdu_hdr(&mxa);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ goto fault_exit;
+
+ if (mxa.ptype != MLRPC_PTYPE_RESPONSE) {
+ rc = MLRPC_DRC_FAULT_RECEIVED_MALFORMED;
+ goto fault_exit;
+ }
+
+ rsphdr = &mxa.recv_hdr.common_hdr;
+
+ if (!MLRPC_IS_LAST_FRAG(rsphdr->pfc_flags)) {
+ /*
+ * This is a multi-fragment response.
+ * Preserve the current scan offset while getting
+ * fragments so that we can continue afterward
+ * as if we had received the entire response as
+ * a single PDU.
+ */
+ recv_pdu_scan_offset = mxa.recv_mlnds.pdu_scan_offset;
+
+ if (mlrpc_c_get_frags(mcli, &mxa) < 0) {
+ rc = MLRPC_DRC_FAULT_RECEIVED_MALFORMED;
+ goto fault_exit;
+ }
+
+ mxa.recv_mlnds.pdu_scan_offset = recv_pdu_scan_offset;
+ }
+
+ rc = mlrpc_decode_return(&mxa, params);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ goto fault_exit;
+
+ rc = (*mcli->xa_preserve)(mcli, &mxa, heapref);
+ if (MLRPC_DRC_IS_FAULT(rc))
+ goto fault_exit;
+
+ (*mcli->xa_destruct)(mcli, &mxa);
+ return (MLRPC_DRC_OK);
+
+fault_exit:
+ (*mcli->xa_destruct)(mcli, &mxa);
+ return (rc);
+}
+
+int
+mlrpc_c_free_heap(struct mlrpc_binding *mbind, mlrpc_heapref_t *heapref)
+{
+ struct mlrpc_client *mcli = mbind->context;
+
+ (*mcli->xa_release)(mcli, heapref);
+ return (0);
+}
+
+static void
+mlrpc_c_init_hdr(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
+{
+ mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
+
+ hdr->rpc_vers = 5;
+ hdr->rpc_vers_minor = 0;
+ hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
+ hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII;
+#ifndef _BIG_ENDIAN
+ hdr->packed_drep.intg_char_rep |= MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
+#endif
+ /* hdr->frag_length */
+ hdr->auth_length = 0;
+ hdr->call_id = mcli->next_call_id++;
+}
+
+/*
+ * mlrpc_c_remove_hdr
+ *
+ * Remove an RPC fragment header from the received data stream.
+ *
+ * Original RPC receive buffer:
+ * |- frag1 -| |-frag M(partial)-|
+ * +==================+=============+----+=================+
+ * | SmbTransact Rsp1 | SmbTransact | | SmbReadX RspN |
+ * | (with RPC hdr) | Rsp2 | .. | (with RPC hdr) |
+ * +-----+------------+-------------+ +-----+-----------+
+ * | hdr | data | data | .. | hdr | data |
+ * +=====+============+=============+----+=====+===========+
+ * <------
+ * ^ ^ ^
+ * | | |
+ * base_offset hdr data
+ *
+ * |-------------------------------------|-----------------|
+ * offset len
+ *
+ * RPC receive buffer (after this call):
+ * +==================+=============+----+===========+
+ * | SmbTransact Rsp1 | SmbTransact | | SmbReadX |
+ * | (with RPC hdr) | Rsp2 | .. | RspN |
+ * +-----+------------+-------------+ +-----------+
+ * | hdr | data | data | .. | data |
+ * +=====+============+=============+----+===========+
+ */
+static void
+mlrpc_c_remove_hdr(struct mlndr_stream *mlnds, int *nbytes)
+{
+ char *hdr;
+ char *data;
+
+ hdr = (char *)mlnds->pdu_base_offset + mlnds->pdu_scan_offset;
+ data = hdr + MLRPC_RSP_HDR_SIZE;
+ *nbytes -= MLRPC_RSP_HDR_SIZE;
+
+ bcopy(data, hdr, *nbytes);
+ mlnds->pdu_size -= MLRPC_RSP_HDR_SIZE;
+}
+
+/*
+ * mlrpc_c_get_frags
+ *
+ * A DCE RPC message that is larger than a single fragment is transmitted
+ * as a series of fragments: 5280 bytes for Windows NT and 4280 bytes for
+ * both Windows 2000 and 2003.
+ *
+ * Collect RPC fragments and append them to the receive stream buffer.
+ * Each received fragment has a header, which we need to remove as we
+ * build the full RPC PDU.
+ *
+ * The xa_read() calls will translate to SmbReadX requests. Note that
+ * there is no correspondence between SmbReadX buffering and DCE RPC
+ * fragment alignment.
+ *
+ * Return -1 on error. Otherwise, return the total data count of the
+ * complete RPC response upon success.
+ */
+static int
+mlrpc_c_get_frags(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
+{
+ struct mlndr_stream *mlnds = &mxa->recv_mlnds;
+ mlrpcconn_common_header_t hdr;
+ int frag_rcvd;
+ int frag_size;
+ int last_frag;
+ int nbytes;
+
+ /*
+ * The scan offest will be used to locate the frag header.
+ */
+ mlnds->pdu_scan_offset = mlnds->pdu_base_offset + mlnds->pdu_size;
+
+ do {
+ frag_rcvd = 0;
+
+ do {
+ if ((nbytes = (*mcli->xa_read)(mcli, mxa)) < 0)
+ return (-1);
+
+ if (frag_rcvd == 0) {
+ mlrpc_decode_frag_hdr(mlnds, &hdr);
+
+ last_frag = MLRPC_IS_LAST_FRAG(hdr.pfc_flags);
+ frag_size = hdr.frag_length
+ - MLRPC_RSP_HDR_SIZE;
+
+ mlrpc_c_remove_hdr(mlnds, &nbytes);
+ mlnds->pdu_scan_offset += frag_size;
+ }
+
+ frag_rcvd += nbytes;
+
+ } while (frag_rcvd < frag_size);
+ } while (!last_frag);
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_encdec.c b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_encdec.c
new file mode 100644
index 0000000000..884683dfe4
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_encdec.c
@@ -0,0 +1,349 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+#include <sys/param.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ndr.h>
+#include <smbsrv/mlrpc.h>
+
+#ifdef _BIG_ENDIAN
+static const int mlrpc_native_byte_order = MLRPC_REPLAB_INTG_BIG_ENDIAN;
+#else
+static const int mlrpc_native_byte_order = MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
+#endif
+
+int
+mlrpc_encode_decode_common(struct mlrpc_xaction *mxa, int mode, unsigned opnum,
+ struct ndr_typeinfo *ti, void *datum)
+{
+ struct mlndr_stream *mlnds;
+ int m_op = NDR_MODE_TO_M_OP(mode);
+ int rc;
+
+ if (m_op == NDR_M_OP_MARSHALL)
+ mlnds = &mxa->send_mlnds;
+ else
+ mlnds = &mxa->recv_mlnds;
+
+ /*
+ * Make sure that mlnds is in the correct mode
+ */
+ if (!NDR_MODE_MATCH(mlnds, mode))
+ return (MLRPC_DRC_FAULT_MODE_MISMATCH);
+
+ /*
+ * Perform the (un)marshalling
+ */
+ if (mlndo_operation(mlnds, ti, opnum, datum))
+ return (MLRPC_DRC_OK);
+
+ switch (mlnds->error) {
+ case NDR_ERR_MALLOC_FAILED:
+ rc = MLRPC_DRC_FAULT_OUT_OF_MEMORY;
+ break;
+
+ case NDR_ERR_SWITCH_VALUE_INVALID:
+ rc = MLRPC_DRC_FAULT_PARAM_0_INVALID;
+ break;
+
+ case NDR_ERR_UNDERFLOW:
+ rc = MLRPC_DRC_FAULT_RECEIVED_RUNT;
+ break;
+
+ case NDR_ERR_GROW_FAILED:
+ rc = MLRPC_DRC_FAULT_ENCODE_TOO_BIG;
+ break;
+
+ default:
+ if (m_op == NDR_M_OP_MARSHALL)
+ rc = MLRPC_DRC_FAULT_ENCODE_FAILED;
+ else
+ rc = MLRPC_DRC_FAULT_DECODE_FAILED;
+ break;
+ }
+
+ return (rc);
+}
+
+int
+mlrpc_decode_call(struct mlrpc_xaction *mxa, void *params)
+{
+ int rc;
+
+ rc = mlrpc_encode_decode_common(mxa, NDR_MODE_CALL_RECV,
+ mxa->opnum, mxa->binding->service->interface_ti, params);
+
+ return (rc + MLRPC_PTYPE_REQUEST);
+}
+
+int
+mlrpc_encode_return(struct mlrpc_xaction *mxa, void *params)
+{
+ int rc;
+
+ rc = mlrpc_encode_decode_common(mxa, NDR_MODE_RETURN_SEND,
+ mxa->opnum, mxa->binding->service->interface_ti, params);
+
+ return (rc + MLRPC_PTYPE_RESPONSE);
+}
+
+int
+mlrpc_encode_call(struct mlrpc_xaction *mxa, void *params)
+{
+ int rc;
+
+ rc = mlrpc_encode_decode_common(mxa, NDR_MODE_CALL_SEND,
+ mxa->opnum, mxa->binding->service->interface_ti, params);
+
+ return (rc + MLRPC_PTYPE_REQUEST);
+}
+
+int
+mlrpc_decode_return(struct mlrpc_xaction *mxa, void *params)
+{
+ int rc;
+
+ rc = mlrpc_encode_decode_common(mxa, NDR_MODE_RETURN_RECV,
+ mxa->opnum, mxa->binding->service->interface_ti, params);
+
+ return (rc + MLRPC_PTYPE_RESPONSE);
+}
+
+int
+mlrpc_decode_pdu_hdr(struct mlrpc_xaction *mxa)
+{
+ mlrpcconn_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
+ struct mlndr_stream *mlnds = &mxa->recv_mlnds;
+ int ptype;
+ int rc;
+ int charset;
+ int byte_order;
+
+ if (mlnds->m_op != NDR_M_OP_UNMARSHALL)
+ return (MLRPC_DRC_FAULT_MODE_MISMATCH + 0xFF);
+
+ /*
+ * All PDU headers are at least this big
+ */
+ rc = MLNDS_GROW_PDU(mlnds, sizeof (mlrpcconn_common_header_t), 0);
+ if (!rc)
+ return (MLRPC_DRC_FAULT_RECEIVED_RUNT + 0xFF);
+
+ /*
+ * Peek at the first eight bytes to figure out what we're doing.
+ */
+ rc = MLNDS_GET_PDU(mlnds, 0, 8, (char *)hdr, 0, 0);
+ if (!rc)
+ return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
+
+ /*
+ * Verify the protocol version.
+ */
+ if ((hdr->rpc_vers != 5) || (hdr->rpc_vers_minor != 0))
+ return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
+
+ /*
+ * Check for ASCII as the character set. This is an ASCII
+ * versus EBCDIC option and has nothing to do with Unicode.
+ */
+ charset = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_CHAR_MASK;
+ if (charset != MLRPC_REPLAB_CHAR_ASCII)
+ return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
+
+ /*
+ * Set the byte swap flag if the PDU byte-order
+ * is different from the local byte-order.
+ */
+ byte_order = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_INTG_MASK;
+ mlnds->swap = (byte_order != mlrpc_native_byte_order) ? 1 : 0;
+
+ ptype = hdr->ptype;
+ if (ptype == MLRPC_PTYPE_REQUEST &&
+ (hdr->pfc_flags & MLRPC_PFC_OBJECT_UUID) != 0) {
+ ptype = MLRPC_PTYPE_REQUEST_WITH; /* fake for sizing */
+ }
+
+ mxa->ptype = hdr->ptype;
+
+ rc = mlrpc_encode_decode_common(mxa,
+ NDR_M_OP_AND_DIR_TO_MODE(mlnds->m_op, mlnds->dir),
+ ptype, &TYPEINFO(mlrpcconn_hdr), hdr);
+
+ return (rc + 0xFF);
+}
+
+/*
+ * Decode an RPC fragment header. Use mlrpc_decode_pdu_hdr() to process
+ * the first fragment header then this function to process additional
+ * fragment headers.
+ */
+void
+mlrpc_decode_frag_hdr(struct mlndr_stream *mlnds,
+ mlrpcconn_common_header_t *hdr)
+{
+ mlrpcconn_common_header_t *tmp;
+ uint8_t *pdu;
+ int byte_order;
+
+ pdu = (uint8_t *)mlnds->pdu_base_offset + mlnds->pdu_scan_offset;
+ bcopy(pdu, hdr, MLRPC_RSP_HDR_SIZE);
+
+ /*
+ * Swap non-byte fields if the PDU byte-order
+ * is different from the local byte-order.
+ */
+ byte_order = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_INTG_MASK;
+
+ if (byte_order != mlrpc_native_byte_order) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ tmp = (mlrpcconn_common_header_t *)pdu;
+
+ mlnds_bswap(&tmp->frag_length, &hdr->frag_length,
+ sizeof (WORD));
+ mlnds_bswap(&tmp->auth_length, &hdr->auth_length,
+ sizeof (WORD));
+ mlnds_bswap(&tmp->call_id, &hdr->call_id, sizeof (DWORD));
+ }
+}
+
+int
+mlrpc_encode_pdu_hdr(struct mlrpc_xaction *mxa)
+{
+ mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
+ struct mlndr_stream *mlnds = &mxa->send_mlnds;
+ int ptype;
+ int rc;
+
+ if (mlnds->m_op != NDR_M_OP_MARSHALL)
+ return (MLRPC_DRC_FAULT_MODE_MISMATCH + 0xFF);
+
+ ptype = hdr->ptype;
+ if (ptype == MLRPC_PTYPE_REQUEST &&
+ (hdr->pfc_flags & MLRPC_PFC_OBJECT_UUID) != 0) {
+ ptype = MLRPC_PTYPE_REQUEST_WITH; /* fake for sizing */
+ }
+
+ rc = mlrpc_encode_decode_common(mxa,
+ NDR_M_OP_AND_DIR_TO_MODE(mlnds->m_op, mlnds->dir),
+ ptype, &TYPEINFO(mlrpcconn_hdr), hdr);
+
+ return (rc + 0xFF);
+}
+
+/*
+ * This is a hand-coded derivative of the automatically generated
+ * (un)marshalling routine for bind_ack headers. bind_ack headers
+ * have an interior conformant array, which is inconsistent with
+ * IDL/NDR rules.
+ */
+extern struct ndr_typeinfo ndt__uchar;
+extern struct ndr_typeinfo ndt__ushort;
+extern struct ndr_typeinfo ndt__ulong;
+
+int mlndr__mlrpcconn_bind_ack_hdr(struct ndr_reference *encl_ref);
+struct ndr_typeinfo ndt__mlrpcconn_bind_ack_hdr = {
+ 1, /* NDR version */
+ 3, /* alignment */
+ NDR_F_STRUCT, /* flags */
+ mlndr__mlrpcconn_bind_ack_hdr, /* ndr_func */
+ 68, /* pdu_size_fixed_part */
+ 0, /* pdu_size_variable_part */
+ 68, /* c_size_fixed_part */
+ 0, /* c_size_variable_part */
+};
+
+/*
+ * [_no_reorder]
+ */
+int
+mlndr__mlrpcconn_bind_ack_hdr(struct ndr_reference *encl_ref)
+{
+ struct mlndr_stream *mlnds = encl_ref->stream;
+ struct mlrpcconn_bind_ack_hdr *val = /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ (struct mlrpcconn_bind_ack_hdr *)encl_ref->datum;
+ struct ndr_reference myref;
+ unsigned long offset;
+
+ bzero(&myref, sizeof (myref));
+ myref.enclosing = encl_ref;
+ myref.stream = encl_ref->stream;
+ myref.packed_alignment = 0;
+
+ /* do all members in order */
+ NDR_MEMBER(_mlrpcconn_common_header, common_hdr, 0UL);
+ NDR_MEMBER(_ushort, max_xmit_frag, 16UL);
+ NDR_MEMBER(_ushort, max_recv_frag, 18UL);
+ NDR_MEMBER(_ulong, assoc_group_id, 20UL);
+
+ /* port any is the conformant culprit */
+ offset = 24UL;
+
+ switch (mlnds->m_op) {
+ case NDR_M_OP_MARSHALL:
+ val->sec_addr.length =
+ strlen((char *)val->sec_addr.port_spec) + 1;
+ break;
+
+ case NDR_M_OP_UNMARSHALL:
+ break;
+
+ default:
+ NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
+ return (0);
+ }
+
+ NDR_MEMBER(_ushort, sec_addr.length, offset);
+ NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec,
+ offset+2UL, val->sec_addr.length);
+
+ offset += 2;
+ offset += val->sec_addr.length;
+ offset += (4 - offset) & 3;
+
+ NDR_MEMBER(_mlrpc_p_result_list, p_result_list, offset);
+ return (1);
+}
+
+unsigned
+mlrpc_bind_ack_hdr_size(struct mlrpcconn_bind_ack_hdr *bahdr)
+{
+ unsigned offset;
+ unsigned length;
+
+ /* port any is the conformant culprit */
+ offset = 24UL;
+
+ length = strlen((char *)bahdr->sec_addr.port_spec) + 1;
+
+ offset += 2;
+ offset += length;
+ offset += (4 - offset) & 3;
+ offset += sizeof (bahdr->p_result_list);
+ return (offset);
+}
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_heap.c b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_heap.c
new file mode 100644
index 0000000000..97a16ea010
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_heap.c
@@ -0,0 +1,236 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MLRPC heap management. The heap is used for temporary storage by
+ * both the client and server side library routines. In order to
+ * support the different requirements of the various RPCs, the heap
+ * can grow dynamically if required. We start with a single block
+ * and perform sub-allocations from it. If an RPC requires more space
+ * we will continue to add it a block at a time. This means that we
+ * don't hog lots of memory on every call to support the few times
+ * that we actually need a lot heap space.
+ *
+ * Note that there is no individual free function. Once space has been
+ * allocated, it remains allocated until the heap is destroyed. This
+ * shouldn't be an issue because the heap is being filled with data to
+ * be marshalled or unmarshalled and we need it all to be there until
+ * the point that the entire heap is no longer required.
+ */
+
+#include <sys/errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/uio.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/mlrpc.h>
+
+/*
+ * Allocate a heap structure and the first heap block. For many RPC
+ * operations this will be the only time we need to malloc memory
+ * in this instance of the heap. The only point of note here is that
+ * we put the heap management data in the first block to avoid a
+ * second malloc. Make sure that sizeof(mlrpc_heap_t) is smaller
+ * than MLRPC_HEAP_BLKSZ.
+ *
+ * Note that the heap management data is at the start of the first block.
+ *
+ * Returns a pointer to the newly created heap, which is used like an
+ * opaque handle with the rest of the heap management interface..
+ */
+mlrpc_heap_t *
+mlrpc_heap_create(void)
+{
+ mlrpc_heap_t *heap;
+ char *base;
+
+ if ((base = (char *)malloc(MLRPC_HEAP_BLKSZ)) == NULL)
+ return (NULL);
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ heap = (mlrpc_heap_t *)base;
+ bzero(heap, sizeof (mlrpc_heap_t));
+
+ heap->iovcnt = MLRPC_HEAP_MAXIOV;
+ heap->iov = heap->iovec;
+ heap->iov->iov_base = base;
+ heap->iov->iov_len = sizeof (mlrpc_heap_t);
+ heap->top = base + MLRPC_HEAP_BLKSZ;
+ heap->next = base + sizeof (mlrpc_heap_t);
+
+ return (heap);
+}
+
+/*
+ * Deallocate all of the memory associated with a heap. This is the
+ * only way to deallocate heap memory, it isn't possible to free the
+ * space obtained by individual malloc calls.
+ *
+ * Note that the first block contains the heap management data, which
+ * is deleted last.
+ */
+void
+mlrpc_heap_destroy(mlrpc_heap_t *heap)
+{
+ int i;
+ char *p;
+
+ if (heap) {
+ for (i = 1; i < MLRPC_HEAP_MAXIOV; ++i) {
+ if ((p = heap->iovec[i].iov_base) != NULL)
+ free(p);
+ }
+
+ free(heap);
+ }
+}
+
+/*
+ * Allocate space in the specified heap. All requests are padded, if
+ * required, to ensure dword alignment. If the current iov will be
+ * exceeded, we allocate a new block and setup the next iov. Otherwise
+ * all we have to do is move the next pointer and update the current
+ * iov length.
+ *
+ * On success, a pointer to the allocated (dword aligned) area is
+ * returned. Otherwise a null pointer is returned.
+ */
+void *
+mlrpc_heap_malloc(mlrpc_heap_t *heap, unsigned size)
+{
+ char *p;
+ int align;
+ int incr_size;
+
+ align = (4 - size) & 3;
+ size += align;
+
+ if (heap == NULL || size == 0)
+ return (NULL);
+
+ p = heap->next;
+
+ if (p + size > heap->top) {
+ if ((heap->iovcnt == 0) || ((--heap->iovcnt) == 0))
+ return (NULL);
+
+ incr_size = (size < MLRPC_HEAP_BLKSZ) ? MLRPC_HEAP_BLKSZ : size;
+
+ if ((p = (char *)malloc(incr_size)) == NULL)
+ return (NULL);
+
+ ++heap->iov;
+ heap->iov->iov_base = p;
+ heap->iov->iov_len = 0;
+ heap->top = p + incr_size;
+ }
+
+ heap->next = p + size;
+ heap->iov->iov_len += size;
+ return ((void *)p);
+}
+
+/*
+ * Convenience function to do heap strdup.
+ */
+void *
+mlrpc_heap_strsave(mlrpc_heap_t *heap, char *s)
+{
+ int len;
+ void *p;
+
+ if (s == NULL)
+ return (NULL);
+
+ /*
+ * We don't need to clutter the heap with empty strings.
+ */
+ if ((len = strlen(s)) == 0)
+ return ("");
+
+ if ((p = mlrpc_heap_malloc(heap, len+1)) != NULL)
+ (void) strcpy((char *)p, s);
+
+ return (p);
+}
+
+/*
+ * Our regular string marshalling always creates null terminated strings
+ * but some Windows clients and servers are pedantic about the string
+ * formats they will accept and require non-null terminated strings.
+ * This function can be used to build a wide-char, non-null terminated
+ * string in the heap as a varying/conformant array. We need to do the
+ * wide-char conversion here because the marshalling code won't be
+ * aware that this is really a string.
+ */
+void
+mlrpc_heap_mkvcs(mlrpc_heap_t *heap, char *s, mlrpc_vcbuf_t *vcs)
+{
+ int mlen;
+
+ vcs->wclen = mts_wcequiv_strlen(s);
+ vcs->wcsize = vcs->wclen;
+
+ mlen = sizeof (struct mlrpc_vcb) + vcs->wcsize + sizeof (mts_wchar_t);
+
+ vcs->vcb = (struct mlrpc_vcb *)mlrpc_heap_malloc(heap, mlen);
+
+ if (vcs->vcb) {
+ vcs->vcb->vc_first_is = 0;
+ vcs->vcb->vc_length_is = vcs->wclen / sizeof (mts_wchar_t);
+ (void) mts_mbstowcs((mts_wchar_t *)vcs->vcb->buffer, s,
+ vcs->vcb->vc_length_is);
+ }
+}
+
+int
+mlrpc_heap_used(mlrpc_heap_t *heap)
+{
+ int used = 0;
+ int i;
+
+ for (i = 0; i < MLRPC_HEAP_MAXIOV; ++i)
+ used += heap->iovec[i].iov_len;
+
+ return (used);
+}
+
+int
+mlrpc_heap_avail(mlrpc_heap_t *heap)
+{
+ int avail;
+ int count;
+
+ count = (heap->iovcnt == 0) ? 0 : (heap->iovcnt - 1);
+
+ avail = count * MLRPC_HEAP_BLKSZ;
+ avail += (heap->top - heap->next);
+
+ return (avail);
+}
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_server.c b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_server.c
new file mode 100644
index 0000000000..a5bf41a617
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_server.c
@@ -0,0 +1,836 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Server side RPC handler.
+ */
+
+#include <thread.h>
+#include <synch.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <time.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/ndr.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/smb_winpipe.h>
+
+/*
+ * Fragment size (5680: NT style).
+ */
+#define MLRPC_FRAG_SZ 5680
+static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ;
+
+/*
+ * Context table.
+ */
+#define CTXT_TABLE_ENTRIES 128
+static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES];
+static mutex_t mlsvc_context_lock;
+
+static int mlrpc_s_process(struct mlrpc_xaction *);
+static int mlrpc_s_bind(struct mlrpc_xaction *);
+static int mlrpc_s_request(struct mlrpc_xaction *);
+static int mlrpc_generic_call_stub(struct mlrpc_xaction *);
+static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *);
+static int mlrpc_s_alter_context(struct mlrpc_xaction *);
+static void mlrpc_reply_bind_ack(struct mlrpc_xaction *);
+static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long);
+static int mlrpc_build_reply(struct mlrpc_xaction *);
+
+/*
+ * The is the RPC service server-side entry point. All MSRPC encoded
+ * messages should be passed through here. We use the same context
+ * structure as the client side but we don't need to set up the client
+ * side info.
+ */
+int
+mlsvc_rpc_process(smb_pipe_t *inpipe, smb_pipe_t **outpipe,
+ smb_dr_user_ctx_t *user_ctx)
+{
+ struct mlsvc_rpc_context *context;
+ struct mlrpc_xaction *mxa;
+ struct mlndr_stream *recv_mlnds;
+ struct mlndr_stream *send_mlnds;
+ unsigned char *pdu_base_addr;
+ int datalen;
+
+ if (inpipe == NULL || user_ctx == NULL)
+ return (-1);
+
+ context = mlsvc_lookup_context(inpipe->sp_pipeid);
+ if (context == NULL)
+ return (-1);
+
+ context->user_ctx = user_ctx;
+
+ mxa = (struct mlrpc_xaction *)malloc(sizeof (struct mlrpc_xaction));
+ if (mxa == NULL)
+ return (-1);
+
+ bzero(mxa, sizeof (struct mlrpc_xaction));
+ mxa->context = context;
+ mxa->binding_list = context->binding;
+
+ if ((mxa->heap = mlrpc_heap_create()) == NULL) {
+ free(mxa);
+ return (-1);
+ }
+
+ recv_mlnds = &mxa->recv_mlnds;
+
+ (void) mlnds_initialize(recv_mlnds, inpipe->sp_datalen,
+ NDR_MODE_CALL_RECV, mxa->heap);
+
+ bcopy(inpipe->sp_data, recv_mlnds->pdu_base_addr, inpipe->sp_datalen);
+
+ send_mlnds = &mxa->send_mlnds;
+ (void) mlnds_initialize(send_mlnds, 0,
+ NDR_MODE_RETURN_SEND, mxa->heap);
+
+ (void) mlrpc_s_process(mxa);
+
+ /*
+ * copy into outpipe
+ */
+ datalen = send_mlnds->pdu_size_with_rpc_hdrs;
+ *outpipe = calloc(1, sizeof (smb_pipe_t) + datalen);
+ (*outpipe)->sp_datalen = datalen;
+
+ /*
+ * Different pointers for single frag vs multi frag responses.
+ */
+ if (send_mlnds->pdu_base_addr_with_rpc_hdrs)
+ pdu_base_addr = send_mlnds->pdu_base_addr_with_rpc_hdrs;
+ else
+ pdu_base_addr = send_mlnds->pdu_base_addr;
+
+ bcopy((char *)pdu_base_addr, (*outpipe)->sp_data, datalen);
+ mlnds_destruct(&mxa->recv_mlnds);
+ mlnds_destruct(&mxa->send_mlnds);
+ mlrpc_heap_destroy(mxa->heap);
+ free(mxa);
+ return (datalen);
+}
+
+/*
+ * Lookup the context for pipeid. If one exists, return a pointer to it.
+ * Otherwise attempt to allocate a new context and return it. If the
+ * context table is full, return a null pointer.
+ */
+struct mlsvc_rpc_context *
+mlsvc_lookup_context(int fid)
+{
+ struct mlsvc_rpc_context *context;
+ struct mlsvc_rpc_context *available = NULL;
+ int i;
+
+ (void) mutex_lock(&mlsvc_context_lock);
+
+ for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
+ context = &context_table[i];
+
+ if (available == NULL && context->fid == 0) {
+ available = context;
+ continue;
+ }
+
+ if (context->fid == fid) {
+ (void) mutex_unlock(&mlsvc_context_lock);
+ return (context);
+ }
+ }
+
+ if (available) {
+ bzero(available, sizeof (struct mlsvc_rpc_context));
+ available->fid = fid;
+
+ mlrpc_binding_pool_initialize(&available->binding,
+ available->binding_pool, CTXT_N_BINDING_POOL);
+ }
+
+ (void) mutex_unlock(&mlsvc_context_lock);
+ return (available);
+}
+
+/*
+ * This function should be called to release the context associated
+ * with a fid when the client performs a close file.
+ */
+void
+mlsvc_rpc_release(int fid)
+{
+ struct mlsvc_rpc_context *context;
+ int i;
+
+ (void) mutex_lock(&mlsvc_context_lock);
+
+ for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
+ context = &context_table[i];
+
+ if (context->fid == fid) {
+ bzero(context, sizeof (struct mlsvc_rpc_context));
+ break;
+ }
+ }
+
+ (void) mutex_unlock(&mlsvc_context_lock);
+}
+
+/*
+ * This is the entry point for all server-side RPC processing.
+ * It is assumed that the PDU has already been received.
+ */
+static int
+mlrpc_s_process(struct mlrpc_xaction *mxa)
+{
+ int rc;
+
+ rc = mlrpc_decode_pdu_hdr(mxa);
+ if (!MLRPC_DRC_IS_OK(rc))
+ return (-1);
+
+ (void) mlrpc_reply_prepare_hdr(mxa);
+
+ switch (mxa->ptype) {
+ case MLRPC_PTYPE_BIND:
+ rc = mlrpc_s_bind(mxa);
+ break;
+
+ case MLRPC_PTYPE_REQUEST:
+ rc = mlrpc_s_request(mxa);
+ break;
+
+ case MLRPC_PTYPE_ALTER_CONTEXT:
+ rc = mlrpc_s_alter_context(mxa);
+ break;
+
+ default:
+ rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID;
+ break;
+ }
+
+ if (MLRPC_DRC_IS_FAULT(rc))
+ mlrpc_reply_fault(mxa, rc);
+
+ (void) mlrpc_build_reply(mxa);
+ return (rc);
+}
+
+/*
+ * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
+ * p_results[] not supported.
+ */
+static int
+mlrpc_s_bind(struct mlrpc_xaction *mxa)
+{
+ mlrpc_p_cont_list_t *cont_list;
+ mlrpc_p_result_list_t *result_list;
+ mlrpc_p_result_t *result;
+ unsigned p_cont_id;
+ struct mlrpc_binding *mbind;
+ mlrpc_uuid_t *as_uuid;
+ mlrpc_uuid_t *ts_uuid;
+ char as_buf[64];
+ char ts_buf[64];
+ int as_vers;
+ int ts_vers;
+ struct mlndr_stream *send_mlnds;
+ struct mlrpc_service *msvc;
+ int rc;
+ mlrpc_port_any_t *sec_addr;
+
+ /* acquire targets */
+ cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
+ result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
+ result = &result_list->p_results[0];
+
+ /*
+ * Set up temporary secondary address port.
+ * We will correct this later (below).
+ */
+ send_mlnds = &mxa->send_mlnds;
+ sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
+ sec_addr->length = 13;
+ (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
+
+ result_list->n_results = 1;
+ result_list->reserved = 0;
+ result_list->reserved2 = 0;
+ result->result = MLRPC_PCDR_ACCEPTANCE;
+ result->reason = 0;
+ bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
+
+ /* sanity check */
+ if (cont_list->n_context_elem != 1 ||
+ cont_list->p_cont_elem[0].n_transfer_syn != 1) {
+ mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem");
+ }
+
+ p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
+
+ if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) {
+ /*
+ * Duplicate p_cont_id.
+ * Send a bind_ack with a better error.
+ */
+ mlndo_trace("mlrpc_s_bind: duplicate binding");
+ return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
+ }
+
+ if ((mbind = mlrpc_new_binding(mxa)) == NULL) {
+ /*
+ * No free binding slot
+ */
+ result->result = MLRPC_PCDR_PROVIDER_REJECTION;
+ result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED;
+ mlndo_trace("mlrpc_s_bind: no resources");
+ return (MLRPC_DRC_OK);
+ }
+
+ as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
+ as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
+
+ ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
+ ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
+
+ msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers);
+ if (!msvc) {
+ mlrpc_uuid_to_str(as_uuid, as_buf);
+ mlrpc_uuid_to_str(ts_uuid, ts_buf);
+
+ mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service");
+ mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d",
+ as_buf, as_vers, ts_buf, ts_vers);
+
+ result->result = MLRPC_PCDR_PROVIDER_REJECTION;
+ result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
+ return (MLRPC_DRC_OK);
+ }
+
+ /*
+ * We can now use the correct secondary address port.
+ */
+ sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
+ sec_addr->length = strlen(msvc->sec_addr_port) + 1;
+ (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
+ MLRPC_PORT_ANY_MAX_PORT_SPEC);
+
+ mbind->p_cont_id = p_cont_id;
+ mbind->which_side = MLRPC_BIND_SIDE_SERVER;
+ /* mbind->context set by app */
+ mbind->service = msvc;
+ mbind->instance_specific = 0;
+
+ mxa->binding = mbind;
+
+ if (msvc->bind_req) {
+ /*
+ * Call the service-specific bind() handler. If
+ * this fails, we shouild send a specific error
+ * on the bind ack.
+ */
+ rc = (msvc->bind_req)(mxa);
+ if (MLRPC_DRC_IS_FAULT(rc)) {
+ mbind->service = 0; /* free binding slot */
+ mbind->which_side = 0;
+ mbind->p_cont_id = 0;
+ mbind->instance_specific = 0;
+ return (rc);
+ }
+ }
+
+ result->transfer_syntax =
+ cont_list->p_cont_elem[0].transfer_syntaxes[0];
+
+ /*
+ * Special rejection of Windows 2000 DSSETUP interface.
+ * This interface was introduced in Windows 2000 but has
+ * been subsequently deprecated due to problems.
+ */
+ if (strcmp(msvc->name, "DSSETUP") == 0) {
+ result->result = MLRPC_PCDR_PROVIDER_REJECTION;
+ result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
+ }
+
+ return (MLRPC_DRC_BINDING_MADE);
+}
+
+/*
+ * mlrpc_s_alter_context
+ *
+ * The alter context request is used to request additional presentation
+ * context for another interface and/or version. It's very similar to a
+ * bind request.
+ *
+ * We don't fully support multiple contexts so, for now, we reject this
+ * request. Windows 2000 clients attempt to use an alternate LSA context
+ * when ACLs are modified.
+ */
+static int
+mlrpc_s_alter_context(struct mlrpc_xaction *mxa)
+{
+ mlrpc_p_result_list_t *result_list;
+ mlrpc_p_result_t *result;
+ mlrpc_p_cont_list_t *cont_list;
+ struct mlrpc_binding *mbind;
+ struct mlrpc_service *msvc;
+ unsigned p_cont_id;
+ mlrpc_uuid_t *as_uuid;
+ mlrpc_uuid_t *ts_uuid;
+ int as_vers;
+ int ts_vers;
+ mlrpc_port_any_t *sec_addr;
+
+ result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
+ result_list->n_results = 1;
+ result_list->reserved = 0;
+ result_list->reserved2 = 0;
+
+ result = &result_list->p_results[0];
+ result->result = MLRPC_PCDR_ACCEPTANCE;
+ result->reason = 0;
+ bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
+
+ if (mxa != NULL) {
+ result->result = MLRPC_PCDR_PROVIDER_REJECTION;
+ result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
+ return (MLRPC_DRC_OK);
+ }
+
+ cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
+ p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
+
+ if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL)
+ return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
+
+ if ((mbind = mlrpc_new_binding(mxa)) == NULL) {
+ result->result = MLRPC_PCDR_PROVIDER_REJECTION;
+ result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED;
+ return (MLRPC_DRC_OK);
+ }
+
+ as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
+ as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
+
+ ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
+ ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
+
+ msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers);
+ if (msvc == 0) {
+ result->result = MLRPC_PCDR_PROVIDER_REJECTION;
+ result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
+ return (MLRPC_DRC_OK);
+ }
+
+ mbind->p_cont_id = p_cont_id;
+ mbind->which_side = MLRPC_BIND_SIDE_SERVER;
+ /* mbind->context set by app */
+ mbind->service = msvc;
+ mbind->instance_specific = 0;
+ mxa->binding = mbind;
+
+ sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
+ sec_addr->length = 0;
+ bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC);
+
+ result->transfer_syntax =
+ cont_list->p_cont_elem[0].transfer_syntaxes[0];
+
+ return (MLRPC_DRC_BINDING_MADE);
+}
+
+static int
+mlrpc_s_request(struct mlrpc_xaction *mxa)
+{
+ struct mlrpc_binding *mbind;
+ struct mlrpc_service *msvc;
+ unsigned p_cont_id;
+ int rc;
+
+ mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
+ p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
+
+ if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL)
+ return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID);
+
+ mxa->binding = mbind;
+ msvc = mbind->service;
+
+ /*
+ * Make room for the response hdr.
+ */
+ mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE;
+
+ if (msvc->call_stub)
+ rc = (*msvc->call_stub)(mxa);
+ else
+ rc = mlrpc_generic_call_stub(mxa);
+
+ if (MLRPC_DRC_IS_FAULT(rc)) {
+ mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
+ msvc->name, mxa->opnum, rc);
+ }
+
+ return (rc);
+}
+
+/*
+ * The transaction and the two mlnds streams use the same heap, which
+ * should already exist at this point. The heap will also be available
+ * to the stub.
+ */
+static int
+mlrpc_generic_call_stub(struct mlrpc_xaction *mxa)
+{
+ struct mlrpc_binding *mbind = mxa->binding;
+ struct mlrpc_service *msvc = mbind->service;
+ struct ndr_typeinfo *intf_ti = msvc->interface_ti;
+ struct mlrpc_stub_table *ste;
+ int opnum = mxa->opnum;
+ unsigned p_len = intf_ti->c_size_fixed_part;
+ char *param;
+ int rc;
+
+ if (mxa->heap == NULL) {
+ mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+ }
+
+ if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) {
+ mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
+ msvc->name, opnum);
+ return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
+ }
+
+ if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL)
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+
+ bzero(param, p_len);
+
+ rc = mlrpc_decode_call(mxa, param);
+ if (!MLRPC_DRC_IS_OK(rc))
+ return (rc);
+
+ rc = (*ste->func)(param, mxa);
+ if (rc == MLRPC_DRC_OK)
+ rc = mlrpc_encode_return(mxa, param);
+
+ return (rc);
+}
+
+/*
+ * We can perform some initial setup of the response header here.
+ * We also need to cache some of the information from the bind
+ * negotiation for use during subsequent RPC calls.
+ */
+static void
+mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa)
+{
+ mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
+ mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
+
+ hdr->rpc_vers = 5;
+ hdr->rpc_vers_minor = 0;
+ hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
+ hdr->packed_drep = rhdr->packed_drep;
+ hdr->frag_length = 0;
+ hdr->auth_length = 0;
+ hdr->call_id = rhdr->call_id;
+#ifdef _BIG_ENDIAN
+ hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
+ | MLRPC_REPLAB_INTG_BIG_ENDIAN;
+#else
+ hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
+ | MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
+#endif
+
+ switch (mxa->ptype) {
+ case MLRPC_PTYPE_BIND:
+ hdr->ptype = MLRPC_PTYPE_BIND_ACK;
+ mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
+ mxa->recv_hdr.bind_hdr.max_xmit_frag;
+ mxa->send_hdr.bind_ack_hdr.max_recv_frag =
+ mxa->recv_hdr.bind_hdr.max_recv_frag;
+ mxa->send_hdr.bind_ack_hdr.assoc_group_id =
+ mxa->recv_hdr.bind_hdr.assoc_group_id;
+
+ if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
+ mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
+
+ /*
+ * Save the maximum fragment sizes
+ * for use with subsequent requests.
+ */
+ mxa->context->max_xmit_frag =
+ mxa->recv_hdr.bind_hdr.max_xmit_frag;
+
+ mxa->context->max_recv_frag =
+ mxa->recv_hdr.bind_hdr.max_recv_frag;
+
+ break;
+
+ case MLRPC_PTYPE_REQUEST:
+ hdr->ptype = MLRPC_PTYPE_RESPONSE;
+ /* mxa->send_hdr.response_hdr.alloc_hint */
+ mxa->send_hdr.response_hdr.p_cont_id =
+ mxa->recv_hdr.request_hdr.p_cont_id;
+ mxa->send_hdr.response_hdr.cancel_count = 0;
+ mxa->send_hdr.response_hdr.reserved = 0;
+ break;
+
+ case MLRPC_PTYPE_ALTER_CONTEXT:
+ hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP;
+ /*
+ * The max_xmit_frag, max_recv_frag
+ * and assoc_group_id are ignored.
+ */
+ break;
+
+ default:
+ hdr->ptype = 0xFF;
+ }
+}
+
+/*
+ * Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header.
+ * The frag_length is different from a regular RPC response.
+ */
+static void
+mlrpc_reply_bind_ack(struct mlrpc_xaction *mxa)
+{
+ mlrpcconn_common_header_t *hdr;
+ mlrpcconn_bind_ack_hdr_t *bahdr;
+
+ hdr = &mxa->send_hdr.common_hdr;
+ bahdr = &mxa->send_hdr.bind_ack_hdr;
+ hdr->frag_length = mlrpc_bind_ack_hdr_size(bahdr);
+}
+
+/*
+ * Signal an RPC fault. The stream is reset and we overwrite whatever
+ * was in the response header with the fault information.
+ */
+static void
+mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc)
+{
+ mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
+ mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
+ struct mlndr_stream *mlnds = &mxa->send_mlnds;
+ unsigned long fault_status;
+
+ MLNDS_RESET(mlnds);
+
+ hdr->rpc_vers = 5;
+ hdr->rpc_vers_minor = 0;
+ hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
+ hdr->packed_drep = rhdr->packed_drep;
+ hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
+ hdr->auth_length = 0;
+ hdr->call_id = rhdr->call_id;
+#ifdef _BIG_ENDIAN
+ hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
+ | MLRPC_REPLAB_INTG_BIG_ENDIAN;
+#else
+ hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
+ | MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
+#endif
+
+ switch (drc & MLRPC_DRC_MASK_SPECIFIER) {
+ case MLRPC_DRC_FAULT_OUT_OF_MEMORY:
+ case MLRPC_DRC_FAULT_ENCODE_TOO_BIG:
+ fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG;
+ break;
+
+ case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID:
+ fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
+ break;
+
+ case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID:
+ fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR;
+ break;
+
+ case MLRPC_DRC_FAULT_DECODE_FAILED:
+ case MLRPC_DRC_FAULT_ENCODE_FAILED:
+ fault_status = MLRPC_FAULT_NCA_PROTO_ERROR;
+ break;
+
+ default:
+ fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT;
+ break;
+ }
+
+ mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT;
+ mxa->send_hdr.fault_hdr.status = fault_status;
+ mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
+}
+
+static int
+mlrpc_build_reply(struct mlrpc_xaction *mxa)
+{
+ mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
+ struct mlndr_stream *mlnds = &mxa->send_mlnds;
+ unsigned long pdu_size;
+ unsigned long frag_size;
+ unsigned long pdu_data_size;
+ unsigned long frag_data_size;
+ uint32_t rem_dlen;
+ uint32_t save_rem_dlen;
+ uint32_t bytesoff;
+ uint32_t cnt;
+ uint32_t obytes;
+ uint32_t num_ext_frags;
+ uint16_t last_frag = 0;
+ uchar_t *frag_startp;
+ mlrpcconn_common_header_t *rpc_hdr;
+
+ hdr = &mxa->send_hdr.common_hdr;
+
+ frag_size = mlrpc_frag_size;
+ pdu_size = mlnds->pdu_size;
+
+ if (pdu_size <= frag_size) {
+ /*
+ * Single fragment response. The PDU size may be zero
+ * here (i.e. bind or fault response). So don't make
+ * any assumptions about it until after the header is
+ * encoded.
+ */
+ switch (hdr->ptype) {
+ case MLRPC_PTYPE_BIND_ACK:
+ mlrpc_reply_bind_ack(mxa);
+ break;
+
+ case MLRPC_PTYPE_FAULT:
+ /* already setup */
+ break;
+
+ case MLRPC_PTYPE_RESPONSE:
+ hdr->frag_length = pdu_size;
+ mxa->send_hdr.response_hdr.alloc_hint =
+ hdr->frag_length;
+ break;
+
+ default:
+ hdr->frag_length = pdu_size;
+ break;
+ }
+
+ mlnds->pdu_scan_offset = 0;
+ (void) mlrpc_encode_pdu_hdr(mxa);
+
+ mlnds->pdu_size_with_rpc_hdrs = mlnds->pdu_size;
+ mlnds->pdu_base_addr_with_rpc_hdrs = 0;
+ return (0);
+ }
+
+ /*
+ * Multiple fragment response.
+ */
+ hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG;
+ hdr->frag_length = frag_size;
+ mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE;
+ mlnds->pdu_scan_offset = 0;
+
+ (void) mlrpc_encode_pdu_hdr(mxa);
+
+ /*
+ * We need to update the 24-byte header in subsequent fragments.
+ *
+ * pdu_data_size: total data remaining to be handled
+ * frag_size: total fragment size including header
+ * frag_data_size: data in fragment
+ * (i.e. frag_size - MLRPC_RSP_HDR_SIZE)
+ */
+ pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE;
+ frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE;
+
+ num_ext_frags = pdu_data_size / frag_data_size;
+ /*
+ * if the outpipe is bigger than a frag_size, we need
+ * to stretch the pipe and insert an RPC header at each
+ * frag boundary. This outpipe gets chunked out in xdrlen
+ * sizes for each trans request
+ */
+ mlnds->pdu_base_addr_with_rpc_hdrs
+ = malloc(pdu_size + (num_ext_frags * MLRPC_RSP_HDR_SIZE));
+ mlnds->pdu_size_with_rpc_hdrs =
+ mlnds->pdu_size + (num_ext_frags * MLRPC_RSP_HDR_SIZE);
+
+ /*
+ * Start stretching loop.
+ */
+ bcopy(mlnds->pdu_base_addr,
+ mlnds->pdu_base_addr_with_rpc_hdrs, frag_size);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ rpc_hdr = (mlrpcconn_common_header_t *)
+ mlnds->pdu_base_addr_with_rpc_hdrs;
+ rpc_hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG;
+ rem_dlen = pdu_data_size - frag_size;
+ bytesoff = frag_size;
+ cnt = 1;
+ while (num_ext_frags--) {
+ /* first copy the RPC header to the front of the frag */
+ bcopy(mlnds->pdu_base_addr, mlnds->pdu_base_addr_with_rpc_hdrs +
+ (cnt * frag_size), MLRPC_RSP_HDR_SIZE);
+
+ /* then copy the data portion of the frag */
+ save_rem_dlen = rem_dlen;
+ if (rem_dlen >= (frag_size - MLRPC_RSP_HDR_SIZE)) {
+ rem_dlen = rem_dlen - frag_size + MLRPC_RSP_HDR_SIZE;
+ obytes = frag_size - MLRPC_RSP_HDR_SIZE;
+ } else {
+ last_frag = 1; /* this is the last one */
+ obytes = rem_dlen;
+ }
+
+ frag_startp = mlnds->pdu_base_addr_with_rpc_hdrs +
+ (cnt * frag_size);
+ bcopy(mlnds->pdu_base_addr + bytesoff,
+ frag_startp + MLRPC_RSP_HDR_SIZE, obytes);
+
+ /* set the FRAG FLAGS in the frag header spot */
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ rpc_hdr = (mlrpcconn_common_header_t *)frag_startp;
+ if (last_frag) {
+ rpc_hdr->frag_length = save_rem_dlen;
+ rpc_hdr->pfc_flags = MLRPC_PFC_LAST_FRAG;
+ } else {
+ rpc_hdr->pfc_flags = 0;
+ }
+
+ bytesoff += (frag_size - MLRPC_RSP_HDR_SIZE);
+ cnt++;
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_svc.c b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_svc.c
new file mode 100644
index 0000000000..771e54b7e4
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mlrpc_svc.c
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ndr.h>
+#include <smbsrv/mlrpc.h>
+
+#define NDL_MAX_SERVICES 32
+static struct mlrpc_service *mlrpc_services[NDL_MAX_SERVICES];
+
+struct mlrpc_stub_table *
+mlrpc_find_stub_in_svc(struct mlrpc_service *msvc, int opnum)
+{
+ struct mlrpc_stub_table *ste;
+
+ for (ste = msvc->stub_table; ste->func; ste++) {
+ if (ste->opnum == opnum)
+ return (ste);
+ }
+
+ return (NULL);
+}
+
+struct mlrpc_service *
+mlrpc_find_service_by_name(const char *name)
+{
+ struct mlrpc_service *msvc;
+ int i;
+
+ for (i = 0; i < NDL_MAX_SERVICES; i++) {
+ if ((msvc = mlrpc_services[i]) == NULL)
+ continue;
+
+ if (strcasecmp(name, msvc->name) != 0)
+ continue;
+
+ mlndo_printf(0, 0, "%s %s", msvc->name, msvc->desc);
+ return (msvc);
+ }
+
+ return (NULL);
+}
+
+struct mlrpc_service *
+mlrpc_find_service_by_uuids(mlrpc_uuid_t *as_uuid, int as_vers,
+ mlrpc_uuid_t *ts_uuid, int ts_vers)
+{
+ struct mlrpc_service *msvc;
+ char abstract_syntax[128];
+ char transfer_syntax[128];
+ int i;
+
+ if (as_uuid)
+ mlrpc_uuid_to_str(as_uuid, abstract_syntax);
+
+ if (ts_uuid)
+ mlrpc_uuid_to_str(ts_uuid, transfer_syntax);
+
+ for (i = 0; i < NDL_MAX_SERVICES; i++) {
+ if ((msvc = mlrpc_services[i]) == NULL)
+ continue;
+
+ if (as_uuid) {
+ if (msvc->abstract_syntax_uuid == 0)
+ continue;
+
+ if (msvc->abstract_syntax_version != as_vers)
+ continue;
+
+ if (strcasecmp(abstract_syntax,
+ msvc->abstract_syntax_uuid))
+ continue;
+ }
+
+ if (ts_uuid) {
+ if (msvc->transfer_syntax_uuid == 0)
+ continue;
+
+ if (msvc->transfer_syntax_version != ts_vers)
+ continue;
+
+ if (strcasecmp(transfer_syntax,
+ msvc->transfer_syntax_uuid))
+ continue;
+ }
+
+ mlndo_printf(0, 0, "%s %s", msvc->name, msvc->desc);
+ return (msvc);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Register a service.
+ *
+ * Returns:
+ * 0 Success
+ * -1 Duplicate service
+ * -2 Duplicate name
+ * -3 Table overflow
+ */
+int
+mlrpc_register_service(struct mlrpc_service *msvc)
+{
+ struct mlrpc_service *p;
+ int free_slot = -1;
+ int i;
+
+ for (i = 0; i < NDL_MAX_SERVICES; i++) {
+ if ((p = mlrpc_services[i]) == NULL) {
+ if (free_slot < 0)
+ free_slot = i;
+ continue;
+ }
+
+ if (p == msvc)
+ return (-1);
+
+ if (strcasecmp(p->name, msvc->name) == 0)
+ return (-2);
+ }
+
+ if (free_slot < 0)
+ return (-3);
+
+ mlrpc_services[free_slot] = msvc;
+ return (0);
+}
+
+void
+mlrpc_unregister_service(struct mlrpc_service *msvc)
+{
+ int i;
+
+ for (i = 0; i < NDL_MAX_SERVICES; i++) {
+ if (mlrpc_services[i] == msvc)
+ mlrpc_services[i] = NULL;
+ }
+}
+
+int
+mlrpc_list_services(char *buffer, int bufsize)
+{
+ struct mlrpc_service *msvc;
+ smb_ctxbuf_t ctx;
+ int i;
+
+ (void) smb_ctxbuf_init(&ctx, (uint8_t *)buffer, bufsize);
+
+ for (i = 0; i < NDL_MAX_SERVICES; i++) {
+ if ((msvc = mlrpc_services[i]) != 0) {
+ (void) smb_ctxbuf_printf(&ctx, "%-16s %s\n",
+ msvc->name, msvc->desc);
+ }
+ }
+
+ return (smb_ctxbuf_len(&ctx));
+}
+
+void
+mlrpc_uuid_to_str(mlrpc_uuid_t *uuid, char *str)
+{
+ (void) sprintf(str, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
+ uuid->data1, uuid->data2, uuid->data3,
+ uuid->data4[0], uuid->data4[1],
+ uuid->data4[2], uuid->data4[3],
+ uuid->data4[4], uuid->data4[5],
+ uuid->data4[6], uuid->data4[7]);
+}
+
+int
+mlrpc_str_to_uuid(char *str, mlrpc_uuid_t *uuid)
+{
+ char *p = str;
+ char *q;
+ char buf[4];
+ int i;
+
+ uuid->data1 = strtoul(p, &p, 16);
+ if (*p != '-')
+ return (0);
+ p++;
+
+ uuid->data2 = strtol(p, &p, 16);
+ if (*p != '-')
+ return (0);
+ p++;
+
+ uuid->data3 = strtol(p, &p, 16);
+ if (*p != '-')
+ return (0);
+ p++;
+
+ for (i = 0; i < 8; i++) {
+ if (p[0] == 0 || p[1] == 0)
+ return (0);
+
+ buf[0] = *p++;
+ buf[1] = *p++;
+ buf[2] = 0;
+ uuid->data4[i] = strtol(buf, &q, 16);
+ if (*q != 0)
+ return (0);
+ }
+
+ if (*p != 0)
+ return (0);
+
+ return (1);
+}
+
+void
+mlrpc_binding_pool_initialize(struct mlrpc_binding **headpp,
+ struct mlrpc_binding pool[], unsigned n_pool)
+{
+ struct mlrpc_binding *head = NULL;
+ int ix;
+
+ for (ix = n_pool - 1; ix >= 0; ix--) {
+ pool[ix].next = head;
+ pool[ix].service = NULL;
+ pool[ix].p_cont_id = 0xffff;
+ pool[ix].instance_specific = 0;
+ head = &pool[ix];
+ }
+
+ *headpp = head;
+}
+
+struct mlrpc_binding *
+mlrpc_find_binding(struct mlrpc_xaction *mxa, mlrpc_p_context_id_t p_cont_id)
+{
+ struct mlrpc_binding *mbind;
+
+ for (mbind = mxa->binding_list; mbind; mbind = mbind->next) {
+ if (mbind->service != NULL &&
+ mbind->which_side == MLRPC_BIND_SIDE_SERVER &&
+ mbind->p_cont_id == p_cont_id)
+ break;
+ }
+
+ return (mbind);
+}
+
+struct mlrpc_binding *
+mlrpc_new_binding(struct mlrpc_xaction *mxa)
+{
+ struct mlrpc_binding *mbind;
+
+ for (mbind = mxa->binding_list; mbind; mbind = mbind->next) {
+ if (mbind->service == NULL)
+ break;
+ }
+
+ return (mbind);
+}
diff --git a/usr/src/lib/smbsrv/libmlrpc/i386/Makefile b/usr/src/lib/smbsrv/libmlrpc/i386/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libmlrpc/sparc/Makefile b/usr/src/lib/smbsrv/libmlrpc/sparc/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libmlrpc/sparcv9/Makefile b/usr/src/lib/smbsrv/libmlrpc/sparcv9/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlrpc/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libmlsvc/Makefile b/usr/src/lib/smbsrv/libmlsvc/Makefile
new file mode 100644
index 0000000000..21f844a2c0
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+HDRS= libmlsvc.h
+
+include ../Makefile.smbsrv
diff --git a/usr/src/lib/smbsrv/libmlsvc/Makefile.com b/usr/src/lib/smbsrv/libmlsvc/Makefile.com
new file mode 100644
index 0000000000..e0c1ee5c4c
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/Makefile.com
@@ -0,0 +1,86 @@
+#
+# 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.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libmlsvc.a
+VERS = .1
+
+OBJS_COMMON = \
+ lsalib.o \
+ lsar_lookup.o \
+ lsar_open.o \
+ mlsvc_client.o \
+ mlsvc_dssetup.o \
+ mlsvc_handle.o \
+ mlsvc_init.o \
+ mlsvc_logr.o \
+ mlsvc_lsa.o \
+ mlsvc_netr.o \
+ mlsvc_sam.o \
+ mlsvc_srvsvc.o \
+ mlsvc_svcctl.o \
+ mlsvc_util.o \
+ mlsvc_winreg.o \
+ mlsvc_wkssvc.o \
+ netdfs.o \
+ netr_auth.o \
+ netr_logon.o \
+ samlib.o \
+ samr_open.o \
+ samr_lookup.o \
+ secdb.o \
+ srvsvc_client.o \
+ lmshare.o \
+ smb_share_util.o \
+ smb_autohome.o
+
+# Automatically generated from .ndl files
+NDLLIST = \
+ dssetup \
+ eventlog \
+ lsarpc \
+ netdfs \
+ netlogon \
+ samrpc \
+ spoolss \
+ srvsvc \
+ svcctl \
+ winreg
+
+OBJECTS= $(OBJS_COMMON) $(NDLLIST:%=%_ndr.o)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+INCS += -I$(SRC)/common/smbsrv
+
+LDLIBS += -lmlrpc -lsmbrdr -lsmb -lsmbns -lshare -lnsl -lc
+
+SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_SHARED:%.o=$(SRC)/common/smbsrv/%.c)
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbsrv/libmlsvc/amd64/Makefile b/usr/src/lib/smbsrv/libmlsvc/amd64/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
new file mode 100644
index 0000000000..71cc37af48
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBMLSVC_H
+#define _LIBMLSVC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/hash_table.h>
+#include <smbsrv/smb_token.h>
+#include <smbsrv/smb_privilege.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/libsmb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int mlsvc_init(void);
+extern int mlsvc_is_local_domain(const char *);
+extern DWORD lsa_query_primary_domain_info(void);
+extern DWORD lsa_query_account_domain_info(void);
+extern DWORD lsa_enum_trusted_domains(void);
+
+extern boolean_t locate_resource_pdc(char *);
+
+#define SMB_AUTOHOME_FILE "smbautohome"
+#define SMB_AUTOHOME_PATH "/etc"
+
+typedef struct smb_autohome {
+ struct smb_autohome *ah_next;
+ uint32_t ah_hits;
+ time_t ah_timestamp;
+ char *ah_name; /* User account name */
+ char *ah_path; /* Home directory path */
+ char *ah_container; /* ADS container distinguished name */
+} smb_autohome_t;
+
+extern int smb_autohome_add(const char *);
+extern int smb_autohome_remove(const char *);
+extern int smb_is_autohome(const lmshare_info_t *);
+extern void smb_autohome_setent(void);
+extern void smb_autohome_endent(void);
+extern smb_autohome_t *smb_autohome_getent(const char *name);
+extern smb_autohome_t *smb_autohome_lookup(const char *name);
+
+/*
+ * Local groups
+ */
+#define NT_GROUP_FMRI_PREFIX "network/smb/group"
+
+typedef enum {
+ RWLOCK_NONE,
+ RWLOCK_WRITER,
+ RWLOCK_READER
+} krwmode_t;
+
+typedef struct nt_group_data {
+ void *data;
+ int size;
+} nt_group_data_t;
+
+/*
+ * IMPORTANT NOTE:
+ * If you change nt_group_member_t, nt_group_members_t, or nt_group_t
+ * structures, you MIGHT have to change following functions accordingly:
+ * nt_group_setfields
+ * nt_group_init_size
+ * nt_group_init
+ */
+typedef struct nt_group_member {
+ uint16_t info_size; /* size of the whole structure */
+ uint16_t sid_name_use; /* type of the specified SID */
+ char *account; /* Pointer to account name of member */
+ nt_sid_t sid; /* Variable length */
+} nt_group_member_t;
+
+typedef struct nt_group_members {
+ uint32_t size; /* in bytes */
+ uint32_t count;
+ nt_group_member_t list[ANY_SIZE_ARRAY];
+} nt_group_members_t;
+
+typedef struct nt_group {
+ time_t age;
+ nt_group_data_t info;
+ /*
+ * following fields point to a contigous block
+ * of memory that is read and written from/to DB
+ */
+ uint32_t *attr;
+ uint16_t *sid_name_use;
+ char *name;
+ char *comment;
+ nt_sid_t *sid;
+ smb_privset_t *privileges;
+ nt_group_members_t *members;
+} nt_group_t;
+
+typedef struct nt_group_iterator {
+ HT_ITERATOR *iterator;
+ int iteration;
+} nt_group_iterator_t;
+
+extern int nt_group_num_groups(void);
+extern uint32_t nt_group_add(char *, char *);
+extern uint32_t nt_group_modify(char *, char *, char *);
+extern uint32_t nt_group_delete(char *);
+extern nt_group_t *nt_group_getinfo(char *, krwmode_t);
+extern void nt_group_putinfo(nt_group_t *);
+
+extern int nt_group_getpriv(nt_group_t *, uint32_t);
+extern uint32_t nt_group_setpriv(nt_group_t *, uint32_t, uint32_t);
+
+/* Member manipulation functions */
+extern int nt_group_is_member(nt_group_t *, nt_sid_t *);
+extern uint32_t nt_group_del_member(nt_group_t *, void *, int);
+extern uint32_t nt_group_add_member(nt_group_t *, nt_sid_t *, uint16_t, char *);
+extern int nt_group_num_members(nt_group_t *);
+
+extern void nt_group_ht_lock(krwmode_t);
+extern void nt_group_ht_unlock(void);
+
+extern nt_group_iterator_t *nt_group_open_iterator(void);
+extern void nt_group_close_iterator(nt_group_iterator_t *);
+extern nt_group_t *nt_group_iterate(nt_group_iterator_t *);
+
+extern int nt_group_cache_size(void);
+
+extern int nt_group_member_list(int offset, nt_group_t *grp,
+ ntgrp_member_list_t *rmembers);
+extern void nt_group_list(int offset, char *pattern, ntgrp_list_t *list);
+
+extern uint32_t sam_init(void);
+
+extern uint32_t nt_group_add_member_byname(char *, char *);
+extern uint32_t nt_group_del_member_byname(nt_group_t *, char *);
+extern void nt_group_add_groupprivs(nt_group_t *, smb_privset_t *);
+
+extern uint32_t nt_groups_member_privs(nt_sid_t *, smb_privset_t *);
+extern int nt_groups_member_ngroups(nt_sid_t *);
+extern uint32_t nt_groups_member_groups(nt_sid_t *, smb_id_t *, int);
+extern nt_group_t *nt_groups_lookup_rid(uint32_t);
+extern int nt_groups_count(int);
+
+/*
+ * source for account name size is MSDN
+ */
+#define NT_GROUP_NAME_CHAR_MAX 32
+#define NT_GROUP_NAME_MAX (NT_GROUP_NAME_CHAR_MAX * 3 + 1)
+#define NT_GROUP_USER_NAME_MAX (NT_GROUP_NAME_CHAR_MAX * 3 + 1)
+#define NT_GROUP_MEMBER_NAME_MAX (NT_GROUP_NAME_CHAR_MAX * 3 + 1)
+#define NT_GROUP_COMMENT_MAX 256
+
+/*
+ * flags for count operation
+ */
+#define NT_GROUP_CNT_BUILTIN 1
+#define NT_GROUP_CNT_LOCAL 2
+#define NT_GROUP_CNT_ALL 3
+
+/*
+ * flag to distinguish between add and modify
+ * operations.
+ */
+#define NT_GROUP_OP_CHANGE 1
+#define NT_GROUP_OP_SYNC 2
+
+/*
+ * specify key type for deleting a member i.e.
+ * whether it's member's name or member's SID.
+ */
+#define NT_GROUP_KEY_SID 1
+#define NT_GROUP_KEY_NAME 2
+
+/* Macro for walking members */
+#define NEXT_MEMBER(m) (nt_group_member_t *)((char *)(m) + (m)->info_size)
+
+/*
+ * When NT requests the security descriptor for a local file that
+ * doesn't already have a one, we generate one on-the-fly. The SD
+ * contains both user and group SIDs. The problem is that we need a
+ * way to distinguish a user SID from a group SID when NT performs a
+ * subsequent SID lookup to obtain the appropriate name to display.
+ * The following macros are used to map to and from an external
+ * representation so that we can tell the difference between UIDs
+ * and GIDs. The local UID/GID is shifted left and the LSB is used
+ * to distinguish the id type before it is inserted into the SID.
+ * We can then use this type identifier during lookup operations.
+ */
+#define SAM_MIN_RID 1000
+#define SAM_RT_ERROR -1
+#define SAM_RT_UNIX_UID 0
+#define SAM_RT_UNIX_GID 1
+#define SAM_RT_NT_UID 2
+#define SAM_RT_NT_GID 3
+#define SAM_RT_MASK 0x3
+#define SAM_RT_EVERYONE 4
+#define SAM_RT_UNKNOWN 5
+
+#define SAM_RID_TYPE(rid) ((rid) & SAM_RT_MASK)
+#define SAM_DECODE_RID(rid) (((rid) - SAM_MIN_RID) >> 2)
+#define SAM_ENCODE_RID(type, id) ((((id) << 2) | type) + SAM_MIN_RID)
+#define SAM_ENCODE_UXUID(id) SAM_ENCODE_RID(SAM_RT_UNIX_UID, id)
+#define SAM_ENCODE_UXGID(id) SAM_ENCODE_RID(SAM_RT_UNIX_GID, id)
+#define SAM_ENCODE_NTUID(id) SAM_ENCODE_RID(SAM_RT_NT_UID, id)
+#define SAM_ENCODE_NTGID(id) SAM_ENCODE_RID(SAM_RT_NT_GID, id)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBMLSVC_H */
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/llib-lmlsvc b/usr/src/lib/smbsrv/libmlsvc/common/llib-lmlsvc
new file mode 100644
index 0000000000..412e13d740
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/llib-lmlsvc
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <smbsrv/libmlsvc.h>
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lmshare.c b/usr/src/lib/smbsrv/libmlsvc/common/lmshare.c
new file mode 100644
index 0000000000..5fb02b71f4
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lmshare.c
@@ -0,0 +1,1233 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Lan Manager (SMB/CIFS) share interface implementation. This interface
+ * returns Win32 error codes, usually network error values (lmerr.h).
+ */
+
+#include <errno.h>
+#include <synch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <syslog.h>
+#include <thread.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <synch.h>
+#include <pthread.h>
+#include <sys/mnttab.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <ctype.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbns.h>
+
+#include <libshare.h>
+
+#include <smbsrv/lm.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/cifs.h>
+
+#include <smbsrv/ctype.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_fsd.h>
+
+#define LMSHR_HASHTAB_SZ 1024
+
+static HT_HANDLE *lmshare_handle = NULL;
+
+static rwlock_t lmshare_lock;
+static pthread_t lmshare_load_thread;
+static void *lmshare_load(void *);
+static DWORD lmshare_create_table();
+static int lmshare_delete_shmgr(struct lmshare_info *);
+static int lmshare_setinfo_shmgr(struct lmshare_info *);
+static DWORD lmshare_set_refcnt(char *share_name, int refcnt);
+
+typedef struct lmshare_ad_item {
+ TAILQ_ENTRY(lmshare_ad_item) next;
+ char name[MAXNAMELEN];
+ char container[MAXPATHLEN];
+ char flag;
+} lmshare_ad_item_t;
+
+typedef struct lmshare_ad_queue {
+ int nentries;
+ TAILQ_HEAD(adqueue, lmshare_ad_item) adlist;
+} lmshare_ad_queue_t;
+
+static lmshare_ad_queue_t ad_queue;
+static int publish_on = 0;
+
+static pthread_t lmshare_publish_thread;
+static mutex_t lmshare_publish_mutex = PTHREAD_MUTEX_INITIALIZER;
+static cond_t lmshare_publish_cv = DEFAULTCV;
+
+static void *lmshare_publisher(void *);
+static void lmshare_stop_publish();
+
+/*
+ * Start loading lmshare information from sharemanager
+ * and create the cache.
+ */
+int
+lmshare_start()
+{
+ int rc;
+
+ rc = pthread_create(&lmshare_publish_thread, NULL,
+ lmshare_publisher, 0);
+ if (rc != 0) {
+ syslog(LOG_ERR, "Failed to start publisher thread, "
+ "share publishing is disabled");
+ }
+
+ rc = pthread_create(&lmshare_load_thread, NULL,
+ lmshare_load, 0);
+ if (rc != 0) {
+ syslog(LOG_ERR, "Failed to start share loading, "
+ "existing shares will not be available");
+ }
+
+ return (rc);
+}
+
+void
+lmshare_stop()
+{
+ lmshare_stop_publish();
+}
+
+/*
+ * Load shares from sharemanager.
+ */
+/*ARGSUSED*/
+static void *
+lmshare_load(void *args)
+{
+ lmshare_info_t si;
+ sa_handle_t handle;
+ sa_group_t group;
+ sa_share_t share;
+ sa_resource_t resource;
+ sa_optionset_t opts;
+ char *gstate, *path, *rname;
+
+ if (lmshare_create_table() != NERR_Success) {
+ syslog(LOG_ERR, "Failed to create share hash table");
+ return (NULL);
+ }
+
+ handle = sa_init(SA_INIT_SHARE_API);
+ if (handle == NULL) {
+ syslog(LOG_ERR, "Failed to load share "
+ "information: no libshare handle");
+ return (NULL);
+ }
+
+ for (group = sa_get_group(handle, NULL);
+ group != NULL; group = sa_get_next_group(group)) {
+ gstate = sa_get_group_attr(group, "state");
+ if ((gstate == NULL) ||
+ (strcasecmp(gstate, "disabled") == 0)) {
+ /* Skip disabled or unknown state group */
+ continue;
+ }
+ /* Check and see if smb protocol is available */
+ if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
+ continue;
+ for (share = sa_get_share(group, NULL);
+ share != NULL; share = sa_get_next_share(share)) {
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL) {
+ syslog(LOG_ERR, "Invalid share NO path");
+ continue;
+ }
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ rname = sa_get_resource_attr(resource, "name");
+ if (rname == NULL) {
+ syslog(LOG_ERR, "Invalid share "
+ "resource for path: %s", path);
+ continue;
+ }
+ opts = sa_get_derived_optionset(resource,
+ SMB_PROTOCOL_NAME, 1);
+ smb_build_lmshare_info(rname, path, opts, &si);
+ sa_free_derived_optionset(opts);
+ (void) free(rname);
+ if (lmshare_add(&si, 0) != NERR_Success) {
+ syslog(LOG_ERR, "Failed to load "
+ "share %s", si.share_name);
+ }
+ }
+ /* We are done with all shares for same path */
+ (void) free(path);
+ }
+ }
+
+ sa_fini(handle);
+
+ return (NULL);
+}
+
+/*
+ * lmshare_callback
+ *
+ * Call back to free share structures stored
+ * in shares' hash table.
+ */
+static void
+lmshare_callback(HT_ITEM *item)
+{
+ if (item && item->hi_data)
+ (void) free(item->hi_data);
+}
+
+/*
+ * lmshare_create_table
+ *
+ * Create the share hash table.
+ */
+static DWORD
+lmshare_create_table(void)
+{
+ if (lmshare_handle == NULL) {
+ (void) rwlock_init(&lmshare_lock, USYNC_THREAD, 0);
+ (void) rw_wrlock(&lmshare_lock);
+
+ lmshare_handle = ht_create_table(LMSHR_HASHTAB_SZ,
+ MAXNAMELEN, 0);
+ if (lmshare_handle == NULL) {
+ syslog(LOG_ERR, "lmshare_create_table:"
+ " unable to create share table");
+ (void) rw_unlock(&lmshare_lock);
+ return (NERR_InternalError);
+ }
+ (void) ht_register_callback(lmshare_handle, lmshare_callback);
+ (void) rw_unlock(&lmshare_lock);
+ }
+
+ return (NERR_Success);
+}
+
+/*
+ * lmshare_add_adminshare
+ *
+ * add the admin share for the volume when the share database
+ * for that volume is going to be loaded.
+ */
+DWORD
+lmshare_add_adminshare(char *volname, unsigned char drive)
+{
+ struct lmshare_info si;
+ DWORD rc;
+
+ if (drive == 0)
+ return (NERR_InvalidDevice);
+
+ bzero(&si, sizeof (lmshare_info_t));
+ (void) strcpy(si.directory, volname);
+ si.mode = LMSHRM_TRANS;
+ (void) snprintf(si.share_name, sizeof (si.share_name), "%c$", drive);
+ rc = lmshare_add(&si, 0);
+
+ return (rc);
+}
+
+/*
+ * lmshare_num_shares
+ *
+ * Return the total number of shares, which should be the same value
+ * that would be returned from a share enum request.
+ */
+int
+lmshare_num_shares(void)
+{
+ int n_shares;
+
+ n_shares = ht_get_total_items(lmshare_handle);
+
+ /* If we don't store IPC$ in hash table we should do this */
+ n_shares++;
+
+ return (n_shares);
+}
+
+/*
+ * lmshare_open_iterator
+ *
+ * Create and initialize an iterator for traversing hash table.
+ * It gets a mode that can be LMSHR_IM_ALL to iterate through all
+ * the shares stored in table or LMSHR_IM_PRES to iterate through
+ * only presentable shares.
+ *
+ * It also accepts a local IP address. This is used in dual head
+ * systems to only return the shares that belong to the head which
+ * is specified by the 'ipaddr'. If ipaddr is 0 it'll return shares
+ * of both heads.
+ *
+ * On success return pointer to the new iterator.
+ * On failure return (NULL).
+ */
+lmshare_iterator_t *
+lmshare_open_iterator(int mode)
+{
+ lmshare_iterator_t *shi;
+ int sz = sizeof (lmshare_iterator_t) + sizeof (HT_ITERATOR);
+
+ shi = malloc(sz);
+ if (shi != NULL) {
+ bzero(shi, sz);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ shi->iterator = (HT_ITERATOR *)
+ ((char *)shi + sizeof (lmshare_iterator_t));
+ shi->mode = mode;
+ } else {
+ syslog(LOG_DEBUG, "Failed to create share iterator handle");
+ }
+ return (shi);
+}
+
+/*
+ * lmshare_close_iterator
+ *
+ * Free memory allocated by the given iterator.
+ */
+void
+lmshare_close_iterator(lmshare_iterator_t *shi)
+{
+ (void) free(shi);
+}
+
+/*
+ * lmshare_iterate
+ *
+ * Iterate on the shares in the hash table. The iterator must be opened
+ * before the first iteration. On subsequent calls, the iterator must be
+ * passed unchanged.
+ *
+ * Returns NULL on failure or when all shares are visited, otherwise
+ * returns information of visited share.
+ *
+ * Note that there are some special shares, i.e. IPC$, that must also
+ * be processed.
+ */
+lmshare_info_t *
+lmshare_iterate(lmshare_iterator_t *shi)
+{
+ HT_ITEM *item;
+ lmshare_info_t *si;
+
+ if (lmshare_handle == NULL || shi == NULL)
+ return (NULL);
+
+ if (shi->iteration == 0) {
+ /*
+ * IPC$ is always first.
+ */
+ (void) strcpy(shi->si.share_name, "IPC$");
+ shi->si.mode = LMSHRM_TRANS;
+ shi->si.stype = (int)(STYPE_IPC | STYPE_SPECIAL);
+ shi->iteration = 1;
+ return (&(shi->si));
+ }
+
+ if (shi->iteration == 1) {
+ if ((item = ht_findfirst(
+ lmshare_handle, shi->iterator)) == NULL) {
+ return (NULL);
+ }
+
+ si = (lmshare_info_t *)(item->hi_data);
+ ++shi->iteration;
+
+ if (si->mode & shi->mode) {
+ (void) memcpy(&(shi->si), si,
+ sizeof (lmshare_info_t));
+ return (&(shi->si));
+ }
+ }
+
+ while ((item = ht_findnext(shi->iterator)) != NULL) {
+ si = (lmshare_info_t *)(item->hi_data);
+ ++shi->iteration;
+ if (si->mode & shi->mode) {
+ (void) memcpy(&(shi->si), si, sizeof (lmshare_info_t));
+
+ return (&(shi->si));
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * lmshare_add
+ *
+ * Add a share. This is a wrapper round lmshare_setinfo that checks
+ * whether or not the share already exists. If the share exists, an
+ * error is returned.
+ *
+ * Don't check lmshare_is_dir here: it causes rootfs to recurse.
+ */
+DWORD
+lmshare_add(lmshare_info_t *si, int doshm)
+{
+ DWORD status = NERR_Success;
+
+ if (si == 0 || lmshare_is_valid(si->share_name) == 0)
+ return (NERR_InvalidDevice);
+
+ (void) utf8_strlwr(si->share_name);
+
+ if (lmshare_exists(si->share_name)) {
+ if ((si->mode & LMSHRM_TRANS) == 0)
+ return (NERR_DuplicateShare);
+ }
+
+ if (si->refcnt == 0) {
+ status = lmshare_setinfo(si, doshm);
+ lmshare_do_publish(si, LMSHR_PUBLISH, 1);
+ }
+
+ if ((si->mode & LMSHRM_TRANS) && (status == NERR_Success)) {
+ si->refcnt++;
+ status = lmshare_set_refcnt(si->share_name, si->refcnt);
+ }
+
+ if (status)
+ return (status);
+
+ return (smb_dwncall_share(LMSHR_ADD, si->directory, si->share_name));
+}
+
+/*
+ * lmshare_delete
+ *
+ * Remove a share. Ensure that all SMB trees associated with this share
+ * are disconnected. If the share does not exist, an error is returned.
+ */
+DWORD
+lmshare_delete(char *share_name, int doshm)
+{
+ lmshare_info_t *si;
+ HT_ITEM *item;
+ DWORD status;
+ char path[MAXPATHLEN];
+
+ if (share_name)
+ (void) utf8_strlwr(share_name);
+
+ if (lmshare_is_valid(share_name) == 0 ||
+ lmshare_exists(share_name) == 0) {
+ return (NERR_NetNameNotFound);
+ }
+
+ (void) rw_wrlock(&lmshare_lock);
+ item = ht_find_item(lmshare_handle, share_name);
+
+ if (item == NULL) {
+ (void) rw_unlock(&lmshare_lock);
+ return (NERR_ItemNotFound);
+ }
+
+ si = (lmshare_info_t *)item->hi_data;
+ if (si == NULL) {
+ (void) rw_unlock(&lmshare_lock);
+ return (NERR_InternalError);
+ }
+
+ if ((si->mode & LMSHRM_TRANS) != 0) {
+ si->refcnt--;
+ if (si->refcnt > 0) {
+ status = lmshare_set_refcnt(si->share_name, si->refcnt);
+ (void) rw_unlock(&lmshare_lock);
+ return (status);
+ }
+ }
+
+ if (doshm && (lmshare_delete_shmgr(si) != 0)) {
+ (void) rw_unlock(&lmshare_lock);
+ return (NERR_InternalError);
+ }
+
+ lmshare_do_publish(si, LMSHR_UNPUBLISH, 1);
+
+ /*
+ * Copy the path before the entry is removed from the hash table
+ */
+
+ (void) strlcpy(path, si->directory, MAXPATHLEN);
+
+ /* Delete from hash table */
+
+ (void) ht_remove_item(lmshare_handle, share_name);
+ (void) rw_unlock(&lmshare_lock);
+
+ return (smb_dwncall_share(LMSHR_DELETE, path, share_name));
+}
+
+/*
+ * lmshare_set_refcnt
+ *
+ * sets the autohome refcnt for a share
+ */
+static DWORD
+lmshare_set_refcnt(char *share_name, int refcnt)
+{
+ lmshare_info_t *si;
+ HT_ITEM *item;
+
+ if (share_name) {
+ (void) utf8_strlwr(share_name);
+ }
+ (void) rw_wrlock(&lmshare_lock);
+ item = ht_find_item(lmshare_handle, share_name);
+ if (item == NULL) {
+ (void) rw_unlock(&lmshare_lock);
+ return (NERR_ItemNotFound);
+ }
+
+ si = (lmshare_info_t *)item->hi_data;
+ if (si == NULL) {
+ (void) rw_unlock(&lmshare_lock);
+ return (NERR_InternalError);
+ }
+ si->refcnt = refcnt;
+ (void) rw_unlock(&lmshare_lock);
+ return (NERR_Success);
+}
+
+/*
+ * lmshare_rename
+ *
+ * Rename a share. Check that the current name exists and the new name
+ * doesn't exist. The rename is performed by deleting the current share
+ * definition and creating a new share with the new name.
+ */
+DWORD
+lmshare_rename(char *from_name, char *to_name, int doshm)
+{
+ struct lmshare_info si;
+ DWORD nerr;
+
+ if (lmshare_is_valid(from_name) == 0 ||
+ lmshare_is_valid(to_name) == 0)
+ return (NERR_InvalidDevice);
+
+ (void) utf8_strlwr(from_name);
+ (void) utf8_strlwr(to_name);
+
+ if (lmshare_exists(from_name) == 0)
+ return (NERR_NetNameNotFound);
+
+ if (lmshare_exists(to_name))
+ return (NERR_DuplicateShare);
+
+ if ((nerr = lmshare_getinfo(from_name, &si)) != NERR_Success)
+ return (nerr);
+
+ if ((nerr = lmshare_delete(from_name, doshm)) != NERR_Success)
+ return (nerr);
+
+ (void) strlcpy(si.share_name, to_name, MAXNAMELEN);
+ return (lmshare_add(&si, 1));
+}
+
+/*
+ * lmshare_exists
+ *
+ * Returns 1 if the share exists. Otherwise returns 0.
+ */
+int
+lmshare_exists(char *share_name)
+{
+ if (share_name == 0 || *share_name == 0)
+ return (0);
+
+ if (ht_find_item(lmshare_handle, share_name) == NULL)
+ return (0);
+ else
+ return (1);
+}
+
+/*
+ * lmshare_is_special
+ *
+ * Simple check to determine if share name represents a special share,
+ * i.e. the last character of the name is a '$'. Returns STYPE_SPECIAL
+ * if the name is special. Otherwise returns 0.
+ */
+int
+lmshare_is_special(char *share_name)
+{
+ int len;
+
+ if (share_name == 0)
+ return (0);
+
+ if ((len = strlen(share_name)) == 0)
+ return (0);
+
+ if (share_name[len - 1] == '$')
+ return (STYPE_SPECIAL);
+ else
+ return (0);
+}
+
+
+/*
+ * lmshare_is_restricted
+ *
+ * Check whether or not there is a restriction on a share. Restricted
+ * shares are generally STYPE_SPECIAL, for example, IPC$. All the
+ * administration share names are restricted: C$, D$ etc. Returns 1
+ * if the share is restricted. Otherwise 0 is returned to indicate
+ * that there are no restrictions.
+ */
+int
+lmshare_is_restricted(char *share_name)
+{
+ static char *restricted[] = {
+ "IPC$"
+ };
+
+ int i;
+
+ for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
+ if (strcasecmp(restricted[i], share_name) == 0)
+ return (1);
+ }
+
+ if (lmshare_is_admin(share_name))
+ return (1);
+
+ return (0);
+}
+
+
+/*
+ * lmshare_is_admin
+ *
+ * Check whether or not access to the share should be restricted to
+ * administrators. This is a bit of a hack because what we're doing
+ * is checking for the default admin shares: C$, D$ etc.. There are
+ * other shares that have restrictions: see lmshare_is_restricted().
+ *
+ * Returns 1 if the shares is an admin share. Otherwise 0 is returned
+ * to indicate that there are no restrictions.
+ */
+int
+lmshare_is_admin(char *share_name)
+{
+ if (share_name == 0)
+ return (0);
+
+ if (strlen(share_name) == 2 &&
+ mts_isalpha(share_name[0]) && share_name[1] == '$') {
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * lmshare_is_valid
+ *
+ * Check if any invalid char is present in share name. According to
+ * MSDN article #236388: "Err Msg: The Share Name Contains Invalid
+ * Characters", the list of invalid character is:
+ *
+ * " / \ [ ] : | < > + ; , ? * =
+ *
+ * Also rejects if control characters are embedded.
+ *
+ * If the sharename is valid, return (1). Otherwise return (0).
+ */
+int
+lmshare_is_valid(char *share_name)
+{
+ char *invalid = "\"/\\[]:|<>+;,?*=";
+ char *cp;
+
+ if (share_name == 0)
+ return (0);
+
+ if (strpbrk(share_name, invalid))
+ return (0);
+
+ for (cp = share_name; *cp != '\0'; cp++)
+ if (iscntrl(*cp))
+ return (0);
+
+ return (1);
+}
+
+/*
+ * lmshare_is_dir
+ *
+ * Check to determine if a share object represents a directory.
+ *
+ * Returns 1 if the path leads to a directory. Otherwise returns 0.
+ */
+int
+lmshare_is_dir(char *path)
+{
+ struct stat stat_info;
+
+ if (stat(path, &stat_info) == 0)
+ if (S_ISDIR(stat_info.st_mode))
+ return (1);
+
+ return (0);
+
+}
+
+/*
+ * lmshare_getinfo
+ *
+ * Load the information for the specified share into the supplied share
+ * info structure. If the shared directory does not begin with a /, one
+ * will be inserted as a prefix.
+ */
+DWORD
+lmshare_getinfo(char *share_name, struct lmshare_info *si)
+{
+ int i, endidx;
+ int dirlen;
+ HT_ITEM *item;
+
+ (void) rw_rdlock(&lmshare_lock);
+
+ (void) utf8_strlwr(share_name);
+ if ((item = ht_find_item(lmshare_handle, share_name)) == NULL) {
+ bzero(si, sizeof (lmshare_info_t));
+ (void) rw_unlock(&lmshare_lock);
+ return (NERR_NetNameNotFound);
+ }
+
+ (void) memcpy(si, item->hi_data, sizeof (lmshare_info_t));
+ (void) rw_unlock(&lmshare_lock);
+
+ if (si->directory[0] == '\0')
+ return (NERR_NetNameNotFound);
+
+ if (si->directory[0] != '/') {
+ dirlen = strlen(si->directory) + 1;
+ endidx = (dirlen < MAXPATHLEN-1) ?
+ dirlen : MAXPATHLEN - 2;
+ for (i = endidx; i >= 0; i--)
+ si->directory[i+1] = si->directory[i];
+ si->directory[MAXPATHLEN-1] = '\0';
+ si->directory[0] = '/';
+ }
+
+ return (NERR_Success);
+}
+
+/*
+ * Remove share from sharemanager repository.
+ */
+static int
+lmshare_delete_shmgr(struct lmshare_info *si)
+{
+ sa_handle_t handle;
+ sa_share_t share;
+ sa_resource_t resource;
+
+ handle = sa_init(SA_INIT_SHARE_API);
+ if (handle == NULL) {
+ syslog(LOG_ERR, "Failed to get handle to "
+ "share lib");
+ return (1);
+ }
+ share = sa_find_share(handle, si->directory);
+ if (share == NULL) {
+ syslog(LOG_ERR, "Failed to get share to delete");
+ sa_fini(handle);
+ return (1);
+ }
+ resource = sa_get_share_resource(share, si->share_name);
+ if (resource == NULL) {
+ syslog(LOG_ERR, "Failed to get share resource to delete");
+ sa_fini(handle);
+ return (1);
+ }
+ if (sa_remove_resource(resource) != SA_OK) {
+ syslog(LOG_ERR, "Failed to remove resource");
+ sa_fini(handle);
+ return (1);
+ }
+ sa_fini(handle);
+ return (0);
+}
+
+static int
+lmshare_setinfo_shmgr(struct lmshare_info *si)
+{
+ sa_handle_t handle;
+ sa_share_t share;
+ sa_group_t group;
+ sa_resource_t resource;
+ int share_created = 0;
+ int err;
+
+ /* Add share to sharemanager */
+ handle = sa_init(SA_INIT_SHARE_API);
+ if (handle == NULL) {
+ syslog(LOG_ERR, "Failed to get handle to share lib");
+ return (1);
+ }
+ share = sa_find_share(handle, si->directory);
+ if (share == NULL) {
+ group = smb_get_smb_share_group(handle);
+ if (group == NULL) {
+ sa_fini(handle);
+ return (1);
+ }
+ share = sa_add_share(group, si->directory, 0, &err);
+ if (share == NULL) {
+ sa_fini(handle);
+ return (1);
+ }
+ share_created = 1;
+ }
+ resource = sa_get_share_resource(share, si->share_name);
+ if (resource == NULL) {
+ resource = sa_add_resource(share, si->share_name,
+ SA_SHARE_PERMANENT, &err);
+ if (resource == NULL) {
+ goto failure;
+ }
+ }
+ if (sa_set_resource_attr(resource,
+ "description", si->comment) != SA_OK) {
+ syslog(LOG_ERR, "Falied to set resource "
+ "description in sharemgr");
+ goto failure;
+ }
+ if (sa_set_resource_attr(resource,
+ SHOPT_AD_CONTAINER, si->container) != SA_OK) {
+ syslog(LOG_ERR, "Falied to set ad-container in sharemgr");
+ goto failure;
+ }
+
+ sa_fini(handle);
+ return (0);
+failure:
+ if (share_created && (share != NULL)) {
+ if (sa_remove_share(share) != SA_OK) {
+ syslog(LOG_ERR, "Failed to cleanup share");
+ }
+ }
+ if (resource != NULL) {
+ if (sa_remove_resource(resource) != SA_OK) {
+ syslog(LOG_ERR, "Failed to cleanup share resource");
+ }
+ }
+ sa_fini(handle);
+ return (1);
+}
+
+/*
+ * del_fromhash
+ *
+ * Delete the given share only from hash table
+ */
+static DWORD
+del_fromhash(char *share_name)
+{
+ if (share_name == 0)
+ return (NERR_NetNameNotFound);
+
+ (void) utf8_strlwr(share_name);
+
+ if (lmshare_is_valid(share_name) == 0 ||
+ lmshare_exists(share_name) == 0) {
+ return (NERR_NetNameNotFound);
+ }
+
+ (void) rw_wrlock(&lmshare_lock);
+ (void) ht_remove_item(lmshare_handle, share_name);
+ (void) rw_unlock(&lmshare_lock);
+
+ return (NERR_Success);
+}
+
+/*
+ * lmshare_setinfo
+ *
+ * Adds the specified share into the system hash table
+ * and also store its info in the corresponding disk
+ * structure if it is not a temporary (LMSHRM_TRANS) share.
+ * when the first share is going to be added, create shares
+ * hash table if it is not already created.
+ * If the share already exists, it will be replaced. If the
+ * new share directory name does not begin with a /, one will be
+ * inserted as a prefix.
+ */
+DWORD
+lmshare_setinfo(lmshare_info_t *si, int doshm)
+{
+ int i, endidx;
+ int dirlen;
+ lmshare_info_t *add_si;
+ int res = NERR_Success;
+ lmshare_info_t old_si;
+
+ if (si->directory[0] != '/') {
+ dirlen = strlen(si->directory) + 1;
+ endidx = (dirlen < MAXPATHLEN - 1) ?
+ dirlen : MAXPATHLEN - 2;
+ for (i = endidx; i >= 0; i--)
+ si->directory[i+1] = si->directory[i];
+ si->directory[MAXPATHLEN-1] = '\0';
+ si->directory[0] = '/';
+ }
+
+ /* XXX Do we need to translate the directory here? to real path */
+ if (lmshare_is_dir(si->directory) == 0)
+ return (NERR_UnknownDevDir);
+
+ /*
+ * We should allocate memory for new entry because we
+ * don't know anything about the passed pointer i.e.
+ * it maybe destroyed by caller of this function while
+ * we only store a pointer to the data in hash table.
+ * Hash table doesn't do any allocation for the data that
+ * is being added.
+ */
+ add_si = malloc(sizeof (lmshare_info_t));
+ if (add_si == NULL) {
+ syslog(LOG_ERR, "LmshareSetinfo: resource shortage");
+ return (NERR_NoRoom);
+ }
+
+ (void) memcpy(add_si, si, sizeof (lmshare_info_t));
+
+ /*
+ * If we can't find it, use the new one to get things in sync,
+ * but if there is an existing one, that is the one to
+ * unpublish.
+ */
+ if (lmshare_getinfo(si->share_name, &old_si) != NERR_Success)
+ (void) memcpy(&old_si, si, sizeof (lmshare_info_t));
+
+ if (doshm) {
+ res = lmshare_delete(si->share_name, doshm);
+ if (res != NERR_Success) {
+ free(add_si);
+ syslog(LOG_ERR, "LmshareSetinfo: delete failed", res);
+ return (res);
+ }
+ } else {
+ /* Unpublish old share from AD */
+ if ((si->mode & LMSHRM_TRANS) == 0) {
+ lmshare_do_publish(&old_si, LMSHR_UNPUBLISH, 1);
+ }
+ (void) del_fromhash(si->share_name);
+ }
+ /* if it's not transient it should be permanent */
+ if ((add_si->mode & LMSHRM_TRANS) == 0)
+ add_si->mode |= LMSHRM_PERM;
+
+
+ add_si->stype = STYPE_DISKTREE;
+ add_si->stype |= lmshare_is_special(add_si->share_name);
+
+ (void) rw_wrlock(&lmshare_lock);
+ if (ht_add_item(lmshare_handle, add_si->share_name, add_si) == NULL) {
+ syslog(LOG_ERR, "lmshare_setinfo[%s]: error in adding share",
+ add_si->share_name);
+ (void) rw_unlock(&lmshare_lock);
+ free(add_si);
+ return (NERR_InternalError);
+ }
+ (void) rw_unlock(&lmshare_lock);
+
+ if ((add_si->mode & LMSHRM_TRANS) == 0) {
+ if (doshm && (lmshare_setinfo_shmgr(add_si) != 0)) {
+ syslog(LOG_ERR, "Update share %s in sharemgr failed",
+ add_si->share_name);
+ return (NERR_InternalError);
+ }
+ lmshare_do_publish(add_si, LMSHR_PUBLISH, 1);
+ }
+
+ return (res);
+}
+
+/*
+ * lmshare_decode_type
+ *
+ * Gets a SMB share type as an integer value and return
+ * a string name for it.
+ */
+static char *
+lmshare_decode_type(uint_t stype)
+{
+ switch (stype) {
+ case STYPE_DISKTREE:
+ return ("Disk");
+ case STYPE_PRINTQ:
+ return ("Print Queue");
+ case STYPE_DEVICE:
+ return ("Device");
+ case STYPE_IPC:
+ return ("IPC");
+ case STYPE_DFS:
+ return ("DFS");
+ case STYPE_SPECIAL:
+ return ("Special");
+ default:
+ return ("Unknown");
+ /* NOTREACHED */
+ };
+}
+
+/*
+ * lmshare_loginfo
+ *
+ * Decodes and writes the information of the given
+ * share to the specified file.
+ */
+void
+lmshare_loginfo(FILE *fp, lmshare_info_t *si)
+{
+ (void) fprintf(fp, "\n%s Information:\n", si->share_name);
+ (void) fprintf(fp, "\tFolder: %s\n", si->directory);
+ (void) fprintf(fp, "\tType: %s\n",
+ lmshare_decode_type((uint_t)si->stype));
+ (void) fprintf(fp, "\tComment: %s\n", si->comment);
+
+ (void) fprintf(fp, "\tStatus: %s\n",
+ ((si->mode & LMSHRM_TRANS) ? "Transient" : "Permanent"));
+
+ (void) fprintf(fp, "\tContainer: %s\n", si->container);
+}
+
+DWORD
+lmshare_list(int offset, lmshare_list_t *list)
+{
+ lmshare_iterator_t *iterator;
+ lmshare_info_t *si;
+ int list_idx = 0;
+ int i = 0;
+
+ bzero(list, sizeof (lmshare_list_t));
+ if ((iterator = lmshare_open_iterator(LMSHRM_ALL)) == NULL)
+ return (NERR_InternalError);
+
+ (void) lmshare_iterate(iterator); /* To skip IPC$ */
+
+ while ((si = lmshare_iterate(iterator)) != NULL) {
+ if (lmshare_is_special(si->share_name)) {
+ /*
+ * Don't return restricted shares.
+ */
+ if (lmshare_is_restricted(si->share_name))
+ continue;
+ }
+
+ if (i++ < offset)
+ continue;
+
+ (void) memcpy(&list->smbshr[list_idx], si,
+ sizeof (lmshare_info_t));
+ if (++list_idx == LMSHARES_PER_REQUEST)
+ break;
+ }
+ lmshare_close_iterator(iterator);
+
+ list->no = list_idx;
+
+ return (NERR_Success);
+}
+
+/*
+ * Put the share on publish queue.
+ */
+void
+lmshare_do_publish(lmshare_info_t *si, char flag, int poke)
+{
+ lmshare_ad_item_t *item = NULL;
+
+ if (publish_on == 0)
+ return;
+ if ((si == NULL) || (si->container[0] == '\0'))
+ return;
+ (void) mutex_lock(&lmshare_publish_mutex);
+ item = (lmshare_ad_item_t *)malloc(sizeof (lmshare_ad_item_t));
+ if (item == NULL) {
+ syslog(LOG_ERR, "Failed to allocate share publish item");
+ (void) mutex_unlock(&lmshare_publish_mutex);
+ return;
+ }
+ item->flag = flag;
+ (void) strlcpy(item->name, si->share_name, sizeof (item->name));
+ (void) strlcpy(item->container, si->container,
+ sizeof (item->container));
+ /*LINTED - E_CONSTANT_CONDITION*/
+ TAILQ_INSERT_TAIL(&ad_queue.adlist, item, next);
+ ad_queue.nentries++;
+ if (poke)
+ (void) cond_signal(&lmshare_publish_cv);
+ (void) mutex_unlock(&lmshare_publish_mutex);
+}
+
+void
+lmshare_stop_publish()
+{
+ (void) mutex_lock(&lmshare_publish_mutex);
+ publish_on = 0;
+ (void) cond_signal(&lmshare_publish_cv);
+ (void) mutex_unlock(&lmshare_publish_mutex);
+}
+
+/*
+ * This functions waits to be signaled and once running
+ * will publish/unpublish any items on list.
+ * lmshare_stop_publish when called will exit this thread.
+ */
+/*ARGSUSED*/
+static void *
+lmshare_publisher(void *arg)
+{
+ ADS_HANDLE *ah;
+ lmshare_ad_item_t *item;
+ char hostname[MAXHOSTNAMELEN];
+ char name[MAXNAMELEN];
+ char container[MAXPATHLEN];
+ char flag;
+
+ /*LINTED - E_CONSTANT_CONDITION*/
+ TAILQ_INIT(&ad_queue.adlist);
+ ad_queue.nentries = 0;
+ publish_on = 1;
+ hostname[0] = '\0';
+
+ for (;;) {
+ (void) cond_wait(&lmshare_publish_cv,
+ &lmshare_publish_mutex);
+
+ if (hostname[0] == '\0') {
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0)
+ continue;
+ }
+
+ if (publish_on == 0) {
+ syslog(LOG_DEBUG, "lmshare: publisher exit");
+ if (ad_queue.nentries == 0) {
+ (void) mutex_unlock(&lmshare_publish_mutex);
+ break;
+ }
+ for (item = TAILQ_FIRST(&ad_queue.adlist); item;
+ item = TAILQ_FIRST(&ad_queue.adlist)) {
+ /*LINTED - E_CONSTANT_CONDITION*/
+ TAILQ_REMOVE(&ad_queue.adlist, item, next);
+ (void) free(item);
+ }
+ ad_queue.nentries = 0;
+ (void) mutex_unlock(&lmshare_publish_mutex);
+ break;
+ }
+ if (ad_queue.nentries == 0)
+ continue;
+ ah = ads_open();
+ if (ah == NULL) {
+ /* We mostly have no AD config so just clear the list */
+ for (item = TAILQ_FIRST(&ad_queue.adlist); item;
+ item = TAILQ_FIRST(&ad_queue.adlist)) {
+ /*LINTED - E_CONSTANT_CONDITION*/
+ TAILQ_REMOVE(&ad_queue.adlist, item, next);
+ (void) free(item);
+ }
+ ad_queue.nentries = 0;
+ continue;
+ }
+ TAILQ_FOREACH(item, &ad_queue.adlist, next) {
+ (void) strlcpy(name, item->name, sizeof (name));
+ (void) strlcpy(container, item->container,
+ sizeof (container));
+ flag = item->flag;
+
+ if (flag == LMSHR_UNPUBLISH)
+ (void) ads_remove_share(ah, name, NULL,
+ container, hostname);
+ else
+ (void) ads_publish_share(ah, name, NULL,
+ container, hostname);
+ }
+ for (item = TAILQ_FIRST(&ad_queue.adlist); item;
+ item = TAILQ_FIRST(&ad_queue.adlist)) {
+ /*LINTED - E_CONSTANT_CONDITION*/
+ TAILQ_REMOVE(&ad_queue.adlist, item, next);
+ (void) free(item);
+ }
+ ad_queue.nentries = 0;
+ if (ah != NULL) {
+ ads_close(ah);
+ ah = NULL;
+ }
+ }
+
+ syslog(LOG_DEBUG, "lmshare: Stopping publisher");
+ return (NULL);
+}
+
+/*
+ * lmshare_get_realpath
+ *
+ * Derive the real path of a share from the path provided by a
+ * Windows client application during the share addition.
+ *
+ * For instance, the real path of C:\ is /cvol and the
+ * real path of F:\home is /vol1/home.
+ *
+ * clipath - path provided by the Windows client is in the
+ * format of <drive letter>:\<dir>
+ * realpath - path that will be stored as the directory field of
+ * the lmshare_info_t structure of the share.
+ * maxlen - maximum length fo the realpath buffer
+ *
+ * Return LAN Manager network error code.
+ */
+/*ARGSUSED*/
+DWORD
+lmshare_get_realpath(const char *clipath, char *realpath, int maxlen)
+{
+ /* XXX do this translation */
+ return (NERR_Success);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c
new file mode 100644
index 0000000000..ca98eb8eab
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c
@@ -0,0 +1,637 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the high level interface to the LSA RPC functions.
+ */
+
+#include <strings.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbns.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/lsalib.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/smb_token.h>
+
+static int lsa_list_accounts(mlsvc_handle_t *);
+
+/*
+ * lsa_query_primary_domain_info
+ *
+ * Obtains the primary domain SID and name from the specified server
+ * (domain controller). The information is stored in the NT domain
+ * database by the lower level lsar_query_info_policy call. The caller
+ * should query the database to obtain a reference to the primary
+ * domain information.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+lsa_query_primary_domain_info(void)
+{
+ mlsvc_handle_t domain_handle;
+ DWORD status;
+
+ if ((lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle)) != 0)
+ return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+
+ status = lsar_query_info_policy(&domain_handle,
+ MSLSA_POLICY_PRIMARY_DOMAIN_INFO);
+
+ (void) lsar_close(&domain_handle);
+ return (status);
+}
+
+/*
+ * lsa_query_account_domain_info
+ *
+ * Obtains the account domain SID and name from the current server
+ * (domain controller). The information is stored in the NT domain
+ * database by the lower level lsar_query_info_policy call. The caller
+ * should query the database to obtain a reference to the account
+ * domain information.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+lsa_query_account_domain_info(void)
+{
+ mlsvc_handle_t domain_handle;
+ DWORD status;
+
+ if ((lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle)) != 0)
+ return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+
+ status = lsar_query_info_policy(&domain_handle,
+ MSLSA_POLICY_ACCOUNT_DOMAIN_INFO);
+
+ (void) lsar_close(&domain_handle);
+ return (status);
+}
+
+/*
+ * lsa_enum_trusted_domains
+ *
+ * Enumerate the trusted domains in our primary domain. The information
+ * is stored in the NT domain database by the lower level
+ * lsar_enum_trusted_domains call. The caller should query the database
+ * to obtain a reference to the trusted domain information.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+lsa_enum_trusted_domains(void)
+{
+ mlsvc_handle_t domain_handle;
+ DWORD enum_context;
+ DWORD status;
+
+ if ((lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle)) != 0)
+ return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+
+ enum_context = 0;
+
+ status = lsar_enum_trusted_domains(&domain_handle, &enum_context);
+ if (status == MLSVC_NO_MORE_DATA) {
+ /*
+ * MLSVC_NO_MORE_DATA indicates that we
+ * have all of the available information.
+ */
+ status = NT_STATUS_SUCCESS;
+ }
+
+ (void) lsar_close(&domain_handle);
+ return (status);
+}
+
+/*
+ * lsa_test_lookup
+ *
+ * Test routine for lsa_lookup_name and lsa_lookup_sid.
+ */
+void
+lsa_test_lookup(char *name)
+{
+ smb_userinfo_t *user_info;
+ nt_sid_t *sid;
+ DWORD status;
+ smb_ntdomain_t *di;
+
+ if ((di = smb_getdomaininfo(0)) == 0)
+ return;
+
+ user_info = mlsvc_alloc_user_info();
+
+ if (lsa_lookup_builtin_name(name, user_info) != 0) {
+ status = lsa_lookup_name(di->server, di->domain, name,
+ user_info);
+
+ if (status == 0) {
+ sid = nt_sid_splice(user_info->domain_sid,
+ user_info->rid);
+
+ (void) lsa_lookup_sid(sid, user_info);
+ free(sid);
+ }
+ }
+
+ mlsvc_free_user_info(user_info);
+}
+
+/*
+ * lsa_lookup_builtin_name
+ *
+ * lookup builtin account table to see if account_name is
+ * there. If it is there, set sid_name_use, domain_sid,
+ * domain_name, and rid fields of the passed user_info
+ * structure and return 0. If lookup fails return 1.
+ */
+int
+lsa_lookup_builtin_name(char *account_name, smb_userinfo_t *user_info)
+{
+ char *domain;
+ int res;
+
+ user_info->domain_sid = nt_builtin_lookup_name(account_name,
+ &user_info->sid_name_use);
+
+ if (user_info->domain_sid == 0)
+ return (1);
+
+ res = nt_sid_split(user_info->domain_sid, &user_info->rid);
+ if (res < 0)
+ return (1);
+
+ domain = nt_builtin_lookup_domain(account_name);
+ if (domain) {
+ user_info->domain_name = strdup(domain);
+ return (0);
+ }
+
+ return (1);
+}
+
+/*
+ * lsa_lookup_local_sam
+ *
+ * lookup for the given account name in the local SAM database.
+ * Returns 0 on success. If lookup fails return 1.
+ */
+int
+lsa_lookup_local_sam(char *domain, char *account_name,
+ smb_userinfo_t *user_info)
+{
+ nt_group_t *grp;
+
+ if (*domain == '\0' || *account_name == '\0')
+ return (1);
+
+ grp = nt_group_getinfo(account_name, RWLOCK_READER);
+ if (grp == 0)
+ return (1);
+
+ user_info->sid_name_use = *grp->sid_name_use;
+ user_info->domain_sid = nt_sid_dup(grp->sid);
+ nt_group_putinfo(grp);
+
+ if (user_info->domain_sid == 0)
+ return (1);
+
+ (void) nt_sid_split(user_info->domain_sid, &user_info->rid);
+ user_info->domain_name = strdup(domain);
+
+ if (user_info->domain_name == 0) {
+ free(user_info->domain_sid);
+ user_info->domain_sid = 0;
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * lsa_lookup_local
+ *
+ * if given account name has domain part, check to see if
+ * it matches with host name or any of host's primary addresses.
+ * if any match found first lookup in builtin accounts table and
+ * then in local SAM table.
+ *
+ * if account name doesn't have domain part, first do local lookups
+ * if nothing is found return 1. This means that caller function should
+ * do domain lookup.
+ * if any error happened return -1, if name is found return 0.
+ */
+int
+lsa_lookup_local(char *name, smb_userinfo_t *user_info)
+{
+ char hostname[MAXHOSTNAMELEN];
+ int res = 0;
+ int local_lookup = 0;
+ char *tmp;
+ net_cfg_t cfg;
+ uint32_t addr;
+
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0)
+ return (-1);
+
+ tmp = strchr(name, '\\');
+ if (tmp != 0) {
+ *tmp = 0;
+ if (strcasecmp(name, hostname) == 0)
+ local_lookup = 1;
+
+ if (!local_lookup) {
+ addr = inet_addr(name);
+ if (smb_nic_get_byip(addr, &cfg) != NULL) {
+ local_lookup = 1;
+ }
+ }
+
+ if (!local_lookup) {
+ /* do domain lookup */
+ *tmp = '\\';
+ return (1);
+ }
+
+ name = tmp + 1;
+ local_lookup = 1;
+ }
+
+ res = lsa_lookup_builtin_name(name, user_info);
+ if (res != 0)
+ res = lsa_lookup_local_sam(hostname, name, user_info);
+
+ if (res == 0)
+ return (0);
+
+ if (local_lookup)
+ return (-1);
+
+ return (1);
+}
+
+/*
+ * lsa_lookup_name
+ *
+ * Lookup a name on the specified server (domain controller) and obtain
+ * the appropriate SID. The information is returned in the user_info
+ * structure. The caller is responsible for allocating and releasing
+ * this structure. On success sid_name_use will be set to indicate the
+ * type of SID. If the name is the domain name, this function will be
+ * identical to lsa_domain_info. Otherwise the rid and name fields will
+ * also be valid. On failure sid_name_use will be set to SidTypeUnknown.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+int lsa_lookup_name(char *server, char *domain, char *account_name,
+ smb_userinfo_t *user_info)
+{
+ mlsvc_handle_t domain_handle;
+ int rc;
+
+ rc = lsar_open(MLSVC_IPC_ANON, server, domain, 0, 0, &domain_handle);
+ if (rc != 0)
+ return (-1);
+
+ rc = lsar_lookup_names(&domain_handle, account_name, user_info);
+
+ (void) lsar_close(&domain_handle);
+ return (rc);
+}
+
+/*
+ * lsa_lookup_name2
+ *
+ * Returns NT status codes.
+ */
+DWORD lsa_lookup_name2(char *server, char *domain, char *account_name,
+ smb_userinfo_t *user_info)
+{
+ mlsvc_handle_t domain_handle;
+ DWORD status;
+ int rc;
+
+ rc = lsar_open(MLSVC_IPC_ANON, server, domain, 0, 0, &domain_handle);
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ status = lsar_lookup_names2(&domain_handle, account_name, user_info);
+ if (status == NT_STATUS_REVISION_MISMATCH) {
+ /*
+ * Not a Windows 2000 domain controller:
+ * use the NT compatible call.
+ */
+ if (lsar_lookup_names(&domain_handle, account_name,
+ user_info) != 0)
+ status = NT_STATUS_NONE_MAPPED;
+ else
+ status = 0;
+ }
+
+ (void) lsar_close(&domain_handle);
+ return (status);
+}
+
+/*
+ * lsa_lookup_sid
+ *
+ * Lookup a SID on the specified server (domain controller) and obtain
+ * the appropriate name. The information is returned in the user_info
+ * structure. The caller is responsible for allocating and releasing
+ * this structure. On success sid_name_use will be set to indicate the
+ * type of SID. On failure sid_name_use will be set to SidTypeUnknown.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+int
+lsa_lookup_sid(nt_sid_t *sid, smb_userinfo_t *user_info)
+{
+ mlsvc_handle_t domain_handle;
+ int rc;
+
+ rc = lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle);
+ if (rc != 0)
+ return (-1);
+
+ rc = lsar_lookup_sids(&domain_handle,
+ (struct mslsa_sid *)sid, user_info);
+
+ (void) lsar_close(&domain_handle);
+ return (rc);
+}
+
+/*
+ * lsa_lookup_sid2
+ *
+ * Returns NT status codes.
+ */
+DWORD
+lsa_lookup_sid2(nt_sid_t *sid, smb_userinfo_t *user_info)
+{
+ mlsvc_handle_t domain_handle;
+ DWORD status;
+ int rc;
+
+ rc = lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle);
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ status = lsar_lookup_sids2(&domain_handle,
+ (struct mslsa_sid *)sid, user_info);
+
+ if (status == NT_STATUS_REVISION_MISMATCH) {
+ /*
+ * Not a Windows 2000 domain controller:
+ * use the NT compatible call.
+ */
+ if (lsar_lookup_sids(&domain_handle, (struct mslsa_sid *)sid,
+ user_info) != 0)
+ status = NT_STATUS_NONE_MAPPED;
+ else
+ status = 0;
+ }
+
+ (void) lsar_close(&domain_handle);
+ return (status);
+}
+
+/*
+ * lsa_test_lookup2
+ *
+ * Test routine for lsa_lookup_name2 and lsa_lookup_sid2.
+ */
+void
+lsa_test_lookup2(char *name)
+{
+ smb_userinfo_t *user_info;
+ nt_sid_t *sid;
+ DWORD status;
+ smb_ntdomain_t *di;
+
+ if ((di = smb_getdomaininfo(0)) == 0)
+ return;
+
+ user_info = mlsvc_alloc_user_info();
+
+ if (lsa_lookup_builtin_name(name, user_info) != 0) {
+ status = lsa_lookup_name2(di->server, di->domain, name,
+ user_info);
+
+ if (status == 0) {
+ sid = nt_sid_splice(user_info->domain_sid,
+ user_info->rid);
+
+ (void) lsa_lookup_sid2(sid, user_info);
+ free(sid);
+ }
+ }
+
+ mlsvc_free_user_info(user_info);
+}
+
+/*
+ * lsa_lookup_privs
+ *
+ * Request the privileges associated with the specified account. In
+ * order to get the privileges, we first have to lookup the name on
+ * the specified domain controller and obtain the appropriate SID.
+ * The SID can then be used to open the account and obtain the
+ * account privileges. The results from both the name lookup and the
+ * privileges are returned in the user_info structure. The caller is
+ * responsible for allocating and releasing this structure.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+/*ARGSUSED*/
+int
+lsa_lookup_privs(char *server, char *account_name, char *target_name,
+ smb_userinfo_t *user_info)
+{
+ mlsvc_handle_t domain_handle;
+ int rc;
+#if 0
+ mlsvc_handle_t account_handle;
+ struct mslsa_sid *sid;
+
+ lsa_lookup_name(0, 0, target_name, user_info);
+
+ sid = (struct mslsa_sid *)
+ nt_sid_splice(user_info->domain_sid, user_info->rid);
+
+ lsa_lookup_sid(server, account_name, (nt_sid_t *)sid, user_info);
+#endif
+ if ((lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle)) != 0)
+ return (-1);
+
+ rc = lsa_list_accounts(&domain_handle);
+#if 0
+ rc = lsar_open_account(&domain_handle, sid, &account_handle);
+ if (rc == 0) {
+ (void) lsar_enum_privs_account(&account_handle, user_info);
+ (void) lsar_close(&account_handle);
+ }
+
+ free(sid);
+#endif
+ (void) lsar_close(&domain_handle);
+ return (rc);
+}
+
+/*
+ * lsa_list_privs
+ *
+ * List the privileges supported by the specified server.
+ * This function is only intended for diagnostics.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+lsa_list_privs(char *server, char *domain)
+{
+ static char name[128];
+ static struct ms_luid luid;
+ mlsvc_handle_t domain_handle;
+ int rc;
+ int i;
+
+ rc = lsar_open(MLSVC_IPC_ANON, server, domain, 0, 0, &domain_handle);
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ for (i = 0; i < 30; ++i) {
+ luid.low_part = i;
+ rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128);
+ if (rc != 0)
+ continue;
+
+ (void) lsar_lookup_priv_value(&domain_handle, name, &luid);
+ (void) lsar_lookup_priv_display_name(&domain_handle, name,
+ name, 128);
+ }
+
+ (void) lsar_close(&domain_handle);
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * lsa_test
+ *
+ * LSA test routine: open and close the LSA interface.
+ * TBD: the parameters should be server and domain.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+/*ARGSUSED*/
+int
+lsa_test(char *server, char *account_name)
+{
+ mlsvc_handle_t domain_handle;
+ int rc;
+
+ rc = lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle);
+ if (rc != 0)
+ return (-1);
+
+ if (lsar_close(&domain_handle) != 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * lsa_list_accounts
+ *
+ * This function can be used to list the accounts in the specified
+ * domain. For now the SIDs are just listed in the system log.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+static int
+lsa_list_accounts(mlsvc_handle_t *domain_handle)
+{
+ mlsvc_handle_t account_handle;
+ struct mslsa_EnumAccountBuf accounts;
+ struct mslsa_sid *sid;
+ char *name;
+ WORD sid_name_use;
+ smb_userinfo_t *user_info;
+ DWORD enum_context = 0;
+ int rc;
+ int i;
+
+ user_info = mlsvc_alloc_user_info();
+ bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf));
+
+ do {
+ rc = lsar_enum_accounts(domain_handle, &enum_context,
+ &accounts);
+ if (rc != 0)
+ return (rc);
+
+ for (i = 0; i < accounts.entries_read; ++i) {
+ sid = accounts.info[i].sid;
+
+ name = nt_builtin_lookup_sid((nt_sid_t *)sid,
+ &sid_name_use);
+
+ if (name == 0) {
+ if (lsar_lookup_sids(domain_handle, sid,
+ user_info) == 0) {
+ name = user_info->name;
+ sid_name_use = user_info->sid_name_use;
+ } else {
+ name = "unknown";
+ sid_name_use = SidTypeUnknown;
+ }
+ }
+
+ nt_sid_logf((nt_sid_t *)sid);
+
+ if (lsar_open_account(domain_handle, sid,
+ &account_handle) == 0) {
+ (void) lsar_enum_privs_account(&account_handle,
+ user_info);
+ (void) lsar_close(&account_handle);
+ }
+
+ free(accounts.info[i].sid);
+ mlsvc_release_user_info(user_info);
+ }
+
+ if (accounts.info)
+ free(accounts.info);
+ } while (rc == 0 && accounts.entries_read != 0);
+
+ mlsvc_free_user_info(user_info);
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c
new file mode 100644
index 0000000000..5216818cce
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c
@@ -0,0 +1,875 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Local Security Authority RPC (LSARPC) library interface functions for
+ * query, lookup and enumeration calls.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/errno.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ntaccess.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntlocale.h>
+#include <smbsrv/lsalib.h>
+#include <smbsrv/string.h>
+#include <smbsrv/mlsvc.h>
+
+/*
+ * The maximum number of bytes we are prepared to deal with in a
+ * response.
+ */
+#define MLSVC_MAX_RESPONSE_LEN 1024
+
+/*
+ * This structure is used when lookuping up names. We only lookup one
+ * name at a time but the structure will allow for more.
+ */
+typedef struct lookup_name_table {
+ DWORD n_entry;
+ mslsa_string_t name[8];
+} lookup_name_table_t;
+
+/*
+ * lsar_query_security_desc
+ *
+ * Don't use this call yet. It is just a place holder for now.
+ */
+int
+lsar_query_security_desc(mlsvc_handle_t *lsa_handle)
+{
+ struct mslsa_QuerySecurityObject arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int rc;
+ int opnum;
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_QuerySecurityObject;
+
+ bzero(&arg, sizeof (struct mslsa_QuerySecurityObject));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * lsar_query_info_policy
+ *
+ * The general purpose of this function is to allow various pieces of
+ * information to be queried on the domain controller. The only
+ * information queries supported are MSLSA_POLICY_PRIMARY_DOMAIN_INFO
+ * and MSLSA_POLICY_ACCOUNT_DOMAIN_INFO.
+ *
+ * On success, the return code will be 0 and the user_info structure
+ * will be set up. The sid_name_use field will be set to SidTypeDomain
+ * indicating that the domain name and domain sid fields are vaild. If
+ * the infoClass returned from the server is not one of the supported
+ * values, the sid_name_use willbe set to SidTypeUnknown. If the RPC
+ * fails, a negative error code will be returned, in which case the
+ * user_info will not have been updated.
+ */
+DWORD
+lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass)
+{
+ struct mslsa_QueryInfoPolicy arg;
+ struct mlsvc_rpc_context *context;
+ struct mslsa_PrimaryDomainInfo *pd_info;
+ struct mslsa_AccountDomainInfo *ad_info;
+ mlrpc_heapref_t heap;
+ nt_domain_t *nt_new_dp;
+ int opnum;
+ DWORD status;
+
+ if (lsa_handle == 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_QueryInfoPolicy;
+
+ bzero(&arg, sizeof (struct mslsa_QueryInfoPolicy));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+ arg.info_class = infoClass;
+
+ (void) mlsvc_rpc_init(&heap);
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ status = NT_SC_VALUE(arg.status);
+ } else {
+ switch (infoClass) {
+ case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
+ pd_info = &arg.info->ru.pd_info;
+
+ nt_domain_flush(NT_DOMAIN_PRIMARY);
+ nt_new_dp = nt_domain_new(NT_DOMAIN_PRIMARY,
+ (char *)pd_info->name.str,
+ (nt_sid_t *)pd_info->sid);
+ (void) nt_domain_add(nt_new_dp);
+ status = NT_STATUS_SUCCESS;
+ break;
+
+ case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
+ ad_info = &arg.info->ru.ad_info;
+
+ nt_domain_flush(NT_DOMAIN_ACCOUNT);
+ nt_new_dp = nt_domain_new(NT_DOMAIN_ACCOUNT,
+ (char *)ad_info->name.str,
+ (nt_sid_t *)ad_info->sid);
+ (void) nt_domain_add(nt_new_dp);
+ status = NT_STATUS_SUCCESS;
+ break;
+
+ default:
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+/*
+ * lsar_lookup_names
+ *
+ * Lookup a name and obtain the domain and user rid. The RPC call will
+ * actually support lookup of multiple names but we probably don't
+ * need to do that. On the final system the lookup level should be
+ * level 2 but for now we want to restrict it to level 1 so that we
+ * don't crash the PDC when we get things wrong.
+ *
+ * If the lookup fails, the status will typically be
+ * NT_STATUS_NONE_MAPPED.
+ */
+int
+lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name,
+ smb_userinfo_t *user_info)
+{
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ int index;
+ struct mslsa_LookupNames arg;
+ size_t length;
+ lookup_name_table_t name_table;
+ struct mslsa_rid_entry *rid_entry;
+ struct mslsa_domain_entry *domain_entry;
+ char *p;
+
+ if (lsa_handle == NULL || name == NULL || user_info == NULL)
+ return (-1);
+
+ bzero(user_info, sizeof (smb_userinfo_t));
+ user_info->sid_name_use = SidTypeUnknown;
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_LookupNames;
+
+ bzero(&arg, sizeof (struct mslsa_LookupNames));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+
+ arg.name_table = (struct mslsa_lup_name_table *)&name_table;
+ name_table.n_entry = 1;
+
+ /*
+ * Windows NT expects the name length to exclude the terminating
+ * wchar null but doesn't care whether the allosize includes or
+ * excludes the null char. Windows 2000 insists that both the
+ * length and the allosize include the wchar null.
+ *
+ * Note: NT returns an error if the mapped_count is non-zero
+ * when the RPC is called.
+ */
+ if (context->server_os == NATIVE_OS_WIN2000) {
+ /*
+ * Windows 2000 doesn't like an LSA lookup for
+ * DOMAIN\Administrator.
+ */
+ if ((p = strchr(name, '\\')) != 0) {
+ ++p;
+
+ if (strcasecmp(p, "administrator") == 0)
+ name = p;
+ }
+
+ length = mts_wcequiv_strlen(name) + sizeof (mts_wchar_t);
+ arg.lookup_level = MSLSA_LOOKUP_LEVEL_1;
+ } else {
+ length = mts_wcequiv_strlen(name);
+ arg.lookup_level = MSLSA_LOOKUP_LEVEL_1;
+ }
+
+ name_table.name[0].length = length;
+ name_table.name[0].allosize = length;
+ name_table.name[0].str = (unsigned char *)name;
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0) {
+ rc = -1;
+ } else if (arg.mapped_count == 0) {
+ rc = -1;
+ } else {
+ rid_entry = &arg.translated_sids.rids[0];
+ user_info->sid_name_use = rid_entry->sid_name_use;
+ user_info->rid = rid_entry->rid;
+ user_info->name = MEM_STRDUP("mlrpc", name);
+
+ if ((index = rid_entry->domain_index) == -1) {
+ user_info->domain_sid = 0;
+ user_info->domain_name = 0;
+ } else {
+ domain_entry =
+ &arg.domain_table->entries[index];
+ user_info->domain_sid = nt_sid_dup(
+ (nt_sid_t *)domain_entry->domain_sid);
+ user_info->domain_name = MEM_STRDUP("mlrpc",
+ (const char *)
+ domain_entry->domain_name.str);
+ }
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * lsar_lookup_sids
+ *
+ * Lookup a sid and obtain the domain sid and user name. The RPC call
+ * will actually support lookup of multiple sids but we probably don't
+ * need to do that. On the final system the lookup level should be
+ * level 2 but for now we want to restrict it to level 1 so that we
+ * don't crash the PDC when we get things wrong.
+ */
+int
+lsar_lookup_sids(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid,
+ smb_userinfo_t *user_info)
+{
+ struct mslsa_LookupSids arg;
+ struct mslsa_lup_sid_entry sid_entry;
+ struct mslsa_name_entry *name_entry;
+ struct mslsa_domain_entry *domain_entry;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ int index;
+
+ if (lsa_handle == NULL || sid == NULL || user_info == NULL)
+ return (-1);
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_LookupSids;
+
+ bzero(&arg, sizeof (struct mslsa_LookupSids));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+ arg.lookup_level = MSLSA_LOOKUP_LEVEL_2;
+
+ sid_entry.psid = sid;
+ arg.lup_sid_table.n_entry = 1;
+ arg.lup_sid_table.entries = &sid_entry;
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.mapped_count == 0) {
+ user_info->sid_name_use = SidTypeInvalid;
+ rc = 1;
+ } else {
+ name_entry = &arg.name_table.entries[0];
+ user_info->sid_name_use = name_entry->sid_name_use;
+
+ if (user_info->sid_name_use == SidTypeUser ||
+ user_info->sid_name_use == SidTypeGroup ||
+ user_info->sid_name_use == SidTypeAlias) {
+
+ user_info->rid =
+ sid->SubAuthority[sid->SubAuthCount - 1];
+
+ user_info->name = MEM_STRDUP("mlrpc",
+ (const char *)name_entry->name.str);
+ }
+
+ if ((index = name_entry->domain_ix) == -1) {
+ user_info->domain_sid = 0;
+ user_info->domain_name = 0;
+ } else {
+ domain_entry =
+ &arg.domain_table->entries[index];
+
+ user_info->domain_sid = nt_sid_dup(
+ (nt_sid_t *)domain_entry->domain_sid);
+
+ user_info->domain_name = MEM_STRDUP("mlrpc",
+ (const char *)
+ domain_entry->domain_name.str);
+ }
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * lsar_enum_accounts
+ *
+ * Enumerate the list of accounts (i.e. SIDs). Use the handle returned
+ * from lsa_open_policy2. The enum_context is used to support multiple
+ * calls to this enumeration function. It should be set to 0 on the
+ * first call. It will be updated by the domain controller and should
+ * simply be passed unchanged to subsequent calls until there are no
+ * more accounts. A warning status of 0x1A indicates that no more data
+ * is available. The list of accounts will be returned in accounts.
+ * This list is dynamically allocated using malloc, it should be freed
+ * by the caller when it is no longer required.
+ */
+int
+lsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
+ struct mslsa_EnumAccountBuf *accounts)
+{
+ struct mslsa_EnumerateAccounts arg;
+ struct mslsa_AccountInfo *info;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ DWORD n_entries;
+ DWORD i;
+ int nbytes;
+
+ if (lsa_handle == NULL || enum_context == NULL || accounts == NULL)
+ return (-1);
+
+ accounts->entries_read = 0;
+ accounts->info = 0;
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_EnumerateAccounts;
+
+ bzero(&arg, sizeof (struct mslsa_EnumerateAccounts));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+ arg.enum_context = *enum_context;
+ arg.max_length = MLSVC_MAX_RESPONSE_LEN;
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0) {
+ if ((arg.status & 0x00FFFFFF) == MLSVC_NO_MORE_DATA) {
+ *enum_context = arg.enum_context;
+ } else {
+ mlsvc_rpc_report_status(opnum,
+ (DWORD)arg.status);
+ rc = -1;
+ }
+ } else if (arg.enum_buf->entries_read != 0) {
+ n_entries = arg.enum_buf->entries_read;
+ nbytes = n_entries * sizeof (struct mslsa_AccountInfo);
+
+ info = (struct mslsa_AccountInfo *)MEM_MALLOC("mlrpc",
+ nbytes);
+ if (info == NULL) {
+ mlsvc_rpc_free(context, &heap);
+ return (-1);
+ }
+
+ for (i = 0; i < n_entries; ++i)
+ info[i].sid = (struct mslsa_sid *)nt_sid_dup(
+ (nt_sid_t *)arg.enum_buf->info[i].sid);
+
+ accounts->entries_read = n_entries;
+ accounts->info = info;
+ *enum_context = arg.enum_context;
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * lsar_enum_trusted_domains
+ *
+ * Enumerate the list of trusted domains. Use the handle returned from
+ * lsa_open_policy2. The enum_context is used to support multiple calls
+ * to this enumeration function. It should be set to 0 on the first
+ * call. It will be updated by the domain controller and should simply
+ * be passed unchanged to subsequent calls until there are no more
+ * domains.
+ *
+ * The trusted domains aren't actually returned here. They are added
+ * to the NT domain database. After all of the trusted domains have
+ * been discovered, the database can be interrogated to find all of
+ * the trusted domains.
+ */
+DWORD
+lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context)
+{
+ struct mslsa_EnumTrustedDomain arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ nt_domain_t *nt_new_dp;
+ int opnum;
+ DWORD status;
+ DWORD n_entries;
+ DWORD i;
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_EnumTrustedDomain;
+
+ bzero(&arg, sizeof (struct mslsa_EnumTrustedDomain));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+ arg.enum_context = *enum_context;
+ arg.max_length = MLSVC_MAX_RESPONSE_LEN;
+
+ (void) mlsvc_rpc_init(&heap);
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ *enum_context = arg.enum_context;
+ status = NT_SC_VALUE(arg.status);
+
+ /*
+ * status 0x8000001A means NO_MORE_DATA,
+ * which is not an error.
+ */
+ if (status != MLSVC_NO_MORE_DATA)
+ mlsvc_rpc_report_status(opnum, arg.status);
+ } else if (arg.enum_buf->entries_read == 0) {
+ *enum_context = arg.enum_context;
+ status = 0;
+ } else {
+ nt_domain_flush(NT_DOMAIN_TRUSTED);
+ n_entries = arg.enum_buf->entries_read;
+
+ for (i = 0; i < n_entries; ++i) {
+ nt_new_dp = nt_domain_new(
+ NT_DOMAIN_TRUSTED,
+ (char *)arg.enum_buf->info[i].name.str,
+ (nt_sid_t *)arg.enum_buf->info[i].sid);
+
+ (void) nt_domain_add(nt_new_dp);
+ }
+
+ *enum_context = arg.enum_context;
+ status = 0;
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+/*
+ * lsar_enum_privs_account
+ *
+ * Privileges enum? Need an account handle.
+ */
+/*ARGSUSED*/
+int
+lsar_enum_privs_account(mlsvc_handle_t *account_handle,
+ smb_userinfo_t *user_info)
+{
+ struct mslsa_EnumPrivsAccount arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+
+ context = account_handle->context;
+ opnum = LSARPC_OPNUM_EnumPrivsAccount;
+
+ bzero(&arg, sizeof (struct mslsa_EnumPrivsAccount));
+ (void) memcpy(&arg.account_handle, &account_handle->handle,
+ sizeof (mslsa_handle_t));
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if ((rc == 0) && (arg.status != 0)) {
+ mlsvc_rpc_report_status(opnum, (DWORD)arg.status);
+ rc = -1;
+ }
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * lsar_lookup_priv_value
+ *
+ * Map a privilege name to a local unique id (LUID). Privilege names
+ * are consistent across the network. LUIDs are machine specific.
+ * This function provides the means to map a privilege name to the
+ * LUID used by a remote server to represent it. The handle here is
+ * a policy handle.
+ */
+int
+lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle, char *name,
+ struct ms_luid *luid)
+{
+ struct mslsa_LookupPrivValue arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ size_t length;
+
+ if (lsa_handle == NULL || name == NULL || luid == NULL)
+ return (-1);
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_LookupPrivValue;
+
+ bzero(&arg, sizeof (struct mslsa_LookupPrivValue));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+
+ length = mts_wcequiv_strlen(name);
+ if (context->server_os == NATIVE_OS_WIN2000)
+ length += sizeof (mts_wchar_t);
+
+ arg.name.length = length;
+ arg.name.allosize = length;
+ arg.name.str = (unsigned char *)name;
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0)
+ rc = -1;
+ else
+ (void) memcpy(luid, &arg.luid, sizeof (struct ms_luid));
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * lsar_lookup_priv_name
+ *
+ * Map a local unique id (LUID) to a privilege name. Privilege names
+ * are consistent across the network. LUIDs are machine specific.
+ * This function the means to map the LUID used by a remote server to
+ * the appropriate privilege name. The handle here is a policy handle.
+ */
+int
+lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle, struct ms_luid *luid,
+ char *name, int namelen)
+{
+ struct mslsa_LookupPrivName arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+
+ if (lsa_handle == NULL || luid == NULL || name == NULL)
+ return (-1);
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_LookupPrivName;
+
+ bzero(&arg, sizeof (struct mslsa_LookupPrivName));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+ (void) memcpy(&arg.luid, luid, sizeof (struct ms_luid));
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0)
+ rc = -1;
+ else
+ (void) strlcpy(name, (char const *)arg.name->str,
+ namelen);
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * lsar_lookup_priv_display_name
+ *
+ * Map a privilege name to a privilege display name. The input handle
+ * should be an LSA policy handle and the name would normally be one
+ * of the privileges defined in smb_privilege.h
+ *
+ * There's something peculiar about the return status from NT servers,
+ * it's not always present. So for now, I'm ignoring the status in the
+ * RPC response.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name,
+ char *display_name, int display_len)
+{
+ struct mslsa_LookupPrivDisplayName arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ size_t length;
+ DWORD status;
+
+ if (lsa_handle == NULL || name == NULL || display_name == NULL)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_LookupPrivDisplayName;
+
+ bzero(&arg, sizeof (struct mslsa_LookupPrivDisplayName));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+
+ length = mts_wcequiv_strlen(name);
+ arg.name.length = length;
+ arg.name.allosize = length;
+ arg.name.str = (unsigned char *)name;
+
+ arg.client_language = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
+ arg.default_language = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);
+
+ (void) mlsvc_rpc_init(&heap);
+
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0)
+ status = NT_STATUS_INVALID_PARAMETER;
+#if 0
+ else if (arg.status != 0)
+ status = NT_SC_VALUE(arg.status);
+#endif
+ else {
+ (void) strlcpy(display_name,
+ (char const *)arg.display_name->str, display_len);
+ status = NT_STATUS_SUCCESS;
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+/*
+ * lsar_lookup_sids2
+ */
+DWORD
+lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid,
+ smb_userinfo_t *user_info)
+{
+ struct lsar_lookup_sids2 arg;
+ struct lsar_name_entry2 *name_entry;
+ struct mslsa_lup_sid_entry sid_entry;
+ struct mslsa_domain_entry *domain_entry;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int index;
+ DWORD status;
+
+ if (lsa_handle == NULL || sid == NULL || user_info == NULL)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_LookupSids2;
+
+ if (context->server_os != NATIVE_OS_WIN2000)
+ return (NT_STATUS_REVISION_MISMATCH);
+
+ bzero(&arg, sizeof (struct lsar_lookup_sids2));
+ (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
+
+ sid_entry.psid = sid;
+ arg.lup_sid_table.n_entry = 1;
+ arg.lup_sid_table.entries = &sid_entry;
+ arg.lookup_level = MSLSA_LOOKUP_LEVEL_1;
+ arg.requested_count = arg.lup_sid_table.n_entry;
+
+ (void) mlsvc_rpc_init(&heap);
+
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.mapped_count == 0) {
+ user_info->sid_name_use = SidTypeInvalid;
+ status = NT_STATUS_NONE_MAPPED;
+ } else if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ status = NT_SC_VALUE(arg.status);
+ } else {
+ status = 0;
+
+ name_entry = &arg.name_table.entries[0];
+ user_info->sid_name_use = name_entry->sid_name_use;
+
+ if (user_info->sid_name_use == SidTypeUser ||
+ user_info->sid_name_use == SidTypeGroup ||
+ user_info->sid_name_use == SidTypeAlias) {
+
+ user_info->rid =
+ sid->SubAuthority[sid->SubAuthCount - 1];
+
+ user_info->name = MEM_STRDUP("mlrpc",
+ (char const *)name_entry->name.str);
+
+ }
+
+ if ((index = name_entry->domain_ix) == -1) {
+ user_info->domain_sid = 0;
+ user_info->domain_name = 0;
+ } else {
+ domain_entry = &arg.domain_table->entries[index];
+
+ user_info->domain_sid = nt_sid_dup(
+ (nt_sid_t *)domain_entry->domain_sid);
+
+ user_info->domain_name = MEM_STRDUP("mlrpc",
+ (char const *)domain_entry->domain_name.str);
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+
+/*
+ * lsar_lookup_names2
+ *
+ * Windows NT expects the name length to exclude the terminating
+ * wchar null but Windows 2000 insists that both the length and
+ * the allosize include the wchar null. Windows NT doesn't care
+ * whether or not the allosize includes or excludes the null char.
+ *
+ * As a precaution, I set the lookup level to 1 on Windows 2000
+ * until I can do some more testing.
+ *
+ * Note that NT returns an error if the mapped_count is non-zero
+ * when the RPC is called.
+ *
+ * It should be okay to lookup DOMAIN\Administrator in this function.
+ */
+DWORD
+lsar_lookup_names2(mlsvc_handle_t *lsa_handle, char *name,
+ smb_userinfo_t *user_info)
+{
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int index;
+ struct lsar_LookupNames2 arg;
+ size_t length;
+ lookup_name_table_t name_table;
+ struct lsar_rid_entry2 *rid_entry;
+ struct mslsa_domain_entry *domain_entry;
+ DWORD status;
+
+ if (lsa_handle == NULL || name == NULL || user_info == NULL)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ bzero(user_info, sizeof (smb_userinfo_t));
+ user_info->sid_name_use = SidTypeUnknown;
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_LookupNames2;
+
+ if (context->server_os != NATIVE_OS_WIN2000)
+ return (NT_STATUS_REVISION_MISMATCH);
+
+ bzero(&arg, sizeof (struct lsar_LookupNames2));
+ (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
+ arg.unknown_sb2 = 0x00000002;
+ arg.lookup_level = MSLSA_LOOKUP_LEVEL_1;
+
+ arg.name_table = (struct mslsa_lup_name_table *)&name_table;
+ name_table.n_entry = 1;
+
+ length = mts_wcequiv_strlen(name) + sizeof (mts_wchar_t);
+ name_table.name[0].length = length;
+ name_table.name[0].allosize = length;
+ name_table.name[0].str = (unsigned char *)name;
+
+ (void) mlsvc_rpc_init(&heap);
+
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ status = NT_SC_VALUE(arg.status);
+ } else if (arg.mapped_count == 0) {
+ user_info->sid_name_use = SidTypeInvalid;
+ status = NT_STATUS_NONE_MAPPED;
+ } else {
+ status = 0;
+
+ rid_entry = &arg.translated_sids.rids[0];
+ user_info->sid_name_use = rid_entry->sid_name_use;
+ user_info->rid = rid_entry->rid;
+ user_info->name = MEM_STRDUP("mlrpc", name);
+
+ if ((index = rid_entry->domain_index) == -1) {
+ user_info->domain_sid = 0;
+ user_info->domain_name = 0;
+ } else {
+ domain_entry = &arg.domain_table->entries[index];
+
+ user_info->domain_sid = nt_sid_dup(
+ (nt_sid_t *)domain_entry->domain_sid);
+
+ user_info->domain_name = MEM_STRDUP("mlrpc",
+ (char const *)domain_entry->domain_name.str);
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+void
+mlsvc_rpc_report_status(int opnum, DWORD status)
+{
+ char *s = "unknown";
+
+ if (status == 0)
+ s = "success";
+ else if (NT_SC_IS_ERROR(status))
+ s = "error";
+ else if (NT_SC_IS_WARNING(status))
+ s = "warning";
+ else if (NT_SC_IS_INFO(status))
+ s = "info";
+
+ smb_tracef("mlrpc[0x%02x]: %s: %s (0x%08x)",
+ opnum, s, xlate_nt_status(status), status);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_open.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_open.c
new file mode 100644
index 0000000000..57b1b62a97
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_open.c
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Local Security Authority RPC (LSARPC) library interface functions for
+ * open and close calls.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbrdr.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/ntaccess.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/lsalib.h>
+
+/*
+ * lsar_open
+ *
+ * This is a wrapper round lsar_open_policy2 to ensure that we connect
+ * using the appropriate session and logon. We default to the resource
+ * domain information if the caller didn't supply a server name and a
+ * domain name.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+int lsar_open(int ipc_mode, char *server, char *domain, char *username,
+ char *password, mlsvc_handle_t *domain_handle)
+{
+ smb_ntdomain_t *di;
+ int remote_os;
+ int remote_lm;
+ int rc;
+
+ if ((di = smb_getdomaininfo(0)) == NULL)
+ return (-1);
+
+ if (server == NULL || domain == NULL) {
+ server = di->server;
+ domain = di->domain;
+ }
+
+ switch (ipc_mode) {
+ case MLSVC_IPC_USER:
+ /*
+ * Use the supplied credentials.
+ */
+ rc = mlsvc_user_logon(server, domain, username, password);
+ break;
+
+ case MLSVC_IPC_ADMIN:
+ /*
+ * Use the resource domain administrator credentials.
+ */
+ server = di->server;
+ domain = di->domain;
+ username = smbrdr_ipc_get_user();
+
+ rc = mlsvc_admin_logon(server, domain);
+ break;
+
+ case MLSVC_IPC_ANON:
+ default:
+ rc = mlsvc_anonymous_logon(server, domain, &username);
+ break;
+ }
+
+ if (rc != 0)
+ return (-1);
+
+ rc = lsar_open_policy2(server, domain, username, domain_handle);
+ if (rc == 0) {
+ if (mlsvc_session_native_values(domain_handle->context->fid,
+ &remote_os, &remote_lm, 0) != 0)
+ remote_os = NATIVE_OS_UNKNOWN;
+
+ domain_handle->context->server_os = remote_os;
+ }
+ return (rc);
+}
+
+
+/*
+ * lsar_open_policy2
+ *
+ * Obtain an LSA policy handle. A policy handle is required to access
+ * LSA resources on a remote server. The server name supplied here does
+ * not need the double backslash prefix; it is added here. Call this
+ * function via lsar_open to ensure that the appropriate connection is
+ * in place.
+ *
+ * I'm not sure if it makes a difference whether we use GENERIC_EXECUTE
+ * or STANDARD_RIGHTS_EXECUTE. For a long time I used the standard bit
+ * and then I added the generic bit while working on privileges because
+ * NT sets that bit. I don't think it matters.
+ *
+ * Returns 0 on success. Otherwise non-zero to indicate a failure.
+ */
+int lsar_open_policy2(char *server, char *domain, char *username,
+ mlsvc_handle_t *lsa_handle)
+{
+ struct mslsa_OpenPolicy2 arg;
+ mlrpc_heapref_t heap;
+ int rc;
+ int opnum;
+ int fid;
+ int remote_os;
+ int remote_lm;
+ int len;
+
+ if (server == NULL || domain == NULL ||
+ username == NULL || lsa_handle == NULL)
+ return (-1);
+
+ fid = mlsvc_open_pipe(server, domain, username, "\\lsarpc");
+ if (fid < 0)
+ return (-1);
+
+ if ((rc = mlsvc_rpc_bind(lsa_handle, fid, "LSARPC")) < 0) {
+ (void) mlsvc_close_pipe(fid);
+ return (rc);
+ }
+
+ opnum = LSARPC_OPNUM_OpenPolicy2;
+ bzero(&arg, sizeof (struct mslsa_OpenPolicy2));
+
+ len = strlen(server) + 4;
+ arg.servername = malloc(len);
+ if (arg.servername == NULL) {
+ (void) mlsvc_close_pipe(fid);
+ free(lsa_handle->context);
+ return (-1);
+ }
+
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ arg.attributes.length = sizeof (struct mslsa_object_attributes);
+
+ (void) mlsvc_session_native_values(fid, &remote_os, &remote_lm, 0);
+
+ if (remote_os == NATIVE_OS_NT5_0) {
+ arg.desiredAccess = MAXIMUM_ALLOWED;
+ } else {
+ arg.desiredAccess = GENERIC_EXECUTE
+ | STANDARD_RIGHTS_EXECUTE
+ | POLICY_VIEW_LOCAL_INFORMATION
+ | POLICY_LOOKUP_NAMES;
+ }
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(lsa_handle->context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0) {
+ rc = -1;
+ } else {
+ (void) memcpy(&lsa_handle->handle, &arg.domain_handle,
+ sizeof (mslsa_handle_t));
+
+ if (mlsvc_is_null_handle(lsa_handle))
+ rc = -1;
+ }
+ }
+
+ mlsvc_rpc_free(lsa_handle->context, &heap);
+ free(arg.servername);
+
+ if (rc != 0) {
+ (void) mlsvc_close_pipe(fid);
+ free(lsa_handle->context);
+ }
+
+ return (rc);
+}
+
+/*
+ * lsar_open_account
+ *
+ * Obtain an LSA account handle. The lsa_handle must be a valid handle
+ * obtained via lsar_open_policy2. The main thing to remember here is
+ * to set up the context in the lsa_account_handle. I'm not sure what
+ * the requirements are for desired access. Some values require admin
+ * access.
+ *
+ * Returns 0 on success. Otherwise non-zero to indicate a failure.
+ */
+int
+lsar_open_account(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid,
+ mlsvc_handle_t *lsa_account_handle)
+{
+ struct mslsa_OpenAccount arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int rc;
+ int opnum;
+
+ if (mlsvc_is_null_handle(lsa_handle) ||
+ sid == NULL || lsa_account_handle == NULL)
+ return (-1);
+
+ context = lsa_handle->context;
+ opnum = LSARPC_OPNUM_OpenAccount;
+ bzero(&arg, sizeof (struct mslsa_OpenAccount));
+
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+ arg.sid = sid;
+ arg.access_mask = STANDARD_RIGHTS_REQUIRED
+#if 0
+ | POLICY_VIEW_AUDIT_INFORMATION
+ | POLICY_GET_PRIVATE_INFORMATION
+ | POLICY_TRUST_ADMIN
+#endif
+ | POLICY_VIEW_LOCAL_INFORMATION;
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0) {
+ rc = -1;
+ } else {
+ lsa_account_handle->context = context;
+
+ (void) memcpy(&lsa_account_handle->handle,
+ &arg.account_handle, sizeof (mslsa_handle_t));
+
+ if (mlsvc_is_null_handle(lsa_account_handle))
+ rc = -1;
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * lsar_close
+ *
+ * Close the LSA connection associated with the handle. The lsa_handle
+ * must be a valid handle obtained via a call to lsar_open_policy2 or
+ * lsar_open_account. On success the handle will be zeroed out to
+ * ensure that it is not used again. If this is the top level handle
+ * (i.e. the one obtained via lsar_open_policy2) the pipe is closed
+ * and the context is freed.
+ *
+ * Returns 0 on success. Otherwise non-zero to indicate a failure.
+ */
+int
+lsar_close(mlsvc_handle_t *lsa_handle)
+{
+ struct mslsa_CloseHandle arg;
+ mlrpc_heapref_t heap;
+ int rc;
+ int opnum;
+
+ if (mlsvc_is_null_handle(lsa_handle))
+ return (-1);
+
+ opnum = LSARPC_OPNUM_CloseHandle;
+ bzero(&arg, sizeof (struct mslsa_CloseHandle));
+ (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(lsa_handle->context, opnum, &arg, &heap);
+ mlsvc_rpc_free(lsa_handle->context, &heap);
+
+ if (lsa_handle->context->handle == &lsa_handle->handle) {
+ (void) mlsvc_close_pipe(lsa_handle->context->fid);
+ free(lsa_handle->context);
+ }
+
+ bzero(lsa_handle, sizeof (mlsvc_handle_t));
+ return (rc);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers
new file mode 100644
index 0000000000..e05f51b279
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers
@@ -0,0 +1,97 @@
+#
+# 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.
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+SUNWprivate {
+ global:
+ lmshare_add;
+ lmshare_close_iterator;
+ lmshare_delete;
+ lmshare_exists;
+ lmshare_getinfo;
+ lmshare_get_realpath;
+ lmshare_is_admin;
+ lmshare_is_dir;
+ lmshare_is_restricted;
+ lmshare_is_special;
+ lmshare_is_valid;
+ lmshare_iterate;
+ lmshare_list;
+ lmshare_num_shares;
+ lmshare_open_iterator;
+ lmshare_rename;
+ lmshare_setinfo;
+ lmshare_start;
+ lmshare_stop;
+ lsa_lookup_name2;
+ lsa_lookup_sid2;
+ lsa_query_primary_domain_info;
+ lsa_query_account_domain_info;
+ lsa_enum_trusted_domains;
+ mlsvc_init;
+ mlsvc_validate_user;
+ mlsvc_is_local_domain;
+ nt_group_add;
+ nt_group_add_groupprivs;
+ nt_group_add_member_byname;
+ nt_group_cache_size;
+ nt_group_close_iterator;
+ nt_group_delete;
+ nt_group_del_member_byname;
+ nt_group_getinfo;
+ nt_group_getpriv;
+ nt_group_ht_lock;
+ nt_group_ht_unlock;
+ nt_group_is_member;
+ nt_group_iterate;
+ nt_group_modify;
+ nt_group_num_groups;
+ nt_group_num_members;
+ nt_group_open_iterator;
+ nt_group_putinfo;
+ nt_groups_count;
+ nt_group_setpriv;
+ nt_groups_lookup_rid;
+ nt_groups_member_groups;
+ nt_groups_member_ngroups;
+ nt_groups_member_privs;
+ nt_group_list;
+ nt_group_member_list;
+ sam_init;
+ smb_logon;
+ smb_token_destroy;
+ smb_build_lmshare_info;
+ smb_get_smb_share_group;
+ smb_autohome_add;
+ smb_autohome_endent;
+ smb_autohome_getent;
+ smb_autohome_lookup;
+ smb_autohome_remove;
+ smb_autohome_setent;
+ smb_is_autohome;
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
new file mode 100644
index 0000000000..ac8cc3003c
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Context functions to support the RPC interface library.
+ */
+
+#include <sys/errno.h>
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbrdr.h>
+#include <smbsrv/mlsvc_util.h>
+
+static int mlsvc_xa_init(struct mlrpc_client *, struct mlrpc_xaction *,
+ mlrpc_heap_t *);
+static int mlsvc_xa_exchange(struct mlrpc_client *, struct mlrpc_xaction *);
+static int mlsvc_xa_read(struct mlrpc_client *, struct mlrpc_xaction *);
+static int mlsvc_xa_preserve(struct mlrpc_client *, struct mlrpc_xaction *,
+ mlrpc_heapref_t *);
+static int mlsvc_xa_destruct(struct mlrpc_client *, struct mlrpc_xaction *);
+static void mlsvc_xa_release(struct mlrpc_client *, mlrpc_heapref_t *heapref);
+
+/*
+ * mlsvc_rpc_bind
+ *
+ * This the entry point for all client RPC services. This call must be
+ * made to initialize an RPC context structure and bind to the remote
+ * service before any RPCs can be exchanged with that service. The
+ * descriptor is a wrapper that is used to associate an RPC handle with
+ * the context data for that specific instance of the interface. The
+ * handle is zeroed to ensure that it doesn't look like a valid handle.
+ * The context handle is assigned to point at the RPC handle so that we
+ * know when to free the context. As each handle is initialized it will
+ * include a pointer to this context but only when we close this initial
+ * RPC handle can the context be freed.
+ *
+ * On success, return a pointer to the descriptor. Otherwise return a
+ * null pointer.
+ */
+int
+mlsvc_rpc_bind(mlsvc_handle_t *desc, int fid, char *service)
+{
+ struct mlsvc_rpc_context *context;
+ int rc;
+
+ bzero(&desc->handle, sizeof (ms_handle_t));
+
+ context = malloc(sizeof (struct mlsvc_rpc_context));
+ if ((desc->context = context) == NULL)
+ return (-1);
+
+ bzero(context, sizeof (struct mlsvc_rpc_context));
+ context->cli.context = context;
+
+ mlrpc_binding_pool_initialize(&context->cli.binding_list,
+ context->binding_pool, CTXT_N_BINDING_POOL);
+
+ context->fid = fid;
+ context->handle = &desc->handle;
+ context->cli.xa_init = mlsvc_xa_init;
+ context->cli.xa_exchange = mlsvc_xa_exchange;
+ context->cli.xa_read = mlsvc_xa_read;
+ context->cli.xa_preserve = mlsvc_xa_preserve;
+ context->cli.xa_destruct = mlsvc_xa_destruct;
+ context->cli.xa_release = mlsvc_xa_release;
+
+ rc = mlrpc_c_bind(&context->cli, service, &context->binding);
+ if (MLRPC_DRC_IS_FAULT(rc)) {
+ free(context);
+ desc->context = NULL;
+ return (-1);
+ }
+
+ return (rc);
+}
+
+/*
+ * mlsvc_rpc_init
+ *
+ * This function must be called by client side applications before
+ * calling mlsvc_rpc_call to allocate a heap. The heap must be
+ * destroyed by either calling mlrpc_heap_destroy or mlsvc_rpc_free.
+ * Use mlrpc_heap_destroy if mlsvc_rpc_call has not yet been called.
+ * Otherwise use mlsvc_rpc_free.
+ *
+ * Returns 0 on success. Otherwise returns -1 to indicate an error.
+ */
+int
+mlsvc_rpc_init(mlrpc_heapref_t *heapref)
+{
+ bzero(heapref, sizeof (mlrpc_heapref_t));
+
+ if ((heapref->heap = mlrpc_heap_create()) == NULL)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * mlsvc_rpc_call
+ *
+ * This function should be called by the client RPC interface functions
+ * to make an RPC call. The remote service is identified by the context
+ * handle, which should have been initialized with by mlsvc_rpc_bind.
+ */
+int
+mlsvc_rpc_call(struct mlsvc_rpc_context *context, int opnum, void *params,
+ mlrpc_heapref_t *heapref)
+{
+ return (mlrpc_c_call(context->binding, opnum, params, heapref));
+}
+
+/*
+ * mlsvc_rpc_free
+ *
+ * This function should be called by the client RPC interface functions
+ * to free the heap after an RPC call returns.
+ */
+void
+mlsvc_rpc_free(struct mlsvc_rpc_context *context, mlrpc_heapref_t *heapref)
+{
+ mlrpc_c_free_heap(context->binding, heapref);
+}
+
+/*
+ * The following functions provide the callback interface in the
+ * context handle.
+ */
+/*ARGSUSED*/
+static int
+mlsvc_xa_init(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa,
+ mlrpc_heap_t *heap)
+{
+ struct mlndr_stream *recv_mlnds = &mxa->recv_mlnds;
+ struct mlndr_stream *send_mlnds = &mxa->send_mlnds;
+
+ /*
+ * If the caller hasn't provided a heap, create one here.
+ */
+ if (heap == 0) {
+ if ((heap = mlrpc_heap_create()) == 0)
+ return (-1);
+ }
+
+ mxa->heap = heap;
+
+ mlnds_initialize(send_mlnds, 0, NDR_MODE_CALL_SEND, heap);
+ mlnds_initialize(recv_mlnds, 16 * 1024, NDR_MODE_RETURN_RECV, heap);
+ return (0);
+}
+
+/*
+ * mlsvc_xa_exchange
+ *
+ * This is the entry pointy for an RPC client call exchange with
+ * a server, which will result in an smbrdr SmbTransact request.
+ *
+ * SmbTransact should return the number of bytes received, which
+ * we record as the PDU size, or a negative error code.
+ */
+static int
+mlsvc_xa_exchange(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
+{
+ struct mlsvc_rpc_context *context = mcli->context;
+ struct mlndr_stream *recv_mlnds = &mxa->recv_mlnds;
+ struct mlndr_stream *send_mlnds = &mxa->send_mlnds;
+ int rc;
+
+ rc = smbrdr_rpc_transact(context->fid,
+ (char *)send_mlnds->pdu_base_offset, send_mlnds->pdu_size,
+ (char *)recv_mlnds->pdu_base_offset, recv_mlnds->pdu_max_size);
+
+ if (rc < 0)
+ recv_mlnds->pdu_size = 0;
+ else
+ recv_mlnds->pdu_size = rc;
+
+ return (rc);
+}
+
+/*
+ * mlsvc_xa_read
+ *
+ * This entry point will be invoked if the xa-exchange response contained
+ * only the first fragment of a multi-fragment response. The RPC client
+ * code will then make repeated xa-read requests to obtain the remaining
+ * fragments, which will result in smbrdr SmbReadX requests.
+ *
+ * SmbReadX should return the number of bytes received, in which case we
+ * expand the PDU size to include the received data, or a negative error
+ * code.
+ */
+static int
+mlsvc_xa_read(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
+{
+ struct mlsvc_rpc_context *context = mcli->context;
+ struct mlndr_stream *mlnds = &mxa->recv_mlnds;
+ int len;
+ int rc;
+
+ if ((len = (mlnds->pdu_max_size - mlnds->pdu_size)) < 0)
+ return (-1);
+
+ rc = smbrdr_rpc_readx(context->fid,
+ (char *)mlnds->pdu_base_offset + mlnds->pdu_size, len);
+
+ if (rc < 0)
+ return (-1);
+
+ mlnds->pdu_size += rc;
+
+ if (mlnds->pdu_size > mlnds->pdu_max_size) {
+ mlnds->pdu_size = mlnds->pdu_max_size;
+ return (-1);
+ }
+
+ return (rc);
+}
+
+/*
+ * mlsvc_xa_preserve
+ *
+ * This function is called to preserve the heap. We save a reference
+ * to the heap and set the mxa heap pointer to null so that the heap
+ * will not be discarded when mlsvc_xa_destruct is called.
+ */
+/*ARGSUSED*/
+static int
+mlsvc_xa_preserve(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa,
+ mlrpc_heapref_t *heapref)
+{
+ heapref->state = MLRPC_HRST_PRESERVED;
+ heapref->heap = mxa->heap;
+ heapref->recv_pdu_buf = (char *)mxa->recv_mlnds.pdu_base_addr;
+ heapref->send_pdu_buf = (char *)mxa->send_mlnds.pdu_base_addr;
+
+ mxa->heap = NULL;
+ return (0);
+}
+
+/*
+ * mlsvc_xa_destruct
+ *
+ * This function is called to dispose of the heap. If the heap has
+ * been preserved via mlsvc_xa_preserve, the mxa heap pointer will
+ * be null and we assume that the heap will be released later via
+ * a call to mlsvc_xa_release. Otherwise we free the memory here.
+ */
+/*ARGSUSED*/
+static int
+mlsvc_xa_destruct(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
+{
+ if (mxa->heap) {
+ mlnds_destruct(&mxa->recv_mlnds);
+ mlnds_destruct(&mxa->send_mlnds);
+ mlrpc_heap_destroy(mxa->heap);
+ }
+
+ return (0);
+}
+
+/*
+ * mlsvc_xa_release
+ *
+ * This function is called, via some indirection, as a result of a
+ * call to mlsvc_rpc_free. This is where we free the heap memory
+ * that was preserved during an RPC call.
+ */
+/*ARGSUSED*/
+static void
+mlsvc_xa_release(struct mlrpc_client *mcli, mlrpc_heapref_t *heapref)
+{
+ if (heapref == NULL)
+ return;
+
+ if (heapref->state == MLRPC_HRST_PRESERVED) {
+ free(heapref->recv_pdu_buf);
+ free(heapref->send_pdu_buf);
+ mlrpc_heap_destroy(heapref->heap);
+ }
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_dssetup.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_dssetup.c
new file mode 100644
index 0000000000..a20304afa8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_dssetup.c
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Active Directory Setup RPC interface used by Windows2000.
+ */
+
+#include <strings.h>
+#include <stdlib.h>
+#include <netdb.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlrpc.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/dssetup.ndl>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/nmpipes.h>
+
+static int dssetup_DsRoleGetPrimaryDomainInfo(void *, struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t dssetup_stub_table[] = {
+ { dssetup_DsRoleGetPrimaryDomainInfo,
+ DSSETUP_OPNUM_DsRoleGetPrimaryDomainInfo },
+ {0}
+};
+
+static mlrpc_service_t dssetup_service = {
+ "DSSETUP", /* name */
+ "Active Directory Setup", /* desc */
+ "\\lsarpc", /* endpoint */
+ PIPE_LSASS, /* sec_addr_port */
+ "3919286a-b10c-11d0-9ba800c04fd92ef5", 0, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(dssetup_interface), /* interface ti */
+ dssetup_stub_table /* stub_table */
+};
+
+/*
+ * dssetup_initialize
+ *
+ * This function registers the DSSETUP interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+dssetup_initialize(void)
+{
+ (void) mlrpc_register_service(&dssetup_service);
+}
+
+/*
+ * Request for primary domain information and status.
+ */
+static int
+dssetup_DsRoleGetPrimaryDomainInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct dssetup_DsRoleGetPrimaryDomainInfo *param = arg;
+ char dns_domain[MAXHOSTNAMELEN];
+ smb_ntdomain_t *di;
+ DWORD status;
+
+ switch (param->level) {
+ case DS_ROLE_BASIC_INFORMATION:
+ break;
+
+ case DS_ROLE_UPGRADE_STATUS:
+ case DS_ROLE_OP_STATUS:
+ default:
+ bzero(param,
+ sizeof (struct dssetup_DsRoleGetPrimaryDomainInfo));
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_LEVEL);
+ return (MLRPC_DRC_OK);
+ }
+
+ di = smb_getdomaininfo(0);
+ (void) smb_getdomainname(dns_domain, MAXHOSTNAMELEN);
+
+ if (di == NULL) {
+ bzero(param,
+ sizeof (struct dssetup_DsRoleGetPrimaryDomainInfo));
+ param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+ return (MLRPC_DRC_OK);
+ }
+
+ (void) utf8_strlwr(dns_domain);
+
+ param->ru.info1.role = DS_ROLE_MEMBER_SERVER;
+ param->ru.info1.flags = 0;
+ param->ru.info1.nt_domain =
+ (uint8_t *)MLRPC_HEAP_STRSAVE(mxa, di->domain);
+ param->ru.info1.dns_domain =
+ (uint8_t *)MLRPC_HEAP_STRSAVE(mxa, dns_domain);
+ param->ru.info1.forest =
+ (uint8_t *)MLRPC_HEAP_STRSAVE(mxa, dns_domain);
+ bzero(&param->ru.info1.domain_guid, sizeof (mlrpc_uuid_t));
+
+ if (param->ru.info1.nt_domain == NULL ||
+ param->ru.info1.dns_domain == NULL ||
+ param->ru.info1.forest == NULL) {
+ bzero(param,
+ sizeof (struct dssetup_DsRoleGetPrimaryDomainInfo));
+ status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ } else {
+ status = NT_STATUS_SUCCESS;
+ }
+
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+DECL_FIXUP_STRUCT(dssetup_GetPrimaryDomainInfo_ru);
+DECL_FIXUP_STRUCT(dssetup_GetPrimaryDomainInfoRes);
+DECL_FIXUP_STRUCT(dssetup_DsRoleGetPrimaryDomainInfo);
+
+void
+fixup_dssetup_DsRoleGetPrimaryDomainInfo(
+ struct dssetup_DsRoleGetPrimaryDomainInfo *val)
+{
+ unsigned short size1 = 0;
+ unsigned short size2 = 0;
+ unsigned short size3 = 0;
+
+ switch (val->switch_value) {
+ CASE_INFO_ENT(dssetup_DsRolePrimaryDomInfo, 1);
+ CASE_INFO_ENT(dssetup_DsRolePrimaryDomInfo, 2);
+ CASE_INFO_ENT(dssetup_DsRolePrimaryDomInfo, 3);
+
+ default:
+ return;
+ };
+
+ size2 = size1 + (2 * sizeof (DWORD));
+ size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD);
+
+ FIXUP_PDU_SIZE(dssetup_GetPrimaryDomainInfo_ru, size1);
+ FIXUP_PDU_SIZE(dssetup_GetPrimaryDomainInfoRes, size2);
+ FIXUP_PDU_SIZE(dssetup_DsRoleGetPrimaryDomainInfo, size3);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_handle.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_handle.c
new file mode 100644
index 0000000000..a13b7346f5
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_handle.c
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the handles used in the various server-side
+ * RPC functions. I don't think other systems care about the value in
+ * the handle. It should be treated as an opaque data block. Handles
+ * are issued when a service is opened and obsoleted when it is closed.
+ * We should check incoming RPC requests to ensure that the handle
+ * being used is associated with the particular service being accessed.
+ */
+
+#include <strings.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ntsid.h>
+
+/*
+ * Each time a handle is allocated it is added to the global handle
+ * descriptor list because we need some way of identifying the
+ * interface and domain to which the handle was assigned when it is
+ * returned on a subsequent RPC.
+ */
+ms_handle_t mlsvc_handle;
+ms_handle_desc_t *mlsvc_desc_list;
+
+/*
+ * mlsvc_get_handle
+ *
+ * This function returns a handle for use with the server-side RPC
+ * functions. Every time it is called it will increment the handle
+ * value and return a pointer to it. On NT, handle[0] always seems
+ * to be zero and handle[1] increments. The rest seems to be some
+ * sort of unique value so the local domain SID should do.
+ *
+ * The handle is added to the global handle descriptor list with the
+ * designated ifspec and key tag.
+ */
+ms_handle_t *
+mlsvc_get_handle(ms_ifspec_t ifspec, char *key, DWORD discrim)
+{
+ ms_handle_desc_t *desc;
+ nt_sid_t *sid;
+
+ if ((desc = malloc(sizeof (ms_handle_desc_t))) == NULL)
+ assert(desc);
+
+ sid = nt_domain_local_sid();
+ if (mlsvc_handle.handle[1] == 0) {
+ mlsvc_handle.handle[0] = 0;
+ mlsvc_handle.handle[1] = 0;
+ mlsvc_handle.handle[2] = sid->SubAuthority[1];
+ mlsvc_handle.handle[3] = sid->SubAuthority[2];
+ mlsvc_handle.handle[4] = sid->SubAuthority[3];
+ }
+
+ ++mlsvc_handle.handle[1];
+
+ bcopy(&mlsvc_handle, &desc->handle, sizeof (ms_handle_t));
+ desc->ifspec = ifspec;
+ desc->discrim = discrim;
+ desc->next = mlsvc_desc_list;
+ mlsvc_desc_list = desc;
+
+ if (key)
+ (void) strlcpy(desc->key, key, MLSVC_HANDLE_KEY_MAX);
+ else
+ desc->key[0] = '\0';
+
+ return (&mlsvc_handle);
+}
+
+
+/*
+ * mlsvc_put_handle
+ *
+ * Remove a handle from the global handle descriptor list and free the
+ * memory it was using. If the list contained the descriptor, a value
+ * of 0 is returned. Otherwise -1 is returned.
+ */
+int
+mlsvc_put_handle(ms_handle_t *handle)
+{
+ ms_handle_desc_t *desc;
+ ms_handle_desc_t **ppdesc = &mlsvc_desc_list;
+
+ assert(handle);
+
+ while (*ppdesc) {
+ desc = *ppdesc;
+
+ if (bcmp(&desc->handle, handle, sizeof (ms_handle_t)) == 0) {
+ *ppdesc = desc->next;
+ free(desc);
+ return (0);
+ }
+
+ ppdesc = &(*ppdesc)->next;
+ }
+
+ return (-1);
+}
+
+
+/*
+ * mlsvc_validate_handle
+ *
+ * Lookup a handle in the global handle descriptor list. If the handle
+ * is in the list, a pointer to the descriptor is returned. Otherwise
+ * a null pointer is returned.
+ */
+int
+mlsvc_validate_handle(ms_handle_t *handle, char *key)
+{
+ ms_handle_desc_t *desc;
+
+ assert(handle);
+ assert(key);
+
+ if ((desc = mlsvc_lookup_handle(handle)) == 0)
+ return (NULL);
+
+ if (strcmp(desc->key, key))
+ return (NULL);
+
+ return (1);
+}
+
+
+/*
+ * mlsvc_lookup_handle
+ *
+ * Lookup a handle in the global handle descriptor list. If the handle
+ * is in the list, a pointer to the descriptor is returned. Otherwise
+ * a null pointer is returned.
+ */
+ms_handle_desc_t *
+mlsvc_lookup_handle(ms_handle_t *handle)
+{
+ ms_handle_desc_t *desc = mlsvc_desc_list;
+
+ assert(handle);
+
+ while (desc) {
+ if (bcmp(&desc->handle, handle, sizeof (ms_handle_t)) == 0)
+ return (desc);
+
+ desc = desc->next;
+ }
+
+ return (NULL);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c
new file mode 100644
index 0000000000..fc17554949
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/lsalib.h>
+
+void dssetup_initialize(void);
+void srvsvc_initialize(void);
+void wkssvc_initialize(void);
+void lsarpc_initialize(void);
+void logr_initialize(void);
+void netr_initialize(void);
+void samr_initialize(void);
+void svcctl_initialize(void);
+void winreg_initialize(void);
+
+/*
+ * All mlrpc initialization is invoked from here.
+ * Returns 0 upon success. Otherwise, returns -1.
+ */
+int
+mlsvc_init(void)
+{
+ srvsvc_initialize();
+ wkssvc_initialize();
+ lsarpc_initialize();
+ netr_initialize();
+ dssetup_initialize();
+ samr_initialize();
+ svcctl_initialize();
+ winreg_initialize();
+ logr_initialize();
+
+ (void) sam_init();
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_logr.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_logr.c
new file mode 100644
index 0000000000..14c13a0315
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_logr.c
@@ -0,0 +1,574 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Event Log Service RPC (LOGR) interface definition.
+ */
+
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/eventlog.ndl>
+
+#define FWD +1
+#define REW -1
+
+/* define the logging structs here - from syslog.h */
+#define NMSGMASK 1023
+#define MAXMSGLEN 223
+#define LOGBUFSIZE (MAXMSGLEN + 1)
+
+#define LOG_PRI(p) ((p) & LOG_PRIMASK)
+
+typedef struct log_entry {
+ struct timeval timestamp; /* time of log entry */
+ int pri; /* message priority */
+ char msg[LOGBUFSIZE]; /* log message text */
+ int thread_id; /* calling function thread ID */
+ char thread_name[12]; /* calling function thread name */
+ unsigned long caller_adr; /* calling function address */
+} log_entry_t;
+
+typedef struct log_info {
+ log_entry_t entry[NMSGMASK+1];
+ int ix;
+ int alarm_on;
+ int alarm_disable;
+ int timestamp_level;
+ int disp_msg_len;
+ int prefix_len;
+} log_info_t;
+
+/*
+ * READ flags for EventLogRead
+ *
+ * EVENTLOG_SEEK_READ
+ * The read operation proceeds from the record specified by the
+ * dwRecordOffset parameter. This flag cannot be used with
+ * EVENTLOG_SEQUENTIAL_READ.
+ *
+ * EVENTLOG_SEQUENTIAL_READ
+ * The read operation proceeds sequentially from the last call to the
+ * ReadEventLog function using this handle. This flag cannot be used
+ * with EVENTLOG_SEEK_READ.
+ *
+ * If the buffer is large enough, more than one record can be read at
+ * the specified seek position; you must specify one of the following
+ * flags to indicate the direction for successive read operations.
+ *
+ * EVENTLOG_FORWARDS_READ
+ * The log is read in chronological order. This flag cannot be used
+ * with EVENTLOG_BACKWARDS_READ.
+ *
+ * EVENTLOG_BACKWARDS_READ
+ * The log is read in reverse chronological order. This flag cannot be
+ * used with EVENTLOG_FORWARDS_READ.
+ */
+#define EVENTLOG_SEQUENTIAL_READ 0x0001
+#define EVENTLOG_SEEK_READ 0x0002
+#define EVENTLOG_FORWARDS_READ 0x0004
+#define EVENTLOG_BACKWARDS_READ 0x0008
+
+/*
+ * The types of events that can be logged.
+ */
+#define EVENTLOG_SUCCESS 0x0000
+#define EVENTLOG_ERROR_TYPE 0x0001
+#define EVENTLOG_WARNING_TYPE 0x0002
+#define EVENTLOG_INFORMATION_TYPE 0x0004
+#define EVENTLOG_AUDIT_SUCCESS 0x0008
+#define EVENTLOG_AUDIT_FAILURE 0x0010
+
+/*
+ * Event Identifiers
+ *
+ * Event identifiers uniquely identify a particular event. Each event
+ * source can define its own numbered events and the description strings
+ * to which they are mapped. Event viewers can present these strings to
+ * the user. They should help the user understand what went wrong and
+ * suggest what actions to take. Direct the description at users solving
+ * their own problems, not at administrators or support technicians.
+ * Make the description clear and concise and avoid culture-specific
+ * phrases.
+ *
+ * The following diagram illustrates the format of an event identifier.
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---+-+-+-----------------------+-------------------------------+
+ * |Sev|C|R| Facility | Code |
+ * +---+-+-+-----------------------+-------------------------------+
+ *
+ * Sev
+ * Indicates the severity. This is one of the following values:
+ * 00 - Success
+ * 01 - Informational
+ * 10 - Warning
+ * 11 - Error
+ *
+ * C
+ * Indicates a customer code (1) or a system code (0).
+ * R
+ * Reserved bit.
+ * Facility
+ * Facility code.
+ * Code
+ * Status code for the facility.
+ */
+#define EVENTID_SEVERITY_SUCCESS 0x00000000
+#define EVENTID_SEVERITY_INFO 0x40000000
+#define EVENTID_SEVERITY_WARNING 0x80000000
+#define EVENTID_SEVERITY_ERROR 0xC0000000
+
+#define EVENTID_SYSTEM_CODE 0x00000000
+#define EVENTID_CUSTOMER_CODE 0x20000000
+
+#define MAX_SRCNAME_LEN 20
+#define LOGR_KEY "LogrOpen"
+
+
+static int logr_s_EventLogClose(void *, struct mlrpc_xaction *);
+static int logr_s_EventLogQueryCount(void *, struct mlrpc_xaction *);
+static int logr_s_EventLogGetOldestRec(void *, struct mlrpc_xaction *);
+static int logr_s_EventLogOpen(void *, struct mlrpc_xaction *);
+static int logr_s_EventLogRead(void *, struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t logr_stub_table[] = {
+ { logr_s_EventLogClose, LOGR_OPNUM_EventLogClose },
+ { logr_s_EventLogQueryCount, LOGR_OPNUM_EventLogQueryCount },
+ { logr_s_EventLogGetOldestRec, LOGR_OPNUM_EventLogGetOldestRec },
+ { logr_s_EventLogOpen, LOGR_OPNUM_EventLogOpen },
+ { logr_s_EventLogRead, LOGR_OPNUM_EventLogRead },
+ {0}
+};
+
+static mlrpc_service_t logr_service = {
+ "LOGR", /* name */
+ "Event Log Service", /* desc */
+ "\\eventlog", /* endpoint */
+ PIPE_NTSVCS, /* sec_addr_port */
+ "82273fdc-e32a-18c3-3f78827929dc23ea", 0, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(logr_interface), /* interface ti */
+ logr_stub_table /* stub_table */
+};
+
+typedef struct {
+ DWORD tot_recnum;
+ DWORD last_sentrec;
+ char first_read;
+ struct log_info log;
+} read_data_t;
+
+static char logr_sysname[SYS_NMLN];
+static char hostname[MAXHOSTNAMELEN];
+static mts_wchar_t wcs_hostname[MAXHOSTNAMELEN];
+static int hostname_len = 0;
+static mts_wchar_t wcs_srcname[MAX_SRCNAME_LEN];
+static int srcname_len = 0;
+static int str_offs, sh_len;
+
+/*
+ * logr_initialize
+ *
+ * This function registers the LOGR RPC interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+logr_initialize(void)
+{
+ struct utsname name;
+ char *sysname;
+
+ if (uname(&name) < 0)
+ sysname = "Solaris";
+ else
+ sysname = name.sysname;
+
+ (void) strlcpy(logr_sysname, sysname, SYS_NMLN);
+ (void) mlrpc_register_service(&logr_service);
+}
+
+/*
+ * logr_s_EventLogClose
+ *
+ * This is a request to close the LOGR interface specified by the
+ * handle. Free the handle and its associated resources and zero out
+ * the result handle for the client.
+ */
+/*ARGSUSED*/
+static int
+logr_s_EventLogClose(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct logr_EventLogClose *param = arg;
+ ms_handle_desc_t *desc;
+ read_data_t *data;
+
+ if ((desc = mlsvc_lookup_handle((ms_handle_t *)&param->handle)) == 0) {
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+ return (MLRPC_DRC_OK);
+ }
+
+ data = (read_data_t *)(desc->discrim);
+ free(data);
+ (void) mlsvc_put_handle((ms_handle_t *)&param->handle);
+
+ bzero(&param->result_handle, sizeof (logr_handle_t));
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * logr_s_EventLogOpen
+ *
+ * This is a request to open the event log.
+ *
+ * Return a handle for use with subsequent event log requests.
+ */
+/*ARGSUSED*/
+static int
+logr_s_EventLogOpen(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct logr_EventLogOpen *param = arg;
+ ms_handle_t *handle;
+ int log_enable = 0;
+
+ smb_config_rdlock();
+ log_enable = smb_config_getyorn(SMB_CI_LOGR_ENABLE);
+ smb_config_unlock();
+
+ if (log_enable == 0) {
+ bzero(&param->handle, sizeof (logr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+ }
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_LOGR, LOGR_KEY, 0);
+ bcopy(handle, &param->handle, sizeof (logr_handle_t));
+
+ if (hostname_len == 0) {
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) {
+ bzero(&param->handle, sizeof (logr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+ }
+
+ hostname_len = (strlen(hostname) + 1) * 2;
+ (void) mts_mbstowcs(wcs_hostname, hostname, hostname_len / 2);
+ srcname_len = (strlen(logr_sysname) + 1) * 2;
+ (void) mts_mbstowcs(wcs_srcname, logr_sysname, srcname_len / 2);
+ sh_len = srcname_len + hostname_len;
+ str_offs = 12 * sizeof (DWORD) + 4 * sizeof (WORD) + sh_len;
+ }
+
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * logr_get_snapshot
+ *
+ * Allocate memory and make a copy, as a snapshot, from system log.
+ */
+static read_data_t *
+logr_get_snapshot(void)
+{
+ read_data_t *data = NULL;
+ return (data);
+}
+
+/*
+ * logr_s_EventLogQueryCount
+ *
+ * take a snapshot from system log, assign it to the given handle.
+ * return number of log entries in the snapshot as result of RPC
+ * call.
+ */
+/*ARGSUSED*/
+static int
+logr_s_EventLogQueryCount(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct logr_EventLogQueryCount *param = arg;
+ ms_handle_desc_t *desc;
+ read_data_t *data;
+
+ if ((desc = mlsvc_lookup_handle((ms_handle_t *)&param->handle)) == 0) {
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+ return (MLRPC_DRC_OK);
+ }
+
+ if ((data = logr_get_snapshot()) == NULL) {
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ desc->discrim = (DWORD)data;
+ param->rec_num = data->tot_recnum;
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * logr_s_EventLogGetOldestRec
+ *
+ * Return oldest record number in the snapshot as result of RPC call.
+ */
+/*ARGSUSED*/
+static int
+logr_s_EventLogGetOldestRec(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct logr_EventLogGetOldestRec *param = arg;
+ ms_handle_desc_t *desc;
+ read_data_t *data;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->handle);
+ if (desc == NULL) {
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+ return (MLRPC_DRC_OK);
+ }
+
+ data = (read_data_t *)desc->discrim;
+ param->oldest_rec = data->log.ix - data->tot_recnum;
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * set_event_typeid
+ *
+ * Map the local system log priority to the event type and event ID
+ * for Windows events.
+ */
+void
+set_event_typeid(int le_pri, WORD *etype, DWORD *eid)
+{
+ switch (LOG_PRI(le_pri)) {
+ case LOG_EMERG:
+ case LOG_ALERT:
+ case LOG_CRIT:
+ case LOG_ERR:
+ *eid = EVENTID_SEVERITY_ERROR;
+ *etype = EVENTLOG_ERROR_TYPE;
+ break;
+ case LOG_WARNING:
+ *eid = EVENTID_SEVERITY_WARNING;
+ *etype = EVENTLOG_WARNING_TYPE;
+ break;
+ case LOG_NOTICE:
+ case LOG_INFO:
+ case LOG_DEBUG:
+ *eid = EVENTID_SEVERITY_INFO;
+ *etype = EVENTLOG_INFORMATION_TYPE;
+ break;
+ default:
+ *eid = EVENTID_SEVERITY_SUCCESS;
+ *etype = EVENTLOG_SUCCESS;
+ }
+}
+
+static log_entry_t *
+log_get_entry(struct log_info *linfo, int entno)
+{
+ return (&linfo->entry[entno]);
+}
+
+/*
+ * Fill a Windows event record based on a local system log record.
+ */
+static void
+set_logrec(log_entry_t *le, DWORD recno, logr_record_t *rec)
+{
+ int len;
+
+ rec->Length1 = sizeof (logr_record_t);
+ rec->Reserved = 0x654C664C;
+ rec->RecordNumber = recno;
+ rec->TimeGenerated = le->timestamp.tv_sec;
+ rec->TimeWritten = le->timestamp.tv_sec;
+ set_event_typeid(le->pri, &rec->EventType, &rec->EventID);
+ rec->NumStrings = 1;
+ rec->EventCategory = 0;
+ rec->ReservedFlags = 0;
+ rec->ClosingRecordNumber = 0;
+ rec->StringOffset = str_offs;
+ rec->UserSidLength = 0;
+ rec->UserSidOffset = sizeof (logr_record_t) - sizeof (DWORD);
+ rec->DataLength = 0;
+ rec->DataOffset = sizeof (logr_record_t) - sizeof (DWORD);
+ bzero(rec->info, LOGR_INFOLEN);
+ (void) memcpy(rec->info, wcs_srcname, srcname_len);
+ (void) memcpy(rec->info + srcname_len, wcs_hostname, hostname_len);
+
+ len = (LOGR_INFOLEN - sh_len) / 2;
+
+ if ((strlen(le->msg) + 1) < len)
+ len = strlen(le->msg) + 1;
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ (void) mts_mbstowcs((mts_wchar_t *)(rec->info+sh_len), le->msg, len);
+ rec->Length2 = sizeof (logr_record_t);
+}
+
+/*
+ * logr_s_EventLogRead
+ *
+ * Reads a whole number of entries from system log. The function can
+ * read log entries in chronological or reverse chronological order.
+ */
+/*ARGSUSED*/
+static int
+logr_s_EventLogRead(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct logr_EventLogRead *param = arg;
+ ms_handle_desc_t *desc;
+ read_data_t *rdata;
+ log_entry_t *le;
+ DWORD ent_no, ent_num, ent_remain;
+ logr_record_t *rec;
+ BYTE *buf;
+ int dir, ent_per_req;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->handle);
+ if (desc == NULL) {
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+ return (MLRPC_DRC_OK);
+ }
+
+ rdata = (read_data_t *)(desc->discrim);
+ if (rdata == 0) {
+ if ((rdata = logr_get_snapshot()) == NULL) {
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ desc->discrim = (DWORD)rdata;
+ }
+
+ dir = (param->read_flags & EVENTLOG_FORWARDS_READ) ? FWD : REW;
+
+ if (param->read_flags & EVENTLOG_SEEK_READ) {
+ rdata->last_sentrec = param->rec_offset;
+ } else if (rdata->first_read) {
+ /*
+ * set last record number which is read for
+ * the first iteration of sequential read.
+ */
+ rdata->last_sentrec = (dir == FWD)
+ ? (rdata->log.ix - rdata->tot_recnum) : rdata->log.ix;
+ }
+
+ ent_remain = (dir == FWD)
+ ? (rdata->tot_recnum - rdata->last_sentrec) : rdata->last_sentrec;
+
+ /*
+ * function should return as many whole log entries as
+ * will fit in the buffer; it should not return partial
+ * entries, even if there is room in the buffer.
+ */
+ ent_per_req = param->nbytes_to_read / sizeof (logr_record_t);
+ if (ent_remain > ent_per_req)
+ ent_remain = ent_per_req;
+
+ if (ent_remain == 0) {
+ /*
+ * Send this error to Windows client so that it
+ * can figure out that there is no more record
+ * to read.
+ */
+ param->sent_size = 0;
+ param->unknown = 0;
+ param->status = NT_SC_ERROR(NT_STATUS_END_OF_FILE);
+ return (MLRPC_DRC_OK);
+ }
+
+ buf = (param->read_flags & EVENTLOG_SEEK_READ)
+ ? param->ru.rec : param->ru.recs;
+
+ for (ent_num = 0, ent_no = rdata->last_sentrec;
+ ent_num < ent_remain; ent_num++, ent_no += dir) {
+ le = log_get_entry(&rdata->log, ent_no & NMSGMASK);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ rec = (logr_record_t *)buf;
+ set_logrec(le, ent_no, rec);
+ buf += sizeof (logr_record_t);
+ }
+ rdata->last_sentrec = ent_no;
+ rdata->first_read = 0;
+
+ param->sent_size = sizeof (logr_record_t) * ent_remain;
+ param->unknown = 0;
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Declare extern references.
+ */
+DECL_FIXUP_STRUCT(logr_read_u);
+DECL_FIXUP_STRUCT(logr_read_info);
+DECL_FIXUP_STRUCT(logr_EventLogRead);
+
+/*
+ * Patch the logr_EventLogRead union.
+ * This function is called from mlsvc_logr_ndr.c
+ */
+void
+fixup_logr_EventLogRead(void *xarg)
+{
+ struct logr_EventLogRead *arg = (struct logr_EventLogRead *)xarg;
+ unsigned short size1 = 0;
+ unsigned short size2 = 0;
+ unsigned short size3 = 0;
+ DWORD nbr = arg->nbytes_to_read;
+
+ switch (nbr) {
+ case 0:
+ size1 = 0;
+ break;
+ default:
+ size1 = nbr;
+ break;
+ };
+
+ size2 = size1 + (2 * sizeof (DWORD));
+ size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD);
+
+ FIXUP_PDU_SIZE(logr_read_u, size1);
+ FIXUP_PDU_SIZE(logr_read_info, size2);
+ FIXUP_PDU_SIZE(logr_EventLogRead, size3);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c
new file mode 100644
index 0000000000..6aa4d716fe
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c
@@ -0,0 +1,1385 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * Local Security Authority RPC (LSARPC) server-side interface definition.
+ */
+
+#include <unistd.h>
+#include <strings.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/lsarpc.ndl>
+#include <smbsrv/lsalib.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/ntlocale.h>
+
+struct local_group_table {
+ WORD sid_name_use;
+ WORD domain_ix;
+ char *sid;
+ char *name;
+};
+
+static int lsarpc_s_CloseHandle(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_QuerySecurityObject(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_EnumAccounts(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_EnumTrustedDomain(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_OpenAccount(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_EnumPrivsAccount(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_LookupPrivValue(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_LookupPrivName(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_LookupPrivDisplayName(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_QueryInfoPolicy(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_OpenDomainHandle(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_OpenDomainHandle(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_LookupSids(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_LookupNames(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_GetConnectedUser(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_LookupSids2(void *arg, struct mlrpc_xaction *);
+static int lsarpc_s_LookupNames2(void *arg, struct mlrpc_xaction *);
+
+static int lsarpc_s_PrimaryDomainInfo(struct mslsa_PrimaryDomainInfo *,
+ struct mlrpc_xaction *);
+static int lsarpc_s_AccountDomainInfo(struct mslsa_AccountDomainInfo *,
+ struct mlrpc_xaction *);
+static int lsarpc_s_LookupNtSid(struct mlrpc_xaction *, nt_sid_t *,
+ smb_userinfo_t *, struct mslsa_name_entry *, int);
+static int lsarpc_s_LookupLocalSid(struct mlrpc_xaction *, nt_sid_t *,
+ smb_userinfo_t *, struct mslsa_name_entry *);
+static int lsarpc_s_LookupBuiltinSid(struct mlrpc_xaction *, nt_sid_t *,
+ smb_userinfo_t *, struct mslsa_name_entry *);
+static int lsarpc_s_UnknownSid(struct mlrpc_xaction *, nt_sid_t *,
+ smb_userinfo_t *, struct mslsa_name_entry *);
+static int lsarpc_s_UpdateDomainTable(struct mlrpc_xaction *,
+ smb_userinfo_t *, struct mslsa_domain_table *, DWORD *);
+
+static int lsarpc_w2k_enable;
+
+static mlrpc_stub_table_t lsarpc_stub_table[] = {
+ { lsarpc_s_CloseHandle, LSARPC_OPNUM_CloseHandle },
+ { lsarpc_s_QuerySecurityObject, LSARPC_OPNUM_QuerySecurityObject },
+ { lsarpc_s_EnumAccounts, LSARPC_OPNUM_EnumerateAccounts },
+ { lsarpc_s_EnumTrustedDomain, LSARPC_OPNUM_EnumTrustedDomain },
+ { lsarpc_s_OpenAccount, LSARPC_OPNUM_OpenAccount },
+ { lsarpc_s_EnumPrivsAccount, LSARPC_OPNUM_EnumPrivsAccount },
+ { lsarpc_s_LookupPrivValue, LSARPC_OPNUM_LookupPrivValue },
+ { lsarpc_s_LookupPrivName, LSARPC_OPNUM_LookupPrivName },
+ { lsarpc_s_LookupPrivDisplayName, LSARPC_OPNUM_LookupPrivDisplayName },
+ { lsarpc_s_QueryInfoPolicy, LSARPC_OPNUM_QueryInfoPolicy },
+ { lsarpc_s_OpenDomainHandle, LSARPC_OPNUM_OpenPolicy },
+ { lsarpc_s_OpenDomainHandle, LSARPC_OPNUM_OpenPolicy2 },
+ { lsarpc_s_LookupSids, LSARPC_OPNUM_LookupSids },
+ { lsarpc_s_LookupNames, LSARPC_OPNUM_LookupNames },
+ { lsarpc_s_GetConnectedUser, LSARPC_OPNUM_GetConnectedUser },
+ { lsarpc_s_LookupSids2, LSARPC_OPNUM_LookupSids2 },
+ { lsarpc_s_LookupNames2, LSARPC_OPNUM_LookupNames2 },
+ {0}
+};
+
+static mlrpc_service_t lsarpc_service = {
+ "LSARPC", /* name */
+ "Local Security Authority", /* desc */
+ "\\lsarpc", /* endpoint */
+ PIPE_LSASS, /* sec_addr_port */
+ "12345778-1234-abcd-ef000123456789ab", 0, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(lsarpc_interface), /* interface ti */
+ lsarpc_stub_table /* stub_table */
+};
+
+/*
+ * Windows 2000 interface.
+ */
+static mlrpc_service_t lsarpc_w2k_service = {
+ "LSARPC_W2K", /* name */
+ "Local Security Authority", /* desc */
+ "\\lsarpc", /* endpoint */
+ PIPE_LSASS, /* sec_addr_port */
+ "3919286a-b10c-11d0-9ba800c04fd92ef5", 0, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(lsarpc_interface), /* interface ti */
+ lsarpc_stub_table /* stub_table */
+};
+
+/*
+ * lsarpc_initialize
+ *
+ * This function registers the LSA RPC interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+lsarpc_initialize(void)
+{
+ (void) mlrpc_register_service(&lsarpc_service);
+
+ if (lsarpc_w2k_enable)
+ (void) mlrpc_register_service(&lsarpc_w2k_service);
+}
+
+/*
+ * lsarpc_s_OpenDomainHandle opnum=0x06
+ *
+ * This is a request to open the LSA (OpenPolicy and OpenPolicy2).
+ * The client is looking for an LSA domain handle. Handles appear to
+ * be a 20 byte opaque object with the top 4 bytes all zero. As it is
+ * opaque to the client, we can put anything we like in it. Real handles
+ * do appear to contain a sequence number which is incremented when a
+ * new handle is issued. However, we don't really care about that
+ * (yet). Always return MLRPC_DRC_OK.
+ */
+/*ARGSUSED*/
+static int
+lsarpc_s_OpenDomainHandle(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_OpenPolicy2 *param = arg;
+
+ bzero(&param->domain_handle, sizeof (mslsa_handle_t));
+ (void) strcpy((char *)&param->domain_handle.hand2, "DomainHandle");
+ param->status = 0;
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_CloseHandle opnum=0x00
+ *
+ * This is a request to close the LSA interface specified by the handle.
+ * We don't track handles (yet), so just zero out the handle and return
+ * MLRPC_DRC_OK. Setting the handle to zero appears to be standard
+ * behaviour and someone may rely on it, i.e. we do on the client side.
+ */
+/*ARGSUSED*/
+static int
+lsarpc_s_CloseHandle(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_CloseHandle *param = arg;
+
+ bzero(&param->result_handle, sizeof (param->result_handle));
+ param->status = 0;
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_QuerySecurityObject
+ */
+/*ARGSUSED*/
+static int
+lsarpc_s_QuerySecurityObject(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_QuerySecurityObject *param = arg;
+
+ bzero(param, sizeof (struct mslsa_QuerySecurityObject));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_EnumAccounts
+ *
+ * Enumerate the list of local accounts SIDs. The client should supply
+ * a valid OpenPolicy2 handle. The enum_context is used to support
+ * multiple enumeration calls to obtain the complete list of SIDs.
+ * It should be set to 0 on the first call and passed unchanged on
+ * subsequent calls until there are no more accounts - the server will
+ * return NT_SC_WARNING(MLSVC_NO_MORE_DATA).
+ *
+ * For now just set the status to access-denied. Note that we still have
+ * to provide a valid address for enum_buf because it's a reference and
+ * the marshalling rules require that references must not be null.
+ * The enum_context is used to support multiple
+ */
+static int
+lsarpc_s_EnumAccounts(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_EnumerateAccounts *param = arg;
+ struct mslsa_EnumAccountBuf *enum_buf;
+
+ bzero(param, sizeof (struct mslsa_EnumerateAccounts));
+
+ enum_buf = MLRPC_HEAP_NEW(mxa, struct mslsa_EnumAccountBuf);
+ if (enum_buf == NULL) {
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(enum_buf, sizeof (struct mslsa_EnumAccountBuf));
+ param->enum_buf = enum_buf;
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * lsarpc_s_EnumTrustedDomain
+ *
+ * This is the server side function for handling requests to enumerate
+ * the list of trusted domains: currently held in the NT domain database.
+ * This call requires an OpenPolicy2 handle. The enum_context is used to
+ * support multiple enumeration calls to obtain the complete list.
+ * It should be set to 0 on the first call and passed unchanged on
+ * subsequent calls until there are no more accounts - the server will
+ * return NT_SC_WARNING(MLSVC_NO_MORE_DATA).
+ *
+ * For now just set the status to access-denied. Note that we still have
+ * to provide a valid address for enum_buf because it's a reference and
+ * the marshalling rules require that references must not be null.
+ */
+static int
+lsarpc_s_EnumTrustedDomain(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_EnumTrustedDomain *param = arg;
+ struct mslsa_EnumTrustedDomainBuf *enum_buf;
+
+ bzero(param, sizeof (struct mslsa_EnumTrustedDomain));
+
+ enum_buf = MLRPC_HEAP_NEW(mxa, struct mslsa_EnumTrustedDomainBuf);
+ if (enum_buf == NULL) {
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(enum_buf, sizeof (struct mslsa_EnumTrustedDomainBuf));
+ param->enum_buf = enum_buf;
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * lsarpc_s_OpenAccount
+ *
+ * This is a request to open an account handle. This function hasn't
+ * been tested. It is just a template in case some server somewhere
+ * makes this call. See lsarpc_s_OpenDomainHandle for more information.
+ */
+/*ARGSUSED*/
+static int
+lsarpc_s_OpenAccount(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_OpenAccount *param = arg;
+
+ if (param->handle.hand1 != 0 ||
+ strcmp("DomainHandle", (char *)&param->handle.hand2)) {
+ param->status = NT_SC_ERROR(ERROR_NO_SUCH_DOMAIN);
+ } else {
+ (void) strcpy((char *)&param->account_handle.hand2,
+ "AccountHandle");
+ param->status = 0;
+ }
+
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * lsarpc_s_EnumPrivsAccount
+ *
+ * This is the server side function for handling requests for account
+ * privileges. For now just set the status to not-supported status and
+ * return MLRPC_DRC_OK. Note that we still have to provide a valid
+ * address for enum_buf because it's a reference and the marshalling
+ * rules require that references must not be null.
+ */
+/*ARGSUSED*/
+static int
+lsarpc_s_EnumPrivsAccount(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_EnumPrivsAccount *param = arg;
+
+ bzero(param, sizeof (struct mslsa_EnumPrivsAccount));
+ param->status = NT_SC_ERROR(NT_STATUS_NOT_SUPPORTED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_LookupPrivValue
+ *
+ * Server side function used to map a privilege name to a locally unique
+ * identifier (LUID).
+ */
+/*ARGSUSED*/
+static int
+lsarpc_s_LookupPrivValue(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_LookupPrivValue *param = arg;
+ smb_privinfo_t *pi;
+
+ if ((pi = smb_priv_getbyname((char *)param->name.str)) == NULL) {
+ bzero(param, sizeof (struct mslsa_LookupPrivValue));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_PRIVILEGE);
+ return (MLRPC_DRC_OK);
+ }
+
+ param->luid.low_part = pi->id;
+ param->luid.high_part = 0;
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_LookupPrivName
+ *
+ * Server side function used to map a locally unique identifier (LUID)
+ * to the appropriate privilege name string.
+ */
+static int
+lsarpc_s_LookupPrivName(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_LookupPrivName *param = arg;
+ smb_privinfo_t *pi;
+ int rc;
+
+ if ((pi = smb_priv_getbyvalue(param->luid.low_part)) == NULL) {
+ bzero(param, sizeof (struct mslsa_LookupPrivName));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_PRIVILEGE);
+ return (MLRPC_DRC_OK);
+ }
+
+ param->name = MLRPC_HEAP_NEW(mxa, mslsa_string_t);
+ if (param->name == NULL) {
+ bzero(param, sizeof (struct mslsa_LookupPrivName));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ rc = mlsvc_string_save((ms_string_t *)param->name, pi->name, mxa);
+ if (rc == 0) {
+ bzero(param, sizeof (struct mslsa_LookupPrivName));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_LookupPrivDisplayName
+ *
+ * This is the server side function for handling requests for account
+ * privileges. For now just set the status to not-supported status and
+ * return MLRPC_DRC_OK.
+ */
+static int
+lsarpc_s_LookupPrivDisplayName(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_LookupPrivDisplayName *param = arg;
+ smb_privinfo_t *pi;
+ int rc;
+
+ if ((pi = smb_priv_getbyname((char *)param->name.str)) == NULL) {
+ bzero(param, sizeof (struct mslsa_LookupPrivDisplayName));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_PRIVILEGE);
+ return (MLRPC_DRC_OK);
+ }
+
+ param->display_name = MLRPC_HEAP_NEW(mxa, mslsa_string_t);
+ if (param->display_name == NULL) {
+ bzero(param, sizeof (struct mslsa_LookupPrivDisplayName));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ rc = mlsvc_string_save((ms_string_t *)param->display_name,
+ pi->display_name, mxa);
+
+ if (rc == 0) {
+ bzero(param, sizeof (struct mslsa_LookupPrivDisplayName));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ param->language_ret = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_GetConnectedUser
+ *
+ * This is still guesswork. Netmon doesn't know about this
+ * call and I'm not really sure what it is intended to achieve.
+ * Another packet capture application, Ethereal, calls this RPC as
+ * GetConnectedUser.
+ * We will receive our own hostname in the request and it appears
+ * we should respond with an account name and the domain name of connected
+ * user from the client that makes this call.
+ */
+static int
+lsarpc_s_GetConnectedUser(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_GetConnectedUser *param = arg;
+ smb_dr_user_ctx_t *user_ctx = mxa->context->user_ctx;
+ DWORD status = NT_STATUS_SUCCESS;
+ int rc1;
+ int rc2;
+
+ if (user_ctx == NULL) {
+ bzero(param, sizeof (struct mslsa_GetConnectedUser));
+ status = NT_SC_ERROR(NT_STATUS_NO_TOKEN);
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (smb_getdomaininfo(0) == NULL) {
+ bzero(param, sizeof (struct mslsa_GetConnectedUser));
+ status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->owner = MLRPC_HEAP_NEW(mxa, struct mslsa_string_desc);
+ param->domain = MLRPC_HEAP_NEW(mxa, struct mslsa_DomainName);
+ if (param->owner == NULL || param->domain == NULL) {
+ status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->domain->name = MLRPC_HEAP_NEW(mxa, struct mslsa_string_desc);
+ if (param->domain->name == NULL) {
+ status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ rc1 = mlsvc_string_save((ms_string_t *)param->owner,
+ user_ctx->du_account, mxa);
+
+ rc2 = mlsvc_string_save((ms_string_t *)param->domain->name,
+ user_ctx->du_domain, mxa);
+
+ if (rc1 == 0 || rc2 == 0)
+ status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * lsarpc_s_QueryInfoPolicy
+ *
+ * This is the server side function for handling LSA information policy
+ * queries. Currently, we only support primary domain and account
+ * domain queries. This is just a front end to switch on the request
+ * and hand it off to the appropriate function to actually deal with
+ * obtaining and building the response.
+ */
+static int
+lsarpc_s_QueryInfoPolicy(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_QueryInfoPolicy *param = arg;
+ struct mslsa_PolicyInfo *info;
+ int result;
+
+ info = (struct mslsa_PolicyInfo *)MLRPC_HEAP_MALLOC(
+ mxa, sizeof (struct mslsa_PolicyInfo));
+
+ info->switch_value = param->info_class;
+
+ switch (param->info_class) {
+ case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
+ result = lsarpc_s_PrimaryDomainInfo(&info->ru.pd_info, mxa);
+ break;
+
+ case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
+ result = lsarpc_s_AccountDomainInfo(&info->ru.ad_info, mxa);
+ break;
+
+ default:
+ result = (MLRPC_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
+ break;
+ }
+
+ param->info = info;
+ param->status = NT_STATUS_SUCCESS;
+ return (result);
+}
+
+
+/*
+ * lsarpc_s_PrimaryDomainInfo
+ *
+ * This is the service side function for handling primary domain policy
+ * queries. This will return the primary domain name and sid. This is
+ * currently a pass through interface so all we do is act as a proxy
+ * between the client and the DC. If there is no session, fake up the
+ * response with default values - useful for share mode.
+ *
+ * If the server name matches the local hostname, we should return
+ * the local domain SID.
+ */
+static int
+lsarpc_s_PrimaryDomainInfo(struct mslsa_PrimaryDomainInfo *pd_info,
+ struct mlrpc_xaction *mxa)
+{
+ int security_mode;
+ smb_ntdomain_t *di;
+ nt_domain_t *ntdp;
+ nt_sid_t *sid;
+ char domain_name[MLSVC_DOMAIN_NAME_MAX];
+ char *name;
+ DWORD status;
+ int rc;
+
+ status = NT_STATUS_SUCCESS;
+
+ security_mode = smb_get_security_mode();
+
+ if (security_mode != SMB_SECMODE_DOMAIN) {
+ rc = smb_gethostname(domain_name, MLSVC_DOMAIN_NAME_MAX, 1);
+ if (rc != 0) {
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+ }
+
+ name = domain_name;
+ sid = nt_sid_dup(nt_domain_local_sid());
+ } else {
+ if ((di = smb_getdomaininfo(0)) == 0) {
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+ }
+
+ ntdp = nt_domain_lookup_name(di->domain);
+ if (ntdp == 0) {
+ (void) lsa_query_primary_domain_info();
+ ntdp = nt_domain_lookup_name(di->domain);
+ }
+
+ if (ntdp == 0) {
+ sid = nt_sid_gen_null_sid();
+ name = di->domain;
+ } else {
+ sid = nt_sid_dup(ntdp->sid);
+ name = ntdp->name;
+ }
+ }
+
+ if (sid == 0) {
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+ }
+
+ if (mlsvc_string_save((ms_string_t *)&pd_info->name, name, mxa) == 0)
+ status = NT_STATUS_INSUFFICIENT_RESOURCES;
+
+ if ((pd_info->sid = (struct mslsa_sid *)mlsvc_sid_save(sid, mxa)) == 0)
+ status = NT_STATUS_INSUFFICIENT_RESOURCES;
+
+ free(sid);
+
+ if (status != NT_STATUS_SUCCESS)
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * lsarpc_s_AccountDomainInfo
+ *
+ * This is the service side function for handling account domain policy
+ * queries. This is where we return our local domain information so that
+ * NT knows who to query for information on local names and SIDs. The
+ * domain name is the local hostname.
+ */
+static int
+lsarpc_s_AccountDomainInfo(struct mslsa_AccountDomainInfo *ad_info,
+ struct mlrpc_xaction *mxa)
+{
+ char domain_name[MLSVC_DOMAIN_NAME_MAX];
+ nt_sid_t *domain_sid;
+ int rc;
+
+ if (smb_gethostname(domain_name, MLSVC_DOMAIN_NAME_MAX, 1) != 0)
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+
+ if ((domain_sid = nt_domain_local_sid()) == NULL)
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+
+ rc = mlsvc_string_save((ms_string_t *)&ad_info->name,
+ domain_name, mxa);
+ if (rc == 0)
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+
+ ad_info->sid = (struct mslsa_sid *)mlsvc_sid_save(domain_sid, mxa);
+ if (ad_info->sid == NULL)
+ return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_LookupNames
+ *
+ * This is the service side function for handling name lookup requests.
+ * Currently, we only support lookups of a single name. This is also a
+ * pass through interface so all we do is act as a proxy between the
+ * client and the DC.
+ */
+static int
+lsarpc_s_LookupNames(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_LookupNames *param = arg;
+ struct mslsa_rid_entry *rids;
+ smb_userinfo_t *user_info = 0;
+ struct mslsa_domain_table *domain_table;
+ struct mslsa_domain_entry *domain_entry;
+ char *name = "";
+ DWORD status = NT_STATUS_SUCCESS;
+ int rc = 0;
+
+ if (param->name_table->n_entry != 1)
+ return (MLRPC_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
+
+ rids = MLRPC_HEAP_NEW(mxa, struct mslsa_rid_entry);
+ domain_table = MLRPC_HEAP_NEW(mxa, struct mslsa_domain_table);
+ domain_entry = MLRPC_HEAP_NEW(mxa, struct mslsa_domain_entry);
+ user_info = mlsvc_alloc_user_info();
+
+ if (rids == NULL || domain_table == NULL ||
+ domain_entry == NULL || user_info == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto name_lookup_failed;
+ }
+
+ name = (char *)param->name_table->names->str;
+
+ rc = lsa_lookup_local(name, user_info);
+ if (rc < 0) {
+ status = NT_STATUS_NO_SUCH_USER;
+ goto name_lookup_failed;
+ }
+
+ if (rc > 0) {
+ if (lsa_lookup_name(0, 0, name, user_info) != 0) {
+ status = NT_STATUS_NO_SUCH_USER;
+ goto name_lookup_failed;
+ }
+ }
+
+ /*
+ * Set up the rid table.
+ */
+ rids[0].sid_name_use = user_info->sid_name_use;
+ rids[0].rid = user_info->rid;
+ rids[0].domain_index = 0;
+ param->translated_sids.n_entry = 1;
+ param->translated_sids.rids = rids;
+
+ /*
+ * Set up the domain table.
+ */
+ domain_table->entries = domain_entry;
+ domain_table->n_entry = 1;
+ domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
+
+ rc = mlsvc_string_save((ms_string_t *)&domain_entry->domain_name,
+ user_info->domain_name, mxa);
+
+ domain_entry->domain_sid =
+ (struct mslsa_sid *)mlsvc_sid_save(user_info->domain_sid, mxa);
+
+ if (rc == 0 || domain_entry->domain_sid == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto name_lookup_failed;
+ }
+
+ param->domain_table = domain_table;
+ param->mapped_count = 1;
+ param->status = 0;
+
+ mlsvc_free_user_info(user_info);
+ return (MLRPC_DRC_OK);
+
+name_lookup_failed:
+ mlsvc_free_user_info(user_info);
+ bzero(param, sizeof (struct mslsa_LookupNames));
+ param->status = NT_SC_ERROR(status);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_LookupSids
+ *
+ * This is the service side function for handling sid lookup requests.
+ * We have to set up both the name table and the domain table in the
+ * response. For each SID, we check for UNIX domain (local lookup) or
+ * NT domain (DC lookup) and call the appropriate lookup function. This
+ * should resolve the SID to a name. Then we need to update the domain
+ * table and make the name entry point at the appropriate domain table
+ * entry.
+ *
+ * On success return 0. Otherwise return an RPC specific error code.
+ */
+static int
+lsarpc_s_LookupSids(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslsa_LookupSids *param = arg;
+ struct mslsa_domain_table *domain_table;
+ struct mslsa_domain_entry *domain_entry;
+ struct mslsa_name_entry *names;
+ smb_userinfo_t *user_info;
+ nt_sid_t *sid;
+ DWORD n_entry;
+ int result;
+ int i;
+
+ user_info = mlsvc_alloc_user_info();
+
+ n_entry = param->lup_sid_table.n_entry;
+ names = MLRPC_HEAP_NEWN(mxa, struct mslsa_name_entry, n_entry);
+ domain_table = MLRPC_HEAP_NEW(mxa, struct mslsa_domain_table);
+ domain_entry = MLRPC_HEAP_NEWN(mxa, struct mslsa_domain_entry,
+ MLSVC_DOMAIN_MAX);
+
+ if (names == NULL || domain_table == NULL ||
+ domain_entry == NULL || user_info == NULL) {
+ bzero(param, sizeof (struct mslsa_LookupSids));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ domain_table->entries = domain_entry;
+ domain_table->n_entry = 0;
+ domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
+
+ for (i = 0; i < n_entry; ++i) {
+ bzero(&names[i], sizeof (struct mslsa_name_entry));
+ sid = (nt_sid_t *)param->lup_sid_table.entries[i].psid;
+
+ if (nt_sid_is_local(sid)) {
+ result = lsarpc_s_LookupLocalSid(mxa, sid, user_info,
+ &names[i]);
+ } else {
+ result = lsarpc_s_LookupBuiltinSid(mxa, sid, user_info,
+ &names[i]);
+
+ if (result != 0)
+ result = lsarpc_s_LookupNtSid(mxa, sid,
+ user_info, &names[i], 1);
+
+ if (result != 0) {
+ result = lsarpc_s_UnknownSid(mxa, sid,
+ user_info, &names[i]);
+ }
+ }
+
+ if (result == -1) {
+ mlsvc_free_user_info(user_info);
+ param->domain_table = 0;
+ param->name_table.n_entry = 0;
+ param->name_table.entries = 0;
+ param->mapped_count = 0;
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_SID);
+ return (MLRPC_DRC_OK);
+ }
+
+ result = lsarpc_s_UpdateDomainTable(mxa, user_info,
+ domain_table, &names[i].domain_ix);
+
+ if (result == -1) {
+ mlsvc_free_user_info(user_info);
+ param->domain_table = 0;
+ param->name_table.n_entry = 0;
+ param->name_table.entries = 0;
+ param->mapped_count = 0;
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_SID);
+ return (MLRPC_DRC_OK);
+ }
+
+ mlsvc_release_user_info(user_info);
+ }
+
+ param->domain_table = domain_table;
+ param->name_table.n_entry = n_entry;
+ param->name_table.entries = names;
+ param->mapped_count = n_entry;
+ param->status = 0;
+
+ mlsvc_free_user_info(user_info);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_LookupLocalSid
+ *
+ * This function handles local domain SID lookup. If the SID matches the
+ * local domain SID, we lookup the local files to map the RID to a name.
+ * We attempt to handle both users and groups. When the SID was supplied
+ * to the client, the ID type should have been encoded in the RID. We
+ * decode the RID and lookup it up in either the passwd file or the
+ * group file as appropriate.
+ *
+ * On success, 0 is returned. Otherwise -1 is returned.
+ */
+static int
+lsarpc_s_LookupLocalSid(struct mlrpc_xaction *mxa, nt_sid_t *sid,
+ smb_userinfo_t *user_info, struct mslsa_name_entry *name)
+{
+ char buffer[MLSVC_DOMAIN_NAME_MAX];
+ char namebuf[MLSVC_DOMAIN_NAME_MAX];
+ nt_sid_t *lds;
+ nt_sid_t *tmp_sid;
+ nt_group_t *grp;
+ struct passwd *pw;
+ struct group *gr;
+ DWORD rid;
+ int unix_id;
+
+ if (smb_gethostname(buffer, MLSVC_DOMAIN_NAME_MAX, 1) != 0)
+ return (-1);
+
+ /*
+ * Only free tmp_sid in error paths. If it is assigned to the
+ * user_info, it will be freed later when that structure is
+ * released.
+ */
+ if ((tmp_sid = nt_sid_dup(sid)) == NULL)
+ return (-1);
+
+ rid = 0;
+ lds = nt_domain_local_sid();
+ user_info->sid_name_use = SidTypeInvalid;
+
+ if (nt_sid_is_equal(lds, tmp_sid)) {
+ user_info->sid_name_use = SidTypeDomain;
+ user_info->name = strdup(buffer);
+ } else {
+ (void) nt_sid_split(tmp_sid, &rid);
+
+ switch (SAM_RID_TYPE(rid)) {
+ case SAM_RT_NT_UID:
+ break;
+
+ case SAM_RT_NT_GID:
+ user_info->sid_name_use = SidTypeAlias;
+ grp = nt_groups_lookup_rid(rid);
+ if (grp)
+ user_info->name = strdup(grp->name);
+ else {
+ (void) snprintf(namebuf, sizeof (namebuf),
+ "%d (no name)", rid);
+ user_info->name = strdup(namebuf);
+ }
+ break;
+
+ case SAM_RT_UNIX_UID:
+ /*
+ * It is always possible that the rid will not
+ * correspond to an entry in the local passwd or group
+ * file. In this case we can return the RID with a
+ * message to indicate the problem, which seems better
+ * than returning an invalid SID error.
+ */
+ unix_id = SAM_DECODE_RID(rid);
+ (void) snprintf(namebuf, sizeof (namebuf),
+ "%d (no name)", unix_id);
+ user_info->sid_name_use = SidTypeUser;
+ pw = getpwuid(unix_id);
+ user_info->name = (pw) ?
+ strdup(pw->pw_name) : strdup(namebuf);
+ break;
+
+ case SAM_RT_UNIX_GID:
+ unix_id = SAM_DECODE_RID(rid);
+ (void) snprintf(namebuf, sizeof (namebuf),
+ "%d (no name)", unix_id);
+ user_info->sid_name_use = SidTypeAlias;
+ gr = getgrgid(unix_id);
+ user_info->name = (gr) ?
+ strdup(gr->gr_name) : strdup(namebuf);
+ break;
+ }
+ }
+
+ if (user_info->sid_name_use == SidTypeInvalid) {
+ free(tmp_sid);
+ return (-1);
+ }
+
+ /*
+ * Set up the rest of user_info.
+ * Don't free tmp_sid after this.
+ */
+ user_info->rid = rid;
+ user_info->domain_name = strdup(buffer);
+ user_info->domain_sid = tmp_sid;
+
+ bzero(name, sizeof (struct mslsa_name_entry));
+ name->sid_name_use = user_info->sid_name_use;
+
+ if (!mlsvc_string_save(
+ (ms_string_t *)&name->name, user_info->name, mxa)) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * lsarpc_s_LookupNtSid
+ *
+ * This function handles NT domain SID lookup on the domain controller.
+ * Most of the work is performed by lsa_lookup_sid. We just have to
+ * update the name data for the response. It is assumed that any SID
+ * passed to this function has already been checked and correctly
+ * identified as an NT domain SID. It shouldn't break anything if you
+ * get it wrong, the domain controller will just reject the SID.
+ *
+ * On success, 0 is returned. Otherwise -1 is returned.
+ */
+static int
+lsarpc_s_LookupNtSid(struct mlrpc_xaction *mxa, nt_sid_t *sid,
+ smb_userinfo_t *user_info, struct mslsa_name_entry *name, int version)
+{
+ char *username;
+ DWORD status;
+
+ if (smb_getdomaininfo(0) == 0) {
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ return (-1);
+ }
+
+ if (version == 2)
+ status = lsa_lookup_sid2(sid, user_info);
+ else
+ status = lsa_lookup_sid(sid, user_info);
+
+ if (status != 0)
+ return (-1);
+
+ switch (user_info->sid_name_use) {
+ case SidTypeDomain:
+ if ((username = user_info->domain_name) == 0)
+ user_info->sid_name_use = SidTypeUnknown;
+ break;
+
+ case SidTypeUser:
+ case SidTypeGroup:
+ case SidTypeAlias:
+ case SidTypeDeletedAccount:
+ case SidTypeWellKnownGroup:
+ if ((username = user_info->name) == 0)
+ user_info->sid_name_use = SidTypeUnknown;
+ break;
+
+ default:
+ return (-1);
+ }
+
+ if (username == 0)
+ username = "unknown";
+ bzero(name, sizeof (struct mslsa_name_entry));
+ name->sid_name_use = user_info->sid_name_use;
+
+ if (!mlsvc_string_save((ms_string_t *)&name->name, username, mxa))
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * lsarpc_s_LookupBuiltinSid
+ *
+ * This function handles predefined local groups and aliases in the NT
+ * AUTHORITY or BUILTIN domains, and some other miscellaneous bits. I
+ * don't think NT cares about the domain field of well-known groups or
+ * aliases but it seems sensible to set it up anyway. If we get a match,
+ * set up the name in the response heap.
+ *
+ * On success, 0 is returned. Otherwise non-zero is returned. A non-zero
+ * return value should not be automatically interpreted as an error. The
+ * caller should attempt to resolve the SID through alternative means.
+ */
+static int
+lsarpc_s_LookupBuiltinSid(struct mlrpc_xaction *mxa, nt_sid_t *sid,
+ smb_userinfo_t *user_info, struct mslsa_name_entry *name)
+{
+ char *np;
+ WORD sid_name_use;
+
+ if ((np = nt_builtin_lookup_sid(sid, &sid_name_use)) == NULL)
+ return (1);
+
+ user_info->sid_name_use = sid_name_use;
+ user_info->name = strdup(np);
+ user_info->domain_sid = nt_sid_dup(sid);
+
+ if (user_info->name == NULL || user_info->domain_sid == NULL) {
+ mlsvc_release_user_info(user_info);
+ return (-1);
+ }
+
+ if (sid_name_use != SidTypeDomain && sid->SubAuthCount != 0)
+ user_info->rid = sid->SubAuthority[sid->SubAuthCount - 1];
+ else
+ user_info->rid = 0;
+
+ if ((np = nt_builtin_lookup_domain(user_info->name)) != NULL)
+ user_info->domain_name = strdup(np);
+ else
+ user_info->domain_name = strdup("UNKNOWN");
+
+ if (user_info->domain_name == NULL) {
+ mlsvc_release_user_info(user_info);
+ return (-1);
+ }
+
+ if (sid_name_use == SidTypeAlias &&
+ user_info->domain_sid->SubAuthCount != 0) {
+ --user_info->domain_sid->SubAuthCount;
+ }
+
+ bzero(name, sizeof (struct mslsa_name_entry));
+ name->sid_name_use = sid_name_use;
+
+ if (sid_name_use == SidTypeUnknown) {
+ mlsvc_release_user_info(user_info);
+ return (1);
+ }
+
+ if (!mlsvc_string_save(
+ (ms_string_t *)&name->name, user_info->name, mxa)) {
+ mlsvc_release_user_info(user_info);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * lsarpc_s_UnknownSid
+ *
+ * This function handles unknown SIDs. By the time this is called we
+ * know that this is not a local SID and that the PDC has no idea to
+ * whom this sid refers. It may be a remnant from a time when the
+ * server was in another domain. All we can do is turn into the SID
+ * into a string and return it in place of a user name.
+ *
+ * On success, 0 is returned. Otherwise -1 is returned.
+ */
+static int
+lsarpc_s_UnknownSid(struct mlrpc_xaction *mxa, nt_sid_t *sid,
+ smb_userinfo_t *user_info, struct mslsa_name_entry *name)
+{
+ char domain_name[MLSVC_DOMAIN_NAME_MAX];
+ char *sidbuf;
+
+ if ((sidbuf = nt_sid_format(sid)) == NULL)
+ return (-1);
+
+ if (smb_gethostname(domain_name, MLSVC_DOMAIN_NAME_MAX, 1) != 0)
+ return (-1);
+
+ (void) utf8_strupr(domain_name);
+ mlsvc_release_user_info(user_info);
+ user_info->sid_name_use = SidTypeUnknown;
+ user_info->name = sidbuf;
+ user_info->domain_name = strdup(domain_name);
+ user_info->domain_sid = nt_sid_dup(nt_domain_local_sid());
+
+ bzero(name, sizeof (struct mslsa_name_entry));
+ name->sid_name_use = user_info->sid_name_use;
+
+ if (!mlsvc_string_save(
+ (ms_string_t *)&name->name, user_info->name, mxa)) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * lsarpc_s_UpdateDomainTable
+ *
+ * This routine is responsible for maintaining the domain table which
+ * will be returned from a SID lookup. Whenever a name is added to the
+ * name table, this function should be called with the corresponding
+ * domain name. If the domain information is not already in the table,
+ * it is added. On success return 0; Otherwise -1 is returned.
+ */
+static int
+lsarpc_s_UpdateDomainTable(struct mlrpc_xaction *mxa,
+ smb_userinfo_t *user_info, struct mslsa_domain_table *domain_table,
+ DWORD *domain_idx)
+{
+ struct mslsa_domain_entry *dentry;
+ DWORD n_entry;
+ DWORD i;
+
+ if (user_info->sid_name_use == SidTypeWellKnownGroup ||
+ user_info->sid_name_use == SidTypeUnknown ||
+ user_info->sid_name_use == SidTypeInvalid) {
+ /*
+ * These types don't need to reference an entry in the
+ * domain table. So return -1.
+ */
+ *domain_idx = (DWORD)-1;
+ return (0);
+ }
+
+ if ((dentry = domain_table->entries) == NULL)
+ return (-1);
+
+ if ((n_entry = domain_table->n_entry) >= MLSVC_DOMAIN_MAX)
+ return (-1);
+
+ for (i = 0; i < n_entry; ++i) {
+ if (nt_sid_is_equal((nt_sid_t *)dentry[i].domain_sid,
+ user_info->domain_sid)) {
+ *domain_idx = i;
+ return (0);
+ }
+ }
+
+ if (i == MLSVC_DOMAIN_MAX)
+ return (-1);
+
+ if (!mlsvc_string_save((ms_string_t *)&dentry[i].domain_name,
+ user_info->domain_name, mxa))
+ return (-1);
+
+ dentry[i].domain_sid =
+ (struct mslsa_sid *)mlsvc_sid_save(user_info->domain_sid, mxa);
+
+ if (dentry[i].domain_sid == NULL)
+ return (-1);
+
+ ++domain_table->n_entry;
+ *domain_idx = i;
+ return (0);
+}
+
+/*
+ * lsarpc_s_LookupSids2
+ *
+ * Other than the use of lsar_lookup_sids2 and lsar_name_entry2, this
+ * is identical to lsarpc_s_LookupSids.
+ */
+static int
+lsarpc_s_LookupSids2(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct lsar_lookup_sids2 *param = arg;
+ struct lsar_name_entry2 *names;
+ struct mslsa_domain_table *domain_table;
+ struct mslsa_domain_entry *domain_entry;
+ smb_userinfo_t *user_info;
+ nt_sid_t *sid;
+ DWORD n_entry;
+ int result;
+ int i;
+
+ user_info = mlsvc_alloc_user_info();
+
+ n_entry = param->lup_sid_table.n_entry;
+ names = MLRPC_HEAP_NEWN(mxa, struct lsar_name_entry2, n_entry);
+ domain_table = MLRPC_HEAP_NEW(mxa, struct mslsa_domain_table);
+ domain_entry = MLRPC_HEAP_NEWN(mxa, struct mslsa_domain_entry,
+ MLSVC_DOMAIN_MAX);
+
+ if (names == NULL || domain_table == NULL ||
+ domain_entry == NULL || user_info == NULL) {
+ bzero(param, sizeof (struct lsar_lookup_sids2));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ domain_table->entries = domain_entry;
+ domain_table->n_entry = 0;
+ domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
+
+ for (i = 0; i < n_entry; ++i) {
+ bzero(&names[i], sizeof (struct lsar_name_entry2));
+ sid = (nt_sid_t *)param->lup_sid_table.entries[i].psid;
+
+ if (nt_sid_is_local(sid)) {
+ result = lsarpc_s_LookupLocalSid(mxa, sid, user_info,
+ (struct mslsa_name_entry *)&names[i]);
+ } else {
+ result = lsarpc_s_LookupBuiltinSid(mxa, sid, user_info,
+ (struct mslsa_name_entry *)&names[i]);
+
+ if (result != 0)
+ result = lsarpc_s_LookupNtSid(mxa, sid,
+ user_info,
+ (struct mslsa_name_entry *)&names[i], 2);
+
+ if (result != 0) {
+ result = lsarpc_s_UnknownSid(mxa, sid,
+ user_info,
+ (struct mslsa_name_entry *)&names[i]);
+ }
+ }
+
+ if (result == -1) {
+ mlsvc_free_user_info(user_info);
+ param->domain_table = 0;
+ param->name_table.n_entry = 0;
+ param->name_table.entries = 0;
+ param->mapped_count = 0;
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_SID);
+ return (MLRPC_DRC_OK);
+ }
+
+ result = lsarpc_s_UpdateDomainTable(mxa, user_info,
+ domain_table, &names[i].domain_ix);
+
+ if (result == -1) {
+ mlsvc_free_user_info(user_info);
+ param->domain_table = 0;
+ param->name_table.n_entry = 0;
+ param->name_table.entries = 0;
+ param->mapped_count = 0;
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_SID);
+
+ return (MLRPC_DRC_OK);
+ }
+
+ mlsvc_release_user_info(user_info);
+ }
+
+ param->domain_table = domain_table;
+ param->name_table.n_entry = n_entry;
+ param->name_table.entries = names;
+ param->mapped_count = n_entry;
+ param->status = 0;
+
+ mlsvc_free_user_info(user_info);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * lsarpc_s_LookupNames2
+ *
+ * Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this
+ * is identical to lsarpc_s_LookupNames.
+ */
+static int
+lsarpc_s_LookupNames2(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct lsar_LookupNames2 *param = arg;
+ struct lsar_rid_entry2 *rids;
+ smb_userinfo_t *user_info = 0;
+ struct mslsa_domain_table *domain_table;
+ struct mslsa_domain_entry *domain_entry;
+ char *name = "";
+ DWORD status = NT_STATUS_SUCCESS;
+ int rc = 0;
+
+ if (param->name_table->n_entry != 1)
+ return (MLRPC_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
+
+ rids = MLRPC_HEAP_NEW(mxa, struct lsar_rid_entry2);
+ domain_table = MLRPC_HEAP_NEW(mxa, struct mslsa_domain_table);
+ domain_entry = MLRPC_HEAP_NEW(mxa, struct mslsa_domain_entry);
+ user_info = mlsvc_alloc_user_info();
+
+ if (rids == 0 || domain_table == 0 ||
+ domain_entry == 0 || user_info == 0) {
+ status = NT_STATUS_NO_MEMORY;
+ goto name_lookup2_failed;
+ }
+
+ name = (char *)param->name_table->names->str;
+
+ rc = lsa_lookup_local(name, user_info);
+ if (rc < 0) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto name_lookup2_failed;
+ }
+
+ if (rc > 0) {
+ if (lsa_lookup_name2(0, 0, name, user_info) != 0) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto name_lookup2_failed;
+ }
+ }
+
+ /*
+ * Set up the rid table.
+ */
+ bzero(rids, sizeof (struct lsar_rid_entry2));
+ rids[0].sid_name_use = user_info->sid_name_use;
+ rids[0].rid = user_info->rid;
+ rids[0].domain_index = 0;
+ param->translated_sids.n_entry = 1;
+ param->translated_sids.rids = rids;
+
+ /*
+ * Set up the domain table.
+ */
+ domain_table->entries = domain_entry;
+ domain_table->n_entry = 1;
+ domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
+
+ rc = mlsvc_string_save((ms_string_t *)&domain_entry->domain_name,
+ user_info->domain_name, mxa);
+
+ domain_entry->domain_sid =
+ (struct mslsa_sid *)mlsvc_sid_save(user_info->domain_sid, mxa);
+
+ if (rc == 0 || domain_entry->domain_sid == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto name_lookup2_failed;
+ }
+
+ param->domain_table = domain_table;
+ param->mapped_count = 1;
+ param->status = 0;
+
+ mlsvc_free_user_info(user_info);
+ return (MLRPC_DRC_OK);
+
+name_lookup2_failed:
+ mlsvc_free_user_info(user_info);
+ bzero(param, sizeof (struct lsar_LookupNames2));
+ param->status = NT_SC_ERROR(status);
+ return (MLRPC_DRC_OK);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_netr.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_netr.c
new file mode 100644
index 0000000000..4edfcacd51
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_netr.c
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NetLogon RPC (NETR) interface definition. This module provides
+ * the server side NETR RPC interface and the interface registration
+ * function.
+ */
+
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/netlogon.ndl>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/netrauth.h>
+
+static int netr_s_ServerReqChallenge(void *, struct mlrpc_xaction *);
+static int netr_s_ServerAuthenticate2(void *, struct mlrpc_xaction *);
+static int netr_s_ServerPasswordSet(void *, struct mlrpc_xaction *);
+static int netr_s_SamLogon(void *, struct mlrpc_xaction *);
+static int netr_s_SamLogoff(void *, struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t netr_stub_table[] = {
+ { netr_s_ServerReqChallenge, NETR_OPNUM_ServerReqChallenge },
+ { netr_s_ServerAuthenticate2, NETR_OPNUM_ServerAuthenticate2 },
+ { netr_s_ServerPasswordSet, NETR_OPNUM_ServerPasswordSet },
+ { netr_s_SamLogon, NETR_OPNUM_SamLogon },
+ { netr_s_SamLogoff, NETR_OPNUM_SamLogoff },
+ {0}
+};
+
+static mlrpc_service_t netr_service = {
+ "NETR", /* name */
+ "NetLogon", /* desc */
+ "\\netlogon", /* endpoint */
+ PIPE_LSASS, /* sec_addr_port */
+ "12345678-1234-abcd-ef0001234567cffb", 1, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(netr_interface), /* interface ti */
+ netr_stub_table /* stub_table */
+};
+
+/*
+ * netr_initialize
+ *
+ * This function registers the NETR RPC interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+netr_initialize(void)
+{
+ (void) mlrpc_register_service(&netr_service);
+}
+
+/*
+ * netr_s_ServerReqChallenge
+ */
+/*ARGSUSED*/
+static int
+netr_s_ServerReqChallenge(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netr_ServerReqChallenge *param = arg;
+
+ bzero(param, sizeof (struct netr_ServerReqChallenge));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * netr_s_ServerAuthenticate2
+ */
+/*ARGSUSED*/
+static int
+netr_s_ServerAuthenticate2(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netr_ServerAuthenticate2 *param = arg;
+
+ bzero(param, sizeof (struct netr_ServerAuthenticate2));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * netr_s_ServerPasswordSet
+ */
+/*ARGSUSED*/
+static int
+netr_s_ServerPasswordSet(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netr_PasswordSet *param = arg;
+
+ bzero(param, sizeof (struct netr_PasswordSet));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * netr_s_SamLogon
+ */
+/*ARGSUSED*/
+static int
+netr_s_SamLogon(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netr_SamLogon *param = arg;
+
+ bzero(param, sizeof (struct netr_SamLogon));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * netr_s_SamLogoff
+ */
+/*ARGSUSED*/
+static int
+netr_s_SamLogoff(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netr_SamLogoff *param = arg;
+
+ bzero(param, sizeof (struct netr_SamLogoff));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Declare extern references.
+ */
+DECL_FIXUP_STRUCT(netr_validation_u);
+DECL_FIXUP_STRUCT(netr_validation_info);
+DECL_FIXUP_STRUCT(netr_SamLogon);
+
+/*
+ * Patch the netr_SamLogon union.
+ * This function is called from mlsvc_netr_ndr.c
+ */
+void
+fixup_netr_SamLogon(struct netr_SamLogon *arg)
+{
+ unsigned short size1 = 0;
+ unsigned short size2 = 0;
+ unsigned short size3 = 0;
+ WORD level = (WORD)arg->validation_level;
+
+ switch (level) {
+ case 3:
+ /*
+ * The netr_validation_u union contains a pointer, which
+ * is a DWORD in NDR. So we need to set size1 to ensure
+ * that we can correctly decode the remaining parameters.
+ */
+ size1 = sizeof (DWORD);
+ break;
+
+ default:
+ /*
+ * If the request is badly formed or the level is invalid,
+ * the server returns NT_STATUS_INVALID_INFO_CLASS. Size1
+ * must be zero to correctly decode the status.
+ */
+ size1 = 0;
+ break;
+ };
+
+ size2 = size1 + (2 * sizeof (DWORD));
+ size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD);
+
+ FIXUP_PDU_SIZE(netr_validation_u, size1);
+ FIXUP_PDU_SIZE(netr_validation_info, size2);
+ FIXUP_PDU_SIZE(netr_SamLogon, size3);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c
new file mode 100644
index 0000000000..3b51c05e71
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c
@@ -0,0 +1,1463 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Security Accounts Manager RPC (SAMR) interface definition.
+ */
+
+#include <strings.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/samrpc.ndl>
+#include <smbsrv/samlib.h>
+
+/*
+ * The keys associated with the various handles dispensed
+ * by the SAMR server. These keys can be used to validate
+ * client activity. These values are never passed over
+ * the network so security shouldn't be an issue.
+ */
+#define SAMR_CONNECT_KEY "SamrConnect"
+#define SAMR_DOMAIN_KEY "SamrDomain"
+#define SAMR_USER_KEY "SamrUser"
+#define SAMR_GROUP_KEY "SamrGroup"
+#define SAMR_ALIAS_KEY "SamrAlias"
+
+/*
+ * Domain discriminator values. Set the top bit to try
+ * to distinguish these values from user and group ids.
+ */
+#define SAMR_DATABASE_DOMAIN 0x80000001
+#define SAMR_LOCAL_DOMAIN 0x80000002
+#define SAMR_BUILTIN_DOMAIN 0x80000003
+#define SAMR_PRIMARY_DOMAIN 0x80000004
+
+static DWORD samr_s_enum_local_domains(struct samr_EnumLocalDomain *,
+ struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t samr_stub_table[];
+
+static mlrpc_service_t samr_service = {
+ "SAMR", /* name */
+ "Security Accounts Manager", /* desc */
+ "\\samr", /* endpoint */
+ PIPE_LSASS, /* sec_addr_port */
+ "12345778-1234-abcd-ef000123456789ac", 1, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(samr_interface), /* interface ti */
+ samr_stub_table /* stub_table */
+};
+
+/*
+ * samr_initialize
+ *
+ * This function registers the SAM RPC interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+samr_initialize(void)
+{
+ (void) mlrpc_register_service(&samr_service);
+}
+
+/*
+ * samr_s_ConnectAnon
+ *
+ * This is a request to connect to the local SAM database. We don't
+ * support any form of update request and our database doesn't
+ * contain any private information, so there is little point in
+ * doing any access access checking here.
+ *
+ * Return a handle for use with subsequent SAM requests.
+ */
+/*ARGSUSED*/
+static int
+samr_s_ConnectAnon(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_ConnectAnon *param = arg;
+ ms_handle_t *handle;
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_CONNECT_KEY,
+ SAMR_DATABASE_DOMAIN);
+ bcopy(handle, &param->handle, sizeof (samr_handle_t));
+
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_CloseHandle
+ *
+ * This is a request to close the SAM interface specified by the handle.
+ * Free the handle and zero out the result handle for the client.
+ *
+ * We could do some checking here but it probably doesn't matter.
+ */
+/*ARGSUSED*/
+static int
+samr_s_CloseHandle(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_CloseHandle *param = arg;
+
+#ifdef SAMR_S_DEBUG
+ if (mlsvc_lookup_handle((ms_handle_t *)&param->handle) == 0) {
+ bzero(&param->result_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+ return (MLRPC_DRC_OK);
+ }
+#endif /* SAMR_S_DEBUG */
+
+ (void) mlsvc_put_handle((ms_handle_t *)&param->handle);
+ bzero(&param->result_handle, sizeof (samr_handle_t));
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_LookupDomain
+ *
+ * This is a request to map a domain name to a domain SID. We can map
+ * the primary domain name, our local domain name (hostname) and the
+ * builtin domain names to the appropriate SID. Anything else will be
+ * rejected.
+ */
+static int
+samr_s_LookupDomain(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_LookupDomain *param = arg;
+ char resource_domain[MAXHOSTNAMELEN];
+ char *domain_name;
+ char *p;
+ nt_sid_t *sid = NULL;
+
+ if ((domain_name = (char *)param->domain_name.str) == NULL) {
+ bzero(param, sizeof (struct samr_LookupDomain));
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
+ return (MLRPC_DRC_OK);
+ }
+
+ smb_config_rdlock();
+ p = smb_config_getstr(SMB_CI_DOMAIN_NAME);
+ (void) strlcpy(resource_domain, p, MAXHOSTNAMELEN);
+ smb_config_unlock();
+
+ if (mlsvc_is_local_domain(domain_name) == 1) {
+ sid = nt_sid_dup(nt_domain_local_sid());
+ } else if (strcasecmp(resource_domain, domain_name) == 0) {
+ /*
+ * We should not be asked to provide
+ * the domain SID for the primary domain.
+ */
+ sid = NULL;
+ } else {
+ sid = nt_builtin_lookup_name(domain_name, 0);
+ }
+
+ if (sid) {
+ param->sid = (struct samr_sid *)mlsvc_sid_save(sid, mxa);
+ free(sid);
+
+ if (param->sid == NULL) {
+ bzero(param, sizeof (struct samr_LookupDomain));
+ param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ param->status = NT_STATUS_SUCCESS;
+ } else {
+ param->sid = NULL;
+ param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_DOMAIN);
+ }
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_EnumLocalDomains
+ *
+ * This is a request for the local domains supported by this server.
+ * All we do here is validate the handle and set the status. The real
+ * work is done in samr_s_enum_local_domains.
+ */
+static int
+samr_s_EnumLocalDomains(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_EnumLocalDomain *param = arg;
+ ms_handle_t *handle;
+ DWORD status;
+
+ handle = (ms_handle_t *)&param->handle;
+
+ if (mlsvc_validate_handle(handle, SAMR_CONNECT_KEY) == 0)
+ status = NT_STATUS_ACCESS_DENIED;
+ else
+ status = samr_s_enum_local_domains(param, mxa);
+
+ if (status == NT_STATUS_SUCCESS) {
+ param->enum_context = param->info->entries_read;
+ param->total_entries = param->info->entries_read;
+ param->status = NT_STATUS_SUCCESS;
+ } else {
+ bzero(param, sizeof (struct samr_EnumLocalDomain));
+ param->status = NT_SC_ERROR(status);
+ }
+
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * samr_s_enum_local_domains
+ *
+ * This function should only be called via samr_s_EnumLocalDomains to
+ * ensure that the appropriate validation is performed. We will answer
+ * queries about two domains: the local domain, synonymous with the
+ * local hostname, and the BUILTIN domain. So we return these two
+ * strings.
+ *
+ * Returns NT status values.
+ */
+static DWORD
+samr_s_enum_local_domains(struct samr_EnumLocalDomain *param,
+ struct mlrpc_xaction *mxa)
+{
+ struct samr_LocalDomainInfo *info;
+ struct samr_LocalDomainEntry *entry;
+ char *hostname;
+
+ hostname = MLRPC_HEAP_MALLOC(mxa, MAXHOSTNAMELEN);
+ if (hostname == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0)
+ return (NT_STATUS_NO_MEMORY);
+
+ entry = MLRPC_HEAP_NEWN(mxa, struct samr_LocalDomainEntry, 2);
+ if (entry == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ bzero(entry, (sizeof (struct samr_LocalDomainEntry) * 2));
+ (void) mlsvc_string_save((ms_string_t *)&entry[0].name, hostname, mxa);
+ (void) mlsvc_string_save((ms_string_t *)&entry[1].name, "Builtin", mxa);
+
+ info = MLRPC_HEAP_NEW(mxa, struct samr_LocalDomainInfo);
+ if (info == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ info->entries_read = 2;
+ info->entry = entry;
+ param->info = info;
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * samr_s_OpenDomain
+ *
+ * This is a request to open a domain within the local SAM database.
+ * The caller must supply a valid handle obtained via a successful
+ * connect. We return a handle to be used to access objects within
+ * this domain.
+ */
+/*ARGSUSED*/
+static int
+samr_s_OpenDomain(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_OpenDomain *param = arg;
+ ms_handle_t *handle = 0;
+ nt_domain_t *domain;
+
+ if (!mlsvc_validate_handle(
+ (ms_handle_t *)&param->handle, SAMR_CONNECT_KEY)) {
+ bzero(&param->domain_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+ }
+
+ domain = nt_domain_lookup_sid((nt_sid_t *)param->sid);
+ if (domain == NULL) {
+ bzero(&param->domain_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+ return (MLRPC_DRC_OK);
+ }
+
+ switch (domain->type) {
+ case NT_DOMAIN_BUILTIN:
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR,
+ SAMR_DOMAIN_KEY, SAMR_BUILTIN_DOMAIN);
+
+ bcopy(handle, &param->domain_handle, sizeof (samr_handle_t));
+ param->status = 0;
+ break;
+
+ case NT_DOMAIN_LOCAL:
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR,
+ SAMR_DOMAIN_KEY, SAMR_LOCAL_DOMAIN);
+
+ bcopy(handle, &param->domain_handle, sizeof (samr_handle_t));
+ param->status = 0;
+ break;
+
+ default:
+ bzero(&param->domain_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+ }
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_QueryDomainInfo
+ *
+ * The caller should pass a domain handle.
+ *
+ * Windows 95 Server Manager sends requests for levels 6 and 7 when
+ * the services menu item is selected. Level 2 is basically for getting
+ * number of users, groups, and aliases in a domain.
+ * We have no information on what the various information levels mean.
+ */
+static int
+samr_s_QueryDomainInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_QueryDomainInfo *param = arg;
+ ms_handle_desc_t *desc;
+ char *hostname;
+ char *domain_str = "";
+ int rc;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->domain_handle);
+ if (desc == NULL || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) {
+ bzero(param, sizeof (struct samr_QueryDomainInfo));
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+ return (MLRPC_DRC_OK);
+ }
+
+ switch (param->info_level) {
+ case SAMR_QUERY_DOMAIN_INFO_6:
+ param->ru.info6.unknown1 = 0x00000000;
+ param->ru.info6.unknown2 = 0x00147FB0;
+ param->ru.info6.unknown3 = 0x00000000;
+ param->ru.info6.unknown4 = 0x00000000;
+ param->ru.info6.unknown5 = 0x00000000;
+ param->status = NT_STATUS_SUCCESS;
+ break;
+
+ case SAMR_QUERY_DOMAIN_INFO_7:
+ param->ru.info7.unknown1 = 0x00000003;
+ param->status = NT_STATUS_SUCCESS;
+ break;
+
+ case SAMR_QUERY_DOMAIN_INFO_2:
+ if (desc->discrim == SAMR_LOCAL_DOMAIN) {
+ hostname = MLRPC_HEAP_MALLOC(mxa, MAXHOSTNAMELEN);
+ rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
+ if (rc != 0 || hostname == NULL) {
+ bzero(param,
+ sizeof (struct samr_QueryDomainInfo));
+ param->status =
+ NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+ return (MLRPC_DRC_OK);
+ }
+
+ domain_str = hostname;
+ } else {
+ if (desc->discrim == SAMR_BUILTIN_DOMAIN)
+ domain_str = "Builtin";
+ }
+
+ param->ru.info2.unknown1 = 0x00000000;
+ param->ru.info2.unknown2 = 0x80000000;
+
+ (void) mlsvc_string_save((ms_string_t *)&(param->ru.info2.s1),
+ "", mxa);
+
+ (void) mlsvc_string_save(
+ (ms_string_t *)&(param->ru.info2.domain), domain_str, mxa);
+
+ (void) mlsvc_string_save((ms_string_t *)&(param->ru.info2.s2),
+ "", mxa);
+
+ param->ru.info2.sequence_num = 0x0000002B;
+ param->ru.info2.unknown3 = 0x00000000;
+ param->ru.info2.unknown4 = 0x00000001;
+ param->ru.info2.unknown5 = 0x00000003;
+ param->ru.info2.unknown6 = 0x00000001;
+ param->ru.info2.num_users = 0;
+ param->ru.info2.num_groups = 0;
+ param->ru.info2.num_aliases =
+ (desc->discrim == SAMR_BUILTIN_DOMAIN) ?
+ nt_groups_count(NT_GROUP_CNT_BUILTIN) :
+ nt_groups_count(NT_GROUP_CNT_LOCAL);
+
+ param->status = NT_STATUS_SUCCESS;
+ break;
+
+ default:
+ bzero(param, sizeof (struct samr_QueryDomainInfo));
+ return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
+ };
+
+ param->address = (DWORD)&param->ru;
+ param->switch_value = param->info_level;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_LookupNames
+ *
+ * The definition for this interface is obviously wrong but I can't
+ * seem to get it to work the way I think it should. It should
+ * support multiple name lookup but I can only get one working for now.
+ */
+static int
+samr_s_LookupNames(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_LookupNames *param = arg;
+ ms_handle_desc_t *desc;
+ struct passwd *pw;
+ struct group *gr;
+ nt_sid_t *sid;
+ nt_group_t *grp;
+ WORD rid_type;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->handle);
+ if (desc == 0 || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) {
+ bzero(param, sizeof (struct samr_LookupNames));
+ param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+ return (MLRPC_DRC_OK);
+ }
+
+ if (param->n_entry != 1) {
+ bzero(param, sizeof (struct samr_LookupNames));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+ }
+
+ if (param->name.str == NULL) {
+ bzero(param, sizeof (struct samr_LookupNames));
+ /*
+ * Windows NT returns NT_STATUS_NONE_MAPPED when the
+ * name is NULL.
+ * Windows 2000 returns STATUS_INVALID_ACCOUNT_NAME.
+ */
+ param->status = NT_SC_ERROR(NT_STATUS_NONE_MAPPED);
+ return (MLRPC_DRC_OK);
+ }
+
+ param->rids.rid = MLRPC_HEAP_NEW(mxa, DWORD);
+ param->rid_types.rid_type = MLRPC_HEAP_NEW(mxa, DWORD);
+
+ if (desc->discrim == SAMR_BUILTIN_DOMAIN) {
+ sid = nt_builtin_lookup_name((char *)param->name.str,
+ &rid_type);
+
+ if (sid != 0) {
+ param->rids.n_entry = 1;
+ (void) nt_sid_get_rid(sid, &param->rids.rid[0]);
+ param->rid_types.n_entry = 1;
+ param->rid_types.rid_type[0] = rid_type;
+ param->status = NT_STATUS_SUCCESS;
+ free(sid);
+ return (MLRPC_DRC_OK);
+ }
+ } else if (desc->discrim == SAMR_LOCAL_DOMAIN) {
+ grp = nt_group_getinfo((char *)param->name.str, RWLOCK_READER);
+
+ if (grp != NULL) {
+ param->rids.n_entry = 1;
+ (void) nt_sid_get_rid(grp->sid, &param->rids.rid[0]);
+ param->rid_types.n_entry = 1;
+ param->rid_types.rid_type[0] = *grp->sid_name_use;
+ param->status = NT_STATUS_SUCCESS;
+ nt_group_putinfo(grp);
+ return (MLRPC_DRC_OK);
+ }
+
+ if ((pw = getpwnam((const char *)param->name.str)) != NULL) {
+ param->rids.n_entry = 1;
+ param->rids.rid[0] = SAM_ENCODE_UXUID(pw->pw_uid);
+ param->rid_types.n_entry = 1;
+ param->rid_types.rid_type[0] = SidTypeUser;
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+ }
+
+ if ((gr = getgrnam((const char *)param->name.str)) != NULL) {
+ param->rids.n_entry = 1;
+ param->rids.rid[0] = SAM_ENCODE_UXGID(gr->gr_gid);
+ param->rid_types.n_entry = 1;
+ param->rid_types.rid_type[0] = SidTypeAlias;
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+ }
+ }
+
+ param->rids.n_entry = 0;
+ param->rid_types.n_entry = 0;
+ param->status = NT_SC_ERROR(NT_STATUS_NONE_MAPPED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_OpenUser
+ *
+ * This is a request to open a user within a specified domain in the
+ * local SAM database. The caller must supply a valid domain handle,
+ * obtained via a successful domain open request. The user is
+ * specified by the rid in the request.
+ */
+/*ARGSUSED*/
+static int
+samr_s_OpenUser(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_OpenUser *param = arg;
+ ms_handle_t *handle;
+
+ if (!mlsvc_validate_handle(
+ (ms_handle_t *)&param->handle, SAMR_DOMAIN_KEY)) {
+ bzero(&param->user_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+ }
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_USER_KEY,
+ param->rid);
+ bcopy(handle, &param->user_handle, sizeof (samr_handle_t));
+
+ /*
+ * Need QueryUserInfo(level 21).
+ */
+ bzero(&param->user_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_DeleteUser
+ *
+ * This is a request to delete a user within a specified domain in the
+ * local SAM database. The caller should supply a valid user handle but
+ * we deny access regardless.
+ */
+/*ARGSUSED*/
+static int
+samr_s_DeleteUser(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_DeleteUser *param = arg;
+
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_QueryUserInfo
+ *
+ * Returns:
+ * NT_STATUS_SUCCESS
+ * NT_STATUS_ACCESS_DENIED
+ * NT_STATUS_INVALID_INFO_CLASS
+ */
+/*ARGSUSED*/
+static int
+samr_s_QueryUserInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_QueryUserInfo *param = arg;
+
+ if (!mlsvc_validate_handle(
+ (ms_handle_t *)&param->user_handle, SAMR_USER_KEY)) {
+ bzero(param, sizeof (struct samr_QueryUserInfo));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param, sizeof (struct samr_QueryUserInfo));
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_QueryUserGroups
+ *
+ * This is a request to obtain a list of groups of which a user is a
+ * member. The user is identified from the handle, which contains an
+ * encoded uid in the discriminator field.
+ *
+ * Get complete list of groups and check for builtin domain.
+ */
+static int
+samr_s_QueryUserGroups(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_QueryUserGroups *param = arg;
+ struct samr_UserGroupInfo *info;
+ ms_handle_desc_t *desc;
+ struct passwd *pw;
+ DWORD uid;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->user_handle);
+ if (desc == 0 || strcmp(desc->key, SAMR_USER_KEY)) {
+ bzero(param, sizeof (struct samr_QueryUserGroups));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+ }
+
+ info = MLRPC_HEAP_NEW(mxa, struct samr_UserGroupInfo);
+ info->groups = MLRPC_HEAP_NEW(mxa, struct samr_UserGroups);
+
+ uid = SAM_DECODE_RID(desc->discrim);
+
+ if ((pw = getpwuid(uid)) != 0) {
+ info->n_entry = 1;
+ info->groups->rid = SAM_ENCODE_UXGID(pw->pw_gid);
+ info->groups->attr = SE_GROUP_MANDATORY
+ | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
+ param->info = info;
+ param->status = 0;
+ } else {
+ bzero(param, sizeof (struct samr_QueryUserGroups));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ }
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_OpenGroup
+ *
+ * This is a request to open a group within the specified domain in the
+ * local SAM database. The caller must supply a valid domain handle,
+ * obtained via a successful domain open request. The group is
+ * specified by the rid in the request. If this is a local RID it
+ * should already be encoded with type information.
+ *
+ * We return a handle to be used to access information about this group.
+ */
+/*ARGSUSED*/
+static int
+samr_s_OpenGroup(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_OpenGroup *param = arg;
+ ms_handle_t *handle;
+
+ if (!mlsvc_validate_handle(
+ (ms_handle_t *)&param->handle, SAMR_DOMAIN_KEY)) {
+ bzero(&param->group_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+ }
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_GROUP_KEY,
+ param->rid);
+ bcopy(handle, &param->group_handle, sizeof (samr_handle_t));
+
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_Connect
+ *
+ * This is a request to connect to the local SAM database. We don't
+ * support any form of update request and our database doesn't
+ * contain any private information, so there is little point in
+ * doing any access access checking here.
+ *
+ * Return a handle for use with subsequent SAM requests.
+ */
+/*ARGSUSED*/
+static int
+samr_s_Connect(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_Connect *param = arg;
+ ms_handle_t *handle;
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR,
+ SAMR_CONNECT_KEY, SAMR_DATABASE_DOMAIN);
+ bcopy(handle, &param->handle, sizeof (samr_handle_t));
+
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_GetUserPwInfo
+ *
+ * This is a request to get a user's password.
+ */
+/*ARGSUSED*/
+static int
+samr_s_GetUserPwInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_GetUserPwInfo *param = arg;
+ ms_handle_t *handle;
+ DWORD status = 0;
+
+ handle = (ms_handle_t *)&param->user_handle;
+
+ if (!mlsvc_validate_handle(handle, SAMR_USER_KEY))
+ status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+
+ bzero(param, sizeof (struct samr_GetUserPwInfo));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_CreateUser
+ *
+ * This is a request to create a user within a specified domain in the
+ * local SAM database. We always deny access.
+ */
+/*ARGSUSED*/
+static int
+samr_s_CreateUser(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_CreateUser *param = arg;
+
+ bzero(&param->user_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_ChangeUserPasswd
+ */
+/*ARGSUSED*/
+static int
+samr_s_ChangeUserPasswd(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_ChangeUserPasswd *param = arg;
+
+ bzero(param, sizeof (struct samr_ChangeUserPasswd));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_GetDomainPwInfo
+ */
+/*ARGSUSED*/
+static int
+samr_s_GetDomainPwInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_GetDomainPwInfo *param = arg;
+
+ bzero(param, sizeof (struct samr_GetDomainPwInfo));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_SetUserInfo
+ */
+/*ARGSUSED*/
+static int
+samr_s_SetUserInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_SetUserInfo *param = arg;
+
+ bzero(param, sizeof (struct samr_SetUserInfo));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_QueryDispInfo
+ *
+ * This function is supposed to return local users' information.
+ * As we don't support local users, this function dosen't send
+ * back any information.
+ *
+ * I added a peice of code that returns information for Administrator
+ * and Guest builtin users. All information are hard-coded which I get
+ * from packet captures. Currently, this peice of code is opt-out.
+ */
+/*ARGSUSED*/
+static int
+samr_s_QueryDispInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_QueryDispInfo *param = arg;
+ ms_handle_desc_t *desc;
+ DWORD status = 0;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->domain_handle);
+ if (desc == NULL || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0))
+ status = NT_STATUS_INVALID_HANDLE;
+
+#ifdef SAMR_SUPPORT_USER
+ if ((desc->discrim != SAMR_LOCAL_DOMAIN) || (param->start_idx != 0)) {
+ param->total_size = 0;
+ param->returned_size = 0;
+ param->switch_value = 1;
+ param->count = 0;
+ param->users = 0;
+ } else {
+ param->total_size = 328;
+ param->returned_size = 328;
+ param->switch_value = 1;
+ param->count = 2;
+ param->users = (struct user_disp_info *)MLRPC_HEAP_MALLOC(mxa,
+ sizeof (struct user_disp_info));
+
+ param->users->count = 2;
+ param->users->acct[0].index = 1;
+ param->users->acct[0].rid = 500;
+ param->users->acct[0].ctrl = 0x210;
+
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->users->acct[0].name,
+ "Administrator", mxa);
+
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->users->acct[0].fullname,
+ "Built-in account for administering the computer/domain",
+ mxa);
+
+ bzero(&param->users->acct[0].desc, sizeof (samr_string_t));
+
+ param->users->acct[1].index = 2;
+ param->users->acct[1].rid = 501;
+ param->users->acct[1].ctrl = 0x211;
+
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->users->acct[1].name,
+ "Guest", mxa);
+
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->users->acct[1].fullname,
+ "Built-in account for guest access to the computer/domain",
+ mxa);
+
+ bzero(&param->users->acct[1].desc, sizeof (samr_string_t));
+ }
+#else
+ param->total_size = 0;
+ param->returned_size = 0;
+ param->switch_value = 1;
+ param->count = 0;
+ param->users = 0;
+#endif
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_EnumDomainGroups
+ *
+ *
+ * This function is supposed to return local users' information.
+ * As we don't support local users, this function dosen't send
+ * back any information.
+ *
+ * I added a peice of code that returns information for a
+ * domain group as None. All information are hard-coded which I get
+ * from packet captures. Currently, this peice of code is opt-out.
+ */
+/*ARGSUSED*/
+static int
+samr_s_EnumDomainGroups(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_EnumDomainGroups *param = arg;
+ ms_handle_desc_t *desc;
+ DWORD status = NT_STATUS_SUCCESS;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->domain_handle);
+ if (desc == NULL || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0))
+ status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+
+ param->total_size = 0;
+ param->returned_size = 0;
+ param->switch_value = 3;
+ param->count = 0;
+ param->groups = 0;
+ param->status = status;
+ return (MLRPC_DRC_OK);
+
+#ifdef SAMR_SUPPORT_GROUPS
+ if ((desc->discrim != SAMR_LOCAL_DOMAIN) || (param->start_idx != 0)) {
+ param->total_size = 0;
+ param->returned_size = 0;
+ param->switch_value = 3;
+ param->count = 0;
+ param->groups = 0;
+ } else {
+ param->total_size = 64;
+ param->returned_size = 64;
+ param->switch_value = 3;
+ param->count = 1;
+ param->groups = (struct group_disp_info *)MLRPC_HEAP_MALLOC(
+ mxa, sizeof (struct group_disp_info));
+
+ param->groups->count = 1;
+ param->groups->acct[0].index = 1;
+ param->groups->acct[0].rid = 513;
+ param->groups->acct[0].ctrl = 0x7;
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->groups->acct[0].name, "None", mxa);
+
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->groups->acct[0].desc,
+ "Ordinary users", mxa);
+ }
+
+ param->status = NT_STATUS_SUCCESS;
+ return (MLRPC_DRC_OK);
+#endif
+}
+
+/*
+ * samr_s_OpenAlias
+ *
+ * Lookup for requested alias, if it exists return a handle
+ * for that alias. The alias domain sid should match with
+ * the passed domain handle.
+ */
+/*ARGSUSED*/
+static int
+samr_s_OpenAlias(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_OpenAlias *param = arg;
+ ms_handle_desc_t *desc = 0;
+ ms_handle_t *handle;
+ nt_group_t *grp;
+ DWORD status = NT_STATUS_SUCCESS;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->domain_handle);
+ if (desc == 0 || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto open_alias_err;
+ }
+
+ if (param->access_mask != SAMR_ALIAS_ACCESS_GET_INFO) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto open_alias_err;
+ }
+
+ grp = nt_groups_lookup_rid(param->rid);
+ if (grp == 0) {
+ status = NT_STATUS_NO_SUCH_ALIAS;
+ goto open_alias_err;
+ }
+
+ if (((desc->discrim == SAMR_LOCAL_DOMAIN) &&
+ !nt_sid_is_local(grp->sid)) ||
+ ((desc->discrim == SAMR_BUILTIN_DOMAIN) &&
+ !nt_sid_is_builtin(grp->sid))) {
+ status = NT_STATUS_NO_SUCH_ALIAS;
+ goto open_alias_err;
+ }
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_ALIAS_KEY,
+ param->rid);
+ bcopy(handle, &param->alias_handle, sizeof (samr_handle_t));
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+
+open_alias_err:
+ bzero(&param->alias_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(status);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_CreateDomainAlias
+ *
+ * Creates a local group in the security database, which is the
+ * security accounts manager (SAM)
+ * For more information you can look at MSDN page for NetLocalGroupAdd.
+ * This RPC is used by CMC and right now it returns access denied.
+ * The peice of code that creates a local group doesn't get compiled.
+ */
+/*ARGSUSED*/
+static int
+samr_s_CreateDomainAlias(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_CreateDomainAlias *param = arg;
+
+#ifdef SAMR_SUPPORT_ADD_ALIAS
+ DWORD status = NT_STATUS_SUCCESS;
+ ms_handle_desc_t *desc = 0;
+ ms_handle_t *handle;
+ nt_group_t *grp;
+ char *alias_name;
+#endif
+ bzero(&param->alias_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+
+#ifdef SAMR_SUPPORT_ADD_ALIAS
+ alias_name = param->alias_name.str;
+ if (alias_name == 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto create_alias_err;
+ }
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->domain_handle);
+ if (desc == 0 ||
+ (desc->discrim != SAMR_LOCAL_DOMAIN) ||
+ (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto create_alias_err;
+ }
+
+ /*
+ * Check access mask. User should be member of
+ * Administrators or Account Operators local group.
+ */
+ status = nt_group_add(alias_name, 0,
+ NT_GROUP_AF_ADD | NT_GROUP_AF_LOCAL);
+
+ if (status != NT_STATUS_SUCCESS)
+ goto create_alias_err;
+
+ grp = nt_group_getinfo(alias_name, RWLOCK_READER);
+ if (grp == NULL) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto create_alias_err;
+ }
+
+ (void) nt_sid_get_rid(grp->sid, &param->rid);
+ nt_group_putinfo(grp);
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_ALIAS_KEY,
+ param->rid);
+ bcopy(handle, &param->alias_handle, sizeof (samr_handle_t));
+
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+
+create_alias_err:
+ bzero(&param->alias_handle, sizeof (samr_handle_t));
+ param->status = NT_SC_ERROR(status);
+ return (MLRPC_DRC_OK);
+#endif
+}
+
+/*
+ * samr_s_SetAliasInfo
+ *
+ * For more information you can look at MSDN page for NetLocalGroupSetInfo.
+ */
+/*ARGSUSED*/
+static int
+samr_s_SetAliasInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_SetAliasInfo *param = arg;
+ DWORD status = NT_STATUS_SUCCESS;
+
+ if (!mlsvc_validate_handle(
+ (ms_handle_t *)&param->alias_handle, SAMR_ALIAS_KEY)) {
+ status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
+ }
+
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_QueryAliasInfo
+ *
+ * Retrieves information about the specified local group account
+ * by given handle.
+ */
+static int
+samr_s_QueryAliasInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_QueryAliasInfo *param = arg;
+ ms_handle_desc_t *desc;
+ nt_group_t *grp;
+ DWORD status;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->alias_handle);
+ if (desc == NULL || (strcmp(desc->key, SAMR_ALIAS_KEY) != 0)) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto query_alias_err;
+ }
+
+ grp = nt_groups_lookup_rid(desc->discrim);
+ if (grp == NULL) {
+ status = NT_STATUS_NO_SUCH_ALIAS;
+ goto query_alias_err;
+ }
+
+ switch (param->level) {
+ case SAMR_QUERY_ALIAS_INFO_1:
+ param->ru.info1.level = param->level;
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->ru.info1.name, grp->name, mxa);
+
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->ru.info1.desc, grp->comment, mxa);
+
+ param->ru.info1.unknown = 1;
+ break;
+
+ case SAMR_QUERY_ALIAS_INFO_3:
+ param->ru.info3.level = param->level;
+ (void) mlsvc_string_save(
+ (ms_string_t *)&param->ru.info3.desc, grp->comment, mxa);
+
+ break;
+
+ default:
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ goto query_alias_err;
+ };
+
+ param->address = (DWORD)&param->ru;
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+
+query_alias_err:
+ param->status = NT_SC_ERROR(status);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_DeleteDomainAlias
+ *
+ * Deletes a local group account and all its members from the
+ * security database, which is the security accounts manager (SAM) database.
+ * Only members of the Administrators or Account Operators local group can
+ * execute this function.
+ * For more information you can look at MSDN page for NetLocalGroupSetInfo.
+ *
+ * This RPC is used by CMC and right now it returns access denied.
+ * The peice of code that removes a local group doesn't get compiled.
+ */
+/*ARGSUSED*/
+static int
+samr_s_DeleteDomainAlias(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_DeleteDomainAlias *param = arg;
+
+#ifdef SAMR_SUPPORT_DEL_ALIAS
+ ms_handle_desc_t *desc = 0;
+ nt_group_t *grp;
+ char *alias_name;
+ DWORD status;
+#endif
+
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (MLRPC_DRC_OK);
+
+#ifdef SAMR_SUPPORT_DEL_ALIAS
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->alias_handle);
+ if (desc == 0 || (strcmp(desc->key, SAMR_ALIAS_KEY) != 0)) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto delete_alias_err;
+ }
+
+ grp = nt_groups_lookup_rid(desc->discrim);
+ if (grp == 0) {
+ status = NT_STATUS_NO_SUCH_ALIAS;
+ goto delete_alias_err;
+ }
+
+ alias_name = strdup(grp->name);
+ if (alias_name == 0) {
+ status = NT_STATUS_NO_MEMORY;
+ goto delete_alias_err;
+ }
+
+ status = nt_group_delete(alias_name);
+ free(alias_name);
+ if (status != NT_STATUS_SUCCESS)
+ goto delete_alias_err;
+
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+
+delete_alias_err:
+ param->status = NT_SC_ERROR(status);
+ return (MLRPC_DRC_OK);
+#endif
+}
+
+/*
+ * samr_s_EnumDomainAliases
+ *
+ * This function sends back a list which contains all local groups' name.
+ */
+static int
+samr_s_EnumDomainAliases(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_EnumDomainAliases *param = arg;
+ ms_handle_desc_t *desc;
+ nt_group_t *grp = NULL;
+ DWORD status;
+ nt_group_iterator_t *gi;
+ nt_sid_t *local_sid;
+ nt_sid_t *builtin_sid;
+ nt_sid_t *sid;
+ DWORD cnt, skip;
+ struct name_rid *info;
+
+ desc = mlsvc_lookup_handle((ms_handle_t *)&param->domain_handle);
+ if (desc == NULL || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto enum_alias_err;
+ }
+
+ local_sid = nt_domain_local_sid();
+ builtin_sid = nt_builtin_lookup_name("BUILTIN", 0);
+
+ if (desc->discrim == SAMR_LOCAL_DOMAIN) {
+ sid = local_sid;
+ } else if (desc->discrim == SAMR_BUILTIN_DOMAIN) {
+ sid = builtin_sid;
+ } else {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto enum_alias_err;
+ }
+
+ cnt = skip = 0;
+ gi = nt_group_open_iterator();
+ nt_group_ht_lock(RWLOCK_READER);
+ while ((grp = nt_group_iterate(gi)) != 0) {
+ if (skip++ < param->resume_handle)
+ continue;
+ if (nt_sid_is_indomain(sid, grp->sid))
+ cnt++;
+ }
+ nt_group_ht_unlock();
+ nt_group_close_iterator(gi);
+
+ param->aliases = (struct aliases_info *)MLRPC_HEAP_MALLOC(mxa,
+ sizeof (struct aliases_info) + (cnt-1) * sizeof (struct name_rid));
+
+ param->aliases->count = cnt;
+ param->aliases->address = cnt;
+ info = param->aliases->info;
+
+ skip = 0;
+ gi = nt_group_open_iterator();
+ nt_group_ht_lock(RWLOCK_READER);
+ while ((grp = nt_group_iterate(gi)) != NULL) {
+ if (skip++ < param->resume_handle)
+ continue;
+ if (nt_sid_is_indomain(sid, grp->sid)) {
+ (void) nt_sid_get_rid(grp->sid, &info->rid);
+ (void) mlsvc_string_save((ms_string_t *)&info->name,
+ grp->name, mxa);
+
+ info++;
+ }
+ }
+ nt_group_ht_unlock();
+ nt_group_close_iterator(gi);
+
+ param->out_resume = cnt;
+ param->entries = cnt;
+ param->status = 0;
+ return (MLRPC_DRC_OK);
+
+enum_alias_err:
+ param->status = NT_SC_ERROR(status);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * samr_s_Connect3
+ *
+ * This is the connect3 form of the connect request. It contains an
+ * extra parameter over samr_Connect. See samr_s_Connect for other
+ * details. NT returns an RPC fault - so we can do the same for now.
+ * Doing it this way should avoid the unsupported opnum error message
+ * appearing in the log.
+ */
+/*ARGSUSED*/
+static int
+samr_s_Connect3(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_Connect3 *param = arg;
+
+ bzero(param, sizeof (struct samr_Connect3));
+ return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
+}
+
+
+/*
+ * samr_s_Connect4
+ *
+ * This is the connect4 form of the connect request used by Windows XP.
+ * Returns an RPC fault for now.
+ */
+/*ARGSUSED*/
+static int
+samr_s_Connect4(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct samr_Connect4 *param = arg;
+
+ bzero(param, sizeof (struct samr_Connect4));
+ return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
+}
+
+static mlrpc_stub_table_t samr_stub_table[] = {
+ { samr_s_ConnectAnon, SAMR_OPNUM_ConnectAnon },
+ { samr_s_CloseHandle, SAMR_OPNUM_CloseHandle },
+ { samr_s_LookupDomain, SAMR_OPNUM_LookupDomain },
+ { samr_s_EnumLocalDomains, SAMR_OPNUM_EnumLocalDomains },
+ { samr_s_OpenDomain, SAMR_OPNUM_OpenDomain },
+ { samr_s_QueryDomainInfo, SAMR_OPNUM_QueryDomainInfo },
+ { samr_s_LookupNames, SAMR_OPNUM_LookupNames },
+ { samr_s_OpenUser, SAMR_OPNUM_OpenUser },
+ { samr_s_DeleteUser, SAMR_OPNUM_DeleteUser },
+ { samr_s_QueryUserInfo, SAMR_OPNUM_QueryUserInfo },
+ { samr_s_QueryUserGroups, SAMR_OPNUM_QueryUserGroups },
+ { samr_s_OpenGroup, SAMR_OPNUM_OpenGroup },
+ { samr_s_Connect, SAMR_OPNUM_Connect },
+ { samr_s_GetUserPwInfo, SAMR_OPNUM_GetUserPwInfo },
+ { samr_s_CreateUser, SAMR_OPNUM_CreateUser },
+ { samr_s_ChangeUserPasswd, SAMR_OPNUM_ChangeUserPasswd },
+ { samr_s_GetDomainPwInfo, SAMR_OPNUM_GetDomainPwInfo },
+ { samr_s_SetUserInfo, SAMR_OPNUM_SetUserInfo },
+ { samr_s_Connect3, SAMR_OPNUM_Connect3 },
+ { samr_s_Connect4, SAMR_OPNUM_Connect4 },
+ { samr_s_QueryDispInfo, SAMR_OPNUM_QueryDispInfo },
+ { samr_s_OpenAlias, SAMR_OPNUM_OpenAlias },
+ { samr_s_CreateDomainAlias, SAMR_OPNUM_CreateDomainAlias },
+ { samr_s_SetAliasInfo, SAMR_OPNUM_SetAliasInfo },
+ { samr_s_QueryAliasInfo, SAMR_OPNUM_QueryAliasInfo },
+ { samr_s_DeleteDomainAlias, SAMR_OPNUM_DeleteDomainAlias },
+ { samr_s_EnumDomainAliases, SAMR_OPNUM_EnumDomainAliases },
+ { samr_s_EnumDomainGroups, SAMR_OPNUM_EnumDomainGroups },
+ {0}
+};
+
+/*
+ * There is a bug in the way that midl and the marshalling code handles
+ * unions so we need to fix some of the data offsets at runtime. The
+ * following macros and the fixup functions handle the corrections.
+ */
+DECL_FIXUP_STRUCT(samr_QueryDomainInfo_ru);
+DECL_FIXUP_STRUCT(samr_QueryDomainInfoRes);
+DECL_FIXUP_STRUCT(samr_QueryDomainInfo);
+
+DECL_FIXUP_STRUCT(samr_QueryAliasInfo_ru);
+DECL_FIXUP_STRUCT(samr_QueryAliasInfoRes);
+DECL_FIXUP_STRUCT(samr_QueryAliasInfo);
+
+DECL_FIXUP_STRUCT(QueryUserInfo_result_u);
+DECL_FIXUP_STRUCT(QueryUserInfo_result);
+DECL_FIXUP_STRUCT(samr_QueryUserInfo);
+
+void
+fixup_samr_QueryDomainInfo(struct samr_QueryDomainInfo *val)
+{
+ unsigned short size1 = 0;
+ unsigned short size2 = 0;
+ unsigned short size3 = 0;
+
+ switch (val->switch_value) {
+ CASE_INFO_ENT(samr_QueryDomainInfo, 2);
+ CASE_INFO_ENT(samr_QueryDomainInfo, 6);
+ CASE_INFO_ENT(samr_QueryDomainInfo, 7);
+
+ default:
+ return;
+ };
+
+ size2 = size1 + (2 * sizeof (DWORD));
+ size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD);
+
+ FIXUP_PDU_SIZE(samr_QueryDomainInfo_ru, size1);
+ FIXUP_PDU_SIZE(samr_QueryDomainInfoRes, size2);
+ FIXUP_PDU_SIZE(samr_QueryDomainInfo, size3);
+}
+
+void
+fixup_samr_QueryAliasInfo(struct samr_QueryAliasInfo *val)
+{
+ unsigned short size1 = 0;
+ unsigned short size2 = 0;
+ unsigned short size3 = 0;
+
+ switch (val->level) {
+ CASE_INFO_ENT(samr_QueryAliasInfo, 1);
+ CASE_INFO_ENT(samr_QueryAliasInfo, 3);
+
+ default:
+ return;
+ };
+
+ size2 = size1 + (2 * sizeof (DWORD));
+ size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD);
+
+ FIXUP_PDU_SIZE(samr_QueryAliasInfo_ru, size1);
+ FIXUP_PDU_SIZE(samr_QueryAliasInfoRes, size2);
+ FIXUP_PDU_SIZE(samr_QueryAliasInfo, size3);
+}
+
+void
+fixup_samr_QueryUserInfo(struct samr_QueryUserInfo *val)
+{
+ unsigned short size1 = 0;
+ unsigned short size2 = 0;
+ unsigned short size3 = 0;
+
+ switch (val->switch_index) {
+ CASE_INFO_ENT(samr_QueryUserInfo, 1);
+ CASE_INFO_ENT(samr_QueryUserInfo, 6);
+ CASE_INFO_ENT(samr_QueryUserInfo, 7);
+ CASE_INFO_ENT(samr_QueryUserInfo, 8);
+ CASE_INFO_ENT(samr_QueryUserInfo, 9);
+ CASE_INFO_ENT(samr_QueryUserInfo, 16);
+
+ default:
+ return;
+ };
+
+ size2 = size1 + (2 * sizeof (DWORD));
+ size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD);
+
+ FIXUP_PDU_SIZE(QueryUserInfo_result_u, size1);
+ FIXUP_PDU_SIZE(QueryUserInfo_result, size2);
+ FIXUP_PDU_SIZE(samr_QueryUserInfo, size3);
+}
+
+/*
+ * As long as there is only one entry in the union, there is no need
+ * to patch anything.
+ */
+/*ARGSUSED*/
+void
+fixup_samr_QueryGroupInfo(struct samr_QueryGroupInfo *val)
+{
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_spoolss.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_spoolss.c
new file mode 100644
index 0000000000..bac138cf09
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_spoolss.c
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Printing and Spooling RPC interface definition.
+ * A stub to resolve RPC requests to this service.
+ */
+
+#include <smbsrv/ndl/spoolss.ndl>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nmpipes.h>
+
+static mlrpc_stub_table_t spoolss_stub_table[];
+
+static mlrpc_service_t spoolss_service = {
+ "SPOOLSS", /* name */
+ "Print Spool Service", /* desc */
+ "\\spoolss", /* endpoint */
+ PIPE_SPOOLSS, /* sec_addr_port */
+ "12345678-1234-abcd-ef000123456789ab", 1, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(spoolss_interface), /* interface ti */
+ spoolss_stub_table /* stub_table */
+};
+
+/*
+ * spoolss_initialize
+ *
+ * This function registers the SPOOLSS RPC interface with the RPC
+ * runtime library. It must be called in order to use either the
+ * client side or the server side functions.
+ */
+void
+spoolss_initialize(void)
+{
+ (void) mlrpc_register_service(&spoolss_service);
+}
+
+/*
+ * spoolss_s_OpenPrinter
+ *
+ * We don't offer print spooling support. It should be okay to
+ * set the status to access denied and return MLRPC_DRC_OK.
+ */
+static int
+spoolss_s_OpenPrinter(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct spoolss_OpenPrinter *param = arg;
+
+ bzero(param, sizeof (struct spoolss_OpenPrinter));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * spoolss_s_stub
+ */
+static int
+spoolss_s_stub(void *arg, struct mlrpc_xaction *mxa)
+{
+ return (MLRPC_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
+}
+
+static mlrpc_stub_table_t spoolss_stub_table[] = {
+ { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinter },
+ { spoolss_s_stub, SPOOLSS_OPNUM_GetJob },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinter },
+ { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterDriver },
+ { spoolss_s_stub, SPOOLSS_OPNUM_AddPrintProcessor },
+ { spoolss_s_stub, SPOOLSS_OPNUM_GetPrintProcessorDirectory },
+ { spoolss_s_stub, SPOOLSS_OPNUM_AbortPrinter },
+ { spoolss_s_stub, SPOOLSS_OPNUM_ReadPrinter },
+ { spoolss_s_stub, SPOOLSS_OPNUM_WaitForPrinterChange },
+ { spoolss_s_stub, SPOOLSS_OPNUM_AddForm },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeleteForm },
+ { spoolss_s_stub, SPOOLSS_OPNUM_GetForm },
+ { spoolss_s_stub, SPOOLSS_OPNUM_SetForm },
+ { spoolss_s_stub, SPOOLSS_OPNUM_EnumMonitors },
+ { spoolss_s_stub, SPOOLSS_OPNUM_AddPort },
+ { spoolss_s_stub, SPOOLSS_OPNUM_ConfigurePort },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeletePort },
+ { spoolss_s_stub, SPOOLSS_OPNUM_CreatePrinterIc },
+ { spoolss_s_stub, SPOOLSS_OPNUM_PlayDescriptionPrinterIc },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterIc },
+ { spoolss_s_stub, SPOOLSS_OPNUM_AddPrinterConnection },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterConnection },
+ { spoolss_s_stub, SPOOLSS_OPNUM_PrinterMessageBox },
+ { spoolss_s_stub, SPOOLSS_OPNUM_AddMonitor },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeleteMonitor },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrintProcessor },
+ { spoolss_s_stub, SPOOLSS_OPNUM_AddPrintProvider },
+ { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrintProvider },
+ { spoolss_s_stub, SPOOLSS_OPNUM_ResetPrinter },
+ { spoolss_s_stub, SPOOLSS_OPNUM_FindFirstChangeNotify },
+ { spoolss_s_stub, SPOOLSS_OPNUM_FindNextChangeNotify },
+ { spoolss_s_stub, SPOOLSS_OPNUM_RouterFindFirstNotify },
+ { spoolss_s_stub, SPOOLSS_OPNUM_ReplyOpenPrinter },
+ { spoolss_s_stub, SPOOLSS_OPNUM_RouterReplyPrinter },
+ { spoolss_s_stub, SPOOLSS_OPNUM_ReplyClosePrinter },
+ { spoolss_s_stub, SPOOLSS_OPNUM_AddPortEx },
+ { spoolss_s_stub, SPOOLSS_OPNUM_RemoteFindFirstChangeNotify },
+ { spoolss_s_stub, SPOOLSS_OPNUM_SpoolerInitialize },
+ { spoolss_s_stub, SPOOLSS_OPNUM_ResetPrinterEx },
+ { spoolss_s_stub, SPOOLSS_OPNUM_RouterRefreshChangeNotify },
+ { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinter2 },
+ {0}
+};
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_srvsvc.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_srvsvc.c
new file mode 100644
index 0000000000..2a9a1f52d0
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_srvsvc.c
@@ -0,0 +1,1684 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Server Service RPC (SRVSVC) server-side interface definition.
+ * The server service provides a remote administration interface.
+ *
+ * This service uses NERR/Win32 error codes rather than NT status
+ * values.
+ */
+
+#include <sys/errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <strings.h>
+#include <time.h>
+#include <tzfile.h>
+#include <time.h>
+#include <thread.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <smbsrv/smb_fsd.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/cifs.h>
+#include <smbsrv/netrauth.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/srvsvc.ndl>
+#include <smbsrv/smb_common_door.h>
+
+#define SV_TYPE_SENT_BY_ME (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_NT)
+
+static DWORD mlsvc_NetSessionEnumLevel0(struct mslm_infonres *, DWORD,
+ struct mlrpc_xaction *);
+static DWORD mlsvc_NetSessionEnumLevel1(struct mslm_infonres *, DWORD,
+ struct mlrpc_xaction *);
+static DWORD mlsvc_NetShareEnumLevel0(struct mslm_infonres *, DWORD,
+ struct mlrpc_xaction *, char);
+static DWORD mlsvc_NetShareEnumLevel1(struct mslm_infonres *, DWORD,
+ struct mlrpc_xaction *, char);
+static DWORD mlsvc_NetShareEnumLevel2(struct mslm_infonres *, DWORD,
+ struct mlrpc_xaction *, char);
+static DWORD mlsvc_NetShareEnumLevel502(struct mslm_infonres *, DWORD,
+ struct mlrpc_xaction *, char);
+static DWORD mlsvc_NetShareEnumCommon(struct mlrpc_xaction *, DWORD,
+ int, lmshare_info_t *, void *);
+static int srvsvc_is_poweruser(struct mlrpc_xaction *);
+
+static char empty_string[1];
+
+static mlrpc_stub_table_t srvsvc_stub_table[];
+
+static mlrpc_service_t srvsvc_service = {
+ "SRVSVC", /* name */
+ "Server services", /* desc */
+ "\\srvsvc", /* endpoint */
+ PIPE_NTSVCS, /* sec_addr_port */
+ "4b324fc8-1670-01d3-12785a47bf6ee188", 3, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(srvsvc_interface), /* interface ti */
+ srvsvc_stub_table /* stub_table */
+};
+
+/*
+ * srvsvc_fix_comment
+ *
+ * The parser sometimes has problems with empty strings so we
+ * need to ensure that the comment field has something in it.
+ */
+static inline char *
+srvsvc_fix_comment(char *original, char *alternative)
+{
+ if (original == 0 || strlen(original) == 0)
+ return (alternative);
+
+ return (original);
+}
+
+/*
+ * srvsvc_share_mkpath
+ *
+ * Create the share path required by the share enum calls. This function
+ * creates the path in a MLRPC heap buffer ready for use by the caller.
+ *
+ * Some Windows over-the-wire backup applications do not work unless a
+ * drive letter is present in the share path. We don't care about the
+ * drive letter since the path is fully qualified with the volume name.
+ * We can try using drive B since by default that letter isn't assigned
+ * and even if it conflicts, we should still be okay with the fully
+ * qualified path.
+ *
+ * Windows clients seem to be mostly okay with the forward slash in
+ * share paths but they cannot handle one immediately after the drive
+ * letter, i.e. D:/. For consistency we convert all the slashes in
+ * the path.
+ *
+ * Returns a pointer to a heap buffer containing the share path, which
+ * could be a null pointer if the heap allocation fails.
+ */
+static char *
+srvsvc_share_mkpath(struct mlrpc_xaction *mxa, char *path)
+{
+ char tmpbuf[MAXPATHLEN];
+ char *p;
+
+ if (strlen(path) == 0)
+ return (MLRPC_HEAP_STRSAVE(mxa, path));
+
+ /* strip the volume from the path (/vol1/home -> /home) */
+ p = strchr(path[0] == '/' ? &path[1] : path, '/');
+
+ (void) snprintf(tmpbuf, MAXPATHLEN, "%c:%s", 'B'
+ /* vattr.drive_letter */, p == NULL ? "/": p);
+ (void) strsubst(tmpbuf, '/', '\\');
+
+ return (MLRPC_HEAP_STRSAVE(mxa, tmpbuf));
+}
+
+/*
+ * srvsvc_add_autohome
+ *
+ * Add the autohome share for the user to the shares' list
+ * if autohome is enabled the share is not a permanent share.
+ */
+static int
+srvsvc_add_autohome(struct mlrpc_xaction *mxa, char *username, DWORD i,
+ int level, char *infop)
+{
+ lmshare_info_t si;
+ DWORD status;
+
+ if ((lmshare_getinfo(username, &si) == NERR_Success) &&
+ (si.mode & LMSHRM_TRANS)) {
+ status = mlsvc_NetShareEnumCommon(mxa, i, level, &si,
+ (void *)infop);
+ if (status == ERROR_SUCCESS)
+ i++;
+ }
+
+ return (i);
+}
+
+/*
+ * srvsvc_initialize
+ *
+ * This function registers the SRVSVC RPC interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+srvsvc_initialize(void)
+{
+ (void) mlrpc_register_service(&srvsvc_service);
+}
+
+/*
+ * srvsvc_s_NetConnectEnum
+ *
+ * Under construction. This is just enough to get the interface working.
+ * Current level 0 and level 1 connection info are supported.
+ *
+ * Level 1 request is made by 'srvmgr' (Server Manager)
+ * utility of NT Server part of NT Domain to MLRPC server
+ * while double click of share info icon. These values
+ * are currectly virtual to MLRPC client and does't
+ * reflect the real state of server.
+ */
+static int
+srvsvc_s_NetConnectEnum(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetConnectEnum *param = arg;
+ struct mslm_NetConnectInfoBuf0 *ci0;
+ struct mslm_NetConnectInfoBuf1 *ci1;
+ DWORD status;
+
+ status = ERROR_SUCCESS;
+ switch (param->info.level) {
+ case 0:
+ ci0 = MLRPC_HEAP_NEW(mxa, struct mslm_NetConnectInfoBuf0);
+ if (ci0 == 0) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ ci0->coni0_id = 0x17;
+
+ param->info.ru.info0
+ = MLRPC_HEAP_NEW(mxa, struct mslm_NetConnectInfo0);
+
+ if (param->info.ru.info0 == 0) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ param->info.ru.info0->ci0 = ci0;
+ param->info.ru.info0->entries_read = 1;
+
+ param->total_entries = 1;
+ param->resume_handle = 0;
+ break;
+
+ case 1:
+ ci1 = MLRPC_HEAP_NEW(mxa, struct mslm_NetConnectInfoBuf1);
+ if (ci1 == 0) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ ci1->coni1_id = 0x17;
+ ci1->coni1_type = STYPE_IPC;
+ ci1->coni1_num_opens = 1;
+ ci1->coni1_num_users = 1;
+ ci1->coni1_time = 16;
+ ci1->coni1_username =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, "Administrator");
+
+ ci1->coni1_netname =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, "IPC$");
+
+ param->info.ru.info1 = MLRPC_HEAP_NEW(mxa,
+ struct mslm_NetConnectInfo1);
+
+ if (param->info.ru.info1 == 0) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ param->info.ru.info1->ci1 = ci1;
+ param->info.ru.info1->entries_read = 1;
+
+ param->total_entries = 1;
+ param->resume_handle = 0;
+ break;
+
+ default:
+ status = ERROR_ACCESS_DENIED;
+ break;
+ }
+
+ if (status != ERROR_SUCCESS)
+ bzero(param, sizeof (struct mslm_NetConnectEnum));
+
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * srvsvc_s_NetFileEnum
+ *
+ * Under construction. The values used here are fictional values and
+ * bear no relation to any real values, living or otherwise. I just
+ * made them up to get the interface working.
+ */
+static int
+srvsvc_s_NetFileEnum(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetFileEnum *param = arg;
+ struct mslm_NetFileInfoBuf3 *fi3;
+
+ if (param->info.switch_value != 3) {
+ bzero(param, sizeof (struct mslm_NetFileEnum));
+ param->status = ERROR_INVALID_LEVEL;
+ return (MLRPC_DRC_OK);
+ }
+
+ fi3 = MLRPC_HEAP_NEW(mxa, struct mslm_NetFileInfoBuf3);
+ if (fi3 == 0) {
+ bzero(param, sizeof (struct mslm_NetFileEnum));
+ param->status = ERROR_NOT_ENOUGH_MEMORY;
+ return (MLRPC_DRC_OK);
+ }
+
+ fi3->fi3_id = 0xF5;
+ fi3->fi3_permissions = 0x23;
+ fi3->fi3_num_locks = 0;
+ fi3->fi3_pathname =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, "\\PIPE\\srvsvc");
+
+ fi3->fi3_username =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, "Administrator");
+
+ param->info.ru.info3 = MLRPC_HEAP_NEW(mxa, struct mslm_NetFileInfo3);
+ if (param->info.ru.info3 == 0) {
+ bzero(param, sizeof (struct mslm_NetFileEnum));
+ param->status = ERROR_NOT_ENOUGH_MEMORY;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->info.ru.info3->fi3 = fi3;
+ param->info.ru.info3->entries_read = 1;
+ param->total_entries = 1;
+
+ if (param->resume_handle)
+ *param->resume_handle = 0x5F;
+
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * srvsvc_s_NetFileClose
+ *
+ * Under construction. This is just enough to get the interface working.
+ */
+/*ARGSUSED*/
+static int
+srvsvc_s_NetFileClose(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetFileClose *param = arg;
+
+ bzero(param, sizeof (struct mslm_NetFileClose));
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * srvsvc_s_NetShareGetInfo
+ *
+ * This call is made by Windows2000 to get share information. There are
+ * probably other information levels but these are the only ones I've
+ * seen so far.
+ *
+ * Returns Win32 error codes.
+ */
+static int
+srvsvc_s_NetShareGetInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mlsm_NetShareGetInfo *param = arg;
+ struct mslm_NetShareGetInfo0 *info0;
+ struct mslm_NetShareGetInfo1 *info1;
+ struct mslm_NetShareGetInfo2 *info2;
+ struct mslm_NetShareGetInfo502 *info502;
+ struct mslm_NetShareGetInfo1005 *info1005;
+ struct lmshare_info si;
+ char shr_comment[LMSHR_COMMENT_MAX];
+ DWORD status;
+
+ status = lmshare_getinfo((char *)param->netname, &si);
+ if (status != NERR_Success) {
+ if (strcasecmp((const char *)param->netname, "IPC$") == 0) {
+ /*
+ * Windows clients don't send the \\PIPE path for IPC$.
+ */
+ (void) memset(&si, 0, sizeof (lmshare_info_t));
+ (void) strcpy(si.share_name, "IPC$");
+ (void) strcpy(si.comment, "Remote IPC");
+ si.stype = (int)(STYPE_IPC | STYPE_SPECIAL);
+ } else {
+ bzero(param, sizeof (struct mlsm_NetShareGetInfo));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+ }
+
+ if (si.comment && strlen(si.comment))
+ (void) snprintf(shr_comment, sizeof (shr_comment), "%s %s",
+ si.directory, si.comment);
+ else
+ (void) strcpy(shr_comment, si.directory);
+
+ status = ERROR_SUCCESS;
+
+ switch (param->level) {
+ case 0:
+ info0 = MLRPC_HEAP_NEW(mxa, struct mslm_NetShareGetInfo0);
+ if (info0 == 0) {
+
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ info0->shi0_netname
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, si.share_name);
+
+ param->result.ru.info0 = info0;
+ break;
+
+ case 1:
+ info1 = MLRPC_HEAP_NEW(mxa, struct mslm_NetShareGetInfo1);
+ if (info1 == 0) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ info1->shi1_netname =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, si.share_name);
+ info1->shi1_comment =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, shr_comment);
+ info1->shi1_type = si.stype;
+ param->result.ru.info1 = info1;
+ break;
+
+ case 2:
+ info2 = MLRPC_HEAP_NEW(mxa, struct mslm_NetShareGetInfo2);
+ if (info2 == 0) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ info2->shi2_netname =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, si.share_name);
+ info2->shi2_comment =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, shr_comment);
+ info2->shi2_path =
+ (unsigned char *)srvsvc_share_mkpath(mxa, si.directory);
+ info2->shi2_passwd = 0;
+ info2->shi2_type = si.stype;
+ info2->shi2_permissions = 0;
+ info2->shi2_max_uses = SHI_USES_UNLIMITED;
+ info2->shi2_current_uses = 0;
+ param->result.ru.info2 = info2;
+ break;
+
+ case 1005:
+ info1005 = MLRPC_HEAP_NEW(mxa, struct mslm_NetShareGetInfo1005);
+ if (info1005 == 0) {
+
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ info1005->shi1005_flags = 0;
+ param->result.ru.info1005 = info1005;
+ break;
+
+ case 502:
+ /*
+ * Level 502 provides level 2 information plus a
+ * security descriptor. We don't support security
+ * descriptors on shares yet.
+ */
+ info502 = MLRPC_HEAP_NEW(mxa, struct mslm_NetShareGetInfo502);
+ if (info502 == 0) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ info502->shi502_netname =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, si.share_name);
+ info502->shi502_comment =
+ (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, shr_comment);
+ info502->shi502_path =
+ (unsigned char *)srvsvc_share_mkpath(mxa, si.directory);
+ info502->shi502_passwd = 0;
+ info502->shi502_type = si.stype;
+ info502->shi502_permissions = 0;
+ info502->shi502_max_uses = SHI_USES_UNLIMITED;
+ info502->shi502_current_uses = 0;
+ info502->shi502_reserved = 0;
+ info502->shi502_security_descriptor = 0;
+ param->result.ru.info502 = info502;
+ break;
+
+ default:
+ status = ERROR_ACCESS_DENIED;
+ break;
+ }
+
+ if (status != ERROR_SUCCESS)
+ bzero(param, sizeof (struct mlsm_NetShareGetInfo));
+ else
+ param->result.switch_value = param->level;
+
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * srvsvc_s_NetShareSetInfo
+ *
+ * This call is made by SrvMgr to set share information.
+ * Always returns ERROR_ACCESS_DENIED for now.
+ *
+ * Returns Win32 error codes.
+ */
+static int
+srvsvc_s_NetShareSetInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mlsm_NetShareSetInfo *param = arg;
+
+ (void) memset(param, 0, sizeof (struct mlsm_NetShareSetInfo));
+ param->parm_err_ptr = (DWORD)MLRPC_HEAP_MALLOC(mxa, sizeof (DWORD));
+ param->parm_err = 0;
+
+ smb_config_rdlock();
+ if (smb_config_getyorn(SMB_CI_SRVSVC_SHRSET_ENABLE) != 0)
+ param->status = ERROR_SUCCESS;
+ else
+ param->status = ERROR_ACCESS_DENIED;
+ smb_config_unlock();
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * srvsvc_s_NetSessionEnum
+ *
+ * Level 1 request is made by the 'srvmgr' (Server Manager) utility on
+ * NT Server when the user info icon is selected.
+ *
+ * Return Values
+ * If the function succeeds, the return value is NERR_Success.
+ * If the function fails, the return value can be one of the following
+ * error codes:
+ *
+ * ERROR_ACCESS_DENIED The user does not have access to the requested
+ * information.
+ * ERROR_INVALID_LEVEL The value specified for the level parameter is
+ * invalid.
+ * ERROR_INVALID_PARAMETER The specified parameter is invalid.
+ * ERROR_MORE_DATA More entries are available. Specify a large
+ * enough buffer to receive all entries.
+ * ERROR_NOT_ENOUGH_MEMORY Insufficient memory is available.
+ * NERR_ClientNameNotFound A session does not exist with the computer
+ * name.
+ * NERR_InvalidComputer The computer name is invalid.
+ * NERR_UserNotFound The user name could not be found.
+ */
+static int
+srvsvc_s_NetSessionEnum(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetSessionEnum *param = arg;
+ struct mslm_infonres *infonres;
+ DWORD status;
+ DWORD n_sessions;
+
+ infonres = MLRPC_HEAP_NEW(mxa, struct mslm_infonres);
+ if (infonres == 0) {
+ bzero(param, sizeof (struct mslm_NetSessionEnum));
+ param->status = ERROR_NOT_ENOUGH_MEMORY;
+ return (MLRPC_DRC_OK);
+ }
+
+ infonres->entriesread = 0;
+ infonres->entries = 0;
+ param->result.level = param->level;
+ param->result.bufptr.p = infonres;
+ param->total_entries = 1;
+ param->status = ERROR_SUCCESS;
+
+ n_sessions = (DWORD) smb_dwncall_user_num();
+
+ switch (param->level) {
+ case 0:
+ status = mlsvc_NetSessionEnumLevel0(infonres, n_sessions, mxa);
+ break;
+
+ case 1:
+ status = mlsvc_NetSessionEnumLevel1(infonres, n_sessions, mxa);
+ break;
+
+ default:
+ status = ERROR_INVALID_LEVEL;
+ break;
+ }
+
+ if (status != 0) {
+ bzero(param, sizeof (struct mslm_NetSessionEnum));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->resume_handle = 0;
+ param->total_entries = infonres->entriesread;
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * mlsvc_NetSessionEnumLevel0
+ *
+ * Build the level 0 session information.
+ */
+/*ARGSUSED*/
+static DWORD
+mlsvc_NetSessionEnumLevel0(struct mslm_infonres *infonres, DWORD n_sessions,
+ struct mlrpc_xaction *mxa)
+{
+ struct mslm_SESSION_INFO_0 *info0;
+ smb_dr_ulist_t *ulist;
+ smb_dr_user_ctx_t *user;
+ char *workstation;
+ char ipaddr_buf[INET_ADDRSTRLEN];
+ int i, offset, cnt, total;
+
+ info0 = MLRPC_HEAP_NEWN(mxa, struct mslm_SESSION_INFO_0, n_sessions);
+ if (info0 == 0)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ ulist = malloc(sizeof (smb_dr_ulist_t));
+ if (!ulist)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ for (total = 0, offset = 0;
+ (cnt = smb_dwncall_get_users(offset, ulist)) > 0;
+ offset += cnt) {
+ for (i = 0; i < cnt && total < n_sessions; i++, total++) {
+ user = &ulist->dul_users[i];
+ /*
+ * Ignore local tokens (IP address is zero).
+ */
+ if (user->du_ipaddr == 0) {
+ total--;
+ smb_dr_ulist_free(ulist);
+ ulist = malloc(sizeof (smb_dr_ulist_t));
+ if (!ulist)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ continue;
+ }
+
+ if ((workstation = user->du_workstation) == 0) {
+ (void) inet_ntop(AF_INET,
+ (char *)&user->du_ipaddr, ipaddr_buf,
+ sizeof (ipaddr_buf));
+ workstation = ipaddr_buf;
+ }
+
+ info0[total].sesi0_cname = MLRPC_HEAP_STRSAVE(mxa,
+ workstation);
+ if (info0[total].sesi0_cname == 0) {
+ smb_dr_ulist_free(ulist);
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ }
+ smb_dr_ulist_free(ulist);
+ ulist = malloc(sizeof (smb_dr_ulist_t));
+ if (!ulist)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ }
+
+ infonres->entriesread = total;
+ infonres->entries = info0;
+ return (ERROR_SUCCESS);
+}
+
+
+/*
+ * mlsvc_NetSessionEnumLevel1
+ *
+ * Build the level 1 session information.
+ */
+/*ARGSUSED*/
+static DWORD
+mlsvc_NetSessionEnumLevel1(struct mslm_infonres *infonres, DWORD n_sessions,
+ struct mlrpc_xaction *mxa)
+{
+ struct mslm_SESSION_INFO_1 *info1;
+ smb_dr_ulist_t *ulist;
+ smb_dr_user_ctx_t *user;
+ char *workstation;
+ char *account;
+ char ipaddr_buf[INET_ADDRSTRLEN];
+ int i, offset, cnt, total;
+
+ info1 = MLRPC_HEAP_NEWN(mxa, struct mslm_SESSION_INFO_1, n_sessions);
+ if (info1 == 0)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ ulist = malloc(sizeof (smb_dr_ulist_t));
+ if (!ulist)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ for (total = 0, offset = 0;
+ (cnt = smb_dwncall_get_users(offset, ulist)) > 0;
+ offset += cnt) {
+ for (i = 0; i < cnt && total < n_sessions; i++, total++) {
+ user = &ulist->dul_users[i];
+ /*
+ * Ignore local user_ctxs (IP address is zero).
+ */
+ if (user->du_ipaddr == 0) {
+ total--;
+ smb_dr_ulist_free(ulist);
+ ulist = malloc(sizeof (smb_dr_ulist_t));
+ if (!ulist)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ continue;
+ }
+
+ if ((workstation = user->du_workstation) == 0) {
+ (void) inet_ntop(AF_INET,
+ (char *)&user->du_ipaddr,
+ ipaddr_buf, sizeof (ipaddr_buf));
+ workstation = ipaddr_buf;
+ }
+
+ if ((account = user->du_account) == 0)
+ account = "Unknown";
+
+ info1[total].sesi1_cname = MLRPC_HEAP_STRSAVE(mxa,
+ workstation);
+ info1[total].sesi1_uname = MLRPC_HEAP_STRSAVE(mxa,
+ account);
+
+ if (info1[total].sesi1_cname == 0 ||
+ info1[total].sesi1_uname == 0) {
+ smb_dr_ulist_free(ulist);
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ info1[total].sesi1_nopens = 1;
+ info1[total].sesi1_time = time(0) -
+ user->du_logon_time;
+ info1[total].sesi1_itime = 0;
+ info1[total].sesi1_uflags =
+ (user->du_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
+ }
+ smb_dr_ulist_free(ulist);
+ ulist = malloc(sizeof (smb_dr_ulist_t));
+ if (!ulist)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ infonres->entriesread = total;
+ infonres->entries = info1;
+ return (ERROR_SUCCESS);
+}
+
+/*
+ * srvsvc_s_NetSessionDel
+ *
+ * Ends a network session between a server and a workstation.
+ * On NT only members of the Administrators or Account Operators
+ * local groups are permitted to use NetSessionDel.
+ *
+ * Return Values
+ * If the function succeeds, the return value is NERR_Success/
+ * ERROR_SUCCESS. If the function fails, the return value can be
+ * one of the following error codes:
+ *
+ * ERROR_ACCESS_DENIED The user does not have access to the
+ * requested information.
+ * ERROR_INVALID_PARAMETER The specified parameter is invalid.
+ * ERROR_NOT_ENOUGH_MEMORY Insufficient memory is available.
+ * NERR_ClientNameNotFound A session does not exist with that
+ * computer name.
+ */
+static int
+srvsvc_s_NetSessionDel(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetSessionDel *param = arg;
+
+ if (srvsvc_is_poweruser(mxa) == 0) {
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * SRVSVC NetServerGetInfo
+ *
+ * IN LPTSTR servername,
+ * IN DWORD level,
+ * OUT union switch(level) {
+ * case 100: mslm_SERVER_INFO_100 *p100;
+ * case 101: mslm_SERVER_INFO_101 *p101;
+ * case 102: mslm_SERVER_INFO_102 *p102;
+ * default: char *nullptr;
+ * } bufptr,
+ * OUT DWORD status
+ */
+static int
+srvsvc_s_NetServerGetInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetServerGetInfo *param = arg;
+ struct mslm_SERVER_INFO_100 *info100;
+ struct mslm_SERVER_INFO_101 *info101;
+ struct mslm_SERVER_INFO_102 *info102;
+ char *sys_comment;
+ char hostname[MAXHOSTNAMELEN];
+
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) {
+netservergetinfo_no_memory:
+ bzero(param, sizeof (struct mslm_NetServerGetInfo));
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ smb_config_rdlock();
+ sys_comment = smb_config_getstr(SMB_CI_SYS_CMNT);
+ sys_comment = srvsvc_fix_comment(sys_comment, " ");
+ smb_config_unlock();
+
+ switch (param->level) {
+ case 100:
+ info100 = MLRPC_HEAP_NEW(mxa, struct mslm_SERVER_INFO_100);
+ if (info100 == 0)
+ goto netservergetinfo_no_memory;
+
+ bzero(info100, sizeof (struct mslm_SERVER_INFO_100));
+ info100->sv100_platform_id = SV_PLATFORM_ID_NT;
+ info100->sv100_name
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, hostname);
+
+ if (info100->sv100_name == 0)
+ goto netservergetinfo_no_memory;
+
+ param->result.bufptr.bufptr100 = info100;
+ break;
+
+ case 101:
+ info101 = MLRPC_HEAP_NEW(mxa, struct mslm_SERVER_INFO_101);
+ if (info101 == 0)
+ goto netservergetinfo_no_memory;
+
+ bzero(info101, sizeof (struct mslm_SERVER_INFO_101));
+ info101->sv101_platform_id = SV_PLATFORM_ID_NT;
+ info101->sv101_version_major = 4;
+ info101->sv101_version_minor = 0;
+ info101->sv101_type = SV_TYPE_SENT_BY_ME;
+ info101->sv101_name
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, hostname);
+
+ info101->sv101_comment
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, sys_comment);
+
+ if (info101->sv101_name == 0 || info101->sv101_comment == 0)
+ goto netservergetinfo_no_memory;
+
+ param->result.bufptr.bufptr101 = info101;
+ break;
+
+ case 102:
+ info102 = MLRPC_HEAP_NEW(mxa, struct mslm_SERVER_INFO_102);
+ if (info102 == 0)
+ goto netservergetinfo_no_memory;
+
+ bzero(info102, sizeof (struct mslm_SERVER_INFO_102));
+ info102->sv102_platform_id = SV_PLATFORM_ID_NT;
+ info102->sv102_version_major = 4;
+ info102->sv102_version_minor = 0;
+ info102->sv102_type = SV_TYPE_SENT_BY_ME;
+ info102->sv102_name
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, hostname);
+
+ info102->sv102_comment
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, sys_comment);
+
+ /*
+ * The following level 102 fields are defaulted to zero
+ * by virtue of the call to bzero above.
+ *
+ * sv102_users
+ * sv102_disc
+ * sv102_hidden
+ * sv102_announce
+ * sv102_anndelta
+ * sv102_licenses
+ * sv102_userpath
+ */
+ if (info102->sv102_name == 0 || info102->sv102_comment == 0)
+ goto netservergetinfo_no_memory;
+
+ param->result.bufptr.bufptr102 = info102;
+ break;
+
+ default:
+ bzero(&param->result,
+ sizeof (struct mslm_NetServerGetInfo_result));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->result.level = param->level;
+ param->status = (ERROR_SUCCESS);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * NetRemoteTOD
+ *
+ * Returns information about the time of day on this server.
+ *
+ * typedef struct _TIME_OF_DAY_INFO {
+ * DWORD tod_elapsedt; // seconds since 00:00:00 January 1 1970 GMT
+ * DWORD tod_msecs; // arbitrary milliseconds (since reset)
+ * DWORD tod_hours; // current hour [0-23]
+ * DWORD tod_mins; // current minute [0-59]
+ * DWORD tod_secs; // current second [0-59]
+ * DWORD tod_hunds; // current hundredth (0.01) second [0-99]
+ * LONG tod_timezone; // time zone of the server
+ * DWORD tod_tinterval; // clock tick time interval
+ * DWORD tod_day; // day of the month [1-31]
+ * DWORD tod_month; // month of the year [1-12]
+ * DWORD tod_year; // current year
+ * DWORD tod_weekday; // day of the week since sunday [0-6]
+ * } TIME_OF_DAY_INFO;
+ *
+ * The time zone of the server is calculated in minutes from Greenwich
+ * Mean Time (GMT). For time zones west of Greenwich, the value is
+ * positive; for time zones east of Greenwich, the value is negative.
+ * A value of -1 indicates that the time zone is undefined.
+ *
+ * The clock tick value represents a resolution of one ten-thousandth
+ * (0.0001) second.
+ */
+static int
+srvsvc_s_NetRemoteTOD(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetRemoteTOD *param = arg;
+ struct mslm_TIME_OF_DAY_INFO *tod;
+ struct timeval time_val;
+ struct tm tm;
+
+ (void) gettimeofday(&time_val, 0);
+ (void) gmtime_r(&time_val.tv_sec, &tm);
+
+ tod = MLRPC_HEAP_NEW(mxa, struct mslm_TIME_OF_DAY_INFO);
+ if (tod == NULL) {
+ bzero(param, sizeof (struct mslm_NetRemoteTOD));
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ tod->tod_elapsedt = time_val.tv_sec;
+ tod->tod_msecs = time_val.tv_usec;
+ tod->tod_hours = tm.tm_hour;
+ tod->tod_mins = tm.tm_min;
+ tod->tod_secs = tm.tm_sec;
+ tod->tod_hunds = 0;
+ tod->tod_tinterval = 1000;
+ tod->tod_day = tm.tm_mday;
+ tod->tod_month = tm.tm_mon+1;
+ tod->tod_year = tm.tm_year+1900;
+ tod->tod_weekday = tm.tm_wday;
+
+ (void) localtime_r(&time_val.tv_sec, &tm);
+
+ param->bufptr = tod;
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * srvsvc_s_NetNameValidate
+ *
+ * Perform name validation.
+ * I've observed that the Computer Management Windows Application
+ * always send this request with type=0x09 and the flags=0 when
+ * attempting to validate a share name.
+ *
+ * The share name is consider invalid if it contains any of the
+ * following character (as mentioned in MSDN article #236388).
+ *
+ * " / \ [ ] : | < > + ; , ? * =
+ *
+ *
+ * For now, if the type is other than 0x09, return access denied.
+ *
+ * Returns Win32 error codes.
+ */
+/*ARGSUSED*/
+static int
+srvsvc_s_NetNameValidate(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetNameValidate *param = arg;
+
+ switch (param->type) {
+ case 0x09:
+ param->status = lmshare_is_valid((char *)param->pathname) ?
+ ERROR_SUCCESS : ERROR_INVALID_NAME;
+ break;
+
+ default:
+ param->status = ERROR_ACCESS_DENIED;
+ break;
+ }
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * srvsvc_s_NetShareAdd
+ *
+ * Add a new share. We support info levels 2 and 502 but ignore the
+ * security descriptor in level 502 requests. Only the administrator,
+ * or a member of the domain administrators group, is allowed to add
+ * shares.
+ *
+ * This interface is used by the rmtshare command from the NT resource
+ * kit. Rmtshare allows a client to add or remove shares on a server
+ * from the client's command line.
+ *
+ * Note that we don't support security descriptors on a share. If the
+ * /grant is used, the share will be created but the subsequent attempt
+ * to manipulate the security descriptor (NetShareGetInfo) will fail.
+ * Similarly for the /remove option.
+ *
+ * Returns Win32 error codes.
+ */
+static int
+srvsvc_s_NetShareAdd(void *arg, struct mlrpc_xaction *mxa)
+{
+ static DWORD parm_err = 0;
+ DWORD parm_stat;
+ struct mslm_NetShareAdd *param = arg;
+ smb_dr_user_ctx_t *user_ctx;
+ struct mslm_SHARE_INFO_2 *info2;
+ struct lmshare_info si;
+ char realpath[MAXPATHLEN];
+
+ user_ctx = mxa->context->user_ctx;
+
+ if (srvsvc_is_poweruser(mxa) == 0) {
+ bzero(param, sizeof (struct mslm_NetShareAdd));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+ }
+
+ switch (param->level) {
+ case 2:
+ info2 = param->info.un.info2;
+ break;
+
+ case 502:
+ info2 = (struct mslm_SHARE_INFO_2 *)param->info.un.info502;
+ break;
+
+ default:
+ bzero(param, sizeof (struct mslm_NetShareAdd));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (info2->shi2_netname == 0 || info2->shi2_path == 0) {
+ bzero(param, sizeof (struct mslm_NetShareAdd));
+ param->status = NERR_NetNameNotFound;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (lmshare_is_restricted((char *)info2->shi2_netname)) {
+ bzero(param, sizeof (struct mslm_NetShareAdd));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (info2->shi2_remark == 0)
+ info2->shi2_remark = (unsigned char *)"";
+
+ /*
+ * Derive the real path which will be stored in the
+ * directory field of the lmshare_info_t structure
+ * from the path field in this RPC request.
+ */
+ parm_stat = lmshare_get_realpath((const char *)info2->shi2_path,
+ realpath, MAXPATHLEN);
+
+ if (parm_stat != NERR_Success) {
+ bzero(param, sizeof (struct mslm_NetShareAdd));
+ param->status = parm_stat;
+ param->parm_err
+ = (user_ctx->du_native_os == NATIVE_OS_WIN95) ?
+ 0 : &parm_err;
+ return (MLRPC_DRC_OK);
+ }
+
+ (void) memset(&si, 0, sizeof (lmshare_info_t));
+ (void) strlcpy(si.share_name, (const char *)info2->shi2_netname,
+ MAXNAMELEN);
+
+ (void) strlcpy(si.directory, realpath, MAXPATHLEN);
+ (void) strlcpy(si.comment, (const char *)info2->shi2_remark,
+ LMSHR_COMMENT_MAX);
+
+ si.mode = LMSHRM_PERM;
+
+ param->status = lmshare_add(&si, 1);
+ param->parm_err = (user_ctx->du_native_os == NATIVE_OS_WIN95) ?
+ 0 : &parm_err;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * srvsvc_is_poweruser
+ *
+ * Check whether or not the specified user has power-user privileges,
+ * i.e. is a member of the Domain Admins, Administrators or Power
+ * Users groups. This is typically required for operations such as
+ * adding/deleting shares.
+ *
+ * Returns 1 if the user is a power user, otherwise returns 0.
+ */
+static int
+srvsvc_is_poweruser(struct mlrpc_xaction *mxa)
+{
+ smb_dr_user_ctx_t *user = mxa->context->user_ctx;
+
+ return ((user->du_flags & SMB_ATF_ADMIN) ||
+ (user->du_flags & SMB_ATF_POWERUSER));
+}
+
+/*
+ * srvsvc_s_NetShareEnum
+ *
+ * Request for various levels of information about our shares.
+ * Level 0: just the share names.
+ * Level 1: the share name, the share type and the comment field.
+ * Level 2: everything that we know about the shares.
+ */
+static int
+srvsvc_s_NetShareEnum(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetShareEnum *param = arg;
+ struct mslm_infonres *infonres;
+ DWORD status;
+ DWORD n_shares;
+
+ infonres = MLRPC_HEAP_NEW(mxa, struct mslm_infonres);
+ if (infonres == 0) {
+ bzero(param, sizeof (struct mslm_NetShareEnum));
+ param->status = ERROR_NOT_ENOUGH_MEMORY;
+ return (MLRPC_DRC_OK);
+ }
+
+ infonres->entriesread = 0;
+ infonres->entries = 0;
+ param->result.level = param->level;
+ param->result.bufptr.p = infonres;
+ param->totalentries = 1; /* NT stream hint value: prefmaxlen? */
+ param->status = ERROR_SUCCESS;
+
+ n_shares = lmshare_num_shares();
+
+ switch (param->level) {
+ case 0:
+ status = mlsvc_NetShareEnumLevel0(infonres, n_shares, mxa, 0);
+ break;
+
+ case 1:
+ status = mlsvc_NetShareEnumLevel1(infonres, n_shares, mxa, 0);
+ break;
+
+ case 2:
+ status = mlsvc_NetShareEnumLevel2(infonres, n_shares, mxa, 0);
+ break;
+
+ case 502:
+ status = mlsvc_NetShareEnumLevel502(infonres, n_shares, mxa, 0);
+ break;
+
+ default:
+ status = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (status != 0) {
+ bzero(param, sizeof (struct mslm_NetShareEnum));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->resume_handle = 0;
+ param->totalentries = infonres->entriesread;
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+
+/*
+ * srvsvc_s_NetShareEnumSticky
+ *
+ * Request for various levels of information about our shares.
+ * Level 0: just the share names.
+ * Level 1: the share name, the share type and the comment field.
+ * Level 2: everything that we know about the shares.
+ *
+ * NetShareEnumSticky is the same as NetShareEnum except that hidden
+ * shares are not returned. This call was apparently added due to a
+ * bug in the NT implementation of NetShareEnum - it didn't process
+ * the resume handle correctly so that attempts to enumerate large
+ * share lists resulted in an infinite loop.
+ */
+static int
+srvsvc_s_NetShareEnumSticky(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetShareEnum *param = arg;
+ struct mslm_infonres *infonres;
+ DWORD resume_handle;
+ DWORD status;
+ DWORD n_shares;
+
+ infonres = MLRPC_HEAP_NEW(mxa, struct mslm_infonres);
+ if (infonres == 0) {
+ bzero(param, sizeof (struct mslm_NetShareEnum));
+ param->status = ERROR_NOT_ENOUGH_MEMORY;
+ return (MLRPC_DRC_OK);
+ }
+
+ infonres->entriesread = 0;
+ infonres->entries = 0;
+ param->result.level = param->level;
+ param->result.bufptr.p = infonres;
+ param->totalentries = 1; /* NT stream hint value: prefmaxlen? */
+ param->status = ERROR_SUCCESS;
+
+ n_shares = lmshare_num_shares();
+
+ if (param->resume_handle)
+ resume_handle = *param->resume_handle;
+ else
+ resume_handle = 0;
+
+ switch (param->level) {
+ case 0:
+ status = mlsvc_NetShareEnumLevel0(infonres, n_shares, mxa, 1);
+ break;
+
+ case 1:
+ status = mlsvc_NetShareEnumLevel1(infonres, n_shares, mxa, 1);
+ break;
+
+ case 2:
+ status = mlsvc_NetShareEnumLevel2(infonres, n_shares, mxa, 1);
+ break;
+
+ case 502:
+ status = mlsvc_NetShareEnumLevel502(infonres, n_shares, mxa, 1);
+ break;
+
+ default:
+ status = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (status != 0) {
+ bzero(param, sizeof (struct mslm_NetShareEnum));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (param->resume_handle)
+ *param->resume_handle = resume_handle;
+ param->totalentries = infonres->entriesread;
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+
+
+/*
+ * mlsvc_NetShareEnumLevel0
+ *
+ * Build the level 0 share information. The list should have been built
+ * before we got here so all we have to do is copy the share names to
+ * the response heap and setup the infonres values.
+ */
+static DWORD
+mlsvc_NetShareEnumLevel0(struct mslm_infonres *infonres, DWORD n_shares,
+ struct mlrpc_xaction *mxa, char sticky)
+{
+ struct mslm_SHARE_INFO_0 *info0;
+ lmshare_iterator_t *iterator;
+ lmshare_info_t *si;
+ DWORD i;
+ DWORD status;
+ smb_dr_user_ctx_t *user_ctx = mxa->context->user_ctx;
+
+ info0 = MLRPC_HEAP_NEWN(mxa, struct mslm_SHARE_INFO_0, n_shares);
+ if (info0 == 0) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ return (status);
+ }
+
+ iterator = lmshare_open_iterator(LMSHRM_ALL);
+ if (iterator == NULL) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ return (status);
+ }
+
+ i = 0;
+ while ((si = lmshare_iterate(iterator)) != 0) {
+ if (sticky && (si->stype & STYPE_SPECIAL))
+ continue;
+
+ if (smb_is_autohome(si))
+ continue;
+
+ status = mlsvc_NetShareEnumCommon(mxa, i, 0, si,
+ (void *)info0);
+
+ if (status != ERROR_SUCCESS)
+ break;
+
+ i++;
+ }
+
+ i = srvsvc_add_autohome(mxa, user_ctx->du_account, i, 0, (char *)info0);
+
+ lmshare_close_iterator(iterator);
+
+ infonres->entriesread = i;
+ infonres->entries = info0;
+ return (ERROR_SUCCESS);
+}
+
+
+/*
+ * mlsvc_NetShareEnumLevel1
+ *
+ * Build the level 1 share information. The list should have been built
+ * before we arrived here so all we have to do is copy the share info
+ * to the response heap and setup the infonres values. The only thing
+ * to be aware of here is that there are minor difference between the
+ * various share types.
+ */
+static DWORD
+mlsvc_NetShareEnumLevel1(struct mslm_infonres *infonres, DWORD n_shares,
+ struct mlrpc_xaction *mxa, char sticky)
+{
+ struct mslm_SHARE_INFO_1 *info1;
+ lmshare_iterator_t *iterator;
+ lmshare_info_t *si;
+ DWORD i;
+ smb_dr_user_ctx_t *user_ctx = mxa->context->user_ctx;
+
+ info1 = MLRPC_HEAP_NEWN(mxa, struct mslm_SHARE_INFO_1, n_shares);
+ if (info1 == 0)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ iterator = lmshare_open_iterator(LMSHRM_ALL);
+ if (iterator == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ i = 0;
+ while ((si = lmshare_iterate(iterator)) != 0) {
+ if (sticky && (si->stype & STYPE_SPECIAL))
+ continue;
+
+ if (smb_is_autohome(si))
+ continue;
+
+ if (mlsvc_NetShareEnumCommon(mxa, i, 1, si,
+ (void *)info1) != ERROR_SUCCESS)
+ break;
+ i++;
+ }
+
+ i = srvsvc_add_autohome(mxa, user_ctx->du_account, i, 1, (char *)info1);
+
+ lmshare_close_iterator(iterator);
+
+ infonres->entriesread = i;
+ infonres->entries = info1;
+ return (ERROR_SUCCESS);
+}
+
+/*
+ * mlsvc_NetShareEnumLevel2
+ *
+ * Build the level 2 share information. The list should have been built
+ * before we arrived here so all we have to do is copy the share info
+ * to the response heap and setup the infonres values. The only thing
+ * to be aware of here is that there are minor difference between the
+ * various share types.
+ */
+static DWORD
+mlsvc_NetShareEnumLevel2(struct mslm_infonres *infonres, DWORD n_shares,
+ struct mlrpc_xaction *mxa, char sticky)
+{
+ struct mslm_SHARE_INFO_2 *info2;
+ lmshare_iterator_t *iterator;
+ lmshare_info_t *si;
+ DWORD i;
+ smb_dr_user_ctx_t *user_ctx = mxa->context->user_ctx;
+
+ info2 = MLRPC_HEAP_NEWN(mxa, struct mslm_SHARE_INFO_2, n_shares);
+ if (info2 == 0)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ iterator = lmshare_open_iterator(LMSHRM_ALL);
+ if (iterator == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ i = 0;
+ while ((si = lmshare_iterate(iterator)) != 0) {
+ if (sticky && (si->stype & STYPE_SPECIAL))
+ continue;
+
+ if (smb_is_autohome(si))
+ continue;
+
+ if (mlsvc_NetShareEnumCommon(mxa, i, 2, si,
+ (void *)info2) != ERROR_SUCCESS)
+ break;
+ i++;
+ }
+
+ i = srvsvc_add_autohome(mxa, user_ctx->du_account, i, 2, (char *)info2);
+
+ lmshare_close_iterator(iterator);
+ infonres->entriesread = i;
+ infonres->entries = info2;
+ return (ERROR_SUCCESS);
+}
+
+/*
+ * mlsvc_NetShareEnumLevel502
+ *
+ * Build the level 502 share information. This is the same as level 2
+ * but with a security descriptor in the share structure. We don't
+ * support SD's on shares so we can just set that field to zero. See
+ * mlsvc_NetShareEnumLevel2 for more information.
+ */
+static DWORD
+mlsvc_NetShareEnumLevel502(struct mslm_infonres *infonres, DWORD n_shares,
+ struct mlrpc_xaction *mxa, char sticky)
+{
+ struct mslm_SHARE_INFO_502 *info502;
+ lmshare_iterator_t *iterator;
+ lmshare_info_t *si;
+ DWORD i;
+ smb_dr_user_ctx_t *user_ctx = mxa->context->user_ctx;
+
+ info502 = MLRPC_HEAP_NEWN(mxa, struct mslm_SHARE_INFO_502, n_shares);
+
+ if (info502 == 0)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ iterator = lmshare_open_iterator(LMSHRM_ALL);
+ if (iterator == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ i = 0;
+ while ((si = lmshare_iterate(iterator)) != 0) {
+ if (sticky && (si->stype & STYPE_SPECIAL))
+ continue;
+
+ if (smb_is_autohome(si))
+ continue;
+
+ if (mlsvc_NetShareEnumCommon(
+ mxa, i, 502, si, (void *)info502) != ERROR_SUCCESS)
+ break;
+ i++;
+ }
+
+ i = srvsvc_add_autohome(mxa, user_ctx->du_account, i, 502,
+ (char *)info502);
+
+ lmshare_close_iterator(iterator);
+ infonres->entriesread = i;
+ infonres->entries = info502;
+ return (ERROR_SUCCESS);
+}
+
+/*
+ * mlsvc_NetShareEnumCommon
+ *
+ * Build the levels 0, 1, 2 and 502 share information. This function
+ * is called by the various NetShareEnum levels for each share. If
+ * we cannot build the share data for some reason, we return an error
+ * but the actual value of the error is not important to the caller.
+ * The caller just needs to know not to include this info in the RPC
+ * response.
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_NOT_ENOUGH_MEMORY
+ * ERROR_INVALID_LEVEL
+ */
+static DWORD
+mlsvc_NetShareEnumCommon(struct mlrpc_xaction *mxa, DWORD i, int level,
+ lmshare_info_t *si, void *infop)
+{
+ struct mslm_SHARE_INFO_0 *info0;
+ struct mslm_SHARE_INFO_1 *info1;
+ struct mslm_SHARE_INFO_2 *info2;
+ struct mslm_SHARE_INFO_502 *info502;
+ char shr_comment[LMSHR_COMMENT_MAX];
+
+ if ((si->stype & STYPE_MASK) == STYPE_IPC) {
+ /*
+ * Windows clients don't send the \\PIPE path for IPC$.
+ */
+ si->directory[0] = '\0';
+ (void) strcpy(si->comment, "Remote IPC");
+ }
+
+ if (si->comment && strlen(si->comment))
+ (void) snprintf(shr_comment, sizeof (shr_comment), "%s (%s)",
+ si->directory, si->comment);
+ else
+ (void) strcpy(shr_comment, si->directory);
+
+ switch (level) {
+ case 0:
+ info0 = (struct mslm_SHARE_INFO_0 *)infop;
+ info0[i].shi0_netname
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, si->share_name);
+
+ if (info0[i].shi0_netname == 0)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ break;
+
+ case 1:
+ info1 = (struct mslm_SHARE_INFO_1 *)infop;
+ info1[i].shi1_netname
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, si->share_name);
+
+ info1[i].shi1_remark
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, shr_comment);
+
+ info1[i].shi1_type = si->stype;
+
+ if (!info1[i].shi1_netname || !info1[i].shi1_remark)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ break;
+
+ case 2:
+ info2 = (struct mslm_SHARE_INFO_2 *)infop;
+ info2[i].shi2_netname
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, si->share_name);
+
+ info2[i].shi2_remark
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, shr_comment);
+
+ info2[i].shi2_path
+ = (unsigned char *)srvsvc_share_mkpath(mxa, si->directory);
+
+ info2[i].shi2_type = si->stype;
+ info2[i].shi2_permissions = 0;
+ info2[i].shi2_max_uses = SHI_USES_UNLIMITED;
+ info2[i].shi2_current_uses = 0;
+ info2[i].shi2_passwd
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, empty_string);
+
+ if (!info2[i].shi2_netname || !info2[i].shi2_remark ||
+ !info2[i].shi2_passwd || !info2[i].shi2_path)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ break;
+
+ case 502:
+ info502 = (struct mslm_SHARE_INFO_502 *)infop;
+ info502[i].shi502_netname
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, si->share_name);
+
+ info502[i].shi502_remark
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, shr_comment);
+
+ info502[i].shi502_path
+ = (unsigned char *)srvsvc_share_mkpath(mxa, si->directory);
+
+ info502[i].shi502_type = si->stype;
+ info502[i].shi502_permissions = 0;
+ info502[i].shi502_max_uses = SHI_USES_UNLIMITED;
+ info502[i].shi502_current_uses = 0;
+ info502[i].shi502_passwd
+ = (unsigned char *)MLRPC_HEAP_STRSAVE(mxa, empty_string);
+
+ info502[i].shi502_reserved = 0;
+ info502[i].shi502_security_descriptor = 0;
+
+ if (!info502[i].shi502_netname || !info502[i].shi502_remark ||
+ !info502[i].shi502_passwd || !info502[i].shi502_path)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ break;
+
+ default:
+ return (ERROR_INVALID_LEVEL);
+ }
+
+ return (ERROR_SUCCESS);
+}
+
+/*
+ * srvsvc_s_NetShareDel
+ *
+ * Delete a share. Only the administrator, or a member of the domain
+ * administrators group, is allowed to delete shares.
+ *
+ * This interface is used by the rmtshare command from the NT resource
+ * kit. Rmtshare allows a client to add or remove shares on a server
+ * from the client's command line.
+ *
+ * Returns Win32 error codes.
+ */
+static int
+srvsvc_s_NetShareDel(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetShareDel *param = arg;
+
+ if (srvsvc_is_poweruser(mxa) == 0 ||
+ lmshare_is_restricted((char *)param->netname)) {
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->status = lmshare_delete((char *)param->netname, 1);
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * srvsvc_s_NetGetFileSecurity
+ *
+ * Get security descriptor of the requested file/folder
+ *
+ * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
+ * get the requested SD here in MLRPC code.
+ */
+/*ARGSUSED*/
+static int
+srvsvc_s_NetGetFileSecurity(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetGetFileSecurity *param = arg;
+
+ param->length = 0;
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * srvsvc_s_NetSetFileSecurity
+ *
+ * Set the given security descriptor for the requested file/folder
+ *
+ * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
+ * set the requested SD here in MLRPC code.
+ */
+/*ARGSUSED*/
+static int
+srvsvc_s_NetSetFileSecurity(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetSetFileSecurity *param = arg;
+
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+static mlrpc_stub_table_t srvsvc_stub_table[] = {
+ { srvsvc_s_NetConnectEnum, SRVSVC_OPNUM_NetConnectEnum },
+ { srvsvc_s_NetFileEnum, SRVSVC_OPNUM_NetFileEnum },
+ { srvsvc_s_NetFileClose, SRVSVC_OPNUM_NetFileClose },
+ { srvsvc_s_NetShareGetInfo, SRVSVC_OPNUM_NetShareGetInfo },
+ { srvsvc_s_NetShareSetInfo, SRVSVC_OPNUM_NetShareSetInfo },
+ { srvsvc_s_NetSessionEnum, SRVSVC_OPNUM_NetSessionEnum },
+ { srvsvc_s_NetSessionDel, SRVSVC_OPNUM_NetSessionDel },
+ { srvsvc_s_NetServerGetInfo, SRVSVC_OPNUM_NetServerGetInfo },
+ { srvsvc_s_NetRemoteTOD, SRVSVC_OPNUM_NetRemoteTOD },
+ { srvsvc_s_NetNameValidate, SRVSVC_OPNUM_NetNameValidate },
+ { srvsvc_s_NetShareAdd, SRVSVC_OPNUM_NetShareAdd },
+ { srvsvc_s_NetShareDel, SRVSVC_OPNUM_NetShareDel },
+ { srvsvc_s_NetShareEnum, SRVSVC_OPNUM_NetShareEnum },
+ { srvsvc_s_NetShareEnumSticky, SRVSVC_OPNUM_NetShareEnumSticky },
+ { srvsvc_s_NetGetFileSecurity, SRVSVC_OPNUM_NetGetFileSecurity },
+ { srvsvc_s_NetSetFileSecurity, SRVSVC_OPNUM_NetSetFileSecurity },
+ {0}
+};
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_svcctl.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_svcctl.c
new file mode 100644
index 0000000000..eca831f899
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_svcctl.c
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Service Control Services (SVCCTL) RPC interface definition.
+ * This interface provides remote access to add, remove, start and
+ * stop services.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/winsvc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/svcctl.ndl>
+
+/*
+ * SVCCTL diagnostics flag: set to 1 to enable verbose logging.
+ */
+int svcctl_debug = 0;
+
+/*
+ * The handle keys for the various types of handles returned
+ * by this interface.
+ */
+#define SVCCTL_MANAGER_KEY "svcctlManager"
+#define SVCCTL_SERVICE_KEY "svcctlService"
+
+
+typedef struct {
+ char *svc_name;
+ char *display_name;
+ char *local_name;
+} svc_info_t;
+
+
+/*
+ * The list of service we report to Server Manager. Entries don't
+ * have to be alphabetically arranged here; Server Manager will
+ * sort the list.
+ *
+ * NOTE: The enumeration list is currently built in a fixed-size,
+ * 1024 byte buffer. Be careful not to over-run the buffer.
+ */
+static svc_info_t svc_info[] = {
+ { "Dhcp", "DHCP Client", "dhcpc" },
+ { "EventLog", "EventLog", NULL },
+ { "Netlogon", "Net Logon", NULL },
+ { "WebAdmin", "Web Administration", "httpd" },
+ { "RlgnSvr", "Remote Login", "rlogin" },
+ { "RpcSs", "Remote Procedure Call (RPC) Service", NULL },
+ { "RshSvr", "Remote Shell", "rsh" },
+ { "SshSvr", "Secure Shell", "ssh" },
+ { "TlntSvr", "Telnet", "telnet" },
+ { "Dnscache", "DNS Client", "dns" },
+ { "NisSvr", "Network Information Services", NULL },
+ { "NtLmSsp", "NT LM Security Support Provider", NULL },
+ { "Samss", "Security Accounts Manager", NULL },
+ { "UPS", "Uninterruptible Power Supply", "ups" },
+ { "TftpSvr", "TFTP", "tftp" }
+};
+
+#define SVCCTL_NUM_SVCS (sizeof (svc_info)/sizeof (svc_info[0]))
+
+
+static DWORD svcctl_get_status(const char *);
+static DWORD svcctl_validate_service(char *);
+static DWORD svcctl_validate_handle(char *, ms_handle_t *, char *,
+ struct mlrpc_xaction *);
+static int svcctl_is_admin(struct mlrpc_xaction *);
+
+static int svcctl_s_Close(void *, struct mlrpc_xaction *);
+static int svcctl_s_OpenManager(void *, struct mlrpc_xaction *);
+static int svcctl_s_OpenService(void *, struct mlrpc_xaction *);
+static int svcctl_s_QueryServiceStatus(void *, struct mlrpc_xaction *);
+static int svcctl_s_QueryServiceConfig(void *, struct mlrpc_xaction *);
+static int svcctl_s_EnumServicesStatus(void *, struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t svcctl_stub_table[] = {
+ { svcctl_s_Close, SVCCTL_OPNUM_Close },
+ { svcctl_s_OpenManager, SVCCTL_OPNUM_OpenManager },
+ { svcctl_s_OpenService, SVCCTL_OPNUM_OpenService },
+ { svcctl_s_QueryServiceStatus, SVCCTL_OPNUM_QueryServiceStatus },
+ { svcctl_s_QueryServiceConfig, SVCCTL_OPNUM_QueryServiceConfig },
+ { svcctl_s_EnumServicesStatus, SVCCTL_OPNUM_EnumServicesStatus },
+ {0}
+};
+
+static mlrpc_service_t svcctl_service = {
+ "SVCCTL", /* name */
+ "Service Control Services", /* desc */
+ "\\svcctl", /* endpoint */
+ PIPE_NTSVCS, /* sec_addr_port */
+ "367abb81-9844-35f1-ad3298f038001003", 2, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(svcctl_interface), /* interface ti */
+ svcctl_stub_table /* stub_table */
+};
+
+/*
+ * svcctl_initialize
+ *
+ * This function registers the SVCCTL RPC interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+svcctl_initialize(void)
+{
+ (void) mlrpc_register_service(&svcctl_service);
+}
+
+/*
+ * svcctl_s_Close
+ *
+ * This is a request to close the SVCCTL interface specified by the
+ * handle. Free the handle and zero out the result handle for the
+ * client.
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_INVALID_HANDLE
+ */
+static int
+svcctl_s_Close(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct svcctl_Close *param = arg;
+ smb_dr_user_ctx_t *user_ctx = mxa->context->user_ctx;
+ ms_handle_t *handle;
+ DWORD status;
+
+ if (svcctl_debug)
+ smb_token_log(LOG_DEBUG, user_ctx, "(SvcctlClose)");
+
+ handle = (ms_handle_t *)&param->handle;
+ status = svcctl_validate_handle("SvcctlClose", handle, 0, mxa);
+
+ if (status == ERROR_SUCCESS)
+ (void) mlsvc_put_handle((ms_handle_t *)&param->handle);
+
+ bzero(&param->result_handle, sizeof (svcctl_handle_t));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_OpenManager
+ *
+ * This is a request to open the service control manager. Dependent
+ * on the desired access we either generate a handle to be used on
+ * subsequent requests or deny access.
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_ACCESS_DENIED
+ *
+ * Return a handle for use with subsequent svcctl requests.
+ */
+static int
+svcctl_s_OpenManager(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct svcctl_OpenManager *param = arg;
+ ms_handle_t *handle;
+ int rc;
+
+ rc = svcctl_is_admin(mxa);
+
+ if ((rc == 0) || (param->desired_access & SC_MANAGER_LOCK) != 0) {
+ /*
+ * The user doesn't have Administrator rights
+ * or wants a write lock on the Services DB.
+ */
+ bzero(&param->handle, sizeof (svcctl_handle_t));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+ }
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SVCCTL, SVCCTL_MANAGER_KEY, 0);
+ bcopy(handle, &param->handle, sizeof (svcctl_handle_t));
+
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_OpenService
+ *
+ * Return a handle for use with subsequent svcctl requests.
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_INVALID_HANDLE
+ * ERROR_SERVICE_DOES_NOT_EXIST
+ */
+static int
+svcctl_s_OpenService(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct svcctl_OpenService *param = arg;
+ ms_handle_t *handle;
+ DWORD status;
+
+ status = svcctl_validate_handle("SvcctlOpenService",
+ (ms_handle_t *)&param->manager_handle, SVCCTL_MANAGER_KEY, mxa);
+
+ if (status != ERROR_SUCCESS) {
+ bzero(&param->service_handle, sizeof (svcctl_handle_t));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ status = svcctl_validate_service((char *)param->service_name);
+ if (status != ERROR_SUCCESS) {
+ bzero(&param->service_handle, sizeof (svcctl_handle_t));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_SVCCTL, SVCCTL_SERVICE_KEY, 0);
+ bcopy(handle, &param->service_handle, sizeof (svcctl_handle_t));
+
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_QueryServiceStatus
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_INVALID_HANDLE
+ */
+static int
+svcctl_s_QueryServiceStatus(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct svcctl_QueryServiceStatus *param = arg;
+ DWORD status;
+
+ status = svcctl_validate_handle("SvcctlQueryServiceStatus",
+ (ms_handle_t *)&param->service_handle, SVCCTL_SERVICE_KEY, mxa);
+
+ if (status != ERROR_SUCCESS) {
+ bzero(&param, sizeof (struct svcctl_QueryServiceStatus));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->service_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
+ param->service_status.cur_state = SERVICE_RUNNING;
+ param->service_status.ctrl_accepted = 0;
+ param->service_status.w32_exitcode = 0;
+ param->service_status.svc_specified_exitcode = 0;
+ param->service_status.check_point = 0;
+ param->service_status.wait_hint = 0;
+
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_EnumServicesStatus
+ *
+ * Enumerate the list of services we support. Currently, this list
+ * is built in a fixed-size 1024 byte buffer - be careful not to
+ * over-run the buffer.
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_INVALID_HANDLE
+ */
+static int
+svcctl_s_EnumServicesStatus(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct svcctl_EnumServicesStatus *param = arg;
+ svc_enum_status_t *service_table;
+ svc_enum_status_t *svc;
+ mts_wchar_t *wide_name;
+ char *name;
+ int i, namelen;
+ int offs;
+ DWORD status;
+
+ status = svcctl_validate_handle("SvcctlEnumServicesStatus",
+ (ms_handle_t *)&param->manager_handle, SVCCTL_MANAGER_KEY, mxa);
+
+ if (status != ERROR_SUCCESS) {
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (param->buf_size < 1024) {
+ param->status = ERROR_MORE_DATA;
+ return (MLRPC_DRC_OK);
+ }
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ service_table = (svc_enum_status_t *)param->services;
+ offs = SVCCTL_NUM_SVCS * sizeof (svc_enum_status_t);
+
+ for (i = 0; i < SVCCTL_NUM_SVCS; i++) {
+ svc = &service_table[i];
+
+ svc->svc_name = offs;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ wide_name = (mts_wchar_t *)&param->services[offs];
+ name = svc_info[i].svc_name;
+ namelen = strlen(name) + 1;
+ (void) mts_mbstowcs(wide_name, name, namelen);
+
+ offs += namelen * 2;
+
+ svc->display_name = offs;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ wide_name = (mts_wchar_t *)&param->services[offs];
+ name = svc_info[i].display_name;
+ namelen = strlen(name) + 1;
+ (void) mts_mbstowcs(wide_name, name, namelen);
+
+ offs += namelen * 2;
+
+ name = svc_info[i].local_name;
+ if (name)
+ svc->svc_status.cur_state = svcctl_get_status(name);
+ else
+ svc->svc_status.cur_state = SERVICE_RUNNING;
+
+ svc->svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
+ svc->svc_status.ctrl_accepted = 0;
+ svc->svc_status.w32_exitcode = 0;
+ svc->svc_status.svc_specified_exitcode = 0;
+ svc->svc_status.check_point = 0;
+ svc->svc_status.wait_hint = 0;
+ }
+
+ param->buf_size = 1024;
+ param->bytes_needed = 0;
+ param->svc_num = SVCCTL_NUM_SVCS;
+ param->resume_handle = 0;
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_QueryServiceConfig
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_INVALID_HANDLE
+ */
+static int
+svcctl_s_QueryServiceConfig(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct svcctl_QueryServiceConfig *param = arg;
+ DWORD status;
+
+ status = svcctl_validate_handle("SvcctlQueryServiceConfig",
+ (ms_handle_t *)&param->service_handle, SVCCTL_SERVICE_KEY, mxa);
+
+ if (status != ERROR_SUCCESS) {
+ bzero(&param, sizeof (struct svcctl_QueryServiceConfig));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->service_cfg.service_type = SERVICE_WIN32_SHARE_PROCESS;
+ param->service_cfg.start_type = SERVICE_AUTO_START;
+ param->service_cfg.error_control = SERVICE_ERROR_IGNORE;
+ param->service_cfg.binary_pathname = 0;
+ param->service_cfg.loadorder_group = 0;
+ param->service_cfg.tag_id = 0;
+ param->service_cfg.dependencies = 0;
+ param->service_cfg.service_startname = 0;
+ param->service_cfg.display_name = 0;
+
+ param->cfg_bytes = sizeof (svc_config_t);
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Check to see whether or not a service is supported. The check is
+ * case-insensitive to avoid any naming issues due to the different
+ * versions of Windows.
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_SERVICE_DOES_NOT_EXIST
+ */
+static DWORD
+svcctl_validate_service(char *svc_name)
+{
+ int i;
+
+ if (svc_name == NULL)
+ return (ERROR_SERVICE_DOES_NOT_EXIST);
+
+ for (i = 0; i < SVCCTL_NUM_SVCS; i++) {
+ if (strcasecmp(svc_name, svc_info[i].svc_name) == 0)
+ return (ERROR_SUCCESS);
+ }
+
+ return (ERROR_SERVICE_DOES_NOT_EXIST);
+}
+
+/*
+ * Check whether or not the svcctl module allocated this handle.
+ *
+ * Returns:
+ * ERROR_SUCCESS
+ * ERROR_INVALID_HANDLE.
+ */
+/*ARGSUSED*/
+static DWORD
+svcctl_validate_handle(char *name, ms_handle_t *handle, char *key,
+ struct mlrpc_xaction *mxa)
+{
+ int mgr_erc;
+ int svc_erc;
+
+ mgr_erc = mlsvc_validate_handle(handle, SVCCTL_MANAGER_KEY);
+ svc_erc = mlsvc_validate_handle(handle, SVCCTL_SERVICE_KEY);
+
+ if (mgr_erc == 0 && svc_erc == 0)
+ return (ERROR_INVALID_HANDLE);
+
+ return (ERROR_SUCCESS);
+}
+
+/*
+ * Report the service status: SERVICE_PAUSED or SERVICE_RUNNING.
+ */
+/*ARGSUSED*/
+static DWORD
+svcctl_get_status(const char *name)
+{
+ return (SERVICE_RUNNING);
+}
+
+/*
+ * SVCCTL access is restricted to administrators: members of
+ * the Domain Admins or Administrators groups.
+ *
+ * Returns 1 if the user has admin rights. Otherwise returns 0.
+ */
+static int
+svcctl_is_admin(struct mlrpc_xaction *mxa)
+{
+ smb_dr_user_ctx_t *user_ctx = mxa->context->user_ctx;
+
+ if (user_ctx == NULL)
+ return (0);
+
+ return (user_ctx->du_flags & SMB_ATF_ADMIN);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
new file mode 100644
index 0000000000..29cd3f058a
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
@@ -0,0 +1,752 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Utility functions to support the RPC interface library.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <strings.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <sys/time.h>
+#include <sys/systm.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbrdr.h>
+#include <smbsrv/libsmbns.h>
+#include <smbsrv/libmlsvc.h>
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/lsalib.h>
+#include <smbsrv/samlib.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/mlsvc.h>
+
+extern int netr_open(char *, char *, mlsvc_handle_t *);
+extern int netr_close(mlsvc_handle_t *);
+extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
+extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *);
+
+static int mlsvc_lookup_local_name(char *name, nt_sid_t **sid);
+static int mlsvc_lookup_nt_name(char *name, nt_sid_t **sid);
+static int mlsvc_lookup_nt_sid(nt_sid_t *sid, char *buf, int bufsize);
+
+/*
+ * Compare the supplied domain name with the local hostname.
+ * We need to deal with both server names and fully-qualified
+ * domain names.
+ *
+ * Returns:
+ * 0 The specified domain is not the local domain,
+ * 1 The Specified domain is the local domain.
+ * -1 Invalid parameter or unable to get the local
+ * system information.
+ */
+int
+mlsvc_is_local_domain(const char *domain)
+{
+ char hostname[MAXHOSTNAMELEN];
+ uint32_t mode;
+ int rc;
+
+ if (strchr(domain, '.') != NULL)
+ rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN);
+ else
+ rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
+
+ if (rc != 0)
+ return (-1);
+
+ rc = strcasecmp(domain, hostname);
+ mode = smb_get_security_mode();
+
+ if ((rc == 0) || (mode == SMB_SECMODE_WORKGRP))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * mlsvc_lookup_name
+ *
+ * Lookup a name in the specified domain and translate it to a SID.
+ * If the name is in the NT domain, it may refer to a user, group or
+ * alias. Otherwise it must refer to a UNIX username. The memory for
+ * the sid is allocated using malloc so the caller should call free
+ * when it is no longer required.
+ *
+ * On success, 0 will be returned and sid will point to a local domain
+ * user SID. Otherwise -1 will be returned.
+ */
+int
+mlsvc_lookup_name(char *domain, char *name, nt_sid_t **sid)
+{
+ if (domain == NULL || name == NULL || sid == NULL)
+ return (-1);
+
+ if (mlsvc_is_local_domain(domain) == 1)
+ return (mlsvc_lookup_local_name(name, sid));
+ else
+ return (mlsvc_lookup_nt_name(name, sid));
+}
+
+/*
+ * mlsvc_lookup_local_name
+ *
+ * Lookup a name in the local password file and translate it to a SID.
+ * The name must refer to a user. This is a private function intended
+ * to support mlsvc_lookup_name so it doesn't perform any parameter
+ * validation. The memory for the sid is allocated using malloc so the
+ * caller must call free when it is no longer required.
+ *
+ * On success, 0 will be returned and sid will point to a local domain
+ * user SID. Otherwise -1 will be returned.
+ */
+static int
+mlsvc_lookup_local_name(char *name, nt_sid_t **sid)
+{
+ struct passwd *pw;
+ nt_sid_t *domain_sid;
+
+ if ((pw = getpwnam(name)) == NULL)
+ return (-1);
+
+ if ((domain_sid = nt_domain_local_sid()) == NULL)
+ return (-1);
+
+ *sid = nt_sid_splice(domain_sid, pw->pw_uid);
+ return (0);
+}
+
+/*
+ * mlsvc_lookup_nt_name
+ *
+ * Lookup a name in the specified NT domain and translate it to a SID.
+ * The name may refer to a user, group or alias. This is a private
+ * function intended to support mlsvc_lookup_name so it doesn't do any
+ * parameter validation. The memory for the sid is allocated using
+ * malloc so the caller should call free when it is no longer required.
+ *
+ * On success, 0 will be returned and sid will point to an NT domain
+ * user SID. Otherwise -1 will be returned.
+ */
+static int
+mlsvc_lookup_nt_name(char *name, nt_sid_t **sid)
+{
+ smb_userinfo_t *user_info;
+
+ if ((user_info = mlsvc_alloc_user_info()) == NULL)
+ return (-1);
+
+ if (lsa_lookup_name(0, 0, name, user_info) != 0)
+ return (-1);
+
+ *sid = nt_sid_splice(user_info->domain_sid, user_info->rid);
+ mlsvc_free_user_info(user_info);
+ return (0);
+}
+
+/*
+ * mlsvc_lookup_sid
+ *
+ * Lookup a SID and translate it to a name. The name returned may refer
+ * to a domain, user, group or alias dependent on the SID. On success 0
+ * will be returned. Otherwise -1 will be returned.
+ */
+int
+mlsvc_lookup_sid(nt_sid_t *sid, char *buf, int bufsize)
+{
+ struct passwd *pw;
+ struct group *gr;
+ nt_group_t *grp;
+ DWORD rid;
+
+ if (sid == NULL || buf == NULL)
+ return (-1);
+
+ if (nt_sid_is_local(sid)) {
+ (void) nt_sid_get_rid(sid, &rid);
+
+ switch (SAM_RID_TYPE(rid)) {
+ case SAM_RT_NT_UID:
+ break;
+
+ case SAM_RT_NT_GID:
+ if ((grp = nt_groups_lookup_rid(rid)) == NULL)
+ return (-1);
+
+ (void) strlcpy(buf, grp->name, bufsize);
+ break;
+
+ case SAM_RT_UNIX_UID:
+ if ((pw = getpwuid(SAM_DECODE_RID(rid))) == NULL)
+ return (-1);
+
+ (void) strlcpy(buf, pw->pw_name, bufsize);
+ break;
+
+ case SAM_RT_UNIX_GID:
+ if ((gr = getgrgid(SAM_DECODE_RID(rid))) == NULL)
+ return (-1);
+
+ (void) strlcpy(buf, gr->gr_name, bufsize);
+ break;
+ }
+
+ return (0);
+ }
+
+ return (mlsvc_lookup_nt_sid(sid, buf, bufsize));
+}
+
+/*
+ * mlsvc_lookup_nt_sid
+ *
+ * Lookup an NT SID and translate it to a name. This is a private
+ * function intended to support mlsvc_lookup_sid so it doesn't do any
+ * parameter validation. The input account_name specifies the logon/
+ * session to be used for the lookup. It doesn't need to have any
+ * association with the SID being looked up. The name returned may
+ * refer to a domain, user, group or alias dependent on the SID.
+ *
+ * On success the name will be copied into buf and 0 will be returned.
+ * Otherwise -1 will be returned.
+ */
+static int
+mlsvc_lookup_nt_sid(nt_sid_t *sid, char *buf, int bufsize)
+{
+ smb_userinfo_t *user_info;
+ int rc;
+
+ if ((user_info = mlsvc_alloc_user_info()) == NULL)
+ return (-1);
+
+ if ((rc = lsa_lookup_sid(sid, user_info)) == 0)
+ (void) strlcpy(buf, user_info->name, bufsize);
+
+ mlsvc_free_user_info(user_info);
+ return (rc);
+}
+
+/*
+ * mlsvc_alloc_user_info
+ *
+ * Allocate a user_info structure and set the contents to zero. A
+ * pointer to the user_info structure is returned.
+ */
+smb_userinfo_t *
+mlsvc_alloc_user_info(void)
+{
+ smb_userinfo_t *user_info;
+
+ user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t));
+ if (user_info == NULL)
+ return (NULL);
+
+ bzero(user_info, sizeof (smb_userinfo_t));
+ return (user_info);
+}
+
+/*
+ * mlsvc_free_user_info
+ *
+ * Free a user_info structure. This function ensures that the contents
+ * of the user_info are freed as well as the user_info itself.
+ */
+void
+mlsvc_free_user_info(smb_userinfo_t *user_info)
+{
+ if (user_info) {
+ mlsvc_release_user_info(user_info);
+ free(user_info);
+ }
+}
+
+/*
+ * mlsvc_release_user_info
+ *
+ * Release the contents of a user_info structure and zero out the
+ * elements but do not free the user_info structure itself. This
+ * function cleans out the structure so that it can be reused without
+ * worrying about stale contents.
+ */
+void
+mlsvc_release_user_info(smb_userinfo_t *user_info)
+{
+ int i;
+
+ if (user_info == NULL)
+ return;
+
+ free(user_info->name);
+ free(user_info->domain_sid);
+ free(user_info->domain_name);
+ free(user_info->groups);
+
+ if (user_info->n_other_grps) {
+ for (i = 0; i < user_info->n_other_grps; i++)
+ free(user_info->other_grps[i].sid);
+
+ free(user_info->other_grps);
+ }
+
+ free(user_info->user_sid);
+ free(user_info->pgrp_sid);
+ bzero(user_info, sizeof (smb_userinfo_t));
+}
+
+/*
+ * mlsvc_setadmin_user_info
+ *
+ * Determines if the given user is the domain Administrator or a
+ * member of Domain Admins or Administrators group and set the
+ * user_info->flags accordingly.
+ */
+void
+mlsvc_setadmin_user_info(smb_userinfo_t *user_info)
+{
+ nt_domain_t *domain;
+ nt_group_t *grp;
+ int i;
+
+ if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
+ return;
+
+ if (!nt_sid_is_equal((nt_sid_t *)user_info->domain_sid, domain->sid))
+ return;
+
+ if (user_info->rid == DOMAIN_USER_RID_ADMIN)
+ user_info->flags |= SMB_UINFO_FLAG_DADMIN;
+ else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS)
+ user_info->flags |= SMB_UINFO_FLAG_DADMIN;
+ else {
+ for (i = 0; i < user_info->n_groups; i++)
+ if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS)
+ user_info->flags |= SMB_UINFO_FLAG_DADMIN;
+ }
+
+ grp = nt_group_getinfo("Administrators", RWLOCK_READER);
+ if (grp) {
+ i = nt_group_is_member(grp, user_info->user_sid);
+ nt_group_putinfo(grp);
+ if (i)
+ user_info->flags |= SMB_UINFO_FLAG_LADMIN;
+ }
+}
+
+/*
+ * mlsvc_string_save
+ *
+ * This is a convenience function to prepare strings for an RPC call.
+ * An ms_string_t is set up with the appropriate lengths and str is
+ * set up to point to a copy of the original string on the heap. The
+ * macro MLRPC_HEAP_STRSAVE is an alias for mlrpc_heap_strsave, which
+ * extends the heap and copies the string into the new area.
+ */
+int
+mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa)
+{
+ int length;
+ char *p;
+
+ if (ms == NULL || str == NULL || mxa == NULL)
+ return (0);
+
+ /*
+ * Windows NT expects the name length to exclude the
+ * terminating wchar null but doesn't care whether or
+ * not the allosize includes it. Windows 2000 insists
+ * that both the length and the allosize include the
+ * wchar null.
+ */
+ length = mts_wcequiv_strlen(str);
+ ms->allosize = length + sizeof (mts_wchar_t);
+
+ if (mxa->context->user_ctx->du_native_os == NATIVE_OS_WIN2000)
+ ms->length = ms->allosize;
+ else
+ ms->length = length;
+
+ if ((p = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL) {
+ return (0);
+ }
+
+ ms->str = (LPTSTR)p;
+ return (1);
+}
+
+/*
+ * mlsvc_sid_save
+ *
+ * Expand the heap and copy the sid into the new area.
+ * Returns a pointer to the copy of the sid on the heap.
+ */
+nt_sid_t *
+mlsvc_sid_save(nt_sid_t *sid, struct mlrpc_xaction *mxa)
+{
+ nt_sid_t *heap_sid;
+ unsigned size;
+
+ if (sid == NULL)
+ return (NULL);
+
+ size = nt_sid_length(sid);
+
+ if ((heap_sid = (nt_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL)
+ return (0);
+
+ bcopy(sid, heap_sid, size);
+ return (heap_sid);
+}
+
+/*
+ * mlsvc_is_null_handle
+ *
+ * Check a handle against a null handle. Returns 1 if the handle is
+ * null. Otherwise returns 0.
+ */
+int
+mlsvc_is_null_handle(mlsvc_handle_t *handle)
+{
+ static ms_handle_t zero_handle;
+
+ if (handle == NULL || handle->context == NULL)
+ return (1);
+
+ if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t)))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * mlsvc_validate_user
+ *
+ * Returns NT status codes.
+ */
+DWORD
+mlsvc_validate_user(char *server, char *domain, char *plain_user,
+ char *plain_text)
+{
+ smb_auth_info_t auth;
+ smb_ntdomain_t *di;
+ int erc;
+ DWORD status;
+ mlsvc_handle_t netr_handle;
+ char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX];
+
+ machine_passwd[0] = '\0';
+
+ /*
+ * Ensure that the domain name is uppercase.
+ */
+ (void) utf8_strupr(domain);
+
+ /*
+ * There is no point continuing if the domain information is
+ * not available. Wait for up to 10 seconds and then give up.
+ */
+ if ((di = smb_getdomaininfo(10)) == 0) {
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ return (status);
+ }
+
+ if (strcasecmp(domain, di->domain) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ return (status);
+ }
+
+ erc = mlsvc_user_logon(server, domain, plain_user, plain_text);
+
+ if (erc == AUTH_USER_GRANT) {
+ int isenabled;
+
+ smb_config_rdlock();
+ isenabled = smb_config_getyorn(SMB_CI_ADS_ENABLE);
+ smb_config_unlock();
+ if (isenabled) {
+ if (adjoin(machine_passwd,
+ sizeof (machine_passwd)) == ADJOIN_SUCCESS) {
+ status = NT_STATUS_SUCCESS;
+ } else {
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+ } else {
+ /*
+ * Ensure that we don't have an old account in
+ * this domain. There's no need to check the
+ * return status.
+ */
+ (void) sam_remove_trust_account(server, domain);
+
+ if (mlsvc_user_getauth(server, plain_user, &auth)
+ != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ return (status);
+ }
+
+ status = sam_create_trust_account(server, domain,
+ &auth);
+ if (status == NT_STATUS_SUCCESS) {
+ (void) smb_gethostname(machine_passwd,
+ sizeof (machine_passwd), 0);
+ (void) utf8_strlwr(machine_passwd);
+ }
+ }
+
+ if (status == NT_STATUS_SUCCESS) {
+ smb_config_wrlock();
+ if (smb_config_set(SMB_CI_MACHINE_PASSWD,
+ machine_passwd) != 0) {
+ smb_config_unlock();
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+ smb_config_unlock();
+
+ /*
+ * If we successfully create a trust account, we mark
+ * ourselves as a domain member in the environment so
+ * that we use the SAMLOGON version of the NETLOGON
+ * PDC location protocol.
+ */
+ smb_set_domain_member(1);
+
+ if (netr_open(server, domain, &netr_handle) == 0) {
+ status = netlogon_auth(server, &netr_handle,
+ NETR_FLG_INIT);
+ (void) netr_close(&netr_handle);
+ } else {
+ status = NT_STATUS_OPEN_FAILED;
+ }
+ }
+ } else {
+ status = NT_STATUS_LOGON_FAILURE;
+ }
+
+ return (status);
+}
+
+/*ARGSUSED*/
+void
+nt_group_ht_lock(krwmode_t locktype)
+{
+}
+
+void
+nt_group_ht_unlock(void)
+{
+}
+
+int
+nt_group_num_groups(void)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_group_add(char *gname, char *comment)
+{
+ return (NT_STATUS_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_group_modify(char *gname, char *new_gname, char *comment)
+{
+ return (NT_STATUS_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_group_delete(char *gname)
+{
+ return (NT_STATUS_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+nt_group_t *
+nt_group_getinfo(char *gname, krwmode_t locktype)
+{
+ return (NULL);
+}
+
+/*ARGSUSED*/
+void
+nt_group_putinfo(nt_group_t *grp)
+{
+}
+
+/*ARGSUSED*/
+int
+nt_group_getpriv(nt_group_t *grp, uint32_t priv_id)
+{
+ return (SE_PRIVILEGE_DISABLED);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_group_setpriv(nt_group_t *grp, uint32_t priv_id, uint32_t new_attr)
+{
+ return (NT_STATUS_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+int
+nt_group_is_member(nt_group_t *grp, nt_sid_t *sid)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_group_add_member(nt_group_t *grp, nt_sid_t *msid, uint16_t sid_name_use,
+ char *account)
+{
+ return (NT_STATUS_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_group_del_member(nt_group_t *grp, void *key, int keytype)
+{
+ return (NT_STATUS_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+int
+nt_group_num_members(nt_group_t *grp)
+{
+ return (0);
+}
+
+nt_group_iterator_t *
+nt_group_open_iterator(void)
+{
+ return (NULL);
+}
+
+/*ARGSUSED*/
+void
+nt_group_close_iterator(nt_group_iterator_t *gi)
+{
+}
+
+/*ARGSUSED*/
+nt_group_t *
+nt_group_iterate(nt_group_iterator_t *gi)
+{
+ return (NULL);
+}
+
+int
+nt_group_cache_size(void)
+{
+ return (0);
+}
+
+uint32_t
+sam_init(void)
+{
+ return (NT_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_group_add_member_byname(char *gname, char *account)
+{
+ return (NT_STATUS_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_group_del_member_byname(nt_group_t *grp, char *member_name)
+{
+ return (NT_STATUS_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+void
+nt_group_add_groupprivs(nt_group_t *grp, smb_privset_t *priv)
+{
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_groups_member_privs(nt_sid_t *sid, smb_privset_t *priv)
+{
+ return (NT_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+int
+nt_groups_member_ngroups(nt_sid_t *sid)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+uint32_t
+nt_groups_member_groups(nt_sid_t *sid, smb_id_t *grps, int ngrps)
+{
+ return (NT_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+nt_group_t *
+nt_groups_lookup_rid(uint32_t rid)
+{
+ return (NULL);
+}
+
+/*ARGSUSED*/
+int
+nt_groups_count(int cnt_opt)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+nt_group_member_list(int offset, nt_group_t *grp,
+ ntgrp_member_list_t *rmembers)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+void
+nt_group_list(int offset, char *pattern, ntgrp_list_t *list)
+{
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_winreg.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_winreg.c
new file mode 100644
index 0000000000..bd2d5ee26f
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_winreg.c
@@ -0,0 +1,454 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Windows Registry RPC (WINREG) server-side interface.
+ *
+ * The WINREG RPC interface returns Win32 error codes.
+ *
+ * HKLM Hive Key Local Machine
+ * HKU Hive Key Users
+ */
+
+#include <sys/utsname.h>
+#include <strings.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/winreg.ndl>
+
+/*
+ * List of mlsvc handle (local handle management) keys.
+ */
+#define WINREG_HKLM "WinregOpenHKLM"
+#define WINREG_HKU "WinregOpenUser"
+#define WINREG_KEY "WinregOpenKey"
+
+/*
+ * List of supported registry keys (case-insensitive).
+ * "System\\CurrentControlSet\\Services\\Alerter\\Parameters"
+ */
+static char *winreg_keys[] = {
+ "System\\CurrentControlSet\\Control\\ProductOptions",
+ "System\\CurrentControlSet\\Services\\Eventlog\\System"
+};
+
+static char *winreg_lookup_value(const char *);
+
+static int winreg_s_OpenHKLM(void *, struct mlrpc_xaction *);
+static int winreg_s_OpenHKUsers(void *, struct mlrpc_xaction *);
+static int winreg_s_Close(void *, struct mlrpc_xaction *);
+static int winreg_s_CreateKey(void *, struct mlrpc_xaction *);
+static int winreg_s_DeleteKey(void *, struct mlrpc_xaction *);
+static int winreg_s_DeleteValue(void *, struct mlrpc_xaction *);
+static int winreg_s_OpenKey(void *, struct mlrpc_xaction *);
+static int winreg_s_QueryKey(void *, struct mlrpc_xaction *);
+static int winreg_s_QueryValue(void *, struct mlrpc_xaction *);
+static int winreg_s_CreateValue(void *, struct mlrpc_xaction *);
+static int winreg_s_Shutdown(void *, struct mlrpc_xaction *);
+static int winreg_s_GetVersion(void *, struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t winreg_stub_table[] = {
+ { winreg_s_OpenHKLM, WINREG_OPNUM_OpenHKLM },
+ { winreg_s_OpenHKUsers, WINREG_OPNUM_OpenHKUsers },
+ { winreg_s_Close, WINREG_OPNUM_Close },
+ { winreg_s_CreateKey, WINREG_OPNUM_CreateKey },
+ { winreg_s_DeleteKey, WINREG_OPNUM_DeleteKey },
+ { winreg_s_DeleteValue, WINREG_OPNUM_DeleteValue },
+ { winreg_s_OpenKey, WINREG_OPNUM_OpenKey },
+ { winreg_s_QueryKey, WINREG_OPNUM_QueryKey },
+ { winreg_s_QueryValue, WINREG_OPNUM_QueryValue },
+ { winreg_s_CreateValue, WINREG_OPNUM_CreateValue },
+ { winreg_s_Shutdown, WINREG_OPNUM_Shutdown },
+ { winreg_s_GetVersion, WINREG_OPNUM_GetVersion },
+ {0}
+};
+
+static mlrpc_service_t winreg_service = {
+ "Winreg", /* name */
+ "Windows Registry", /* desc */
+ "\\winreg", /* endpoint */
+ PIPE_WINREG, /* sec_addr_port */
+ "338cd001-2244-31f1-aaaa900038001003", 1, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(winreg_interface), /* interface ti */
+ winreg_stub_table /* stub_table */
+};
+
+static char winreg_sysname[SYS_NMLN];
+
+/*
+ * winreg_initialize
+ *
+ * This function registers the WINREG RPC interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+winreg_initialize(void)
+{
+ struct utsname name;
+ char *sysname;
+
+ if (uname(&name) < 0)
+ sysname = "Solaris";
+ else
+ sysname = name.sysname;
+
+ (void) strlcpy(winreg_sysname, sysname, SYS_NMLN);
+ (void) mlrpc_register_service(&winreg_service);
+}
+
+/*
+ * winreg_s_OpenHKLM
+ *
+ * This is a request to open the HKLM and get a handle. The client
+ * should treat the handle as an opaque object.
+ *
+ * Status:
+ * ERROR_SUCCESS Valid handle returned.
+ * ERROR_ACCESS_DENIED Unable to allocate a handle.
+ */
+/*ARGSUSED*/
+static int
+winreg_s_OpenHKLM(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_OpenHKLM *param = arg;
+ ms_handle_t *handle;
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_WINREG, WINREG_HKLM, 0);
+ if (handle == NULL) {
+ bzero(&param->handle, sizeof (msreg_handle_t));
+ param->status = ERROR_ACCESS_DENIED;
+ } else {
+ bcopy(handle, &param->handle, sizeof (msreg_handle_t));
+ param->status = ERROR_SUCCESS;
+ }
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_OpenHKUsers
+ *
+ * This is a request to get a HKUsers handle. I'm not sure we are
+ * ready to fully support this interface yet, mostly due to the need
+ * to support subsequent requests, but we may support enough now. It
+ * seems okay with regedt32.
+ */
+/*ARGSUSED*/
+static int
+winreg_s_OpenHKUsers(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_OpenHKUsers *param = arg;
+ ms_handle_t *handle;
+
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_WINREG, WINREG_HKU, 0);
+ if (handle == NULL) {
+ bzero(&param->handle, sizeof (msreg_handle_t));
+ param->status = ERROR_ACCESS_DENIED;
+ } else {
+ bcopy(handle, &param->handle, sizeof (msreg_handle_t));
+ param->status = ERROR_SUCCESS;
+ }
+
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_Close
+ *
+ * This is a request to close the WINREG interface specified by the
+ * handle. We don't track handles (yet), so just zero out the handle
+ * and return MLRPC_DRC_OK. Setting the handle to zero appears to be
+ * standard behaviour.
+ */
+/*ARGSUSED*/
+static int
+winreg_s_Close(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_Close *param = arg;
+
+ (void) mlsvc_put_handle((ms_handle_t *)&param->handle);
+ bzero(&param->result_handle, sizeof (msreg_handle_t));
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_CreateKey
+ */
+/*ARGSUSED*/
+static int
+winreg_s_CreateKey(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_CreateKey *param = arg;
+
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_DeleteKey
+ */
+/*ARGSUSED*/
+static int
+winreg_s_DeleteKey(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_DeleteKey *param = arg;
+
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_DeleteValue
+ */
+/*ARGSUSED*/
+static int
+winreg_s_DeleteValue(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_DeleteValue *param = arg;
+
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_OpenKey
+ *
+ * This is a request to open a windows registry key. The list
+ * of supported keys is listed in the winreg_keys table. If we
+ * recognize the key, we return a handle.
+ *
+ * Returns:
+ * ERROR_SUCCESS Valid handle returned.
+ * ERROR_FILE_NOT_FOUND No key or unable to allocate a handle.
+ */
+/*ARGSUSED*/
+static int
+winreg_s_OpenKey(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_OpenKey *param = arg;
+ ms_handle_t *handle;
+ char *key = (char *)param->name.str;
+ int i;
+
+ for (i = 0; i < sizeof (winreg_keys)/sizeof (winreg_keys[0]); ++i) {
+ if (strcasecmp(key, winreg_keys[i]) == 0) {
+ handle = mlsvc_get_handle(MLSVC_IFSPEC_WINREG,
+ WINREG_KEY, 0);
+
+ if (handle == NULL)
+ break;
+
+ bcopy(handle, &param->result_handle,
+ sizeof (msreg_handle_t));
+
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+ }
+ }
+
+ bzero(&param->result_handle, sizeof (msreg_handle_t));
+ param->status = ERROR_FILE_NOT_FOUND;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_QueryKey
+ */
+/*ARGSUSED*/
+static int
+winreg_s_QueryKey(void *arg, struct mlrpc_xaction *mxa)
+{
+ static char nullstr[2] = { 0, 0 };
+ struct msreg_QueryKey *param = arg;
+
+ bzero(param, sizeof (struct msreg_QueryKey));
+
+ param->name.length = 2;
+ param->name.allosize = 0;
+ param->name.str = (unsigned char *)nullstr;
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_QueryValue
+ *
+ * This is a request to get the value associated with a specified name.
+ *
+ * Returns:
+ * ERROR_SUCCESS Value returned.
+ * ERROR_FILE_NOT_FOUND PrimaryModule is not supported.
+ * ERROR_CANTREAD No such name or memory problem.
+ */
+static int
+winreg_s_QueryValue(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_QueryValue *param = arg;
+ struct msreg_value *pv;
+ char *name;
+ char *value;
+ DWORD slen;
+ DWORD msize;
+
+ name = (char *)param->value_name.str;
+
+ if (strcasecmp(name, "PrimaryModule") == 0) {
+ param->status = ERROR_FILE_NOT_FOUND;
+ return (MLRPC_DRC_OK);
+ }
+
+ if ((value = winreg_lookup_value(name)) == NULL) {
+ param->status = ERROR_CANTREAD;
+ return (MLRPC_DRC_OK);
+ }
+
+ slen = mts_wcequiv_strlen(value) + sizeof (mts_wchar_t);
+ msize = sizeof (struct msreg_value) + slen;
+
+ param->value = (struct msreg_value *)MLRPC_HEAP_MALLOC(mxa, msize);
+ param->type = MLRPC_HEAP_NEW(mxa, DWORD);
+ param->value_size = MLRPC_HEAP_NEW(mxa, DWORD);
+ param->value_size_total = MLRPC_HEAP_NEW(mxa, DWORD);
+
+ if (param->value == NULL || param->type == NULL ||
+ param->value_size == NULL || param->value_size_total == NULL) {
+ param->status = ERROR_CANTREAD;
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param->value, msize);
+ pv = param->value;
+ pv->vc_first_is = 0;
+ pv->vc_length_is = slen;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ (void) mts_mbstowcs((mts_wchar_t *)pv->value, value, slen);
+
+ *param->type = 1;
+ *param->value_size = slen;
+ *param->value_size_total = slen;
+
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Lookup a name in the registry and return the associated value.
+ * Our registry is a case-insensitive, name-value pair table.
+ *
+ * Windows ProductType: WinNT, ServerNT, LanmanNT.
+ * Windows NT4.0 workstation: WinNT
+ * Windows NT4.0 server: ServerNT
+ *
+ * If LanmanNT is used here, Windows 2000 sends LsarQueryInfoPolicy
+ * with info level 6, which we don't support. If we use ServerNT
+ * (as reported by NT4.0 Server) Windows 2000 send requests for
+ * levels 3 and 5, which are support.
+ *
+ * On success, returns a pointer to the value. Otherwise returns
+ * a null pointer.
+ */
+static char *
+winreg_lookup_value(const char *name)
+{
+ static struct registry {
+ char *name;
+ char *value;
+ } registry[] = {
+ { "ProductType", "ServerNT" },
+ { "Sources", NULL } /* product name */
+ };
+
+ int i;
+
+ for (i = 0; i < sizeof (registry)/sizeof (registry[0]); ++i) {
+ if (strcasecmp(registry[i].name, name) == 0) {
+ if (registry[i].value == NULL)
+ return (winreg_sysname);
+ else
+ return (registry[i].value);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * winreg_s_CreateValue
+ */
+/*ARGSUSED*/
+static int
+winreg_s_CreateValue(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_CreateValue *param = arg;
+
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_Shutdown
+ *
+ * Attempt to shutdown or reboot the system: access denied.
+ */
+/*ARGSUSED*/
+static int
+winreg_s_Shutdown(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_Shutdown *param = arg;
+
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * winreg_s_GetVersion
+ *
+ * Return the windows registry version. The current version is 5.
+ * This call is usually made prior to enumerating or querying registry
+ * keys or values.
+ */
+/*ARGSUSED*/
+static int
+winreg_s_GetVersion(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct msreg_GetVersion *param = arg;
+
+ param->version = 5;
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_wkssvc.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_wkssvc.c
new file mode 100644
index 0000000000..b7453b171e
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_wkssvc.c
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <string.h>
+#include <strings.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/srvsvc.ndl>
+
+static int wkssvc_s_NetWkstaGetInfo(void *, struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t wkssvc_stub_table[] = {
+ { wkssvc_s_NetWkstaGetInfo, WKSSVC_OPNUM_NetWkstaGetInfo },
+ {0}
+};
+
+static mlrpc_service_t wkssvc_service = {
+ "Workstation", /* name (WKSSVC or WKSTA) */
+ "Workstation services", /* desc */
+ "\\wkssvc", /* endpoint */
+ PIPE_NTSVCS, /* sec_addr_port */
+ "6bffd098-a112-3610-983346c3f87e345a", 1, /* abstract */
+ "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+ &TYPEINFO(wkssvc_interface), /* interface ti */
+ wkssvc_stub_table /* stub_table */
+};
+
+void
+wkssvc_initialize(void)
+{
+ (void) mlrpc_register_service(&wkssvc_service);
+}
+
+/*
+ * WKSSVC NetWkstaGetInfo (
+ * IN LPTSTR servername,
+ * IN DWORD level,
+ * OUT union switch(level) {
+ * case 100: _WKSTA_INFO_100 * p100;
+ * case 101: _WKSTA_INFO_101 * p101;
+ * case 102: _WKSTA_INFO_102 * p102;
+ * } bufptr,
+ * OUT DWORD status
+ * )
+ */
+static int
+wkssvc_s_NetWkstaGetInfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct mslm_NetWkstaGetInfo *param = arg;
+ mslm_NetWkstaGetInfo_rb *rb;
+ char hostname[MAXHOSTNAMELEN];
+ char *resource_domain;
+ char *p;
+ DWORD status;
+ int rc;
+
+ rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN);
+ rb = MLRPC_HEAP_NEW(mxa, mslm_NetWkstaGetInfo_rb);
+
+ if ((rc != 0) || (rb == NULL)) {
+ bzero(param, sizeof (struct mslm_NetWkstaGetInfo));
+ param->status = ERROR_NOT_ENOUGH_MEMORY;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->result.level = param->level;
+ param->result.bufptr.nullptr = (void *) rb;
+
+ switch (param->level) {
+ case 100:
+ rb->buf100.wki100_platform_id = SV_PLATFORM_ID_NT;
+ rb->buf100.wki100_ver_major = 4;
+ rb->buf100.wki100_ver_minor = 0;
+
+ if ((p = MLRPC_HEAP_STRSAVE(mxa, hostname)) == NULL) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+ rb->buf100.wki100_computername = (unsigned char *)p;
+
+ smb_config_rdlock();
+ resource_domain = smb_config_getstr(SMB_CI_DOMAIN_NAME);
+
+ if ((p = MLRPC_HEAP_STRSAVE(mxa, resource_domain)) == NULL) {
+ smb_config_unlock();
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ smb_config_unlock();
+ rb->buf100.wki100_langroup = (unsigned char *)p;
+ status = ERROR_SUCCESS;
+ break;
+
+ default:
+ param->result.bufptr.nullptr = 0;
+ status = ERROR_INVALID_LEVEL;
+ break;
+ }
+
+ if (status != ERROR_SUCCESS) {
+ bzero(param, sizeof (struct mslm_NetWkstaGetInfo));
+ param->status = status;
+ }
+
+ return (MLRPC_DRC_OK);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c b/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c
new file mode 100644
index 0000000000..aad7e1bbd0
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c
@@ -0,0 +1,519 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Net DFS server side RPC service.
+ */
+
+#include <sys/types.h>
+#include <strings.h>
+#include <string.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/lmdfs.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/ndl/netdfs.ndl>
+
+typedef struct {
+ char *server;
+ char *share;
+ char *path;
+ char *buf;
+} netdfs_unc_t;
+
+static int netdfs_unc_parse(struct mlrpc_xaction *, const char *,
+ netdfs_unc_t *);
+
+static int netdfs_s_getver(void *, struct mlrpc_xaction *);
+static int netdfs_s_add(void *, struct mlrpc_xaction *);
+static int netdfs_s_remove(void *, struct mlrpc_xaction *);
+static int netdfs_s_setinfo(void *, struct mlrpc_xaction *);
+static int netdfs_s_getinfo(void *, struct mlrpc_xaction *);
+static int netdfs_s_enum(void *, struct mlrpc_xaction *);
+static int netdfs_s_move(void *, struct mlrpc_xaction *);
+static int netdfs_s_rename(void *, struct mlrpc_xaction *);
+static int netdfs_s_addstdroot(void *, struct mlrpc_xaction *);
+static int netdfs_s_remstdroot(void *, struct mlrpc_xaction *);
+static int netdfs_s_enumex(void *, struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t netdfs_stub_table[] = {
+ { netdfs_s_getver, NETDFS_OPNUM_GETVER },
+ { netdfs_s_add, NETDFS_OPNUM_ADD },
+ { netdfs_s_remove, NETDFS_OPNUM_REMOVE },
+ { netdfs_s_setinfo, NETDFS_OPNUM_SETINFO },
+ { netdfs_s_getinfo, NETDFS_OPNUM_GETINFO },
+ { netdfs_s_enum, NETDFS_OPNUM_ENUM },
+ { netdfs_s_rename, NETDFS_OPNUM_RENAME },
+ { netdfs_s_move, NETDFS_OPNUM_MOVE },
+ { netdfs_s_addstdroot, NETDFS_OPNUM_ADDSTDROOT },
+ { netdfs_s_remstdroot, NETDFS_OPNUM_REMSTDROOT },
+ { netdfs_s_enumex, NETDFS_OPNUM_ENUMEX },
+ {0}
+};
+
+static mlrpc_service_t netdfs_service = {
+ "NETDFS", /* name */
+ "DFS", /* desc */
+ "\\dfs", /* endpoint */
+ PIPE_NTSVCS, /* sec_addr_port */
+ NETDFS_ABSTRACT_UUID, NETDFS_ABSTRACT_VERS,
+ NETDFS_TRANSFER_UUID, NETDFS_TRANSFER_VERS,
+
+ 0, /* no bind_instance_size */
+ 0, /* no bind_req() */
+ 0, /* no unbind_and_close() */
+ 0, /* use generic_call_stub() */
+
+ &TYPEINFO(netdfs_interface), /* interface ti */
+ netdfs_stub_table /* stub_table */
+};
+
+/*
+ * Register the NETDFS RPC interface with the RPC runtime library.
+ * The service must be registered in order to use either the client
+ * side or the server side functions.
+ */
+void
+netdfs_initialize(void)
+{
+ (void) mlrpc_register_service(&netdfs_service);
+}
+
+/*
+ * Return the version.
+ *
+ * We have to indicate that we emulate a Windows 2003 Server or the
+ * client will not use the EnumEx RPC and this would limit support
+ * to a single DFS root.
+ */
+/*ARGSUSED*/
+static int
+netdfs_s_getver(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_getver *param = arg;
+
+ param->version = DFS_MANAGER_VERSION_W2K3;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Add a new volume or additional storage for an existing volume at
+ * dfs_path.
+ */
+static int
+netdfs_s_add(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_add *param = arg;
+ netdfs_unc_t unc;
+ DWORD status = ERROR_SUCCESS;
+
+ if (param->dfs_path == NULL || param->server == NULL ||
+ param->share == NULL) {
+ bzero(param, sizeof (struct netdfs_add));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
+ status = ERROR_INVALID_PARAMETER;
+ } else {
+ if (unc.path == NULL)
+ status = ERROR_BAD_PATHNAME;
+
+ if (unc.share == NULL)
+ status = ERROR_INVALID_SHARENAME;
+ }
+
+ if (param->status != ERROR_SUCCESS) {
+ bzero(param, sizeof (struct netdfs_add));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param, sizeof (struct netdfs_add));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * netdfs_s_remove
+ *
+ * Remove a volume or additional storage for volume from the DFS at
+ * dfs_path. When applied to the last storage in a volume, removes
+ * the volume from the DFS.
+ */
+static int
+netdfs_s_remove(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_remove *param = arg;
+ netdfs_unc_t unc;
+ DWORD status = ERROR_SUCCESS;
+
+ if (param->dfs_path == NULL || param->server == NULL ||
+ param->share == NULL) {
+ bzero(param, sizeof (struct netdfs_remove));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
+ status = ERROR_INVALID_PARAMETER;
+ } else {
+ if (unc.path == NULL)
+ status = ERROR_BAD_PATHNAME;
+
+ if (unc.share == NULL)
+ status = ERROR_INVALID_SHARENAME;
+ }
+
+ if (param->status != ERROR_SUCCESS) {
+ bzero(param, sizeof (struct netdfs_remove));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param, sizeof (struct netdfs_remove));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Set information about the volume or storage. If the server and share
+ * are specified, the information set is specific to that server and
+ * share. Otherwise the information is specific to the volume as a whole.
+ *
+ * Valid levels are 100-102.
+ */
+/*ARGSUSED*/
+static int
+netdfs_s_setinfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_setinfo *param = arg;
+ netdfs_unc_t unc;
+ DWORD status = ERROR_SUCCESS;
+
+ if (param->dfs_path == NULL) {
+ bzero(param, sizeof (struct netdfs_setinfo));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
+ status = ERROR_INVALID_PARAMETER;
+ } else {
+ if (unc.share == NULL)
+ status = ERROR_INVALID_SHARENAME;
+ }
+
+ if (param->status != ERROR_SUCCESS) {
+ bzero(param, sizeof (struct netdfs_setinfo));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ switch (param->info.level) {
+ case 100:
+ case 101:
+ case 102:
+ break;
+
+ default:
+ bzero(param, sizeof (struct netdfs_setinfo));
+ param->status = ERROR_INVALID_LEVEL;
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param, sizeof (struct netdfs_setinfo));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Get information about the volume or storage. If the server and share
+ * are specified, the information returned is specific to that server
+ * and share. Otherwise the information is specific to the volume as a
+ * whole.
+ *
+ * Valid levels are 1-4, 100-104.
+ */
+/*ARGSUSED*/
+static int
+netdfs_s_getinfo(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_getinfo *param = arg;
+ netdfs_unc_t unc;
+ DWORD status = ERROR_SUCCESS;
+
+ if (param->dfs_path == NULL) {
+ bzero(param, sizeof (struct netdfs_getinfo));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
+ status = ERROR_INVALID_PARAMETER;
+ } else {
+ if (unc.share == NULL)
+ status = ERROR_INVALID_SHARENAME;
+ }
+
+ if (param->status != ERROR_SUCCESS) {
+ bzero(param, sizeof (struct netdfs_getinfo));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ switch (param->level) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ break;
+
+ default:
+ bzero(param, sizeof (struct netdfs_getinfo));
+ param->status = ERROR_INVALID_LEVEL;
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param, sizeof (struct netdfs_getinfo));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Get information about all of the volumes in the DFS. dfs_name is
+ * the "server" part of the UNC name used to refer to this particular
+ * DFS.
+ *
+ * Valid levels are 1-3.
+ */
+/*ARGSUSED*/
+static int
+netdfs_s_enum(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_enum *param = arg;
+
+ switch (param->level) {
+ case 1:
+ case 2:
+ case 3:
+ break;
+
+ default:
+ (void) bzero(param, sizeof (struct netdfs_enum));
+ param->status = ERROR_INVALID_LEVEL;
+ return (MLRPC_DRC_OK);
+ }
+
+ (void) bzero(param, sizeof (struct netdfs_enum));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Move a DFS volume and all subordinate volumes from one place in the
+ * DFS to another place in the DFS.
+ */
+/*ARGSUSED*/
+static int
+netdfs_s_move(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_move *param = arg;
+
+ if (param->dfs_path == NULL || param->new_path == NULL) {
+ bzero(param, sizeof (struct netdfs_move));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param, sizeof (struct netdfs_move));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Rename the current path in a DFS to a new path in the same DFS.
+ */
+/*ARGSUSED*/
+static int
+netdfs_s_rename(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_rename *param = arg;
+
+ if (param->dfs_path == NULL || param->new_path == NULL) {
+ bzero(param, sizeof (struct netdfs_rename));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param, sizeof (struct netdfs_rename));
+ param->status = ERROR_ACCESS_DENIED;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Add a DFS root share.
+ */
+/*ARGSUSED*/
+static int
+netdfs_s_addstdroot(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_addstdroot *param = arg;
+
+ bzero(param, sizeof (struct netdfs_addstdroot));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Remove a DFS root share.
+ */
+/*ARGSUSED*/
+static int
+netdfs_s_remstdroot(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_remstdroot *param = arg;
+
+ bzero(param, sizeof (struct netdfs_remstdroot));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Get information about all of the volumes in the DFS. dfs_path is
+ * the "server" part of the UNC name used to refer to this particular
+ * DFS.
+ *
+ * Valid levels are 1-3, 300.
+ */
+static int
+netdfs_s_enumex(void *arg, struct mlrpc_xaction *mxa)
+{
+ struct netdfs_enumex *param = arg;
+ netdfs_unc_t unc;
+ DWORD status = ERROR_SUCCESS;
+
+ if (param->dfs_path == NULL) {
+ bzero(param, sizeof (struct netdfs_enumex));
+ param->status = ERROR_INVALID_PARAMETER;
+ return (MLRPC_DRC_OK);
+ }
+
+ if (param->resume_handle == NULL)
+ param->resume_handle = MLRPC_HEAP_NEW(mxa, DWORD);
+
+ if (param->resume_handle)
+ *(param->resume_handle) = 0;
+
+ if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
+ status = ERROR_INVALID_PARAMETER;
+ } else {
+ if (unc.path == NULL)
+ status = ERROR_BAD_PATHNAME;
+
+ if (unc.share == NULL)
+ status = ERROR_INVALID_SHARENAME;
+ }
+
+ if (param->status != ERROR_SUCCESS) {
+ bzero(param, sizeof (struct netdfs_enumex));
+ param->status = status;
+ return (MLRPC_DRC_OK);
+ }
+
+ param->info = MLRPC_HEAP_NEW(mxa, struct netdfs_enum_info);
+ if (param->info == NULL) {
+ bzero(param, sizeof (struct netdfs_enumex));
+ param->status = ERROR_NOT_ENOUGH_MEMORY;
+ return (MLRPC_DRC_OK);
+ }
+
+ bzero(param->info, sizeof (struct netdfs_enumex));
+ param->status = ERROR_SUCCESS;
+ return (MLRPC_DRC_OK);
+}
+
+/*
+ * Parse a UNC path (\\server\share\path) into components.
+ * Path separators are converted to forward slashes.
+ *
+ * Returns 0 on success, otherwise -1 to indicate an error.
+ */
+static int
+netdfs_unc_parse(struct mlrpc_xaction *mxa, const char *path, netdfs_unc_t *unc)
+{
+ char *p;
+
+ if (path == NULL || unc == NULL)
+ return (-1);
+
+ if ((unc->buf = MLRPC_HEAP_STRSAVE(mxa, (char *)path)) == NULL)
+ return (-1);
+
+ if ((p = strchr(unc->buf, '\n')) != NULL)
+ *p = '\0';
+
+ (void) strsubst(unc->buf, '\\', '/');
+ (void) strcanon(unc->buf, "/");
+
+ unc->server = unc->buf;
+ unc->server += strspn(unc->buf, "/");
+
+ if (unc->server) {
+ unc->share = strchr(unc->server, '/');
+ if ((p = unc->share) != NULL) {
+ unc->share += strspn(unc->share, "/");
+ *p = '\0';
+ }
+ }
+
+ if (unc->share) {
+ unc->path = strchr(unc->share, '/');
+ if ((p = unc->path) != NULL) {
+ unc->path += strspn(unc->path, "/");
+ *p = '\0';
+ }
+ }
+
+ if (unc->path) {
+ if ((p = strchr(unc->path, '\0')) != NULL) {
+ if (*(--p) == '/')
+ *p = '\0';
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c b/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c
new file mode 100644
index 0000000000..2eb3e78bb7
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c
@@ -0,0 +1,502 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NETR challenge/response client functions.
+ *
+ * NT_STATUS_INVALID_PARAMETER
+ * NT_STATUS_NO_TRUST_SAM_ACCOUNT
+ * NT_STATUS_ACCESS_DENIED
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ndl/netlogon.ndl>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/netrauth.h>
+
+int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *,
+ struct netr_authenticator *);
+DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *);
+
+static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *);
+static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *);
+static int netr_gen_password(BYTE *, BYTE *, BYTE *);
+
+/*
+ * Shared with netr_logon.c
+ */
+netr_info_t netr_global_info;
+
+/*
+ * netlogon_auth
+ *
+ * This is the core of the NETLOGON authentication protocol.
+ * Do the challenge response authentication.
+ *
+ * Prior to calling this function, an anonymous session to the NETLOGON
+ * pipe on a domain controller(server) should have already been opened.
+ */
+DWORD
+netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags)
+{
+ netr_info_t *netr_info;
+ int rc;
+ DWORD random_challenge[2];
+
+ netr_info = &netr_global_info;
+ bzero(netr_info, sizeof (netr_info_t));
+
+ netr_info->flags |= flags;
+
+ rc = smb_getnetbiosname(netr_info->hostname, MLSVC_DOMAIN_NAME_MAX);
+ if (rc != 0)
+ return (NT_STATUS_UNSUCCESSFUL);
+
+ (void) snprintf(netr_info->server, sizeof (netr_info->server),
+ "\\\\%s", server);
+
+ random_challenge[0] = random();
+ random_challenge[1] = random();
+
+ (void) memcpy(&netr_info->client_challenge, random_challenge,
+ sizeof (struct netr_credential));
+
+ if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) {
+ rc = netr_server_authenticate2(netr_handle, netr_info);
+ if (rc == 0)
+ netr_info->flags |= NETR_FLG_VALID;
+ }
+
+ return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS);
+}
+
+/*
+ * netr_open
+ *
+ * Open an anonymous session to the NETLOGON pipe on a domain
+ * controller and bind to the NETR RPC interface. We store the
+ * remote server's native OS type - we may need it due to
+ * differences between versions of Windows.
+ */
+int
+netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle)
+{
+ int fid;
+ int remote_os = 0;
+ int remote_lm = 0;
+ int server_pdc;
+ char *username;
+
+ if (mlsvc_anonymous_logon(server, domain, &username) != 0)
+ return (-1);
+
+ fid = mlsvc_open_pipe(server, domain, username, "\\NETLOGON");
+ if (fid < 0)
+ return (-1);
+
+ if (mlsvc_rpc_bind(netr_handle, fid, "NETR") < 0) {
+ (void) mlsvc_close_pipe(fid);
+ return (-1);
+ }
+
+ (void) mlsvc_session_native_values(fid, &remote_os, &remote_lm,
+ &server_pdc);
+ netr_handle->context->server_os = remote_os;
+ netr_handle->context->server_pdc = server_pdc;
+ return (0);
+}
+
+/*
+ * netr_close
+ *
+ * Close a NETLOGON pipe and free the RPC context.
+ */
+int
+netr_close(mlsvc_handle_t *netr_handle)
+{
+ (void) mlsvc_close_pipe(netr_handle->context->fid);
+ free(netr_handle->context);
+ return (0);
+}
+
+/*
+ * netr_server_req_challenge
+ */
+static int
+netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
+{
+ struct netr_ServerReqChallenge arg;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+
+ bzero(&arg, sizeof (struct netr_ServerReqChallenge));
+ opnum = NETR_OPNUM_ServerReqChallenge;
+
+ arg.servername = (unsigned char *)netr_info->server;
+ arg.hostname = (unsigned char *)netr_info->hostname;
+
+ (void) memcpy(&arg.client_challenge, &netr_info->client_challenge,
+ sizeof (struct netr_credential));
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ rc = -1;
+ } else {
+ (void) memcpy(&netr_info->server_challenge,
+ &arg.server_challenge,
+ sizeof (struct netr_credential));
+ }
+ }
+
+ mlsvc_rpc_free(netr_handle->context, &heap);
+ return (rc);
+}
+
+/*
+ * netr_server_authenticate2
+ */
+static int
+netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
+{
+ struct netr_ServerAuthenticate2 arg;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
+
+ bzero(&arg, sizeof (struct netr_ServerAuthenticate2));
+ opnum = NETR_OPNUM_ServerAuthenticate2;
+
+ (void) snprintf(account_name, sizeof (account_name), "%s$",
+ netr_info->hostname);
+
+ arg.servername = (unsigned char *)netr_info->server;
+ arg.account_name = (unsigned char *)account_name;
+ arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
+ arg.hostname = (unsigned char *)netr_info->hostname;
+ arg.negotiate_flags = NETR_NEGOTIATE_FLAGS;
+
+ smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n",
+ netr_info->server, account_name, netr_info->hostname);
+
+ if (netr_gen_session_key(netr_info) != SMBAUTH_SUCCESS)
+ return (-1);
+
+ if (netr_gen_credentials(netr_info->session_key,
+ &netr_info->client_challenge,
+ 0,
+ &netr_info->client_credential) != SMBAUTH_SUCCESS) {
+ return (-1);
+ }
+
+ if (netr_gen_credentials(netr_info->session_key,
+ &netr_info->server_challenge,
+ 0,
+ &netr_info->server_credential) != SMBAUTH_SUCCESS) {
+ return (-1);
+ }
+
+ (void) memcpy(&arg.client_credential, &netr_info->client_credential,
+ sizeof (struct netr_credential));
+
+ (void) mlsvc_rpc_init(&heap);
+
+ rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ rc = -1;
+ } else {
+ rc = memcmp(&netr_info->server_credential,
+ &arg.server_credential,
+ sizeof (struct netr_credential));
+ }
+ }
+
+ mlsvc_rpc_free(netr_handle->context, &heap);
+ return (rc);
+}
+
+/*
+ * netr_gen_session_key
+ *
+ * Generate a session key from the client and server challenges. The
+ * algorithm is a two stage hash. For the first hash, the input is
+ * the combination of the client and server challenges, the key is
+ * the first 8 bytes of the password. The initial password is formed
+ * using the NT password hash on the local hostname in lower case.
+ * The result is stored in a temporary buffer.
+ *
+ * input: challenge
+ * key: passwd lower 8 bytes
+ * output: intermediate result
+ *
+ * For the second hash, the input is the result of the first hash and
+ * the key is the last 8 bytes of the password.
+ *
+ * input: result of first hash
+ * key: passwd upper 8 bytes
+ * output: session_key
+ *
+ * The final output should be the session key.
+ *
+ * FYI: smb_auth_DES(output, key, input)
+ *
+ * If any difficulties occur using the cryptographic framework, the
+ * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
+ * returned.
+ */
+int
+netr_gen_session_key(netr_info_t *netr_info)
+{
+ unsigned char md4hash[32];
+ unsigned char buffer[8];
+ DWORD data[2];
+ DWORD *client_challenge;
+ DWORD *server_challenge;
+ int rc;
+ char *machine_passwd;
+ DWORD new_data[2];
+
+ client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge;
+ server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge;
+ bzero(md4hash, 32);
+
+ /*
+ * We should check (netr_info->flags & NETR_FLG_INIT) and use
+ * the appropriate password but it isn't working yet. So we
+ * always use the default one for now.
+ */
+ smb_config_rdlock();
+ machine_passwd = smb_config_getstr(SMB_CI_MACHINE_PASSWD);
+
+ if (!machine_passwd || *machine_passwd == 0) {
+ smb_config_unlock();
+ return (-1);
+ }
+
+ bzero(netr_info->password, sizeof (netr_info->password));
+ (void) strlcpy((char *)netr_info->password, (char *)machine_passwd,
+ sizeof (netr_info->password));
+
+ rc = smb_auth_ntlm_hash((char *)machine_passwd, md4hash);
+ smb_config_unlock();
+
+ if (rc != SMBAUTH_SUCCESS)
+ return (SMBAUTH_FAILURE);
+
+ data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]);
+ data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]);
+ LE_OUT32(&new_data[0], data[0]);
+ LE_OUT32(&new_data[1], data[1]);
+
+ rc = smb_auth_DES(buffer, 8, md4hash, 8, (unsigned char *)new_data, 8);
+ if (rc != SMBAUTH_SUCCESS)
+ return (rc);
+
+ rc = smb_auth_DES(netr_info->session_key, 8, &md4hash[9], 8, buffer, 8);
+ return (rc);
+}
+
+/*
+ * netr_gen_credentials
+ *
+ * Generate a set of credentials from a challenge and a session key.
+ * The algorithm is a two stage hash. For the first hash, the
+ * timestamp is added to the challenge and the result is stored in a
+ * temporary buffer:
+ *
+ * input: challenge (including timestamp)
+ * key: session_key
+ * output: intermediate result
+ *
+ * For the second hash, the input is the result of the first hash and
+ * a strange partial key is used:
+ *
+ * input: result of first hash
+ * key: funny partial key
+ * output: credentiails
+ *
+ * The final output should be an encrypted set of credentials.
+ *
+ * FYI: smb_auth_DES(output, key, input)
+ *
+ * If any difficulties occur using the cryptographic framework, the
+ * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
+ * returned.
+ */
+int
+netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
+ DWORD timestamp, netr_cred_t *out_cred)
+{
+ unsigned char buffer[8];
+ unsigned char partial_key[8];
+ DWORD data[2];
+ DWORD *p;
+ int rc;
+
+ p = (DWORD *)(uintptr_t)challenge;
+ data[0] = p[0] + LE_IN32(&timestamp);
+ data[1] = p[1];
+
+ if (smb_auth_DES(buffer, 8, session_key, 8,
+ (unsigned char *)data, 8) != SMBAUTH_SUCCESS)
+ return (SMBAUTH_FAILURE);
+
+ bzero(partial_key, 8);
+ partial_key[0] = session_key[7];
+
+ rc = smb_auth_DES((unsigned char *)out_cred, 8, partial_key, 8,
+ buffer, 8);
+ return (rc);
+}
+
+/*
+ * netr_server_password_set
+ *
+ * Attempt to change the trust account password for this system.
+ *
+ * Note that this call may legitimately fail if the registry on the
+ * domain controller has been setup to deny attempts to change the
+ * trust account password. In this case we should just continue to
+ * use the original password.
+ *
+ * Possible status values:
+ * NT_STATUS_ACCESS_DENIED
+ */
+int
+netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
+{
+ struct netr_PasswordSet arg;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ BYTE new_password[NETR_OWF_PASSWORD_SZ];
+ char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
+
+ bzero(&arg, sizeof (struct netr_PasswordSet));
+ opnum = NETR_OPNUM_ServerPasswordSet;
+
+ (void) snprintf(account_name, sizeof (account_name), "%s$",
+ netr_info->hostname);
+
+ arg.servername = (unsigned char *)netr_info->server;
+ arg.account_name = (unsigned char *)account_name;
+ arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
+ arg.hostname = (unsigned char *)netr_info->hostname;
+
+ /*
+ * Set up the client side authenticator.
+ */
+ if (netr_setup_authenticator(netr_info, &arg.auth, 0) !=
+ SMBAUTH_SUCCESS) {
+ return (-1);
+ }
+
+ /*
+ * Generate a new password from the old password.
+ */
+ if (netr_gen_password(netr_info->session_key,
+ netr_info->password, new_password) == SMBAUTH_FAILURE) {
+ return (-1);
+ }
+
+ (void) memcpy(&arg.uas_new_password, &new_password,
+ NETR_OWF_PASSWORD_SZ);
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
+ if ((rc != 0) || (arg.status != 0)) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ mlsvc_rpc_free(netr_handle->context, &heap);
+ return (-1);
+ }
+
+ /*
+ * Check the returned credentials. The server returns the new
+ * client credential rather than the new server credentiali,
+ * as documented elsewhere.
+ *
+ * Generate the new seed for the credential chain. Increment
+ * the timestamp and add it to the client challenge. Then we
+ * need to copy the challenge to the credential field in
+ * preparation for the next cycle.
+ */
+ if (netr_validate_chain(netr_info, &arg.auth) == 0) {
+ /*
+ * Save the new password.
+ */
+ (void) memcpy(netr_info->password, new_password,
+ NETR_OWF_PASSWORD_SZ);
+ }
+
+ mlsvc_rpc_free(netr_handle->context, &heap);
+ return (0);
+}
+
+/*
+ * netr_gen_password
+ *
+ * Generate a new pasword from the old password and the session key.
+ * The algorithm is a two stage hash. The session key is used in the
+ * first hash but only part of the session key is used in the second
+ * hash.
+ *
+ * If any difficulties occur using the cryptographic framework, the
+ * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
+ * returned.
+ */
+static int
+netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password)
+{
+ unsigned char partial_key[8];
+ int rv;
+
+ rv = smb_auth_DES(new_password, 8, session_key, 8, old_password, 8);
+ if (rv != SMBAUTH_SUCCESS)
+ return (rv);
+
+ bzero(partial_key, 8);
+ partial_key[0] = session_key[7];
+
+ rv = smb_auth_DES(&new_password[8], 8, partial_key, 8,
+ &old_password[8], 8);
+ return (rv);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c
new file mode 100644
index 0000000000..d26d6f0dc7
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c
@@ -0,0 +1,584 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NETR SamLogon and SamLogoff RPC client functions.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <time.h>
+#include <alloca.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ndl/netlogon.ndl>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/netrauth.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/smb_token.h>
+
+extern int netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle);
+extern int netr_close(mlsvc_handle_t *netr_handle);
+extern DWORD netlogon_auth(char *server, mlsvc_handle_t *netr_handle,
+ DWORD flags);
+extern int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *,
+ struct netr_authenticator *);
+extern DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *);
+
+static DWORD netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
+ netr_client_t *, smb_userinfo_t *);
+static void netr_invalidate_chain(void);
+static void netr_interactive_samlogon(netr_info_t *, netr_client_t *,
+ struct netr_logon_info1 *);
+static void netr_network_samlogon(netr_info_t *, netr_client_t *,
+ netr_response_t *, netr_response_t *, struct netr_logon_info2 *);
+static void netr_setup_identity(mlrpc_heap_t *, netr_client_t *,
+ netr_logon_id_t *);
+
+/*
+ * Shared with netr_auth.c
+ */
+extern netr_info_t netr_global_info;
+
+/*
+ * netlogon_logon
+ *
+ * This is the entry point for authenticating a remote logon. The
+ * parameters here all refer to the remote user and workstation, i.e.
+ * the domain is the user's account domain, not our primary domain.
+ * In order to make it easy to track which domain is being used at
+ * each stage, and to reduce the number of things being pushed on the
+ * stack, the client information is bundled up in the clnt structure.
+ *
+ * If the user is successfully authenticated, an access token will be
+ * built and NT_STATUS_SUCCESS will be returned. Otherwise a non-zero
+ * NT status will be returned, in which case the token contents will
+ * be invalid.
+ */
+DWORD
+netlogon_logon(netr_client_t *clnt, smb_userinfo_t *user_info)
+{
+ char resource_domain[SMB_PI_MAX_DOMAIN];
+ mlsvc_handle_t netr_handle;
+ smb_ntdomain_t *di;
+ DWORD status;
+ int retries = 0;
+
+ smb_config_rdlock();
+ (void) strlcpy(resource_domain, smb_config_getstr(SMB_CI_DOMAIN_NAME),
+ sizeof (resource_domain));
+ smb_config_unlock();
+
+ /*
+ * If the SMB info cache is not valid,
+ * try to locate a domain controller.
+ */
+ if ((di = smb_getdomaininfo(0)) == NULL) {
+ (void) mlsvc_locate_domain_controller(resource_domain);
+
+ if ((di = smb_getdomaininfo(0)) == NULL)
+ return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+ }
+
+ if ((mlsvc_echo(di->server)) < 0) {
+ /*
+ * We had a session to the DC but it's not responding.
+ * So drop the credential chain and find another DC.
+ */
+ netr_invalidate_chain();
+ (void) mlsvc_locate_domain_controller(resource_domain);
+
+ if ((di = smb_getdomaininfo(0)) == NULL)
+ return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+ }
+
+ do {
+ status = netr_open(di->server, di->domain, &netr_handle);
+ if (status != 0)
+ return (status);
+
+ if ((netr_global_info.flags & NETR_FLG_VALID) == 0) {
+ status = netlogon_auth(di->server, &netr_handle,
+ NETR_FLG_NULL);
+
+ if (status != 0) {
+ (void) netr_close(&netr_handle);
+ return (NT_STATUS_LOGON_FAILURE);
+ }
+
+ netr_global_info.flags |= NETR_FLG_VALID;
+ }
+
+ status = netr_server_samlogon(&netr_handle,
+ &netr_global_info, di->server, clnt, user_info);
+
+ (void) netr_close(&netr_handle);
+ } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3);
+
+ if (retries >= 3)
+ status = NT_STATUS_LOGON_FAILURE;
+
+ return (status);
+}
+
+static DWORD
+netr_setup_userinfo(struct netr_validation_info3 *info3,
+ smb_userinfo_t *user_info, netr_client_t *clnt)
+{
+ smb_sid_attrs_t *other_grps;
+ char *username, *domain;
+ int i, nbytes;
+
+ user_info->sid_name_use = SidTypeUser;
+ user_info->rid = info3->UserId;
+ user_info->primary_group_rid = info3->PrimaryGroupId;
+ user_info->domain_sid = nt_sid_dup((nt_sid_t *)info3->LogonDomainId);
+
+ if (user_info->domain_sid == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ user_info->user_sid = nt_sid_splice(user_info->domain_sid,
+ user_info->rid);
+ if (user_info->user_sid == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ user_info->pgrp_sid = nt_sid_splice(user_info->domain_sid,
+ user_info->primary_group_rid);
+ if (user_info->pgrp_sid == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ username = (info3->EffectiveName.str)
+ ? (char *)info3->EffectiveName.str : clnt->username;
+ domain = (info3->LogonDomainName.str)
+ ? (char *)info3->LogonDomainName.str : clnt->domain;
+
+ if (username)
+ user_info->name = strdup(username);
+ if (domain)
+ user_info->domain_name = strdup(domain);
+
+ if (user_info->name == NULL || user_info->domain_name == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ nbytes = info3->GroupCount * sizeof (smb_rid_attrs_t);
+ if (nbytes) {
+ if ((user_info->groups = malloc(nbytes)) != NULL) {
+ user_info->n_groups = info3->GroupCount;
+ (void) memcpy(user_info->groups,
+ info3->GroupIds, nbytes);
+ } else {
+ return (NT_STATUS_NO_MEMORY);
+ }
+ }
+
+ nbytes = info3->SidCount * sizeof (smb_sid_attrs_t);
+ if (nbytes) {
+ if ((other_grps = malloc(nbytes)) != NULL) {
+ user_info->other_grps = other_grps;
+ for (i = 0; i < info3->SidCount; i++) {
+ other_grps[i].attrs =
+ info3->ExtraSids[i].attributes;
+
+ other_grps[i].sid = nt_sid_dup(
+ (nt_sid_t *)info3->ExtraSids[i].sid);
+
+ if (other_grps[i].sid == NULL)
+ break;
+ }
+ user_info->n_other_grps = i;
+ } else {
+ return (NT_STATUS_NO_MEMORY);
+ }
+ }
+
+ mlsvc_setadmin_user_info(user_info);
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * netr_server_samlogon
+ *
+ * NetrServerSamLogon RPC: interactive or network. It is assumed that
+ * we have already authenticated with the PDC. If everything works,
+ * we build a user info structure and return it, where the caller will
+ * probably build an access token.
+ *
+ * Returns an NT status. There are numerous possibilities here.
+ * For example:
+ * NT_STATUS_INVALID_INFO_CLASS
+ * NT_STATUS_INVALID_PARAMETER
+ * NT_STATUS_ACCESS_DENIED
+ * NT_STATUS_PASSWORD_MUST_CHANGE
+ * NT_STATUS_NO_SUCH_USER
+ * NT_STATUS_WRONG_PASSWORD
+ * NT_STATUS_LOGON_FAILURE
+ * NT_STATUS_ACCOUNT_RESTRICTION
+ * NT_STATUS_INVALID_LOGON_HOURS
+ * NT_STATUS_INVALID_WORKSTATION
+ * NT_STATUS_INTERNAL_ERROR
+ * NT_STATUS_PASSWORD_EXPIRED
+ * NT_STATUS_ACCOUNT_DISABLED
+ */
+DWORD
+netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info,
+ char *server, netr_client_t *clnt, smb_userinfo_t *user_info)
+{
+ struct netr_SamLogon arg;
+ struct netr_authenticator auth;
+ struct netr_authenticator ret_auth;
+ struct netr_logon_info1 info1;
+ struct netr_logon_info2 info2;
+ struct netr_validation_info3 *info3;
+ netr_response_t nt_rsp;
+ netr_response_t lm_rsp;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc, len;
+ DWORD status;
+
+ bzero(&arg, sizeof (struct netr_SamLogon));
+ opnum = NETR_OPNUM_SamLogon;
+ (void) mlsvc_rpc_init(&heap);
+
+ /*
+ * Should we get the server and hostname from netr_info?
+ */
+ len = strlen(server) + 4;
+ arg.servername = alloca(len);
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+
+ arg.hostname = alloca(MLSVC_DOMAIN_NAME_MAX);
+ rc = smb_gethostname((char *)arg.hostname, MLSVC_DOMAIN_NAME_MAX, 0);
+ if (rc != 0) {
+ mlrpc_heap_destroy(heap.heap);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ rc = netr_setup_authenticator(netr_info, &auth, &ret_auth);
+ if (rc != SMBAUTH_SUCCESS) {
+ mlrpc_heap_destroy(heap.heap);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ arg.auth = &auth;
+ arg.ret_auth = &ret_auth;
+ arg.validation_level = NETR_VALIDATION_LEVEL3;
+ arg.logon_info.logon_level = clnt->logon_level;
+ arg.logon_info.switch_value = clnt->logon_level;
+
+ switch (clnt->logon_level) {
+ case NETR_INTERACTIVE_LOGON:
+ netr_setup_identity(heap.heap, clnt, &info1.identity);
+ netr_interactive_samlogon(netr_info, clnt, &info1);
+ arg.logon_info.ru.info1 = &info1;
+ break;
+
+ case NETR_NETWORK_LOGON:
+ netr_setup_identity(heap.heap, clnt, &info2.identity);
+ netr_network_samlogon(netr_info, clnt, &nt_rsp, &lm_rsp,
+ &info2);
+ arg.logon_info.ru.info2 = &info2;
+ break;
+
+ default:
+ mlrpc_heap_destroy(heap.heap);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
+ if (rc != 0) {
+ bzero(netr_info, sizeof (netr_info_t));
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ status = NT_SC_VALUE(arg.status);
+
+ /*
+ * We need to validate the chain even though we have
+ * a non-zero status. If the status is ACCESS_DENIED
+ * this will trigger a new credential chain. However,
+ * a valid credential is returned with some status
+ * codes; for example, WRONG_PASSWORD.
+ */
+ (void) netr_validate_chain(netr_info, arg.ret_auth);
+ } else {
+ status = netr_validate_chain(netr_info, arg.ret_auth);
+ if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
+ mlsvc_rpc_free(netr_handle->context, &heap);
+ return (status);
+ }
+
+ info3 = arg.ru.info3;
+ status = netr_setup_userinfo(info3, user_info, clnt);
+ }
+
+ mlsvc_rpc_free(netr_handle->context, &heap);
+ return (status);
+}
+
+/*
+ * netr_interactive_samlogon
+ *
+ * Set things up for an interactive SamLogon. Copy the NT and LM
+ * passwords to the logon structure and hash them with the session
+ * key.
+ */
+static void
+netr_interactive_samlogon(netr_info_t *netr_info, netr_client_t *clnt,
+ struct netr_logon_info1 *info1)
+{
+ BYTE key[NETR_OWF_PASSWORD_SZ];
+
+ (void) memcpy(&info1->lm_owf_password,
+ clnt->lm_password.lm_password_val, sizeof (netr_owf_password_t));
+
+ (void) memcpy(&info1->nt_owf_password,
+ clnt->nt_password.nt_password_val, sizeof (netr_owf_password_t));
+
+ (void) memset(key, 0, NETR_OWF_PASSWORD_SZ);
+ (void) memcpy(key, netr_info->session_key, NETR_SESSION_KEY_SZ);
+
+ rand_hash((unsigned char *)&info1->lm_owf_password,
+ NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
+
+ rand_hash((unsigned char *)&info1->nt_owf_password,
+ NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
+}
+
+/*
+ * netr_network_samlogon
+ *
+ * Set things up for a network SamLogon. We provide a copy of the random
+ * challenge, that we sent to the client, to the domain controller. This
+ * is the key that the client will have used to encrypt the NT and LM
+ * passwords. Note that Windows 9x clients may not provide both passwords.
+ */
+/*ARGSUSED*/
+static void
+netr_network_samlogon(netr_info_t *netr_info, netr_client_t *clnt,
+ netr_response_t *ntr, netr_response_t *lmr, struct netr_logon_info2 *info2)
+{
+ bcopy(clnt->challenge_key.challenge_key_val, info2->lm_challenge.data,
+ 8);
+
+ if (clnt->nt_password.nt_password_len == NETR_CR_PASSWORD_SIZE) {
+ ntr->length = NETR_CR_PASSWORD_SIZE;
+ ntr->start = 0;
+ ntr->max_length = NETR_CR_PASSWORD_SIZE;
+ bcopy(clnt->nt_password.nt_password_val, ntr->data,
+ NETR_CR_PASSWORD_SIZE);
+
+ info2->nt_response.length = NETR_CR_PASSWORD_SIZE;
+ info2->nt_response.max_length = NETR_CR_PASSWORD_SIZE;
+ info2->nt_response.data = ntr;
+ } else {
+ info2->nt_response.length = 0;
+ info2->nt_response.max_length = 0;
+ info2->nt_response.data = 0;
+ }
+
+ if (clnt->lm_password.lm_password_len == NETR_CR_PASSWORD_SIZE) {
+ lmr->length = NETR_CR_PASSWORD_SIZE;
+ lmr->start = 0;
+ lmr->max_length = NETR_CR_PASSWORD_SIZE;
+ bcopy(clnt->lm_password.lm_password_val, lmr->data,
+ NETR_CR_PASSWORD_SIZE);
+
+ info2->lm_response.length = NETR_CR_PASSWORD_SIZE;
+ info2->lm_response.max_length = NETR_CR_PASSWORD_SIZE;
+ info2->lm_response.data = lmr;
+ } else {
+ info2->lm_response.length = 0;
+ info2->lm_response.max_length = 0;
+ info2->lm_response.data = 0;
+ }
+}
+
+/*
+ * netr_setup_authenticator
+ *
+ * Set up the request and return authenticators. A new credential is
+ * generated from the session key, the current client credential and
+ * the current time, i.e.
+ *
+ * NewCredential = Cred(SessionKey, OldCredential, time);
+ *
+ * The timestamp, which is used as a random seed, is stored in both
+ * the request and return authenticators.
+ *
+ * If any difficulties occur using the cryptographic framework, the
+ * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
+ * returned.
+ */
+int
+netr_setup_authenticator(netr_info_t *netr_info,
+ struct netr_authenticator *auth, struct netr_authenticator *ret_auth)
+{
+ bzero(auth, sizeof (struct netr_authenticator));
+
+#ifdef _BIG_ENDIAN
+ netr_info->timestamp = 0;
+#else
+ netr_info->timestamp = time(0) << 8;
+#endif
+ auth->timestamp = netr_info->timestamp;
+
+ if (netr_gen_credentials(netr_info->session_key,
+ &netr_info->client_credential,
+ netr_info->timestamp,
+ (netr_cred_t *)&auth->credential) != SMBAUTH_SUCCESS)
+ return (SMBAUTH_FAILURE);
+
+ if (ret_auth) {
+ bzero(ret_auth, sizeof (struct netr_authenticator));
+ ret_auth->timestamp = netr_info->timestamp;
+ }
+
+ return (SMBAUTH_SUCCESS);
+}
+
+/*
+ * Validate the returned credentials and update the credential chain.
+ * The server returns an updated client credential rather than a new
+ * server credential. The server uses (timestamp + 1) when generating
+ * the credential.
+ *
+ * Generate the new seed for the credential chain. The new seed is
+ * formed by adding (timestamp + 1) to the current client credential.
+ * The only quirk is the DWORD style addition.
+ *
+ * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a
+ * NULL pointer. The Authenticator field of the SamLogon response packet
+ * sent by the Samba 3 PDC always return NULL pointer if the received
+ * SamLogon request is not immediately followed by the ServerReqChallenge
+ * and ServerAuthenticate2 requests.
+ *
+ * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
+ * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
+ */
+DWORD
+netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth)
+{
+ netr_cred_t cred;
+ DWORD result = NT_STATUS_SUCCESS;
+ DWORD *dwp;
+
+ ++netr_info->timestamp;
+
+ if (netr_gen_credentials(netr_info->session_key,
+ &netr_info->client_credential,
+ netr_info->timestamp, &cred) != SMBAUTH_SUCCESS)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ if (&auth->credential == 0) {
+ /*
+ * If the validation fails, destroy the credential chain.
+ * This should trigger a new authentication chain.
+ */
+ bzero(netr_info, sizeof (netr_info_t));
+ return (NT_STATUS_INSUFFICIENT_LOGON_INFO);
+ }
+
+ result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t));
+ if (result != 0) {
+ /*
+ * If the validation fails, destroy the credential chain.
+ * This should trigger a new authentication chain.
+ */
+ bzero(netr_info, sizeof (netr_info_t));
+ result = NT_STATUS_UNSUCCESSFUL;
+ } else {
+ /*
+ * Otherwise generate the next step in the chain.
+ */
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ dwp = (DWORD *)&netr_info->client_credential;
+ dwp[0] += netr_info->timestamp;
+
+ netr_info->flags |= NETR_FLG_VALID;
+ }
+
+ return (result);
+}
+
+/*
+ * netr_invalidate_chain
+ *
+ * Mark the credential chain as invalid so that it will be recreated
+ * on the next attempt.
+ */
+static void
+netr_invalidate_chain(void)
+{
+ netr_global_info.flags &= ~NETR_FLG_VALID;
+}
+
+/*
+ * netr_setup_identity
+ *
+ * Set up the client identity information. All of this information is
+ * specifically related to the client user and workstation attempting
+ * to access this system. It may not be in our primary domain.
+ *
+ * I don't know what logon_id is, it seems to be a unique identifier.
+ * Increment it before each use.
+ */
+static void
+netr_setup_identity(mlrpc_heap_t *heap, netr_client_t *clnt,
+ netr_logon_id_t *identity)
+{
+ static DWORD logon_id;
+
+ if (logon_id == 0)
+ logon_id = 0xDCD0;
+
+ ++logon_id;
+ clnt->logon_id = logon_id;
+
+ identity->parameter_control = 0;
+ identity->logon_id.LowPart = logon_id;
+ identity->logon_id.HighPart = 0;
+
+ mlrpc_heap_mkvcs(heap, clnt->domain,
+ (mlrpc_vcbuf_t *)&identity->domain_name);
+
+ mlrpc_heap_mkvcs(heap, clnt->username,
+ (mlrpc_vcbuf_t *)&identity->username);
+
+ /*
+ * Some systems prefix the client workstation name with \\.
+ * It doesn't seem to make any difference whether it's there
+ * or not.
+ */
+ mlrpc_heap_mkvcs(heap, clnt->workstation,
+ (mlrpc_vcbuf_t *)&identity->workstation);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
new file mode 100644
index 0000000000..aa75c2678e
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
@@ -0,0 +1,512 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the high level interface to the SAM RPC
+ * functions.
+ */
+
+#include <unistd.h>
+#include <netdb.h>
+#include <alloca.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntaccess.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/lsalib.h>
+#include <smbsrv/samlib.h>
+
+/*
+ * Valid values for the OEM OWF password encryption.
+ */
+#define SAM_PASSWORD_516 516
+#define SAM_KEYLEN 16
+
+extern DWORD samr_set_user_info(mlsvc_handle_t *, smb_auth_info_t *);
+static int get_user_group_info(mlsvc_handle_t *, smb_userinfo_t *);
+
+/*
+ * sam_lookup_user_info
+ *
+ * Lookup user information in the SAM database on the specified server
+ * (domain controller). The LSA interface is used to obtain the user
+ * RID, the domain name and the domain SID (user privileges are TBD).
+ * Then the various SAM layers are opened using the domain SID and the
+ * user RID to obtain the users's group membership information.
+ *
+ * The information is returned in the user_info structure. The caller
+ * is responsible for allocating and releasing this structure. If the
+ * lookup is successful, sid_name_use will be set to SidTypeUser.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+int
+sam_lookup_user_info(char *server, char *domain_name,
+ char *account_name, char *password, smb_userinfo_t *user_info)
+{
+ mlsvc_handle_t samr_handle;
+ mlsvc_handle_t domain_handle;
+ mlsvc_handle_t user_handle;
+ struct samr_sid *sid;
+ int rc;
+ DWORD access_mask;
+ DWORD status;
+
+ if (lsa_lookup_name(server, domain_name, account_name, user_info) != 0)
+ return (-1);
+
+ if (user_info->sid_name_use != SidTypeUser ||
+ user_info->rid == 0 || user_info->domain_sid == 0) {
+ return (-1);
+ }
+
+ rc = samr_open(MLSVC_IPC_USER, server, domain_name, account_name,
+ password, SAM_LOOKUP_INFORMATION, &samr_handle);
+ if (rc != 0)
+ return (-1);
+#if 0
+ rc = samr_lookup_domain(&samr_handle, domain_name, user_info);
+ if (rc != 0)
+ return (-1);
+#endif
+ sid = (struct samr_sid *)user_info->domain_sid;
+
+ status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
+ sid, &domain_handle);
+ if (status == 0) {
+#if 0
+ (void) samr_lookup_domain_names(&domain_handle, account_name,
+ user_info);
+#endif
+ access_mask = STANDARD_RIGHTS_EXECUTE | SAM_ACCESS_USER_READ;
+
+ rc = samr_open_user(&domain_handle, access_mask,
+ user_info->rid, &user_handle);
+
+ if (rc == 0) {
+ (void) get_user_group_info(&user_handle, user_info);
+ (void) samr_close_handle(&user_handle);
+ }
+
+ (void) samr_close_handle(&domain_handle);
+ }
+
+ (void) samr_close_handle(&samr_handle);
+ return (rc);
+}
+
+/*
+ * get_user_group_info
+ *
+ * This is a private function to obtain the primary group and group
+ * memberships for the user specified by the user_handle. This function
+ * should only be called from sam_lookup_user_info.
+ *
+ * On success 0 is returned. Otherwise -1 is returned.
+ */
+static int
+get_user_group_info(mlsvc_handle_t *user_handle, smb_userinfo_t *user_info)
+{
+ union samr_user_info sui;
+ int rc;
+
+ rc = samr_query_user_info(user_handle, SAMR_QUERY_USER_GROUPRID, &sui);
+ if (rc != 0)
+ return (-1);
+
+ rc = samr_query_user_groups(user_handle, user_info);
+ if (rc != 0)
+ return (-1);
+
+ user_info->primary_group_rid = sui.info9.group_rid;
+ return (0);
+}
+
+/*
+ * sam_create_trust_account
+ *
+ * Create a trust account for this system.
+ *
+ * SAMR_AF_WORKSTATION_TRUST_ACCOUNT: servers and workstations.
+ * SAMR_AF_SERVER_TRUST_ACCOUNT: domain controllers.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+sam_create_trust_account(char *server, char *domain, smb_auth_info_t *auth)
+{
+ smb_userinfo_t *user_info;
+ char account_name[MAXHOSTNAMELEN];
+ DWORD status;
+
+ if (smb_gethostname(account_name, MAXHOSTNAMELEN - 2, 1) != 0)
+ return (NT_STATUS_NO_MEMORY);
+
+ (void) strlcat(account_name, "$", MAXHOSTNAMELEN);
+
+ if ((user_info = mlsvc_alloc_user_info()) == 0)
+ return (NT_STATUS_NO_MEMORY);
+
+ /*
+ * The trust account value here should match
+ * the value that will be used when the user
+ * information is set on this account.
+ */
+ status = sam_create_account(server, domain, account_name,
+ auth, SAMR_AF_WORKSTATION_TRUST_ACCOUNT, user_info);
+
+ mlsvc_free_user_info(user_info);
+ return (status);
+}
+
+
+/*
+ * sam_create_account
+ *
+ * Create the specified domain account in the SAM database on the
+ * domain controller.
+ *
+ * Account flags:
+ * SAMR_AF_NORMAL_ACCOUNT
+ * SAMR_AF_WORKSTATION_TRUST_ACCOUNT
+ * SAMR_AF_SERVER_TRUST_ACCOUNT
+ *
+ * Returns NT status codes.
+ */
+DWORD
+sam_create_account(char *server, char *domain_name, char *account_name,
+ smb_auth_info_t *auth, DWORD account_flags, smb_userinfo_t *user_info)
+{
+ mlsvc_handle_t samr_handle;
+ mlsvc_handle_t domain_handle;
+ mlsvc_handle_t user_handle;
+ union samr_user_info sui;
+ struct samr_sid *sid;
+ DWORD rid;
+ DWORD status;
+ int rc;
+
+ rc = samr_open(MLSVC_IPC_ADMIN, server, domain_name, 0, 0,
+ SAM_CONNECT_CREATE_ACCOUNT, &samr_handle);
+
+ if (rc != 0) {
+ status = NT_STATUS_OPEN_FAILED;
+ smb_tracef("SamCreateAccount[%s\\%s]: %s",
+ domain_name, account_name, xlate_nt_status(status));
+ return (status);
+ }
+
+ if (samr_handle.context->server_os == NATIVE_OS_WIN2000) {
+ nt_domain_t *ntdp;
+
+ if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) {
+ (void) lsa_query_account_domain_info();
+ if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) {
+ (void) samr_close_handle(&samr_handle);
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ smb_tracef("SamCreateAccount[%s\\%s]: %s",
+ domain_name, account_name,
+ xlate_nt_status(status));
+ return (status);
+ }
+ }
+
+ sid = (struct samr_sid *)ntdp->sid;
+ } else {
+ if (samr_lookup_domain(&samr_handle,
+ domain_name, user_info) != 0) {
+ (void) samr_close_handle(&samr_handle);
+ smb_tracef("SamCreateAccount[%s]: lookup failed",
+ account_name);
+
+ return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+ }
+
+ sid = (struct samr_sid *)user_info->domain_sid;
+ }
+
+ status = samr_open_domain(&samr_handle,
+ SAM_DOMAIN_CREATE_ACCOUNT, sid, &domain_handle);
+
+ if (status == NT_STATUS_SUCCESS) {
+ status = samr_create_user(&domain_handle, account_name,
+ account_flags, &rid, &user_handle);
+
+ if (status == NT_STATUS_SUCCESS) {
+ (void) samr_query_user_info(&user_handle,
+ SAMR_QUERY_USER_UNKNOWN16, &sui);
+
+ (void) samr_get_user_pwinfo(&user_handle);
+ (void) samr_set_user_info(&user_handle, auth);
+ (void) samr_close_handle(&user_handle);
+ } else if (status == NT_STATUS_USER_EXISTS) {
+ mlsvc_release_user_info(user_info);
+
+ rc = lsa_lookup_name(server, domain_name, account_name,
+ user_info);
+ if (rc == 0)
+ rid = user_info->rid;
+ status = 0;
+ } else {
+ smb_tracef("SamCreateAccount[%s]: %s",
+ account_name, xlate_nt_status(status));
+ }
+
+ (void) samr_close_handle(&domain_handle);
+ } else {
+ smb_tracef("SamCreateAccount[%s]: open domain failed",
+ account_name);
+ status = (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+ }
+
+ (void) samr_close_handle(&samr_handle);
+ return (status);
+}
+
+
+/*
+ * sam_remove_trust_account
+ *
+ * Attempt to remove the workstation trust account for this system.
+ * Administrator access is required to perform this operation.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+sam_remove_trust_account(char *server, char *domain)
+{
+ char account_name[MAXHOSTNAMELEN];
+
+ if (smb_gethostname(account_name, MAXHOSTNAMELEN - 2, 1) != 0)
+ return (NT_STATUS_NO_MEMORY);
+
+ (void) strcat(account_name, "$");
+
+ return (sam_delete_account(server, domain, account_name));
+}
+
+
+/*
+ * sam_delete_account
+ *
+ * Attempt to remove an account from the SAM database on the specified
+ * server.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+sam_delete_account(char *server, char *domain_name, char *account_name)
+{
+ mlsvc_handle_t samr_handle;
+ mlsvc_handle_t domain_handle;
+ mlsvc_handle_t user_handle;
+ smb_userinfo_t *user_info;
+ struct samr_sid *sid;
+ DWORD rid;
+ DWORD access_mask;
+ DWORD status;
+ int rc;
+
+ if ((user_info = mlsvc_alloc_user_info()) == 0)
+ return (NT_STATUS_NO_MEMORY);
+
+ rc = samr_open(MLSVC_IPC_ADMIN, server, domain_name, 0, 0,
+ SAM_LOOKUP_INFORMATION, &samr_handle);
+
+ if (rc != 0) {
+ mlsvc_free_user_info(user_info);
+ return (NT_STATUS_OPEN_FAILED);
+ }
+
+ if (samr_handle.context->server_os == NATIVE_OS_WIN2000) {
+ nt_domain_t *ntdp;
+
+ if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) {
+ (void) lsa_query_account_domain_info();
+ if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) {
+
+ (void) samr_close_handle(&samr_handle);
+ return (NT_STATUS_NO_SUCH_DOMAIN);
+ }
+ }
+
+ sid = (struct samr_sid *)ntdp->sid;
+ } else {
+ if (samr_lookup_domain(
+ &samr_handle, domain_name, user_info) != 0) {
+ (void) samr_close_handle(&samr_handle);
+ mlsvc_free_user_info(user_info);
+ return (NT_STATUS_NO_SUCH_DOMAIN);
+ }
+
+ sid = (struct samr_sid *)user_info->domain_sid;
+ }
+
+ status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
+ sid, &domain_handle);
+ if (status == 0) {
+ mlsvc_release_user_info(user_info);
+ status = samr_lookup_domain_names(&domain_handle,
+ account_name, user_info);
+
+ if (status == 0) {
+ rid = user_info->rid;
+ access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
+
+ rc = samr_open_user(&domain_handle, access_mask,
+ rid, &user_handle);
+ if (rc == 0) {
+ if (samr_delete_user(&user_handle) != 0)
+ (void) samr_close_handle(&user_handle);
+ }
+ }
+
+ (void) samr_close_handle(&domain_handle);
+ }
+
+ (void) samr_close_handle(&samr_handle);
+ mlsvc_free_user_info(user_info);
+ return (status);
+}
+
+/*
+ * sam_lookup_name
+ *
+ * Lookup an account name in the SAM database on the specified domain
+ * controller. Provides the account RID on success.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+sam_lookup_name(char *server, char *domain_name, char *account_name,
+ DWORD *rid_ret)
+{
+ mlsvc_handle_t samr_handle;
+ mlsvc_handle_t domain_handle;
+ smb_userinfo_t *user_info;
+ struct samr_sid *domain_sid;
+ int rc;
+ DWORD status;
+
+ *rid_ret = 0;
+
+ if ((user_info = mlsvc_alloc_user_info()) == 0)
+ return (NT_STATUS_NO_MEMORY);
+
+ rc = samr_open(MLSVC_IPC_ANON, server, domain_name, 0, 0,
+ SAM_LOOKUP_INFORMATION, &samr_handle);
+
+ if (rc != 0) {
+ mlsvc_free_user_info(user_info);
+ return (NT_STATUS_OPEN_FAILED);
+ }
+
+ rc = samr_lookup_domain(&samr_handle, domain_name, user_info);
+ if (rc != 0) {
+ (void) samr_close_handle(&samr_handle);
+ mlsvc_free_user_info(user_info);
+ return (NT_STATUS_NO_SUCH_DOMAIN);
+ }
+
+ domain_sid = (struct samr_sid *)user_info->domain_sid;
+
+ status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
+ domain_sid, &domain_handle);
+ if (status == 0) {
+ mlsvc_release_user_info(user_info);
+
+ status = samr_lookup_domain_names(&domain_handle,
+ account_name, user_info);
+ if (status == 0)
+ *rid_ret = user_info->rid;
+
+ (void) samr_close_handle(&domain_handle);
+ }
+
+ (void) samr_close_handle(&samr_handle);
+ mlsvc_free_user_info(user_info);
+ return (status);
+}
+
+
+/*
+ * sam_get_local_domains
+ *
+ * Query a remote server to get the list of local domains that it
+ * supports.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+sam_get_local_domains(char *server, char *domain_name)
+{
+ mlsvc_handle_t samr_handle;
+ DWORD status;
+ int rc;
+
+ rc = samr_open(MLSVC_IPC_ANON, server, domain_name, 0, 0,
+ SAM_ENUM_LOCAL_DOMAIN, &samr_handle);
+ if (rc != 0)
+ return (NT_STATUS_OPEN_FAILED);
+
+ status = samr_enum_local_domains(&samr_handle);
+ (void) samr_close_handle(&samr_handle);
+ return (status);
+}
+
+/*
+ * sam_oem_password
+ *
+ * Generate an OEM password.
+ */
+int sam_oem_password(oem_password_t *oem_password, unsigned char *new_password,
+ unsigned char *old_password)
+{
+ mts_wchar_t *unicode_password;
+ int length;
+
+#ifdef PBSHORTCUT
+ assert(sizeof (oem_password_t) == SAM_PASSWORD_516);
+#endif /* PBSHORTCUT */
+
+ length = strlen((char const *)new_password);
+ unicode_password = alloca((length + 1) * sizeof (mts_wchar_t));
+
+ length = smb_auth_qnd_unicode((unsigned short *)unicode_password,
+ (char *)new_password, length);
+ oem_password->length = length;
+
+ (void) memcpy(&oem_password->data[512 - length],
+ unicode_password, length);
+
+ rand_hash((unsigned char *)oem_password, sizeof (oem_password_t),
+ old_password, SAM_KEYLEN);
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c
new file mode 100644
index 0000000000..7eccd83e22
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c
@@ -0,0 +1,565 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Security Access Manager RPC (SAMR) library interface functions for
+ * query and lookup calls.
+ */
+
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/samlib.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/mlsvc.h>
+
+static int samr_setup_user_info(WORD, struct samr_QueryUserInfo *,
+ union samr_user_info *);
+static void samr_set_user_unknowns(struct samr_SetUserInfo23 *);
+static void samr_set_user_logon_hours(struct samr_SetUserInfo *);
+static int samr_set_user_password(smb_auth_info_t *, BYTE *);
+
+/*
+ * samr_lookup_domain
+ *
+ * Lookup up the domain SID for the specified domain name. The handle
+ * should be one returned from samr_connect. The results will be
+ * returned in user_info - which should have been allocated by the
+ * caller. On success sid_name_use will be set to SidTypeDomain.
+ *
+ * Returns 0 on success, otherwise returns -ve error code.
+ */
+int
+samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name,
+ smb_userinfo_t *user_info)
+{
+ struct samr_LookupDomain arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ size_t length;
+
+ if (mlsvc_is_null_handle(samr_handle) ||
+ domain_name == NULL || user_info == NULL) {
+ return (-1);
+ }
+
+ context = samr_handle->context;
+ opnum = SAMR_OPNUM_LookupDomain;
+ bzero(&arg, sizeof (struct samr_LookupDomain));
+
+ (void) memcpy(&arg.handle, &samr_handle->handle,
+ sizeof (samr_handle_t));
+
+ length = mts_wcequiv_strlen(domain_name);
+ if (context->server_os == NATIVE_OS_WIN2000)
+ length += sizeof (mts_wchar_t);
+
+ arg.domain_name.length = length;
+ arg.domain_name.allosize = length;
+ arg.domain_name.str = (unsigned char *)domain_name;
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ user_info->sid_name_use = SidTypeDomain;
+ user_info->domain_sid = nt_sid_dup((nt_sid_t *)arg.sid);
+ user_info->domain_name = MEM_STRDUP("mlrpc", domain_name);
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * samr_enum_local_domains
+ *
+ * Get the list of local domains supported by a server.
+ *
+ * Returns NT status codes.
+ */
+DWORD
+samr_enum_local_domains(mlsvc_handle_t *samr_handle)
+{
+ struct samr_EnumLocalDomain arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ DWORD status;
+
+ if (mlsvc_is_null_handle(samr_handle))
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ context = samr_handle->context;
+ opnum = SAMR_OPNUM_EnumLocalDomains;
+ bzero(&arg, sizeof (struct samr_EnumLocalDomain));
+
+ (void) memcpy(&arg.handle, &samr_handle->handle,
+ sizeof (samr_handle_t));
+ arg.enum_context = 0;
+ arg.max_length = 0x00002000; /* Value used by NT */
+
+ (void) mlsvc_rpc_init(&heap);
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else {
+ status = NT_SC_VALUE(arg.status);
+
+ /*
+ * Handle none-mapped status quietly.
+ */
+ if (status != NT_STATUS_NONE_MAPPED)
+ mlsvc_rpc_report_status(opnum, arg.status);
+ }
+
+ return (status);
+}
+
+/*
+ * samr_lookup_domain_names
+ *
+ * Lookup up a name
+ * returned in user_info - which should have been allocated by the
+ * caller. On success sid_name_use will be set to SidTypeDomain.
+ *
+ * Returns 0 on success. Otherwise returns an NT status code.
+ */
+DWORD
+samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
+ smb_userinfo_t *user_info)
+{
+ struct samr_LookupNames arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ DWORD status;
+ size_t length;
+
+ if (mlsvc_is_null_handle(domain_handle) ||
+ name == NULL || user_info == NULL) {
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ context = domain_handle->context;
+ opnum = SAMR_OPNUM_LookupNames;
+ bzero(&arg, sizeof (struct samr_LookupNames));
+
+ (void) memcpy(&arg.handle, &domain_handle->handle,
+ sizeof (samr_handle_t));
+ arg.n_entry = 1;
+ arg.max_n_entry = 1000;
+ arg.index = 0;
+ arg.total = 1;
+
+ length = mts_wcequiv_strlen(name);
+ if (context->server_os == NATIVE_OS_WIN2000)
+ length += sizeof (mts_wchar_t);
+
+ arg.name.length = length;
+ arg.name.allosize = length;
+ arg.name.str = (unsigned char *)name;
+
+ (void) mlsvc_rpc_init(&heap);
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ status = NT_SC_VALUE(arg.status);
+
+ /*
+ * Handle none-mapped status quietly.
+ */
+ if (status != NT_STATUS_NONE_MAPPED)
+ mlsvc_rpc_report_status(opnum, arg.status);
+ } else {
+ user_info->name = MEM_STRDUP("mlrpc", name);
+ user_info->sid_name_use = arg.rid_types.rid_type[0];
+ user_info->rid = arg.rids.rid[0];
+ status = 0;
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+/*
+ * samr_query_user_info
+ *
+ * Query information on a specific user. The handle must be a valid
+ * user handle obtained via samr_open_user.
+ *
+ * Returns 0 on success, otherwise returns -ve error code.
+ */
+int
+samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value,
+ union samr_user_info *user_info)
+{
+ struct samr_QueryUserInfo arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+
+ if (mlsvc_is_null_handle(user_handle) || user_info == 0)
+ return (-1);
+
+ context = user_handle->context;
+ opnum = SAMR_OPNUM_QueryUserInfo;
+ bzero(&arg, sizeof (struct samr_QueryUserInfo));
+
+ (void) memcpy(&arg.user_handle, &user_handle->handle,
+ sizeof (samr_handle_t));
+ arg.switch_value = switch_value;
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0)
+ rc = -1;
+ else
+ rc = samr_setup_user_info(switch_value, &arg,
+ user_info);
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+
+/*
+ * samr_setup_user_info
+ *
+ * Private function to set up the samr_user_info data. Dependent on
+ * the switch value this function may use strdup which will malloc
+ * memory. The caller is responsible for deallocating this memory.
+ *
+ * Returns 0 on success, otherwise returns -1.
+ */
+static int samr_setup_user_info(WORD switch_value,
+ struct samr_QueryUserInfo *arg, union samr_user_info *user_info)
+{
+ struct samr_QueryUserInfo1 *info1;
+ struct samr_QueryUserInfo6 *info6;
+
+ switch (switch_value) {
+ case 1:
+ info1 = &arg->ru.info1;
+ user_info->info1.username = strdup(
+ (char const *)info1->username.str);
+ user_info->info1.fullname = strdup(
+ (char const *)info1->fullname.str);
+ user_info->info1.description = strdup(
+ (char const *)info1->description.str);
+ user_info->info1.unknown = 0;
+ user_info->info1.group_rid = info1->group_rid;
+ return (0);
+
+ case 6:
+ info6 = &arg->ru.info6;
+ user_info->info6.username = strdup(
+ (char const *)info6->username.str);
+ user_info->info6.fullname = strdup(
+ (char const *)info6->fullname.str);
+ return (0);
+
+ case 7:
+ user_info->info7.username = strdup(
+ (char const *)arg->ru.info7.username.str);
+ return (0);
+
+ case 8:
+ user_info->info8.fullname = strdup(
+ (char const *)arg->ru.info8.fullname.str);
+ return (0);
+
+ case 9:
+ user_info->info9.group_rid = arg->ru.info9.group_rid;
+ return (0);
+
+ case 16:
+ return (0);
+
+ default:
+ break;
+ };
+
+ return (-1);
+}
+
+/*
+ * samr_query_user_groups
+ *
+ * Query the groups for a specific user. The handle must be a valid
+ * user handle obtained via samr_open_user. The list of groups is
+ * returned in group_info. Note that group_info->groups is allocated
+ * using malloc. The caller is responsible for deallocating this
+ * memory when it is no longer required. If group_info->n_entry is 0
+ * then no memory was allocated.
+ *
+ * Returns 0 on success, otherwise returns -1.
+ */
+int
+samr_query_user_groups(mlsvc_handle_t *user_handle, smb_userinfo_t *user_info)
+{
+ struct samr_QueryUserGroups arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ int nbytes;
+
+ if (mlsvc_is_null_handle(user_handle) || user_info == NULL)
+ return (-1);
+
+ context = user_handle->context;
+ opnum = SAMR_OPNUM_QueryUserGroups;
+ bzero(&arg, sizeof (struct samr_QueryUserGroups));
+
+ (void) memcpy(&arg.user_handle, &user_handle->handle,
+ sizeof (samr_handle_t));
+
+ (void) mlsvc_rpc_init(&heap);
+
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.info == 0) {
+ rc = -1;
+ } else {
+ nbytes = arg.info->n_entry *
+ sizeof (struct samr_UserGroups);
+ user_info->groups = malloc(nbytes);
+
+ if (user_info->groups == NULL) {
+ user_info->n_groups = 0;
+ rc = -1;
+ } else {
+ user_info->n_groups = arg.info->n_entry;
+ (void) memcpy(user_info->groups,
+ arg.info->groups, nbytes);
+ }
+ }
+ }
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+
+/*
+ * samr_get_user_pwinfo
+ *
+ * Get some user password info. I'm not sure what this is yet but it is
+ * part of the create user sequence. The handle must be a valid user
+ * handle. Since I don't know what this is returning, I haven't provided
+ * any return data yet.
+ *
+ * Returns 0 on success. Otherwise returns an NT status code.
+ */
+DWORD
+samr_get_user_pwinfo(mlsvc_handle_t *user_handle)
+{
+ struct samr_GetUserPwInfo arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ DWORD status;
+
+ if (mlsvc_is_null_handle(user_handle))
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ context = user_handle->context;
+ opnum = SAMR_OPNUM_GetUserPwInfo;
+ bzero(&arg, sizeof (struct samr_GetUserPwInfo));
+ (void) memcpy(&arg.user_handle, &user_handle->handle,
+ sizeof (samr_handle_t));
+
+ (void) mlsvc_rpc_init(&heap);
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ status = NT_SC_VALUE(arg.status);
+ } else {
+ status = 0;
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+
+/*
+ * samr_set_user_info
+ *
+ * Returns 0 on success. Otherwise returns an NT status code.
+ * NT status codes observed so far:
+ * NT_STATUS_WRONG_PASSWORD
+ */
+/*ARGSUSED*/
+DWORD
+samr_set_user_info(mlsvc_handle_t *user_handle, smb_auth_info_t *auth)
+{
+ struct samr_SetUserInfo arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ DWORD status = 0;
+
+ if (mlsvc_is_null_handle(user_handle))
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ (void) mlsvc_rpc_init(&heap);
+
+ context = user_handle->context;
+ opnum = SAMR_OPNUM_SetUserInfo;
+ bzero(&arg, sizeof (struct samr_SetUserInfo));
+ (void) memcpy(&arg.user_handle, &user_handle->handle,
+ sizeof (samr_handle_t));
+
+ arg.info.index = SAMR_SET_USER_INFO_23;
+ arg.info.switch_value = SAMR_SET_USER_INFO_23;
+
+ samr_set_user_unknowns(&arg.info.ru.info23);
+ samr_set_user_logon_hours(&arg);
+
+ if (samr_set_user_password(auth, arg.info.ru.info23.password) < 0)
+ status = NT_STATUS_INTERNAL_ERROR;
+
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ status = NT_SC_VALUE(arg.status);
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+static void
+samr_set_user_unknowns(struct samr_SetUserInfo23 *info)
+{
+ bzero(info, sizeof (struct samr_SetUserInfo23));
+
+ info->sd.length = 0;
+ info->sd.data = 0;
+ info->user_rid = 0;
+ info->group_rid = MLSVC_DOMAIN_GROUP_RID_USERS;
+
+ /*
+ * The trust account value used here should probably
+ * match the one used to create the trust account.
+ */
+ info->acct_info = SAMR_AF_WORKSTATION_TRUST_ACCOUNT;
+ info->flags = 0x09F827FA;
+}
+
+/*
+ * samr_set_user_logon_hours
+ *
+ * SamrSetUserInfo appears to contain some logon hours information, which
+ * looks like a varying, conformant array. The top level contains a value
+ * (units), which probably indicates the how to interpret the array. The
+ * array definition looks like it contains a maximum size, an initial
+ * offset and a bit length (units/8), followed by the bitmap.
+ *
+ * (info)
+ * +-------+
+ * | units |
+ * +-------+ (hours)
+ * | hours |-->+-----------+
+ * +-------+ | max_is |
+ * +-----------+
+ * | first_is |
+ * +-----------+
+ * | length_is |
+ * +------------------------+
+ * | bitmap[length_is] |
+ * +---------+--------------+
+ *
+ * 10080 minutes/week => 10080/8 = 1260 (0x04EC) bytes.
+ * 168 hours/week => 168/8 = 21 (0xA8) bytes.
+ * In the netmon examples seen so far, all bits are set to 1, i.e.
+ * an array containing 0xff. This is probably the default setting.
+ *
+ * ndrgen has a problem with complex [size_is] statements (length/8).
+ * So, for now, we fake it using two separate components.
+ */
+static void
+samr_set_user_logon_hours(struct samr_SetUserInfo *sui)
+{
+ sui->logon_hours.size = SAMR_HOURS_MAX_SIZE;
+ sui->logon_hours.first = 0;
+ sui->logon_hours.length = SAMR_SET_USER_HOURS_SZ;
+ (void) memset(sui->logon_hours.bitmap, 0xFF, SAMR_SET_USER_HOURS_SZ);
+
+ sui->info.ru.info23.logon_info.units = SAMR_HOURS_PER_WEEK;
+ sui->info.ru.info23.logon_info.hours = (DWORD)sui->logon_hours.bitmap;
+}
+
+/*
+ * samr_set_user_password
+ *
+ * Set the initial password for the user.
+ *
+ * Returns 0 if everything goes well, -1 if there is trouble generating a
+ * key.
+ */
+static int
+samr_set_user_password(smb_auth_info_t *auth, BYTE *oem_password)
+{
+ unsigned char nt_key[SMBAUTH_SESSION_KEY_SZ];
+ char hostname[64];
+
+ randomize((char *)oem_password, SAMR_SET_USER_DATA_SZ);
+
+ /*
+ * The new password is going to be
+ * the hostname in lower case.
+ */
+ if (smb_gethostname(hostname, 64, 0) != 0)
+ return (-1);
+
+ (void) utf8_strlwr(hostname);
+
+ if (smb_auth_gen_session_key(auth, nt_key) != SMBAUTH_SUCCESS)
+ return (-1);
+
+ /*
+ * Generate the OEM password from the hostname and the user session
+ * key(nt_key).
+ */
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ (void) sam_oem_password((oem_password_t *)oem_password,
+ (unsigned char *)hostname, nt_key);
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_open.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_open.c
new file mode 100644
index 0000000000..38dca838cd
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_open.c
@@ -0,0 +1,684 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Security Access Manager RPC (SAMR) library interface functions for
+ * connect, open and close calls. The SAM is a hierarchical database.
+ * If you want to talk to the SAM you need a SAM handle, if you want
+ * to work with a domain, you need to use the SAM handle to obtain a
+ * domain handle. Then you can use the domain handle to obtain a user
+ * handle etc. Be careful about returning null handles to the
+ * application. Use of a null handle may crash the domain controller
+ * if you attempt to use it.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/param.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbrdr.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntaccess.h>
+#include <smbsrv/samlib.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/mlsvc.h>
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD samr_connect1(char *, char *, char *, DWORD, mlsvc_handle_t *);
+static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *);
+static DWORD samr_connect3(char *, char *, char *, DWORD, mlsvc_handle_t *);
+static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *);
+
+/*
+ * samr_open
+ *
+ * This is a wrapper round samr_connect to ensure that we connect using
+ * the appropriate session and logon. We default to the resource domain
+ * information if the caller doesn't supply a server name and a domain
+ * name. We store the remote server's native OS type - we may need it
+ * due to differences between platforms like NT and Windows 2000.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+int
+samr_open(int ipc_mode, char *server, char *domain, char *username,
+ char *password, DWORD access_mask, mlsvc_handle_t *samr_handle)
+{
+ smb_ntdomain_t *di;
+ int remote_os;
+ int remote_lm;
+ int rc;
+
+ if ((di = smb_getdomaininfo(0)) == NULL)
+ return (-1);
+
+ if (server == NULL || domain == NULL) {
+ server = di->server;
+ domain = di->domain;
+ }
+
+ switch (ipc_mode) {
+ case MLSVC_IPC_USER:
+ /*
+ * Use the supplied credentials.
+ */
+ rc = mlsvc_user_logon(server, domain, username, password);
+ break;
+
+ case MLSVC_IPC_ADMIN:
+ /*
+ * Use the resource domain administrator credentials.
+ */
+ server = di->server;
+ domain = di->domain;
+ username = smbrdr_ipc_get_user();
+
+ rc = mlsvc_admin_logon(server, domain);
+ break;
+
+ case MLSVC_IPC_ANON:
+ default:
+ rc = mlsvc_anonymous_logon(server, domain, &username);
+ break;
+ }
+
+ if (rc != 0)
+ return (-1);
+
+ rc = samr_connect(server, domain, username, access_mask, samr_handle);
+ if (rc == 0) {
+ (void) mlsvc_session_native_values(samr_handle->context->fid,
+ &remote_os, &remote_lm, 0);
+ samr_handle->context->server_os = remote_os;
+ }
+ return (rc);
+}
+
+
+/*
+ * samr_connect
+ *
+ * Connect to the SAM on the specified server (domain controller).
+ * This is the entry point for the various SAM connect calls. We do
+ * parameter validation and open the samr named pipe here. The actual
+ * RPC is based on the native OS of the server.
+ *
+ * Returns 0 on success. Otherwise returns a -ve error code.
+ */
+int
+samr_connect(char *server, char *domain, char *username, DWORD access_mask,
+ mlsvc_handle_t *samr_handle)
+{
+ DWORD status;
+ int remote_os;
+ int remote_lm;
+ int fid;
+ int rc = 0;
+
+ if (server == NULL || domain == NULL ||
+ username == NULL || samr_handle == NULL)
+ return (-1);
+
+ if ((fid = mlsvc_open_pipe(server, domain, username, "\\samr")) < 0)
+ return (-1);
+
+ if (mlsvc_rpc_bind(samr_handle, fid, "SAMR") < 0) {
+ (void) mlsvc_close_pipe(fid);
+ return (-1);
+ }
+
+ (void) mlsvc_session_native_values(fid, &remote_os, &remote_lm, 0);
+
+ switch (remote_os) {
+ case NATIVE_OS_NT5_1:
+ status = samr_connect4(server, domain, username, access_mask,
+ samr_handle);
+ break;
+
+ case NATIVE_OS_NT5_0:
+ status = samr_connect3(server, domain, username, access_mask,
+ samr_handle);
+ break;
+
+ case NATIVE_OS_NT4_0:
+ default:
+ status = samr_connect2(server, domain, username, access_mask,
+ samr_handle);
+ break;
+ }
+
+ if (status != NT_STATUS_SUCCESS) {
+ (void) mlsvc_close_pipe(fid);
+ free(samr_handle->context);
+ rc = -1;
+ }
+ return (rc);
+}
+
+/*
+ * samr_connect1
+ *
+ * Original SAMR connect call; probably used on Windows NT 3.51.
+ * Windows 95 uses this call with the srvmgr tools update.
+ * Servername appears to be a dword rather than a string.
+ * The first word contains '\' and the second word contains 0x001,
+ * (which is probably uninitialized junk: 0x0001005c.
+ */
+/*ARGSUSED*/
+static DWORD
+samr_connect1(char *server, char *domain, char *username, DWORD access_mask,
+ mlsvc_handle_t *samr_handle)
+{
+ struct samr_ConnectAnon arg;
+ mlrpc_heapref_t heapref;
+ int opnum;
+ DWORD status;
+
+ bzero(&arg, sizeof (struct samr_ConnectAnon));
+ opnum = SAMR_OPNUM_ConnectAnon;
+ status = NT_STATUS_SUCCESS;
+
+ (void) mlsvc_rpc_init(&heapref);
+ arg.servername = (DWORD *)mlrpc_heap_malloc(heapref.heap,
+ sizeof (DWORD));
+ *(arg.servername) = 0x0001005c;
+ arg.access_mask = access_mask;
+
+ if (mlsvc_rpc_call(samr_handle->context, opnum, &arg, &heapref) != 0) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ } else if (arg.status != 0) {
+ status = NT_SC_VALUE(arg.status);
+ } else {
+ (void) memcpy(&samr_handle->handle, &arg.handle,
+ sizeof (ms_handle_t));
+
+ if (mlsvc_is_null_handle(samr_handle))
+ status = NT_STATUS_INVALID_HANDLE;
+ }
+
+ mlsvc_rpc_free(samr_handle->context, &heapref);
+ return (status);
+}
+
+/*
+ * samr_connect2
+ *
+ * Connect to the SAM on a Windows NT 4.0 server (domain controller).
+ * We need the domain controller name and, if everything works, we
+ * return a handle. This function adds the double backslash prefx to
+ * make it easy for applications.
+ *
+ * Returns 0 on success. Otherwise returns a -ve error code.
+ */
+/*ARGSUSED*/
+static DWORD
+samr_connect2(char *server, char *domain, char *username, DWORD access_mask,
+ mlsvc_handle_t *samr_handle)
+{
+ struct samr_Connect arg;
+ mlrpc_heapref_t heapref;
+ int opnum;
+ DWORD status;
+ int len;
+
+ bzero(&arg, sizeof (struct samr_Connect));
+ opnum = SAMR_OPNUM_Connect;
+ status = NT_STATUS_SUCCESS;
+
+ (void) mlsvc_rpc_init(&heapref);
+ len = strlen(server) + 4;
+ arg.servername = mlrpc_heap_malloc(heapref.heap, len);
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ arg.access_mask = access_mask;
+
+ if (mlsvc_rpc_call(samr_handle->context, opnum, &arg, &heapref) != 0) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ } else if (arg.status != 0) {
+ status = NT_SC_VALUE(arg.status);
+ } else {
+ (void) memcpy(&samr_handle->handle, &arg.handle,
+ sizeof (ms_handle_t));
+
+ if (mlsvc_is_null_handle(samr_handle))
+ status = NT_STATUS_INVALID_HANDLE;
+ }
+
+ mlsvc_rpc_free(samr_handle->context, &heapref);
+ return (status);
+}
+
+/*
+ * samr_connect3
+ *
+ * Connect to the SAM on a Windows 2000 domain controller.
+ */
+/*ARGSUSED*/
+static DWORD
+samr_connect3(char *server, char *domain, char *username, DWORD access_mask,
+ mlsvc_handle_t *samr_handle)
+{
+ struct samr_Connect3 arg;
+ mlrpc_heapref_t heapref;
+ int opnum;
+ DWORD status;
+ int len;
+
+ bzero(&arg, sizeof (struct samr_Connect3));
+ opnum = SAMR_OPNUM_Connect3;
+ status = NT_STATUS_SUCCESS;
+
+ (void) mlsvc_rpc_init(&heapref);
+ len = strlen(server) + 4;
+ arg.servername = mlrpc_heap_malloc(heapref.heap, len);
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ arg.unknown_02 = 0x00000002;
+ arg.access_mask = access_mask;
+
+ if (mlsvc_rpc_call(samr_handle->context, opnum, &arg, &heapref) != 0) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ } else if (arg.status != 0) {
+ status = NT_SC_VALUE(arg.status);
+ } else {
+ (void) memcpy(&samr_handle->handle, &arg.handle,
+ sizeof (ms_handle_t));
+
+ if (mlsvc_is_null_handle(samr_handle))
+ status = NT_STATUS_INVALID_HANDLE;
+ }
+
+ mlsvc_rpc_free(samr_handle->context, &heapref);
+ return (status);
+}
+
+/*
+ * samr_connect4
+ *
+ * Connect to the SAM on a Windows XP domain controller. On Windows
+ * XP, the server should be the fully qualified DNS domain name with
+ * a double backslash prefix. At this point, it is assumed that we
+ * need to add the prefix and the DNS domain name here.
+ *
+ * If this call succeeds, a SAMR handle is placed in samr_handle and
+ * zero is returned. Otherwise, a -ve error code is returned.
+ */
+/*ARGSUSED*/
+static DWORD
+samr_connect4(char *server, char *domain, char *username, DWORD access_mask,
+ mlsvc_handle_t *samr_handle)
+{
+ struct samr_Connect4 arg;
+ mlrpc_heapref_t heapref;
+ char *dns_name;
+ int len;
+ int opnum;
+ DWORD status;
+
+ bzero(&arg, sizeof (struct samr_Connect4));
+ opnum = SAMR_OPNUM_Connect;
+ status = NT_STATUS_SUCCESS;
+
+ (void) mlsvc_rpc_init(&heapref);
+ dns_name = mlrpc_heap_malloc(heapref.heap, MAXHOSTNAMELEN);
+ (void) smb_getdomainname(dns_name, MAXHOSTNAMELEN);
+
+ if (strlen(dns_name) > 0) {
+ len = strlen(server) + strlen(dns_name) + 4;
+ arg.servername = mlrpc_heap_malloc(heapref.heap, len);
+ (void) snprintf((char *)arg.servername, len, "\\\\%s.%s",
+ server, dns_name);
+ } else {
+ len = strlen(server) + 4;
+ arg.servername = mlrpc_heap_malloc(heapref.heap, len);
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ }
+
+ arg.access_mask = SAM_ENUM_LOCAL_DOMAIN;
+ arg.unknown2_00000001 = 0x00000001;
+ arg.unknown3_00000001 = 0x00000001;
+ arg.unknown4_00000003 = 0x00000003;
+ arg.unknown5_00000000 = 0x00000000;
+
+ if (mlsvc_rpc_call(samr_handle->context, opnum, &arg, &heapref) != 0) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ } else if (arg.status != 0) {
+ status = NT_SC_VALUE(arg.status);
+ } else {
+
+ (void) memcpy(&samr_handle->handle, &arg.handle,
+ sizeof (ms_handle_t));
+
+ if (mlsvc_is_null_handle(samr_handle))
+ status = NT_STATUS_INVALID_HANDLE;
+ }
+
+ mlsvc_rpc_free(samr_handle->context, &heapref);
+
+ return (status);
+}
+
+
+/*
+ * samr_close_handle
+ *
+ * This is function closes any valid handle, i.e. sam, domain, user etc.
+ * Just to be safe we check for, and reject, null handles. The handle
+ * returned by the SAM server is all null. If the handle being closed is
+ * the top level connect handle, we also close the pipe. Then we zero
+ * out the handle to invalidate it. Things go badly if you attempt to
+ * use an invalid handle, i.e. the DC crashes.
+ */
+int
+samr_close_handle(mlsvc_handle_t *desc)
+{
+ struct samr_CloseHandle arg;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+
+ if (mlsvc_is_null_handle(desc))
+ return (-1);
+
+ opnum = SAMR_OPNUM_CloseHandle;
+ bzero(&arg, sizeof (struct samr_CloseHandle));
+ (void) memcpy(&arg.handle, &desc->handle, sizeof (ms_handle_t));
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(desc->context, opnum, &arg, &heap);
+ mlsvc_rpc_free(desc->context, &heap);
+
+ if (desc->context->handle == &desc->handle) {
+ (void) mlsvc_close_pipe(desc->context->fid);
+ free(desc->context);
+ }
+
+ bzero(desc, sizeof (mlsvc_handle_t));
+ return (rc);
+}
+
+/*
+ * samr_open_domain
+ *
+ * We use a SAM handle to obtain a handle for a domain, specified by
+ * the SID. The SID can be obtain via the LSA interface. A handle for
+ * the domain is returned in domain_handle.
+ */
+DWORD
+samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask,
+ struct samr_sid *sid, mlsvc_handle_t *domain_handle)
+{
+ struct samr_OpenDomain arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ DWORD status;
+
+ if (mlsvc_is_null_handle(samr_handle) ||
+ sid == 0 || domain_handle == 0) {
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ context = samr_handle->context;
+ opnum = SAMR_OPNUM_OpenDomain;
+ bzero(&arg, sizeof (struct samr_OpenDomain));
+ (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ms_handle_t));
+
+ arg.access_mask = access_mask;
+ arg.sid = sid;
+
+ (void) mlsvc_rpc_init(&heap);
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ } else if (arg.status != 0) {
+ status = arg.status;
+ } else {
+ status = NT_STATUS_SUCCESS;
+ (void) memcpy(&domain_handle->handle, &arg.domain_handle,
+ sizeof (ms_handle_t));
+ domain_handle->context = context;
+ if (mlsvc_is_null_handle(domain_handle))
+ status = NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (status != NT_STATUS_SUCCESS)
+ mlsvc_rpc_report_status(opnum, status);
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+/*
+ * samr_open_user
+ *
+ * Use a domain handle to obtain a handle for a user, specified by the
+ * user RID. A user RID (effectively a uid) can be obtained via the
+ * LSA interface. A handle for the user is returned in user_handle.
+ * Once you have a user handle it should be possible to query the SAM
+ * for information on that user.
+ */
+int
+samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask, DWORD rid,
+ mlsvc_handle_t *user_handle)
+{
+ struct samr_OpenUser arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+
+ if (mlsvc_is_null_handle(domain_handle) || user_handle == NULL)
+ return (-1);
+
+ context = domain_handle->context;
+ opnum = SAMR_OPNUM_OpenUser;
+ bzero(&arg, sizeof (struct samr_OpenUser));
+ (void) memcpy(&arg.handle, &domain_handle->handle,
+ sizeof (ms_handle_t));
+ arg.access_mask = access_mask;
+ arg.rid = rid;
+
+ (void) mlsvc_rpc_init(&heap);
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ rc = -1;
+ } else {
+ (void) memcpy(&user_handle->handle, &arg.user_handle,
+ sizeof (ms_handle_t));
+ user_handle->context = context;
+
+ if (mlsvc_is_null_handle(user_handle))
+ rc = -1;
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * samr_delete_user
+ *
+ * Delete the user specified by the user_handle.
+ */
+DWORD
+samr_delete_user(mlsvc_handle_t *user_handle)
+{
+ struct samr_DeleteUser arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ DWORD status;
+
+ if (mlsvc_is_null_handle(user_handle))
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ context = user_handle->context;
+ opnum = SAMR_OPNUM_DeleteUser;
+ bzero(&arg, sizeof (struct samr_DeleteUser));
+ (void) memcpy(&arg.user_handle, &user_handle->handle,
+ sizeof (ms_handle_t));
+
+ (void) mlsvc_rpc_init(&heap);
+ if (mlsvc_rpc_call(context, opnum, &arg, &heap) != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ status = NT_SC_VALUE(arg.status);
+ } else {
+ status = 0;
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
+
+/*
+ * samr_open_group
+ *
+ * Use a domain handle to obtain a handle for a group, specified by the
+ * group RID. A group RID (effectively a gid) can be obtained via the
+ * LSA interface. A handle for the group is returned in group_handle.
+ * Once you have a group handle it should be possible to query the SAM
+ * for information on that group.
+ */
+int
+samr_open_group(
+ mlsvc_handle_t *domain_handle,
+ DWORD rid,
+ mlsvc_handle_t *group_handle)
+{
+ struct samr_OpenGroup arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+
+ if (mlsvc_is_null_handle(domain_handle) || group_handle == 0)
+ return (-1);
+
+ context = domain_handle->context;
+ opnum = SAMR_OPNUM_OpenGroup;
+ bzero(&arg, sizeof (struct samr_OpenUser));
+ (void) memcpy(&arg.handle, &domain_handle->handle,
+ sizeof (ms_handle_t));
+ arg.access_mask = SAM_LOOKUP_INFORMATION | SAM_ACCESS_USER_READ;
+ arg.rid = rid;
+
+ (void) mlsvc_rpc_init(&heap);
+
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc == 0) {
+ if (arg.status != 0) {
+ mlsvc_rpc_report_status(opnum, arg.status);
+ rc = -1;
+ } else {
+ (void) memcpy(&group_handle->handle, &arg.group_handle,
+ sizeof (ms_handle_t));
+ group_handle->context = context;
+ if (mlsvc_is_null_handle(group_handle))
+ rc = -1;
+ }
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (rc);
+}
+
+/*
+ * samr_create_user
+ *
+ * Create a user in the domain specified by the domain handle. If this
+ * call is successful, the server will return the RID for the user and
+ * a user handle, which may be used to set or query the SAM.
+ *
+ * Observed status codes:
+ * NT_STATUS_INVALID_PARAMETER
+ * NT_STATUS_INVALID_ACCOUNT_NAME
+ * NT_STATUS_ACCESS_DENIED
+ * NT_STATUS_USER_EXISTS
+ *
+ * Returns 0 on success. Otherwise returns an NT status code.
+ */
+DWORD
+samr_create_user(mlsvc_handle_t *domain_handle, char *username,
+ DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle)
+{
+ struct samr_CreateUser arg;
+ struct mlsvc_rpc_context *context;
+ mlrpc_heapref_t heap;
+ int opnum;
+ int rc;
+ DWORD status = 0;
+
+ if (mlsvc_is_null_handle(domain_handle) ||
+ username == NULL || rid == NULL) {
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ context = domain_handle->context;
+ opnum = SAMR_OPNUM_CreateUser;
+
+ bzero(&arg, sizeof (struct samr_CreateUser));
+ (void) memcpy(&arg.handle, &domain_handle->handle,
+ sizeof (ms_handle_t));
+
+ (void) mlsvc_rpc_init(&heap);
+ mlrpc_heap_mkvcs(heap.heap, username, (mlrpc_vcbuf_t *)&arg.username);
+
+ arg.account_flags = account_flags;
+ arg.unknown_e00500b0 = 0xE00500B0;
+
+ rc = mlsvc_rpc_call(context, opnum, &arg, &heap);
+ if (rc != 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ } else if (arg.status != 0) {
+ status = NT_SC_VALUE(arg.status);
+
+ if (status != NT_STATUS_USER_EXISTS) {
+ smb_tracef("SamrCreateUser[%s]: %s", username,
+ xlate_nt_status(status));
+ }
+ } else {
+ (void) memcpy(&user_handle->handle, &arg.user_handle,
+ sizeof (ms_handle_t));
+ user_handle->context = context;
+ *rid = arg.rid;
+
+ if (mlsvc_is_null_handle(user_handle))
+ status = NT_STATUS_INVALID_HANDLE;
+ else
+ status = 0;
+ }
+
+ mlsvc_rpc_free(context, &heap);
+ return (status);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/secdb.c b/usr/src/lib/smbsrv/libmlsvc/common/secdb.c
new file mode 100644
index 0000000000..cc4d96456f
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/secdb.c
@@ -0,0 +1,932 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Security database interface.
+ */
+#include <unistd.h>
+#include <strings.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <syslog.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_token.h>
+#include <smbsrv/lsalib.h>
+#include <smbsrv/alloc.h>
+
+extern uint32_t netlogon_logon(netr_client_t *clnt, smb_userinfo_t *uinfo);
+static uint32_t smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo);
+static uint32_t smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo);
+static uint32_t smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo);
+
+static uint32_t smb_setup_luinfo(smb_userinfo_t *, netr_client_t *, uid_t);
+
+static int smb_token_is_member(smb_token_t *token, nt_sid_t *sid);
+static int smb_token_is_valid(smb_token_t *token);
+static smb_win_grps_t *smb_token_create_wingrps(smb_userinfo_t *user_info);
+
+static smb_posix_grps_t *smb_token_create_pxgrps(uid_t uid);
+
+/* Consolidation private function from Network Repository */
+extern int _getgroupsbymember(const char *, gid_t[], int, int);
+
+static idmap_stat
+smb_token_idmap(smb_token_t *token, smb_idmap_batch_t *sib)
+{
+ idmap_stat stat;
+ smb_idmap_t *sim;
+ smb_id_t *id;
+ int i;
+
+ if (!token || !sib)
+ return (IDMAP_ERR_ARG);
+
+ sim = sib->sib_maps;
+
+ if (token->tkn_flags & SMB_ATF_ANON) {
+ token->tkn_user->i_id = UID_NOBODY;
+ token->tkn_owner->i_id = UID_NOBODY;
+ } else {
+ /* User SID */
+ id = token->tkn_user;
+ sim->sim_id = &id->i_id;
+ stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
+ id->i_sidattr.sid, SMB_IDMAP_USER);
+
+ if (stat != IDMAP_SUCCESS)
+ return (stat);
+
+ /* Owner SID */
+ id = token->tkn_owner;
+ sim->sim_id = &id->i_id;
+ stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
+ id->i_sidattr.sid, SMB_IDMAP_UNKNOWN);
+
+ if (stat != IDMAP_SUCCESS)
+ return (stat);
+ }
+
+ /* Primary Group SID */
+ id = token->tkn_primary_grp;
+ sim->sim_id = &id->i_id;
+ stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
+ id->i_sidattr.sid, SMB_IDMAP_GROUP);
+
+ if (stat != IDMAP_SUCCESS)
+ return (stat);
+
+ /* Other Windows Group SIDs */
+ for (i = 0; i < token->tkn_win_grps->wg_count; i++, sim++) {
+ id = &token->tkn_win_grps->wg_groups[i];
+ sim->sim_id = &id->i_id;
+ stat = smb_idmap_batch_getid(sib->sib_idmaph, sim,
+ id->i_sidattr.sid, SMB_IDMAP_GROUP);
+
+ if (stat != IDMAP_SUCCESS)
+ break;
+ }
+
+ return (stat);
+}
+
+/*
+ * smb_token_sids2ids
+ *
+ * This will map all the SIDs of the access token to UIDs/GIDs.
+ *
+ * Returns 0 upon success. Otherwise, returns -1.
+ */
+static int
+smb_token_sids2ids(smb_token_t *token)
+{
+ idmap_stat stat;
+ int nmaps, retries = 0;
+ smb_idmap_batch_t sib;
+
+ /*
+ * Number of idmap lookups: user SID, owner SID, primary group SID,
+ * and all Windows group SIDs
+ */
+ if (token->tkn_flags & SMB_ATF_ANON)
+ /*
+ * Don't include user and owner SID, they're Anonymous
+ */
+ nmaps = 1;
+ else
+ nmaps = 3;
+
+ nmaps += token->tkn_win_grps->wg_count;
+
+ do {
+ stat = smb_idmap_batch_create(&sib, nmaps, SMB_IDMAP_SID2ID);
+ if (stat != IDMAP_SUCCESS) {
+ syslog(LOG_ERR, "smb_token_sids2ids:"
+ " idmap_get_create failed (%d)", stat);
+ return (-1);
+ }
+
+ stat = smb_token_idmap(token, &sib);
+ if (stat != IDMAP_SUCCESS) {
+ smb_idmap_batch_destroy(&sib);
+ return (-1);
+ }
+
+ stat = smb_idmap_batch_getmappings(&sib);
+ smb_idmap_batch_destroy(&sib);
+ if (stat == IDMAP_ERR_RPC_HANDLE)
+ if (smb_idmap_restart() < 0)
+ break;
+ } while (stat == IDMAP_ERR_RPC_HANDLE && retries++ < 3);
+
+ return (stat == IDMAP_SUCCESS ? 0 : -1);
+}
+
+/*
+ * smb_token_create_pxgrps
+ *
+ * Setup the POSIX group membership of the access token if the given UID is
+ * a POSIX UID (non-ephemeral). Both the user's primary group and
+ * supplementary groups will be added to the POSIX group array of the access
+ * token.
+ */
+static smb_posix_grps_t *
+smb_token_create_pxgrps(uid_t uid)
+{
+ struct passwd *pwd;
+ smb_posix_grps_t *pgrps;
+ int ngroups_max, num;
+ gid_t *gids;
+
+ if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) < 0) {
+ syslog(LOG_ERR, "smb_logon: failed to get _SC_NGROUPS_MAX");
+ return (NULL);
+ }
+
+ pwd = getpwuid(uid);
+ if (pwd == NULL) {
+ pgrps = malloc(sizeof (smb_posix_grps_t));
+ if (pgrps == NULL)
+ return (NULL);
+
+ pgrps->pg_ngrps = 0;
+ return (pgrps);
+ }
+
+ if (pwd->pw_name == NULL) {
+ pgrps = malloc(sizeof (smb_posix_grps_t));
+ if (pgrps == NULL)
+ return (NULL);
+
+ pgrps->pg_ngrps = 1;
+ pgrps->pg_grps[0] = pwd->pw_gid;
+ return (pgrps);
+ }
+
+ gids = (gid_t *)malloc(ngroups_max * sizeof (gid_t));
+ if (gids == NULL) {
+ return (NULL);
+ }
+ bzero(gids, ngroups_max * sizeof (gid_t));
+
+ gids[0] = pwd->pw_gid;
+
+ /*
+ * Setup the groups starting at index 1 (the last arg)
+ * of gids array.
+ */
+ num = _getgroupsbymember(pwd->pw_name, gids, ngroups_max, 1);
+
+ if (num == -1) {
+ syslog(LOG_ERR, "smb_logon: unable "
+ "to get user's supplementary groups");
+ num = 1;
+ }
+
+ pgrps = (smb_posix_grps_t *)malloc(SMB_POSIX_GRPS_SIZE(num));
+ if (pgrps) {
+ pgrps->pg_ngrps = num;
+ bcopy(gids, pgrps->pg_grps, num * sizeof (gid_t));
+ }
+
+ free(gids);
+ return (pgrps);
+}
+
+/*
+ * smb_token_destroy
+ *
+ * Release all of the memory associated with a token structure. Ensure
+ * that the token has been unlinked before calling.
+ */
+void
+smb_token_destroy(smb_token_t *token)
+{
+ smb_win_grps_t *groups;
+ int i;
+
+ if (token == NULL)
+ return;
+
+ if (token->tkn_user) {
+ free(token->tkn_user->i_sidattr.sid);
+ free(token->tkn_user);
+ }
+
+ if (token->tkn_owner) {
+ free(token->tkn_owner->i_sidattr.sid);
+ free(token->tkn_owner);
+ }
+
+ if (token->tkn_primary_grp) {
+ free(token->tkn_primary_grp->i_sidattr.sid);
+ free(token->tkn_primary_grp);
+ }
+
+ if ((groups = token->tkn_win_grps) != NULL) {
+ for (i = 0; i < groups->wg_count; ++i)
+ free(groups->wg_groups[i].i_sidattr.sid);
+ free(groups);
+ }
+
+ smb_privset_free(token->tkn_privileges);
+
+ free(token->tkn_posix_grps);
+ free(token->tkn_account_name);
+ free(token->tkn_domain_name);
+ free(token->tkn_session_key);
+
+ free(token);
+}
+
+static smb_id_t *
+smb_token_create_id(nt_sid_t *sid)
+{
+ smb_id_t *id;
+
+ id = (smb_id_t *)malloc(sizeof (smb_id_t));
+ if (id == NULL)
+ return (NULL);
+
+ id->i_id = (uid_t)-1;
+ id->i_sidattr.attrs = 7;
+ id->i_sidattr.sid = nt_sid_dup(sid);
+
+ if (id->i_sidattr.sid == NULL) {
+ free(id);
+ id = NULL;
+ }
+
+ return (id);
+}
+
+/*
+ * Token owner should be set to local Administrators group
+ * in two cases:
+ * 1. The logged on user is a member of Domain Admins group
+ * 2. he/she is a member of local Administrators group
+ */
+static smb_id_t *
+smb_token_create_owner(smb_userinfo_t *user_info)
+{
+ smb_id_t *owner;
+
+#ifdef PBSHORTCUT
+ if (user_info->flags & SMB_UINFO_FLAG_ADMIN) {
+ well_known_account_t *wka;
+ /*
+ * Need Winchester update on Group ID as file owner issue.
+ * For now, the file owner will always be set with user SID.
+ */
+ wka = nt_builtin_lookup("Administratrors");
+ owner = smb_token_create_id(wka->binsid);
+ } else
+#endif
+ owner = smb_token_create_id(user_info->user_sid);
+ return (owner);
+}
+
+static smb_privset_t *
+smb_token_create_privs(smb_userinfo_t *user_info)
+{
+ smb_privset_t *privs;
+ nt_group_t *grp;
+
+ privs = smb_privset_new();
+ if (privs == NULL)
+ return (NULL);
+
+ (void) nt_groups_member_privs(user_info->user_sid, privs);
+
+ if (user_info->flags & SMB_UINFO_FLAG_ADMIN) {
+ grp = nt_group_getinfo("Administrators", RWLOCK_READER);
+ if (grp) {
+ nt_group_add_groupprivs(grp, privs);
+ nt_group_putinfo(grp);
+ }
+
+ /*
+ * This privilege is required for view/edit of SACL
+ */
+ smb_privset_enable(privs, SE_SECURITY_LUID);
+ }
+
+ return (privs);
+}
+
+static void
+smb_token_set_flags(smb_token_t *token, smb_userinfo_t *user_info)
+{
+ well_known_account_t *wka;
+
+ if (user_info->flags & SMB_UINFO_FLAG_ANON) {
+ token->tkn_flags |= SMB_ATF_ANON;
+ return;
+ }
+
+ if (user_info->rid == DOMAIN_USER_RID_GUEST) {
+ token->tkn_flags |= SMB_ATF_GUEST;
+ return;
+ }
+
+ wka = nt_builtin_lookup("Administrators");
+ if (wka->binsid && smb_token_is_member(token, wka->binsid))
+ token->tkn_flags |= SMB_ATF_ADMIN;
+
+ wka = nt_builtin_lookup("Power Users");
+ if (wka->binsid && smb_token_is_member(token, wka->binsid))
+ token->tkn_flags |= SMB_ATF_POWERUSER;
+
+ wka = nt_builtin_lookup("Backup Operators");
+ if (wka->binsid && smb_token_is_member(token, wka->binsid))
+ token->tkn_flags |= SMB_ATF_BACKUPOP;
+
+}
+
+/*
+ * smb_token_create
+ *
+ * Build an access token based on the given user information (user_info).
+ *
+ * If everything is successful, a pointer to an access token is
+ * returned. Otherwise a null pointer is returned.
+ */
+static smb_token_t *
+smb_token_create(smb_userinfo_t *user_info)
+{
+ smb_token_t *token;
+
+ if (user_info->sid_name_use != SidTypeUser) {
+ return (NULL);
+ }
+
+ token = (smb_token_t *)malloc(sizeof (smb_token_t));
+ if (token == NULL) {
+ syslog(LOG_ERR, "smb_token_create: resource shortage");
+ return (NULL);
+ }
+ bzero(token, sizeof (smb_token_t));
+
+ /* User */
+ token->tkn_user = smb_token_create_id(user_info->user_sid);
+ if (token->tkn_user == NULL) {
+ smb_token_destroy(token);
+ syslog(LOG_ERR, "smb_token_create: resource shortage");
+ return (NULL);
+ }
+
+ /* Owner */
+ token->tkn_owner = smb_token_create_owner(user_info);
+ if (token->tkn_owner == NULL) {
+ syslog(LOG_ERR, "smb_token_create: resource shortage");
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ /* Primary Group */
+ token->tkn_primary_grp = smb_token_create_id(user_info->pgrp_sid);
+ if (token->tkn_primary_grp == NULL) {
+ syslog(LOG_ERR, "smb_token_create: resource shortage");
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ /* Privileges */
+ token->tkn_privileges = smb_token_create_privs(user_info);
+ if (token->tkn_privileges == NULL) {
+ smb_token_destroy(token);
+ syslog(LOG_ERR, "smb_token_create: resource shortage");
+ return (NULL);
+ }
+
+ /* Windows Groups */
+ token->tkn_win_grps = smb_token_create_wingrps(user_info);
+
+ smb_token_set_flags(token, user_info);
+
+ /*
+ * IMPORTANT
+ *
+ * This function has to be called after all the SIDs in the
+ * token are setup (i.e. user, owner, primary and supplementary
+ * groups) and before setting up Solaris groups.
+ */
+ if (smb_token_sids2ids(token) != 0) {
+ syslog(LOG_ERR, "smb_token_create: idmap failed");
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ /* Solaris Groups */
+ token->tkn_posix_grps = smb_token_create_pxgrps(token->tkn_user->i_id);
+
+ if (user_info->session_key) {
+ token->tkn_session_key = malloc(sizeof (smb_session_key_t));
+ if (token->tkn_session_key == NULL) {
+ syslog(LOG_ERR, "smb_token_create: resource shortage");
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ (void) memcpy(token->tkn_session_key,
+ user_info->session_key, sizeof (smb_session_key_t));
+ }
+
+ token->tkn_account_name = strdup(user_info->name);
+ token->tkn_domain_name = strdup(user_info->domain_name);
+
+ if (!smb_token_is_valid(token)) {
+ smb_token_destroy(token);
+ return (NULL);
+ }
+
+ return (token);
+}
+
+/*
+ * smb_token_create_wingrps
+ *
+ * This private function supports smb_token_create() by mapping the group
+ * information in the user_info structure to the form required in an
+ * access token. The main difference is that the user_info contains
+ * RIDs while and access token contains full SIDs. Memory allocated
+ * here will be deallocated as part of smb_token_destroy().
+ *
+ * If everything is successful, a pointer to a smb_win_grps_t
+ * structure is returned. Otherwise a null pointer is returned.
+ */
+static smb_win_grps_t *
+smb_token_create_wingrps(smb_userinfo_t *user_info)
+{
+ static char *wk_grps[] =
+ {"Authenticated Users", "NETWORK", "Administrators"};
+ smb_win_grps_t *tkn_grps;
+ smb_sid_attrs_t *dlg_grps;
+ smb_rid_attrs_t *g_grps;
+ smb_sid_attrs_t *grp;
+ nt_sid_t *builtin_sid;
+ uint32_t n_gg, n_lg, n_dlg, n_wg;
+ uint32_t i, j;
+ int size, count;
+
+ if (user_info == NULL)
+ return (NULL);
+
+ n_gg = user_info->n_groups; /* Global Groups */
+ n_dlg = user_info->n_other_grps; /* Domain Local Groups */
+
+ /* Local Groups */
+ n_lg = nt_groups_member_ngroups(user_info->user_sid);
+
+ /* Well known Groups */
+ if ((user_info->flags & SMB_UINFO_FLAG_ADMIN) == SMB_UINFO_FLAG_DADMIN)
+ /* if user is a domain admin but not a local admin */
+ n_wg = 3;
+ else if (user_info->flags & SMB_UINFO_FLAG_ANON)
+ n_wg = 0;
+ else
+ n_wg = 2;
+
+ count = n_gg + n_dlg + n_lg + n_wg;
+ size = sizeof (smb_win_grps_t) + (count * sizeof (smb_id_t));
+
+ tkn_grps = (smb_win_grps_t *)malloc(size);
+ if (tkn_grps == NULL) {
+ return (NULL);
+ }
+ bzero(tkn_grps, size);
+
+ tkn_grps->wg_count = count;
+
+ /* Add global groups */
+ g_grps = user_info->groups;
+ for (i = 0; i < n_gg; ++i) {
+ grp = &tkn_grps->wg_groups[i].i_sidattr;
+ grp->attrs = g_grps[i].attributes;
+ grp->sid = nt_sid_splice(user_info->domain_sid, g_grps[i].rid);
+ }
+
+ if (n_gg == 0) {
+ /*
+ * if there's no global group should add the
+ * primary group.
+ */
+ grp = &tkn_grps->wg_groups[i++].i_sidattr;
+ grp->attrs = 0x7;
+ grp->sid = nt_sid_dup(user_info->pgrp_sid);
+ tkn_grps->wg_count++;
+ }
+
+ /* Add domain local groups */
+ dlg_grps = user_info->other_grps;
+ for (j = 0; j < n_dlg; ++j, ++i) {
+ grp = &tkn_grps->wg_groups[i].i_sidattr;
+ grp->attrs = dlg_grps[j].attrs;
+ grp->sid = nt_sid_dup(dlg_grps[j].sid);
+ }
+
+ if (n_lg) {
+ /* Add local groups */
+ (void) nt_groups_member_groups(user_info->user_sid,
+ &tkn_grps->wg_groups[i], n_lg);
+ i += n_lg;
+ }
+
+ /* Add well known groups */
+ for (j = 0; j < n_wg; ++j, ++i) {
+ builtin_sid = nt_builtin_lookup_name(wk_grps[j], NULL);
+ tkn_grps->wg_groups[i].i_sidattr.sid = builtin_sid;
+ tkn_grps->wg_groups[i].i_sidattr.attrs = 0x7;
+ }
+
+ return (tkn_grps);
+}
+
+/*
+ * smb_logon
+ *
+ * Performs user authentication and creates a token if the
+ * authentication is successful.
+ *
+ * Returns pointer to the created token.
+ */
+smb_token_t *
+smb_logon(netr_client_t *clnt)
+{
+ smb_token_t *token = NULL;
+ smb_userinfo_t *uinfo;
+ uint32_t status;
+
+ if ((uinfo = mlsvc_alloc_user_info()) == 0)
+ return (NULL);
+
+ switch (clnt->flags) {
+ case NETR_CFLG_DOMAIN:
+ /* Pass through authentication with DC */
+ status = smb_logon_domain(clnt, uinfo);
+ break;
+
+ case NETR_CFLG_LOCAL:
+ /* Local authentication */
+ status = smb_logon_local(clnt, uinfo);
+ break;
+
+ case NETR_CFLG_ANON:
+ /* Anonymous user; no authentication */
+ status = smb_logon_none(clnt, uinfo);
+ break;
+
+ default:
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (status == NT_STATUS_SUCCESS)
+ token = smb_token_create(uinfo);
+
+ mlsvc_free_user_info(uinfo);
+ return (token);
+}
+
+/*
+ * smb_logon_domain
+ *
+ * Performs pass through authentication with PDC.
+ */
+static uint32_t
+smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo)
+{
+ uint32_t status;
+
+ if ((status = netlogon_logon(clnt, uinfo)) != 0) {
+ if (status == NT_STATUS_CANT_ACCESS_DOMAIN_INFO) {
+ if ((status = netlogon_logon(clnt, uinfo)) != 0) {
+ syslog(LOG_INFO, "SmbLogon[%s\\%s]: %s",
+ clnt->domain, clnt->username,
+ xlate_nt_status(status));
+ return (status);
+ }
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * smb_logon_local
+ *
+ * Check to see if connected user has an entry in the local
+ * smbpasswd database. If it has, tries both LM hash and NT
+ * hash with user's password(s) to authenticate the user.
+ */
+static uint32_t
+smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo)
+{
+ smb_passwd_t smbpw;
+ boolean_t lm_ok, nt_ok;
+ uint32_t status;
+
+ if (smb_pwd_getpasswd(clnt->username, &smbpw) == NULL) {
+ /*
+ * If user doesn't have entry either in smbpasswd
+ * or passwd it's considered as an invalid user.
+ */
+ status = NT_STATUS_NO_SUCH_USER;
+ syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
+ clnt->domain, clnt->username,
+ xlate_nt_status(status));
+ return (status);
+ }
+
+ if (smbpw.pw_flags & SMB_PWF_DISABLE)
+ return (NT_STATUS_ACCOUNT_DISABLED);
+
+ nt_ok = lm_ok = B_FALSE;
+ if ((smbpw.pw_flags & SMB_PWF_LM) &&
+ (clnt->lm_password.lm_password_len != 0)) {
+ lm_ok = smb_auth_validate_lm(
+ clnt->challenge_key.challenge_key_val,
+ clnt->challenge_key.challenge_key_len,
+ &smbpw,
+ clnt->lm_password.lm_password_val,
+ clnt->lm_password.lm_password_len,
+ clnt->username);
+ }
+
+ if (!lm_ok && (clnt->nt_password.nt_password_len != 0)) {
+ nt_ok = smb_auth_validate_nt(
+ clnt->challenge_key.challenge_key_val,
+ clnt->challenge_key.challenge_key_len,
+ &smbpw,
+ clnt->nt_password.nt_password_val,
+ clnt->nt_password.nt_password_len,
+ clnt->username);
+ }
+
+ if (!nt_ok && !lm_ok) {
+ status = NT_STATUS_WRONG_PASSWORD;
+ syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
+ clnt->domain, clnt->username,
+ xlate_nt_status(status));
+ return (status);
+ }
+
+ status = smb_setup_luinfo(uinfo, clnt, smbpw.pw_uid);
+ return (status);
+}
+
+/*
+ * smb_logon_none
+ *
+ * Setup user information for anonymous user.
+ * No authentication is required.
+ */
+static uint32_t
+smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo)
+{
+ return (smb_setup_luinfo(uinfo, clnt, (uid_t)-1));
+}
+
+/*
+ * smb_setup_luinfo
+ *
+ * Setup local user information based on the client information and
+ * user's record in the local password file.
+ */
+static uint32_t
+smb_setup_luinfo(smb_userinfo_t *lui, netr_client_t *clnt, uid_t uid)
+{
+ idmap_stat stat;
+ smb_idmap_batch_t sib;
+ smb_idmap_t *umap, *gmap;
+ nt_group_t *grp;
+ struct passwd pw;
+ char pwbuf[1024];
+
+ lui->sid_name_use = SidTypeUser;
+ lui->domain_sid = nt_sid_dup(nt_domain_local_sid());
+ lui->name = strdup(clnt->username);
+ lui->domain_name = strdup(clnt->domain);
+ lui->n_groups = 0;
+ lui->groups = NULL;
+ lui->n_other_grps = 0;
+ lui->other_grps = NULL;
+ lui->flags = 0;
+
+ if (lui->name == NULL || lui->domain_name == NULL ||
+ lui->domain_sid == NULL)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ if (clnt->flags & NETR_CFLG_ANON) {
+ lui->user_sid = nt_builtin_lookup_name("Anonymous", NULL);
+ lui->pgrp_sid = nt_builtin_lookup_name("Anonymous", NULL);
+ lui->flags = SMB_UINFO_FLAG_ANON;
+
+ if (lui->user_sid == NULL || lui->pgrp_sid == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ return (NT_STATUS_SUCCESS);
+ }
+
+ if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL)
+ return (NT_STATUS_NO_SUCH_USER);
+
+ /* Get the SID for user's uid & gid */
+ stat = smb_idmap_batch_create(&sib, 2, SMB_IDMAP_ID2SID);
+ if (stat != IDMAP_SUCCESS) {
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ umap = &sib.sib_maps[0];
+ stat = smb_idmap_batch_getsid(sib.sib_idmaph, umap, pw.pw_uid,
+ SMB_IDMAP_USER);
+
+ if (stat != IDMAP_SUCCESS) {
+ smb_idmap_batch_destroy(&sib);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ gmap = &sib.sib_maps[1];
+ stat = smb_idmap_batch_getsid(sib.sib_idmaph, gmap, pw.pw_gid,
+ SMB_IDMAP_GROUP);
+
+ if (stat != IDMAP_SUCCESS) {
+ smb_idmap_batch_destroy(&sib);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ stat = smb_idmap_batch_getmappings(&sib);
+
+ if (stat != IDMAP_SUCCESS) {
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ lui->rid = umap->sim_rid;
+ lui->user_sid = nt_sid_dup(umap->sim_sid);
+
+ lui->primary_group_rid = gmap->sim_rid;
+ lui->pgrp_sid = nt_sid_dup(gmap->sim_sid);
+
+ smb_idmap_batch_destroy(&sib);
+
+ if ((lui->user_sid == NULL) || (lui->pgrp_sid == NULL))
+ return (NT_STATUS_NO_MEMORY);
+
+ grp = nt_group_getinfo("Administrators", RWLOCK_READER);
+ if (grp) {
+ if (nt_group_is_member(grp, lui->user_sid))
+ lui->flags = SMB_UINFO_FLAG_LADMIN;
+ nt_group_putinfo(grp);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_token_is_valid
+ *
+ * check to see if specified fields of the given access
+ * token are valid.
+ * Returns 1 if all of them are valid; otherwise 0.
+ */
+static int
+smb_token_is_valid(smb_token_t *token)
+{
+ int valid;
+
+ valid = (token->tkn_user != 0) &&
+ (token->tkn_user->i_sidattr.sid != 0) &&
+ (token->tkn_privileges != 0) &&
+ (token->tkn_win_grps != 0) &&
+ (token->tkn_owner != 0) &&
+ (token->tkn_owner->i_sidattr.sid != 0) &&
+ (token->tkn_primary_grp != 0) &&
+ (token->tkn_primary_grp->i_sidattr.sid != 0);
+
+ return (valid);
+}
+
+/*
+ * smb_token_user_sid
+ *
+ * Return a pointer to the user SID in the specified token. A null
+ * pointer indicates an error.
+ */
+static nt_sid_t *
+smb_token_user_sid(smb_token_t *token)
+{
+ if (token && token->tkn_user)
+ return ((token)->tkn_user->i_sidattr.sid);
+
+ return (NULL);
+}
+
+/*
+ * smb_token_group_sid
+ *
+ * Return a pointer to the group SID as indicated by the iterator.
+ * Setting the iterator to 0 before calling this function will return
+ * the first group, which will always be the primary group. The
+ * iterator will be incremented before returning the SID so that this
+ * function can be used to cycle through the groups. The caller can
+ * adjust the iterator as required between calls to obtain any specific
+ * group.
+ *
+ * On success a pointer to the appropriate group SID will be returned.
+ * Otherwise a null pointer will be returned.
+ */
+static nt_sid_t *
+smb_token_group_sid(smb_token_t *token, int *iterator)
+{
+ smb_win_grps_t *groups;
+ int index;
+
+ if (token == NULL || iterator == NULL) {
+ return (NULL);
+ }
+
+ if ((groups = token->tkn_win_grps) == NULL) {
+ return (NULL);
+ }
+
+ index = *iterator;
+
+ if (index < 0 || index >= groups->wg_count) {
+ return (NULL);
+ }
+
+ ++(*iterator);
+ return (groups->wg_groups[index].i_sidattr.sid);
+}
+
+/*
+ * smb_token_is_member
+ *
+ * This function will determine whether or not the specified SID is a
+ * member of a token. The user SID and all group SIDs are tested.
+ * Returns 1 if the SID is a member of the token. Otherwise returns 0.
+ */
+static int
+smb_token_is_member(smb_token_t *token, nt_sid_t *sid)
+{
+ nt_sid_t *tsid;
+ int iterator = 0;
+
+ tsid = smb_token_user_sid(token);
+ while (tsid) {
+ if (nt_sid_is_equal(tsid, sid))
+ return (1);
+
+ tsid = smb_token_group_sid(token, &iterator);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
new file mode 100644
index 0000000000..a9810bd538
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
@@ -0,0 +1,413 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/smbinfo.h>
+
+#define SMB_AUTOHOME_KEYSIZ 128
+#define SMB_AUTOHOME_MAXARG 4
+#define SMB_AUTOHOME_BUFSIZ 2048
+
+typedef struct smb_autohome_info {
+ struct smb_autohome_info *magic1;
+ FILE *fp;
+ smb_autohome_t autohome;
+ char buf[SMB_AUTOHOME_BUFSIZ];
+ char *argv[SMB_AUTOHOME_MAXARG];
+ int lineno;
+ struct smb_autohome_info *magic2;
+} smb_autohome_info_t;
+
+static smb_autohome_info_t smb_ai;
+
+static smb_autohome_t *smb_autohome_make_entry(smb_autohome_info_t *);
+static char *smb_autohome_keysub(const char *, char *, int);
+static smb_autohome_info_t *smb_autohome_getinfo(void);
+
+/*
+ * Add an autohome share. See smb_autohome(4) for details.
+ *
+ * If share directory contains backslash path separators, they will
+ * be converted to forward slash to support NT/DOS path style for
+ * autohome shares.
+ *
+ * Returns 0 on success or -1 to indicate an error.
+ */
+int
+smb_autohome_add(const char *username)
+{
+ lmshare_info_t si;
+ char *sharename;
+ smb_autohome_t *ai;
+
+ if (username == NULL)
+ return (-1);
+
+ if ((sharename = strdup(username)) == NULL)
+ return (-1);
+
+ if ((ai = smb_autohome_lookup(sharename)) == NULL) {
+ free(sharename);
+ return (0);
+ }
+
+ (void) memset(&si, 0, sizeof (lmshare_info_t));
+ (void) strlcpy(si.directory, ai->ah_path, MAXPATHLEN);
+ (void) strsubst(si.directory, '\\', '/');
+ (void) strlcpy(si.container, ai->ah_container, MAXPATHLEN);
+
+ if (lmshare_is_dir(si.directory) == 0) {
+ free(sharename);
+ return (0);
+ }
+
+ if (lmshare_exists(sharename) != 0) {
+ (void) lmshare_getinfo(sharename, &si);
+ if (!(si.mode & LMSHRM_TRANS)) {
+ free(sharename);
+ return (0);
+ }
+ } else {
+ (void) strcpy(si.share_name, sharename);
+ si.mode = LMSHRM_TRANS;
+ }
+
+ (void) lmshare_add(&si, 0);
+ free(sharename);
+ return (0);
+}
+
+/*
+ * Remove an autohome share.
+ *
+ * Returns 0 on success or -1 to indicate an error.
+ */
+int
+smb_autohome_remove(const char *username)
+{
+ lmshare_info_t si;
+ char *sharename;
+
+ if (username == NULL)
+ return (-1);
+
+ if ((sharename = strdup(username)) == NULL)
+ return (-1);
+
+ if (lmshare_getinfo(sharename, &si) == NERR_Success) {
+ if (si.mode & LMSHRM_TRANS) {
+ (void) lmshare_delete(sharename, 0);
+ }
+ }
+
+ free(sharename);
+ return (0);
+}
+
+/*
+ * Find out if a share is an autohome share.
+ *
+ * Returns 1 if the share is an autohome share.
+ * Otherwise returns 0.
+ */
+int
+smb_is_autohome(const lmshare_info_t *si)
+{
+ if (si && (si->mode & LMSHRM_TRANS) &&
+ (lmshare_is_restricted((char *)si->share_name) == 0)) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Search the autohome database for the specified name. The name cannot
+ * be an empty string or begin with * or +.
+ * 1. Search the file for the specified name.
+ * 2. Check for the wildcard rule and, if present, treat it as a match.
+ * 3. Check for the nsswitch rule and, if present, lookup the name
+ * via the name services. Note that the nsswitch rule will never
+ * be applied if the wildcard rule is present.
+ *
+ * Returns a pointer to the entry on success or null on failure.
+ */
+smb_autohome_t *
+smb_autohome_lookup(const char *name)
+{
+ struct passwd *pw;
+ smb_autohome_t *ah = 0;
+
+ if (name == NULL)
+ return (NULL);
+
+ if (*name == '\0' || *name == '*' || *name == '+')
+ return (NULL);
+
+ smb_autohome_setent();
+
+ while ((ah = smb_autohome_getent(name)) != NULL) {
+ if (strcasecmp(ah->ah_name, name) == 0)
+ break;
+ }
+
+ if (ah == NULL) {
+ smb_autohome_setent();
+
+ while ((ah = smb_autohome_getent(name)) != NULL) {
+ if (strcasecmp(ah->ah_name, "*") == 0) {
+ ah->ah_name = (char *)name;
+ break;
+ }
+ }
+ }
+
+ if (ah == NULL) {
+ smb_autohome_setent();
+
+ while ((ah = smb_autohome_getent("+nsswitch")) != NULL) {
+ if (strcasecmp("+nsswitch", ah->ah_name) != 0)
+ continue;
+ if ((pw = getpwnam(name)) == NULL) {
+ ah = 0;
+ break;
+ }
+
+ ah->ah_name = pw->pw_name;
+
+ if (ah->ah_path)
+ ah->ah_container = ah->ah_path;
+
+ ah->ah_path = pw->pw_dir;
+ break;
+ }
+ }
+
+ smb_autohome_endent();
+ return (ah);
+}
+
+/*
+ * Open or rewind the autohome database.
+ */
+void
+smb_autohome_setent(void)
+{
+ smb_autohome_info_t *si;
+ char *mappath;
+ char filename[MAXNAMELEN];
+
+ if ((si = smb_autohome_getinfo()) != 0) {
+ (void) fseek(si->fp, 0L, SEEK_SET);
+ si->lineno = 0;
+ return;
+ }
+
+ if ((si = &smb_ai) == 0)
+ return;
+
+ smb_config_rdlock();
+ if ((mappath = smb_config_get(SMB_CI_AUTOHOME_MAP)) == NULL)
+ mappath = SMB_AUTOHOME_PATH;
+ (void) snprintf(filename, MAXNAMELEN, "%s/%s", mappath,
+ SMB_AUTOHOME_FILE);
+ smb_config_unlock();
+
+ if ((si->fp = fopen(filename, "r")) == NULL)
+ return;
+
+ si->magic1 = si;
+ si->magic2 = si;
+ si->lineno = 0;
+}
+
+/*
+ * Close the autohome database and invalidate the autohome info.
+ * We can't zero the whole info structure because the application
+ * should still have access to the data after the file is closed.
+ */
+void
+smb_autohome_endent(void)
+{
+ smb_autohome_info_t *si;
+
+ if ((si = smb_autohome_getinfo()) != 0) {
+ (void) fclose(si->fp);
+ si->fp = 0;
+ si->magic1 = 0;
+ si->magic2 = 0;
+ }
+}
+
+/*
+ * Return the next entry in the autohome database, opening the file
+ * if necessary. Returns null on EOF or error.
+ *
+ * Note that we are not looking for the specified name. The name is
+ * only used for key substitution, so that the caller sees the entry
+ * in expanded form.
+ */
+smb_autohome_t *
+smb_autohome_getent(const char *name)
+{
+ smb_autohome_info_t *si;
+ char *bp;
+
+ if ((si = smb_autohome_getinfo()) == 0) {
+ smb_autohome_setent();
+
+ if ((si = smb_autohome_getinfo()) == 0)
+ return (0);
+ }
+
+ /*
+ * Find the next non-comment, non-empty line.
+ * Anything after a # is a comment and can be discarded.
+ * Discard a newline to avoid it being included in the parsing
+ * that follows.
+ * Leading and training whitespace is discarded, and replicated
+ * whitespace is compressed to simplify the token parsing,
+ * although strsep() deals with that better than strtok().
+ */
+ do {
+ if (fgets(si->buf, SMB_AUTOHOME_BUFSIZ, si->fp) == 0)
+ return (0);
+
+ ++si->lineno;
+
+ if ((bp = strpbrk(si->buf, "#\r\n")) != 0)
+ *bp = '\0';
+
+ (void) trim_whitespace(si->buf);
+ bp = strcanon(si->buf, " \t");
+ } while (*bp == '\0');
+
+ (void) smb_autohome_keysub(name, si->buf, SMB_AUTOHOME_BUFSIZ);
+ return (smb_autohome_make_entry(si));
+}
+
+/*
+ * Set up an autohome entry from the line buffer. The line should just
+ * contain tokens separated by single whitespace. The line format is:
+ * <username> <home-dir-path> <ADS container>
+ */
+static smb_autohome_t *
+smb_autohome_make_entry(smb_autohome_info_t *si)
+{
+ char *bp;
+ int i;
+
+ bp = si->buf;
+
+ for (i = 0; i < SMB_AUTOHOME_MAXARG; ++i)
+ si->argv[i] = 0;
+
+ for (i = 0; i < SMB_AUTOHOME_MAXARG; ++i) {
+ do {
+ if ((si->argv[i] = strsep((char **)&bp, " \t")) == 0)
+ break;
+ } while (*(si->argv[i]) == '\0');
+
+ if (si->argv[i] == 0)
+ break;
+ }
+
+ if ((si->autohome.ah_name = si->argv[0]) == NULL) {
+ /*
+ * Sanity check: the name could be an empty
+ * string but it can't be a null pointer.
+ */
+ return (0);
+ }
+
+ if ((si->autohome.ah_path = si->argv[1]) == NULL)
+ si->autohome.ah_path = "";
+
+ if ((si->autohome.ah_container = si->argv[2]) == NULL)
+ si->autohome.ah_container = "";
+
+ return (&si->autohome);
+}
+
+/*
+ * Substitute the ? and & map keys.
+ * ? is replaced by the first character of the name
+ * & is replaced by the whole name.
+ */
+static char *
+smb_autohome_keysub(const char *name, char *buf, int buflen)
+{
+ char key[SMB_AUTOHOME_KEYSIZ];
+ char *ampersand;
+ char *tmp;
+
+ (void) strlcpy(key, buf, SMB_AUTOHOME_KEYSIZ);
+
+ if ((tmp = strpbrk(key, " \t")) == NULL)
+ return (NULL);
+
+ *tmp = '\0';
+
+ if (strcmp(key, "*") == 0 && name != NULL)
+ (void) strlcpy(key, name, SMB_AUTOHOME_KEYSIZ);
+
+ (void) strsubst(buf, '?', *key);
+
+ while ((ampersand = strchr(buf, '&')) != NULL) {
+ if ((tmp = strdup(ampersand + 1)) == NULL)
+ return (0);
+
+ (void) strlcpy(ampersand, key, buflen);
+ (void) strlcat(ampersand, tmp, buflen);
+ free(tmp);
+ }
+
+ return (buf);
+}
+
+/*
+ * Get a pointer to the context buffer and validate it.
+ */
+static smb_autohome_info_t *
+smb_autohome_getinfo(void)
+{
+ smb_autohome_info_t *si;
+
+ if ((si = &smb_ai) == 0)
+ return (0);
+
+ if ((si->magic1 == si) && (si->magic2 == si) && (si->fp != NULL))
+ return (si);
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_share_util.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_share_util.c
new file mode 100644
index 0000000000..8e5a7ca031
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share_util.c
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <pthread.h>
+#include <synch.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <libshare.h>
+#include <smbsrv/lmshare.h>
+
+static pthread_mutex_t smb_group_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Sharemanager shared API */
+
+void
+smb_build_lmshare_info(char *share_name, char *path,
+ sa_optionset_t opts, lmshare_info_t *si)
+{
+ sa_property_t prop;
+ char *val = NULL;
+
+ bzero(si, sizeof (lmshare_info_t));
+ /* Share is read from SMF so it should be permanent */
+ si->mode = LMSHRM_PERM;
+
+ (void) strlcpy(si->directory, path, sizeof (si->directory));
+ (void) strlcpy(si->share_name, share_name, sizeof (si->share_name));
+
+ if (opts == NULL)
+ return;
+
+ prop = (sa_property_t)sa_get_property(opts, SHOPT_AD_CONTAINER);
+ if (prop != NULL) {
+ if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+ (void) strlcpy(si->container, val,
+ sizeof (si->container));
+ free(val);
+ }
+ }
+
+ prop = (sa_property_t)sa_get_property(opts, "description");
+ if (prop != NULL) {
+ if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+ (void) strlcpy(si->comment, val, sizeof (si->comment));
+ free(val);
+ }
+ }
+}
+
+/*
+ * smb_get_smb_share_group
+ *
+ * Creates "smb" share group for putting in shares
+ * created by windows client.
+ */
+sa_group_t
+smb_get_smb_share_group(sa_handle_t handle)
+{
+ sa_group_t group = NULL;
+ int err;
+
+ (void) pthread_mutex_lock(&smb_group_mutex);
+ group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
+ if (group != NULL) {
+ (void) pthread_mutex_unlock(&smb_group_mutex);
+ return (group);
+ }
+ group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
+ if (group == NULL) {
+ (void) pthread_mutex_unlock(&smb_group_mutex);
+ return (NULL);
+ }
+ if (group != NULL) {
+ if (sa_create_optionset(group,
+ SMB_DEFAULT_SHARE_GROUP) == NULL) {
+ (void) sa_remove_group(group);
+ group = NULL;
+ }
+ }
+ (void) pthread_mutex_unlock(&smb_group_mutex);
+ return (group);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_client.c b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_client.c
new file mode 100644
index 0000000000..aa9b12d241
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_client.c
@@ -0,0 +1,554 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Server Service (srvsvc) client side RPC library interface. The
+ * srvsvc interface allows a client to query a server for information
+ * on shares, sessions, connections and files on the server. Some
+ * functions are available via anonymous IPC while others require
+ * administrator privilege. Also, some functions return NT status
+ * values while others return Win32 errors codes.
+ */
+
+#include <sys/errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <strings.h>
+#include <time.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libsmbrdr.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ndl/srvsvc.ndl>
+#include <smbsrv/mlsvc_util.h>
+
+/*
+ * Information level for NetShareGetInfo.
+ */
+DWORD srvsvc_info_level = 1;
+
+static int srvsvc_net_remote_tod(char *, char *, struct timeval *, struct tm *);
+
+/*
+ * Ensure that an appropriate session and logon exists for the srvsvc
+ * client calls. Open and bind the RPC interface.
+ *
+ * On success 0 is returned. Otherwise a -ve error code.
+ */
+int
+srvsvc_open(int ipc_mode, char *server, char *domain, char *username,
+ char *password, mlsvc_handle_t *handle, mlrpc_heapref_t *heapref)
+{
+ smb_ntdomain_t *di;
+ int fid;
+ int rc;
+
+ if ((di = smb_getdomaininfo(0)) == NULL)
+ return (-1);
+
+ if (server == NULL || domain == NULL) {
+ server = di->server;
+ domain = di->domain;
+ }
+
+ switch (ipc_mode) {
+ case MLSVC_IPC_USER:
+ /*
+ * Use the supplied credentials.
+ */
+ rc = mlsvc_user_logon(server, domain, username, password);
+ break;
+
+ case MLSVC_IPC_ADMIN:
+ /*
+ * Use the resource domain administrator credentials.
+ */
+ server = di->server;
+ domain = di->domain;
+ username = smbrdr_ipc_get_user();
+
+ rc = mlsvc_admin_logon(server, domain);
+ break;
+
+ case MLSVC_IPC_ANON:
+ default:
+ rc = mlsvc_anonymous_logon(server, domain, &username);
+ break;
+ }
+
+ if (rc != 0)
+ return (-1);
+
+ fid = mlsvc_open_pipe(server, domain, username, "\\srvsvc");
+ if (fid < 0)
+ return (-1);
+
+ if ((rc = mlsvc_rpc_bind(handle, fid, "SRVSVC")) < 0) {
+ (void) mlsvc_close_pipe(fid);
+ return (rc);
+ }
+
+ rc = mlsvc_rpc_init(heapref);
+ return (rc);
+}
+
+/*
+ * Close the srvsvc pipe and free the associated context. This function
+ * should only be called if the open was successful.
+ */
+void
+srvsvc_close(mlsvc_handle_t *handle, mlrpc_heapref_t *heapref)
+{
+ mlsvc_rpc_free(handle->context, heapref);
+ (void) mlsvc_close_pipe(handle->context->fid);
+ free(handle->context);
+}
+
+/*
+ * This is a client side routine for NetShareGetInfo.
+ * Levels 0 and 1 work with an anonymous connection but
+ * level 2 requires administrator access.
+ */
+int
+srvsvc_net_share_get_info(char *server, char *domain, char *netname)
+{
+ struct mlsm_NetShareGetInfo arg;
+ mlsvc_handle_t handle;
+ mlrpc_heapref_t heap;
+ int rc;
+ int opnum;
+ struct mslm_NetShareGetInfo0 *info0;
+ struct mslm_NetShareGetInfo1 *info1;
+ struct mslm_NetShareGetInfo2 *info2;
+ int ipc_mode;
+ int len;
+
+ if (netname == NULL)
+ return (-1);
+
+ if (srvsvc_info_level == 2)
+ ipc_mode = MLSVC_IPC_ADMIN;
+ else
+ ipc_mode = MLSVC_IPC_ANON;
+
+ rc = srvsvc_open(ipc_mode, server, domain, 0, 0, &handle, &heap);
+ if (rc != 0)
+ return (-1);
+
+ opnum = SRVSVC_OPNUM_NetShareGetInfo;
+ bzero(&arg, sizeof (struct mlsm_NetShareGetInfo));
+
+ len = strlen(server) + 4;
+ arg.servername = mlrpc_heap_malloc(heap.heap, len);
+ if (arg.servername == NULL) {
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ arg.netname = (LPTSTR)netname;
+ arg.level = srvsvc_info_level; /* share information level */
+
+ rc = mlsvc_rpc_call(handle.context, opnum, &arg, &heap);
+ if ((rc != 0) || (arg.status != 0)) {
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ switch (arg.result.switch_value) {
+ case 0:
+ info0 = arg.result.ru.info0;
+ smb_tracef("srvsvc shi0_netname=%s", info0->shi0_netname);
+ break;
+
+ case 1:
+ info1 = arg.result.ru.info1;
+ smb_tracef("srvsvc shi1_netname=%s", info1->shi1_netname);
+ smb_tracef("srvsvc shi1_type=%u", info1->shi1_type);
+
+ if (info1->shi1_comment)
+ smb_tracef("srvsvc shi1_comment=%s",
+ info1->shi1_comment);
+ break;
+
+ case 2:
+ info2 = arg.result.ru.info2;
+ smb_tracef("srvsvc shi2_netname=%s", info2->shi2_netname);
+ smb_tracef("srvsvc shi2_type=%u", info2->shi2_type);
+
+ if (info2->shi2_comment)
+ smb_tracef("srvsvc shi2_comment=%s",
+ info2->shi2_comment);
+
+ smb_tracef("srvsvc shi2_perms=%d", info2->shi2_permissions);
+ smb_tracef("srvsvc shi2_max_use=%d", info2->shi2_max_uses);
+ smb_tracef("srvsvc shi2_cur_use=%d", info2->shi2_current_uses);
+
+ if (info2->shi2_path)
+ smb_tracef("srvsvc shi2_path=%s", info2->shi2_path);
+
+ if (info2->shi2_passwd)
+ smb_tracef("srvsvc shi2_passwd=%s", info2->shi2_passwd);
+ break;
+
+ default:
+ smb_tracef("srvsvc: unknown level");
+ break;
+ }
+
+ srvsvc_close(&handle, &heap);
+ return (0);
+}
+
+/*
+ * This is a client side routine for NetSessionEnum.
+ * NetSessionEnum requires administrator rights.
+ */
+int
+srvsvc_net_session_enum(char *server, char *domain, char *netname)
+{
+ struct mslm_NetSessionEnum arg;
+ mlsvc_handle_t handle;
+ mlrpc_heapref_t heap;
+ int rc;
+ int opnum;
+ struct mslm_infonres infonres;
+ struct mslm_SESSION_INFO_1 *nsi1;
+ int len;
+
+ if (netname == NULL)
+ return (-1);
+
+ rc = srvsvc_open(MLSVC_IPC_ADMIN, server, domain, 0, 0, &handle, &heap);
+ if (rc != 0)
+ return (-1);
+
+ opnum = SRVSVC_OPNUM_NetSessionEnum;
+ bzero(&arg, sizeof (struct mslm_NetSessionEnum));
+
+ len = strlen(server) + 4;
+ arg.servername = mlrpc_heap_malloc(heap.heap, len);
+ if (arg.servername == NULL) {
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ infonres.entriesread = 0;
+ infonres.entries = 0;
+ arg.level = 1;
+ arg.result.level = 1;
+ arg.result.bufptr.p = &infonres;
+ arg.resume_handle = 0;
+ arg.pref_max_len = 0xFFFFFFFF;
+
+ rc = mlsvc_rpc_call(handle.context, opnum, &arg, &heap);
+ if ((rc != 0) || (arg.status != 0)) {
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ /* Only the first session info is dereferenced. */
+ nsi1 = ((struct mslm_infonres *)arg.result.bufptr.p)->entries;
+
+ smb_tracef("srvsvc switch_value=%d", arg.level);
+ smb_tracef("srvsvc sesi1_cname=%s", nsi1->sesi1_cname);
+ smb_tracef("srvsvc sesi1_uname=%s", nsi1->sesi1_uname);
+ smb_tracef("srvsvc sesi1_nopens=%u", nsi1->sesi1_nopens);
+ smb_tracef("srvsvc sesi1_time=%u", nsi1->sesi1_time);
+ smb_tracef("srvsvc sesi1_itime=%u", nsi1->sesi1_itime);
+ smb_tracef("srvsvc sesi1_uflags=%u", nsi1->sesi1_uflags);
+
+ srvsvc_close(&handle, &heap);
+ return (0);
+}
+
+/*
+ * This is a client side routine for NetConnectEnum.
+ * NetConnectEnum requires administrator rights.
+ * Level 0 and level 1 requests are supported.
+ */
+int
+srvsvc_net_connect_enum(char *server, char *domain, char *netname, int level)
+{
+ struct mslm_NetConnectEnum arg;
+ mlsvc_handle_t handle;
+ mlrpc_heapref_t heap;
+ int rc;
+ int opnum;
+ struct mslm_NetConnectInfo1 info1;
+ struct mslm_NetConnectInfo0 info0;
+ struct mslm_NetConnectInfoBuf1 *cib1;
+ int len;
+
+ if (netname == NULL)
+ return (-1);
+
+ rc = srvsvc_open(MLSVC_IPC_ADMIN, server, domain, 0, 0, &handle, &heap);
+ if (rc != 0)
+ return (-1);
+
+ opnum = SRVSVC_OPNUM_NetConnectEnum;
+ bzero(&arg, sizeof (struct mslm_NetConnectEnum));
+
+ len = strlen(server) + 4;
+ arg.servername = mlrpc_heap_malloc(heap.heap, len);
+ if (arg.servername == NULL) {
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ arg.qualifier = (LPTSTR)netname;
+
+ switch (level) {
+ case 0:
+ arg.info.level = 0;
+ arg.info.switch_value = 0;
+ arg.info.ru.info0 = &info0;
+ info0.entries_read = 0;
+ info0.ci0 = 0;
+ break;
+ case 1:
+ arg.info.level = 1;
+ arg.info.switch_value = 1;
+ arg.info.ru.info1 = &info1;
+ info1.entries_read = 0;
+ info1.ci1 = 0;
+ break;
+ default:
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ arg.resume_handle = 0;
+ arg.pref_max_len = 0xFFFFFFFF;
+
+ rc = mlsvc_rpc_call(handle.context, opnum, &arg, &heap);
+ if ((rc != 0) || (arg.status != 0)) {
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ smb_tracef("srvsvc switch_value=%d", arg.info.switch_value);
+
+ switch (level) {
+ case 0:
+ if (arg.info.ru.info0 && arg.info.ru.info0->ci0) {
+ smb_tracef("srvsvc coni0_id=%x",
+ arg.info.ru.info0->ci0->coni0_id);
+ }
+ break;
+ case 1:
+ if (arg.info.ru.info1 && arg.info.ru.info1->ci1) {
+ cib1 = arg.info.ru.info1->ci1;
+
+ smb_tracef("srvsvc coni_uname=%s",
+ cib1->coni1_username ?
+ (char *)cib1->coni1_username : "(null)");
+ smb_tracef("srvsvc coni1_netname=%s",
+ cib1->coni1_netname ?
+ (char *)cib1->coni1_netname : "(null)");
+ smb_tracef("srvsvc coni1_nopens=%u",
+ cib1->coni1_num_opens);
+ smb_tracef("srvsvc coni1_time=%u", cib1->coni1_time);
+ smb_tracef("srvsvc coni1_num_users=%u",
+ cib1->coni1_num_users);
+ }
+ break;
+
+ default:
+ smb_tracef("srvsvc: unknown level");
+ break;
+ }
+
+ srvsvc_close(&handle, &heap);
+ return (0);
+}
+
+/*
+ * Synchronize the local system clock with the domain controller.
+ */
+void
+srvsvc_timesync(void)
+{
+ smb_ntdomain_t *di;
+ struct timeval tv;
+ struct tm tm;
+ time_t tsecs;
+
+ if ((di = smb_getdomaininfo(0)) == NULL)
+ return;
+
+ if (srvsvc_net_remote_tod(di->server, di->domain, &tv, &tm) != 0)
+ return;
+
+ if (settimeofday(&tv, 0))
+ smb_tracef("unable to set system time");
+
+ tsecs = time(0);
+ (void) localtime_r(&tsecs, &tm);
+ smb_tracef("SrvsvcTimeSync %s", ctime((time_t *)&tv.tv_sec));
+}
+
+/*
+ * NetRemoteTOD to get the current GMT time from a Windows NT server.
+ */
+int
+srvsvc_gettime(unsigned long *t)
+{
+ smb_ntdomain_t *di;
+ struct timeval tv;
+ struct tm tm;
+
+ if ((di = smb_getdomaininfo(0)) == NULL)
+ return (-1);
+
+ if (srvsvc_net_remote_tod(di->server, di->domain, &tv, &tm) != 0)
+ return (-1);
+
+ *t = tv.tv_sec;
+ return (0);
+}
+
+/*
+ * This is a client side routine for NetRemoteTOD, which gets the time
+ * and date from a remote system. The time information is returned in
+ * the timeval and tm.
+ *
+ * typedef struct _TIME_OF_DAY_INFO {
+ * DWORD tod_elapsedt; // seconds since 00:00:00 January 1 1970 GMT
+ * DWORD tod_msecs; // arbitrary milliseconds (since reset)
+ * DWORD tod_hours; // current hour [0-23]
+ * DWORD tod_mins; // current minute [0-59]
+ * DWORD tod_secs; // current second [0-59]
+ * DWORD tod_hunds; // current hundredth (0.01) second [0-99]
+ * LONG tod_timezone; // time zone of the server
+ * DWORD tod_tinterval; // clock tick time interval
+ * DWORD tod_day; // day of the month [1-31]
+ * DWORD tod_month; // month of the year [1-12]
+ * DWORD tod_year; // current year
+ * DWORD tod_weekday; // day of the week since sunday [0-6]
+ * } TIME_OF_DAY_INFO;
+ *
+ * The time zone of the server is calculated in minutes from Greenwich
+ * Mean Time (GMT). For time zones west of Greenwich, the value is
+ * positive; for time zones east of Greenwich, the value is negative.
+ * A value of -1 indicates that the time zone is undefined.
+ *
+ * The clock tick value represents a resolution of one ten-thousandth
+ * (0.0001) second.
+ */
+int
+srvsvc_net_remote_tod(char *server, char *domain, struct timeval *tv,
+ struct tm *tm)
+{
+ char timebuf[64];
+ struct mslm_NetRemoteTOD arg;
+ struct mslm_TIME_OF_DAY_INFO *tod;
+ mlsvc_handle_t handle;
+ mlrpc_heapref_t heap;
+ int rc;
+ int opnum;
+ int len;
+
+ rc = srvsvc_open(MLSVC_IPC_ANON, server, domain, 0, 0, &handle, &heap);
+ if (rc != 0)
+ return (-1);
+
+ opnum = SRVSVC_OPNUM_NetRemoteTOD;
+ bzero(&arg, sizeof (struct mslm_NetRemoteTOD));
+
+ len = strlen(server) + 4;
+ arg.servername = mlrpc_heap_malloc(heap.heap, len);
+ if (arg.servername == NULL) {
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+
+ rc = mlsvc_rpc_call(handle.context, opnum, &arg, &heap);
+ if ((rc != 0) || (arg.status != 0)) {
+ srvsvc_close(&handle, &heap);
+ return (-1);
+ }
+
+ /*
+ * We're assigning milliseconds to microseconds
+ * here but the value's not really relevant.
+ */
+ tod = arg.bufptr;
+
+ if (tv) {
+ tv->tv_sec = tod->tod_elapsedt;
+ tv->tv_usec = tod->tod_msecs;
+ smb_tracef("RemoteTime: %s", ctime(&tv->tv_sec));
+ }
+
+ if (tm) {
+ tm->tm_sec = tod->tod_secs;
+ tm->tm_min = tod->tod_mins;
+ tm->tm_hour = tod->tod_hours;
+ tm->tm_mday = tod->tod_day;
+ tm->tm_mon = tod->tod_month - 1;
+ tm->tm_year = tod->tod_year - 1900;
+ tm->tm_wday = tod->tod_weekday;
+
+ (void) strftime(timebuf, sizeof (timebuf),
+ "NetRemoteTOD: %D %T", tm);
+ smb_tracef("NetRemoteTOD: %s", timebuf);
+ }
+
+ srvsvc_close(&handle, &heap);
+ return (0);
+}
+
+void
+srvsvc_net_test(char *server, char *domain, char *netname)
+{
+ smb_ntdomain_t *di;
+
+ (void) smb_tracef("%s %s %s", server, domain, netname);
+
+ if ((di = smb_getdomaininfo(0)) != NULL) {
+ server = di->server;
+ domain = di->domain;
+ }
+
+ (void) srvsvc_net_share_get_info(server, domain, netname);
+#if 0
+ /*
+ * The NetSessionEnum server-side definition was updated.
+ * Disabled until the client-side has been updated.
+ */
+ (void) srvsvc_net_session_enum(server, domain, netname);
+#endif
+ (void) srvsvc_net_connect_enum(server, domain, netname, 0);
+ (void) srvsvc_net_connect_enum(server, domain, netname, 1);
+}
diff --git a/usr/src/lib/smbsrv/libmlsvc/i386/Makefile b/usr/src/lib/smbsrv/libmlsvc/i386/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libmlsvc/sparc/Makefile b/usr/src/lib/smbsrv/libmlsvc/sparc/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile b/usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libsmb/Makefile b/usr/src/lib/smbsrv/libsmb/Makefile
new file mode 100644
index 0000000000..cbe44c764c
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+HDRS= libsmb.h
+
+include ../Makefile.smbsrv
diff --git a/usr/src/lib/smbsrv/libsmb/Makefile.com b/usr/src/lib/smbsrv/libsmb/Makefile.com
new file mode 100644
index 0000000000..c479406282
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/Makefile.com
@@ -0,0 +1,86 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY= libsmb.a
+VERS= .1
+
+OBJS_SHARED = \
+ smb_common_door_decode.o \
+ smb_match.o \
+ smb_msgbuf.o \
+ smb_native.o \
+ smb_oem.o \
+ smb_opmlang.o \
+ smb_share_door_decode.o \
+ smb_sid.o \
+ smb_status_xlat.o \
+ smb_strcase.o \
+ smb_string.o \
+ smb_token.o \
+ smb_token_xdr.o \
+ smb_utf8.o \
+ smb_xdr_utils.o
+
+OBJS_COMMON = \
+ smb_api_door_calls.o \
+ smb_auth.o \
+ smb_cfg.o \
+ smb_crypt.o \
+ smb_ctxbuf.o \
+ smb_domain.o \
+ smb_door_client.o \
+ smb_door_encdec.o \
+ smb_doorclnt.o \
+ smb_downcalls.o \
+ smb_group_door_encdec.o \
+ smb_group_xdr.o \
+ smb_ht.o \
+ smb_idmap.o \
+ smb_info.o \
+ smb_mac.o \
+ smb_pwdutil.o \
+ smb_privilege.o \
+ smb_scfutil.o \
+ smb_util.o \
+ smb_wins.o \
+ smb_wksids.o
+
+OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+INCS += -I$(SRC)/common/smbsrv
+
+LDLIBS += -lscf -lmd -lnsl -lpkcs11 -lc -lidmap
+CPPFLAGS += $(INCS) -D_REENTRANT
+
+SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_SHARED:%.o=$(SRC)/common/smbsrv/%.c)
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbsrv/libsmb/amd64/Makefile b/usr/src/lib/smbsrv/libsmb/amd64/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h
new file mode 100644
index 0000000000..44da30085d
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h
@@ -0,0 +1,778 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBSMB_H
+#define _LIBSMB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <libscf.h>
+#include <libshare.h>
+
+#include <smbsrv/smb_idmap.h>
+
+/*
+ * XXX - These header files are here, only because other libraries
+ * can compile. Move the header files in to the internal header files
+ * of other libraries, once the restructure is complete. libsmb.h does not
+ * need these header files.
+ */
+#include <smbsrv/lmshare.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/codepage.h>
+#include <smbsrv/crypt.h>
+#include <smbsrv/ctype.h>
+#include <smbsrv/hash_table.h>
+#include <smbsrv/msgbuf.h>
+#include <smbsrv/oem.h>
+#include <smbsrv/string.h>
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smbinfo.h>
+/* End of header files to be removed. */
+
+/* Max value length of all SMB properties */
+#define MAX_VALUE_BUFLEN 512
+#define SMB_PI_MAX_DOMAIN_U 48
+
+#define SMBD_FMRI_PREFIX "network/smb/server"
+#define SMBD_DEFAULT_INSTANCE_FMRI "svc:/network/smb/server:default"
+#define SMBD_PG_NAME "smbd"
+#define SMBD_PROTECTED_PG_NAME "read"
+
+#define SMBD_SMF_OK 0
+#define SMBD_SMF_NO_MEMORY 1 /* no memory for data structures */
+#define SMBD_SMF_SYSTEM_ERR 2 /* system error, use errno */
+#define SMBD_SMF_NO_PERMISSION 3 /* no permission for operation */
+
+#define SCH_STATE_UNINIT 0
+#define SCH_STATE_INITIALIZING 1
+#define SCH_STATE_INIT 2
+
+typedef struct smb_scfhandle {
+ scf_handle_t *scf_handle;
+ int scf_state;
+ scf_service_t *scf_service;
+ scf_scope_t *scf_scope;
+ scf_transaction_t *scf_trans;
+ scf_transaction_entry_t *scf_entry;
+ scf_propertygroup_t *scf_pg;
+ scf_instance_t *scf_instance;
+ scf_iter_t *scf_inst_iter;
+ scf_iter_t *scf_pg_iter;
+} smb_scfhandle_t;
+
+/*
+ * CIFS Configuration Management
+ */
+
+/* macros for the description of all config params */
+#define SMB_CD_RDR_IPCMODE "rdr_ipcmode"
+#define SMB_CD_RDR_IPCUSER "rdr_ipcuser"
+#define SMB_CD_RDR_IPCPWD "rdr_ipcpasswd"
+
+#define SMB_CD_OPLOCK_ENABLE "oplock_enable"
+#define SMB_CD_OPLOCK_TIMEOUT "oplock_timeout"
+
+#define SMB_CD_AUTOHOME_MAP "autohome_map"
+
+#define SMB_CD_DOMAIN_SID "domain_sid"
+#define SMB_CD_DOMAIN_MEMB "domain_member"
+#define SMB_CD_DOMAIN_NAME "domain_name"
+#define SMB_CD_DOMAIN_SRV "pdc"
+
+#define SMB_CD_WINS_SRV1 "wins_server_1"
+#define SMB_CD_WINS_SRV2 "wins_server_2"
+#define SMB_CD_WINS_EXCL "wins_exclude"
+
+#define SMB_CD_SRVSVC_SHRSET_ENABLE "srvsvc_sharesetinfo_enable"
+#define SMB_CD_LOGR_ENABLE "logr_enable"
+#define SMB_CD_MLRPC_KALIVE "mlrpc_keep_alive_interval"
+
+#define SMB_CD_MAX_BUFSIZE "max_bufsize"
+#define SMB_CD_MAX_WORKERS "max_workers"
+#define SMB_CD_MAX_CONNECTIONS "max_connections"
+#define SMB_CD_KEEPALIVE "keep_alive"
+#define SMB_CD_RESTRICT_ANON "restrict_anonymous"
+
+#define SMB_CD_SIGNING_ENABLE "signing_enabled"
+#define SMB_CD_SIGNING_REQD "signing_required"
+#define SMB_CD_SIGNING_CHECK "signing_check"
+
+#define SMB_CD_FLUSH_REQUIRED "flush_required"
+#define SMB_CD_SYNC_ENABLE "sync_enable"
+#define SMB_CD_DIRSYMLINK_DISABLE "dir_symlink_disable"
+#define SMB_CD_ANNONCE_QUOTA "announce_quota"
+
+#define SMB_CD_SECURITY "security"
+#define SMB_CD_NBSCOPE "netbios_scope"
+#define SMB_CD_SYS_CMNT "system_comment"
+#define SMB_CD_LM_LEVEL "lmauth_level"
+#define SMB_CD_MSDCS_DISABLE "msdcs_disable"
+
+#define SMB_CD_ADS_ENABLE "ads_enable"
+#define SMB_CD_ADS_USER "ads_user"
+#define SMB_CD_ADS_PASSWD "ads_passwd"
+#define SMB_CD_ADS_DOMAIN "ads_domain"
+#define SMB_CD_ADS_USER_CONTAINER "ads_user_container"
+#define SMB_CD_ADS_SITE "ads_site"
+#define SMB_CD_ADS_IPLOOKUP "ads_ip_lookup"
+
+#define SMB_CD_DYNDNS_ENABLE "ddns_enable"
+#define SMB_CD_DYNDNS_RETRY_COUNT "ddns_retry_cnt"
+#define SMB_CD_DYNDNS_RETRY_SEC "ddns_retry_sec"
+
+#define SMB_CD_MACHINE_PASSWD "machine_passwd"
+
+/* configuration identifier */
+typedef enum {
+ SMB_CI_RDR_IPCMODE = 0,
+ SMB_CI_RDR_IPCUSER,
+ SMB_CI_RDR_IPCPWD,
+
+ SMB_CI_OPLOCK_ENABLE,
+ SMB_CI_OPLOCK_TIMEOUT,
+
+ SMB_CI_AUTOHOME_MAP,
+
+ SMB_CI_DOMAIN_SID,
+ SMB_CI_DOMAIN_MEMB,
+ SMB_CI_DOMAIN_NAME,
+ SMB_CI_DOMAIN_SRV,
+
+ SMB_CI_WINS_SRV1,
+ SMB_CI_WINS_SRV2,
+ SMB_CI_WINS_EXCL,
+
+ SMB_CI_SRVSVC_SHRSET_ENABLE,
+ SMB_CI_LOGR_ENABLE,
+ SMB_CI_MLRPC_KALIVE,
+
+ SMB_CI_MAX_BUFSIZE,
+ SMB_CI_MAX_WORKERS,
+ SMB_CI_MAX_CONNECTIONS,
+ SMB_CI_KEEPALIVE,
+ SMB_CI_RESTRICT_ANON,
+
+ SMB_CI_SIGNING_ENABLE,
+ SMB_CI_SIGNING_REQD,
+ SMB_CI_SIGNING_CHECK,
+
+ SMB_CI_FLUSH_REQUIRED,
+ SMB_CI_SYNC_ENABLE,
+ SMB_CI_DIRSYMLINK_DISABLE,
+ SMB_CI_ANNONCE_QUOTA,
+
+ SMB_CI_SECURITY,
+ SMB_CI_NBSCOPE,
+ SMB_CI_SYS_CMNT,
+ SMB_CI_LM_LEVEL,
+ SMB_CI_MSDCS_DISABLE,
+
+ SMB_CI_ADS_ENABLE,
+ SMB_CI_ADS_USER,
+ SMB_CI_ADS_PASSWD,
+ SMB_CI_ADS_DOMAIN,
+ SMB_CI_ADS_USER_CONTAINER,
+ SMB_CI_ADS_SITE,
+ SMB_CI_ADS_IPLOOKUP,
+
+ SMB_CI_DYNDNS_ENABLE,
+ SMB_CI_DYNDNS_RETRY_COUNT,
+ SMB_CI_DYNDNS_RETRY_SEC,
+
+ SMB_CI_MACHINE_PASSWD,
+ SMB_CI_MAX
+} smb_cfg_id_t;
+
+/* SMF helper functions */
+extern smb_scfhandle_t *smb_smf_scf_init(char *);
+extern void smb_smf_scf_fini(smb_scfhandle_t *);
+extern int smb_smf_start_transaction(smb_scfhandle_t *);
+extern int smb_smf_end_transaction(smb_scfhandle_t *);
+extern int smb_smf_set_string_property(smb_scfhandle_t *, char *, char *);
+extern int smb_smf_get_string_property(smb_scfhandle_t *, char *,
+ char *, size_t);
+extern int smb_smf_set_integer_property(smb_scfhandle_t *, char *, int64_t);
+extern int smb_smf_get_integer_property(smb_scfhandle_t *, char *, int64_t *);
+extern int smb_smf_set_boolean_property(smb_scfhandle_t *, char *, uint8_t);
+extern int smb_smf_get_boolean_property(smb_scfhandle_t *, char *, uint8_t *);
+extern int smb_smf_set_opaque_property(smb_scfhandle_t *, char *,
+ void *, size_t);
+extern int smb_smf_get_opaque_property(smb_scfhandle_t *, char *,
+ void *, size_t);
+extern int smb_smf_create_service_pgroup(smb_scfhandle_t *, char *);
+extern int smb_smf_delete_service_pgroup(smb_scfhandle_t *, char *);
+extern int smb_smf_create_instance_pgroup(smb_scfhandle_t *, char *);
+extern int smb_smf_delete_instance_pgroup(smb_scfhandle_t *, char *);
+extern int smb_smf_delete_property(smb_scfhandle_t *, char *);
+extern int smb_smf_instance_exists(smb_scfhandle_t *, char *);
+extern int smb_smf_instance_create(smb_scfhandle_t *, char *, char *);
+extern int smb_smf_instance_delete(smb_scfhandle_t *, char *);
+extern smb_scfhandle_t *smb_smf_get_iterator(char *);
+extern int smb_smf_get_property(smb_scfhandle_t *, int, char *, char *,
+ size_t);
+extern int smb_smf_set_property(smb_scfhandle_t *, int, char *, char *);
+
+/* Configuration management functions */
+extern int smb_config_load(void);
+extern void smb_config_rdlock(void);
+extern void smb_config_wrlock(void);
+extern void smb_config_unlock(void);
+extern char *smb_config_get(smb_cfg_id_t);
+extern char *smb_config_getstr(smb_cfg_id_t);
+extern int smb_config_getyorn(smb_cfg_id_t);
+extern uint32_t smb_config_getnum(smb_cfg_id_t);
+
+/*
+ * smb_config_getenv
+ *
+ * Retrieves the property value from SMF.
+ * Caller must free the returned buffer.
+ *
+ */
+extern char *smb_config_getenv(smb_cfg_id_t id);
+
+extern int smb_config_set(smb_cfg_id_t, char *);
+extern int smb_config_setnum(smb_cfg_id_t, uint32_t);
+extern uint8_t smb_config_get_fg_flag(void);
+extern int smb_config_setenv(smb_cfg_id_t id, char *);
+extern char *smb_config_get_localsid(void);
+extern int smb_config_secmode_fromstr(char *secmode);
+extern char *smb_config_secmode_tostr(int secmode);
+extern int smb_config_get_secmode(void);
+extern int smb_config_set_secmode(int secmode);
+extern int smb_config_set_idmap_domain(char *value);
+extern int smb_config_set_idmap_gc(char *value);
+extern int smb_config_refresh_idmap(void);
+
+/* smb_door_client.c */
+typedef struct smb_joininfo {
+ char domain_name[SMB_PI_MAX_DOMAIN];
+ char domain_username[BUF_LEN + 1];
+ char domain_passwd[BUF_LEN + 1];
+ uint32_t mode;
+} smb_joininfo_t;
+
+/* APIs to communicate with SMB daemon via door calls */
+extern int smbd_set_param(smb_cfg_id_t, char *);
+extern int smbd_get_param(smb_cfg_id_t, char *);
+extern int smbd_get_security_mode(int *);
+extern int smbd_netbios_reconfig(void);
+extern uint32_t smb_join(smb_joininfo_t *info);
+
+
+#define SMB_DOMAIN_NOMACHINE_SID -1
+#define SMB_DOMAIN_NODOMAIN_SID -2
+
+extern int nt_domain_init(char *resource_domain, uint32_t secmode);
+
+/* Following set of functions, manipulate WINS server configuration */
+extern int smb_wins_allow_list(char *config_list, char *allow_list);
+extern int smb_wins_exclude_list(char *config_list, char *exclude_list);
+extern boolean_t smb_wins_is_excluded(in_addr_t ipaddr,
+ unsigned long *exclude_list, int nexclude);
+extern void smb_wins_build_list(char *buf, uint32_t iplist[], int max_naddr);
+extern int smb_wins_iplist(char *list, uint32_t iplist[], int max_naddr);
+
+/*
+ * Information on a particular domain: the domain name, the
+ * name of a controller (PDC or BDC) and it's ip address.
+ */
+typedef struct smb_ntdomain {
+ char domain[SMB_PI_MAX_DOMAIN_U];
+ char server[SMB_PI_MAX_DOMAIN_U];
+ uint32_t ipaddr;
+} smb_ntdomain_t;
+
+/* SMB domain information management functions */
+extern void smb_purge_domain_info(void);
+extern int smb_is_domain_member(void);
+extern uint8_t smb_get_fg_flag(void);
+extern void smb_set_domain_member(int set);
+extern smb_ntdomain_t *smb_getdomaininfo(uint32_t timeout);
+extern void smb_setdomaininfo(char *domain, char *server, uint32_t ipaddr);
+extern void smb_logdomaininfo(smb_ntdomain_t *di);
+extern uint32_t smb_get_security_mode(void);
+
+extern int nt_priv_presentable_num(void);
+
+/*
+ * Following set of function, handle calls to SMB Kernel driver, via
+ * Kernel doors interface.
+ */
+extern uint64_t smb_dwncall_user_num(void);
+extern int smb_dwncall_share(int, char *, char *);
+
+/*
+ * buffer context structure. This is used to keep track of the buffer
+ * context.
+ *
+ * basep: points to the beginning of the buffer
+ * curp: points to the current offset
+ * endp: points to the limit of the buffer
+ */
+typedef struct {
+ unsigned char *basep;
+ unsigned char *curp;
+ unsigned char *endp;
+} smb_ctxbuf_t;
+
+extern int smb_ctxbuf_init(smb_ctxbuf_t *ctx, unsigned char *buf,
+ size_t buflen);
+extern int smb_ctxbuf_len(smb_ctxbuf_t *ctx);
+extern int smb_ctxbuf_printf(smb_ctxbuf_t *ctx, const char *fmt, ...);
+
+/* Functions to handle SMB daemon communications with idmap service */
+extern int smb_idmap_start(void);
+extern void smb_idmap_stop(void);
+extern int smb_idmap_restart(void);
+
+/* Miscellaneous functions */
+extern void hexdump(unsigned char *, int);
+extern size_t bintohex(const char *, size_t, char *, size_t);
+extern size_t hextobin(const char *, size_t, char *, size_t);
+extern char *trim_whitespace(char *buf);
+extern void randomize(char *, unsigned);
+extern void rand_hash(unsigned char *, size_t, unsigned char *, size_t);
+
+extern int smb_getdomainname(char *, size_t);
+extern int smb_getfqhostname(char *, size_t);
+extern int smb_gethostname(char *, size_t, int);
+extern int smb_getnetbiosname(char *, size_t);
+
+void smb_trace(const char *s);
+void smb_tracef(const char *fmt, ...);
+
+/*
+ * Authentication
+ */
+
+#define SMBAUTH_LM_MAGIC_STR "KGS!@#$%"
+
+#define SMBAUTH_HASH_SZ 16 /* also LM/NTLM/NTLMv2 Hash size */
+#define SMBAUTH_LM_RESP_SZ 24 /* also NTLM Response size */
+#define SMBAUTH_LM_PWD_SZ 14 /* LM password size */
+#define SMBAUTH_V2_CLNT_CHALLENGE_SZ 8 /* both LMv2 and NTLMv2 */
+#define SMBAUTH_SESSION_KEY_SZ SMBAUTH_HASH_SZ
+#define SMBAUTH_HEXHASH_SZ (SMBAUTH_HASH_SZ * 2)
+
+#define SMBAUTH_FAILURE 1
+#define SMBAUTH_SUCCESS 0
+#define MD_DIGEST_LEN 16
+
+/*
+ * Name Types
+ *
+ * The list of names near the end of the data blob (i.e. the ndb_names
+ * field of the smb_auth_data_blob_t data structure) can be classify into
+ * the following types:
+ *
+ * 0x0000 Indicates the end of the list.
+ * 0x0001 The name is a NetBIOS machine name (e.g. server name)
+ * 0x0002 The name is an NT Domain NetBIOS name.
+ * 0x0003 The name is the server's DNS hostname.
+ * 0x0004 The name is a W2K Domain name (a DNS name).
+ */
+#define SMBAUTH_NAME_TYPE_LIST_END 0x0000
+#define SMBAUTH_NAME_TYPE_SERVER_NETBIOS 0x0001
+#define SMBAUTH_NAME_TYPE_DOMAIN_NETBIOS 0x0002
+#define SMBAUTH_NAME_TYPE_SERVER_DNS 0x0003
+#define SMBAUTH_NAME_TYPE_DOMAIN_DNS 0x0004
+
+/*
+ * smb_auth_name_entry_t
+ *
+ * Each name entry in the data blob consists of the following 3 fields:
+ *
+ * nne_type - name type
+ * nne_len - the length of the name
+ * nne_name - the name, in uppercase UCS-2LE Unicode format
+ */
+typedef struct smb_auth_name_entry {
+ unsigned short nne_type;
+ unsigned short nne_len;
+ mts_wchar_t nne_name[SMB_PI_MAX_DOMAIN * 2];
+} smb_auth_name_entry_t;
+
+/*
+ * smb_auth_data_blob
+ *
+ * The format of this NTLMv2 data blob structure is as follow:
+ *
+ * - Blob Signature 0x01010000 (4 bytes)
+ * - Reserved (0x00000000) (4 bytes)
+ * - Timestamp Little-endian, 64-bit signed value representing
+ * the number of tenths of a microsecond since January 1, 1601.
+ * (8 bytes)
+ * - Client Challenge (8 bytes)
+ * - Unknown1 (4 bytes)
+ * - List of Target Information (variable length)
+ * - Unknown2 (4 bytes)
+ */
+typedef struct smb_auth_data_blob {
+ unsigned char ndb_signature[4];
+ unsigned char ndb_reserved[4];
+ uint64_t ndb_timestamp;
+ unsigned char ndb_clnt_challenge[SMBAUTH_V2_CLNT_CHALLENGE_SZ];
+ unsigned char ndb_unknown[4];
+ smb_auth_name_entry_t ndb_names[2];
+ unsigned char ndb_unknown2[4];
+} smb_auth_data_blob_t;
+
+#define SMBAUTH_BLOB_MAXLEN (sizeof (smb_auth_data_blob_t))
+#define SMBAUTH_CI_MAXLEN SMBAUTH_LM_RESP_SZ
+#define SMBAUTH_CS_MAXLEN (SMBAUTH_BLOB_MAXLEN + SMBAUTH_HASH_SZ)
+
+/*
+ * smb_auth_info_t
+ *
+ * The structure contains all the authentication information
+ * needed for the preparaton of the SMBSessionSetupAndx request
+ * and the user session key.
+ *
+ * hash - NTLM hash
+ * hash_v2 - NTLMv2 hash
+ * ci_len - the length of the case-insensitive password
+ * ci - case-insensitive password
+ * (If NTLMv2 authentication mechanism is used, it
+ * represents the LMv2 response. Otherwise, it
+ * is empty.)
+ * cs_len - the length of the case-sensitive password
+ * cs - case-sensitive password
+ * (If NTLMv2 authentication mechanism is used, it
+ * represents the NTLMv2 response. Otherwise, it
+ * represents the NTLM response.)
+ * data_blob - NTLMv2 data blob
+ */
+typedef struct smb_auth_info {
+ unsigned char hash[SMBAUTH_HASH_SZ];
+ unsigned char hash_v2[SMBAUTH_HASH_SZ];
+ unsigned short ci_len;
+ unsigned char ci[SMBAUTH_CI_MAXLEN];
+ unsigned short cs_len;
+ unsigned char cs[SMBAUTH_CS_MAXLEN];
+ int lmcompatibility_lvl;
+ smb_auth_data_blob_t data_blob;
+} smb_auth_info_t;
+
+extern int smb_getdomainname(char *, size_t);
+extern int smb_getfqhostname(char *, size_t);
+extern int smb_gethostname(char *, size_t, int);
+extern int smb_getnetbiosname(char *, size_t);
+
+void smb_trace(const char *s);
+void smb_tracef(const char *fmt, ...);
+
+/*
+ * SMB password management
+ */
+
+#define SMB_PWF_LM 0x01 /* LM hash is present */
+#define SMB_PWF_NT 0x02 /* NT hash is present */
+#define SMB_PWF_DISABLE 0x04 /* Account is disabled */
+
+typedef struct smb_passwd {
+ uid_t pw_uid;
+ uint32_t pw_flags;
+ unsigned char pw_lmhash[SMBAUTH_HASH_SZ];
+ unsigned char pw_nthash[SMBAUTH_HASH_SZ];
+} smb_passwd_t;
+
+/*
+ * Control flags passed to smb_pwd_setcntl
+ */
+#define SMB_PWC_DISABLE 0x01
+#define SMB_PWC_ENABLE 0x02
+#define SMB_PWC_NOLM 0x04
+
+#define SMB_PWE_SUCCESS 0
+#define SMB_PWE_USER_UNKNOWN 1
+#define SMB_PWE_USER_DISABLE 2
+#define SMB_PWE_CLOSE_FAILED 3
+#define SMB_PWE_OPEN_FAILED 4
+#define SMB_PWE_WRITE_FAILED 6
+#define SMB_PWE_UPDATE_FAILED 7
+#define SMB_PWE_STAT_FAILED 8
+#define SMB_PWE_BUSY 9
+#define SMB_PWE_DENIED 10
+#define SMB_PWE_SYSTEM_ERROR 11
+#define SMB_PWE_MAX 12
+
+extern smb_passwd_t *smb_pwd_getpasswd(const char *, smb_passwd_t *);
+extern int smb_pwd_setpasswd(const char *, const char *);
+extern int smb_pwd_setcntl(const char *, int);
+
+extern int smb_auth_qnd_unicode(mts_wchar_t *dst, char *src, int length);
+extern int smb_auth_hmac_md5(unsigned char *data, int data_len,
+ unsigned char *key, int key_len, unsigned char *digest);
+
+/*
+ * A variation on HMAC-MD5 known as HMACT64 is used by Windows systems.
+ * The HMACT64() function is the same as the HMAC-MD5() except that
+ * it truncates the input key to 64 bytes rather than hashing it down
+ * to 16 bytes using the MD5() function.
+ */
+#define SMBAUTH_HMACT64(D, Ds, K, Ks, digest) \
+ smb_auth_hmac_md5(D, Ds, K, (Ks > 64) ? 64 : Ks, digest)
+
+extern int smb_auth_DES(unsigned char *, int, unsigned char *, int,
+ unsigned char *, int);
+
+extern int smb_auth_md4(unsigned char *, unsigned char *, int);
+extern int smb_auth_lm_hash(char *, unsigned char *);
+extern int smb_auth_ntlm_hash(char *, unsigned char *);
+
+extern int smb_auth_set_info(char *, char *,
+ unsigned char *, char *, unsigned char *,
+ int, int, smb_auth_info_t *);
+
+extern int smb_auth_gen_session_key(smb_auth_info_t *, unsigned char *);
+
+boolean_t smb_auth_validate_lm(unsigned char *, uint32_t, smb_passwd_t *,
+ unsigned char *, int, char *);
+boolean_t smb_auth_validate_nt(unsigned char *, uint32_t, smb_passwd_t *,
+ unsigned char *, int, char *);
+
+/*
+ * SMB MAC Signing
+ */
+
+#define SMB_MAC_KEY_SZ (SMBAUTH_SESSION_KEY_SZ + SMBAUTH_CS_MAXLEN)
+#define SMB_SIG_OFFS 14 /* signature field offset within header */
+#define SMB_SIG_SIZE 8 /* SMB signature size */
+
+/*
+ * Signing flags:
+ *
+ * SMB_SCF_ENABLE Signing is enabled.
+ *
+ * SMB_SCF_REQUIRED Signing is enabled and required.
+ * This flag shouldn't be set if
+ * SMB_SCF_ENABLE isn't set.
+ *
+ * SMB_SCF_STARTED Signing will start after receiving
+ * the first non-anonymous SessionSetup
+ * request.
+ *
+ * SMB_SCF_KEY_ISSET_THIS_LOGON Indicates whether the MAC key has just
+ * been set for this logon. (prior to
+ * sending the SMBSessionSetup request)
+ *
+ */
+#define SMB_SCF_ENABLE 0x01
+#define SMB_SCF_REQUIRED 0x02
+#define SMB_SCF_STARTED 0x04
+#define SMB_SCF_KEY_ISSET_THIS_LOGON 0x08
+
+/*
+ * smb_sign_ctx
+ *
+ * SMB signing context.
+ *
+ * ssc_seqnum sequence number
+ * ssc_keylen mac key length
+ * ssc_mid multiplex id - reserved
+ * ssc_flags flags
+ * ssc_mackey mac key
+ * ssc_sign mac signature
+ *
+ */
+typedef struct smb_sign_ctx {
+ unsigned int ssc_seqnum;
+ unsigned short ssc_keylen;
+ unsigned short ssc_mid;
+ unsigned int ssc_flags;
+ unsigned char ssc_mackey[SMB_MAC_KEY_SZ];
+ unsigned char ssc_sign[SMB_SIG_SIZE];
+} smb_sign_ctx_t;
+
+extern int smb_mac_init(smb_sign_ctx_t *sign_ctx, smb_auth_info_t *auth);
+extern int smb_mac_calc(smb_sign_ctx_t *sign_ctx,
+ const unsigned char *buf, size_t buf_len, unsigned char *mac_sign);
+extern int smb_mac_chk(smb_sign_ctx_t *sign_ctx,
+ const unsigned char *buf, size_t buf_len);
+extern int smb_mac_sign(smb_sign_ctx_t *sign_ctx,
+ unsigned char *buf, size_t buf_len);
+extern void smb_mac_inc_seqnum(smb_sign_ctx_t *sign_ctx);
+extern void smb_mac_dec_seqnum(smb_sign_ctx_t *sign_ctx);
+
+/*
+ * Each domain is categorized using the enum values below.
+ * The local domain refers to the local machine and is named
+ * after the local hostname. The primary domain is the domain
+ * that the system joined. All other domains are either
+ * trusted or untrusted, as defined by the primary domain PDC.
+ *
+ * This enum must be kept in step with the table of strings
+ * in ntdomain.c.
+ */
+typedef enum nt_domain_type {
+ NT_DOMAIN_NULL,
+ NT_DOMAIN_BUILTIN,
+ NT_DOMAIN_LOCAL,
+ NT_DOMAIN_PRIMARY,
+ NT_DOMAIN_ACCOUNT,
+ NT_DOMAIN_TRUSTED,
+ NT_DOMAIN_UNTRUSTED,
+ NT_DOMAIN_NUM_TYPES
+} nt_domain_type_t;
+
+
+/*
+ * This is the information that is held about each domain. The database
+ * is a linked list that is threaded through the domain structures. As
+ * the number of domains in the database should be small (32 max), this
+ * should be sufficient.
+ */
+typedef struct nt_domain {
+ struct nt_domain *next;
+ nt_domain_type_t type;
+ char *name;
+ nt_sid_t *sid;
+} nt_domain_t;
+
+nt_domain_t *nt_domain_new(nt_domain_type_t type, char *name, nt_sid_t *sid);
+void nt_domain_delete(nt_domain_t *domain);
+nt_domain_t *nt_domain_add(nt_domain_t *new_domain);
+void nt_domain_remove(nt_domain_t *domain);
+void nt_domain_flush(nt_domain_type_t domain_type);
+void nt_domain_sync(void);
+char *nt_domain_xlat_type(nt_domain_type_t domain_type);
+nt_domain_type_t nt_domain_xlat_type_name(char *type_name);
+nt_domain_t *nt_domain_lookup_name(char *domain_name);
+nt_domain_t *nt_domain_lookup_sid(nt_sid_t *domain_sid);
+nt_domain_t *nt_domain_lookupbytype(nt_domain_type_t type);
+nt_sid_t *nt_domain_local_sid(void);
+
+#define SMB_GROUP_PER_LIST 5
+
+/*
+ * This structure takes different args passed from the client/server routines
+ * of the SMB local group door service. Extend this structure if a new type
+ * client paramater needs to be passed.
+ */
+typedef struct ntgrp_dr_arg {
+ char *gname;
+ char *desc;
+ char *member;
+ char *newgname;
+ uint32_t privid;
+ uint32_t priv_attr;
+ int offset;
+ char *scope;
+ int type;
+ int count;
+ uint32_t ntstatus;
+} ntgrp_dr_arg_t;
+
+typedef struct ntgrp {
+ DWORD rid; /* Rid of the group */
+ char *name; /* Name of the group */
+ char *desc; /* Desc of gruup */
+ char *type; /* sid_name_use */
+ char *sid; /* Sid */
+ DWORD attr; /* Attribute */
+} ntgrp_t;
+
+typedef struct ntgrp_list {
+ int cnt;
+ ntgrp_t groups[SMB_GROUP_PER_LIST];
+} ntgrp_list_t;
+
+typedef char *members_list;
+typedef struct ntgrp_member_list {
+ DWORD rid; /* Rid of the group in which members belong */
+ int cnt; /* members */
+ members_list members[SMB_GROUP_PER_LIST];
+} ntgrp_member_list_t;
+
+typedef struct ntpriv {
+ DWORD id; /* Id of priv */
+ char *name; /* Name of priv */
+} ntpriv_t;
+typedef ntpriv_t *privs_t;
+
+typedef struct ntpriv_list {
+ int cnt; /* Number of privs */
+ privs_t privs[ANY_SIZE_ARRAY]; /* privs only presentable ones */
+} ntpriv_list_t;
+
+
+/* the xdr functions */
+extern bool_t xdr_ntgrp_dr_arg_t(XDR *, ntgrp_dr_arg_t *);
+extern bool_t xdr_ntgrp_t(XDR *, ntgrp_t *);
+extern bool_t xdr_ntgrp_list_t(XDR *, ntgrp_list_t *);
+extern bool_t xdr_members_list(XDR *, members_list *);
+extern bool_t xdr_ntgrp_member_list_t(XDR *, ntgrp_member_list_t *);
+extern bool_t xdr_ntpriv_t(XDR *, ntpriv_t *);
+extern bool_t xdr_privs_t(XDR *, privs_t *);
+extern bool_t xdr_ntpriv_list_t(XDR *, ntpriv_list_t *);
+
+extern void smb_group_free_memberlist(ntgrp_member_list_t *, int);
+extern void smb_group_free_list(ntgrp_list_t *, int);
+extern void smb_group_free_privlist(ntpriv_list_t *, int);
+
+extern uint32_t smb_group_add(char *, char *);
+extern uint32_t smb_group_modify(char *, char *, char *);
+extern uint32_t smb_group_delete(char *);
+extern uint32_t smb_group_member_remove(char *, char *);
+extern uint32_t smb_group_member_add(char *, char *);
+extern uint32_t smb_group_priv_num(int *);
+extern uint32_t smb_group_priv_list(ntpriv_list_t **);
+extern uint32_t smb_group_priv_get(char *, uint32_t, uint32_t *);
+extern uint32_t smb_group_priv_set(char *, uint32_t, uint32_t);
+extern uint32_t smb_group_count(int *);
+extern uint32_t smb_group_list(int, ntgrp_list_t **, char *, int);
+extern uint32_t smb_group_member_count(char *, int *);
+extern uint32_t smb_group_member_list(char *, int, ntgrp_member_list_t **);
+
+extern char *smb_dr_encode_grp_privlist(uint32_t, ntpriv_list_t *, size_t *);
+extern ntpriv_list_t *smb_dr_decode_grp_privlist(char *, size_t);
+
+extern char *smb_dr_encode_grp_list(uint32_t, ntgrp_list_t *, size_t *);
+extern ntgrp_list_t *smb_dr_decode_grp_list(char *, size_t);
+
+extern char *smb_dr_encode_grp_memberlist(uint32_t, ntgrp_member_list_t *,
+ size_t *);
+extern ntgrp_member_list_t *smb_dr_decode_grp_memberlist(char *buf, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSMB_H */
diff --git a/usr/src/lib/smbsrv/libsmb/common/llib-lsmb b/usr/src/lib/smbsrv/libsmb/common/llib-lsmb
new file mode 100644
index 0000000000..e900ce8047
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/llib-lsmb
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <smbsrv/libsmb.h>
diff --git a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers
new file mode 100644
index 0000000000..05c89f93ff
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers
@@ -0,0 +1,325 @@
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate {
+ global:
+ bintohex;
+ codepage_islower;
+ codepage_isupper;
+ codepage_tolower;
+ codepage_toupper;
+ hexdump;
+ hextobin;
+ ht_add_item;
+ ht_clean_table;
+ ht_clear_delete;
+ ht_create_table;
+ ht_destroy_table;
+ ht_find_item;
+ ht_findfirst;
+ ht_findnext;
+ ht_findnext;
+ ht_get_total_items;
+ ht_mark_delete;
+ ht_register_callback;
+ ht_remove_item;
+ ht_replace_item;
+ ht_set_cmpfn;
+ smb_msgbuf_base;
+ smb_msgbuf_decode;
+ smb_msgbuf_dword_align;
+ smb_msgbuf_encode;
+ smb_msgbuf_fclear;
+ smb_msgbuf_fset;
+ smb_msgbuf_has_space;
+ smb_msgbuf_init;
+ smb_msgbuf_size;
+ smb_msgbuf_term;
+ smb_msgbuf_used;
+ smb_msgbuf_word_align;
+ mts_mbstos;
+ mts_mbstowcs;
+ mts_mbtowc;
+ mts_sbequiv_strlen;
+ mts_stombs;
+ mts_wcequiv_strlen;
+ mts_wcstombs;
+ mts_wctomb;
+ netr_client_mkabsolute;
+ nt_builtin_findfirst;
+ nt_builtin_findnext;
+ nt_builtin_fini;
+ nt_builtin_init;
+ nt_builtin_is_wellknown;
+ nt_builtin_lookup;
+ nt_builtin_lookup_domain;
+ nt_builtin_lookup_name;
+ nt_builtin_lookup_sid;
+ nt_domain_add;
+ nt_domain_flush;
+ nt_domain_init;
+ nt_domain_local_sid;
+ nt_domain_lookup_name;
+ nt_domain_lookup_sid;
+ nt_domain_lookupbytype;
+ nt_domain_new;
+ nt_sid_dup;
+ nt_sid_format2;
+ nt_sid_format;
+ nt_sid_gen_null_sid;
+ nt_sid_get_rid;
+ nt_sid_is_builtin;
+ nt_sid_is_equal;
+ nt_sid_is_indomain;
+ nt_sid_is_local;
+ nt_sid_is_valid;
+ nt_sid_length;
+ nt_sid_logf;
+ nt_sid_name_use;
+ nt_sid_splice;
+ nt_sid_split;
+ nt_sid_strtosid;
+ oem_get_smb_cpid;
+ oem_get_telnet_cpid;
+ oem_language_set;
+ oemstounicodes;
+ rand_hash;
+ randomize;
+ smb_auth_DES;
+ smb_auth_gen_session_key;
+ smb_auth_ntlm_hash;
+ smb_auth_qnd_unicode;
+ smb_auth_set_info;
+ smb_auth_validate_lm;
+ smb_auth_validate_nt;
+ smb_config_get;
+ smb_config_get_fg_flag;
+ smb_config_get_localsid;
+ smb_config_get_secmode;
+ smb_config_getenv;
+ smb_config_getnum;
+ smb_config_getstr;
+ smb_config_getyorn;
+ smb_config_load;
+ smb_config_rdlock;
+ smb_config_refresh_idmap;
+ smb_config_secmode_fromstr;
+ smb_config_secmode_tostr;
+ smb_config_set;
+ smb_config_set_idmap_domain;
+ smb_config_set_idmap_gc;
+ smb_config_set_secmode;
+ smb_config_setenv;
+ smb_config_setnum;
+ smb_config_unlock;
+ smb_config_wrlock;
+ smb_ctxbuf_init;
+ smb_ctxbuf_len;
+ smb_ctxbuf_printf;
+ smb_dr_decode_arg_get_token;
+ smb_dr_decode_common;
+ smb_dr_decode_finish;
+ smb_dr_decode_grp_list;
+ smb_dr_decode_grp_memberlist;
+ smb_dr_decode_grp_privlist;
+ smb_dr_decode_start;
+ smb_dr_decode_string;
+ smb_dr_encode_common;
+ smb_dr_encode_finish;
+ smb_dr_encode_grp_list;
+ smb_dr_encode_grp_memberlist;
+ smb_dr_encode_grp_privlist;
+ smb_dr_encode_res_token;
+ smb_dr_encode_start;
+ smb_dr_encode_string;
+ smb_dr_free_string;
+ smb_dr_get_BYTE;
+ smb_dr_get_buf;
+ smb_dr_get_dword;
+ smb_dr_get_int32;
+ smb_dr_get_lmshare;
+ smb_dr_get_lmshr_iterator;
+ smb_dr_get_lmshr_list;
+ smb_dr_get_opcode;
+ smb_dr_get_res_stat;
+ smb_dr_get_short;
+ smb_dr_get_string;
+ smb_dr_get_uint32;
+ smb_dr_get_uint64;
+ smb_dr_get_ushort;
+ smb_dr_get_word;
+ smb_dr_put_BYTE;
+ smb_dr_put_buf;
+ smb_dr_put_dword;
+ smb_dr_put_int32;
+ smb_dr_put_kconfig;
+ smb_dr_put_lmshare;
+ smb_dr_put_lmshr_iterator;
+ smb_dr_put_lmshr_list;
+ smb_dr_put_short;
+ smb_dr_put_string;
+ smb_dr_put_uint32;
+ smb_dr_put_uint64;
+ smb_dr_put_ushort;
+ smb_dr_put_word;
+ smb_dr_set_opcode;
+ smb_dr_set_res_stat;
+ smb_dr_ulist_free;
+ smb_dwncall_get_users;
+ smb_dwncall_install_callback;
+ smb_dwncall_share;
+ smb_dwncall_user_num;
+ smb_get_fg_flag;
+ smb_get_security_mode;
+ smb_getdomaininfo;
+ smb_getdomainname;
+ smb_getfqhostname;
+ smb_gethostname;
+ smb_getnetbiosname;
+ smb_group_add;
+ smb_group_count;
+ smb_group_delete;
+ smb_group_free_list;
+ smb_group_free_memberlist;
+ smb_group_free_privlist;
+ smb_group_list;
+ smb_group_member_add;
+ smb_group_member_count;
+ smb_group_member_list;
+ smb_group_member_remove;
+ smb_group_modify;
+ smb_group_priv_get;
+ smb_group_priv_list;
+ smb_group_priv_num;
+ smb_group_priv_set;
+ smb_idmap_batch_create;
+ smb_idmap_batch_destroy;
+ smb_idmap_batch_getid;
+ smb_idmap_batch_getmappings;
+ smb_idmap_batch_getsid;
+ smb_idmap_getsid;
+ smb_idmap_restart;
+ smb_idmap_start;
+ smb_idmap_stop;
+ smb_is_domain_member;
+ smb_join;
+ smb_load_kconfig;
+ smb_mac_chk;
+ smb_mac_dec_seqnum;
+ smb_mac_inc_seqnum;
+ smb_mac_init;
+ smb_mac_sign;
+ smb_match83;
+ smb_match;
+ smb_match_ci;
+ smb_priv_getbyname;
+ smb_priv_getbyvalue;
+ smb_priv_presentable_ids;
+ smb_priv_presentable_num;
+ smb_privset_copy;
+ smb_privset_enable;
+ smb_privset_free;
+ smb_privset_init;
+ smb_privset_log;
+ smb_privset_new;
+ smb_privset_query;
+ smb_privset_size;
+ smb_privset_validate;
+ smb_purge_domain_info;
+ smb_trace;
+ smb_tracef;
+ xdr_ntgrp_dr_arg_t;
+ xdr_ntgrp_list_t;
+ xdr_ntgrp_member_list_t;
+ xdr_ntpriv_list_t;
+ smb_pwd_getpasswd;
+ smb_pwd_setcntl;
+ smb_pwd_setpasswd;
+ smb_set_domain_member;
+ smb_setdomaininfo;
+ smb_smf_create_instance_pgroup;
+ smb_smf_create_service_pgroup;
+ smb_smf_delete_instance_pgroup;
+ smb_smf_delete_property;
+ smb_smf_delete_service_pgroup;
+ smb_smf_end_transaction;
+ smb_smf_get_boolean_property;
+ smb_smf_get_integer_property;
+ smb_smf_get_iterator;
+ smb_smf_get_opaque_property;
+ smb_smf_get_string_property;
+ smb_smf_instance_create;
+ smb_smf_instance_delete;
+ smb_smf_instance_exists;
+ smb_smf_scf_fini;
+ smb_smf_scf_init;
+ smb_smf_set_boolean_property;
+ smb_smf_set_integer_property;
+ smb_smf_set_opaque_property;
+ smb_smf_set_string_property;
+ smb_smf_start_transaction;
+ smb_token_log;
+ smb_token_mkselfrel;
+ smb_token_print;
+ smb_token_query_privilege;
+ smb_trace;
+ smb_tracef;
+ smb_wins_allow_list;
+ smb_wins_build_list;
+ smb_wins_exclude_list;
+ smb_wins_iplist;
+ smb_wins_is_excluded;
+ smbd_get_param;
+ smbd_get_security_mode;
+ smbd_netbios_reconfig;
+ smbd_set_param;
+ smbnative_lm_value;
+ smbnative_os_value;
+ smbnative_pdc_value;
+ strcanon;
+ strsep;
+ strsubst;
+ trim_whitespace;
+ unicodestooems;
+ utf8_isstrascii;
+ utf8_isstrlwr;
+ utf8_isstrupr;
+ utf8_strcasecmp;
+ utf8_strlwr;
+ utf8_strncasecmp;
+ utf8_strupr;
+ xdr_ntgrp_dr_arg_t;
+ xdr_ntgrp_list_t;
+ xdr_ntgrp_member_list_t;
+ xdr_ntpriv_list_t;
+ xdr_smb_dr_bytes_t;
+ xdr_smb_dr_string_t;
+ xdr_smb_dr_ulist_t;
+ xdr_smb_dr_user_ctx_t;
+ xlate_nt_status;
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c
new file mode 100644
index 0000000000..4a84b5d462
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c
@@ -0,0 +1,864 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Door calls invoked by CLIs to obtain various SMB door service provided
+ * by SMB daemon.
+ */
+
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+
+/* indexed via opcode (smb_dr_opcode_t) */
+char *smbapi_desc[] = {
+ "",
+ "",
+ "",
+ "",
+ "SmbapiUserList",
+ "SmbGroupAdd",
+ "SmbGroupDelete",
+ "SmbGroupAddMember",
+ "SmbGroupRemoveMember",
+ "SmbGroupGetCount",
+ "SmbGroupGetCacheSize",
+ "SmbGroupModify",
+ "SmbGroupPresentablePrivNum",
+ "SmbGroupPresentablePriv",
+ "SmbGroupGetPriv",
+ "SmbGroupSetPriv",
+ "SmbGroupListGroups",
+ "SmbGroupListMembers",
+ "SmbGroupMembersCount",
+ 0
+};
+
+/*
+ * This function will return information on the connected users
+ * starting at the given offset.
+ *
+ * At most 50 users (i.e. SMB_DR_MAX_USER) will be returned via this
+ * function. Multiple calls might be needed to obtain all connected
+ * users.
+ *
+ * smb_dr_ulist_free must be called to free memory allocated for the
+ * account and workstation fields of each user in the returned list.
+ */
+int
+smb_api_ulist(int offset, smb_dr_ulist_t *users)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ int rc = -1;
+ uint_t opcode = SMB_DR_USER_LIST;
+ int fd;
+
+ bzero(users, sizeof (smb_dr_ulist_t));
+ buf = smb_dr_encode_common(opcode, &offset, xdr_uint32_t, &buflen);
+ if (!buf)
+ return (-1);
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (-1);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+ if (rbufp) {
+ rc = smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_smb_dr_ulist_t, users);
+
+ }
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+/* Routines for SMB Group Door Client APIs */
+uint32_t
+smb_group_add(char *gname, char *desc)
+{
+ ntgrp_dr_arg_t *args;
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_ADD;
+ int fd;
+
+ if ((gname == 0) || (*gname == 0)) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ args->gname = gname;
+ args->desc = desc;
+ if ((buf = smb_dr_encode_common(opcode, args,
+ xdr_ntgrp_dr_arg_t, &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ free(args);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ free(args);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, &rc) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_delete(char *gname)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_DELETE;
+ int fd;
+
+ if ((gname == 0) || (*gname == 0)) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((buf = smb_dr_encode_string(opcode, gname, &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, &rc) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_member_add(char *gname, char *member)
+{
+ ntgrp_dr_arg_t *args;
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_MEMBER_ADD;
+ int fd;
+
+ if ((gname == 0) || (*gname == 0) ||
+ (member == 0) || (*member == 0)) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ args->gname = gname;
+ args->member = member;
+ if ((buf = smb_dr_encode_common(opcode, args, xdr_ntgrp_dr_arg_t,
+ &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ free(args);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ free(args);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, &rc) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_member_remove(char *gname, char *member)
+{
+ ntgrp_dr_arg_t *args;
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_MEMBER_REMOVE;
+ int fd;
+
+ if ((gname == 0) || (*gname == 0) ||
+ (member == 0) || (*member == 0)) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ args->gname = gname;
+ args->member = member;
+ if ((buf = smb_dr_encode_common(opcode, args, xdr_ntgrp_dr_arg_t,
+ &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ free(args);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ free(args);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, &rc) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+
+uint32_t
+smb_group_count(int *cnt)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ uint_t opcode = SMB_DR_GROUP_COUNT;
+ int fd;
+
+ if (cnt == 0) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+ *cnt = 0;
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME,
+ smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ if ((buf = smb_dr_set_opcode(opcode, &buflen)) == 0) {
+ (void) close(fd);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, cnt) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+ rc = NT_STATUS_SUCCESS;
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_cachesize(int *sz)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ uint_t opcode = SMB_DR_GROUP_CACHE_SIZE;
+ int fd;
+
+ if (sz == 0) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+ *sz = 0;
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME,
+ smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ if ((buf = smb_dr_set_opcode(opcode, &buflen)) == 0) {
+ (void) close(fd);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, sz) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+ rc = NT_STATUS_SUCCESS;
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_modify(char *gname, char *newgname, char *desc)
+{
+ ntgrp_dr_arg_t *args;
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_MODIFY;
+ int fd;
+
+ if ((gname == 0) || (*gname == 0) ||
+ (newgname == 0) || (*newgname == 0)) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ args->gname = gname;
+ args->desc = desc;
+ args->newgname = newgname;
+ if ((buf = smb_dr_encode_common(opcode, args, xdr_ntgrp_dr_arg_t,
+ &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ free(args);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ free(args);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, &rc) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_priv_num(int *num)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_PRIV_NUM;
+ int fd;
+
+ if (num == 0) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+ *num = 0;
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME,
+ smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ if ((buf = smb_dr_set_opcode(opcode, &buflen)) == 0) {
+ (void) close(fd);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, num) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ rc = NT_STATUS_SUCCESS;
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_priv_list(ntpriv_list_t **list)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_PRIV_LIST;
+ int fd;
+ *list = NULL;
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME,
+ smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ if ((buf = smb_dr_set_opcode(opcode, &buflen)) == 0) {
+ (void) close(fd);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result */
+ if (rbufp) {
+ if ((*list = smb_dr_decode_grp_privlist(
+ rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET)) == 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ rc = NT_STATUS_SUCCESS;
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_priv_get(char *gname, uint32_t privid, uint32_t *privval)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ ntgrp_dr_arg_t *args;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_PRIV_GET;
+ int fd;
+ uint32_t retval;
+
+ *privval = SE_PRIVILEGE_DISABLED;
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ args->gname = gname;
+ args->privid = privid;
+ if ((buf = smb_dr_encode_common(opcode, args, xdr_ntgrp_dr_arg_t,
+ &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ free(args);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ free(args);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t,
+ &retval) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ *privval = retval;
+ rc = NT_STATUS_SUCCESS;
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_priv_set(char *gname, uint32_t privid, uint32_t priv_attr)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ ntgrp_dr_arg_t *args;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_PRIV_SET;
+ int fd;
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ args->gname = gname;
+ args->privid = privid;
+ args->priv_attr = priv_attr;
+ if ((buf = smb_dr_encode_common(opcode, args, xdr_ntgrp_dr_arg_t,
+ &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ free(args);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ free(args);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, &rc) != 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_list(int offset, ntgrp_list_t **list, char *scope, int type)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ ntgrp_dr_arg_t *args;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_LIST;
+ int fd;
+ *list = NULL;
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ args->offset = offset;
+ args->type = type;
+ args->scope = scope;
+ if ((buf = smb_dr_encode_common(opcode, args, xdr_ntgrp_dr_arg_t,
+ &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ free(args);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ free(args);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if ((*list = smb_dr_decode_grp_list(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET)) == 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ rc = NT_STATUS_SUCCESS;
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_member_list(char *gname, int offset, ntgrp_member_list_t **members)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ ntgrp_dr_arg_t *args;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_MEMBER_LIST;
+ int fd;
+ *members = NULL;
+
+ if ((gname == 0) || (*gname == 0)) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((args = (ntgrp_dr_arg_t *)malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory for ret_mem_list",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(args, sizeof (ntgrp_dr_arg_t));
+ args->gname = gname;
+ args->offset = offset;
+ if ((buf = smb_dr_encode_common(opcode, args, xdr_ntgrp_dr_arg_t,
+ &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ free(args);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ free(args);
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if (rbufp) {
+ if ((*members = smb_dr_decode_grp_memberlist(
+ rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET)) == 0) {
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ rc = NT_STATUS_SUCCESS;
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ (void) close(fd);
+ return (rc);
+}
+
+uint32_t
+smb_group_member_count(char *gname, int *cnt)
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ ntgrp_dr_arg_t *dec_args;
+ uint32_t rc = NT_STATUS_UNSUCCESSFUL;
+ int opcode = SMB_DR_GROUP_MEMBER_COUNT;
+ int fd;
+
+ if ((gname == 0) || (*gname == 0) || (cnt == 0)) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)",
+ smbapi_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (smb_dr_clnt_open(&fd, SMB_DR_SVC_NAME, smbapi_desc[opcode]) == -1)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ /* Encode */
+ if ((buf = smb_dr_encode_string(opcode, gname, &buflen)) == 0) {
+ syslog(LOG_ERR, "%s: Encode error", smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smbapi_desc[opcode]);
+
+ /* Decode Result. */
+ if ((dec_args = (ntgrp_dr_arg_t *)
+ malloc(sizeof (ntgrp_dr_arg_t))) == 0) {
+ syslog(LOG_ERR, "%s: cannot allocate memory",
+ smbapi_desc[opcode]);
+ (void) close(fd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(dec_args, sizeof (ntgrp_dr_arg_t));
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_ntgrp_dr_arg_t, dec_args)
+ != 0) {
+ free(dec_args);
+ (void) close(fd);
+ return (dec_args->ntstatus);
+ }
+ }
+ *cnt = dec_args->count;
+ rc = dec_args->ntstatus;
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ free(dec_args);
+ (void) close(fd);
+ return (rc);
+}
+
+/* Helper functions for local group door service to free up data structures */
+void
+smb_group_free_privlist(ntpriv_list_t *list, int deletelist)
+{
+ int i;
+ if (!list)
+ return;
+ if (list->privs != NULL) {
+ for (i = 0; i < list->cnt; i++) {
+ if (list->privs[i] != NULL) {
+ free(list->privs[i]->name);
+ free(list->privs[i]);
+ }
+ }
+ if (deletelist)
+ free(list);
+ }
+}
+
+void
+smb_group_free_list(ntgrp_list_t *list, int entries_only)
+{
+ int i;
+
+ if (!list) {
+ return;
+ }
+
+ for (i = 0; i < list->cnt; i++) {
+ free(list->groups[i].name);
+ free(list->groups[i].desc);
+ free(list->groups[i].type);
+ free(list->groups[i].sid);
+ }
+ if (!entries_only)
+ free(list);
+}
+
+void
+smb_group_free_memberlist(ntgrp_member_list_t *members,
+ int entries_only)
+{
+ int i;
+
+ if (!members) {
+ return;
+ }
+
+ for (i = 0; i < members->cnt; i++) {
+ free(members->members[i]);
+ }
+ if (!entries_only)
+ free(members);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
new file mode 100644
index 0000000000..d8950616db
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
@@ -0,0 +1,706 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+#include <stdlib.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/codepage.h>
+#include <smbsrv/oem.h>
+#include <smbsrv/ctype.h>
+#include <smbsrv/crypt.h>
+#include <smbsrv/libsmb.h>
+
+extern void randomize(char *data, unsigned len);
+static uint64_t unix_micro_to_nt_time(struct timeval *unix_time);
+
+/*
+ * smb_auth_qnd_unicode
+ *
+ * Quick and dirty unicode conversion!
+ * Returns the length of dst in bytes.
+ */
+int
+smb_auth_qnd_unicode(mts_wchar_t *dst, char *src, int length)
+{
+ int i;
+
+ unsigned int cpid = oem_get_telnet_cpid();
+ unsigned int count;
+ mts_wchar_t new_char;
+
+ if ((count = oemstounicodes(dst, src, length, cpid)) == 0) {
+ for (i = 0; i < length; ++i) {
+ new_char = (mts_wchar_t)src[i] & 0xff;
+ dst[i] = LE_IN16(&new_char);
+ }
+ dst[i] = 0;
+ count = length;
+ }
+
+ return (count * sizeof (mts_wchar_t));
+}
+
+/*
+ * smb_auth_lmupr
+ *
+ * Converts the given LM password to all uppercase.
+ * The standard strupr cannot
+ * be used here because lm_pwd doesn't have to be
+ * nul terminated.
+ */
+static void
+smb_auth_lmupr(unsigned char *lm_pwd)
+{
+ unsigned char *p = lm_pwd;
+ int i;
+
+ for (i = 0; (*p) && (i < SMBAUTH_LM_PWD_SZ); i++) {
+ if (mts_isascii(*p)) {
+ *p = codepage_toupper(*p);
+ p++;
+ }
+ }
+}
+
+/*
+ * smb_auth_lm_hash
+ *
+ * Source: Implementing CIFS (Chris Hertel)
+ *
+ * 1. The password, as entered by user, is either padded with nulls
+ * or trimmed to 14 bytes.
+ * . Note that the 14-byte result string is not handled as a
+ * nul-terminated string.
+ * . The given password is OEM not Unicode
+ *
+ * 2. The 14-byte password is converted to all uppercase
+ *
+ * 3. The result is used as key to encrypt the KGS magic string to
+ * make a 16-byte hash.
+ */
+int
+smb_auth_lm_hash(char *password, unsigned char *lm_hash)
+{
+ unsigned char lm_pwd[SMBAUTH_LM_PWD_SZ];
+
+ bzero((void *)lm_pwd, SMBAUTH_LM_PWD_SZ);
+ (void) strncpy((char *)lm_pwd, password, SMBAUTH_LM_PWD_SZ);
+ smb_auth_lmupr(lm_pwd);
+
+ return (smb_auth_DES(lm_hash, SMBAUTH_HASH_SZ, lm_pwd,
+ SMBAUTH_LM_PWD_SZ, (unsigned char *)SMBAUTH_LM_MAGIC_STR,
+ sizeof (SMBAUTH_LM_MAGIC_STR)));
+}
+
+/*
+ * smb_auth_lm_response
+ *
+ * Create a LM response from the given LM hash and challenge.
+ *
+ * Returns SMBAUTH_FAILURE if any problems occur, SMBAUTH_SUCCESS if
+ * all goes well.
+ */
+static int
+smb_auth_lm_response(unsigned char *hash,
+ unsigned char *challenge, int clen,
+ unsigned char *lm_rsp)
+{
+ unsigned char S21[21];
+
+ /*
+ * 14-byte LM Hash should be padded with 5 nul bytes to create
+ * a 21-byte string to be used in producing LM response
+ */
+ bzero(&S21[SMBAUTH_HASH_SZ], 5);
+ bcopy(hash, S21, SMBAUTH_HASH_SZ);
+
+ /* padded LM Hash -> LM Response */
+ return (smb_auth_DES(lm_rsp, SMBAUTH_LM_RESP_SZ, S21, 21,
+ challenge, clen));
+}
+
+/*
+ * smb_auth_ntlm_hash
+ *
+ * Make NTLM Hash (using MD4) from the given password.
+ * The result will contain a 16-byte NTLM hash.
+ */
+int
+smb_auth_ntlm_hash(char *password, unsigned char *hash)
+{
+ mts_wchar_t *unicode_password;
+ int length;
+ int rc;
+
+ if (password == NULL || hash == NULL)
+ return (SMBAUTH_FAILURE);
+
+ length = strlen(password);
+ unicode_password = (mts_wchar_t *)
+ malloc((length + 1) * sizeof (mts_wchar_t));
+
+ if (unicode_password == NULL)
+ return (SMBAUTH_FAILURE);
+
+ length = smb_auth_qnd_unicode(unicode_password, password, length);
+ rc = smb_auth_md4(hash, (unsigned char *)unicode_password, length);
+
+ free(unicode_password);
+ return (rc);
+}
+
+/*
+ * smb_auth_ntlm_response
+ *
+ * Make LM/NTLM response from the given LM/NTLM Hash and given
+ * challenge.
+ */
+static int
+smb_auth_ntlm_response(unsigned char *hash,
+ unsigned char *challenge, int clen,
+ unsigned char *ntlm_rsp)
+{
+ unsigned char S21[21];
+
+ bcopy(hash, S21, SMBAUTH_HASH_SZ);
+ bzero(&S21[SMBAUTH_HASH_SZ], 5);
+ if (smb_auth_DES((unsigned char *)ntlm_rsp, SMBAUTH_LM_RESP_SZ,
+ S21, 21, challenge, clen) == SMBAUTH_FAILURE)
+ return (0);
+ return (SMBAUTH_LM_RESP_SZ);
+}
+
+/*
+ * smb_auth_gen_data_blob
+ *
+ * Fill the NTLMv2 data blob structure with information as described in
+ * "Implementing CIFS, The Common Internet File System". (pg. 282)
+ */
+static void
+smb_auth_gen_data_blob(smb_auth_data_blob_t *blob, char *ntdomain)
+{
+ struct timeval now;
+
+ (void) memset(blob->ndb_signature, 1, 2);
+ (void) memset(&blob->ndb_signature[2], 0, 2);
+ (void) memset(blob->ndb_reserved, 0, sizeof (blob->ndb_reserved));
+
+ (void) gettimeofday(&now, 0);
+ blob->ndb_timestamp = unix_micro_to_nt_time(&now);
+ randomize((char *)blob->ndb_clnt_challenge,
+ SMBAUTH_V2_CLNT_CHALLENGE_SZ);
+ (void) memset(blob->ndb_unknown, 0, sizeof (blob->ndb_unknown));
+ blob->ndb_names[0].nne_len = smb_auth_qnd_unicode(
+ blob->ndb_names[0].nne_name, ntdomain, strlen(ntdomain));
+ blob->ndb_names[0].nne_type = SMBAUTH_NAME_TYPE_DOMAIN_NETBIOS;
+ blob->ndb_names[1].nne_len = 0;
+ blob->ndb_names[1].nne_type = SMBAUTH_NAME_TYPE_LIST_END;
+ *blob->ndb_names[1].nne_name = 0;
+ (void) memset(blob->ndb_unknown2, 0, sizeof (blob->ndb_unknown2));
+}
+
+/*
+ * smb_auth_memcpy
+ *
+ * It increments the pointer to the destination buffer for the easy of
+ * concatenation.
+ */
+static void
+smb_auth_memcpy(unsigned char **dstbuf,
+ unsigned char *srcbuf,
+ int srcbuf_len)
+{
+ (void) memcpy(*dstbuf, srcbuf, srcbuf_len);
+ *dstbuf += srcbuf_len;
+}
+
+/*
+ * smb_auth_blob_to_string
+ *
+ * Prepare the data blob string which will be used in NTLMv2 response
+ * generation.
+ *
+ * Assumption: Caller must allocate big enough buffer to prevent buffer
+ * overrun.
+ *
+ * Returns the len of the data blob string.
+ */
+static int
+smb_auth_blob_to_string(smb_auth_data_blob_t *blob, unsigned char *data_blob)
+{
+ unsigned char *bufp = data_blob;
+
+ smb_auth_memcpy(&bufp, blob->ndb_signature,
+ sizeof (blob->ndb_signature));
+ smb_auth_memcpy(&bufp, blob->ndb_reserved,
+ sizeof (blob->ndb_reserved));
+ smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_timestamp,
+ sizeof (blob->ndb_timestamp));
+ smb_auth_memcpy(&bufp, blob->ndb_clnt_challenge,
+ SMBAUTH_V2_CLNT_CHALLENGE_SZ);
+ smb_auth_memcpy(&bufp, blob->ndb_unknown, sizeof (blob->ndb_unknown));
+ smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_type,
+ sizeof (blob->ndb_names[0].nne_type));
+ smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_len,
+ sizeof (blob->ndb_names[0].nne_len));
+ smb_auth_memcpy(&bufp, (unsigned char *)blob->ndb_names[0].nne_name,
+ blob->ndb_names[0].nne_len);
+ smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_type,
+ sizeof (blob->ndb_names[1].nne_type));
+ smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_len,
+ sizeof (blob->ndb_names[1].nne_len));
+ smb_auth_memcpy(&bufp, blob->ndb_unknown2, sizeof (blob->ndb_unknown2));
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (bufp - data_blob);
+}
+
+/*
+ * smb_auth_ntlmv2_hash
+ *
+ * The NTLM v2 hash will be created from the given NTLM hash, username,
+ * and the NETBIOS name of the domain.
+ *
+ * The NTLMv2 hash will be returned via the ntlmv2_hash parameter which
+ * will be used in the calculation of the NTLMv2 and LMv2 responses.
+ */
+static int
+smb_auth_ntlmv2_hash(unsigned char *ntlm_hash,
+ char *username,
+ char *ntdomain,
+ unsigned char *ntlmv2_hash)
+{
+ mts_wchar_t *data;
+ int data_len;
+ unsigned char *buf;
+ int rc;
+
+ if (username == NULL || ntdomain == NULL)
+ return (SMBAUTH_FAILURE);
+
+ (void) utf8_strupr(username);
+ (void) utf8_strupr(ntdomain);
+
+ data_len = strlen(username) + strlen(ntdomain);
+ buf = (unsigned char *)malloc((data_len + 1) * sizeof (char));
+ if (buf == NULL)
+ return (SMBAUTH_FAILURE);
+
+ (void) snprintf((char *)buf, data_len + 1, "%s%s", username, ntdomain);
+ data = (mts_wchar_t *)malloc((data_len + 1) * sizeof (mts_wchar_t));
+ if (data == NULL) {
+ free(buf);
+ return (SMBAUTH_FAILURE);
+ }
+
+ data_len = smb_auth_qnd_unicode(data, (char *)buf, data_len);
+ rc = SMBAUTH_HMACT64((unsigned char *)data, data_len, ntlm_hash,
+ SMBAUTH_HASH_SZ, ntlmv2_hash);
+
+ free(buf);
+ free(data);
+ return (rc);
+}
+
+/*
+ * smb_auth_v2_response
+ *
+ * Caculates either the LMv2 or NTLMv2 response.
+ *
+ * Same algorithm is used for calculating both LMv2 or NTLMv2 responses.
+ * This routine will return NTLMv2 response if the data blob information
+ * is passed in as the clnt_data. Otherwise, it will return LMv2 response
+ * with the 8-byte client challenge(a.k.a blip) as the clnt_data.
+ *
+ * (LM/NTLM)v2 response is the hmac-md5 hash of the specified data
+ * (server challenge + NTLMv2 data blob or LMv2 client challenge)
+ * using the NTLMv2 hash as the key.
+ *
+ * Returns the size of the corresponding v2 response upon success.
+ * Otherwise, returns -1 on error.
+ */
+static int
+smb_auth_v2_response(
+ unsigned char *hash,
+ unsigned char *srv_challenge, int slen,
+ unsigned char *clnt_data, int clen,
+ unsigned char *v2_rsp)
+{
+ unsigned char *hmac_data;
+
+ hmac_data = (unsigned char *)malloc((slen + clen) * sizeof (char));
+ if (!hmac_data) {
+ return (-1);
+ }
+
+ (void) memcpy(hmac_data, srv_challenge, slen);
+ (void) memcpy(&hmac_data[slen], clnt_data, clen);
+ if (SMBAUTH_HMACT64(hmac_data, slen + clen, (unsigned char *)hash,
+ SMBAUTH_HASH_SZ, (unsigned char *)v2_rsp) != SMBAUTH_SUCCESS)
+ return (-1);
+ (void) memcpy(&v2_rsp[SMBAUTH_HASH_SZ], clnt_data, clen);
+
+ free(hmac_data);
+ return (SMBAUTH_HASH_SZ + clen);
+}
+
+/*
+ * smb_auth_set_info
+ *
+ * Fill the smb_auth_info instance with either NTLM or NTLMv2 related
+ * authentication information based on the LMCompatibilityLevel.
+ *
+ * If the LMCompatibilityLevel equals 2, the SMB Redirector will perform
+ * NTLM challenge/response authentication which requires the NTLM hash and
+ * NTLM response.
+ *
+ * If the LMCompatibilityLevel is 3 or above, the SMB Redirector will
+ * perfrom NTLMv2 challenge/response authenticatoin which requires the
+ * NTLM hash, NTLMv2 hash, NTLMv2 response and LMv2 response.
+ *
+ * Returns -1 on error. Otherwise, returns 0 upon success.
+ */
+int
+smb_auth_set_info(char *username,
+ char *password,
+ unsigned char *ntlm_hash,
+ char *domain,
+ unsigned char *srv_challenge_key,
+ int srv_challenge_len,
+ int lmcomp_lvl,
+ smb_auth_info_t *auth)
+{
+ unsigned short blob_len;
+ unsigned char blob_buf[SMBAUTH_BLOB_MAXLEN];
+ int rc;
+
+ auth->lmcompatibility_lvl = lmcomp_lvl;
+ if (lmcomp_lvl == 2) {
+ auth->ci_len = 0;
+ *auth->ci = 0;
+ if (!ntlm_hash) {
+ if (smb_auth_ntlm_hash(password, auth->hash) !=
+ SMBAUTH_SUCCESS)
+ return (-1);
+ } else {
+ (void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
+ }
+
+ auth->cs_len = smb_auth_ntlm_response(auth->hash,
+ srv_challenge_key, srv_challenge_len, auth->cs);
+ } else {
+ if (!ntlm_hash) {
+ if (smb_auth_ntlm_hash(password, auth->hash) !=
+ SMBAUTH_SUCCESS)
+ return (-1);
+ } else {
+ (void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
+ }
+
+ if (smb_auth_ntlmv2_hash(auth->hash, username,
+ domain, auth->hash_v2) != SMBAUTH_SUCCESS)
+ return (-1);
+
+ /* generate data blob */
+ smb_auth_gen_data_blob(&auth->data_blob, domain);
+ blob_len = smb_auth_blob_to_string(&auth->data_blob, blob_buf);
+
+ /* generate NTLMv2 response */
+ rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key,
+ srv_challenge_len, blob_buf, blob_len, auth->cs);
+
+ if (rc < 0)
+ return (-1);
+
+ auth->cs_len = rc;
+
+ /* generate LMv2 response */
+ rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key,
+ srv_challenge_len, auth->data_blob.ndb_clnt_challenge,
+ SMBAUTH_V2_CLNT_CHALLENGE_SZ, auth->ci);
+
+ if (rc < 0)
+ return (-1);
+
+ auth->ci_len = rc;
+ }
+
+ return (0);
+}
+
+/*
+ * smb_auth_gen_session_key
+ *
+ * Generate the NTLM user session key if LMCompatibilityLevel is 2 or
+ * NTLMv2 user session key if LMCompatibilityLevel is 3 or above.
+ *
+ * NTLM_Session_Key = MD4(NTLM_Hash);
+ *
+ * NTLMv2_Session_Key = HMAC_MD5(NTLMv2Hash, 16, NTLMv2_HMAC, 16)
+ *
+ * Prior to calling this function, the auth instance should be set
+ * via smb_auth_set_info().
+ *
+ * Returns the appropriate session key.
+ */
+int
+smb_auth_gen_session_key(smb_auth_info_t *auth, unsigned char *session_key)
+{
+ int rc;
+
+ if (auth->lmcompatibility_lvl == 2)
+ rc = smb_auth_md4(session_key, auth->hash, SMBAUTH_HASH_SZ);
+ else
+ rc = SMBAUTH_HMACT64((unsigned char *)auth->cs,
+ SMBAUTH_HASH_SZ, (unsigned char *)auth->hash_v2,
+ SMBAUTH_SESSION_KEY_SZ, session_key);
+
+ return (rc);
+}
+
+/* 100's of ns between 1/1/1970 and 1/1/1601 */
+#define NT_TIME_BIAS (134774LL * 24LL * 60LL * 60LL * 10000000LL)
+
+static uint64_t
+unix_micro_to_nt_time(struct timeval *unix_time)
+{
+ uint64_t nt_time;
+
+ nt_time = unix_time->tv_sec;
+ nt_time *= 10000000; /* seconds to 100ns */
+ nt_time += unix_time->tv_usec * 10;
+ return (nt_time + NT_TIME_BIAS);
+}
+
+static boolean_t
+smb_lm_password_ok(
+ unsigned char *challenge,
+ uint32_t clen,
+ unsigned char *lm_hash,
+ unsigned char *passwd)
+{
+ unsigned char lm_resp[SMBAUTH_LM_RESP_SZ];
+ int rc;
+
+ rc = smb_auth_lm_response(lm_hash, challenge, clen, lm_resp);
+ if (rc != SMBAUTH_SUCCESS)
+ return (B_FALSE);
+
+ return (bcmp(lm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
+}
+
+static boolean_t
+smb_ntlm_password_ok(
+ unsigned char *challenge,
+ uint32_t clen,
+ unsigned char *ntlm_hash,
+ unsigned char *passwd)
+{
+ unsigned char ntlm_resp[SMBAUTH_LM_RESP_SZ];
+ int rc;
+
+ rc = smb_auth_ntlm_response(ntlm_hash, challenge, clen, ntlm_resp);
+
+ if (rc != SMBAUTH_LM_RESP_SZ)
+ return (B_FALSE);
+
+ return (bcmp(ntlm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
+}
+
+static boolean_t
+smb_ntlmv2_password_ok(
+ unsigned char *challenge,
+ uint32_t clen,
+ unsigned char *ntlm_hash,
+ unsigned char *passwd,
+ int pwdlen,
+ char *username)
+{
+ unsigned char *clnt_blob;
+ int clnt_blob_len;
+ unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
+ unsigned char *ntlmv2_resp;
+ boolean_t ok;
+
+ clnt_blob_len = pwdlen - SMBAUTH_HASH_SZ;
+ clnt_blob = &passwd[SMBAUTH_HASH_SZ];
+
+ /*
+ * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
+ *
+ * * The NTLMv2 Hash is created from:
+ * - NTLM hash
+ * - user's username, and
+ * - the name of the logon destination(i.e. the NetBIOS name of either
+ * the SMB server or NT Domain against which the suer is trying to
+ * authenticate.
+ *
+ * (N.L.) With my experience, this is not exactly true. It's really
+ * tricky how the NTLMv2 hash is generated by the Windows client when
+ * logging into a standalone server using NTLMv2 challenge / response.
+ * The NTLMv2 hash is actually created with the destination info=""
+ * as opposed to the SMB server name mentioned in the book.
+ */
+ if (smb_auth_ntlmv2_hash(ntlm_hash, username, "", ntlmv2_hash) !=
+ SMBAUTH_SUCCESS) {
+ return (B_FALSE);
+ }
+
+ ntlmv2_resp = (unsigned char *)malloc(SMBAUTH_HASH_SZ + clnt_blob_len);
+ if (ntlmv2_resp == NULL)
+ return (B_FALSE);
+
+ if (smb_auth_v2_response(ntlmv2_hash, challenge,
+ clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0) {
+ free(ntlmv2_resp);
+ return (B_FALSE);
+ }
+
+ ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
+
+ free(ntlmv2_resp);
+ return (ok);
+}
+
+static int
+smb_lmv2_password_ok(
+ unsigned char *challenge,
+ uint32_t clen,
+ unsigned char *ntlm_hash,
+ unsigned char *passwd,
+ char *username)
+{
+ unsigned char *clnt_challenge;
+ unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
+ unsigned char lmv2_resp[SMBAUTH_LM_RESP_SZ];
+
+ clnt_challenge = &passwd[SMBAUTH_HASH_SZ];
+
+ /*
+ * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
+ *
+ * The NTLMv2 Hash is created from:
+ * - NTLM hash
+ * - user's username, and
+ * - the name of the logon destination(i.e. the NetBIOS name of either
+ * the SMB server or NT Domain against which the suer is trying to
+ * authenticate.
+ *
+ * (N.L.) With my experience, this is not exactly true. It's really
+ * tricky how the NTLMv2 hash is generated by the Windows client when
+ * logging into a standalone server using LMv2 challenge/response.
+ * The NTLMv2 hash is actually created with the destination info = ""
+ * as opposed to the SMB server name mentioned in the book.
+ */
+ if (smb_auth_ntlmv2_hash(ntlm_hash, username, "", ntlmv2_hash) !=
+ SMBAUTH_SUCCESS) {
+ return (B_FALSE);
+ }
+ if (smb_auth_v2_response(ntlmv2_hash, challenge,
+ clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ,
+ lmv2_resp) < 0) {
+ return (B_FALSE);
+ }
+
+ return (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0);
+}
+
+/*
+ * smb_auth_validate_lm
+ *
+ * Validates given LM/LMv2 client response, passed in passwd arg, against
+ * stored user's password, passed in smbpw
+ *
+ * If LM level <=3 server accepts LM responses, otherwise LMv2
+ */
+boolean_t
+smb_auth_validate_lm(
+ unsigned char *challenge,
+ uint32_t clen,
+ smb_passwd_t *smbpw,
+ unsigned char *passwd,
+ int pwdlen,
+ char *username)
+{
+ int lmlevel;
+ boolean_t ok = B_FALSE;
+
+ if (pwdlen != SMBAUTH_LM_RESP_SZ)
+ return (B_FALSE);
+
+ smb_config_rdlock();
+ lmlevel = smb_config_getnum(SMB_CI_LM_LEVEL);
+ smb_config_unlock();
+
+ if (lmlevel <= 3) {
+ ok = smb_lm_password_ok(challenge, clen, smbpw->pw_lmhash,
+ passwd);
+ }
+
+ if (!ok)
+ ok = smb_lmv2_password_ok(challenge, clen, smbpw->pw_nthash,
+ passwd, username);
+
+ return (ok);
+}
+
+/*
+ * smb_auth_validate_nt
+ *
+ * Validates given NTLM/NTLMv2 client response, passed in passwd arg, against
+ * stored user's password, passed in smbpw
+ *
+ * If LM level <=4 server accepts NTLM/NTLMv2 responses, otherwise only NTLMv2
+ */
+boolean_t
+smb_auth_validate_nt(
+ unsigned char *challenge,
+ uint32_t clen,
+ smb_passwd_t *smbpw,
+ unsigned char *passwd,
+ int pwdlen,
+ char *username)
+{
+ int lmlevel;
+ boolean_t ok;
+
+ smb_config_rdlock();
+ lmlevel = smb_config_getnum(SMB_CI_LM_LEVEL);
+ smb_config_unlock();
+
+ if ((lmlevel == 5) && (pwdlen <= SMBAUTH_LM_RESP_SZ))
+ return (B_FALSE);
+
+ if (pwdlen > SMBAUTH_LM_RESP_SZ)
+ ok = smb_ntlmv2_password_ok(challenge, clen,
+ smbpw->pw_nthash, passwd, pwdlen, username);
+ else
+ ok = smb_ntlm_password_ok(challenge, clen,
+ smbpw->pw_nthash, passwd);
+
+ return (ok);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
new file mode 100644
index 0000000000..844789e367
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
@@ -0,0 +1,1090 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * CIFS configuration management library
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <synch.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <libscf.h>
+#include <smbsrv/libsmb.h>
+
+typedef struct smb_cfg_param {
+ char *sc_pg;
+ char *sc_name;
+ int sc_type;
+ char *sc_value;
+ uint32_t sc_flags;
+} smb_cfg_param_t;
+
+/*
+ * config parameter flags
+ */
+#define SMB_CF_NOTINIT 0x00 /* Not initialized yet */
+#define SMB_CF_DEFINED 0x01 /* Defined/read from env */
+#define SMB_CF_MODIFIED 0x02 /* Has been modified */
+#define SMB_CF_SYSTEM 0x04 /* system; not part of cifs config */
+
+#define SMB_CL_NONE 0
+#define SMB_CL_READ 1
+#define SMB_CL_WRITE 2
+
+/* idmap SMF fmri and Property Group */
+#define IDMAP_FMRI_PREFIX "system/idmap"
+#define MACHINE_SID "machine_sid"
+#define MAPPING_DOMAIN "mapping_domain"
+#define GLOBAL_CATALOG "global_catalog"
+#define IDMAP_PG_NAME "config"
+
+#define SMB_SECMODE_WORKGRP_STR "workgroup"
+#define SMB_SECMODE_DOMAIN_STR "domain"
+
+#define SMB_ENC_LEN 1024
+#define SMB_DEC_LEN 256
+
+static char *b64_data =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static rwlock_t smb_cfg_rwlk;
+static int lock_type = SMB_CL_NONE;
+
+/*
+ * IMPORTANT: any changes to the order of this table's entries
+ * need to be reflected in smb_cfg_id_t enum in libsmb.h
+ */
+static smb_cfg_param_t smb_cfg_table[] =
+{
+ /* Redirector configuration, User space */
+ {SMBD_PG_NAME, SMB_CD_RDR_IPCMODE, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PROTECTED_PG_NAME, SMB_CD_RDR_IPCUSER,
+ SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PROTECTED_PG_NAME, SMB_CD_RDR_IPCPWD,
+ SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+
+ /* Oplock configuration, Kernel Only */
+ {SMBD_PG_NAME, SMB_CD_OPLOCK_ENABLE,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_OPLOCK_TIMEOUT,
+ SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+
+ /* Autohome configuration */
+ {SMBD_PG_NAME, SMB_CD_AUTOHOME_MAP,
+ SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+
+ /* Domain/PDC configuration */
+ {SMBD_PG_NAME, SMB_CD_DOMAIN_SID, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_DOMAIN_MEMB, SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_DOMAIN_NAME, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_DOMAIN_SRV, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+
+ /* WINS configuration */
+ {SMBD_PG_NAME, SMB_CD_WINS_SRV1, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_WINS_SRV2, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_WINS_EXCL, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+
+ /* RPC services configuration */
+ {SMBD_PG_NAME, SMB_CD_SRVSVC_SHRSET_ENABLE,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_LOGR_ENABLE, SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_MLRPC_KALIVE,
+ SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+
+ /* Kmod specific configuration */
+ {SMBD_PG_NAME, SMB_CD_MAX_BUFSIZE, SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_MAX_WORKERS, SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_MAX_CONNECTIONS,
+ SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_KEEPALIVE, SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_RESTRICT_ANON,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+
+ {SMBD_PG_NAME, SMB_CD_SIGNING_ENABLE,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_SIGNING_REQD,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_SIGNING_CHECK,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+
+ /* Kmod tuning configuration */
+ {SMBD_PG_NAME, SMB_CD_FLUSH_REQUIRED,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_SYNC_ENABLE, SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_DIRSYMLINK_DISABLE,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_ANNONCE_QUOTA,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+
+ /* SMBd configuration */
+ {SMBD_PG_NAME, SMB_CD_SECURITY, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_NBSCOPE, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_SYS_CMNT, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_LM_LEVEL, SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_MSDCS_DISABLE,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+
+ /* ADS Configuration */
+ {SMBD_PG_NAME, SMB_CD_ADS_ENABLE, SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PROTECTED_PG_NAME, SMB_CD_ADS_USER,
+ SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PROTECTED_PG_NAME, SMB_CD_ADS_PASSWD,
+ SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_ADS_DOMAIN, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_ADS_USER_CONTAINER,
+ SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_ADS_SITE, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_ADS_IPLOOKUP,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+
+ /* Dynamic DNS */
+ {SMBD_PG_NAME, SMB_CD_DYNDNS_ENABLE,
+ SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_DYNDNS_RETRY_COUNT,
+ SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+ {SMBD_PG_NAME, SMB_CD_DYNDNS_RETRY_SEC,
+ SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
+
+ {SMBD_PROTECTED_PG_NAME, SMB_CD_MACHINE_PASSWD,
+ SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT}
+ /* SMB_CI_MAX */
+};
+
+static boolean_t smb_is_base64(unsigned char c);
+static char *smb_base64_encode(char *str_to_encode);
+static char *smb_base64_decode(char *encoded_str);
+static int smb_config_update(smb_cfg_param_t *cfg, char *value);
+static int smb_config_save_all();
+static int smb_config_save(char *pgname);
+
+static boolean_t
+smb_is_base64(unsigned char c)
+{
+ return (isalnum(c) || (c == '+') || (c == '/'));
+}
+
+/*
+ * smb_base64_encode
+ *
+ * Encode a string using base64 algorithm.
+ * Caller should free the returned buffer when done.
+ */
+static char *
+smb_base64_encode(char *str_to_encode)
+{
+ int ret_cnt = 0;
+ int i = 0, j = 0;
+ char arr_3[3], arr_4[4];
+ int len = strlen(str_to_encode);
+ char *ret = malloc(SMB_ENC_LEN);
+
+ if (ret == NULL) {
+ return (NULL);
+ }
+
+ while (len--) {
+ arr_3[i++] = *(str_to_encode++);
+ if (i == 3) {
+ arr_4[0] = (arr_3[0] & 0xfc) >> 2;
+ arr_4[1] = ((arr_3[0] & 0x03) << 4) +
+ ((arr_3[1] & 0xf0) >> 4);
+ arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
+ ((arr_3[2] & 0xc0) >> 6);
+ arr_4[3] = arr_3[2] & 0x3f;
+
+ for (i = 0; i < 4; i++)
+ ret[ret_cnt++] = b64_data[arr_4[i]];
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j < 3; j++)
+ arr_3[j] = '\0';
+
+ arr_4[0] = (arr_3[0] & 0xfc) >> 2;
+ arr_4[1] = ((arr_3[0] & 0x03) << 4) +
+ ((arr_3[1] & 0xf0) >> 4);
+ arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
+ ((arr_3[2] & 0xc0) >> 6);
+ arr_4[3] = arr_3[2] & 0x3f;
+
+ for (j = 0; j < (i + 1); j++)
+ ret[ret_cnt++] = b64_data[arr_4[j]];
+
+ while (i++ < 3)
+ ret[ret_cnt++] = '=';
+ }
+
+ ret[ret_cnt++] = '\0';
+ return (ret);
+}
+
+/*
+ * smb_base64_decode
+ *
+ * Decode using base64 algorithm.
+ * Caller should free the returned buffer when done.
+ */
+static char *
+smb_base64_decode(char *encoded_str)
+{
+ int len = strlen(encoded_str);
+ int i = 0, j = 0;
+ int en_ind = 0;
+ char arr_4[4], arr_3[3];
+ int ret_cnt = 0;
+ char *ret = malloc(SMB_DEC_LEN);
+ char *p;
+
+ if (ret == NULL) {
+ return (NULL);
+ }
+
+ while (len-- && (encoded_str[en_ind] != '=') &&
+ smb_is_base64(encoded_str[en_ind])) {
+ arr_4[i++] = encoded_str[en_ind];
+ en_ind++;
+ if (i == 4) {
+ for (i = 0; i < 4; i++) {
+ if ((p = strchr(b64_data, arr_4[i])) == NULL)
+ return (NULL);
+
+ arr_4[i] = (int)(p - b64_data);
+ }
+
+ arr_3[0] = (arr_4[0] << 2) +
+ ((arr_4[1] & 0x30) >> 4);
+ arr_3[1] = ((arr_4[1] & 0xf) << 4) +
+ ((arr_4[2] & 0x3c) >> 2);
+ arr_3[2] = ((arr_4[2] & 0x3) << 6) +
+ arr_4[3];
+
+ for (i = 0; i < 3; i++)
+ ret[ret_cnt++] = arr_3[i];
+
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j < 4; j++)
+ arr_4[j] = 0;
+
+ for (j = 0; j < 4; j++) {
+ if ((p = strchr(b64_data, arr_4[j])) == NULL)
+ return (NULL);
+
+ arr_4[j] = (int)(p - b64_data);
+ }
+ arr_3[0] = (arr_4[0] << 2) +
+ ((arr_4[1] & 0x30) >> 4);
+ arr_3[1] = ((arr_4[1] & 0xf) << 4) +
+ ((arr_4[2] & 0x3c) >> 2);
+ arr_3[2] = ((arr_4[2] & 0x3) << 6) +
+ arr_4[3];
+ for (j = 0; j < (i - 1); j++)
+ ret[ret_cnt++] = arr_3[j];
+ }
+
+ ret[ret_cnt++] = '\0';
+ return (ret);
+}
+
+/*
+ * Basically commit the transaction.
+ */
+static int
+smb_config_saveenv(smb_scfhandle_t *handle)
+{
+ int ret = 0;
+
+ ret = smb_smf_end_transaction(handle);
+
+ smb_smf_scf_fini(handle);
+ return (ret);
+}
+
+/*
+ * smb_config_getenv
+ *
+ * Get the property value from SMF.
+ */
+char *
+smb_config_getenv(smb_cfg_id_t id)
+{
+ smb_scfhandle_t *handle;
+ char *value;
+
+ if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
+ return (NULL);
+
+ handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
+ if (handle == NULL) {
+ free(value);
+ return (NULL);
+ }
+
+ (void) smb_smf_create_service_pgroup(handle, smb_cfg_table[id].sc_pg);
+
+ if (smb_smf_get_property(handle, smb_cfg_table[id].sc_type,
+ smb_cfg_table[id].sc_name, value,
+ sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
+ smb_smf_scf_fini(handle);
+ free(value);
+ return (NULL);
+ }
+
+ smb_smf_scf_fini(handle);
+ return (value);
+}
+
+/*
+ * smb_config_getenv_dec
+ *
+ * For protected property, the value obtained from SMF will be decoded.
+ * The decoded property value will be returned.
+ *
+ * This function should only be called by smb_config_load to populate
+ * the SMB config cache.
+ */
+static char *
+smb_config_getenv_dec(smb_cfg_id_t id)
+{
+ smb_scfhandle_t *handle;
+ char *value;
+ char *dec;
+
+ if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
+ return (NULL);
+
+ handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
+ if (handle == NULL) {
+ free(value);
+ return (NULL);
+ }
+
+ (void) smb_smf_create_service_pgroup(handle, smb_cfg_table[id].sc_pg);
+
+ if (smb_smf_get_property(handle, smb_cfg_table[id].sc_type,
+ smb_cfg_table[id].sc_name, value,
+ sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
+ smb_smf_scf_fini(handle);
+ free(value);
+ return (NULL);
+ }
+ smb_smf_scf_fini(handle);
+ if (strcmp(smb_cfg_table[id].sc_pg, SMBD_PROTECTED_PG_NAME))
+ return (value);
+
+ if (!value)
+ return (NULL);
+
+ if (*value == '\0') {
+ free(value);
+ return (NULL);
+ }
+
+ dec = smb_base64_decode(value);
+ free(value);
+ return (dec);
+}
+
+static char *
+smb_config_getenv_generic(char *name, char *svc_fmri_prefix, char *svc_propgrp)
+{
+ smb_scfhandle_t *handle;
+ char *value;
+
+ if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
+ return (NULL);
+
+ handle = smb_smf_scf_init(svc_fmri_prefix);
+ if (handle == NULL) {
+ free(value);
+ return (NULL);
+ }
+
+ (void) smb_smf_create_service_pgroup(handle, svc_propgrp);
+
+ if (smb_smf_get_string_property(handle, name, value,
+ sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
+ smb_smf_scf_fini(handle);
+ free(value);
+ return (NULL);
+ }
+
+ smb_smf_scf_fini(handle);
+ return (value);
+
+}
+
+int
+smb_config_setenv_generic(char *svc_fmri_prefix, char *svc_propgrp,
+ char *name, char *value)
+{
+ smb_scfhandle_t *handle = NULL;
+ int rc = 0;
+
+
+ handle = smb_smf_scf_init(svc_fmri_prefix);
+ if (handle == NULL) {
+ return (1);
+ }
+
+ (void) smb_smf_create_service_pgroup(handle, svc_propgrp);
+
+ if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
+ smb_smf_scf_fini(handle);
+ return (1);
+ }
+
+ if (smb_smf_set_string_property(handle, name, value) != SMBD_SMF_OK)
+ rc = 1;
+
+ if (smb_smf_end_transaction(handle) != SMBD_SMF_OK)
+ rc = 1;
+
+ smb_smf_scf_fini(handle);
+ return (rc);
+}
+
+/*
+ * smb_config_setenv
+ *
+ * For protected properties, the value will be encoded using base64
+ * algorithm. The encoded string will be stored in SMF.
+ */
+int
+smb_config_setenv(smb_cfg_id_t id, char *value)
+{
+ smb_scfhandle_t *handle = NULL;
+ char *enc = NULL;
+ int is_protected = 0;
+
+ if ((id >= SMB_CI_MAX) || (id < 0)) {
+ return (1);
+ }
+
+ handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
+ if (handle == NULL) {
+ return (1);
+ }
+
+ (void) smb_smf_create_service_pgroup(handle, smb_cfg_table[id].sc_pg);
+
+ if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
+ smb_smf_scf_fini(handle);
+ return (1);
+ }
+
+ if (strcmp(smb_cfg_table[id].sc_pg, SMBD_PROTECTED_PG_NAME) == 0) {
+ if ((value == NULL) || (*value == '\0')) {
+ (void) smb_smf_end_transaction(handle);
+ smb_smf_scf_fini(handle);
+ return (1);
+ }
+
+ if ((enc = smb_base64_encode(value)) == NULL) {
+ (void) smb_smf_end_transaction(handle);
+ smb_smf_scf_fini(handle);
+ return (1);
+ }
+
+ is_protected = 1;
+ }
+
+ if (smb_smf_set_property(handle, smb_cfg_table[id].sc_type,
+ smb_cfg_table[id].sc_name, is_protected ? enc : value)
+ != SMBD_SMF_OK) {
+ if (enc)
+ free(enc);
+ (void) smb_smf_end_transaction(handle);
+ smb_smf_scf_fini(handle);
+ return (1);
+ }
+
+ if (enc)
+ free(enc);
+
+ if (smb_smf_end_transaction(handle) != SMBD_SMF_OK) {
+ smb_smf_scf_fini(handle);
+ return (1);
+ }
+
+ smb_smf_scf_fini(handle);
+ return (0);
+}
+
+static void
+smb_config_setenv_trans(smb_scfhandle_t *handle, int type,
+ char *name, char *value)
+{
+ if (smb_smf_set_property(handle, type, name, value) != SMBD_SMF_OK) {
+ syslog(LOG_ERR, "Failed to save service property %s", name);
+ }
+}
+
+/*
+ * smb_config_setenv_trans_protected
+ *
+ * This function should only be called to set protected properties
+ * in SMF. The argument 'value' will be encoded using base64 algorithm.
+ * The encoded string will be stored in SMF.
+ */
+static void
+smb_config_setenv_trans_protected(smb_scfhandle_t *handle, char *name,
+ char *value)
+{
+ char *enc;
+
+ if ((value == NULL) || (*value == '\0'))
+ return;
+
+ if ((enc = smb_base64_encode(value)) == NULL)
+ return;
+
+ if (smb_smf_set_string_property(handle, name, enc) != SMBD_SMF_OK) {
+ syslog(LOG_ERR, "Failed to save service protected property"
+ " %s", name);
+ }
+
+ free(enc);
+}
+
+int
+smb_config_unsetenv(smb_cfg_id_t id)
+{
+ smb_scfhandle_t *handle = NULL;
+ int ret = 1;
+
+ handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
+ if (handle == NULL) {
+ return (ret);
+ }
+
+ (void) smb_smf_create_service_pgroup(handle, smb_cfg_table[id].sc_pg);
+ if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
+ smb_smf_scf_fini(handle);
+ return (ret);
+ }
+ ret = smb_smf_delete_property(handle, smb_cfg_table[id].sc_name);
+ (void) smb_smf_end_transaction(handle);
+
+ smb_smf_scf_fini(handle);
+ return (ret);
+}
+
+static int
+smb_config_unsetenv_trans(smb_scfhandle_t *handle, char *name)
+{
+ return (smb_smf_delete_property(handle, name));
+}
+
+/*
+ * smb_config_load
+ *
+ * Loads all the CIFS configuration parameters and sets up the
+ * config table.
+ */
+int
+smb_config_load()
+{
+ smb_cfg_id_t id;
+ smb_cfg_param_t *cfg;
+ char *value;
+
+ (void) rw_rdlock(&smb_cfg_rwlk);
+ for (id = 0; id < SMB_CI_MAX; id++) {
+ value = smb_config_getenv_dec(id);
+ cfg = &smb_cfg_table[id];
+ /*
+ * enval == 0 could mean two things, either the
+ * config param is not defined, or it has been
+ * removed. If the variable has already been defined
+ * and now enval is 0, it should be removed, otherwise
+ * we don't need to do anything in this case.
+ */
+ if ((cfg->sc_flags & SMB_CF_DEFINED) || value) {
+ if (smb_config_update(cfg, value) != 0) {
+ (void) rw_unlock(&smb_cfg_rwlk);
+ if (value)
+ free(value);
+ return (1);
+ }
+ }
+ if (value) {
+ free(value);
+ }
+ }
+
+ (void) rw_unlock(&smb_cfg_rwlk);
+
+ return (0);
+}
+
+/*
+ * smb_config_get
+ *
+ * Returns value of the specified config param.
+ * The return value is a string pointer to the locally
+ * allocated memory if the config param is defined
+ * otherwise it would be NULL.
+ *
+ * This function MUST be called after a smb_config_rd/wrlock
+ * function. Caller MUST NOT modify the returned buffer directly.
+ */
+char *
+smb_config_get(smb_cfg_id_t id)
+{
+ if (id < SMB_CI_MAX)
+ return (smb_cfg_table[id].sc_value);
+
+ return (0);
+}
+
+/*
+ * smb_config_getstr
+ *
+ * Returns value of the specified config param.
+ * The returned pointer never will be NULL if the given
+ * 'id' is valid. If the config param is not defined its
+ * default value will be returned.
+ *
+ * This function MUST be called after a smb_config_rd/wrlock
+ * function. Caller MUST NOT modify the returned buffer directly.
+ */
+char *
+smb_config_getstr(smb_cfg_id_t id)
+{
+ smb_cfg_param_t *cfg;
+
+ if (id < SMB_CI_MAX) {
+ cfg = &smb_cfg_table[id];
+ if (cfg->sc_value)
+ return (cfg->sc_value);
+ }
+
+ return (NULL);
+}
+
+/*
+ * smb_config_getnum
+ *
+ * Returns the value of a numeric config param.
+ * If the config param is not defined it'll return the
+ * default value.
+ *
+ * This function MUST be called after a smb_config_rd/wrlock
+ * function.
+ */
+uint32_t
+smb_config_getnum(smb_cfg_id_t id)
+{
+ smb_cfg_param_t *cfg;
+ char *strval = NULL;
+
+ if (id < SMB_CI_MAX) {
+ cfg = &smb_cfg_table[id];
+ if (cfg->sc_value)
+ strval = cfg->sc_value;
+
+ if (strval)
+ return (strtol(strval, 0, 10));
+ }
+
+ return (0);
+}
+
+/*
+ * smb_config_getyorn
+ *
+ * Returns the value of a yes/no config param.
+ * Returns 1 is config is set to "yes", otherwise 0.
+ *
+ * This function MUST be called after a smb_config_rd/wrlock
+ * function.
+ */
+int
+smb_config_getyorn(smb_cfg_id_t id)
+{
+ char *val;
+
+ val = smb_config_get(id);
+ if (val) {
+ if (strcasecmp(val, "true") == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_config_set
+ *
+ * Set/update the specified config param with the given
+ * value. If the value is NULL the config param will be
+ * unset as if it is not defined.
+ *
+ * This function MUST be called after a smb_config_wrlock
+ * function.
+ */
+int
+smb_config_set(smb_cfg_id_t id, char *value)
+{
+ smb_cfg_param_t *cfg;
+ int rc = 0;
+
+ if (id < SMB_CI_MAX) {
+ cfg = &smb_cfg_table[id];
+ rc = smb_config_update(cfg, value);
+ if (rc == 0)
+ cfg->sc_flags |= SMB_CF_MODIFIED;
+ return (rc);
+ }
+
+ return (1);
+}
+
+/*
+ * smb_config_setnum
+ *
+ * Set/update the specified config param with the given
+ * value. This is used for numeric config params. The given
+ * number will be converted to string before setting the
+ * config param.
+ *
+ * This function MUST be called after a smb_config_wrlock
+ * function.
+ */
+int
+smb_config_setnum(smb_cfg_id_t id, uint32_t num)
+{
+ smb_cfg_param_t *cfg;
+ char value[32];
+ int rc = 0;
+
+ if (id < SMB_CI_MAX) {
+ cfg = &smb_cfg_table[id];
+ (void) snprintf(value, sizeof (value), "%u", num);
+ rc = smb_config_update(cfg, value);
+ if (rc == 0)
+ cfg->sc_flags |= SMB_CF_MODIFIED;
+ return (rc);
+ }
+
+ return (1);
+}
+
+/*
+ * smb_config_rdlock
+ *
+ * Lock the config table for read access.
+ * This function MUST be called before any kind of
+ * read access to the config table i.e. all flavors of
+ * smb_config_get function
+ */
+void
+smb_config_rdlock()
+{
+ (void) rw_rdlock(&smb_cfg_rwlk);
+ lock_type = SMB_CL_READ;
+}
+
+/*
+ * smb_config_wrlock
+ *
+ * Lock the config table for write access.
+ * This function MUST be called before any kind of
+ * write access to the config table i.e. all flavors of
+ * smb_config_set function
+ */
+void
+smb_config_wrlock()
+{
+ (void) rw_wrlock(&smb_cfg_rwlk);
+ lock_type = SMB_CL_WRITE;
+}
+
+/*
+ * smb_config_wrlock
+ *
+ * Unlock the config table.
+ * If the config table has been locked for write access
+ * smb_config_save_all() will be called to save the changes
+ * before unlocking the table.
+ *
+ * This function MUST be called after smb_config_rd/wrlock
+ */
+void
+smb_config_unlock()
+{
+ if (lock_type == SMB_CL_WRITE)
+ (void) smb_config_save_all();
+ (void) rw_unlock(&smb_cfg_rwlk);
+}
+
+/*
+ * smb_config_save_all
+ *
+ * Save all modified parameters to SMF.
+ */
+static int
+smb_config_save_all()
+{
+ int rc;
+
+ if ((rc = smb_config_save(SMBD_PG_NAME)) != 0)
+ return (rc);
+
+ return (smb_config_save(SMBD_PROTECTED_PG_NAME));
+}
+
+/*
+ * smb_config_save
+ *
+ * Scan the config table and call smb_config_setenv/smb_config_unsetenv
+ * for params in the specified property group that has been modified.
+ * When the scan is finished, smb_config_saveenv() will be called to
+ * make the changes persistent.
+ */
+static int
+smb_config_save(char *pgname)
+{
+ smb_cfg_id_t id;
+ smb_cfg_param_t *cfg;
+ smb_scfhandle_t *handle = NULL;
+ int dorefresh = 0;
+
+ handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
+ if (handle == NULL) {
+ syslog(LOG_ERR, "smbd: cannot save configuration");
+ return (1);
+ }
+
+ (void) smb_smf_create_service_pgroup(handle, pgname);
+ if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
+ syslog(LOG_ERR, "smbd: cannot save configuration");
+ return (1);
+ }
+
+ for (id = 0; id < SMB_CI_MAX; id++) {
+ cfg = &smb_cfg_table[id];
+ if (strcmp(cfg->sc_pg, pgname))
+ continue;
+
+ if (cfg->sc_flags & SMB_CF_MODIFIED) {
+ if (cfg->sc_value) {
+ if (strcmp(pgname, SMBD_PG_NAME) == 0)
+ smb_config_setenv_trans(handle,
+ cfg->sc_type, cfg->sc_name,
+ cfg->sc_value);
+ else
+ smb_config_setenv_trans_protected(
+ handle, cfg->sc_name,
+ cfg->sc_value);
+ } else {
+ (void) smb_config_unsetenv_trans(handle,
+ cfg->sc_name);
+ }
+ cfg->sc_flags &= ~SMB_CF_MODIFIED;
+ dorefresh = 1;
+ }
+ }
+
+ if (smb_config_saveenv(handle) != 0) {
+ syslog(LOG_ERR, "smbd: cannot save configuration");
+ return (1);
+ }
+ if (dorefresh)
+ (void) smf_refresh_instance(SMBD_DEFAULT_INSTANCE_FMRI);
+ return (0);
+}
+
+/*
+ * smb_config_update
+ *
+ * Updates the specified config param with the given value.
+ * This function is called both on (re)load and set.
+ */
+static int
+smb_config_update(smb_cfg_param_t *cfg, char *value)
+{
+ char *curval;
+ int rc = 0;
+ int len;
+
+ if (value) {
+ len = strlen(value);
+ if (cfg->sc_value) {
+ curval = (char *)realloc(cfg->sc_value,
+ (len + 1));
+ } else {
+ curval = (char *)malloc(len + 1);
+ }
+
+ if (curval) {
+ cfg->sc_value = curval;
+ (void) strcpy(cfg->sc_value, value);
+ cfg->sc_flags |= SMB_CF_DEFINED;
+ } else {
+ rc = 1;
+ }
+ } else if (cfg->sc_value) {
+ free(cfg->sc_value);
+ cfg->sc_value = NULL;
+ cfg->sc_flags &= ~SMB_CF_DEFINED;
+ }
+
+ return (rc);
+}
+
+uint8_t
+smb_config_get_fg_flag()
+{
+ uint8_t run_fg = 0; /* Default is to run in daemon mode */
+ smb_scfhandle_t *handle = NULL;
+
+ handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
+ if (handle == NULL) {
+ return (run_fg);
+ }
+
+ if (smb_smf_create_service_pgroup(handle,
+ SMBD_PG_NAME) != SMBD_SMF_OK) {
+ smb_smf_scf_fini(handle);
+ return (run_fg);
+ }
+
+ if (smb_smf_get_boolean_property(handle, "run_fg", &run_fg) != 0) {
+ smb_smf_scf_fini(handle);
+ return (run_fg);
+ }
+
+ smb_smf_scf_fini(handle);
+
+ return (run_fg);
+}
+
+/*
+ * smb_config_get_localsid
+ *
+ * Returns value of the "config/machine_sid" parameter
+ * from the IDMAP SMF configuration repository.
+ *
+ */
+char *
+smb_config_get_localsid(void)
+{
+ return (smb_config_getenv_generic(MACHINE_SID, IDMAP_FMRI_PREFIX,
+ IDMAP_PG_NAME));
+}
+
+/*
+ * smb_config_set_idmap_domain
+ *
+ * Set the "config/mapping_domain" parameter from IDMAP SMF repository.
+ */
+int
+smb_config_set_idmap_domain(char *value)
+{
+ return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
+ MAPPING_DOMAIN, value));
+}
+
+/*
+ * smb_config_set_idmap_gc
+ *
+ * Set the "config/global_catalog" parameter from IDMAP SMF repository.
+ */
+int
+smb_config_set_idmap_gc(char *value)
+{
+ return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
+ GLOBAL_CATALOG, value));
+}
+
+/*
+ * smb_config_refresh_idmap
+ *
+ * Refresh IDMAP SMF service after making changes to its configuration.
+ */
+int
+smb_config_refresh_idmap(void)
+{
+ char instance[32];
+
+ (void) snprintf(instance, sizeof (instance), "%s:default",
+ IDMAP_FMRI_PREFIX);
+ return (smf_refresh_instance(instance));
+}
+
+int
+smb_config_secmode_fromstr(char *secmode)
+{
+ if (secmode == NULL)
+ return (SMB_SECMODE_WORKGRP);
+
+ if (strcasecmp(secmode, SMB_SECMODE_DOMAIN_STR) == 0)
+ return (SMB_SECMODE_DOMAIN);
+
+ return (SMB_SECMODE_WORKGRP);
+}
+
+char *
+smb_config_secmode_tostr(int secmode)
+{
+ if (secmode == SMB_SECMODE_DOMAIN)
+ return (SMB_SECMODE_DOMAIN_STR);
+
+ return (SMB_SECMODE_WORKGRP_STR);
+}
+
+int
+smb_config_get_secmode()
+{
+ char *p;
+
+ p = smb_config_getstr(SMB_CI_SECURITY);
+ return (smb_config_secmode_fromstr(p));
+}
+
+int
+smb_config_set_secmode(int secmode)
+{
+ char *p;
+
+ p = smb_config_secmode_tostr(secmode);
+ return (smb_config_set(SMB_CI_SECURITY, p));
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_crypt.c b/usr/src/lib/smbsrv/libsmb/common/smb_crypt.c
new file mode 100644
index 0000000000..94489b0b40
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_crypt.c
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/md4.h>
+#include <sys/types.h>
+#include <string.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#include <cryptoutil.h>
+#include <smbsrv/libsmb.h>
+
+static void smb_auth_keyprep(const unsigned char *pwstr, unsigned char *keystr);
+
+/*
+ * smb_auth_md4
+ *
+ * Compute an MD4 digest.
+ */
+int
+smb_auth_md4(unsigned char *result, unsigned char *input, int length)
+{
+ MD4_CTX md4_context;
+
+ MD4Init(&md4_context);
+ MD4Update(&md4_context, input, length);
+ MD4Final(result, &md4_context);
+ return (SMBAUTH_SUCCESS);
+}
+
+int
+smb_auth_hmac_md5(unsigned char *data,
+ int data_len,
+ unsigned char *key,
+ int key_len,
+ unsigned char *digest)
+{
+ CK_RV rv;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE hKey;
+ CK_SESSION_HANDLE hSession;
+ unsigned long diglen = MD_DIGEST_LEN;
+
+ mechanism.mechanism = CKM_MD5_HMAC;
+ mechanism.pParameter = 0;
+ mechanism.ulParameterLen = 0;
+ rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
+ if (rv != CKR_OK) {
+ return (SMBAUTH_FAILURE);
+ }
+
+ rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
+ key, key_len, &hKey);
+ if (rv != CKR_OK) {
+ (void) C_CloseSession(hSession);
+ return (SMBAUTH_FAILURE);
+ }
+
+ /* Initialize the digest operation in the session */
+ rv = C_SignInit(hSession, &mechanism, hKey);
+ if (rv != CKR_OK) {
+ (void) C_DestroyObject(hSession, hKey);
+ (void) C_CloseSession(hSession);
+ return (SMBAUTH_FAILURE);
+ }
+ rv = C_SignUpdate(hSession, (CK_BYTE_PTR)data, data_len);
+ if (rv != CKR_OK) {
+ (void) C_DestroyObject(hSession, hKey);
+ (void) C_CloseSession(hSession);
+ return (SMBAUTH_FAILURE);
+ }
+ rv = C_SignFinal(hSession, (CK_BYTE_PTR)digest, &diglen);
+ if (rv != CKR_OK) {
+ (void) C_DestroyObject(hSession, hKey);
+ (void) C_CloseSession(hSession);
+ return (SMBAUTH_FAILURE);
+ }
+ (void) C_DestroyObject(hSession, hKey);
+ (void) C_CloseSession(hSession);
+ if (diglen != MD_DIGEST_LEN) {
+ return (SMBAUTH_FAILURE);
+ }
+ return (SMBAUTH_SUCCESS);
+}
+
+int
+smb_auth_DES(unsigned char *Result, int ResultLen,
+ unsigned char *Key, int KeyLen,
+ unsigned char *Data, int DataLen)
+{
+ CK_RV rv;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE hKey;
+ CK_SESSION_HANDLE hSession;
+ CK_ULONG ciphertext_len;
+ uchar_t des_key[8];
+ int error = 0;
+ int K, D;
+ int k, d;
+
+ /* Calculate proper number of iterations */
+ K = KeyLen / 7;
+ D = DataLen / 8;
+
+ if (ResultLen < (K * 8 * D)) {
+ return (SMBAUTH_FAILURE);
+ }
+
+ /*
+ * Use SUNW convenience function to initialize the cryptoki
+ * library, and open a session with a slot that supports
+ * the mechanism we plan on using.
+ */
+ mechanism.mechanism = CKM_DES_ECB;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+ rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
+ if (rv != CKR_OK) {
+ return (SMBAUTH_FAILURE);
+ }
+
+ for (k = 0; k < K; k++) {
+ smb_auth_keyprep(&Key[k * 7], des_key);
+ rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
+ des_key, 8, &hKey);
+ if (rv != CKR_OK) {
+ error = 1;
+ goto exit_session;
+ }
+ /* Initialize the encryption operation in the session */
+ rv = C_EncryptInit(hSession, &mechanism, hKey);
+ if (rv != CKR_OK) {
+ error = 1;
+ goto exit_encrypt;
+ }
+ ciphertext_len = DataLen;
+ for (d = 0; d < D; d++) {
+ /* Read in the data and encrypt this portion */
+ rv = C_EncryptUpdate(hSession,
+ (CK_BYTE_PTR)Data + (d * 8), 8,
+ &Result[(k * (8 * D)) + (d * 8)],
+ &ciphertext_len);
+ if (rv != CKR_OK) {
+ error = 1;
+ goto exit_encrypt;
+ }
+ }
+ (void) C_DestroyObject(hSession, hKey);
+ }
+ goto exit_session;
+
+exit_encrypt:
+ (void) C_DestroyObject(hSession, hKey);
+exit_session:
+ (void) C_CloseSession(hSession);
+
+ if (error)
+ return (SMBAUTH_FAILURE);
+
+ return (SMBAUTH_SUCCESS);
+}
+
+/*
+ * smb_auth_keyprep
+ *
+ * Takes 7 bytes of keying material and expands it into 8 bytes with
+ * the keying material in the upper 7 bits of each byte.
+ */
+static void
+smb_auth_keyprep(const unsigned char *pwstr, unsigned char *keystr)
+{
+ keystr[0] = pwstr[0];
+ keystr[1] = (pwstr[0] << 7) | (pwstr[1] >> 1);
+ keystr[2] = (pwstr[1] << 6) | (pwstr[2] >> 2);
+ keystr[3] = (pwstr[2] << 5) | (pwstr[3] >> 3);
+ keystr[4] = (pwstr[3] << 4) | (pwstr[4] >> 4);
+ keystr[5] = (pwstr[4] << 3) | (pwstr[5] >> 5);
+ keystr[6] = (pwstr[5] << 2) | (pwstr[6] >> 6);
+ keystr[7] = pwstr[6] << 1;
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_ctxbuf.c b/usr/src/lib/smbsrv/libsmb/common/smb_ctxbuf.c
new file mode 100644
index 0000000000..2b51f2b6af
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_ctxbuf.c
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+/*
+ * Buffer manipulation routines. These routines can be used to format
+ * data within a data buffer without worrying about overrunning the
+ * buffer.
+ *
+ * A ctxbuf_t structure is used to track the current location within
+ * the buffer. The ctxbuf_init() must be called first to initialize the
+ * context structure. ctxbuf_printf() can then be called to fill the buffer.
+ * ctxbuf_printf will discard any data that would overrun the buffer and
+ * the buffer will always be null terminated.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <smbsrv/libsmb.h>
+
+/*
+ * smb_ctxbuf_init
+ *
+ * Initialize the buffer context structure.
+ * This must be called before any of the other
+ * buffer routines can be used.
+ *
+ * Returns -1 if invalid parameters, 0 otherwise
+ */
+int
+smb_ctxbuf_init(smb_ctxbuf_t *ctx, unsigned char *buf, size_t buflen)
+{
+ if (ctx == 0 || buf == 0 || buflen == 0)
+ return (-1);
+
+ buf[0] = '\0';
+
+ ctx->basep = buf;
+ ctx->curp = buf;
+ ctx->endp = &buf[buflen];
+
+ return (0);
+}
+
+/*
+ * smb_ctxbuf_len
+ *
+ * Return the amount of data stored in the buffer,
+ * excluding the terminating null character. Similar
+ * to strlen()
+ *
+ * Returns 0 if the ctx is invalid.
+ */
+int
+smb_ctxbuf_len(smb_ctxbuf_t *ctx)
+{
+ if (ctx == 0 || ctx->basep == 0 ||
+ ctx->curp == 0 || ctx->endp == 0)
+ return (0);
+ else
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (ctx->curp - ctx->basep);
+}
+
+/*
+ * smb_ctxbuf_printf
+ *
+ * Move formatted output (based on fmt string) to the buffer
+ * identified in ctxbuf. Any output characters beyond the buffer
+ * are discarded and a null character is written at the end of the
+ * characters actually written.
+ *
+ * Returns
+ * Always return the number of bytes actually written (excluding the
+ * terminating null).
+ */
+int
+smb_ctxbuf_printf(smb_ctxbuf_t *ctx, const char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ if (ctx == 0 || ctx->basep == 0 ||
+ ctx->curp == 0 || ctx->endp == 0)
+ return (-1);
+
+ va_start(args, fmt);
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ n = vsnprintf((char *)ctx->curp, ctx->endp-ctx->curp, fmt, args);
+ ctx->curp += n;
+ va_end(args);
+
+ /*
+ * return the number of bytes moved into the buffer.
+ */
+ return (n);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_domain.c b/usr/src/lib/smbsrv/libsmb/common/smb_domain.c
new file mode 100644
index 0000000000..22ea5e61fb
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_domain.c
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the NT domain environment values and the domain
+ * database interface. The database is a single linked list of
+ * structures containing domain type, name and SID information.
+ */
+
+#include <strings.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <synch.h>
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/string.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/alloc.h>
+
+#include <smbsrv/libsmb.h>
+
+
+static void nt_domain_unlist(nt_domain_t *);
+
+/*
+ * Valid domain type identifiers as text. This table must be kept
+ * in step with the nt_domain_type_t enum in ntdomain.h.
+ */
+static char *nt_domain_type_name[NT_DOMAIN_NUM_TYPES] = {
+ "null",
+ "builtin",
+ "local",
+ "primary",
+ "account",
+ "trusted",
+ "untrusted"
+};
+
+
+static rwlock_t nt_domain_lock;
+static nt_domain_t *nt_domain_list;
+
+/*
+ * nt_domain_init
+ *
+ * NT domain database one time initialization. This function should
+ * be called during module installation.
+ *
+ * Returns 0 on successful domain initialization. Less than zero otherwise.
+ */
+int
+nt_domain_init(char *resource_domain, uint32_t secmode)
+{
+ nt_domain_t *domain;
+ nt_sid_t *sid;
+ char *sidstr;
+ char *lsidstr;
+ char hostname[MAXHOSTNAMELEN];
+
+ if (rwlock_init(&nt_domain_lock, USYNC_THREAD, NULL))
+ return (SMB_DOMAIN_NODOMAIN_SID);
+
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) {
+ (void) rwlock_destroy(&nt_domain_lock);
+ return (SMB_DOMAIN_NOMACHINE_SID);
+ }
+
+ lsidstr = smb_config_get_localsid();
+
+ if (lsidstr) {
+ sid = nt_sid_strtosid(lsidstr);
+
+ if (sid) {
+ domain = nt_domain_new(NT_DOMAIN_LOCAL, hostname, sid);
+ (void) nt_domain_add(domain);
+ free(sid);
+ }
+ free(lsidstr);
+ } else {
+ (void) rwlock_destroy(&nt_domain_lock);
+ return (SMB_DOMAIN_NOMACHINE_SID);
+ }
+
+ if (secmode == SMB_SECMODE_DOMAIN) {
+ sid = nt_sid_strtosid(NT_BUILTIN_DOMAIN_SIDSTR);
+ domain = nt_domain_new(NT_DOMAIN_BUILTIN, "BUILTIN", sid);
+ (void) nt_domain_add(domain);
+ free(sid);
+
+ smb_config_rdlock();
+ sidstr = smb_config_get(SMB_CI_DOMAIN_SID);
+ if (sidstr) {
+ sid = nt_sid_strtosid(sidstr);
+ smb_config_unlock();
+ domain = nt_domain_new(NT_DOMAIN_PRIMARY,
+ resource_domain, sid);
+ (void) nt_domain_add(domain);
+ free(sid);
+ } else {
+ smb_config_unlock();
+ (void) rwlock_destroy(&nt_domain_lock);
+ return (SMB_DOMAIN_NODOMAIN_SID);
+ }
+
+ }
+ return (0);
+}
+
+/*
+ * nt_domain_new
+ *
+ * Allocate and initialize a new domain structure. On success, a pointer to
+ * the new domain structure is returned. Otherwise a null pointer is returned.
+ */
+nt_domain_t *
+nt_domain_new(nt_domain_type_t type, char *name, nt_sid_t *sid)
+{
+ nt_domain_t *new_domain;
+
+ if ((name == NULL) || (sid == NULL))
+ return (NULL);
+
+ if (type == NT_DOMAIN_NULL || type >= NT_DOMAIN_NUM_TYPES)
+ return (NULL);
+
+ if ((new_domain = malloc(sizeof (nt_domain_t))) == NULL)
+ return (NULL);
+
+ bzero(new_domain, sizeof (nt_domain_t));
+ new_domain->type = type;
+ new_domain->name = strdup(name);
+ new_domain->sid = nt_sid_dup(sid);
+
+ return (new_domain);
+}
+
+/*
+ * nt_domain_delete
+ *
+ * Free the memory used by the specified domain structure.
+ */
+void
+nt_domain_delete(nt_domain_t *domain)
+{
+ if (domain) {
+ free(domain->name);
+ free(domain->sid);
+ free(domain);
+ }
+}
+
+
+/*
+ * nt_domain_add
+ *
+ * Add a domain structure to the global list. There is no checking
+ * for duplicates. If it's the primary domain, we save the SID in the
+ * environment. Returns a pointer to the new domain entry on success.
+ * Otherwise a null pointer is returned.
+ */
+nt_domain_t *
+nt_domain_add(nt_domain_t *new_domain)
+{
+ char *sidstr;
+
+ if (new_domain == NULL)
+ return (NULL);
+
+ (void) rw_wrlock(&nt_domain_lock);
+
+ new_domain->next = nt_domain_list;
+ nt_domain_list = new_domain;
+
+ if (new_domain->type == NT_DOMAIN_PRIMARY) {
+ sidstr = nt_sid_format(new_domain->sid);
+ smb_config_wrlock();
+ (void) smb_config_set(SMB_CI_DOMAIN_SID, sidstr);
+ smb_config_unlock();
+ free(sidstr);
+ }
+ (void) rw_unlock(&nt_domain_lock);
+
+ return (new_domain);
+}
+
+
+/*
+ * nt_domain_remove
+ *
+ * Remove a domain from the global list. The memory
+ * used by the structure is not freed.
+ */
+void
+nt_domain_remove(nt_domain_t *domain)
+{
+ (void) rw_wrlock(&nt_domain_lock);
+ nt_domain_unlist(domain);
+ (void) rw_unlock(&nt_domain_lock);
+}
+
+
+/*
+ * nt_domain_flush
+ *
+ * Flush all domains of the specified type from the list. This is
+ * useful for things like updating the list of trusted domains.
+ */
+void
+nt_domain_flush(nt_domain_type_t domain_type)
+{
+ nt_domain_t *domain = nt_domain_list;
+
+ (void) rw_wrlock(&nt_domain_lock);
+ while (domain) {
+ if (domain->type == domain_type) {
+ nt_domain_unlist(domain);
+ nt_domain_delete(domain);
+ domain = nt_domain_list;
+ continue;
+ }
+ domain = domain->next;
+ }
+ (void) rw_unlock(&nt_domain_lock);
+}
+
+/*
+ * nt_domain_xlat_type
+ *
+ * Translate a domain type into a text string.
+ */
+char *
+nt_domain_xlat_type(nt_domain_type_t domain_type)
+{
+ if (domain_type < NT_DOMAIN_NUM_TYPES)
+ return (nt_domain_type_name[domain_type]);
+ else
+ return ("unknown");
+}
+
+
+/*
+ * nt_domain_xlat_type_name
+ *
+ * Translate a domain type test string into a domain type.
+ */
+nt_domain_type_t
+nt_domain_xlat_type_name(char *type_name)
+{
+ int i;
+
+ for (i = 0; i < NT_DOMAIN_NUM_TYPES; ++i)
+ if (utf8_strcasecmp(nt_domain_type_name[i], type_name) == 0)
+ return (i);
+
+ return (NT_DOMAIN_NUM_TYPES);
+}
+
+
+/*
+ * nt_domain_lookup_name
+ *
+ * Lookup a domain by its domain name. If the domain is in the list,
+ * a pointer to it is returned. Otherwise a null pointer is returned.
+ */
+nt_domain_t *
+nt_domain_lookup_name(char *domain_name)
+{
+ nt_domain_t *domain = nt_domain_list;
+
+ (void) rw_rdlock(&nt_domain_lock);
+ while (domain) {
+ if (utf8_strcasecmp(domain->name, domain_name) == 0)
+ break;
+
+ domain = domain->next;
+ }
+ (void) rw_unlock(&nt_domain_lock);
+
+ return (domain);
+}
+
+
+/*
+ * nt_domain_lookup_sid
+ *
+ * Lookup a domain by its domain SID. If the domain is in the list,
+ * a pointer to it is returned. Otherwise a null pointer is returned.
+ */
+nt_domain_t *
+nt_domain_lookup_sid(nt_sid_t *domain_sid)
+{
+ nt_domain_t *domain = nt_domain_list;
+
+ (void) rw_rdlock(&nt_domain_lock);
+ while (domain) {
+ if (nt_sid_is_equal(domain->sid, domain_sid))
+ break;
+
+ domain = domain->next;
+ }
+ (void) rw_unlock(&nt_domain_lock);
+
+ return (domain);
+}
+
+
+/*
+ * nt_domain_lookupbytype
+ *
+ * Lookup a domain by its type. The first matching entry in the list
+ * is returned. Otherwise a null pointer is returned.
+ */
+nt_domain_t *
+nt_domain_lookupbytype(nt_domain_type_t type)
+{
+ nt_domain_t *domain = nt_domain_list;
+
+ (void) rw_rdlock(&nt_domain_lock);
+ while (domain) {
+ if (domain->type == type)
+ break;
+
+ domain = domain->next;
+ }
+ (void) rw_unlock(&nt_domain_lock);
+
+ return (domain);
+}
+
+
+/*
+ * nt_domain_local_sid
+ *
+ * Return a pointer to the local domain SID. Each system has a SID that
+ * represents the local domain, which is named after the local hostname.
+ * The local domain SID must exist.
+ */
+nt_sid_t *
+nt_domain_local_sid(void)
+{
+ nt_domain_t *domain = nt_domain_list;
+
+ (void) rw_rdlock(&nt_domain_lock);
+ while (domain) {
+ if (domain->type == NT_DOMAIN_LOCAL)
+ break;
+
+ domain = domain->next;
+ }
+ (void) rw_unlock(&nt_domain_lock);
+
+ return (domain->sid);
+}
+
+
+static void
+nt_domain_unlist(nt_domain_t *domain)
+{
+ nt_domain_t **ppdomain = &nt_domain_list;
+
+ while (*ppdomain) {
+ if (*ppdomain == domain) {
+ *ppdomain = domain->next;
+ domain->next = NULL;
+ return;
+ }
+ ppdomain = &(*ppdomain)->next;
+ }
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_door_client.c b/usr/src/lib/smbsrv/libsmb/common/smb_door_client.c
new file mode 100644
index 0000000000..7e09b237b3
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_door_client.c
@@ -0,0 +1,411 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * User-space door client for SMBd
+ */
+
+#include <fcntl.h>
+#include <syslog.h>
+#include <door.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/smb_common_door.h>
+
+#include <smbsrv/libsmb.h>
+
+static int smb_door_fildes = -1;
+
+static char *smbd_desc[] = {
+ "",
+ "SmbdJoinDomain",
+ "SmbdGetParam",
+ "SmbdSetParam",
+ "SmbdNetbiosReconfig",
+ 0
+};
+
+/*
+ * Returns 0 on success. Otherwise, -1.
+ */
+static int
+smbd_door_open(int opcode)
+{
+ int rc = 0;
+
+ if (smb_door_fildes == -1 &&
+ (smb_door_fildes = open(SMBD_DOOR_NAME, O_RDONLY)) < 0) {
+ syslog(LOG_ERR, "%s: open %s failed %s", smbd_desc[opcode],
+ SMBD_DOOR_NAME, strerror(errno));
+ rc = -1;
+ }
+
+ return (rc);
+}
+
+/*
+ * Return 0 upon success. Otherwise, -1.
+ */
+static int
+smbd_door_check_srv_status(int opcode, smb_dr_ctx_t *dec_ctx)
+{
+ int status = smb_dr_get_int32(dec_ctx);
+ int err;
+ int rc = -1;
+
+ switch (status) {
+ case SMBD_DOOR_SRV_SUCCESS:
+ rc = 0;
+ break;
+
+ case SMBD_DOOR_SRV_ERROR:
+ err = smb_dr_get_uint32(dec_ctx);
+ syslog(LOG_ERR, "%s: Encountered door server error %s",
+ smbd_desc[opcode], strerror(err));
+ break;
+
+ default:
+ syslog(LOG_ERR, "%s: Unknown door server status",
+ smbd_desc[opcode]);
+ }
+
+ if (rc != 0) {
+ if ((err = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ smbd_desc[opcode], strerror(err));
+ }
+ }
+
+ return (rc);
+}
+
+uint32_t
+smb_join(smb_joininfo_t *jdi)
+{
+ door_arg_t arg;
+ char *buf;
+ uint32_t used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ uint32_t rc;
+ int opcode = SMBD_DOOR_JOIN;
+
+ if ((jdi == 0) || (*jdi->domain_name == 0)) {
+ syslog(LOG_ERR, "%s: invalid parameter(s)", smbd_desc[opcode]);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (smbd_door_open(opcode) == -1) {
+ syslog(LOG_ERR, "%s: cannot open the door", smbd_desc[opcode]);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ buf = MEM_MALLOC("smb_door_client", SMBD_DOOR_SIZE);
+ if (!buf) {
+ syslog(LOG_ERR, "%s: resource shortage", smbd_desc[opcode]);
+ return (NT_STATUS_NO_MEMORY);
+ }
+
+ enc_ctx = smb_dr_encode_start(buf, SMBD_DOOR_SIZE);
+ if (enc_ctx == 0) {
+ syslog(LOG_ERR, "%s: encode start failed", smbd_desc[opcode]);
+ MEM_FREE("smb_door_client", buf);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_uint32(enc_ctx, jdi->mode);
+ smb_dr_put_string(enc_ctx, jdi->domain_name);
+ smb_dr_put_string(enc_ctx, jdi->domain_username);
+ smb_dr_put_string(enc_ctx, jdi->domain_passwd);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ smbd_desc[opcode], strerror(status));
+ MEM_FREE("smb_door_client", buf);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = SMBD_DOOR_SIZE;
+
+ if (door_call(smb_door_fildes, &arg) < 0) {
+ syslog(LOG_ERR, "%s: Door call failed %s", smbd_desc[opcode],
+ strerror(errno));
+ MEM_FREE("smb_door_client", buf);
+ smb_door_fildes = -1;
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (smbd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("smb_door_client", buf);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ smbd_desc[opcode], strerror(status));
+ MEM_FREE("smb_door_client", buf);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ MEM_FREE("smb_door_client", buf);
+ return (rc);
+}
+
+int
+smbd_netbios_reconfig()
+{
+ door_arg_t arg;
+ char *buf;
+ uint32_t used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = SMBD_DOOR_NETBIOS_RECONFIG;
+
+ if (smbd_door_open(opcode) == -1) {
+ syslog(LOG_ERR, "%s: cannot open the door", smbd_desc[opcode]);
+ return (1);
+ }
+
+ buf = MEM_MALLOC("smb_door_client", SMBD_DOOR_SIZE);
+ if (!buf) {
+ syslog(LOG_ERR, "%s: resource shortage", smbd_desc[opcode]);
+ return (1);
+ }
+
+ enc_ctx = smb_dr_encode_start(buf, SMBD_DOOR_SIZE);
+ if (enc_ctx == 0) {
+ syslog(LOG_ERR, "%s: encode start failed", smbd_desc[opcode]);
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+
+ smb_dr_put_uint32(enc_ctx, opcode);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ smbd_desc[opcode], strerror(status));
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = SMBD_DOOR_SIZE;
+
+ if (door_call(smb_door_fildes, &arg) < 0) {
+ syslog(LOG_ERR, "%s: Door call failed %s", smbd_desc[opcode],
+ strerror(errno));
+ MEM_FREE("smb_door_client", buf);
+ smb_door_fildes = -1;
+ return (1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ rc = smb_dr_get_uint32(dec_ctx);
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ smbd_desc[opcode], strerror(status));
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+ MEM_FREE("smb_door_client", buf);
+ return (rc);
+}
+
+int
+smbd_set_param(smb_cfg_id_t id, char *value)
+{
+ door_arg_t arg;
+ char *buf;
+ uint32_t used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = SMBD_DOOR_PARAM_SET;
+
+ if (smbd_door_open(opcode) == -1) {
+ syslog(LOG_ERR, "%s: cannot open the door", smbd_desc[opcode]);
+ return (1);
+ }
+
+ buf = MEM_MALLOC("smb_door_client", SMBD_DOOR_SIZE);
+ if (!buf) {
+ syslog(LOG_ERR, "%s: resource shortage", smbd_desc[opcode]);
+ return (1);
+ }
+
+ enc_ctx = smb_dr_encode_start(buf, SMBD_DOOR_SIZE);
+ if (enc_ctx == 0) {
+ syslog(LOG_ERR, "%s: encode start failed", smbd_desc[opcode]);
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_uint32(enc_ctx, id);
+ smb_dr_put_string(enc_ctx, value);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ smbd_desc[opcode], strerror(status));
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = SMBD_DOOR_SIZE;
+
+ if (door_call(smb_door_fildes, &arg) < 0) {
+ syslog(LOG_ERR, "%s: Door call failed %s", smbd_desc[opcode],
+ strerror(errno));
+ MEM_FREE("smb_door_client", buf);
+ smb_door_fildes = -1;
+ return (1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ rc = smb_dr_get_uint32(dec_ctx);
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ smbd_desc[opcode], strerror(status));
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+ MEM_FREE("smb_door_client", buf);
+ return (rc);
+}
+
+int
+smbd_get_param(smb_cfg_id_t id, char *value)
+{
+ door_arg_t arg;
+ char *buf;
+ char *tmp = NULL;
+ uint32_t used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = SMBD_DOOR_PARAM_GET;
+
+ if (smbd_door_open(opcode) == -1) {
+ syslog(LOG_ERR, "%s: cannot open the door", smbd_desc[opcode]);
+ return (1);
+ }
+
+ buf = MEM_MALLOC("smb_door_client", SMBD_DOOR_SIZE);
+ if (!buf) {
+ syslog(LOG_ERR, "%s: resource shortage", smbd_desc[opcode]);
+ return (1);
+ }
+
+ enc_ctx = smb_dr_encode_start(buf, SMBD_DOOR_SIZE);
+ if (enc_ctx == 0) {
+ syslog(LOG_ERR, "%s: encode start failed", smbd_desc[opcode]);
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_uint32(enc_ctx, id);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ syslog(LOG_ERR, "%s: Encode error %s",
+ smbd_desc[opcode], strerror(status));
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = SMBD_DOOR_SIZE;
+
+ if (door_call(smb_door_fildes, &arg) < 0) {
+ syslog(LOG_ERR, "%s: Door call failed %s", smbd_desc[opcode],
+ strerror(errno));
+ MEM_FREE("smb_door_client", buf);
+ smb_door_fildes = -1;
+ return (1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ rc = smb_dr_get_uint32(dec_ctx);
+ tmp = smb_dr_get_string(dec_ctx);
+ (void) strcpy(value, tmp);
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ syslog(LOG_ERR, "%s: Decode error %s",
+ smbd_desc[opcode], strerror(status));
+ MEM_FREE("smb_door_client", buf);
+ return (1);
+ }
+ MEM_FREE("smb_door_client", buf);
+ return (rc);
+}
+
+int
+smbd_get_security_mode(int *mode)
+{
+ char buf[64];
+ int rc;
+
+ buf[0] = '\0';
+ rc = smbd_get_param(SMB_CI_SECURITY, buf);
+ *mode = smb_config_secmode_fromstr(buf);
+ return (rc);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c b/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c
new file mode 100644
index 0000000000..3734f6e49c
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c
@@ -0,0 +1,313 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <strings.h>
+#include <rpc/xdr.h>
+#include <errno.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smb_door_svc.h>
+
+/*
+ * smb_dr_decode_common
+ *
+ * This function can be used to decode both door request and result buffer.
+ * pre-condition: data is non-null pointer, and is bzero'd.
+ */
+int
+smb_dr_decode_common(char *buf, size_t len, xdrproc_t proc, void *data)
+{
+ XDR xdrs;
+ int rc = 0;
+
+ if (!data) {
+ syslog(LOG_ERR, "smb_dr_decode_common: invalid param");
+ return (-1);
+ }
+
+ xdrmem_create(&xdrs, buf, len, XDR_DECODE);
+ if (!proc(&xdrs, data)) {
+ rc = -1;
+ }
+ xdr_destroy(&xdrs);
+ return (rc);
+}
+
+/*
+ * smb_dr_encode_common
+ *
+ * This function can be used to encode both request and result door buffer.
+ * The 'opcode' paramater is set to the 'opcode' of the operation to be invoked
+ * on the server, by the client. The server sets the same 'opcode' paramater
+ * to indicate the 'status' of the door call.
+ *
+ * This function will first encode integer value 'opcode' (opcode/status),
+ * followed by the data (which will be encoded via the specified XDR routine).
+ *
+ * Returns encoded buffer upon success. Otherwise, returns NULL.
+ */
+char *
+smb_dr_encode_common(uint_t opcode, void *data, xdrproc_t proc, size_t *len)
+{
+ XDR xdrs;
+ char *buf;
+
+ if (proc && !data) {
+ syslog(LOG_ERR, "smb_dr_encode_common: invalid param");
+ *len = 0;
+ return (NULL);
+ }
+
+ *len = xdr_sizeof(xdr_uint32_t, &opcode);
+ if (proc)
+ *len += xdr_sizeof(proc, data);
+ buf = (char *)malloc(*len);
+ if (!buf) {
+ syslog(LOG_ERR, "smb_dr_encode_common: resource shortage");
+ *len = 0;
+ return (NULL);
+ }
+ xdrmem_create(&xdrs, buf, *len, XDR_ENCODE);
+ if (!xdr_uint32_t(&xdrs, &opcode)) {
+ syslog(LOG_DEBUG, "smb_dr_encode_common: encode error 1");
+ free(buf);
+ *len = 0;
+ xdr_destroy(&xdrs);
+ return (NULL);
+ }
+
+ if (proc && !proc(&xdrs, data)) {
+ syslog(LOG_DEBUG, "smb_dr_encode_common: encode error 2");
+ free(buf);
+ buf = NULL;
+ *len = 0;
+ }
+
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+/*
+ * Get the opcode of the door argument buffer.
+ */
+int
+smb_dr_get_opcode(char *argp, size_t arg_size)
+{
+ int opcode;
+
+ if (smb_dr_decode_common(argp, arg_size, xdr_uint32_t, &opcode) != 0)
+ opcode = -1;
+ return (opcode);
+}
+
+/*
+ * Set the opcode of the door argument buffer.
+ */
+char *
+smb_dr_set_opcode(uint32_t opcode, size_t *len)
+{
+ char *buf;
+
+ buf = smb_dr_encode_common(opcode, NULL, NULL, len);
+ return (buf);
+}
+
+/*
+ * Get the status of the door result buffer.
+ */
+int
+smb_dr_get_res_stat(char *rbufp, size_t rbuf_size)
+{
+ int stat;
+ if (smb_dr_decode_common(rbufp, rbuf_size, xdr_uint32_t, &stat) != 0)
+ stat = -1;
+ return (stat);
+}
+
+/*
+ * Set the status of the door result buffer.
+ */
+char *
+smb_dr_set_res_stat(uint32_t stat, size_t *len)
+{
+ char *buf;
+
+ buf = smb_dr_encode_common(stat, NULL, NULL, len);
+ return (buf);
+}
+
+char *
+smb_dr_encode_res_token(smb_token_t *token, size_t *len)
+{
+ smb_dr_bytes_t res;
+ char *buf = NULL;
+
+ res.bytes_val = smb_token_mkselfrel(token, &res.bytes_len);
+ if (!res.bytes_val) {
+ syslog(LOG_ERR, "smb_dr_encode_res_token: mkselfrel error");
+ *len = 0;
+ return (NULL);
+ }
+
+ if ((buf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &res,
+ xdr_smb_dr_bytes_t, len)) == NULL) {
+ syslog(LOG_ERR, "smb_dr_encode_res_token: failed");
+ *len = 0;
+ free(res.bytes_val);
+ return (NULL);
+
+ }
+ free(res.bytes_val);
+ return (buf);
+}
+
+char *
+smb_dr_encode_kshare(smb_dr_kshare_t *kshare, size_t *buflen)
+{
+ smb_dr_bytes_t res;
+ char *buf = NULL;
+
+ res.bytes_val = smb_kshare_mkselfrel(kshare, &res.bytes_len);
+
+ free(kshare->k_path);
+ free(kshare->k_sharename);
+
+ if (!res.bytes_val)
+ return (NULL);
+
+ buf = smb_dr_encode_common(SMB_KDR_SHARE, &res, xdr_smb_dr_bytes_t,
+ buflen);
+
+ free(res.bytes_val);
+
+ return (buf);
+}
+
+/*
+ * smb_kshare_mkselfrel
+ *
+ * encode: structure -> flat buffer (buffer size)
+ * Pre-condition: kshare is non-null.
+ */
+
+uint8_t *
+smb_kshare_mkselfrel(smb_dr_kshare_t *kshare, uint32_t *len)
+{
+ uint8_t *buf;
+ XDR xdrs;
+
+ if (!kshare)
+ return (NULL);
+
+ *len = xdr_sizeof(xdr_smb_dr_kshare_t, kshare);
+ buf = (uint8_t *)malloc(*len);
+ if (!buf)
+ return (NULL);
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, *len, XDR_ENCODE);
+
+ if (!xdr_smb_dr_kshare_t(&xdrs, kshare)) {
+ *len = 0;
+ free(buf);
+ buf = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+char *
+smb_dr_encode_string(uint32_t opcode, char *str, size_t *len)
+{
+ char *buf;
+ smb_dr_string_t res;
+
+ res.buf = str;
+
+ if ((buf = smb_dr_encode_common(opcode, &res,
+ xdr_smb_dr_string_t, len)) == NULL)
+ syslog(LOG_ERR, "smb_dr_encode_string: failed");
+ return (buf);
+}
+
+char *
+smb_dr_decode_string(char *buf, size_t len)
+{
+ smb_dr_string_t res;
+ char *str = NULL;
+
+ bzero(&res, sizeof (smb_dr_string_t));
+ if (smb_dr_decode_common(buf, len, xdr_smb_dr_string_t,
+ &res) == 0) {
+ str = res.buf;
+ } else {
+ syslog(LOG_ERR, "smb_dr_decode_string: failed");
+ }
+ return (str);
+}
+
+netr_client_t *
+smb_dr_decode_arg_get_token(char *buf, size_t len)
+{
+ smb_dr_bytes_t arg;
+ netr_client_t *clnt_info;
+
+ bzero(&arg, sizeof (smb_dr_bytes_t));
+ if (smb_dr_decode_common(buf, len, xdr_smb_dr_bytes_t, &arg)
+ != 0) {
+ syslog(LOG_ERR, "smb_dr_decode_arg_get_token: failed");
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
+ return (NULL);
+ }
+ clnt_info = netr_client_mkabsolute(arg.bytes_val,
+ arg.bytes_len);
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
+ return (clnt_info);
+}
+
+void
+smb_dr_ulist_free(smb_dr_ulist_t *ulist)
+{
+ int i;
+ smb_dr_user_ctx_t *uinfo;
+
+ if (!ulist)
+ return;
+
+ for (i = 0; i < ulist->dul_cnt; i++) {
+ uinfo = &ulist->dul_users[i];
+
+ if (!uinfo)
+ continue;
+
+ xdr_free(xdr_smb_dr_ulist_t, (char *)ulist);
+ }
+
+ free(ulist);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c b/usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c
new file mode 100644
index 0000000000..36373f10f0
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * User-space door client routines for both SMB daemon and CLIs.
+ */
+
+#include <fcntl.h>
+#include <syslog.h>
+#include <door.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+
+/*
+ * Returns 0 on success. Otherwise, -1.
+ */
+int
+smb_dr_clnt_open(int *fd, char *path, char *op_desc)
+{
+ int rc = 0;
+
+ if (!op_desc)
+ op_desc = "unknown operation";
+
+ if (!path || !fd)
+ return (-1);
+
+ if ((*fd = open(path, O_RDONLY)) < 0) {
+ syslog(LOG_ERR, "%s: open %s failed %s", op_desc,
+ path, strerror(errno));
+ rc = -1;
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_dr_clnt_call
+ *
+ * This function will make a door call to the server function
+ * associated with the door descriptor fd. The specified door
+ * request buffer (i.e. argp) will be passed as the argument to the
+ * door_call(). Upon success, the result buffer is returned. Otherwise,
+ * NULL pointer is returned. The size of the result buffer is returned
+ * via rbufsize.
+ */
+char *
+smb_dr_clnt_call(int fd, char *argp, size_t arg_size, size_t *rbufsize,
+ char *op_desc)
+{
+ door_arg_t arg;
+
+ if (!argp) {
+ syslog(LOG_ERR, "smb_dr_clnt_call: invalid parameter");
+ return (NULL);
+ }
+
+ arg.data_ptr = argp;
+ arg.data_size = arg_size;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = argp;
+ arg.rsize = arg_size;
+
+ if (!op_desc)
+ op_desc = "unknown operation";
+
+ if (door_call(fd, &arg) < 0) {
+ syslog(LOG_ERR, "%s: Door call failed %s", op_desc,
+ strerror(errno));
+ free(argp);
+ argp = NULL;
+ return (NULL);
+ }
+
+ if (smb_dr_get_res_stat(arg.data_ptr, arg.rsize)
+ != SMB_DR_OP_SUCCESS) {
+ smb_dr_clnt_free(argp, arg_size, arg.rbuf, arg.rsize);
+ *rbufsize = 0;
+ return (NULL);
+ }
+ *rbufsize = arg.rsize;
+ return (arg.data_ptr);
+}
+
+/*
+ * smb_dr_clnt_free
+ *
+ * This function should be invoked to free both the argument/result door buffer
+ * regardless of the status of the door call.
+ *
+ * The doorfs allocates a new buffer if the result buffer passed by the client
+ * is too small. This function will munmap if that happens.
+ */
+/*ARGSUSED*/
+void
+smb_dr_clnt_free(char *argp, size_t arg_size, char *rbufp, size_t rbuf_size)
+{
+ if (argp) {
+ if (argp == rbufp) {
+ free(argp);
+ argp = NULL;
+ } else if (rbufp) {
+ free(argp);
+ argp = NULL;
+ if (munmap(rbufp, rbuf_size) != 0) {
+ syslog(LOG_ERR, "munmap failed");
+ }
+ }
+ } else {
+ if (rbufp) {
+ if (munmap(rbufp, rbuf_size) != 0) {
+ syslog(LOG_ERR, "munmap failed");
+ }
+ }
+ }
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_downcalls.c b/usr/src/lib/smbsrv/libsmb/common/smb_downcalls.c
new file mode 100644
index 0000000000..2f76b4e875
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_downcalls.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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Down calls to SMB Kmod for obtaining various kernel door services.
+ */
+
+#include <syslog.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/xdr.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/libsmb.h>
+
+/* indexed via opcode (smb_kdr_opcode_t) */
+char *smb_dwncall_info[] = {
+ "SmbDwncallNumUser",
+ "SmbDwncallUserList",
+ "SmbDwncallShare",
+ 0
+};
+
+static smb_dwncall_get_desc_t get_dwncall_desc;
+
+int
+smb_dwncall_install_callback(smb_dwncall_get_desc_t get_desc_cb)
+{
+ if (!get_desc_cb)
+ return (-1);
+
+ get_dwncall_desc = get_desc_cb;
+ return (0);
+}
+
+int
+smb_dwncall_init_fd(uint_t opcode)
+{
+ int fd;
+
+ if (!get_dwncall_desc) {
+ syslog(LOG_DEBUG, "%s: failed (unable to get fd)",
+ smb_dwncall_info[opcode]);
+ return (-1);
+ }
+
+ if ((fd = get_dwncall_desc()) == -1) {
+ syslog(LOG_ERR, "%s: failed (invalid fd)",
+ smb_dwncall_info[opcode]);
+ return (-1);
+ }
+
+ return (fd);
+}
+
+uint64_t
+smb_dwncall_user_num()
+{
+ char *buf, *rbufp;
+ size_t buflen, rbufsize;
+ int64_t num;
+ uint_t opcode = SMB_KDR_USER_NUM;
+ int fd;
+
+ if ((fd = smb_dwncall_init_fd(opcode)) < 0)
+ return (0);
+
+ buf = smb_dr_set_opcode(opcode, &buflen);
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smb_dwncall_info[opcode]);
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_uint32_t, &num) != 0) {
+ num = -1;
+ }
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ return (num);
+}
+
+/*
+ * smb_dwncall_get_users
+ *
+ * The calling function must free the output parameter 'users'.
+ */
+int
+smb_dwncall_get_users(int offset, smb_dr_ulist_t *users)
+{
+ char *buf = NULL, *rbufp;
+ size_t buflen, rbufsize;
+ uint_t opcode = SMB_KDR_USER_LIST;
+ int fd, rc = -1;
+
+ bzero(users, sizeof (smb_dr_ulist_t));
+ if ((fd = smb_dwncall_init_fd(opcode)) < 0)
+ return (-1);
+
+ buf = smb_dr_encode_common(opcode, &offset, xdr_uint32_t, &buflen);
+ if (!buf) {
+ syslog(LOG_ERR, "smb_dwncall_get_users: encode error");
+ return (-1);
+ }
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smb_dwncall_info[opcode]);
+
+
+ if (rbufp) {
+ rc = smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_smb_dr_ulist_t, users);
+ if (rc)
+ syslog(LOG_ERR, "smb_dwncall_get_users: decode error");
+ else
+ rc = users->dul_cnt;
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ return (rc);
+}
+
+/*
+ * smb_dwncall_share()
+ *
+ * This is a downcall to the kernel that is executed
+ * upon share enable and disable.
+ */
+
+int
+smb_dwncall_share(int op, char *path, char *sharename)
+{
+ char *buf = NULL, *rbufp;
+ size_t buflen, rbufsize;
+ int32_t opcode = SMB_KDR_SHARE;
+ smb_dr_kshare_t kshare;
+ int fd, rc = -1;
+
+ if ((op != LMSHR_ADD) &&
+ (op != LMSHR_DELETE))
+ return (-1);
+
+ if ((fd = smb_dwncall_init_fd(opcode)) < 0) {
+ syslog(LOG_ERR, "smb_dwncall_share: init error");
+ return (-1);
+ }
+
+ kshare.k_op = op;
+ kshare.k_path = strdup(path);
+ kshare.k_sharename = strdup(sharename);
+
+ buf = smb_dr_encode_kshare(&kshare, &buflen);
+
+ if (!buf) {
+ syslog(LOG_ERR, "smb_dwncall_share: encode error");
+ return (-1);
+ }
+
+ rbufp = smb_dr_clnt_call(fd, buf, buflen, &rbufsize,
+ smb_dwncall_info[opcode]);
+
+ if (rbufp) {
+ if (smb_dr_decode_common(rbufp + SMB_DR_DATA_OFFSET,
+ rbufsize - SMB_DR_DATA_OFFSET, xdr_int32_t, &rc) != 0) {
+ rc = -1;
+ }
+ }
+
+ smb_dr_clnt_free(buf, buflen, rbufp, rbufsize);
+ return (rc);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_group_door_encdec.c b/usr/src/lib/smbsrv/libsmb/common/smb_group_door_encdec.c
new file mode 100644
index 0000000000..0b29764926
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_group_door_encdec.c
@@ -0,0 +1,337 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_door_svc.h>
+
+/*
+ * smb_grplist_mkselfrel
+ *
+ * encode: structure -> flat buffer (buffer size)
+ * Pre-condition: obj is non-null.
+ */
+static uint8_t *
+smb_grplist_mkselfrel(ntgrp_list_t *obj, uint32_t *len)
+{
+ uint8_t *buf;
+ XDR xdrs;
+
+ if (!obj) {
+ syslog(LOG_ERR, "smb_grplist_mkselfrel: invalid parameter");
+ return (NULL);
+ }
+ *len = xdr_sizeof(xdr_ntgrp_list_t, obj);
+ buf = (uint8_t *)malloc(*len);
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, *len, XDR_ENCODE);
+
+ if (!xdr_ntgrp_list_t(&xdrs, obj)) {
+ syslog(LOG_ERR, "smb_grplist_mkselfrel: XDR encode error");
+ free(buf);
+ *len = 0;
+ buf = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+/*
+ * smb_grplist_mkabsolute
+ *
+ * decode: flat buffer -> structure
+ */
+static ntgrp_list_t *
+smb_grplist_mkabsolute(uint8_t *buf, uint32_t len)
+{
+ ntgrp_list_t *obj;
+ XDR xdrs;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
+
+ if ((obj = (ntgrp_list_t *)
+ malloc(sizeof (ntgrp_list_t))) == 0) {
+ syslog(LOG_ERR, "smb_grplist_mkabsolute: resource shortage");
+ xdr_destroy(&xdrs);
+ return (NULL);
+ }
+ bzero(obj, sizeof (ntgrp_list_t));
+ if (!xdr_ntgrp_list_t(&xdrs, obj)) {
+ syslog(LOG_ERR, "smb_grplist_mkabsolute: XDR decode error");
+ smb_group_free_list(obj, 1);
+ obj = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (obj);
+}
+
+/*
+ * smb_grpmemberlist_mkselfrel
+ *
+ * encode: structure -> flat buffer (buffer size)
+ * Pre-condition: obj is non-null.
+ */
+static uint8_t *
+smb_grpmemberlist_mkselfrel(ntgrp_member_list_t *obj, uint32_t *len)
+{
+ uint8_t *buf;
+ XDR xdrs;
+
+ if (!obj) {
+ syslog(LOG_ERR,
+ "smb_grpmemberlist_mkselfrel: invalid parameter");
+ return (NULL);
+ }
+ *len = xdr_sizeof(xdr_ntgrp_member_list_t, obj);
+ buf = (uint8_t *)malloc(*len);
+ xdrmem_create(&xdrs, (const caddr_t)buf, *len, XDR_ENCODE);
+ if (!xdr_ntgrp_member_list_t(&xdrs, obj)) {
+ syslog(LOG_ERR,
+ "smb_grpmemberlist_mkselfrel: XDR encode error");
+ free(buf);
+ *len = 0;
+ buf = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+/*
+ * ntgrp_list_mkabsolute
+ *
+ * decode: flat buffer -> structure
+ */
+static ntgrp_member_list_t *
+smb_grpmemberlist_mkabsolute(uint8_t *buf, uint32_t len)
+{
+ ntgrp_member_list_t *obj = NULL;
+ XDR xdrs;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
+
+ if ((obj = (ntgrp_member_list_t *)
+ malloc(sizeof (ntgrp_member_list_t))) == 0) {
+ xdr_destroy(&xdrs);
+ syslog(LOG_ERR,
+ "smb_grpmemberlist_mkabsolute: resource shortage");
+ return (NULL);
+ }
+ bzero(obj, sizeof (ntgrp_member_list_t));
+ bzero(obj->members, SMB_GROUP_PER_LIST * sizeof (members_list));
+ if (!xdr_ntgrp_member_list_t(&xdrs, obj)) {
+ syslog(LOG_ERR,
+ "smb_grpmemberlist_mkabsolute: XDR decode error");
+ smb_group_free_memberlist(obj, 1);
+ obj = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (obj);
+}
+
+/*
+ * smb_privlist_mkselfrel
+ *
+ * encode: structure -> flat buffer (buffer size)
+ * Pre-condition: obj is non-null.
+ */
+static uint8_t *
+smb_grpprivlist_mkselfrel(ntpriv_list_t *obj, uint32_t *len)
+{
+ uint8_t *buf;
+ XDR xdrs;
+
+ if (!obj) {
+ syslog(LOG_ERR,
+ "smb_grpprivlist_mkselfrel: invalid parameter");
+ return (NULL);
+ }
+ *len = xdr_sizeof(xdr_ntpriv_list_t, obj);
+ buf = (uint8_t *)malloc(*len);
+ if (!buf) {
+ syslog(LOG_ERR,
+ "smb_grpprivlist_mkselfrel: resource shortage");
+ return (NULL);
+ }
+ xdrmem_create(&xdrs, (const caddr_t)buf, *len, XDR_ENCODE);
+ if (!xdr_ntpriv_list_t(&xdrs, obj)) {
+ syslog(LOG_ERR,
+ "smb_grpprivlist_mkselfrel: XDR encode error");
+ *len = 0;
+ free(buf);
+ buf = NULL;
+ }
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+/*
+ * smb_privlist_mkabsolute
+ *
+ * decode: flat buffer -> structure
+ */
+static ntpriv_list_t *
+smb_grpprivlist_mkabsolute(uint8_t *buf, uint32_t len)
+{
+ ntpriv_list_t *obj = NULL;
+ XDR xdrs;
+ uint32_t status;
+ int length = 0, num_privs = 0;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
+ status = smb_group_priv_num(&num_privs);
+ if (status != 0) {
+ syslog(LOG_ERR,
+ "smb_grpprivlist_mkabsolute: Cannot get privlist.");
+ xdr_destroy(&xdrs);
+ return (NULL);
+ }
+
+ if (num_privs > 0) {
+ length = sizeof (int) + (num_privs * sizeof (privs_t));
+ if ((obj = (ntpriv_list_t *)malloc(length)) == 0) {
+ syslog(LOG_ERR,
+ "smb_grpprivlist_mkabsolute: resource shortage");
+ xdr_destroy(&xdrs);
+ return (NULL);
+ }
+ }
+ bzero(obj, sizeof (ntpriv_list_t));
+ bzero(obj->privs, num_privs * sizeof (privs_t));
+ if (!xdr_ntpriv_list_t(&xdrs, obj)) {
+ syslog(LOG_ERR, "smb_grpprivlist_mkabsolute: XDR decode error");
+ smb_group_free_privlist(obj, 1);
+ obj = NULL;
+ }
+ xdr_destroy(&xdrs);
+ return (obj);
+}
+
+char *
+smb_dr_encode_grp_list(uint32_t opcode, ntgrp_list_t *list,
+ size_t *len)
+{
+ char *buf;
+ smb_dr_bytes_t arg;
+
+ arg.bytes_val = smb_grplist_mkselfrel(list, &arg.bytes_len);
+
+ buf = smb_dr_encode_common(opcode, &arg, xdr_smb_dr_bytes_t, len);
+ free(arg.bytes_val);
+ return (buf);
+}
+
+ntgrp_list_t *
+smb_dr_decode_grp_list(char *buf, size_t len)
+{
+ smb_dr_bytes_t arg;
+ ntgrp_list_t *list;
+
+ bzero(&arg, sizeof (smb_dr_bytes_t));
+ if (smb_dr_decode_common(buf, len, xdr_smb_dr_bytes_t, &arg)
+ != 0) {
+ syslog(LOG_ERR, "smb_dr_decode_grplist: XDR decode error");
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
+ return (NULL);
+ }
+ list = smb_grplist_mkabsolute(arg.bytes_val, arg.bytes_len);
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
+ return (list);
+}
+
+char *
+smb_dr_encode_grp_memberlist(uint32_t opcode,
+ ntgrp_member_list_t *list, size_t *len)
+{
+ char *buf;
+ smb_dr_bytes_t arg;
+
+ arg.bytes_val = smb_grpmemberlist_mkselfrel(list, &arg.bytes_len);
+
+ buf = smb_dr_encode_common(opcode, &arg, xdr_smb_dr_bytes_t, len);
+ free(arg.bytes_val);
+ return (buf);
+}
+
+ntgrp_member_list_t *
+smb_dr_decode_grp_memberlist(char *buf, size_t len)
+{
+ smb_dr_bytes_t arg;
+ ntgrp_member_list_t *list;
+
+ bzero(&arg, sizeof (smb_dr_bytes_t));
+ if (smb_dr_decode_common(buf, len, xdr_smb_dr_bytes_t, &arg)
+ != 0) {
+ syslog(LOG_ERR,
+ "smb_dr_decode_grpmemberlist: XDR decode error");
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
+ return (NULL);
+ }
+ list = smb_grpmemberlist_mkabsolute(arg.bytes_val, arg.bytes_len);
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
+ return (list);
+}
+
+char *
+smb_dr_encode_grp_privlist(uint32_t opcode,
+ ntpriv_list_t *list, size_t *len)
+{
+ char *buf;
+ smb_dr_bytes_t arg;
+
+ arg.bytes_val = smb_grpprivlist_mkselfrel(list, &arg.bytes_len);
+
+ buf = smb_dr_encode_common(opcode, &arg, xdr_smb_dr_bytes_t, len);
+ free(arg.bytes_val);
+ return (buf);
+}
+
+ntpriv_list_t *
+smb_dr_decode_grp_privlist(char *buf, size_t len)
+{
+ smb_dr_bytes_t arg;
+ ntpriv_list_t *list;
+
+ bzero(&arg, sizeof (smb_dr_bytes_t));
+ if (smb_dr_decode_common(buf, len, xdr_smb_dr_bytes_t, &arg)
+ != 0) {
+ syslog(LOG_ERR, "smb_dr_decode_grp_privlist: XDR decode error");
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
+ return (NULL);
+ }
+ list = smb_grpprivlist_mkabsolute(arg.bytes_val, arg.bytes_len);
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
+ return (list);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_group_xdr.c b/usr/src/lib/smbsrv/libsmb/common/smb_group_xdr.c
new file mode 100644
index 0000000000..723a6471f9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_group_xdr.c
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#include <rpc/rpc.h>
+#include <smbsrv/libsmb.h>
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file was originally generated using rpcgen.
+ */
+
+bool_t
+xdr_ntgrp_dr_arg_t(xdrs, objp)
+ XDR *xdrs;
+ ntgrp_dr_arg_t *objp;
+{
+ if (!xdr_string(xdrs, &objp->gname, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->desc, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->member, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->newgname, ~0))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->privid))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->priv_attr))
+ return (FALSE);
+ if (!xdr_int(xdrs, &objp->offset))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->scope, ~0))
+ return (FALSE);
+ if (!xdr_int(xdrs, &objp->type))
+ return (FALSE);
+ if (!xdr_int(xdrs, &objp->count))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ntstatus))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ntgrp_t(xdrs, objp)
+ XDR *xdrs;
+ ntgrp_t *objp;
+{
+ if (!xdr_uint32_t(xdrs, &objp->rid))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->name, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->desc, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->type, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->sid, ~0))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->attr))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ntgrp_list_t(xdrs, objp)
+ XDR *xdrs;
+ ntgrp_list_t *objp;
+{
+ if (!xdr_int(xdrs, &objp->cnt))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->groups, SMB_GROUP_PER_LIST,
+ sizeof (ntgrp_t), (xdrproc_t)xdr_ntgrp_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_members_list(xdrs, objp)
+ XDR *xdrs;
+ members_list *objp;
+{
+ if (!xdr_string(xdrs, objp, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ntgrp_member_list_t(xdrs, objp)
+ XDR *xdrs;
+ ntgrp_member_list_t *objp;
+{
+ if (!xdr_uint32_t(xdrs, &objp->rid))
+ return (FALSE);
+ if (!xdr_int(xdrs, &objp->cnt))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->members, SMB_GROUP_PER_LIST,
+ sizeof (members_list), (xdrproc_t)xdr_members_list))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ntpriv_t(xdrs, objp)
+ XDR *xdrs;
+ ntpriv_t *objp;
+{
+ if (!xdr_uint32_t(xdrs, &objp->id))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->name, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_privs_t(xdrs, objp)
+ XDR *xdrs;
+ privs_t *objp;
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof (ntpriv_t),
+ (xdrproc_t)xdr_ntpriv_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ntpriv_list_t(xdrs, objp)
+ XDR *xdrs;
+ ntpriv_list_t *objp;
+{
+ if (!xdr_int(xdrs, &objp->cnt))
+ return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->privs, objp->cnt,
+ sizeof (privs_t), (xdrproc_t)xdr_privs_t))
+ return (FALSE);
+ return (TRUE);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_ht.c b/usr/src/lib/smbsrv/libsmb/common/smb_ht.c
new file mode 100644
index 0000000000..d167931539
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_ht.c
@@ -0,0 +1,639 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Generic hash table library. The hash table is an array of pointers
+ * to items. Hash collisions are handled using linked lists from the
+ * table entries. A handle is associated with each table, which is used
+ * to maintain the hash table.
+ *
+ * +------+ +-------+ +----+ +----+
+ * |handle|---> |index 0|--->|item|--->|item|--->
+ * | ... | +-------+ +----+ +----+
+ * | ... | |index 1|--->
+ * +------+ +-------+ +----+ +----+ +----+
+ * |index 2|--->|item|--->|item|--->|item|--->
+ * +-------+ +----+ +----+ +----+
+ * | ... |--->
+ * +-------+
+ * | ... |--->
+ * +-------+
+ * |index n|--->
+ * +-------+
+ *
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <smbsrv/hash_table.h>
+
+static size_t ht_default_hash(HT_HANDLE *handle, const char *key);
+
+/*
+ * ht_is_power2
+ *
+ * Inline function to determine if a value is a power of two. This
+ * function is used by the library to validate the table size when
+ * a new table is created.
+ *
+ * Returns 1 if value given is power of two, otherwise returns 0.
+ */
+static size_t
+ht_is_power2(size_t value)
+{
+ return (((value & (value - 1)) == 0)? 1 : 0);
+}
+
+
+/*
+ * ht_create_table
+ *
+ * Create a hash table. The table size must be a positive integer and
+ * must be a power of two. The key size must be a positive integer.
+ * For null terminated keys, the key size does not need to include the
+ * null terminating character. The type of key is indicated by the
+ * flags (see hash_table.h).
+ *
+ * The handle and the table are are malloc'd using a single call, to
+ * avoid two allocations. The table is located immediately after the
+ * handle.
+ *
+ * On success a pointer to an opaque handle is returned. Otherwise a
+ * null pointer is returned.
+ */
+HT_HANDLE *
+ht_create_table(size_t table_size, size_t key_size, size_t flags)
+{
+ HT_HANDLE *ht;
+ size_t msize;
+ size_t i;
+
+ if ((table_size == 0) || (key_size == 0))
+ return (NULL);
+
+ if (ht_is_power2(table_size) == 0)
+ return (NULL);
+
+ msize = sizeof (HT_HANDLE) + (sizeof (HT_TABLE_ENTRY) * table_size);
+
+ if ((ht = (HT_HANDLE *)malloc(msize)) == 0)
+ return (NULL);
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ht->ht_table = (HT_TABLE_ENTRY *)((char *)ht + sizeof (HT_HANDLE));
+ ht->ht_table_size = table_size;
+ ht->ht_table_mask = table_size - 1;
+ ht->ht_key_size = key_size;
+ ht->ht_total_items = 0;
+ ht->ht_flags = flags;
+ ht->ht_hash = ht_default_hash;
+ ht->ht_callback = 0;
+ ht->ht_sequence = random();
+ ht->ht_cmp = ((flags & HTHF_FIXED_KEY) == 0)
+ ? (HT_CMP)strncmp : (HT_CMP)memcmp;
+
+ for (i = 0; i < table_size; i++)
+ bzero(&ht->ht_table[i], sizeof (HT_TABLE_ENTRY));
+
+ return (ht);
+}
+
+
+/*
+ * ht_destroy_table
+ *
+ * Destroy a hash table. All entries in the table are removed, which
+ * may invoke the callback if it's installed, and the memory is freed.
+ */
+void
+ht_destroy_table(HT_HANDLE *handle)
+{
+ HT_ITEM *item;
+ HT_ITERATOR iterator;
+
+ if (handle == 0)
+ return;
+
+ /* To remove marked entries */
+ (void) ht_clean_table(handle);
+ while ((item = ht_findfirst(handle, &iterator)) != 0)
+ (void) ht_remove_item(handle, item->hi_key);
+
+ free(handle);
+}
+
+
+/*
+ * ht_get_total_items
+ *
+ * Return the total number of items in the table. Returns -1 if the
+ * handle is invalid.
+ */
+size_t
+ht_get_total_items(HT_HANDLE *handle)
+{
+ if (handle == 0)
+ return ((size_t)-1);
+
+ return (handle->ht_total_items);
+}
+
+
+/*
+ * ht_default_hash
+ *
+ * Default hash function to compute the table index (hash value) based
+ * on the specified key. This will identify the location for the
+ * corresponding item in the hash table. The handle and key pointers
+ * should be validated before this function is called.
+ *
+ * Returns the table index location for the item.
+ */
+static size_t
+ht_default_hash(HT_HANDLE *handle, const char *key)
+{
+ unsigned int hash_ndx = 0;
+ size_t rval;
+
+ if ((handle->ht_flags & HTHF_FIXED_KEY) == 0) {
+ while (*key) {
+ hash_ndx += *key;
+ ++key;
+ }
+ } else {
+ int key_len = handle->ht_key_size;
+
+ while (key_len--) {
+ hash_ndx += *key;
+ ++key;
+ }
+ }
+
+ rval = (hash_ndx * HASH_MESH_VALUE) & handle->ht_table_mask;
+ return (rval);
+}
+
+
+/*
+ * ht_set_cmpfn
+ *
+ * Replace the current compare function. As the this is function
+ * for comparing items' key, it should not be called while there are
+ * items in the table.
+ */
+void
+ht_set_cmpfn(HT_HANDLE *handle, HT_CMP cmpfn)
+{
+ if (handle)
+ handle->ht_cmp = cmpfn;
+}
+
+/*
+ * ht_add_item
+ *
+ * Adds an item to a hash table. The hash table is identified by the
+ * handle and the key is used to generate a hashed index. The data
+ * item can be null; it is never dereferenced. We don't check for
+ * duplicates. If duplicate keys are added to the table, the last
+ * item added will be to the front of the duplicate list.
+ *
+ * The table sequence number may be modified here.
+ *
+ * If the item is successfully inserted, a pointer to the item object
+ * is returned. Otherwise a null pointer is returned.
+ */
+HT_ITEM *
+ht_add_item(HT_HANDLE *handle, const char *key, const void *data)
+{
+ size_t h_index, key_len;
+ size_t msize;
+ HT_ITEM *item;
+
+ if (handle == 0 || key == 0)
+ return (NULL);
+
+ if (handle->ht_flags & HTHF_FIXED_KEY) {
+ key_len = handle->ht_key_size;
+ } else {
+ key_len = strlen(key);
+
+ if (key_len > handle->ht_key_size)
+ return (NULL);
+
+ /* Include the null terminator */
+ ++key_len;
+ }
+
+ msize = key_len + sizeof (HT_ITEM);
+
+ if ((item = malloc(msize)) == 0)
+ return (NULL);
+
+ item->hi_key = (char *)item + sizeof (HT_ITEM);
+ (void) memcpy(item->hi_key, key, key_len);
+ item->hi_data = (void *)data;
+ item->hi_flags = 0;
+
+ h_index = handle->ht_hash(handle, key);
+
+ /*
+ * Add to the front of the list.
+ */
+ item->hi_next = handle->ht_table[h_index].he_head;
+ handle->ht_table[h_index].he_head = item;
+
+ handle->ht_table[h_index].he_count++;
+ handle->ht_total_items++;
+ handle->ht_sequence++;
+
+ return (item);
+}
+
+
+/*
+ * ht_replace_item
+ *
+ * Replace an item in a hash table. The item associated with key is removed
+ * using ht_remove_item and a new item is added using ht_add_item. We rely
+ * on parameter validation in ht_remove_item and ht_add_item.
+ *
+ * The table sequence number may be modified here.
+ */
+HT_ITEM *
+ht_replace_item(HT_HANDLE *handle, const char *key, const void *data)
+{
+ (void) ht_remove_item(handle, key);
+
+ return (ht_add_item(handle, key, data));
+}
+
+
+/*
+ * ht_remove_item
+ *
+ * Remove an item from a hash table. If there are duplicate keys, then the
+ * first key found will be deleted. Note that the data pointer is never
+ * dereferenced. If a callback is installed, it will be invoked and the
+ * return value will be null. Otherwise, the data pointer supplied by the
+ * application will be returned. If there is an error, a null pointer will
+ * be returned.
+ *
+ * The table sequence number may be modified here.
+ */
+void *
+ht_remove_item(HT_HANDLE *handle, const char *key)
+{
+ size_t h_index;
+ HT_ITEM *cur, *prev;
+ int key_len;
+ void *data = 0;
+
+ if (handle == 0 || key == 0)
+ return (NULL);
+
+ if ((handle->ht_flags & HTHF_FIXED_KEY) == 0)
+ key_len = strlen(key) + 1;
+ else
+ key_len = handle->ht_key_size;
+
+ h_index = handle->ht_hash(handle, key);
+
+ cur = handle->ht_table[h_index].he_head;
+ prev = 0;
+
+ while (cur) {
+ if (!(cur->hi_flags & HTIF_MARKED_DELETED) &&
+ (handle->ht_cmp(cur->hi_key, key, key_len) == 0)) {
+ /* found key */
+ if (prev == 0)
+ handle->ht_table[h_index].he_head =
+ cur->hi_next;
+ else
+ prev->hi_next = cur->hi_next;
+
+ if (handle->ht_callback)
+ handle->ht_callback(cur);
+ else
+ data = cur->hi_data;
+
+ /*
+ * Since the key and the item were allocated as
+ * a single chunk, we only need one free here.
+ */
+ free(cur);
+
+ handle->ht_table[h_index].he_count--;
+ handle->ht_total_items--;
+ handle->ht_sequence++;
+ break;
+ }
+
+ prev = cur;
+ cur = cur->hi_next;
+ }
+
+ return (data);
+}
+
+/*
+ * ht_find_item
+ *
+ * Find an item in a hash table. If there are duplicate keys then the
+ * first item found (which will be the last one added) will be returned.
+ *
+ * Returns a pointer to an item. Otherwise returns a null pointer to
+ * indicate an error or that the key didn't match anything in the table.
+ */
+HT_ITEM *
+ht_find_item(HT_HANDLE *handle, const char *key)
+{
+ size_t h_index;
+ HT_ITEM *cur;
+ int key_len;
+
+ if (handle == 0 || key == 0)
+ return (NULL);
+
+ if ((handle->ht_flags & HTHF_FIXED_KEY) == 0)
+ key_len = strlen(key) + 1;
+ else
+ key_len = handle->ht_key_size;
+
+ h_index = handle->ht_hash(handle, key);
+ cur = handle->ht_table[h_index].he_head;
+
+ while (cur) {
+ if (!(cur->hi_flags & HTIF_MARKED_DELETED) &&
+ (handle->ht_cmp(cur->hi_key, key, key_len) == 0))
+ return (cur);
+
+ cur = cur->hi_next;
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * ht_register_callback
+ *
+ * Register an application callback function that can be used to process
+ * an item when it is removed from the table, i.e. free any memory
+ * allocated for that data item.
+ *
+ * The previous callback function pointer, which may be null, before
+ * registering the new one. This provides the caller with the option to
+ * restore a previous callback as required.
+ */
+HT_CALLBACK
+ht_register_callback(HT_HANDLE *handle, HT_CALLBACK callback)
+{
+ HT_CALLBACK old_callback;
+
+ if (handle == 0)
+ return (NULL);
+
+ old_callback = handle->ht_callback;
+ handle->ht_callback = callback;
+
+ return (old_callback);
+}
+
+
+/*
+ * ht_clean_table
+ *
+ * This function removes all the items that are marked for deletion. Note
+ * that this will invoke the callback, if one has been installed. If this
+ * call is used, the callback mechanism is the only way for an application
+ * to free the item data if it was dynamically allocated.
+ *
+ * The table sequence number may be modified here.
+ *
+ * Returns 0 if the handle is valid; otherwise returns -1.
+ */
+size_t
+ht_clean_table(HT_HANDLE *handle)
+{
+ size_t i;
+ HT_ITEM *cur, *prev;
+
+ if (handle == 0)
+ return ((size_t)-1);
+
+ for (i = 0; i < handle->ht_table_size; i++) {
+ cur = handle->ht_table[i].he_head;
+ prev = 0;
+
+ while (cur) {
+ if (cur->hi_flags & HTIF_MARKED_DELETED) {
+ /*
+ * We have a marked item: remove it.
+ */
+ if (prev == 0)
+ handle->ht_table[i].he_head =
+ cur->hi_next;
+ else
+ prev->hi_next = cur->hi_next;
+
+ if (handle->ht_callback)
+ handle->ht_callback(cur);
+
+ /*
+ * Since the key and the item were allocated as
+ * a single chunk, we only need one free here.
+ */
+ free(cur);
+
+ handle->ht_table[i].he_count--;
+ handle->ht_sequence++;
+
+ if (prev == 0)
+ cur = handle->ht_table[i].he_head;
+ else
+ cur = prev->hi_next;
+ continue;
+ }
+
+ prev = cur;
+ cur = cur->hi_next;
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * ht_mark_delete
+ *
+ * This function marks an item for deletion, which may be useful when
+ * using findfirst/findnext to avoid modifying the table during the
+ * table scan. Marked items can be removed later using ht_clean_table.
+ */
+void
+ht_mark_delete(HT_HANDLE *handle, HT_ITEM *item)
+{
+ if (handle && item) {
+ item->hi_flags |= HTIF_MARKED_DELETED;
+ handle->ht_total_items--;
+ }
+}
+
+/*
+ * ht_clear_delete
+ *
+ * This function clear an item from marked for deletion list.
+ */
+void
+ht_clear_delete(HT_HANDLE *handle, HT_ITEM *item)
+{
+ if (handle && item) {
+ item->hi_flags &= ~HTIF_MARKED_DELETED;
+ handle->ht_total_items++;
+ }
+}
+
+/*
+ * ht_bucket_search
+ *
+ * Returns first item which is not marked as deleted
+ * in the specified bucket by 'head'
+ */
+static HT_ITEM *
+ht_bucket_search(HT_ITEM *head)
+{
+ HT_ITEM *item = head;
+ while ((item != 0) && (item->hi_flags & HTIF_MARKED_DELETED))
+ item = item->hi_next;
+
+ return (item);
+}
+
+/*
+ * ht_findfirst
+ *
+ * This function is used to begin an iteration through the hash table.
+ * The iterator is initialized and the first item in the table (as
+ * determined by the hash algorithm) is returned. The current sequence
+ * number is stored in the iterator to determine whether or not the
+ * the table has changed between calls. If the table is empty, a null
+ * pointer is returned.
+ */
+HT_ITEM *
+ht_findfirst(HT_HANDLE *handle, HT_ITERATOR *iterator)
+{
+ HT_ITEM *item;
+ size_t h_index;
+
+ if (handle == 0 || iterator == 0 || handle->ht_total_items == 0)
+ return (NULL);
+
+ (void) memset(iterator, 0, sizeof (HT_ITERATOR));
+ iterator->hti_handle = handle;
+ iterator->hti_sequence = handle->ht_sequence;
+
+ for (h_index = 0; h_index < handle->ht_table_size; ++h_index) {
+ item = ht_bucket_search(handle->ht_table[h_index].he_head);
+ if (item != 0) {
+ iterator->hti_index = h_index;
+ iterator->hti_item = item;
+ return (item);
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * ht_findnext
+ *
+ * Find the next item in the table for the given iterator. Iterators must
+ * be initialized by ht_findfirst, which will also return the first item
+ * in the table. If an item is available, a pointer to it is returned.
+ * Otherwise a null pointer is returned. A null pointer may indicate:
+ *
+ * - an invalid iterator (i.e. ht_findfirst has not been called)
+ * - the table has changed since the previous findfirst/findnext
+ * - the entire table has been traversed
+ *
+ * The caller can use ht_get_total_items to determine whether or not all
+ * of the items in the table have been visited.
+ */
+HT_ITEM *
+ht_findnext(HT_ITERATOR *iterator)
+{
+ HT_HANDLE *handle;
+ HT_ITEM *item;
+ size_t total;
+ size_t index;
+
+ if (iterator == 0 || iterator->hti_handle == 0 ||
+ iterator->hti_sequence == 0) {
+ /* Invalid iterator */
+ return (NULL);
+ }
+
+ handle = iterator->hti_handle;
+
+ if (iterator->hti_item == 0 ||
+ iterator->hti_sequence != handle->ht_sequence) {
+ /*
+ * No more items or the table has changed
+ * since the last call.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Check for another item in the current bucket.
+ */
+ item = ht_bucket_search(iterator->hti_item->hi_next);
+ if (item != 0) {
+ iterator->hti_item = item;
+ return (item);
+ }
+
+ /*
+ * Nothing else in the current bucket. Look for another
+ * bucket with something in it and return the head item.
+ */
+ total = handle->ht_table_size;
+ for (index = iterator->hti_index + 1; index < total; ++index) {
+ item = ht_bucket_search(handle->ht_table[index].he_head);
+ if (item != 0) {
+ iterator->hti_index = index;
+ iterator->hti_item = item;
+ return (item);
+ }
+ }
+
+ iterator->hti_index = 0;
+ iterator->hti_item = 0;
+ iterator->hti_sequence = 0;
+ return (NULL);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c b/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c
new file mode 100644
index 0000000000..f410fe3237
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c
@@ -0,0 +1,382 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+#include <smbsrv/libsmb.h>
+
+static idmap_handle_t *idmap_clnt_hdl = NULL;
+static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
+
+/*
+ * smb_idmap_start
+ *
+ * This function initializes the idmap client handle. It should be called
+ * at startup.
+ */
+int
+smb_idmap_start(void)
+{
+ idmap_stat stat;
+
+ if (idmap_clnt_hdl)
+ return (0);
+
+ stat = idmap_init(&idmap_clnt_hdl);
+ if (stat < 0) {
+ syslog(LOG_ERR, "smb_idmap_start: idmap_init failed (%s)",
+ idmap_stat2string(NULL, stat));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_idmap_stop
+ *
+ * This function destroys the idmap client handle. It should be called
+ * prior to exiting the SMB daemon.
+ */
+void
+smb_idmap_stop(void)
+{
+ if (idmap_clnt_hdl) {
+ (void) idmap_fini(idmap_clnt_hdl);
+ idmap_clnt_hdl = NULL;
+ }
+}
+
+/*
+ * smb_idmap_restart
+ *
+ * This function should be called when the idmap client handle
+ * becomes invalid.
+ */
+int
+smb_idmap_restart(void)
+{
+ smb_idmap_stop();
+ if (smb_idmap_start() != 0) {
+ syslog(LOG_ERR, "smb_idmap_restart: smb_idmap_start failed");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_idmap_getsid
+ *
+ * Tries to get a mapping for the given uid/gid
+ */
+idmap_stat
+smb_idmap_getsid(uid_t id, int idtype, nt_sid_t **sid)
+{
+ smb_idmap_batch_t sib;
+ idmap_stat stat;
+
+ stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_ID2SID);
+ if (stat != IDMAP_SUCCESS)
+ return (stat);
+
+ stat = smb_idmap_batch_getsid(sib.sib_idmaph, &sib.sib_maps[0],
+ id, idtype);
+
+ if (stat != IDMAP_SUCCESS) {
+ smb_idmap_batch_destroy(&sib);
+ return (stat);
+ }
+
+ stat = smb_idmap_batch_getmappings(&sib);
+
+ if (stat != IDMAP_SUCCESS) {
+ smb_idmap_batch_destroy(&sib);
+ return (stat);
+ }
+
+ *sid = nt_sid_dup(sib.sib_maps[0].sim_sid);
+
+ smb_idmap_batch_destroy(&sib);
+
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * smb_idmap_batch_create
+ *
+ * Creates and initializes the context for batch ID mapping.
+ */
+idmap_stat
+smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
+{
+ idmap_stat stat;
+
+ if (!sib)
+ return (IDMAP_ERR_ARG);
+
+ bzero(sib, sizeof (smb_idmap_batch_t));
+ stat = idmap_get_create(idmap_clnt_hdl, &sib->sib_idmaph);
+ if (stat != IDMAP_SUCCESS)
+ return (stat);
+
+ sib->sib_flags = flags;
+ sib->sib_nmap = nmap;
+ sib->sib_size = nmap * sizeof (smb_idmap_t);
+ sib->sib_maps = malloc(sib->sib_size);
+ if (!sib->sib_maps)
+ return (IDMAP_ERR_MEMORY);
+
+ bzero(sib->sib_maps, sib->sib_size);
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * smb_idmap_batch_destroy
+ *
+ * Frees the batch ID mapping context.
+ */
+void
+smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
+{
+ nt_sid_t *sid;
+ char *domsid;
+ int i;
+
+ if (!sib)
+ return;
+
+ if (sib->sib_idmaph) {
+ idmap_get_destroy(sib->sib_idmaph);
+ sib->sib_idmaph = NULL;
+ }
+
+ if (!sib->sib_maps)
+ return;
+
+ switch (sib->sib_flags) {
+ case SMB_IDMAP_SID2ID:
+ /*
+ * SIDs are allocated only when mapping
+ * UID/GID to SIDs
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ sid = sib->sib_maps[i].sim_sid;
+ if (sid)
+ free(sid);
+ }
+ break;
+ case SMB_IDMAP_ID2SID:
+ /*
+ * SID prefixes are allocated only when mapping
+ * SIDs to UID/GID
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ domsid = sib->sib_maps[i].sim_domsid;
+ if (domsid)
+ free(domsid);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (sib->sib_size && sib->sib_maps) {
+ free(sib->sib_maps);
+ sib->sib_maps = NULL;
+ }
+}
+
+/*
+ * smb_idmap_batch_getid
+ *
+ * Queue a request to map the given SID to a UID or GID.
+ *
+ * sim->sim_id should point to variable that's supposed to
+ * hold the returned UID/GID. This needs to be setup by caller
+ * of this function.
+ * If requested ID type is known, it's passed as 'idtype',
+ * if it's unknown it'll be returned in sim->sim_idtype.
+ */
+idmap_stat
+smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
+ nt_sid_t *sid, int idtype)
+{
+ nt_sid_t *tmpsid;
+ idmap_stat stat;
+ int flag = 0;
+
+ if (!idmaph || !sim || !sid)
+ return (IDMAP_ERR_ARG);
+
+ tmpsid = nt_sid_dup(sid);
+ if (!tmpsid)
+ return (IDMAP_ERR_MEMORY);
+
+ if (nt_sid_split(tmpsid, &sim->sim_rid) != 0) {
+ free(tmpsid);
+ return (IDMAP_ERR_ARG);
+ }
+
+ sim->sim_domsid = nt_sid_format(tmpsid);
+ free(tmpsid);
+
+ switch (idtype) {
+ case SMB_IDMAP_USER:
+ stat = idmap_get_uidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ stat = idmap_get_gidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_UNKNOWN:
+ stat = idmap_get_pidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, flag, sim->sim_id, &sim->sim_idtype,
+ &sim->sim_stat);
+ break;
+
+ default:
+ return (IDMAP_ERR_ARG);
+ }
+
+ return (stat);
+}
+
+/*
+ * smb_idmap_batch_getsid
+ *
+ * Queue a request to map the given UID/GID to a SID.
+ *
+ * sim->sim_domsid and sim->sim_rid will contain the mapping
+ * result upon successful process of the batched request.
+ */
+idmap_stat
+smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
+ uid_t id, int idtype)
+{
+ idmap_stat stat;
+ int flag = 0;
+
+ if (!idmaph || !sim)
+ return (IDMAP_ERR_ARG);
+
+ switch (idtype) {
+ case SMB_IDMAP_USER:
+ stat = idmap_get_sidbyuid(idmaph, id, flag,
+ &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ stat = idmap_get_sidbygid(idmaph, id, flag,
+ &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_EVERYONE:
+ /* Everyone S-1-1-0 */
+ sim->sim_domsid = "S-1-1";
+ sim->sim_rid = 0;
+ sim->sim_stat = IDMAP_SUCCESS;
+ stat = IDMAP_SUCCESS;
+ break;
+
+ default:
+ return (IDMAP_ERR_ARG);
+ }
+
+ return (stat);
+}
+
+/*
+ * smb_idmap_batch_getmappings
+ *
+ * trigger ID mapping service to get the mappings for queued
+ * requests.
+ *
+ * Checks the result of all the queued requests.
+ */
+idmap_stat
+smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
+{
+ idmap_stat stat = IDMAP_SUCCESS;
+ int i;
+
+ stat = idmap_get_mappings(sib->sib_idmaph);
+ if (stat != IDMAP_SUCCESS) {
+ return (stat);
+ }
+
+ /*
+ * Check the status for all the queued requests
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS) {
+ return (sib->sib_maps[i].sim_stat);
+ }
+ }
+
+ if (smb_idmap_batch_binsid(sib) != 0) {
+ stat = IDMAP_ERR_OTHER;
+ }
+
+ return (stat);
+}
+
+/*
+ * smb_idmap_batch_binsid
+ *
+ * Convert sidrids to binary sids
+ *
+ * Returns 0 if successful and non-zero upon failure.
+ */
+static int
+smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
+{
+ nt_sid_t *sid;
+ smb_idmap_t *sim;
+ int i;
+
+ if (sib->sib_flags & SMB_IDMAP_SID2ID)
+ /* This operation is not required */
+ return (0);
+
+ sim = sib->sib_maps;
+ for (i = 0; i < sib->sib_nmap; sim++, i++) {
+ if (sim->sim_domsid == NULL)
+ return (-1);
+
+ sid = nt_sid_strtosid(sim->sim_domsid);
+ if (sid == NULL)
+ return (-1);
+
+ sim->sim_sid = nt_sid_splice(sid, sim->sim_rid);
+ free(sid);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_info.c b/usr/src/lib/smbsrv/libsmb/common/smb_info.c
new file mode 100644
index 0000000000..24d7b1b3d1
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c
@@ -0,0 +1,382 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <synch.h>
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <sys/sockio.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/netbios.h>
+#include <smbsrv/libsmb.h>
+
+static smb_ntdomain_t smbpdc_cache;
+static mutex_t smbpdc_mtx;
+static cond_t smbpdc_cv;
+
+extern int getdomainname(char *, int);
+
+uint32_t
+smb_get_security_mode()
+{
+ uint32_t mode;
+
+ smb_config_rdlock();
+ mode = smb_config_get_secmode();
+ smb_config_unlock();
+
+ return (mode);
+}
+
+/*
+ * smb_purge_domain_info
+ *
+ * Clean out the environment in preparation for joining a domain.
+ * This ensures that we don't have any old information lying around.
+ */
+void
+smb_purge_domain_info(void)
+{
+ smb_config_wrlock();
+ (void) smb_config_set(SMB_CI_DOMAIN_NAME, 0);
+ (void) smb_config_set(SMB_CI_DOMAIN_SID, 0);
+ (void) smb_config_set(SMB_CI_DOMAIN_MEMB, 0);
+ smb_config_unlock();
+}
+
+int
+smb_is_domain_member(void)
+{
+ int is_memb;
+
+ smb_config_rdlock();
+ is_memb = smb_config_getyorn(SMB_CI_DOMAIN_MEMB);
+ smb_config_unlock();
+
+ return (is_memb);
+}
+
+uint8_t
+smb_get_fg_flag(void)
+{
+ uint8_t run_fg;
+
+ smb_config_rdlock();
+ run_fg = smb_config_get_fg_flag();
+ smb_config_unlock();
+
+ return (run_fg);
+}
+
+void
+smb_set_domain_member(int set)
+{
+ char *member;
+
+ smb_config_wrlock();
+ member = (set) ? "true" : "false";
+ (void) smb_config_set(SMB_CI_DOMAIN_MEMB, member);
+ smb_config_unlock();
+}
+
+/*
+ * smb_getdomaininfo
+ *
+ * Returns a pointer to the cached domain data. The caller can specify
+ * whether or not he is prepared to wait if the cache is not yet valid
+ * and for how long. The specified timeout is in seconds.
+ */
+smb_ntdomain_t *
+smb_getdomaininfo(uint32_t timeout)
+{
+ timestruc_t to;
+ int err;
+
+ if (timeout != 0) {
+ (void) mutex_lock(&smbpdc_mtx);
+ while (smbpdc_cache.ipaddr == 0) {
+ to.tv_sec = timeout;
+ to.tv_nsec = 0;
+ err = cond_reltimedwait(&smbpdc_cv, &smbpdc_mtx, &to);
+ if (err == ETIME)
+ break;
+ }
+ (void) mutex_unlock(&smbpdc_mtx);
+ }
+
+ if (smbpdc_cache.ipaddr != 0)
+ return (&smbpdc_cache);
+ else
+ return (0);
+}
+
+void
+smb_logdomaininfo(smb_ntdomain_t *di)
+{
+ char ipstr[16];
+
+ (void) inet_ntop(AF_INET, (const void *)&di->ipaddr, ipstr,
+ sizeof (ipstr));
+ syslog(LOG_DEBUG, "smbd: %s (%s:%s)", di->domain, di->server, ipstr);
+}
+
+/*
+ * smb_setdomaininfo
+ *
+ * Set the information for the specified domain. If the information is
+ * non-null, the notification event is raised to wakeup any threads
+ * blocking on the cache.
+ */
+void
+smb_setdomaininfo(char *domain, char *server, uint32_t ipaddr)
+{
+ char *p;
+
+ bzero(&smbpdc_cache, sizeof (smb_ntdomain_t));
+
+ if (domain && server && ipaddr) {
+ (void) strlcpy(smbpdc_cache.domain, domain, SMB_PI_MAX_DOMAIN);
+ (void) strlcpy(smbpdc_cache.server, server, SMB_PI_MAX_DOMAIN);
+
+ /*
+ * Remove DNS domain name extension
+ * to avoid confusing NetBIOS.
+ */
+ if ((p = strchr(smbpdc_cache.domain, '.')) != 0)
+ *p = '\0';
+
+ if ((p = strchr(smbpdc_cache.server, '.')) != 0)
+ *p = '\0';
+
+ (void) mutex_lock(&smbpdc_mtx);
+ smbpdc_cache.ipaddr = ipaddr;
+ (void) cond_broadcast(&smbpdc_cv);
+ (void) mutex_unlock(&smbpdc_mtx);
+ }
+}
+
+void
+smb_load_kconfig(smb_kmod_cfg_t *kcfg)
+{
+ smb_config_rdlock();
+ bzero(kcfg, sizeof (smb_kmod_cfg_t));
+
+ kcfg->skc_maxbufsize = smb_config_getnum(SMB_CI_MAX_BUFSIZE);
+ kcfg->skc_maxworkers = smb_config_getnum(SMB_CI_MAX_WORKERS);
+ kcfg->skc_keepalive = smb_config_getnum(SMB_CI_KEEPALIVE);
+ if ((kcfg->skc_keepalive != 0) &&
+ (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN))
+ kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN;
+ kcfg->skc_restrict_anon = smb_config_getyorn(SMB_CI_RESTRICT_ANON);
+
+ kcfg->skc_signing_enable = smb_config_getyorn(SMB_CI_SIGNING_ENABLE);
+ kcfg->skc_signing_required = smb_config_getyorn(SMB_CI_SIGNING_REQD);
+ kcfg->skc_signing_check = smb_config_getyorn(SMB_CI_SIGNING_CHECK);
+
+ kcfg->skc_oplock_enable = smb_config_getyorn(SMB_CI_OPLOCK_ENABLE);
+ kcfg->skc_oplock_timeout = smb_config_getnum(SMB_CI_OPLOCK_TIMEOUT);
+
+ kcfg->skc_flush_required = smb_config_getyorn(SMB_CI_FLUSH_REQUIRED);
+ kcfg->skc_sync_enable = smb_config_getyorn(SMB_CI_SYNC_ENABLE);
+ kcfg->skc_dirsymlink_enable =
+ !smb_config_getyorn(SMB_CI_DIRSYMLINK_DISABLE);
+ kcfg->skc_announce_quota = smb_config_getyorn(SMB_CI_ANNONCE_QUOTA);
+ kcfg->skc_announce_quota = smb_config_getyorn(SMB_CI_ANNONCE_QUOTA);
+
+ kcfg->skc_secmode = smb_config_get_secmode();
+ kcfg->skc_lmlevel = smb_config_getnum(SMB_CI_LM_LEVEL);
+ kcfg->skc_maxconnections = smb_config_getnum(SMB_CI_MAX_CONNECTIONS);
+
+ (void) strlcpy(kcfg->skc_resource_domain,
+ smb_config_getstr(SMB_CI_DOMAIN_NAME),
+ sizeof (kcfg->skc_resource_domain));
+
+ (void) smb_gethostname(kcfg->skc_hostname,
+ sizeof (kcfg->skc_hostname), 1);
+
+ (void) strlcpy(kcfg->skc_system_comment,
+ smb_config_getstr(SMB_CI_SYS_CMNT),
+ sizeof (kcfg->skc_system_comment));
+
+ smb_config_unlock();
+}
+
+/*
+ * Get the current system NetBIOS name. The hostname is truncated at
+ * the first `.` or 15 bytes, whichever occurs first, and converted
+ * to uppercase (by smb_gethostname). Text that appears after the
+ * first '.' is considered to be part of the NetBIOS scope.
+ *
+ * Returns 0 on success, otherwise -1 to indicate an error.
+ */
+int
+smb_getnetbiosname(char *buf, size_t buflen)
+{
+ if (smb_gethostname(buf, buflen, 1) != 0)
+ return (-1);
+
+ if (buflen >= NETBIOS_NAME_SZ)
+ buf[NETBIOS_NAME_SZ - 1] = '\0';
+
+ return (0);
+}
+
+/*
+ * Get the current system node name. The returned name is guaranteed
+ * to be null-terminated (gethostname may not null terminate the name).
+ * If the hostname has been fully-qualified for some reason, the domain
+ * part will be removed. If the caller would like the name in upper
+ * case, it is folded to uppercase.
+ *
+ * If gethostname fails, the returned buffer will contain an empty
+ * string.
+ */
+int
+smb_gethostname(char *buf, size_t buflen, int upcase)
+{
+ char *p;
+
+ if (buf == NULL || buflen == 0)
+ return (-1);
+
+ if (gethostname(buf, buflen) != 0) {
+ *buf = '\0';
+ return (-1);
+ }
+
+ buf[buflen - 1] = '\0';
+
+ if ((p = strchr(buf, '.')) != NULL)
+ *p = '\0';
+
+ if (upcase)
+ (void) utf8_strupr(buf);
+
+ return (0);
+}
+
+/*
+ * The ADS domain is often the same as the DNS domain but they can be
+ * different - one might be a sub-domain of the other.
+ *
+ * If an ADS domain name has been configured, return it. Otherwise,
+ * return the DNS domain name.
+ *
+ * If getdomainname fails, the returned buffer will contain an empty
+ * string.
+ */
+int
+smb_getdomainname(char *buf, size_t buflen)
+{
+ char *domain;
+
+ if (buf == NULL || buflen == 0)
+ return (-1);
+
+ smb_config_rdlock();
+
+ domain = smb_config_getstr(SMB_CI_ADS_DOMAIN);
+ if ((domain != NULL) && (*domain != '\0')) {
+ (void) strlcpy(buf, domain, buflen);
+ smb_config_unlock();
+ return (0);
+ }
+
+ smb_config_unlock();
+
+ if (getdomainname(buf, buflen) != 0) {
+ *buf = '\0';
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Obtain the fully-qualified name for this machine. If the
+ * hostname is fully-qualified, accept it. Otherwise, try to
+ * find an appropriate domain name to append to the hostname.
+ */
+int
+smb_getfqhostname(char *buf, size_t buflen)
+{
+ char hostname[MAXHOSTNAMELEN];
+ char domain[MAXHOSTNAMELEN];
+
+ hostname[0] = '\0';
+ domain[0] = '\0';
+
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0)
+ return (-1);
+
+ if (smb_getdomainname(domain, MAXHOSTNAMELEN) != 0)
+ return (-1);
+
+ if (hostname[0] == '\0')
+ return (-1);
+
+ if (domain[0] == '\0') {
+ (void) strlcpy(buf, hostname, buflen);
+ return (0);
+ }
+
+ (void) snprintf(buf, buflen, "%s.%s", hostname, domain);
+ return (0);
+}
+
+/*
+ * Temporary fbt for dtrace until user space sdt enabled.
+ */
+void
+smb_tracef(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[128];
+
+ va_start(ap, fmt);
+ (void) vsnprintf(buf, 128, fmt, ap);
+ va_end(ap);
+
+ smb_trace(buf);
+}
+
+/*
+ * Temporary fbt for dtrace until user space sdt enabled.
+ */
+void
+smb_trace(const char *s)
+{
+ syslog(LOG_DEBUG, "%s", s);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_mac.c b/usr/src/lib/smbsrv/libsmb/common/smb_mac.c
new file mode 100644
index 0000000000..57fb74530c
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_mac.c
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB MAC Signing support.
+ */
+
+#include <strings.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+
+#include <smbsrv/libsmb.h>
+
+#include <smbsrv/smb.h>
+
+/*
+ * smb_mac_init
+ *
+ * Calculates the MAC key using the specified user session
+ * key (NTLM or NTLMv2).
+ *
+ * Returns SMBAUTH_SUCCESS if key generation was successful,
+ * SMBAUTH_FAILURE if not.
+ */
+int
+smb_mac_init(smb_sign_ctx_t *sign_ctx, smb_auth_info_t *auth)
+{
+ unsigned char S16[SMBAUTH_SESSION_KEY_SZ];
+
+ if (smb_auth_gen_session_key(auth, S16) != SMBAUTH_SUCCESS)
+ return (SMBAUTH_FAILURE);
+ bcopy(S16, sign_ctx->ssc_mackey, SMBAUTH_SESSION_KEY_SZ);
+ bcopy(auth->cs, &(sign_ctx->ssc_mackey[SMBAUTH_SESSION_KEY_SZ]),
+ auth->cs_len);
+ sign_ctx->ssc_keylen = SMBAUTH_SESSION_KEY_SZ + auth->cs_len;
+ return (SMBAUTH_SUCCESS);
+}
+
+/*
+ * smb_mac_calc
+ *
+ * Calculates MAC signature for the given buffer and returns
+ * it in the mac_sign parameter.
+ *
+ * The MAC signature is calculated as follows:
+ *
+ * data = concat(MAC_Key, MAC_Key_Len, SMB_Msg, SMB_Msg_Len);
+ * hash = MD5(data);
+ * MAC = head(hash, 8);
+ *
+ * The tricky part is that a sequence number should be used
+ * in calculation instead of the signature field in the
+ * SMB header.
+ *
+ * Returns SMBAUTH_SUCCESS if cryptology framework use was successful,
+ * SMBAUTH_FAILURE if not.
+ */
+int
+smb_mac_calc(smb_sign_ctx_t *sign_ctx, const unsigned char *buf,
+ size_t buf_len, unsigned char *mac_sign)
+{
+ CK_RV rv;
+ CK_MECHANISM mechanism;
+ CK_SESSION_HANDLE hSession;
+ unsigned long diglen = MD_DIGEST_LEN;
+ int rc = SMBAUTH_FAILURE;
+
+ int offset_end_of_sig = (SMB_SIG_OFFS + SMB_SIG_SIZE);
+ unsigned char seq_buf[SMB_SIG_SIZE];
+ unsigned char mac[16];
+
+ /*
+ * put seq_num into the first 4 bytes and
+ * zero out the next 4 bytes
+ */
+ bcopy(&sign_ctx->ssc_seqnum, seq_buf, 4);
+ bzero(seq_buf + 4, 4);
+
+ mechanism.mechanism = CKM_MD5;
+ mechanism.pParameter = 0;
+ mechanism.ulParameterLen = 0;
+
+ rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
+ if (rv != CKR_OK)
+ return (SMBAUTH_FAILURE);
+
+ /* Initialize the digest operation in the session */
+ rv = C_DigestInit(hSession, &mechanism);
+ if (rv != CKR_OK)
+ goto smbmacdone;
+
+ /* init with the MAC key */
+ rv = C_DigestUpdate(hSession, sign_ctx->ssc_mackey,
+ sign_ctx->ssc_keylen);
+ if (rv != CKR_OK)
+ goto smbmacdone;
+
+ /* copy in SMB packet info till signature field */
+ rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf, SMB_SIG_OFFS);
+ if (rv != CKR_OK)
+ goto smbmacdone;
+
+ /* copy in the seq_buf instead of the signature */
+ rv = C_DigestUpdate(hSession, seq_buf, sizeof (seq_buf));
+ if (rv != CKR_OK)
+ goto smbmacdone;
+
+ /* copy in the rest of the packet, skipping the signature */
+ rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf + offset_end_of_sig,
+ buf_len - offset_end_of_sig);
+ if (rv != CKR_OK)
+ goto smbmacdone;
+
+ rv = C_DigestFinal(hSession, mac, &diglen);
+ if (rv != CKR_OK)
+ goto smbmacdone;
+
+ bcopy(mac, mac_sign, SMB_SIG_SIZE);
+ rc = SMBAUTH_SUCCESS;
+
+smbmacdone:
+ (void) C_CloseSession(hSession);
+ return (rc);
+}
+
+/*
+ * smb_mac_chk
+ *
+ * Calculates MAC signature for the given buffer
+ * and compares it to the signature in the given context.
+ * Return 1 if the signature are match, otherwise, return (0);
+ */
+int
+smb_mac_chk(smb_sign_ctx_t *sign_ctx,
+ const unsigned char *buf, size_t buf_len)
+{
+ unsigned char mac_sign[SMB_SIG_SIZE];
+
+ /* calculate mac signature */
+ if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS)
+ return (0);
+
+ /* compare the signatures */
+ if (memcmp(sign_ctx->ssc_sign, mac_sign, SMB_SIG_SIZE) == 0)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * smb_mac_sign
+ *
+ * Calculates MAC signature for the given buffer,
+ * and write it to the buffer's signature field.
+ *
+ * Returns SMBAUTH_SUCCESS if cryptology framework use was successful,
+ * SMBAUTH_FAILURE if not.
+ */
+int
+smb_mac_sign(smb_sign_ctx_t *sign_ctx, unsigned char *buf, size_t buf_len)
+{
+ unsigned char mac_sign[SMB_SIG_SIZE];
+
+ /* calculate mac signature */
+ if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS)
+ return (SMBAUTH_FAILURE);
+
+ /* put mac signature in the header's signature field */
+ (void) memcpy(buf + SMB_SIG_OFFS, mac_sign, SMB_SIG_SIZE);
+ return (SMBAUTH_SUCCESS);
+}
+
+void
+smb_mac_inc_seqnum(smb_sign_ctx_t *sign_ctx)
+{
+ sign_ctx->ssc_seqnum++;
+}
+
+void
+smb_mac_dec_seqnum(smb_sign_ctx_t *sign_ctx)
+{
+ sign_ctx->ssc_seqnum--;
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_privilege.c b/usr/src/lib/smbsrv/libsmb/common/smb_privilege.c
new file mode 100644
index 0000000000..ce7cef198a
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_privilege.c
@@ -0,0 +1,361 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the interface to the built-in privilege names
+ * and id's. NT privileges are known on the network using strings. Each
+ * system assigns locally unique identifiers (LUID) for use within the
+ * system. Each built-in privilege also has a display-name, which is a
+ * short description of the privilege. The functions here provide an
+ * interface to map between LUIDs, names and display names.
+ */
+
+#include <string.h>
+#include <syslog.h>
+
+#include <smbsrv/string.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/smb_privilege.h>
+
+#define SMB_PRIV_MIN 2
+#define SMB_PRIV_MAX 24
+
+static char *smb_priv_getname(uint32_t id);
+
+/*
+ * Table of built-in privilege id's, names and display strings. This
+ * table matches the response from an NT4.0 PDC LSARPC service.
+ * Requests for values 0 and 1 return STATUS_NO_SUCH_PRIVILEGE.
+ *
+ * SE_UNSOLICITED_INPUT_NAME/SeUnsolicitedInputPrivilege is defined in
+ * winnt.h but doesn't appear in the list reported by the NT4.0 LSA.
+ */
+static smb_privinfo_t priv_table[] = {
+ { 0, "", "", 0 },
+ { 1, "", "", 0 },
+ { 2, SE_CREATE_TOKEN_NAME, "Create a token object", 0 },
+ { 3, SE_ASSIGNPRIMARYTOKEN_NAME, "Replace a process level token", 0 },
+ { 4, SE_LOCK_MEMORY_NAME, "Lock pages in memory", 0 },
+ { 5, SE_INCREASE_QUOTA_NAME, "Increase quotas", 0 },
+ { 6, SE_MACHINE_ACCOUNT_NAME, "Add workstations to domain", 0 },
+ { 7, SE_TCB_NAME, "Act as part of the operating system", 0 },
+ { 8, SE_SECURITY_NAME, "Manage auditing and security log", 0 },
+ { 9, SE_TAKE_OWNERSHIP_NAME,
+ "Take ownership of files or other objects", PF_PRESENTABLE },
+ { 10, SE_LOAD_DRIVER_NAME, "Load and unload device drivers", 0 },
+ { 11, SE_SYSTEM_PROFILE_NAME, "Profile system performance", 0 },
+ { 12, SE_SYSTEMTIME_NAME, "Change the system time", 0 },
+ { 13, SE_PROF_SINGLE_PROCESS_NAME, "Profile single process", 0 },
+ { 14, SE_INC_BASE_PRIORITY_NAME, "Increase scheduling priority", 0 },
+ { 15, SE_CREATE_PAGEFILE_NAME, "Create a pagefile", 0 },
+ { 16, SE_CREATE_PERMANENT_NAME, "Create permanent shared objects", 0 },
+ { 17, SE_BACKUP_NAME, "Back up files and directories",
+ PF_PRESENTABLE },
+ { 18, SE_RESTORE_NAME, "Restore files and directories",
+ PF_PRESENTABLE },
+ { 19, SE_SHUTDOWN_NAME, "Shut down the system", 0 },
+ { 20, SE_DEBUG_NAME, "Debug programs", 0 },
+ { 21, SE_AUDIT_NAME, "Generate security audits", 0 },
+ { 22, SE_SYSTEM_ENVIRONMENT_NAME,
+ "Modify firmware environment values", 0 },
+ { 23, SE_CHANGE_NOTIFY_NAME, "Bypass traverse checking", 0 },
+ { 24, SE_REMOTE_SHUTDOWN_NAME,
+ "Force shutdown from a remote system", 0 }
+};
+
+/*
+ * smb_priv_presentable_num
+ *
+ * Returns number of presentable privileges
+ */
+int
+smb_priv_presentable_num()
+{
+ int i, num;
+
+ num = 0;
+ for (i = SMB_PRIV_MIN; i <= SMB_PRIV_MAX; i++)
+ if (priv_table[i].flags == PF_PRESENTABLE)
+ num++;
+
+ return (num);
+}
+
+/*
+ * smb_priv_presentable_ids
+ *
+ * Returns IDs of presentable privileges
+ * Returns 0 in case of invalid parameter and 1 on success.
+ */
+int
+smb_priv_presentable_ids(uint32_t *ids, int num)
+{
+ int i, j;
+
+ if (ids == NULL || num <= 0)
+ return (0);
+
+ for (i = SMB_PRIV_MIN, j = 0; i <= SMB_PRIV_MAX; i++)
+ if (priv_table[i].flags == PF_PRESENTABLE)
+ ids[j++] = priv_table[i].id;
+
+ return (1);
+}
+
+/*
+ * smb_priv_getbyvalue
+ *
+ * Return the privilege info for the specified id (low part of the LUID).
+ * Returns a null pointer if id is out-of-range.
+ */
+smb_privinfo_t *
+smb_priv_getbyvalue(uint32_t id)
+{
+ if (id < SMB_PRIV_MIN || id > SMB_PRIV_MAX)
+ return (0);
+
+ return (&priv_table[id]);
+}
+
+
+/*
+ * smb_priv_getbyname
+ *
+ * Return the privilege info for the specified name. Returns a null
+ * pointer if we can't find a matching name in the table.
+ */
+smb_privinfo_t *
+smb_priv_getbyname(char *name)
+{
+ smb_privinfo_t *entry;
+ int i;
+
+ if (name == 0)
+ return (0);
+
+ for (i = SMB_PRIV_MIN; i <= SMB_PRIV_MAX; ++i) {
+ entry = &priv_table[i];
+
+ if (utf8_strcasecmp(name, entry->name) == 0)
+ return (entry);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_privset_size
+ *
+ * Returns the memory block size needed to keep a complete
+ * set of privileges in a smb_privset_t structure.
+ */
+int
+smb_privset_size()
+{
+ int pcnt = SMB_PRIV_MAX - SMB_PRIV_MIN + 1;
+
+ return (2 * sizeof (uint32_t) +
+ pcnt * sizeof (smb_luid_attrs_t));
+}
+
+/*
+ * smb_privset_validate
+ *
+ * Validates the given privilege set structure
+ * Returns 1 if the structure is Ok, otherwise returns 0.
+ */
+int
+smb_privset_validate(smb_privset_t *privset)
+{
+ int count;
+ uint32_t i;
+
+ if (privset == 0) {
+ return (0);
+ }
+
+ count = SMB_PRIV_MAX - SMB_PRIV_MIN + 1;
+
+ if (privset->priv_cnt != count) {
+ return (0);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (privset->priv[i].luid.hi_part != 0) {
+ return (0);
+ }
+
+ if (privset->priv[i].luid.lo_part !=
+ i + SMB_PRIV_MIN) {
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+/*
+ * smb_privset_init
+ *
+ * initialize all privileges in disable state.
+ */
+void
+smb_privset_init(smb_privset_t *privset)
+{
+ int count;
+ uint32_t i;
+
+ if (privset == 0)
+ return;
+
+ count = SMB_PRIV_MAX - SMB_PRIV_MIN + 1;
+
+ privset->priv_cnt = count;
+ privset->control = 0;
+ for (i = 0; i < count; i++) {
+ privset->priv[i].luid.hi_part = 0;
+ privset->priv[i].luid.lo_part = i + SMB_PRIV_MIN;
+ privset->priv[i].attrs = 0;
+ }
+}
+
+/*
+ * smb_privset_new
+ *
+ * Allocate memory and initialize all privileges in disable state.
+ * Returns pointer to allocated space or NULL if there is not
+ * enough memory.
+ */
+smb_privset_t *
+smb_privset_new()
+{
+ smb_privset_t *privset;
+
+ privset = malloc(smb_privset_size());
+ if (privset == NULL)
+ return (NULL);
+
+ smb_privset_init(privset);
+
+ return (privset);
+}
+
+/*
+ * smb_privset_copy
+ *
+ * Copy privleges information specified by 'src' to the
+ * buffer specified by dst.
+ */
+void
+smb_privset_copy(smb_privset_t *dst, smb_privset_t *src)
+{
+ if (src == 0 || dst == 0)
+ return;
+
+ (void) memcpy(dst, src, smb_privset_size());
+}
+
+/*
+ * smb_privset_free
+ *
+ * This will free the memory allocated by the 'privset'.
+ */
+void
+smb_privset_free(smb_privset_t *privset)
+{
+ free(privset);
+}
+
+void
+smb_privset_enable(smb_privset_t *privset, uint32_t id)
+{
+ int i;
+
+ if (privset == NULL)
+ return;
+
+ for (i = 0; i < privset->priv_cnt; i++) {
+ if (privset->priv[i].luid.lo_part == id)
+ privset->priv[i].attrs = SE_PRIVILEGE_ENABLED;
+ }
+}
+
+void
+smb_privset_log(smb_privset_t *privset)
+{
+ smb_luid_t *luid;
+ int i, ecnt;
+
+ if (privset == NULL)
+ return;
+
+ for (i = 0, ecnt = 0; i < privset->priv_cnt; ++i) {
+ if (privset->priv[i].attrs != 0) {
+ ecnt++;
+ }
+ }
+
+ syslog(LOG_DEBUG, " Privilege Count: %d (Enable=%d)",
+ privset->priv_cnt, ecnt);
+
+ for (i = 0; i < privset->priv_cnt; ++i) {
+ if (privset->priv[i].attrs != 0) {
+ luid = &privset->priv[i].luid;
+ syslog(LOG_DEBUG, " %s",
+ smb_priv_getname(luid->lo_part));
+ }
+ }
+}
+
+int
+smb_privset_query(smb_privset_t *privset, uint32_t id)
+{
+ int i;
+
+ if (privset == NULL)
+ return (0);
+
+ for (i = 0; privset->priv_cnt; i++) {
+ if (privset->priv[i].luid.lo_part == id) {
+ if (privset->priv[i].attrs == SE_PRIVILEGE_ENABLED)
+ return (1);
+ else
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+static char *
+smb_priv_getname(uint32_t id)
+{
+ if (id < SMB_PRIV_MIN || id > SMB_PRIV_MAX)
+ return ("Unknown Privilege");
+
+ return (priv_table[id].name);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c
new file mode 100644
index 0000000000..10026d7418
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c
@@ -0,0 +1,529 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <strings.h>
+#include <synch.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <thread.h>
+#include <pwd.h>
+#include <smbsrv/libsmb.h>
+
+#define SMB_PASSWD "/var/smb/smbpasswd"
+#define SMB_OPASSWD "/var/smb/osmbpasswd"
+#define SMB_PASSTEMP "/var/smb/ptmp"
+#define SMB_PASSLCK "/var/smb/.pwd.lock"
+
+#define SMB_PWD_DISABLE "*DIS*"
+#define SMB_PWD_BUFSIZE 256
+
+#define S_WAITTIME 15
+
+typedef enum {
+ SMB_PWD_NAME = 0,
+ SMB_PWD_UID,
+ SMB_PWD_LMHASH,
+ SMB_PWD_NTHASH,
+ SMB_PWD_NARG
+} smb_pwdarg_t;
+
+static struct flock flock = {
+ 0, /* l_type */
+ 0, /* l_whence */
+ 0, /* l_start */
+ 0, /* l_len */
+ 0, /* l_sysid */
+ 0 /* l_pid */
+ };
+
+static pid_t lck_pid = 0; /* process's pid at last lock */
+static thread_t lck_tid = 0; /* thread that holds the lock */
+static int fildes = -1;
+static mutex_t lck_lock = DEFAULTMUTEX;
+
+typedef struct smb_pwbuf {
+ char *pw_name;
+ smb_passwd_t *pw_pwd;
+} smb_pwbuf_t;
+
+static int smb_pwd_lock(void);
+static int smb_pwd_unlock(void);
+static int smb_pwd_flck(void);
+static int smb_pwd_fulck(void);
+
+static smb_pwbuf_t *smb_pwd_fgetent(FILE *, smb_pwbuf_t *, char *, size_t);
+static int smb_pwd_fputent(FILE *, smb_pwbuf_t *);
+static int smb_pwd_chgpwent(smb_passwd_t *, const char *, int);
+static int smb_pwd_update(const char *, const char *, int);
+
+/*
+ * smb_pwd_get
+ *
+ * Returns a smb password structure for the given user name.
+ * smbpw is a pointer to a buffer allocated by the caller.
+ *
+ * Returns NULL upon failure.
+ */
+smb_passwd_t *
+smb_pwd_getpasswd(const char *name, smb_passwd_t *smbpw)
+{
+ char buf[SMB_PWD_BUFSIZE];
+ boolean_t found = B_FALSE;
+ smb_pwbuf_t pwbuf;
+ int err;
+ FILE *fp;
+
+ err = smb_pwd_lock();
+ if (err != SMB_PWE_SUCCESS)
+ return (NULL);
+
+ if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
+ (void) smb_pwd_unlock();
+ return (NULL);
+ }
+
+ pwbuf.pw_name = NULL;
+ pwbuf.pw_pwd = smbpw;
+
+ while (smb_pwd_fgetent(fp, &pwbuf, buf, sizeof (buf)) != NULL) {
+ if (strcmp(name, pwbuf.pw_name) == 0) {
+ if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)))
+ found = B_TRUE;
+ break;
+ }
+ }
+
+ (void) fclose(fp);
+ (void) smb_pwd_unlock();
+
+ if (!found) {
+ bzero(smbpw, sizeof (smb_passwd_t));
+ return (NULL);
+ }
+
+ return (smbpw);
+}
+
+/*
+ * smb_pwd_set
+ *
+ * Update/add the given user to the smbpasswd file.
+ */
+int
+smb_pwd_setpasswd(const char *name, const char *password)
+{
+ return (smb_pwd_update(name, password, 0));
+}
+
+/*
+ * smb_pwd_setcntl
+ *
+ * Change the account state. This can be making the account
+ * disable/enable or removing its LM hash.
+ */
+int
+smb_pwd_setcntl(const char *name, int control)
+{
+ if (control == 0)
+ return (SMB_PWE_SUCCESS);
+
+ return (smb_pwd_update(name, NULL, control));
+}
+
+static int
+smb_pwd_update(const char *name, const char *password, int control)
+{
+ struct stat64 stbuf;
+ FILE *src, *dst;
+ int tempfd;
+ char buf[SMB_PWD_BUFSIZE];
+ int err = SMB_PWE_SUCCESS;
+ smb_pwbuf_t pwbuf;
+ smb_passwd_t smbpw;
+ boolean_t newent = B_TRUE;
+ boolean_t user_disable = B_FALSE;
+ char uxbuf[1024];
+ struct passwd uxpw;
+ int lm_level;
+ char *lm_str;
+
+ err = smb_pwd_lock();
+ if (err != SMB_PWE_SUCCESS)
+ return (err);
+
+ if (stat64(SMB_PASSWD, &stbuf) < 0) {
+ err = SMB_PWE_STAT_FAILED;
+ goto passwd_exit;
+ }
+
+ if ((tempfd = open(SMB_PASSTEMP, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
+ err = SMB_PWE_OPEN_FAILED;
+ goto passwd_exit;
+ }
+
+ if ((dst = fdopen(tempfd, "wF")) == NULL) {
+ err = SMB_PWE_OPEN_FAILED;
+ goto passwd_exit;
+ }
+
+ if ((src = fopen(SMB_PASSWD, "rF")) == NULL) {
+ err = SMB_PWE_OPEN_FAILED;
+ (void) fclose(dst);
+ (void) unlink(SMB_PASSTEMP);
+ goto passwd_exit;
+ }
+
+ lm_str = smb_config_getenv(SMB_CI_LM_LEVEL);
+ if (lm_str) {
+ lm_level = strtoul(lm_str, 0, 10);
+ free(lm_str);
+ } else {
+ lm_level = 4;
+ }
+
+ if (lm_level >= 4)
+ control |= SMB_PWC_NOLM;
+
+ /*
+ * copy old password entries to temporary file while replacing
+ * the entry that matches "name"
+ */
+ pwbuf.pw_name = NULL;
+ pwbuf.pw_pwd = &smbpw;
+
+ while (smb_pwd_fgetent(src, &pwbuf, buf, sizeof (buf)) != NULL) {
+ if (strcmp(pwbuf.pw_name, name) == 0) {
+ err = smb_pwd_chgpwent(&smbpw, password, control);
+ if (err == SMB_PWE_USER_DISABLE)
+ user_disable = B_TRUE;
+ err = smb_pwd_fputent(dst, &pwbuf);
+ newent = B_FALSE;
+ } else {
+ err = smb_pwd_fputent(dst, &pwbuf);
+ }
+
+ if (err != SMB_PWE_SUCCESS) {
+ (void) fclose(src);
+ (void) fclose(dst);
+ goto passwd_exit;
+ }
+ }
+
+ if (newent) {
+ if (getpwnam_r(name, &uxpw, uxbuf, sizeof (uxbuf))) {
+ pwbuf.pw_name = uxpw.pw_name;
+ smbpw.pw_flags = 0;
+ smbpw.pw_uid = uxpw.pw_uid;
+ (void) smb_pwd_chgpwent(&smbpw, password, control);
+ err = smb_pwd_fputent(dst, &pwbuf);
+ } else {
+ err = SMB_PWE_USER_UNKNOWN;
+ }
+
+ if (err != SMB_PWE_SUCCESS) {
+ (void) fclose(src);
+ (void) fclose(dst);
+ goto passwd_exit;
+ }
+ }
+
+ (void) fclose(src);
+ if (fclose(dst) != 0) {
+ err = SMB_PWE_CLOSE_FAILED;
+ goto passwd_exit; /* Don't trust the temporary file */
+ }
+
+ /* Rename temp to passwd */
+ if (unlink(SMB_OPASSWD) && access(SMB_OPASSWD, 0) == 0) {
+ err = SMB_PWE_UPDATE_FAILED;
+ (void) unlink(SMB_PASSTEMP);
+ goto passwd_exit;
+ }
+
+ if (link(SMB_PASSWD, SMB_OPASSWD) == -1) {
+ err = SMB_PWE_UPDATE_FAILED;
+ (void) unlink(SMB_PASSTEMP);
+ goto passwd_exit;
+ }
+
+ if (rename(SMB_PASSTEMP, SMB_PASSWD) == -1) {
+ err = SMB_PWE_UPDATE_FAILED;
+ (void) unlink(SMB_PASSTEMP);
+ goto passwd_exit;
+ }
+
+ (void) chmod(SMB_PASSWD, 0400);
+
+passwd_exit:
+ (void) smb_pwd_unlock();
+ if ((err == SMB_PWE_SUCCESS) && user_disable)
+ err = SMB_PWE_USER_DISABLE;
+
+ return (err);
+}
+
+/*
+ * smb_getpwent
+ *
+ * Parse the buffer in the passed pwbuf and fill in the
+ * smb password structure to point to the parsed information.
+ * The entry format is:
+ *
+ * <user-name>:<user-id>:<LM hash>:<NTLM hash>
+ *
+ * Returns a pointer to the password structure on success,
+ * otherwise returns NULL.
+ */
+static smb_pwbuf_t *
+smb_pwd_fgetent(FILE *fp, smb_pwbuf_t *pwbuf, char *buf, size_t bufsize)
+{
+ char *argv[SMB_PWD_NARG];
+ smb_passwd_t *pw;
+ smb_pwdarg_t i;
+ int lm_len, nt_len;
+
+ if (fgets(buf, bufsize, fp) == NULL)
+ return (NULL);
+ (void) trim_whitespace(buf);
+
+ for (i = 0; i < SMB_PWD_NARG; ++i) {
+ if ((argv[i] = strsep((char **)&buf, ":")) == 0) {
+ return (NULL);
+ }
+ }
+
+ if ((*argv[SMB_PWD_NAME] == '\0') || (*argv[SMB_PWD_UID] == '\0'))
+ return (NULL);
+
+ pwbuf->pw_name = argv[SMB_PWD_NAME];
+ pw = pwbuf->pw_pwd;
+ bzero(pw, sizeof (smb_passwd_t));
+ pw->pw_uid = strtoul(argv[SMB_PWD_UID], 0, 10);
+
+ if (strcmp(argv[SMB_PWD_LMHASH], SMB_PWD_DISABLE) == 0) {
+ pw->pw_flags |= SMB_PWF_DISABLE;
+ (void) strcpy((char *)pw->pw_lmhash, SMB_PWD_DISABLE);
+ (void) strcpy((char *)pw->pw_nthash, SMB_PWD_DISABLE);
+ return (pwbuf);
+ }
+
+ lm_len = strlen(argv[SMB_PWD_LMHASH]);
+ if (lm_len == SMBAUTH_HEXHASH_SZ) {
+ (void) hextobin(argv[SMB_PWD_LMHASH], SMBAUTH_HEXHASH_SZ,
+ (char *)pw->pw_lmhash, SMBAUTH_HASH_SZ);
+
+ pw->pw_flags |= SMB_PWF_LM;
+ } else if (lm_len != 0) {
+ return (NULL);
+ }
+
+ nt_len = strlen(argv[SMB_PWD_NTHASH]);
+ if (nt_len == SMBAUTH_HEXHASH_SZ) {
+ (void) hextobin(argv[SMB_PWD_NTHASH], SMBAUTH_HEXHASH_SZ,
+ (char *)pw->pw_nthash, SMBAUTH_HASH_SZ);
+
+ pw->pw_flags |= SMB_PWF_NT;
+ } else if (nt_len != 0) {
+ return (NULL);
+ }
+
+ return (pwbuf);
+}
+
+static int
+smb_pwd_chgpwent(smb_passwd_t *smbpw, const char *password, int control)
+{
+ if (control & SMB_PWC_DISABLE) {
+ smbpw->pw_flags |= SMB_PWF_DISABLE;
+ (void) strcpy((char *)smbpw->pw_lmhash, SMB_PWD_DISABLE);
+ (void) strcpy((char *)smbpw->pw_nthash, SMB_PWD_DISABLE);
+ smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT);
+ return (SMB_PWE_SUCCESS);
+ } else if ((control & SMB_PWC_ENABLE) &&
+ (smbpw->pw_flags & SMB_PWF_DISABLE)) {
+ *smbpw->pw_lmhash = '\0';
+ *smbpw->pw_nthash = '\0';
+ smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT);
+ return (SMB_PWE_SUCCESS);
+ }
+
+ /* No password update if account is disabled */
+ if (smbpw->pw_flags & SMB_PWF_DISABLE)
+ return (SMB_PWE_USER_DISABLE);
+
+ if (control & SMB_PWC_NOLM) {
+ smbpw->pw_flags &= ~SMB_PWF_LM;
+ *smbpw->pw_lmhash = '\0';
+ } else {
+ smbpw->pw_flags |= SMB_PWF_LM;
+ (void) smb_auth_lm_hash((char *)password, smbpw->pw_lmhash);
+ }
+
+ smbpw->pw_flags |= SMB_PWF_NT;
+ (void) smb_auth_ntlm_hash((char *)password, smbpw->pw_nthash);
+ return (SMB_PWE_SUCCESS);
+}
+
+/*
+ * smb_putpwent
+ *
+ * Creates LM and NTLM hash from the given plain text password
+ * and write them along with user's name and Id to the smbpasswd
+ * file.
+ */
+static int
+smb_pwd_fputent(FILE *fp, smb_pwbuf_t *pwbuf)
+{
+ smb_passwd_t *pw = pwbuf->pw_pwd;
+ char hex_nthash[SMBAUTH_HEXHASH_SZ+1];
+ char hex_lmhash[SMBAUTH_HEXHASH_SZ+1];
+ int rc;
+
+ if ((pw->pw_flags & SMB_PWF_LM) == SMB_PWF_LM) {
+ (void) bintohex((char *)pw->pw_lmhash, SMBAUTH_HASH_SZ,
+ hex_lmhash, SMBAUTH_HEXHASH_SZ);
+ hex_lmhash[SMBAUTH_HEXHASH_SZ] = '\0';
+ } else {
+ (void) strcpy(hex_lmhash, (char *)pw->pw_lmhash);
+ }
+
+ if ((pw->pw_flags & SMB_PWF_NT) == SMB_PWF_NT) {
+ (void) bintohex((char *)pw->pw_nthash, SMBAUTH_HASH_SZ,
+ hex_nthash, SMBAUTH_HEXHASH_SZ);
+ hex_nthash[SMBAUTH_HEXHASH_SZ] = '\0';
+ } else {
+ (void) strcpy(hex_nthash, (char *)pw->pw_nthash);
+ }
+
+ rc = fprintf(fp, "%s:%d:%s:%s\n", pwbuf->pw_name, pw->pw_uid,
+ hex_lmhash, hex_nthash);
+
+ if (rc <= 0)
+ return (SMB_PWE_WRITE_FAILED);
+
+ return (SMB_PWE_SUCCESS);
+}
+
+static int
+smb_pwd_lock(void)
+{
+ int res;
+
+ if (smb_pwd_flck()) {
+ switch (errno) {
+ case EINTR:
+ res = SMB_PWE_BUSY;
+ break;
+ case EACCES:
+ res = SMB_PWE_DENIED;
+ break;
+ case 0:
+ res = SMB_PWE_SUCCESS;
+ break;
+ }
+ } else
+ res = SMB_PWE_SUCCESS;
+
+ return (res);
+}
+
+static int
+smb_pwd_unlock(void)
+{
+ if (smb_pwd_fulck())
+ return (SMB_PWE_SYSTEM_ERROR);
+
+ return (SMB_PWE_SUCCESS);
+}
+
+static int
+smb_pwd_flck(void)
+{
+ int seconds = 0;
+
+ (void) mutex_lock(&lck_lock);
+ for (;;) {
+ if (lck_pid != 0 && lck_pid != getpid()) {
+ /* somebody forked */
+ lck_pid = 0;
+ lck_tid = 0;
+ }
+
+ if (lck_tid == 0) {
+ if ((fildes = creat(SMB_PASSLCK, 0600)) == -1)
+ break;
+ flock.l_type = F_WRLCK;
+ if (fcntl(fildes, F_SETLK, &flock) != -1) {
+ lck_pid = getpid();
+ lck_tid = thr_self();
+ (void) mutex_unlock(&lck_lock);
+ return (0);
+ }
+ (void) close(fildes);
+ fildes = -1;
+ }
+
+ if (seconds++ >= S_WAITTIME) {
+ /*
+ * For compatibility with the past, pretend
+ * that we were interrupted by SIGALRM.
+ */
+ errno = EINTR;
+ break;
+ }
+
+ (void) mutex_unlock(&lck_lock);
+ (void) sleep(1);
+ (void) mutex_lock(&lck_lock);
+ }
+ (void) mutex_unlock(&lck_lock);
+
+ return (-1);
+}
+
+static int
+smb_pwd_fulck(void)
+{
+ (void) mutex_lock(&lck_lock);
+ if (lck_tid == thr_self() && fildes >= 0) {
+ flock.l_type = F_UNLCK;
+ (void) fcntl(fildes, F_SETLK, &flock);
+ (void) close(fildes);
+ fildes = -1;
+ lck_pid = 0;
+ lck_tid = 0;
+ (void) mutex_unlock(&lck_lock);
+ return (0);
+ }
+ (void) mutex_unlock(&lck_lock);
+ return (-1);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c b/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c
new file mode 100644
index 0000000000..1f5083f448
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c
@@ -0,0 +1,1035 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* helper functions for using libscf with CIFS */
+
+#include <libscf.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <errno.h>
+#include <libintl.h>
+#include <assert.h>
+#include <strings.h>
+
+#include <uuid/uuid.h>
+#include <sys/param.h>
+
+#include <smbsrv/alloc.h>
+
+#include <smbsrv/libsmb.h>
+
+/*
+ * smb_smf_scf_log_error(msg)
+ * Logs error messages from scf API's
+ */
+static void
+smb_smf_scf_log_error(char *msg)
+{
+ if (!msg) {
+ syslog(LOG_ERR, " SMBD SMF problem: %s\n",
+ scf_strerror(scf_error()));
+ } else { /*LINTED E_SEC_PRINTF_E_VAR_FMT*/
+ syslog(LOG_ERR, msg, scf_strerror(scf_error()));
+ }
+}
+
+/*
+ * Check if instance with given name exists for a service.
+ * Returns 0 is instance exist
+ */
+int
+smb_smf_instance_exists(smb_scfhandle_t *handle, char *inst_name)
+{
+ int ret = SMBD_SMF_OK;
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ handle->scf_instance = scf_instance_create(handle->scf_handle);
+ if (scf_service_get_instance(handle->scf_service, inst_name,
+ handle->scf_instance) != SCF_SUCCESS)
+ ret = SMBD_SMF_SYSTEM_ERR;
+
+ scf_instance_destroy(handle->scf_instance);
+ handle->scf_instance = NULL;
+ return (ret);
+}
+
+/*
+ * Create a service instance. returns 0 if successful.
+ * If instance already exists enable it.
+ */
+int
+smb_smf_instance_create(smb_scfhandle_t *handle, char *serv_prefix,
+ char *inst_name)
+{
+ char *instance;
+ int ret = SMBD_SMF_OK;
+ int sz;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ if (!serv_prefix || !inst_name)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ sz = strlen(serv_prefix) + strlen(inst_name) + 2;
+ instance = malloc(sz);
+ if (!instance)
+ return (SMBD_SMF_NO_MEMORY);
+
+ (void) snprintf(instance, sz, "%s:%s", serv_prefix, inst_name);
+ handle->scf_instance = scf_instance_create(handle->scf_handle);
+ if (scf_service_get_instance(handle->scf_service, inst_name,
+ handle->scf_instance) != SCF_SUCCESS) {
+ if (scf_service_add_instance(handle->scf_service,
+ inst_name, handle->scf_instance) == SCF_SUCCESS) {
+ if (smf_enable_instance(instance, 0))
+ ret = SMBD_SMF_SYSTEM_ERR;
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ if (smf_enable_instance(instance, 0))
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ free(instance);
+ return (ret);
+}
+
+/*
+ * Delete a specified instance. Return SMBD_SMF_OK for success.
+ */
+int
+smb_smf_instance_delete(smb_scfhandle_t *handle, char *inst_name)
+{
+ int ret = SMBD_SMF_OK;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ handle->scf_instance = scf_instance_create(handle->scf_handle);
+ if (scf_service_get_instance(handle->scf_service, inst_name,
+ handle->scf_instance) == SCF_SUCCESS) {
+ if (scf_instance_delete(handle->scf_instance) == SCF_SUCCESS) {
+ return (ret);
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ smb_smf_scf_log_error(NULL);
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ return (ret);
+}
+
+/*
+ * smb_smf_create_service_pgroup(handle, pgroup)
+ *
+ * create a new property group at service level.
+ */
+int
+smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
+{
+ int ret = SMBD_SMF_OK;
+ int err;
+
+ if (handle == NULL) {
+ return (SMBD_SMF_SYSTEM_ERR);
+ }
+
+ /*
+ * only create a handle if it doesn't exist. It is ok to exist
+ * since the pg handle will be set as a side effect.
+ */
+ if (handle->scf_pg == NULL)
+ handle->scf_pg = scf_pg_create(handle->scf_handle);
+
+ /*
+ * if the pgroup exists, we are done. If it doesn't, then we
+ * need to actually add one to the service instance.
+ */
+ if (scf_service_get_pg(handle->scf_service,
+ pgroup, handle->scf_pg) != 0) {
+ /* doesn't exist so create one */
+ if (scf_service_add_pg(handle->scf_service, pgroup,
+ SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) {
+ err = scf_error();
+ if (err != SCF_ERROR_NONE)
+ smb_smf_scf_log_error(NULL);
+ switch (err) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SMBD_SMF_NO_PERMISSION;
+ break;
+ default:
+ ret = SMBD_SMF_SYSTEM_ERR;
+ break;
+ }
+ }
+ }
+ return (ret);
+}
+
+/*
+ * smb_smf_create_instance_pgroup(handle, pgroup)
+ *
+ * create a new property group at instance level.
+ */
+int
+smb_smf_create_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
+{
+ int ret = SMBD_SMF_OK;
+ int err;
+
+ if (handle == NULL) {
+ return (SMBD_SMF_SYSTEM_ERR);
+ }
+
+ /*
+ * only create a handle if it doesn't exist. It is ok to exist
+ * since the pg handle will be set as a side effect.
+ */
+ if (handle->scf_pg == NULL)
+ handle->scf_pg = scf_pg_create(handle->scf_handle);
+
+ /*
+ * if the pgroup exists, we are done. If it doesn't, then we
+ * need to actually add one to the service instance.
+ */
+ if (scf_instance_get_pg(handle->scf_instance,
+ pgroup, handle->scf_pg) != 0) {
+ /* doesn't exist so create one */
+ if (scf_instance_add_pg(handle->scf_instance, pgroup,
+ SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) {
+ err = scf_error();
+ if (err != SCF_ERROR_NONE)
+ smb_smf_scf_log_error(NULL);
+ switch (err) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SMBD_SMF_NO_PERMISSION;
+ break;
+ default:
+ ret = SMBD_SMF_SYSTEM_ERR;
+ break;
+ }
+ }
+ }
+ return (ret);
+}
+
+/*
+ * smb_smf_delete_service_pgroup(handle, pgroup)
+ *
+ * remove the property group from the current service.
+ * but only if it actually exists.
+ */
+int
+smb_smf_delete_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
+{
+ int ret = SMBD_SMF_OK;
+ int err;
+
+ if (handle == NULL) {
+ return (SMBD_SMF_SYSTEM_ERR);
+ }
+
+ /*
+ * only create a handle if it doesn't exist. It is ok to exist
+ * since the pg handle will be set as a side effect.
+ */
+ if (handle->scf_pg == NULL)
+ handle->scf_pg = scf_pg_create(handle->scf_handle);
+
+ /*
+ * only delete if it does exist.
+ */
+ if (scf_service_get_pg(handle->scf_service,
+ pgroup, handle->scf_pg) == 0) {
+ /* does exist so delete it */
+ if (scf_pg_delete(handle->scf_pg) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ err = scf_error();
+ if (err != SCF_ERROR_NONE) {
+ smb_smf_scf_log_error("SMF delpg "
+ "problem: %s\n");
+ }
+ }
+ } else {
+ err = scf_error();
+ if (err != SCF_ERROR_NONE)
+ smb_smf_scf_log_error("SMF getpg problem: %s\n");
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (ret == SMBD_SMF_SYSTEM_ERR &&
+ scf_error() == SCF_ERROR_PERMISSION_DENIED) {
+ ret = SMBD_SMF_NO_PERMISSION;
+ }
+ return (ret);
+}
+
+/*
+ * smb_smf_delete_instance_pgroup(handle, pgroup)
+ *
+ * remove the property group from the current instance.
+ * but only if it actually exists.
+ */
+int
+smb_smf_delete_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
+{
+ int ret = SMBD_SMF_OK;
+ int err;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ /*
+ * only create a handle if it doesn't exist. It is ok to exist
+ * since the pg handle will be set as a side effect.
+ */
+ if (handle->scf_pg == NULL)
+ handle->scf_pg = scf_pg_create(handle->scf_handle);
+
+ /*
+ * only delete if it does exist.
+ */
+ if (scf_instance_get_pg(handle->scf_instance,
+ pgroup, handle->scf_pg) == 0) {
+ /* does exist so delete it */
+ if (scf_pg_delete(handle->scf_pg) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ err = scf_error();
+ if (err != SCF_ERROR_NONE) {
+ smb_smf_scf_log_error("SMF delpg "
+ "problem: %s\n");
+ }
+ }
+ } else {
+ err = scf_error();
+ if (err != SCF_ERROR_NONE)
+ smb_smf_scf_log_error("SMF getpg problem: %s\n");
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (ret == SMBD_SMF_SYSTEM_ERR &&
+ scf_error() == SCF_ERROR_PERMISSION_DENIED)
+ ret = SMBD_SMF_NO_PERMISSION;
+
+ return (ret);
+}
+
+/*
+ * Start transaction on current pg in handle.
+ * The pg could be service or instance level.
+ * Must be called after pg handle is obtained
+ * from create or get.
+ */
+int
+smb_smf_start_transaction(smb_scfhandle_t *handle)
+{
+ int ret = SMBD_SMF_OK;
+
+ if (!handle || (!handle->scf_pg))
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ /*
+ * lookup the property group and create it if it doesn't already
+ * exist.
+ */
+ if (handle->scf_state == SCH_STATE_INIT) {
+ if (ret == SMBD_SMF_OK) {
+ handle->scf_trans =
+ scf_transaction_create(handle->scf_handle);
+ if (handle->scf_trans != NULL) {
+ if (scf_transaction_start(handle->scf_trans,
+ handle->scf_pg) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ scf_transaction_destroy(
+ handle->scf_trans);
+ handle->scf_trans = NULL;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ }
+ }
+ if (ret == SMBD_SMF_SYSTEM_ERR &&
+ scf_error() == SCF_ERROR_PERMISSION_DENIED)
+ ret = SMBD_SMF_NO_PERMISSION;
+
+ return (ret);
+}
+
+/*
+ * smb_smf_end_transaction(handle)
+ *
+ * Commit the changes that were added to the transaction in the
+ * handle. Do all necessary cleanup.
+ */
+int
+smb_smf_end_transaction(smb_scfhandle_t *handle)
+{
+ int ret = SMBD_SMF_OK;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ if (handle->scf_trans == NULL) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ } else {
+ if (scf_transaction_commit(handle->scf_trans) < 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ smb_smf_scf_log_error("Failed to commit "
+ "transaction: %s");
+ }
+ scf_transaction_destroy_children(handle->scf_trans);
+ scf_transaction_destroy(handle->scf_trans);
+ handle->scf_trans = NULL;
+ }
+ return (ret);
+}
+
+/*
+ * Deletes property in current pg
+ */
+int
+smb_smf_delete_property(smb_scfhandle_t *handle, char *propname)
+{
+ int ret = SMBD_SMF_OK;
+ scf_transaction_entry_t *entry = NULL;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ /*
+ * properties must be set in transactions and don't take
+ * effect until the transaction has been ended/committed.
+ */
+ entry = scf_entry_create(handle->scf_handle);
+ if (entry != NULL) {
+ if (scf_transaction_property_delete(handle->scf_trans, entry,
+ propname) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (ret == SMBD_SMF_SYSTEM_ERR) {
+ switch (scf_error()) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SMBD_SMF_NO_PERMISSION;
+ break;
+ }
+ }
+
+ /*
+ * cleanup if there were any errors that didn't leave these
+ * values where they would be cleaned up later.
+ */
+ if ((ret != SMBD_SMF_OK) && (entry != NULL))
+ scf_entry_destroy(entry);
+
+ return (ret);
+}
+
+/*
+ * Sets string property in current pg
+ */
+int
+smb_smf_set_string_property(smb_scfhandle_t *handle,
+ char *propname, char *valstr)
+{
+ int ret = SMBD_SMF_OK;
+ scf_value_t *value = NULL;
+ scf_transaction_entry_t *entry = NULL;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ /*
+ * properties must be set in transactions and don't take
+ * effect until the transaction has been ended/committed.
+ */
+ value = scf_value_create(handle->scf_handle);
+ entry = scf_entry_create(handle->scf_handle);
+ if (value != NULL && entry != NULL) {
+ if (scf_transaction_property_change(handle->scf_trans, entry,
+ propname, SCF_TYPE_ASTRING) == 0 ||
+ scf_transaction_property_new(handle->scf_trans, entry,
+ propname, SCF_TYPE_ASTRING) == 0) {
+ if (scf_value_set_astring(value, valstr) == 0) {
+ if (scf_entry_add_value(entry, value) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ scf_value_destroy(value);
+ }
+ /* the value is in the transaction */
+ value = NULL;
+ } else {
+ /* value couldn't be constructed */
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ /* the entry is in the transaction */
+ entry = NULL;
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (ret == SMBD_SMF_SYSTEM_ERR) {
+ switch (scf_error()) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SMBD_SMF_NO_PERMISSION;
+ break;
+ }
+ }
+
+ /*
+ * cleanup if there were any errors that didn't leave these
+ * values where they would be cleaned up later.
+ */
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (entry != NULL)
+ scf_entry_destroy(entry);
+ return (ret);
+}
+
+/*
+ * Gets string property value.upto sz size.
+ * Caller is responsible to have enough memory allocated.
+ */
+int
+smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
+ char *valstr, size_t sz)
+{
+ int ret = SMBD_SMF_OK;
+ scf_value_t *value;
+ scf_property_t *prop;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ value = scf_value_create(handle->scf_handle);
+ prop = scf_property_create(handle->scf_handle);
+ if (value && prop &&
+ (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
+ if (scf_property_get_value(prop, value) == 0) {
+ if (scf_value_get_astring(value, valstr, sz) < 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (prop != NULL)
+ scf_property_destroy(prop);
+ return (ret);
+}
+
+/*
+ * Set integer value of property.
+ * The value is returned as int64_t value
+ * Caller ensures appropriate translation.
+ */
+int
+smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
+ int64_t valint)
+{
+ int ret = SMBD_SMF_OK;
+ scf_value_t *value = NULL;
+ scf_transaction_entry_t *entry = NULL;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ /*
+ * properties must be set in transactions and don't take
+ * effect until the transaction has been ended/committed.
+ */
+ value = scf_value_create(handle->scf_handle);
+ entry = scf_entry_create(handle->scf_handle);
+ if (value != NULL && entry != NULL) {
+ if (scf_transaction_property_change(handle->scf_trans, entry,
+ propname, SCF_TYPE_INTEGER) == 0 ||
+ scf_transaction_property_new(handle->scf_trans, entry,
+ propname, SCF_TYPE_INTEGER) == 0) {
+ scf_value_set_integer(value, valint);
+ if (scf_entry_add_value(entry, value) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ scf_value_destroy(value);
+ }
+ /* the value is in the transaction */
+ value = NULL;
+ }
+ /* the entry is in the transaction */
+ entry = NULL;
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (ret == SMBD_SMF_SYSTEM_ERR) {
+ switch (scf_error()) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SMBD_SMF_NO_PERMISSION;
+ break;
+ }
+ }
+ /*
+ * cleanup if there were any errors that didn't leave these
+ * values where they would be cleaned up later.
+ */
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (entry != NULL)
+ scf_entry_destroy(entry);
+ return (ret);
+}
+
+/*
+ * Gets integer property value.
+ * Caller is responsible to have enough memory allocated.
+ */
+int
+smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
+ int64_t *valint)
+{
+ int ret = SMBD_SMF_OK;
+ scf_value_t *value = NULL;
+ scf_property_t *prop = NULL;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ value = scf_value_create(handle->scf_handle);
+ prop = scf_property_create(handle->scf_handle);
+ if ((prop) && (value) &&
+ (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
+ if (scf_property_get_value(prop, value) == 0) {
+ if (scf_value_get_integer(value,
+ valint) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (prop != NULL)
+ scf_property_destroy(prop);
+ return (ret);
+}
+
+/*
+ * Set boolean value of property.
+ * The value is returned as int64_t value
+ * Caller ensures appropriate translation.
+ */
+int
+smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
+ uint8_t valbool)
+{
+ int ret = SMBD_SMF_OK;
+ scf_value_t *value = NULL;
+ scf_transaction_entry_t *entry = NULL;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ /*
+ * properties must be set in transactions and don't take
+ * effect until the transaction has been ended/committed.
+ */
+ value = scf_value_create(handle->scf_handle);
+ entry = scf_entry_create(handle->scf_handle);
+ if (value != NULL && entry != NULL) {
+ if (scf_transaction_property_change(handle->scf_trans, entry,
+ propname, SCF_TYPE_BOOLEAN) == 0 ||
+ scf_transaction_property_new(handle->scf_trans, entry,
+ propname, SCF_TYPE_BOOLEAN) == 0) {
+ scf_value_set_boolean(value, valbool);
+ if (scf_entry_add_value(entry, value) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ scf_value_destroy(value);
+ }
+ /* the value is in the transaction */
+ value = NULL;
+ }
+ /* the entry is in the transaction */
+ entry = NULL;
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (ret == SMBD_SMF_SYSTEM_ERR) {
+ switch (scf_error()) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SMBD_SMF_NO_PERMISSION;
+ break;
+ }
+ }
+ /*
+ * cleanup if there were any errors that didn't leave these
+ * values where they would be cleaned up later.
+ */
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (entry != NULL)
+ scf_entry_destroy(entry);
+ return (ret);
+}
+
+/*
+ * Gets boolean property value.
+ * Caller is responsible to have enough memory allocated.
+ */
+int
+smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
+ uint8_t *valbool)
+{
+ int ret = SMBD_SMF_OK;
+ scf_value_t *value = NULL;
+ scf_property_t *prop = NULL;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ value = scf_value_create(handle->scf_handle);
+ prop = scf_property_create(handle->scf_handle);
+ if ((prop) && (value) &&
+ (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
+ if (scf_property_get_value(prop, value) == 0) {
+ if (scf_value_get_boolean(value,
+ valbool) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (prop != NULL)
+ scf_property_destroy(prop);
+ return (ret);
+}
+
+/*
+ * Sets a blob property value.
+ */
+int
+smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
+ void *voidval, size_t sz)
+{
+ int ret = SMBD_SMF_OK;
+ scf_value_t *value;
+ scf_transaction_entry_t *entry;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ /*
+ * properties must be set in transactions and don't take
+ * effect until the transaction has been ended/committed.
+ */
+ value = scf_value_create(handle->scf_handle);
+ entry = scf_entry_create(handle->scf_handle);
+ if (value != NULL && entry != NULL) {
+ if (scf_transaction_property_change(handle->scf_trans, entry,
+ propname, SCF_TYPE_OPAQUE) == 0 ||
+ scf_transaction_property_new(handle->scf_trans, entry,
+ propname, SCF_TYPE_OPAQUE) == 0) {
+ if (scf_value_set_opaque(value, voidval, sz) == 0) {
+ if (scf_entry_add_value(entry, value) != 0) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ scf_value_destroy(value);
+ }
+ /* the value is in the transaction */
+ value = NULL;
+ } else {
+ /* value couldn't be constructed */
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ /* the entry is in the transaction */
+ entry = NULL;
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (ret == SMBD_SMF_SYSTEM_ERR) {
+ switch (scf_error()) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SMBD_SMF_NO_PERMISSION;
+ break;
+ }
+ }
+ /*
+ * cleanup if there were any errors that didn't leave these
+ * values where they would be cleaned up later.
+ */
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (entry != NULL)
+ scf_entry_destroy(entry);
+ return (ret);
+}
+
+/*
+ * Gets a blob property value.
+ * Caller is responsible to have enough memory allocated.
+ */
+int
+smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
+ void *v, size_t sz)
+{
+ int ret = SMBD_SMF_OK;
+ scf_value_t *value = NULL;
+ scf_property_t *prop = NULL;
+
+ if (handle == NULL)
+ return (SMBD_SMF_SYSTEM_ERR);
+
+ value = scf_value_create(handle->scf_handle);
+ prop = scf_property_create(handle->scf_handle);
+ if ((prop) && (value) &&
+ (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
+ if (scf_property_get_value(prop, value) == 0) {
+ if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ } else {
+ ret = SMBD_SMF_SYSTEM_ERR;
+ }
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (prop != NULL)
+ scf_property_destroy(prop);
+ return (ret);
+}
+
+/*
+ * Get property based on property type. Returns string value of that
+ * property. Only SCF_TYPE_ASTRING, SCF_TYPE_INTEGER, SCF_TYPE_BOOLEAN
+ * supported.
+ */
+int
+smb_smf_get_property(smb_scfhandle_t *handle, int proptype, char *propname,
+ char *valstr, size_t sz)
+{
+ int64_t valint = 0;
+ uint8_t valbool = 0;
+ int ret = SMBD_SMF_OK;
+
+ switch (proptype) {
+ case SCF_TYPE_ASTRING:
+ ret = smb_smf_get_string_property(handle, propname,
+ valstr, sz);
+ break;
+ case SCF_TYPE_INTEGER:
+ if ((ret = smb_smf_get_integer_property(handle, propname,
+ &valint)) != 0)
+ return (ret);
+ (void) snprintf(valstr, sz, "%lld", valint);
+ break;
+ case SCF_TYPE_BOOLEAN:
+ if ((ret = smb_smf_get_boolean_property(handle, propname,
+ &valbool)) != 0)
+ return (ret);
+ (void) strlcpy(valstr, (valbool ? "true" : "false"), sz);
+ break;
+ default:
+ return (SMBD_SMF_SYSTEM_ERR);
+ }
+ return (ret);
+}
+
+/*
+ * Set property based on property type.
+ * Only SCF_TYPE_ASTRING, SCF_TYPE_INTEGER, SCF_TYPE_BOOLEAN supported.
+ */
+int
+smb_smf_set_property(smb_scfhandle_t *handle, int proptype,
+ char *propname, char *valstr)
+{
+ int64_t valint = 0;
+ uint8_t valbool = 0;
+ int ret = SMBD_SMF_OK;
+
+ switch (proptype) {
+ case SCF_TYPE_ASTRING:
+ ret = smb_smf_set_string_property(handle, propname,
+ valstr);
+ break;
+ case SCF_TYPE_INTEGER:
+ valint = strtol(valstr, 0, 10);
+ ret = smb_smf_set_integer_property(handle, propname,
+ valint);
+ break;
+ case SCF_TYPE_BOOLEAN:
+ if (strcasecmp(valstr, "true") == 0)
+ valbool = 1;
+ ret = smb_smf_set_boolean_property(handle, propname, valbool);
+ break;
+ default:
+ return (SMBD_SMF_SYSTEM_ERR);
+ }
+ return (ret);
+}
+
+/*
+ * Gets an instance iterator for the service specified.
+ */
+smb_scfhandle_t *
+smb_smf_get_iterator(char *svc_name)
+{
+ smb_scfhandle_t *handle = NULL;
+
+ handle = smb_smf_scf_init(svc_name);
+ if (!handle)
+ return (NULL);
+
+ handle->scf_inst_iter = scf_iter_create(handle->scf_handle);
+ if (handle->scf_inst_iter) {
+ if (scf_iter_service_instances(handle->scf_inst_iter,
+ handle->scf_service) != 0) {
+ smb_smf_scf_fini(handle);
+ handle = NULL;
+ } else {
+ handle->scf_instance = NULL;
+ }
+ } else {
+ smb_smf_scf_fini(handle);
+ handle = NULL;
+ }
+ return (handle);
+}
+
+/*
+ * smb_smf_scf_init()
+ *
+ * must be called before using any of the SCF functions.
+ * Returns smb_scfhandle_t pointer if success.
+ */
+smb_scfhandle_t *
+smb_smf_scf_init(char *svc_name)
+{
+ smb_scfhandle_t *handle;
+
+ handle = malloc(sizeof (smb_scfhandle_t));
+ if (handle != NULL) {
+ bzero((char *)handle, sizeof (smb_scfhandle_t));
+ handle->scf_state = SCH_STATE_INITIALIZING;
+ handle->scf_handle = scf_handle_create(SCF_VERSION);
+ if (handle->scf_handle != NULL) {
+ if (scf_handle_bind(handle->scf_handle) == 0) {
+ handle->scf_scope =
+ scf_scope_create(handle->scf_handle);
+ if (scf_handle_get_local_scope(
+ handle->scf_handle, handle->scf_scope) != 0)
+ goto err;
+
+ handle->scf_service =
+ scf_service_create(handle->scf_handle);
+
+ if (scf_scope_get_service(handle->scf_scope,
+ svc_name, handle->scf_service)
+ != SCF_SUCCESS) {
+ goto err;
+ }
+ handle->scf_pg =
+ scf_pg_create(handle->scf_handle);
+ handle->scf_state = SCH_STATE_INIT;
+ } else {
+ goto err;
+ }
+ } else {
+ free(handle);
+ handle = NULL;
+ smb_smf_scf_log_error("Could not access SMF "
+ "repository: %s\n");
+ }
+ }
+ return (handle);
+
+ /* error handling/unwinding */
+err:
+ (void) smb_smf_scf_fini(handle);
+ (void) smb_smf_scf_log_error("SMF initialization problem: %s\n");
+ return (NULL);
+}
+
+/*
+ * smb_smf_scf_fini(handle)
+ *
+ * must be called when done. Called with the handle allocated in
+ * smb_smf_scf_init(), it cleans up the state and frees any SCF resources
+ * still in use.
+ */
+void
+smb_smf_scf_fini(smb_scfhandle_t *handle)
+{
+ if (handle != NULL) {
+ int unbind = 0;
+ scf_iter_destroy(handle->scf_pg_iter);
+ handle->scf_pg_iter = NULL;
+
+ scf_iter_destroy(handle->scf_inst_iter);
+ handle->scf_inst_iter = NULL;
+
+ unbind = 1;
+ scf_scope_destroy(handle->scf_scope);
+ handle->scf_scope = NULL;
+
+ scf_instance_destroy(handle->scf_instance);
+ handle->scf_instance = NULL;
+
+ scf_service_destroy(handle->scf_service);
+ handle->scf_service = NULL;
+
+ scf_pg_destroy(handle->scf_pg);
+ handle->scf_pg = NULL;
+
+ handle->scf_state = SCH_STATE_UNINIT;
+ if (unbind)
+ (void) scf_handle_unbind(handle->scf_handle);
+ scf_handle_destroy(handle->scf_handle);
+ handle->scf_handle = NULL;
+
+ free(handle);
+ }
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_util.c b/usr/src/lib/smbsrv/libsmb/common/smb_util.c
new file mode 100644
index 0000000000..bce8efee8e
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c
@@ -0,0 +1,336 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <sys/varargs.h>
+#include <sys/types.h>
+#include <smbsrv/string.h>
+
+#define C2H(c) "0123456789ABCDEF"[(c)]
+#define H2C(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
+ ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
+ ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
+ '\0')
+#define DEFAULT_SBOX_SIZE 256
+
+/*
+ *
+ * hexdump
+ *
+ * Simple hex dump display function. Displays nbytes of buffer in hex and
+ * printable format. Non-printing characters are shown as '.'. It is safe
+ * to pass a null pointer. Each line begins with the offset. If nbytes is
+ * 0, the line will be blank except for the offset. Example output:
+ *
+ * 00000000 54 68 69 73 20 69 73 20 61 20 70 72 6F 67 72 61 This is a progra
+ * 00000010 6D 20 74 65 73 74 2E 00 m test..
+ *
+ */
+void
+hexdump_offset(unsigned char *buffer, int nbytes, unsigned long *start, int log)
+{
+ static char *hex = "0123456789ABCDEF";
+ int i, count;
+ int offset;
+ unsigned char *p;
+ char ascbuf[64];
+ char hexbuf[64];
+ char *ap = ascbuf;
+ char *hp = hexbuf;
+
+ if ((p = buffer) == 0) {
+ if (log)
+ syslog(LOG_DEBUG, "hexdump: (null)");
+ else
+ (void) printf("hexdump: (null)\n");
+ return;
+ }
+
+ offset = *start;
+
+ *ap = '\0';
+ *hp = '\0';
+ count = 0;
+
+ for (i = 0; i < nbytes; ++i) {
+ if (i && (i % 16) == 0) {
+ if (log)
+ syslog(LOG_DEBUG,
+ "%06X %s %s", offset, hexbuf, ascbuf);
+ else
+ (void) printf("%06X %s %s\n",
+ offset, hexbuf, ascbuf);
+ ap = ascbuf;
+ hp = hexbuf;
+ count = 0;
+ offset += 16;
+ }
+
+ ap += sprintf(ap, "%c",
+ (*p >= 0x20 && *p < 0x7F) ? *p : '.');
+ hp += sprintf(hp, " %c%c",
+ hex[(*p >> 4) & 0x0F], hex[(*p & 0x0F)]);
+ ++p;
+ ++count;
+ }
+
+ if (count) {
+ if (log)
+ syslog(LOG_DEBUG,
+ "%06X %-48s %s", offset, hexbuf, ascbuf);
+ else
+ (void) printf("%06X %-48s %s\n",
+ offset, hexbuf, ascbuf);
+
+ offset += count;
+ }
+
+ *start = offset;
+}
+
+void
+hexdump(unsigned char *buffer, int nbytes)
+{
+ unsigned long start = 0;
+
+ hexdump_offset(buffer, nbytes, &start, 1);
+}
+
+/*
+ * bintohex
+ *
+ * Converts the given binary data (srcbuf) to
+ * its equivalent hex chars (hexbuf).
+ *
+ * hexlen should be at least twice as srclen.
+ * if hexbuf is not big enough returns 0.
+ * otherwise returns number of valid chars in
+ * hexbuf which is srclen * 2.
+ */
+size_t
+bintohex(const char *srcbuf, size_t srclen,
+ char *hexbuf, size_t hexlen)
+{
+ size_t outlen;
+ char c;
+
+ outlen = srclen << 1;
+
+ if (hexlen < outlen)
+ return (0);
+
+ while (srclen-- > 0) {
+ c = *srcbuf++;
+ *hexbuf++ = C2H(c & 0xF);
+ *hexbuf++ = C2H((c >> 4) & 0xF);
+ }
+
+ return (outlen);
+}
+
+/*
+ * hextobin
+ *
+ * Converts hex to binary.
+ *
+ * Assuming hexbuf only contains hex digits (chars)
+ * this function convert every two bytes of hexbuf
+ * to one byte and put it in dstbuf.
+ *
+ * hexlen should be an even number.
+ * dstlen should be at least half of hexlen.
+ *
+ * Returns 0 if sizes are not correct, otherwise
+ * returns the number of converted bytes in dstbuf
+ * which is half of hexlen.
+ */
+size_t
+hextobin(const char *hexbuf, size_t hexlen,
+ char *dstbuf, size_t dstlen)
+{
+ size_t outlen;
+
+ if ((hexlen % 2) != 0)
+ return (0);
+
+ outlen = hexlen >> 1;
+ if (dstlen < outlen)
+ return (0);
+
+ while (hexlen > 0) {
+ *dstbuf = H2C(*hexbuf) & 0x0F;
+ hexbuf++;
+ *dstbuf++ |= (H2C(*hexbuf) << 4) & 0xF0;
+ hexbuf++;
+
+ hexlen -= 2;
+ }
+
+ return (outlen);
+}
+
+/*
+ * trim_whitespace
+ *
+ * Trim leading and trailing whitespace chars (as defined by isspace)
+ * from a buffer. Example; if the input buffer contained " text ",
+ * it will contain "text", when we return. We assume that the buffer
+ * contains a null terminated string. A pointer to the buffer is
+ * returned.
+ */
+char *
+trim_whitespace(char *buf)
+{
+ char *p = buf;
+ char *q = buf;
+
+ if (buf == 0)
+ return (0);
+
+ while (*p && isspace(*p))
+ ++p;
+
+ while ((*q = *p++) != 0)
+ ++q;
+
+ if (q != buf) {
+ while ((--q, isspace(*q)) != 0)
+ *q = '\0';
+ }
+
+ return (buf);
+}
+
+/*
+ * randomize
+ *
+ * Randomize the contents of the specified buffer.
+ */
+void
+randomize(char *data, unsigned len)
+{
+ unsigned dwlen = len / 4;
+ unsigned remlen = len % 4;
+ unsigned tmp;
+ unsigned i; /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ unsigned *p = (unsigned *)data;
+
+ for (i = 0; i < dwlen; ++i)
+ *p++ = random();
+
+ if (remlen) {
+ tmp = random();
+ (void) memcpy(p, &tmp, remlen);
+ }
+}
+
+/*
+ * This is the hash mechanism used to encrypt passwords for commands like
+ * SamrSetUserInformation. It uses a 256 byte s-box.
+ */
+void
+rand_hash(
+ unsigned char *data,
+ size_t datalen,
+ unsigned char *key,
+ size_t keylen)
+{
+ unsigned char sbox[DEFAULT_SBOX_SIZE];
+ unsigned char tmp;
+ unsigned char index_i = 0;
+ unsigned char index_j = 0;
+ unsigned char j = 0;
+ int i;
+
+ for (i = 0; i < DEFAULT_SBOX_SIZE; ++i)
+ sbox[i] = (unsigned char)i;
+
+ for (i = 0; i < DEFAULT_SBOX_SIZE; ++i) {
+ j += (sbox[i] + key[i % keylen]);
+
+ tmp = sbox[i];
+ sbox[i] = sbox[j];
+ sbox[j] = tmp;
+ }
+
+ for (i = 0; i < datalen; ++i) {
+ index_i++;
+ index_j += sbox[index_i];
+
+ tmp = sbox[index_i];
+ sbox[index_i] = sbox[index_j];
+ sbox[index_j] = tmp;
+
+ tmp = sbox[index_i] + sbox[index_j];
+ data[i] = data[i] ^ sbox[tmp];
+ }
+}
+
+/*
+ * strsep
+ *
+ * The strsep() function locates, in the string referenced by *stringp, the
+ * first occurrence of any character in the string delim (or the terminating
+ * `\0' character) and replaces it with a `\0'. The location of the next
+ * character after the delimiter character (or NULL, if the end of the
+ * string was reached) is stored in *stringp. The original value of
+ * *stringp is returned.
+ *
+ * If *stringp is initially NULL, strsep() returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+
+ for (tok = s; ; ) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_wins.c b/usr/src/lib/smbsrv/libsmb/common/smb_wins.c
new file mode 100644
index 0000000000..09498abfca
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_wins.c
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB WINS support functions
+ */
+
+#include <strings.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <smbsrv/smbinfo.h>
+
+#include <smbsrv/libsmb.h>
+
+/*
+ * smb_wins_iplist
+ *
+ * Get a string containing a list of comma separated IP addresses
+ * and return an array containing numeric equivalent for string IPs.
+ *
+ * Returns the number of parsed IPs.
+ * Return -1 if list is badly formatted.
+ * This routine need fix for IPv6
+ */
+int
+smb_wins_iplist(char *list, uint32_t iplist[], int max_naddr)
+{
+ char *ip, *ctx;
+ char *tmp;
+ int n = 0;
+
+ if ((list == NULL) || (*list == '\0'))
+ return (0);
+
+ if ((tmp = strdup(list)) == NULL)
+ return (0);
+
+ ip = strtok_r(tmp, ",", &ctx);
+ while (ip && (n < max_naddr)) {
+ ip = trim_whitespace(ip);
+ if (*ip != 0) {
+ if (inet_pton(AF_INET, ip, &iplist[n]) == 1) {
+ n++;
+ } else {
+ return (-1);
+ }
+ }
+ ip = strtok_r(0, ",", &ctx);
+ }
+
+ free(tmp);
+ return (n);
+}
+
+/*
+ * smb_wins_is_excluded
+ *
+ * Check to see if the given IP addr shouldn't be registered in WINS.
+ *
+ * Returns 1 if it's excluded, 0 if it's not.
+ */
+boolean_t
+smb_wins_is_excluded(in_addr_t ipaddr,
+ unsigned long *exclude_list, int nexclude)
+{
+ int i;
+
+ if (nexclude == 0)
+ return (B_FALSE);
+
+ for (i = 0; i < nexclude; i++)
+ if (ipaddr == exclude_list[i]) {
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Build a CSV list of ips to be excluded.
+ * This function needs fix for IPv6
+ */
+void
+smb_wins_build_list(char *buf, uint32_t iplist[], int max_naddr)
+{
+ char ipstr[16];
+ int i;
+
+ if (!buf)
+ return;
+
+ buf[0] = '\0';
+ for (i = 0; i < max_naddr; i++) {
+ /* XXX these will be removed */
+ /*LINTED*/
+ if (iplist[i] == -1)
+ continue;
+
+ if (inet_ntop(AF_INET, (const void *)(&iplist[i]), ipstr,
+ sizeof (ipstr)) == 0)
+ continue;
+ (void) strcat(buf, ipstr);
+ (void) strcat(buf, ",");
+ }
+ buf[strlen(buf)-1] = '\0';
+}
+
+/*
+ * This function build the new WINS exclude list from
+ * configured list + new additions to exclude list
+ * It also assumes that the buffers are of enough space.
+ */
+int
+smb_wins_exclude_list(char *config_list, char *exclude_list)
+{
+ int ccnt, ecnt, already_there;
+ int i, j;
+ uint32_t ncur_list[SMB_PI_MAX_NETWORKS];
+ uint32_t ecur_list[SMB_PI_MAX_NETWORKS];
+
+ ccnt = smb_wins_iplist(config_list, ncur_list, SMB_PI_MAX_NETWORKS);
+ if (ccnt < 0)
+ return (-1);
+
+ ecnt = smb_wins_iplist(exclude_list, ecur_list, SMB_PI_MAX_NETWORKS);
+ if (ecnt < 0)
+ return (-1);
+
+ if ((ccnt + ecnt) > SMB_PI_MAX_NETWORKS)
+ return (-1);
+
+ for (i = 0; i < ecnt; i++) {
+ already_there = 0;
+ for (j = 0; j < ccnt; j++) {
+ if (ncur_list[j] == ecur_list[i]) {
+ already_there = 1;
+ }
+ }
+ if (already_there)
+ continue;
+
+ ncur_list[ccnt++] = ecur_list[i];
+ }
+
+ smb_wins_build_list(config_list, ncur_list, ccnt);
+ return (0);
+}
+
+/*
+ * This function build the new WINS allow list from
+ * configured list - new allowed list
+ * It also assumes that the buffers are of enough space.
+ */
+int
+smb_wins_allow_list(char *config_list, char *allow_list)
+{
+ int ccnt, acnt;
+ int i, j;
+ uint32_t ncur_list[SMB_PI_MAX_NETWORKS];
+ uint32_t acur_list[SMB_PI_MAX_NETWORKS];
+
+ ccnt = smb_wins_iplist(config_list, ncur_list, SMB_PI_MAX_NETWORKS);
+ if (ccnt < 0)
+ return (-1);
+
+ acnt = smb_wins_iplist(allow_list, acur_list, SMB_PI_MAX_NETWORKS);
+ if (acnt < 0)
+ return (0);
+
+ for (i = 0; i < acnt; i++) {
+ for (j = 0; j < ccnt; j++) {
+ if (ncur_list[j] == (in_addr_t)(-1))
+ continue;
+ if (ncur_list[j] == acur_list[i]) {
+ ncur_list[j] = (in_addr_t)(-1);
+ }
+ }
+ }
+ smb_wins_build_list(config_list, ncur_list, ccnt);
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c b/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c
new file mode 100644
index 0000000000..0a40b95418
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the interface to builtin domain information.
+ * These are the predefined groups and aliases in the NT AUTHORITY or
+ * BUILTIN domains, and some other miscellaneous bits.
+ */
+
+#include <string.h>
+#include <synch.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/string.h>
+#include <smbsrv/alloc.h>
+
+/*
+ * This table should contain all of the NT builtin domain names.
+ */
+static char *domain[] = {
+ "LOCAL",
+ "BUILTIN",
+ "NT AUTHORITY",
+ "UNKNOWN"
+};
+
+static int wk_init = 0;
+static rwlock_t wk_rwlock;
+
+/*
+ * This table should contain all of the builtin domains, groups and
+ * aliases. The order is important because we do string compares on
+ * the SIDs. For each domain, ensure that the domain SID appears
+ * before any aliases in that domain.
+ */
+static well_known_account_t wkt[] = {
+ { SidTypeWellKnownGroup, 0, "S-1-0-0", "Null",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 1, "S-1-1-0", "Everyone",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 1, "S-1-2-0", "LOCAL",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 1, "S-1-3-0", "CREATOR OWNER",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 1, "S-1-3-1", "CREATOR GROUP",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 1, "S-1-3-2", "CREATOR OWNER SERVER",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 1, "S-1-3-3", "CREATOR GROUP SERVER",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeDomain, 1, "S-1-4", "NON UNIQUE",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeDomain, 2, "S-1-5", "NT AUTHORITY",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-1", "DIALUP",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-2", "NETWORK",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-3", "BATCH",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-4", "INTERACTIVE",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-6", "SERVICE",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-7", "ANONYMOUS",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-8", "PROXY",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-9", "SERVER",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-10", "SELF",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-11", "Authenticated Users",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-12", "RESTRICTED",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-18", "SYSTEM",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeWellKnownGroup, 2, "S-1-5-21", "NON_UNIQUE",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeDomain, 2, "S-1-5-32", "BUILTIN",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeAlias, 1, "S-1-5-32-544", "Administrators",
+ 0, "Members can fully administer the computer/domain", NULL },
+ { SidTypeAlias, 1, "S-1-5-32-545", "Users",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeAlias, 1, "S-1-5-32-546", "Guests",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeAlias, 1, "S-1-5-32-547", "Power Users",
+ 0, "Members can share directories", NULL },
+ { SidTypeAlias, 1, "S-1-5-32-548", "Account Operators",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeAlias, 1, "S-1-5-32-549", "Server Operators",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeAlias, 1, "S-1-5-32-550", "Print Operators",
+ LGF_HIDDEN, 0, NULL},
+ { SidTypeAlias, 1, "S-1-5-32-551", "Backup Operators",
+ 0, "Members can bypass file security to back up files", NULL },
+ { SidTypeAlias, 1, "S-1-5-32-552", "Replicator",
+ LGF_HIDDEN, 0, NULL}
+};
+
+
+/*
+ * nt_builtin_lookup_sid
+ *
+ * Search the wkt looking for a match on the specified SID. If the
+ * SID matches a builtin entry, the associated name is returned.
+ * Otherwise a null pointer is returned.
+ */
+char *
+nt_builtin_lookup_sid(nt_sid_t *sid, WORD *sid_name_use)
+{
+ well_known_account_t *entry;
+ char *sidbuf;
+ int sidlen;
+ int i;
+
+ if ((sidbuf = nt_sid_format(sid)) == 0) {
+ return (0);
+ }
+
+ sidlen = strlen(sidbuf);
+
+ for (i = 0; i < sizeof (wkt)/sizeof (wkt[0]); ++i) {
+ entry = &wkt[i];
+
+ if (strncmp(sidbuf, entry->sid, sidlen) == 0) {
+ if (sid_name_use)
+ *sid_name_use = entry->sid_name_use;
+ free(sidbuf);
+ return (entry->name);
+ }
+ }
+
+ free(sidbuf);
+ return (0);
+}
+
+
+/*
+ * nt_builtin_lookup_name
+ *
+ * Search the wkt looking for a match on the specified name. If the
+ * name matches a builtin entry, the associated SID (which is in
+ * malloc'd memory) is returned. Otherwise a null pointer is returned.
+ */
+nt_sid_t *
+nt_builtin_lookup_name(char *name, WORD *sid_name_use)
+{
+ well_known_account_t *entry;
+ int i;
+
+ for (i = 0; i < sizeof (wkt)/sizeof (wkt[0]); ++i) {
+ entry = &wkt[i];
+
+ if (!utf8_strcasecmp(name, entry->name)) {
+ if (sid_name_use)
+ *sid_name_use = entry->sid_name_use;
+ return (nt_sid_strtosid(entry->sid));
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * nt_builtin_lookup
+ *
+ * Search the wkt looking for a match on the specified name. If the
+ * name matches a builtin entry then pointer to that entry will be
+ * returned. Otherwise 0 is returned.
+ */
+well_known_account_t *
+nt_builtin_lookup(char *name)
+{
+ well_known_account_t *entry;
+ int i;
+
+ (void) rw_rdlock(&wk_rwlock);
+ for (i = 0; i < sizeof (wkt)/sizeof (wkt[0]); ++i) {
+ entry = &wkt[i];
+
+ if (!utf8_strcasecmp(name, entry->name)) {
+ (void) rw_unlock(&wk_rwlock);
+ return (entry);
+ }
+ }
+
+ (void) rw_unlock(&wk_rwlock);
+ return (0);
+}
+
+
+/*
+ * nt_builtin_is_wellknown
+ *
+ * Search the wkt looking for a match on the specified name. If the
+ * name matches a builtin entry returns 1. Otherwise returns 0.
+ */
+int
+nt_builtin_is_wellknown(char *name)
+{
+ well_known_account_t *entry;
+ int i;
+
+ for (i = 0; i < sizeof (wkt)/sizeof (wkt[0]); ++i) {
+ entry = &wkt[i];
+
+ if (!utf8_strcasecmp(name, entry->name)) {
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * nt_builtin_lookup_domain
+ *
+ * Return the builtin domain name for the specified alias or group name.
+ */
+char *
+nt_builtin_lookup_domain(char *name)
+{
+ well_known_account_t *entry;
+ char *domain_name;
+ int i;
+
+ for (i = 0; i < sizeof (wkt)/sizeof (wkt[0]); ++i) {
+ entry = &wkt[i];
+
+ if (!utf8_strcasecmp(name, entry->name)) {
+ domain_name = domain[entry->domain_ix];
+ return (domain_name);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * nt_builtin_findfirst
+ *
+ * Returns pointer to the first entry of well known sids table.
+ */
+well_known_account_t *
+nt_builtin_findfirst(DWORD *iterator)
+{
+ *iterator = 1;
+ return (&wkt[0]);
+}
+
+/*
+ * nt_builtin_findnext
+ *
+ * Returns pointer to the entry of well known sids table specified
+ * by the iterator. Increments iterator to point to the next entry.
+ */
+well_known_account_t *
+nt_builtin_findnext(DWORD *iterator)
+{
+ if (*iterator < sizeof (wkt)/sizeof (wkt[0]))
+ return (&wkt[(*iterator)++]);
+
+ return (0);
+}
+
+/*
+ * nt_builtin_init
+ *
+ * Generate binary SIDs from the string SIDs in the table
+ * and set the proper field.
+ *
+ * Caller MUST not store the binary SID pointer anywhere that
+ * could lead to freeing it.
+ *
+ * This function should only be called once.
+ */
+int
+nt_builtin_init()
+{
+ well_known_account_t *entry;
+ int i;
+
+ (void) rw_wrlock(&wk_rwlock);
+ if (wk_init) {
+ (void) rw_unlock(&wk_rwlock);
+ return (1);
+ }
+
+ for (i = 0; i < sizeof (wkt)/sizeof (wkt[0]); ++i) {
+ entry = &wkt[i];
+ entry->binsid = nt_sid_strtosid(entry->sid);
+ if (entry->binsid == NULL) {
+ (void) rw_unlock(&wk_rwlock);
+ nt_builtin_fini();
+ return (0);
+ }
+ }
+
+ wk_init = 1;
+ (void) rw_unlock(&wk_rwlock);
+ return (1);
+}
+
+void
+nt_builtin_fini()
+{
+ int i;
+
+ (void) rw_wrlock(&wk_rwlock);
+ if (wk_init == 0) {
+ (void) rw_unlock(&wk_rwlock);
+ return;
+ }
+
+ for (i = 0; i < sizeof (wkt)/sizeof (wkt[0]); ++i) {
+ if (wkt[i].binsid) {
+ free(wkt[i].binsid);
+ wkt[i].binsid = NULL;
+ }
+ }
+
+ wk_init = 0;
+ (void) rw_unlock(&wk_rwlock);
+}
diff --git a/usr/src/lib/smbsrv/libsmb/i386/Makefile b/usr/src/lib/smbsrv/libsmb/i386/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libsmb/sparc/Makefile b/usr/src/lib/smbsrv/libsmb/sparc/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libsmb/sparcv9/Makefile b/usr/src/lib/smbsrv/libsmb/sparcv9/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmb/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libsmbns/Makefile b/usr/src/lib/smbsrv/libsmbns/Makefile
new file mode 100644
index 0000000000..495ff5688d
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+HDRS= libsmbns.h
+
+include ../Makefile.smbsrv
diff --git a/usr/src/lib/smbsrv/libsmbns/Makefile.com b/usr/src/lib/smbsrv/libsmbns/Makefile.com
new file mode 100644
index 0000000000..2166b2640d
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/Makefile.com
@@ -0,0 +1,62 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY= libsmbns.a
+VERS= .1
+
+OBJS_SHARED = \
+ smb_netbios_util.o \
+
+OBJS_COMMON= \
+ smbns_ads.o \
+ smbns_browser.o \
+ smbns_dyndns.o \
+ smbns_krb.o \
+ smbns_ksetpwd.o \
+ smbns_netbios.o \
+ smbns_netbios_cache.o \
+ smbns_netbios_datagram.o\
+ smbns_netbios_name.o \
+ smbns_netlogon.o \
+ smbns_nicconfig.o
+
+OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_SHARED:%.o=$(SRC)/common/smbsrv/%.c)
+
+LDLIBS += -lsmb -lgss -lldap -lresolv -lnsl -lsocket -lc
+CPPFLAGS += -D_REENTRANT
+
+# DYNLIB libraries do not have lint libs and are not linted
+$(DYNLIB) := LDLIBS += -lkrb5
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbsrv/libsmbns/amd64/Makefile b/usr/src/lib/smbsrv/libsmbns/amd64/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h
new file mode 100644
index 0000000000..a05c197c35
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBSMBNS_H
+#define _LIBSMBNS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ldap.h>
+#include <net/if.h>
+
+#include <smbsrv/libsmb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ADS typedef/data structures and functions */
+#define ADS_MAXBUFLEN 100
+
+typedef struct ads_handle_s {
+ char *user; /* admin user to create share in ADS */
+ char *pwd; /* user password */
+ char *container; /* user container in ADS */
+ char *domain; /* ADS domain */
+ char *domain_dn; /* domain in Distinquish Name format */
+ char *ip_addr; /* ip addr in string format */
+ char *hostname; /* fully qualified hostname */
+ char *site; /* local ADS site */
+ LDAP *ld; /* LDAP handle */
+} ADS_HANDLE;
+
+/*
+ * The possible return status of the adjoin routine.
+ */
+typedef enum adjoin_status {
+ ADJOIN_SUCCESS = 0,
+ ADJOIN_ERR_GET_HANDLE,
+ ADJOIN_ERR_GEN_PASSWD,
+ ADJOIN_ERR_ADD_TRUST_ACCT,
+ ADJOIN_ERR_GET_ENCTYPES,
+ ADJOIN_ERR_GET_HOST_PRINC,
+ ADJOIN_ERR_INIT_KRB_CTX,
+ ADJOIN_ERR_GET_KRB_PRINC,
+ ADJOIN_ERR_KSETPWD,
+ ADJOIN_ERR_MOD_TRUST_ACCT,
+ ADJOIN_ERR_WRITE_KEYTAB,
+ ADJOIN_ERR_IDMAP_SET_DOMAIN,
+ ADJOIN_ERR_IDMAP_SET_GC,
+ ADJOIN_ERR_IDMAP_REFRESH,
+ ADJOIN_ERR_IDMAP_CCACHE,
+
+ ADJOIN_NUM_STATUS
+} adjoin_status_t;
+
+/* ADS functions */
+extern ADS_HANDLE *ads_open(void);
+extern void ads_close(ADS_HANDLE *);
+extern int ads_publish_share(ADS_HANDLE *, const char *, const char *,
+ const char *, const char *);
+extern int ads_remove_share(ADS_HANDLE *, const char *, const char *,
+ const char *, const char *);
+extern int ads_build_unc_name(char *, int, const char *, const char *);
+extern int ads_lookup_share(ADS_HANDLE *, const char *, const char *, char *);
+extern int ads_add_share(ADS_HANDLE *, const char *, const char *,
+ const char *);
+
+extern adjoin_status_t adjoin(char *, int);
+extern char *adjoin_report_err(adjoin_status_t status);
+
+/* DYNDNS functions */
+extern int dyndns_update(void);
+extern int dyndns_clear_rev_zone(void);
+
+/* Kerberos initialization function */
+extern int smb_kinit(char *user, char *passwd);
+
+
+/* NETBIOS Functions */
+extern int msdcs_lookup_ads(void);
+extern void smb_netbios_start(void);
+extern void smb_netbios_shutdown(void);
+extern void smb_netbios_name_reconfig(void);
+
+/* Browser Configure */
+extern void smb_browser_config(void);
+
+extern void smb_netlogon_request(int, int, char *);
+
+/*
+ * NIC listing and config
+ */
+#define MAXIFS 256
+#define SIZE_IP 17
+
+typedef struct {
+ char ifname[LIFNAMSIZ];
+ uint32_t ip;
+ uint32_t mask;
+ uint32_t broadcast;
+ boolean_t exclude;
+ uint64_t flags;
+ char groupname[LIFGRNAMSIZ];
+ char **aliases;
+ int naliases;
+} net_cfg_t;
+typedef struct {
+ net_cfg_t *net_cfg_list;
+ int net_cfg_cnt;
+} net_cfg_list_t;
+
+struct if_list {
+ char name[IFNAMSIZ+1];
+ struct if_list *next;
+};
+
+struct ip_alias {
+ char name[SIZE_IP];
+ struct ip_alias *next;
+};
+
+#define GATEWAY_FILE "/etc/defaultrouter"
+
+/* NIC Config functions */
+extern void smb_resolver_init(void);
+extern void smb_resolver_close(void);
+extern int smb_get_nameservers(struct in_addr *, int);
+extern uint16_t smb_get_next_resid(void);
+extern void smb_nic_lock(void);
+extern void smb_nic_unlock(void);
+extern int smb_nic_init(void);
+extern void smb_nic_build_info(void);
+extern net_cfg_t *smb_nic_get_byind(int, net_cfg_t *);
+extern net_cfg_t *smb_nic_get_bysubnet(uint32_t, net_cfg_t *);
+extern net_cfg_t *smb_nic_get_byip(uint32_t, net_cfg_t *);
+extern int smb_nic_get_num(void);
+extern int smb_nic_get_IP(char *, uint32_t *uip);
+extern int smb_nic_get_broadcast(char *, uint32_t *uip);
+extern int smb_nic_get_netmask(char *, uint32_t *uip);
+extern int smb_nic_get_IP_aliases(char *, struct ip_alias **);
+extern int smb_nic_get_number(void);
+extern int smb_nic_get_num_physical(void);
+extern int smb_nic_get_num_logical(void);
+extern int smb_nic_get_num_aliases(char *);
+extern int smb_nic_get_default_gateway(char *, unsigned int);
+extern int smb_nic_flags(char *, uint64_t *);
+extern int smb_nic_build_if_name(char ***);
+extern int smb_nic_build_network_structures(net_cfg_t **, int *);
+extern char *smb_nic_get_ifnames(int, int);
+extern int smb_nic_validate_ip_address(char *);
+extern int smb_nic_status(char *, uint64_t);
+extern int smb_nic_get_group(char *lifname, char *grname);
+extern int smb_nic_set_group(char *lifname, char *grname);
+extern int smb_nic_clear_niclist(net_cfg_t *, int);
+extern int smb_nic_clear_name_list(char **, int);
+extern int smb_nic_clear_ip_alias(struct ip_alias *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSMBNS_H */
diff --git a/usr/src/lib/smbsrv/libsmbns/common/llib-lsmbns b/usr/src/lib/smbsrv/libsmbns/common/llib-lsmbns
new file mode 100644
index 0000000000..5420d543b5
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/llib-lsmbns
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <smbsrv/libsmbns.h>
diff --git a/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers b/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers
new file mode 100644
index 0000000000..d20641252d
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers
@@ -0,0 +1,81 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate {
+ global:
+ adjoin;
+ adjoin_report_err;
+ ads_add_share;
+ ads_build_unc_name;
+ ads_close;
+ ads_lookup_share;
+ ads_open;
+ ads_publish_share;
+ ads_remove_share;
+ dyndns_clear_rev_zone;
+ dyndns_update;
+ msdcs_lookup_ads;
+ smb_browser_config;
+ smb_get_nameservers;
+ smb_get_next_resid;
+ smb_kinit;
+ smb_netbios_name_reconfig;
+ smb_netbios_start;
+ smb_netbios_shutdown;
+ smb_netlogon_request;
+ smb_nic_build_if_name;
+ smb_nic_build_network_structures;
+ smb_nic_clear_ip_alias;
+ smb_nic_clear_name_list;
+ smb_nic_clear_niclist;
+ smb_nic_free_niclist;
+ smb_nic_get_IP;
+ smb_nic_get_IP_aliases;
+ smb_nic_get_broadcast;
+ smb_nic_build_info;
+ smb_nic_get_byind;
+ smb_nic_get_byip;
+ smb_nic_get_bysubnet;
+ smb_nic_get_default_gateway;
+ smb_nic_get_group;
+ smb_nic_get_ifnames;
+ smb_nic_get_netmask;
+ smb_nic_get_num;
+ smb_nic_get_num_aliases;
+ smb_nic_get_number;
+ smb_nic_get_num_logical;
+ smb_nic_get_num_physical;
+ smb_nic_init;
+ smb_nic_lock;
+ smb_nic_status;
+ smb_nic_unlock;
+ smb_nic_validate_ip_address;
+ smb_resolver_close;
+ smb_resolver_init;
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c
new file mode 100644
index 0000000000..c57971e455
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c
@@ -0,0 +1,2304 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <ldap.h>
+#include <stdlib.h>
+#include <gssapi/gssapi.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <sys/synch.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <smbsrv/libsmbns.h>
+#include <smbns_ads.h>
+#include <smbns_dyndns.h>
+#include <smbns_krb.h>
+
+#define ADS_DN_MAX 300
+#define ADS_MAXMSGLEN 512
+#define ADS_HOST_PREFIX "host/"
+#define ADS_COMPUTERS_CN "Computers"
+
+/* current ADS server to communicate with */
+ADS_HOST_INFO *ads_host_info = NULL;
+mutex_t ads_mtx;
+
+/*
+ * adjoin_errmsg
+ *
+ * Use the adjoin return status defined in adjoin_status_t as the index
+ * to this table.
+ */
+static char *adjoin_errmsg[] = {
+ "ADJOIN succeeded.",
+ "ADJOIN failed to get handle.",
+ "ADJOIN failed to generate machine password.",
+ "ADJOIN failed to add workstation trust account.",
+ "ADJOIN failed to get list of encryption types.",
+ "ADJOIN failed to get host principal.",
+ "ADJOIN failed to initialize kerberos context.",
+ "ADJOIN failed to get kerberos principal.",
+ "ADJOIN failed to set machine account password on AD.",
+ "ADJOIN failed to modify workstation trust account.",
+ "ADJOIN failed to write Keberos keytab file.",
+ "ADJOIN failed to configure idmap(mapping domain).",
+ "ADJOIN failed to configure idmap(global catalog).",
+ "ADJOIN failed to refresh idmap service."
+ "ADJOIN failed to remove idmap ccache."
+};
+
+static int ads_bind(ADS_HANDLE *);
+static void ads_get_computer_dn(ADS_HANDLE *, char *, size_t);
+static char *ads_get_host_principal(char *fqhost);
+static char *ads_get_host_principal_w_realm(char *princ, char *domain);
+static int ads_get_host_principals(char *fqhost, char *domain,
+ char **princ, char **princ_r);
+static int ads_add_computer(ADS_HANDLE *ah);
+static void ads_del_computer(ADS_HANDLE *ah);
+static int ads_lookup_computer_n_attr(ADS_HANDLE *ah, char *attr, char **val);
+static int ads_modify_computer(ADS_HANDLE *ah, int des_only);
+static krb5_kvno ads_lookup_computer_attr_kvno(ADS_HANDLE *ah);
+static int ads_gen_machine_passwd(char *machine_passwd, int bufsz);
+static void ads_set_host_info(ADS_HOST_INFO *host);
+static ADS_HOST_INFO *ads_get_host_info(void);
+
+/*
+ * ads_build_unc_name
+ *
+ * Construct the UNC name of the share object in the format of
+ * \\hostname.domain\shareUNC
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+ads_build_unc_name(char *unc_name, int maxlen,
+ const char *hostname, const char *shareUNC)
+{
+ char my_domain[ADS_MAXBUFLEN];
+
+ if (smb_getdomainname(my_domain, sizeof (my_domain)) != 0)
+ return (-1);
+
+ (void) snprintf(unc_name, maxlen, "\\\\%s.%s\\%s",
+ hostname, my_domain, shareUNC);
+ return (0);
+}
+
+/*
+ * ads_skip_domain_name
+ * Skip domain name format in DNS message. The format is a sequence of
+ * ascii labels with each label having a length byte at the beginning.
+ * The domain name is terminated with a NULL character.
+ * i.e. 3sun3com0
+ * Parameters:
+ * bufptr: address of pointer of buffer that contains domain name
+ * Returns:
+ * bufptr: points to the data after the domain name label
+ */
+static void
+ads_skip_domain_name(char **bufptr)
+{
+ int i = 0;
+ unsigned char c, d;
+
+ c = (*bufptr)[i++];
+ d = c & 0xC0;
+ while (c != 0 && (d != 0xC0)) { /* do nothing */
+ c = (*bufptr)[i++];
+ d = c & 0xC0;
+ }
+
+ if (d == 0xC0)
+ /* skip 2nd byte in 2 byte ptr info */
+ i++;
+ *bufptr += i;
+}
+
+static int
+ads_is_ptr(char *buf, int len, char *offset_ptr, char **new_loc)
+{
+ uint16_t offset;
+ unsigned char c;
+
+ c = len & 0xC0;
+ if (c == 0xC0) {
+ offset_ptr = dyndns_get_nshort(offset_ptr, &offset);
+ offset &= 0x3FFF;
+ if (offset > NS_PACKETSZ) {
+ return (-1);
+ }
+ *new_loc = buf + offset;
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * ads_get_domain_name
+ * Converts the domain name format in DNS message back to string format.
+ * The format is a sequence of ascii labels with each label having a length
+ * byte at the beginning. The domain name is terminated with a NULL
+ * character.
+ * i.e. 6procom3com0 -> procom.com
+ * Parameters:
+ * bufptr : address of pointer to buffer that contains domain name
+ * dname_len: length of domain name in label format
+ * Returns:
+ * NULL : error
+ * domain name: in string format using allocated memory
+ * bufptr : points to the data after the domain name label
+ */
+static char *
+ads_get_domain_name(char *buf, char **bufptr)
+{
+ char str[256], *ptr, *new_loc;
+ int i, j, k, len, ret;
+ int skip = 0;
+ i = 0;
+ k = 0;
+ ptr = *bufptr;
+
+ /* get len of first label */
+ len = ptr[i++];
+ if ((ret = ads_is_ptr(buf, len, &ptr[i-1], &new_loc)) == 1) {
+ if (skip == 0) {
+ /* skip up to first ptr */
+ skip = i;
+ }
+
+ i = 0;
+ ptr = new_loc;
+
+ /* get len of first label */
+ len = ptr[i++];
+ } else {
+ if (ret == -1) {
+ return (NULL);
+ }
+ }
+
+ while (len) {
+ if ((len > 63) || (k >= 255))
+ return (NULL);
+
+ for (j = 0; j < len; j++)
+ str[k++] = ptr[i++];
+
+ /* get len of next label */
+ len = ptr[i++];
+ if ((ret = ads_is_ptr(buf, len, &ptr[i-1], &new_loc)) == 1) {
+ if (skip == 0) {
+ /* skip up to first ptr */
+ skip = i;
+ }
+ i = 0;
+ ptr = new_loc;
+
+ /* get len of first label */
+ len = ptr[i++];
+ } else if (ret == -1) {
+ return (NULL);
+ }
+
+ if (len) {
+ /* replace label len or ptr with '.' */
+ str[k++] = '.';
+ }
+ }
+
+ str[k] = 0;
+
+ if (skip) {
+ /* skip name with ptr or just ptr */
+ *bufptr += skip + 1;
+ } else {
+ /* skip name */
+ *bufptr += i;
+ }
+
+ return (strdup(str));
+}
+
+/*
+ * ads_ping
+ * Ping IP without displaying log. This is used to ping an ADS server to see
+ * if it is still alive before connecting to it with TCP.
+ * Taken from os/service/ping.c
+ * Parameters:
+ * hostinetaddr: 4 bytes IP address in network byte order
+ * Returns:
+ * -1: error
+ * 0: successful
+ */
+/*ARGSUSED*/
+static int
+ads_ping(unsigned long hostinetaddr)
+{
+ return (0);
+}
+
+/*
+ * ads_free_host_list
+ */
+static void
+ads_free_host_list(ADS_HOST_INFO *host_list, int count)
+{
+ int i;
+ for (i = 0; i < count; i++) {
+ free(host_list[i].name);
+ }
+ free(host_list);
+}
+
+/*
+ * ads_set_host_info
+ * Cache the result of the ADS discovery if the cache is empty.
+ */
+static void
+ads_set_host_info(ADS_HOST_INFO *host)
+{
+ (void) mutex_lock(&ads_mtx);
+ if (!ads_host_info)
+ ads_host_info = host;
+ (void) mutex_unlock(&ads_mtx);
+}
+
+/*
+ * ads_get_host_info
+ * Get the cached ADS host info.
+ */
+static ADS_HOST_INFO *
+ads_get_host_info(void)
+{
+ ADS_HOST_INFO *host;
+
+ (void) mutex_lock(&ads_mtx);
+ host = ads_host_info;
+ (void) mutex_unlock(&ads_mtx);
+ return (host);
+}
+/*
+ * ads_find_host
+ * This routine builds a DNS service location message and sends it to the
+ * DNS server via UDP to query it for a list of ADS server(s). Once a reply
+ * is received, the reply message is parsed to get the hostname and IP
+ * addresses of the ADS server(s). One ADS server will be selected from the
+ * list. A ping is sent to each host at a time and the one that respond will
+ * be selected.
+ *
+ * The service location of _ldap._tcp.dc.msdcs.<ADS domain> is used to
+ * guarantee that Microsoft domain controllers are returned. Microsoft domain
+ * controllers are also ADS servers.
+ *
+ * The ADS hostnames are stored in the answer section of the DNS reply message.
+ * The IP addresses are stored in the additional section. If the additional
+ * section does not contain any IP addresses then a DNS query by hostname is
+ * sent to get the IP address of the hostname. This is very unlikely.
+ *
+ * The DNS reply message may be in compress formed. The compression is done
+ * on repeating domain name label in the message. i.e hostname.
+ * Parameters:
+ * ns: Nameserver to use to find the ADS host
+ * domain: domain of ADS host.
+ * Returns:
+ * ADS host: fully qualified hostname, ip address, ldap port
+ * port : LDAP port of ADS host
+ */
+/*ARGSUSED*/
+ADS_HOST_INFO *
+ads_find_host(char *ns, char *domain, int *port, char *service, int *go_next)
+{
+ int s;
+ uint16_t id, rid, data_len, eport;
+ int ipaddr;
+ struct hostent *h;
+ char buf[NS_PACKETSZ], buf2[NS_PACKETSZ];
+ char *bufptr, *str;
+ int i, ret;
+ int queryReq;
+ uint16_t query_cnt, ans_cnt, namser_cnt, addit_cnt;
+ int quest_type, quest_class;
+ int dns_ip, decode_ip;
+ struct in_addr addr;
+ uint16_t flags = 0;
+ int force_recurs = 0;
+ ADS_HOST_INFO *ads_hosts_list = NULL, *ads_host;
+ ADS_HOST_INFO *ads_hosts_list2 = NULL;
+
+ *go_next = 0;
+
+ /*
+ * If we have already found an ADS server, skip the ads_find_host
+ * process. Returns the ADS host from the cache.
+ */
+ ads_host = ads_get_host_info();
+ if (ads_host)
+ return (ads_host);
+
+ if (ns == NULL || *ns == 0) {
+ return (NULL);
+ }
+ dns_ip = inet_addr(ns);
+
+ if ((s = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0)
+ return (NULL);
+
+retry:
+ /* build query request */
+ queryReq = REQ_QUERY;
+ query_cnt = 1;
+ ans_cnt = 0;
+ namser_cnt = 0;
+ addit_cnt = 0;
+
+ (void) memset(buf, 0, NS_PACKETSZ);
+ bufptr = buf;
+ id = smb_get_next_resid();
+ if (dyndns_build_header(&bufptr, BUFLEN_UDP(bufptr, buf), id, queryReq,
+ query_cnt, ans_cnt, namser_cnt, addit_cnt, flags) == -1) {
+ (void) close(s);
+ return (NULL);
+ }
+
+ quest_type = ns_t_srv;
+ quest_class = ns_c_in;
+
+ if (dyndns_build_quest_zone(&bufptr, BUFLEN_UDP(bufptr, buf), service,
+ quest_type, quest_class) == -1) {
+ (void) close(s);
+ return (NULL);
+ }
+
+ if (dyndns_udp_send_recv(s, buf, bufptr - buf, buf2) == -1) {
+ (void) close(s);
+ syslog(LOG_ERR, "smb_ads: send/receive error");
+ *go_next = 1;
+ return (NULL);
+ }
+ (void) close(s);
+
+ (void) dyndns_get_nshort(buf2, &rid);
+ if (id != rid)
+ return (NULL);
+
+ /*
+ * check if query is successful by checking error
+ * field in UDP
+ */
+ ret = buf2[3] & 0xf;
+ if (ret != NOERROR) {
+ syslog(LOG_ERR, "smb_ads: DNS query for ADS host error: %d: ",
+ ret);
+ dyndns_msg_err(ret);
+ *go_next = 1;
+ return (NULL);
+ }
+
+ bufptr = buf2;
+ bufptr += 2; /* Skip ID section */
+ bufptr = dyndns_get_nshort(bufptr, &flags);
+ bufptr = dyndns_get_nshort(bufptr, &query_cnt);
+ bufptr = dyndns_get_nshort(bufptr, &ans_cnt);
+ bufptr = dyndns_get_nshort(bufptr, &namser_cnt);
+ bufptr = dyndns_get_nshort(bufptr, &addit_cnt);
+
+ if (ans_cnt == 0) {
+ /* Check if the server supports recursive queries */
+ if (force_recurs++ == 0 && (flags & DNSF_RECUR_SUPP) != 0) {
+ flags = DNSF_RECUR_QRY;
+ goto retry;
+ }
+
+ syslog(LOG_DEBUG, "smb_ads: No ADS host found: "
+ "No answer section\n");
+ return (NULL);
+ }
+
+ /* skip question section */
+ if (query_cnt == 1) {
+ ads_skip_domain_name(&bufptr);
+ bufptr += 4;
+ } else {
+ syslog(LOG_ERR, "smb_ads: No ADS host found, malformed "
+ "question section, query_cnt: %d???\n", query_cnt);
+ return (NULL);
+ }
+
+ ads_hosts_list = (ADS_HOST_INFO *)
+ malloc(sizeof (ADS_HOST_INFO)*ans_cnt);
+ if (ads_hosts_list == NULL)
+ return (NULL);
+
+ bzero(ads_hosts_list, sizeof (ADS_HOST_INFO) * ans_cnt);
+
+ /* check answer section */
+ for (i = 0; i < ans_cnt; i++) {
+ ads_skip_domain_name(&bufptr);
+
+ /* skip type, class, ttl */
+ bufptr += 8;
+
+ /* len of data after this point */
+ bufptr = dyndns_get_nshort(bufptr, &data_len);
+
+ /* skip priority, weight */
+ bufptr += 4;
+ bufptr = dyndns_get_nshort(bufptr, &eport);
+ ads_hosts_list[i].port = eport;
+
+ if ((str = ads_get_domain_name(buf2, &bufptr)) == NULL) {
+ syslog(LOG_ERR, "smb_ads: No ADS host found, "
+ "error decoding DNS answer section\n");
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+ return (NULL);
+ }
+ ads_hosts_list[i].name = str;
+ }
+
+ /* check authority section */
+ for (i = 0; i < namser_cnt; i++) {
+ ads_skip_domain_name(&bufptr);
+
+ /* skip type, class, ttl */
+ bufptr += 8;
+
+ /* get len of data */
+ bufptr = dyndns_get_nshort(bufptr, &data_len);
+
+ /* skip data */
+ bufptr += data_len;
+ }
+
+ /* check additional section to get IP address of ads host */
+ decode_ip = 1;
+ smb_config_rdlock();
+ if (smb_config_getyorn(SMB_CI_ADS_IPLOOKUP) == 1)
+ decode_ip = 0;
+ smb_config_unlock();
+
+ if (decode_ip && (addit_cnt > 0)) {
+ int j;
+
+ ads_hosts_list2 = (ADS_HOST_INFO *)
+ malloc(sizeof (ADS_HOST_INFO) * addit_cnt);
+ if (ads_hosts_list2 == NULL) {
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+ return (NULL);
+ }
+
+ bzero(ads_hosts_list2, sizeof (ADS_HOST_INFO) * addit_cnt);
+
+ for (i = 0; i < addit_cnt; i++) {
+
+ if ((str = ads_get_domain_name(buf2,
+ &bufptr)) == NULL) {
+ syslog(LOG_ERR, "smb_ads: No ADS host found, "
+ "error decoding DNS additional section\n");
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+ ads_free_host_list(ads_hosts_list2, addit_cnt);
+ return (NULL);
+ }
+
+ ads_hosts_list2[i].name = str;
+ bufptr += 10;
+ bufptr = dyndns_get_int(bufptr, &ipaddr);
+ ads_hosts_list2[i].ip_addr = ipaddr;
+ }
+
+ /* pick a host that is up */
+ for (i = 0; i < addit_cnt; i++) {
+ if (ads_ping(ads_hosts_list2[i].ip_addr) != 0) {
+ continue;
+ }
+ for (j = 0; j < ans_cnt; j++)
+ if (strcmp(ads_hosts_list2[i].name,
+ ads_hosts_list[j].name) == 0)
+ break;
+ if (j == ans_cnt) {
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+ ads_free_host_list(ads_hosts_list2, addit_cnt);
+ return (NULL);
+ }
+ ads_host = (ADS_HOST_INFO *)
+ malloc(sizeof (ADS_HOST_INFO));
+ if (ads_host == NULL) {
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+ ads_free_host_list(ads_hosts_list2, addit_cnt);
+ return (NULL);
+ }
+ bzero(ads_host, sizeof (ADS_HOST_INFO));
+ ads_host->name = strdup(ads_hosts_list[j].name);
+ if (ads_host->name == NULL) {
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+ ads_free_host_list(ads_hosts_list2, addit_cnt);
+ return (NULL);
+ }
+ ads_host->ip_addr = ads_hosts_list2[i].ip_addr;
+ ads_host->port = ads_hosts_list[j].port;
+ *port = ads_host->port;
+ addr.s_addr = ads_host->ip_addr;
+ syslog(LOG_DEBUG, "smb_ads: Found ADS server: %s (%s)"
+ " from %s\n", ads_host->name, inet_ntoa(addr), ns);
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+ ads_free_host_list(ads_hosts_list2, addit_cnt);
+ ads_set_host_info(ads_host);
+ return (ads_host);
+ }
+ ads_free_host_list(ads_hosts_list2, addit_cnt);
+ } else {
+ /* use DNS to get IP address of ads host */
+ /*
+ * Shouldn't get here unless entries exist in
+ * DNS but DNS server did
+ * not put them in additional section of DNS reply packet.
+ */
+ for (i = 0; i < ans_cnt; i++) {
+ h = gethostbyname(ads_hosts_list[i].name);
+ if (h == NULL)
+ continue;
+ if (h->h_addr == NULL)
+ continue;
+ (void) memcpy(&ads_hosts_list[i].ip_addr,
+ h->h_addr, sizeof (addr.s_addr));
+ if (ads_ping(ads_hosts_list[i].ip_addr) == 0) {
+ ads_host = (ADS_HOST_INFO *)
+ malloc(sizeof (ADS_HOST_INFO));
+ if (ads_host == NULL) {
+ ads_free_host_list(ads_hosts_list,
+ ans_cnt);
+ return (NULL);
+ }
+ bzero(ads_host, sizeof (ADS_HOST_INFO));
+ ads_host->name = strdup(ads_hosts_list[i].name);
+ if (ads_host->name == NULL) {
+ ads_free_host_list(ads_hosts_list,
+ ans_cnt);
+ return (NULL);
+ }
+ ads_host->ip_addr = ads_hosts_list[i].ip_addr;
+ ads_host->port = ads_hosts_list[i].port;
+ *port = ads_host->port;
+ addr.s_addr = ads_host->ip_addr;
+ syslog(LOG_DEBUG, "smb_ads: Found ADS server"
+ " using DNS: %s (%s) port %d",
+ ads_host->name, inet_ntoa(addr),
+ ads_host->port);
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+ ads_set_host_info(ads_host);
+ return (ads_host);
+ }
+ }
+ }
+ syslog(LOG_ERR, "smb_ads: Can't get IP for "
+ "ADS host or ADS host is down.\n");
+ ads_free_host_list(ads_hosts_list, ans_cnt);
+
+ *go_next = 1;
+ return (NULL);
+}
+
+/*
+ * ads_convert_domain
+ * Converts a domain string into its distinguished name i.e. a unique
+ * name for an entry in the Directory Service.
+ * Memory is allocated
+ * for the new string.
+ * i.e. procom.com -> dc=procom,dc=com
+ * Parameters:
+ * s: fully qualified DNS domain string
+ * Returns:
+ * NULL if error
+ * DNS domain in LDAP DN string format
+ */
+static char *
+ads_convert_domain(char *s)
+{
+ char *t, *s2, *t2;
+ int len, cnt;
+
+ if (s == NULL || *s == 0)
+ return (NULL);
+
+ cnt = 0;
+ t = s;
+ while (*t) {
+ if (*t++ == '.') {
+ cnt++;
+ }
+ }
+
+ len = 3 + strlen(s) + cnt*3 + 1;
+
+ s2 = (char *)malloc(len);
+ if (s2 == NULL)
+ return (NULL);
+
+ bzero(s2, len);
+
+ t = s2;
+ (void) strncpy(t, "dc=", 3);
+ t += 3;
+ t2 = s;
+ while (*s) {
+ if (*s == '.') {
+ if (t + 3 >= s2 + len - 1) {
+ syslog(LOG_ERR, "[ads_convert_domain] "
+ "buffer overrun for string "
+ "conversion of %s: tot buf "
+ "sz alloc: %d, last "
+ "written buf offset: %d\n",
+ t2, len, t+3-s2);
+ free(s2);
+ return (NULL);
+ }
+ (void) strncpy(t, ",dc=", 4);
+ t += 4;
+ s++;
+ } else {
+ if (t >= s2 + len - 1) {
+ syslog(LOG_ERR, "[ads_convert_domain] "
+ "buffer overrun for string "
+ "conversion of %s: tot buf "
+ "sz alloc: %d, last "
+ "written buf offset: %d\n",
+ t2, len, t-s2);
+ free(s2);
+ return (NULL);
+ }
+ *t++ = *s++;
+ }
+ }
+ *t = '\0';
+ return (s2);
+}
+
+/*
+ * ads_free_host_info
+ * Free the memory use by the global ads_host_info and set it to NULL.
+ */
+void
+ads_free_host_info(void)
+{
+ (void) mutex_lock(&ads_mtx);
+ if (ads_host_info) {
+ free(ads_host_info->name);
+ free(ads_host_info);
+ ads_host_info = NULL;
+ }
+ (void) mutex_unlock(&ads_mtx);
+}
+
+/*
+ * ads_open
+ * Open a LDAP connection to an ADS server.
+ * If ADS is enabled and the administrative username, password, container, and
+ * ADS domain are defined then query DNS to find an ADS server if this is the
+ * very first call to this routine. After an ADS server is found then this
+ * server will be used everytime this routine is called until the system is
+ * rebooted or the ADS server becomes unavailable then an ADS server will
+ * be queried again. The ADS server is always ping before an LDAP connection
+ * is made to it. If the pings fail then DNS is used once more to find an
+ * available ADS server. If the ping is successful then an LDAP connection
+ * is made to the ADS server. After the connection is made then an ADS handle
+ * is created to be returned.
+ *
+ * After the LDAP connection, the LDAP version will be set to 3 using
+ * ldap_set_option().
+ *
+ * The ads_bind() routine is also called before the ADS handle is returned.
+ * Parameters:
+ * None
+ * Returns:
+ * NULL : can't connect to ADS server or other errors
+ * ADS_HANDLE* : handle to ADS server
+ */
+ADS_HANDLE *
+ads_open(void)
+{
+ ADS_HANDLE *ah;
+ LDAP *ld;
+ int version = 3, ads_port, find_ads_retry;
+ char *adminUser, *password, *container;
+ char domain[MAXHOSTNAMELEN];
+ int enable;
+ ADS_HOST_INFO *ads_host = NULL;
+ struct in_addr addr;
+ char *site, *service = NULL, *site_service = NULL;
+ int service_sz;
+ struct in_addr ns_list[MAXNS];
+ int i, cnt, go_next;
+
+ if (smb_getdomainname(domain, MAXHOSTNAMELEN) != 0)
+ return (NULL);
+
+ smb_config_rdlock();
+ enable = smb_config_getyorn(SMB_CI_ADS_ENABLE);
+ if (!enable) {
+ smb_config_unlock();
+ return (NULL);
+ }
+ adminUser = smb_config_getstr(SMB_CI_ADS_USER);
+ if (adminUser == NULL || *adminUser == 0) {
+ syslog(LOG_ERR, "smb_ads: admin user is not set");
+ smb_config_unlock();
+ return (NULL);
+ }
+ password = smb_config_getstr(SMB_CI_ADS_PASSWD);
+ if (password == NULL || *password == 0) {
+ syslog(LOG_ERR, "smb_ads: admin user password is not set");
+ smb_config_unlock();
+ return (NULL);
+ }
+ container = smb_config_getstr(SMB_CI_ADS_USER_CONTAINER);
+ if (container == NULL || *container == 0)
+ container = "cn=Users";
+
+ site = smb_config_getstr(SMB_CI_ADS_SITE);
+ smb_config_unlock();
+
+
+
+ find_ads_retry = 0;
+find_ads_host:
+
+ ads_host = ads_get_host_info();
+ if (!ads_host) {
+ if (site && *site != 0) {
+ service_sz = strlen("_ldap._tcp.._sites.dc._msdcs.") +
+ strlen(site) + strlen(domain) + 1;
+ site_service = (char *)malloc(service_sz);
+ if (site_service == NULL) {
+ syslog(LOG_ERR, "smb_ads: No ADS host found"
+ " malloc failed...");
+ return (NULL);
+ }
+ (void) snprintf(site_service, service_sz,
+ "_ldap._tcp.%s._sites.dc._msdcs.%s", site, domain);
+ }
+ service_sz = strlen("_ldap._tcp.dc._msdcs.") + strlen(domain)
+ + 1;
+ service = (char *)malloc(service_sz);
+ if (service == NULL) {
+ syslog(LOG_ERR, "smb_ads: No ADS host found malloc"
+ " failed...");
+ if (site_service != NULL)
+ (void) free(site_service);
+ return (NULL);
+ }
+ (void) snprintf(service, service_sz, "_ldap._tcp.dc._msdcs.%s",
+ domain);
+
+ cnt = smb_get_nameservers(ns_list, MAXNS);
+
+ ads_host = NULL;
+ go_next = 0;
+ for (i = 0; i < cnt; i++) {
+ if (site_service != NULL) {
+ ads_host = ads_find_host(inet_ntoa(ns_list[i]),
+ domain, &ads_port, site_service, &go_next);
+ }
+ if (ads_host == NULL) {
+ ads_host = ads_find_host(inet_ntoa(ns_list[i]),
+ domain, &ads_port, service, &go_next);
+ }
+ if (ads_host != NULL)
+ break;
+ if (go_next == 0)
+ break;
+ }
+ }
+
+ if (site_service)
+ (void) free(site_service);
+ if (service)
+ (void) free(service);
+
+ if (ads_host == NULL) {
+ syslog(LOG_ERR, "smb_ads: No ADS host found from "
+ "configured nameservers");
+ return (NULL);
+ }
+
+ if (ads_ping(ads_host->ip_addr) != 0) {
+ ads_free_host_info();
+ ads_host = NULL;
+ if (find_ads_retry == 0) {
+ find_ads_retry = 1;
+ goto find_ads_host;
+ }
+ return (NULL);
+ }
+
+ ah = (ADS_HANDLE *)malloc(sizeof (ADS_HANDLE));
+ if (ah == NULL) {
+ return (NULL);
+ }
+ (void) memset(ah, 0, sizeof (ADS_HANDLE));
+
+ addr.s_addr = ads_host->ip_addr;
+ if ((ld = ldap_init((char *)inet_ntoa(addr), ads_host->port)) == NULL) {
+ syslog(LOG_ERR, "smb_ads: Could not open connection "
+ "to host: %s\n", ads_host->name);
+ ads_free_host_info();
+ ads_host = NULL;
+ free(ah);
+ if (find_ads_retry == 0) {
+ find_ads_retry = 1;
+ goto find_ads_host;
+ }
+ return (NULL);
+ }
+
+ if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version)
+ != LDAP_SUCCESS) {
+ syslog(LOG_ERR, "smb_ads: Could not set "
+ "LDAP_OPT_PROTOCOL_VERSION %d\n", version);
+ ads_free_host_info();
+ free(ah);
+ (void) ldap_unbind(ld);
+ return (NULL);
+ }
+
+ ah->ld = ld;
+ ah->user = strdup(adminUser);
+ ah->pwd = strdup(password);
+ ah->container = strdup(container);
+ ah->domain = strdup(domain);
+
+ if ((ah->user == NULL) || (ah->pwd == NULL) ||
+ (ah->container == NULL) || (ah->domain == NULL)) {
+ ads_close(ah);
+ return (NULL);
+ }
+
+ ah->domain_dn = ads_convert_domain(domain);
+ if (ah->domain_dn == NULL) {
+ ads_close(ah);
+ return (NULL);
+ }
+
+ ah->hostname = strdup(ads_host->name);
+ if (ah->hostname == NULL) {
+ ads_close(ah);
+ return (NULL);
+ }
+ if (site) {
+ ah->site = strdup(site);
+ if (ah->site == NULL) {
+ ads_close(ah);
+ return (NULL);
+ }
+ } else {
+ ah->site = NULL;
+ }
+
+ if (ads_bind(ah) == -1) {
+ ads_close(ah);
+ return (NULL);
+ }
+
+ return (ah);
+}
+
+/*
+ * ads_close
+ * Close connection to ADS server and free memory allocated for ADS handle.
+ * LDAP unbind is called here.
+ * Parameters:
+ * ah: handle to ADS server
+ * Returns:
+ * void
+ */
+void
+ads_close(ADS_HANDLE *ah)
+{
+ int len;
+
+ if (ah == NULL)
+ return;
+ /* close and free connection resources */
+ if (ah->ld)
+ (void) ldap_unbind(ah->ld);
+
+ free(ah->user);
+ if (ah->pwd) {
+ len = strlen(ah->pwd);
+ /* zero out the memory that contains user's password */
+ if (len > 0)
+ bzero(ah->pwd, len);
+ free(ah->pwd);
+ }
+ free(ah->container);
+ free(ah->domain);
+ free(ah->domain_dn);
+ free(ah->hostname);
+ free(ah->site);
+ free(ah);
+}
+
+/*
+ * ads_display_stat
+ * Display error message for GSS-API routines.
+ * Parameters:
+ * maj: GSS major status
+ * min: GSS minor status
+ * Returns:
+ * None
+ */
+static void
+ads_display_stat(OM_uint32 maj, OM_uint32 min)
+{
+ gss_buffer_desc msg;
+ OM_uint32 msg_ctx = 0;
+ OM_uint32 min2;
+ (void) gss_display_status(&min2, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ syslog(LOG_ERR, "smb_ads: major status error: %s\n", (char *)msg.value);
+ (void) gss_display_status(&min2, min, GSS_C_MECH_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ syslog(LOG_ERR, "smb_ads: minor status error: %s\n", (char *)msg.value);
+}
+
+/*
+ * free_attr
+ * Free memory allocated when publishing a share.
+ * Parameters:
+ * addattrs: an array of LDAPMod pointers
+ * Returns:
+ * None
+ */
+static void
+free_attr(LDAPMod *addattrs[])
+{
+ int i;
+ for (i = 0; addattrs[i]; i++) {
+ free(addattrs[i]);
+ }
+}
+
+/*
+ * ads_acquire_cred
+ * Called by ads_bind() to get a handle to administrative user's credential
+ * stored locally on the system. The credential is the TGT. If the attempt at
+ * getting handle fails then a second attempt will be made after getting a
+ * new TGT.
+ * Please look at ads_bind() for more information.
+ *
+ * Paramters:
+ * ah : handle to ADS server
+ * kinit_retry: if 0 then a second attempt will be made to get handle to the
+ * credential if the first attempt fails
+ * Returns:
+ * cred_handle: handle to the administrative user's credential (TGT)
+ * oid : contains Kerberos 5 object identifier
+ * kinit_retry: A 1 indicates that a second attempt has been made to get
+ * handle to the credential and no further attempts can be made
+ * -1 : error
+ * 0 : success
+ */
+static int
+ads_acquire_cred(ADS_HANDLE *ah, gss_cred_id_t *cred_handle, gss_OID *oid,
+ int *kinit_retry)
+{
+ return (krb5_acquire_cred_kinit(ah->user, ah->pwd, cred_handle, oid,
+ kinit_retry, "ads"));
+}
+
+/*
+ * ads_establish_sec_context
+ * Called by ads_bind() to establish a security context to an LDAP service on
+ * an ADS server. If the attempt at establishing the security context fails
+ * then a second attempt will be made by ads_bind() if a new TGT has not been
+ * already obtained in ads_acquire_cred. The second attempt, if allowed, will
+ * obtained a new TGT here and a new handle to the credential will also be
+ * obtained in ads_acquire_cred. LDAP SASL bind is used to send and receive
+ * the GSS tokens to and from the ADS server.
+ * Please look at ads_bind for more information.
+ * Paramters:
+ * ah : handle to ADS server
+ * cred_handle : handle to administrative user's credential (TGT)
+ * oid : Kerberos 5 object identifier
+ * kinit_retry : if 0 then a second attempt can be made to establish a
+ * security context with ADS server if first attempt fails
+ * Returns:
+ * gss_context : security context to ADS server
+ * sercred : encrypted ADS server's supported security layers
+ * do_acquire_cred: if 1 then a second attempt will be made to establish a
+ * security context with ADS server after getting a new
+ * handle to the user's credential
+ * kinit_retry : if 1 then a second attempt will be made to establish a
+ * a security context and no further attempts can be made
+ * -1 : error
+ * 0 : success
+ */
+static int
+ads_establish_sec_context(ADS_HANDLE *ah, gss_ctx_id_t *gss_context,
+ gss_cred_id_t cred_handle, gss_OID oid, struct berval **sercred,
+ int *kinit_retry, int *do_acquire_cred)
+{
+ OM_uint32 maj, min, time_rec;
+ char service_name[ADS_MAXBUFLEN], *user_dn;
+ gss_buffer_desc send_tok, service_buf;
+ gss_name_t target_name;
+ gss_buffer_desc input;
+ gss_buffer_desc *inputptr;
+ struct berval cred;
+ OM_uint32 ret_flags;
+ int stat, len;
+ int gss_flags;
+
+ /*
+ * 6 additional bytes for the "cn=,, " and the null terminator
+ */
+ len = strlen(ah->user) + strlen(ah->container) +
+ strlen(ah->domain_dn) + 6;
+
+ if ((user_dn = (char *)malloc(len)) == NULL)
+ return (-1);
+
+ (void) snprintf(user_dn, len, "cn=%s,%s,%s", ah->user, ah->container,
+ ah->domain_dn);
+
+ (void) snprintf(service_name, ADS_MAXBUFLEN, "ldap@%s", ah->hostname);
+ service_buf.value = service_name;
+ service_buf.length = strlen(service_name)+1;
+ if ((maj = gss_import_name(&min, &service_buf,
+ (gss_OID) gss_nt_service_name,
+ &target_name)) != GSS_S_COMPLETE) {
+ ads_display_stat(maj, min);
+ (void) gss_release_oid(&min, &oid);
+ free(user_dn);
+ return (-1);
+ }
+
+ *gss_context = GSS_C_NO_CONTEXT;
+ *sercred = NULL;
+ inputptr = GSS_C_NO_BUFFER;
+ gss_flags = GSS_C_MUTUAL_FLAG;
+ do {
+ if (krb5_establish_sec_ctx_kinit(ah->user, ah->pwd,
+ cred_handle, gss_context, target_name, oid,
+ gss_flags, inputptr, &send_tok,
+ &ret_flags, &time_rec, kinit_retry,
+ do_acquire_cred, &maj, "ads") == -1) {
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ free(user_dn);
+ return (-1);
+ }
+
+ cred.bv_val = send_tok.value;
+ cred.bv_len = send_tok.length;
+ if (*sercred) {
+ ber_bvfree(*sercred);
+ *sercred = NULL;
+ }
+ stat = ldap_sasl_bind_s(ah->ld, user_dn, "GSSAPI",
+ &cred, NULL, NULL, sercred);
+ if (stat != LDAP_SUCCESS &&
+ stat != LDAP_SASL_BIND_IN_PROGRESS) {
+ /* LINTED - E_SEC_PRINTF_VAR_FMT */
+ syslog(LOG_ERR, ldap_err2string(stat));
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ (void) gss_release_buffer(&min, &send_tok);
+ free(user_dn);
+ return (-1);
+ }
+ input.value = (*sercred)->bv_val;
+ input.length = (*sercred)->bv_len;
+ inputptr = &input;
+ if (send_tok.length > 0)
+ (void) gss_release_buffer(&min, &send_tok);
+ } while (maj != GSS_S_COMPLETE);
+
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ free(user_dn);
+
+ return (0);
+}
+
+/*
+ * ads_negotiate_sec_layer
+ * Call by ads_bind() to negotiate additional security layer for further
+ * communication after security context establishment. No additional security
+ * is needed so a "no security layer" is negotiated. The security layer is
+ * described in the SASL RFC 2478 and this step is needed for secure LDAP
+ * binding. LDAP SASL bind is used to send and receive the GSS tokens to and
+ * from the ADS server.
+ * Please look at ads_bind for more information.
+ *
+ * Paramters:
+ * ah : handle to ADS server
+ * gss_context: security context to ADS server
+ * sercred : encrypted ADS server's supported security layers
+ * Returns:
+ * -1 : error
+ * 0 : success
+ */
+static int
+ads_negotiate_sec_layer(ADS_HANDLE *ah, gss_ctx_id_t gss_context,
+ struct berval *sercred)
+{
+ OM_uint32 maj, min;
+ gss_buffer_desc unwrap_inbuf, unwrap_outbuf;
+ gss_buffer_desc wrap_inbuf, wrap_outbuf;
+ int conf_state, sec_layer;
+ char auth_id[5];
+ struct berval cred;
+ int stat;
+ gss_qop_t qt;
+
+ /* check for server supported security layer */
+ unwrap_inbuf.value = sercred->bv_val;
+ unwrap_inbuf.length = sercred->bv_len;
+ if ((maj = gss_unwrap(&min, gss_context,
+ &unwrap_inbuf, &unwrap_outbuf,
+ &conf_state, &qt)) != GSS_S_COMPLETE) {
+ ads_display_stat(maj, min);
+ if (sercred)
+ ber_bvfree(sercred);
+ return (-1);
+ }
+ sec_layer = *((char *)unwrap_outbuf.value);
+ (void) gss_release_buffer(&min, &unwrap_outbuf);
+ if (!(sec_layer & 1)) {
+ syslog(LOG_ERR, "smb_ads: ADS server does not support "
+ "no security layer!\n");
+ if (sercred) ber_bvfree(sercred);
+ return (-1);
+ }
+ if (sercred) ber_bvfree(sercred);
+
+ /* no security layer needed after successful binding */
+ auth_id[0] = 0x01;
+
+ /* byte 2-4: max client recv size in network byte order */
+ auth_id[1] = 0x00;
+ auth_id[2] = 0x40;
+ auth_id[3] = 0x00;
+ wrap_inbuf.value = auth_id;
+ wrap_inbuf.length = 4;
+ conf_state = 0;
+ if ((maj = gss_wrap(&min, gss_context, conf_state, 0, &wrap_inbuf,
+ &conf_state, &wrap_outbuf)) != GSS_S_COMPLETE) {
+ ads_display_stat(maj, min);
+ return (-1);
+ }
+
+ cred.bv_val = wrap_outbuf.value;
+ cred.bv_len = wrap_outbuf.length;
+ sercred = NULL;
+ stat = ldap_sasl_bind_s(ah->ld, NULL, "GSSAPI", &cred, NULL, NULL,
+ &sercred);
+ if (stat != LDAP_SUCCESS && stat != LDAP_SASL_BIND_IN_PROGRESS) {
+ /* LINTED - E_SEC_PRINTF_VAR_FMT */
+ syslog(LOG_ERR, ldap_err2string(stat));
+ (void) gss_release_buffer(&min, &wrap_outbuf);
+ return (-1);
+ }
+
+ (void) gss_release_buffer(&min, &wrap_outbuf);
+ if (sercred)
+ ber_bvfree(sercred);
+
+ return (0);
+}
+
+/*
+ * ads_bind
+ * Use secure binding to bind to ADS server.
+ * Use GSS-API with Kerberos 5 as the security mechanism and LDAP SASL with
+ * Kerberos 5 as the security mechanisn to authenticate, obtain a security
+ * context, and securely bind an administrative user so that other LDAP
+ * commands can be used, i.e. add and delete.
+ *
+ * To obtain the security context, a Kerberos ticket-granting ticket (TGT)
+ * for the user is needed to obtain a ticket for the LDAP service. To get
+ * a TGT for the user, the username and password is needed. Once a TGT is
+ * obtained then it will be stored locally and used until it is expired.
+ * This routine will automatically obtained a TGT for the first time or when
+ * it expired. LDAP SASL bind is then finally used to send GSS tokens to
+ * obtain a security context for the LDAP service on the ADS server. If
+ * there is any problem getting the security context then a new TGT will be
+ * obtain to try getting the security context once more.
+ *
+ * After the security context is obtain and established, the LDAP SASL bind
+ * is used to negotiate an additional security layer. No further security is
+ * needed so a "no security layer" is negotiated. After this the security
+ * context can be deleted and further LDAP commands can be sent to the ADS
+ * server until a LDAP unbind command is issued to the ADS server.
+ * Paramaters:
+ * ah: handle to ADS server
+ * Returns:
+ * -1: error
+ * 0: success
+ */
+static int
+ads_bind(ADS_HANDLE *ah)
+{
+ OM_uint32 min;
+ gss_cred_id_t cred_handle;
+ gss_ctx_id_t gss_context;
+ OM_uint32 maj;
+ gss_OID oid;
+ struct berval *sercred;
+ int kinit_retry, do_acquire_cred;
+
+ kinit_retry = 0;
+ do_acquire_cred = 0;
+ acquire_cred:
+
+ if (ads_acquire_cred(ah, &cred_handle, &oid, &kinit_retry))
+ return (-1);
+
+ if (ads_establish_sec_context(ah, &gss_context, cred_handle,
+ oid, &sercred, &kinit_retry, &do_acquire_cred)) {
+ (void) gss_release_cred(&min, &cred_handle);
+ if (do_acquire_cred) {
+ do_acquire_cred = 0;
+ goto acquire_cred;
+ }
+ return (-1);
+ }
+
+ if (ads_negotiate_sec_layer(ah, gss_context, sercred)) {
+ (void) gss_release_cred(&min, &cred_handle);
+ (void) gss_delete_sec_context(&min, &gss_context, NULL);
+ return (-1);
+ }
+
+ if ((maj = gss_release_cred(&min, &cred_handle))
+ != GSS_S_COMPLETE) {
+ syslog(LOG_ERR, "smb_ads: Can't release credential handle\n");
+ ads_display_stat(maj, min);
+ (void) gss_delete_sec_context(&min, &gss_context, NULL);
+ return (-1);
+ }
+
+ if ((maj = gss_delete_sec_context(&min, &gss_context, NULL))
+ != GSS_S_COMPLETE) {
+ syslog(LOG_ERR, "smb_ads: Can't delete security context\n");
+ ads_display_stat(maj, min);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * ads_add_share
+ * Call by ads_publish_share to create share object in ADS.
+ * This routine specifies the attributes of an ADS LDAP share object. The first
+ * attribute and values define the type of ADS object, the share object. The
+ * second attribute and value define the UNC of the share data for the share
+ * object. The LDAP synchronous add command is used to add the object into ADS.
+ * The container location to add the object needs to specified.
+ * Parameters:
+ * ah : handle to ADS server
+ * adsShareName: name of share object to be created in ADS
+ * shareUNC : share name on NetForce
+ * adsContainer: location in ADS to create share object
+ *
+ * Returns:
+ * -1 : error
+ * 0 : success
+ */
+int
+ads_add_share(ADS_HANDLE *ah, const char *adsShareName,
+ const char *unc_name, const char *adsContainer)
+{
+ LDAPMod *addattrs[3];
+ char *tmp1[5], *tmp2[5];
+ int j = -1;
+ char *share_dn;
+ char buf[ADS_MAXMSGLEN];
+
+ int len, ret;
+
+ len = 5 + strlen(adsShareName) + strlen(adsContainer) +
+ strlen(ah->domain_dn) + 1;
+
+ share_dn = (char *)malloc(len);
+ if (share_dn == NULL)
+ return (-1);
+
+ (void) snprintf(share_dn, len, "cn=%s,%s,%s", adsShareName,
+ adsContainer, ah->domain_dn);
+
+ addattrs[++j] = (LDAPMod *)malloc(sizeof (LDAPMod));
+ addattrs[j]->mod_op = LDAP_MOD_ADD;
+ addattrs[j]->mod_type = "objectClass";
+ tmp1[0] = "top";
+ tmp1[1] = "leaf";
+ tmp1[2] = "connectionPoint";
+ tmp1[3] = "volume";
+ tmp1[4] = 0;
+ addattrs[j]->mod_values = tmp1;
+
+ addattrs[++j] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ addattrs[j]->mod_op = LDAP_MOD_ADD;
+ addattrs[j]->mod_type = "uNCName";
+
+ tmp2[0] = (char *)unc_name;
+ tmp2[1] = 0;
+ addattrs[j]->mod_values = tmp2;
+
+ addattrs[++j] = 0;
+
+ if ((ret = ldap_add_s(ah->ld, share_dn, addattrs)) != LDAP_SUCCESS) {
+ (void) snprintf(buf, ADS_MAXMSGLEN,
+ "ads_add_share: %s:", share_dn);
+ /* LINTED - E_SEC_PRINTF_VAR_FMT */
+ syslog(LOG_ERR, ldap_err2string(ret));
+ free_attr(addattrs);
+ free(share_dn);
+ return (ret);
+ }
+ free(share_dn);
+ free_attr(addattrs);
+
+ (void) snprintf(buf, ADS_MAXMSGLEN,
+ "Share %s has been added to ADS container: %s.\n", adsShareName,
+ adsContainer);
+ syslog(LOG_DEBUG, "smb_ads: %s", buf);
+
+ return (0);
+}
+
+/*
+ * ads_del_share
+ * Call by ads_remove_share to remove share object from ADS. The container
+ * location to remove the object needs to specified. The LDAP synchronous
+ * delete command is used.
+ * Parameters:
+ * ah : handle to ADS server
+ * adsShareName: name of share object in ADS to be removed
+ * adsContainer: location of share object in ADS
+ * Returns:
+ * -1 : error
+ * 0 : success
+ */
+static int
+ads_del_share(ADS_HANDLE *ah, const char *adsShareName,
+ const char *adsContainer)
+{
+ char *share_dn, buf[ADS_MAXMSGLEN];
+ int len, ret;
+
+ len = 5 + strlen(adsShareName) + strlen(adsContainer) +
+ strlen(ah->domain_dn) + 1;
+
+ share_dn = (char *)malloc(len);
+ if (share_dn == NULL)
+ return (-1);
+
+ (void) snprintf(share_dn, len, "cn=%s,%s,%s", adsShareName,
+ adsContainer, ah->domain_dn);
+ if ((ret = ldap_delete_s(ah->ld, share_dn)) != LDAP_SUCCESS) {
+ /* LINTED - E_SEC_PRINTF_VAR_FMT */
+ syslog(LOG_ERR, ldap_err2string(ret));
+ free(share_dn);
+ return (-1);
+ }
+ free(share_dn);
+
+ (void) snprintf(buf, ADS_MAXMSGLEN,
+ "Share %s has been removed from ADS container: %s.\n",
+ adsShareName, adsContainer);
+ syslog(LOG_DEBUG, "smb_ads: %s", buf);
+
+ return (0);
+}
+
+
+/*
+ * ads_escape_search_filter_chars
+ *
+ * This routine will escape the special characters found in a string
+ * that will later be passed to the ldap search filter.
+ *
+ * RFC 1960 - A String Representation of LDAP Search Filters
+ * 3. String Search Filter Definition
+ * If a value must contain one of the characters '*' OR '(' OR ')',
+ * these characters
+ * should be escaped by preceding them with the backslash '\' character.
+ *
+ * RFC 2252 - LDAP Attribute Syntax Definitions
+ * a backslash quoting mechanism is used to escape
+ * the following separator symbol character (such as "'", "$" or "#") if
+ * it should occur in that string.
+ */
+static int
+ads_escape_search_filter_chars(const char *src, char *dst)
+{
+ int avail = ADS_MAXBUFLEN - 1; /* reserve a space for NULL char */
+
+ if (src == NULL || dst == NULL)
+ return (-1);
+
+ while (*src) {
+ if (!avail) {
+ *dst = 0;
+ return (-1);
+ }
+
+ switch (*src) {
+ case '\\':
+ case '\'':
+ case '$':
+ case '#':
+ case '*':
+ case '(':
+ case ')':
+ *dst++ = '\\';
+ avail--;
+ /* fall through */
+
+ default:
+ *dst++ = *src++;
+ avail--;
+ }
+ }
+
+ *dst = 0;
+
+ return (0);
+}
+
+/*
+ * ads_lookup_share
+ * The search filter is set to search for a specific share name in the
+ * specified ADS container. The LDSAP synchronous search command is used.
+ * Parameters:
+ * ah : handle to ADS server
+ * adsShareName: name of share object in ADS to be searched
+ * adsContainer: location of share object in ADS
+ * Returns:
+ * -1 : error
+ * 0 : not found
+ * 1 : found
+ */
+int
+ads_lookup_share(ADS_HANDLE *ah, const char *adsShareName,
+ const char *adsContainer, char *unc_name)
+{
+ char *attrs[4], filter[ADS_MAXBUFLEN];
+ char *share_dn;
+ int len, ret;
+ LDAPMessage *res;
+ char tmpbuf[ADS_MAXBUFLEN];
+
+ if (adsShareName == NULL || adsContainer == NULL)
+ return (-1);
+
+ len = 5 + strlen(adsShareName) + strlen(adsContainer) +
+ strlen(ah->domain_dn) + 1;
+
+ share_dn = (char *)malloc(len);
+ if (share_dn == NULL)
+ return (-1);
+
+ (void) snprintf(share_dn, len, "cn=%s,%s,%s", adsShareName,
+ adsContainer, ah->domain_dn);
+
+ res = NULL;
+ attrs[0] = "cn";
+ attrs[1] = "objectClass";
+ attrs[2] = "uNCName";
+ attrs[3] = NULL;
+
+ if (ads_escape_search_filter_chars(unc_name, tmpbuf) != 0) {
+ free(share_dn);
+ return (-1);
+ }
+
+ (void) snprintf(filter, sizeof (filter),
+ "(&(objectClass=volume)(uNCName=%s))", tmpbuf);
+
+ if ((ret = ldap_search_s(ah->ld, share_dn,
+ LDAP_SCOPE_BASE, filter, attrs, 0, &res)) != LDAP_SUCCESS) {
+ /* LINTED - E_SEC_PRINTF_VAR_FMT */
+ syslog(LOG_ERR, ldap_err2string(ret));
+ (void) ldap_msgfree(res);
+ free(share_dn);
+ return (0);
+ }
+
+ (void) free(share_dn);
+
+ /* no match is found */
+ if (ldap_count_entries(ah->ld, res) == 0) {
+ (void) ldap_msgfree(res);
+ return (0);
+ }
+
+ /* free the search results */
+ (void) ldap_msgfree(res);
+
+ return (1);
+}
+
+/*
+ * ads_convert_directory
+ * Convert relative share directory to UNC to be appended to hostname.
+ * i.e. cvol/a/b -> cvol\a\b
+ */
+char *
+ads_convert_directory(char *rel_dir)
+{
+ char *t, *s2;
+ int len;
+
+ if (rel_dir == NULL)
+ return (NULL);
+
+ len = strlen(rel_dir) + 1;
+ s2 = (char *)malloc(len);
+ if (s2 == NULL)
+ return (NULL);
+
+ t = s2;
+ while (*rel_dir) {
+ if (*rel_dir == '/') {
+ *t++ = '\\';
+ rel_dir++;
+ } else {
+ *t++ = *rel_dir++;
+ }
+ }
+ *t = '\0';
+ return (s2);
+}
+
+/*
+ * ads_publish_share
+ * Publish share into ADS. If a share name already exist in ADS in the same
+ * container then the existing share object is removed before adding the new
+ * share object.
+ * Parameters:
+ * ah : handle return from ads_open
+ * adsShareName: name of share to be added to ADS directory
+ * shareUNC : name of share on client, can be NULL to use the same name
+ * as adsShareName
+ * adsContainer: location for share to be added in ADS directory, ie
+ * ou=share_folder
+ * uncType : use UNC_HOSTNAME to use hostname for UNC, use UNC_HOSTADDR
+ * to use host ip addr for UNC.
+ * Returns:
+ * -1 : error
+ * 0 : success
+ */
+int
+ads_publish_share(ADS_HANDLE *ah, const char *adsShareName,
+ const char *shareUNC, const char *adsContainer, const char *hostname)
+{
+ int ret;
+ char unc_name[ADS_MAXBUFLEN];
+
+ if (adsShareName == NULL || adsContainer == NULL)
+ return (-1);
+
+ if (shareUNC == 0 || *shareUNC == 0)
+ shareUNC = adsShareName;
+
+ if (ads_build_unc_name(unc_name, sizeof (unc_name),
+ hostname, shareUNC) < 0) {
+ syslog(LOG_DEBUG, "smb_ads: Cannot publish share '%s' "
+ "[missing UNC name]", shareUNC);
+ return (-1);
+ }
+
+ ret = ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
+
+ switch (ret) {
+ case 1:
+ (void) ads_del_share(ah, adsShareName, adsContainer);
+ ret = ads_add_share(ah, adsShareName, unc_name, adsContainer);
+ break;
+
+ case 0:
+ ret = ads_add_share(ah, adsShareName, unc_name, adsContainer);
+ if (ret == LDAP_ALREADY_EXISTS) {
+ syslog(LOG_DEBUG, "smb_ads: Cannot publish share '%s' "
+ "[name is already in use]", adsShareName);
+ ret = -1;
+ }
+ break;
+
+ case -1:
+ default:
+ /* return with error code */
+ ret = -1;
+ }
+
+ return (ret);
+}
+
+/*
+ * ads_remove_share
+ * Remove share from ADS. A search is done first before explicitly removing
+ * the share.
+ * Parameters:
+ * ah : handle return from ads_open
+ * adsShareName: name of share to be removed from ADS directory
+ * adsContainer: location for share to be removed from ADS directory, ie
+ * ou=share_folder
+ * Returns:
+ * -1 : error
+ * 0 : success
+ */
+int
+ads_remove_share(ADS_HANDLE *ah, const char *adsShareName, const char *shareUNC,
+ const char *adsContainer, const char *hostname)
+{
+ int ret;
+ char unc_name[ADS_MAXBUFLEN];
+
+ if (adsShareName == NULL || adsContainer == NULL)
+ return (-1);
+ if (shareUNC == 0 || *shareUNC == 0)
+ shareUNC = adsShareName;
+
+ if (ads_build_unc_name(unc_name, sizeof (unc_name),
+ hostname, shareUNC) < 0) {
+ syslog(LOG_DEBUG, "smb_ads: Unable to remove share '%s' from "
+ "ADS [missing UNC name]", shareUNC);
+ return (-1);
+ }
+
+ ret = ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
+ if (ret == 0)
+ return (0);
+ if (ret == -1)
+ return (-1);
+
+ return (ads_del_share(ah, adsShareName, adsContainer));
+}
+
+/*
+ * ads_get_computer_dn
+ *
+ * Build the distinguish name for this system.
+ */
+static void
+ads_get_computer_dn(ADS_HANDLE *ah, char *buf, size_t buflen)
+{
+ char hostname[MAXHOSTNAMELEN];
+
+ (void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
+ (void) snprintf(buf, buflen, "cn=%s,cn=%s,%s",
+ hostname, ADS_COMPUTERS_CN, ah->domain_dn);
+}
+
+static char *
+ads_get_host_principal(char *fqhost)
+{
+ int len;
+ char *princ;
+
+ if (!fqhost)
+ return (NULL);
+
+ len = strlen(ADS_HOST_PREFIX) + strlen(fqhost) + 1;
+ princ = (char *)malloc(len);
+
+ if (!princ) {
+ syslog(LOG_ERR, "ads_get_host_principal: resource shortage");
+ return (NULL);
+ }
+ (void) snprintf(princ, len, "%s%s", ADS_HOST_PREFIX,
+ fqhost);
+
+ return (princ);
+}
+
+static char *
+ads_get_host_principal_w_realm(char *princ, char *domain)
+{
+ int len;
+ char *realm;
+ char *princ_r;
+
+ if (!princ || !domain)
+ return (NULL);
+
+ realm = strdup(domain);
+ if (!realm)
+ return (NULL);
+
+ (void) utf8_strupr(realm);
+
+ len = strlen(princ) + 1 + strlen(realm) + 1;
+ princ_r = (char *)malloc(len);
+ if (!princ_r) {
+ syslog(LOG_ERR, "ads_get_host_principal_w_realm: resource"
+ " shortage");
+ free(realm);
+ return (NULL);
+ }
+
+ (void) snprintf(princ_r, len, "%s@%s", princ, realm);
+ free(realm);
+
+ return (princ_r);
+}
+
+/*
+ * ads_get_host_principals
+ *
+ * If fqhost is NULL, this function will attempt to obtain fully qualified
+ * hostname prior to generating the host principals.
+ */
+static int
+ads_get_host_principals(char *fqhost, char *domain, char **princ,
+ char **princ_r)
+{
+ char hostname[MAXHOSTNAMELEN];
+
+ *princ = *princ_r = NULL;
+
+ if (fqhost) {
+ (void) strlcpy(hostname, fqhost, MAXHOSTNAMELEN);
+ } else {
+ if (smb_getfqhostname(hostname, MAXHOSTNAMELEN) != 0)
+ return (-1);
+ }
+
+ if ((*princ = ads_get_host_principal(hostname)) == NULL) {
+ return (-1);
+ }
+
+ *princ_r = ads_get_host_principal_w_realm(*princ, domain);
+ if (*princ_r == NULL) {
+ free(*princ);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * ads_add_computer
+ *
+ * Returns 0 upon success. Otherwise, returns -1.
+ */
+static int
+ads_add_computer(ADS_HANDLE *ah)
+{
+ LDAPMod *addattrs[7];
+ char *oc_vals[6], *sam_val[2], *usr_val[2];
+ char *svc_val[2], *ctl_val[2], *fqh_val[2];
+ int j = -1;
+ int ret, usrctl_flags = 0;
+ char sam_acct[MAXHOSTNAMELEN + 1];
+ char fqhost[MAXHOSTNAMELEN];
+ char dn[ADS_DN_MAX];
+ char *user_principal, *svc_principal;
+ char usrctl_buf[16];
+
+ if (smb_getfqhostname(fqhost, MAXHOSTNAMELEN) != 0)
+ return (-1);
+
+ if (smb_gethostname(sam_acct, MAXHOSTNAMELEN, 0) != 0)
+ return (-1);
+
+ (void) strlcat(sam_acct, "$", MAXHOSTNAMELEN + 1);
+
+ if (ads_get_host_principals(fqhost, ah->domain, &svc_principal,
+ &user_principal) == -1) {
+ syslog(LOG_ERR,
+ "ads_add_computer: unable to get host principal");
+ return (-1);
+ }
+
+ ads_get_computer_dn(ah, dn, ADS_DN_MAX);
+
+ addattrs[++j] = (LDAPMod *)malloc(sizeof (LDAPMod));
+ addattrs[j]->mod_op = LDAP_MOD_ADD;
+ addattrs[j]->mod_type = "objectClass";
+ oc_vals[0] = "top";
+ oc_vals[1] = "person";
+ oc_vals[2] = "organizationalPerson";
+ oc_vals[3] = "user";
+ oc_vals[4] = "computer";
+ oc_vals[5] = 0;
+ addattrs[j]->mod_values = oc_vals;
+
+ addattrs[++j] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ addattrs[j]->mod_op = LDAP_MOD_ADD;
+ addattrs[j]->mod_type = "sAMAccountName";
+
+ sam_val[0] = sam_acct;
+ sam_val[1] = 0;
+ addattrs[j]->mod_values = sam_val;
+
+
+ addattrs[++j] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ addattrs[j]->mod_op = LDAP_MOD_ADD;
+ addattrs[j]->mod_type = "userPrincipalName";
+
+ usr_val[0] = user_principal;
+ usr_val[1] = 0;
+ addattrs[j]->mod_values = usr_val;
+
+ addattrs[++j] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ addattrs[j]->mod_op = LDAP_MOD_ADD;
+ addattrs[j]->mod_type = "servicePrincipalName";
+
+ svc_val[0] = svc_principal;
+ svc_val[1] = 0;
+ addattrs[j]->mod_values = svc_val;
+
+ addattrs[++j] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ addattrs[j]->mod_op = LDAP_MOD_ADD;
+ addattrs[j]->mod_type = "userAccountControl";
+
+ usrctl_flags |= (ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
+ ADS_USER_ACCT_CTL_PASSWD_NOTREQD |
+ ADS_USER_ACCT_CTL_ACCOUNTDISABLE);
+
+ (void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", usrctl_flags);
+ ctl_val[0] = usrctl_buf;
+ ctl_val[1] = 0;
+ addattrs[j]->mod_values = ctl_val;
+ addattrs[++j] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ addattrs[j]->mod_op = LDAP_MOD_ADD;
+ addattrs[j]->mod_type = "dNSHostName";
+
+ fqh_val[0] = fqhost;
+ fqh_val[1] = 0;
+ addattrs[j]->mod_values = fqh_val;
+ addattrs[++j] = 0;
+
+ if ((ret = ldap_add_s(ah->ld, dn, addattrs)) != LDAP_SUCCESS) {
+ syslog(LOG_ERR, "ads_add_computer: %s", ldap_err2string(ret));
+ ret = -1;
+ }
+
+ free_attr(addattrs);
+ free(user_principal);
+ free(svc_principal);
+
+ return (ret);
+}
+
+/*
+ * Delete an ADS computer account.
+ */
+static void
+ads_del_computer(ADS_HANDLE *ah)
+{
+ char dn[ADS_DN_MAX];
+ int rc;
+
+ ads_get_computer_dn(ah, dn, ADS_DN_MAX);
+
+ if ((rc = ldap_delete_s(ah->ld, dn)) != LDAP_SUCCESS) {
+ syslog(LOG_DEBUG, "ads_del_computer: %s",
+ ldap_err2string(rc));
+ }
+}
+
+/*
+ * ads_lookup_computer_n_attr
+ *
+ * Lookup the value of the specified attribute on the computer
+ * object. If the specified attribute can be found, its value is returned
+ * via 'val' parameter.
+ *
+ * 'attr' parameter can be set to NULL if you only attempt to
+ * see whether the computer object exists on AD or not.
+ *
+ * Return:
+ * 1 if both the computer and the specified attribute is found.
+ * 0 if either the computer or the specified attribute is not found.
+ * -1 on error.
+ */
+static int
+ads_lookup_computer_n_attr(ADS_HANDLE *ah, char *attr, char **val)
+{
+ char *attrs[2], filter[ADS_MAXBUFLEN];
+ LDAPMessage *res, *entry;
+ char **vals;
+ char tmpbuf[ADS_MAXBUFLEN];
+ char my_hostname[MAXHOSTNAMELEN], sam_acct[MAXHOSTNAMELEN + 1];
+ char dn[ADS_DN_MAX];
+
+ if (smb_gethostname(my_hostname, MAXHOSTNAMELEN, 0) != 0)
+ return (-1);
+
+ (void) snprintf(sam_acct, sizeof (sam_acct), "%s$", my_hostname);
+ ads_get_computer_dn(ah, dn, ADS_DN_MAX);
+
+ res = NULL;
+ attrs[0] = attr;
+ attrs[1] = NULL;
+
+ if (ads_escape_search_filter_chars(sam_acct, tmpbuf) != 0) {
+ return (-1);
+ }
+
+ (void) snprintf(filter, sizeof (filter),
+ "(&(objectClass=computer)(sAMAccountName=%s))",
+ tmpbuf);
+
+ if (ldap_search_s(ah->ld, dn, LDAP_SCOPE_BASE, filter, attrs, 0,
+ &res) != LDAP_SUCCESS) {
+ (void) ldap_msgfree(res);
+ return (0);
+ }
+
+ if (attr) {
+ /* no match for the specified attribute is found */
+ if (ldap_count_entries(ah->ld, res) == 0) {
+ if (val)
+ *val = NULL;
+
+ (void) ldap_msgfree(res);
+ return (0);
+ }
+
+ entry = ldap_first_entry(ah->ld, res);
+ if (entry) {
+ vals = ldap_get_values(ah->ld, entry, attr);
+ if (!vals && val) {
+ *val = NULL;
+ (void) ldap_msgfree(res);
+ return (0);
+ }
+
+ if (vals[0] != NULL && val)
+ *val = strdup(vals[0]);
+ }
+ }
+
+ /* free the search results */
+ (void) ldap_msgfree(res);
+ return (1);
+}
+
+/*
+ * ads_find_computer
+ *
+ * Return:
+ * 1 if found.
+ * 0 if not found or encounters error.
+ */
+static int
+ads_find_computer(ADS_HANDLE *ah)
+{
+ return (ads_lookup_computer_n_attr(ah, NULL, NULL) == 1);
+}
+
+/*
+ * ads_modify_computer
+ *
+ * Modify the user account control attribute of an existing computer
+ * object on AD.
+ *
+ * Returns 0 on success. Otherwise, returns -1.
+ */
+static int
+ads_modify_computer(ADS_HANDLE *ah, int des_only)
+{
+ LDAPMod *attrs[6];
+ char *ctl_val[2];
+ int j = -1;
+ int ret, usrctl_flags = 0;
+ char dn[ADS_DN_MAX];
+ char usrctl_buf[16];
+
+ ads_get_computer_dn(ah, dn, ADS_DN_MAX);
+
+ attrs[++j] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ attrs[j]->mod_op = LDAP_MOD_REPLACE;
+ attrs[j]->mod_type = "userAccountControl";
+
+ usrctl_flags |= (ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
+ ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION |
+ ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
+
+ if (des_only)
+ usrctl_flags |= ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY;
+
+ (void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", usrctl_flags);
+ ctl_val[0] = usrctl_buf;
+ ctl_val[1] = 0;
+ attrs[j]->mod_values = ctl_val;
+
+ attrs[++j] = 0;
+
+ if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
+ syslog(LOG_ERR, "ads_modify_computer: %s",
+ ldap_err2string(ret));
+ ret = -1;
+ }
+
+ free_attr(attrs);
+ return (ret);
+}
+
+/*
+ * ads_lookup_computer_attr_kvno
+ *
+ * Lookup the value of the Kerberos version number attribute of the computer
+ * account.
+ */
+static krb5_kvno
+ads_lookup_computer_attr_kvno(ADS_HANDLE *ah)
+{
+ char *val = NULL;
+ int kvno = 1;
+
+ if (ads_lookup_computer_n_attr(ah, "ms-DS-KeyVersionNumber",
+ &val) == 1) {
+ if (val) {
+ kvno = atoi(val);
+ free(val);
+ }
+ }
+
+ return (kvno);
+}
+
+/*
+ * ads_gen_machine_passwd
+ *
+ * Returned a null-terminated machine password generated randomly
+ * from [0-9a-zA-Z] character set. In order to pass the password
+ * quality check (three character classes), an uppercase letter is
+ * used as the first character of the machine password.
+ */
+static int
+ads_gen_machine_passwd(char *machine_passwd, int bufsz)
+{
+ char *data = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJK"
+ "LMNOPQRSTUVWXYZ";
+ int datalen = strlen(data);
+ int i, data_idx;
+
+ if (!machine_passwd || bufsz == 0)
+ return (-1);
+
+ /*
+ * The decimal value of upper case 'A' is 65. Randomly pick
+ * an upper-case letter from the ascii table.
+ */
+ machine_passwd[0] = (random() % 26) + 65;
+ for (i = 1; i < bufsz - 1; i++) {
+ data_idx = random() % datalen;
+ machine_passwd[i] = data[data_idx];
+ }
+
+ machine_passwd[bufsz - 1] = 0;
+ return (0);
+}
+
+/*
+ * adjoin
+ *
+ * Besides the NT-4 style domain join (using MS-RPC), CIFS server also
+ * provides the domain join using Kerberos Authentication, Keberos
+ * Change & Set password, and LDAP protocols. Basically, adjoin
+ * operation would require the following tickets to be acquired for the
+ * the user account that is provided for the domain join.
+ *
+ * 1) a Keberos TGT ticket,
+ * 2) a ldap service ticket, and
+ * 3) kadmin/changpw service ticket
+ *
+ * The ADS client first sends a ldap search request to find out whether
+ * or not the workstation trust account already exists in the Active Directory.
+ * The existing computer object for this workstation will be removed and
+ * a new one will be added. The machine account password is randomly
+ * generated and set for the newly created computer object using KPASSD
+ * protocol (See RFC 3244). Once the password is set, our ADS client
+ * finalizes the machine account by modifying the user acount control
+ * attribute of the computer object. Kerberos keys derived from the machine
+ * account password will be stored locally in /etc/krb5/krb5.keytab file.
+ * That would be needed while acquiring Kerberos TGT ticket for the host
+ * principal after the domain join operation.
+ */
+adjoin_status_t
+adjoin(char *machine_passwd, int len)
+{
+ ADS_HANDLE *ah = NULL;
+ krb5_enctype enctypes[10];
+ krb5_context ctx = NULL;
+ krb5_principal krb5princ;
+ krb5_kvno kvno;
+ char *princ, *princ_r;
+ int des_only, delete = 1, fini_krbctx = 1;
+ adjoin_status_t rc = ADJOIN_SUCCESS;
+ struct stat fstat;
+
+ char *idmap_ccache = "/var/run/idmap/ccache";
+
+ if ((ah = ads_open()) == NULL)
+ return (ADJOIN_ERR_GET_HANDLE);
+
+ if (ads_gen_machine_passwd(machine_passwd, len) != 0) {
+ ads_close(ah);
+ return (ADJOIN_ERR_GEN_PASSWD);
+ }
+
+ if (ads_find_computer(ah))
+ ads_del_computer(ah);
+
+ if (ads_add_computer(ah) != 0) {
+ ads_close(ah);
+ return (ADJOIN_ERR_ADD_TRUST_ACCT);
+ }
+
+ /*
+ * Call library functions that can be used to get
+ * the list of encryption algorithms available on the system.
+ * (similar to what 'encrypt -l' CLI does). For now,
+ * unless someone has modified the configuration of the
+ * cryptographic framework (very unlikely), the following is the
+ * list of algorithms available on any system running Nevada
+ * by default.
+ */
+ enctypes[0] = ENCTYPE_DES_CBC_CRC;
+ enctypes[1] = ENCTYPE_DES_CBC_MD5;
+ enctypes[2] = ENCTYPE_ARCFOUR_HMAC;
+ enctypes[3] = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+
+ des_only = 0;
+
+ /*
+ * If we are talking to a Longhorn server, we need to set up
+ * the msDS-SupportedEncryptionTypes attribute of the computer
+ * object accordingly
+ *
+ * The code to modify the msDS-SupportedEncryptionTypes can be
+ * added once we figure out why the Longhorn server rejects the
+ * SmbSessionSetup request sent by SMB redirector.
+ */
+
+ if (ads_get_host_principals(NULL, ah->domain, &princ, &princ_r) == -1) {
+ ads_del_computer(ah);
+ ads_close(ah);
+ return (ADJOIN_ERR_GET_HOST_PRINC);
+ }
+
+ if (smb_krb5_ctx_init(&ctx) != 0) {
+ fini_krbctx = 0;
+ rc = ADJOIN_ERR_INIT_KRB_CTX;
+ goto adjoin_cleanup;
+ }
+
+ if (smb_krb5_get_principal(ctx, princ_r, &krb5princ) != 0) {
+ rc = ADJOIN_ERR_GET_KRB_PRINC;
+ goto adjoin_cleanup;
+ }
+
+ if (smb_krb5_setpwd(ctx, krb5princ, machine_passwd) != 0) {
+ rc = ADJOIN_ERR_KSETPWD;
+ goto adjoin_cleanup;
+ }
+
+ kvno = ads_lookup_computer_attr_kvno(ah);
+ if (ads_modify_computer(ah, des_only) != 0) {
+ rc = ADJOIN_ERR_MOD_TRUST_ACCT;
+ goto adjoin_cleanup;
+ }
+ if (smb_krb5_write_keytab(ctx, krb5princ, "/etc/krb5/krb5.keytab", kvno,
+ machine_passwd, enctypes, 4) != 0) {
+ rc = ADJOIN_ERR_WRITE_KEYTAB;
+ goto adjoin_cleanup;
+ }
+
+ /* Set IDMAP config */
+ if (smb_config_set_idmap_domain(ah->domain) != 0) {
+ rc = ADJOIN_ERR_IDMAP_SET_DOMAIN;
+ goto adjoin_cleanup;
+ }
+
+ if (smb_config_set_idmap_gc(ah->hostname) != 0) {
+ rc = ADJOIN_ERR_IDMAP_SET_GC;
+ goto adjoin_cleanup;
+ }
+
+ /* Refresh IDMAP service */
+ if (smb_config_refresh_idmap() != 0) {
+ rc = ADJOIN_ERR_IDMAP_REFRESH;
+ goto adjoin_cleanup;
+ }
+
+ /* Remove the idmap ccache */
+ if (stat(idmap_ccache, &fstat) == 0) {
+ if (remove(idmap_ccache) != 0) {
+ rc = ADJOIN_ERR_IDMAP_CCACHE;
+ goto adjoin_cleanup;
+ }
+ }
+
+ delete = 0;
+adjoin_cleanup:
+ if (delete)
+ ads_del_computer(ah);
+
+ if (fini_krbctx)
+ smb_krb5_ctx_fini(ctx);
+
+ ads_close(ah);
+ free(princ);
+ free(princ_r);
+
+ return (rc);
+}
+
+/*
+ * adjoin_report_err
+ *
+ * Display error message for the specific adjoin error code.
+ */
+char *
+adjoin_report_err(adjoin_status_t status)
+{
+ if (status < 0 || status >= ADJOIN_NUM_STATUS)
+ return ("ADJOIN: unknown status");
+
+ return (adjoin_errmsg[status]);
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h
new file mode 100644
index 0000000000..af52f0ebfc
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_ADS_H
+#define _SMBSRV_ADS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <smbsrv/libsmbns.h>
+#include <smbsrv/string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * UserAccountControl flags: manipulate user account properties.
+ *
+ * The hexadecimal value of the following property flags are based on MSDN
+ * article # 305144.
+ */
+#define ADS_USER_ACCT_CTL_SCRIPT 0x00000001
+#define ADS_USER_ACCT_CTL_ACCOUNTDISABLE 0x00000002
+#define ADS_USER_ACCT_CTL_HOMEDIR_REQUIRED 0x00000008
+#define ADS_USER_ACCT_CTL_LOCKOUT 0x00000010
+#define ADS_USER_ACCT_CTL_PASSWD_NOTREQD 0x00000020
+#define ADS_USER_ACCT_CTL_PASSWD_CANT_CHANGE 0x00000040
+#define ADS_USER_ACCT_CTL_ENCRYPTED_TEXT_PWD_ALLOWED 0x00000080
+#define ADS_USER_ACCT_CTL_TMP_DUP_ACCT 0x00000100
+#define ADS_USER_ACCT_CTL_NORMAL_ACCT 0x00000200
+#define ADS_USER_ACCT_CTL_INTERDOMAIN_TRUST_ACCT 0x00000800
+#define ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT 0x00001000
+#define ADS_USER_ACCT_CTL_SRV_TRUST_ACCT 0x00002000
+#define ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD 0x00010000
+#define ADS_USER_ACCT_CTL_MNS_LOGON_ACCT 0x00020000
+#define ADS_USER_ACCT_CTL_SMARTCARD_REQUIRED 0x00040000
+#define ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION 0x00080000
+#define ADS_USER_ACCT_CTL_NOT_DELEGATED 0x00100000
+#define ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY 0x00200000
+#define ADS_USER_ACCT_CTL_DONT_REQ_PREAUTH 0x00400000
+#define ADS_USER_ACCT_CTL_PASSWD_EXPIRED 0x00800000
+#define ADS_USER_ACCT_CTL_TRUSTED_TO_AUTH_FOR_DELEGATION 0x01000000
+
+typedef struct ads_host_info_s {
+ char *name; /* fully qualified hostname */
+ int port; /* ldap port */
+ in_addr_t ip_addr; /* network byte order */
+} ADS_HOST_INFO;
+
+#define UNC_HOSTADDR 0 /* use ip addr in UNC */
+#define UNC_HOSTNAME 1 /* use hostname in UNC */
+#define ADS_PATH_SCRN_LEN 60
+
+ADS_HOST_INFO *ads_find_host(char *, char *, int *, char *, int *);
+char *ads_convert_directory(char *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_ADS_H */
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c
new file mode 100644
index 0000000000..853d1ff814
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c
@@ -0,0 +1,1410 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <synch.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <smbsrv/libsmbns.h>
+
+#include <smbsrv/cifs.h>
+#include <smbsrv/mailslot.h>
+
+#include <smbns_browser.h>
+#include <smbns_netbios.h>
+
+#define SMB_SERVER_SIGNATURE 0xaa550415
+
+/*
+ * Macro definitions:
+ */
+static char *lanman = MAILSLOT_LANMAN;
+static char *browse = MAILSLOT_BROWSE;
+
+typedef struct server_info {
+ uint32_t type;
+ uint32_t signature;
+ char major;
+ char minor;
+ char hostname[NETBIOS_NAME_SZ];
+ char comment[SMB_PI_MAX_COMMENT];
+ char update_count;
+ struct name_entry name;
+} server_info_t;
+
+#define BROWSER_NF_INVALID 0x00
+#define BROWSER_NF_VALID 0x01
+
+typedef struct browser_netinfo {
+ uint32_t flags;
+ int next_announce;
+ int reps;
+ int interval;
+ server_info_t server;
+ mutex_t mtx;
+} browser_netinfo_t;
+
+/*
+ * Local Data Definitions:
+ */
+static struct browser_netinfo smb_browser_info[SMB_PI_MAX_NETWORKS];
+
+static void smb_browser_init(void);
+
+static inline browser_netinfo_t *
+smb_browser_getnet(int net)
+{
+ browser_netinfo_t *subnet;
+
+ if (net < smb_nic_get_num()) {
+ subnet = &smb_browser_info[net];
+ (void) mutex_lock(&subnet->mtx);
+ if (subnet->flags & BROWSER_NF_VALID)
+ return (subnet);
+ }
+
+ return (0);
+}
+
+static inline void
+smb_browser_putnet(browser_netinfo_t *netinfo)
+{
+ if (netinfo)
+ (void) mutex_unlock(&netinfo->mtx);
+}
+
+/*
+ * 3. Browser Overview
+ *
+ * Hosts involved in the browsing process can be separated into two
+ * distinct groups, browser clients and browser servers (often referred to
+ * simply as "browsers").
+ *
+ * A browser is a server which maintains information about servers -
+ * primarily the domain they are in and the services that they are running
+ * -- and about domains. Browsers may assume several different roles in
+ * their lifetimes, and dynamically switch between them.
+ *
+ * Browser clients are of two types: workstations and (non-browser)
+ * servers. In the context of browsing, workstations query browsers for the
+ * information they contain; servers supply browsers the information by
+ * registering with them. Note that, at times, browsers may themselves
+ * behave as browser clients and query other browsers.
+ *
+ * For the purposes of this specification, a domain is simply a name with
+ * which to associate a group of resources such as computers, servers and
+ * users. Domains allow a convenient means for browser clients to restrict
+ * the scope of a search when they query browser servers. Every domain has
+ * a "master" server called the Primary Domain Controller (PDC) that
+ * manages various activities within the domain.
+ *
+ * One browser for each domain on a subnet is designated the Local Master
+ * Browser for that domain. Servers in its domain on the subnet register
+ * with it, as do the Local Master Browsers for other domains on the
+ * subnet. It uses these registrations to maintain authoritative
+ * information about its domain on its subnet. If there are other subnets
+ * in the network, it also knows the name of the server running the
+ * domain's Domain Master Browser; it registers with it, and uses it to
+ * obtain information about the rest of the network (see below).
+ *
+ * Clients on a subnet query browsers designated as the Backup Browsers for
+ * the subnet (not the Master Browser). Backup Browsers maintain a copy of
+ * the information on the Local Master Browser; they get it by periodically
+ * querying the Local Master Browser for all of its information. Clients
+ * find the Backup Browsers by asking the Local Master Browser. Clients are
+ * expected to spread their queries evenly across Backup Browsers to
+ * balance the load.
+ *
+ * The Local Master Browser is dynamically elected automatically. Multiple
+ * Backup Browser Servers may exist per subnet; they are selected from
+ * among the potential browser servers by the Local Master Browser, which
+ * is configured to select enough to handle the expected query load.
+ *
+ * When there are multiple subnets, a Domain Master Browser is assigned
+ * the task of keeping the multiple subnets in synchronization. The Primary
+ * Domain Controller (PDC) always acts as the Domain Master Browser. The
+ * Domain Master Browser periodically acts as a client and queries all the
+ * Local Master Browsers for its domain, asking them for a list containing
+ * all the domains and all the servers in their domain known within their
+ * subnets; it merges all the replies into a single master list. This
+ * allows a Domain Master Browser server to act as a collection point for
+ * inter-subnet browsing information. Local Master Browsers periodically
+ * query the Domain Master Browser to retrieve the network-wide information
+ * it maintains.
+ *
+ * When a domain spans only a single subnet, there will not be any distinct
+ * Local Master Browser; this role will be handled by the Domain Master
+ * Browser. Similarly, the Domain Master Browser is always the Local Master
+ * Browser for the subnet it is on.
+ *
+ * When a browser client suspects that the Local Master Browser has failed,
+ * the client will instigate an election in which the browser servers
+ * participate, and some browser servers may change roles.
+ *
+ * Some characteristics of a good browsing mechanism include:
+ * . minimal network traffic
+ * . minimum server discovery time
+ * . minimum change discovery latency
+ * . immunity to machine failures
+ *
+ * Historically, Browser implementations had been very closely tied to
+ * NETBIOS and datagrams. The early implementations caused a lot of
+ * broadcast traffic. See Appendix D for an overview that presents how the
+ * Browser specification evolved.
+ *
+ * 4. Browsing Protocol Architecture
+ *
+ * This section first describes the how the browsing protocol is layered,
+ * then describes the roles of clients, servers, and browsers in the
+ * browsing subsystem.
+ *
+ * 4.1 Layering of Browsing Protocol Requests
+ *
+ * Most of the browser functionality is implemented using mailslots.
+ * Mailslots provide a mechanism for fast, unreliable unidirectional data
+ * transfer; they are named via ASCII "mailslot (path) name". Mailslots are
+ * implemented using the CIFS Transact SMB which is encapsulated in a
+ * NETBIOS datagram. Browser protocol requests are sent to browser specific
+ * mailslots using some browser-specific NETBIOS names. These datagrams can
+ * either be unicast or broadcast, depending on whether the NETBIOS name is
+ * a "unique name" or a "group name". Various data structures, which are
+ * detailed subsequently within this document, flow as the data portion of
+ * the Transact SMB.
+ *
+ * Here is an example of a generic browser SMB, showing how a browser
+ * request is encapsulated in a TRANSACT SMB request. Note that the PID,
+ * TID, MID, UID, and Flags are all 0 in mailslot requests.
+ *
+ * SMB: C transact, File = \MAILSLOT\BROWSE
+ * SMB: SMB Status = Error Success
+ * SMB: Error class = No Error
+ * SMB: Error code = No Error
+ * SMB: Header: PID = 0x0000 TID = 0x0000 MID = 0x0000 UID = 0x0000
+ * SMB: Tree ID (TID) = 0 (0x0)
+ * SMB: Process ID (PID) = 0 (0x0)
+ * SMB: User ID (UID) = 0 (0x0)
+ * SMB: Multiplex ID (MID) = 0 (0x0)
+ * SMB: Flags Summary = 0 (0x0)
+ * SMB: Command = C transact
+ * SMB: Word count = 17
+ * SMB: Word parameters
+ * SMB: Total parm bytes = 0
+ * SMB: Total data bytes = 33
+ * SMB: Max parm bytes = 0
+ * SMB: Max data bytes = 0
+ * SMB: Max setup words = 0
+ * SMB: Transact Flags Summary = 0 (0x0)
+ * SMB: ...............0 = Leave session intact
+ * SMB: ..............0. = Response required
+ * SMB: Transact timeout = 0 (0x0)
+ * SMB: Parameter bytes = 0 (0x0)
+ * SMB: Parameter offset = 0 (0x0)
+ * SMB: Data bytes = 33 (0x21)
+ * SMB: Data offset = 86 (0x56)
+ * SMB: Setup word count = 3
+ * SMB: Setup words
+ * SMB: Mailslot opcode = Write mailslot
+ * SMB: Transaction priority = 1
+ * SMB: Mailslot class = Unreliable (broadcast)
+ * SMB: Byte count = 50
+ * SMB: Byte parameters
+ * SMB: Path name = \MAILSLOT\BROWSE
+ * SMB: Transaction data
+ * SMB: Data: Number of data bytes remaining = 33 (0x0021)
+ *
+ * Note the SMB command is Transact, the opcode within the Transact SMB is
+ * Mailslot Write, and the browser data structure is carried as the
+ * Transact data.
+ * The Transaction data begins with an opcode, that signifies the operation
+ * and determines the size and structure of data that follows. This opcode
+ * is named as per one of the below:
+ *
+ * HostAnnouncement 1
+ * AnnouncementRequest 2
+ * RequestElection 8
+ * GetBackupListReq 9
+ * GetBackupListResp 10
+ * BecomeBackup 11
+ * DomainAnnouncment 12
+ * MasterAnnouncement 13
+ * LocalMasterAnnouncement 15
+ *
+ * Browser datagrams are often referred to as simply browser frames. The
+ * frames are in particular, referred to by the name of the opcode within
+ * the Transaction data e.g. a GetBackupListReq browser frame, a
+ * RequestElection browser frame, etc.
+ *
+ * The structures that are sent as the data portion of the Transact SMB are
+ * described in section(s) 6.2 through 6.12 in this document. These
+ * structures are tightly packed, i.e. there are no intervening pad bytes
+ * in the structure, unless they are explicitly described as being there.
+ * All quantities are sent in native Intel format and multi-byte values are
+ * transmitted least significant byte first.
+ *
+ * Besides mailslots and Transaction SMBs, the other important piece of the
+ * browser architecture is the NetServerEnum2 request. This request that
+ * allows an application to interrogate a Browser Server and obtain a
+ * complete list of resources (servers, domains, etc) known to that Browser
+ * server. Details of the NetServerEnum2 request are presented in section
+ * 6.4. Some examples of the NetServerEnum2 request being used are when a
+ * Local Master Browser sends a NetServerEnum2 request to the Domain Master
+ * Browser and vice versa. Another example is when a browser client sends a
+ * NetServerEnum2 request to a Backup Browser server.
+ *
+ * 4.3 Non-Browser Server
+ *
+ * A non-browser server is a server that has some resource(s) or service(s)
+ * it wishes to advertise as being available using the browsing protocol.
+ * Examples of non-browser servers would be an SQL server, print server,
+ * etc.
+ *
+ * A non-browser server MUST periodically send a HostAnnouncement browser
+ * frame, specifying the type of resources or services it is advertising.
+ * Details are in section 6.5.
+ *
+ * A non-browser server SHOULD announce itself relatively frequently when
+ * it first starts up in order to make its presence quickly known to the
+ * browsers and thence to potential clients. The frequency of the
+ * announcements SHOULD then be gradually stretched, so as to minimize
+ * network traffic. Typically, non-browser servers announce themselves
+ * once every minute upon start up and then gradually adjust the frequency
+ * of the announcements to once every 12 minutes.
+ *
+ * A non-browser server SHOULD send a HostAnnouncement browser frame
+ * specifying a type of 0 just prior to shutting down, to allow it to
+ * quickly be removed from the list of available servers.
+ *
+ * A non-browser server MUST receive and process AnnouncementRequest frames
+ * from the Local Master Browser, and MUST respond with a HostAnnouncement
+ * frame, after a delay chosen randomly from the interval [0,30] seconds.
+ * AnnouncementRequests typically happen when a Local Master Browser starts
+ * up with an empty list of servers for the domain, and wants to fill it
+ * quickly. The 30 second range for responses prevents the Master Browser
+ * from becoming overloaded and losing replies, as well as preventing the
+ * network from being flooded with responses.
+ *
+ * 4.4 Browser Servers
+ *
+ * The following sections describe the roles of the various types of
+ * browser servers.
+ *
+ * 4.4.1 Potential Browser Server
+ *
+ * A Potential Browser server is a browser server that is capable of being
+ * a Backup Browser server or Master Browser server, but is not currently
+ * fulfilling either of those roles.
+ *
+ * A Potential Browser MUST set type SV_TYPE_POTENTIAL_BROWSER (see section
+ * 6.4.1) in its HostAnnouncement until it is ready to shut down. In its
+ * last HostAnnouncement frame before it shuts down, it SHOULD specify a
+ * type of 0.
+ *
+ * A Potential Browser server MUST receive and process BecomeBackup frames
+ * (see section 6.9) and become a backup browser upon their receipt.
+ *
+ * A Potential Browser MUST participate in browser elections (see section
+ * 6.8).
+ *
+ * 4.4.2 Backup Browser
+ *
+ * Backup Browser servers are a subset of the Potential Browsers that have
+ * been chosen by the Master Browser on their subnet to be the Backup
+ * Browsers for the subnet.
+ *
+ * A Backup Browser MUST set type SV_TYPE_BACKUP_BROWSER (see section
+ * 6.4.1) in its HostAnnouncement until it is ready to shut down. In its
+ * last HostAnnouncement frame before it shuts down, it SHOULD specify a
+ * type of 0.
+ *
+ * A Backup Browser MUST listen for a LocalMasterAnnouncement frame (see
+ * section 6.10) from the Local Master Browser, and use it to set the name
+ * of the Master Browser it queries for the server and domain lists.
+ *
+ * A Backup Browsers MUST periodically make a NetServerEnum2 request of
+ * the Master Browser on its subnet for its domain to get a list of servers
+ * in that domain, as well as a list of domains. The period is a
+ * configuration option balancing currency of the information with network
+ * traffic costs - a typical value is 15 minutes.
+ *
+ * A Backup Browser SHOULD force an election by sending a RequestElection
+ * frame (see section 6.7) if it does not get a response to its periodic
+ * NetServeEnum2 request to the Master Browser.
+ *
+ * A Backup Browser MUST receive and process NetServerEnum2 requests from
+ * browser clients, for its own domain and others. If the request is for a
+ * list of servers in its domain, or for a list of domains, it can answer
+ * from its internal lists. If the request is for a list of servers in a
+ * domain different than the one it serves, it sends a NetServerEnum2
+ * request to the Domain Master Browser for that domain (which it can in
+ * find in its list of domains and their Domain Master Browsers).
+ *
+ * A Backup Browser MUST participate in browser elections (see section
+ * 6.8).
+ *
+ * 4.4.3 Master Browser
+ *
+ * Master Browsers are responsible for:
+ * . indicating it is a Master Browser
+ * . receiving server announcements and building a list of such servers
+ * and keeping it reasonably up-to-date.
+ * . returning lists of Backup Browsers to browser clients.
+ * . ensuring an appropriate number of Backup Browsers are available.
+ * . announcing their existence to other Master Browsers on their subnet,
+ * to the Domain Master Browser for their domain, and to all browsers in
+ * their domain on their subnet
+ * . forwarding requests for lists of servers on other domains to the
+ * Master Browser for that domain
+ * . keeping a list of domains in its subnet
+ * . synchronizing with the Domain Master Browser (if any) for its domain
+ * . participating in browser elections
+ * . ensuring that there is only one Master Browser on its subnet
+ *
+ * A Master Browser MUST set type SV_TYPE_MASTER_BROWSER (see section
+ * 6.4.1) in its HostAnnouncement until it is ready to shut down. In its
+ * last HostAnnouncement frame before it shuts down, it SHOULD specify a
+ * type of 0.
+ *
+ * A Master Browser MUST receive and process HostAnnouncement frames from
+ * servers, adding the server name and other information to its servers
+ * list; it must mark them as "local" entries. Periodically, it MUST check
+ * all local server entries to see if a server's HostAnnouncement has timed
+ * out (no HostAnnouncement received for three times the periodicity the
+ * server gave in the last received HostAnnouncement) and remove timed-out
+ * servers from its list.
+ *
+ * A Master Browser MUST receive and process DomainAnnouncement frames (see
+ * section 6.12) and maintain the domain names and their associated (Local)
+ * Master Browsers in its internal domain list until they time out; it must
+ * mark these as "local" entries. Periodically, it MUST check all local
+ * domain entries to see if a server's DomainAnnouncement has timed out (no
+ * DomainAnnouncement received for three times the periodicity the server
+ * gave in the last received DomainAnnouncement) and remove timed-out
+ * servers from its list.
+ *
+ * A Master Browser MUST receive and process GetBackupListRequest frames
+ * from clients, returning GetBackupListResponse frames containing a list
+ * of the Backup Servers for its domain.
+ *
+ * A Master Browser MUST eventually send BecomeBackup frames (see section
+ * 6.9) to one or more Potential Browser servers to increase the number of
+ * Backup Browsers if there are not enough Backup Browsers to handle the
+ * anticipated query load. Note: possible good times for checking for
+ * sufficient backup browsers are after being elected, when timing out
+ * server HostAnnouncements, and when receiving a server's HostAnnouncement
+ * for the first time.
+ *
+ * A Master Browser MUST periodically announce itself and the domain it
+ * serves to other (Local) Master Browsers on its subnet, by sending a
+ * DomainAnnouncement frame (see section 6.12) to its subnet.
+ *
+ * A Master Browser MUST send a MasterAnnouncement frame (see section 6.11)
+ * to the Domain Master Browser after it is first elected, and periodically
+ * thereafter. This informs the Domain Master Browser of the presence of
+ * all the Master Browsers.
+ *
+ * A Master Browser MUST periodically announce itself to all browsers for
+ * its domain on its subnet by sending a LocalMasterAnnouncement frame (see
+ * section 6.10).
+ *
+ * A Master Browser MUST receive and process NetServerEnum2 requests from
+ * browser clients, for its own domain and others. If the request is for a
+ * list of servers in its domain, or for a list of domains, it can answer
+ * from its internal lists. Entries in its list marked "local" MUST have
+ * the SV_TYPE_LOCAL_LIST_ONLY bit set in the returned results; it must be
+ * clear for all other entries. If the request is for a list of servers in
+ * a domain different than the one it serves, it sends a NetServerEnum2
+ * request to the Domain Master Browser for that domain (which it can in
+ * find in its list of domains and their Domain Master Browsers).
+ *
+ * Note: The list of servers that the Master Browser maintains and
+ * returns to the Backup Browsers, is limited in size to 64K of
+ * data. This will limit the number of systems that can be in a
+ * browse list in a single workgroup or domain to approximately two
+ * thousand systems.
+ *
+ * A Master Browser SHOULD request all servers to register with it by
+ * sending an AnnouncementRequest frame, if, on becoming the Master Browser
+ * by winning an election, its server list is empty. Otherwise, clients
+ * might get an incomplete list of servers until the servers' periodic
+ * registrations fill the server list.
+ *
+ * If the Master Browser on a subnet is not the Primary Domain Controller
+ * (PDC), then it is a Local Master Browser.
+ *
+ * A Local Master Browser MUST periodically synchronize with the Domain
+ * Master Browser (which is the PDC). This synchronization is performed by
+ * making a NetServerEnum2 request to the Domain Master Browser and merging
+ * the results with its list of servers and domains. An entry from the
+ * Domain Master Browser should be marked "non-local", and must not
+ * overwrite an entry with the same name marked "local". The Domain Master
+ * Browser is located as specified in Appendix B.
+ *
+ * A Master Browser MUST participate in browser elections (see section
+ * 6.8).
+ *
+ * A Master Browser MUST, if it receives a HostAnnouncement,
+ * DomainAnnouncement, or LocalMasterAnnouncement frame another system that
+ * claims to be the Master Browser for its domain, demote itself from
+ * Master Browser and force an election. This ensures that there is only
+ * ever one Master Browser in each workgroup or domain.
+ *
+ * A Master Browser SHOULD, if it loses an election, become a Backup
+ * Browser (without being told to do so by the new Master Browser). Since
+ * it has more up-to-date information in its lists than a Potential
+ * Browser, it is more efficient to have it be a Backup Browser than to
+ * promote a Potential Browser.
+ *
+ * 4.4.3.1 Preferred Master Browser
+ *
+ * A Preferred Master Browser supports exactly the same protocol elements
+ * as a Potential Browser, except as follows.
+ *
+ * A Preferred Master Browser MUST always force an election when it starts
+ * up.
+ *
+ * A Preferred Master Browser MUST participate in browser elections (see
+ * section 6.8).
+ *
+ * A Preferred Master Browser MUST set the Preferred Master bit in the
+ * RequestElection frame (see section 6.7) to bias the election in its
+ * favor.
+ *
+ * A Preferred Master Browser SHOULD, if it loses an election,
+ * automatically become a Backup Browser, without being told to do so by
+ * the Master Browser.
+ *
+ * 4.4.4 Domain Master Browser
+ *
+ * Since the Domain Master Browser always runs on the PDC, it must
+ * implement all the protocols required of a PDC in addition to the
+ * browsing protocol, and that is way beyond the scope of this
+ * specification.
+ *
+ * 5. Mailslot Protocol Specification
+ *
+ * The only transaction allowed to a mailslot is a mailslot write. Mailslot
+ * writes requests are encapsulated in TRANSACT SMBs. The following table
+ * shows the interpretation of the TRANSACT SMB parameters for a mailslot
+ * transaction:
+ *
+ * Name Value Description
+ * Command SMB_COM_TRANSACTION
+ * Name <name> STRING name of mail slot to write;
+ * must start with "\\MAILSLOT\\"
+ * SetupCount 3 Always 3 for mailslot writes
+ * Setup[0] 1 Command code == write mailslot
+ * Setup[1] Ignored
+ * Setup[2] Ignored
+ * TotalDataCount n Size of data in bytes to write to
+ * the mailslot
+ * Data[ n ] The data to write to the mailslot
+ *
+ */
+
+/*
+ * SMB: C transact, File = \MAILSLOT\BROWSE
+ * SMB: SMB Status = Error Success
+ * SMB: Error class = No Error
+ * SMB: Error code = No Error
+ * SMB: Header: PID = 0x0000 TID = 0x0000 MID = 0x0000 UID = 0x0000
+ * SMB: Tree ID (TID) = 0 (0x0)
+ * SMB: Process ID (PID) = 0 (0x0)
+ * SMB: User ID (UID) = 0 (0x0)
+ * SMB: Multiplex ID (MID) = 0 (0x0)
+ * SMB: Flags Summary = 0 (0x0)
+ * SMB: Command = C transact
+ * SMB: Word count = 17
+ * SMB: Word parameters
+ * SMB: Total parm bytes = 0
+ * SMB: Total data bytes = 33
+ * SMB: Max parm bytes = 0
+ * SMB: Max data bytes = 0
+ * SMB: Max setup words = 0
+ * SMB: Transact Flags Summary = 0 (0x0)
+ * SMB: ...............0 = Leave session intact
+ * SMB: ..............0. = Response required
+ * SMB: Transact timeout = 0 (0x0)
+ * SMB: Parameter bytes = 0 (0x0)
+ * SMB: Parameter offset = 0 (0x0)
+ * SMB: Data bytes = 33 (0x21)
+ * SMB: Data offset = 86 (0x56)
+ * SMB: Setup word count = 3
+ * SMB: Setup words
+ * SMB: Mailslot opcode = Write mailslot
+ * SMB: Transaction priority = 1
+ * SMB: Mailslot class = Unreliable (broadcast)
+ * SMB: Byte count = 50
+ * SMB: Byte parameters
+ * SMB: Path name = \MAILSLOT\BROWSE
+ * SMB: Transaction data
+ * SMB: Data: Number of data bytes remaining = 33 (0x0021)
+ *
+ * 5. Mailslot Protocol Specification
+ *
+ * The only transaction allowed to a mailslot is a mailslot write. Mailslot
+ * writes requests are encapsulated in TRANSACT SMBs. The following table
+ * shows the interpretation of the TRANSACT SMB parameters for a mailslot
+ * transaction:
+ *
+ * Name Value Description
+ * Command SMB_COM_TRANSACTION
+ * Name <name> STRING name of mail slot to write;
+ * must start with "\MAILSLOT\"
+ * SetupCount 3 Always 3 for mailslot writes
+ * Setup[0] 1 Command code == write mailslot
+ * Setup[1] Ignored
+ * Setup[2] Ignored
+ * TotalDataCount n Size of data in bytes to write to
+ * the mailslot
+ * Data[ n ] The data to write to the mailslot
+ *
+ * Magic 0xFF 'S' 'M' 'B'
+ * smb_com a byte, the "first" command
+ * Error a 4-byte union, ignored in a request
+ * smb_flg a one byte set of eight flags
+ * smb_flg2 a two byte set of 16 flags
+ * . twelve reserved bytes, have a role
+ * in connectionless transports (IPX, UDP?)
+ * smb_tid a 16-bit tree ID, a mount point sorta,
+ * 0xFFFF is this command does not have
+ * or require a tree context
+ * smb_pid a 16-bit process ID
+ * smb_uid a 16-bit user ID, specific to this "session"
+ * and mapped to a system (bona-fide) UID
+ * smb_mid a 16-bit multiplex ID, used to differentiate
+ * multiple simultaneous requests from the same
+ * process (pid) (ref RPC "xid")
+ */
+
+int
+smb_browser_load_transact_header(unsigned char *buffer, int maxcnt,
+ int data_count, int reply, char *mailbox)
+{
+ smb_msgbuf_t mb;
+ int mailboxlen;
+ char *fmt;
+ int result;
+ short class = (reply == ONE_WAY_TRANSACTION) ? 2 : 0;
+
+ /*
+ * If the mailboxlen is an even number we need to pad the
+ * header so that the data starts on a word boundary.
+ */
+ fmt = "Mb4.bw20.bwwwwb.wl2.wwwwb.wwwws";
+ mailboxlen = strlen(mailbox) + 1;
+
+ if ((mailboxlen & 0x01) == 0) {
+ ++mailboxlen;
+ fmt = "Mb4.bw20.bwwwwb.wl2.wwwwb.wwwws.";
+ }
+
+ bzero(buffer, maxcnt);
+ smb_msgbuf_init(&mb, buffer, maxcnt, 0);
+
+ result = smb_msgbuf_encode(&mb, fmt,
+ SMB_COM_TRANSACTION, /* Command */
+ 0x18,
+ 0x3,
+ 17, /* Count of parameter words */
+ 0, /* Total Parameter words sent */
+ data_count, /* Total Data bytes sent */
+ 2, /* Max Parameters to return */
+ 0, /* Max data bytes to return */
+ 0, /* Max setup bytes to return */
+ reply, /* No reply */
+ 0xffffffff, /* Timeout */
+ 0, /* Parameter bytes sent */
+ 0, /* Parameter offset */
+ data_count, /* Data bytes sent */
+ 69 + mailboxlen, /* Data offset */
+ 3, /* Setup word count */
+ 1, /* Setup word[0] */
+ 0, /* Setup word[1] */
+ class, /* Setup word[2] */
+ mailboxlen + data_count, /* Total request bytes */
+ mailbox); /* Mailbox address */
+
+ smb_msgbuf_term(&mb);
+ return (result);
+}
+
+/*
+ * smb_net_id
+ *
+ * Lookup for the given IP in the NICs info table.
+ * If it finds a matching entry it'll return the index,
+ * otherwise returns -1.
+ *
+ * SMB network table and SMB browser info table share
+ * the same index.
+ */
+int
+smb_net_id(uint32_t ipaddr)
+{
+ uint32_t myaddr, mask;
+ int net, smb_nc_cnt;
+
+ smb_nc_cnt = smb_nic_get_num();
+ for (net = 0; net < smb_nc_cnt; net++) {
+ net_cfg_t cfg;
+ if (smb_nic_get_byind(net, &cfg) == NULL)
+ break;
+ mask = cfg.mask;
+ myaddr = cfg.ip;
+ if ((ipaddr & mask) == (myaddr & mask))
+ return (net);
+ }
+
+ return (-1);
+}
+
+/*
+ * smb_browser_get_srvname
+ *
+ */
+struct name_entry *
+smb_browser_get_srvname(unsigned short netid)
+{
+ if (netid < smb_nic_get_num())
+ return (&(smb_browser_info[netid].server.name));
+
+ return (NULL);
+}
+
+static int
+smb_browser_addr_of_subnet(struct name_entry *name, int subnet,
+ struct name_entry *result)
+{
+ uint32_t ipaddr, mask, saddr;
+ struct addr_entry *addr;
+ int smb_nc_cnt;
+ net_cfg_t cfg;
+
+ smb_nc_cnt = smb_nic_get_num();
+ if ((name == 0) || subnet >= smb_nc_cnt)
+ return (-1);
+
+ if (smb_nic_get_byind(subnet, &cfg) == NULL)
+ return (-1);
+ ipaddr = cfg.ip;
+ mask = cfg.mask;
+
+ *result = *name;
+ addr = &name->addr_list;
+ do {
+ saddr = addr->sin.sin_addr.s_addr;
+ if ((saddr & mask) == (ipaddr & mask)) {
+ *result = *name;
+ result->addr_list = *addr;
+ result->addr_list.forw = result->addr_list.back =
+ &result->addr_list;
+ return (0);
+ }
+ addr = addr->forw;
+ } while (addr != &name->addr_list);
+
+ return (-1);
+}
+
+
+static int
+smb_browser_bcast_addr_of_subnet(struct name_entry *name, int net,
+ struct name_entry *result)
+{
+ uint32_t broadcast;
+ int smb_nc_cnt;
+ net_cfg_t cfg;
+
+ smb_nc_cnt = smb_nic_get_num();
+ if (net >= smb_nc_cnt)
+ return (-1);
+
+ if (name != 0 && name != result)
+ *result = *name;
+
+ if (smb_nic_get_byind(net, &cfg) == NULL)
+ return (-1);
+
+ broadcast = cfg.broadcast;
+ result->addr_list.sin.sin_family = AF_INET;
+ result->addr_list.sinlen = sizeof (result->addr_list.sin);
+ result->addr_list.sin.sin_addr.s_addr = broadcast;
+ result->addr_list.sin.sin_port = htons(DGM_SRVC_UDP_PORT);
+ result->addr_list.forw = result->addr_list.back = &result->addr_list;
+ return (0);
+}
+
+/*
+ * 6.5 HostAnnouncement Browser Frame
+ *
+ * To advertise its presence, i.e. to publish itself as being available, a
+ * non-browser server sends a HostAnnouncement browser frame. If the server
+ * is a member of domain "D", this frame is sent to the NETBIOS unique name
+ * D(1d) and mailslot "\\MAILSLOT\\BROWSE". The definition of the
+ * HostAnnouncement frame is:
+ *
+ * struct {
+ * unsigned short Opcode;
+ * unsigned char UpdateCount;
+ * uint32_t Periodicity;
+ * unsigned char ServerName[];
+ * unsigned char VersionMajor;
+ * unsigned char VersionMinor;
+ * uint32_t Type;
+ * uint32_t Signature;
+ * unsigned char Comment[];
+ * }
+ *
+ * where:
+ * Opcode - Identifies this structure as a browser server
+ * announcement and is defined as HostAnnouncement with a
+ * value of decimal 1.
+ *
+ * UpdateCount - must be sent as zero and ignored on receipt.
+ *
+ * Periodicity - The announcement frequency of the server (in
+ * seconds). The server will be removed from the browse list
+ * if it has not been heard from in 3X its announcement
+ * frequency. In no case will the server be removed from the
+ * browse list before the period 3X has elapsed. Actual
+ * implementations may take more than 3X to actually remove
+ * the server from the browse list.
+ *
+ * ServerName - Null terminated ASCII server name (up to 16 bytes
+ * in length).
+ *
+ * VersionMajor - The major version number of the OS the server
+ * is running. it will be returned by NetServerEnum2.
+ *
+ * VersionMinor - The minor version number of the OS the server
+ * is running. This is entirely informational and does not
+ * have any significance for the browsing protocol.
+ *
+ * Type - Specifies the type of the server. The server type bits
+ * are specified in the NetServerEnum2 section.
+ *
+ * Signature - The browser protocol minor version number in the
+ * low 8 bits, the browser protocol major version number in
+ * the next higher 8 bits and the signature 0xaa55 in the
+ * high 16 bits of this field. Thus, for this version of the
+ * browser protocol (1.15) this field has the value
+ * 0xaa55010f. This may used to isolate browser servers that
+ * are running out of revision browser software; otherwise,
+ * it is ignored.
+ *
+ * Comment - Null terminated ASCII comment for the server.
+ * Limited to 43 bytes.
+ *
+ * When a non-browser server starts up, it announces itself in the manner
+ * described once every minute. The frequency of these statements is
+ * gradually stretched to once every 12 minutes.
+ *
+ * Note: older non-browser servers in a domain "D" sent HostAnnouncement
+ * frames to the NETBIOS group name D(00). Non-Browser servers supporting
+ * version 1.15 of the browsing protocol SHOULD NOT use this NETBIOS name,
+ * but for backwards compatibility Master Browsers MAY receive and process
+ * HostAnnouncement frames on this name as described above for D(1d).
+ */
+
+void
+smb_browser_send_HostAnnouncement(int net, int32_t next_announcement,
+ struct addr_entry *addr, char suffix)
+{
+ smb_msgbuf_t mb;
+ int offset, announce_len, data_length;
+ struct name_entry dest_name;
+ struct name_entry server_name;
+ struct browser_netinfo *subnet;
+ server_info_t *server;
+ unsigned char *buffer;
+ uint32_t type;
+ char resource_domain[SMB_PI_MAX_DOMAIN];
+
+ syslog(LOG_DEBUG, "smb_browse: send_HostAnnouncement(%d)", net);
+
+ smb_config_rdlock();
+ (void) strlcpy(resource_domain,
+ smb_config_getstr(SMB_CI_DOMAIN_NAME), SMB_PI_MAX_DOMAIN);
+ (void) utf8_strupr(resource_domain);
+ smb_config_unlock();
+
+ if (addr == 0) {
+ /* Local master Browser */
+ smb_init_name_struct(
+ (unsigned char *)resource_domain, suffix,
+ 0, 0, 0, 0, 0, &dest_name);
+ if (smb_browser_bcast_addr_of_subnet(0, net, &dest_name) < 0)
+ return;
+ } else {
+ smb_init_name_struct(
+ (unsigned char *)resource_domain, suffix,
+ 0, 0, 0, 0, 0, &dest_name);
+ dest_name.addr_list = *addr;
+ dest_name.addr_list.forw = dest_name.addr_list.back =
+ &dest_name.addr_list;
+ }
+
+ /* give some extra room */
+ buffer = (unsigned char *)malloc(MAX_DATAGRAM_LENGTH * 2);
+ if (buffer == 0) {
+ syslog(LOG_ERR, "HostAnnouncement: resource shortage");
+ return;
+ }
+
+ subnet = smb_browser_getnet(net);
+ if (subnet == 0) {
+ free(buffer);
+ return;
+ }
+
+ server = &subnet->server;
+
+ data_length = 1 + 1 + 4 + 16 + 1 + 1 + 4 + 4 +
+ strlen(server->comment) + 1;
+
+ if ((offset = smb_browser_load_transact_header(buffer,
+ MAX_DATAGRAM_LENGTH, data_length, ONE_WAY_TRANSACTION,
+ browse)) < 0) {
+
+ smb_browser_putnet(subnet);
+ free(buffer);
+ return;
+ }
+
+ /*
+ * A non-browser server SHOULD send a HostAnnouncement browser frame
+ * specifying a type of 0 just prior to shutting down, to allow it to
+ * quickly be removed from the list of available servers.
+ */
+ type = (nb_status.state & NETBIOS_SHUTTING_DOWN) ? 0 : server->type;
+
+ smb_msgbuf_init(&mb, buffer + offset, MAX_DATAGRAM_LENGTH - offset, 0);
+ announce_len = smb_msgbuf_encode(&mb, "bbl16cbblls",
+ (char)HOST_ANNOUNCEMENT, /* Announcement opcode */
+ (char)++subnet->server.update_count,
+ next_announcement * 60000, /* Periodicity in MilliSeconds */
+ server->hostname, /* Server name */
+ server->major, /* our major version */
+ server->minor, /* our minor version */
+ type, /* server type */
+ server->signature, /* Signature */
+ server->comment); /* Let 'em know */
+
+ server_name = server->name;
+ smb_browser_putnet(subnet);
+
+ if (announce_len > 0)
+ (void) smb_netbios_datagram_send(&server_name, &dest_name,
+ buffer, offset + announce_len);
+
+ free(buffer);
+ smb_msgbuf_term(&mb);
+}
+
+void
+smb_browser_process_AnnouncementRequest(struct datagram *datagram,
+ char *mailbox)
+{
+ struct browser_netinfo *subnet;
+ unsigned int next_announcement;
+ uint32_t delay = random() % 29; /* in seconds */
+ int net;
+
+ if (strcmp(mailbox, lanman) != 0) {
+ syslog(LOG_DEBUG, "smb_browse: Wrong Mailbox (%s)", mailbox);
+ return;
+ }
+
+ net = smb_net_id(datagram->src.addr_list.sin.sin_addr.s_addr);
+ if (net < 0) {
+ /* We don't know who this is so ignore it... */
+ return;
+ }
+
+ (void) sleep(delay);
+
+ subnet = smb_browser_getnet(net);
+ if (subnet) {
+ next_announcement = subnet->next_announce * 60 * 1000;
+ smb_browser_putnet(subnet);
+ smb_browser_send_HostAnnouncement(net, next_announcement,
+ &datagram->src.addr_list, 0x1D);
+ }
+}
+
+void *
+smb_browser_dispatch(void *arg)
+{
+ struct datagram *datagram = (struct datagram *)arg;
+ smb_msgbuf_t mb;
+ int rc;
+ unsigned char command;
+ unsigned char parameter_words;
+ unsigned short total_parameter_words;
+ unsigned short total_data_count;
+ unsigned short max_parameters_to_return;
+ unsigned short max_data_to_return;
+ unsigned char max_setup_bytes_to_return;
+ unsigned short reply;
+ unsigned short parameter_bytes_sent;
+ unsigned short parameter_offset;
+ unsigned short data_bytes_sent;
+ unsigned short data_offset;
+ unsigned char setup_word_count;
+ unsigned short setup_word_0;
+ unsigned short setup_word_1;
+ unsigned short setup_word_2;
+ unsigned short total_request_bytes;
+ char *mailbox;
+ unsigned char message_type;
+ unsigned char *data;
+ int datalen;
+
+ syslog(LOG_DEBUG, "smb_browse: packet_received");
+
+ smb_msgbuf_init(&mb, datagram->data, datagram->data_length, 0);
+ rc = smb_msgbuf_decode(&mb, "Mb27.bwwwwb.w6.wwwwb.wwwws",
+ &command, /* Command */
+ &parameter_words, /* Count of parameter words */
+ &total_parameter_words, /* Total Parameter words sent */
+ &total_data_count, /* Total Data bytes sent */
+ &max_parameters_to_return, /* Max Parameters to return */
+ &max_data_to_return, /* Max data bytes to return */
+ &max_setup_bytes_to_return, /* Max setup bytes to return */
+ &reply, /* No reply */
+ &parameter_bytes_sent, /* Parameter bytes sent */
+ &parameter_offset, /* Parameter offset */
+ &data_bytes_sent, /* Data bytes sent */
+ &data_offset, /* Data offset */
+ &setup_word_count, /* Setup word count */
+ &setup_word_0, /* Setup word[0] */
+ &setup_word_1, /* Setup word[1] */
+ &setup_word_2, /* Setup word[2] */
+ &total_request_bytes, /* Total request bytes */
+ &mailbox); /* Mailbox address */
+
+ if (rc < 0) {
+ syslog(LOG_ERR, "smb_browser_dispatch: decode error");
+ smb_msgbuf_term(&mb);
+ free(datagram);
+ return (0);
+ }
+
+ data = &datagram->data[data_offset];
+ datalen = datagram->data_length - data_offset;
+
+ /*
+ * The PDC location protocol, i.e. anything on the \\NET
+ * mailslot, is handled by the smb_netlogon module.
+ */
+ if (strncasecmp("\\MAILSLOT\\NET\\", mailbox, 14) == 0) {
+ smb_netlogon_receive(datagram, mailbox, data, datalen);
+ smb_msgbuf_term(&mb);
+ free(datagram);
+ return (0);
+ }
+
+ /*
+ * If it's not a netlogon message, assume it's a browser request.
+ * This is not the most elegant way to extract the command byte
+ * but at least we no longer use it to get the netlogon opcode.
+ */
+ message_type = datagram->data[data_offset];
+
+ switch (message_type) {
+ case ANNOUNCEMENT_REQUEST :
+ smb_browser_process_AnnouncementRequest(datagram, mailbox);
+ break;
+
+ default:
+ syslog(LOG_DEBUG, "smb_browse: invalid message_type(%d, %x)",
+ message_type, message_type);
+ break;
+ }
+
+ smb_msgbuf_term(&mb);
+ free(datagram);
+ return (0);
+}
+
+
+/*
+ * 11.1 Registered unique names
+ *
+ * <COMPUTER>(00)
+ * This name is used by all servers and clients to receive second
+ * class mailslot messages. A system must add this name in order to
+ * receive mailslot messages. The only browser requests that should
+ * appear on this name are BecomeBackup, GetBackupListResp,
+ * MasterAnnouncement, and LocalMasterAnnouncement frames. All other
+ * datagrams (other than the expected non-browser datagrams) may be
+ * ignored and an error logged.
+ *
+ * <DOMAIN>(1d)
+ * This name is used to identify a master browser server for domain
+ * "DOMAIN" on a subnet. A master browser server adds this name as a
+ * unique NETBIOS name when it becomes master browser. If the attempt
+ * to add the name fails, the master browser server assumes that there
+ * is another master in the domain and will fail to come up. It may
+ * log an error if the failure occurs more than 3 times in a row (this
+ * either indicates some form of network misconfiguration or a
+ * software error). The only requests that should appear on this name
+ * are GetBackupListRequest and HostAnnouncement requests. All other
+ * datagrams on this name may be ignored (and an error logged). If
+ * running a NETBIOS name service (NBNS, such as WINS), this name
+ * should not be registered with the NBNS.
+ *
+ * <DOMAIN>(1b)
+ * This name is used to identify the Domain Master Browser for domain
+ * "DOMAIN" (which is also the primary domain controller). It is a
+ * unique name added only by the primary domain controller. The
+ * primary domain controller will respond to GetBackupListRequest on
+ * this name just as it responds to these requests on the <DOMAIN>(1d)
+ * name.
+ *
+ * 11.2 Registered group names
+ *
+ * (01)(02)__MSBROWSE__(02)(01)
+ * This name is used by Master Browsers to announce themselves to the
+ * other Master Browsers on a subnet. It is added as a group name by
+ * all Master Browser servers. The only broadcasts that should appear
+ * on this name is DomainAnnouncement requests. All other datagrams
+ * can be ignored.
+ *
+ * <DOMAIN>(00)
+ * This name is used by clients and servers in domain "DOMAIN" to
+ * process server announcements. The only requests that should appear
+ * on this name that the browser is interested in are
+ * AnnouncementRequest and NETLOGON_QUERY (to locate the PDC) packets.
+ * All other unidentifiable requests may be ignored (and an error
+ * logged).
+ *
+ * <DOMAIN>(1E)
+ * This name is used for announcements to browsers for domain "DOMAIN"
+ * on a subnet. This name is registered by all the browser servers in
+ * the domain. The only requests that should appear on this name are
+ * RequestElection and AnnouncementRequest packets. All other
+ * datagrams may be ignored (and an error logged).
+ *
+ * <DOMAIN>(1C)
+ * This name is registered by Primary Domain Controllers.
+ */
+
+void
+smb_browser_config(void)
+{
+ struct name_entry name;
+ struct name_entry master;
+ struct name_entry dest;
+ struct name_entry *entry;
+ int smb_nc_cnt;
+ net_cfg_t cfg;
+ int net;
+ char resource_domain[SMB_PI_MAX_DOMAIN];
+
+ syslog(LOG_DEBUG, "smb_browse: reconfigure");
+
+ smb_browser_init();
+
+ smb_config_rdlock();
+ (void) strlcpy(resource_domain,
+ smb_config_getstr(SMB_CI_DOMAIN_NAME), SMB_PI_MAX_DOMAIN);
+ (void) utf8_strupr(resource_domain);
+ smb_config_unlock();
+
+ /* domain<00> */
+ smb_init_name_struct((unsigned char *)resource_domain, 0x00,
+ 0, 0, 0, 0, 0, &name);
+ entry = smb_name_find_name(&name);
+ smb_name_unlock_name(entry);
+
+ smb_nc_cnt = smb_nic_get_num();
+ for (net = 0; net < smb_nc_cnt; net++) {
+ if (smb_nic_get_byind(net, &cfg) == NULL)
+ break;
+ if (cfg.exclude)
+ continue;
+ smb_init_name_struct(
+ (unsigned char *)resource_domain, 0x00, 0,
+ cfg.ip, htons(DGM_SRVC_UDP_PORT),
+ NAME_ATTR_GROUP, NAME_ATTR_LOCAL, &name);
+ (void) smb_name_add_name(&name);
+ }
+
+ /* All our local master browsers */
+ smb_init_name_struct((unsigned char *)resource_domain, 0x1D,
+ 0, 0, 0, 0, 0, &dest);
+ entry = smb_name_find_name(&dest);
+
+ if (entry) {
+ for (net = 0; net < smb_nc_cnt; net++) {
+ if (smb_browser_addr_of_subnet(entry, net, &master)
+ == 0) {
+ syslog(LOG_DEBUG,
+ "smbd: Master browser found at %s",
+ inet_ntoa(master.addr_list.sin.sin_addr));
+ }
+ }
+ smb_name_unlock_name(entry);
+ }
+ smb_init_name_struct((unsigned char *)resource_domain,
+ 0x1B, 0, 0, 0, 0, 0, &dest);
+
+ if ((entry = smb_name_find_name(&dest)) != 0) {
+ syslog(LOG_DEBUG, "smbd: Domain Master browser for %s is %s",
+ resource_domain,
+ inet_ntoa(entry->addr_list.sin.sin_addr));
+ smb_name_unlock_name(entry);
+ }
+}
+
+static void
+smb_browser_init()
+{
+ struct browser_netinfo *subnet;
+ struct server_info *server;
+ char cmnt[SMB_PI_MAX_COMMENT], hostname[MAXHOSTNAMELEN];
+ int i, j;
+ int smb_nc_cnt;
+ net_cfg_t cfg;
+
+ (void) smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
+
+ smb_config_rdlock();
+ (void) strlcpy(cmnt, smb_config_getstr(SMB_CI_SYS_CMNT),
+ sizeof (cmnt));
+ smb_config_unlock();
+
+ smb_nc_cnt = smb_nic_get_num();
+ for (i = 0; i < smb_nc_cnt; i++) {
+ if (smb_nic_get_byind(i, &cfg) == NULL)
+ break;
+ if (cfg.exclude)
+ continue;
+
+ subnet = &smb_browser_info[i];
+ (void) mutex_lock(&subnet->mtx);
+
+ /* One Minute announcements for first five */
+ subnet->flags = BROWSER_NF_VALID;
+ subnet->next_announce = 1;
+ subnet->interval = 1;
+ subnet->reps = 5;
+
+ server = &subnet->server;
+ bzero(server, sizeof (struct server_info));
+
+ server->type = MY_SERVER_TYPE;
+ server->major = SMB_VERSION_MAJOR;
+ server->minor = SMB_VERSION_MINOR;
+ server->signature = SMB_SERVER_SIGNATURE;
+ (void) strlcpy(server->comment, cmnt, SMB_PI_MAX_COMMENT);
+
+ (void) snprintf(server->hostname, NETBIOS_NAME_SZ, "%.15s",
+ hostname);
+
+ /*
+ * 00 is workstation service.
+ * 20 is file server service.
+ */
+ smb_init_name_struct((unsigned char *)server->hostname, 0x20, 0,
+ cfg.ip, htons(DGM_SRVC_UDP_PORT),
+ NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &server->name);
+
+ (void) mutex_unlock(&subnet->mtx);
+ }
+
+ /* Invalidate unconfigured NICs */
+ for (j = i; j < SMB_PI_MAX_NETWORKS; j++) {
+ subnet = &smb_browser_info[j];
+ (void) mutex_lock(&subnet->mtx);
+ subnet->flags = BROWSER_NF_INVALID;
+ (void) mutex_unlock(&subnet->mtx);
+ }
+}
+
+/*
+ * smb_browser_non_master_duties
+ *
+ * To advertise its presence, i.e. to publish itself as being available, a
+ * non-browser server sends a HostAnnouncement browser frame. If the server
+ * is a member of domain "D", this frame is sent to the NETBIOS unique name
+ * D(1d) and mailslot "\\MAILSLOT\\BROWSE".
+ */
+void
+smb_browser_non_master_duties(int net)
+{
+ struct browser_netinfo *subnet;
+ struct name_entry name;
+ struct name_entry *dest;
+ struct addr_entry addr;
+ int interval;
+ char resource_domain[SMB_PI_MAX_DOMAIN];
+
+ subnet = smb_browser_getnet(net);
+ if (subnet == 0)
+ return;
+
+ interval = subnet->interval;
+ smb_browser_putnet(subnet);
+
+ smb_browser_send_HostAnnouncement(net, interval, 0, 0x1D);
+
+ smb_config_rdlock();
+ (void) strlcpy(resource_domain,
+ smb_config_getstr(SMB_CI_DOMAIN_NAME), SMB_PI_MAX_DOMAIN);
+ (void) utf8_strupr(resource_domain);
+ smb_config_unlock();
+
+ smb_init_name_struct((unsigned char *)resource_domain, 0x1D,
+ 0, 0, 0, 0, 0, &name);
+
+ if ((dest = smb_name_find_name(&name))) {
+ addr = dest->addr_list;
+ addr.forw = addr.back = &addr;
+ smb_name_unlock_name(dest);
+ smb_browser_send_HostAnnouncement(net, interval, &addr, 0x1D);
+ } else {
+ smb_init_name_struct(
+ (unsigned char *)resource_domain, 0x1B,
+ 0, 0, 0, 0, 0, &name);
+ if ((dest = smb_name_find_name(&name))) {
+ addr = dest->addr_list;
+ addr.forw = addr.back = &addr;
+ smb_name_unlock_name(dest);
+ smb_browser_send_HostAnnouncement(net, interval,
+ &addr, 0x1B);
+ }
+ }
+
+ subnet = smb_browser_getnet(net);
+ /*
+ * One Minute announcements for first five
+ * minutes, one munute longer each round
+ * until 12 minutes and every 12 minutes
+ * thereafter.
+ */
+ if (--subnet->reps == 0) {
+ if (subnet->interval < 12)
+ subnet->interval++;
+
+ subnet->reps = 1;
+ }
+
+ subnet->next_announce = subnet->interval;
+ smb_browser_putnet(subnet);
+}
+
+
+/*
+ * browser_sleep
+ *
+ * Put browser in 1 minute sleep if netbios services are not
+ * shutting down and both name and datagram services are still
+ * running. It'll wake up after 1 minute or if one of the above
+ * conditions go false. It checks the conditions again and return
+ * 1 if everything is ok or 0 if browser shouldn't continue
+ * running.
+ */
+static int
+browser_sleep()
+{
+ int slept = 0;
+ timestruc_t to;
+
+ (void) mutex_lock(&nb_status.mtx);
+ while (((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) &&
+ (nb_status.state & NETBIOS_NAME_SVC_RUNNING) &&
+ (nb_status.state & NETBIOS_DATAGRAM_SVC_RUNNING)) {
+
+ if (slept) {
+ (void) mutex_unlock(&nb_status.mtx);
+ return (1);
+ }
+
+ to.tv_sec = 60; /* 1 minute */
+ to.tv_nsec = 0;
+ (void) cond_reltimedwait(&nb_status.cv, &nb_status.mtx, &to);
+ slept = 1;
+ }
+ (void) mutex_unlock(&nb_status.mtx);
+
+ return (0);
+}
+
+/*
+ * smb_browser_start
+ *
+ * Smb Netbios browser daemon.
+ */
+/*ARGSUSED*/
+void *
+smb_browser_daemon(void *arg)
+{
+ int net;
+ int next_announce;
+ struct browser_netinfo *subnet;
+ int run = 1;
+ int smb_nc_cnt;
+ net_cfg_t cfg;
+
+ smb_browser_config();
+
+ nb_status.state |= NETBIOS_BROWSER_RUNNING;
+
+ while (run) {
+ smb_nc_cnt = smb_nic_get_num();
+ for (net = 0; net < smb_nc_cnt; net++) {
+ if (smb_nic_get_byind(net, &cfg) == NULL)
+ break;
+ if (cfg.exclude)
+ continue;
+
+ subnet = smb_browser_getnet(net);
+ next_announce = --subnet->next_announce;
+ smb_browser_putnet(subnet);
+
+ if (next_announce > 0 || cfg.broadcast == 0)
+ continue;
+
+ smb_browser_non_master_duties(net);
+ }
+
+ run = browser_sleep();
+ }
+
+ smb_netbios_chg_status(NETBIOS_BROWSER_RUNNING, 0);
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.h b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.h
new file mode 100644
index 0000000000..17f3fdf4a9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.h
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#ifndef _BROWSER_H_
+#define _BROWSER_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NetBIOS name types describe the functionality of the registration.
+ * A following list of NetBIOS suffixes (16th Character of the NetBIOS
+ * Name) is detailed in Microsoft knowledge base article Q163409.
+ *
+ * Name Number(h) Type Usage
+ * --------------------------------------------------------------------------
+ * <computername> 00 U Workstation Service
+ * <computername> 01 U Messenger Service
+ * <\\--__MSBROWSE__> 01 G Master Browser
+ * <computername> 03 U Messenger Service
+ * <computername> 06 U RAS Server Service
+ * <computername> 1F U NetDDE Service
+ * <computername> 20 U File Server Service
+ * <computername> 21 U RAS Client Service
+ * <computername> 22 U Microsoft Exchange Interchange(MSMail
+ * Connector)
+ * <computername> 23 U Microsoft Exchange Store
+ * <computername> 24 U Microsoft Exchange Directory
+ * <computername> 30 U Modem Sharing Server Service
+ * <computername> 31 U Modem Sharing Client Service
+ * <computername> 43 U SMS Clients Remote Control
+ * <computername> 44 U SMS Administrators Remote Control
+ * Tool
+ * <computername> 45 U SMS Clients Remote Chat
+ * <computername> 46 U SMS Clients Remote Transfer
+ * <computername> 4C U DEC Pathworks TCPIP service on
+ * Windows NT
+ * <computername> 52 U DEC Pathworks TCPIP service on
+ * Windows NT
+ * <computername> 87 U Microsoft Exchange Message Transfer
+ * Agent
+ * <computername> 6A U Microsoft Exchange IMC
+ * <computername> BE U Network Monitor Agent
+ * <computername> BF U Network Monitor Application
+ * <username> 03 U Messenger Service
+ * <domain> 00 G Domain Name
+ * <domain> 1B U Domain Master Browser
+ * <domain> 1C G Domain Controllers
+ * <domain> 1D U Master Browser
+ * <domain> 1E G Browser Service Elections
+ * <INet~Services> 1C G IIS
+ * <IS~computer name> 00 U IIS
+ * <computername> [2B] U Lotus Notes Server Service
+ * IRISMULTICAST [2F] G Lotus Notes
+ * IRISNAMESERVER [33] G Lotus Notes
+ * Forte_$ND800ZA [20] U DCA IrmaLan Gateway Server Service
+ *
+ * Unique (U): The name may have only one IP address assigned to it. On
+ * a network device multiple occurrences of a single name may appear to
+ * be registered. The suffix may be the only unique character in the name.
+ *
+ * Group (G): A normal group; the single name may exist with many IP
+ * addresses. WINS responds to a name query on a group name with the
+ * limited broadcast address (255.255.255.255). Because routers block
+ * the transmission of these addresses, the Internet Group was designed
+ * to service communications between subnets.
+ *
+ * Multihomed (M): The name is unique, but due to multiple network
+ * interfaces on the same computer this configuration is necessary to
+ * permit the registration. The maximum number of addresses is 25.
+ *
+ * Internet Group (I): This is a special configuration of the group name
+ * used to manage Windows NT Domain names.
+ *
+ * Domain Name (D): New in Windows NT 4.0.
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Message flags used when building the SMB transact headers.
+ */
+#define TWO_WAY_TRANSACTION 0x00
+#define END_SESSION_TRANSACTION 0x01
+#define ONE_WAY_TRANSACTION 0x02
+
+
+/*
+ * Browser commands associated with the BROWSE and MSBROWSE mailslots.
+ */
+#define HOST_ANNOUNCEMENT 0x01
+#define ANNOUNCEMENT_REQUEST 0x02
+#define REQUEST_ELECTION 0x08
+#define GET_BACKUP_LIST_REQ 0x09
+#define GET_BACKUP_LIST_RESP 0x0A
+#define BECOME_BACKUP 0x0B
+#define DOMAIN_ANNOUNCEMENT 0x0C
+#define MASTER_ANNOUNCEMENT 0x0D
+#define LOCAL_MASTER_ANNOUNCEMENT 0x0F
+
+
+/*
+ * Opcodes associated with NETLOGON or NTLOGON mailslots (KB 109626).
+ * LOGON_REQUEST LM1.0/2.0 LOGON Request from client
+ * LOGON_RESPONSE LM1.0 Response to LOGON_REQUEST
+ * LOGON_CENTRAL_QUERY LM1.0 QUERY for centralized init
+ * LOGON_DISTRIB_QUERY LM1.0 QUERY for non-centralized init
+ * LOGON_CENTRAL_RESPONSE LM1.0 response to LOGON_CENTRAL_QUERY
+ * LOGON_DISTRIB_RESPONSE LM1.0 resp to LOGON_DISTRIB_QUERY
+ * LOGON_RESPONSE2 LM2.0 Response to LOGON_REQUEST
+ * LOGON_PRIMARY_QUERY QUERY for Primary DC
+ * LOGON_START_PRIMARY announce startup of Primary DC
+ * LOGON_FAIL_PRIMARY announce failed Primary DC
+ * LOGON_UAS_CHANGE announce change to UAS or SAM
+ * LOGON_NO_USER announce no user on machine
+ * LOGON_PRIMARY_RESPONSE response to LOGON_PRIMARY_QUERY
+ * LOGON_RELOGON_RESPONSE LM1.0/2.0 resp to relogon request
+ * LOGON_WKSTINFO_RESPONSE LM1.0/2.0 resp to interrogate request
+ * LOGON_PAUSE_RESPONSE LM2.0 resp when NETLOGON is paused
+ * LOGON_USER_UNKNOWN LM2.0 response when user is unknown
+ * LOGON_UPDATE_ACCOUNT LM2.1 announce account updates
+ * LOGON_SAM_LOGON_REQUEST SAM LOGON request from client
+ * LOGON_SAM_LOGON_RESPONSE SAM Response to SAM logon request
+ * LOGON_SAM_PAUSE_RESPONSE SAM response when NETLOGON is paused
+ * LOGON_SAM_USER_UNKNOWN SAM response when user is unknown
+ * LOGON_SAM_WKSTINFO_RESPONSE SAM response to interrogate request
+ */
+#define LOGON_REQUEST 0
+#define LOGON_RESPONSE 1
+#define LOGON_CENTRAL_QUERY 2
+#define LOGON_DISTRIB_QUERY 3
+#define LOGON_CENTRAL_RESPONSE 4
+#define LOGON_DISTRIB_RESPONSE 5
+#define LOGON_RESPONSE2 6
+#define LOGON_PRIMARY_QUERY 7
+#define LOGON_START_PRIMARY 8
+#define LOGON_FAIL_PRIMARY 9
+#define LOGON_UAS_CHANGE 10
+#define LOGON_NO_USER 11
+#define LOGON_PRIMARY_RESPONSE 12
+#define LOGON_RELOGON_RESPONSE 13
+#define LOGON_WKSTINFO_RESPONSE 14
+#define LOGON_PAUSE_RESPONSE 15
+#define LOGON_USER_UNKNOWN 16
+#define LOGON_UPDATE_ACCOUNT 17
+#define LOGON_SAM_LOGON_REQUEST 18
+#define LOGON_SAM_LOGON_RESPONSE 19
+#define LOGON_SAM_PAUSE_RESPONSE 20
+#define LOGON_SAM_USER_UNKNOWN 21
+#define LOGON_SAM_WKSTINFO_RESPONSE 22
+
+
+/*
+ * Local protocol flags used to indicate which version of the
+ * netlogon protocol to use when attempting to find the PDC.
+ */
+#define NETLOGON_PROTO_NETLOGON 0x01
+#define NETLOGON_PROTO_SAMLOGON 0x02
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _BROWSER_H_ */
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c
new file mode 100644
index 0000000000..474adca09b
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c
@@ -0,0 +1,1894 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <syslog.h>
+#include <gssapi/gssapi.h>
+#include <kerberosv5/krb5.h>
+#include <net/if.h>
+
+#include <smbns_dyndns.h>
+#include <smbns_krb.h>
+
+/* internal use, in dyndns_add_entry */
+#define DEL_NONE 2
+/* Maximum retires if not authoritative */
+#define MAX_AUTH_RETRIES 3
+
+
+static int
+dyndns_enabled(void)
+{
+ int enabled;
+
+ smb_config_rdlock();
+ enabled = smb_config_getyorn(SMB_CI_DYNDNS_ENABLE);
+ smb_config_unlock();
+
+ return ((enabled) ? 1 : 0);
+}
+
+/*
+ * XXX The following should be removed once head/arpa/nameser_compat.h
+ * defines BADSIG, BADKEY, BADTIME macros
+ */
+#ifndef BADSIG
+#define BADSIG ns_r_badsig
+#endif /* BADSIG */
+
+#ifndef BADKEY
+#define BADKEY ns_r_badkey
+#endif /* BADKEY */
+
+#ifndef BADTIME
+#define BADTIME ns_r_badtime
+#endif /* BADTIME */
+
+/*
+ * dyndns_msg_err
+ * Display error message for DNS error code found in the DNS header in
+ * reply message.
+ * Parameters:
+ * err: DNS errer code
+ * Returns:
+ * None
+ */
+void
+dyndns_msg_err(int err)
+{
+ switch (err) {
+ case NOERROR:
+ break;
+ case FORMERR:
+ syslog(LOG_ERR, "DNS message format error\n");
+ break;
+ case SERVFAIL:
+ syslog(LOG_ERR, "DNS server internal error\n");
+ break;
+ case NXDOMAIN:
+ syslog(LOG_ERR, "DNS entry should exist but does not exist\n");
+ break;
+ case NOTIMP:
+ syslog(LOG_ERR, "DNS opcode not supported\n");
+ break;
+ case REFUSED:
+ syslog(LOG_ERR, "DNS operation refused\n");
+ break;
+ case YXDOMAIN:
+ syslog(LOG_ERR, "DNS entry shouldn't exist but does exist\n");
+ break;
+ case YXRRSET:
+ syslog(LOG_ERR, "DNS RRSet shouldn't exist but does exist\n");
+ break;
+ case NXRRSET:
+ syslog(LOG_ERR, "DNS RRSet should exist but does not exist\n");
+ break;
+ case NOTAUTH:
+ syslog(LOG_ERR, "DNS server is not authoritative "
+ "for specified zone\n");
+ break;
+ case NOTZONE:
+ syslog(LOG_ERR, "Name in Prereq or Update section not "
+ "within specified zone\n");
+ break;
+ case BADSIG:
+ syslog(LOG_ERR, "Bad transaction signature (TSIG)");
+ break;
+ case BADKEY:
+ syslog(LOG_ERR, "Bad transaction key (TKEY)");
+ break;
+ case BADTIME:
+ syslog(LOG_ERR, "Time not synchronized");
+ break;
+
+ default:
+ syslog(LOG_ERR, "Unknown DNS error\n");
+ }
+}
+
+/*
+ * display_stat
+ * Display GSS error message from error code. This routine is used to display
+ * the mechanism independent and mechanism specific error messages for GSS
+ * routines. The major status error code is the mechanism independent error
+ * code and the minor status error code is the mechanism specific error code.
+ * Parameters:
+ * maj: GSS major status
+ * min: GSS minor status
+ * Returns:
+ * None
+ */
+static void
+display_stat(OM_uint32 maj, OM_uint32 min)
+{
+ gss_buffer_desc msg;
+ OM_uint32 msg_ctx = 0;
+ OM_uint32 min2;
+ (void) gss_display_status(&min2, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ syslog(LOG_ERR, "dyndns: GSS major status error: %s\n",
+ (char *)msg.value);
+ (void) gss_display_status(&min2, min, GSS_C_MECH_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ syslog(LOG_ERR, "dyndns: GSS minor status error: %s\n",
+ (char *)msg.value);
+}
+
+static char *
+dyndns_put_nshort(char *buf, uint16_t val)
+{
+ uint16_t nval;
+
+ nval = htons(val);
+ (void) memcpy(buf, &nval, sizeof (uint16_t));
+ buf += sizeof (uint16_t);
+ return (buf);
+}
+
+char *
+dyndns_get_nshort(char *buf, uint16_t *val)
+{
+ uint16_t nval;
+
+ (void) memcpy(&nval, buf, sizeof (uint16_t));
+ *val = ntohs(nval);
+ buf += sizeof (uint16_t);
+ return (buf);
+}
+
+static char *
+dyndns_put_nlong(char *buf, uint32_t val)
+{
+ uint32_t lval;
+
+ lval = htonl(val);
+ (void) memcpy(buf, &lval, sizeof (uint32_t));
+ buf += sizeof (uint32_t);
+ return (buf);
+}
+
+static char *
+dyndns_put_byte(char *buf, char val)
+{
+ *buf = val;
+ buf++;
+ return (buf);
+}
+
+static char *
+dyndns_put_int(char *buf, int val)
+{
+ (void) memcpy(buf, &val, sizeof (int));
+ buf += sizeof (int);
+ return (buf);
+}
+
+char *
+dyndns_get_int(char *buf, int *val)
+{
+ (void) memcpy(val, buf, sizeof (int));
+ buf += sizeof (int);
+ return (buf);
+}
+
+
+/*
+ * dyndns_stuff_str
+ * Converts a domain string by removing periods and replacing with a byte value
+ * of how many characters following period. A byte value is placed in front
+ * to indicate how many characters before first period. A NULL character is
+ * placed at the end. i.e. host.procom.com -> 4host5procom3com0
+ * Buffer space checking is done by caller.
+ * Parameters:
+ * ptr : address of pointer to buffer to store converted string
+ * zone: domain name string
+ * Returns:
+ * ptr: address of pointer to next available buffer space
+ * -1 : error
+ * 0 : success
+ */
+static int
+dyndns_stuff_str(char **ptr, char *zone)
+{
+ int len;
+ char *lenPtr, *zonePtr;
+
+ for (zonePtr = zone; *zonePtr; ) {
+ lenPtr = *ptr;
+ *ptr = *ptr + 1;
+ len = 0;
+ while (*zonePtr != '.' && *zonePtr != 0) {
+ *ptr = dyndns_put_byte(*ptr, *zonePtr);
+ zonePtr++;
+ len++;
+ }
+ *lenPtr = len;
+ if (*zonePtr == '.')
+ zonePtr++;
+ }
+ *ptr = dyndns_put_byte(*ptr, 0);
+ return (0);
+}
+
+/*
+ * dyndns_build_header
+ * Build the header for DNS query and DNS update request message.
+ * Parameters:
+ * ptr : address of pointer to buffer to store header
+ * buf_len : buffer length
+ * msg_id : message id
+ * query_req : use REQ_QUERY for query message or REQ_UPDATE for
+ * update message
+ * quest_zone_cnt : number of question record for query message or
+ * number of zone record for update message
+ * ans_prereq_cnt : number of answer record for query message or
+ * number of prerequisite record for update message
+ * nameser_update_cnt: number of name server for query message or
+ * number of update record for update message
+ * addit_cnt : number of additional record
+ * flags : query flags word
+ * Returns:
+ * ptr: address of pointer to next available buffer space
+ * -1 : error
+ * 0 : success
+ */
+int
+dyndns_build_header(char **ptr, int buf_len, uint16_t msg_id, int query_req,
+ uint16_t quest_zone_cnt, uint16_t ans_prereq_cnt,
+ uint16_t nameser_update_cnt, uint16_t addit_cnt, int flags)
+{
+ uint16_t opcode;
+
+ if (buf_len < 12) {
+ syslog(LOG_ERR, "dyndns: no more buf for header section\n");
+ return (-1);
+ }
+
+ *ptr = dyndns_put_nshort(*ptr, msg_id); /* mesg ID */
+ if (query_req == REQ_QUERY)
+ opcode = ns_o_query; /* query msg */
+ else
+ opcode = ns_o_update << 11; /* update msg */
+ opcode |= flags;
+ /* mesg opcode */
+ *ptr = dyndns_put_nshort(*ptr, opcode);
+ /* zone record count */
+ *ptr = dyndns_put_nshort(*ptr, quest_zone_cnt);
+ /* prerequiste record count */
+ *ptr = dyndns_put_nshort(*ptr, ans_prereq_cnt);
+ /* update record count */
+ *ptr = dyndns_put_nshort(*ptr, nameser_update_cnt);
+ /* additional record count */
+ *ptr = dyndns_put_nshort(*ptr, addit_cnt);
+
+ return (0);
+}
+
+/*
+ * dyndns_build_quest_zone
+ * Build the question section for query message or zone section for
+ * update message.
+ * Parameters:
+ * ptr : address of pointer to buffer to store question or zone section
+ * buf_len: buffer length
+ * name : question or zone name
+ * type : type of question or zone
+ * class : class of question or zone
+ * Returns:
+ * ptr: address of pointer to next available buffer space
+ * -1 : error
+ * 0 : success
+ */
+int
+dyndns_build_quest_zone(char **ptr, int buf_len, char *name, int type,
+ int class)
+{
+ char *zonePtr;
+
+ if ((strlen(name) + 6) > buf_len) {
+ syslog(LOG_ERR, "dyndns: no more buf "
+ "for question/zone section\n");
+ return (-1);
+ }
+
+ zonePtr = *ptr;
+ (void) dyndns_stuff_str(&zonePtr, name);
+ *ptr = zonePtr;
+ *ptr = dyndns_put_nshort(*ptr, type);
+ *ptr = dyndns_put_nshort(*ptr, class);
+ return (0);
+}
+
+/*
+ * dyndns_build_update
+ * Build update section of update message for adding and removing a record.
+ * If the ttl value is 0 then this message is for record deletion.
+ *
+ * Parameters:
+ * ptr : address of pointer to buffer to store update section
+ * buf_len : buffer length
+ * name : resource name of this record
+ * type : type of this record
+ * class : class of this record
+ * ttl : time-to-live, cached time of this entry by others and not
+ * within DNS database, a zero value for record(s) deletion
+ * data : data of this resource record
+ * forw_rev: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone
+ * add_del : UPDATE_ADD for adding entry, UPDATE_DEL for removing zone
+ * del_type: DEL_ONE for deleting one entry, DEL_ALL for deleting all
+ * entries of the same resource name. Only valid for UPDATE_DEL.
+ * Returns:
+ * ptr: address of pointer to next available buffer space
+ * -1 : error
+ * 0 : success
+ */
+static int
+dyndns_build_update(char **ptr, int buf_len, char *name, int type, int class,
+ uint32_t ttl, char *data, int forw_rev, int add_del, int del_type)
+{
+ char *namePtr;
+ int rec_len, data_len;
+
+ rec_len = strlen(name) + 10;
+ if (add_del == UPDATE_ADD) {
+ if (forw_rev == UPDATE_FORW)
+ data_len = 4;
+ else
+ data_len = strlen(data) + 2;
+ } else {
+ if (del_type == DEL_ALL)
+ data_len = 0;
+ else if (forw_rev == UPDATE_FORW)
+ data_len = 4;
+ else
+ data_len = strlen(data) + 2;
+ }
+
+ if (rec_len + data_len > buf_len) {
+ syslog(LOG_ERR, "dyndns: no more buf for update section\n");
+ return (-1);
+ }
+
+ namePtr = *ptr;
+ (void) dyndns_stuff_str(&namePtr, name);
+ *ptr = namePtr;
+ *ptr = dyndns_put_nshort(*ptr, type);
+ *ptr = dyndns_put_nshort(*ptr, class);
+ *ptr = dyndns_put_nlong(*ptr, ttl);
+
+ if (add_del == UPDATE_DEL && del_type == DEL_ALL) {
+ *ptr = dyndns_put_nshort(*ptr, 0);
+ return (0);
+ }
+
+ if (forw_rev == UPDATE_FORW) {
+ *ptr = dyndns_put_nshort(*ptr, 4);
+ *ptr = dyndns_put_int(*ptr, inet_addr(data)); /* ip address */
+ } else {
+ *ptr = dyndns_put_nshort(*ptr, strlen(data)+2);
+ namePtr = *ptr;
+ (void) dyndns_stuff_str(&namePtr, data); /* hostname */
+ *ptr = namePtr;
+ }
+ return (0);
+}
+
+/*
+ * dyndns_build_tkey
+ * Build TKEY section to establish security context for secure dynamic DNS
+ * update. DNS header and question sections need to be build before this
+ * section. The TKEY data are the tokens generated during security context
+ * establishment and the TKEY message is used to transmit those tokens, one
+ * at a time, to the DNS server.
+ * Parameters:
+ * ptr : address of pointer to buffer to store TKEY
+ * buf_len : buffer length
+ * name : key name, must be unique and same as for TSIG record
+ * key_expire: expiration time of this key in second
+ * data : TKEY data
+ * data_size : data size
+ * Returns:
+ * ptr: address of the pointer to the next available buffer space
+ * -1 : error
+ * 0 : success
+ */
+static int
+dyndns_build_tkey(char **ptr, int buf_len, char *name, int key_expire,
+ char *data, int data_size)
+{
+ char *namePtr;
+ struct timeval tp;
+
+ if (strlen(name)+2 + 45 + data_size > buf_len) {
+ syslog(LOG_ERR, "dyndns: no more buf for TKEY record\n");
+ return (-1);
+ }
+
+ namePtr = *ptr;
+ (void) dyndns_stuff_str(&namePtr, name); /* unique global name */
+ *ptr = namePtr;
+ *ptr = dyndns_put_nshort(*ptr, ns_t_tkey);
+ *ptr = dyndns_put_nshort(*ptr, ns_c_any);
+ *ptr = dyndns_put_nlong(*ptr, 0);
+ /* 19 + 14 + data_size + 2 */
+ *ptr = dyndns_put_nshort(*ptr, 35 + data_size);
+ namePtr = *ptr;
+ (void) dyndns_stuff_str(&namePtr, "gss.microsoft.com");
+ *ptr = namePtr;
+ (void) gettimeofday(&tp, 0);
+ *ptr = dyndns_put_nlong(*ptr, tp.tv_sec); /* inception */
+ /* expiration, 86400 */
+ *ptr = dyndns_put_nlong(*ptr, tp.tv_sec + key_expire);
+ *ptr = dyndns_put_nshort(*ptr, MODE_GSS_API); /* mode: gss-api */
+ *ptr = dyndns_put_nshort(*ptr, 0); /* error */
+ *ptr = dyndns_put_nshort(*ptr, data_size); /* key size */
+ (void) memcpy(*ptr, data, data_size); /* key data */
+ *ptr += data_size;
+ *ptr = dyndns_put_nshort(*ptr, 0); /* other */
+ return (0);
+}
+
+/*
+ * dyndns_build_tsig
+ * Build TSIG section for secure dynamic DNS update. This routine will be
+ * called twice. First called with TSIG_UNSIGNED, and second with TSIG_SIGNED.
+ * The TSIG data is NULL and ignored for TSIG_UNSIGNED and is the update request
+ * message encrypted for TSIG_SIGNED. The message id must be the same id as the
+ * one in the update request before it is encrypted.
+ * Parameters:
+ * ptr : address of pointer to buffer to store TSIG
+ * buf_len : buffer length
+ * msg_id : message id
+ * name : key name, must be the same as in TKEY record
+ * fudge_time : amount of error time allow in seconds
+ * data : TSIG data if TSIG_SIGNED, otherwise NULL
+ * data_size : size of data, otherwise 0 if data is NULL
+ * data_signed: TSIG_SIGNED to indicate data is signed and encrypted,
+ * otherwise TSIG_UNSIGNED
+ * Returns:
+ * ptr: address of pointer to next available buffer space
+ * -1 : error
+ * 0 : success
+ */
+static int
+dyndns_build_tsig(char **ptr, int buf_len, int msg_id, char *name,
+ int fudge_time, char *data, int data_size, int data_signed)
+{
+ char *namePtr;
+ struct timeval tp;
+ int signtime, fudge, rec_len;
+
+ if (data_signed == TSIG_UNSIGNED)
+ rec_len = strlen(name)+2 + 37;
+ else
+ rec_len = strlen(name)+2 + 45 + data_size;
+
+ if (rec_len > buf_len) {
+ syslog(LOG_ERR, "dyndns: no more buf for TSIG record\n");
+ return (-1);
+ }
+
+ namePtr = *ptr;
+ (void) dyndns_stuff_str(&namePtr, name); /* unique global name */
+ *ptr = namePtr;
+ if (data_signed == TSIG_SIGNED)
+ *ptr = dyndns_put_nshort(*ptr, ns_t_tsig);
+ *ptr = dyndns_put_nshort(*ptr, ns_c_any);
+ *ptr = dyndns_put_nlong(*ptr, 0);
+ if (data_signed == TSIG_SIGNED) {
+ /* 19 + 10 + data_size + 6 */
+ *ptr = dyndns_put_nshort(*ptr, 35 + data_size);
+ }
+ namePtr = *ptr;
+ (void) dyndns_stuff_str(&namePtr, "gss.microsoft.com");
+ *ptr = namePtr;
+ (void) gettimeofday(&tp, 0);
+ signtime = tp.tv_sec >> 16;
+ *ptr = dyndns_put_nlong(*ptr, signtime); /* sign time */
+ fudge = tp.tv_sec << 16;
+ fudge |= fudge_time;
+ *ptr = dyndns_put_nlong(*ptr, fudge); /* fudge time */
+ if (data_signed == TSIG_SIGNED) {
+ /* signed data size */
+ *ptr = dyndns_put_nshort(*ptr, data_size);
+ (void) memcpy(*ptr, data, data_size); /* signed data */
+ *ptr += data_size;
+ *ptr = dyndns_put_nshort(*ptr, msg_id); /* original id */
+ }
+ *ptr = dyndns_put_nshort(*ptr, 0); /* error */
+ *ptr = dyndns_put_nshort(*ptr, 0); /* other */
+ return (0);
+}
+
+/*
+ * dyndns_open_init_socket
+ * This routine creates a SOCK_STREAM or SOCK_DGRAM socket and initializes it
+ * by doing bind() and setting linger option to off.
+ *
+ * Parameters:
+ * sock_type: SOCK_STREAM for TCP or SOCK_DGRAM for UDP
+ * dest_addr: destination address in network byte order
+ * port : destination port number
+ * Returns:
+ * descriptor: descriptor referencing the created socket
+ * -1 : error
+ */
+int
+dyndns_open_init_socket(int sock_type, unsigned long dest_addr, int port)
+{
+ int s;
+ struct sockaddr_in my_addr;
+ struct linger l;
+ struct sockaddr_in serv_addr;
+
+ if ((s = socket(AF_INET, sock_type, 0)) == -1) {
+ syslog(LOG_ERR, "dyndns: socket err\n");
+ return (-1);
+ }
+
+ l.l_onoff = 0;
+ if (setsockopt(s, SOL_SOCKET, SO_LINGER,
+ (char *)&l, sizeof (l)) == -1) {
+ syslog(LOG_ERR, "dyndns: setsocket err\n");
+ (void) close(s);
+ return (-1);
+ }
+
+ bzero(&my_addr, sizeof (my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons(0);
+ my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(s, (struct sockaddr *)&my_addr, sizeof (my_addr)) < 0) {
+ syslog(LOG_ERR, "dyndns: client bind err\n");
+ (void) close(s);
+ return (-1);
+ }
+
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(port);
+ serv_addr.sin_addr.s_addr = dest_addr;
+
+ if (connect(s, (struct sockaddr *)&serv_addr,
+ sizeof (struct sockaddr_in)) < 0) {
+ syslog(LOG_ERR, "dyndns: client connect err (%s)\n",
+ strerror(errno));
+ (void) close(s);
+ return (-1);
+ }
+
+ return (s);
+}
+
+/*
+ * dyndns_acquire_cred
+ * This routine is used to acquire a GSS credential handle to a user's Kerberos
+ * ticket-granting ticket (TGT) stored locally on the system. If getting a
+ * handle fails, then a new TGT will be obtained again before trying to get a
+ * handle once more.
+ * The user's password is taken from the environment variable
+ * lookup.dns.dynamic.passwd and is encrypted.
+ * Paramaters:
+ * kinit_retry: if 0 then a new TGT can be obtained before second attempt to
+ * get a handle to TGT if first attempt fails
+ * Returns:
+ * user_name : name of user to get credential handle from
+ * credHandle : handle to user's credential (TGT)
+ * oid : contains Kerberos 5 object identifier
+ * kinit_retry: 1 if a new TGT has been acquired in this routine, otherwise 0
+ * -1 : error
+ */
+static int
+dyndns_acquire_cred(gss_cred_id_t *credHandle, char *user_name,
+ gss_OID *oid, int *kinit_retry)
+{
+ char *p, pwd[100];
+
+ smb_config_rdlock();
+ p = smb_config_getstr(SMB_CI_ADS_USER);
+ if (p == NULL || *p == 0) {
+ syslog(LOG_ERR, "No user configured for "
+ "secure dynamic DNS update.\n");
+ smb_config_unlock();
+ return (-1);
+ }
+ (void) strcpy(user_name, p);
+
+ p = smb_config_getstr(SMB_CI_ADS_PASSWD);
+ if (p == NULL || *p == 0) {
+ syslog(LOG_ERR, "No password configured for "
+ "secure dynamic DNS update.\n");
+ smb_config_unlock();
+ return (-1);
+ }
+ smb_config_unlock();
+
+ (void) strcpy(pwd, p);
+
+ return krb5_acquire_cred_kinit(user_name, pwd, credHandle,
+ oid, kinit_retry, "dyndns");
+}
+
+/*
+ * dyndns_build_tkey_msg
+ * This routine is used to build the TKEY message to transmit GSS tokens
+ * during GSS security context establishment for secure DNS update. The
+ * TKEY message format uses the DNS query message format. The TKEY section
+ * is the answer section of the query message format.
+ * Microsoft uses a value of 86400 seconds (24 hours) for key expiration time.
+ * Parameters:
+ * buf : buffer to build and store TKEY message
+ * key_name: a unique key name, this same key name must be also be used in
+ * the TSIG message
+ * out_tok : TKEY message data (GSS tokens)
+ * Returns:
+ * id : message id of this TKEY message
+ * message size: the size of the TKEY message
+ * -1 : error
+ */
+static int
+dyndns_build_tkey_msg(char *buf, char *key_name, uint16_t *id,
+ gss_buffer_desc *out_tok)
+{
+ int queryReq, zoneCount, preqCount, updateCount, additionalCount;
+ int zoneType, zoneClass;
+ char *bufptr;
+
+ queryReq = REQ_QUERY;
+ /* query section of query request */
+ zoneCount = 1;
+ /* answer section of query request */
+ preqCount = 1;
+ updateCount = 0;
+ additionalCount = 0;
+
+ (void) memset(buf, 0, MAX_TCP_SIZE);
+ bufptr = buf;
+ *id = smb_get_next_resid();
+
+ /* add TCP length info that follows this field */
+ bufptr = dyndns_put_nshort(bufptr,
+ 26 + (strlen(key_name)+2)*2 + 35 + out_tok->length);
+
+ if (dyndns_build_header(&bufptr, BUFLEN_TCP(bufptr, buf), *id, queryReq,
+ zoneCount, preqCount, updateCount, additionalCount, 0) == -1) {
+ return (-1);
+ }
+
+ zoneType = ns_t_tkey;
+ zoneClass = ns_c_in;
+ if (dyndns_build_quest_zone(&bufptr, BUFLEN_TCP(bufptr, buf), key_name,
+ zoneType, zoneClass) == -1) {
+ return (-1);
+ }
+
+ if (dyndns_build_tkey(&bufptr, BUFLEN_TCP(bufptr, buf), key_name,
+ 86400, out_tok->value, out_tok->length) == -1) {
+ return (-1);
+ }
+
+ return (bufptr - buf);
+}
+
+/*
+ * dyndns_establish_sec_ctx
+ * This routine is used to establish a security context with the DNS server
+ * by building TKEY messages and sending them to the DNS server. TKEY messages
+ * are also received from the DNS server for processing. The security context
+ * establishment is done with the GSS client on the system producing a token
+ * and sending the token within the TKEY message to the GSS server on the DNS
+ * server. The GSS server then processes the token and then send a TKEY reply
+ * message with a new token to be processed by the GSS client. The GSS client
+ * processes the new token and then generates a new token to be sent to the
+ * GSS server. This cycle is continued until the security establishment is
+ * done. TCP is used to send and receive TKEY messages.
+ * If gss_init_sec_context fails then a new TGT will be acquired so that
+ * security establishment can be retry once more by the caller after getting
+ * a handle to the new TGT (credential).
+ * Parameters:
+ * credHandle : handle to credential
+ * s : socket descriptor to DNS server
+ * key_name : TKEY key name
+ * dns_hostname: fully qualified DNS hostname
+ * oid : contains Kerberos 5 object identifier
+ * user_name : name of user to perform DNS update
+ * kinit_retry : if 0 and gss_init_sec_context fails then get new TGT so
+ * the caller can restart doing security context establishment
+ * Returns:
+ * gss_context : handle to security context
+ * kinit_retry : 1 if a new TGT has been acquired in this routine,
+ * otherwise 0
+ * do_acquire_cred: if 1 then caller will restart security context
+ * establishment
+ * -1 : error
+ */
+static int
+dyndns_establish_sec_ctx(gss_ctx_id_t *gss_context, gss_cred_id_t credHandle,
+ int s, char *key_name, char *dns_hostname, gss_OID oid, char *user_name,
+ int *kinit_retry, int *do_acquire_cred)
+{
+ uint16_t id, rid, rsz;
+ char buf[MAX_TCP_SIZE], buf2[MAX_TCP_SIZE];
+ int ret;
+ char *service_name, *tmpptr;
+ int service_sz;
+ OM_uint32 min, maj, time_rec;
+ gss_buffer_desc service_buf, in_tok, out_tok;
+ gss_name_t target_name;
+ gss_buffer_desc *inputptr;
+ int gss_flags;
+ OM_uint32 ret_flags;
+ int buf_sz;
+ char *p, pwd[100];
+
+ smb_config_rdlock();
+ p = smb_config_getstr(SMB_CI_ADS_PASSWD);
+ if (p == NULL || *p == 0) {
+ syslog(LOG_ERR, "No password configured for "
+ "secure dynamic DNS update.\n");
+ smb_config_unlock();
+ return (-1);
+ }
+ smb_config_unlock();
+ (void) strcpy(pwd, p);
+
+ service_sz = strlen(dns_hostname) + 5;
+ service_name = (char *)malloc(sizeof (char) * service_sz);
+ if (service_name == NULL) {
+ syslog(LOG_ERR, "Malloc failed for %d bytes ", service_sz);
+ smb_config_unlock();
+ return (-1);
+ }
+ (void) snprintf(service_name, service_sz, "DNS@%s", dns_hostname);
+ service_buf.value = service_name;
+ service_buf.length = strlen(service_name)+1;
+ if ((maj = gss_import_name(&min, &service_buf,
+ (gss_OID) gss_nt_service_name,
+ &target_name)) != GSS_S_COMPLETE) {
+ display_stat(maj, min);
+ (void) gss_release_oid(&min, &oid);
+ (void) free(service_name);
+ return (-1);
+ }
+ (void) free(service_name);
+
+ inputptr = GSS_C_NO_BUFFER;
+ *gss_context = GSS_C_NO_CONTEXT;
+ gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG | GSS_C_REPLAY_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
+ do {
+ if (krb5_establish_sec_ctx_kinit(user_name, pwd, credHandle,
+ gss_context, target_name, oid, gss_flags, inputptr,
+ &out_tok, &ret_flags, &time_rec, kinit_retry,
+ do_acquire_cred, &maj, "dyndns") == -1) {
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ return (-1);
+ }
+
+ if ((maj == GSS_S_COMPLETE) &&
+ !(ret_flags & GSS_C_REPLAY_FLAG)) {
+ syslog(LOG_ERR, "dyndns: No GSS_C_REPLAY_FLAG\n");
+ if (out_tok.length > 0)
+ (void) gss_release_buffer(&min, &out_tok);
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ return (-1);
+ }
+
+ if ((maj == GSS_S_COMPLETE) &&
+ !(ret_flags & GSS_C_MUTUAL_FLAG)) {
+ syslog(LOG_ERR, "dyndns: No GSS_C_MUTUAL_FLAG\n");
+ if (out_tok.length > 0)
+ (void) gss_release_buffer(&min, &out_tok);
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ return (-1);
+ }
+
+ if (out_tok.length > 0) {
+ if ((buf_sz = dyndns_build_tkey_msg(buf, key_name,
+ &id, &out_tok)) <= 0) {
+ (void) gss_release_buffer(&min, &out_tok);
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ return (-1);
+ }
+
+ (void) gss_release_buffer(&min, &out_tok);
+
+ if (send(s, buf, buf_sz, 0) == -1) {
+ syslog(LOG_ERR, "dyndns: TKEY send error\n");
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ return (-1);
+ }
+
+ bzero(buf2, MAX_TCP_SIZE);
+ if (recv(s, buf2, MAX_TCP_SIZE, 0) == -1) {
+ syslog(LOG_ERR, "dyndns: TKEY "
+ "reply recv error\n");
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ return (-1);
+ }
+
+ ret = buf2[5] & 0xf; /* error field in TCP */
+ if (ret != NOERROR) {
+ syslog(LOG_ERR, "dyndns: Error in "
+ "TKEY reply: %d: ", ret);
+ dyndns_msg_err(ret);
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ return (-1);
+ }
+
+ tmpptr = &buf2[2];
+ (void) dyndns_get_nshort(tmpptr, &rid);
+ if (id != rid) {
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+ return (-1);
+ }
+
+ tmpptr = &buf2[59+(strlen(key_name)+2)*2];
+ (void) dyndns_get_nshort(tmpptr, &rsz);
+ in_tok.length = rsz;
+
+ /* bsd38 -> 2*7=14 */
+ in_tok.value = &buf2[61+(strlen(key_name)+2)*2];
+ inputptr = &in_tok;
+ }
+
+ } while (maj != GSS_S_COMPLETE);
+
+ (void) gss_release_oid(&min, &oid);
+ (void) gss_release_name(&min, &target_name);
+
+ return (0);
+}
+
+/*
+ * dyndns_get_sec_context
+ * Get security context for secure dynamic DNS update. This routine opens
+ * a TCP socket to the DNS server and calls routines to get a handle to a
+ * locally cached user's credential and establish a security context with
+ * the DNS server to perform secure dynamic DNS update. If getting security
+ * context fails then a retry may be done after reobtaining new credential and
+ * getting a new credential handle. If obtaining new credential has been
+ * done earlier during getting a handle to credential then there is no need to
+ * do a retry for security context.
+ * Parameters:
+ * hostname: fully qualified hostname
+ * dns_ip : ip address of hostname in network byte order
+ * Returns:
+ * gss_handle: gss credential handle
+ * gss_context: gss security context
+ * -1: error
+ * 0: success
+ */
+static gss_ctx_id_t
+dyndns_get_sec_context(const char *hostname, int dns_ip)
+{
+ int s;
+ gss_cred_id_t credHandle;
+ gss_ctx_id_t gss_context;
+ gss_OID oid;
+ OM_uint32 min;
+ struct hostent *hentry;
+ int kinit_retry, do_acquire_cred;
+ char *key_name, dns_hostname[255], user_name[50];
+
+ key_name = (char *)hostname;
+
+ hentry = gethostbyaddr((char *)&dns_ip, 4, AF_INET);
+ if (hentry == NULL) {
+ syslog(LOG_ERR, "dyndns: Can't get DNS "
+ "hostname from DNS ip.\n");
+ return (NULL);
+ }
+ (void) strcpy(dns_hostname, hentry->h_name);
+
+ if ((s = dyndns_open_init_socket(SOCK_STREAM, dns_ip, 53)) < 0) {
+ return (NULL);
+ }
+
+ kinit_retry = 0;
+ do_acquire_cred = 0;
+ acquire_cred:
+
+ if (dyndns_acquire_cred(&credHandle, user_name, &oid, &kinit_retry)) {
+ (void) close(s);
+ return (NULL);
+ }
+
+ if (dyndns_establish_sec_ctx(&gss_context, credHandle, s, key_name,
+ dns_hostname, oid, user_name, &kinit_retry, &do_acquire_cred)) {
+ (void) gss_release_cred(&min, &credHandle);
+ if (do_acquire_cred) {
+ do_acquire_cred = 0;
+ goto acquire_cred;
+ }
+ (void) close(s);
+ return (NULL);
+ }
+
+ (void) close(s);
+
+ (void) gss_release_cred(&min, &credHandle);
+ return (gss_context);
+}
+
+/*
+ * dyndns_build_add_remove_msg
+ * This routine builds the update request message for adding and removing DNS
+ * entries which is used for non-secure and secure DNS update.
+ * This routine builds an UDP message.
+ * Parameters:
+ * buf : buffer to build message
+ * update_zone: the type of zone to update, use UPDATE_FORW for forward
+ * lookup zone, use UPDATE_REV for reverse lookup zone
+ * hostname : fully qualified hostname to update DNS with
+ * ip_addr : IP address of hostname
+ * life_time : cached time of this entry by others and not within DNS
+ * database
+ * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry
+ * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all
+ * entries of the same resource name. Only valid for UPDATE_DEL.
+ * addit_cnt : Indicate how many record is in the additional section of
+ * the DNS message. A value of zero is always used with
+ * non-secure update message. For secure update message,
+ * the value will be one because the signed TSIG message
+ * is added as the additional record of the DNS update message.
+ * id : DNS message ID. If a positive value then this ID value is
+ * used, otherwise the next incremented value is used
+ * level : This is the domain level which we send the request to, level
+ * zero is the default level, it can go upto 2 in reverse zone
+ * and virtually to any level in forward zone.
+ * Returns:
+ * buf : buffer containing update message
+ * id : DNS message ID
+ * int : size of update message
+ * -1 : error
+ *
+ * This function is changed to handle dynamic DNS update retires to higher
+ * authoritative domains.
+ */
+static int
+dyndns_build_add_remove_msg(char *buf, int update_zone, const char *hostname,
+ const char *ip_addr, int life_time, int update_type, int del_type,
+ int addit_cnt, uint16_t *id, int level)
+{
+ int a, b, c, d;
+ char *bufptr;
+ int queryReq, zoneCount, preqCount, updateCount, additionalCount;
+ char *zone, *resource, *data, zone_buf[100], resrc_buf[100];
+ int zoneType, zoneClass, type, class, ttl;
+ char *p;
+
+ queryReq = REQ_UPDATE;
+ zoneCount = 1;
+ preqCount = 0;
+ updateCount = 1;
+ additionalCount = addit_cnt;
+
+ (void) memset(buf, 0, NS_PACKETSZ);
+ bufptr = buf;
+
+ if (*id == 0)
+ *id = smb_get_next_resid();
+
+ if (dyndns_build_header(&bufptr, BUFLEN_UDP(bufptr, buf), *id, queryReq,
+ zoneCount, preqCount, updateCount, additionalCount, 0) == -1) {
+ return (-1);
+ }
+
+ zoneType = ns_t_soa;
+ zoneClass = ns_c_in;
+
+ if (update_zone == UPDATE_FORW) {
+ p = (char *)hostname;
+
+ /* Try higher domains according to the level requested */
+ do {
+ /* domain */
+ if ((zone = (char *)strchr(p, '.')) == NULL)
+ return (-1);
+ zone += 1;
+ p = zone;
+ } while (--level >= 0);
+ resource = (char *)hostname;
+ data = (char *)ip_addr;
+ } else {
+ (void) sscanf(ip_addr, "%d.%d.%d.%d", &a, &b, &c, &d);
+ (void) sprintf(zone_buf, "%d.%d.%d.in-addr.arpa", c, b, a);
+ zone = p = zone_buf;
+
+ /* Try higher domains according to the level requested */
+ while (--level >= 0) {
+ /* domain */
+ if ((zone = (char *)strchr(p, '.')) == NULL) {
+ return (-1);
+ }
+ zone += 1;
+ p = zone;
+ }
+
+ (void) sprintf(resrc_buf, "%d.%d.%d.%d.in-addr.arpa",
+ d, c, b, a);
+ resource = resrc_buf; /* ip info */
+ data = (char *)hostname;
+ }
+
+ if (dyndns_build_quest_zone(&bufptr, BUFLEN_UDP(bufptr, buf), zone,
+ zoneType, zoneClass) == -1) {
+ return (-1);
+ }
+
+ if (update_zone == UPDATE_FORW)
+ type = ns_t_a;
+ else
+ type = ns_t_ptr;
+
+ if (update_type == UPDATE_ADD) {
+ class = ns_c_in;
+ ttl = life_time;
+ } else {
+ if (del_type == DEL_ONE)
+ class = ns_c_none; /* remove one */
+ else
+ class = ns_c_any; /* remove all */
+ ttl = 0;
+ }
+ if (dyndns_build_update(&bufptr, BUFLEN_UDP(bufptr, buf),
+ resource, type, class, ttl, data, update_zone,
+ update_type, del_type) == -1) {
+ return (-1);
+ }
+
+ return (bufptr - buf);
+}
+
+/*
+ * dyndns_build_unsigned_tsig_msg
+ * This routine is used to build the unsigned TSIG message for signing. The
+ * unsigned TSIG message contains the update request message with certain TSIG
+ * fields included. An error time of 300 seconds is used for fudge time. This
+ * is the number used by Microsoft clients.
+ * This routine builds a UDP message.
+ * Parameters:
+ * buf : buffer to build message
+ * update_zone: the type of zone to update, use UPDATE_FORW for forward
+ * lookup zone, use UPDATE_REV for reverse lookup zone
+ * hostname : fully qualified hostname to update DNS with
+ * ip_addr : IP address of hostname
+ * life_time : cached time of this entry by others and not within DNS
+ * database
+ * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry
+ * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all
+ * entries of the same resource name. Only valid for UPDATE_DEL.
+ * key_name : same key name used in TKEY message
+ * id : DNS message ID. If a positive value then this ID value is
+ * used, otherwise the next incremented value is used
+ * level : This is the domain level which we send the request to, level
+ * zero is the default level, it can go upto 2 in reverse zone
+ * and virtually to any level in forward zone.
+ * Returns:
+ * buf : buffer containing update message
+ * id : DNS message ID
+ * int : size of update message
+ * -1 : error
+ */
+static int
+dyndns_build_unsigned_tsig_msg(char *buf, int update_zone, const char *hostname,
+ const char *ip_addr, int life_time, int update_type, int del_type,
+ char *key_name, uint16_t *id, int level)
+{
+ char *bufptr;
+ int buf_sz;
+
+ if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname,
+ ip_addr, life_time, update_type, del_type, 0, id, level)) <= 0) {
+ return (-1);
+ }
+
+ bufptr = buf + buf_sz;
+
+ if (dyndns_build_tsig(&bufptr, BUFLEN_UDP(bufptr, buf), 0,
+ key_name, 300, NULL, 0, TSIG_UNSIGNED) == -1) {
+ return (-1);
+ }
+
+ return (bufptr - buf);
+}
+
+/*
+ * dyndns_build_signed_tsig_msg
+ * This routine build the signed TSIG message which contains the update
+ * request message encrypted. An error time of 300 seconds is used for fudge
+ * time. This is the number used by Microsoft clients.
+ * This routine builds a UDP message.
+ * Parameters:
+ * buf : buffer to build message
+ * update_zone: the type of zone to update, use UPDATE_FORW for forward
+ * lookup zone, use UPDATE_REV for reverse lookup zone
+ * hostname : fully qualified hostname to update DNS with
+ * ip_addr : IP address of hostname
+ * life_time : cached time of this entry by others and not within DNS
+ * database
+ * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry
+ * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all
+ * entries of the same resource name. Only valid for UPDATE_DEL.
+ * key_name : same key name used in TKEY message
+ * id : DNS message ID. If a positive value then this ID value is
+ * used, otherwise the next incremented value is used
+ * in_mic : the update request message encrypted
+ * level : This is the domain level which we send the request to, level
+ * zero is the default level, it can go upto 2 in reverse zone
+ * and virtually to any level in forward zone.
+ *
+ * Returns:
+ * buf : buffer containing update message
+ * id : DNS message ID
+ * int : size of update message
+ * -1 : error
+ */
+static int
+dyndns_build_signed_tsig_msg(char *buf, int update_zone, const char *hostname,
+ const char *ip_addr, int life_time, int update_type, int del_type,
+ char *key_name, uint16_t *id, gss_buffer_desc *in_mic, int level)
+{
+ char *bufptr;
+ int buf_sz;
+
+ if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname,
+ ip_addr, life_time, update_type, del_type, 1, id, level)) <= 0) {
+ return (-1);
+ }
+
+ bufptr = buf + buf_sz;
+
+ if (dyndns_build_tsig(&bufptr, BUFLEN_UDP(bufptr, buf),
+ *id, key_name, 300, in_mic->value,
+ in_mic->length, TSIG_SIGNED) == -1) {
+ return (-1);
+ }
+
+ return (bufptr - buf);
+}
+
+/*
+ * dyndns_udp_send_recv
+ * This routine sends and receives UDP DNS request and reply messages. Time
+ * out value and retry count is indicated by two environment variables:
+ * lookup_dns_retry_cnt
+ * lookup_dns_retry_sec
+ * If either of these two variables are undefined or their value exceed the
+ * value of 10 then a default value of 3 retry and/or a default value of 3
+ * secs are used.
+ *
+ * Pre-condition: Caller must call dyndns_open_init_socket() before calling
+ * this function.
+ *
+ * Parameters:
+ * s : socket descriptor
+ * buf : buffer containing data to send
+ * buf_sz : size of data to send
+ * Returns:
+ * -1 : error
+ * rec_buf: reply dat
+ * 0 : success
+ */
+int
+dyndns_udp_send_recv(int s, char *buf, int buf_sz, char *rec_buf)
+{
+ int i, retval, addr_len, max_retries;
+ struct timeval tv, timeout;
+ fd_set rfds;
+ struct sockaddr_in from_addr;
+ char *p;
+
+ smb_config_rdlock();
+ p = smb_config_getstr(SMB_CI_DYNDNS_RETRY_COUNT);
+ if (p == NULL || *p == 0) {
+ max_retries = 3;
+ } else {
+ max_retries = atoi(p);
+ if (max_retries < 1 || max_retries > 10)
+ max_retries = 3;
+ }
+
+ p = smb_config_getstr(SMB_CI_DYNDNS_RETRY_SEC);
+ timeout.tv_usec = 0;
+ if (p == NULL || *p == 0) {
+ timeout.tv_sec = 3;
+ } else {
+ timeout.tv_sec = atoi(p);
+ if (timeout.tv_sec < 1 || timeout.tv_sec > 10)
+ timeout.tv_sec = 3;
+ }
+ smb_config_unlock();
+
+ for (i = 0; i < max_retries + 1; i++) {
+ if (send(s, buf, buf_sz, 0) == -1) {
+ syslog(LOG_ERR, "dyndns: UDP send error (%s)\n",
+ strerror(errno));
+ return (-1);
+ }
+
+ FD_ZERO(&rfds);
+ FD_SET(s, &rfds);
+
+ tv = timeout;
+
+ retval = select(s+1, &rfds, NULL, NULL, &tv);
+
+ if (retval == -1) {
+ return (-1);
+ } else if (retval > 0) {
+ bzero(rec_buf, NS_PACKETSZ);
+ /* required by recvfrom */
+ addr_len = sizeof (struct sockaddr_in);
+ if (recvfrom(s, rec_buf, NS_PACKETSZ, 0,
+ (struct sockaddr *)&from_addr, &addr_len) == -1) {
+ syslog(LOG_ERR, "dyndns: UDP recv err\n");
+ return (-1);
+ }
+ break;
+ }
+ }
+
+ if (i == (max_retries + 1)) { /* did not receive anything */
+ syslog(LOG_ERR, "dyndns: max retries for UDP recv reached\n");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * dyndns_sec_add_remove_entry
+ * Perform secure dynamic DNS update after getting security context.
+ * This routine opens a UDP socket to the DNS sever, gets the security context,
+ * builds the unsigned TSIG message and signed TSIG message. The signed TSIG
+ * message containing the encrypted update request message is sent to the DNS
+ * server. The response is received and check for error. If there is no
+ * error then credential handle and security context are released and the local
+ * NSS cached is purged.
+ * Parameters:
+ * update_zone : UPDATE_FORW for forward zone, UPDATE_REV for reverse zone
+ * hostname : fully qualified hostname
+ * ip_addr : ip address of hostname in string format
+ * life_time : cached time of this entry by others and not within DNS
+ * database
+ * max_retries : maximum retries for sending DNS update request
+ * recv_timeout: receive timeout
+ * update_type : UPDATE_ADD for adding entry, UPDATE_DEL for removing entry
+ * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all
+ * entries of the same resource name. Only valid for UPDATE_DEL
+ * dns_str : DNS IP address in string format
+ * Returns:
+ * -1: error
+ * 0: success
+ *
+ * This function is enhanced to handle the case of NOTAUTH error when DNS server
+ * is not authoritative for specified zone. In this case we need to resend the
+ * same request to the higher authoritative domains.
+ * This is true for both secure and unsecure dynamic DNS updates.
+ */
+static int
+dyndns_sec_add_remove_entry(int update_zone, const char *hostname,
+ const char *ip_addr, int life_time, int update_type, int del_type,
+ char *dns_str)
+{
+ int s2;
+ uint16_t id, rid;
+ char buf[NS_PACKETSZ], buf2[NS_PACKETSZ];
+ int ret;
+ OM_uint32 min, maj;
+ gss_buffer_desc in_mic, out_mic;
+ gss_ctx_id_t gss_context;
+ int dns_ip;
+ char *key_name;
+ int buf_sz;
+ int level = 0;
+
+ assert(dns_str);
+ assert(*dns_str);
+
+ dns_ip = inet_addr(dns_str);
+
+sec_retry_higher:
+
+ if ((gss_context = dyndns_get_sec_context(hostname,
+ dns_ip)) == NULL) {
+ return (-1);
+ }
+
+ key_name = (char *)hostname;
+
+ if ((s2 = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0) {
+ (void) gss_delete_sec_context(&min, &gss_context, NULL);
+ return (-1);
+ }
+
+ id = 0;
+ if ((buf_sz = dyndns_build_unsigned_tsig_msg(buf, update_zone, hostname,
+ ip_addr, life_time, update_type, del_type,
+ key_name, &id, level)) <= 0) {
+ (void) close(s2);
+ (void) gss_delete_sec_context(&min, &gss_context, NULL);
+ return (-1);
+ }
+
+ in_mic.length = buf_sz;
+ in_mic.value = buf;
+
+ /* sign update message */
+ if ((maj = gss_get_mic(&min, gss_context, 0, &in_mic, &out_mic)) !=
+ GSS_S_COMPLETE) {
+ display_stat(maj, min);
+ (void) close(s2);
+ (void) gss_delete_sec_context(&min, &gss_context, NULL);
+ return (-1);
+ }
+
+ if ((buf_sz = dyndns_build_signed_tsig_msg(buf, update_zone, hostname,
+ ip_addr, life_time, update_type, del_type, key_name, &id,
+ &out_mic, level)) <= 0) {
+ (void) close(s2);
+ (void) gss_release_buffer(&min, &out_mic);
+ (void) gss_delete_sec_context(&min, &gss_context, NULL);
+ return (-1);
+ }
+
+ (void) gss_release_buffer(&min, &out_mic);
+
+ if (dyndns_udp_send_recv(s2, buf, buf_sz, buf2)) {
+ (void) close(s2);
+ (void) gss_delete_sec_context(&min, &gss_context, NULL);
+ return (-1);
+ }
+
+ (void) close(s2);
+
+ (void) gss_delete_sec_context(&min, &gss_context, NULL);
+
+ ret = buf2[3] & 0xf; /* error field in UDP */
+
+ /*
+ * If it is a NOTAUTH error we should retry with higher domains
+ * until we get a successful reply or the maximum retries is met.
+ */
+ if (ret == NOTAUTH && level++ < MAX_AUTH_RETRIES)
+ goto sec_retry_higher;
+
+ /* check here for update request is successful */
+ if (ret != NOERROR) {
+ syslog(LOG_ERR, "dyndns: Error in TSIG reply: %d: ", ret);
+ dyndns_msg_err(ret);
+ return (-1);
+ }
+
+ (void) dyndns_get_nshort(buf2, &rid);
+ if (id != rid)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * dyndns_seach_entry
+ * Query DNS server for entry. This routine can indicate if an entry exist
+ * or not during forward or reverse lookup. Also can indicate if the data
+ * of the entry matched. For example, for forward lookup, the entry is
+ * searched using the hostname and the data is the IP address. For reverse
+ * lookup, the entry is searched using the IP address and the data is the
+ * hostname.
+ * Parameters:
+ * update_zone: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone
+ * hostname : fully qualified hostname
+ * ip_addr : ip address of hostname in string format
+ * update_type: UPDATE_ADD for adding entry, UPDATE_DEL for removing entry
+ * Returns:
+ * time_out: no use
+ * is_match: is 1 for found matching entry, otherwise 0
+ * 1 : an entry exist but not necessarily match
+ * 0 : an entry does not exist
+ */
+/*ARGSUSED*/
+static int
+dyndns_search_entry(int update_zone, const char *hostname, const char *ip_addr,
+ int update_type, struct timeval *time_out, int *is_match)
+{
+ struct hostent *hentry;
+ struct in_addr in;
+ in_addr_t ip;
+ int i;
+
+ *is_match = 0;
+ if (update_zone == UPDATE_FORW) {
+ hentry = gethostbyname(hostname);
+ if (hentry) {
+ ip = inet_addr(ip_addr);
+ for (i = 0; hentry->h_addr_list[i]; i++) {
+ (void) memcpy(&in.s_addr,
+ hentry->h_addr_list[i], sizeof (in.s_addr));
+ if (ip == in.s_addr) {
+ *is_match = 1;
+ break;
+ }
+ }
+ return (1);
+ }
+ } else {
+ int dns_ip = inet_addr(ip_addr);
+ hentry = gethostbyaddr((char *)&dns_ip, 4, AF_INET);
+ if (hentry) {
+ if (strncasecmp(hentry->h_name, hostname,
+ strlen(hostname)) == 0) {
+ *is_match = 1;
+ }
+ return (1);
+ }
+ }
+
+ /* entry does not exist */
+ return (0);
+}
+
+/*
+ * dyndns_add_remove_entry
+ * Perform non-secure dynamic DNS update. If fail then tries secure update.
+ * This routine opens a UDP socket to the DNS sever, build the update request
+ * message, and sends the message to the DNS server. The response is received
+ * and check for error. If there is no error then the local NSS cached is
+ * purged. DNS may be used to check to see if an entry already exist before
+ * adding or to see if an entry does exist before removing it. Adding
+ * duplicate entries or removing non-existing entries does not cause any
+ * problems. DNS is not check when doing a delete all.
+ * Parameters:
+ * update_zone: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone
+ * hostname : fully qualified hostname
+ * ip_addr : ip address of hostname in string format
+ * life_time : cached time of this entry by others and not within DNS
+ * database
+ * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry
+ * do_check : DNS_CHECK to check first in DNS, DNS_NOCHECK for no DNS
+ * checking before update
+ * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all
+ * entries of the same resource name. Only valid for UPDATE_DEL.
+ * dns_str : DNS IP address in string format
+ * Returns:
+ * -1: error
+ * 0: success
+ *
+ * This function is enhanced to handle the case of NOTAUTH error when DNS server
+ * is not authoritative for specified zone. In this case we need to resend the
+ * same request to the higher authoritative domains.
+ * This is true for both secure and unsecure dynamic DNS updates.
+ */
+static int
+dyndns_add_remove_entry(int update_zone, const char *hostname,
+ const char *ip_addr, int life_time, int update_type,
+ int do_check, int del_type, char *dns_str)
+{
+ int s;
+ uint16_t id, rid;
+ char buf[NS_PACKETSZ], buf2[NS_PACKETSZ];
+ int ret, dns_ip;
+ int is_exist, is_match;
+ struct timeval timeout;
+ int buf_sz;
+ int level = 0;
+
+ assert(dns_str);
+ assert(*dns_str);
+
+ dns_ip = inet_addr(dns_str);
+
+ if (do_check == DNS_CHECK && del_type != DEL_ALL) {
+ is_exist = dyndns_search_entry(update_zone, hostname, ip_addr,
+ update_type, &timeout, &is_match);
+
+ if (update_type == UPDATE_ADD && is_exist && is_match) {
+ return (0);
+ } else if (update_type == UPDATE_DEL && !is_exist) {
+ return (0);
+ }
+ }
+
+retry_higher:
+ if ((s = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0) {
+ return (-1);
+ }
+
+ id = 0;
+ if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname,
+ ip_addr, life_time, update_type, del_type, 0, &id, level)) <= 0) {
+ (void) close(s);
+ return (-1);
+ }
+
+ if (dyndns_udp_send_recv(s, buf, buf_sz, buf2)) {
+ (void) close(s);
+ return (-1);
+ }
+
+ (void) close(s);
+
+ ret = buf2[3] & 0xf; /* error field in UDP */
+
+ /*
+ * If it is a NOTAUTH error we should retry with higher domains
+ * until we get a successful reply
+ */
+ if (ret == NOTAUTH && level++ < MAX_AUTH_RETRIES)
+ goto retry_higher;
+
+ /* check here for update request is successful */
+ if (ret == NOERROR) {
+ (void) dyndns_get_nshort(buf2, &rid);
+ if (id != rid)
+ return (-1);
+ return (0);
+ }
+
+ if (ret == NOTIMP) {
+ syslog(LOG_ERR, "dyndns: DNS does not "
+ "support dynamic update\n");
+ return (-1);
+ } else if (ret == NOTAUTH) {
+ syslog(LOG_ERR, "dyndns: DNS is not authoritative for "
+ "zone name in zone section\n");
+ return (-1);
+ }
+
+ ret = dyndns_sec_add_remove_entry(update_zone, hostname,
+ ip_addr, life_time, update_type, del_type, dns_str);
+
+ return (ret);
+}
+
+/*
+ * dyndns_add_entry
+ * Main routine to add an entry into DNS. The attempt will be made on the
+ * the servers returned by smb_get_nameserver(). Upon a successful
+ * attempt on any one of the server, the function will exit with 0.
+ * Otherwise, -1 is retuned to indicate the update attempt on all the
+ * nameservers has failed.
+ *
+ * Parameters:
+ * update_zone: the type of zone to update, use UPDATE_FORW for forward
+ * lookup zone, use UPDATE_REV for reverse lookup zone
+ * hostname : fully qualified hostname
+ * ip_addr : ip address of hostname in string format
+ * life_time : cached time of this entry by others and not within DNS
+ * database
+ * Returns:
+ * -1: error
+ * 0: success
+ */
+static int
+dyndns_add_entry(int update_zone, const char *hostname, const char *ip_addr,
+ int life_time)
+{
+ char *dns_str;
+ struct in_addr ns_list[MAXNS];
+ int i, cnt;
+ int addr, rc = 0;
+
+ if (hostname == NULL || ip_addr == NULL) {
+ return (-1);
+ }
+
+ addr = (int)inet_addr(ip_addr);
+ if ((addr == -1) || (addr == 0)) {
+ return (-1);
+ }
+
+ cnt = smb_get_nameservers(ns_list, MAXNS);
+
+ for (i = 0; i < cnt; i++) {
+ dns_str = inet_ntoa(ns_list[i]);
+ if ((dns_str == NULL) ||
+ (strcmp(dns_str, "0.0.0.0") == 0)) {
+ continue;
+ }
+
+ if (update_zone == UPDATE_FORW) {
+ syslog(LOG_DEBUG, "Dynamic update on forward lookup "
+ "zone for %s (%s)...\n", hostname, ip_addr);
+ } else {
+ syslog(LOG_DEBUG, "Dynamic update on reverse lookup "
+ "zone for %s (%s)...\n", hostname, ip_addr);
+ }
+ if (dyndns_add_remove_entry(update_zone, hostname,
+ ip_addr, life_time,
+ UPDATE_ADD, DNS_NOCHECK, DEL_NONE, dns_str) != -1) {
+ rc = 1;
+ break;
+ }
+ }
+
+ return (rc ? 0 : -1);
+}
+
+/*
+ * dyndns_remove_entry
+ * Main routine to remove an entry or all entries of the same resource name
+ * from DNS. The update attempt will be made on the primary DNS server. If
+ * there is a failure then another attempt will be made on the secondary DNS
+ * server.
+ * Parameters:
+ * update_zone: the type of zone to update, use UPDATE_FORW for forward
+ * lookup zone, use UPDATE_REV for reverse lookup zone
+ * hostname : fully qualified hostname
+ * ip_addr : ip address of hostname in string format
+ * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all
+ * entries of the same resource name. Only valid for UPDATE_DEL
+ * Returns:
+ * -1: error
+ * 0: success
+ */
+static int
+dyndns_remove_entry(int update_zone, const char *hostname, const char *ip_addr,
+ int del_type)
+{
+ char *dns_str;
+ struct in_addr ns_list[MAXNS];
+ int i, cnt, scnt;
+ int addr;
+
+ if ((hostname == NULL || ip_addr == NULL)) {
+ return (-1);
+ }
+
+ addr = (int)inet_addr(ip_addr);
+ if ((addr == -1) || (addr == 0)) {
+ return (-1);
+ }
+
+ cnt = smb_get_nameservers(ns_list, MAXNS);
+ scnt = 0;
+
+ for (i = 0; i < cnt; i++) {
+ dns_str = inet_ntoa(ns_list[i]);
+ if ((dns_str == NULL) ||
+ (strcmp(dns_str, "0.0.0.0") == 0)) {
+ continue;
+ }
+
+ if (update_zone == UPDATE_FORW) {
+ if (del_type == DEL_ONE) {
+ syslog(LOG_DEBUG, "Dynamic update "
+ "on forward lookup "
+ "zone for %s (%s)...\n", hostname, ip_addr);
+ } else {
+ syslog(LOG_DEBUG, "Removing all "
+ "entries of %s "
+ "in forward lookup zone...\n", hostname);
+ }
+ } else {
+ if (del_type == DEL_ONE) {
+ syslog(LOG_DEBUG, "Dynamic update "
+ "on reverse lookup "
+ "zone for %s (%s)...\n", hostname, ip_addr);
+ } else {
+ syslog(LOG_DEBUG, "Removing all "
+ "entries of %s "
+ "in reverse lookup zone...\n", ip_addr);
+ }
+ }
+ if (dyndns_add_remove_entry(update_zone, hostname, ip_addr, 0,
+ UPDATE_DEL, DNS_NOCHECK, del_type, dns_str) != -1) {
+ scnt++;
+ break;
+ }
+ }
+ if (scnt)
+ return (0);
+ return (-1);
+}
+
+/*
+ * dyndns_update
+ * Perform dynamic update on both forward and reverse lookup zone using
+ * current hostname and IP addresses. Before updating DNS, existing host
+ * entries with the same hostname in the forward lookup zone are removed
+ * and existing pointer entries with the same IP addresses in the reverse
+ * lookup zone are removed. After DNS update, host entries for current
+ * hostname will show current IP addresses and pointer entries for current
+ * IP addresses will show current hostname.
+ * Parameters:
+ * None
+ * Returns:
+ * -1: some dynamic DNS updates errors
+ * 0: successful
+ */
+int
+dyndns_update(void)
+{
+ int i, forw_update_ok, error;
+ char fqdn[MAXHOSTNAMELEN];
+ char *my_ip;
+ int nc_cnt;
+ struct in_addr addr;
+ int rc;
+
+ if (!dyndns_enabled())
+ return (-1);
+
+ if (smb_getfqhostname(fqdn, MAXHOSTNAMELEN) != 0)
+ return (-1);
+
+ nc_cnt = smb_nic_get_num();
+
+ error = 0;
+ forw_update_ok = 0;
+
+ /*
+ * Dummy IP is okay since we are removing all using the hostname.
+ */
+ if (dyndns_remove_entry(UPDATE_FORW, fqdn, "1.1.1.1", DEL_ALL) == 0) {
+ forw_update_ok = 1;
+ } else {
+ error++;
+ }
+
+ for (i = 0; i < nc_cnt; i++) {
+ net_cfg_t cfg;
+ if (smb_nic_get_byind(i, &cfg) == NULL)
+ break;
+ addr.s_addr = cfg.ip;
+ if (addr.s_addr == 0)
+ continue;
+ if (smb_nic_status(cfg.ifname, IFF_STANDBY) ||
+ smb_nic_status(cfg.ifname, IFF_PRIVATE))
+ continue;
+
+ my_ip = (char *)strdup(inet_ntoa(addr));
+ if (my_ip == NULL) {
+ error++;
+ continue;
+ }
+
+ if (forw_update_ok) {
+ rc = dyndns_add_entry(UPDATE_FORW, fqdn, my_ip,
+ DDNS_TTL);
+
+ if (rc == -1)
+ error++;
+ }
+
+ rc = dyndns_remove_entry(UPDATE_REV, fqdn, my_ip, DEL_ALL);
+ if (rc == 0) {
+ rc = dyndns_add_entry(UPDATE_REV, fqdn, my_ip,
+ DDNS_TTL);
+ }
+
+ if (rc == -1)
+ error++;
+
+ (void) free(my_ip);
+ }
+
+ return ((error == 0) ? 0 : -1);
+}
+
+/*
+ * dyndns_clear_rev_zone
+ * Clear the rev zone records. Must be called to clear the OLD if list
+ * of down records prior to updating the list with new information.
+ *
+ * Parameters:
+ * None
+ * Returns:
+ * -1: some dynamic DNS updates errors
+ * 0: successful
+ */
+int
+dyndns_clear_rev_zone(void)
+{
+ int i, error;
+ char fqdn[MAXHOSTNAMELEN];
+ char *my_ip;
+ int nc_cnt;
+ struct in_addr addr;
+ int rc;
+
+ if (!dyndns_enabled())
+ return (-1);
+
+ if (smb_getfqhostname(fqdn, MAXHOSTNAMELEN) != 0)
+ return (-1);
+
+ nc_cnt = smb_nic_get_num();
+
+ error = 0;
+
+ for (i = 0; i < nc_cnt; i++) {
+ net_cfg_t cfg;
+ if (smb_nic_get_byind(i, &cfg) == NULL)
+ break;
+ addr.s_addr = cfg.ip;
+ if (addr.s_addr == 0)
+ continue;
+ if (smb_nic_status(cfg.ifname, IFF_STANDBY) ||
+ smb_nic_status(cfg.ifname, IFF_PRIVATE))
+ continue;
+
+ my_ip = (char *)strdup(inet_ntoa(addr));
+ if (my_ip == NULL) {
+ error++;
+ continue;
+ }
+
+ rc = dyndns_remove_entry(UPDATE_REV, fqdn, my_ip, DEL_ALL);
+ if (rc != 0)
+ error++;
+
+ (void) free(my_ip);
+ }
+
+ return ((error == 0) ? 0 : -1);
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.h b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.h
new file mode 100644
index 0000000000..7140eb4d59
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.h
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_DYNDNS_H
+#define _SMBSRV_DYNDNS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/libsmbns.h>
+
+/*
+ * Header section format:
+ *
+ * The header contains the following fields:
+ *
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ID |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QDCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ANCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | NSCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ARCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *
+ * where:
+ *
+ * ID A 16 bit identifier assigned by the program that
+ * generates any kind of query. This identifier is copied
+ * the corresponding reply and can be used by the requester
+ * to match up replies to outstanding queries.
+ *
+ * QR A one bit field that specifies whether this message is a
+ * query (0), or a response (1).
+ *
+ * OPCODE A four bit field that specifies kind of query in this
+ * message. This value is set by the originator of a query
+ * and copied into the response. The values are:
+ *
+ * 0 a standard query (QUERY)
+ *
+ * 1 an inverse query (IQUERY)
+ *
+ * 2 a server status request (STATUS)
+ *
+ * 3-15 reserved for future use
+ *
+ * AA Authoritative Answer - this bit is valid in responses,
+ * and specifies that the responding name server is an
+ * authority for the domain name in question section.
+ *
+ * Note that the contents of the answer section may have
+ * multiple owner names because of aliases. The AA bit
+ *
+ * corresponds to the name which matches the query name, or
+ * the first owner name in the answer section.
+ *
+ * TC TrunCation - specifies that this message was truncated
+ * due to length greater than that permitted on the
+ * transmission channel.
+ *
+ * RD Recursion Desired - this bit may be set in a query and
+ * is copied into the response. If RD is set, it directs
+ * the name server to pursue the query recursively.
+ * Recursive query support is optional.
+ *
+ * RA Recursion Available - this be is set or cleared in a
+ * response, and denotes whether recursive query support is
+ * available in the name server.
+ *
+ * Z Reserved for future use. Must be zero in all queries
+ * and responses.
+ *
+ * RCODE Response code - this 4 bit field is set as part of
+ * responses. The values have the following
+ * interpretation:
+ *
+ * 0 No error condition
+ *
+ * 1 Format error - The name server was
+ * unable to interpret the query.
+ *
+ * 2 Server failure - The name server was
+ * unable to process this query due to a
+ * problem with the name server.
+ *
+ * 3 Name Error - Meaningful only for
+ * responses from an authoritative name
+ * server, this code signifies that the
+ * domain name referenced in the query does
+ * not exist.
+ *
+ * 4 Not Implemented - The name server does
+ * not support the requested kind of query.
+ *
+ * 5 Refused - The name server refuses to
+ * perform the specified operation for
+ * policy reasons. For example, a name
+ * server may not wish to provide the
+ * information to the particular requester,
+ * or a name server may not wish to perform
+ * a particular operation (e.g., zone
+ *
+ * transfer) for particular data.
+ *
+ * 6-15 Reserved for future use.
+ *
+ * QDCOUNT an unsigned 16 bit integer specifying the number of
+ * entries in the question section.
+ *
+ * ANCOUNT an unsigned 16 bit integer specifying the number of
+ * resource records in the answer section.
+ *
+ * NSCOUNT an unsigned 16 bit integer specifying the number of name
+ * server resource records in the authority records
+ * section.
+ *
+ * ARCOUNT an unsigned 16 bit integer specifying the number of
+ * resource records in the additional records section.
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Other definitions: */
+#define REQ_QUERY 1 /* DNS query request */
+#define REQ_UPDATE 0 /* DNS update request */
+#define UPDATE_FORW 1 /* Update forward lookup zone */
+#define UPDATE_REV 0 /* Update reverse lookup zone */
+#define UPDATE_ADD 1 /* Update add request */
+#define UPDATE_DEL 0 /* Update remove request */
+#define MODE_GSS_API 3 /* Key negotiation mode */
+
+/* Max buffer size for send and receive buffer */
+#define MAX_BUF_SIZE 2000
+#define MAX_RETRIES 3 /* Max number of send retries if no response */
+#define TSIG_SIGNED 1 /* TSIG contains signed data */
+#define TSIG_UNSIGNED 0 /* TSIG does not conain signed data */
+#define DNS_CHECK 1 /* Check DNS for entry */
+#define DNS_NOCHECK 0 /* Don't check DNS for entry */
+#define MAX_TCP_SIZE 2000 /* max tcp DNS message size */
+
+/* Delete 1 entry */
+#define DEL_ONE 1
+/* Delete all entries of the same resource name */
+#define DEL_ALL 0
+
+#define DNSF_RECUR_SUPP 0x80 /* Server can do recursive queries */
+#define DNSF_RECUR_QRY 0x100 /* Query is recursive */
+
+#define BUFLEN_TCP(x, y) (MAX_TCP_SIZE-(x-y))
+#define BUFLEN_UDP(x, y) (NS_PACKETSZ-(x-y))
+
+extern char *dyndns_get_nshort(char *, uint16_t *);
+extern char *dyndns_get_int(char *, int *);
+extern int dyndns_build_header(char **, int, uint16_t, int,
+ uint16_t, uint16_t, uint16_t, uint16_t, int);
+extern int dyndns_build_quest_zone(char **, int, char *, int, int);
+extern int dyndns_open_init_socket(int sock_type, unsigned long dest_addr,
+ int port);
+extern int dyndns_udp_send_recv(int, char *, int, char *);
+extern void dyndns_msg_err(int);
+
+/*
+ * DDNS_TTL is the time to live in DNS caches. Note that this
+ * does not affect the entry in the authoritative DNS database.
+ */
+#define DDNS_TTL 1200
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_DYNDNS_H */
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.c
new file mode 100644
index 0000000000..c1a2de7913
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.c
@@ -0,0 +1,543 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Initialize a credentials cache.
+ */
+#include <kerberosv5/krb5.h>
+#include <kerberosv5/com_err.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <locale.h>
+#include <strings.h>
+#include <sys/synch.h>
+#include <gssapi/gssapi.h>
+
+#include <smbsrv/libsmbns.h>
+
+#include <smbns_krb.h>
+
+static int krb5_acquire_cred_kinit_main();
+
+typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
+
+struct k_opts {
+ /* in seconds */
+ krb5_deltat starttime;
+ krb5_deltat lifetime;
+ krb5_deltat rlife;
+
+ int forwardable;
+ int proxiable;
+ int addresses;
+
+ int not_forwardable;
+ int not_proxiable;
+ int no_addresses;
+
+ int verbose;
+
+ char *principal_name;
+ char *principal_passwd;
+ char *service_name;
+ char *keytab_name;
+ char *k5_cache_name;
+ char *k4_cache_name;
+
+ action_type action;
+};
+
+struct k5_data {
+ krb5_context ctx;
+ krb5_ccache cc;
+ krb5_principal me;
+ char *name;
+};
+
+static int
+k5_begin(struct k_opts *opts, struct k5_data *k5)
+{
+ int code;
+ code = krb5_init_context(&k5->ctx);
+ if (code) {
+ return (code);
+ }
+
+ if ((code = krb5_cc_default(k5->ctx, &k5->cc))) {
+ return (code);
+ }
+
+ /* Use specified name */
+ if ((code = krb5_parse_name(k5->ctx, opts->principal_name, &k5->me))) {
+ return (code);
+ }
+
+ code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
+ if (code) {
+ return (code);
+ }
+ opts->principal_name = k5->name;
+
+ return (0);
+}
+
+static void
+k5_end(struct k5_data *k5)
+{
+ if (k5->name)
+ krb5_free_unparsed_name(k5->ctx, k5->name);
+ if (k5->me)
+ krb5_free_principal(k5->ctx, k5->me);
+ if (k5->cc)
+ krb5_cc_close(k5->ctx, k5->cc);
+ if (k5->ctx)
+ krb5_free_context(k5->ctx);
+ (void) memset(k5, 0, sizeof (*k5));
+}
+
+static int
+k5_kinit(struct k_opts *opts, struct k5_data *k5)
+{
+ int notix = 1;
+ krb5_keytab keytab = 0;
+ krb5_creds my_creds;
+ krb5_error_code code = 0;
+ krb5_get_init_creds_opt options;
+ const char *errmsg;
+
+ krb5_get_init_creds_opt_init(&options);
+ (void) memset(&my_creds, 0, sizeof (my_creds));
+
+ /*
+ * From this point on, we can goto cleanup because my_creds is
+ * initialized.
+ */
+ if (opts->lifetime)
+ krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime);
+ if (opts->rlife)
+ krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife);
+ if (opts->forwardable)
+ krb5_get_init_creds_opt_set_forwardable(&options, 1);
+ if (opts->not_forwardable)
+ krb5_get_init_creds_opt_set_forwardable(&options, 0);
+ if (opts->proxiable)
+ krb5_get_init_creds_opt_set_proxiable(&options, 1);
+ if (opts->not_proxiable)
+ krb5_get_init_creds_opt_set_proxiable(&options, 0);
+ if (opts->addresses) {
+ krb5_address **addresses = NULL;
+ code = krb5_os_localaddr(k5->ctx, &addresses);
+ if (code != 0) {
+ errmsg = error_message(code);
+ syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "k5_kinit: "
+ "getting local addresses (%s)"), errmsg);
+ goto cleanup;
+ }
+ krb5_get_init_creds_opt_set_address_list(&options, addresses);
+ }
+ if (opts->no_addresses)
+ krb5_get_init_creds_opt_set_address_list(&options, NULL);
+
+ if ((opts->action == INIT_KT) && opts->keytab_name) {
+ code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab);
+ if (code != 0) {
+ errmsg = error_message(code);
+ syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "k5_kinit: "
+ "resolving keytab %s (%s)"), errmsg,
+ opts->keytab_name);
+ goto cleanup;
+ }
+ }
+
+ switch (opts->action) {
+ case INIT_PW:
+ code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me,
+ opts->principal_passwd, NULL, 0, opts->starttime,
+ opts->service_name, &options);
+ break;
+ case INIT_KT:
+ code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me,
+ keytab, opts->starttime, opts->service_name, &options);
+ break;
+ case VALIDATE:
+ code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me,
+ k5->cc, opts->service_name);
+ break;
+ case RENEW:
+ code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me,
+ k5->cc, opts->service_name);
+ break;
+ }
+
+ if (code) {
+ char *doing = 0;
+ switch (opts->action) {
+ case INIT_PW:
+ case INIT_KT:
+ doing = dgettext(TEXT_DOMAIN, "k5_kinit: "
+ "getting initial credentials");
+ break;
+ case VALIDATE:
+ doing = dgettext(TEXT_DOMAIN, "k5_kinit: "
+ "validating credentials");
+ break;
+ case RENEW:
+ doing = dgettext(TEXT_DOMAIN, "k5_kinit: "
+ "renewing credentials");
+ break;
+ }
+
+ /*
+ * If got code == KRB5_AP_ERR_V4_REPLY && got_k4, we should
+ * let the user know that maybe he/she wants -4.
+ */
+ if (code == KRB5KRB_AP_ERR_V4_REPLY) {
+ syslog(LOG_ERR, "%s\n"
+ "The KDC doesn't support v5. "
+ "You may want the -4 option in the future", doing);
+ return (1);
+ } else if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+ syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "%s "
+ "(Password incorrect)"), doing);
+ } else {
+ errmsg = error_message(code);
+ syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "%s (%s)"),
+ doing, errmsg);
+ }
+ goto cleanup;
+ }
+
+ if (!opts->lifetime) {
+ /* We need to figure out what lifetime to use for Kerberos 4. */
+ opts->lifetime = my_creds.times.endtime -
+ my_creds.times.authtime;
+ }
+
+ code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me);
+ if (code) {
+ errmsg = error_message(code);
+ syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "k5_kinit: "
+ "initializing cache %s (%s)"),
+ opts->k5_cache_name?opts->k5_cache_name:"", errmsg);
+ goto cleanup;
+ }
+
+ code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds);
+ if (code) {
+ errmsg = error_message(code);
+ syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "k5_kinit: "
+ "storing credentials (%s)"), errmsg);
+ goto cleanup;
+ }
+
+ notix = 0;
+
+ cleanup:
+ if (my_creds.client == k5->me) {
+ my_creds.client = 0;
+ }
+ krb5_free_cred_contents(k5->ctx, &my_creds);
+ if (keytab)
+ krb5_kt_close(k5->ctx, keytab);
+ return (notix?0:1);
+}
+
+int
+smb_kinit(char *user, char *passwd)
+{
+ struct k_opts opts;
+ struct k5_data k5;
+ int authed_k5 = 0;
+
+ (void) memset(&opts, 0, sizeof (opts));
+ opts.action = INIT_PW;
+ opts.principal_name = strdup(user);
+ opts.principal_passwd = strdup(passwd);
+
+ (void) memset(&k5, 0, sizeof (k5));
+
+ if (k5_begin(&opts, &k5) != 0) {
+ syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "smb_kinit: "
+ "NOT Authenticated to Kerberos v5 k5_begin failed\n"));
+ return (0);
+ }
+
+ authed_k5 = k5_kinit(&opts, &k5);
+ if (authed_k5) {
+ syslog(LOG_DEBUG, dgettext(TEXT_DOMAIN, "smb_kinit: "
+ "Authenticated to Kerberos v5\n"));
+ } else {
+ syslog(LOG_DEBUG, dgettext(TEXT_DOMAIN, "smb_kinit: "
+ "NOT Authenticated to Kerberos v5\n"));
+ }
+
+ k5_end(&k5);
+
+ return (authed_k5);
+}
+
+/*
+ * krb5_display_stat
+ * Display error message for GSS-API routines.
+ * Parameters:
+ * maj : GSS major status
+ * min : GSS minor status
+ * caller_mod: module name that calls this routine so that the module name
+ * can be displayed with the error messages
+ * Returns:
+ * None
+ */
+static void
+krb5_display_stat(OM_uint32 maj, OM_uint32 min, char *caller_mod)
+{
+ gss_buffer_desc msg;
+ OM_uint32 msg_ctx = 0;
+ OM_uint32 min2;
+ (void) gss_display_status(&min2, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ syslog(LOG_ERR, "%s: major status error: %s\n",
+ caller_mod, (char *)msg.value);
+ (void) gss_display_status(&min2, min, GSS_C_MECH_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ syslog(LOG_ERR, "%s: minor status error: %s\n",
+ caller_mod, (char *)msg.value);
+}
+
+/*
+ * krb5_acquire_cred_kinit
+ *
+ * Wrapper for krb5_acquire_cred_kinit_main with mutex to protect credential
+ * cache file when calling krb5_acquire_cred or kinit.
+ */
+
+int
+krb5_acquire_cred_kinit(char *user, char *pwd, gss_cred_id_t *cred_handle,
+ gss_OID *oid, int *kinit_retry, char *caller_mod)
+{
+ int ret;
+
+ ret = krb5_acquire_cred_kinit_main(user, pwd,
+ cred_handle, oid, kinit_retry, caller_mod);
+ return (ret);
+}
+
+/*
+ * krb5_acquire_cred_kinit_main
+ *
+ * This routine is called both by ADS and Dyn DNS modules to get a handle to
+ * administrative user's credential stored locally on the system. The
+ * credential is the TGT. If the attempt at getting handle fails then a second
+ * attempt will be made after getting a new TGT.
+ *
+ * Paramters:
+ * user : username to retrieve a handle to its credential
+ * pwd : password of username in case obtaining a new TGT is needed
+ * kinit_retry: if 0 then a second attempt will be made to get handle to the
+ * credential if the first attempt fails
+ * caller_mod : name of module that call this routine so that the module name
+ * can be included with error messages
+ * Returns:
+ * cred_handle: handle to the administrative user's credential (TGT)
+ * oid : contains Kerberos 5 object identifier
+ * kinit_retry: A 1 indicates that a second attempt has been made to get
+ * handle to the credential and no further attempts can be made
+ * -1 : error
+ * 0 : success
+ */
+static int
+krb5_acquire_cred_kinit_main(char *user, char *pwd, gss_cred_id_t *cred_handle,
+ gss_OID *oid, int *kinit_retry, char *caller_mod)
+{
+ OM_uint32 maj, min;
+ gss_name_t desired_name;
+ gss_OID_set desired_mechs;
+ gss_buffer_desc oidstr, name_buf;
+ char str[50], user_name[50];
+
+ acquire_cred:
+
+ /* Object Identifier for Kerberos 5 */
+ (void) strcpy(str, "{ 1 2 840 113554 1 2 2 }");
+ oidstr.value = str;
+ oidstr.length = strlen(str);
+ if ((maj = gss_str_to_oid(&min, &oidstr, oid)) != GSS_S_COMPLETE) {
+ krb5_display_stat(maj, min, caller_mod);
+ return (-1);
+ }
+ if ((maj = gss_create_empty_oid_set(&min, &desired_mechs))
+ != GSS_S_COMPLETE) {
+ krb5_display_stat(maj, min, caller_mod);
+ (void) gss_release_oid(&min, oid);
+ return (-1);
+ }
+ if ((maj = gss_add_oid_set_member(&min, *oid, &desired_mechs))
+ != GSS_S_COMPLETE) {
+ krb5_display_stat(maj, min, caller_mod);
+ (void) gss_release_oid(&min, oid);
+ (void) gss_release_oid_set(&min, &desired_mechs);
+ return (-1);
+ }
+
+ (void) strcpy(user_name, user);
+ name_buf.value = user_name;
+ name_buf.length = strlen(user_name)+1;
+ if ((maj = gss_import_name(&min, &name_buf, GSS_C_NT_USER_NAME,
+ &desired_name)) != GSS_S_COMPLETE) {
+ krb5_display_stat(maj, min, caller_mod);
+ (void) gss_release_oid(&min, oid);
+ (void) gss_release_oid_set(&min, &desired_mechs);
+ return (-1);
+ }
+
+ if ((maj = gss_acquire_cred(&min, desired_name, 0, desired_mechs,
+ GSS_C_INITIATE, cred_handle, NULL, NULL)) != GSS_S_COMPLETE) {
+ if (!*kinit_retry) {
+ (void) gss_release_oid(&min, oid);
+ (void) gss_release_oid_set(&min, &desired_mechs);
+ (void) gss_release_name(&min, &desired_name);
+ syslog(LOG_ERR, "%s: Retry kinit to "
+ "acquire credential.\n", caller_mod);
+ (void) smb_kinit(user, pwd);
+ *kinit_retry = 1;
+ goto acquire_cred;
+ } else {
+ krb5_display_stat(maj, min, caller_mod);
+ (void) gss_release_oid(&min, oid);
+ (void) gss_release_oid_set(&min, &desired_mechs);
+ (void) gss_release_name(&min, &desired_name);
+ return (-1);
+ }
+ }
+ (void) gss_release_oid_set(&min, &desired_mechs);
+ (void) gss_release_name(&min, &desired_name);
+
+ return (0);
+}
+
+/*
+ * krb5_establish_sec_ctx_kinit
+ *
+ * This routine is called by both the ADS and Dyn DNS modules to establish a
+ * security context before ADS or Dyn DNS updates are allowed. If establishing
+ * a security context fails for any reason, a second attempt will be made after
+ * a new TGT is obtained. This routine is called many time as needed until
+ * a security context is established.
+ *
+ * The resources use for the security context must be released if security
+ * context establishment process fails.
+ * Parameters:
+ * user : user used in establishing a security context for. Is used for
+ * obtaining a new TGT for a second attempt at establishing
+ * security context
+ * pwd : password of above user
+ * cred_handle: a handle to the user credential (TGT) stored locally
+ * gss_context: initially set to GSS_C_NO_CONTEXT but will contain a handle
+ * to a security context
+ * target_name: contains service name to establish a security context with,
+ * ie ldap or dns
+ * gss_flags : flags used in establishing security context
+ * inputptr : initially set to GSS_C_NO_BUFFER but will be token data
+ * received from service's server to be processed to generate
+ * further token to be sent back to service's server during
+ * security context establishment
+ * kinit_retry: if 0 then a second attempt will be made to get handle to the
+ * credential if the first attempt fails
+ * caller_mod : name of module that call this routine so that the module name
+ * can be included with error messages
+ * Returns:
+ * gss_context : a handle to a security context
+ * out_tok : token data to be sent to service's server to establish
+ * security context
+ * ret_flags : return flags
+ * time_rec : valid time for security context, not currently used
+ * kinit_retry : A 1 indicates that a second attempt has been made to get
+ * handle to the credential and no further attempts can be
+ * made
+ * do_acquire_cred: A 1 indicates that a new handle to the local credential
+ * is needed for second attempt at security context
+ * establishment
+ * maj : major status code used if determining is security context
+ * establishment is successful
+ */
+int
+krb5_establish_sec_ctx_kinit(char *user, char *pwd,
+ gss_cred_id_t cred_handle, gss_ctx_id_t *gss_context,
+ gss_name_t target_name, gss_OID oid, int gss_flags,
+ gss_buffer_desc *inputptr, gss_buffer_desc* out_tok,
+ OM_uint32 *ret_flags, OM_uint32 *time_rec,
+ int *kinit_retry, int *do_acquire_cred,
+ OM_uint32 *maj, char *caller_mod)
+{
+ OM_uint32 min;
+
+ *maj = gss_init_sec_context(&min, cred_handle, gss_context,
+ target_name, oid, gss_flags, 0, NULL, inputptr, NULL,
+ out_tok, ret_flags, time_rec);
+ if (*maj != GSS_S_COMPLETE && *maj != GSS_S_CONTINUE_NEEDED) {
+ if (*gss_context != NULL)
+ (void) gss_delete_sec_context(&min, gss_context, NULL);
+
+ if (!*kinit_retry) {
+ syslog(LOG_ERR, "%s: Retry kinit to establish "
+ "security context.\n", caller_mod);
+ (void) smb_kinit(user, pwd);
+ *kinit_retry = 1;
+ *do_acquire_cred = 1;
+ return (-1);
+ } else {
+ krb5_display_stat(*maj, min, caller_mod);
+ return (-1);
+ }
+ }
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h
new file mode 100644
index 0000000000..22028fcdb5
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMB_KRB5_H
+#define _SMBSRV_SMB_KRB5_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <gssapi/gssapi.h>
+#include <kerberosv5/krb5.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern gss_OID gss_nt_user_name;
+extern gss_OID gss_nt_machine_uid_name;
+extern gss_OID gss_nt_string_uid_name;
+extern gss_OID gss_nt_service_name;
+extern gss_OID gss_nt_exported_name;
+extern gss_OID gss_nt_service_name_v2;
+
+int krb5_acquire_cred_kinit(char *, char *, gss_cred_id_t *,
+ gss_OID *, int *, char *);
+int krb5_establish_sec_ctx_kinit(char *, char *, gss_cred_id_t,
+ gss_ctx_id_t *, gss_name_t, gss_OID, int, gss_buffer_desc *,
+ gss_buffer_desc *, OM_uint32 *, OM_uint32 *, int *,
+ int *, OM_uint32 *, char *);
+int smb_krb5_ctx_init(krb5_context *ctx);
+void smb_krb5_ctx_fini(krb5_context ctx);
+int smb_krb5_get_principal(krb5_context ctx, char *princ_str,
+ krb5_principal *princ);
+int smb_krb5_setpwd(krb5_context ctx, krb5_principal princ, char *passwd);
+int smb_krb5_write_keytab(krb5_context ctx, krb5_principal princ,
+ char *fname, krb5_kvno kvno, char *passwd, krb5_enctype *enctypes,
+ int enctype_count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_KRB5_H */
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c
new file mode 100644
index 0000000000..a6c99799d1
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <kerberosv5/krb5.h>
+
+static int smb_krb5_ktadd(krb5_context ctx, krb5_keytab kt,
+ const krb5_principal princ, krb5_enctype enctype, krb5_kvno kvno,
+ const char *pw);
+
+/*
+ * smb_krb5_ctx_init
+ *
+ * Initialize the kerberos context.
+ * Return 0 on success. Otherwise, return -1.
+ */
+int
+smb_krb5_ctx_init(krb5_context *ctx)
+{
+ if (krb5_init_context(ctx) != 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * smb_krb5_get_principal
+ *
+ * Setup the krb5_principal given the host principal in string format.
+ * Return 0 on success. Otherwise, return -1.
+ */
+int
+smb_krb5_get_principal(krb5_context ctx, char *princ_str, krb5_principal *princ)
+{
+ if (krb5_parse_name(ctx, princ_str, princ) != 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * smb_krb5_ctx_fini
+ *
+ * Free the kerberos context.
+ */
+void
+smb_krb5_ctx_fini(krb5_context ctx)
+{
+ krb5_free_context(ctx);
+}
+
+/*
+ * smb_ksetpw
+ *
+ * Set the workstation trust account password.
+ * Returns 0 on success. Otherwise, returns non-zero value.
+ */
+int
+smb_krb5_setpwd(krb5_context ctx, krb5_principal princ, char *passwd)
+{
+ krb5_error_code code;
+ krb5_ccache cc = NULL;
+ int result_code;
+ krb5_data result_code_string, result_string;
+
+ (void) memset(&result_code_string, 0, sizeof (result_code_string));
+ (void) memset(&result_string, 0, sizeof (result_string));
+
+ if ((code = krb5_cc_default(ctx, &cc)) != 0) {
+ syslog(LOG_ERR, "smb_krb5_setpwd: failed to find a ccache\n");
+ return (-1);
+ }
+
+ code = krb5_set_password_using_ccache(ctx, cc, passwd, princ,
+ &result_code, &result_code_string, &result_string);
+
+ krb5_cc_close(ctx, cc);
+
+ if (code != 0)
+ (void) syslog(LOG_ERR,
+ "smb_krb5_setpwd: Result: %.*s (%d) %.*s\n",
+ result_code == 0 ?
+ strlen("success") : result_code_string.length,
+ result_code == 0 ? "success" : result_code_string.data,
+ result_code, result_string.length, result_string.data);
+ return (code);
+}
+
+/*
+ * smb_krb5_write_keytab
+ *
+ * Write all the Kerberos keys to the keytab file.
+ * Returns 0 on success. Otherwise, returns -1.
+ */
+int
+smb_krb5_write_keytab(krb5_context ctx, krb5_principal princ, char *fname,
+ krb5_kvno kvno, char *passwd, krb5_enctype *enctypes, int enctype_count)
+{
+ krb5_keytab kt = NULL;
+ char *ktname;
+ int i, len;
+ int rc = 0;
+ struct stat fstat;
+
+ if (stat(fname, &fstat) == 0) {
+ if (remove(fname) != 0) {
+ syslog(LOG_ERR, "smb_krb5_write_keytab: cannot remove"
+ " existing keytab");
+ return (-1);
+ }
+ }
+
+ len = snprintf(NULL, 0, "WRFILE:%s", fname) + 1;
+ if ((ktname = malloc(len)) == NULL) {
+ syslog(LOG_ERR, "smb_krb5_write_keytab: resource shortage");
+ return (-1);
+ }
+
+ (void) snprintf(ktname, len, "WRFILE:%s", fname);
+
+ if (krb5_kt_resolve(ctx, ktname, &kt) != 0) {
+ syslog(LOG_ERR, "smb_krb5_write_keytab: failed to open/create "
+ "keytab %s\n", fname);
+ free(ktname);
+ return (-1);
+ }
+
+ free(ktname);
+
+ for (i = 0; i < enctype_count; i++) {
+ if (smb_krb5_ktadd(ctx, kt, princ, enctypes[i], kvno, passwd)
+ != 0) {
+ rc = -1;
+ break;
+ }
+
+ }
+
+ if (kt != NULL)
+ krb5_kt_close(ctx, kt);
+
+ return (rc);
+}
+
+/*
+ * smb_krb5_ktadd
+ *
+ * Add a Keberos key to the keytab file.
+ * Returns 0 on success. Otherwise, returns -1.
+ */
+static int
+smb_krb5_ktadd(krb5_context ctx, krb5_keytab kt, const krb5_principal princ,
+ krb5_enctype enctype, krb5_kvno kvno, const char *pw)
+{
+ krb5_keytab_entry *entry;
+ krb5_data password, salt;
+ krb5_keyblock key;
+ krb5_error_code code;
+ char buf[100];
+ int rc = 0;
+
+ if ((code = krb5_enctype_to_string(enctype, buf, sizeof (buf)))) {
+ syslog(LOG_ERR, "smb_krb5_ktadd[%d]: unknown enctype",
+ enctype);
+ return (-1);
+ }
+
+ if ((entry = (krb5_keytab_entry *) malloc(sizeof (*entry))) == NULL) {
+ syslog(LOG_ERR, "smb_krb5_ktadd[%d]: resource shortage",
+ enctype);
+ return (-1);
+ }
+
+ (void) memset((char *)entry, 0, sizeof (*entry));
+
+ password.length = strlen(pw);
+ password.data = (char *)pw;
+
+ if ((code = krb5_principal2salt(ctx, princ, &salt)) != 0) {
+ syslog(LOG_ERR, "smb_krb5_ktadd[%d]: failed to compute salt",
+ enctype);
+ free(entry);
+ return (-1);
+ }
+
+ code = krb5_c_string_to_key(ctx, enctype, &password, &salt, &key);
+ krb5_xfree(salt.data);
+ if (code != 0) {
+ syslog(LOG_ERR, "smb_krb5_ktadd[%d]: failed to generate key",
+ enctype);
+ free(entry);
+ return (-1);
+ }
+
+ (void) memcpy(&entry->key, &key, sizeof (krb5_keyblock));
+ entry->vno = kvno;
+ entry->principal = princ;
+
+ if ((code = krb5_kt_add_entry(ctx, kt, entry)) != 0) {
+ syslog(LOG_ERR, "smb_krb5_ktadd[%d] failed to add entry to "
+ "keytab (%d)", enctype, code);
+ rc = -1;
+ }
+
+ free(entry);
+ return (rc);
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c
new file mode 100644
index 0000000000..7b165e3b44
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c
@@ -0,0 +1,300 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Main startup code for SMB/NETBIOS and some utility routines
+ * for the NETBIOS layer.
+ */
+
+#include <synch.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/socket.h>
+
+#include <smbns_netbios.h>
+
+netbios_status_t nb_status;
+
+static pthread_t smb_nbns_thr; /* name service */
+static pthread_t smb_nbds_thr; /* dgram service */
+static pthread_t smb_nbts_thr; /* timer */
+static pthread_t smb_nbbs_thr; /* browser */
+
+static void *smb_netbios_timer(void *);
+
+void
+smb_netbios_chg_status(uint32_t status, int set)
+{
+ (void) mutex_lock(&nb_status.mtx);
+ if (set)
+ nb_status.state |= status;
+ else
+ nb_status.state &= ~status;
+ (void) cond_broadcast(&nb_status.cv);
+ (void) mutex_unlock(&nb_status.mtx);
+}
+
+void
+smb_netbios_shutdown(void)
+{
+ smb_netbios_chg_status(NETBIOS_SHUTTING_DOWN, 1);
+
+ (void) pthread_join(smb_nbts_thr, 0);
+ (void) pthread_join(smb_nbbs_thr, 0);
+ (void) pthread_join(smb_nbns_thr, 0);
+ (void) pthread_join(smb_nbds_thr, 0);
+
+ nb_status.state = NETBIOS_SHUT_DOWN;
+}
+
+void
+smb_netbios_start()
+{
+ int rc;
+ mutex_t *mp;
+ cond_t *cvp;
+
+ /* Startup Netbios named; port 137 */
+ rc = pthread_create(&smb_nbns_thr, 0,
+ smb_netbios_name_service_daemon, 0);
+ if (rc)
+ return;
+
+ mp = &nb_status.mtx;
+ cvp = &nb_status.cv;
+
+ (void) mutex_lock(mp);
+
+ while (!(nb_status.state & (NETBIOS_NAME_SVC_RUNNING |
+ NETBIOS_NAME_SVC_FAILED))) {
+ (void) cond_wait(cvp, mp);
+ }
+
+ if (nb_status.state & NETBIOS_NAME_SVC_FAILED) {
+ (void) mutex_unlock(mp);
+ (void) fprintf(stderr,
+ "smbd: Netbios Name service startup failed!");
+ smb_netbios_shutdown();
+ return;
+ }
+ (void) mutex_unlock(mp);
+
+ (void) fprintf(stderr, "smbd: Netbios Name service started.");
+ smb_netbios_name_config();
+
+ /* Startup Netbios datagram service; port 138 */
+ rc = pthread_create(&smb_nbds_thr, 0,
+ smb_netbios_datagram_service_daemon, 0);
+ if (rc == 0) {
+ (void) mutex_lock(mp);
+ while (!(nb_status.state & (NETBIOS_DATAGRAM_SVC_RUNNING |
+ NETBIOS_DATAGRAM_SVC_FAILED))) {
+ (void) cond_wait(cvp, mp);
+ }
+
+ if (nb_status.state & NETBIOS_DATAGRAM_SVC_FAILED) {
+ (void) mutex_unlock(mp);
+ (void) fprintf(stderr, "smbd: Netbios Datagram service "
+ "startup failed!");
+ smb_netbios_shutdown();
+ return;
+ }
+ (void) mutex_unlock(mp);
+ } else {
+ smb_netbios_shutdown();
+ return;
+ }
+
+ (void) fprintf(stderr, "smbd: Netbios Datagram service started.");
+
+ /* Startup Netbios browser service */
+ rc = pthread_create(&smb_nbbs_thr, 0, smb_browser_daemon, 0);
+ if (rc) {
+ smb_netbios_shutdown();
+ return;
+ }
+
+ (void) fprintf(stderr, "smbd: Netbios Browser client started.");
+
+ /* Startup Our internal, 1 second resolution, timer */
+ rc = pthread_create(&smb_nbts_thr, 0, smb_netbios_timer, 0);
+ if (rc == 0) {
+ (void) mutex_lock(mp);
+ while (!(nb_status.state & (NETBIOS_TIMER_RUNNING |
+ NETBIOS_TIMER_FAILED))) {
+ (void) cond_wait(cvp, mp);
+ }
+
+ if (nb_status.state & NETBIOS_TIMER_FAILED) {
+ (void) mutex_unlock(mp);
+ smb_netbios_shutdown();
+ return;
+ }
+ (void) mutex_unlock(mp);
+ } else {
+ smb_netbios_shutdown();
+ return;
+ }
+
+ (void) fprintf(stderr, "smbd: Netbios Timer service started.");
+}
+
+/*ARGSUSED*/
+static void *
+smb_netbios_timer(void *arg)
+{
+ static unsigned int ticks;
+
+ smb_netbios_chg_status(NETBIOS_TIMER_RUNNING, 1);
+
+ while ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) {
+ (void) sleep(1);
+
+ if (nb_status.state & NETBIOS_DATAGRAM_SVC_RUNNING)
+ smb_netbios_datagram_tick();
+ else
+ break;
+
+ if (nb_status.state & NETBIOS_NAME_SVC_RUNNING) {
+ smb_netbios_name_tick();
+
+ /* every 10 minutes */
+ if ((ticks % 600) == 0)
+ smb_netbios_cache_clean();
+ }
+ else
+ break;
+ }
+
+ nb_status.state &= ~NETBIOS_TIMER_RUNNING;
+ if ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) {
+ /* either name or datagram service has failed */
+ smb_netbios_shutdown();
+ }
+
+ return (0);
+}
+
+int
+smb_first_level_name_encode(struct name_entry *name,
+ unsigned char *out, int max_out)
+{
+ return (netbios_first_level_name_encode(name->name, name->scope,
+ out, max_out));
+}
+
+int
+smb_first_level_name_decode(unsigned char *in, struct name_entry *name)
+{
+ return (netbios_first_level_name_decode((char *)in, (char *)name->name,
+ (char *)name->scope));
+}
+
+/*
+ * smb_encode_netbios_name
+ *
+ * Set up the name and scope fields in the destination name_entry structure.
+ * The name is padded with spaces to 15 bytes. The suffix is copied into the
+ * last byte, i.e. "netbiosname <suffix>". The scope is copied and folded
+ * to uppercase.
+ */
+void
+smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
+ struct name_entry *dest)
+{
+ char tmp_name[NETBIOS_NAME_SZ];
+ mts_wchar_t wtmp_name[NETBIOS_NAME_SZ];
+ unsigned int cpid;
+ int len;
+ size_t rc;
+
+ len = 0;
+ rc = mts_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ);
+
+ if (rc != (size_t)-1) {
+ wtmp_name[NETBIOS_NAME_SZ - 1] = 0;
+ cpid = oem_get_smb_cpid();
+ rc = unicodestooems(tmp_name, wtmp_name, NETBIOS_NAME_SZ, cpid);
+ if (rc > 0)
+ len = strlen(tmp_name);
+ }
+
+ (void) memset(dest->name, ' ', NETBIOS_NAME_SZ - 1);
+ if (len) {
+ (void) utf8_strupr(tmp_name);
+ (void) memcpy(dest->name, tmp_name, len);
+ }
+ dest->name[NETBIOS_NAME_SZ - 1] = suffix;
+
+ if (scope == NULL) {
+ smb_config_rdlock();
+ (void) strlcpy((char *)dest->scope,
+ smb_config_getstr(SMB_CI_NBSCOPE), NETBIOS_DOMAIN_NAME_MAX);
+ smb_config_unlock();
+ } else {
+ (void) strlcpy((char *)dest->scope, (const char *)scope,
+ NETBIOS_DOMAIN_NAME_MAX);
+ }
+ (void) utf8_strupr((char *)dest->scope);
+}
+
+void
+smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope,
+ uint32_t ipaddr, unsigned short port, uint32_t attr,
+ uint32_t addr_attr, struct name_entry *dest)
+{
+ bzero(dest, sizeof (struct name_entry));
+ smb_encode_netbios_name(name, suffix, scope, dest);
+
+ switch (smb_node_type) {
+ case 'H':
+ dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE;
+ break;
+ case 'M':
+ dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE;
+ break;
+ case 'P':
+ dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE;
+ break;
+ case 'B':
+ default:
+ dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE;
+ break;
+ }
+
+ dest->addr_list.refresh_ttl = dest->addr_list.ttl =
+ TO_SECONDS(DEFAULT_TTL);
+
+ dest->addr_list.sin.sin_family = AF_INET;
+ dest->addr_list.sinlen = sizeof (dest->addr_list.sin);
+ dest->addr_list.sin.sin_addr.s_addr = ipaddr;
+ dest->addr_list.sin.sin_port = port;
+ dest->addr_list.attributes = addr_attr;
+ dest->addr_list.forw = dest->addr_list.back = &dest->addr_list;
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.h b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.h
new file mode 100644
index 0000000000..54ac5cf2ab
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.h
@@ -0,0 +1,1617 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMB_NETBIOS_H_
+#define _SMB_NETBIOS_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * 4.2. NAME SERVICE PACKETS
+ *
+ * 4.2.1. GENERAL FORMAT OF NAME SERVICE PACKETS
+ *
+ * The NetBIOS Name Service packets follow the packet structure defined
+ * in the Domain Name Service (DNS) RFC 883 [7 (pg 26-31)]. The
+ * structures are compatible with the existing DNS packet formats,
+ * however, additional types and codes have been added to work with
+ * NetBIOS.
+ *
+ * If Name Service packets are sent over a TCP connection they are
+ * preceded by a 16 bit unsigned integer representing the length of the
+ * Name Service packet.
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * + ------ ------- +
+ * | HEADER |
+ * + ------ ------- +
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION ENTRIES /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / ANSWER RESOURCE RECORDS /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / AUTHORITY RESOURCE RECORDS /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / ADDITIONAL RESOURCE RECORDS /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.1.1 HEADER
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID | OPCODE | NM_FLAGS | RCODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | QDCOUNT | ANCOUNT |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NSCOUNT | ARCOUNT |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Field Description
+ *
+ * NAME_TRN_ID Transaction ID for Name Service Transaction.
+ * Requester places a unique value for each active
+ * transaction. Responder puts NAME_TRN_ID value
+ * from request packet in response packet.
+ *
+ * OPCODE Packet type code, see table below.
+ *
+ * NM_FLAGS Flags for operation, see table below.
+ *
+ * RCODE Result codes of request. Table of RCODE values
+ * for each response packet below.
+ *
+ * QDCOUNT Unsigned 16 bit integer specifying the number of
+ * entries in the question section of a Name
+ * Service packet. Always zero (0) for responses.
+ * Must be non-zero for all NetBIOS Name requests.
+ *
+ * ANCOUNT Unsigned 16 bit integer specifying the number of
+ * resource records in the answer section of a Name
+ * Service packet.
+ *
+ * NSCOUNT Unsigned 16 bit integer specifying the number of
+ * resource records in the authority section of a
+ * Name Service packet.
+ *
+ * ARCOUNT Unsigned 16 bit integer specifying the number of
+ * resource records in the additional records
+ * section of a Name Service packet.
+ */
+
+
+/*
+ * The OPCODE field is defined as:
+ *
+ * 0 1 2 3 4
+ * +---+---+---+---+---+
+ * | R | OPCODE |
+ * +---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description
+ *
+ * OPCODE 1-4 Operation specifier:
+ * 0 = query
+ * 5 = registration
+ * 6 = release
+ * 7 = WACK
+ * 8 = refresh
+ *
+ * R 0 RESPONSE flag:
+ * if bit == 0 then request packet
+ * if bit == 1 then response packet.
+ */
+
+/*
+ * The NM_FLAGS field is defined as:
+ *
+ *
+ * 0 1 2 3 4 5 6
+ * +---+---+---+---+---+---+---+
+ * |AA |TC |RD |RA | 0 | 0 | B |
+ * +---+---+---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description
+ *
+ * B 6 Broadcast Flag.
+ * = 1: packet was broadcast or multicast
+ * = 0: unicast
+ *
+ * RA 3 Recursion Available Flag.
+ *
+ * Only valid in responses from a NetBIOS Name
+ * Server -- must be zero in all other
+ * responses.
+ *
+ * If one (1) then the NBNS supports recursive
+ * query, registration, and release.
+ *
+ * If zero (0) then the end-node must iterate
+ * for query and challenge for registration.
+ *
+ * RD 2 Recursion Desired Flag.
+ *
+ * May only be set on a request to a NetBIOS
+ * Name Server.
+ *
+ * The NBNS will copy its state into the
+ * response packet.
+ *
+ * If one (1) the NBNS will iterate on the
+ * query, registration, or release.
+ *
+ * TC 1 Truncation Flag.
+ *
+ * Set if this message was truncated because the
+ * datagram carrying it would be greater than
+ * 576 bytes in length. Use TCP to get the
+ * information from the NetBIOS Name Server.
+ *
+ * AA 0 Authoritative Answer flag.
+ *
+ * Must be zero (0) if R flag of OPCODE is zero
+ * (0).
+ *
+ * If R flag is one (1) then if AA is one (1)
+ * then the node responding is an authority for
+ * the domain name.
+ *
+ * End nodes responding to queries always set
+ * this bit in responses.
+ */
+
+/*
+ * 4.2.1.2 QUESTION SECTION
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | QUESTION_TYPE | QUESTION_CLASS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Field Description
+ *
+ * QUESTION_NAME The compressed name representation of the
+ * NetBIOS name for the request.
+ *
+ * QUESTION_TYPE The type of request. The values for this field
+ * are specified for each request.
+ *
+ * QUESTION_CLASS The class of the request. The values for this
+ * field are specified for each request.
+ *
+ * QUESTION_TYPE is defined as:
+ *
+ * Symbol Value Description:
+ *
+ * NB 0x0020 NetBIOS general Name Service Resource Record
+ * NBSTAT 0x0021 NetBIOS NODE STATUS Resource Record (See NODE
+ * STATUS REQUEST)
+ *
+ * QUESTION_CLASS is defined as:
+ *
+ * Symbol Value Description:
+ *
+ * IN 0x0001 Internet class
+ */
+
+/*
+ * 4.2.1.3 RESOURCE RECORD
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RR_TYPE | RR_CLASS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RDLENGTH | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ * / /
+ * / RDATA /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Field Description
+ *
+ * RR_NAME The compressed name representation of the
+ * NetBIOS name corresponding to this resource
+ * record.
+ *
+ * RR_TYPE Resource record type code
+ *
+ * RR_CLASS Resource record class code
+ *
+ * TTL The Time To Live of a the resource record's
+ * name.
+ *
+ * RDLENGTH Unsigned 16 bit integer that specifies the
+ * number of bytes in the RDATA field.
+ *
+ * RDATA RR_CLASS and RR_TYPE dependent field. Contains
+ * the resource information for the NetBIOS name.
+ *
+ * RESOURCE RECORD RR_TYPE field definitions:
+ *
+ * Symbol Value Description:
+ *
+ * A 0x0001 IP address Resource Record (See REDIRECT NAME
+ * QUERY RESPONSE)
+ * NS 0x0002 Name Server Resource Record (See REDIRECT
+ * NAME QUERY RESPONSE)
+ * NULL 0x000A NULL Resource Record (See WAIT FOR
+ * ACKNOWLEDGEMENT RESPONSE)
+ * NB 0x0020 NetBIOS general Name Service Resource Record
+ * (See NB_FLAGS and NB_ADDRESS, below)
+ * NBSTAT 0x0021 NetBIOS NODE STATUS Resource Record (See NODE
+ * STATUS RESPONSE)
+ *
+ * RESOURCE RECORD RR_CLASS field definitions:
+ *
+ * Symbol Value Description:
+ *
+ * IN 0x0001 Internet class
+ *
+ * NB_FLAGS field of the RESOURCE RECORD RDATA field for RR_TYPE of
+ * "NB":
+ *
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * | G | ONT | RESERVED |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description:
+ *
+ * RESERVED 3-15 Reserved for future use. Must be zero (0).
+ * ONT 1,2 Owner Node Type:
+ * 00 = B node
+ * 01 = P node
+ * 10 = M node
+ * 11 = Reserved for future use
+ * For registration requests this is the
+ * claimant's type.
+ * For responses this is the actual owner's
+ * type.
+ *
+ * G 0 Group Name Flag.
+ * If one (1) then the RR_NAME is a GROUP
+ * NetBIOS name.
+ * If zero (0) then the RR_NAME is a UNIQUE
+ * NetBIOS name.
+ *
+ * The NB_ADDRESS field of the RESOURCE RECORD RDATA field for
+ * RR_TYPE of "NB" is the IP address of the name's owner.
+ */
+
+/*
+ * 4.2.2. NAME REGISTRATION REQUEST
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x5 |0|0|1|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Since the RR_NAME is the same name as the QUESTION_NAME, the
+ * RR_NAME representation must use pointers to the QUESTION_NAME
+ * name's labels to guarantee the length of the datagram is less
+ * than the maximum 576 bytes. See section above on name formats
+ * and also page 31 and 32 of RFC 883, Domain Names - Implementation
+ * and Specification, for a complete description of compressed name
+ * label pointers.
+ */
+
+/*
+ * 4.2.3 NAME OVERWRITE REQUEST & DEMAND
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x5 |0|0|0|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.4 NAME REFRESH REQUEST
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x9 |0|0|0|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.5 POSITIVE NAME REGISTRATION RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x5 |1|0|1|1|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.6 NEGATIVE NAME REGISTRATION RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x5 |1|0|1|1|0 0|0| RCODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * RCODE field values:
+ *
+ * Symbol Value Description:
+ *
+ * FMT_ERR 0x1 Format Error. Request was invalidly
+ * formatted.
+ * SRV_ERR 0x2 Server failure. Problem with NBNS, cannot
+ * process name.
+ * IMP_ERR 0x4 Unsupported request error. Allowable only
+ * for challenging NBNS when gets an Update type
+ * registration request.
+ * RFS_ERR 0x5 Refused error. For policy reasons server
+ * will not register this name from this host.
+ * ACT_ERR 0x6 Active error. Name is owned by another node.
+ * CFT_ERR 0x7 Name in conflict error. A UNIQUE name is
+ * owned by more than one node.
+ */
+
+/*
+ * 4.2.7 END-NODE CHALLENGE REGISTRATION RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x5 |1|0|1|0|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.8 NAME CONFLICT DEMAND
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x5 |1|0|1|1|0 0|0| 0x7 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x00000000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 |0|ONT|0| 0x000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x00000000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * This packet is identical to a NEGATIVE NAME REGISTRATION RESPONSE
+ * with RCODE = CFT_ERR.
+ */
+
+/*
+ * 4.2.9 NAME RELEASE REQUEST & DEMAND
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x6 |0|0|0|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x00000000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Since the RR_NAME is the same name as the QUESTION_NAME, the
+ * RR_NAME representation must use label string pointers to the
+ * QUESTION_NAME labels to guarantee the length of the datagram is
+ * less than the maximum 576 bytes. This is the same condition as
+ * with the NAME REGISTRATION REQUEST.
+ */
+
+/*
+ * 4.2.10 POSITIVE NAME RELEASE RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x6 |1|0|0|0|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.11 NEGATIVE NAME RELEASE RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x6 |1|0|0|0|0 0|0| RCODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * RCODE field values:
+ *
+ * Symbol Value Description:
+ *
+ * FMT_ERR 0x1 Format Error. Request was invalidly
+ * formatted.
+ *
+ * SRV_ERR 0x2 Server failure. Problem with NBNS, cannot
+ * process name.
+ *
+ * RFS_ERR 0x5 Refused error. For policy reasons server
+ * will not release this name from this host.
+ *
+ * ACT_ERR 0x6 Active error. Name is owned by another node.
+ * Only that node may release it. A NetBIOS
+ * Name Server can optionally allow a node to
+ * release a name it does not own. This would
+ * facilitate detection of inactive names for
+ * nodes that went down silently.
+ */
+
+/*
+ * 4.2.12 NAME QUERY REQUEST
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x0 |0|0|1|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.13 POSITIVE NAME QUERY RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x0 |1|T|1|?|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RDLENGTH | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ * | |
+ * / ADDR_ENTRY ARRAY /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The ADDR_ENTRY ARRAY a sequence of zero or more ADDR_ENTRY
+ * records. Each ADDR_ENTRY record represents an owner of a name.
+ * For group names there may be multiple entries. However, the list
+ * may be incomplete due to packet size limitations. Bit 22, "T",
+ * will be set to indicate truncated data.
+ *
+ * Each ADDR_ENTRY has the following format:
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_FLAGS | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS (continued) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.14 NEGATIVE NAME QUERY RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x0 |1|0|1|?|0 0|0| RCODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NULL (0x000A) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x00000000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * RCODE field values:
+ *
+ * Symbol Value Description
+ *
+ * FMT_ERR 0x1 Format Error. Request was invalidly
+ * formatted.
+ * SRV_ERR 0x2 Server failure. Problem with NBNS, cannot
+ * process name.
+ * NAM_ERR 0x3 Name Error. The name requested does not
+ * exist.
+ * IMP_ERR 0x4 Unsupported request error. Allowable only
+ * for challenging NBNS when gets an Update type
+ * registration request.
+ * RFS_ERR 0x5 Refused error. For policy reasons server
+ * will not register this name from this host.
+ */
+
+/*
+ * 4.2.15 REDIRECT NAME QUERY RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x0 |0|0|1|0|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NS (0x0002) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RDLENGTH | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+ * | |
+ * / NSD_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | A (0x0001) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0004 | NSD_IP_ADDR |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NSD_IP_ADDR, continued |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * An end node responding to a NAME QUERY REQUEST always responds
+ * with the AA and RA bits set for both the NEGATIVE and POSITIVE
+ * NAME QUERY RESPONSE packets. An end node never sends a REDIRECT
+ * NAME QUERY RESPONSE packet.
+ *
+ * When the requestor receives the REDIRECT NAME QUERY RESPONSE it
+ * must reiterate the NAME QUERY REQUEST to the NBNS specified by
+ * the NSD_IP_ADDR field of the A type RESOURCE RECORD in the
+ * ADDITIONAL section of the response packet. This is an optional
+ * packet for the NBNS.
+ *
+ * The NSD_NAME and the RR_NAME in the ADDITIONAL section of the
+ * response packet are the same name. Space can be optimized if
+ * label string pointers are used in the RR_NAME which point to the
+ * labels in the NSD_NAME.
+ *
+ * The RR_NAME in the AUTHORITY section is the name of the domain
+ * the NBNS called by NSD_NAME has authority over.
+ */
+
+/*
+ * 4.2.16 WAIT FOR ACKNOWLEDGEMENT (WACK) RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x7 |1|0|0|0|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NULL (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0002 | OPCODE | NM_FLAGS | 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The NAME_TRN_ID of the WACK RESPONSE packet is the same
+ * NAME_TRN_ID of the request that the NBNS is telling the requestor
+ * to wait longer to complete. The RR_NAME is the name from the
+ * request, if any. If no name is available from the request then
+ * it is a null name, single byte of zero.
+ *
+ * The TTL field of the ResourceRecord is the new time to wait, in
+ * seconds, for the request to complete. The RDATA field contains
+ * the OPCODE and NM_FLAGS of the request.
+ *
+ * A TTL value of 0 means that the NBNS can not estimate the time it
+ * may take to complete a response.
+ */
+
+/*
+ * 4.2.17 NODE STATUS REQUEST
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x0 |0|0|0|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NBSTAT (0x0021) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * 4.2.18 NODE STATUS RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x0 |1|0|0|0|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NBSTAT (0x0021) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x00000000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RDLENGTH | NUM_NAMES | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+ * | |
+ * + +
+ * / NODE_NAME ARRAY /
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * + +
+ * / STATISTICS /
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The NODE_NAME ARRAY is an array of zero or more NUM_NAMES entries
+ * of NODE_NAME records. Each NODE_NAME entry represents an active
+ * name in the same NetBIOS scope as the requesting name in the
+ * local name table of the responder. RR_NAME is the requesting
+ * name.
+ */
+
+#include <stdio.h>
+#include <synch.h>
+#include <pthread.h>
+#include <strings.h>
+#include <netinet/in.h>
+
+#include <smbsrv/libsmbns.h>
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/netbios.h>
+
+#define QUEUE_INSERT_TAIL(q, e) \
+ ((e)->back) = (void *)((q)->back); \
+ ((e)->forw) = (void *)(q); \
+ ((q)->back->forw) = (void *)(e); \
+ ((q)->back) = (void *)(e);
+
+#define QUEUE_CLIP(e) \
+ (e)->forw->back = (e)->back; \
+ (e)->back->forw = (e)->forw; \
+ (e)->forw = 0; \
+ (e)->back = 0;
+
+#define NETBIOS_NAME_SVC_LAUNCHED 0x00001
+#define NETBIOS_NAME_SVC_RUNNING 0x00002
+#define NETBIOS_NAME_SVC_FAILED 0x00004
+
+#define NETBIOS_DATAGRAM_SVC_LAUNCHED 0x00010
+#define NETBIOS_DATAGRAM_SVC_RUNNING 0x00020
+#define NETBIOS_DATAGRAM_SVC_FAILED 0x00040
+
+#define NETBIOS_TIMER_LAUNCHED 0x00100
+#define NETBIOS_TIMER_RUNNING 0x00200
+#define NETBIOS_TIMER_FAILED 0x00400
+
+#define NETBIOS_BROWSER_LAUNCHED 0x01000
+#define NETBIOS_BROWSER_RUNNING 0x02000
+#define NETBIOS_BROWSER_FAILED 0x04000
+
+#define NETBIOS_SHUTTING_DOWN 0x10000
+#define NETBIOS_SHUT_DOWN 0x20000
+
+char smb_node_type;
+
+typedef struct {
+ mutex_t mtx;
+ cond_t cv;
+ uint32_t state;
+} netbios_status_t;
+extern netbios_status_t nb_status;
+
+/*
+ * NAME service definitions
+ */
+#define ADDR_FLAG_INVALID 0x0000
+#define ADDR_FLAG_VALID 0x0001
+
+typedef struct addr_entry {
+ struct addr_entry *forw;
+ struct addr_entry *back;
+ uint32_t attributes;
+ uint32_t conflict_timer;
+ uint32_t refresh_ttl;
+ uint32_t ttl;
+ struct sockaddr_in sin;
+ int sinlen;
+ uint32_t flags;
+} addr_entry_t;
+
+/*
+ * The NODE_NAME ARRAY is an array of zero or more NUM_NAMES entries
+ * of NODE_NAME records. Each NODE_NAME entry represents an active
+ * name in the same NetBIOS scope as the requesting name in the
+ * local name table of the responder. RR_NAME is the requesting
+ * name.
+ *
+ * NODE_NAME Entry:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * +--- ---+
+ * | |
+ * +--- NETBIOS FORMAT NAME ---+
+ * | |
+ * +--- ---+
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The NAME_FLAGS field:
+ *
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * | G | ONT |DRG|CNF|ACT|PRM| RESERVED |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * The NAME_FLAGS field is defined as:
+ *
+ * Symbol Bit(s) Description:
+ *
+ * RESERVED 7-15 Reserved for future use. Must be zero (0).
+ * PRM 6 Permanent Name Flag. If one (1) then entry
+ * is for the permanent node name. Flag is zero
+ * (0) for all other names.
+ * ACT 5 Active Name Flag. All entries have this flag
+ * set to one (1).
+ * CNF 4 Conflict Flag. If one (1) then name on this
+ * node is in conflict.
+ * DRG 3 Deregister Flag. If one (1) then this name
+ * is in the process of being deleted.
+ * ONT 1,2 Owner Node Type:
+ * 00 = B node
+ * 01 = P node
+ * 10 = M node
+ * 11 = Reserved for future use
+ * G 0 Group Name Flag.
+ * name.
+ * If zero (0) then it is a UNIQUE NetBIOS name.
+ */
+
+typedef struct name_entry {
+ struct name_entry *forw;
+ struct name_entry *back;
+ unsigned char name[NETBIOS_NAME_SZ];
+ unsigned char scope[NETBIOS_DOMAIN_NAME_MAX];
+ unsigned short attributes;
+ struct addr_entry addr_list;
+ mutex_t mtx;
+} name_entry;
+
+struct name_question {
+ struct name_entry *name;
+ unsigned question_type;
+ unsigned question_class;
+};
+
+struct resource_record {
+ /*
+ * These two flags and address are contained within RDATA
+ * when rr_type==0x0020 (NB - NetBIOS general Name Service)
+ * and rr_class==0x01 (IN - Internet Class).
+ */
+
+ struct name_entry *name;
+ unsigned short rr_type;
+ unsigned short rr_class;
+ uint32_t ttl;
+ unsigned short rdlength;
+ unsigned char *rdata;
+};
+
+struct name_packet {
+ unsigned short name_trn_id;
+ unsigned short info;
+
+ unsigned qdcount; /* question entries */
+ unsigned ancount; /* answer recs */
+ unsigned nscount; /* authority recs */
+ unsigned arcount; /* additional recs */
+
+ struct name_question *question;
+ struct resource_record *answer;
+ struct resource_record *authority;
+ struct resource_record *additional;
+
+ unsigned char block_data[4]; /* begining of space */
+};
+
+#define NAME_OPCODE_R 0x8000 /* RESPONSE flag: 1 bit */
+#define NAME_OPCODE_OPCODE_MASK 0x7800 /* OPCODE Field: 4 bits */
+#define NAME_OPCODE_QUERY 0x0000
+#define NAME_OPCODE_REGISTRATION 0x2800
+#define NAME_OPCODE_RELEASE 0x3000
+#define NAME_OPCODE_WACK 0x3800
+#define NAME_OPCODE_REFRESH 0x4000
+#define NAME_OPCODE_MULTIHOME 0x7800
+#define NAME_NM_FLAGS_AA 0x0400 /* Authoritative Answer:1 bit */
+#define NAME_NM_FLAGS_TC 0x0200 /* Truncation: 1 bit */
+#define NAME_NM_FLAGS_RD 0x0100 /* Recursion desired: 1 bit */
+#define NAME_NM_FLAGS_RA 0x0080 /* Recursion available: 1 bit */
+#define NAME_NM_FLAGS_x2 0x0040 /* reserved, mbz: 1 bit */
+#define NAME_NM_FLAGS_x1 0x0020 /* reserved, mbz: 1 bit */
+#define NAME_NM_FLAGS_B 0x0010 /* Broadcast: 1 bit */
+#define NAME_RCODE_MASK 0x000f /* RCODE Field: 4 bits */
+#define RCODE_FMT_ERR 0x0001
+#define RCODE_SRV_ERR 0x0002
+#define RCODE_NAM_ERR 0x0003
+#define RCODE_IMP_ERR 0x0004
+#define RCODE_RFS_ERR 0x0005
+#define RCODE_ACT_ERR 0x0006
+#define RCODE_CFT_ERR 0x0007
+
+#define NM_FLAGS_UNICAST 0
+#define NM_FLAGS_BROADCAST NAME_NM_FLAGS_B
+
+#define PACKET_TYPE(x) ((x) & (NAME_OPCODE_R | NAME_OPCODE_OPCODE_MASK | \
+ NAME_NM_FLAGS_AA | NAME_NM_FLAGS_RD))
+
+#define RCODE(x) ((x) & NAME_RCODE_MASK)
+#define POSITIVE_RESPONSE(x) (RCODE(x) == 0)
+#define NEGATIVE_RESPONSE(x) (RCODE(x) != 0)
+
+#define END_NODE_CHALLENGE_REGISTRATION_REQUEST \
+ (NAME_OPCODE_REGISTRATION | NAME_NM_FLAGS_AA | NAME_NM_FLAGS_RD)
+#define END_NODE_CHALLENGE_NAME_REGISTRATION_RESPONSE \
+ (NAME_OPCODE_R | END_NODE_CHALLENGE_REGISTRATION_REQUEST)
+
+#define NAME_QUERY_REQUEST \
+ (NAME_OPCODE_QUERY | NAME_NM_FLAGS_RD)
+#define NAME_QUERY_RESPONSE \
+ (NAME_OPCODE_R | NAME_QUERY_REQUEST | \
+ NAME_NM_FLAGS_AA | NAME_NM_FLAGS_RD)
+
+#define NODE_STATUS_REQUEST \
+ (NAME_OPCODE_QUERY)
+#define NODE_STATUS_RESPONSE \
+ (NAME_OPCODE_R | NODE_STATUS_REQUEST | NAME_NM_FLAGS_AA)
+
+#define REDIRECT_NAME_QUERY_RESPONSE \
+ (NAME_OPCODE_R | NAME_QUERY_REQUEST | NAME_NM_FLAGS_RD)
+
+#define NAME_REFRESH_REQUEST \
+ (NAME_OPCODE_REFRESH)
+#define NAME_REGISTRATION_REQUEST \
+ (NAME_OPCODE_REGISTRATION | NAME_NM_FLAGS_RD)
+#define NAME_MULTIHOME_REGISTRATION_REQUEST \
+ (NAME_OPCODE_MULTIHOME | NAME_NM_FLAGS_RD)
+#define NAME_REGISTRATION_RESPONSE \
+ (NAME_OPCODE_R | NAME_REGISTRATION_REQUEST | NAME_NM_FLAGS_AA)
+
+#define NAME_RELEASE_REQUEST \
+ (NAME_OPCODE_RELEASE)
+#define NAME_RELEASE_RESPONSE \
+ (NAME_OPCODE_R | NAME_RELEASE_REQUEST | NAME_NM_FLAGS_AA)
+
+#define WACK_RESPONSE \
+ (NAME_OPCODE_R | NAME_OPCODE_WACK | NAME_NM_FLAGS_AA)
+
+#define NAME_QUESTION_TYPE_NB 0x0020
+#define NAME_QUESTION_TYPE_NBSTAT 0x0021
+#define NAME_QUESTION_CLASS_IN 0x0001
+
+
+#define NAME_RR_TYPE_A 0x0001 /* IP Address */
+#define NAME_RR_TYPE_NS 0x0002 /* Name Server */
+#define NAME_RR_TYPE_NULL 0x000A /* NULL */
+#define NAME_RR_TYPE_NB 0x0020 /* NetBIOS Name Service */
+#define NAME_RR_TYPE_NBSTAT 0x0021 /* NetBIOS Node Status */
+
+#define NAME_RR_CLASS_IN 0x0001 /* NetBIOS Node Status */
+
+#define NAME_NB_FLAGS_ONT_MASK (3<<13)
+#define NAME_NB_FLAGS_ONT_B (0<<13) /* B-node (broadcast) */
+#define NAME_NB_FLAGS_ONT_P (1<<13) /* P-node (point-to-point) */
+#define NAME_NB_FLAGS_ONT_M (2<<13) /* M-node (multicast) */
+#define NAME_NB_FLAGS_ONT_resv (3<<13)
+#define NAME_NB_FLAGS_G (1<<15) /* Group Name */
+
+#define UNICAST 0
+#define BROADCAST 1
+#define POINTCAST 2
+
+#define NAME_ATTR_UNIQUE 0x0000
+#define NAME_ATTR_GROUP 0x8000
+#define NAME_ATTR_OWNER_NODE_TYPE 0x6000
+#define NAME_ATTR_OWNER_TYPE_BNODE 0x0000
+#define NAME_ATTR_OWNER_TYPE_PNODE 0x2000
+#define NAME_ATTR_OWNER_TYPE_MNODE 0x4000
+#define NAME_ATTR_OWNER_TYPE_HNODE 0x6000
+#define NAME_ATTR_DEREGISTER 0x1000
+#define NAME_ATTR_CONFLICT 0x0800
+#define NAME_ATTR_ACTIVE_NAME 0x0400
+#define NAME_ATTR_PERMANENT 0x0200
+#define NAME_ATTR_RESERVED 0x01FF
+#define NAME_ATTR_LOCAL 0x0001
+
+#define NODE_TYPE(x) ((x) & NAME_ATTR_OWNER_NODE_TYPE))
+#define IS_BNODE(x) (NODE_TYPE(x) == NAME_ATTR_OWNER_TYPE_BNODE)
+#define IS_PNODE(x) (NODE_TYPE(x) == NAME_ATTR_OWNER_TYPE_PNODE)
+#define IS_MNODE(x) (NODE_TYPE(x) == NAME_ATTR_OWNER_TYPE_MNODE)
+#define IS_HNODE(x) (NODE_TYPE(x) == NAME_ATTR_OWNER_TYPE_HNODE)
+
+#define IS_UNIQUE(x) (((x) & NAME_ATTR_GROUP) == 0)
+#define IS_GROUP(x) (((x) & NAME_ATTR_GROUP) != 0)
+#define IS_PERMANENT(x) (((x) & NAME_ATTR_PERMANENT) != 0)
+#define IS_CONFLICTING(x) (((x) & NAME_ATTR_CONFLICT) != 0)
+#define IS_ACTIVE(x) (((x) & NAME_ATTR_ACTIVE) != 0)
+#define IS_DEGREGISTERED(x) (((x) & NAME_ATTR_ACTIVE) != 0)
+
+#define IS_LOCAL(x) (((x) & NAME_ATTR_LOCAL) != 0)
+#define IS_PUBLIC(x) (((x) & NAME_ATTR_LOCAL) == 0)
+#define PUBLIC_BITS(x) ((x) & ~NAME_ATTR_RESERVED)
+
+#define SAME_SCOPE(scope, e) (strcmp((scope), ((e)->scope)) == 0)
+
+/*
+ * STATISTICS Field of the NODE STATUS RESPONSE:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | UNIT_ID (Unique unit ID) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | UNIT_ID,continued | JUMPERS | TEST_RESULT |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | VERSION_NUMBER | PERIOD_OF_STATISTICS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_OF_CRCs | NUMBER_ALIGNMENT_ERRORS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_OF_COLLISIONS | NUMBER_SEND_ABORTS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_GOOD_SENDS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_GOOD_RECEIVES |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_RETRANSMITS | NUMBER_NO_RESOURCE_CONDITIONS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_FREE_COMMAND_BLOCKS | TOTAL_NUMBER_COMMAND_BLOCKS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |MAX_TOTAL_NUMBER_COMMAND_BLOCKS| NUMBER_PENDING_SESSIONS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MAX_NUMBER_PENDING_SESSIONS | MAX_TOTAL_SESSIONS_POSSIBLE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SESSION_DATA_PACKET_SIZE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+typedef struct {
+ unsigned char unit_id[6];
+ unsigned char jumpers;
+ unsigned char test_result;
+ unsigned short version_number;
+ unsigned short statistical_period;
+ unsigned short crc_errors;
+ unsigned short alignment_errors;
+ unsigned short collisions;
+ unsigned short send_aborts;
+ unsigned int good_sends;
+ unsigned int good_receives;
+ unsigned short retransmits;
+ unsigned short no_resource_conditions;
+ unsigned short free_command_blocks;
+ unsigned short total_command_blocks;
+ unsigned short max_total_command_blocks;
+ unsigned short pending_sessions;
+ unsigned short max_pending_sessions;
+ unsigned short total_possible_sessions;
+ unsigned short session_data_packet_size;
+} node_status_response;
+
+/*
+ * 4.4.1. NetBIOS DATAGRAM HEADER
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MSG_TYPE | FLAGS | DGM_ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_IP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_PORT | DGM_LENGTH |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PACKET_OFFSET |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+typedef struct {
+ unsigned char msg_type;
+ unsigned char flags;
+ unsigned short dgm_id;
+ uint32_t source_ip;
+ unsigned short source_port;
+ unsigned short dgm_length;
+ unsigned short packet_offset;
+} datagram_header;
+
+/*
+ * MSG_TYPE values (in hexidecimal):
+ *
+ * 10 - DIRECT_UNIQUE DATAGRAM
+ * 11 - DIRECT_GROUP DATAGRAM
+ * 12 - BROADCAST DATAGRAM
+ * 13 - DATAGRAM ERROR
+ * 14 - DATAGRAM QUERY REQUEST
+ * 15 - DATAGRAM POSITIVE QUERY RESPONSE
+ * 16 - DATAGRAM NEGATIVE QUERY RESPONSE
+ */
+#define DATAGRAM_TYPE_DIRECT_UNIQUE 0x10
+#define DATAGRAM_TYPE_DIRECT_GROUP 0x11
+#define DATAGRAM_TYPE_BROADCAST 0x12
+#define DATAGRAM_TYPE_ERROR_DATAGRAM 0x13
+#define DATAGRAM_TYPE_QUERY_REQUEST 0x14
+#define DATAGRAM_TYPE_POSITIVE_RESPONSE 0x15
+#define DATAGRAM_TYPE_NEGATIVE_RESPONSE 0x16
+
+
+/*
+ * Bit definitions of the FLAGS field:
+ *
+ * 0 1 2 3 4 5 6 7
+ * +---+---+---+---+---+---+---+---+
+ * | 0 | 0 | 0 | 0 | SNT | F | M |
+ * +---+---+---+---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description
+ *
+ * M 7 MORE flag, If set then more NetBIOS datagram
+ * fragments follow.
+ *
+ * F 6 FIRST packet flag, If set then this is first
+ * (and possibly only) fragment of NetBIOS
+ * datagram
+ *
+ * SNT 4,5 Source End-Node type:
+ * 00 = B node
+ * 01 = P node
+ * 10 = M node
+ * 11 = H node
+ * RESERVED 0-3 Reserved, must be zero (0)
+ */
+#define DATAGRAM_FLAGS_MORE 0x01
+#define DATAGRAM_FLAGS_FIRST 0x02
+#define DATAGRAM_FLAGS_SRC_TYPE 0x0c
+#define DATAGRAM_FLAGS_B_NODE 0x00
+#define DATAGRAM_FLAGS_P_NODE 0x04
+#define DATAGRAM_FLAGS_M_NODE 0x08
+#define DATAGRAM_FLAGS_H_NODE 0x0C
+#define DATAGRAM_FLAGS_NBDD 0x0c
+#define DATAGRAM_FLAGS_RESERVED 0xf0
+
+/*
+ * 4.4.2. DIRECT_UNIQUE, DIRECT_GROUP, & BROADCAST DATAGRAM
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MSG_TYPE | FLAGS | DGM_ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_IP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_PORT | DGM_LENGTH |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PACKET_OFFSET | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ * | |
+ * / SOURCE_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / DESTINATION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / USER_DATA /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+typedef struct {
+ datagram_header header;
+ unsigned char *source_name;
+ unsigned char *destination_name;
+ unsigned char *user_data;
+} datagram_packet;
+
+
+/*
+ * 4.4.3. DATAGRAM ERROR PACKET
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MSG_TYPE | FLAGS | DGM_ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_IP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_PORT | ERROR_CODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * ERROR_CODE values (in hexidecimal):
+ *
+ * 82 - DESTINATION NAME NOT PRESENT
+ * 83 - INVALID SOURCE NAME FORMAT
+ * 84 - INVALID DESTINATION NAME FORMAT
+ */
+
+typedef struct {
+ unsigned char msg_type;
+ unsigned char flags;
+ unsigned short dgm_id;
+ uint32_t source_ip;
+ unsigned short source_port;
+ unsigned char error;
+} datagram_error_packet;
+
+/*
+ * 4.4.4. DATAGRAM QUERY REQUEST
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MSG_TYPE | FLAGS | DGM_ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_IP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_PORT | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+ * | |
+ * / DESTINATION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 4.4.5. DATAGRAM POSITIVE AND NEGATIVE QUERY RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MSG_TYPE | FLAGS | DGM_ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_IP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_PORT | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+ * | |
+ * / DESTINATION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+typedef struct datagram_query_packet {
+ unsigned char msg_type;
+ unsigned char flags;
+ unsigned short dgm_id;
+ uint32_t source_ip;
+ unsigned short source_port;
+ unsigned char destination_name[MAX_NAME_LENGTH];
+} datagram_query_packet;
+
+
+typedef struct datagram {
+ struct datagram *forw;
+ struct datagram *back;
+ struct addr_entry inaddr;
+ int discard_timer;
+ unsigned char packet_type;
+ unsigned char flags;
+ unsigned short datagram_id;
+ struct name_entry src;
+ struct name_entry dest;
+ unsigned short offset;
+ unsigned short data_length;
+ unsigned char *data;
+ unsigned int rawbytes;
+ unsigned char rawbuf[MAX_DATAGRAM_LENGTH];
+} datagram;
+
+typedef struct datagram_queue {
+ struct datagram *forw;
+ struct datagram *back;
+} datagram_queue;
+
+typedef struct name_queue {
+ struct name_entry head;
+ mutex_t mtx;
+} name_queue_t;
+
+#define NETBIOS_EMPTY_NAME (unsigned char *)""
+
+#define NETBIOS_NAME_IS_STAR(name) \
+ (bcmp(name, "*\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", NETBIOS_NAME_SZ) == 0)
+
+void smb_netbios_chg_status(uint32_t status, int set);
+
+/*
+ * Name Cache Functions
+ */
+int smb_netbios_cache_init(void);
+void smb_netbios_cache_fini(void);
+void smb_netbios_cache_dump(void);
+void smb_netbios_cache_print(void);
+void smb_netbios_cache_diag(char ** pbuf);
+int smb_netbios_cache_count(void);
+void smb_netbios_cache_clean(void);
+void smb_netbios_cache_reset_ttl(void);
+void smb_netbios_cache_delete_locals(name_queue_t *delq);
+void smb_netbios_cache_refresh(name_queue_t *refq);
+
+int smb_netbios_cache_insert(struct name_entry *name);
+int smb_netbios_cache_insert_list(struct name_entry *name);
+void smb_netbios_cache_delete(struct name_entry *name);
+int smb_netbios_cache_delete_addr(struct name_entry *name);
+struct name_entry *smb_netbios_cache_lookup(struct name_entry *name);
+struct name_entry *smb_netbios_cache_lookup_addr(struct name_entry *name);
+void smb_netbios_cache_update_entry(struct name_entry *entry,
+ struct name_entry *name);
+void smb_netbios_cache_unlock_entry(struct name_entry *name);
+unsigned char *smb_netbios_cache_status(unsigned char *buf, int bufsize,
+ unsigned char *scope);
+
+void smb_netbios_name_dump(struct name_entry *entry);
+void smb_netbios_name_logf(struct name_entry *entry);
+void smb_netbios_name_freeaddrs(struct name_entry *entry);
+struct name_entry *smb_netbios_name_dup(struct name_entry *entry,
+ int alladdr);
+
+/* Name service functions */
+void *smb_netbios_name_service_daemon(void *);
+void smb_init_name_struct(unsigned char *, char,
+ unsigned char *, uint32_t, unsigned short,
+ uint32_t, uint32_t, struct name_entry *);
+
+struct name_entry *smb_name_find_name(struct name_entry *name);
+int smb_name_add_name(struct name_entry *name);
+int smb_name_delete_name(struct name_entry *name);
+void smb_name_unlock_name(struct name_entry *name);
+
+void smb_netbios_name_config(void);
+void smb_netbios_name_unconfig(void);
+void smb_netbios_name_tick(void);
+
+int smb_first_level_name_encode(struct name_entry *name,
+ unsigned char *out, int max_out);
+int smb_first_level_name_decode(unsigned char *in,
+ struct name_entry *name);
+void smb_encode_netbios_name(unsigned char *name,
+ char suffix, unsigned char *scope,
+ struct name_entry *dest);
+
+/* Datagram service functions */
+void *smb_netbios_datagram_service_daemon(void *);
+int smb_netbios_datagram_send(struct name_entry *,
+ struct name_entry *, unsigned char *, int);
+void smb_netbios_datagram_tick(void);
+
+
+/* browser functions */
+void smb_browser_config(void);
+void *smb_browser_dispatch(void *arg);
+void *smb_browser_daemon(void *);
+int smb_net_id(uint32_t ipaddr);
+struct name_entry *smb_browser_get_srvname(unsigned short netid);
+int smb_browser_load_transact_header(unsigned char *buffer,
+ int maxcnt, int data_count, int reply, char *mailbox);
+
+/* Netlogon function */
+/*
+ * smb_netlogon_receive
+ *
+ * This is where we handle all incoming NetLogon messages. Currently, we
+ * ignore requests from anyone else. We are only interested in responses
+ * to our own requests. The NetLogonResponse provides the name of the PDC.
+ * If we don't already have a controller name, we use the name provided
+ * in the message. Otherwise we use the name already in the environment.
+ */
+void smb_netlogon_receive(struct datagram *datagram, char *mailbox,
+ unsigned char *data, int datalen);
+
+#endif /* _SMB_NETBIOS_H_ */
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_cache.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_cache.c
new file mode 100644
index 0000000000..1e47658700
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_cache.c
@@ -0,0 +1,776 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <synch.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <smbsrv/libsmbns.h>
+#include <smbns_netbios.h>
+
+#define NETBIOS_HTAB_SZ 128
+#define NETBIOS_HKEY_SZ (NETBIOS_NAME_SZ + NETBIOS_DOMAIN_NAME_MAX)
+
+#define NETBIOS_NAMEBUF char namebuf[20]
+
+#define NETBIOS_SAME_IP(addr1, addr2) \
+ ((addr1)->sin.sin_addr.s_addr == (addr2)->sin.sin_addr.s_addr)
+
+int smb_netbios_name_debug = 0;
+
+typedef char nb_key_t[NETBIOS_HKEY_SZ];
+static HT_HANDLE *smb_netbios_cache = 0;
+static rwlock_t nb_cache_lock;
+
+static char *smb_strname(struct name_entry *name, char *buf, int bufsize);
+static void hash_callback(HT_ITEM *item);
+static int smb_netbios_match(const char *key1, const char *key2, size_t n);
+static void smb_netbios_cache_key(char *key, unsigned char *name,
+ unsigned char *scope);
+
+int
+smb_netbios_cache_init()
+{
+ (void) rw_wrlock(&nb_cache_lock);
+ if (smb_netbios_cache == 0) {
+ smb_netbios_cache = ht_create_table(NETBIOS_HTAB_SZ,
+ NETBIOS_HKEY_SZ, HTHF_FIXED_KEY);
+ if (smb_netbios_cache == 0) {
+ syslog(LOG_ERR,
+ "smbd: cannot create NetBIOS name cache");
+ (void) rw_unlock(&nb_cache_lock);
+ return (0);
+ }
+ (void) ht_register_callback(smb_netbios_cache, hash_callback);
+ ht_set_cmpfn(smb_netbios_cache, smb_netbios_match);
+ }
+ (void) rw_unlock(&nb_cache_lock);
+
+ return (1);
+}
+
+void
+smb_netbios_cache_fini()
+{
+ (void) rw_wrlock(&nb_cache_lock);
+ ht_destroy_table(smb_netbios_cache);
+ smb_netbios_cache = 0;
+ (void) rw_unlock(&nb_cache_lock);
+}
+
+void
+smb_netbios_cache_clean()
+{
+ (void) rw_wrlock(&nb_cache_lock);
+ (void) ht_clean_table(smb_netbios_cache);
+ (void) rw_unlock(&nb_cache_lock);
+}
+
+/*
+ * smb_netbios_cache_lookup
+ *
+ * Searches the name cache for the given entry, if found
+ * the entry will be locked before returning to caller
+ * so caller MUST unlock the entry after it's done with it.
+ */
+struct name_entry *
+smb_netbios_cache_lookup(struct name_entry *name)
+{
+ HT_ITEM *item;
+ nb_key_t key;
+ struct name_entry *entry = NULL;
+ unsigned char scope[SMB_PI_MAX_SCOPE];
+ unsigned char hostname[MAXHOSTNAMELEN];
+
+ if (NETBIOS_NAME_IS_STAR(name->name)) {
+ /* Return our address */
+ smb_config_rdlock();
+ (void) strlcpy((char *)scope,
+ smb_config_getstr(SMB_CI_NBSCOPE), sizeof (scope));
+ (void) utf8_strupr((char *)scope);
+ smb_config_unlock();
+
+ if (smb_getnetbiosname((char *)hostname, MAXHOSTNAMELEN) != 0)
+ return (NULL);
+
+ smb_encode_netbios_name(hostname, 0x00, scope, name);
+ }
+
+ (void) rw_rdlock(&nb_cache_lock);
+
+ smb_netbios_cache_key(key, name->name, name->scope);
+ item = ht_find_item(smb_netbios_cache, key);
+ if (item) {
+ entry = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&entry->mtx);
+ if ((entry->attributes & NAME_ATTR_CONFLICT) != 0) {
+ (void) mutex_unlock(&entry->mtx);
+ entry = NULL;
+ }
+ }
+
+ (void) rw_unlock(&nb_cache_lock);
+ return (entry);
+}
+
+void
+smb_netbios_cache_unlock_entry(struct name_entry *name)
+{
+ if (name)
+ (void) mutex_unlock(&name->mtx);
+}
+
+/*
+ * smb_netbios_cache_lookup_addr
+ *
+ * lookup the given 'name' in the cache and then checks
+ * if the address also matches with the found entry.
+ * 'name' is supposed to contain only one address.
+ *
+ * The found entry will be locked before returning to caller
+ * so caller MUST unlock the entry after it's done with it.
+ */
+struct name_entry *
+smb_netbios_cache_lookup_addr(struct name_entry *name)
+{
+ struct name_entry *entry = 0;
+ struct addr_entry *addr;
+ struct addr_entry *name_addr;
+ HT_ITEM *item;
+ nb_key_t key;
+
+ (void) rw_rdlock(&nb_cache_lock);
+ smb_netbios_cache_key(key, name->name, name->scope);
+ item = ht_find_item(smb_netbios_cache, key);
+
+ if (item && item->hi_data) {
+ name_addr = &name->addr_list;
+ entry = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&entry->mtx);
+ addr = &entry->addr_list;
+ do {
+ if (NETBIOS_SAME_IP(addr, name_addr)) {
+ /* note that entry lock isn't released here */
+ (void) rw_unlock(&nb_cache_lock);
+ return (entry);
+ }
+ addr = addr->forw;
+ } while (addr != &entry->addr_list);
+ (void) mutex_unlock(&entry->mtx);
+ }
+
+ (void) rw_unlock(&nb_cache_lock);
+ return (0);
+}
+
+int
+smb_netbios_cache_insert(struct name_entry *name)
+{
+ struct name_entry *entry;
+ struct addr_entry *addr;
+ struct addr_entry *name_addr;
+ HT_ITEM *item;
+ nb_key_t key;
+
+ /* No point in adding a name with IP address 255.255.255.255 */
+ if (name->addr_list.sin.sin_addr.s_addr == 0xffffffff)
+ return (0);
+
+ (void) rw_wrlock(&nb_cache_lock);
+ smb_netbios_cache_key(key, name->name, name->scope);
+ item = ht_find_item(smb_netbios_cache, key);
+
+ if (item && item->hi_data) {
+ /* Name already exists */
+ entry = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&entry->mtx);
+
+ name_addr = &name->addr_list;
+ addr = &entry->addr_list;
+ if (NETBIOS_SAME_IP(addr, name_addr) &&
+ (addr->sin.sin_port == name_addr->sin.sin_port)) {
+ entry->attributes |=
+ name_addr->attributes & NAME_ATTR_LOCAL;
+ syslog(LOG_DEBUG, "cache_insert: exists");
+ (void) mutex_unlock(&entry->mtx);
+ (void) rw_unlock(&nb_cache_lock);
+ return (0); /* exists */
+ }
+
+ /* Was not primary: looks for others */
+ for (addr = entry->addr_list.forw;
+ addr != &entry->addr_list; addr = addr->forw) {
+ if (NETBIOS_SAME_IP(addr, name_addr) &&
+ (addr->sin.sin_port == name_addr->sin.sin_port)) {
+ syslog(LOG_DEBUG, "cache_insert: dup");
+ (void) mutex_unlock(&entry->mtx);
+ (void) rw_unlock(&nb_cache_lock);
+ return (0); /* exists */
+ }
+ }
+
+ addr = (struct addr_entry *)malloc(sizeof (struct addr_entry));
+ if (addr == 0) {
+ (void) mutex_unlock(&entry->mtx);
+ (void) rw_unlock(&nb_cache_lock);
+ return (-1);
+ }
+ *addr = name->addr_list;
+ entry->attributes |= addr->attributes;
+ QUEUE_INSERT_TAIL(&entry->addr_list, addr);
+ (void) mutex_unlock(&entry->mtx);
+ (void) rw_unlock(&nb_cache_lock);
+ return (0);
+ }
+
+ entry = (struct name_entry *)malloc(sizeof (struct name_entry));
+ if (entry == 0) {
+ (void) rw_unlock(&nb_cache_lock);
+ return (-1);
+ }
+ *entry = *name;
+ entry->addr_list.forw = entry->addr_list.back = &entry->addr_list;
+ entry->attributes |= entry->addr_list.attributes;
+ (void) mutex_init(&entry->mtx, 0, 0);
+ if (ht_replace_item(smb_netbios_cache, key, entry) == 0) {
+ free(entry);
+ (void) rw_unlock(&nb_cache_lock);
+ return (-1);
+ }
+
+ (void) rw_unlock(&nb_cache_lock);
+ return (0);
+}
+
+
+void
+smb_netbios_cache_delete(struct name_entry *name)
+{
+ nb_key_t key;
+ HT_ITEM *item;
+ struct name_entry *entry;
+
+ (void) rw_wrlock(&nb_cache_lock);
+ smb_netbios_cache_key(key, name->name, name->scope);
+ item = ht_find_item(smb_netbios_cache, key);
+ if (item && item->hi_data) {
+ entry = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&entry->mtx);
+ ht_mark_delete(smb_netbios_cache, item);
+ (void) mutex_unlock(&entry->mtx);
+ }
+ (void) rw_unlock(&nb_cache_lock);
+}
+
+/*
+ * smb_netbios_cache_insert_list
+ *
+ * Insert a name with multiple addresses
+ */
+int
+smb_netbios_cache_insert_list(struct name_entry *name)
+{
+ struct name_entry entry;
+ struct addr_entry *addr;
+
+ addr = &name->addr_list;
+ do {
+ smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, name->scope,
+ addr->sin.sin_addr.s_addr,
+ addr->sin.sin_port,
+ name->attributes,
+ addr->attributes,
+ &entry);
+ (void) memcpy(entry.name, name->name, NETBIOS_NAME_SZ);
+ entry.addr_list.refresh_ttl = entry.addr_list.ttl =
+ addr->refresh_ttl;
+ (void) smb_netbios_cache_insert(&entry);
+ addr = addr->forw;
+ } while (addr != &name->addr_list);
+
+ return (0);
+}
+
+void
+smb_netbios_cache_update_entry(struct name_entry *entry,
+ struct name_entry *name)
+{
+ struct addr_entry *addr;
+ struct addr_entry *name_addr;
+
+ addr = &entry->addr_list;
+ name_addr = &name->addr_list;
+
+ if (IS_UNIQUE(entry->attributes)) {
+ do {
+ addr->ttl = name_addr->ttl;
+ addr = addr->forw;
+ } while (addr != &entry->addr_list);
+
+ } else {
+ do {
+ if (NETBIOS_SAME_IP(addr, name_addr) &&
+ (addr->sin.sin_port == name_addr->sin.sin_port)) {
+ addr->ttl = name_addr->ttl;
+ return;
+ }
+ addr = addr->forw;
+ } while (addr != &entry->addr_list);
+ }
+}
+
+/*
+ * smb_netbios_cache_status
+ *
+ * Scan the name cache and gather status for
+ * Node Status response for names in the given scope
+ */
+unsigned char *
+smb_netbios_cache_status(unsigned char *buf, int bufsize, unsigned char *scope)
+{
+ HT_ITERATOR hti;
+ HT_ITEM *item;
+ struct name_entry *name;
+ unsigned char *numnames;
+ unsigned char *scan;
+ unsigned char *scan_end;
+
+ scan = buf;
+ scan_end = scan + bufsize;
+
+ numnames = scan++;
+ *numnames = 0;
+
+ (void) rw_rdlock(&nb_cache_lock);
+ item = ht_findfirst(smb_netbios_cache, &hti);
+ do {
+ if (item == 0)
+ break;
+
+ if (item->hi_data == 0)
+ continue;
+
+ if ((scan + NETBIOS_NAME_SZ + 2) >= scan_end)
+ /* no room for adding next entry */
+ break;
+
+ name = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&name->mtx);
+
+ if (IS_LOCAL(name->attributes) &&
+ (strcasecmp((char *)scope, (char *)name->scope) == 0)) {
+ bcopy(name->name, scan, NETBIOS_NAME_SZ);
+ scan += NETBIOS_NAME_SZ;
+ *scan++ = PUBLIC_BITS(name->attributes) >> 8;
+ *scan++ = PUBLIC_BITS(name->attributes);
+ (*numnames)++;
+ }
+
+ (void) mutex_unlock(&name->mtx);
+ } while ((item = ht_findnext(&hti)) != 0);
+ (void) rw_unlock(&nb_cache_lock);
+
+ return (scan);
+}
+
+void
+smb_netbios_cache_reset_ttl()
+{
+ struct addr_entry *addr;
+ struct name_entry *name;
+ HT_ITERATOR hti;
+ HT_ITEM *item;
+
+ (void) rw_rdlock(&nb_cache_lock);
+ item = ht_findfirst(smb_netbios_cache, &hti);
+ do {
+ if (item == 0)
+ break;
+
+ if (item->hi_data == 0)
+ continue;
+
+ name = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&name->mtx);
+
+ addr = &name->addr_list;
+ do {
+ if (addr->ttl < 1) {
+ if (addr->refresh_ttl)
+ addr->ttl = addr->refresh_ttl;
+ else
+ addr->refresh_ttl = addr->ttl =
+ TO_SECONDS(DEFAULT_TTL);
+ }
+ addr = addr->forw;
+ } while (addr != &name->addr_list);
+
+ (void) mutex_unlock(&name->mtx);
+ } while ((item = ht_findnext(&hti)) != 0);
+ (void) rw_unlock(&nb_cache_lock);
+}
+
+/*
+ * Returns TRUE when given name is added to the refresh queue
+ * FALSE if not.
+ */
+static boolean_t
+smb_netbios_cache_insrefq(name_queue_t *refq, HT_ITEM *item)
+{
+ struct name_entry *name;
+ struct name_entry *refent;
+
+ name = (struct name_entry *)item->hi_data;
+
+ if (IS_LOCAL(name->attributes)) {
+ if (IS_UNIQUE(name->attributes)) {
+ refent = smb_netbios_name_dup(name, 1);
+ if (refent)
+ QUEUE_INSERT_TAIL(&refq->head, refent)
+
+ /* next name */
+ return (B_TRUE);
+ }
+ } else {
+ ht_mark_delete(smb_netbios_cache, item);
+ refent = smb_netbios_name_dup(name, 0);
+ if (refent)
+ QUEUE_INSERT_TAIL(&refq->head, refent)
+
+ /* next name */
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * smb_netbios_cache_refresh
+ *
+ * Scans the name cache and add all local unique names
+ * and non-local names the passed refresh queue. Non-
+ * local names will also be marked as deleted.
+ *
+ * NOTE that the caller MUST protect the queue using
+ * its mutex
+ */
+void
+smb_netbios_cache_refresh(name_queue_t *refq)
+{
+ struct name_entry *name;
+ struct addr_entry *addr;
+ HT_ITERATOR hti;
+ HT_ITEM *item;
+
+ bzero(&refq->head, sizeof (refq->head));
+ refq->head.forw = refq->head.back = &refq->head;
+
+ (void) rw_rdlock(&nb_cache_lock);
+ item = ht_findfirst(smb_netbios_cache, &hti);
+ do { /* name loop */
+ if (item == 0)
+ break;
+
+ if (item->hi_data == 0)
+ continue;
+
+ name = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&name->mtx);
+
+ addr = &name->addr_list;
+ do { /* address loop */
+ if (addr->ttl > 0) {
+ addr->ttl--;
+ if (addr->ttl == 0) {
+ if (smb_netbios_cache_insrefq(refq,
+ item))
+ break;
+ }
+ }
+ addr = addr->forw;
+ } while (addr != &name->addr_list);
+
+ (void) mutex_unlock(&name->mtx);
+ } while ((item = ht_findnext(&hti)) != 0);
+ (void) rw_unlock(&nb_cache_lock);
+}
+
+/*
+ * smb_netbios_cache_delete_locals
+ *
+ * Scans the name cache and add all local names to
+ * the passed delete queue.
+ *
+ * NOTE that the caller MUST protect the queue using
+ * its mutex
+ */
+void
+smb_netbios_cache_delete_locals(name_queue_t *delq)
+{
+ struct name_entry *entry;
+ struct name_entry *delent;
+ HT_ITERATOR hti;
+ HT_ITEM *item;
+
+ bzero(&delq->head, sizeof (delq->head));
+ delq->head.forw = delq->head.back = &delq->head;
+
+ (void) rw_wrlock(&nb_cache_lock);
+ item = ht_findfirst(smb_netbios_cache, &hti);
+ do {
+ if (item == 0)
+ break;
+
+ if (item->hi_data == 0)
+ continue;
+
+ entry = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&entry->mtx);
+
+ if (IS_LOCAL(entry->attributes)) {
+ ht_mark_delete(smb_netbios_cache, item);
+ delent = smb_netbios_name_dup(entry, 1);
+ if (delent)
+ QUEUE_INSERT_TAIL(&delq->head, delent)
+ }
+
+ (void) mutex_unlock(&entry->mtx);
+ } while ((item = ht_findnext(&hti)) != 0);
+ (void) rw_unlock(&nb_cache_lock);
+}
+
+void
+smb_netbios_name_freeaddrs(struct name_entry *entry)
+{
+ struct addr_entry *addr;
+
+ if (entry == 0)
+ return;
+
+ while ((addr = entry->addr_list.forw) != &entry->addr_list) {
+ QUEUE_CLIP(addr);
+ free(addr);
+ }
+}
+
+/*
+ * smb_netbios_cache_count
+ *
+ * Returns the number of names in the cache
+ */
+int
+smb_netbios_cache_count()
+{
+ int cnt;
+
+ (void) rw_rdlock(&nb_cache_lock);
+ cnt = ht_get_total_items(smb_netbios_cache);
+ (void) rw_unlock(&nb_cache_lock);
+
+ return (cnt);
+}
+
+void
+smb_netbios_cache_dump(void)
+{
+ struct name_entry *name;
+ HT_ITERATOR hti;
+ HT_ITEM *item;
+
+ (void) rw_rdlock(&nb_cache_lock);
+ item = ht_findfirst(smb_netbios_cache, &hti);
+ while (item) {
+ if (item->hi_data) {
+ name = (struct name_entry *)item->hi_data;
+ (void) mutex_lock(&name->mtx);
+ smb_netbios_name_dump(name);
+ (void) mutex_unlock(&name->mtx);
+ }
+ item = ht_findnext(&hti);
+ }
+ (void) rw_unlock(&nb_cache_lock);
+}
+
+void
+smb_netbios_name_dump(struct name_entry *entry)
+{
+ struct addr_entry *addr;
+ int count = 0;
+
+ if (smb_netbios_name_debug == 0)
+ return;
+
+ syslog(LOG_DEBUG, "name='%15.15s<%02X>' scope='%s' attr=0x%x",
+ entry->name, entry->name[15],
+ entry->scope, entry->attributes);
+ addr = &entry->addr_list;
+ do {
+ syslog(LOG_DEBUG, "addr_list[%d]:", count++);
+ syslog(LOG_DEBUG, " attributes = 0x%x", addr->attributes);
+ syslog(LOG_DEBUG, " conflict_timer = %d",
+ addr->conflict_timer);
+ syslog(LOG_DEBUG, " refresh_ttl = %d", addr->refresh_ttl);
+ syslog(LOG_DEBUG, " ttl = %d", addr->ttl);
+ syslog(LOG_DEBUG, " sin.sin_addr = %s",
+ inet_ntoa(addr->sin.sin_addr));
+ syslog(LOG_DEBUG, " sin.sin_port = %d", addr->sin.sin_port);
+ syslog(LOG_DEBUG, " sin.sinlen = %d", addr->sinlen);
+ addr = addr->forw;
+ } while (addr != &entry->addr_list);
+}
+
+void
+smb_netbios_name_logf(struct name_entry *entry)
+{
+ struct addr_entry *addr;
+ NETBIOS_NAMEBUF;
+
+ (void) smb_strname(entry, namebuf, sizeof (namebuf));
+ syslog(LOG_DEBUG, "%s flags=0x%x\n", namebuf, entry->attributes);
+ addr = &entry->addr_list;
+ do {
+ syslog(LOG_DEBUG, " %s ttl=%d flags=0x%x",
+ inet_ntoa(addr->sin.sin_addr),
+ addr->ttl, addr->attributes);
+ addr = addr->forw;
+ } while (addr && (addr != &entry->addr_list));
+}
+
+/*
+ * smb_netbios_name_dup
+ *
+ * Duplicate the given name entry. If 'alladdr' is 0 only
+ * copy the primary address otherwise duplicate all the
+ * addresses. NOTE that the duplicate structure is not
+ * like a regular cache entry i.e. it's a contiguous block
+ * of memory and each addr structure doesn't have it's own
+ * allocated memory. So, the returned structure can be freed
+ * by one free call.
+ */
+struct name_entry *
+smb_netbios_name_dup(struct name_entry *entry, int alladdr)
+{
+ struct addr_entry *addr;
+ struct addr_entry *dup_addr;
+ struct name_entry *dup;
+ int addr_cnt = 0;
+ int size = 0;
+
+ if (alladdr) {
+ addr = entry->addr_list.forw;
+ while (addr && (addr != &entry->addr_list)) {
+ addr_cnt++;
+ addr = addr->forw;
+ }
+ }
+
+ size = sizeof (struct name_entry) +
+ (addr_cnt * sizeof (struct addr_entry));
+ dup = (struct name_entry *)malloc(size);
+ if (dup == 0)
+ return (0);
+
+ bzero(dup, size);
+
+ dup->forw = dup->back = dup;
+ dup->attributes = entry->attributes;
+ (void) memcpy(dup->name, entry->name, NETBIOS_NAME_SZ);
+ (void) strlcpy((char *)dup->scope, (char *)entry->scope,
+ NETBIOS_DOMAIN_NAME_MAX);
+ dup->addr_list = entry->addr_list;
+ dup->addr_list.forw = dup->addr_list.back = &dup->addr_list;
+
+ if (alladdr == 0)
+ return (dup);
+
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ dup_addr = (struct addr_entry *)((unsigned char *)dup +
+ sizeof (struct name_entry));
+
+ addr = entry->addr_list.forw;
+ while (addr && (addr != &entry->addr_list)) {
+ *dup_addr = *addr;
+ QUEUE_INSERT_TAIL(&dup->addr_list, dup_addr);
+ addr = addr->forw;
+ dup_addr++;
+ }
+
+ return (dup);
+}
+
+static char *
+smb_strname(struct name_entry *name, char *buf, int bufsize)
+{
+ char *p;
+
+ (void) snprintf(buf, bufsize, "%15.15s", name->name);
+ p = strchr(buf, ' ');
+ if (p)
+ (void) snprintf(p, 5, "<%02X>", name->name[15]);
+
+ return (buf);
+}
+
+static void
+hash_callback(HT_ITEM *item)
+{
+ struct name_entry *entry;
+
+ if (item && item->hi_data) {
+ entry = (struct name_entry *)item->hi_data;
+ smb_netbios_name_freeaddrs(entry);
+ free(entry);
+ }
+}
+
+
+/*ARGSUSED*/
+static int
+smb_netbios_match(const char *key1, const char *key2, size_t n)
+{
+ int res;
+
+ res = bcmp(key1, key2, NETBIOS_NAME_SZ);
+ if (res == 0) {
+ /* Names are the same, compare scopes */
+ res = strcmp(key1 + NETBIOS_NAME_SZ, key2 + NETBIOS_NAME_SZ);
+ }
+
+ return (res);
+}
+
+static void
+smb_netbios_cache_key(char *key, unsigned char *name, unsigned char *scope)
+{
+ bzero(key, NETBIOS_HKEY_SZ);
+ (void) memcpy(key, name, NETBIOS_NAME_SZ);
+ (void) memcpy(key + NETBIOS_NAME_SZ, scope,
+ strlen((const char *)scope));
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c
new file mode 100644
index 0000000000..2775ccfe7a
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c
@@ -0,0 +1,1061 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Description:
+ *
+ * Contains base code for netbios datagram service.
+ *
+ * Relavent sections from RFC1002:
+ *
+ * 5.3. NetBIOS DATAGRAM SERVICE PROTOCOLS
+ *
+ * The following are GLOBAL variables and should be NetBIOS user
+ * configurable:
+ *
+ * - SCOPE_ID: the non-leaf section of the domain name preceded by a
+ * '.' which represents the domain of the NetBIOS scope for the
+ * NetBIOS name. The following protocol description only supports
+ * single scope operation.
+ *
+ * - MAX_DATAGRAM_LENGTH: the maximum length of an IP datagram. The
+ * minimal maximum length defined in for IP is 576 bytes. This
+ * value is used when determining whether to fragment a NetBIOS
+ * datagram. Implementations are expected to be capable of
+ * receiving unfragmented NetBIOS datagrams up to their maximum
+ * size.
+ *
+ * - BROADCAST_ADDRESS: the IP address B-nodes use to send datagrams
+ * with group name destinations and broadcast datagrams. The
+ * default is the IP broadcast address for a single IP network.
+ *
+ *
+ * The following are Defined Constants for the NetBIOS Datagram
+ * Service:
+ *
+ * - DGM_SRVC_UDP_PORT: the globally well-known UDP port allocated
+ * where the NetBIOS Datagram Service receives UDP packets. See
+ * section 6, "Defined Constants", for its value.
+ */
+
+/*
+ *
+ * 6. DEFINED CONSTANTS AND VARIABLES
+ *
+ * GENERAL:
+ *
+ * SCOPE_ID The name of the NetBIOS scope.
+ *
+ * This is expressed as a character
+ * string meeting the requirements of
+ * the domain name system and without
+ * a leading or trailing "dot".
+ *
+ * An implementation may elect to make
+ * this a single global value for the
+ * node or allow it to be specified
+ * with each separate NetBIOS name
+ * (thus permitting cross-scope
+ * references.)
+ *
+ * BROADCAST_ADDRESS An IP address composed of the
+ * node network and subnetwork
+ * numbers with all remaining bits set
+ * to one.
+ *
+ * I.e. "Specific subnet" broadcast
+ * addressing according to section 2.3
+ * of RFC 950.
+ *
+ * BCAST_REQ_RETRY_TIMEOUT 250 milliseconds.
+ * An adaptive timer may be used.
+ *
+ * BCAST_REQ_RETRY_COUNT 3
+ *
+ * UCAST_REQ_RETRY_TIMEOUT 5 seconds
+ * An adaptive timer may be used.
+ *
+ * UCAST_REQ_RETRY_COUNT 3
+ *
+ * MAX_DATAGRAM_LENGTH 576 bytes (default)
+ *
+ * DATAGRAM SERVICE:
+ *
+ * DGM_SRVC_UDP_PORT 138 (decimal)
+ *
+ * FRAGMENT_TO 2 seconds (default)
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <synch.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <smbns_netbios.h>
+
+#include <smbsrv/libsmbns.h>
+
+static int datagram_sock = -1;
+static short datagram_id = 1;
+static struct datagram_queue smb_datagram_queue;
+static mutex_t smb_dgq_mtx;
+
+/*
+ * Function: smb_netbios_datagram_tick(void)
+ *
+ * Description:
+ *
+ * Called once a second to handle time to live timeouts in
+ * datagram assembly queue.
+ *
+ * Inputs:
+ *
+ * Returns:
+ * void -> Nothing at all...
+ */
+
+void
+smb_netbios_datagram_tick(void)
+{
+ struct datagram *entry;
+ struct datagram *next;
+
+ (void) mutex_lock(&smb_dgq_mtx);
+
+ for (entry = smb_datagram_queue.forw;
+ entry != (struct datagram *)((uintptr_t)&smb_datagram_queue);
+ entry = next) {
+ next = entry->forw;
+ if (--entry->discard_timer == 0) {
+ /* Toss it */
+ QUEUE_CLIP(entry);
+ free(entry);
+ }
+ }
+ (void) mutex_unlock(&smb_dgq_mtx);
+}
+
+void
+smb_netbios_datagram_fini()
+{
+ struct datagram *entry;
+
+ (void) mutex_lock(&smb_dgq_mtx);
+ while ((entry = smb_datagram_queue.forw) !=
+ (struct datagram *)((uintptr_t)&smb_datagram_queue)) {
+ QUEUE_CLIP(entry);
+ free(entry);
+ }
+ (void) mutex_unlock(&smb_dgq_mtx);
+}
+
+/*
+ * Function: int smb_netbios_send_Bnode_datagram(unsigned char *data,
+ * struct name_entry *source, struct name_entry *destination,
+ * uint32_t broadcast)
+ *
+ * Description from rfc1002:
+ *
+ * 5.3.1. B NODE TRANSMISSION OF NetBIOS DATAGRAMS
+ *
+ * PROCEDURE send_datagram(data, source, destination, broadcast)
+ *
+ * (*
+ * * user initiated processing on B node
+ * *)
+ *
+ * BEGIN
+ * group = FALSE;
+ *
+ * do name discovery on destination name, returns name type and
+ * IP address;
+ *
+ * IF name type is group name THEN
+ * BEGIN
+ * group = TRUE;
+ * END
+ *
+ * (*
+ * * build datagram service UDP packet;
+ * *)
+ * convert source and destination NetBIOS names into
+ * half-ASCII, biased encoded name;
+ * SOURCE_NAME = cat(source, SCOPE_ID);
+ * SOURCE_IP = this nodes IP address;
+ * SOURCE_PORT = DGM_SRVC_UDP_PORT;
+ *
+ * IF NetBIOS broadcast THEN
+ * BEGIN
+ * DESTINATION_NAME = cat("*", SCOPE_ID)
+ * END
+ * ELSE
+ * BEGIN
+ * DESTINATION_NAME = cat(destination, SCOPE_ID)
+ * END
+ *
+ * MSG_TYPE = select_one_from_set
+ * {BROADCAST, DIRECT_UNIQUE, DIRECT_GROUP}
+ * DGM_ID = next transaction id for Datagrams;
+ * DGM_LENGTH = length of data + length of second level encoded
+ * source and destination names;
+ *
+ * IF (length of the NetBIOS Datagram, including UDP and
+ * IP headers, > MAX_DATAGRAM_LENGTH) THEN
+ * BEGIN
+ * (*
+ * * fragment NetBIOS datagram into 2 UDP packets
+ * *)
+ * Put names into 1st UDP packet and any data that fits
+ * after names;
+ * Set MORE and FIRST bits in 1st UDP packets FLAGS;
+ * OFFSET in 1st UDP = 0;
+ *
+ * Replicate NetBIOS Datagram header from 1st UDP packet
+ * into 2nd UDP packet;
+ * Put rest of data in 2nd UDP packet;
+ * Clear MORE and FIRST bits in 2nd UDP packets FLAGS;
+ * OFFSET in 2nd UDP = DGM_LENGTH - number of name and
+ * data bytes in 1st UDP;
+ * END
+ * BEGIN
+ * (*
+ * * Only need one UDP packet
+ * *)
+ * USER_DATA = data;
+ * Clear MORE bit and set FIRST bit in FLAGS;
+ * OFFSET = 0;
+ * END
+ *
+ * IF (group == TRUE) OR (NetBIOS broadcast) THEN
+ * BEGIN
+ * send UDP packet(s) to BROADCAST_ADDRESS;
+ * END
+ * ELSE
+ * BEGIN
+ * send UDP packet(s) to IP address returned by name
+ * discovery;
+ * END
+ * END (* procedure *)
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MSG_TYPE | FLAGS | DGM_ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_IP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_PORT | DGM_LENGTH |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PACKET_OFFSET |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * MSG_TYPE values (in hexidecimal):
+ *
+ * 10 - DIRECT_UNIQUE DATAGRAM
+ * 11 - DIRECT_GROUP DATAGRAM
+ * 12 - BROADCAST DATAGRAM
+ * 13 - DATAGRAM ERROR
+ * 14 - DATAGRAM QUERY REQUEST
+ * 15 - DATAGRAM POSITIVE QUERY RESPONSE
+ * 16 - DATAGRAM NEGATIVE QUERY RESPONSE
+ *
+ * Bit definitions of the FLAGS field:
+ *
+ * 0 1 2 3 4 5 6 7
+ * +---+---+---+---+---+---+---+---+
+ * | 0 | 0 | 0 | 0 | SNT | F | M |
+ * +---+---+---+---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description
+ *
+ * M 7 MORE flag, If set then more NetBIOS datagram
+ * fragments follow.
+ *
+ * F 6 FIRST packet flag, If set then this is first
+ * (and possibly only) fragment of NetBIOS
+ * datagram
+ *
+ * SNT 4,5 Source End-Node type:
+ * 00 = B node
+ * 01 = P node
+ * 10 = M node
+ * 11 = NBDD
+ * RESERVED 0-3 Reserved, must be zero (0)
+ * (But MS sets bit 3 in this field)
+ *
+ */
+
+int
+smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest,
+ unsigned char *data, int length)
+{
+ uint32_t ipaddr;
+ size_t count, srclen, destlen, sinlen;
+ struct addr_entry *addr;
+ struct sockaddr_in sin;
+ char *buffer;
+ char ha_source[NETBIOS_DOMAIN_NAME_MAX];
+ char ha_dest[NETBIOS_DOMAIN_NAME_MAX];
+ net_cfg_t cfg;
+
+ (void) smb_first_level_name_encode(src, (unsigned char *)ha_source,
+ sizeof (ha_source));
+ srclen = strlen(ha_source) + 1;
+
+ (void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest,
+ sizeof (ha_dest));
+ destlen = strlen(ha_dest) + 1;
+
+ /* give some extra room */
+ buffer = (char *)malloc(MAX_DATAGRAM_LENGTH * 4);
+ if (buffer == 0) {
+ syslog(LOG_ERR, "netbios: datagram send (resource shortage)");
+ return (-1);
+ }
+
+ buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE;
+ switch (smb_node_type) {
+ case 'B':
+ buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST;
+ break;
+ case 'P':
+ buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST;
+ break;
+ case 'M':
+ buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST;
+ break;
+ case 'H':
+ default:
+ buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST;
+ break;
+ }
+
+ datagram_id++;
+ BE_OUT16(&buffer[2], datagram_id);
+ (void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+ (void) memcpy(&buffer[8], &src->addr_list.sin.sin_port,
+ sizeof (uint16_t));
+ BE_OUT16(&buffer[10], length + srclen + destlen);
+ BE_OUT16(&buffer[12], 0);
+
+ bcopy(ha_source, &buffer[14], srclen);
+ bcopy(ha_dest, &buffer[14 + srclen], destlen);
+ bcopy(data, &buffer[14 + srclen + destlen], length);
+ count = &buffer[14 + srclen + destlen + length] - buffer;
+
+ bzero(&sin, sizeof (sin));
+ sin.sin_family = AF_INET;
+ sinlen = sizeof (sin);
+ addr = &dest->addr_list;
+ do {
+ ipaddr = addr->sin.sin_addr.s_addr;
+ /* Don't send anything to myself... */
+ if (smb_nic_get_byip(ipaddr, &cfg) != NULL) {
+ goto next;
+ }
+
+ sin.sin_addr.s_addr = ipaddr;
+ sin.sin_port = addr->sin.sin_port;
+ (void) sendto(datagram_sock, buffer, count, 0,
+ (struct sockaddr *)&sin, sinlen);
+
+next: addr = addr->forw;
+ } while (addr != &dest->addr_list);
+ free(buffer);
+ return (0);
+}
+
+
+int
+smb_netbios_datagram_send_to_net(struct name_entry *src,
+ struct name_entry *dest, char *data, int length)
+{
+ uint32_t ipaddr;
+ size_t count, srclen, destlen, sinlen;
+ struct addr_entry *addr;
+ struct sockaddr_in sin;
+ char *buffer;
+ char ha_source[NETBIOS_DOMAIN_NAME_MAX];
+ char ha_dest[NETBIOS_DOMAIN_NAME_MAX];
+ net_cfg_t cfg;
+
+ (void) smb_first_level_name_encode(src, (unsigned char *)ha_source,
+ sizeof (ha_source));
+ srclen = strlen(ha_source) + 1;
+
+ (void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest,
+ sizeof (ha_dest));
+ destlen = strlen(ha_dest) + 1;
+
+ /* give some extra room */
+ buffer = (char *)malloc(MAX_DATAGRAM_LENGTH * 4);
+ if (buffer == 0) {
+ syslog(LOG_ERR, "netbios: datagram send (resource shortage)");
+ return (-1);
+ }
+
+ buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE;
+ switch (smb_node_type) {
+ case 'B':
+ buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST;
+ break;
+ case 'P':
+ buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST;
+ break;
+ case 'M':
+ buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST;
+ break;
+ case 'H':
+ default:
+ buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST;
+ break;
+ }
+
+ datagram_id++;
+ BE_OUT16(&buffer[2], datagram_id);
+ (void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+ (void) memcpy(&buffer[8], &src->addr_list.sin.sin_port,
+ sizeof (uint16_t));
+ BE_OUT16(&buffer[10], length + srclen + destlen);
+ BE_OUT16(&buffer[12], 0);
+
+ bcopy(ha_source, &buffer[14], srclen);
+ bcopy(ha_dest, &buffer[14 + srclen], destlen);
+ bcopy(data, &buffer[14 + srclen + destlen], length);
+ count = &buffer[14 + srclen + destlen + length] - buffer;
+
+ bzero(&sin, sizeof (sin));
+ sin.sin_family = AF_INET;
+ sinlen = sizeof (sin);
+ addr = &dest->addr_list;
+ do {
+ ipaddr = addr->sin.sin_addr.s_addr;
+ if (smb_nic_get_byip(ipaddr, &cfg) != NULL) {
+ goto next;
+ }
+ sin.sin_addr.s_addr = ipaddr;
+ sin.sin_port = addr->sin.sin_port;
+ (void) sendto(datagram_sock, buffer, count, 0,
+ (struct sockaddr *)&sin, sinlen);
+
+next: addr = addr->forw;
+ } while (addr != &dest->addr_list);
+ free(buffer);
+ return (0);
+}
+
+
+int
+smb_datagram_decode(struct datagram *datagram, int bytes)
+{
+ unsigned char *ha_src;
+ unsigned char *ha_dest;
+ unsigned char *data;
+
+ if (bytes < DATAGRAM_HEADER_LENGTH) {
+ syslog(LOG_ERR, "NbtDatagramDecode[%d]: too small packet",
+ bytes);
+ return (-1);
+ }
+
+ ha_src = &datagram->rawbuf[DATAGRAM_HEADER_LENGTH];
+ ha_dest = ha_src + strlen((char *)ha_src) + 1;
+ data = ha_dest + strlen((char *)ha_dest) + 1;
+
+ bzero(&datagram->src, sizeof (struct name_entry));
+ bzero(&datagram->dest, sizeof (struct name_entry));
+
+ datagram->rawbytes = bytes;
+ datagram->packet_type = datagram->rawbuf[0];
+ datagram->flags = datagram->rawbuf[1];
+ datagram->datagram_id = BE_IN16(&datagram->rawbuf[2]);
+
+ datagram->src.addr_list.sinlen = sizeof (struct sockaddr_in);
+ (void) memcpy(&datagram->src.addr_list.sin.sin_addr.s_addr,
+ &datagram->rawbuf[4], sizeof (uint32_t));
+ (void) memcpy(&datagram->src.addr_list.sin.sin_port,
+ &datagram->rawbuf[8], sizeof (uint16_t));
+ datagram->src.addr_list.forw = datagram->src.addr_list.back =
+ &datagram->src.addr_list;
+
+ datagram->data = data;
+ datagram->data_length = BE_IN16(&datagram->rawbuf[10]);
+ datagram->offset = BE_IN16(&datagram->rawbuf[12]);
+
+ if (smb_first_level_name_decode(ha_src, &datagram->src) < 0) {
+ syslog(LOG_DEBUG, "NbtDatagram[%s]: invalid calling name",
+ inet_ntoa(datagram->src.addr_list.sin.sin_addr));
+ syslog(LOG_DEBUG, "Calling name: <%02X>%32.32s",
+ ha_src[0], &ha_src[1]);
+ }
+
+ datagram->dest.addr_list.forw = datagram->dest.addr_list.back =
+ &datagram->dest.addr_list;
+
+ if (smb_first_level_name_decode(ha_dest, &datagram->dest) < 0) {
+ syslog(LOG_DEBUG, "NbtDatagram[%s]: invalid called name",
+ inet_ntoa(datagram->src.addr_list.sin.sin_addr));
+ syslog(LOG_DEBUG, "Called name: <%02X>%32.32s", ha_dest[0],
+ &ha_dest[1]);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Function: int smb_netbios_process_BPM_datagram(unsigned char *packet,
+ * struct addr_entry *addr)
+ *
+ * Description from rfc1002:
+ *
+ * 5.3.3. RECEPTION OF NetBIOS DATAGRAMS BY ALL NODES
+ *
+ * The following algorithm discards out of order NetBIOS Datagram
+ * fragments. An implementation which reassembles out of order
+ * NetBIOS Datagram fragments conforms to this specification. The
+ * fragment discard timer is initialized to the value FRAGMENT_TIMEOUT.
+ * This value should be user configurable. The default value is
+ * given in Section 6, "Defined Constants and Variables".
+ *
+ * PROCEDURE datagram_packet(packet)
+ *
+ * (*
+ * * processing initiated by datagram packet reception
+ * * on B, P and M nodes
+ * *)
+ * BEGIN
+ * (*
+ * * if this node is a P node, ignore
+ * * broadcast packets.
+ * *)
+ *
+ * IF this is a P node AND incoming packet is
+ * a broadcast packet THEN
+ * BEGIN
+ * discard packet;
+ * END
+ *
+ * CASE packet type OF
+ *
+ * DATAGRAM SERVICE:
+ * BEGIN
+ * IF FIRST bit in FLAGS is set THEN
+ * BEGIN
+ * IF MORE bit in FLAGS is set THEN
+ * BEGIN
+ * Save 1st UDP packet of the Datagram;
+ * Set this Datagrams fragment discard
+ * timer to FRAGMENT_TIMEOUT;
+ * return;
+ * END
+ * ELSE
+ * Datagram is composed of a single
+ * UDP packet;
+ * END
+ * ELSE
+ * BEGIN
+ * (* Have the second fragment of a Datagram *)
+ *
+ * Search for 1st fragment by source IP address
+ * and DGM_ID;
+ * IF found 1st fragment THEN
+ * Process both UDP packets;
+ * ELSE
+ * BEGIN
+ * discard 2nd fragment UDP packet;
+ * return;
+ * END
+ * END
+ *
+ * IF DESTINATION_NAME is '*' THEN
+ * BEGIN
+ * (* NetBIOS broadcast *)
+ *
+ * deliver USER_DATA from UDP packet(s) to all
+ * outstanding receive broadcast
+ * datagram requests;
+ * return;
+ * END
+ * ELSE
+ * BEGIN (* non-broadcast *)
+ * (* Datagram for Unique or Group Name *)
+ *
+ * IF DESTINATION_NAME is not present in the
+ * local name table THEN
+ * BEGIN
+ * (* destination not present *)
+ * build DATAGRAM ERROR packet, clear
+ * FIRST and MORE bit, put in
+ * this nodes IP and PORT, set
+ * ERROR_CODE;
+ * send DATAGRAM ERROR packet to
+ * source IP address and port
+ * of UDP;
+ * discard UDP packet(s);
+ * return;
+ * END
+ * ELSE
+ * BEGIN (* good *)
+ * (*
+ * * Replicate received NetBIOS datagram for
+ * * each recipient
+ * *)
+ * FOR EACH pending NetBIOS users receive
+ * datagram operation
+ * BEGIN
+ * IF source name of operation
+ * matches destination name
+ * of packet THEN
+ * BEGIN
+ * deliver USER_DATA from UDP
+ * packet(s);
+ * END
+ * END (* for each *)
+ * return;
+ * END (* good *)
+ * END (* non-broadcast *)
+ * END (* datagram service *)
+ *
+ * DATAGRAM ERROR:
+ * BEGIN
+ * (*
+ * * name service returned incorrect information
+ * *)
+ *
+ * inform local name service that incorrect
+ * information was provided;
+ *
+ * IF this is a P or M node THEN
+ * BEGIN
+ * (*
+ * * tell NetBIOS Name Server that it may
+ * * have given incorrect information
+ * *)
+ *
+ * send NAME RELEASE REQUEST with name
+ * and incorrect IP address to NetBIOS
+ * Name Server;
+ * END
+ * END (* datagram error *)
+ *
+ * END (* case *)
+ * END
+ */
+
+static struct datagram *
+smb_netbios_datagram_getq(struct datagram *datagram)
+{
+ struct datagram *prev = 0;
+
+ (void) mutex_lock(&smb_dgq_mtx);
+ for (prev = smb_datagram_queue.forw;
+ prev != (struct datagram *)((uintptr_t)&smb_datagram_queue);
+ prev = prev->forw) {
+ if (prev->src.addr_list.sin.sin_addr.s_addr ==
+ datagram->src.addr_list.sin.sin_addr.s_addr) {
+ /* Something waiting */
+ QUEUE_CLIP(prev);
+ (void) mutex_unlock(&smb_dgq_mtx);
+ bcopy(datagram->data, &prev->data[prev->data_length],
+ datagram->data_length);
+ prev->data_length += datagram->data_length;
+ free(datagram);
+ return (prev);
+ }
+ }
+ (void) mutex_unlock(&smb_dgq_mtx);
+
+ return (0);
+}
+
+static void
+smb_netbios_BPM_datagram(struct datagram *datagram)
+{
+ struct name_entry *entry = 0;
+ struct datagram *qpacket = 0;
+ pthread_t browser_dispatch;
+
+ switch (datagram->packet_type) {
+ case DATAGRAM_TYPE_BROADCAST :
+ if (smb_node_type == 'P') {
+ /*
+ * if this node is a P node, ignore
+ * broadcast packets.
+ */
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case DATAGRAM_TYPE_DIRECT_UNIQUE :
+ case DATAGRAM_TYPE_DIRECT_GROUP :
+ if ((datagram->flags & DATAGRAM_FLAGS_FIRST) != 0) {
+ if (datagram->flags & DATAGRAM_FLAGS_MORE) {
+ /* Save 1st UDP packet of the Datagram */
+ datagram->discard_timer = FRAGMENT_TIMEOUT;
+ (void) mutex_lock(&smb_dgq_mtx);
+ QUEUE_INSERT_TAIL(&smb_datagram_queue, datagram)
+ (void) mutex_unlock(&smb_dgq_mtx);
+ return;
+ }
+ /* process datagram */
+ } else {
+ qpacket = smb_netbios_datagram_getq(datagram);
+ if (qpacket) {
+ datagram = qpacket;
+ goto process_datagram;
+ }
+ break;
+ }
+
+process_datagram:
+ entry = 0;
+ if ((strcmp((char *)datagram->dest.name, "*") == 0) ||
+ ((entry =
+ smb_netbios_cache_lookup(&datagram->dest)) != 0)) {
+ if (entry) {
+ int is_local = IS_LOCAL(entry->attributes);
+ smb_netbios_cache_unlock_entry(entry);
+
+ if (is_local) {
+ (void) pthread_create(&browser_dispatch,
+ 0, smb_browser_dispatch,
+ (void *)datagram);
+ (void) pthread_detach(browser_dispatch);
+ return;
+ }
+ }
+
+ datagram->rawbuf[0] = DATAGRAM_TYPE_ERROR_DATAGRAM;
+ datagram->rawbuf[1] &= DATAGRAM_FLAGS_SRC_TYPE;
+
+ (void) memcpy(&datagram->rawbuf[4],
+ &datagram->src.addr_list.sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+ BE_OUT16(&datagram->rawbuf[8], DGM_SRVC_UDP_PORT);
+
+ (void) sendto(datagram_sock, datagram->rawbuf,
+ datagram->rawbytes, 0,
+ (struct sockaddr *)&datagram->src.addr_list.sin,
+ datagram->src.addr_list.sinlen);
+ }
+ break;
+
+ case DATAGRAM_TYPE_ERROR_DATAGRAM :
+ break;
+ }
+ free(datagram);
+}
+
+
+/*
+ * smb_netbios_process_NBDD_datagram
+ *
+ * Description from rfc1002:
+ *
+ *
+ * 5.3.4. PROTOCOLS FOR THE NBDD
+ *
+ * The key to NetBIOS Datagram forwarding service is the packet
+ * delivered to the destination end node must have the same NetBIOS
+ * header as if the source end node sent the packet directly to the
+ * destination end node. Consequently, the NBDD does not reassemble
+ * NetBIOS Datagrams. It forwards the UDP packet as is.
+ *
+ * PROCEDURE datagram_packet(packet)
+ *
+ * (*
+ * * processing initiated by a incoming datagram service
+ * * packet on a NBDD node.
+ * *)
+ *
+ * BEGIN
+ * CASE packet type OF
+ *
+ * DATAGRAM SERVICE:
+ * BEGIN
+ * IF packet was sent as a directed
+ * NetBIOS datagram THEN
+ * BEGIN
+ * (*
+ * * provide group forwarding service
+ * *
+ * * Forward datagram to each member of the
+ * * group. Can forward via:
+ * * 1) get list of group members and send
+ * * the DATAGRAM SERVICE packet unicast
+ * * to each
+ * * 2) use Group Multicast, if available
+ * * 3) combination of 1) and 2)
+ * *)
+ *
+ * ...
+ *
+ * END
+ *
+ * ELSE
+ * BEGIN
+ * (*
+ * * provide broadcast forwarding service
+ * *
+ * * Forward datagram to every node in the
+ * * NetBIOS scope. Can forward via:
+ * * 1) get list of group members and send
+ * * the DATAGRAM SERVICE packet unicast
+ * * to each
+ * * 2) use Group Multicast, if available
+ * * 3) combination of 1) and 2)
+ * *)
+ *
+ * ...
+ *
+ * END
+ * END (* datagram service *)
+ *
+ * DATAGRAM ERROR:
+ * BEGIN
+ * (*
+ * * Should never receive these because Datagrams
+ * * forwarded have source end node IP address and
+ * * port in NetBIOS header.
+ * *)
+ *
+ * send DELETE NAME REQUEST with incorrect name and
+ * IP address to NetBIOS Name Server;
+ *
+ * END (* datagram error *)
+ *
+ * DATAGRAM QUERY REQUEST:
+ * BEGIN
+ * IF can send packet to DESTINATION_NAME THEN
+ * BEGIN
+ * (*
+ * * NBDD is able to relay Datagrams for
+ * * this name
+ * *)
+ *
+ * send POSITIVE DATAGRAM QUERY RESPONSE to
+ * REQUEST source IP address and UDP port
+ * with requests DGM_ID;
+ * END
+ * ELSE
+ * BEGIN
+ * (*
+ * * NBDD is NOT able to relay Datagrams for
+ * * this name
+ * *)
+ *
+ * send NEGATIVE DATAGRAM QUERY RESPONSE to
+ * REQUEST source IP address and UDP port
+ *
+ * with requests DGM_ID;
+ * END
+ * END (* datagram query request *)
+ *
+ * END (* case *)
+ * END (* procedure *)
+ */
+
+
+/*
+ * Function: int smb_netbios_datagram_service_daemon(void)
+ *
+ * Description:
+ *
+ * 4.4. DATAGRAM SERVICE PACKETS
+ *
+ * 4.4.1. NetBIOS DATAGRAM HEADER
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MSG_TYPE | FLAGS | DGM_ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_IP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOURCE_PORT | DGM_LENGTH |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PACKET_OFFSET |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * MSG_TYPE values (in hexidecimal):
+ *
+ * 10 - DIRECT_UNIQUE DATAGRAM
+ * 11 - DIRECT_GROUP DATAGRAM
+ * 12 - BROADCAST DATAGRAM
+ * 13 - DATAGRAM ERROR
+ * 14 - DATAGRAM QUERY REQUEST
+ * 15 - DATAGRAM POSITIVE QUERY RESPONSE
+ * 16 - DATAGRAM NEGATIVE QUERY RESPONSE
+ *
+ * Bit definitions of the FLAGS field:
+ *
+ * 0 1 2 3 4 5 6 7
+ * +---+---+---+---+---+---+---+---+
+ * | 0 | 0 | 0 | 0 | SNT | F | M |
+ * +---+---+---+---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description
+ *
+ * M 7 MORE flag, If set then more NetBIOS datagram
+ * fragments follow.
+ *
+ * F 6 FIRST packet flag, If set then this is first
+ * (and possibly only) fragment of NetBIOS
+ * datagram
+ *
+ * SNT 4,5 Source End-Node type:
+ * 00 = B node
+ * 01 = P node
+ * 10 = M node
+ * 11 = NBDD
+ * RESERVED 0-3 Reserved, must be zero (0)
+ *
+ * Inputs:
+ * Nothing
+ *
+ * Returns:
+ * int -> Description
+ */
+
+/*ARGSUSED*/
+void *
+smb_netbios_datagram_service_daemon(void *arg)
+{
+ struct sockaddr_in sin;
+ struct datagram *datagram;
+ int bytes, flag = 1;
+ net_cfg_t cfg;
+
+ (void) mutex_lock(&smb_dgq_mtx);
+ bzero(&smb_datagram_queue, sizeof (smb_datagram_queue));
+ smb_datagram_queue.forw = smb_datagram_queue.back =
+ (struct datagram *)((uintptr_t)&smb_datagram_queue);
+ (void) mutex_unlock(&smb_dgq_mtx);
+
+ if ((datagram_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR,
+ "smbd: Could not create AF_INET, SOCK_DGRAM, socket");
+ smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1);
+ return (0);
+ }
+
+ bzero(&sin, sizeof (sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(DGM_SRVC_UDP_PORT);
+ if (bind(datagram_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) {
+ syslog(LOG_ERR, "smbd: Bind to name service port %d failed",
+ DGM_SRVC_UDP_PORT);
+ (void) close(datagram_sock);
+ smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1);
+ return (0);
+ }
+ (void) setsockopt(datagram_sock, SOL_SOCKET, SO_BROADCAST, &flag,
+ sizeof (flag));
+
+ smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_RUNNING, 1);
+
+ while (((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) ||
+ (nb_status.state & NETBIOS_BROWSER_RUNNING)) {
+ if ((datagram = (struct datagram *)
+ malloc(sizeof (struct datagram))) == 0) {
+ /* Sleep for 10 sec and try again */
+ (void) sleep(10);
+ continue;
+ }
+
+ignore: bzero(&datagram->inaddr, sizeof (struct addr_entry));
+ datagram->inaddr.sinlen = sizeof (datagram->inaddr.sin);
+ datagram->inaddr.forw = datagram->inaddr.back =
+ &datagram->inaddr;
+
+ if ((bytes = recvfrom(datagram_sock, datagram->rawbuf,
+ MAX_DATAGRAM_LENGTH, 0,
+ (struct sockaddr *)&datagram->inaddr.sin,
+ &datagram->inaddr.sinlen)) < 0) {
+ syslog(LOG_ERR,
+ "smbd: NETBIOS datagram - recvfrom failed");
+ smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1);
+ break;
+ }
+
+ /* Ignore any incoming packets from myself... */
+ if (smb_nic_get_byip(
+ datagram->inaddr.sin.sin_addr.s_addr,
+ &cfg) != NULL) {
+ goto ignore;
+ }
+ if (smb_datagram_decode(datagram, bytes) < 0)
+ goto ignore;
+
+ /*
+ * This code was doing the wrong thing with responses from a
+ * Windows2000 PDC because both DATAGRAM_FLAGS_H_NODE and
+ * DATAGRAM_FLAGS_NBDD are defined to be the same value (see
+ * netbios.h). Since the Windows2000 PDC wants to be an H-Node,
+ * we need to handle all messages via smb_netbios_BPM_datagram.
+ *
+ * if ((datagram->flags & DATAGRAM_FLAGS_SRC_TYPE) ==
+ * DATAGRAM_FLAGS_NBDD)
+ * smb_netbios_NBDD_datagram(datagram);
+ * else
+ * smb_netbios_BPM_datagram(datagram);
+ */
+
+ smb_netbios_BPM_datagram(datagram);
+ }
+
+ smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_RUNNING, 0);
+
+ (void) mutex_lock(&nb_status.mtx);
+ while (nb_status.state & NETBIOS_BROWSER_RUNNING)
+ (void) cond_wait(&nb_status.cv, &nb_status.mtx);
+ (void) mutex_unlock(&nb_status.mtx);
+
+ (void) close(datagram_sock);
+ smb_netbios_datagram_fini();
+ syslog(LOG_DEBUG, "smbd: Netbios Datagram Service is down\n");
+ return (0);
+}
+
+static char
+/* LINTED - E_STATIC_UNUSED */
+nb_fmt_flags(unsigned char flags)
+{
+ switch (flags & DATAGRAM_FLAGS_SRC_TYPE) {
+ case DATAGRAM_FLAGS_B_NODE: return ('B');
+ case DATAGRAM_FLAGS_P_NODE: return ('P');
+ case DATAGRAM_FLAGS_M_NODE: return ('M');
+ case DATAGRAM_FLAGS_H_NODE: return ('H');
+ default: return ('?');
+ }
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c
new file mode 100644
index 0000000000..2b2d20e3c3
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c
@@ -0,0 +1,4738 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Description:
+ *
+ * Contains base code for netbios name service.
+ *
+ *
+ * 6. DEFINED CONSTANTS AND VARIABLES
+ *
+ * GENERAL:
+ *
+ * SCOPE_ID The name of the NetBIOS scope.
+ *
+ * This is expressed as a character
+ * string meeting the requirements of
+ * the domain name system and without
+ * a leading or trailing "dot".
+ *
+ * An implementation may elect to make
+ * this a single global value for the
+ * node or allow it to be specified
+ * with each separate NetBIOS name
+ * (thus permitting cross-scope
+ * references.)
+ *
+ * BROADCAST_ADDRESS An IP address composed of the
+ * nodes's network and subnetwork
+ * numbers with all remaining bits set
+ * to one.
+ *
+ * I.e. "Specific subnet" broadcast
+ * addressing according to section 2.3
+ * of RFC 950.
+ *
+ * BCAST_REQ_RETRY_TIMEOUT 250 milliseconds.
+ * An adaptive timer may be used.
+ *
+ * BCAST_REQ_RETRY_COUNT 3
+ *
+ * UCAST_REQ_RETRY_TIMEOUT 5 seconds
+ * An adaptive timer may be used.
+ *
+ * UCAST_REQ_RETRY_COUNT 3
+ *
+ * MAX_DATAGRAM_LENGTH 576 bytes (default)
+ *
+ *
+ * NAME SERVICE:
+ *
+ * REFRESH_TIMER Negotiated with NAME for each name.
+ *
+ * CONFLICT_TIMER 1 second
+ * Implementations may chose a longer
+ * value.
+ *
+ *
+ * NAME_SERVICE_TCP_PORT 137 (decimal)
+ *
+ * NAME_SERVICE_UDP_PORT 137 (decimal)
+ *
+ * INFINITE_TTL 0
+ */
+
+#include <unistd.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <synch.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <arpa/inet.h>
+#include <net/if_arp.h>
+
+#include <smbsrv/libsmbns.h>
+#include <smbns_netbios.h>
+
+#define NAME_HEADER_SIZE 12
+
+typedef struct name_reply {
+ struct name_reply *forw;
+ struct name_reply *back;
+ struct name_packet *packet;
+ struct addr_entry *addr;
+ unsigned short name_trn_id;
+ unsigned short flags;
+} name_reply;
+
+static struct name_reply reply_queue;
+static mutex_t rq_mtx;
+
+static mutex_t reply_mtx;
+static cond_t reply_cv;
+
+static name_queue_t delete_queue;
+static name_queue_t refresh_queue;
+
+/*
+ * Flag to control whether or not NetBIOS name refresh requests
+ * are logged. Set to non-zero to enable logging.
+ */
+
+static unsigned short netbios_name_transcation_id = 1;
+static int name_sock = 0;
+
+static int bcast_num = 0;
+static int nbns_num = 0;
+static struct addr_entry smb_bcast_list[SMB_PI_MAX_NETWORKS];
+static struct addr_entry smb_nbns[SMB_PI_MAX_WINS];
+
+static int smb_netbios_process_response(unsigned short, struct addr_entry *,
+ struct name_packet *, uint32_t);
+
+static int smb_send_name_service_packet(struct addr_entry *addr,
+ struct name_packet *packet);
+
+static int
+smb_end_node_challenge(struct name_reply *reply_info)
+{
+ int rc;
+ uint32_t retry;
+ unsigned short tid;
+ struct resource_record *answer;
+ struct name_question question;
+ struct addr_entry *addr;
+ struct name_entry *destination;
+ struct name_packet packet;
+ struct timespec st;
+
+ /*
+ * The response packet has in it the address of the presumed owner
+ * of the name. Challenge that owner. If owner either does not
+ * respond or indicates that he no longer owns the name, claim the
+ * name. Otherwise, the name cannot be claimed.
+ */
+
+ if ((answer = reply_info->packet->answer) == 0)
+ return (-1);
+
+ destination = answer->name;
+ question.name = answer->name;
+
+ packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST;
+ packet.qdcount = 1; /* question entries */
+ packet.question = &question;
+ packet.ancount = 0; /* answer recs */
+ packet.answer = NULL;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 0; /* additional recs */
+ packet.additional = NULL;
+
+ addr = &destination->addr_list;
+ for (retry = 0; retry < UCAST_REQ_RETRY_COUNT; retry++) {
+ tid = netbios_name_transcation_id++;
+ packet.name_trn_id = tid;
+ if (smb_send_name_service_packet(addr, &packet) >= 0) {
+ if ((rc = smb_netbios_process_response(tid, addr,
+ &packet, UCAST_REQ_RETRY_TIMEOUT)) != 0)
+ return (rc);
+ }
+ st.tv_sec = 0;
+ st.tv_nsec = (UCAST_REQ_RETRY_TIMEOUT * 1000000);
+ (void) nanosleep(&st, 0);
+ }
+ /* No reply */
+ return (0);
+}
+
+
+static struct name_reply *
+smb_name_get_reply(unsigned short tid, uint32_t timeout)
+{
+ unsigned short info;
+ struct resource_record *answer;
+ struct name_reply *reply;
+ uint32_t wait_time, to_save; /* in millisecond */
+ struct timeval wt;
+ timestruc_t to;
+
+ to_save = timeout;
+ reply = (struct name_reply *)malloc(sizeof (struct name_reply));
+ if (reply != 0) {
+ reply->flags = 0;
+ reply->name_trn_id = tid;
+ (void) mutex_lock(&rq_mtx);
+ QUEUE_INSERT_TAIL(&reply_queue, reply);
+ (void) mutex_unlock(&rq_mtx);
+
+ for (;;) {
+ (void) gettimeofday(&wt, 0);
+ wait_time = wt.tv_usec / 1000;
+
+ (void) mutex_lock(&reply_mtx);
+ to.tv_sec = 0;
+ to.tv_nsec = timeout * 1000000;
+ (void) cond_reltimedwait(&reply_cv, &reply_mtx, &to);
+ (void) mutex_unlock(&reply_mtx);
+
+ if (reply->flags != 0) {
+ info = reply->packet->info;
+ if (PACKET_TYPE(info) == WACK_RESPONSE) {
+ answer = reply->packet->answer;
+ wait_time = (answer) ?
+ TO_MILLISECONDS(answer->ttl) :
+ DEFAULT_TTL;
+ free(reply->addr);
+ free(reply->packet);
+ timeout = to_save + wait_time;
+ reply->flags = 0;
+ reply->name_trn_id = tid;
+ (void) mutex_lock(&rq_mtx);
+ QUEUE_INSERT_TAIL(&reply_queue, reply);
+ (void) mutex_unlock(&rq_mtx);
+ continue;
+ }
+ return (reply);
+ }
+ (void) gettimeofday(&wt, 0);
+ wait_time = (wt.tv_usec / 1000) - wait_time;
+ if (wait_time >= timeout) {
+ (void) mutex_lock(&rq_mtx);
+ QUEUE_CLIP(reply);
+ (void) mutex_unlock(&rq_mtx);
+ free(reply);
+ break;
+ }
+ timeout -= wait_time;
+ }
+ }
+
+ return (0);
+}
+
+static void
+smb_reply_ready(struct name_packet *packet, struct addr_entry *addr)
+{
+ struct name_reply *reply;
+ struct resource_record *answer;
+
+ (void) mutex_lock(&rq_mtx);
+ for (reply = reply_queue.forw; reply != &reply_queue;
+ reply = reply->forw) {
+ if (reply->name_trn_id == packet->name_trn_id) {
+ QUEUE_CLIP(reply);
+ (void) mutex_unlock(&rq_mtx);
+
+ reply->addr = addr;
+ reply->packet = packet;
+
+ (void) mutex_lock(&reply_mtx);
+ reply->flags |= 0x0001; /* reply ready */
+ (void) cond_signal(&reply_cv);
+ (void) mutex_unlock(&reply_mtx);
+
+ return;
+ }
+ }
+ (void) mutex_unlock(&rq_mtx);
+
+ /* Presumably nobody is waiting any more... */
+ free(addr);
+
+ answer = packet->answer;
+ if (answer)
+ smb_netbios_name_freeaddrs(answer->name);
+ free(packet);
+}
+
+static int
+smb_netbios_process_response(unsigned short tid, struct addr_entry *addr,
+ struct name_packet *packet, uint32_t timeout)
+{
+ int rc = 0;
+ unsigned short info;
+ struct name_reply *reply;
+ struct resource_record *answer;
+ struct name_entry *name;
+ struct name_entry *entry;
+ struct name_question *question;
+ uint32_t ttl;
+
+ if ((reply = smb_name_get_reply(tid, timeout)) == 0) {
+ return (0); /* No reply: retry */
+ }
+ info = reply->packet->info;
+ answer = reply->packet->answer;
+
+ /* response */
+ switch (PACKET_TYPE(info)) {
+ case NAME_QUERY_RESPONSE:
+ if (POSITIVE_RESPONSE(info)) {
+ addr = &answer->name->addr_list;
+ do {
+ /*
+ * Make sure that remote name is not
+ * flagged local
+ */
+ addr->attributes &= ~NAME_ATTR_LOCAL;
+
+ addr->refresh_ttl = addr->ttl =
+ (answer && answer->ttl) ?
+ (answer->ttl >> 1) :
+ TO_SECONDS(DEFAULT_TTL);
+ addr = addr->forw;
+ } while (addr != &answer->name->addr_list);
+ smb_netbios_name_dump(answer->name);
+ (void) smb_netbios_cache_insert_list(answer->name);
+ rc = 1;
+ } else {
+ rc = -1;
+ }
+ break;
+
+ case NAME_REGISTRATION_RESPONSE:
+ if (NEGATIVE_RESPONSE(info)) {
+ if (RCODE(info) == RCODE_CFT_ERR) {
+ if (answer == 0) {
+ rc = -RCODE(info);
+ break;
+ }
+
+ name = answer->name;
+ entry = smb_netbios_cache_lookup(name);
+ if (entry) {
+ /*
+ * a name in the state "conflict
+ * detected" does not "logically" exist
+ * on that node. No further session
+ * will be accepted on that name.
+ * No datagrams can be sent against
+ * that name.
+ * Such an entry will not be used for
+ * purposes of processing incoming
+ * request packets.
+ * The only valid user NetBIOS operation
+ * against such a name is DELETE NAME.
+ */
+ entry->attributes |= NAME_ATTR_CONFLICT;
+ syslog(LOG_DEBUG,
+ "NETBIOS Name conflict: %15.15s",
+ entry->name);
+ smb_netbios_cache_unlock_entry(entry);
+ }
+ }
+ rc = -RCODE(info);
+ break;
+ }
+
+ /*
+ * name can be added:
+ * adjust refresh timeout value,
+ * TTL, for this name
+ */
+ question = packet->question;
+ ttl = (answer && answer->ttl) ? answer->ttl >> 1
+ : TO_SECONDS(DEFAULT_TTL);
+ if ((entry = smb_netbios_cache_lookup(question->name)) != 0) {
+ addr = &entry->addr_list;
+ do {
+ if ((addr->refresh_ttl == 0) ||
+ (ttl < addr->refresh_ttl))
+ addr->refresh_ttl = addr->ttl = ttl;
+ addr = addr->forw;
+ } while (addr != &entry->addr_list);
+ smb_netbios_cache_unlock_entry(entry);
+ }
+
+ rc = 1;
+ break;
+
+ case NAME_RELEASE_RESPONSE:
+ rc = 1;
+ break;
+
+ case END_NODE_CHALLENGE_REGISTRATION_REQUEST:
+ /*
+ * The response packet has in it the
+ * address of the presumed owner of the
+ * name. Challenge that owner. If
+ * owner either does not respond or
+ * indicates that he no longer owns the
+ * name, claim the name. Otherwise,
+ * the name cannot be claimed.
+ */
+ rc = smb_end_node_challenge(reply);
+ break;
+
+ default:
+ rc = 0;
+ break;
+ }
+
+ if (answer)
+ smb_netbios_name_freeaddrs(answer->name);
+ free(reply->addr);
+ free(reply->packet);
+ free(reply);
+ return (rc); /* retry */
+}
+
+/*
+ * smb_name_buf_from_packet
+ *
+ * Description:
+ * Convert a NetBIOS Name Server Packet Block (npb)
+ * into the bits and bytes destined for the wire.
+ * The "buf" is used as a heap.
+ *
+ * Inputs:
+ * char * buf -> Buffer, from the wire
+ * unsigned n_buf -> Length of 'buf'
+ * name_packet *npb -> Packet block, decode into
+ * unsigned n_npb -> Max bytes in 'npb'
+ *
+ * Returns:
+ * >0 -> Encode successful, value is length of packet in "buf"
+ * -1 -> Hard error, can not possibly encode
+ * -2 -> Need more memory in buf -- it's too small
+ */
+
+static int
+smb_name_buf_from_packet(unsigned char *buf,
+ int n_buf,
+ struct name_packet *npb)
+{
+ struct addr_entry *raddr;
+ unsigned char *heap = buf;
+ unsigned char *end_heap = heap + n_buf;
+ unsigned char *dnptrs[32];
+ unsigned char comp_name_buf[MAX_NAME_LENGTH];
+ unsigned int tmp;
+ int i, step;
+
+ if (n_buf < NAME_HEADER_SIZE)
+ return (-1); /* no header, impossible */
+
+ dnptrs[0] = heap;
+ dnptrs[1] = 0;
+
+ BE_OUT16(heap, npb->name_trn_id);
+ heap += 2;
+
+ BE_OUT16(heap, npb->info);
+ heap += 2;
+
+ BE_OUT16(heap, npb->qdcount);
+ heap += 2;
+
+ BE_OUT16(heap, npb->ancount);
+ heap += 2;
+
+ BE_OUT16(heap, npb->nscount);
+ heap += 2;
+
+ BE_OUT16(heap, npb->arcount);
+ heap += 2;
+
+ for (i = 0; i < npb->qdcount; i++) {
+ if ((heap + 34 + 4) > end_heap)
+ return (-2);
+
+ (void) smb_first_level_name_encode(npb->question[i].name,
+ comp_name_buf, sizeof (comp_name_buf));
+ (void) strcpy((char *)heap, (char *)comp_name_buf);
+ heap += strlen((char *)comp_name_buf) + 1;
+
+ BE_OUT16(heap, npb->question[i].question_type);
+ heap += 2;
+
+ BE_OUT16(heap, npb->question[i].question_class);
+ heap += 2;
+ }
+
+ for (step = 1; step <= 3; step++) {
+ struct resource_record *nrr;
+ int n;
+
+ /* truly ugly, but saves code copying */
+ if (step == 1) {
+ n = npb->ancount;
+ nrr = npb->answer;
+ } else if (step == 2) {
+ n = npb->nscount;
+ nrr = npb->authority;
+ } else { /* step == 3 */
+ n = npb->arcount;
+ nrr = npb->additional;
+ }
+
+ for (i = 0; i < n; i++) {
+ if ((heap + 34 + 10) > end_heap)
+ return (-2);
+
+ (void) smb_first_level_name_encode(nrr->name,
+ comp_name_buf, sizeof (comp_name_buf));
+ (void) strcpy((char *)heap, (char *)comp_name_buf);
+ heap += strlen((char *)comp_name_buf) + 1;
+
+ BE_OUT16(heap, nrr[i].rr_type);
+ heap += 2;
+
+ BE_OUT16(heap, nrr[i].rr_class);
+ heap += 2;
+
+ BE_OUT32(heap, nrr[i].ttl);
+ heap += 4;
+
+ BE_OUT16(heap, nrr[i].rdlength);
+ heap += 2;
+
+ if ((tmp = nrr[i].rdlength) > 0) {
+ if ((heap + tmp) > end_heap)
+ return (-2);
+
+ if (nrr[i].rr_type == NAME_RR_TYPE_NB &&
+ nrr[i].rr_class == NAME_RR_CLASS_IN &&
+ tmp >= 6 && nrr[i].rdata == 0) {
+ tmp = nrr[i].name->attributes &
+ (NAME_ATTR_GROUP |
+ NAME_ATTR_OWNER_NODE_TYPE);
+ BE_OUT16(heap, tmp);
+ heap += 2;
+
+ raddr = &nrr[i].name->addr_list;
+ (void) memcpy(heap,
+ &raddr->sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+ heap += 4;
+ } else {
+ bcopy(nrr[i].rdata, heap, tmp);
+ heap += tmp;
+ }
+ }
+ }
+ }
+ return (heap - buf);
+}
+
+/*
+ * strnchr
+ *
+ * Lookup for character 'c' in first 'n' chars of string 's'.
+ * Returns pointer to the found char, otherwise returns 0.
+ */
+static char *
+strnchr(const char *s, char c, int n)
+{
+ char *ps = (char *)s;
+ char *es = (char *)s + n;
+
+ while (ps < es && *ps) {
+ if (*ps == c)
+ return (ps);
+
+ ++ps;
+ }
+
+ if (*ps == '\0' && c == '\0')
+ return (ps);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+is_multihome(char *name)
+{
+ return ((smb_nic_get_num() > 1) ? 1 : 0);
+}
+
+/*
+ * smb_netbios_getname
+ *
+ * Get the Netbios name part of the given record.
+ * Does some boundary checks.
+ *
+ * Returns the name length on success, otherwise
+ * returns 0.
+ */
+static int
+smb_netbios_getname(char *name, char *buf, char *buf_end)
+{
+ char *name_end;
+ int name_len;
+
+ if (buf >= buf_end) {
+ /* no room for a NB name */
+ return (0);
+ }
+
+ name_end = strnchr(buf, '\0', buf_end - buf + 1);
+ if (name_end == 0) {
+ /* not a valid NB name */
+ return (0);
+ }
+
+ name_len = name_end - buf + 1;
+
+ (void) strlcpy(name, buf, name_len);
+ return (name_len);
+}
+
+
+/*
+ * smb_name_buf_to_packet
+ *
+ * Description:
+ * Convert the bits and bytes that came from the wire
+ * into a NetBIOS Name Server Packet Block (npb).
+ * The "block" is used as a heap.
+ *
+ * Inputs:
+ * char * buf -> Buffer, from the wire
+ * int n_buf -> Length of 'buf'
+ * name_packet *npb -> Packet block, decode into
+ * int n_npb -> Max bytes in 'npb'
+ *
+ * Returns:
+ * >0 -> Decode (parse) successful, value is byte length of npb
+ * -1 -> Hard error, can not possibly decode
+ * -2 -> Need more memory in npb -- it's too small
+ */
+
+static struct name_packet *
+smb_name_buf_to_packet(char *buf, int n_buf)
+{
+ struct name_packet *npb;
+ unsigned char *heap;
+ unsigned char *scan = (unsigned char *)buf;
+ unsigned char *scan_end = scan + n_buf;
+ char name_buf[MAX_NAME_LENGTH];
+ struct resource_record *nrr = 0;
+ int rc, i, n, nn, ns;
+ unsigned short name_trn_id, info;
+ unsigned short qdcount, ancount, nscount, arcount;
+ struct addr_entry *next;
+ int name_len;
+
+ if (n_buf < NAME_HEADER_SIZE) {
+ /* truncated header */
+ syslog(LOG_DEBUG, "SmbNBNS: packet is too short (%d)",
+ n_buf);
+ return (0);
+ }
+
+ name_trn_id = BE_IN16(scan); scan += 2;
+ info = BE_IN16(scan); scan += 2;
+ qdcount = BE_IN16(scan); scan += 2;
+ ancount = BE_IN16(scan); scan += 2;
+ nscount = BE_IN16(scan); scan += 2;
+ arcount = BE_IN16(scan); scan += 2;
+
+ ns = sizeof (struct name_entry);
+ n = n_buf + sizeof (struct name_packet) +
+ ((unsigned)qdcount * (sizeof (struct name_question) + ns)) +
+ ((unsigned)ancount * (sizeof (struct resource_record) + ns)) +
+ ((unsigned)nscount * (sizeof (struct resource_record) + ns)) +
+ ((unsigned)arcount * (sizeof (struct resource_record) + ns));
+
+ if ((npb = (struct name_packet *)malloc(n)) == 0) {
+ return (0);
+ }
+ bzero(npb, n);
+
+ heap = npb->block_data;
+ npb->name_trn_id = name_trn_id;
+ npb->info = info;
+ npb->qdcount = qdcount;
+ npb->ancount = ancount;
+ npb->nscount = nscount;
+ npb->arcount = arcount;
+
+ /* scan is in position for question entries */
+
+ /*
+ * Measure the space needed for the tables
+ */
+ if (qdcount > 0) {
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ npb->question = (struct name_question *)heap;
+ heap += qdcount * sizeof (struct name_question);
+ for (i = 0; i < qdcount; i++) {
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ npb->question[i].name = (struct name_entry *)heap;
+ heap += sizeof (struct name_entry);
+ }
+ }
+
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ nrr = (struct resource_record *)heap;
+
+ if (ancount > 0) {
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ npb->answer = (struct resource_record *)heap;
+ heap += ancount * sizeof (struct resource_record);
+ }
+
+ if (nscount > 0) {
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ npb->authority = (struct resource_record *)heap;
+ heap += nscount * sizeof (struct resource_record);
+ }
+
+ if (arcount > 0) {
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ npb->additional = (struct resource_record *)heap;
+ heap += arcount * sizeof (struct resource_record);
+ }
+
+ /*
+ * Populate each resource_record's .name field.
+ * Done as a second pass so that all resource records
+ * (answer, authority, additional) are consecutive via nrr[i].
+ */
+ for (i = 0; i < (ancount + nscount + arcount); i++) {
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ nrr[i].name = (struct name_entry *)heap;
+ heap += sizeof (struct name_entry);
+ }
+
+
+ for (i = 0; i < npb->qdcount; i++) {
+ name_len = smb_netbios_getname(name_buf, (char *)scan,
+ (char *)scan_end);
+ if (name_len <= 0) {
+ free(npb);
+ return (0);
+ }
+
+ smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, 0, 0, 0, 0, 0,
+ npb->question[i].name);
+ rc = smb_first_level_name_decode((unsigned char *)name_buf,
+ npb->question[i].name);
+ if (rc < 0) {
+ /* Couldn't decode the question name */
+ free(npb);
+ return (0);
+ }
+
+ scan += name_len;
+ if (scan + 4 > scan_end) {
+ /* no room for Question Type(2) and Class(2) fields */
+ free(npb);
+ return (0);
+ }
+
+ npb->question[i].question_type = BE_IN16(scan); scan += 2;
+ npb->question[i].question_class = BE_IN16(scan); scan += 2;
+ }
+
+ /*
+ * Cheat. Remaining sections are of the same resource_record
+ * format. Table space is consecutive.
+ */
+
+ for (i = 0; i < (ancount + nscount + arcount); i++) {
+ if (scan[0] == 0xc0) {
+ /* Namebuf is reused... */
+ rc = 2;
+ } else {
+ name_len = smb_netbios_getname(name_buf, (char *)scan,
+ (char *)scan_end);
+ if (name_len <= 0) {
+ free(npb);
+ return (0);
+ }
+ rc = name_len;
+ }
+ scan += rc;
+
+ if (scan + 10 > scan_end) {
+ /*
+ * no room for RR_TYPE (2), RR_CLASS (2), TTL (4) and
+ * RDLENGTH (2) fields.
+ */
+ free(npb);
+ return (0);
+ }
+
+ smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, 0, 0, 0, 0, 0,
+ nrr[i].name);
+ if ((rc = smb_first_level_name_decode((unsigned char *)name_buf,
+ nrr[i].name)) < 0) {
+ free(npb);
+ return (0);
+ }
+
+ nrr[i].rr_type = BE_IN16(scan); scan += 2;
+ nrr[i].rr_class = BE_IN16(scan); scan += 2;
+ nrr[i].ttl = BE_IN32(scan); scan += 4;
+ nrr[i].rdlength = BE_IN16(scan); scan += 2;
+
+ if ((n = nrr[i].rdlength) > 0) {
+ if ((scan + n) > scan_end) {
+ /* no room for RDATA */
+ free(npb);
+ return (0);
+ }
+ bcopy(scan, heap, n);
+
+ nn = n;
+ if (nrr[i].rr_type == 0x0020 &&
+ nrr[i].rr_class == 0x01 && n >= 6) {
+ while (nn) {
+ if (nn == 6)
+ next = &nrr[i].name->addr_list;
+ else {
+ next = (struct addr_entry *)
+ malloc(
+ sizeof (struct addr_entry));
+ if (next == 0) {
+ /* not enough memory */
+ free(npb);
+ return (0);
+ }
+ QUEUE_INSERT_TAIL(
+ &nrr[i].name->addr_list,
+ next);
+ }
+ nrr[i].name->attributes =
+ BE_IN16(scan);
+ next->sin.sin_family = AF_INET;
+ next->sinlen = sizeof (next->sin);
+ (void) memcpy(
+ &next->sin.sin_addr.s_addr,
+ scan + 2, sizeof (uint32_t));
+ next->sin.sin_port =
+ htons(DGM_SRVC_UDP_PORT);
+ nn -= 6;
+ scan += 6;
+ }
+ } else {
+ nrr[i].rdata = heap;
+ scan += n;
+ }
+ heap += n;
+ }
+ }
+ return (npb);
+}
+
+
+/*
+ * smb_send_name_service_packet
+ *
+ * Description:
+ *
+ * Send out a name service packet to proper destination.
+ *
+ * Inputs:
+ * struct netbios_name *dest -> NETBIOS name of destination
+ * struct name_packet *packet -> Packet to send
+ *
+ * Returns:
+ * success -> >0
+ * failure -> <=0
+ */
+
+static int
+smb_send_name_service_packet(struct addr_entry *addr,
+ struct name_packet *packet)
+{
+ unsigned char buf[MAX_DATAGRAM_LENGTH];
+ int len;
+
+ if ((len = smb_name_buf_from_packet(buf, sizeof (buf), packet)) < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (sendto(name_sock, buf, len, MSG_EOR,
+ (struct sockaddr *)&addr->sin, addr->sinlen));
+}
+
+/*
+ * 4.2.1.1. HEADER
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID | OPCODE | NM_FLAGS | RCODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | QDCOUNT | ANCOUNT |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NSCOUNT | ARCOUNT |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Field Description
+ *
+ * NAME_TRN_ID Transaction ID for Name Service Transaction.
+ * Requester places a unique value for each active
+ * transaction. Responder puts NAME_TRN_ID value
+ * from request packet in response packet.
+ *
+ * OPCODE Packet type code, see table below.
+ *
+ * NM_FLAGS Flags for operation, see table below.
+ *
+ * RCODE Result codes of request. Table of RCODE values
+ * for each response packet below.
+ *
+ * QDCOUNT Unsigned 16 bit integer specifying the number of
+ * entries in the question section of a Name
+ *
+ * Service packet. Always zero (0) for responses.
+ * Must be non-zero for all NetBIOS Name requests.
+ *
+ * ANCOUNT Unsigned 16 bit integer specifying the number of
+ * resource records in the answer section of a Name
+ * Service packet.
+ *
+ * NSCOUNT Unsigned 16 bit integer specifying the number of
+ * resource records in the authority section of a
+ * Name Service packet.
+ *
+ * ARCOUNT Unsigned 16 bit integer specifying the number of
+ * resource records in the additional records
+ * section of a Name Service packet.
+ *
+ * The OPCODE field is defined as:
+ *
+ * 0 1 2 3 4
+ * +---+---+---+---+---+
+ * | R | OPCODE |
+ * +---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description
+ *
+ * OPCODE 1-4 Operation specifier:
+ * 0 = query
+ * 5 = registration
+ * 6 = release
+ * 7 = WACK
+ * 8 = refresh
+ *
+ * R 0 RESPONSE flag:
+ * if bit == 0 then request packet
+ * if bit == 1 then response packet.
+ */
+
+
+/*
+ * The NM_FLAGS field is defined as:
+ *
+ *
+ * 0 1 2 3 4 5 6
+ * +---+---+---+---+---+---+---+
+ * |AA |TC |RD |RA | 0 | 0 | B |
+ * +---+---+---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description
+ *
+ * B 6 Broadcast Flag.
+ * = 1: packet was broadcast or multicast
+ * = 0: unicast
+ *
+ * RA 3 Recursion Available Flag.
+ *
+ * Only valid in responses from a NetBIOS Name
+ * Server -- must be zero in all other
+ * responses.
+ *
+ * If one (1) then the NAME supports recursive
+ * query, registration, and release.
+ *
+ * If zero (0) then the end-node must iterate
+ * for query and challenge for registration.
+ *
+ * RD 2 Recursion Desired Flag.
+ *
+ * May only be set on a request to a NetBIOS
+ * Name Server.
+ *
+ * The NAME will copy its state into the
+ * response packet.
+ *
+ * If one (1) the NAME will iterate on the
+ * query, registration, or release.
+ *
+ * TC 1 Truncation Flag.
+ *
+ * Set if this message was truncated because the
+ * datagram carrying it would be greater than
+ * 576 bytes in length. Use TCP to get the
+ * information from the NetBIOS Name Server.
+ *
+ * AA 0 Authoritative Answer flag.
+ *
+ * Must be zero (0) if R flag of OPCODE is zero
+ * (0).
+ *
+ * If R flag is one (1) then if AA is one (1)
+ * then the node responding is an authority for
+ * the domain name.
+ *
+ * End nodes responding to queries always set
+ * this bit in responses.
+ *
+ */
+
+/*
+ * 4.2.1.2. QUESTION SECTION
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | QUESTION_TYPE | QUESTION_CLASS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Field Description
+ *
+ * QUESTION_NAME The compressed name representation of the
+ * NetBIOS name for the request.
+ *
+ * QUESTION_TYPE The type of request. The values for this field
+ * are specified for each request.
+ *
+ * QUESTION_CLASS The class of the request. The values for this
+ * field are specified for each request.
+ *
+ * QUESTION_TYPE is defined as:
+ *
+ * Symbol Value Description:
+ *
+ * NB 0x0020 NetBIOS general Name Service Resource Record
+ * NBSTAT 0x0021 NetBIOS NODE STATUS Resource Record (See NODE
+ * STATUS REQUEST)
+ *
+ * QUESTION_CLASS is defined as:
+ *
+ * Symbol Value Description:
+ *
+ * IN 0x0001 Internet class
+ */
+
+#define QUESTION_TYPE_NETBIOS_GENERAL 0x20
+#define QUESTION_TYPE_NETBIOS_STATUS 0x21
+
+#define QUESTION_CLASS_INTERNET 0x0001
+
+/*
+ *
+ * 4.2.1.3. RESOURCE RECORD
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RR_TYPE | RR_CLASS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RDLENGTH | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ * / /
+ * / RDATA /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Field Description
+ *
+ * RR_NAME The compressed name representation of the
+ * NetBIOS name corresponding to this resource
+ * record.
+ *
+ * RR_TYPE Resource record type code
+ *
+ * RR_CLASS Resource record class code
+ *
+ * TTL The Time To Live of a the resource record's
+ * name.
+ *
+ * RDLENGTH Unsigned 16 bit integer that specifies the
+ * number of bytes in the RDATA field.
+ *
+ * RDATA RR_CLASS and RR_TYPE dependent field. Contains
+ * the resource information for the NetBIOS name.
+ *
+ * RESOURCE RECORD RR_TYPE field definitions:
+ *
+ * Symbol Value Description:
+ *
+ * A 0x0001 IP address Resource Record (See REDIRECT NAME
+ * QUERY RESPONSE)
+ * NS 0x0002 Name Server Resource Record (See REDIRECT
+ * NAME QUERY RESPONSE)
+ * NULL 0x000A NULL Resource Record (See WAIT FOR
+ * ACKNOWLEDGEMENT RESPONSE)
+ * NB 0x0020 NetBIOS general Name Service Resource Record
+ * (See NB_FLAGS and NB_ADDRESS, below)
+ * NBSTAT 0x0021 NetBIOS NODE STATUS Resource Record (See NODE
+ * STATUS RESPONSE)
+ */
+
+#define RR_TYPE_IP_ADDRESS_RESOURCE 0x0001
+#define RR_TYPE_NAME_SERVER_RESOURCE 0x0002
+#define RR_TYPE_NULL_RESOURCE 0x000A
+#define RR_TYPE_NETBIOS_RESOURCE 0x0020
+#define RR_TYPE_NETBIOS_STATUS 0x0021
+
+/*
+ *
+ * RESOURCE RECORD RR_CLASS field definitions:
+ *
+ * Symbol Value Description:
+ *
+ * IN 0x0001 Internet class
+ */
+#define RR_CLASS_INTERNET_CLASS 0x0001
+
+/*
+ *
+ * NB_FLAGS field of the RESOURCE RECORD RDATA field for RR_TYPE of
+ * "NB":
+ *
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * | G | ONT | RESERVED |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * Symbol Bit(s) Description:
+ *
+ * RESERVED 3-15 Reserved for future use. Must be zero (0).
+ * ONT 1,2 Owner Node Type:
+ * 00 = B node
+ * 01 = P node
+ * 10 = M node
+ * 11 = Reserved for future use
+ * For registration requests this is the
+ * claimant's type.
+ * For responses this is the actual owner's
+ * type.
+ *
+ * G 0 Group Name Flag.
+ * If one (1) then the RR_NAME is a GROUP
+ * NetBIOS name.
+ * If zero (0) then the RR_NAME is a UNIQUE
+ * NetBIOS name.
+ *
+ * The NB_ADDRESS field of the RESOURCE RECORD RDATA field for
+ * RR_TYPE of "NB" is the IP address of the name's owner.
+ *
+ */
+#define RR_FLAGS_NB_ONT_MASK 0x6000
+#define RR_FLAGS_NB_ONT_B_NODE 0x0000
+#define RR_FLAGS_NB_ONT_P_NODE 0x2000
+#define RR_FLAGS_NB_ONT_M_NODE 0x4000
+#define RR_FLAGS_NB_ONT_RESERVED 0x6000
+
+#define RR_FLAGS_NB_GROUP_NAME 0x8000
+
+/*
+ * smb_netbios_send_rcv
+ *
+ * This function sends the given NetBIOS packet to the given
+ * address and get back the response. If send operation is not
+ * successful, it's repeated 'retries' times.
+ *
+ * Returns:
+ * 0 Unsuccessful send operation; no reply
+ * 1 Got reply
+ */
+static int
+smb_netbios_send_rcv(int bcast, struct addr_entry *destination,
+ struct name_packet *packet,
+ uint32_t retries, uint32_t timeout)
+{
+ uint32_t retry;
+ unsigned short tid;
+ struct timespec st;
+ int rc;
+
+ for (retry = 0; retry < retries; retry++) {
+ if ((destination->flags & ADDR_FLAG_VALID) == 0)
+ return (0);
+
+ tid = netbios_name_transcation_id++;
+ packet->name_trn_id = tid;
+ if (smb_send_name_service_packet(destination, packet) >= 0) {
+ rc = smb_netbios_process_response(tid, destination,
+ packet, timeout);
+
+ if ((rc > 0) || (bcast == BROADCAST))
+ return (1);
+
+ if (rc != 0)
+ return (0);
+ }
+
+ st.tv_sec = 0;
+ st.tv_nsec = (timeout * 1000000);
+ (void) nanosleep(&st, 0);
+ }
+
+ return (0);
+}
+
+/*
+ * 4.2.2. NAME REGISTRATION REQUEST
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x5 |0|0|1|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Since the RR_NAME is the same name as the QUESTION_NAME, the
+ * RR_NAME representation must use pointers to the QUESTION_NAME
+ * name's labels to guarantee the length of the datagram is less
+ * than the maximum 576 bytes. See section above on name formats
+ * and also page 31 and 32 of RFC 883, Domain Names - Implementation
+ * and Specification, for a complete description of compressed name
+ * label pointers.
+ */
+static int
+smb_send_name_registration_request(int bcast, struct name_question *question,
+ struct resource_record *additional)
+{
+ int gotreply = 0;
+ uint32_t retries;
+ uint32_t timeout;
+ struct addr_entry *destination;
+ struct name_packet packet;
+ unsigned char type;
+ int i, addr_num, rc;
+
+ type = question->name->name[15];
+ if ((type != 0x00) && (type != 0x20)) {
+ syslog(LOG_ERR, "netbios: error trying to register"
+ " non-local name");
+ smb_netbios_name_logf(question->name);
+ question->name->attributes &= ~NAME_ATTR_LOCAL;
+ return (-1);
+ }
+
+ if (bcast == BROADCAST) {
+ if (bcast_num == 0)
+ return (0);
+ destination = smb_bcast_list;
+ addr_num = bcast_num;
+ retries = BCAST_REQ_RETRY_COUNT;
+ timeout = BCAST_REQ_RETRY_TIMEOUT;
+ packet.info = NAME_REGISTRATION_REQUEST | NM_FLAGS_BROADCAST;
+ } else {
+ if (nbns_num == 0)
+ return (0);
+ destination = smb_nbns;
+ addr_num = nbns_num;
+ retries = UCAST_REQ_RETRY_COUNT;
+ timeout = UCAST_REQ_RETRY_TIMEOUT;
+ packet.info = NAME_REGISTRATION_REQUEST | NM_FLAGS_UNICAST;
+ }
+
+ packet.qdcount = 1; /* question entries */
+ packet.question = question;
+ packet.ancount = 0; /* answer recs */
+ packet.answer = NULL;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 1; /* additional recs */
+ packet.additional = additional;
+
+ if (IS_UNIQUE(question->name->attributes) &&
+ (is_multihome((char *)(question->name->name))))
+ packet.info |= NAME_MULTIHOME_REGISTRATION_REQUEST;
+
+ for (i = 0; i < addr_num; i++) {
+ /*
+ * Only register with the Primary WINS server,
+ * unless we got no reply.
+ */
+ if ((bcast == UNICAST) && gotreply)
+ break;
+
+ rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
+ retries, timeout);
+ if (rc == 1)
+ gotreply = 1;
+ }
+
+ return (gotreply);
+}
+
+/*
+ *
+ * 4.2.4. NAME REFRESH REQUEST
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x8 |0|0|0|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+/*ARGSUSED*/
+static int
+smb_send_name_refresh_request(int bcast, struct name_question *question,
+ struct resource_record *additional, int force)
+{
+ int rc = 0;
+ int gotreply = 0;
+ uint32_t retries;
+ uint32_t timeout;
+ struct addr_entry *addr;
+ struct addr_entry *destination;
+ struct name_packet packet;
+ unsigned char type;
+ int i, addr_num, q_addrs = 0;
+
+ type = question->name->name[15];
+ if ((type != 0x00) && (type != 0x20)) {
+ syslog(LOG_ERR, "attempt to refresh non-local name");
+ smb_netbios_name_logf(question->name);
+ question->name->attributes &= ~NAME_ATTR_LOCAL;
+ return (-1);
+ }
+ switch (bcast) {
+ case BROADCAST :
+ if (bcast_num == 0)
+ return (-1);
+ destination = smb_bcast_list;
+ addr_num = bcast_num;
+ retries = BCAST_REQ_RETRY_COUNT;
+ timeout = BCAST_REQ_RETRY_TIMEOUT;
+ packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_BROADCAST;
+ break;
+
+ case UNICAST :
+ if (nbns_num == 0)
+ return (-1);
+ destination = smb_nbns;
+ addr_num = nbns_num;
+ retries = UCAST_REQ_RETRY_COUNT;
+ timeout = UCAST_REQ_RETRY_TIMEOUT;
+ packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_UNICAST;
+ break;
+
+ default:
+ destination = &question->name->addr_list;
+ /*
+ * the value of addr_num is irrelvant here, because
+ * the code is going to do special_process so it doesn't
+ * need the addr_num. We set a value here just to avoid
+ * compiler warning.
+ */
+ addr_num = 0;
+ retries = UCAST_REQ_RETRY_COUNT;
+ timeout = UCAST_REQ_RETRY_TIMEOUT;
+ packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_UNICAST;
+ q_addrs = 1;
+ break;
+ }
+
+ if (IS_UNIQUE(question->name->attributes) &&
+ (is_multihome((char *)(question->name->name))))
+ packet.info |= NAME_MULTIHOME_REGISTRATION_REQUEST;
+
+ packet.qdcount = 1; /* question entries */
+ packet.question = question;
+ packet.ancount = 0; /* answer recs */
+ packet.answer = NULL;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 1; /* additional recs */
+ packet.additional = additional;
+
+ if (q_addrs)
+ goto special_process;
+
+ for (i = 0; i < addr_num; i++) {
+ rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
+ retries, timeout);
+ if (rc == 1)
+ gotreply = 1;
+ }
+
+ return (gotreply);
+
+special_process:
+ addr = destination;
+ do {
+ rc = smb_netbios_send_rcv(bcast, addr, &packet,
+ retries, timeout);
+ if (rc == 1)
+ gotreply = 1;
+ addr = addr->forw;
+ } while (addr != destination);
+
+ return (gotreply);
+}
+
+/*
+ * 4.2.5. POSITIVE NAME REGISTRATION RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x5 |1|0|1|1|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *
+ *
+ * 4.2.6. NEGATIVE NAME REGISTRATION RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x5 |1|0|1|1|0 0|0| RCODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * RCODE field values:
+ *
+ * Symbol Value Description:
+ *
+ * FMT_ERR 0x1 Format Error. Request was invalidly
+ * formatted.
+ * SRV_ERR 0x2 Server failure. Problem with NAME, cannot
+ * process name.
+ * IMP_ERR 0x4 Unsupported request error. Allowable only
+ * for challenging NAME when gets an Update type
+ * registration request.
+ * RFS_ERR 0x5 Refused error. For policy reasons server
+ * will not register this name from this host.
+ * ACT_ERR 0x6 Active error. Name is owned by another node.
+ * CFT_ERR 0x7 Name in conflict error. A UNIQUE name is
+ * owned by more than one node.
+ */
+static int
+smb_send_name_registration_response(struct addr_entry *addr,
+ struct name_packet *original_packet, unsigned short rcode)
+{
+ struct name_packet packet;
+ struct resource_record answer;
+
+ bzero(&packet, sizeof (struct name_packet));
+ bzero(&answer, sizeof (struct resource_record));
+
+ packet.name_trn_id = original_packet->name_trn_id;
+ packet.info = NAME_REGISTRATION_RESPONSE | NAME_NM_FLAGS_RA |
+ (rcode & NAME_RCODE_MASK);
+ packet.qdcount = 0; /* question entries */
+ packet.question = NULL;
+ packet.ancount = 1; /* answer recs */
+ packet.answer = &answer;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 0; /* additional recs */
+ packet.additional = NULL;
+
+ answer.name = original_packet->question->name;
+ answer.rr_type = NAME_QUESTION_TYPE_NB;
+ answer.rr_class = NAME_QUESTION_CLASS_IN;
+ answer.ttl = original_packet->additional->ttl;
+ answer.rdlength = original_packet->additional->rdlength;
+ answer.rdata = original_packet->additional->rdata;
+
+ return (smb_send_name_service_packet(addr, &packet));
+}
+
+/*
+ * 4.2.9. NAME RELEASE REQUEST & DEMAND
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x6 |0|0|0|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x00000000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Since the RR_NAME is the same name as the QUESTION_NAME, the
+ * RR_NAME representation must use label string pointers to the
+ * QUESTION_NAME labels to guarantee the length of the datagram is
+ * less than the maximum 576 bytes. This is the same condition as
+ * with the NAME REGISTRATION REQUEST.
+ */
+static int
+smb_send_name_release_request_and_demand(int bcast,
+ struct name_question *question, struct resource_record *additional)
+{
+ int gotreply = 0;
+ int i, rc;
+ int addr_num;
+ uint32_t retries;
+ uint32_t timeout;
+ struct addr_entry *destination;
+ struct name_packet packet;
+
+ if (bcast == BROADCAST) {
+ if (bcast_num == 0)
+ return (-1);
+ destination = smb_bcast_list;
+ addr_num = bcast_num;
+ retries = 1; /* BCAST_REQ_RETRY_COUNT */
+ timeout = 100; /* BCAST_REQ_RETRY_TIMEOUT */
+ packet.info = NAME_RELEASE_REQUEST | NM_FLAGS_BROADCAST;
+ } else {
+ if (nbns_num == 0)
+ return (-1);
+ destination = smb_nbns;
+ addr_num = nbns_num;
+ retries = 1; /* UCAST_REQ_RETRY_COUNT */
+ timeout = 100; /* UCAST_REQ_RETRY_TIMEOUT */
+ packet.info = NAME_RELEASE_REQUEST | NM_FLAGS_UNICAST;
+ }
+
+ packet.qdcount = 1; /* question entries */
+ packet.question = question;
+ packet.ancount = 0; /* answer recs */
+ packet.answer = NULL;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 1; /* additional recs */
+ packet.additional = additional;
+
+ for (i = 0; i < addr_num; i++) {
+ rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
+ retries, timeout);
+ if (rc == 1)
+ gotreply = 1;
+ }
+
+ return (gotreply);
+}
+
+/*
+ * 4.2.10. POSITIVE NAME RELEASE RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x6 |1|0|0|0|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *
+ * 4.2.11. NEGATIVE NAME RELEASE RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x6 |1|0|0|0|0 0|0| RCODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0006 | NB_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * RCODE field values:
+ *
+ * Symbol Value Description:
+ *
+ * FMT_ERR 0x1 Format Error. Request was invalidly
+ * formatted.
+ *
+ * SRV_ERR 0x2 Server failure. Problem with NAME, cannot
+ * process name.
+ *
+ * RFS_ERR 0x5 Refused error. For policy reasons server
+ * will not release this name from this host.
+ *
+ * ACT_ERR 0x6 Active error. Name is owned by another node.
+ * Only that node may release it. A NetBIOS
+ * Name Server can optionally allow a node to
+ * release a name it does not own. This would
+ * facilitate detection of inactive names for
+ * nodes that went down silently.
+ */
+static int
+/* LINTED - E_STATIC_UNUSED */
+smb_send_name_release_response(struct addr_entry *addr,
+ struct name_packet *original_packet, unsigned short rcode)
+{
+ struct name_packet packet;
+ struct resource_record answer;
+
+ bzero(&packet, sizeof (struct name_packet));
+ bzero(&answer, sizeof (struct resource_record));
+
+ packet.name_trn_id = original_packet->name_trn_id;
+ packet.info = NAME_RELEASE_RESPONSE | (rcode & NAME_RCODE_MASK);
+ packet.qdcount = 0; /* question entries */
+ packet.question = NULL;
+ packet.ancount = 1; /* answer recs */
+ packet.answer = &answer;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 0; /* additional recs */
+ packet.additional = NULL;
+
+ answer.name = original_packet->question->name;
+ answer.rr_type = NAME_QUESTION_TYPE_NB;
+ answer.rr_class = NAME_QUESTION_CLASS_IN;
+ answer.ttl = original_packet->additional->ttl;
+ answer.rdlength = original_packet->additional->rdlength;
+ answer.rdata = original_packet->additional->rdata;
+
+ return (smb_send_name_service_packet(addr, &packet));
+}
+
+/*
+ *
+ * 4.2.12. NAME QUERY REQUEST
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |0| 0x0 |0|0|1|0|0 0|B| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0001 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / QUESTION_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static int
+smb_send_name_query_request(int bcast, struct name_question *question)
+{
+ int rc = 0;
+ uint32_t retry, retries;
+ uint32_t timeout;
+ unsigned short tid;
+ struct addr_entry *destination;
+ struct name_packet packet;
+ int i, addr_num;
+ struct timespec st;
+
+ if (bcast == BROADCAST) {
+ if (bcast_num == 0)
+ return (-1);
+ destination = smb_bcast_list;
+ addr_num = bcast_num;
+ retries = BCAST_REQ_RETRY_COUNT;
+ timeout = BCAST_REQ_RETRY_TIMEOUT;
+ packet.info = NAME_QUERY_REQUEST | NM_FLAGS_BROADCAST;
+ } else {
+ if (nbns_num == 0)
+ return (-1);
+ destination = smb_nbns;
+ addr_num = nbns_num;
+ retries = UCAST_REQ_RETRY_COUNT;
+ timeout = UCAST_REQ_RETRY_TIMEOUT;
+ packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST;
+ }
+ packet.qdcount = 1; /* question entries */
+ packet.question = question;
+ packet.ancount = 0; /* answer recs */
+ packet.answer = NULL;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 0; /* additional recs */
+ packet.additional = NULL;
+
+ for (i = 0; i < addr_num; i++) {
+ for (retry = 0; retry < retries; retry++) {
+ if ((destination->flags & ADDR_FLAG_VALID) == 0)
+ break;
+ tid = netbios_name_transcation_id++;
+ packet.name_trn_id = tid;
+
+ if (smb_send_name_service_packet(&destination[i],
+ &packet) >= 0) {
+ if ((rc = smb_netbios_process_response(tid,
+ &destination[i],
+ &packet, timeout)) != 0)
+ break;
+ }
+ st.tv_sec = 0;
+ st.tv_nsec = (timeout * 1000000);
+ (void) nanosleep(&st, 0);
+ }
+ }
+
+ return (rc);
+}
+
+
+/*
+ *
+ * 4.2.13. POSITIVE NAME QUERY RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x0 |1|T|1|?|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB (0x0020) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RDLENGTH | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ * | |
+ * / ADDR_ENTRY ARRAY /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The ADDR_ENTRY ARRAY a sequence of zero or more ADDR_ENTRY
+ * records. Each ADDR_ENTRY record represents an owner of a name.
+ * For group names there may be multiple entries. However, the list
+ * may be incomplete due to packet size limitations. Bit 22, "T",
+ * will be set to indicate truncated data.
+ *
+ * Each ADDR_ENTRY has the following format:
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_FLAGS | NB_ADDRESS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NB_ADDRESS (continued) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *
+ *
+ * 4.2.14. NEGATIVE NAME QUERY RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x0 |1|0|1|?|0 0|0| RCODE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * / /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NULL (0x000A) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x00000000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * RCODE field values:
+ *
+ * Symbol Value Description
+ *
+ * FMT_ERR 0x1 Format Error. Request was invalidly
+ * formatted.
+ * SRV_ERR 0x2 Server failure. Problem with NAME, cannot
+ * process name.
+ * NAM_ERR 0x3 Name Error. The name requested does not
+ * exist.
+ * IMP_ERR 0x4 Unsupported request error. Allowable only
+ * for challenging NAME when gets an Update type
+ * registration request.
+ * RFS_ERR 0x5 Refused error. For policy reasons server
+ * will not register this name from this host.
+ */
+static int
+smb_send_name_query_response(struct addr_entry *addr,
+ struct name_packet *original_packet, struct name_entry *entry,
+ unsigned short rcode)
+{
+ struct addr_entry *raddr;
+ struct name_packet packet;
+ struct resource_record answer;
+ unsigned short attr;
+ unsigned char data[MAX_DATAGRAM_LENGTH];
+ unsigned char *scan = data;
+
+ packet.name_trn_id = original_packet->name_trn_id;
+ packet.info = NAME_QUERY_RESPONSE | (rcode & NAME_RCODE_MASK);
+ packet.qdcount = 0; /* question entries */
+ packet.question = NULL;
+ packet.ancount = 1; /* answer recs */
+ packet.answer = &answer;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 0; /* additional recs */
+ packet.additional = NULL;
+
+ answer.name = entry;
+ answer.rr_class = NAME_QUESTION_CLASS_IN;
+ answer.ttl = entry->addr_list.ttl;
+ answer.rdata = data;
+ if (rcode) {
+ answer.rr_type = NAME_RR_TYPE_NULL;
+ answer.rdlength = 0;
+ bzero(data, 6);
+ } else {
+ answer.rdlength = 0;
+ answer.rr_type = NAME_QUESTION_TYPE_NB;
+ raddr = &entry->addr_list;
+ scan = data;
+ do {
+ attr = entry->attributes & (NAME_ATTR_GROUP |
+ NAME_ATTR_OWNER_NODE_TYPE);
+
+ BE_OUT16(scan, attr); scan += 2;
+ (void) memcpy(scan, &raddr->sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+ scan += 4;
+
+ answer.rdlength += 6;
+ raddr = raddr->forw;
+ } while (raddr != &entry->addr_list);
+ }
+
+ return (smb_send_name_service_packet(addr, &packet));
+}
+
+/*
+ * 4.2.18. NODE STATUS RESPONSE
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_TRN_ID |1| 0x0 |1|0|0|0|0 0|0| 0x0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0001 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x0000 | 0x0000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * / RR_NAME /
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NBSTAT (0x0021) | IN (0x0001) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x00000000 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RDLENGTH | NUM_NAMES | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+ * | |
+ * + +
+ * / NODE_NAME ARRAY /
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * + +
+ * / STATISTICS /
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The NODE_NAME ARRAY is an array of zero or more NUM_NAMES entries
+ * of NODE_NAME records. Each NODE_NAME entry represents an active
+ * name in the same NetBIOS scope as the requesting name in the
+ * local name table of the responder. RR_NAME is the requesting
+ * name.
+ *
+ * NODE_NAME Entry:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * +--- ---+
+ * | |
+ * +--- NETBIOS FORMAT NAME ---+
+ * | |
+ * +--- ---+
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NAME_FLAGS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The NAME_FLAGS field:
+ *
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * | G | ONT |DRG|CNF|ACT|PRM| RESERVED |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * The NAME_FLAGS field is defined as:
+ *
+ * Symbol Bit(s) Description:
+ *
+ * RESERVED 7-15 Reserved for future use. Must be zero (0).
+ * PRM 6 Permanent Name Flag. If one (1) then entry
+ * is for the permanent node name. Flag is zero
+ * (0) for all other names.
+ * ACT 5 Active Name Flag. All entries have this flag
+ * set to one (1).
+ * CNF 4 Conflict Flag. If one (1) then name on this
+ * node is in conflict.
+ * DRG 3 Deregister Flag. If one (1) then this name
+ * is in the process of being deleted.
+ * ONT 1,2 Owner Node Type:
+ * 00 = B node
+ * 01 = P node
+ * 10 = M node
+ * 11 = Reserved for future use
+ * G 0 Group Name Flag.
+ * If one (1) then the name is a GROUP NetBIOS
+ * name.
+ * If zero (0) then it is a UNIQUE NetBIOS name.
+ */
+#define NAME_FLAGS_PERMANENT_NAME 0x0200
+#define NAME_FLAGS_ACTIVE_NAME 0x0400
+#define NAME_FLAGS_CONFLICT 0x0800
+#define NAME_FLAGS_DEREGISTER 0x1000
+#define NAME_FLAGS_ONT_MASK 0x6000
+#define NAME_FLAGS_ONT_B_NODE 0x0000
+#define NAME_FLAGS_ONT_P_NODE 0x2000
+#define NAME_FLAGS_ONT_M_NODE 0x4000
+#define NAME_FLAGS_ONT_RESERVED 0x6000
+#define NAME_FLAGS_GROUP_NAME 0x8000
+
+
+/*
+ * STATISTICS Field of the NODE STATUS RESPONSE:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | UNIT_ID (Unique unit ID) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | UNIT_ID,continued | JUMPERS | TEST_RESULT |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | VERSION_NUMBER | PERIOD_OF_STATISTICS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_OF_CRCs | NUMBER_ALIGNMENT_ERRORS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_OF_COLLISIONS | NUMBER_SEND_ABORTS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_GOOD_SENDS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_GOOD_RECEIVES |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_RETRANSMITS | NUMBER_NO_RESOURCE_CONDITIONS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NUMBER_FREE_COMMAND_BLOCKS | TOTAL_NUMBER_COMMAND_BLOCKS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |MAX_TOTAL_NUMBER_COMMAND_BLOCKS| NUMBER_PENDING_SESSIONS |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MAX_NUMBER_PENDING_SESSIONS | MAX_TOTAL_SESSIONS_POSSIBLE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SESSION_DATA_PACKET_SIZE |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+#define MAX_NETBIOS_REPLY_DATA_SIZE 500
+
+static int
+smb_send_node_status_response(struct addr_entry *addr,
+ struct name_packet *original_packet)
+{
+ uint32_t net_ipaddr, max_connections;
+ struct arpreq arpreq;
+ struct name_packet packet;
+ struct resource_record answer;
+ unsigned char *scan;
+ unsigned char *scan_end;
+ unsigned char data[MAX_NETBIOS_REPLY_DATA_SIZE];
+ net_cfg_t cfg;
+
+ bzero(&packet, sizeof (struct name_packet));
+ bzero(&answer, sizeof (struct resource_record));
+
+ packet.name_trn_id = original_packet->name_trn_id;
+ packet.info = NODE_STATUS_RESPONSE;
+ packet.qdcount = 0; /* question entries */
+ packet.question = NULL;
+ packet.ancount = 1; /* answer recs */
+ packet.answer = &answer;
+ packet.nscount = 0; /* authority recs */
+ packet.authority = NULL;
+ packet.arcount = 0; /* additional recs */
+ packet.additional = NULL;
+
+ answer.name = original_packet->question->name;
+ answer.rr_type = NAME_RR_TYPE_NBSTAT;
+ answer.rr_class = NAME_QUESTION_CLASS_IN;
+ answer.ttl = 0;
+ answer.rdata = data;
+
+ scan = smb_netbios_cache_status(data, MAX_NETBIOS_REPLY_DATA_SIZE,
+ original_packet->question->name->scope);
+
+ scan_end = data + MAX_NETBIOS_REPLY_DATA_SIZE;
+
+ if (smb_nic_get_bysubnet(addr->sin.sin_addr.s_addr, &cfg) == NULL)
+ net_ipaddr = 0;
+ else
+ net_ipaddr = cfg.ip;
+
+ smb_config_rdlock();
+ max_connections = smb_config_getnum(SMB_CI_MAX_CONNECTIONS);
+ smb_config_unlock();
+ for (;;) {
+ if ((scan + 6) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+
+ if (net_ipaddr != 0) {
+ struct sockaddr_in *s_in;
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ /* LINTED - E_BAD_PTR_CAST_ALIGN */
+ s_in = (struct sockaddr_in *)&arpreq.arp_pa;
+ s_in->sin_family = AF_INET;
+ s_in->sin_addr.s_addr = net_ipaddr;
+ if (ioctl(s, SIOCGARP, (caddr_t)&arpreq) < 0) {
+ bzero(scan, 6);
+ } else {
+ bcopy(&arpreq.arp_ha.sa_data, scan, 6);
+ }
+ (void) close(s);
+ } else {
+ bzero(scan, 6);
+ }
+ scan += 6;
+
+ if ((scan + 26) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ bzero(scan, 26);
+ scan += 26;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ BE_OUT16(scan, 0); scan += 2;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ BE_OUT16(scan, 0); scan += 2;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ BE_OUT16(scan, 0); scan += 2;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ BE_OUT16(scan, 0); scan += 2;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ BE_OUT16(scan, 0); scan += 2;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ BE_OUT16(scan, 0); scan += 2;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ BE_OUT16(scan, 0); scan += 2;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+ BE_OUT16(scan, max_connections); scan += 2;
+
+ if ((scan + 2) >= scan_end) {
+ packet.info |= NAME_NM_FLAGS_TC;
+ break;
+ }
+
+ BE_OUT16(scan, 0); scan += 2;
+
+ break;
+ /*NOTREACHED*/
+ }
+ answer.rdlength = scan - data;
+ return (smb_send_name_service_packet(addr, &packet));
+}
+
+/*
+ *
+ * 5.1. NAME SERVICE PROTOCOLS
+ *
+ * A REQUEST packet is always sent to the well known UDP port -
+ * NAME_SERVICE_UDP_PORT. The destination address is normally
+ * either the IP broadcast address or the address of the NAME - the
+ * address of the NAME server it set up at initialization time. In
+ * rare cases, a request packet will be sent to an end node, e.g. a
+ * NAME QUERY REQUEST sent to "challenge" a node.
+ *
+ * A RESPONSE packet is always sent to the source UDP port and
+ * source IP address of the request packet.
+ *
+ * A DEMAND packet must always be sent to the well known UDP port -
+ * NAME_SERVICE_UDP_PORT. There is no restriction on the target IP
+ * address.
+ *
+ * Terms used in this section:
+ *
+ * tid - Transaction ID. This is a value composed from
+ * the requestor's IP address and a unique 16 bit
+ * value generated by the originator of the
+ * transaction.
+ */
+
+
+/*
+ *
+ * 5.1.1. B-NODE ACTIVITY
+ *
+ * 5.1.1.1. B-NODE ADD NAME
+ *
+ * PROCEDURE add_name(name)
+ *
+ * (*
+ * * Host initiated processing for a B node
+ * *)
+ * BEGIN
+ *
+ * REPEAT
+ *
+ * (* build name service packet *)
+ *
+ * ONT = B_NODE; (* broadcast node *)
+ * G = UNIQUE; (* unique name *)
+ * TTL = 0;
+ *
+ * broadcast NAME REGISTRATION REQUEST packet;
+ *
+ * (*
+ * * remote node(s) will send response packet
+ * * if applicable
+ * *)
+ * pause(BCAST_REQ_RETRY_TIMEOUT);
+ *
+ * UNTIL response packet is received or
+ * retransmit count has been exceeded
+ *
+ * IF no response packet was received THEN
+ * BEGIN (* no response *)
+ * (*
+ * * Build packet
+ * *)
+ *
+ * ONT = B_NODE; (* broadcast node *)
+ * G = UNIQUE; (* unique name *)
+ * TTL = 0;
+ *
+ * (*
+ * * Let other nodes known you have the name
+ * *)
+ *
+ * broadcast NAME UPDATE REQUEST packet;
+ * (* name can be added to local name table *)
+ * return success;
+ * END (* no response *)
+ * ELSE
+ * BEGIN (* got response *)
+ *
+ * (*
+ * * Match return transaction id
+ * * against tid sent in request
+ * *)
+ *
+ * IF NOT response tid = request tid THEN
+ * BEGIN
+ * ignore response packet;
+ * END
+ * ELSE
+ * CASE packet type OF
+ *
+ * NEGATIVE NAME REGISTRATION RESPONSE:
+ *
+ * return failure; (* name cannot be added *)
+ *
+ * POSITIVE NAME REGISTRATION RESPONSE:
+ * END-NODE CHALLENGE NAME REGISTRATION RESPONSE:
+ *
+ * (*
+ * * B nodes should normally not get this
+ * * response.
+ * *)
+ *
+ * ignore packet;
+ * END (* case *);
+ * END (* got response *)
+ * END (* procedure *)
+ *
+ *
+ *
+ * 5.1.1.2. B-NODE ADD_GROUP NAME
+ *
+ * PROCEDURE add_group_name(name)
+ *
+ * (*
+ * * Host initiated processing for a B node
+ * *)
+ *
+ * BEGIN
+ * (*
+ * * same as for a unique name with the
+ * * exception that the group bit (G) must
+ * * be set in the request packets.
+ * *)
+ *
+ * ...
+ * G = GROUP;
+ * ...
+ * ...
+ *
+ * (*
+ * * broadcast request ...
+ * *)
+ *
+ *
+ * END
+ */
+static int
+smb_name_Bnode_add_name(struct name_entry *name)
+{
+ struct name_question question;
+ struct resource_record additional;
+ unsigned char data[8];
+ unsigned short attr;
+ struct addr_entry *addr;
+ int rc = 0;
+
+ addr = &name->addr_list;
+
+ do {
+ /* build name service packet */
+ question.name = name;
+ /*
+ * question.name->attributes |= NAME_NB_FLAGS_ONT_B;
+ * This is commented because NAME_NB_FLAGS_ONT_B is 0
+ */
+ question.question_type = NAME_QUESTION_TYPE_NB;
+ question.question_class = NAME_QUESTION_CLASS_IN;
+
+ additional.name = name;
+ additional.rr_class = NAME_QUESTION_CLASS_IN;
+ additional.ttl = 0;
+ additional.rdata = data;
+ additional.rdlength = 6;
+ additional.rr_type = NAME_QUESTION_TYPE_NB;
+ attr = name->attributes & (NAME_ATTR_GROUP |
+ NAME_ATTR_OWNER_NODE_TYPE);
+
+ BE_OUT16(&data[0], attr);
+ (void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+
+ rc |= smb_send_name_registration_request(BROADCAST, &question,
+ &additional);
+ addr = addr->forw;
+
+ } while (addr != &name->addr_list);
+
+ return (rc);
+}
+
+/*
+ * 5.1.1.3. B-NODE FIND_NAME
+ *
+ * PROCEDURE find_name(name)
+ *
+ * (*
+ * * Host initiated processing for a B node
+ * *)
+ *
+ * BEGIN
+ *
+ * REPEAT
+ * (*
+ * * build packet
+ * *)
+ * ONT = B;
+ * TTL = 0;
+ * G = DONT CARE;
+ * raddr = raddr->forw;
+ *
+ * broadcast NAME QUERY REQUEST packet;
+ * (*
+ * * a node might send response packet
+ * *)
+ *
+ * pause(BCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL response packet received OR
+ * max transmit threshold exceeded
+ *
+ * IF no response packet received THEN
+ * return failure;
+ * ELSE
+ * IF NOT response tid = request tid THEN
+ * ignore packet;
+ * ELSE
+ * CASE packet type OF
+ * POSITIVE NAME QUERY RESPONSE:
+ * (*
+ * * Start a timer to detect conflict.
+ * *
+ * * Be prepared to detect conflict if
+ * * any more response packets are received.
+ * *
+ * *)
+ *
+ * save response as authoritative response;
+ * start_timer(CONFLICT_TIMER);
+ * return success;
+ *
+ * NEGATIVE NAME QUERY RESPONSE:
+ * REDIRECT NAME QUERY RESPONSE:
+ *
+ * (*
+ * * B Node should normally not get either
+ * * response.
+ * *)
+ *
+ * ignore response packet;
+ *
+ * END (* case *)
+ * END (* procedure *)
+ */
+static int
+smb_name_Bnode_find_name(struct name_entry *name)
+{
+ struct name_question question;
+
+ question.name = name;
+ question.question_type = NAME_QUESTION_TYPE_NB;
+ question.question_class = NAME_QUESTION_CLASS_IN;
+
+ return (smb_send_name_query_request(BROADCAST, &question));
+}
+
+/*
+ * 5.1.1.4. B NODE NAME RELEASE
+ *
+ * PROCEDURE delete_name (name)
+ * BEGIN
+ *
+ * REPEAT
+ *
+ * (*
+ * * build packet
+ * *)
+ * ...
+ *
+ * (*
+ * * send request
+ * *)
+ *
+ * broadcast NAME RELEASE REQUEST packet;
+ *
+ * (*
+ * * no response packet expected
+ * *)
+ *
+ * pause(BCAST_REQ_RETRY_TIMEOUT);
+ *
+ * UNTIL retransmit count has been exceeded
+ * END (* procedure *)
+ */
+static int
+smb_name_Bnode_delete_name(struct name_entry *name)
+{
+ struct name_question question;
+ struct resource_record additional;
+ struct addr_entry *raddr;
+ unsigned char data[MAX_DATAGRAM_LENGTH];
+ unsigned char *scan = data;
+ uint32_t attr;
+
+ /* build packet */
+ question.name = name;
+ question.question_type = NAME_QUESTION_TYPE_NB;
+ question.question_class = NAME_QUESTION_CLASS_IN;
+
+ additional.name = name;
+ additional.rr_class = NAME_QUESTION_CLASS_IN;
+ additional.ttl = 0;
+ additional.rdata = data;
+ additional.rdlength = 0;
+ additional.rr_type = NAME_QUESTION_TYPE_NB;
+ raddr = &name->addr_list;
+ scan = data;
+ do {
+ attr = name->attributes & (NAME_ATTR_GROUP |
+ NAME_ATTR_OWNER_NODE_TYPE);
+
+ BE_OUT16(scan, attr); scan += 2;
+ (void) memcpy(scan, &raddr->sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+ scan += 4;
+
+ additional.rdlength += 6;
+ } while (raddr != &name->addr_list);
+
+ return (smb_send_name_release_request_and_demand(BROADCAST,
+ &question, &additional));
+}
+
+/*
+ *
+ * 5.1.2. P-NODE ACTIVITY
+ *
+ * All packets sent or received by P nodes are unicast UDP packets.
+ * A P node sends name service requests to the NAME node that is
+ * specified in the P-node configuration.
+ *
+ * 5.1.2.1. P-NODE ADD_NAME
+ *
+ * PROCEDURE add_name(name)
+ *
+ * (*
+ * * Host initiated processing for a P node
+ * *)
+ *
+ * BEGIN
+ *
+ * REPEAT
+ * (*
+ * * build packet
+ * *)
+ *
+ * ONT = P;
+ * G = UNIQUE;
+ * ...
+ *
+ * (*
+ * * send request
+ * *)
+ *
+ * unicast NAME REGISTRATION REQUEST packet;
+ *
+ * (*
+ * * NAME will send response packet
+ * *)
+ *
+ * IF receive a WACK RESPONSE THEN
+ * pause(time from TTL field of response);
+ * ELSE
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL response packet is received OR
+ * retransmit count has been exceeded
+ *
+ * IF no response packet was received THEN
+ * BEGIN (* no response *)
+ * (*
+ * * NAME is down. Cannot claim name.
+ * *)
+ *
+ * return failure; (* name cannot be claimed *)
+ * END (* no response *)
+ * ELSE
+ * BEGIN (* response *)
+ * IF NOT response tid = request tid THEN
+ * BEGIN
+ * (* Packet may belong to another transaction *)
+ * ignore response packet;
+ * END
+ * ELSE
+ * CASE packet type OF
+ *
+ * POSITIVE NAME REGISTRATION RESPONSE:
+ *
+ * (*
+ * * name can be added
+ * *)
+ *
+ * adjust refresh timeout value, TTL, for this name;
+ * return success; (* name can be added *)
+ *
+ * NEGATIVE NAME REGISTRATION RESPONSE:
+ * return failure; (* name cannot be added *)
+ *
+ * END-NODE CHALLENGE REGISTRATION REQUEST:
+ * BEGIN (* end node challenge *)
+ *
+ * (*
+ * * The response packet has in it the
+ * * address of the presumed owner of the
+ * * name. Challenge that owner.
+ * * If owner either does not
+ * * respond or indicates that he no longer
+ * * owns the name, claim the name.
+ * * Otherwise, the name cannot be claimed.
+ * *
+ * *)
+ *
+ * REPEAT
+ * (*
+ * * build packet
+ * *)
+ * ...
+ *
+ * unicast NAME QUERY REQUEST packet to the
+ * address contained in the END NODE
+ * CHALLENGE RESPONSE packet;
+ *
+ * (*
+ * * remote node may send response packet
+ * *)
+ *
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ *
+ * UNTIL response packet is received or
+ * retransmit count has been exceeded
+ * IF no response packet is received OR
+ * NEGATIVE NAME QUERY RESPONSE packet
+ * received THEN
+ * BEGIN (* update *)
+ *
+ * (*
+ * * name can be claimed
+ * *)
+ *
+ * REPEAT
+ *
+ * (*
+ * * build packet
+ * *)
+ * ...
+ *
+ * unicast NAME UPDATE REQUEST to NAME;
+ *
+ * (*
+ * * NAME node will send response packet
+ * *)
+ *
+ * IF receive a WACK RESPONSE THEN
+ * pause(time from TTL field of response);
+ * ELSE
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL response packet is received or
+ * retransmit count has been exceeded
+ * IF no response packet received THEN
+ * BEGIN (* no response *)
+ *
+ * (*
+ * * name could not be claimed
+ * *)
+ *
+ * return failure;
+ * END (* no response *)
+ * ELSE
+ * CASE packet type OF
+ * POSITIVE NAME REGISTRATION RESPONSE:
+ * (*
+ * * add name
+ * *)
+ * return success;
+ * NEGATIVE NAME REGISTRATION RESPONSE:
+ *
+ * (*
+ * * you lose ...
+ * *)
+ * return failure;
+ * END (* case *)
+ * END (* update *)
+ * ELSE
+ *
+ * (*
+ * * received a positive response to the "challenge"
+ * * Remote node still has name
+ * *)
+ *
+ * return failure;
+ * END (* end node challenge *)
+ * END (* response *)
+ * END (* procedure *)
+ *
+ *
+ * 5.1.2.2. P-NODE ADD GROUP NAME
+ *
+ * PROCEDURE add_group_name(name)
+ *
+ * (*
+ * * Host initiated processing for a P node
+ * *)
+ *
+ * BEGIN
+ * (*
+ * * same as for a unique name, except that the
+ * * request packet must indicate that a
+ * * group name claim is being made.
+ * *)
+ *
+ * ...
+ * G = GROUP;
+ * ...
+ *
+ * (*
+ * * send packet
+ * *)
+ * ...
+ *
+ *
+ * END
+ */
+static int
+smb_name_Pnode_add_name(struct name_entry *name)
+{
+ struct name_question question;
+ struct resource_record additional;
+ unsigned char data[8];
+ unsigned short attr;
+ struct addr_entry *addr;
+ int rc = 0;
+
+ /* build packet */
+ addr = &name->addr_list;
+ do {
+ question.name = name;
+ question.question_type = NAME_QUESTION_TYPE_NB;
+ question.question_class = NAME_QUESTION_CLASS_IN;
+
+ additional.name = name;
+ additional.rr_class = NAME_QUESTION_CLASS_IN;
+ additional.ttl = 0;
+ additional.rdata = data;
+ additional.rdlength = 6;
+ additional.rr_type = NAME_QUESTION_TYPE_NB;
+ attr = name->attributes &
+ (NAME_ATTR_GROUP | NAME_ATTR_OWNER_NODE_TYPE);
+
+ BE_OUT16(&data[0], attr);
+ (void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+
+ rc |= smb_send_name_registration_request(UNICAST, &question,
+ &additional);
+
+ addr = addr->forw;
+
+ } while (addr != &name->addr_list);
+
+ return (rc);
+}
+
+static int
+smb_name_Pnode_refresh_name(struct name_entry *name)
+{
+ struct name_question question;
+ struct resource_record additional;
+ unsigned char data[8];
+ unsigned short attr;
+ struct addr_entry *addr;
+ int rc = 0;
+
+ /* build packet */
+ addr = &name->addr_list;
+ do {
+ question.name = name;
+ question.question_type = NAME_QUESTION_TYPE_NB;
+ question.question_class = NAME_QUESTION_CLASS_IN;
+
+ additional.name = name;
+ additional.rr_class = NAME_QUESTION_CLASS_IN;
+ additional.ttl = 0;
+ additional.rdata = data;
+ additional.rdlength = 6;
+ additional.rr_type = NAME_QUESTION_TYPE_NB;
+ attr = name->attributes &
+ (NAME_ATTR_GROUP | NAME_ATTR_OWNER_NODE_TYPE);
+
+ BE_OUT16(&data[0], attr);
+ (void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+
+ rc |= smb_send_name_refresh_request(UNICAST, &question,
+ &additional, 1);
+
+ addr = addr->forw;
+ } while (addr != &name->addr_list);
+
+ return (rc);
+}
+
+/*
+ * 5.1.2.3. P-NODE FIND NAME
+ *
+ * PROCEDURE find_name(name)
+ *
+ * (*
+ * * Host initiated processing for a P node
+ * *)
+ *
+ * BEGIN
+ * REPEAT
+ * (*
+ * * build packet
+ * *)
+ *
+ * ONT = P;
+ * G = DONT CARE;
+ *
+ * unicast NAME QUERY REQUEST packet;
+ *
+ * (*
+ * * a NAME node might send response packet
+ * *)
+ *
+ * IF receive a WACK RESPONSE THEN
+ * pause(time from TTL field of response);
+ * ELSE
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL response packet received OR
+ * max transmit threshold exceeded
+ *
+ * IF no response packet received THEN
+ * return failure;
+ * ELSE
+ * IF NOT response tid = request tid THEN
+ * ignore packet;
+ * ELSE
+ * CASE packet type OF
+ * POSITIVE NAME QUERY RESPONSE:
+ * return success;
+ *
+ * REDIRECT NAME QUERY RESPONSE:
+ *
+ * (*
+ * * NAME node wants this end node
+ * * to use some other NAME node
+ * * to resolve the query.
+ * *)
+ *
+ * repeat query with NAME address
+ * in the response packet;
+ * NEGATIVE NAME QUERY RESPONSE:
+ * return failure;
+ *
+ * END (* case *)
+ * END (* procedure *)
+ */
+static int
+smb_name_Pnode_find_name(struct name_entry *name)
+{
+ struct name_question question;
+
+ /*
+ * Host initiated processing for a P node
+ */
+ question.name = name;
+ question.name->attributes |= NAME_NB_FLAGS_ONT_P;
+ question.question_type = NAME_QUESTION_TYPE_NB;
+ question.question_class = NAME_QUESTION_CLASS_IN;
+
+ return (smb_send_name_query_request(UNICAST, &question));
+}
+
+/*
+ * 5.1.2.4. P-NODE DELETE_NAME
+ *
+ * PROCEDURE delete_name (name)
+ *
+ * (*
+ * * Host initiated processing for a P node
+ * *)
+ *
+ * BEGIN
+ *
+ * REPEAT
+ *
+ * (*
+ * * build packet
+ * *)
+ * ...
+ *
+ * (*
+ * * send request
+ * *)
+ *
+ * unicast NAME RELEASE REQUEST packet;
+ * IF receive a WACK RESPONSE THEN
+ * pause(time from TTL field of response);
+ * ELSE
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL retransmit count has been exceeded
+ * or response been received
+ *
+ * IF response has been received THEN
+ * CASE packet type OF
+ * POSITIVE NAME RELEASE RESPONSE:
+ * return success;
+ * NEGATIVE NAME RELEASE RESPONSE:
+ *
+ * (*
+ * * NAME does want node to delete this
+ * * name !!!
+ * *)
+ *
+ * return failure;
+ * END (* case *)
+ * END (* procedure *)
+ */
+static int
+smb_name_Pnode_delete_name(struct name_entry *name)
+{
+ struct name_question question;
+ struct resource_record additional;
+ struct addr_entry *raddr;
+ unsigned char data[MAX_DATAGRAM_LENGTH];
+ unsigned char *scan = data;
+ uint32_t attr;
+
+ /* build packet */
+ question.name = name;
+ question.name->attributes |= NAME_NB_FLAGS_ONT_P;
+ question.question_type = NAME_QUESTION_TYPE_NB;
+ question.question_class = NAME_QUESTION_CLASS_IN;
+
+ additional.name = name;
+ additional.rr_class = NAME_QUESTION_CLASS_IN;
+ additional.ttl = 0;
+ additional.rdata = data;
+ additional.rdlength = 0;
+ additional.rr_type = NAME_QUESTION_TYPE_NB;
+ raddr = &name->addr_list;
+ do {
+ scan = data;
+ attr = name->attributes & (NAME_ATTR_GROUP |
+ NAME_ATTR_OWNER_NODE_TYPE);
+
+ BE_OUT16(scan, attr); scan += 2;
+ BE_OUT32(scan, raddr->sin.sin_addr.s_addr); scan += 4;
+ (void) memcpy(scan, &raddr->sin.sin_addr.s_addr,
+ sizeof (uint32_t));
+ scan += 4;
+
+ additional.rdlength = 6;
+ raddr = raddr->forw;
+ (void) smb_send_name_release_request_and_demand(UNICAST,
+ &question, &additional);
+ } while (raddr != &name->addr_list);
+
+ return (1);
+}
+
+/*
+ * 5.1.3. M-NODE ACTIVITY
+ *
+ * M nodes behavior is similar to that of P nodes with the addition
+ * of some B node-like broadcast actions. M node name service
+ * proceeds in two steps:
+ *
+ * 1.Use broadcast UDP based name service. Depending on the
+ * operation, goto step 2.
+ *
+ * 2.Use directed UDP name service.
+ *
+ * The following code for M nodes is exactly the same as for a P
+ * node, with the exception that broadcast operations are done
+ * before P type operation is attempted.
+ *
+ * 5.1.3.1. M-NODE ADD NAME
+ *
+ * PROCEDURE add_name(name)
+ *
+ * (*
+ * * Host initiated processing for a M node
+ * *)
+ *
+ * BEGIN
+ *
+ * (*
+ * * check if name exists on the
+ * * broadcast area
+ * *)
+ * REPEAT
+ * (* build packet *)
+ *
+ * ....
+ * broadcast NAME REGISTRATION REQUEST packet;
+ * pause(BCAST_REQ_RETRY_TIMEOUT);
+ *
+ * UNTIL response packet is received or
+ * retransmit count has been exceeded
+ *
+ * IF valid response received THEN
+ * BEGIN
+ * (* cannot claim name *)
+ *
+ * return failure;
+ * END
+ *
+ * (*
+ * * No objections received within the
+ * * broadcast area.
+ * * Send request to name server.
+ * *)
+ *
+ * REPEAT
+ * (*
+ * * build packet
+ * *)
+ *
+ * ONT = M;
+ * ...
+ *
+ * unicast NAME REGISTRATION REQUEST packet;
+ *
+ * (*
+ * * remote NAME will send response packet
+ * *)
+ *
+ * IF receive a WACK RESPONSE THEN
+ * pause(time from TTL field of response);
+ * ELSE
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ *
+ * UNTIL response packet is received or
+ * retransmit count has been exceeded
+ *
+ * IF no response packet was received THEN
+ * BEGIN (* no response *)
+ * (*
+ * * NAME is down. Cannot claim name.
+ * *)
+ * return failure; (* name cannot be claimed *)
+ * END (* no response *)
+ * ELSE
+ * BEGIN (* response *)
+ * IF NOT response tid = request tid THEN
+ * BEGIN
+ * ignore response packet;
+ * END
+ * ELSE
+ * CASE packet type OF
+ * POSITIVE NAME REGISTRATION RESPONSE:
+ *
+ * (*
+ * * name can be added
+ * *)
+ *
+ * adjust refresh timeout value, TTL;
+ * return success; (* name can be added *)
+ *
+ * NEGATIVE NAME REGISTRATION RESPONSE:
+ * return failure; (* name cannot be added *)
+ *
+ * END-NODE CHALLENGE REGISTRATION REQUEST:
+ * BEGIN (* end node challenge *)
+ *
+ * (*
+ * * The response packet has in it the
+ * * address of the presumed owner of the
+ * * name. Challenge that owner.
+ * * If owner either does not
+ * * respond or indicates that he no longer
+ * * owns the name, claim the name.
+ * * Otherwise, the name cannot be claimed.
+ * *
+ * *)
+ *
+ * REPEAT
+ * (*
+ * * build packet
+ * *)
+ * ...
+ *
+ * (*
+ * * send packet to address contained in the
+ * * response packet
+ * *)
+ *
+ * unicast NAME QUERY REQUEST packet;
+ *
+ * (*
+ * * remote node may send response packet
+ * *)
+ *
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ *
+ * UNTIL response packet is received or
+ * retransmit count has been exceeded
+ * IF no response packet is received THEN
+ * BEGIN (* no response *)
+ *
+ * (*
+ * * name can be claimed
+ * *)
+ * REPEAT
+ *
+ * (*
+ * * build packet
+ * *)
+ * ...
+ *
+ * unicast NAME UPDATE REQUEST to NAME;
+ *
+ * (*
+ * * NAME node will send response packet
+ * *)
+ *
+ * IF receive a WACK RESPONSE THEN
+ * pause(time from TTL field of response);
+ * ELSE
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ *
+ * UNTIL response packet is received or
+ * retransmit count has been exceeded
+ * IF no response packet received THEN
+ * BEGIN (* no response *)
+ *
+ * (*
+ * * name could not be claimed
+ * *)
+ *
+ * return failure;
+ * END (* no response *)
+ * ELSE
+ * CASE packet type OF
+ * POSITIVE NAME REGISTRATION RESPONSE:
+ * (*
+ * * add name
+ * *)
+ *
+ * return success;
+ * NEGATIVE NAME REGISTRATION RESPONSE:
+ * (*
+ * * you lose ...
+ * *)
+ *
+ * return failure;
+ * END (* case *)
+ * END (* no response *)
+ * ELSE
+ * IF NOT response tid = request tid THEN
+ * BEGIN
+ * ignore response packet;
+ * END
+ *
+ * (*
+ * * received a response to the "challenge"
+ * * packet
+ * *)
+ *
+ * CASE packet type OF
+ * POSITIVE NAME QUERY:
+ *
+ * (*
+ * * remote node still has name.
+ * *)
+ *
+ * return failure;
+ * NEGATIVE NAME QUERY:
+ *
+ * (*
+ * * remote node no longer has name
+ * *)
+ *
+ * return success;
+ * END (* case *)
+ * END (* end node challenge *)
+ * END (* case *)
+ * END (* response *)
+ * END (* procedure *)
+ *
+ *
+ * 5.1.3.2. M-NODE ADD GROUP NAME
+ *
+ * PROCEDURE add_group_name(name)
+ *
+ * (*
+ * * Host initiated processing for a P node
+ * *)
+ *
+ * BEGIN
+ * (*
+ * * same as for a unique name, except that the
+ * * request packet must indicate that a
+ * * group name claim is being made.
+ * *)
+ *
+ * ...
+ * G = GROUP;
+ * ...
+ *
+ * (*
+ * * send packet
+ * *)
+ * ...
+ *
+ *
+ * END
+ */
+static int
+smb_name_Mnode_add_name(struct name_entry *name)
+{
+ if (smb_name_Bnode_add_name(name) > 0) {
+ if (nbns_num == 0)
+ return (1); /* No name server configured */
+
+ return (smb_name_Pnode_add_name(name));
+ }
+ return (-1);
+}
+
+static int
+smb_name_Hnode_add_name(struct name_entry *name)
+{
+ if (nbns_num > 0) {
+ if (smb_name_Pnode_add_name(name) == 1)
+ return (1);
+ }
+
+ return (smb_name_Bnode_add_name(name));
+}
+
+/*
+ * 5.1.3.3. M-NODE FIND NAME
+ *
+ * PROCEDURE find_name(name)
+ *
+ * (*
+ * * Host initiated processing for a M node
+ * *)
+ *
+ * BEGIN
+ * (*
+ * * check if any node on the broadcast
+ * * area has the name
+ * *)
+ *
+ * REPEAT
+ * (* build packet *)
+ * ...
+ *
+ * broadcast NAME QUERY REQUEST packet;
+ * pause(BCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL response packet received OR
+ * max transmit threshold exceeded
+ *
+ * IF valid response received THEN
+ * BEGIN
+ * save response as authoritative response;
+ * start_timer(CONFLICT_TIMER);
+ * return success;
+ * END
+ *
+ * (*
+ * * no valid response on the b'cast segment.
+ * * Try the name server.
+ * *)
+ *
+ * REPEAT
+ * (*
+ * * build packet
+ * *)
+ *
+ * ONT = M;
+ * G = DONT CARE;
+ *
+ * unicast NAME QUERY REQUEST packet to NAME;
+ *
+ * (*
+ * * a NAME node might send response packet
+ * *)
+ *
+ * IF receive a WACK RESPONSE THEN
+ * pause(time from TTL field of response);
+ * ELSE
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL response packet received OR
+ * max transmit threshold exceeded
+ *
+ * IF no response packet received THEN
+ * return failure;
+ * ELSE
+ * IF NOT response tid = request tid THEN
+ * ignore packet;
+ * ELSE
+ * CASE packet type OF
+ * POSITIVE NAME QUERY RESPONSE:
+ * return success;
+ *
+ * REDIRECT NAME QUERY RESPONSE:
+ *
+ * (*
+ * * NAME node wants this end node
+ * * to use some other NAME node
+ * * to resolve the query.
+ * *)
+ *
+ * repeat query with NAME address
+ * in the response packet;
+ * NEGATIVE NAME QUERY RESPONSE:
+ * return failure;
+ *
+ * END (* case *)
+ * END (* procedure *)
+ */
+static int
+smb_name_Mnode_find_name(struct name_entry *name)
+{
+ if (smb_name_Bnode_find_name(name) == 1)
+ return (1);
+
+ if (nbns_num == 0)
+ return (1); /* No name server configured */
+
+ return (smb_name_Pnode_find_name(name));
+}
+
+static int
+smb_name_Hnode_find_name(struct name_entry *name)
+{
+ if (nbns_num > 0)
+ if (smb_name_Pnode_find_name(name) == 1)
+ return (1);
+
+ return (smb_name_Bnode_find_name(name));
+}
+
+/*
+ * 5.1.3.4. M-NODE DELETE NAME
+ *
+ * PROCEDURE delete_name (name)
+ *
+ * (*
+ * * Host initiated processing for a P node
+ * *)
+ *
+ * BEGIN
+ * (*
+ * * First, delete name on NAME
+ * *)
+ *
+ * REPEAT
+ *
+ * (*
+ * * build packet
+ * struct addr_entry *addr;
+ * *)
+ * ...
+ *
+ * (*
+ * * send request
+ * *)
+ *
+ * unicast NAME RELEASE REQUEST packet to NAME;
+ *
+ * IF receive a WACK RESPONSE THEN
+ * pause(time from TTL field of response);
+ * ELSE
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL retransmit count has been exceeded
+ * or response been received
+ *
+ * IF response has been received THEN
+ * CASE packet type OF
+ * POSITIVE NAME RELEASE RESPONSE:
+ * (*
+ * * Deletion of name on b'cast segment is deferred
+ * * until after NAME has deleted the name
+ * *)
+ *
+ * REPEAT
+ * (* build packet *)
+ *
+ * ...
+ * broadcast NAME RELEASE REQUEST;
+ * pause(BCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL rexmt threshold exceeded
+ *
+ * return success;
+ * NEGATIVE NAME RELEASE RESPONSE:
+ *
+ * (*
+ * * NAME does want node to delete this
+ * * name
+ * *)
+ * return failure;
+ * END (* case *)
+ * END (* procedure *)
+ */
+static int
+smb_name_Mnode_delete_name(struct name_entry *name)
+{
+ (void) smb_name_Bnode_delete_name(name);
+
+ if (nbns_num == 0)
+ return (-1); /* No name server configured */
+
+ if (smb_name_Pnode_delete_name(name) > 0)
+ return (1);
+
+ return (-1);
+}
+
+static int
+smb_name_Hnode_delete_name(struct name_entry *name)
+{
+ if (nbns_num > 0)
+ if (smb_name_Pnode_delete_name(name) > 0)
+ return (1);
+
+ return (smb_name_Bnode_delete_name(name));
+}
+
+/*
+ * 5.1.1.5. B-NODE INCOMING PACKET PROCESSING
+ *
+ * Following processing is done when broadcast or unicast packets
+ * are received at the NAME_SERVICE_UDP_PORT.
+ *
+ * PROCEDURE process_incoming_packet(packet)
+ *
+ * (*
+ * * Processing initiated by incoming packets for a B node
+ * *)
+ *
+ * BEGIN
+ * (*
+ * * Note: response packets are always sent
+ * * to:
+ * * source IP address of request packet
+ * * source UDP port of request packet
+ * *)
+ *
+ * CASE packet type OF
+ *
+ * NAME REGISTRATION REQUEST (UNIQUE):
+ * IF name exists in local name table THEN
+ * send NEGATIVE_NAME_REGISTRATION_RESPONSE ;
+ * NAME REGISTRATION REQUEST (GROUP):
+ * IF name exists in local name table THEN
+ * BEGIN
+ * IF local entry is a unique name THEN
+ * send NEGATIVE_NAME_REGISTRATION_RESPONSE ;
+ * END
+ * NAME QUERY REQUEST:
+ * IF name exists in local name table THEN
+ * BEGIN
+ * build response packet;
+ * send POSITIVE_NAME_QUERY_RESPONSE;
+ * POSITIVE NAME QUERY RESPONSE:
+ * IF name conflict timer is not active THEN
+ * BEGIN
+ * (*
+ * * timer has expired already... ignore this
+ * * packet
+ * *)
+ *
+ * return;
+ * END
+ * ELSE (* timer is active *)
+ * IF a response for this name has previously been
+ * received THEN
+ * BEGIN (* existing entry *)
+ *
+ * (*
+ * * we sent out a request packet, and
+ * * have already received (at least)
+ * * one response
+ * *
+ * * Check if conflict exists.
+ * * If so, send out a conflict packet.
+ * *
+ * * Note: detecting conflict does NOT
+ * * affect any existing sessions.
+ * *
+ * *)
+ *
+ * (*
+ * * Check for name conflict.
+ * * See "Name Conflict" in Concepts and Methods
+ * *)
+ * check saved authoritative response against
+ * information in this response packet;
+ * IF conflict detected THEN
+ * BEGIN
+ * unicast NAME CONFLICT DEMAND packet;
+ * IF entry exists in cache THEN
+ * BEGIN
+ * remove entry from cache;
+ * END
+ * END
+ * END (* existing entry *)
+ * ELSE
+ * BEGIN
+ * (*
+ * * Note: If this was the first response
+ * * to a name query, it would have been
+ * * handled in the
+ * * find_name() procedure.
+ * *)
+ *
+ * ignore packet;
+ * END
+ * NAME CONFLICT DEMAND:
+ * IF name exists in local name table THEN
+ * BEGIN
+ * mark name as conflict detected;
+ *
+ * (*
+ * * a name in the state "conflict detected"
+ * * does not "logically" exist on that node.
+ * * No further session will be accepted on
+ * * that name.
+ * * No datagrams can be sent against that name.
+ * * Such an entry will not be used for
+ * * purposes of processing incoming request
+ * * packets.
+ * * The only valid user NetBIOS operation
+ * * against such a name is DELETE NAME.
+ * *)
+ * END
+ * NAME RELEASE REQUEST:
+ * IF caching is being done THEN
+ * BEGIN
+ * remove entry from cache;
+ * END
+ * NAME UPDATE REQUEST:
+ * IF caching is being done THEN
+ * BEGIN
+ * IF entry exists in cache already,
+ * update cache;
+ * ELSE IF name is "interesting" THEN
+ * BEGIN
+ * add entry to cache;
+ * END
+ * END
+ *
+ * NODE STATUS REQUEST:
+ * IF name exists in local name table THEN
+ * BEGIN
+ * (*
+ * * send only those names that are
+ * * in the same scope as the scope
+ * * field in the request packet
+ * *)
+ *
+ * send NODE STATUS RESPONSE;
+ * END
+ * END
+ */
+static void
+smb_name_process_Bnode_packet(struct name_packet *packet,
+ struct addr_entry *addr)
+{
+ struct name_entry *name;
+ struct name_entry *entry;
+ struct name_question *question;
+ struct resource_record *additional;
+
+ question = packet->question;
+ additional = packet->additional;
+
+ switch (packet->info & NAME_OPCODE_OPCODE_MASK) {
+ case NAME_OPCODE_REFRESH:
+ /* Guard against malformed packets */
+ if ((question == 0) || (additional == 0))
+ break;
+ if (additional->name->addr_list.sin.sin_addr.s_addr == 0)
+ break;
+
+ name = question->name;
+ name->addr_list.ttl = additional->ttl;
+ name->attributes = additional->name->attributes;
+ name->addr_list.sin = additional->name->addr_list.sin;
+ name->addr_list.forw = name->addr_list.back = &name->addr_list;
+
+ if ((entry = smb_netbios_cache_lookup_addr(name)) != 0) {
+ smb_netbios_cache_update_entry(entry, question->name);
+ smb_netbios_cache_unlock_entry(entry);
+ }
+ else
+ (void) smb_netbios_cache_insert(question->name);
+ break;
+
+ case NAME_OPCODE_QUERY:
+ /*
+ * This opcode covers both NAME_QUERY_REQUEST and
+ * NODE_STATUS_REQUEST. They can be distinguished
+ * based on the type of question entry.
+ */
+
+ /* All query requests have to have question entry */
+ if (question == 0)
+ break;
+
+ if (question->question_type == NAME_QUESTION_TYPE_NB) {
+ name = question->name;
+ if ((entry = smb_netbios_cache_lookup(name)) != 0) {
+ (void) smb_send_name_query_response(addr,
+ packet, entry, 0);
+ smb_netbios_cache_unlock_entry(entry);
+ }
+ }
+ else
+ if (question->question_type == NAME_QUESTION_TYPE_NBSTAT) {
+ /*
+ * Name of "*" may be used to force node to
+ * divulge status for administrative purposes
+ */
+ name = question->name;
+ entry = 0;
+ if (NETBIOS_NAME_IS_STAR(name->name) ||
+ ((entry = smb_netbios_cache_lookup(name)) != 0)) {
+ if (entry)
+ smb_netbios_cache_unlock_entry(entry);
+ /*
+ * send only those names that are
+ * in the same scope as the scope
+ * field in the request packet
+ */
+ (void) smb_send_node_status_response(addr,
+ packet);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * 5.1.2.5. P-NODE INCOMING PACKET PROCESSING
+ *
+ * Processing initiated by reception of packets at a P node
+ *
+ * PROCEDURE process_incoming_packet(packet)
+ *
+ * (*
+ * * Processing initiated by incoming packets at a P node
+ * *)
+ *
+ * BEGIN
+ * (*
+ * * always ignore UDP broadcast packets
+ * *)
+ *
+ * IF packet was sent as a broadcast THEN
+ * BEGIN
+ * ignore packet;
+ * return;
+ * END
+ * CASE packet type of
+ *
+ * NAME CONFLICT DEMAND:
+ * IF name exists in local name table THEN
+ * mark name as in conflict;
+ * return;
+ *
+ * NAME QUERY REQUEST:
+ * IF name exists in local name table THEN
+ * BEGIN (* name exists *)
+ *
+ * (*
+ * * build packet
+ * *)
+ * ...
+ *
+ * (*
+ * * send response to the IP address and port
+ * * number from which the request was received.
+ * *)
+ *
+ * send POSITIVE_NAME_QUERY_RESPONSE ;
+ * return;
+ * END (* exists *)
+ * ELSE
+ * BEGIN (* does not exist *)
+ *
+ * (*
+ * * send response to the requestor
+ * *)
+ *
+ * send NEGATIVE_NAME_QUERY_RESPONSE ;
+ * return;
+ * END (* does not exist *)
+ * NODE STATUS REQUEST:
+ * (*
+ * * Name of "*" may be used for force node to
+ * * divulge status for administrative purposes
+ * *)
+ * IF name in local name table OR name = "*" THEN
+ * BEGIN
+ * (*
+ * * Build response packet and
+ * * send to requestor node
+ * * Send only those names that are
+ * * in the same scope as the scope
+ * * in the request packet.
+ * *)
+ *
+ * send NODE_STATUS_RESPONSE;
+ * END
+ *
+ * NAME RELEASE REQUEST:
+ * (*
+ * * This will be received if the NAME wants to flush the
+ * * name from the local name table, or from the local
+ * * cache.
+ * *)
+ *
+ * IF name exists in the local name table THEN
+ * BEGIN
+ * delete name from local name table;
+ * inform user that name has been deleted;
+ * END
+ * END (* case *)
+ * END (* procedure *)
+ *
+ * (*
+ * * Incoming packet processing on a NS node
+ * *)
+ *
+ * BEGIN
+ * IF packet was sent as a broadcast THEN
+ * BEGIN
+ * discard packet;
+ * return;
+ * END
+ * CASE packet type of
+ *
+ * NAME REGISTRATION REQUEST (UNIQUE):
+ * IF unique name exists in data base THEN
+ * BEGIN (* unique name exists *)
+ * (*
+ * * NAME node may be a "passive"
+ * * server in that it expects the
+ * * end node to do the challenge
+ * * server. Such a NAME node is
+ * * called a "non-secure" server.
+ * * A "secure" server will do the
+ * * challenging before it sends
+ * * back a response packet.
+ * *)
+ *
+ * IF non-secure THEN
+ * BEGIN
+ * (*
+ * * build response packet
+ * *)
+ * ...
+ *
+ *
+ * (*
+ * * let end node do the challenge
+ * *)
+ *
+ * send END-NODE CHALLENGE NAME REGISTRATION
+ * RESPONSE;
+ * return;
+ * END
+ * ELSE
+ * (*
+ * * secure server - do the name
+ * * challenge operation
+ * *)
+ *
+ * REPEAT
+ * send NAME QUERY REQUEST;
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL response has been received or
+ * retransmit count has been exceeded
+ * IF no response was received THEN
+ * BEGIN
+ *
+ * (* node down *)
+ *
+ * update data base - remove entry;
+ * update data base - add new entry;
+ * send POSITIVE NAME REGISTRATION RESPONSE;
+ * return;
+ * END
+ * ELSE
+ * BEGIN (* challenged node replied *)
+ * (*
+ * * challenged node replied with
+ * * a response packet
+ * *)
+ *
+ * CASE packet type
+ *
+ * POSITIVE NAME QUERY RESPONSE:
+ *
+ * (*
+ * * name still owned by the
+ * * challenged node
+ * *
+ * * build packet and send response
+ * *)
+ * ...
+ *
+ *
+ * (*
+ * * Note: The NAME will need to
+ * * keep track (based on transaction id) of
+ * * the IP address and port number
+ * * of the original requestor.
+ * *)
+ *
+ * send NEGATIVE NAME REGISTRATION RESPONSE;
+ * return;
+ * NEGATIVE NAME QUERY RESPONSE:
+ *
+ * update data base - remove entry;
+ * update data base - add new entry;
+ *
+ * (*
+ * * build response packet and send
+ * * response
+ * *)
+ * send POSITIVE NAME REGISTRATION RESPONSE;
+ * return;
+ * END (* case *)
+ * END (* challenged node replied *)
+ * END (* unique name exists in data base *)
+ * ELSE
+ * IF group name exists in data base THEN
+ * BEGIN (* group names exists *)
+ *
+ * (*
+ * * Members of a group name are NOT
+ * * challenged.
+ * * Make the assumption that
+ * * at least some of the group members
+ * * are still alive.
+ * * Refresh mechanism will
+ * * allow the NAME to detect when all
+ * * members of a group no longer use that
+ * * name
+ * *)
+ *
+ * send NEGATIVE NAME REGISTRATION RESPONSE;
+ * END (* group name exists *)
+ * ELSE
+ * BEGIN (* name does not exist *)
+ *
+ * (*
+ * * Name does not exist in data base
+ * *
+ * * This code applies to both non-secure
+ * * and secure server.
+ * *)
+ *
+ * update data base - add new entry;
+ * send POSITIVE NAME REGISTRATION RESPONSE;
+ * return;
+ * END
+ *
+ * NAME QUERY REQUEST:
+ * IF name exists in data base THEN
+ * BEGIN
+ * (*
+ * * build response packet and send to
+ * * requestor
+ * *)
+ * ...
+ *
+ * send POSITIVE NAME QUERY RESPONSE;
+ * return;
+ * ELSE
+ * BEGIN
+ * (*
+ * * build response packet and send to
+ * * requestor
+ * *)
+ * ...
+ *
+ * send NEGATIVE NAME QUERY RESPONSE;
+ * return;
+ * END
+ *
+ * NAME REGISTRATION REQUEST (GROUP):
+ * IF name exists in data base THEN
+ * BEGIN
+ * IF local entry is a unique name THEN
+ * BEGIN (* local is unique *)
+ *
+ * IF non-secure THEN
+ * BEGIN
+ * send END-NODE CHALLENGE NAME
+ * REGISTRATION RESPONSE;
+ * return;
+ * END
+ *
+ * REPEAT
+ * send NAME QUERY REQUEST;
+ * pause(UCAST_REQ_RETRY_TIMEOUT);
+ * UNTIL response received or
+ * retransmit count exceeded
+ * IF no response received or
+ * NEGATIVE NAME QUERY RESPONSE
+ * received THEN
+ * BEGIN
+ * update data base - remove entry;
+ * update data base - add new entry;
+ * send POSITIVE NAME REGISTRATION RESPONSE;
+ * return;
+ * END
+ * ELSE
+ * BEGIN
+ * (*
+ * * name still being held
+ * * by challenged node
+ * *)
+ *
+ * send NEGATIVE NAME REGISTRATION RESPONSE;
+ * END
+ * END (* local is unique *)
+ * ELSE
+ * BEGIN (* local is group *)
+ * (*
+ * * existing entry is a group name
+ * *)
+ *
+ * update data base - remove entry;
+ * update data base - add new entry;
+ * send POSITIVE NAME REGISTRATION RESPONSE;
+ * return;
+ * END (* local is group *)
+ * END (* names exists *)
+ * ELSE
+ * BEGIN (* does not exist *)
+ *
+ * (* name does not exist in data base *)
+ *
+ * update data base - add new entry;
+ * send POSITIVE NAME REGISTRATION RESPONSE;
+ * return;
+ * END (* does not exist *)
+ *
+ * NAME RELEASE REQUEST:
+ *
+ * (*
+ * * secure server may choose to disallow
+ * * a node from deleting a name
+ * *)
+ *
+ * update data base - remove entry;
+ * send POSITIVE NAME RELEASE RESPONSE;
+ * return;
+ *
+ * NAME UPDATE REQUEST:
+ *
+ * (*
+ * * End-node completed a successful challenge,
+ * * no update database
+ * *)
+ *
+ * IF secure server THEN
+ * send NEGATIVE NAME REGISTRATION RESPONSE;
+ * ELSE
+ * BEGIN (* new entry *)
+ * IF entry already exists THEN
+ * update data base - remove entry;
+ * update data base - add new entry;
+ * send POSITIVE NAME REGISTRATION RESPONSE;
+ * start_timer(TTL);
+ * END
+ *
+ * NAME REFRESH REQUEST:
+ * check for consistency;
+ *
+ * IF node not allowed to have name THEN
+ * BEGIN
+ *
+ * (*
+ * * tell end node that it can't have name
+ * *)
+ * send NEGATIVE NAME REGISTRATION RESPONSE;
+ * END
+ * ELSE
+ * BEGIN
+ *
+ * (*
+ * * send confirmation response to the
+ * * end node.
+ * *)
+ * send POSITIVE NAME REGISTRATION;
+ * start_timer(TTL);
+ * END
+ * return;
+ * END (* case *)
+ * END (* procedure *)
+ */
+static void
+smb_name_process_Pnode_packet(struct name_packet *packet,
+ struct addr_entry *addr)
+{
+ struct name_entry *name;
+ struct name_entry *entry;
+ struct name_question *question;
+ struct resource_record *additional;
+
+ question = packet->question;
+ additional = packet->additional;
+
+ if (packet->info & NAME_NM_FLAGS_B) {
+ /*
+ * always ignore UDP broadcast packets
+ */
+ return;
+ }
+
+ switch (packet->info & NAME_OPCODE_OPCODE_MASK) {
+ case NAME_OPCODE_REFRESH:
+ /* Guard against malformed packets */
+ if ((question == 0) || (additional == 0))
+ break;
+ if (additional->name->addr_list.sin.sin_addr.s_addr == 0)
+ break;
+
+ name = question->name;
+ name->addr_list.ttl = additional->ttl;
+ name->attributes = additional->name->attributes;
+ name->addr_list.sin = additional->name->addr_list.sin;
+ name->addr_list.forw = name->addr_list.back = &name->addr_list;
+
+ if ((entry = smb_netbios_cache_lookup(name)) != 0) {
+ smb_netbios_cache_update_entry(entry, name);
+ smb_netbios_cache_unlock_entry(entry);
+ }
+ else
+ (void) smb_netbios_cache_insert(name);
+
+ (void) smb_send_name_registration_response(addr, packet, 0);
+ break;
+
+ case NAME_OPCODE_QUERY:
+ /*
+ * This opcode covers both NAME_QUERY_REQUEST and
+ * NODE_STATUS_REQUEST. They can be distinguished
+ * based on the type of question entry.
+ */
+
+ /* All query requests have to have question entry */
+ if (question == 0)
+ break;
+
+ if (question->question_type == NAME_QUESTION_TYPE_NB) {
+ name = question->name;
+ if ((entry = smb_netbios_cache_lookup(name)) != 0) {
+ /*
+ * send response to the IP address and port
+ * number from which the request was received.
+ */
+ (void) smb_send_name_query_response(addr,
+ packet, entry, 0);
+ smb_netbios_cache_unlock_entry(entry);
+ } else {
+ /*
+ * send response to the requestor
+ */
+ (void) smb_send_name_query_response(addr,
+ packet, name, RCODE_NAM_ERR);
+ }
+ }
+ else
+ if (question->question_type == NAME_QUESTION_TYPE_NBSTAT) {
+ /*
+ * Name of "*" may be used to force node to
+ * divulge status for administrative purposes
+ */
+ name = question->name;
+ entry = 0;
+ if (NETBIOS_NAME_IS_STAR(name->name) ||
+ ((entry = smb_netbios_cache_lookup(name)) != 0)) {
+ /*
+ * send only those names that are
+ * in the same scope as the scope
+ * field in the request packet
+ */
+ if (entry)
+ smb_netbios_cache_unlock_entry(entry);
+ (void) smb_send_node_status_response(addr,
+ packet);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * 5.1.3.5. M-NODE INCOMING PACKET PROCESSING
+ *
+ * Processing initiated by reception of packets at a M node
+ *
+ * PROCEDURE process_incoming_packet(packet)
+ *
+ * (*
+ * * Processing initiated by incoming packets at a M node
+ * *)
+ *
+ * BEGIN
+ * CASE packet type of
+ *
+ * NAME CONFLICT DEMAND:
+ * IF name exists in local name table THEN
+ * mark name as in conflict;
+ * return;
+ *
+ * NAME QUERY REQUEST:
+ * IF name exists in local name table THEN
+ * BEGIN (* name exists *)
+ *
+ * (*
+ * * build packet
+ * *)
+ * ...
+ *
+ * (*
+ * * send response to the IP address and port
+ * * number from which the request was received.
+ * *)
+ *
+ * send POSITIVE NAME QUERY RESPONSE ;
+ * return;
+ * END (* exists *)
+ * ELSE
+ * BEGIN (* does not exist *)
+ *
+ * (*
+ * * send response to the requestor
+ * *)
+ *
+ * IF request NOT broadcast THEN
+ * (*
+ * * Don't send negative responses to
+ * * queries sent by B nodes
+ * *)
+ * send NEGATIVE NAME QUERY RESPONSE ;
+ * return;
+ * END (* does not exist *)
+ * NODE STATUS REQUEST:
+ * BEGIN
+ * (*
+ * * Name of "*" may be used to force node to
+ * * divulge status for administrative purposes
+ * *)
+ * IF name in local name table OR name = "*" THEN
+ * (*
+ * * Build response packet and
+ * * send to requestor node
+ * * Send only those names that are
+ * * in the same scope as the scope
+ * * in the request packet.
+ * *)
+ *
+ * send NODE STATUS RESPONSE;
+ * END
+ *
+ * NAME RELEASE REQUEST:
+ * (*
+ * * This will be received if the NAME wants to flush the
+ * * name from the local name table, or from the local
+ * * cache.
+ * *)
+ *
+ * IF name exists in the local name table THEN
+ * BEGIN
+ * delete name from local name table;
+ * inform user that name has been deleted;
+ * END
+ * NAME REGISTRATION REQUEST (UNIQUE):
+ * IF name exists in local name table THEN
+ * send NEGATIVE NAME REGISTRATION RESPONSE ;
+ * NAME REGISTRATION REQUEST (GROUP):
+ * IF name exists in local name table THEN
+ * BEGIN
+ * IF local entry is a unique name THEN
+ * send NEGATIVE NAME REGISTRATION RESPONSE ;
+ * END
+ * END (* case *)
+ * END (* procedure *)
+ */
+static void
+smb_name_process_Mnode_packet(struct name_packet *packet,
+ struct addr_entry *addr)
+{
+ if (packet->info & NAME_NM_FLAGS_B)
+ smb_name_process_Bnode_packet(packet, addr);
+ else
+ smb_name_process_Pnode_packet(packet, addr);
+}
+
+static void
+smb_name_process_Hnode_packet(struct name_packet *packet,
+ struct addr_entry *addr)
+{
+ if (packet->info & NAME_NM_FLAGS_B)
+ smb_name_process_Bnode_packet(packet, addr);
+ else
+ smb_name_process_Pnode_packet(packet, addr);
+}
+
+
+/*
+ * smb_netbios_name_tick
+ *
+ * Called once a second to handle name server timeouts.
+ */
+void
+smb_netbios_name_tick(void)
+{
+ struct name_entry *name;
+ struct name_entry *entry;
+
+ (void) mutex_lock(&refresh_queue.mtx);
+ smb_netbios_cache_refresh(&refresh_queue);
+
+ while ((name = refresh_queue.head.forw) != &refresh_queue.head) {
+ QUEUE_CLIP(name);
+ if (IS_LOCAL(name->attributes)) {
+ if (IS_UNIQUE(name->attributes)) {
+ (void) smb_name_Pnode_refresh_name(name);
+ }
+ } else {
+ entry = smb_name_find_name(name);
+ smb_name_unlock_name(entry);
+ }
+ free(name);
+ }
+ (void) mutex_unlock(&refresh_queue.mtx);
+
+ smb_netbios_cache_reset_ttl();
+}
+
+
+/*
+ * smb_name_find_name
+ *
+ * Lookup name cache for the given name.
+ * If it's not in the cache it'll send a
+ * name query request and then lookup the
+ * cache again. Note that if a name is
+ * returned it's locked and called MUST
+ * unlock it by calling smb_name_unlock_name()
+ */
+struct name_entry *
+smb_name_find_name(struct name_entry *name)
+{
+ struct name_entry *result;
+
+ if ((result = smb_netbios_cache_lookup(name)) == 0) {
+ switch (smb_node_type) {
+ case 'B':
+ (void) smb_name_Bnode_find_name(name);
+ break;
+ case 'P':
+ (void) smb_name_Pnode_find_name(name);
+ break;
+ case 'M':
+ (void) smb_name_Mnode_find_name(name);
+ break;
+ case 'H':
+ default:
+ (void) smb_name_Hnode_find_name(name);
+ break;
+ }
+ return (smb_netbios_cache_lookup(name));
+ }
+
+ return (result);
+}
+
+void
+smb_name_unlock_name(struct name_entry *name)
+{
+ smb_netbios_cache_unlock_entry(name);
+}
+
+int
+smb_name_add_name(struct name_entry *name)
+{
+ int rc = 1;
+
+ smb_netbios_name_dump(name);
+
+ switch (smb_node_type) {
+ case 'B':
+ rc = smb_name_Bnode_add_name(name);
+ break;
+ case 'P':
+ rc = smb_name_Pnode_add_name(name);
+ break;
+ case 'M':
+ rc = smb_name_Mnode_add_name(name);
+ break;
+ case 'H':
+ default:
+ rc = smb_name_Hnode_add_name(name);
+ break;
+ }
+
+ if (rc >= 0)
+ (void) smb_netbios_cache_insert(name);
+
+ return (rc);
+}
+
+int
+smb_name_delete_name(struct name_entry *name)
+{
+ int rc;
+ unsigned char type;
+
+ type = name->name[15];
+ if ((type != 0x00) && (type != 0x20)) {
+ syslog(LOG_ERR,
+ "netbios: error trying to delete non-local name");
+ smb_netbios_name_logf(name);
+ name->attributes &= ~NAME_ATTR_LOCAL;
+ return (-1);
+ }
+
+ smb_netbios_cache_delete(name);
+
+ switch (smb_node_type) {
+ case 'B':
+ rc = smb_name_Bnode_delete_name(name);
+ break;
+ case 'P':
+ rc = smb_name_Pnode_delete_name(name);
+ break;
+ case 'M':
+ rc = smb_name_Mnode_delete_name(name);
+ break;
+ case 'H':
+ default:
+ rc = smb_name_Hnode_delete_name(name);
+ break;
+ }
+
+ if (rc > 0)
+ return (0);
+
+ return (-1);
+}
+
+typedef struct {
+ struct addr_entry *addr;
+ char *buf;
+ int length;
+} worker_param_t;
+
+/*
+ * smb_netbios_worker
+ *
+ * Process incoming request/response packets for Netbios
+ * name service (on port 138).
+ */
+void *
+smb_netbios_worker(void *arg)
+{
+ worker_param_t *p = (worker_param_t *)arg;
+ struct addr_entry *addr = p->addr;
+ struct name_packet *packet;
+
+ if ((packet = smb_name_buf_to_packet(p->buf, p->length)) != 0) {
+ if (packet->info & NAME_OPCODE_R) {
+ /* Reply packet */
+ smb_reply_ready(packet, addr);
+ free(p->buf);
+ free(p);
+ return (0);
+ }
+
+ /* Request packet */
+ switch (smb_node_type) {
+ case 'B':
+ smb_name_process_Bnode_packet(packet, addr);
+ break;
+ case 'P':
+ smb_name_process_Pnode_packet(packet, addr);
+ break;
+ case 'M':
+ smb_name_process_Mnode_packet(packet, addr);
+ break;
+ case 'H':
+ default:
+ smb_name_process_Hnode_packet(packet, addr);
+ break;
+ }
+
+ if (packet->answer)
+ smb_netbios_name_freeaddrs(packet->answer->name);
+ free(packet);
+ }
+ else
+ {
+ syslog(LOG_DEBUG, "SmbNBNS: error decoding received packet");
+ }
+
+ free(addr);
+ free(p->buf);
+ free(p);
+ return (0);
+}
+
+static void
+smb_netbios_wins_config(char *ip)
+{
+ uint32_t ipaddr;
+
+ ipaddr = inet_addr(ip);
+ if (ipaddr != INADDR_NONE) {
+ smb_nbns[nbns_num].flags = ADDR_FLAG_VALID;
+ smb_nbns[nbns_num].sinlen = sizeof (struct sockaddr_in);
+ smb_nbns[nbns_num].sin.sin_family = AF_INET;
+ smb_nbns[nbns_num].sin.sin_addr.s_addr = ipaddr;
+ smb_nbns[nbns_num++].sin.sin_port =
+ htons(NAME_SERVICE_UDP_PORT);
+ smb_node_type = 'H';
+ }
+}
+
+void
+smb_netbios_name_config(void)
+{
+ uint32_t ipaddr;
+ struct name_entry name;
+ char myname[MAXHOSTNAMELEN];
+ int i;
+ int smb_nc_cnt;
+ net_cfg_t cfg;
+
+ if (smb_getnetbiosname(myname, MAXHOSTNAMELEN) != 0)
+ return;
+
+ /* Start with no broadcast addresses */
+ bcast_num = 0;
+ bzero(smb_bcast_list, sizeof (addr_entry_t) * SMB_PI_MAX_NETWORKS);
+
+ smb_nc_cnt = smb_nic_get_num();
+ /* Add all of my broadcast addresses */
+ for (i = 0; i < smb_nc_cnt; i++) {
+ if (smb_nic_get_byind(i, &cfg) == NULL) {
+ break;
+ }
+ smb_bcast_list[bcast_num].flags = ADDR_FLAG_VALID;
+ smb_bcast_list[bcast_num].attributes = NAME_ATTR_LOCAL;
+ smb_bcast_list[bcast_num].sinlen = sizeof (struct sockaddr_in);
+ smb_bcast_list[bcast_num].sin.sin_family = AF_INET;
+ smb_bcast_list[bcast_num].sin.sin_port =
+ htons(NAME_SERVICE_UDP_PORT);
+ smb_bcast_list[bcast_num++].sin.sin_addr.s_addr =
+ cfg.broadcast;
+ }
+
+ /* Start with no WINS */
+ smb_node_type = 'B';
+ nbns_num = 0;
+ bzero(smb_nbns, sizeof (addr_entry_t) * SMB_PI_MAX_WINS);
+
+ /* add any configured WINS */
+ smb_config_rdlock();
+ smb_netbios_wins_config(smb_config_getstr(SMB_CI_WINS_SRV1));
+ smb_netbios_wins_config(smb_config_getstr(SMB_CI_WINS_SRV2));
+ smb_config_unlock();
+
+ for (i = 0; i < smb_nc_cnt; i++) {
+ if (smb_nic_get_byind(i, &cfg) == NULL) {
+ break;
+ }
+ if (cfg.exclude)
+ continue;
+
+ ipaddr = cfg.ip;
+ smb_init_name_struct((unsigned char *)myname, 0x00, 0, ipaddr,
+ htons(DGM_SRVC_UDP_PORT), NAME_ATTR_UNIQUE,
+ NAME_ATTR_LOCAL, &name);
+ (void) smb_name_add_name(&name);
+
+ smb_init_name_struct((unsigned char *)myname, 0x20, 0,
+ ipaddr, htons(DGM_SRVC_UDP_PORT),
+ NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name);
+ (void) smb_name_add_name(&name);
+ }
+}
+
+void
+smb_netbios_name_unconfig(void)
+{
+ struct name_entry *name;
+
+ (void) mutex_lock(&delete_queue.mtx);
+ smb_netbios_cache_delete_locals(&delete_queue);
+
+ while ((name = delete_queue.head.forw) != &delete_queue.head) {
+ QUEUE_CLIP(name);
+ (void) smb_name_delete_name(name);
+ free(name);
+ }
+ (void) mutex_unlock(&delete_queue.mtx);
+}
+
+void
+smb_netbios_name_reconfig(void)
+{
+ smb_netbios_name_unconfig();
+ smb_netbios_name_config();
+}
+
+/*
+ * process_incoming Function: void smb_netbios_name_service_daemon(void)
+ *
+ * Description:
+ *
+ * Put test description here.
+ *
+ * Inputs:
+ * Nothing
+ *
+ * Returns:
+ * int -> Description
+ */
+/*ARGSUSED*/
+void *
+smb_netbios_name_service_daemon(void *arg)
+{
+ struct sockaddr_in sin;
+ struct addr_entry *addr;
+ int len;
+ int flag = 1;
+ char *buf;
+ worker_param_t *worker_param;
+ net_cfg_t cfg;
+
+ /*
+ * Initialize reply_queue
+ */
+ bzero(&reply_queue, sizeof (reply_queue));
+ reply_queue.forw = reply_queue.back = &reply_queue;
+
+ if (!smb_netbios_cache_init())
+ return (0);
+
+ bcast_num = 0;
+ bzero(smb_bcast_list, sizeof (addr_entry_t) * SMB_PI_MAX_NETWORKS);
+
+ if ((name_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR,
+ "smbd: Could not create AF_INET, SOCK_DGRAM, socket");
+ smb_netbios_cache_fini();
+ smb_netbios_chg_status(NETBIOS_NAME_SVC_FAILED, 1);
+ return (0);
+ }
+
+ (void) setsockopt(name_sock, SOL_SOCKET, SO_BROADCAST, &flag,
+ sizeof (flag));
+
+ bzero(&sin, sizeof (struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(NAME_SERVICE_UDP_PORT);
+ if (bind(name_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) {
+ syslog(LOG_ERR,
+ "smbd: Bind to name service port %d failed (%d)",
+ NAME_SERVICE_UDP_PORT, errno);
+ smb_netbios_cache_fini();
+ (void) close(name_sock);
+ smb_netbios_chg_status(NETBIOS_NAME_SVC_FAILED, 1);
+ return (0);
+ }
+
+ smb_netbios_chg_status(NETBIOS_NAME_SVC_RUNNING, 1);
+
+ while (((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) ||
+ (nb_status.state & NETBIOS_BROWSER_RUNNING)) {
+ if ((buf = malloc(MAX_DATAGRAM_LENGTH)) == 0) {
+ /* Sleep for 10 sec and try again */
+ (void) sleep(10);
+ continue;
+ }
+ if ((addr = (struct addr_entry *)
+ malloc(sizeof (struct addr_entry))) == 0) {
+ /* Sleep for 10 sec and try again */
+ free(buf);
+ (void) sleep(10);
+ continue;
+ }
+ignore: bzero(addr, sizeof (struct addr_entry));
+ addr->sinlen = sizeof (addr->sin);
+ addr->forw = addr->back = addr;
+
+ if ((len = recvfrom(name_sock, buf, MAX_DATAGRAM_LENGTH,
+ 0, (struct sockaddr *)&addr->sin, &addr->sinlen)) < 0) {
+ if (errno == ENOMEM || errno == ENFILE ||
+ errno == EMFILE) {
+ /* Sleep for 10 sec and try again */
+ free(buf);
+ free(addr);
+ (void) sleep(10);
+ continue;
+ }
+ syslog(LOG_ERR,
+ "smbd: NETBIOS name service - recvfrom failed");
+ free(buf);
+ free(addr);
+ smb_netbios_chg_status(NETBIOS_NAME_SVC_FAILED, 1);
+ goto shutdown;
+ }
+
+ /* Ignore any incoming packets from myself... */
+ if (smb_nic_get_byip(addr->sin.sin_addr.s_addr,
+ &cfg) != NULL) {
+ goto ignore;
+ }
+
+ /*
+ * Launch a netbios worker to process the received packet.
+ */
+ worker_param = (worker_param_t *)
+ malloc(sizeof (worker_param_t));
+ if (worker_param) {
+ pthread_t worker;
+ pthread_attr_t tattr;
+
+ worker_param->addr = addr;
+ worker_param->buf = buf;
+ worker_param->length = len;
+
+ (void) pthread_attr_init(&tattr);
+ (void) pthread_attr_setdetachstate(&tattr,
+ PTHREAD_CREATE_DETACHED);
+ (void) pthread_create(&worker, &tattr,
+ smb_netbios_worker, worker_param);
+ (void) pthread_attr_destroy(&tattr);
+ }
+ }
+
+shutdown:
+ smb_netbios_chg_status(NETBIOS_NAME_SVC_RUNNING, 0);
+
+ (void) mutex_lock(&nb_status.mtx);
+ while (nb_status.state & NETBIOS_BROWSER_RUNNING)
+ (void) cond_wait(&nb_status.cv, &nb_status.mtx);
+ (void) mutex_unlock(&nb_status.mtx);
+
+ if ((nb_status.state & NETBIOS_NAME_SVC_FAILED) == 0) {
+ /* this might delay shutdown, do we want to do this? */
+ /*
+ * it'll send name release requests but nobody's waiting
+ * for response and it'll eventually timeout.
+ */
+ smb_netbios_name_unconfig();
+ }
+ (void) close(name_sock);
+ smb_netbios_cache_fini();
+ syslog(LOG_DEBUG, "smbd: Netbios Name Service is down\n");
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c
new file mode 100644
index 0000000000..d74bcb168d
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c
@@ -0,0 +1,643 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module handles the primary domain controller location protocol.
+ * The document claims to be version 1.15 of the browsing protocol. It also
+ * claims to specify the mailslot protocol.
+ *
+ * The NETLOGON protocol uses \MAILSLOT\NET mailslots. The protocol
+ * specification is incomplete, contains errors and is out-of-date but
+ * it does provide some useful background information. The document
+ * doesn't mention the NETLOGON_SAMLOGON version of the protocol.
+ */
+
+#include <stdlib.h>
+#include <syslog.h>
+#include <alloca.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+
+#include <smbsrv/mailslot.h>
+#include <smbsrv/libsmbns.h>
+#include <smbns_ads.h>
+#include <smbns_browser.h>
+#include <smbns_netbios.h>
+
+static void smb_netlogon_query(struct name_entry *server, char *mailbox,
+ char *domain);
+
+static void smb_netlogon_samlogon(struct name_entry *server, char *mailbox,
+ char *domain);
+
+static void smb_netlogon_send(struct name_entry *name, char *domain,
+ unsigned char *buffer, int count);
+
+static void smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr);
+static int better_dc(uint32_t cur_ip, uint32_t new_ip);
+
+static char resource_domain[SMB_PI_MAX_DOMAIN];
+
+/*
+ * smb_netlogon_request
+ *
+ * This is the entry point locating the resource domain PDC. A netlogon
+ * request is sent using the specified protocol on the specified network.
+ * Note that we need to know the domain SID in order to use the samlogon
+ * format.
+ *
+ * Netlogon responses are received asynchronously and eventually handled
+ * in smb_netlogon_receive.
+ */
+void
+smb_netlogon_request(int net, int protocol, char *domain)
+{
+ struct name_entry *server;
+ nt_domain_t *ntdp;
+
+ server = smb_browser_get_srvname(net);
+ if (server == 0)
+ return;
+
+ (void) strlcpy(resource_domain, domain,
+ sizeof (resource_domain));
+
+ if (strlen(resource_domain) > 0) {
+ ntdp = nt_domain_lookup_name(resource_domain);
+ if (protocol == NETLOGON_PROTO_SAMLOGON && ntdp)
+ smb_netlogon_samlogon(server,
+ MAILSLOT_NETLOGON_SAMLOGON_RDC,
+ resource_domain);
+ else
+ smb_netlogon_query(server,
+ MAILSLOT_NETLOGON_RDC,
+ resource_domain);
+ }
+}
+
+/*
+ * smb_netlogon_receive
+ *
+ * This is where we handle all incoming NetLogon messages. Currently, we
+ * ignore requests from anyone else. We are only interested in responses
+ * to our own requests. The NetLogonResponse provides the name of the PDC.
+ * If we don't already have a controller name, we use the name provided
+ * in the message. Otherwise we use the name already in the environment.
+ */
+void
+smb_netlogon_receive(struct datagram *datagram,
+ char *mailbox,
+ unsigned char *data,
+ int datalen)
+{
+ struct netlogon_opt {
+ char *mailslot;
+ void (*handler)();
+ } netlogon_opt[] = {
+ { MAILSLOT_NETLOGON_RDC, smb_netlogon_rdc_rsp },
+ { MAILSLOT_NETLOGON_SAMLOGON_RDC, smb_netlogon_rdc_rsp },
+ };
+
+ smb_msgbuf_t mb;
+ unsigned short opcode;
+ char src_name[SMB_PI_MAX_HOST];
+ mts_wchar_t unicode_src_name[SMB_PI_MAX_HOST];
+ unsigned int cpid = oem_get_smb_cpid();
+ uint32_t src_ipaddr;
+ char *junk;
+ char *primary;
+ char *domain;
+ int i;
+ char ipstr[16];
+ int rc;
+
+ src_ipaddr = datagram->src.addr_list.sin.sin_addr.s_addr;
+
+ /*
+ * The datagram->src.name is in oem codepage format.
+ * Therefore, we need to convert it to unicode and
+ * store it in multi-bytes format.
+ */
+ (void) oemstounicodes(unicode_src_name, (char *)datagram->src.name,
+ SMB_PI_MAX_HOST, cpid);
+ (void) mts_wcstombs(src_name, unicode_src_name, SMB_PI_MAX_HOST);
+
+ (void) trim_whitespace(src_name);
+
+ (void) inet_ntop(AF_INET, (const void *)(&src_ipaddr), ipstr,
+ sizeof (ipstr));
+ syslog(LOG_DEBUG, "NetLogonReceive: src=%s [%s], mbx=%s",
+ src_name, ipstr, mailbox);
+
+ smb_msgbuf_init(&mb, data, datalen, 0);
+
+ if (smb_msgbuf_decode(&mb, "w", &opcode) < 0) {
+ syslog(LOG_ERR, "NetLogonReceive: decode error");
+ smb_msgbuf_term(&mb);
+ return;
+ }
+
+ switch (opcode) {
+ case LOGON_PRIMARY_RESPONSE:
+ /*
+ * Message contains:
+ * PDC name (MBS), PDC name (Unicode), Domain name (unicode)
+ */
+ rc = smb_msgbuf_decode(&mb, "sUU", &junk, &primary, &domain);
+ if (rc < 0) {
+ syslog(LOG_ERR,
+ "NetLogonResponse: opcode %d decode error",
+ opcode);
+ smb_msgbuf_term(&mb);
+ return;
+ }
+ break;
+
+ case LOGON_SAM_LOGON_RESPONSE:
+ case LOGON_SAM_USER_UNKNOWN:
+ /*
+ * Message contains:
+ * PDC name, User name, Domain name (all unicode)
+ */
+ rc = smb_msgbuf_decode(&mb, "UUU", &primary, &junk, &domain);
+ if (rc < 0) {
+ syslog(LOG_ERR,
+ "NetLogonResponse: opcode %d decode error",
+ opcode);
+ smb_msgbuf_term(&mb);
+ return;
+ }
+
+ /*
+ * skip past the "\\" prefix
+ */
+ primary += strspn(primary, "\\");
+ break;
+
+ default:
+ /*
+ * We don't respond to PDC discovery requests.
+ */
+ syslog(LOG_DEBUG, "NetLogonReceive: opcode 0x%04x", opcode);
+ smb_msgbuf_term(&mb);
+ return;
+ }
+
+ if (domain == 0 || primary == 0) {
+ syslog(LOG_ERR, "NetLogonResponse: malformed packet");
+ smb_msgbuf_term(&mb);
+ return;
+ }
+
+ syslog(LOG_DEBUG, "DC Offer Dom=%s PDC=%s From=%s",
+ domain, primary, src_name);
+
+ if (strcasecmp(domain, resource_domain)) {
+ syslog(LOG_DEBUG, "NetLogonResponse: other domain "
+ "%s, requested %s", domain, resource_domain);
+ smb_msgbuf_term(&mb);
+ return;
+ }
+
+ for (i = 0; i < sizeof (netlogon_opt)/sizeof (netlogon_opt[0]); ++i) {
+ if (strcasecmp(netlogon_opt[i].mailslot, mailbox) == 0) {
+ syslog(LOG_DEBUG, "NetLogonReceive: %s", mailbox);
+ (*netlogon_opt[i].handler)(primary, src_ipaddr);
+ smb_msgbuf_term(&mb);
+ return;
+ }
+ }
+
+ syslog(LOG_DEBUG, "NetLogonReceive[%s]: unknown mailslot", mailbox);
+ smb_msgbuf_term(&mb);
+}
+
+
+
+/*
+ * smb_netlogon_query
+ *
+ * Build and send a LOGON_PRIMARY_QUERY to the MAILSLOT_NETLOGON. At some
+ * point we should receive a LOGON_PRIMARY_RESPONSE in the mailslot we
+ * specify in the request.
+ *
+ * struct NETLOGON_QUERY {
+ * unsigned short Opcode; # LOGON_PRIMARY_QUERY
+ * char ComputerName[]; # ASCII hostname. The response
+ * # is sent to <ComputerName>(00).
+ * char MailslotName[]; # MAILSLOT_NETLOGON
+ * char Pad[]; # Pad to short
+ * wchar_t ComputerName[] # UNICODE hostname
+ * DWORD NT_Version; # 0x00000001
+ * WORD LmNTToken; # 0xffff
+ * WORD Lm20Token; # 0xffff
+ * };
+ */
+static void
+smb_netlogon_query(struct name_entry *server,
+ char *mailbox,
+ char *domain)
+{
+ smb_msgbuf_t mb;
+ int offset, announce_len, data_length, name_lengths;
+ unsigned char buffer[MAX_DATAGRAM_LENGTH];
+ char hostname[MAXHOSTNAMELEN];
+
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0)
+ return;
+
+ name_lengths = strlen(mailbox)+1+strlen(hostname)+1;
+
+ /*
+ * The (name_lengths & 1) part is to word align the name_lengths
+ * before the wc equiv strlen and the "+ 2" is to cover the two
+ * zero bytes that terminate the wchar string.
+ */
+ data_length = sizeof (short) + name_lengths + (name_lengths & 1) +
+ mts_wcequiv_strlen(hostname) + 2 + sizeof (long) + sizeof (short) +
+ sizeof (short);
+
+ offset = smb_browser_load_transact_header(buffer,
+ sizeof (buffer), data_length, ONE_WAY_TRANSACTION,
+ MAILSLOT_NETLOGON);
+
+ if (offset < 0)
+ return;
+
+ smb_msgbuf_init(&mb, buffer + offset, sizeof (buffer) - offset, 0);
+
+ announce_len = smb_msgbuf_encode(&mb, "wssUlww",
+ (short)LOGON_PRIMARY_QUERY,
+ hostname,
+ mailbox,
+ hostname,
+ 0x1,
+ 0xffff,
+ 0xffff);
+
+ if (announce_len <= 0) {
+ smb_msgbuf_term(&mb);
+ syslog(LOG_ERR, "NetLogonQuery: encode error");
+ return;
+ }
+
+ smb_netlogon_send(server, domain, buffer, offset + announce_len);
+ smb_msgbuf_term(&mb);
+}
+
+
+/*
+ * smb_netlogon_samlogon
+ *
+ * The SamLogon version of the NetLogon request uses the workstation trust
+ * account and, I think, may be a prerequisite to the challenge/response
+ * netr authentication. The trust account username is the hostname with a
+ * $ appended. The mailslot for this request is MAILSLOT_NTLOGON. At some
+ * we should receive a LOGON_SAM_LOGON_RESPONSE in the mailslot we
+ * specify in the request.
+ *
+ * struct NETLOGON_SAM_LOGON {
+ * unsigned short Opcode; # LOGON_SAM_LOGON_REQUEST
+ * unsigned short RequestCount; # 0
+ * wchar_t UnicodeComputerName; # hostname
+ * wchar_t UnicodeUserName; # hostname$
+ * char *MailslotName; # response mailslot
+ * DWORD AllowableAccountControlBits; # 0x80 = WorkstationTrustAccount
+ * DWORD DomainSidSize; # domain sid length in bytes
+ * BYTE *DomainSid; # domain sid
+ * uint32_t NT_Version; # 0x00000001
+ * unsigned short LmNTToken; # 0xffff
+ * unsigned short Lm20Token; # 0xffff
+ * };
+ */
+static void
+smb_netlogon_samlogon(struct name_entry *server,
+ char *mailbox,
+ char *domain)
+{
+ smb_msgbuf_t mb;
+ nt_domain_t *ntdp;
+ nt_sid_t *domain_sid;
+ unsigned domain_sid_len;
+ char *username;
+ unsigned char buffer[MAX_DATAGRAM_LENGTH];
+ int offset;
+ int announce_len;
+ int data_length;
+ int name_length;
+ char hostname[MAXHOSTNAMELEN];
+
+ syslog(LOG_DEBUG, "NetLogonSamLogonReq: %s", domain);
+
+ if ((ntdp = nt_domain_lookup_name(domain)) == 0) {
+ syslog(LOG_ERR, "NetLogonSamLogonReq[%s]: no sid", domain);
+ return;
+ }
+
+ domain_sid = ntdp->sid;
+ domain_sid_len = nt_sid_length(domain_sid);
+ nt_sid_logf(domain_sid);
+
+ if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0)
+ return;
+
+ /*
+ * The username will be the trust account name on the PDC.
+ */
+ name_length = strlen(hostname) + 2;
+ username = alloca(name_length);
+ (void) snprintf(username, name_length, "%s$", hostname);
+
+ /*
+ * Add 2 to wide-char equivalent strlen to cover the
+ * two zero bytes that terminate the wchar string.
+ */
+ name_length = strlen(mailbox)+1;
+
+ data_length = sizeof (short)
+ + sizeof (short)
+ + mts_wcequiv_strlen(hostname) + 2
+ + mts_wcequiv_strlen(username) + 2
+ + name_length
+ + sizeof (long)
+ + sizeof (long)
+ + domain_sid_len + 3 /* padding */
+ + sizeof (long)
+ + sizeof (short)
+ + sizeof (short);
+
+ offset = smb_browser_load_transact_header(buffer,
+ sizeof (buffer), data_length, ONE_WAY_TRANSACTION,
+ MAILSLOT_NTLOGON);
+
+ if (offset < 0) {
+ syslog(LOG_ERR, "NetLogonSamLogonReq: header error");
+ return;
+ }
+
+ /*
+ * The domain SID is padded with 3 leading zeros.
+ */
+ smb_msgbuf_init(&mb, buffer + offset, sizeof (buffer) - offset, 0);
+ announce_len = smb_msgbuf_encode(&mb, "wwUUsll3.#clww",
+ (short)LOGON_SAM_LOGON_REQUEST,
+ 0, /* RequestCount */
+ hostname, /* UnicodeComputerName */
+ username, /* UnicodeUserName */
+ mailbox, /* MailslotName */
+ 0x00000080, /* AllowableAccountControlBits */
+ domain_sid_len, /* DomainSidSize */
+ domain_sid_len, domain_sid, /* DomainSid */
+ 0x00000001, /* NT_Version */
+ 0xffff, /* LmNTToken */
+ 0xffff); /* Lm20Token */
+
+ if (announce_len <= 0) {
+ syslog(LOG_ERR, "NetLogonSamLogonReq: encode error");
+ smb_msgbuf_term(&mb);
+ return;
+ }
+
+ smb_netlogon_send(server, domain, buffer, offset + announce_len);
+ smb_msgbuf_term(&mb);
+}
+
+
+/*
+ * Send a query for each version of the protocol.
+ */
+static void
+smb_netlogon_send(struct name_entry *name,
+ char *domain,
+ unsigned char *buffer,
+ int count)
+{
+ static char suffix[] = { 0x1B, 0x1C };
+ struct name_entry dname;
+ struct name_entry *dest;
+ struct name_entry *dest_dup;
+ int i;
+
+ for (i = 0; i < sizeof (suffix)/sizeof (suffix[0]); i++) {
+ smb_init_name_struct((unsigned char *)domain, suffix[i],
+ 0, 0, 0, 0, 0, &dname);
+
+ syslog(LOG_DEBUG, "smb_netlogon_send");
+ smb_netbios_name_dump(&dname);
+ if ((dest = smb_name_find_name(&dname)) != 0) {
+ dest_dup = smb_netbios_name_dup(dest, 1);
+ smb_name_unlock_name(dest);
+ if (dest_dup) {
+ (void) smb_netbios_datagram_send(name, dest_dup,
+ buffer, count);
+ free(dest_dup);
+ }
+ } else {
+ syslog(LOG_DEBUG, "smbd: NBNS couldn't find %s<0x%X>",
+ domain, suffix[i]);
+ }
+ }
+}
+
+/*
+ * smb_netlogon_rdc_rsp
+ *
+ * This is where we process netlogon responses for the resource domain.
+ * The src_name is the real name of the remote machine.
+ */
+static void
+smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr)
+{
+ static int initialized = 0;
+ smb_ntdomain_t *pi;
+ uint32_t ipaddr;
+ uint32_t prefer_ipaddr = 0;
+ char ipstr[16];
+ char srcip[16];
+ char *p;
+ int rc;
+
+ (void) inet_ntop(AF_INET, (const void *)(&src_ipaddr),
+ srcip, sizeof (srcip));
+
+ smb_config_rdlock();
+ if ((p = smb_config_get(SMB_CI_DOMAIN_SRV)) != 0) {
+ rc = inet_pton(AF_INET, p, &prefer_ipaddr);
+ if (rc == 0)
+ prefer_ipaddr = 0;
+
+ if (!initialized) {
+ (void) inet_ntop(AF_INET,
+ (const void *)(&prefer_ipaddr),
+ ipstr, sizeof (ipstr));
+ syslog(LOG_DEBUG, "SMB DC Preference: %s", ipstr);
+ initialized = 1;
+ }
+ }
+ smb_config_unlock();
+
+ syslog(LOG_DEBUG, "DC Offer [%s]: %s [%s]",
+ resource_domain, src_name, srcip);
+
+ if ((pi = smb_getdomaininfo(0)) != 0) {
+ if (prefer_ipaddr != 0 && prefer_ipaddr == pi->ipaddr) {
+ syslog(LOG_DEBUG, "DC for %s: %s [%s]",
+ resource_domain, src_name, srcip);
+ return;
+ }
+
+ ipaddr = pi->ipaddr;
+ } else
+ ipaddr = 0;
+
+ if (better_dc(ipaddr, src_ipaddr) ||
+ (prefer_ipaddr != 0 && prefer_ipaddr == src_ipaddr)) {
+ smb_setdomaininfo(resource_domain, src_name,
+ src_ipaddr);
+ syslog(LOG_DEBUG, "DC discovered for %s: %s [%s]",
+ resource_domain, src_name, srcip);
+ }
+}
+
+static int
+better_dc(uint32_t cur_ip, uint32_t new_ip)
+{
+ net_cfg_t cfg;
+
+ /*
+ * If we don't have any current DC,
+ * then use the new one of course.
+ */
+ if (cur_ip == 0)
+ return (1);
+
+ if (smb_nic_get_bysubnet(cur_ip, &cfg) != NULL)
+ return (0);
+ if (smb_nic_get_bysubnet(new_ip, &cfg) != NULL)
+ return (1);
+ /*
+ * Otherwise, just keep the old one.
+ */
+ return (0);
+}
+
+/*
+ * msdcs_lookup_ads
+ *
+ * Try to find a domain controller in ADS. Actually we want to query DNS
+ * but we need to find out if ADS is enabled and this is probably the
+ * best way. The IP address isn't set up in the ADS_HANDLE so we need to
+ * make the ads_find_host call. This will only succeed if ADS is enabled.
+ *
+ * Returns 1 if a domain controller was found and its name and IP address
+ * have been updated. Otherwise returns 0.
+ */
+int
+msdcs_lookup_ads(void)
+{
+ ADS_HOST_INFO *hinfo = 0;
+ int ads_port = 0;
+ char ads_domain[MAXHOSTNAMELEN];
+ char site_service[MAXHOSTNAMELEN];
+ char service[MAXHOSTNAMELEN];
+ char *site;
+ char *p;
+ char *ip_addr;
+ struct in_addr ns_list[MAXNS];
+ int i, cnt, go_next;
+
+ if (smb_getdomainname(ads_domain, MAXHOSTNAMELEN) != 0)
+ return (0);
+
+ /*
+ * Initialize the NT domain name.
+ */
+ (void) strlcpy(resource_domain, ads_domain, SMB_PI_MAX_DOMAIN);
+ if ((p = strchr(resource_domain, '.')) != 0)
+ *p = '\0';
+
+ smb_config_rdlock();
+ if (smb_config_getyorn(SMB_CI_MSDCS_DISABLE) != 0) {
+ /*
+ * The system administrator doesn't
+ * want to use ADS to find the PDC.
+ */
+ syslog(LOG_DEBUG, "msdcsLookupADS: disabled");
+ smb_config_unlock();
+ return (0);
+ }
+ site = smb_config_getstr(SMB_CI_ADS_SITE);
+ smb_config_unlock();
+
+ syslog(LOG_DEBUG, "msdcsLookupADS %s, MAXHOSTNAMELEN=%d",
+ ads_domain, MAXHOSTNAMELEN);
+ if (site && *site != 0) {
+ (void) snprintf(site_service, MAXHOSTNAMELEN,
+ "_ldap._tcp.%s._sites.dc._msdcs.%s",
+ site, ads_domain);
+ }
+
+ (void) snprintf(service, MAXHOSTNAMELEN,
+ "_ldap._tcp.dc._msdcs.%s", ads_domain);
+
+ cnt = smb_get_nameservers(ns_list, MAXNS);
+
+ go_next = 0;
+ for (i = 0; i < cnt; i++) {
+ ip_addr = inet_ntoa(ns_list[i]);
+
+ hinfo = ads_find_host(ip_addr, ads_domain, &ads_port,
+ site_service, &go_next);
+
+ if (hinfo == NULL) {
+ hinfo = ads_find_host(ip_addr, ads_domain, &ads_port,
+ service, &go_next);
+ }
+
+ if ((hinfo != NULL) || (go_next == 0))
+ break;
+ }
+
+ if (hinfo == NULL) {
+ syslog(LOG_DEBUG, "msdcsLookupADS: unable to find host");
+ return (0);
+ }
+
+ syslog(LOG_DEBUG, "msdcsLookupADS: %s [%I]", hinfo->name,
+ hinfo->ip_addr);
+
+ /*
+ * Remove the domain extension - the
+ * NetBIOS browser can't handle it.
+ */
+ if ((p = strchr(hinfo->name, '.')) != 0)
+ *p = '\0';
+
+ smb_netlogon_rdc_rsp(hinfo->name, hinfo->ip_addr);
+
+ return (1);
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_nicconfig.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_nicconfig.c
new file mode 100644
index 0000000000..0aaf8338b4
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_nicconfig.c
@@ -0,0 +1,1163 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <libintl.h>
+#include <strings.h>
+#include <unistd.h>
+#include <synch.h>
+#include <stropts.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include <inet/ip.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <net/route.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/systeminfo.h>
+
+#include <smbsrv/libsmbns.h>
+
+static int smb_nic_get_list(struct if_list **);
+static void smb_nic_clear_if_list(struct if_list *);
+
+/* This is the list we will monitor */
+static net_cfg_list_t smb_nic_list = { NULL, 0 };
+static pthread_mutex_t smb_nic_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t smb_ns_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Nameserver information */
+static struct __res_state smb_res;
+
+void
+smb_resolver_init(void)
+{
+ int ret;
+ (void) pthread_mutex_lock(&smb_ns_mutex);
+ ret = res_ninit(&smb_res);
+ (void) pthread_mutex_unlock(&smb_ns_mutex);
+ if (ret < 0) {
+ syslog(LOG_ERR, "Failed to initialize resolver lib");
+ }
+}
+
+void
+smb_resolver_close(void)
+{
+ (void) pthread_mutex_lock(&smb_ns_mutex);
+ res_nclose(&smb_res);
+ (void) pthread_mutex_unlock(&smb_ns_mutex);
+}
+
+int
+smb_get_nameservers(struct in_addr *ips, int sz)
+{
+ union res_sockaddr_union set[MAXNS];
+ int i, cnt;
+
+ if (ips == NULL)
+ return (0);
+ (void) pthread_mutex_lock(&smb_ns_mutex);
+ cnt = res_getservers(&smb_res, set, MAXNS);
+ for (i = 0; i < cnt; i++) {
+ if (i >= sz)
+ break;
+ ips[i] = set[i].sin.sin_addr;
+ syslog(LOG_DEBUG, "NS Found %s name server\n",
+ inet_ntoa(ips[i]));
+ }
+ syslog(LOG_DEBUG, "NS Found %d name servers\n", i);
+ (void) pthread_mutex_unlock(&smb_ns_mutex);
+ return (i);
+}
+
+uint16_t
+smb_get_next_resid(void)
+{
+ uint16_t id;
+ (void) pthread_mutex_lock(&smb_ns_mutex);
+ id = ++smb_res.id;
+ (void) pthread_mutex_unlock(&smb_ns_mutex);
+ return (id);
+}
+
+/*
+ * The common NIC library will provide functions to obtain information
+ * on all interfaces. Information will include IP addresses, netmasks
+ * and broadcast address, as well as network statistic details.
+ */
+
+/*
+ * Return IP string address associated with interface argument.
+ * If an error occurs, -1 will be returned.
+ * A return value of 1 indicates an unconfigured IP address
+ */
+static int
+smb_nic_get_ip_addr(char *interface, char *IP, unsigned int IP_length)
+{
+ struct lifreq lifrr;
+ struct sockaddr_in *sa;
+ int sfd;
+
+ sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (sfd < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_IP:socket open failed\n");
+ return (-1);
+ }
+
+ (void) strncpy(lifrr.lifr_name, interface, sizeof (lifrr.lifr_name));
+
+ if (ioctl(sfd, SIOCGLIFADDR, &lifrr) < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_IP: get IP address failed\n");
+ (void) close(sfd);
+ return (-1);
+ }
+ /* Test length of allocated memory to avoid buffer overflow */
+ if (IP_length < SIZE_IP) {
+ syslog(LOG_ERR, "%s", "nic_get_IP: insufficient memory"
+ "allocation\n");
+ (void) close(sfd);
+ return (-1);
+ }
+ sa = (struct sockaddr_in *) &lifrr.lifr_addr;
+ (void) strncpy(IP, inet_ntoa(sa->sin_addr), SIZE_IP);
+ /* Check for unconfigured interface */
+ if (strncmp(IP, "0.0.0.0", sizeof (IP)) == 0) {
+ syslog(LOG_ERR, "%s", "nic_get_IP: unconfigured interface\n");
+ (void) close(sfd);
+ return (1);
+ }
+ (void) close(sfd);
+ return (0);
+}
+
+/*
+ * Return IP address associated with interface argument. If an error occurs,
+ * -1 will be returned. A return value of 1 indicates an unconfigured IP
+ * address
+ */
+int
+smb_nic_get_IP(char *interface, uint32_t *uip)
+{
+ struct lifreq lifrr;
+ struct sockaddr_in *sa;
+ int sfd;
+
+ sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (sfd < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_IP:socket open failed\n");
+ return (-1);
+ }
+
+ (void) strncpy(lifrr.lifr_name, interface, sizeof (lifrr.lifr_name));
+
+ if (ioctl(sfd, SIOCGLIFADDR, &lifrr) < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_IP: get IP address failed\n");
+ (void) close(sfd);
+ return (-1);
+ }
+ sa = (struct sockaddr_in *) &lifrr.lifr_addr;
+ if (uip != NULL)
+ *uip = (uint32_t)sa->sin_addr.s_addr;
+ (void) close(sfd);
+ return (0);
+}
+
+/*
+ * Return broadcast address associated with interface argument.If an error
+ * occurs, -1 will be returned. A return value of 1 indicates an unconfigured
+ * broadcast address
+ */
+int
+smb_nic_get_broadcast(char *interface, uint32_t *uip)
+{
+ struct lifreq lifrr;
+ struct sockaddr_in *sa;
+ int sfd;
+
+ sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (sfd < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_broadcast:"
+ "socket open failed\n");
+ return (-1);
+ }
+
+ (void) strncpy(lifrr.lifr_name, interface, sizeof (lifrr.lifr_name));
+
+ if (ioctl(sfd, SIOCGLIFBRDADDR, &lifrr) < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_broadcast:"
+ "get broadcast address failed\n");
+ (void) close(sfd);
+ return (-1);
+ }
+ sa = (struct sockaddr_in *)&lifrr.lifr_broadaddr;
+ if (uip != NULL)
+ *uip = (uint32_t)sa->sin_addr.s_addr;
+ (void) close(sfd);
+ return (0);
+
+}
+
+/*
+ * Return netmask address associated with interface argument. If error occurs,
+ * -1 will be returned. A return value of 1 indicates an unconfigured netmask
+ * address
+ */
+int
+smb_nic_get_netmask(char *interface, uint32_t *uip)
+{
+ struct lifreq lifrr;
+ struct sockaddr_in *sa;
+ int sfd;
+
+ sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (sfd < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_netmask:"
+ "socket open failed\n");
+ return (-1);
+ }
+
+ (void) strncpy(lifrr.lifr_name, interface, sizeof (lifrr.lifr_name));
+
+ if (ioctl(sfd, SIOCGLIFNETMASK, &lifrr) < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_netmask:"
+ "get netmask address failed\n");
+ (void) close(sfd);
+ return (-1);
+ }
+ sa = (struct sockaddr_in *)&lifrr.lifr_addr;
+ if (uip != NULL)
+ *uip = (uint32_t)sa->sin_addr.s_addr;
+ (void) close(sfd);
+ return (0);
+
+}
+
+/*
+ * Fill ip_alias with IP addresses if any
+ * If it returns 0, there are no associated aliases with the interface.
+ * If it returns -1, there was an error
+ * If it returns 1, there are associated IP aliases with the interface.
+ */
+int
+smb_nic_get_IP_aliases(char *interface, struct ip_alias **list)
+{
+ char ** names = NULL;
+ int result = 0;
+ int numnics, i, ret = 0;
+ char IP[SIZE_IP];
+ struct ip_alias *tmp;
+
+ *list = NULL;
+
+ /* If the interface is a logical interface, return immediately */
+ if (strchr(interface, ':') != NULL) {
+ syslog(LOG_ERR, "%s", "nic_get_IP_aliases:"
+ "invalid physical interface");
+ return (ret);
+ }
+
+ numnics = smb_nic_build_if_name(&names);
+
+ for (i = 0; i < numnics; i++) {
+ /*
+ * Compare passed interface name to all other interface names.
+ * If it matches in the form of :1, it is an associated alias
+ * Example bge1:1's ip address is an ip alias of bge1
+ */
+ if (strncasecmp(interface, names[i], strlen(names[0])) == 0 &&
+ strchr(names[i], ':') != 0) {
+
+ result = smb_nic_get_ip_addr(names[i],
+ IP, sizeof (IP));
+ if (result == -1)
+ return (result);
+
+ tmp = (struct ip_alias *)malloc(
+ sizeof (struct ip_alias));
+ if (tmp == NULL) {
+ syslog(LOG_ERR, "%s", "nic_get"
+ "_IP_aliases: out of memory");
+ (void) smb_nic_clear_name_list(names,
+ numnics);
+ return (-1);
+ }
+
+ (void) strncpy(tmp->name, IP, sizeof (tmp->name));
+ tmp->next = *list;
+ *list = tmp;
+ ret = 1;
+ }
+ }
+ (void) smb_nic_clear_name_list(names, numnics);
+ return (ret);
+}
+
+/*
+ * Return number of plumbed interfaces. Loopback interface is ignored
+ */
+int
+smb_nic_get_number(void)
+{
+ struct lifnum lifn;
+ int numifs = 0, sfd;
+
+ sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (sfd < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_number:"
+ "socket open failed");
+ return (-1);
+ }
+
+ lifn.lifn_family = AF_INET;
+ lifn.lifn_flags = 0;
+
+ if (ioctl(sfd, SIOCGLIFNUM, &lifn) < 0) {
+ syslog(LOG_ERR, "%s", "nic_get_number:"
+ "unable to determine number");
+ (void) close(sfd);
+ return (-1);
+ }
+
+ numifs = lifn.lifn_count - 1; /* loopback */
+ (void) close(sfd);
+ return (numifs);
+}
+
+/*
+ * Given an interface name, return the name of the group it belongs to.
+ */
+int
+smb_nic_get_group(char *lifname, char *grname)
+{
+ struct lifreq lifr;
+ int sfd;
+ int save_errno;
+
+ sfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sfd < 0) {
+ syslog(LOG_ERR, "%s", "nic_set_group:socket open failed");
+ return (-1);
+ }
+ if (strchr(lifname, ':') == NULL) {
+ (void) memset(lifr.lifr_groupname, 0,
+ sizeof (lifr.lifr_groupname));
+ (void) strncpy(lifr.lifr_name, lifname,
+ sizeof (lifr.lifr_name));
+ if (ioctl(sfd, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) {
+ if (strlen(lifr.lifr_groupname) > 0) {
+ (void) strncpy(grname, lifr.lifr_groupname,
+ sizeof (lifr.lifr_groupname));
+ }
+ } else {
+ save_errno = errno;
+ syslog(LOG_ERR, "smb_nic_get_group: ioctl failed");
+ (void) close(sfd);
+ errno = save_errno;
+ return (-1);
+ }
+ }
+ (void) close(sfd);
+ return (0);
+}
+
+/*
+ * Read the /etc/defaultrouter file for the gateway address. If an error occurs,
+ * -1 will be returned.
+ */
+int
+smb_nic_get_default_gateway(char *gw, unsigned int gw_length)
+{
+ FILE *fp;
+
+ fp = fopen(GATEWAY_FILE, "r");
+
+ if (fp == NULL) {
+ (void) fclose(fp);
+ return (-1);
+ } else {
+ /* Test length of allocated memory to avoid buffer overflow */
+ if (gw_length < SIZE_IP) {
+ syslog(LOG_ERR, "%s", "get_default_gateway: "
+ "insufficient memory allocation\n");
+ (void) fclose(fp);
+ return (-1);
+ }
+ (void) fgets(gw, SIZE_IP, fp);
+ (void) fclose(fp);
+ }
+
+ return (0);
+}
+
+/*
+ * Build the list of interface names, both physical and logical.
+ * A pointer to a pointer to a char will be filled with the info
+ */
+int
+smb_nic_build_if_name(char ***if_names)
+{
+ struct if_list *iflist;
+ struct if_list *iflistptr;
+ int num_ifs, i;
+
+ /* Get the interfaces */
+ num_ifs = smb_nic_get_list(&iflist);
+
+ /* Build the list of names */
+ *if_names = (char **)malloc(sizeof (char *) * num_ifs);
+
+ if (if_names == NULL) {
+ syslog(LOG_ERR, "%s", "Unable to build interface names");
+ return (-1);
+ }
+
+ for (i = 0, iflistptr = iflist; i < num_ifs;
+ iflistptr = iflistptr->next, i++) {
+ (*if_names)[i] = (char *)strdup(iflistptr->name);
+ }
+ (void) smb_nic_clear_if_list(iflist);
+ return (num_ifs);
+}
+
+/*
+ * Get number of physical interfaces
+ */
+int
+smb_nic_get_num_physical(void)
+{
+ char **names = NULL;
+ int phys_ifs = 0;
+ int i, result = 0;
+ /* Get list of interface names */
+ result = smb_nic_build_if_name(&names);
+ if (result == -1) {
+ syslog(LOG_ERR, "%s", "Unable to determine num interfaces");
+ return (-1);
+ }
+ for (i = 0; i < result; i++) {
+ if (strchr(names[i], ':') == NULL) {
+ /* It's a physical interface */
+ phys_ifs++;
+ }
+ }
+ (void) smb_nic_clear_name_list(names, result);
+ return (phys_ifs);
+}
+
+/*
+ * Get number of logical interfaces
+ */
+int
+smb_nic_get_num_logical(void)
+{
+ char **names = NULL;
+ int log_ifs = 0;
+ int i, result = 0;
+ /* Get list of interface names */
+ result = smb_nic_build_if_name(&names);
+ if (result == -1) {
+ syslog(LOG_ERR, "%s", "Unable to determine num interfaces");
+ return (-1);
+ }
+ for (i = 0; i < result; i++) {
+ if (strchr(names[i], ':') != NULL) {
+ /* It's a logical interface */
+ log_ifs++;
+ }
+ }
+ (void) smb_nic_clear_name_list(names, result);
+ return (log_ifs);
+}
+
+/*
+ * Get number of aliases associated with an interface
+ */
+int
+smb_nic_get_num_aliases(char *interface)
+{
+ char **names = NULL;
+ int aliases = 0;
+ int i, result = 0;
+
+ if (interface == NULL) {
+ syslog(LOG_ERR, "%s", "Interface name not supplied");
+ return (-1);
+ }
+ /* Get list of interface names */
+ result = smb_nic_build_if_name(&names);
+ if (result == -1) {
+ syslog(LOG_ERR, "%s", "Unable to determine num interfaces");
+ return (-1);
+ }
+ for (i = 0; i < result; i++) {
+ if (strncasecmp(interface, names[i], strlen(names[0])) == 0 &&
+ strchr(names[i], ':') != 0) {
+ /* It's an alias */
+ aliases++;
+ }
+ }
+ (void) smb_nic_clear_name_list(names, result);
+ if (aliases == 0)
+ return (1); /* Minimum of 1 for NULL assignment */
+ else
+ return (aliases);
+}
+
+/*
+ * Get the list of currently plumbed interface names. The loopback(lo0)
+ * port is ignored
+ */
+static int
+smb_nic_get_list(struct if_list **list)
+{
+ int cnt = 0;
+ struct if_list *tmp, *p;
+ int n, s;
+ char *buf;
+ struct ifconf ifc;
+ register struct ifreq *ifrp = NULL;
+ struct ifreq ifr;
+ int numifs = 0;
+ unsigned int bufsize = 0;
+
+ *list = NULL;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ syslog(LOG_ERR, "%s", "get_net_list: socket");
+ return (-1);
+ }
+
+ if (ioctl(s, SIOCGIFNUM, (char *)&numifs) < 0) {
+ syslog(LOG_ERR, "%s", "get number of interfaces");
+ return (-1);
+ }
+
+ bufsize = numifs * sizeof (struct ifreq);
+ buf = (char *)malloc(bufsize);
+ if (buf == NULL) {
+ syslog(LOG_ERR, "%s", "out of memory\n");
+ (void) close(s);
+ return (-1);
+ }
+ ifc.ifc_len = bufsize;
+ ifc.ifc_buf = buf;
+
+ if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+ syslog(LOG_ERR, "%s", "Unable to get interface list\n");
+ (void) close(s);
+ (void) free(buf);
+ return (-1);
+ }
+
+ ifrp = ifc.ifc_req;
+ for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifrp++) {
+ /* Get the flags so that we can skip the loopback interface */
+ (void) memset((char *)&ifr, '\0', sizeof (ifr));
+ (void) strncpy(ifr.ifr_name, ifrp->ifr_name,
+ sizeof (ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ syslog(LOG_ERR, "%s", "unable to determine flags");
+ (void) close(s);
+ (void) free(buf);
+ return (-1);
+ }
+
+ if (ifr.ifr_flags & IFF_LOOPBACK)
+ continue;
+ if ((ifr.ifr_flags & IFF_UP) == 0)
+ continue;
+ tmp = (struct if_list *)malloc(sizeof (struct if_list));
+ if (tmp == NULL) {
+ syslog(LOG_ERR, "%s", "out of memory\n");
+ (void) close(s);
+ (void) free(buf);
+ return (-1);
+ }
+
+ tmp->next = NULL;
+ (void) strncpy(tmp->name, ifrp->ifr_name, sizeof (tmp->name));
+ if (*list == NULL) {
+ *list = tmp;
+ } else {
+ for (p = *list; p->next; p = p->next)
+ ;
+ p->next = tmp;
+ }
+ cnt++;
+ }
+ (void) close(s);
+ (void) free(buf);
+ return (cnt);
+}
+
+/*
+ * This will mimick the workings of ifconfig -a command. A net_cfg
+ * pointer will be passed, and all information will be assigned
+ * within this function. Memory will be assigned in this function
+ * also so the user doesn't have to worry about it. Freeing memory
+ * will be handled in a different function - smb_nic_clear_memory
+ */
+int
+smb_nic_build_network_structures(net_cfg_t **nc, int *number)
+{
+ char ** names = NULL;
+ int res, numnics = 0;
+ int num_aliases = 0;
+ uint32_t uip;
+ uint64_t flags;
+ int i = 0;
+ int j = 1;
+ int k = 0;
+ struct ip_alias *list = NULL;
+ net_cfg_t *nc_array;
+ char excludestr[MAX_EXCLUDE_LIST_LEN];
+ ipaddr_t exclude[SMB_PI_MAX_NETWORKS];
+ int nexclude;
+ char *winsexclude;
+
+ *number = 0;
+ numnics = smb_nic_build_if_name(&names);
+ nc_array = *nc = malloc(sizeof (net_cfg_t) * numnics);
+ if (nc_array == NULL) {
+ (void) smb_nic_clear_name_list(names, numnics);
+ return (-1);
+ }
+ bzero(nc_array, sizeof (net_cfg_t) * numnics);
+
+ smb_config_rdlock();
+ excludestr[0] = '\0';
+ winsexclude = smb_config_getstr(SMB_CI_WINS_EXCL);
+ if (winsexclude != NULL)
+ (void) strlcpy(excludestr, winsexclude, sizeof (excludestr));
+ smb_config_unlock();
+ nexclude = smb_wins_iplist(excludestr, exclude, SMB_PI_MAX_NETWORKS);
+
+ for (i = 0; i < numnics; i++) {
+
+ if (strchr(names[i], ':') == NULL) {
+ /* Will not provide info on logical interfaces */
+
+ (void) memset ((*nc), 0, sizeof (net_cfg_t));
+ num_aliases = smb_nic_get_num_aliases(names[i]);
+ if (num_aliases == -1) {
+ (void) smb_nic_clear_name_list(names, numnics);
+ free (*nc);
+ return (-1);
+ }
+
+ (*nc)->aliases = (char **)malloc(
+ (sizeof (char) * IP_ABITS) * num_aliases);
+ if ((*nc)->aliases == NULL) {
+ (void) smb_nic_clear_name_list(names, numnics);
+ free (*nc);
+ return (-1);
+ }
+ (void) strncpy((*nc)->ifname, names[i],
+ sizeof ((*nc)->ifname));
+ (*nc)->naliases = num_aliases;
+
+ res = smb_nic_get_IP((*nc)->ifname, &uip);
+ if (res == -1) { /* error retrieving IP address */
+ (void) smb_nic_clear_name_list(names, numnics);
+ free ((*nc)->aliases);
+ free (*nc);
+ return (-1);
+ }
+ (*nc)->ip = uip;
+ if (smb_wins_is_excluded(uip, (ulong_t *)exclude,
+ nexclude))
+ (*nc)->exclude = B_TRUE;
+ res = smb_nic_get_netmask((*nc)->ifname, &uip);
+ if (res == -1) { /* error retrieving netmask address */
+ (void) smb_nic_clear_name_list(names, numnics);
+ free ((*nc)->aliases);
+ free (*nc);
+ return (-1);
+ }
+ (*nc)->mask = uip;
+ res = smb_nic_get_broadcast((*nc)->ifname, &uip);
+ if (res == -1) { /* error retrieving broadcast add */
+ (void) smb_nic_clear_name_list(names, numnics);
+ free ((*nc)->aliases);
+ free (*nc);
+ return (-1);
+ }
+ (*nc)->broadcast = uip;
+ res = smb_nic_get_group((*nc)->ifname,
+ (*nc)->groupname);
+ if (res == -1) { /* error retrieving group name */
+ (void) smb_nic_clear_name_list(names, numnics);
+ free ((*nc)->aliases);
+ free (*nc);
+ return (-1);
+ }
+ res = smb_nic_flags((*nc)->ifname, &flags);
+ if (res == -1) { /* error retrieving flags */
+ (void) smb_nic_clear_name_list(names, numnics);
+ free ((*nc)->aliases);
+ free (*nc);
+ return (-1);
+ }
+ (*nc)->flags = flags;
+ /*
+ * If an interface has no associated alias, the alias
+ * field will be set to NULL
+ */
+ res = smb_nic_get_IP_aliases((*nc)->ifname, &list);
+ if (res == -1) {
+ (*nc)->aliases[k] = NULL;
+ (void) smb_nic_clear_name_list(names, numnics);
+ free ((*nc)->aliases);
+ free (*nc);
+ return (-1);
+ }
+
+ if (res == 0) {
+ (*nc)->aliases[k] = NULL;
+
+ } else { /* There will be aliases */
+
+ (*nc)->aliases[0] = (char *)list->name;
+ while (list->next != NULL) {
+ (*nc)->aliases[j] =
+ (char *)(list->next);
+ j++;
+ list = list->next;
+ }
+ }
+ k++;
+ j = 1;
+ (*nc)++; /* increment pointer */
+ }
+ } /* end for */
+
+ *nc = nc_array;
+ *number = k;
+ (void) smb_nic_clear_name_list(names, numnics);
+ return (0);
+}
+
+/*
+ * Return a space separated list of interface names depending on specified
+ * flags. Either flags argument can be set to 0 if the caller chooses.
+ * Returns NULL if no interfaces match the passed flags
+ * flags_on: flags which must be on in each interface returned
+ * flags_off : flags which must be off in each interface returned
+ */
+char *
+smb_nic_get_ifnames(int flags_on, int flags_off)
+{
+ struct ifconf ifc;
+ int numifs, i, sfd;
+ char *ifnames;
+
+
+ sfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sfd == -1)
+ return (NULL);
+
+ if ((ioctl(sfd, SIOCGIFNUM, &numifs) == -1) || (numifs <= 0)) {
+ (void) close(sfd);
+ return (NULL);
+ }
+
+ ifnames = malloc(numifs * (LIFNAMSIZ + 1));
+ if (ifnames == NULL) {
+ return (NULL);
+ }
+ ifc.ifc_len = (numifs * sizeof (struct ifreq));
+ ifc.ifc_req = malloc(numifs * sizeof (struct ifreq));
+ if (ifc.ifc_req == NULL) {
+ free(ifnames);
+ return (NULL);
+ }
+
+ if (ioctl(sfd, SIOCGIFCONF, &ifc) == -1) {
+ (void) close(sfd);
+ free(ifnames);
+ free(ifc.ifc_req);
+ return (NULL);
+ }
+
+ for (i = 0; i < numifs; i++) {
+ if (ioctl(sfd, SIOCGIFFLAGS, &ifc.ifc_req[i]) == 0) {
+ if ((ifc.ifc_req[i].ifr_flags &
+ (flags_on | flags_off)) != flags_on) {
+ continue;
+ }
+ }
+
+ (void) strcat(ifnames, ifc.ifc_req[i].ifr_name);
+ (void) strcat(ifnames, " ");
+ }
+
+ if (strlen(ifnames) > 1)
+ ifnames[strlen(ifnames) - 1] = '\0';
+
+ (void) close(sfd);
+ free(ifc.ifc_req);
+
+ return (ifnames);
+}
+
+/*
+ * Function to determine if passed address is of form a.b.c.d.
+ */
+int
+smb_nic_validate_ip_address(char *IP)
+{
+ in_addr_t addr;
+ if ((int)(addr = inet_addr(IP)) == -1) {
+ syslog(LOG_ERR, "%s", "IP-address must be"
+ " of the form a.b.c.d");
+ return (addr);
+ }
+ else
+ return (0);
+
+}
+
+/*
+ * Get flags associated with if
+ * -1 means there was an error retrieving the data
+ * 0 success
+ */
+int
+smb_nic_flags(char *interface, uint64_t *flag)
+{
+ struct lifreq lifrr;
+ int sfd;
+
+ sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (sfd < 0) {
+ syslog(LOG_ERR, "%s", "smb_get_nic_flags: socket open failed");
+ return (-1);
+ }
+
+ (void) strncpy(lifrr.lifr_name, interface, sizeof (lifrr.lifr_name));
+
+ if (ioctl(sfd, SIOCGLIFFLAGS, &lifrr) < 0) {
+ syslog(LOG_ERR, "%s", "smb_get_nic_flags: get flags failed");
+ (void) close(sfd);
+ return (-1);
+ }
+
+ (void) close(sfd);
+ if (flag != NULL)
+ *flag = lifrr.lifr_flags;
+ return (0);
+}
+
+/*
+ * The following list is taken from if.h. The function takes the
+ * given interface name, and the passed flag(s), and returns true if
+ * the flag is associated with the interface, and false if not.
+ *
+ * IFF_UP interface is up
+ * IFF_BROADCAST broadcast address valid
+ * IFF_LOOPBACK is a loopback net
+ * IFF_POINTOPOINT interface is point-to-point link
+ * IFF_RUNNING resources allocated
+ * IFF_MULTICAST supports multicast
+ * IFF_MULTI_BCAST multicast using broadcast address
+ * IFF_UNNUMBERED non-unique address
+ * IFF_DHCPRUNNING DHCP controls this interface
+ * IFF_PRIVATE do not advertise
+ * IFF_DEPRECATED interface address deprecated
+ * IFF_ANYCAST Anycast address
+ * IFF_IPV4 IPv4 interface
+ * IFF_IPV6 IPv6 interface
+ * IFF_NOFAILOVER Don't failover on NIC failure
+ * IFF_FAILED NIC has failed
+ * IFF_STANDBY Standby NIC to be used on failures
+ * IFF_OFFLINE NIC has been offlined
+ * -1 means there was an error retrieving the data
+ * 0 indicates false - the flag isn't associated
+ * 1 indicates true - the flag is associated
+ */
+int
+smb_nic_status(char *interface, uint64_t flag)
+{
+ struct lifreq lifrr;
+ int sfd;
+
+ sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (sfd < 0) {
+ syslog(LOG_ERR, "%s", "nic_status: socket open failed");
+ return (-1);
+ }
+
+ (void) strncpy(lifrr.lifr_name, interface, sizeof (lifrr.lifr_name));
+
+ if (ioctl(sfd, SIOCGLIFFLAGS, &lifrr) < 0) {
+ syslog(LOG_ERR, "%s", "nic_status: get flags failed");
+ (void) close(sfd);
+ return (-1);
+ }
+
+ if (lifrr.lifr_flags & flag) {
+ (void) close(sfd);
+ return (1); /* associated */
+ } else {
+ (void) close(sfd);
+ return (0); /* not associated */
+ }
+}
+
+/*
+ * Free allocated memory for net_cfg structures. Takes number of allocated
+ * structures as argument also
+ */
+int
+smb_nic_clear_niclist(net_cfg_t *niclist, int amount)
+{
+ int i, j = 0;
+
+ if (niclist == NULL)
+ return (-1);
+ for (i = 0; i < amount; i++) {
+ while (niclist[i].aliases[j] != NULL) {
+ free(niclist[i].aliases[j]);
+ j++;
+ }
+ free(niclist[i].aliases);
+ j = 0;
+ }
+ free(niclist);
+
+ return (0);
+}
+
+int
+smb_nic_free_niclist(net_cfg_list_t *niclist)
+{
+ return (smb_nic_clear_niclist(niclist->net_cfg_list,
+ niclist->net_cfg_cnt));
+}
+
+/*
+ * Free allocated memory for names lists. Takes number of allocated
+ * pointers as argument also
+ */
+int
+smb_nic_clear_name_list(char **names, int amount)
+{
+ int i;
+
+ for (i = 0; i < amount; i++) {
+ free(names[i]);
+ }
+
+ free(names);
+ return (0);
+}
+
+/* Free allocated memory for names lists. */
+
+static void
+smb_nic_clear_if_list(struct if_list *iflist)
+{
+ struct if_list *tmp;
+
+ if (iflist == NULL)
+ return;
+ for (; iflist != NULL; iflist = tmp) {
+ tmp = iflist->next;
+ free(iflist);
+ }
+}
+
+/* Free allocated memory for alias lists. */
+int
+smb_nic_clear_ip_alias(struct ip_alias *iplist)
+{
+ struct ip_alias *tmp;
+
+ for (; iplist != NULL; iplist = tmp) {
+ tmp = iplist->next;
+ free(iplist);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_nic_lock
+ *
+ * Lock the nic table
+ */
+void
+smb_nic_lock(void)
+{
+ (void) pthread_mutex_lock(&smb_nic_mutex);
+}
+
+/*
+ * smb_nic_unlock
+ *
+ * Unlock the nic table.
+ *
+ * This function MUST be called after lock
+ */
+void
+smb_nic_unlock(void)
+{
+ (void) pthread_mutex_unlock(&smb_nic_mutex);
+}
+
+int
+smb_nic_init()
+{
+ smb_nic_lock();
+ smb_nic_list.net_cfg_cnt = 0;
+ (void) smb_nic_build_network_structures(&smb_nic_list.net_cfg_list,
+ &smb_nic_list.net_cfg_cnt);
+ smb_nic_unlock();
+ return (0);
+}
+
+/*
+ * Initialize interface list.
+ */
+void
+smb_nic_build_info(void)
+{
+ smb_nic_lock();
+ if (smb_nic_list.net_cfg_list) {
+ (void) smb_nic_free_niclist(&smb_nic_list);
+ smb_nic_list.net_cfg_list = NULL;
+ }
+ smb_nic_list.net_cfg_cnt = 0;
+ (void) smb_nic_build_network_structures(&smb_nic_list.net_cfg_list,
+ &smb_nic_list.net_cfg_cnt);
+ if (smb_nic_list.net_cfg_cnt == 0) {
+ syslog(LOG_ERR, "smb: No network interfaces are configured "
+ "smb server may not function properly");
+ }
+ smb_nic_unlock();
+}
+
+/*
+ * Get number of interfaces.
+ */
+int
+smb_nic_get_num(void)
+{
+ int sz;
+ smb_nic_lock();
+ sz = smb_nic_list.net_cfg_cnt;
+ smb_nic_unlock();
+ return (sz);
+}
+
+/*
+ * Get if by index
+ * Returns: NULL if not found.
+ */
+net_cfg_t *
+smb_nic_get_byind(int ind, net_cfg_t *cfg)
+{
+ if (cfg == NULL)
+ return (cfg);
+ smb_nic_lock();
+ if (ind > smb_nic_list.net_cfg_cnt) {
+ smb_nic_unlock();
+ return (NULL);
+ }
+ bcopy(&smb_nic_list.net_cfg_list[ind], cfg, sizeof (net_cfg_t));
+ smb_nic_unlock();
+ return (cfg);
+}
+
+/*
+ * Get if by subnet
+ * Returns: NULL if not found.
+ */
+net_cfg_t *
+smb_nic_get_bysubnet(uint32_t ipaddr, net_cfg_t *cfg)
+{
+ int i;
+ net_cfg_t *tcfg;
+
+ if (cfg == NULL)
+ return (cfg);
+ smb_nic_lock();
+ bzero(cfg, sizeof (net_cfg_t));
+ for (i = 0; i < smb_nic_list.net_cfg_cnt; i++) {
+ tcfg = &smb_nic_list.net_cfg_list[i];
+ if ((ipaddr & tcfg->mask) ==
+ (tcfg->ip & tcfg->mask)) {
+ bcopy(tcfg, cfg, sizeof (net_cfg_t));
+ smb_nic_unlock();
+ return (cfg);
+ }
+ }
+ smb_nic_unlock();
+ return (NULL);
+}
+
+/*
+ * Get if by ip.
+ * Returns: NULL if not found.
+ */
+net_cfg_t *
+smb_nic_get_byip(uint32_t ipaddr, net_cfg_t *cfg)
+{
+ int i;
+ net_cfg_t *tcfg;
+
+ if (cfg == NULL)
+ return (cfg);
+ smb_nic_lock();
+ bzero(cfg, sizeof (net_cfg_t));
+ for (i = 0; i < smb_nic_list.net_cfg_cnt; i++) {
+ tcfg = &smb_nic_list.net_cfg_list[i];
+ if (ipaddr == tcfg->ip) {
+ bcopy(tcfg, cfg, sizeof (net_cfg_t));
+ smb_nic_unlock();
+ return (cfg);
+ }
+ }
+ smb_nic_unlock();
+ return (NULL);
+}
diff --git a/usr/src/lib/smbsrv/libsmbns/i386/Makefile b/usr/src/lib/smbsrv/libsmbns/i386/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libsmbns/sparc/Makefile b/usr/src/lib/smbsrv/libsmbns/sparc/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libsmbns/sparcv9/Makefile b/usr/src/lib/smbsrv/libsmbns/sparcv9/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbns/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libsmbrdr/Makefile b/usr/src/lib/smbsrv/libsmbrdr/Makefile
new file mode 100644
index 0000000000..6b376227e4
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+HDRS= libsmbrdr.h
+
+include ../Makefile.smbsrv
diff --git a/usr/src/lib/smbsrv/libsmbrdr/Makefile.com b/usr/src/lib/smbsrv/libsmbrdr/Makefile.com
new file mode 100644
index 0000000000..822331f26b
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/Makefile.com
@@ -0,0 +1,53 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libsmbrdr.a
+VERS = .1
+
+OBJS_COMMON = \
+ smbrdr_ipc_util.o \
+ smbrdr_lib.o \
+ smbrdr_logon.o \
+ smbrdr_netbios.o \
+ smbrdr_netuse.o \
+ smbrdr_read_andx.o \
+ smbrdr_rpcpipe.o \
+ smbrdr_session.o \
+ smbrdr_transact.o
+
+OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+LDLIBS += -lsmb -lnsl -lsocket -lc
+
+SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_SHARED:%.o=$(SRC)/common/smbsrv/%.c)
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbsrv/libsmbrdr/amd64/Makefile b/usr/src/lib/smbsrv/libsmbrdr/amd64/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h b/usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h
new file mode 100644
index 0000000000..846ac9d306
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBSMBRDR_H
+#define _LIBSMBRDR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/libsmb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Redirector IPC functions
+ *
+ * The following functions are required by the mlsvc_validate_user to
+ * apply new authentication information for the authenticated IPC, rollback
+ * or commit the changes to the original authentication information.
+ */
+extern void smbrdr_ipc_set(char *, unsigned char *);
+extern void smbrdr_ipc_commit(void);
+extern void smbrdr_ipc_rollback(void);
+extern int smbrdr_ipc_skip_lsa_query(void);
+extern int smbrdr_ipc_get_mode(void);
+extern void smbrdr_ipc_save_mode(char *val);
+extern unsigned smbrdr_ipc_get_flags(void);
+extern void smbrdr_ipc_set_fallback(void);
+extern void smbrdr_ipc_unset_fallback(void);
+extern int smbrdr_ipc_is_fallback(void);
+
+/*
+ * Functions for obtaining the resource domain administrator credentials.
+ */
+extern char *smbrdr_ipc_get_user(void);
+extern char *smbrdr_ipc_get_passwd(void);
+extern int smbrdr_ipc_is_valid(void);
+
+
+/* Redirector LOGON functions */
+extern int mlsvc_anonymous_logon(char *, char *, char **);
+extern int mlsvc_user_logon(char *, char *, char *, char *);
+extern int mlsvc_admin_logon(char *, char *);
+
+extern int smbrdr_rpc_readx(int, char *, int);
+
+
+/* Redirector rpcpipe functions */
+extern int mlsvc_open_pipe(char *, char *, char *, char *);
+extern int mlsvc_close_pipe(int);
+
+
+/* Redirector session functions */
+extern void smbrdr_init(void);
+extern int mlsvc_locate_domain_controller(char *);
+extern int mlsvc_session_native_values(int, int *, int *, int *);
+extern void mlsvc_check_sessions(void);
+extern int mlsvc_echo(char *);
+extern void mlsvc_disconnect(char *);
+
+
+extern int smbrdr_rpc_transact(int, char *, int, char *, int);
+
+
+/* DEBUG functions */
+extern void smbrdr_dump_ofiles(void);
+extern void smbrdr_dump_sessions(void);
+extern void smbrdr_dump_netuse();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSMBRDR_H */
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/llib-lsmbrdr b/usr/src/lib/smbsrv/libsmbrdr/common/llib-lsmbrdr
new file mode 100644
index 0000000000..d238202484
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/llib-lsmbrdr
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <smbsrv/libsmbrdr.h>
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers b/usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers
new file mode 100644
index 0000000000..0ea435ee55
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate {
+ global:
+ mlsvc_admin_logon;
+ mlsvc_anonymous_logon;
+ mlsvc_check_sessions;
+ mlsvc_close_pipe;
+ mlsvc_disconnect;
+ mlsvc_echo;
+ mlsvc_install_pdc_cb;
+ mlsvc_locate_domain_controller;
+ mlsvc_open_pipe;
+ mlsvc_session_native_values;
+ mlsvc_user_getauth;
+ mlsvc_user_logon;
+ smbrdr_dump_netuse;
+ smbrdr_dump_ofiles;
+ smbrdr_dump_sessions;
+ smbrdr_init;
+ smbrdr_ipc_get_mode;
+ smbrdr_ipc_commit;
+ smbrdr_ipc_get_flags;
+ smbrdr_ipc_get_user;
+ smbrdr_ipc_rollback;
+ smbrdr_ipc_set;
+ smbrdr_ipc_skip_lsa_query;
+ smbrdr_ipc_is_fallback;
+ smbrdr_ipc_is_valid;
+ smbrdr_ipc_get_passwd;
+ smbrdr_ipc_save_mode;
+ smbrdr_ipc_set_fallback;
+ smbrdr_ipc_unset_fallback;
+ smbrdr_rpc_readx;
+ smbrdr_rpc_transact;
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h
new file mode 100644
index 0000000000..35db51adc6
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBRDR_H_
+#define _SMBRDR_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <synch.h>
+#include <sys/types.h>
+
+#include <smbsrv/libsmbrdr.h>
+
+#include <smbsrv/cifs.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb.h>
+#include <smbsrv/wintypes.h>
+
+#define SMBRDR_REQ_BUFSZ 4096
+
+#define MAX_ACCOUNT_NAME 32
+#define MAX_SHARE_NAME 32
+#define MAX_SCOPE_NAME 64
+#define MAX_FILE_PATH 128
+
+/*
+ * The number of shares and pipes is limited to 48 based on the note
+ * below. This really shouldn't cause a problem because we always
+ * our shares and named pipes are always opened and closed round every
+ * RPC transaction. This also tends to limit the number of active
+ * logons because we (currently) need two named pipes per logon.
+ *
+ * Q141709 Limit of 49 named pipe connections from a single workstation.
+ * If a named pipe server creates more than 49 distincly named pipes, a
+ * single client cannot connect more than 49 pipes on the named pipe
+ * server. Chapter 4, p113. Network Programming for Microsoft Windows
+ * Anthony Jones and Jim Ohlund, Microsoft Press, ISBN: 0-7356-0560-2
+ */
+#define N_NETUSE_TABLE 48
+#define N_OFILE_TABLE 48
+
+/*
+ * Logon's states
+ */
+#define SDB_LSTATE_START 0
+#define SDB_LSTATE_INIT 1
+#define SDB_LSTATE_LOGGING_OFF 2
+#define SDB_LSTATE_SETUP 3
+
+#define SDB_LOGON_NONE 0
+#define SDB_LOGON_GUEST 1
+#define SDB_LOGON_ANONYMOUS 2
+#define SDB_LOGON_USER 3
+
+typedef struct sdb_logon {
+ struct sdb_session *session;
+ char username[MAX_ACCOUNT_NAME];
+ unsigned short uid;
+ unsigned int type;
+ unsigned short state;
+ smb_auth_info_t auth;
+} sdb_logon_t;
+
+/*
+ * Session's states
+ *
+ * SDB_SSTATE_START ready to be used
+ * SDB_SSTATE_INIT initialized
+ * SDB_SSTATE_STALE lost transport connection
+ * SDB_SSTATE_DISCONNECTING disconnecting: logoff the user
+ * disconnect trees, close files
+ * SDB_SSTATE_CLEANING was in STALE state now just
+ * cleaning up
+ * SDB_SSTATE_CONNECTED got transport connection
+ * SDB_SSTATE_NEGOTIATED did SMB negotiate
+ */
+#define SDB_SSTATE_START 0
+#define SDB_SSTATE_INIT 1
+#define SDB_SSTATE_STALE 2
+#define SDB_SSTATE_DISCONNECTING 3
+#define SDB_SSTATE_CLEANING 4
+#define SDB_SSTATE_CONNECTED 5
+#define SDB_SSTATE_NEGOTIATED 6
+
+#define SDB_SLCK_READ 1
+#define SDB_SLCK_WRITE 2
+
+struct sdb_session {
+ smb_ntdomain_t di;
+ char scope[SMB_PI_MAX_SCOPE];
+ char native_os[SMB_PI_MAX_NATIVE_OS];
+ char native_lanman[SMB_PI_MAX_LANMAN];
+ int sock;
+ short port;
+ unsigned short secmode;
+ uint32_t sesskey;
+ uint32_t challenge_len;
+ unsigned char challenge_key[32];
+ unsigned char smb_flags;
+ unsigned short smb_flags2;
+ unsigned short vc;
+ uint32_t remote_caps;
+ unsigned short state;
+ unsigned int sid; /* session id */
+ int remote_os;
+ int remote_lm;
+ int pdc_type;
+ smb_sign_ctx_t sign_ctx;
+ sdb_logon_t logon;
+ rwlock_t rwl;
+};
+
+/*
+ * Netuse's states
+ */
+#define SDB_NSTATE_START 0
+#define SDB_NSTATE_INIT 1
+#define SDB_NSTATE_DISCONNECTING 2
+#define SDB_NSTATE_CONNECTED 3
+
+struct sdb_netuse {
+ struct sdb_session *session;
+ unsigned short state;
+ int letter; /* local identity */
+ unsigned int sid;
+ unsigned short uid;
+ unsigned short tid; /* remote identity */
+ char share[MAX_SHARE_NAME];
+ mutex_t mtx;
+};
+
+/*
+ * Ofile's states
+ */
+#define SDB_FSTATE_START 0
+#define SDB_FSTATE_INIT 1
+#define SDB_FSTATE_CLOSING 2
+#define SDB_FSTATE_OPEN 3
+
+struct sdb_ofile {
+ struct sdb_session *session;
+ struct sdb_netuse *netuse;
+ unsigned short state;
+ unsigned int sid;
+ unsigned short uid;
+ unsigned short tid;
+ unsigned short fid; /* remote identity */
+ char path[MAX_FILE_PATH];
+ mutex_t mtx;
+};
+
+typedef struct smbrdr_handle {
+ unsigned char *srh_buf;
+ smb_msgbuf_t srh_mbuf;
+ unsigned int srh_mbflags;
+ unsigned char srh_cmd;
+ struct sdb_session *srh_session;
+ struct sdb_logon *srh_user;
+ struct sdb_netuse *srh_tree;
+} smbrdr_handle_t;
+
+/*
+ * smbrdr_netbios.c
+ */
+void nb_lock(void);
+void nb_unlock(void);
+void nb_close(int);
+int nb_keep_alive(int);
+
+int nb_send(int, unsigned char *, unsigned);
+int nb_rcv(int, unsigned char *, unsigned, long);
+int nb_exchange(int, unsigned char *, unsigned,
+ unsigned char *, unsigned, long);
+int nb_session_request(int, char *, char *, char *, char *);
+
+/*
+ * smbrdr_session.c
+ */
+int smbrdr_negotiate(char *);
+struct sdb_session *smbrdr_session_lock(char *, char *, int);
+void smbrdr_session_unlock(struct sdb_session *);
+
+/*
+ * smbrdr_logon.c
+ */
+int smbrdr_smb_logoff(struct sdb_logon *);
+
+/* smbrdr_netuse.c */
+void smbrdr_netuse_logoff(unsigned short);
+struct sdb_netuse *smbrdr_netuse_get(int);
+unsigned short mlsvc_tree_connect(char *, char *, char *);
+int smbrdr_tree_disconnect(unsigned short);
+void smbrdr_netuse_put(struct sdb_netuse *);
+
+/*
+ * smbrdr_rpcpipe.c
+ */
+void smbrdr_ofile_end_of_share(unsigned short);
+struct sdb_ofile *smbrdr_ofile_get(int);
+void smbrdr_ofile_put(struct sdb_ofile *);
+
+/* smbrdr_lib.c */
+DWORD smbrdr_request_init(smbrdr_handle_t *, unsigned char,
+ struct sdb_session *, struct sdb_logon *, struct sdb_netuse *);
+DWORD smbrdr_send(smbrdr_handle_t *);
+DWORD smbrdr_rcv(smbrdr_handle_t *, int);
+DWORD smbrdr_exchange(smbrdr_handle_t *, smb_hdr_t *, long);
+void smbrdr_handle_free(smbrdr_handle_t *);
+int smbrdr_sign_init(struct sdb_session *, struct sdb_logon *);
+int smbrdr_sign_fini(struct sdb_session *);
+int smbrdr_sign_unset_key(struct sdb_session *);
+
+void smbrdr_lock_transport(void);
+void smbrdr_unlock_transport(void);
+
+#endif /* _SMBRDR_H_ */
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.c
new file mode 100644
index 0000000000..908a439864
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.c
@@ -0,0 +1,382 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The IPC connection information is encapsulated within SMB Redirector.
+ * Utility functions are defined here to allow other modules to get and
+ * set the ipc configuration, as well as, to rollback or commit the
+ * changes to the original authentication information.
+ */
+
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <synch.h>
+
+#include <smbsrv/libsmbrdr.h>
+
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smbinfo.h>
+#include <smbrdr.h>
+#include <smbrdr_ipc_util.h>
+
+/*
+ * The binary NTLM hash is 16 bytes. When it is converted to hexidecimal,
+ * it will be at most twice as long.
+ */
+#define SMBRDR_IPC_HEX_PASSWD_MAXLEN (SMBAUTH_HASH_SZ * 2) + 1
+#define SMBRDR_IPC_GETDOMAIN_TIMEOUT 10000
+
+static rwlock_t smbrdr_ipc_lock;
+static smbrdr_ipc_t ipc_info;
+static smbrdr_ipc_t orig_ipc_info;
+
+/*
+ * smbrdr_ipc_init
+ *
+ * Get system configuration regarding IPC connection
+ * credentials and initialize related variables.
+ * This function will normally be called at startup
+ * (i.e. at the time smbrdr gets loaded).
+ */
+void
+smbrdr_ipc_init(void)
+{
+ char *p;
+
+ bzero(&ipc_info, sizeof (smbrdr_ipc_t));
+ bzero(&orig_ipc_info, sizeof (smbrdr_ipc_t));
+
+ smb_config_rdlock();
+ p = smb_config_getstr(SMB_CI_RDR_IPCMODE);
+
+ if (!strncasecmp(p, IPC_MODE_AUTH, IPC_MODE_STRLEN)) {
+ ipc_info.mode = MLSVC_IPC_ADMIN;
+
+ p = smb_config_getstr(SMB_CI_RDR_IPCUSER);
+ if (p)
+ (void) strlcpy(ipc_info.user, p,
+ MLSVC_ACCOUNT_NAME_MAX);
+ else
+ syslog(LOG_WARNING, "smbrdr: (ipc) no admin user name");
+
+ p = smb_config_get(SMB_CI_RDR_IPCPWD);
+ if (p) {
+ if (strlen(p) != SMBRDR_IPC_HEX_PASSWD_MAXLEN - 1) {
+ *ipc_info.passwd = 0;
+ syslog(LOG_WARNING,
+ "smbrdr: (ipc) invalid admin password");
+ } else {
+ (void) hextobin(p,
+ SMBRDR_IPC_HEX_PASSWD_MAXLEN - 1,
+ ipc_info.passwd, SMBAUTH_HASH_SZ);
+ }
+ } else {
+ *ipc_info.passwd = 0;
+ syslog(LOG_WARNING, "smbrdr: (ipc) no admin password");
+ }
+
+ } else {
+ if (!strcasecmp(p, IPC_MODE_FALLBACK_ANON))
+ ipc_info.flags |= IPC_FLG_FALLBACK_ANON;
+
+ ipc_info.mode = MLSVC_IPC_ANON;
+ (void) strlcpy(ipc_info.user, MLSVC_ANON_USER,
+ MLSVC_ACCOUNT_NAME_MAX);
+ *ipc_info.passwd = 0;
+ }
+ smb_config_unlock();
+}
+
+/*
+ * smbrdr_ipc_set
+ *
+ * The given username and password hash will be applied to the
+ * ipc_info which will be used by mlsvc_validate_user().
+ *
+ * If mlsvc_validate_user() succeeds, the calling function is responsible
+ * for invoking smbrdr_ipc_commit() for updating the environment
+ * variables. Otherwise, it should invoke smbrdr_ipc_rollback() to restore
+ * the previous credentials.
+ */
+void
+smbrdr_ipc_set(char *plain_user, unsigned char *passwd_hash)
+{
+ (void) rw_wrlock(&smbrdr_ipc_lock);
+ if (ipc_info.flags & IPC_FLG_FALLBACK_ANON)
+ ipc_info.mode = MLSVC_IPC_ADMIN;
+
+ (void) strlcpy(ipc_info.user, plain_user, sizeof (ipc_info.user));
+ (void) memcpy(ipc_info.passwd, passwd_hash, SMBAUTH_HASH_SZ);
+ ipc_info.flags |= IPC_FLG_NEED_VERIFY;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+
+}
+
+/*
+ * smbrdr_ipc_commit
+ *
+ * Save the new admin credentials as environment variables.
+ * The binary NTLM password hash is first converted to a
+ * hex string before storing in the environment variable.
+ *
+ * The credentials also saved to the original IPC info as
+ * rollback data in case the join domain process
+ * fails in the future.
+ */
+void
+smbrdr_ipc_commit()
+{
+ unsigned char hexpass[SMBRDR_IPC_HEX_PASSWD_MAXLEN];
+
+ (void) rw_wrlock(&smbrdr_ipc_lock);
+ smb_config_wrlock();
+ (void) smb_config_set(SMB_CI_RDR_IPCUSER, ipc_info.user);
+ (void) bintohex(ipc_info.passwd, sizeof (ipc_info.passwd),
+ (char *)hexpass, sizeof (hexpass));
+ hexpass[SMBRDR_IPC_HEX_PASSWD_MAXLEN - 1] = 0;
+ (void) smb_config_set(SMB_CI_RDR_IPCPWD, (char *)hexpass);
+
+ ipc_info.flags &= ~IPC_FLG_NEED_VERIFY;
+
+ if (ipc_info.flags & IPC_FLG_FALLBACK_ANON) {
+ ipc_info.flags &= ~IPC_FLG_FALLBACK_ANON;
+ ipc_info.mode = MLSVC_IPC_ADMIN;
+ (void) smb_config_set(SMB_CI_RDR_IPCMODE, IPC_MODE_AUTH);
+ syslog(LOG_DEBUG, "smbrdr: (ipc) Authenticated IPC "
+ "connection has been restored");
+ }
+
+ (void) memcpy(&orig_ipc_info, &ipc_info, sizeof (smbrdr_ipc_t));
+ smb_config_unlock();
+ (void) rw_unlock(&smbrdr_ipc_lock);
+}
+
+/*
+ * smbrdr_ipc_rollback
+ *
+ * Restore the original credentials
+ */
+void
+smbrdr_ipc_rollback()
+{
+ (void) rw_wrlock(&smbrdr_ipc_lock);
+ (void) strlcpy(ipc_info.user, orig_ipc_info.user,
+ sizeof (ipc_info.user));
+ (void) memcpy(ipc_info.passwd, orig_ipc_info.passwd,
+ sizeof (ipc_info.passwd));
+
+ ipc_info.flags &= ~IPC_FLG_NEED_VERIFY;
+
+ if (ipc_info.flags & IPC_FLG_FALLBACK_ANON)
+ ipc_info.mode = MLSVC_IPC_ANON;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+}
+
+/*
+ * Get & Set functions
+ */
+int
+smbrdr_ipc_get_mode()
+{
+ int mode;
+
+ (void) rw_rdlock(&smbrdr_ipc_lock);
+ mode = ipc_info.mode;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+
+ return (mode);
+}
+
+char *
+smbrdr_ipc_get_user()
+{
+ char *user;
+
+ (void) rw_rdlock(&smbrdr_ipc_lock);
+ user = ipc_info.user;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+ return (user);
+}
+
+char *
+smbrdr_ipc_get_passwd()
+{
+ char *passwd;
+
+ (void) rw_rdlock(&smbrdr_ipc_lock);
+ passwd = ipc_info.passwd;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+ return (passwd);
+}
+
+unsigned
+smbrdr_ipc_get_flags()
+{
+ unsigned flags;
+
+ (void) rw_rdlock(&smbrdr_ipc_lock);
+ flags = ipc_info.flags;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+ return (flags);
+}
+
+void
+smbrdr_ipc_set_fallback()
+{
+ (void) rw_wrlock(&smbrdr_ipc_lock);
+ ipc_info.flags |= IPC_FLG_FALLBACK_ANON;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+}
+
+void
+smbrdr_ipc_unset_fallback()
+{
+ (void) rw_wrlock(&smbrdr_ipc_lock);
+ ipc_info.flags &= ~IPC_FLG_FALLBACK_ANON;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+}
+
+/*
+ * Whether the smbrdr.ipc.mode is set to fallback,anon or not
+ */
+int
+smbrdr_ipc_is_fallback()
+{
+ int is_fallback;
+
+ smb_config_rdlock();
+ is_fallback = (!strcasecmp(smb_config_getstr(SMB_CI_RDR_IPCMODE),
+ IPC_MODE_FALLBACK_ANON) ? 1 : 0);
+ smb_config_unlock();
+
+ return (is_fallback);
+}
+
+/*
+ * smbrdr_ipc_save_mode
+ *
+ * Set the SMBRDR_IPC_MODE_ENV variable and update the
+ * IPC mode of the cache.
+ */
+void
+smbrdr_ipc_save_mode(char *val)
+{
+ (void) rw_wrlock(&smbrdr_ipc_lock);
+ smb_config_wrlock();
+ (void) smb_config_set(SMB_CI_RDR_IPCMODE, val);
+ ipc_info.mode = !strncasecmp(val, IPC_MODE_AUTH, IPC_MODE_STRLEN)
+ ? MLSVC_IPC_ADMIN : MLSVC_IPC_ANON;
+ smb_config_unlock();
+ (void) rw_unlock(&smbrdr_ipc_lock);
+}
+
+/*
+ * smbrdr_ipc_skip_lsa_query
+ *
+ * Determine whether LSA monitor should skip the LSA query due to the
+ * incomplete authentication information if IPC is configured to be
+ * authenticated.
+ */
+int
+smbrdr_ipc_skip_lsa_query()
+{
+ char *user, *pwd;
+
+ if (ipc_info.mode != MLSVC_IPC_ADMIN)
+ return (0);
+
+ smb_config_rdlock();
+ user = smb_config_get(SMB_CI_RDR_IPCUSER);
+ pwd = smb_config_get(SMB_CI_RDR_IPCPWD);
+ smb_config_unlock();
+ if ((user == NULL) && pwd)
+ return (1);
+
+ (void) rw_rdlock(&smbrdr_ipc_lock);
+ user = ipc_info.user;
+ pwd = ipc_info.passwd;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+
+ return (!(*user && *pwd));
+}
+
+static char *
+smbrdr_ipc_modestr(int mode)
+{
+ switch (mode) {
+ case MLSVC_IPC_ANON:
+ return ("Anonymous");
+
+ case MLSVC_IPC_ADMIN:
+ return ("Authenticated");
+
+ default:
+ return ("Unknown");
+ }
+}
+
+/*
+ * For debugging purposes only.
+ */
+void
+smbrdr_ipc_loginfo()
+{
+ smbrdr_ipc_t tmp;
+ smbrdr_ipc_t tmporg;
+
+ (void) rw_rdlock(&smbrdr_ipc_lock);
+ (void) memcpy(&tmp, &ipc_info, sizeof (smbrdr_ipc_t));
+ (void) memcpy(&tmporg, &orig_ipc_info, sizeof (smbrdr_ipc_t));
+ (void) rw_unlock(&smbrdr_ipc_lock);
+
+ syslog(LOG_DEBUG, "smbrdr: current IPC info:");
+ syslog(LOG_DEBUG, "\t%s (user=%s, flags:0x%X)",
+ smbrdr_ipc_modestr(tmp.mode), tmp.user, tmp.flags);
+
+ syslog(LOG_DEBUG, "smbrdr: original IPC info:");
+ syslog(LOG_DEBUG, "\t%s (user=%s, flags:0x%X)",
+ smbrdr_ipc_modestr(tmporg.mode), tmporg.user, tmporg.flags);
+}
+
+/*
+ * smbrdr_ipc_is_valid
+ *
+ * Determine whether the ipc_info has been validated or not.
+ *
+ */
+int
+smbrdr_ipc_is_valid()
+{
+ int isvalid;
+
+ (void) rw_rdlock(&smbrdr_ipc_lock);
+ isvalid = (ipc_info.flags & IPC_FLG_NEED_VERIFY) ? 0 : 1;
+ (void) rw_unlock(&smbrdr_ipc_lock);
+
+ return (isvalid);
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.h b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.h
new file mode 100644
index 0000000000..a967e91b86
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_IPC_UTIL_H
+#define _SMBSRV_IPC_UTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the data structure for the IPC connection and utility
+ * function prototypes.
+ */
+
+#include <smbsrv/mlsvc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMBRDR_IPC_MODE_ENV "smbrdr.ipc.mode"
+#define SMBRDR_IPC_USER_ENV "smbrdr.ipc.user"
+#define SMBRDR_IPC_PASSWD_ENV "smbrdr.ipc.passwd"
+
+#define IPC_MODE_STRLEN 4
+#define IPC_MODE_ANON "anon"
+#define IPC_MODE_AUTH "auth"
+#define IPC_MODE_FALLBACK_ANON "fallback,anon"
+
+#define IPC_FLG_FALLBACK_ANON 0x00000001
+#define IPC_FLG_NEED_VERIFY 0x00000002
+
+/*
+ * smbrdr_ipc_t
+ *
+ * This structure contains information regarding the IPC configuration,
+ * as well as, the authentication info needed for connecting to the
+ * IPC$ share if the IPC connection is configured to be authenticated.
+ *
+ * IPC connection to the Primary Domain Controller [PDC] can be
+ * configured to be either anonymous or authenticated. Therefore,
+ * the IPC mode will be set to either one of the following values:
+ * MLSVC_IPC_ANON
+ * MLSVC_IPC_ADMIN
+ *
+ * The IPC_FLG_FALLBACK_ANON can be set in flags field to indicate whether
+ * a fallback from authenticated IPC to anonymous IPC has occurred. This
+ * flag will be unset once the join domain operation succeeds.
+ */
+typedef struct {
+ int mode;
+ char user[MLSVC_ACCOUNT_NAME_MAX];
+ char passwd[SMBAUTH_HASH_SZ];
+ unsigned flags;
+} smbrdr_ipc_t;
+
+
+void smbrdr_ipc_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_IPC_UTIL_H */
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_lib.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_lib.c
new file mode 100644
index 0000000000..ac4743548c
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_lib.c
@@ -0,0 +1,592 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides some common functionality for SMB Redirector
+ * module.
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <smbsrv/ntstatus.h>
+#include <smbrdr.h>
+
+static DWORD smbrdr_handle_setup(smbrdr_handle_t *srh, unsigned char cmd,
+ struct sdb_session *session, struct sdb_logon *logon,
+ struct sdb_netuse *netuse);
+
+static int smbrdr_hdr_setup(smbrdr_handle_t *srh);
+
+static DWORD smbrdr_hdr_process(smbrdr_handle_t *srh, smb_hdr_t *smb_hdr);
+
+static int smbrdr_sign(smb_sign_ctx_t *sign_ctx, smb_msgbuf_t *mb);
+static int smbrdr_sign_chk(smb_sign_ctx_t *sign_ctx, smb_msgbuf_t *mb,
+ unsigned char *signature);
+
+void smbrdr_lock_transport() { nb_lock(); }
+void smbrdr_unlock_transport() { nb_unlock(); }
+
+/*
+ * smbrdr_request_init
+ *
+ * Setup a handle with given information and then
+ * setup a SMB header structure.
+ *
+ * Returns:
+ *
+ * NT_STATUS_NO_MEMORY no memory for creating request
+ * NT_STATUS_INTERNAL_ERROR header encode failed or crypto failed
+ * NT_STATUS_SUCCESS successful
+ */
+DWORD
+smbrdr_request_init(smbrdr_handle_t *srh,
+ unsigned char cmd,
+ struct sdb_session *session,
+ struct sdb_logon *logon,
+ struct sdb_netuse *netuse)
+{
+ DWORD status;
+
+ status = smbrdr_handle_setup(srh, cmd, session, logon, netuse);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG, "Smbrdr[%d]: initialization failed", cmd);
+ return (status);
+ }
+
+ if (smbrdr_hdr_setup(srh) < SMB_HEADER_LEN) {
+ syslog(LOG_DEBUG, "Smbrdr[%d]: cannot setup header", cmd);
+ smbrdr_handle_free(srh);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smbrdr_send
+ *
+ * Send the SMB packet pointed by the given handle over
+ * network.
+ *
+ * Returns:
+ *
+ * NT_STATUS_INTERNAL_ERROR crypto framework failure
+ * NT_STATUS_UNEXPECTED_NETWORK_ERROR send failed
+ * NT_STATUS_SUCCESS successful
+ */
+DWORD
+smbrdr_send(smbrdr_handle_t *srh)
+{
+ int rc;
+
+ if (smbrdr_sign(&srh->srh_session->sign_ctx, &srh->srh_mbuf) !=
+ SMBAUTH_SUCCESS)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ rc = nb_send(srh->srh_session->sock, srh->srh_buf,
+ smb_msgbuf_used(&srh->srh_mbuf));
+
+ if (rc < 0) {
+ /*
+ * Make the sequence number of the next SMB request even
+ * to avoid DC from failing the next SMB request with
+ * ACCESS_DENIED.
+ */
+ smb_mac_dec_seqnum(&srh->srh_session->sign_ctx);
+ return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smbrdr_rcv
+ *
+ * Receive a SMB response and decode the packet header.
+ *
+ * "Implementing CIFS" book, SMB requests always have an even sequence
+ * number and replies always have an odd.
+ *
+ * With the original code, if the SMB Redirector skip the counter increment
+ * in the event of any failure during SmbSessionSetupAndX, it causes the
+ * domain controller to fail the next SMB request(odd sequence number)
+ * with ACCESS_DENIED.
+ *
+ * Smbrdr module should use the same sequence number (i.e. ssc_seqnum of the
+ * SMB Sign context) for generating the MAC signature for all incoming
+ * responses per SmbTransact request. Otherwise, the validation will fail.
+ * It is now fixed by decrementing the sequence number prior to validating
+ * the subsequent responses for a single request.
+ *
+ * Returns:
+ *
+ * status code returned by smbrdr_hdr_process()
+ * NT_STATUS_UNEXPECTED_NETWORK_ERROR receive failed
+ * NT_STATUS_SUCCESS successful
+ */
+DWORD
+smbrdr_rcv(smbrdr_handle_t *srh, int is_first_rsp)
+{
+ smb_hdr_t smb_hdr;
+ DWORD status;
+ int rc;
+ smb_sign_ctx_t *sign_ctx = &srh->srh_session->sign_ctx;
+
+ rc = nb_rcv(srh->srh_session->sock, srh->srh_buf, SMBRDR_REQ_BUFSZ, 0);
+ if (rc < 0) {
+ smb_mac_inc_seqnum(sign_ctx);
+ return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
+ }
+
+ /* initialize for processing response */
+ smb_msgbuf_init(&srh->srh_mbuf, srh->srh_buf, rc, srh->srh_mbflags);
+
+ status = smbrdr_hdr_process(srh, &smb_hdr);
+ if (status != NT_STATUS_SUCCESS) {
+ smb_mac_inc_seqnum(sign_ctx);
+ return (status);
+ }
+
+ if (!is_first_rsp)
+ smb_mac_dec_seqnum(sign_ctx);
+
+ if (!smbrdr_sign_chk(sign_ctx,
+ &srh->srh_mbuf, smb_hdr.extra.extra.security_sig)) {
+ syslog(LOG_ERR, "SmbrdrExchange[%d]: bad signature",
+ srh->srh_cmd);
+ return (NT_STATUS_INVALID_NETWORK_RESPONSE);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smbrdr_exchange
+ *
+ * Send the SMB packet pointed by the given handle over
+ * network. Receive the response and decode the packet header.
+ *
+ * From "Implementing CIFS" book, SMB requests always have an even sequence
+ * number and replies always have an odd.
+ *
+ * With the original code, if the SMB Redirector skips the counter increment
+ * in the event of any failure during SmbSessionSetupAndX, it causes the
+ * domain controller to fail the next SMB request(odd sequence number)
+ * with ACCESS_DENIED.
+ *
+ * Returns:
+ *
+ * status code returned by smbrdr_hdr_process()
+ * NT_STATUS_INTERNAL_ERROR crypto framework failure
+ * NT_STATUS_UNEXPECTED_NETWORK_ERROR send/receive failed
+ * NT_STATUS_SUCCESS successful
+ */
+DWORD
+smbrdr_exchange(smbrdr_handle_t *srh, smb_hdr_t *smb_hdr, long timeout)
+{
+ smb_sign_ctx_t *sign_ctx;
+ smb_msgbuf_t *mb;
+ DWORD status;
+ int rc;
+
+ mb = &srh->srh_mbuf;
+ sign_ctx = &srh->srh_session->sign_ctx;
+
+ if (smbrdr_sign(sign_ctx, mb) != SMBAUTH_SUCCESS)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ rc = nb_exchange(srh->srh_session->sock,
+ srh->srh_buf, smb_msgbuf_used(mb),
+ srh->srh_buf, SMBRDR_REQ_BUFSZ, timeout);
+
+ if (rc < 0) {
+ syslog(LOG_ERR, "SmbrdrExchange[%d]: failed (%d)",
+ srh->srh_cmd, rc);
+
+ if (srh->srh_cmd != SMB_COM_ECHO) {
+ /*
+ * Since SMB echo is used to check the session
+ * status then don't destroy the session if it's
+ * SMB echo.
+ */
+ srh->srh_session->state = SDB_SSTATE_STALE;
+ }
+ smb_mac_inc_seqnum(sign_ctx);
+ return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
+ }
+
+ /* initialize for processing response */
+ smb_msgbuf_init(mb, srh->srh_buf, rc, srh->srh_mbflags);
+
+ status = smbrdr_hdr_process(srh, smb_hdr);
+ if (status != NT_STATUS_SUCCESS) {
+ smb_mac_inc_seqnum(sign_ctx);
+ return (status);
+ }
+
+ /* Signature validation */
+ if (!smbrdr_sign_chk(sign_ctx, mb, smb_hdr->extra.extra.security_sig)) {
+ syslog(LOG_ERR, "SmbrdrExchange[%d]: bad signature",
+ srh->srh_cmd);
+ return (NT_STATUS_INVALID_NETWORK_RESPONSE);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smbrdr_handle_free
+ *
+ * Frees the memories allocated for the given handle.
+ */
+void
+smbrdr_handle_free(smbrdr_handle_t *srh)
+{
+ if (srh) {
+ smb_msgbuf_term(&srh->srh_mbuf);
+ free(srh->srh_buf);
+ }
+}
+
+
+/*
+ * smbrdr_sign_init
+ *
+ * This function is called from SessionSetup and initialize the
+ * signing context for the session if the connected user isn't
+ * anonymous. This has to call before smbrdr_request_init()
+ * because it modifies smb_flags2.
+ *
+ * The following description is taken out from the "Implementing CIFS"
+ * book(pg. 304):
+ *
+ * "Once the MAC signing has been initialized within a session, all
+ * messages are numbered using the same counters and signed using
+ * the same Session Key. This is true even if additional SESSION
+ * SETUP ANDX exchanges occur."
+ *
+ * The original SMB packet signing implementation calculates a MAC
+ * key each time the SMB Redirector sends the SmbSessionSetupAndx
+ * request for any non-anonymous/non-guest user which is not desired
+ * whenever there is a change in the user session key.
+ *
+ * If NTLMv2 authentication is used, the MAC key generated for each
+ * SessionSetup is unique. Since the domain controller expects the
+ * signature of all incoming requests are signed by the same MAC key
+ * (i.e. the one that generated for the first non-anonymous SessionSetup),
+ * access denied is returned for any subsequent SmbSessionSetupAndX
+ * request.
+ */
+int
+smbrdr_sign_init(struct sdb_session *session, struct sdb_logon *logon)
+{
+ smb_sign_ctx_t *sign_ctx;
+ int rc = 0;
+
+ sign_ctx = &session->sign_ctx;
+
+ if ((sign_ctx->ssc_flags & SMB_SCF_REQUIRED) &&
+ !(sign_ctx->ssc_flags & SMB_SCF_STARTED) &&
+ (logon->type != SDB_LOGON_ANONYMOUS)) {
+ if (smb_mac_init(sign_ctx, &logon->auth) != SMBAUTH_SUCCESS) {
+ syslog(LOG_DEBUG, "SmbrdrSignInit: mac_init failed");
+ return (-1);
+ }
+ sign_ctx->ssc_flags |=
+ (SMB_SCF_STARTED | SMB_SCF_KEY_ISSET_THIS_LOGON);
+ session->smb_flags2 |= SMB_FLAGS2_SMB_SECURITY_SIGNATURE;
+ syslog(LOG_DEBUG, "SmbrdrSignInit: mac key is set");
+ rc = 1;
+ }
+
+ return (rc);
+}
+
+/*
+ * smbrdr_sign_fini
+ *
+ * Invalidate the MAC key if the first non-anonymous/non-guest user logon
+ * fail.
+ */
+int
+smbrdr_sign_fini(struct sdb_session *session)
+{
+ smb_sign_ctx_t *sign_ctx;
+ int rc = 0;
+
+ sign_ctx = &session->sign_ctx;
+
+ if (sign_ctx->ssc_flags & SMB_SCF_KEY_ISSET_THIS_LOGON) {
+ sign_ctx->ssc_flags &= ~SMB_SCF_STARTED;
+ sign_ctx->ssc_flags &= ~SMB_SCF_KEY_ISSET_THIS_LOGON;
+ sign_ctx->ssc_seqnum = 0;
+ syslog(LOG_DEBUG, "SmbrdrSignFini: packet signing stopped");
+ rc = 1;
+ }
+
+ return (rc);
+}
+
+/*
+ * smbrdr_sign_unset_key
+ *
+ * The SMB_SCF_KEY_ISSET_THIS_LOGON should be unset upon the successful
+ * SmbSessionSetupAndX request for the first non-anonymous/non-guest
+ * logon.
+ */
+int
+smbrdr_sign_unset_key(struct sdb_session *session)
+{
+ smb_sign_ctx_t *sign_ctx;
+ int rc = 0;
+
+ sign_ctx = &session->sign_ctx;
+
+ if (sign_ctx->ssc_flags & SMB_SCF_KEY_ISSET_THIS_LOGON) {
+ sign_ctx->ssc_flags &= ~SMB_SCF_KEY_ISSET_THIS_LOGON;
+ syslog(LOG_DEBUG, "SmbrdrSignUnsetKey: unset KEY_ISSET flag");
+ rc = 1;
+ }
+
+ return (rc);
+}
+
+/*
+ * smbrdr_handle_setup
+ *
+ * Allocates a buffer for sending/receiving a SMB request.
+ * Initialize a smb_msgbuf structure with the allocated buffer.
+ * Setup given handle (srh) with the specified information.
+ *
+ * Returns:
+ *
+ * NT_STATUS_NO_MEMORY not enough memory
+ * NT_STATUS_SUCCESS successful
+ */
+static DWORD
+smbrdr_handle_setup(smbrdr_handle_t *srh,
+ unsigned char cmd,
+ struct sdb_session *session,
+ struct sdb_logon *logon,
+ struct sdb_netuse *netuse)
+{
+ srh->srh_buf = (unsigned char *)malloc(SMBRDR_REQ_BUFSZ);
+ if (srh->srh_buf == 0) {
+ syslog(LOG_ERR, "Smbrdr[%d]: resource shortage", cmd);
+ return (NT_STATUS_NO_MEMORY);
+ }
+ bzero(srh->srh_buf, SMBRDR_REQ_BUFSZ);
+
+ srh->srh_mbflags = (session->remote_caps & CAP_UNICODE)
+ ? SMB_MSGBUF_UNICODE : 0;
+
+ smb_msgbuf_init(&srh->srh_mbuf, srh->srh_buf,
+ SMBRDR_REQ_BUFSZ, srh->srh_mbflags);
+
+ srh->srh_cmd = cmd;
+ srh->srh_session = session;
+ srh->srh_user = logon;
+ srh->srh_tree = netuse;
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smbrdr_hdr_setup
+ *
+ * Build an SMB header based on the information in the given handle.
+ * The SMB header is described in section 3.2 of the CIFS spec.
+ * As this is a canned function, no error checking is performed here.
+ * The return value from smb_msgbuf_encode is simply returned to the caller.
+ */
+static int
+smbrdr_hdr_setup(smbrdr_handle_t *srh)
+{
+ static unsigned short my_pid = 0;
+
+ if (!my_pid)
+ my_pid = getpid();
+
+ return (smb_msgbuf_encode(&srh->srh_mbuf, "Mb4.bw12.wwww",
+ srh->srh_cmd,
+ srh->srh_session->smb_flags,
+ srh->srh_session->smb_flags2,
+ (srh->srh_tree) ? srh->srh_tree->tid : 0,
+ my_pid,
+ (srh->srh_user) ? srh->srh_user->uid : 0,
+ 0 /* mid */));
+}
+
+/*
+ * Canned SMB header decode.
+ */
+static int
+smb_decode_nt_hdr(smb_msgbuf_t *mb, smb_hdr_t *hdr)
+{
+ return (smb_msgbuf_decode(mb, SMB_HEADER_NT_FMT,
+ &hdr->command,
+ &hdr->status.ntstatus,
+ &hdr->flags,
+ &hdr->flags2,
+ &hdr->pid_high,
+ SMB_SIG_SIZE,
+ &hdr->extra.extra.security_sig,
+ &hdr->tid,
+ &hdr->pid,
+ &hdr->uid,
+ &hdr->mid));
+}
+
+/*
+ * smbrdr_hdr_process
+ *
+ * Assuming 'srh->srh_mbuf' contains a response from a Windows client,
+ * decodes the 32 bytes SMB header.
+ *
+ * Returns:
+ *
+ * NT_STATUS_INVALID_NETWORK_RESPONSE error decoding the header
+ * NT_STATUS_REPLY_MESSAGE_MISMATCH response doesn't match the request
+ * NT_STATUS_SUCCESS successful
+ * smb_hdr->status.ntstatus error returned by server
+ */
+static DWORD
+smbrdr_hdr_process(smbrdr_handle_t *srh, smb_hdr_t *smb_hdr)
+{
+ int rc;
+
+ /*
+ * Returns the number of decoded bytes on success
+ * or some negative MSGBUF_XXX error code on failure
+ */
+ rc = smb_decode_nt_hdr(&srh->srh_mbuf, smb_hdr);
+
+ if (rc < SMB_HEADER_LEN) {
+ syslog(LOG_ERR, "Smbrdr[%d]: bad SMB header (%d)",
+ srh->srh_cmd, rc);
+ return (NT_STATUS_INVALID_NETWORK_RESPONSE);
+ }
+
+ if (smb_hdr->status.ntstatus != 0) {
+ /*
+ * MSDN article: 193839
+ * "The buffer overflow status is usually returned by a Windows
+ * server to inform the client that there is more data in its
+ * buffer than it could put in the packet.
+ *
+ * The buffer overflow should not be considered as an error.
+ * Subsequent SmbReadX request is required to obtain the
+ * remaining data in the server's buffer.
+ */
+ if (NT_SC_VALUE(smb_hdr->status.ntstatus)
+ == NT_STATUS_BUFFER_OVERFLOW) {
+ syslog(LOG_DEBUG, "Smbrdr[%d]: %s", srh->srh_cmd,
+ xlate_nt_status(smb_hdr->status.ntstatus));
+ } else {
+ syslog(LOG_ERR, "Smbrdr[%d]: request failed (%s)",
+ srh->srh_cmd,
+ xlate_nt_status(smb_hdr->status.ntstatus));
+ return (smb_hdr->status.ntstatus);
+ }
+ }
+
+ if (smb_hdr->command != srh->srh_cmd) {
+ syslog(LOG_ERR, "Smbrdr[%d]: reply mismatch (%d)",
+ srh->srh_cmd, smb_hdr->command);
+ return (NT_STATUS_REPLY_MESSAGE_MISMATCH);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smbrdr_sign
+ *
+ * Signs the given outgoing packet according to the
+ * specified signing context.
+ *
+ * The client and server each maintain an integer counter
+ * which they initialize to zero. Both counters are
+ * incremented for every SMB message - that's once for a
+ * request and once for a reply. As a result, requests sent
+ * by SMB Redirector always have an even sequence number
+ * and replies from the Windows server always have an odd
+ * number.
+ *
+ * Based on the observed Windows 2003 behavior, any SMB
+ * request will fail with NT_STATUS_ACCESS_DENIED if its
+ * sequence number is not even.
+ *
+ * The function can fail if there is trouble with the cryptographic
+ * framework and if that happens SMBAUTH_FAILURE is returned. In the
+ * normal case SMBAUTH_SUCCESS is returned.
+ */
+static int
+smbrdr_sign(smb_sign_ctx_t *sign_ctx, smb_msgbuf_t *mb)
+{
+ if (sign_ctx->ssc_flags & SMB_SCF_STARTED) {
+ if (sign_ctx->ssc_seqnum % 2) {
+ syslog(LOG_DEBUG, "SmbrdrSign: even sequence number"
+ " is expected(%d)",
+ sign_ctx->ssc_seqnum);
+ }
+ if (smb_mac_sign(sign_ctx, smb_msgbuf_base(mb),
+ smb_msgbuf_used(mb)) != SMBAUTH_SUCCESS)
+ return (SMBAUTH_FAILURE);
+ sign_ctx->ssc_seqnum++;
+ }
+ return (SMBAUTH_SUCCESS);
+}
+
+
+/*
+ * smbrdr_sign_chk
+ *
+ * Validates SMB MAC signature in the in-coming message.
+ * Return 1 if the signature are match; otherwise, return 0;
+ *
+ * When packet signing is enabled, the sequence number kept in the
+ * sign_ctx structure will be incremented when a SMB request is
+ * sent and upon the receipt of the first SmbTransact response
+ * if SMB fragmentation occurs.
+ */
+static int
+smbrdr_sign_chk(smb_sign_ctx_t *sign_ctx, smb_msgbuf_t *mb,
+ unsigned char *signature)
+{
+ int sign_ok = 1;
+
+ if (sign_ctx->ssc_flags & SMB_SCF_STARTED) {
+ (void) memcpy(sign_ctx->ssc_sign, signature, SMB_SIG_SIZE);
+ sign_ok = smb_mac_chk(sign_ctx, smb_msgbuf_base(mb),
+ smb_msgbuf_size(mb));
+ sign_ctx->ssc_seqnum++;
+ }
+
+ return (sign_ok);
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c
new file mode 100644
index 0000000000..7dee7e41d2
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c
@@ -0,0 +1,710 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB session logon and logoff functions. See CIFS section 4.1.
+ */
+
+#include <pthread.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <synch.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <smbsrv/libsmbrdr.h>
+
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smb.h>
+#include <smbrdr_ipc_util.h>
+#include <smbrdr.h>
+
+#define SMBRDR_PWD_NULL 0
+#define SMBRDR_PWD_USER 1
+#define SMBRDR_PWD_HASH 2
+
+static int smbrdr_smb_session_setupandx(struct sdb_logon *logon);
+static boolean_t smbrdr_logon_validate(char *server, char *username);
+static struct sdb_logon *smbrdr_logon_init(struct sdb_session *session,
+ char *username, char *pwd, int pwd_type);
+static int smbrdr_logon_user(char *server, char *username, char *pwd,
+ int pwd_type);
+static int smbrdr_authenticate(char *primary_domain, char *account_name,
+ char *pwd, int pwd_type);
+
+/*
+ * mlsvc_anonymous_logon
+ *
+ * Set up an anonymous session. If the session to the resource domain
+ * controller appears to be okay we shouldn't need to do anything here.
+ * Otherwise we clean up the stale session and create a new one.
+ */
+int
+mlsvc_anonymous_logon(char *domain_controller, char *domain_name,
+ char **username)
+{
+ int rc = 0;
+
+ if (username == NULL) {
+ syslog(LOG_ERR, "smbrdr: (anon logon) %s",
+ xlate_nt_status(NT_STATUS_INVALID_PARAMETER));
+ return (-1);
+ }
+
+ /*
+ * if the system is configured to establish Authenticated IPC
+ * connection to PDC
+ */
+ if (smbrdr_ipc_get_mode() == MLSVC_IPC_ADMIN) {
+ rc = mlsvc_admin_logon(domain_controller, domain_name);
+ /*
+ * it is possible for the system to fallback to use
+ * anonymous IPC
+ */
+ if (smbrdr_ipc_get_mode() != MLSVC_IPC_ADMIN)
+ *username = MLSVC_ANON_USER;
+ else
+ *username = smbrdr_ipc_get_user();
+
+ syslog(LOG_DEBUG, "smbrdr: (admin logon) %s", *username);
+ return (rc);
+ }
+
+ *username = MLSVC_ANON_USER;
+
+ if (smbrdr_logon_validate(domain_controller, MLSVC_ANON_USER))
+ /* session & user are good use them */
+ return (0);
+
+
+ if (smbrdr_negotiate(domain_name) != 0) {
+ syslog(LOG_ERR, "smbrdr: (anon logon) negotiate <%s> failed",
+ (domain_name ? domain_name : "NoName"));
+ return (-1);
+ }
+
+ if (smbrdr_logon_user(domain_controller, MLSVC_ANON_USER, 0,
+ SMBRDR_PWD_NULL) < 0) {
+ syslog(LOG_ERR, "smbrdr: (anon logon) logon failed");
+ rc = -1;
+ }
+
+ return (rc);
+}
+
+int
+mlsvc_user_getauth(char *domain_controller, char *username,
+ smb_auth_info_t *auth)
+{
+ struct sdb_session *session;
+
+ if (auth) {
+ bzero(auth, sizeof (smb_auth_info_t));
+ session = smbrdr_session_lock(domain_controller, username,
+ SDB_SLCK_READ);
+ if (session) {
+ *auth = session->logon.auth;
+ smbrdr_session_unlock(session);
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+/*
+ * mlsvc_user_logon
+ *
+ * Set up a user session. If the session to the resource domain controller
+ * appears to be okay we shouldn't need to do anything here. Otherwise we
+ * clean up the stale session and create a new one. Once a session is
+ * established, we leave it intact. It should only need to be set up again
+ * due to an inactivity timeout or a domain controller reset.
+ */
+int
+mlsvc_user_logon(char *domain_controller, char *domain_name, char *username,
+ char *password)
+{
+ int erc;
+
+ if (smbrdr_logon_validate(domain_controller, username))
+ return (0);
+
+ if (smbrdr_negotiate(domain_name) != 0) {
+ syslog(LOG_ERR, "smbrdr: (user logon) negotiate failed");
+ return (-1);
+ }
+
+ erc = smbrdr_authenticate(domain_name, username, password,
+ SMBRDR_PWD_USER);
+
+ return ((erc == AUTH_USER_GRANT) ? 0 : -1);
+}
+
+/*
+ * mlsvc_admin_logon
+ *
+ * Unlike mlsvc_user_logon, mlsvc_admin_logon doesn't take
+ * any username or password as function arguments.
+ */
+int
+mlsvc_admin_logon(char *domain_controller, char *domain_name)
+{
+ char password[PASS_LEN + 1];
+ int erc;
+ char *username, *dummy;
+
+ username = smbrdr_ipc_get_user();
+ (void) memcpy(password, smbrdr_ipc_get_passwd(), SMBAUTH_HASH_SZ);
+
+ if (*username == 0) {
+ syslog(LOG_ERR, "smbrdr: admin logon (no admin user)");
+ return (-1);
+ }
+
+ if (smbrdr_logon_validate(domain_controller, username))
+ return (0);
+
+ if (smbrdr_negotiate(domain_name) != 0) {
+ syslog(LOG_ERR, "smbrdr: admin logon (negotiate failed)");
+ return (-1);
+ }
+
+ erc = smbrdr_authenticate(domain_name, username, password,
+ SMBRDR_PWD_HASH);
+
+ /*
+ * Fallback to anonmyous IPC logon if the IPC password hash is no
+ * longer valid. It happens when the administrator password has
+ * been reset from the Domain Controller.
+ */
+ if (erc < 0 && smbrdr_ipc_is_valid()) {
+ if (!smbrdr_ipc_is_fallback())
+ syslog(LOG_DEBUG, "smbrdr: admin logon "
+ "(fallback to anonymous IPC)");
+ smbrdr_ipc_set_fallback();
+ smbrdr_ipc_save_mode(IPC_MODE_FALLBACK_ANON);
+ erc = mlsvc_anonymous_logon(domain_controller, domain_name,
+ &dummy);
+ }
+
+ return ((erc == AUTH_USER_GRANT) ? 0 : -1);
+}
+
+/*
+ * smbrdr_authenticate
+ *
+ * Authenticate primary_domain\account_name.
+ *
+ * Returns:
+ * 0 User access granted
+ * 1 Guest access granted
+ * 2 IPC access granted
+ * (<0) Error
+ */
+static int
+smbrdr_authenticate(char *primary_domain, char *account_name,
+ char *pwd, int pwd_type)
+{
+ smb_ntdomain_t *di;
+
+ if (pwd == NULL)
+ return (AUTH_USER_GRANT | AUTH_IPC_ONLY_GRANT);
+
+
+ if ((di = smb_getdomaininfo(0)) == 0) {
+ syslog(LOG_ERR, "MlsvcAuthenticate[%s]: %s", account_name,
+ xlate_nt_status(NT_STATUS_CANT_ACCESS_DOMAIN_INFO));
+ return (-1);
+ }
+
+ /*
+ * Ensure that the domain name is uppercase.
+ */
+ (void) utf8_strupr(primary_domain);
+
+ /*
+ * We can only authenticate a user via a controller in the user's
+ * primary domain. If the user's domain name doesn't match the
+ * authenticating server's domain, reject the request before we
+ * create a logon entry for the user. Although the logon will be
+ * denied eventually, we don't want a logon structure for a user
+ * in the resource domain that is pointing to a session structure
+ * for the account domain. If this happened to be our resource
+ * domain user, we would not be able to use that account to connect
+ * to the resource domain.
+ */
+ if (strcasecmp(di->domain, primary_domain)) {
+ syslog(LOG_ERR, "MlsvcAuthenticate: %s\\%s: not account domain",
+ primary_domain, account_name);
+ return (-2);
+ }
+
+ return (smbrdr_logon_user(di->server, account_name, pwd, pwd_type));
+}
+
+/*
+ * smbrdr_logon_user
+ *
+ * This is the entry point for logging a user onto the domain. The
+ * session structure should have been obtained via a successful call
+ * to smbrdr_smb_connect. We allocate a logon structure to hold the
+ * user details and attempt to logon using smbrdr_smb_session_setupandx. Note
+ * that we expect the password fields to have been encrypted before
+ * this call.
+ *
+ * On success, the logon structure will be returned. Otherwise a null
+ * pointer will be returned.
+ */
+static int
+smbrdr_logon_user(char *server, char *username, char *pwd, int pwd_type)
+{
+ struct sdb_session *session;
+ struct sdb_logon *logon;
+ struct sdb_logon old_logon;
+
+ if (server == 0 || username == 0 ||
+ ((pwd == 0) && (pwd_type != SMBRDR_PWD_NULL))) {
+ return (-1);
+ }
+
+ session = smbrdr_session_lock(server, 0, SDB_SLCK_WRITE);
+ if (session == 0) {
+ syslog(LOG_ERR, "smbrdr: (logon[%s]) no session with %s",
+ username, server);
+ return (-1);
+ }
+
+ bzero(&old_logon, sizeof (struct sdb_logon));
+
+ logon = &session->logon;
+ if (logon->type != SDB_LOGON_NONE) {
+ if (strcasecmp(logon->username, username) == 0) {
+ /* The requested user has already been logged in */
+ smbrdr_session_unlock(session);
+ return ((logon->type == SDB_LOGON_GUEST)
+ ? AUTH_GUEST_GRANT : AUTH_USER_GRANT);
+ }
+
+ old_logon = *logon;
+ }
+
+ logon = smbrdr_logon_init(session, username, pwd, pwd_type);
+
+ if (logon == 0) {
+ syslog(LOG_ERR, "smbrdr: (logon[%s]) resource shortage",
+ username);
+ smbrdr_session_unlock(session);
+ return (-1);
+ }
+
+ if (smbrdr_smb_session_setupandx(logon) < 0) {
+ free(logon);
+ smbrdr_session_unlock(session);
+ return (-1);
+ }
+
+ session->logon = *logon;
+ free(logon);
+
+ if (old_logon.type != SDB_LOGON_NONE) {
+ (void) smbrdr_smb_logoff(&old_logon);
+ }
+
+ smbrdr_session_unlock(session);
+ return ((logon->type == SDB_LOGON_GUEST)
+ ? AUTH_GUEST_GRANT : AUTH_USER_GRANT);
+}
+
+
+/*
+ * smbrdr_smb_session_setupandx
+ *
+ * Build and send an SMB session setup command. This is used to log a
+ * user onto the domain. See CIFS section 4.1.2.
+ *
+ * Returns 0 on success. Otherwise returns a -ve error code.
+ */
+static int
+smbrdr_smb_session_setupandx(struct sdb_logon *logon)
+{
+ struct sdb_session *session;
+ smb_hdr_t smb_hdr;
+ smbrdr_handle_t srh;
+ smb_msgbuf_t *mb;
+ char *native_os;
+ char *native_lanman;
+ unsigned short data_bytes;
+ unsigned short guest;
+ unsigned long capabilities;
+ unsigned short null_size;
+ size_t (*strlen_fn)(const char *s);
+ DWORD status;
+ int rc;
+
+ /*
+ * Paranoia check - we should never get this
+ * far without a valid session structure.
+ */
+ if ((session = logon->session) == 0) {
+ syslog(LOG_ERR, "smbrdr_smb_session_setupandx: no data");
+ return (-1);
+ }
+
+ if (session->remote_caps & CAP_UNICODE) {
+ strlen_fn = mts_wcequiv_strlen;
+ null_size = sizeof (mts_wchar_t);
+ session->smb_flags2 |= SMB_FLAGS2_UNICODE;
+ } else {
+ strlen_fn = strlen;
+ null_size = sizeof (char);
+ }
+
+ if (smbrdr_sign_init(session, logon) < 0)
+ return (-1);
+
+ status = smbrdr_request_init(&srh, SMB_COM_SESSION_SETUP_ANDX,
+ session, 0, 0);
+
+ if (status != NT_STATUS_SUCCESS) {
+ (void) smbrdr_sign_fini(session);
+ syslog(LOG_ERR, "SmbrdrSessionSetup: %s",
+ xlate_nt_status(status));
+ return (-1);
+ }
+ mb = &srh.srh_mbuf;
+
+ /*
+ * Regardless of the server's capabilities or what's
+ * reported in smb_flags2, we should report our full
+ * capabilities.
+ */
+ capabilities = CAP_UNICODE | CAP_NT_SMBS | CAP_STATUS32;
+
+ /*
+ * Compute the BCC for unicode or ASCII strings.
+ */
+ data_bytes = logon->auth.ci_len + logon->auth.cs_len + null_size;
+ data_bytes += strlen_fn(session->native_os) + null_size;
+ data_bytes += strlen_fn(session->native_lanman) + null_size;
+
+ if (logon->type == SDB_LOGON_ANONYMOUS) {
+ /*
+ * Anonymous logon: no username or domain name.
+ * We still need to include two null characters.
+ */
+ data_bytes += (2 * null_size);
+
+ rc = smb_msgbuf_encode(mb, "bb.wwwwlwwllwlu.u.",
+ 13, /* smb_wct */
+ 0xff, /* AndXCommand (none) */
+ 32 + 26 + 3 + data_bytes, /* AndXOffset */
+ SMBRDR_REQ_BUFSZ, /* MaxBufferSize */
+ 1, /* MaxMpxCount */
+ 0, /* VcNumber */
+ 0, /* SessionKey */
+ 1, /* CaseInsensitivePassLength */
+ 0, /* CaseSensitivePassLength */
+ 0, /* Reserved */
+ capabilities, /* Capabilities */
+ data_bytes, /* smb_bcc */
+ 0, /* No user or domain */
+ session->native_os, /* NativeOS */
+ session->native_lanman); /* NativeLanMan */
+ } else {
+ data_bytes += strlen_fn(logon->username) + null_size;
+ data_bytes += strlen_fn(session->di.domain) + null_size;
+
+ rc = smb_msgbuf_encode(mb, "bb.wwwwlwwllw#c#cuuu.u.",
+ 13, /* smb_wct */
+ 0xff, /* AndXCommand (none) */
+ 32 + 26 + 3 + data_bytes, /* AndXOffset */
+ SMBRDR_REQ_BUFSZ, /* MaxBufferSize */
+ 1, /* MaxMpxCount */
+ session->vc, /* VcNumber */
+ session->sesskey, /* SessionKey */
+ logon->auth.ci_len, /* CaseInsensitivePassLength */
+ logon->auth.cs_len, /* CaseSensitivePassLength */
+ 0, /* Reserved */
+ capabilities, /* Capabilities */
+ data_bytes, /* smb_bcc */
+ logon->auth.ci_len, /* ci length spec */
+ logon->auth.ci, /* CaseInsensitivePassword */
+ logon->auth.cs_len, /* cs length spec */
+ logon->auth.cs, /* CaseSensitivePassword */
+ logon->username, /* AccountName */
+ session->di.domain, /* PrimaryDomain */
+ session->native_os, /* NativeOS */
+ session->native_lanman); /* NativeLanMan */
+ }
+
+ if (rc <= 0) {
+ syslog(LOG_ERR, "smbrdr_smb_session_setupandx: encode failed");
+ smbrdr_handle_free(&srh);
+ (void) smbrdr_sign_fini(session);
+ return (-1);
+ }
+
+ status = smbrdr_exchange(&srh, &smb_hdr, 0);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrSessionSetup: %s",
+ xlate_nt_status(status));
+ smbrdr_handle_free(&srh);
+ (void) smbrdr_sign_fini(session);
+ return (-1);
+ }
+
+ rc = smb_msgbuf_decode(mb, "5.w2.u", &guest, &native_os);
+
+ /*
+ * There was a problem in decoding response from
+ * a Samba 2.x PDC. This server sends strings in ASCII
+ * format and there is one byte with value 0 between
+ * native_os and native_lm:
+ *
+ * FF 53 4D 42 73 00 .SMBs.
+ * 00 00 00 88 01 00 00 00 00 00 00 00 00 00 00 00 ................
+ * 00 00 00 00 BB 00 64 00 00 00 03 FF 00 00 00 01 ......d.........
+ * 00 1C 00 55 6E 69 78 00 53 61 6D 62 61 20 32 2E ...Unix.Samba.2.
+ * 32 2E 38 61 00 53 41 4D 42 41 5F 44 4F 4D 00 2.8a.SAMBA_DOM.
+ *
+ * The byte doesn't seem to be padding because when change in
+ * native OS from Unix to Unix1 the 0 byte is still there:
+ *
+ * FF 53 4D 42 73 00 .SMBs.
+ * 00 00 00 88 01 00 00 00 00 00 00 00 00 00 00 00 ................
+ * 00 00 00 00 BB 00 64 00 00 00 03 FF 00 00 00 00 ......d.........
+ * 00 1D 00 55 6E 69 78 31 00 53 61 6D 62 61 20 32 ...Unix1.Samba.2
+ * 2E 32 2E 38 61 00 53 41 4D 42 41 5F 44 4F 4D 00 .2.8a.SAMBA_DOM.
+ */
+ if (rc > 0) {
+ if (session->remote_caps & CAP_UNICODE)
+ rc = smb_msgbuf_decode(mb, "u", &native_lanman);
+ else
+ rc = smb_msgbuf_decode(mb, ".u", &native_lanman);
+ }
+
+ if (rc <= 0) {
+ syslog(LOG_ERR, "RdrSessionSetup: decode failed");
+ smbrdr_handle_free(&srh);
+ (void) smbrdr_sign_fini(session);
+ return (-1);
+ }
+
+ session->remote_os = smbnative_os_value(native_os);
+ session->remote_lm = smbnative_lm_value(native_lanman);
+ session->pdc_type = smbnative_pdc_value(native_lanman);
+
+ logon->uid = smb_hdr.uid;
+ if (guest)
+ logon->type = SDB_LOGON_GUEST;
+
+ smbrdr_handle_free(&srh);
+ (void) smbrdr_sign_unset_key(session);
+
+ logon->state = SDB_LSTATE_SETUP;
+
+ return (0);
+}
+
+/*
+ * smbrdr_smb_logoff
+ *
+ * Build and send an SMB session logoff (SMB_COM_LOGOFF_ANDX) command.
+ * This is the inverse of an SMB_COM_SESSION_SETUP_ANDX. See CIFS
+ * section 4.1.3. The logon structure should have been obtained from a
+ * successful call to smbrdr_logon_user.
+ *
+ * Returns 0 on success. Otherwise returns a -ve error code.
+ */
+int
+smbrdr_smb_logoff(struct sdb_logon *logon)
+{
+ struct sdb_session *session;
+ smbrdr_handle_t srh;
+ smb_hdr_t smb_hdr;
+ DWORD status;
+ int rc;
+
+ if (logon->state != SDB_LSTATE_SETUP) {
+ /* No user to logoff */
+ bzero(logon, sizeof (struct sdb_logon));
+ return (0);
+ }
+
+ if ((session = logon->session) == 0) {
+ bzero(logon, sizeof (struct sdb_logon));
+ return (0);
+ }
+
+ logon->state = SDB_LSTATE_LOGGING_OFF;
+ smbrdr_netuse_logoff(logon->uid);
+
+ if ((session->state != SDB_SSTATE_NEGOTIATED) &&
+ (session->state != SDB_SSTATE_DISCONNECTING)) {
+ bzero(logon, sizeof (struct sdb_logon));
+ return (0);
+ }
+
+ status = smbrdr_request_init(&srh, SMB_COM_LOGOFF_ANDX,
+ session, logon, 0);
+
+ if (status != NT_STATUS_SUCCESS) {
+ logon->state = SDB_LSTATE_SETUP;
+ syslog(LOG_ERR, "smbrdr: logoff %s (%s)", logon->username,
+ xlate_nt_status(status));
+ return (-1);
+ }
+
+ rc = smb_msgbuf_encode(&srh.srh_mbuf, "bbbww", 2, 0xff, 0, 0, 0);
+ if (rc < 0) {
+ logon->state = SDB_LSTATE_SETUP;
+ smbrdr_handle_free(&srh);
+ syslog(LOG_ERR, "smbrdr: logoff %s (encode failed)",
+ logon->username);
+ return (rc);
+ }
+
+ status = smbrdr_exchange(&srh, &smb_hdr, 0);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "smbrdr: logoff %s (%s)", logon->username,
+ xlate_nt_status(status));
+ rc = -1;
+ } else {
+ rc = 0;
+ }
+
+ bzero(logon, sizeof (struct sdb_logon));
+ smbrdr_handle_free(&srh);
+ return (rc);
+}
+
+
+/*
+ * smbrdr_logon_init
+ *
+ * Find a slot for account logon information. The account information
+ * is associated with a session so we need a valid session slot before
+ * calling this function. If we already have a record of the specified
+ * account, a pointer to that record is returned. Otherwise we attempt
+ * to allocate a new one.
+ */
+static struct sdb_logon *
+smbrdr_logon_init(struct sdb_session *session, char *username,
+ char *pwd, int pwd_type)
+{
+ struct sdb_logon *logon;
+ int smbrdr_lmcomplvl;
+ int rc;
+
+ logon = (struct sdb_logon *)malloc(sizeof (sdb_logon_t));
+ if (logon == 0)
+ return (0);
+
+ bzero(logon, sizeof (struct sdb_logon));
+ logon->session = session;
+
+ if (strcmp(username, "IPC$") == 0)
+ logon->type = SDB_LOGON_ANONYMOUS;
+ else
+ logon->type = SDB_LOGON_USER;
+
+ (void) strlcpy(logon->username, username, MAX_ACCOUNT_NAME);
+
+ smb_config_rdlock();
+ smbrdr_lmcomplvl = smb_config_getnum(SMB_CI_LM_LEVEL);
+ smb_config_unlock();
+
+ switch (pwd_type) {
+ case SMBRDR_PWD_USER:
+ rc = smb_auth_set_info(username, pwd, 0, session->di.domain,
+ session->challenge_key, session->challenge_len,
+ smbrdr_lmcomplvl, &logon->auth);
+
+ if (rc != 0) {
+ free(logon);
+ return (0);
+ }
+ break;
+
+ case SMBRDR_PWD_HASH:
+ rc = smb_auth_set_info(username, 0, (unsigned char *)pwd,
+ session->di.domain, session->challenge_key,
+ session->challenge_len, smbrdr_lmcomplvl, &logon->auth);
+
+ if (rc != 0) {
+ free(logon);
+ return (0);
+ }
+ break;
+
+ case SMBRDR_PWD_NULL:
+ logon->auth.ci_len = 1;
+ *(logon->auth.ci) = 0;
+ logon->auth.cs_len = 0;
+ break;
+
+ default:
+ /* Unknown password type */
+ free(logon);
+ return (0);
+ }
+
+ logon->state = SDB_LSTATE_INIT;
+ return (logon);
+}
+
+/*
+ * smbrdr_logon_validate
+ *
+ * if session is there and it's alive and also the required
+ * user is already logged in don't need to do anything
+ * otherwise clear the session structure.
+ */
+static boolean_t
+smbrdr_logon_validate(char *server, char *username)
+{
+ struct sdb_session *session;
+ boolean_t valid = B_FALSE;
+
+ session = smbrdr_session_lock(server, username, SDB_SLCK_WRITE);
+ if (session) {
+ if (nb_keep_alive(session->sock) == 0) {
+ valid = B_TRUE;
+ } else {
+ session->state = SDB_SSTATE_STALE;
+ syslog(LOG_DEBUG, "smbrdr: (logon) stale session");
+ }
+
+ smbrdr_session_unlock(session);
+ }
+
+ return (valid);
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netbios.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netbios.c
new file mode 100644
index 0000000000..2066dab051
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netbios.c
@@ -0,0 +1,457 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NetBIOS support functions. NetBIOS is documented in the following
+ * RFC documents:
+ *
+ * RFC 1001: Protocol Standard for a NetBIOS Service on a TCP/UDP
+ * Transport: Concepts and Methods
+ *
+ * RFC 1002: Protocol Standard for a NetBIOS Service on a TCP/UDP
+ * Transport: Detailed Specifications
+ *
+ */
+
+#define BSD_BYTE_STRING_PROTOTYPES
+
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <synch.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include <pthread.h>
+
+#define MAX_NETBIOS_NAME_SIZE 16
+
+#define SESSION_MESSAGE 0x00
+#define SESSION_REQUEST 0x81
+#define POSITIVE_SESSION_RESPONSE 0x82
+#define NEGATIVE_SESSION_RESPONSE 0x83
+#define RETARGET_SESSION_RESPONSE 0x84
+#define SESSION_KEEP_ALIVE 0x85
+
+#define NB_READ_MSG_ERR_EOF 0
+#define NB_READ_MSG_ERR -1
+#define NB_READ_MSG_ERR_OVERFLOW -2
+#define NB_READ_MSG_ERR_UNDERFLOW -3
+#define NB_RCV_MSG_ERR_INVTYPE -4
+
+/*
+ * Semaphore object used to serialize access through NetBIOS exchange.
+ */
+static mutex_t nb_mutex;
+
+static int nb_write_msg(int fd, unsigned char *buf, unsigned count, int type);
+static int nb_read_msg(int fd, unsigned char *buf, unsigned max_buf,
+ int *type, long timeout);
+static int nb_read_itter(int fd, unsigned char *buf, unsigned cnt);
+static int nb_first_level_name_encode(char *name, char *scope,
+ unsigned char *out, int max_out);
+
+
+/*
+ * nb_lock
+ *
+ * Acquire semaphore for doing netbios operations
+ */
+void
+nb_lock()
+{
+ (void) mutex_lock(&nb_mutex);
+}
+
+/*
+ * nb_lock
+ *
+ * Release netbios semaphore.
+ */
+void
+nb_unlock()
+{
+ (void) mutex_unlock(&nb_mutex);
+}
+
+void
+nb_close(int fd)
+{
+ (void) mutex_lock(&nb_mutex);
+ if (fd > 0) {
+ (void) close(fd);
+ (void) printf("[%d] socket (%d) closed\n", pthread_self(), fd);
+ }
+ (void) mutex_unlock(&nb_mutex);
+}
+
+/*
+ * nb_keep_alive
+ *
+ * Send the NetBIOS keep alive message. No response is expected but we
+ * do need to ignore keep-alive messages in nb_exchange. The semaphore
+ * ensures compatibility/serialization with nb_exchange to allow us to
+ * call this function from a separate thread.
+ */
+int
+nb_keep_alive(int fd)
+{
+ int nothing;
+ int rc;
+
+ (void) mutex_lock(&nb_mutex);
+
+ rc = nb_write_msg(fd, (unsigned char *)&nothing, 0, SESSION_KEEP_ALIVE);
+ if (rc < 0)
+ syslog(LOG_ERR, "nb_keep_alive: write failed");
+
+ (void) mutex_unlock(&nb_mutex);
+ return (rc);
+}
+
+/*
+ * nb_send
+ *
+ * This is just a wrapper round the nb_write_msg.
+ */
+int
+nb_send(int fd, unsigned char *send_buf, unsigned send_cnt)
+{
+ int rc;
+
+ if ((rc = nb_write_msg(fd, send_buf, send_cnt, SESSION_MESSAGE)) < 0)
+ syslog(LOG_ERR, "nb_send: write failed: rc=%d", rc);
+
+ return (rc);
+}
+
+/*
+ * nb_rcv
+ *
+ * This is a wrapper round the nb_read_msg() so that if a
+ * keep-alive message is received, just discard it and go
+ * back to look for the real response.
+ */
+int
+nb_rcv(int fd, unsigned char *recv_buf, unsigned recv_max, long timeout)
+{
+ int rc;
+ int type;
+
+ do {
+ rc = nb_read_msg(fd, recv_buf, recv_max, &type, timeout);
+ if (rc < 0) {
+ syslog(LOG_ERR, "nb_rcv: read failed: rc=%d", rc);
+ return (rc);
+ }
+ } while (type == SESSION_KEEP_ALIVE);
+
+ if (type != SESSION_MESSAGE) {
+ syslog(LOG_ERR, "nb_rcv: invalid type: %d", type);
+ return (NB_RCV_MSG_ERR_INVTYPE);
+ }
+
+ return (rc);
+}
+
+/*
+ * nb_exchange
+ *
+ * This is the NetBIOS workhorse function where we do the send/receive
+ * message exchange. A semaphore is used to serialize access because
+ * we may get swapped out between the send and receive operations and
+ * another thread could enter here and collect our response. If a
+ * keep-alive message is received, just discard it and go back to look
+ * for the real response.
+ *
+ * Note: With the addition of support for SMB over TCP, this function
+ * may be exchanging NetBIOS-less SMB data.
+ */
+int
+nb_exchange(int fd, unsigned char *send_buf, unsigned send_cnt,
+ unsigned char *recv_buf, unsigned recv_max, long timeout)
+{
+ int rc;
+
+ (void) mutex_lock(&nb_mutex);
+
+ rc = nb_send(fd, send_buf, send_cnt);
+ if (rc == send_cnt)
+ rc = nb_rcv(fd, recv_buf, recv_max, timeout);
+
+ (void) mutex_unlock(&nb_mutex);
+ return (rc);
+}
+
+/*
+ * nb_session_request
+ *
+ * We should never see descriptor 0 (stdin) or -1.
+ */
+int
+nb_session_request(int fd, char *called_name, char *called_scope,
+ char *calling_name, char *calling_scope)
+{
+ unsigned char sr_buf[200];
+ int len;
+ int rc;
+ int type;
+
+ if (fd == 0 || fd == -1)
+ return (-1);
+
+ rc = nb_first_level_name_encode(called_name, called_scope, sr_buf, 100);
+ len = rc;
+ rc = nb_first_level_name_encode(calling_name, calling_scope,
+ sr_buf+len, 100);
+ len += rc;
+
+ (void) mutex_lock(&nb_mutex);
+
+ rc = nb_write_msg(fd, (unsigned char *)sr_buf, len, SESSION_REQUEST);
+ if (rc < 0) {
+ syslog(LOG_ERR, "nb_session_request: write failed:"
+ " rc=%d", rc);
+ (void) mutex_unlock(&nb_mutex);
+ return (rc);
+ }
+
+ for (;;) {
+ rc = nb_read_msg(fd, (unsigned char *)sr_buf,
+ sizeof (sr_buf), &type, 0);
+ if (rc < 0) {
+ (void) mutex_unlock(&nb_mutex);
+ return (rc);
+ }
+
+ if ((rc == 0) && (type == -1)) {
+ (void) mutex_unlock(&nb_mutex);
+ return (-1); /* EOF */
+ }
+
+ if (type == POSITIVE_SESSION_RESPONSE) {
+ (void) mutex_unlock(&nb_mutex);
+ return (0);
+ }
+
+ if (type == NEGATIVE_SESSION_RESPONSE) {
+ (void) mutex_unlock(&nb_mutex);
+ return (-1);
+ }
+ }
+
+ /* NOTREACHED */
+ (void) mutex_unlock(&nb_mutex);
+ return (-1);
+}
+
+
+
+/*
+ * nb_write_msg
+ */
+static int
+nb_write_msg(int fd, unsigned char *buf, unsigned count, int type)
+{
+ struct iovec iov[2];
+ unsigned char header[4];
+ int rc;
+
+ if (fd == 0 || fd == -1) {
+ /*
+ * We should never see descriptor 0 (stdin).
+ */
+ syslog(LOG_ERR, "nb_write_msg: invalid descriptor (%d)", fd);
+ return (-1);
+ }
+
+ /*
+ * The NetBIOS message length is limited to 17 bits but
+ * we use this layer for SMB over both NetBIOS and TCP
+ * (NetBIOS-less SMB). When using SMB over TCP the length
+ * is 24 bits but we are ignoring that for now because we
+ * don't expect any messages larger than 64KB.
+ */
+ header[0] = type;
+ header[1] = (count >> 16) & 1;
+ header[2] = count >> 8;
+ header[3] = count;
+
+ iov[0].iov_base = (caddr_t)header;
+ iov[0].iov_len = 4;
+ iov[1].iov_base = (caddr_t)buf;
+ iov[1].iov_len = count;
+
+ rc = writev(fd, iov, 2);
+ if (rc != 4 + count) {
+ syslog(LOG_ERR, "nb_write_msg: writev rc=%d", rc);
+ return (-3); /* error */
+ }
+
+ return (count);
+}
+
+
+/*
+ * nb_read_msg
+ *
+ * Added select to ensure that we don't block forever waiting for a
+ * message.
+ */
+static int
+nb_read_msg(int fd, unsigned char *buf, unsigned max_buf,
+ int *type, long timeout)
+{
+ unsigned char header[4];
+ int length;
+ int rc;
+ fd_set readfds;
+ struct timeval tval;
+
+ *type = -1;
+
+ if (fd == 0 || fd == -1) {
+ /*
+ * We should never see descriptor 0 (stdin).
+ */
+ syslog(LOG_ERR, "nb_write_msg: invalid descriptor (%d)", fd);
+ return (NB_READ_MSG_ERR);
+ }
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ tval.tv_sec = (timeout == 0) ? 45 : timeout;
+ tval.tv_usec = 0;
+
+ if ((rc = select(fd + 1, &readfds, 0, 0, &tval)) <= 0) {
+ syslog(LOG_ERR, "nb_read_msg: select: %d", rc);
+ return (NB_READ_MSG_ERR);
+ }
+
+ if ((rc = nb_read_itter(fd, header, 4)) < 0)
+ return (rc); /* error */
+
+ if (rc != 4)
+ return (NB_READ_MSG_ERR_EOF); /* EOF */
+
+ /*
+ * The NetBIOS message length is limited to 17 bits but
+ * we use this layer for SMB over both NetBIOS and TCP
+ * (NetBIOS-less SMB). When using SMB over TCP the length
+ * is 24 bits but we are ignoring that for now because we
+ * don't expect any messages larger than 64KB.
+ */
+ *type = header[0];
+ length = ((header[1]&1) << 16) + (header[2]<<8) + header[3];
+
+ if (length > max_buf)
+ return (NB_READ_MSG_ERR_OVERFLOW); /* error overflow */
+
+ if ((rc = nb_read_itter(fd, buf, length)) != length)
+ return (NB_READ_MSG_ERR_UNDERFLOW); /* error underflow */
+
+ return (rc);
+}
+
+
+/*
+ * nb_read_itter
+ *
+ * We should never see descriptor 0 (stdin) or -1.
+ */
+static int
+nb_read_itter(int fd, unsigned char *buf, unsigned cnt)
+{
+ int ix;
+ int rc;
+
+ for (ix = 0; ix < cnt; ix += rc) {
+ if (fd == 0 || fd == -1)
+ return (-1);
+
+ if ((rc = read(fd, buf+ix, cnt-ix)) < 0)
+ return (rc);
+
+ if (rc == 0)
+ break;
+ }
+
+ return (ix);
+}
+
+
+/*
+ * nb_first_level_name_encode
+ */
+static int
+nb_first_level_name_encode(char *name, char *scope,
+ unsigned char *out, int max_out)
+{
+ unsigned char ch, len;
+ unsigned char *in;
+ unsigned char *lp;
+ unsigned char *op = out;
+ unsigned char *op_end = op + max_out;
+
+ in = (unsigned char *)name;
+ *op++ = 0x20;
+ for (len = 0; ((ch = *in) != 0) && len < MAX_NETBIOS_NAME_SIZE;
+ len++, in++) {
+ *op++ = 'A' + ((ch >> 4) & 0xF);
+ *op++ = 'A' + ((ch) & 0xF);
+ }
+
+ for (; len < MAX_NETBIOS_NAME_SIZE; len++) {
+ ch = ' ';
+ *op++ = 'A' + ((ch >> 4) & 0xF);
+ *op++ = 'A' + ((ch) & 0xF);
+ }
+
+ in = (unsigned char *)scope;
+ len = 0;
+ lp = op++;
+ for (; op < op_end; in++) {
+ ch = *in;
+ if (ch == 0) {
+ if ((*lp = len) != 0)
+ *op++ = 0;
+ break;
+ }
+ if (ch == '.') {
+ *lp = (op - lp) - 1;
+ lp = op++;
+ len = 0;
+ } else {
+ *op++ = ch;
+ len++;
+ }
+ }
+
+ return ((int)(op - out));
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netuse.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netuse.c
new file mode 100644
index 0000000000..508b258cd6
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netuse.c
@@ -0,0 +1,458 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Tree connect and disconnect functions to support SMB shares.
+ * These functions are described in the CIFS draft 1.0 Protocol
+ * Specification (December 19, 1997).
+ */
+
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <synch.h>
+#include <pthread.h>
+
+#include <smbsrv/libsmbrdr.h>
+
+#include <smbrdr.h>
+#include <smbsrv/ntstatus.h>
+
+
+/*
+ * The table of shares set up with the domain controller.
+ */
+static struct sdb_netuse netuse_table[N_NETUSE_TABLE];
+
+static int smbrdr_smb_tcon(struct sdb_session *session,
+ struct sdb_netuse *netuse, char *path, int path_len);
+
+static struct sdb_netuse *smbrdr_netuse_alloc(struct sdb_session *session,
+ char *sharename);
+static int smbrdr_smb_tdcon(struct sdb_netuse *netuse);
+
+static void
+smbrdr_netuse_clear(struct sdb_netuse *netuse)
+{
+ bzero(netuse, sizeof (struct sdb_netuse) - sizeof (mutex_t));
+}
+
+static void
+smbrdr_netuse_free(struct sdb_netuse *netuse)
+{
+ smbrdr_netuse_clear(netuse);
+ (void) mutex_unlock(&netuse->mtx);
+}
+
+/*
+ * mlsvc_tree_connect
+ *
+ * Establish a share (tree connect). We need to retrieve the session
+ * for the specified host and allocate a netuse structure. We set up
+ * the path here (UNC encoded) to make handling the malloc/free easier
+ * and pass everything on to smbrdr_smb_tcon where, if everything goes well,
+ * a valid tid will be stored in the netuse structure.
+ *
+ * On success, a pointer to the netuse is returned. Otherwise the
+ * netuse is cleared and a null pointer is returned.
+ */
+unsigned short
+mlsvc_tree_connect(char *hostname, char *username, char *sharename)
+{
+ struct sdb_session *session;
+ struct sdb_netuse *netuse;
+ char *path;
+ int path_len;
+
+ /*
+ * Make sure there is a session & logon for given info
+ */
+ session = smbrdr_session_lock(hostname, username, SDB_SLCK_READ);
+ if (session == 0) {
+ syslog(LOG_ERR, "smbrdr: (tcon) no session for %s@%s",
+ username, hostname);
+ return (0);
+ }
+
+
+ if ((netuse = smbrdr_netuse_alloc(session, sharename)) == 0) {
+ syslog(LOG_ERR, "smbrdr: (tcon) init failed");
+ smbrdr_session_unlock(session);
+ return (0);
+ }
+
+ /*
+ * Add some padding for the back-slash separators
+ * and the null-terminator.
+ */
+ path_len = SMB_PI_MAX_HOST + MAX_SHARE_NAME + 5;
+
+ if ((path = (char *)malloc(path_len)) == 0) {
+ smbrdr_netuse_free(netuse);
+ smbrdr_session_unlock(session);
+ syslog(LOG_ERR, "smbrdr: (tcon) resource shortage");
+ return (0);
+ }
+
+ bzero(path, path_len);
+ (void) snprintf(path, path_len, "\\\\%s\\%s", hostname, sharename);
+ if (session->remote_caps & CAP_UNICODE)
+ path_len = mts_wcequiv_strlen(path);
+ else
+ path_len = strlen(path);
+
+ if (smbrdr_smb_tcon(session, netuse, path, path_len) < 0) {
+ smbrdr_netuse_free(netuse);
+ smbrdr_session_unlock(session);
+ free(path);
+ syslog(LOG_ERR, "smbrdr: (tcon) failed connecting to %s", path);
+ return (0);
+ }
+
+ free(path);
+ (void) mutex_unlock(&netuse->mtx);
+ smbrdr_session_unlock(session);
+ return (netuse->tid);
+}
+
+
+/*
+ * smbrdr_smb_tcon
+ *
+ * This message requests a share (tree connect) request to the server
+ * associated with the session. The password is not relevant here if
+ * the session was establishment using setup_andx. The outgoing tid
+ * will be ignored - a valid one will be returned by the server.
+ *
+ * Returns 0 on success. Otherwise returns a -ve error code.
+ */
+static int
+smbrdr_smb_tcon(struct sdb_session *session, struct sdb_netuse *netuse,
+ char *path, int path_len)
+{
+ smb_hdr_t smb_hdr;
+ smbrdr_handle_t srh;
+ smb_msgbuf_t *mb;
+ unsigned short flags;
+ char *password;
+ unsigned short password_len;
+ char *service;
+ unsigned service_len;
+ unsigned short data_bytes;
+ DWORD status;
+ int rc;
+
+ status = smbrdr_request_init(&srh, SMB_COM_TREE_CONNECT_ANDX,
+ session, &session->logon, 0);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrTcon: %s", xlate_nt_status(status));
+ return (-1);
+ }
+
+ mb = &srh.srh_mbuf;
+
+ flags = 0; /* no flags */
+ password = "";
+ password_len = 1; /* including nul */
+ service = "?????"; /* does this work? */
+ service_len = strlen(service);
+
+ /*
+ * Calculate the BCC. The path is in UNICODE
+ * but the service is in ASCII.
+ */
+ data_bytes = password_len;
+ data_bytes += path_len + 1;
+ data_bytes += service_len + 1;
+
+ rc = smb_msgbuf_encode(mb, "bb1.wwww#cus",
+ 4, /* smb_wct */
+ 0xff, /* AndXCommand (none) */
+ 0xffff, /* AndXOffset */
+ flags, /* Flags */
+ password_len, /* PasswordLength */
+ data_bytes+1, /* smb_bcc */
+ password_len, password, /* Password */
+ path, /* Path */
+ service); /* Service */
+
+ if (rc <= 0) {
+ syslog(LOG_ERR, "smbrdr_smb_tcon: encode failed");
+ smbrdr_handle_free(&srh);
+ return (-1);
+ }
+
+ status = smbrdr_exchange(&srh, &smb_hdr, 0);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrTcon: %s", xlate_nt_status(status));
+ rc = -1;
+ } else {
+ rc = 0;
+ }
+
+ netuse->tid = smb_hdr.tid;
+ netuse->state = SDB_NSTATE_CONNECTED;
+ smbrdr_handle_free(&srh);
+ return (rc);
+}
+
+
+/*
+ * smbrdr_netuse_logoff
+ *
+ * This function can be used when closing a session to ensure that all
+ * shares associated with the specified session are disconnected and
+ * the resources released. We also notify the pipe interface to ensure
+ * that any pipes associated with this share are also closed. This
+ * function silently ignores errors because we have no idea what state
+ * the session is in. We are more interested in releasing resources.
+ */
+void
+smbrdr_netuse_logoff(unsigned short uid)
+{
+ struct sdb_netuse *netuse;
+ int i;
+
+ for (i = 0; i < N_NETUSE_TABLE; ++i) {
+ netuse = &netuse_table[i];
+ (void) mutex_lock(&netuse->mtx);
+ if (netuse->uid == uid)
+ (void) smbrdr_smb_tdcon(netuse);
+ (void) mutex_unlock(&netuse->mtx);
+ }
+}
+
+int
+smbrdr_tree_disconnect(unsigned short tid)
+{
+ struct sdb_netuse *netuse;
+ int rc = -1;
+
+ netuse = smbrdr_netuse_get(tid);
+ if (netuse) {
+ (void) smbrdr_smb_tdcon(netuse);
+ smbrdr_netuse_put(netuse);
+ rc = 0;
+ }
+
+ return (rc);
+}
+
+/*
+ * smbrdr_smb_tdcon
+ *
+ * Disconnect a share. This message informs the server that we no longer
+ * wish to access the resource specified by tid, obtained via a prior
+ * mlsvc_tree_connect. The tid is passed in the SMB header so the setup
+ * for this call is very straightforward.
+ *
+ * Returns 0 on success. Otherwise returns a -ve error code.
+ */
+static int
+smbrdr_smb_tdcon(struct sdb_netuse *netuse)
+{
+ struct sdb_session *session;
+ smbrdr_handle_t srh;
+ smb_hdr_t smb_hdr;
+ DWORD status;
+ int rc;
+
+ netuse->state = SDB_NSTATE_DISCONNECTING;
+ smbrdr_ofile_end_of_share(netuse->tid);
+
+ if ((session = netuse->session) == 0) {
+ smbrdr_netuse_clear(netuse);
+ return (0);
+ }
+
+ if ((session->state != SDB_SSTATE_NEGOTIATED) &&
+ (session->state != SDB_SSTATE_DISCONNECTING)) {
+ smbrdr_netuse_clear(netuse);
+ return (0);
+ }
+
+ status = smbrdr_request_init(&srh, SMB_COM_TREE_DISCONNECT,
+ session, &session->logon, netuse);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "smbrdr: (tdcon) %s", xlate_nt_status(status));
+ /* should we clear here? */
+ smbrdr_netuse_clear(netuse);
+ return (-1);
+ }
+
+ rc = smb_msgbuf_encode(&srh.srh_mbuf, "bw.", 0, 0);
+ if (rc < 0) {
+ syslog(LOG_ERR, "smbrdr: (tdcon) encode failed");
+ smbrdr_handle_free(&srh);
+ /* should we clear here? */
+ smbrdr_netuse_clear(netuse);
+ return (rc);
+ }
+
+ status = smbrdr_exchange(&srh, &smb_hdr, 0);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "smbrdr: (tdcon) %s", xlate_nt_status(status));
+ rc = -1;
+ } else {
+ rc = 0;
+ }
+
+ smbrdr_handle_free(&srh);
+ smbrdr_netuse_clear(netuse);
+ return (rc);
+}
+
+
+/*
+ * smbrdr_netuse_alloc
+ *
+ * Find a slot in the table for a share. Each share is associated with
+ * a session and assigned a local drive letter name and a sharename.
+ * If a slot is already allocated to the specified share, a pointer to
+ * it is returned. Otherwise we allocate and initialize a new slot in
+ * the table. If the table is full, a null pointer will be returned.
+ *
+ * IMPORTANT! the returned netuse will be locked caller has to unlock
+ * it after it's done with the pointer.
+ */
+static struct sdb_netuse *
+smbrdr_netuse_alloc(struct sdb_session *session, char *sharename)
+{
+ struct sdb_netuse *netuse;
+ int i;
+
+ if (session == 0 || sharename == 0) {
+ syslog(LOG_ERR, "smbrdr: (tcon) invalid arg");
+ return (0);
+ }
+
+ for (i = 0; i < N_NETUSE_TABLE; ++i) {
+ netuse = &netuse_table[i];
+
+ (void) mutex_lock(&netuse->mtx);
+ if (netuse->state == SDB_NSTATE_START) {
+ netuse->session = session;
+ netuse->letter = i + '0';
+ netuse->sid = session->sid;
+ netuse->uid = session->logon.uid;
+ netuse->tid = 0;
+ (void) strcpy(netuse->share, sharename);
+ netuse->state = SDB_NSTATE_INIT;
+ return (netuse);
+ }
+ (void) mutex_unlock(&netuse->mtx);
+ }
+
+ syslog(LOG_WARNING, "smbrdr: (tcon) table full");
+ return (0);
+}
+
+/*
+ * smbrdr_netuse_put
+ *
+ * Unlock given netuse structure.
+ */
+void
+smbrdr_netuse_put(struct sdb_netuse *netuse)
+{
+ (void) mutex_unlock(&netuse->mtx);
+}
+
+/*
+ * smbrdr_netuse_get
+ *
+ * Find the netuse structure associated with the specified tid and
+ * return a pointer to it. A null pointer is returned if no match
+ * can be found.
+ *
+ * IMPORTANT! the returned netuse will be locked caller has to unlock
+ * it after it's done with the pointer.
+ */
+struct sdb_netuse *
+smbrdr_netuse_get(int tid)
+{
+ struct sdb_session *session;
+ struct sdb_netuse *netuse;
+ int i;
+
+ for (i = 0; i < N_NETUSE_TABLE; ++i) {
+ netuse = &netuse_table[i];
+
+ (void) mutex_lock(&netuse->mtx);
+
+ if (netuse->tid == tid) {
+ session = netuse->session;
+
+ /*
+ * status check:
+ * make sure all the structures are in the right state
+ */
+ if (session &&
+ (netuse->state == SDB_NSTATE_CONNECTED) &&
+ (session->logon.state == SDB_LSTATE_SETUP) &&
+ (session->state == SDB_SSTATE_NEGOTIATED)) {
+ /* sanity check */
+ if ((netuse->sid == session->sid) &&
+ (netuse->uid == session->logon.uid))
+ return (netuse);
+ else
+ /* invalid structure */
+ smbrdr_netuse_clear(netuse);
+ }
+
+ }
+
+ (void) mutex_unlock(&netuse->mtx);
+ }
+
+ syslog(LOG_WARNING, "smbrdr: (lookup) no such TID %d", tid);
+ return (0);
+}
+
+/*
+ * smbrdr_dump_netuse
+ */
+void
+smbrdr_dump_netuse()
+{
+ struct sdb_netuse *netuse;
+ int i;
+
+ for (i = 0; i < N_NETUSE_TABLE; ++i) {
+ netuse = &netuse_table[i];
+ (void) mutex_lock(&netuse->mtx);
+ if (netuse->session) {
+ syslog(LOG_DEBUG, "tree[%d]: %s (tid=%d)", i,
+ netuse->share, netuse->tid);
+ syslog(LOG_DEBUG, "tree[%d]: session(%d), user(%d)",
+ i, netuse->session->sock, netuse->uid);
+ }
+ (void) mutex_unlock(&netuse->mtx);
+ }
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_read_andx.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_read_andx.c
new file mode 100644
index 0000000000..ef90fa79ac
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_read_andx.c
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB ReadX functions to support MLRPC.
+ */
+
+#include <syslog.h>
+#include <strings.h>
+
+#include <smbsrv/libsmbrdr.h>
+
+#include <smbsrv/netbios.h>
+#include <smbsrv/ntstatus.h>
+#include <smbrdr.h>
+
+#define SMBRDR_READX_RSP_OVERHEAD \
+ (NETBIOS_HDR_SZ + SMB_HEADER_LEN + sizeof (smb_read_andx_rsp_t))
+#define SMBRDR_READX_RSP_DATA_MAXLEN \
+ (SMBRDR_REQ_BUFSZ - SMBRDR_READX_RSP_OVERHEAD)
+
+static int smbrdr_decode_readx_rsp(smb_msgbuf_t *, char *, unsigned,
+ smb_read_andx_rsp_t *);
+
+static void smbrdr_dump_readx_rsp(smb_read_andx_rsp_t *);
+
+/*
+ * smbrdr_rpc_readx
+ *
+ * Send SMB_COM_READ_ANDX request.
+ */
+int
+smbrdr_rpc_readx(int fid, char *in_buf, int in_len)
+{
+ struct sdb_netuse *netuse;
+ struct sdb_ofile *ofile;
+ smb_read_andx_rsp_t rsp;
+ smbrdr_handle_t srh;
+ smb_msgbuf_t *mb;
+ DWORD status;
+ int rc, max_return;
+
+ if ((ofile = smbrdr_ofile_get(fid)) == 0)
+ return (-1);
+
+ netuse = ofile->netuse;
+
+ status = smbrdr_request_init(&srh, SMB_COM_READ_ANDX,
+ netuse->session, &netuse->session->logon, netuse);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrReadAndx: %s", xlate_nt_status(status));
+ smbrdr_ofile_put(ofile);
+ return (-1);
+ }
+
+ mb = &(srh.srh_mbuf);
+
+ max_return = (in_len > SMBRDR_READX_RSP_DATA_MAXLEN) ?
+ SMBRDR_READX_RSP_DATA_MAXLEN : in_len;
+
+ rc = smb_msgbuf_encode(mb, "bbbwwlwwlwlw",
+ 12, /* Count of parameter words */
+ 0xFF, /* Secondary (X) command; 0xFF = none */
+ 0, /* Reserved (must be 0) */
+ 0, /* Offset to next command WordCount */
+ ofile->fid, /* File handle */
+ 0, /* Offset in file to begin read */
+ max_return, /* Max number of bytes to return */
+ /* Reserved for obsolescent requests [0 = non-blocking read] */
+ max_return,
+ /*
+ * High 16 bits of MaxCount if CAP_LARGE_READX;
+ * else MUST BE ZERO
+ */
+ 0,
+ max_return, /* Reserved for obsolescent requests */
+ /* Upper 32 bits of offset (only if WordCount is 12) */
+ 0,
+ 0); /* Count of data bytes = 0 */
+
+ if (rc < 0) {
+ syslog(LOG_ERR, "SmbrdrReadAndx: smbrdr_prep_readx_req failed");
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_put(ofile);
+ return (rc);
+ }
+
+ smbrdr_lock_transport();
+
+ status = smbrdr_send(&srh);
+ if (status != NT_STATUS_SUCCESS) {
+ smbrdr_unlock_transport();
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_put(ofile);
+ syslog(LOG_ERR, "SmbrdrReadAndx: send failed");
+ return (-1);
+ }
+
+ status = smbrdr_rcv(&srh, 1);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrReadAndx: nb_rcv failed");
+ smbrdr_unlock_transport();
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_put(ofile);
+ return (-1);
+ }
+
+ rc = smbrdr_decode_readx_rsp(mb, in_buf, in_len, &rsp);
+
+ if (rc < 0) {
+ syslog(LOG_ERR, "SmbrdrReadAndx: read decode failure!");
+ smbrdr_unlock_transport();
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_put(ofile);
+ return (-1);
+ }
+
+ smbrdr_unlock_transport();
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_put(ofile);
+
+ return ((rc < 0) ? rc : rsp.DataLength);
+}
+
+static void
+smbrdr_dump_readx_rsp(smb_read_andx_rsp_t *rsp)
+{
+
+ syslog(LOG_DEBUG, "[SmbReadX Rsp] WordCount:%x,AndXCmd:%x,"
+ " AndXReserved:%x, AndXOffset:%d",
+ rsp->WordCount, rsp->AndXCmd, rsp->AndXReserved, rsp->AndXOffset);
+
+ syslog(LOG_DEBUG, "[SmbReadX Rsp] Remaining:%d, Mode:%d, Reserved:%x, "
+ "DataLen:%d, DataOffset:%d, ByteCount: %d",
+ rsp->Remaining, rsp->DataCompactionMode, rsp->Reserved,
+ rsp->DataLength, rsp->DataOffset, rsp->ByteCount);
+}
+
+/*
+ * smbrdr_decode_readx_rsp
+ *
+ * Decode the response from the SMB_COM_READ_ANDX request. The payload
+ * of the response is appended to the end of SmbTransact response data
+ * in the MLRPC receive buffer.
+ *
+ * Return -1 on error, 0 upon success.
+ */
+static int
+smbrdr_decode_readx_rsp(smb_msgbuf_t *mb,
+ char *in,
+ unsigned in_len,
+ smb_read_andx_rsp_t *rsp)
+{
+ int rc;
+
+ rc = smb_msgbuf_decode(mb, "bbbwwwwwwlwwww",
+ &rsp->WordCount,
+ &rsp->AndXCmd,
+ &rsp->AndXReserved,
+ &rsp->AndXOffset,
+ &rsp->Remaining,
+ &rsp->DataCompactionMode,
+ &rsp->Reserved,
+ &rsp->DataLength,
+ &rsp->DataOffset,
+ &rsp->DataLengthHigh,
+ &rsp->Reserved2[0],
+ &rsp->Reserved2[1],
+ &rsp->Reserved2[2],
+ &rsp->ByteCount);
+
+ if (rc <= 0)
+ return (-1);
+
+ smbrdr_dump_readx_rsp(rsp);
+
+ /* it should never happen, but check anyway */
+ if (rsp->DataLength > in_len)
+ return (-1);
+
+ bcopy(mb->base + rsp->DataOffset, in, rsp->DataLength);
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_rpcpipe.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_rpcpipe.c
new file mode 100644
index 0000000000..b89eddf275
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_rpcpipe.c
@@ -0,0 +1,518 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Functions to open and close named pipes. These functions are
+ * described in the CIFS 1.0 Protocol Specification (December 19, 1997).
+ */
+
+#include <alloca.h>
+#include <pthread.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <synch.h>
+
+#include <smbsrv/libsmbrdr.h>
+
+#include <smbsrv/ntstatus.h>
+#include <smbrdr.h>
+
+static int smbrdr_smb_close(struct sdb_ofile *ofile);
+static DWORD smbrdr_smb_ntcreate(struct sdb_ofile *ofile);
+static struct sdb_ofile *smbrdr_ofile_alloc(struct sdb_netuse *netuse,
+ char *name);
+
+static void
+smbrdr_ofile_clear(struct sdb_ofile *ofile)
+{
+ bzero(ofile, sizeof (struct sdb_ofile) - sizeof (mutex_t));
+}
+
+static void
+smbrdr_ofile_free(struct sdb_ofile *ofile)
+{
+ smbrdr_ofile_clear(ofile);
+ (void) mutex_unlock(&ofile->mtx);
+}
+
+
+/*
+ * The ofile table.
+ */
+static struct sdb_ofile ofile_table[N_OFILE_TABLE];
+
+static int mlsvc_pipe_recon_wait = 50;
+static int mlsvc_pipe_recon_tries = 3;
+
+
+/*
+ * mlsvc_open_pipe
+ *
+ * Open an RPC pipe on hostname. On success, return the fid. Otherwise
+ * returns a -ve error code.
+ */
+int
+mlsvc_open_pipe(char *hostname, char *domain, char *username, char *pipename)
+{
+ struct sdb_netuse *netuse;
+ struct sdb_ofile *ofile;
+ unsigned short tid;
+ DWORD status;
+ int retry;
+ struct timespec st;
+
+ tid = mlsvc_tree_connect(hostname, username, "IPC$");
+ if (tid == 0) {
+ syslog(LOG_ERR, "smbrdr: (open) %s %s %s %s %s",
+ hostname, domain, username, pipename,
+ xlate_nt_status(NT_STATUS_UNEXPECTED_NETWORK_ERROR));
+ return (-1);
+ }
+
+ netuse = smbrdr_netuse_get(tid);
+ if (netuse == 0) {
+ syslog(LOG_ERR, "smbrdr: (open) %s %s %s %s %s",
+ hostname, domain, username, pipename,
+ xlate_nt_status(NT_STATUS_CONNECTION_INVALID));
+ return (-1);
+ }
+
+ if ((ofile = smbrdr_ofile_alloc(netuse, pipename)) == 0) {
+ syslog(LOG_ERR, "smbrdr: (open) %s %s %s %s %s",
+ hostname, domain, username, pipename,
+ xlate_nt_status(NT_STATUS_INSUFFICIENT_RESOURCES));
+ smbrdr_netuse_put(netuse);
+ return (-1);
+ }
+
+ status = NT_STATUS_OPEN_FAILED;
+
+ for (retry = 0; retry < mlsvc_pipe_recon_tries; retry++) {
+ status = smbrdr_smb_ntcreate(ofile);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ (void) mutex_unlock(&ofile->mtx);
+ smbrdr_netuse_put(netuse);
+ return (ofile->fid);
+
+ case NT_STATUS_PIPE_NOT_AVAILABLE:
+ case NT_STATUS_PIPE_BUSY:
+ /*
+ * The server might return this error if it is
+ * temporarily busy or unable to create a pipe.
+ * We wait here before trying again to see if
+ * the pipe becomes available.
+ */
+ st.tv_sec = 0;
+ st.tv_nsec = mlsvc_pipe_recon_wait * 1000000;
+ (void) nanosleep(&st, 0);
+ break;
+
+ default:
+ /*
+ * Something else went wrong: no more retries.
+ */
+ retry = mlsvc_pipe_recon_tries;
+ break;
+ }
+ }
+
+ syslog(LOG_DEBUG, "smbrdr: (open) %s %s %s %s %s",
+ hostname, domain, username, pipename,
+ xlate_nt_status(status));
+ smbrdr_ofile_free(ofile);
+ smbrdr_netuse_put(netuse);
+ return (-1);
+}
+
+/*
+ * mlsvc_close_pipe
+ *
+ * Close the named pipe represented by fid.
+ */
+int
+mlsvc_close_pipe(int fid)
+{
+ struct sdb_ofile *ofile;
+ unsigned short tid;
+ int rc;
+
+ if ((ofile = smbrdr_ofile_get(fid)) == 0) {
+ syslog(LOG_ERR, "mlsvc_close_pipe: unknown file (%d)", fid);
+ return (-1);
+ }
+
+ tid = ofile->tid;
+ rc = smbrdr_smb_close(ofile);
+ smbrdr_ofile_put(ofile);
+
+ if (rc == 0)
+ (void) smbrdr_tree_disconnect(tid);
+
+ return (rc);
+}
+
+/*
+ * smbrdr_ofile_put
+ *
+ * Unlock given ofile structure.
+ */
+void
+smbrdr_ofile_put(struct sdb_ofile *ofile)
+{
+ if (ofile)
+ (void) mutex_unlock(&ofile->mtx);
+}
+
+/*
+ * smbrdr_ofile_get
+ *
+ * Locate the ofile for the specified fid. Just to be safe, ensure that
+ * the netuse pointer is valid. Return a pointer to the ofile structure.
+ * Return a null pointer if a valid ofile cannot be found.
+ */
+struct sdb_ofile *
+smbrdr_ofile_get(int fid)
+{
+ struct sdb_session *session;
+ struct sdb_netuse *netuse;
+ struct sdb_ofile *ofile;
+ int i;
+
+ for (i = 0; i < N_OFILE_TABLE; ++i) {
+ ofile = &ofile_table[i];
+
+ (void) mutex_lock(&ofile->mtx);
+
+ if (ofile->fid == fid) {
+ session = ofile->session;
+ netuse = ofile->netuse;
+
+ /*
+ * status check:
+ * make sure all the structures are in the right state
+ */
+ if (session && netuse &&
+ (ofile->state == SDB_FSTATE_OPEN) &&
+ (netuse->state == SDB_NSTATE_CONNECTED) &&
+ (session->logon.state == SDB_LSTATE_SETUP) &&
+ (session->state == SDB_SSTATE_NEGOTIATED)) {
+ /* sanity check */
+ if ((ofile->sid == session->sid) &&
+ (ofile->uid == session->logon.uid) &&
+ (ofile->tid == netuse->tid)) {
+ return (ofile);
+ } else {
+ /* invalid structure */
+ smbrdr_ofile_clear(ofile);
+ }
+ }
+ }
+
+ (void) mutex_unlock(&ofile->mtx);
+ }
+
+ syslog(LOG_WARNING, "smbrdr: (lookup) no such FID %d", fid);
+ return (0);
+}
+
+/*
+ * smbrdr_ofile_end_of_share
+ *
+ * This function can be used when closing a share to ensure that all
+ * ofiles resources are released. Don't call mlsvc_close_pipe because
+ * that will call mlsvc_smb_tdcon and we don't know what state
+ * the share is in. The server will probably close all files anyway.
+ * We are more interested in releasing the ofile resources.
+ */
+void
+smbrdr_ofile_end_of_share(unsigned short tid)
+{
+ struct sdb_ofile *ofile;
+ int i;
+
+ for (i = 0; i < N_OFILE_TABLE; ++i) {
+ ofile = &ofile_table[i];
+ (void) mutex_lock(&ofile->mtx);
+ if (ofile->tid == tid)
+ (void) smbrdr_smb_close(ofile);
+ (void) mutex_unlock(&ofile->mtx);
+ }
+}
+
+/*
+ * smbrdr_dump_ofiles
+ *
+ * Dump the open files table.
+ */
+void
+smbrdr_dump_ofiles()
+{
+ struct sdb_ofile *ofile;
+ struct sdb_netuse *netuse;
+ int i;
+
+ for (i = 0; i < N_OFILE_TABLE; ++i) {
+ ofile = &ofile_table[i];
+ (void) mutex_lock(&ofile->mtx);
+ netuse = ofile->netuse;
+
+ if (netuse) {
+ syslog(LOG_DEBUG, "file[%d]: %s (fid=%d)", i,
+ ofile->path, ofile->fid);
+ syslog(LOG_DEBUG,
+ "file[%d]: session(%d), user(%d), tree(%d)",
+ i, netuse->session->sock, netuse->uid,
+ netuse->tid);
+ }
+ (void) mutex_unlock(&ofile->mtx);
+ }
+}
+
+/*
+ * Private Functions
+ */
+
+/*
+ * smbrdr_smb_close
+ *
+ * Send SMBClose request for the given open file.
+ */
+static int
+smbrdr_smb_close(struct sdb_ofile *ofile)
+{
+ struct sdb_session *session;
+ struct sdb_netuse *netuse;
+ struct sdb_logon *logon;
+ smbrdr_handle_t srh;
+ smb_hdr_t smb_hdr;
+ DWORD status;
+ int fid;
+ int rc;
+
+ if (ofile == 0)
+ return (0);
+
+ ofile->state = SDB_FSTATE_CLOSING;
+
+ if ((session = ofile->session) == 0) {
+ smbrdr_ofile_clear(ofile);
+ return (0);
+ }
+
+ if ((session->state != SDB_SSTATE_NEGOTIATED) &&
+ (session->state != SDB_SSTATE_DISCONNECTING)) {
+ smbrdr_ofile_clear(ofile);
+ return (0);
+ }
+
+ fid = ofile->fid;
+
+ netuse = ofile->netuse;
+ logon = &session->logon;
+
+ status = smbrdr_request_init(&srh, SMB_COM_CLOSE,
+ session, logon, netuse);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrClose: %s", xlate_nt_status(status));
+ smbrdr_ofile_clear(ofile);
+ return (-1);
+ }
+
+ rc = smb_msgbuf_encode(&srh.srh_mbuf,
+ "(wct)b (fid)w (lwrtm)l (bcc)w (pad).",
+ 3, /* WordCount */
+ fid, /* Fid */
+ 0x00000000ul, /* LastWriteTime */
+ 0); /* ByteCount */
+
+ if (rc <= 0) {
+ syslog(LOG_ERR, "SmbrdrClose: encode failed");
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_clear(ofile);
+ return (-1);
+ }
+
+ status = smbrdr_exchange(&srh, &smb_hdr, 0);
+ if (status != NT_STATUS_SUCCESS)
+ syslog(LOG_ERR, "SmbrdrClose: %s", xlate_nt_status(status));
+
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_clear(ofile);
+ return (0);
+}
+
+/*
+ * smbrdr_ofile_alloc
+ *
+ * Allocate an ofile for the specified name. File info is associated
+ * with a share so we need a valid share before calling this function.
+ * If a slot is already allocated to the specified file, a pointer to
+ * that slot is returned. Otherwise we allocate and initialize a new
+ * slot in the table. If the table is full, a null pointer will be
+ * returned.
+ */
+static struct sdb_ofile *
+smbrdr_ofile_alloc(struct sdb_netuse *netuse, char *name)
+{
+ struct sdb_ofile *ofile;
+ int i;
+
+ for (i = 0; i < N_OFILE_TABLE; ++i) {
+ ofile = &ofile_table[i];
+
+ (void) mutex_lock(&ofile->mtx);
+ if (ofile->netuse == 0) {
+
+ ofile->session = netuse->session;
+ ofile->netuse = netuse;
+ ofile->sid = netuse->session->sid;
+ ofile->uid = netuse->session->logon.uid;
+ ofile->tid = netuse->tid;
+ ofile->fid = 0;
+ (void) strcpy(ofile->path, name);
+ ofile->state = SDB_FSTATE_INIT;
+ return (ofile);
+ }
+
+ (void) mutex_unlock(&ofile->mtx);
+ }
+
+ syslog(LOG_WARNING, "smbrdr: (open) table full");
+ return (0);
+}
+
+/*
+ * smbrdr_smb_ntcreate
+ *
+ * This will do an SMB_COM_NT_CREATE_ANDX with lots of default values.
+ * All of the underlying session and share data should already be set
+ * up before we get here. If everything works we'll get a valid fid.
+ */
+static DWORD
+smbrdr_smb_ntcreate(struct sdb_ofile *ofile)
+{
+ struct sdb_logon *logon;
+ struct sdb_netuse *netuse;
+ struct sdb_session *sess;
+ smbrdr_handle_t srh;
+ smb_hdr_t smb_hdr;
+ smb_msgbuf_t *mb;
+ char *path;
+ unsigned path_len;
+ int data_bytes;
+ int rc;
+ unsigned short fid;
+ int null_size;
+ DWORD status;
+
+ netuse = ofile->netuse;
+ sess = netuse->session;
+ logon = &sess->logon;
+
+ /*
+ * If this was a general purpose interface, we should support
+ * full UNC semantics but we only use this for RPC over named
+ * pipes with well-known endpoints.
+ */
+ path_len = strlen(ofile->path) + 2;
+ path = alloca(path_len);
+
+ if (ofile->path[0] != '\\')
+ (void) snprintf(path, path_len, "\\%s", ofile->path);
+ else
+ (void) strcpy(path, ofile->path);
+
+ if (sess->remote_caps & CAP_UNICODE) {
+ path_len = mts_wcequiv_strlen(path);
+ null_size = sizeof (mts_wchar_t);
+ } else {
+ path_len = strlen(path);
+ null_size = sizeof (char);
+ }
+
+ syslog(LOG_DEBUG, "SmbRdrNtCreate: %d %s", path_len, path);
+
+ status = smbrdr_request_init(&srh, SMB_COM_NT_CREATE_ANDX,
+ sess, logon, netuse);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrNtCreate: %s", xlate_nt_status(status));
+ return (NT_STATUS_INVALID_PARAMETER_1);
+ }
+
+ mb = &srh.srh_mbuf;
+
+ data_bytes = path_len + null_size;
+
+ rc = smb_msgbuf_encode(mb,
+ "(wct)b (andx)b1.w (resv). (nlen)w (flg)l"
+ "(rdf)l (dacc)l (allo)q (efa)l (shr)l (cdisp)l (copt)l (impl)l"
+ "(secf)b (bcc)w (name)u",
+ 24, /* smb_wct */
+ 0xff, /* AndXCommand (none) */
+ 0x0000, /* AndXOffset */
+ path_len, /* Unicode NameLength */
+ 0x00000006ul, /* Flags (oplocks) */
+ 0, /* RootDirectoryFid */
+ 0x0002019Ful, /* DesiredAccess */
+ 0x0ull, /* AllocationSize */
+ 0x00000000ul, /* ExtFileAttributes */
+ 0x00000003ul, /* ShareAccess (RW) */
+ 0x00000001ul, /* CreateDisposition (OpenExisting) */
+ 0x00000000ul, /* CreateOptions */
+ 0x00000002ul, /* ImpersonationLevel */
+ 0x01u, /* SecurityFlags */
+ data_bytes, /* smb_bcc */
+ path); /* Name */
+
+ if (rc <= 0) {
+ smbrdr_handle_free(&srh);
+ return (NT_STATUS_INVALID_PARAMETER_1);
+ }
+
+ status = smbrdr_exchange(&srh, &smb_hdr, 0);
+ if (status != NT_STATUS_SUCCESS) {
+ smbrdr_handle_free(&srh);
+ return (NT_SC_VALUE(status));
+ }
+
+ rc = smb_msgbuf_decode(mb, "(wct). (andx)4. (opl)1. (fid)w", &fid);
+ if (rc <= 0) {
+ smbrdr_handle_free(&srh);
+ return (NT_STATUS_INVALID_PARAMETER_2);
+ }
+
+ ofile->fid = fid;
+ ofile->state = SDB_FSTATE_OPEN;
+ syslog(LOG_DEBUG, "SmbRdrNtCreate: fid=%d", ofile->fid);
+ smbrdr_handle_free(&srh);
+ return (NT_STATUS_SUCCESS);
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c
new file mode 100644
index 0000000000..535ad537d9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c
@@ -0,0 +1,889 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the netbios and SMB negotiation, connect and
+ * disconnect interface.
+ */
+
+#include <unistd.h>
+#include <syslog.h>
+#include <synch.h>
+#include <string.h>
+#include <strings.h>
+#include <pthread.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <netdb.h>
+
+#include <smbsrv/libsmbrdr.h>
+#include <smbsrv/netbios.h>
+#include <smbsrv/cifs.h>
+
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/mlsvc.h>
+#include <smbrdr.h>
+#include <smbrdr_ipc_util.h>
+
+
+static uint16_t smbrdr_ports[] = {
+ SMB_SRVC_TCP_PORT,
+ SSN_SRVC_TCP_PORT
+};
+
+static int smbrdr_nports = sizeof (smbrdr_ports) / sizeof (smbrdr_ports[0]);
+
+/*
+ * Pointer to the PDC location interface.
+ * To be set up by SMB when it loads.
+ */
+static mlsvc_locate_pdc_t mlsvc_locate_pdc;
+
+/*
+ * This is a temporary hack to stop the DC from closing a session
+ * due to inactivity.
+ */
+#define MLSVC_SESSION_FORCE_KEEPALIVE 10
+
+/*
+ * This is the session data table.
+ *
+ * The rwlock synchronizes access to the session table
+ *
+ * The mutex is to make session lookup and create atomic
+ * so we don't end up with two sessions with the same
+ * system.
+ */
+static struct sdb_session session_table[MLSVC_DOMAIN_MAX];
+static mutex_t smbrdr_screate_mtx;
+static unsigned int session_id = 0;
+
+static struct sdb_session *smbrdr_session_init(smb_ntdomain_t *di);
+static int smbrdr_trnsprt_connect(struct sdb_session *, uint16_t);
+static int smbrdr_session_connect(smb_ntdomain_t *di);
+static int smbrdr_smb_negotiate(struct sdb_session *session);
+static int smbrdr_smb_echo(struct sdb_session *session);
+static void smbrdr_session_disconnect(struct sdb_session *session, int cleanup);
+static int smbrdr_locate_dc(char *domain);
+
+static void
+smbrdr_session_clear(struct sdb_session *session)
+{
+ bzero(session, sizeof (struct sdb_session) - sizeof (rwlock_t));
+}
+
+/*
+ * mlsvc_install_pdc_cb
+ *
+ * Function to be called by SMB initialization code to set up a
+ * callback to the PDC location interface.
+ */
+void
+mlsvc_install_pdc_cb(mlsvc_locate_pdc_t locate_pdc_cb)
+{
+ mlsvc_locate_pdc = locate_pdc_cb;
+}
+
+/*
+ * mlsvc_locate_domain_controller
+ *
+ * Locate a domain controller. Note that this may close an existing
+ * connection to the current domain controller.
+ */
+int
+mlsvc_locate_domain_controller(char *domain)
+{
+ if (mlsvc_locate_pdc)
+ return (mlsvc_locate_pdc(domain));
+
+ return (0);
+}
+
+/*
+ * Entry pointy for smbrdr initialization.
+ */
+void
+smbrdr_init(void)
+{
+ smbrdr_ipc_init();
+}
+
+/*
+ * mlsvc_disconnect
+ *
+ * Disconnects the session with given server.
+ */
+void
+mlsvc_disconnect(char *server)
+{
+ struct sdb_session *session;
+
+ session = smbrdr_session_lock(server, 0, SDB_SLCK_WRITE);
+ if (session) {
+ smbrdr_session_disconnect(session, 0);
+ smbrdr_session_unlock(session);
+ }
+}
+
+/*
+ * smbrdr_negotiate
+ *
+ * Negotiate a session with a domain controller in the specified domain.
+ * The domain must be one of values from the smbinfo that indicates the
+ * resource domain or the account domain.
+ *
+ * If a session already exists, we can use that one. Otherwise we create
+ * a new one. This sets up the session key and session security info that
+ * we'll need later to authenticate the user. The session security info
+ * is returned to support the SMB client pass-through authentication
+ * interface.
+ *
+ * Returns 0 on success, otherwise -1.
+ */
+int
+smbrdr_negotiate(char *domain_name)
+{
+ struct sdb_session *session = 0;
+ smb_ntdomain_t *di;
+ int retry = 1;
+ int res = 0;
+
+ if ((di = smb_getdomaininfo(0)) == 0) {
+ /*
+ * Attempting to locate a domain controller
+ * will shutdown an existing PDC connection.
+ */
+ (void) smbrdr_locate_dc(domain_name);
+ di = smb_getdomaininfo(0);
+ }
+
+ if (di == 0) {
+ syslog(LOG_ERR, "smbrdr: negotiate (cannot access domain)");
+ return (-1);
+ }
+
+ /*
+ * The mutex is to make session lookup and create atomic
+ * so we don't end up with two sessions with the same
+ * server.
+ */
+ (void) mutex_lock(&smbrdr_screate_mtx);
+ while (retry > 0) {
+ session = smbrdr_session_lock(di->server, 0, SDB_SLCK_WRITE);
+ if (session != 0) {
+ if (nb_keep_alive(session->sock) == 0) {
+ /* session is good, use it */
+ smbrdr_session_unlock(session);
+ break;
+ } else {
+ /* stale session */
+ session->state = SDB_SSTATE_STALE;
+ smbrdr_session_unlock(session);
+ }
+ }
+
+ if (smbrdr_session_connect(di) != 0) {
+ if (retry > 0) {
+ /* Do we really need to do this here? */
+ (void) smbrdr_locate_dc(domain_name);
+ di = smb_getdomaininfo(0);
+ if (di == 0) {
+ syslog(LOG_ERR, "smbrdr: negotiate"
+ " (cannot access domain)");
+ res = -1;
+ break;
+ }
+ retry--;
+ }
+ } else {
+ /* session is created */
+ retry = 0;
+ }
+ }
+ (void) mutex_unlock(&smbrdr_screate_mtx);
+
+ return (res);
+}
+
+/*
+ * smbrdr_session_connect
+ *
+ * This is the entry point for establishing an SMB connection to a
+ * domain controller. A session structure is allocated, a netbios
+ * session is set up and the SMB protocol is negotiated. If this is
+ * successful, the returned session structure can be used to logon
+ * to the the domain. A null pointer is returned if the connect fails.
+ */
+static int
+smbrdr_session_connect(smb_ntdomain_t *di)
+{
+ struct sdb_session *session;
+ uint16_t port;
+ int rc = 0;
+
+ /*
+ * smbrdr_session_init() will lock the session so that it wouldn't
+ * be accessible until it's established otherwise another thread
+ * might get access to a session which is not fully established.
+ */
+ if ((session = smbrdr_session_init(di)) == 0) {
+ syslog(LOG_ERR, "smbrdr: session init failed");
+ return (-1);
+ }
+
+ for (port = 0; port < smbrdr_nports; ++port) {
+ syslog(LOG_DEBUG, "smbrdr: trying port %d",
+ smbrdr_ports[port]);
+
+ rc = smbrdr_trnsprt_connect(session, smbrdr_ports[port]);
+
+ if (rc == 0) {
+ syslog(LOG_DEBUG, "smbrdr: connected port %d",
+ smbrdr_ports[port]);
+ break;
+ }
+ }
+
+ if (rc < 0) {
+ smbrdr_session_clear(session);
+ smbrdr_session_unlock(session);
+ syslog(LOG_ERR, "smbrdr: NBT/TCP connect failed");
+ return (-1);
+ }
+
+ if (smbrdr_smb_negotiate(session) < 0) {
+ (void) close(session->sock);
+ smbrdr_session_clear(session);
+ smbrdr_session_unlock(session);
+ syslog(LOG_ERR, "smbrdr: SMB negotiate failed");
+ return (-1);
+ }
+
+ smbrdr_session_unlock(session);
+ return (0);
+}
+
+
+/*
+ * smbrdr_trnsprt_connect
+ *
+ * Set up the TCP/IP and NETBIOS protocols for a session. This is just
+ * standard socket sutff. The paranoia check for socket descriptor 0
+ * is because we had a problem with this value and the console telnet
+ * interface will lock up if we use and/or close stdin (0).
+ *
+ * Return 0 on success. Otherwise return (-1) to indicate a problem.
+ */
+static int
+smbrdr_trnsprt_connect(struct sdb_session *sess, uint16_t port)
+{
+ char hostname[MAXHOSTNAMELEN];
+ struct sockaddr_in sin;
+ int sock, rc;
+ mts_wchar_t unicode_server_name[SMB_PI_MAX_DOMAIN];
+ char server_name[SMB_PI_MAX_DOMAIN];
+ unsigned int cpid = oem_get_smb_cpid();
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) <= 0) {
+ /*
+ * We should never see descriptor 0 (stdin).
+ */
+ syslog(LOG_ERR, "smbrdr: socket(%d) failed (%s)", sock,
+ strerror(errno));
+ return (-1);
+ }
+
+ bzero(&sin, sizeof (struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = sess->di.ipaddr;
+ sin.sin_port = htons(port);
+
+ if ((rc = connect(sock, (struct sockaddr *)&sin, sizeof (sin))) < 0) {
+ syslog(LOG_ERR, "smbrdr: connect failed (%s)", strerror(errno));
+ if (sock != 0)
+ (void) close(sock);
+ return (-1);
+ }
+
+ (void) mts_mbstowcs(unicode_server_name, sess->di.server,
+ SMB_PI_MAX_DOMAIN);
+ rc = unicodestooems(server_name, unicode_server_name,
+ SMB_PI_MAX_DOMAIN, cpid);
+ if (rc == 0) {
+ syslog(LOG_ERR, "smbrdr: unicode conversion failed");
+ if (sock != 0)
+ (void) close(sock);
+ return (-1);
+ }
+
+ /*
+ * If we are using NetBIOS, we need to set up a NETBIOS session.
+ * This typically implies that we will be using port 139.
+ * Otherwise, we're doing NetBIOS-less SMB, i.e. SMB over TCP,
+ * which is typically on port 445.
+ */
+ if (port == SSN_SRVC_TCP_PORT) {
+ if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) != 0) {
+ syslog(LOG_ERR, "smbrdr: no hostname");
+ if (sock != 0)
+ (void) close(sock);
+ return (-1);
+ }
+
+ rc = nb_session_request(sock,
+ server_name, sess->scope, hostname, sess->scope);
+
+ if (rc != 0) {
+ syslog(LOG_ERR,
+ "smbrdr: NBT session request to %s failed %d",
+ server_name, rc);
+ if (sock != 0)
+ (void) close(sock);
+ return (-1);
+ }
+ }
+
+ sess->sock = sock;
+ sess->port = port;
+ syslog(LOG_DEBUG, "smbrdr: connected on port %d", port);
+ sess->state = SDB_SSTATE_CONNECTED;
+ return (0);
+}
+
+/*
+ * smbrdr_smb_negotiate
+ *
+ * Negotiate the protocol we are going to use as described in CIFS
+ * section 4.1.1. The only protocol we support is NT LM 0.12, so we
+ * really expect to see dialect 0 in the response. The only other
+ * data gathered is the session key.
+ *
+ * Negotiate using ASCII strings.
+ *
+ * Return 0 on success. Otherwise return a -ve error code.
+ */
+static int
+smbrdr_smb_negotiate(struct sdb_session *sess)
+{
+ unsigned short dialect;
+ smbrdr_handle_t srh;
+ smb_hdr_t smb_hdr;
+ smb_msgbuf_t *mb;
+ DWORD status;
+ int rc;
+ uint8_t tmp_secmode;
+ uint8_t tmp_clen;
+
+ status = smbrdr_request_init(&srh, SMB_COM_NEGOTIATE, sess, 0, 0);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "smbrdr: negotiate (%s)",
+ xlate_nt_status(status));
+ return (-1);
+ }
+
+ mb = &srh.srh_mbuf;
+ rc = smb_msgbuf_encode(mb, "(wct)b (bcc)w (dialect)bs",
+ 0, /* smb_wct */
+ 12, /* smb_bcc */
+ 0x02, /* dialect marker */
+ "NT LM 0.12"); /* only dialect we care about */
+
+ if (rc <= 0) {
+ syslog(LOG_ERR, "smbrdr: negotiate (encode failed)");
+ smbrdr_handle_free(&srh);
+ return (-1);
+ }
+
+ status = smbrdr_exchange(&srh, &smb_hdr, 0);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "smbrdr: negotiate (%s)",
+ xlate_nt_status(status));
+ smbrdr_handle_free(&srh);
+ return (-1);
+ }
+
+ sess->secmode = 0;
+ sess->sesskey = 0;
+ sess->challenge_len = 0;
+
+ rc = smb_msgbuf_decode(mb,
+ "(wordcnt)1.(dialect)w(secm)b12.(skey)l(cap)l10.(klen)b2.",
+ &dialect, &tmp_secmode, &sess->sesskey, &sess->remote_caps,
+ &tmp_clen);
+
+ if (rc <= 0 || dialect != 0) {
+ syslog(LOG_ERR, "smbrdr: negotiate (response error)");
+ smbrdr_handle_free(&srh);
+ return (-1);
+ }
+ sess->secmode = tmp_secmode;
+ sess->challenge_len = tmp_clen;
+
+ rc = smb_msgbuf_decode(mb, "#c",
+ sess->challenge_len, sess->challenge_key);
+ if (rc <= 0) {
+ syslog(LOG_ERR, "smbrdr: negotiate (decode error)");
+ smbrdr_handle_free(&srh);
+ return (-1);
+ }
+
+ smbrdr_handle_free(&srh);
+
+ if ((sess->secmode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) &&
+ (sess->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
+ sess->sign_ctx.ssc_flags |= SMB_SCF_REQUIRED;
+ syslog(LOG_DEBUG, "smbrdr: %s requires signing",
+ sess->di.server);
+ }
+
+ sess->state = SDB_SSTATE_NEGOTIATED;
+ return (0);
+}
+
+/*
+ * smbrdr_session_init
+ *
+ * Allocate an available slot in session table for the specified domain
+ * information.
+ *
+ * IMPORTANT! the returned session will be locked caller has to unlock
+ * it by calling smbrdr_session_unlock() after it's done with
+ * the pointer.
+ */
+static struct sdb_session *
+smbrdr_session_init(smb_ntdomain_t *di)
+{
+ struct sdb_session *session = 0;
+ int i;
+ char *p;
+
+ if (di == 0)
+ return (0);
+
+ for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
+ session = &session_table[i];
+
+ (void) rw_wrlock(&session->rwl);
+ if (session->state == SDB_SSTATE_START) {
+ smbrdr_session_clear(session);
+ bcopy(di, &session->di, sizeof (smb_ntdomain_t));
+ (void) utf8_strupr(session->di.domain);
+ (void) utf8_strupr(session->di.server);
+
+ smb_config_rdlock();
+ p = smb_config_getstr(SMB_CI_NBSCOPE);
+ (void) strlcpy(session->scope, p, SMB_PI_MAX_SCOPE);
+ smb_config_unlock();
+
+ (void) strlcpy(session->native_os,
+ "Solaris", SMB_PI_MAX_NATIVE_OS);
+ (void) strlcpy(session->native_lanman,
+ "Windows NT 4.0", SMB_PI_MAX_LANMAN);
+ session->sock = -1;
+ session->port = smbrdr_ports[0];
+ session->smb_flags = SMB_FLAGS_CANONICALIZED_PATHS
+ | SMB_FLAGS_CASE_INSENSITIVE;
+
+ session->smb_flags2 = SMB_FLAGS2_KNOWS_LONG_NAMES
+ | SMB_FLAGS2_KNOWS_EAS;
+
+ /*
+ * Note that by sending vc=0 server will shutdown all
+ * the other connections with NAS if there is any.
+ */
+ session->vc = 0;
+ session->sid = ++session_id;
+ if (session->sid == 0)
+ session->sid = 1;
+ session->state = SDB_SSTATE_INIT;
+ return (session);
+ }
+ (void) rw_unlock(&session->rwl);
+ }
+
+ syslog(LOG_WARNING, "smbrdr: no session available");
+ return (0);
+}
+
+/*
+ * smbrdr_session_disconnect
+ *
+ * This is the entry point for disconnecting an SMB connection. Ensure
+ * that all logons and shares associated with this session are
+ * terminated and then free the session.
+ *
+ * if 'cleanup' is 1 it means that only sessions that are not active
+ * should be cleaned up. if 'cleanup' is 0 disconnect the session in any
+ * states.
+ */
+static void
+smbrdr_session_disconnect(struct sdb_session *session, int cleanup)
+{
+ int state;
+
+ if (session == 0) {
+ syslog(LOG_ERR, "smbrdr: (disconnect) null session");
+ return;
+ }
+
+ state = session->state;
+ if ((state != SDB_SSTATE_DISCONNECTING) &&
+ (state != SDB_SSTATE_CLEANING) &&
+ (state != SDB_SSTATE_START)) {
+ if ((cleanup == 0) || (state == SDB_SSTATE_STALE)) {
+ /*
+ * if session is in stale state it means the connection
+ * is lost so no logoff, tdcon, or close can actually
+ * be sent, thus only cleanup our side.
+ */
+ session->state = (state == SDB_SSTATE_STALE)
+ ? SDB_SSTATE_CLEANING : SDB_SSTATE_DISCONNECTING;
+ (void) smbrdr_smb_logoff(&session->logon);
+ nb_close(session->sock);
+ smbrdr_session_clear(session);
+ }
+ }
+}
+
+/*
+ * smbrdr_session_unlock
+ *
+ * Unlock given session structure.
+ */
+void
+smbrdr_session_unlock(struct sdb_session *session)
+{
+ if (session)
+ (void) rw_unlock(&session->rwl);
+}
+
+/*
+ * smbrdr_session_lock
+ *
+ * Lookup the session associated with the specified domain controller.
+ * If a match is found, we return a pointer to the session, Otherwise
+ * we return null. Only sessions in "negotiated" state are checked.
+ * This mechanism is very simple and implies that we
+ * should only ever have one session open to any domain controller.
+ *
+ * IMPORTANT! the returned session will be locked caller has to unlock
+ * it by calling smbrdr_session_unlock() after it's done with
+ * the pointer.
+ */
+struct sdb_session *
+smbrdr_session_lock(char *server, char *username, int lmode)
+{
+ struct sdb_session *session;
+ int i;
+
+ if (server == 0) {
+ syslog(LOG_ERR, "smbrdr: (lookup) no server specified");
+ return (0);
+ }
+
+ for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
+ session = &session_table[i];
+
+ (lmode == SDB_SLCK_READ) ? (void) rw_rdlock(&session->rwl) :
+ (void) rw_wrlock(&session->rwl);
+
+ if ((session->state == SDB_SSTATE_NEGOTIATED) &&
+ (strcasecmp(session->di.server, server) == 0)) {
+ if (username) {
+ if (strcasecmp(username,
+ session->logon.username) == 0)
+ return (session);
+
+ (void) rw_unlock(&session->rwl);
+ return (0);
+ }
+ return (session);
+ }
+
+ (void) rw_unlock(&session->rwl);
+ }
+
+ return (0);
+}
+
+/*
+ * mlsvc_session_native_values
+ *
+ * Given a file id (i.e. a named pipe fid), return the remote native
+ * OS and LM values for the associated session.
+ */
+int
+mlsvc_session_native_values(int fid, int *remote_os,
+ int *remote_lm, int *pdc_type)
+{
+ struct sdb_session *session;
+ struct sdb_netuse *netuse;
+ struct sdb_ofile *ofile;
+
+ if (remote_os == 0 || remote_lm == 0) {
+ syslog(LOG_ERR, "mlsvc_session_native_values: null");
+ return (-1);
+ }
+
+ if ((ofile = smbrdr_ofile_get(fid)) == 0) {
+ syslog(LOG_ERR,
+ "mlsvc_session_native_values: unknown file (%d)", fid);
+ return (-1);
+ }
+
+ netuse = ofile->netuse;
+ session = netuse->session;
+
+ *remote_os = session->remote_os;
+ *remote_lm = session->remote_lm;
+ if (pdc_type)
+ *pdc_type = session->pdc_type;
+ smbrdr_ofile_put(ofile);
+ return (0);
+}
+
+/*
+ * smbrdr_disconnect_sessions
+ *
+ * Disconnects/cleanups all the sessions
+ */
+static void
+smbrdr_disconnect_sessions(int cleanup)
+{
+ struct sdb_session *session;
+ int i;
+
+ for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
+ session = &session_table[i];
+ (void) rw_wrlock(&session->rwl);
+ smbrdr_session_disconnect(&session_table[i], cleanup);
+ (void) rw_unlock(&session->rwl);
+ }
+}
+
+
+/*
+ * mlsvc_check_sessions
+ *
+ * This function should be run in an independent thread. At the time of
+ * writing it is called periodically from an infinite loop in the start
+ * up thread once initialization is complete. It sends a NetBIOS keep-
+ * alive message on each active session and handles cleanup if a session
+ * is closed from the remote end. Testing demonstrated that the domain
+ * controller will close a session after 15 minutes of inactivity. Note
+ * that neither NetBIOS keep-alive nor SMB echo is deemed as activity
+ * in this case, however, RPC requests appear to reset the timeout and
+ * keep the session open. Note that the NetBIOS request does stop the
+ * remote NetBIOS layer from timing out the connection.
+ */
+void
+mlsvc_check_sessions(void)
+{
+ static int session_keep_alive;
+ struct sdb_session *session;
+ smb_ntdomain_t di;
+ int i;
+
+ ++session_keep_alive;
+
+ for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
+ session = &session_table[i];
+
+ (void) rw_wrlock(&session->rwl);
+
+ if (session->state < SDB_SSTATE_CONNECTED) {
+ (void) rw_unlock(&session->rwl);
+ continue;
+ }
+
+ /*
+ * NetBIOS is only used on with port 139. The keep alive
+ * is not relevant over NetBIOS-less SMB over port 445.
+ * This is just to see if the socket is still alive.
+ */
+ if (session->port == SSN_SRVC_TCP_PORT) {
+ if (nb_keep_alive(session->sock) != 0) {
+ session->state = SDB_SSTATE_STALE;
+ (void) rw_unlock(&session->rwl);
+ continue;
+ }
+ }
+
+ if (session_keep_alive >= MLSVC_SESSION_FORCE_KEEPALIVE) {
+ if (smbrdr_smb_echo(session) != 0) {
+ syslog(LOG_WARNING,
+ "smbrdr: monitor[%s] cannot contact %s",
+ session->di.domain, session->di.server);
+ (void) memcpy(&di, &session->di,
+ sizeof (smb_ntdomain_t));
+ session->state = SDB_SSTATE_STALE;
+ (void) rw_unlock(&session->rwl);
+ if (smb_getdomaininfo(0) == 0)
+ (void) smbrdr_locate_dc(di.domain);
+ }
+ } else
+ (void) rw_unlock(&session->rwl);
+ }
+
+ if (session_keep_alive >= MLSVC_SESSION_FORCE_KEEPALIVE) {
+ session_keep_alive = 0;
+ /* cleanup */
+ smbrdr_disconnect_sessions(1);
+ }
+}
+
+/*
+ * smbrdr_dump_sessions
+ *
+ * Debug function to dump the session table.
+ */
+void
+smbrdr_dump_sessions(void)
+{
+ struct sdb_session *session;
+ struct sdb_logon *logon;
+ char ipstr[16];
+ int i;
+
+ for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
+ session = &session_table[i];
+
+ (void) rw_rdlock(&session->rwl);
+ if (session->state != SDB_SSTATE_START) {
+ (void) inet_ntop(AF_INET,
+ (const void *)(&session->di.ipaddr),
+ ipstr, sizeof (ipstr));
+
+ syslog(LOG_DEBUG, "session[%d]: state=%d",
+ i, session->state);
+ syslog(LOG_DEBUG, "session[%d]: %s %s (%s)", i,
+ session->di.domain, session->di.server, ipstr);
+ syslog(LOG_DEBUG, "session[%d]: %s %s (sock=%d)", i,
+ session->native_os, session->native_lanman,
+ session->sock);
+
+ logon = &session->logon;
+ if (logon->type != SDB_LOGON_NONE)
+ syslog(LOG_DEBUG, "logon[%d]: %s (uid=%d)",
+ i, logon->username, logon->uid);
+ }
+ (void) rw_unlock(&session->rwl);
+ }
+}
+
+/*
+ * mlsvc_echo
+ */
+int
+mlsvc_echo(char *server)
+{
+ struct sdb_session *session;
+ int res = 0;
+
+ if ((session = smbrdr_session_lock(server, 0, SDB_SLCK_WRITE)) == 0)
+ return (1);
+
+ if (smbrdr_smb_echo(session) != 0) {
+ session->state = SDB_SSTATE_STALE;
+ res = -1;
+ }
+
+ smbrdr_session_unlock(session);
+ return (res);
+}
+
+/*
+ * smbrdr_smb_echo
+ *
+ * This request can be used to test the connection to the server. The
+ * server should echo the data sent. The server should ignore the tid
+ * in the header, so this request when there are no tree connections.
+ * See CIFS/1.0 section 4.1.7.
+ *
+ * Return 0 on success. Otherwise return a -ve error code.
+ */
+static int
+smbrdr_smb_echo(struct sdb_session *session)
+{
+ static char *echo_str = "smbrdr";
+ smbrdr_handle_t srh;
+ smb_hdr_t smb_hdr;
+ DWORD status;
+ int rc;
+
+ if ((session->state == SDB_SSTATE_DISCONNECTING) ||
+ (session->state == SDB_SSTATE_CLEANING) ||
+ (session->state == SDB_SSTATE_STALE)) {
+ return (-1);
+ }
+
+ status = smbrdr_request_init(&srh, SMB_COM_ECHO, session, 0, 0);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrEcho: %s", xlate_nt_status(status));
+ return (-1);
+ }
+
+ rc = smb_msgbuf_encode(&srh.srh_mbuf, "bwws", 1, 1,
+ strlen(echo_str), echo_str);
+ if (rc <= 0) {
+ syslog(LOG_ERR, "SmbrdrEcho: encode failed");
+ smbrdr_handle_free(&srh);
+ return (-1);
+ }
+
+ status = smbrdr_exchange(&srh, &smb_hdr, 10);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrEcho: %s", xlate_nt_status(status));
+ rc = -1;
+ } else {
+ rc = 0;
+ }
+
+ smbrdr_handle_free(&srh);
+ return (rc);
+}
+
+/*
+ * smbrdr_locate_dc
+ *
+ * Locate a domain controller. Note that this may close an existing
+ * connection to the current domain controller.
+ */
+static int
+smbrdr_locate_dc(char *domain)
+{
+ if (mlsvc_locate_pdc)
+ return (mlsvc_locate_pdc(domain));
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_transact.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_transact.c
new file mode 100644
index 0000000000..24bf3a5cea
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_transact.c
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB transaction functions to support MLRPC.
+ */
+
+#include <syslog.h>
+#include <strings.h>
+
+#include <smbsrv/libsmbrdr.h>
+
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smb.h>
+#include <smbrdr.h>
+
+/*
+ * The pipe filename, length (including the null terminator)
+ * and the buffer size for the transaction. Moving to unicode
+ * revealed that the length should not include the null.
+ */
+#define TX_FILENAME "\\PIPE\\"
+#define TX_FILENAME_ASCII_LEN 6
+#define TX_FILENAME_WCHAR_LEN 14
+
+
+static int prep_smb_transact(smb_msgbuf_t *, unsigned short, char *,
+ unsigned short, unsigned short, unsigned);
+static int decode_smb_transact(smb_msgbuf_t *, char *, unsigned,
+ smb_transact_rsp_t *);
+
+/*
+ * smbrdr_rpc_transact
+ *
+ * Send a SMB_COM_TRANSACTION request.
+ */
+int
+smbrdr_rpc_transact(int fid, char *out_buf, int out_len,
+ char *in_buf, int in_len)
+{
+ struct sdb_session *session;
+ struct sdb_netuse *netuse;
+ struct sdb_ofile *ofile;
+ struct sdb_logon *logon;
+ smb_transact_rsp_t rsp;
+ smbrdr_handle_t srh;
+ smb_msgbuf_t *mb;
+ DWORD status;
+ int rc;
+ unsigned short rcv_dcnt;
+ int cur_inlen;
+ int first_rsp;
+
+ if ((ofile = smbrdr_ofile_get(fid)) == 0)
+ return (-1);
+
+ netuse = ofile->netuse;
+ session = netuse->session;
+ logon = &session->logon;
+
+ status = smbrdr_request_init(&srh, SMB_COM_TRANSACTION,
+ session, logon, netuse);
+
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "SmbrdrTransact: %s", xlate_nt_status(status));
+ smbrdr_ofile_put(ofile);
+ return (-1);
+ }
+
+ mb = &srh.srh_mbuf;
+
+ rc = prep_smb_transact(mb, ofile->fid, out_buf, out_len, in_len,
+ session->remote_caps & CAP_UNICODE);
+ if (rc < 0) {
+ syslog(LOG_ERR,
+ "smbrdr_rpc_transact: prep_smb_transact failed");
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_put(ofile);
+ return (rc);
+ }
+
+ smbrdr_lock_transport();
+
+ status = smbrdr_send(&srh);
+ if (status != NT_STATUS_SUCCESS) {
+ smbrdr_unlock_transport();
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_put(ofile);
+ syslog(LOG_ERR, "smbrdr_rpc_transact: send failed");
+ return (-1);
+ }
+
+ rcv_dcnt = 0;
+ cur_inlen = in_len;
+ first_rsp = 1;
+
+ do {
+ if (smbrdr_rcv(&srh, first_rsp) != NT_STATUS_SUCCESS) {
+ syslog(LOG_ERR, "smbrdr_rpc_transact: nb_rcv failed");
+ rc = -1;
+ break;
+ }
+
+ rc = decode_smb_transact(mb, in_buf, cur_inlen, &rsp);
+ if (rc < 0 || rsp.TotalDataCount > in_len) {
+ syslog(LOG_ERR,
+ "SmbTransact: transact decode failure!");
+ rc = -1;
+ break;
+ }
+
+ rcv_dcnt += rsp.DataCount;
+ cur_inlen -= rsp.DataCount;
+ first_rsp = 0;
+
+ } while (rcv_dcnt < rsp.TotalDataCount);
+
+ smbrdr_unlock_transport();
+ smbrdr_handle_free(&srh);
+ smbrdr_ofile_put(ofile);
+
+ return ((rc < 0) ? rc : rcv_dcnt);
+}
+
+
+/*
+ * prep_smb_transact
+ *
+ * Prepare the SMB_COM_TRANSACTION request.
+ */
+static int
+prep_smb_transact(smb_msgbuf_t *mb, unsigned short fid, char *out,
+ unsigned short out_len, unsigned short in_max, unsigned unicode)
+{
+ int data_off;
+ int rc;
+ unsigned short bcc;
+
+ /*
+ * The byte count seems to include the pad
+ * byte to word align the filename and two
+ * spurious pad bytes between the filename
+ * and the transaction data.
+ */
+ bcc = out_len + 3;
+ bcc += (unicode) ? TX_FILENAME_WCHAR_LEN : TX_FILENAME_ASCII_LEN;
+
+ data_off = 32; /* sizeof SMB header up to smb_wct */
+ data_off += 1; /* sizeof smb_wct */
+ data_off += 16*2; /* sizeof word parameters */
+ data_off += 2; /* sizeof smb_bcc */
+ data_off += (unicode) ? TX_FILENAME_WCHAR_LEN : TX_FILENAME_ASCII_LEN;
+ data_off += 3;
+ /* this is where data starts */
+
+ rc = smb_msgbuf_encode(mb,
+ "(wct)b"
+ "(tpscnt)w (tdscnt)w (mprcnt)w (mdrcnt)w (msrcnt)b"
+ "(rsvd). (flags)w (timeo)l (rsvd1)2."
+ "(pscnt)w (psoff)w (dscnt)w (dsoff)w (suwcnt)b"
+ "(rsvd2). (pipop)w (fid)w (bcc)w (fname)u",
+ 16, /* smb_wct */
+ 0, /* total parm bytes */
+ out_len, /* total data bytes */
+ 0, /* max parm bytes to ret */
+ in_max, /* max data bytes to ret */
+ 0, /* max setup words to ret */
+ 0, /* transact flags */
+ 0, /* transact timeout */
+ 0, /* parameter bytes */
+ data_off, /* parameter offset */
+ out_len, /* data bytes */
+ data_off, /* data offset */
+ 2, /* total setup words */
+ 0x0026, /* OP=TransactNmPipe */
+ fid, /* FID */
+ bcc, /* byte count */
+ TX_FILENAME); /* file name */
+
+ /*
+ * Transaction data - padded.
+ */
+ rc = smb_msgbuf_encode(mb, "..#c", out_len, out);
+ return (rc);
+}
+
+
+/*
+ * decode_smb_transact
+ *
+ * Decode the response from the SMB_COM_TRANSACTION request.
+ */
+static int
+decode_smb_transact(smb_msgbuf_t *mb, char *in, unsigned in_len,
+ smb_transact_rsp_t *rsp)
+{
+ int rc;
+
+ rc = smb_msgbuf_decode(mb, "b", &rsp->WordCount);
+ if (rc <= 0 || rsp->WordCount < 10) {
+ syslog(LOG_ERR, "SmbTransact: invalid word count");
+ return (-1);
+ }
+
+ rc = smb_msgbuf_decode(mb,
+ "(tpscnt)w (tdscnt)w (rsvd)2."
+ "(pscnt)w (psoff)w (psdisp)w (dscnt)w (dsoff)w"
+ "(dsdisp)w (suwcnt)b (rsvd). (bcc)w",
+ &rsp->TotalParamCount, /* Total parm bytes */
+ &rsp->TotalDataCount, /* Total data bytes */
+ &rsp->ParamCount, /* Parm bytes this buffer */
+ &rsp->ParamOffset, /* Parm offset from hdr */
+ &rsp->ParamDisplacement, /* Parm displacement */
+ &rsp->DataCount, /* Data bytes this buffer */
+ &rsp->DataOffset, /* Data offset from hdr */
+ &rsp->DataDisplacement, /* Data displacement */
+ &rsp->SetupCount, /* Setup word count */
+ &rsp->BCC); /* smb_bcc */
+
+ if (rc <= 0)
+ return (-1);
+
+ if (rsp->DataCount > in_len)
+ return (-1);
+
+ bcopy(mb->base + rsp->DataOffset,
+ in + rsp->DataDisplacement, rsp->DataCount);
+
+ return (0);
+}
diff --git a/usr/src/lib/smbsrv/libsmbrdr/i386/Makefile b/usr/src/lib/smbsrv/libsmbrdr/i386/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libsmbrdr/sparc/Makefile b/usr/src/lib/smbsrv/libsmbrdr/sparc/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbsrv/libsmbrdr/sparcv9/Makefile b/usr/src/lib/smbsrv/libsmbrdr/sparcv9/Makefile
new file mode 100644
index 0000000000..a2f97019c8
--- /dev/null
+++ b/usr/src/lib/smbsrv/libsmbrdr/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/pkgdefs/Makefile b/usr/src/pkgdefs/Makefile
index 7843cd9174..5ae726e3c5 100644
--- a/usr/src/pkgdefs/Makefile
+++ b/usr/src/pkgdefs/Makefile
@@ -354,6 +354,9 @@ COMMON_SUBDIRS= \
SUNWslpr \
SUNWslpu \
SUNWsmapi \
+ SUNWsmbskr \
+ SUNWsmbsr \
+ SUNWsmbsu \
SUNWsmedia \
SUNWsmediar \
SUNWsn1rint \
diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com
index 87facb2c00..3d577416fd 100644
--- a/usr/src/pkgdefs/SUNW0on/prototype_com
+++ b/usr/src/pkgdefs/SUNW0on/prototype_com
@@ -256,6 +256,7 @@ f none usr/lib/help/auths/locale/SmfNWAMStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfPowerStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfRoutingStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfSendmailStates.html 444 root bin
+f none usr/lib/help/auths/locale/SmfSMBStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfSshStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfSyslogStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueHeader.html 444 root bin
@@ -266,6 +267,8 @@ f none usr/lib/help/auths/locale/SmfValueMDNS.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueNADD.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueNWAM.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueRouting.html 444 root bin
+f none usr/lib/help/auths/locale/SmfValueSMB.html 444 root bin
+f none usr/lib/help/auths/locale/AuthReadSMB.html 444 root bin
f none usr/lib/help/auths/locale/SmfWpaStates.html 444 root bin
f none usr/lib/help/auths/locale/NetworkHeader.html 444 root bin
f none usr/lib/help/auths/locale/WifiConfig.html 444 root bin
@@ -333,6 +336,7 @@ f none usr/lib/help/profiles/locale/RtObAccessMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/RtProcManagement.html 444 root bin
f none usr/lib/help/profiles/locale/RtRightsDelegate.html 444 root bin
f none usr/lib/help/profiles/locale/RtSoftwareInstall.html 444 root bin
+f none usr/lib/help/profiles/locale/RtSMBMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/RtSysEvMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/RtUserMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/RtUserSecurity.html 444 root bin
diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com
index 4c0a9807a5..a993f2eea6 100644
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com
@@ -492,6 +492,7 @@ f none usr/lib/help/auths/locale/C/SmfNWAMStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfPowerStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfRoutingStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfSendmailStates.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfSMBStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfSshStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfSyslogStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueHeader.html 444 root bin
@@ -502,6 +503,8 @@ f none usr/lib/help/auths/locale/C/SmfValueMDNS.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueNADD.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueNWAM.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueRouting.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfValueSMB.html 444 root bin
+f none usr/lib/help/auths/locale/C/AuthReadSMB.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfWpaStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SysDate.html 444 root bin
f none usr/lib/help/auths/locale/C/SysHeader.html 444 root bin
@@ -551,6 +554,7 @@ f none usr/lib/help/profiles/locale/C/RtPrntAdmin.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtProcManagement.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtRightsDelegate.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtSoftwareInstall.html 444 root bin
+f none usr/lib/help/profiles/locale/C/RtSMBMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtSysEvMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtUserMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtUserSecurity.html 444 root bin
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com
index 727d760801..81c0ddb2ae 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_com
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com
@@ -164,6 +164,7 @@ f none usr/include/ast/vmalloc.h 644 root bin
f none usr/include/ast/wait.h 644 root bin
f none usr/include/ast/wchar.h 644 root bin
f none usr/include/ast/wordexp.h 644 root bin
+f none usr/include/attr.h 644 root bin
f none usr/include/atomic.h 644 root bin
f none usr/include/auth_attr.h 644 root bin
d none usr/include/bsm 755 root bin
@@ -624,6 +625,7 @@ d none usr/include/sys 755 root bin
f none usr/include/sys/acct.h 644 root bin
f none usr/include/sys/acctctl.h 644 root bin
f none usr/include/sys/acl.h 644 root bin
+f none usr/include/sys/acl_impl.h 644 root bin
f none usr/include/sys/aio.h 644 root bin
f none usr/include/sys/aio_impl.h 644 root bin
f none usr/include/sys/aio_req.h 644 root bin
@@ -634,6 +636,7 @@ f none usr/include/sys/asm_linkage.h 644 root bin
f none usr/include/sys/asynch.h 644 root bin
f none usr/include/sys/atomic.h 644 root bin
f none usr/include/sys/autoconf.h 644 root bin
+f none usr/include/sys/attr.h 644 root bin
f none usr/include/sys/auxv.h 644 root bin
f none usr/include/sys/auxv_386.h 644 root bin
f none usr/include/sys/auxv_SPARC.h 644 root bin
@@ -1296,6 +1299,7 @@ f none usr/include/sys/tuneable.h 644 root bin
f none usr/include/sys/turnstile.h 644 root bin
f none usr/include/sys/types.h 644 root bin
f none usr/include/sys/types32.h 644 root bin
+f none usr/include/sys/tzfile.h 644 root bin
f none usr/include/sys/u8_textprep.h 644 root bin
f none usr/include/sys/uadmin.h 644 root bin
f none usr/include/sys/ucontext.h 644 root bin
diff --git a/usr/src/pkgdefs/SUNWsmbskr/Makefile b/usr/src/pkgdefs/SUNWsmbskr/Makefile
new file mode 100644
index 0000000000..c1bfa57502
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbskr/Makefile
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+include ../Makefile.com
+
+DATAFILES += depend
+
+.KEEP_STATE:
+
+all: $(FILES) postinstall preremove
+
+install: all pkg
+
+include ../Makefile.targ
diff --git a/usr/src/pkgdefs/SUNWsmbskr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWsmbskr/pkginfo.tmpl
new file mode 100644
index 0000000000..1279fa65fa
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbskr/pkginfo.tmpl
@@ -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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# This required package information file describes characteristics of the
+# package, such as package abbreviation, full package name, package version,
+# and package architecture.
+#
+PKG="SUNWsmbskr"
+NAME="SMB Server (Kernel)"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGTYPE="root"
+MAXINST="1000"
+CATEGORY="system"
+DESC="SMB Server kernel root components"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+CLASSES="none"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="true"
+SUNW_PKG_THISZONE="false"
diff --git a/usr/src/pkgdefs/SUNWsmbskr/postinstall b/usr/src/pkgdefs/SUNWsmbskr/postinstall
new file mode 100644
index 0000000000..934bbe8467
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbskr/postinstall
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PATH="/usr/bin:/usr/sbin"
+export PATH
+
+PKG_NAME=SUNWsmbskr
+DRV=smbsrv
+DRVPERM='* 0666 root sys'
+
+ADD_DRV=/usr/sbin/add_drv
+
+#
+# Check if the BASEDIR option is needed
+#
+if [ "${BASEDIR}" = "/" ]; then
+ ADD_DRV_FLAGS=""
+ NAME_TO_MAJOR="/etc/name_to_major"
+else
+ ADD_DRV_FLAGS="-b ${BASEDIR}"
+ NAME_TO_MAJOR="${BASEDIR}/etc/name_to_major"
+fi
+
+#
+# Make sure add_drv has not been previously executed before attempting
+# to add the driver
+#
+grep "^${DRV} " ${NAME_TO_MAJOR} > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ ${ADD_DRV} ${ADD_DRV_FLAGS} -m '* 0666 root sys' ${DRV}
+ if [ $? -ne 0 ]; then
+ echo "${PKG_NAME}: add_drv ${DRV} failed." >&2
+ exit 1
+ fi
+fi
+exit 0
diff --git a/usr/src/pkgdefs/SUNWsmbskr/preremove b/usr/src/pkgdefs/SUNWsmbskr/preremove
new file mode 100644
index 0000000000..2c19159f1f
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbskr/preremove
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PATH="/usr/bin:/usr/sbin:${PATH}"
+export PATH
+
+DRV=smbsrv
+
+REM_DRV=/usr/sbin/rem_drv
+
+#
+# Check if the BASEDIR option is needed
+#
+if [ "${BASEDIR}" = "/" ]; then
+ REM_DRV_FLAGS=""
+else
+ REM_DRV_FLAGS="-b ${BASEDIR}"
+fi
+
+${REM_DRV} ${REM_DRV_FLAGS} ${DRV}
+
+exit 0
diff --git a/usr/src/pkgdefs/SUNWsmbskr/prototype_com b/usr/src/pkgdefs/SUNWsmbskr/prototype_com
new file mode 100644
index 0000000000..245e5e2ba8
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbskr/prototype_com
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+# packaging files
+i copyright
+i depend
+i pkginfo
+i postinstall
+i preremove
+#
+# SUNWsmbskr
+#
+d none kernel 755 root sys
+d none kernel/kmdb 755 root sys
+d none kernel/drv 755 root sys
+f none kernel/drv/smbsrv.conf 644 root sys
diff --git a/usr/src/pkgdefs/SUNWsmbskr/prototype_i386 b/usr/src/pkgdefs/SUNWsmbskr/prototype_i386
new file mode 100644
index 0000000000..bf813c18c0
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbskr/prototype_i386
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+!include prototype_com
+#
+# SUNWsmbskr
+#
+f none kernel/drv/smbsrv 755 root sys
+d none kernel/drv/amd64 755 root sys
+f none kernel/drv/amd64/smbsrv 755 root sys
+f none kernel/kmdb/smbsrv 555 root sys
+d none kernel/kmdb/amd64 755 root sys
+f none kernel/kmdb/amd64/smbsrv 555 root sys
diff --git a/usr/src/pkgdefs/SUNWsmbskr/prototype_sparc b/usr/src/pkgdefs/SUNWsmbskr/prototype_sparc
new file mode 100644
index 0000000000..68ad9f0ed6
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbskr/prototype_sparc
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+!include prototype_com
+#
+# SUNWsmbskr
+#
+d none kernel/drv/sparcv9 755 root sys
+f none kernel/drv/sparcv9/smbsrv 755 root sys
+d none kernel/kmdb/sparcv9 755 root sys
+f none kernel/kmdb/sparcv9/smbsrv 555 root sys
diff --git a/usr/src/pkgdefs/SUNWsmbsr/Makefile b/usr/src/pkgdefs/SUNWsmbsr/Makefile
new file mode 100644
index 0000000000..b0543ab1fb
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsr/Makefile
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+include ../Makefile.com
+
+DATAFILES += i.manifest r.manifest
+
+.KEEP_STATE:
+
+all: $(FILES) depend
+
+install: all pkg
+
+include ../Makefile.targ
diff --git a/usr/src/pkgdefs/SUNWsmbsr/depend b/usr/src/pkgdefs/SUNWsmbsr/depend
new file mode 100644
index 0000000000..a7789666aa
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsr/depend
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# This package information file defines software dependencies associated
+# with the pkg. You can define three types of pkg dependencies with this file:
+# P indicates a prerequisite for installation
+# I indicates an incompatible package
+# R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# (<arch>)<version>
+# (<arch>)<version>
+# ...
+# <type> <pkg.abbr> <name>
+# ...
+#
+
+P SUNWcar Core Architecture, (Root)
+P SUNWcakr Core Solaris Kernel Architecture (Root)
+P SUNWkvm Core Architecture, (Kvm)
+P SUNWcsr Core Solaris, (Root)
+P SUNWckr Core Solaris Kernel (Root)
+P SUNWcsu Core Solaris, (Usr)
+P SUNWcsd Core Solaris Devices
+P SUNWcsl Core Solaris Libraries
+P SUNWsmbskr SMB Kernel (Root)
diff --git a/usr/src/pkgdefs/SUNWsmbsr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWsmbsr/pkginfo.tmpl
new file mode 100644
index 0000000000..334287c664
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsr/pkginfo.tmpl
@@ -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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# This required package information file describes characteristics of the
+# package, such as package abbreviation, full package name, package version,
+# and package architecture.
+#
+PKG="SUNWsmbsr"
+NAME="SMB Server (Root)"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGTYPE="root"
+MAXINST="1000"
+CATEGORY="system"
+DESC="=SMB Server root components"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+CLASSES="none manifest"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="false"
+SUNW_PKG_THISZONE="false"
diff --git a/usr/src/pkgdefs/SUNWsmbsr/prototype_com b/usr/src/pkgdefs/SUNWsmbsr/prototype_com
new file mode 100644
index 0000000000..52fcaaa1a8
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsr/prototype_com
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# packaging files
+i copyright
+i depend
+i pkginfo
+i i.manifest
+i r.manifest
+#
+# SUNWsmbsr
+#
+d none var 0755 root sys
+d none var/smb 0755 root sys
+f none var/smb/smbpasswd 0400 root sys
+d none var/svc 0755 root sys
+d none var/svc/manifest 0755 root sys
+d none var/svc/manifest/network 0755 root sys
+d none var/svc/manifest/network/smb 0755 root sys
+f manifest var/svc/manifest/network/smb/server.xml 0444 root sys
diff --git a/usr/src/pkgdefs/SUNWsmbsr/prototype_i386 b/usr/src/pkgdefs/SUNWsmbsr/prototype_i386
new file mode 100644
index 0000000000..893833a87f
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsr/prototype_i386
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+#
+!include prototype_com
+#
+# List files which are i386 specific here
+# SUNWsmbsr
+#
diff --git a/usr/src/pkgdefs/SUNWsmbsr/prototype_sparc b/usr/src/pkgdefs/SUNWsmbsr/prototype_sparc
new file mode 100644
index 0000000000..6ea63a15ea
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsr/prototype_sparc
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+#
+!include prototype_com
+#
+# List files which are sparc specific here
+# SUNWsmbsr
+#
diff --git a/usr/src/pkgdefs/SUNWsmbsu/Makefile b/usr/src/pkgdefs/SUNWsmbsu/Makefile
new file mode 100644
index 0000000000..176ab5ba1f
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsu/Makefile
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+include ../Makefile.com
+
+.KEEP_STATE:
+
+all: $(FILES) depend preremove
+
+install: all pkg
+
+include ../Makefile.targ
diff --git a/usr/src/pkgdefs/SUNWsmbsu/depend b/usr/src/pkgdefs/SUNWsmbsu/depend
new file mode 100644
index 0000000000..53c41eedf3
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsu/depend
@@ -0,0 +1,55 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# This package information file defines software dependencies associated
+# with the pkg. You can define three types of pkg dependencies with this file:
+# P indicates a prerequisite for installation
+# I indicates an incompatible package
+# R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# (<arch>)<version>
+# (<arch>)<version>
+# ...
+# <type> <pkg.abbr> <name>
+# ...
+#
+
+P SUNWcar Core Architecture, (Root)
+P SUNWcakr Core Solaris Kernel Architecture (Root)
+P SUNWkvm Core Architecture, (Kvm)
+P SUNWcsr Core Solaris, (Root)
+P SUNWckr Core Solaris Kernel (Root)
+P SUNWcsu Core Solaris, (Usr)
+P SUNWcsd Core Solaris Devices
+P SUNWcsl Core Solaris Libraries
+P SUNWsmbskr SMB Kernel (Root)
+P SUNWsmbsr SMB Server (Root)
diff --git a/usr/src/pkgdefs/SUNWsmbsu/pkginfo.tmpl b/usr/src/pkgdefs/SUNWsmbsu/pkginfo.tmpl
new file mode 100644
index 0000000000..440c41086e
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsu/pkginfo.tmpl
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+PKG="SUNWsmbsu"
+NAME="SMB Server (Usr)"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGTYPE="usr"
+MAXINST="1000"
+CATEGORY="system"
+DESC="SMB Server libraries and commands"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+CLASSES="none"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="false"
+SUNW_PKG_THISZONE="false"
diff --git a/usr/src/pkgdefs/SUNWsmbsu/preremove b/usr/src/pkgdefs/SUNWsmbsu/preremove
new file mode 100644
index 0000000000..68fbce22af
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsu/preremove
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Make sure that SMB server daemon (smbd) is not
+# running before removing this package.
+#
+if [ "${PKG_INSTALL_ROOT:-/}" = "/" ]; then
+ for i in smbd
+ do
+ /usr/bin/pgrep -x -u 0 "$i" >/dev/null
+ if [ $? -ne 1 ]; then
+ echo "$i running; unable to remove package"
+ exit 1
+ fi
+ done
+fi
+
+exit 0
diff --git a/usr/src/pkgdefs/SUNWsmbsu/prototype_com b/usr/src/pkgdefs/SUNWsmbsu/prototype_com
new file mode 100644
index 0000000000..eff699e240
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsu/prototype_com
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+i pkginfo
+i copyright
+i depend
+i preremove
+#
+# SUNWsmbsu
+#
+d none usr 755 root sys
+d none usr/lib 755 root bin
+d none usr/lib/smbsrv 755 root bin
+f none usr/lib/smbsrv/libsmb.so.1 755 root bin
+s none usr/lib/smbsrv/libsmb.so=libsmb.so.1
+f none usr/lib/smbsrv/llib-lsmb 644 root bin
+f none usr/lib/smbsrv/llib-lsmb.ln 644 root bin
+f none usr/lib/smbsrv/libmlrpc.so.1 755 root bin
+s none usr/lib/smbsrv/libmlrpc.so=libmlrpc.so.1
+f none usr/lib/smbsrv/llib-lmlrpc 644 root bin
+f none usr/lib/smbsrv/llib-lmlrpc.ln 644 root bin
+f none usr/lib/smbsrv/libmlsvc.so.1 755 root bin
+s none usr/lib/smbsrv/libmlsvc.so=libmlsvc.so.1
+f none usr/lib/smbsrv/llib-lmlsvc 644 root bin
+f none usr/lib/smbsrv/llib-lmlsvc.ln 644 root bin
+f none usr/lib/smbsrv/libsmbns.so.1 755 root bin
+s none usr/lib/smbsrv/libsmbns.so=libsmbns.so.1
+f none usr/lib/smbsrv/llib-lsmbns 644 root bin
+f none usr/lib/smbsrv/llib-lsmbns.ln 644 root bin
+f none usr/lib/smbsrv/libsmbrdr.so.1 755 root bin
+s none usr/lib/smbsrv/libsmbrdr.so=libsmbrdr.so.1
+f none usr/lib/smbsrv/llib-lsmbrdr 644 root bin
+f none usr/lib/smbsrv/llib-lsmbrdr.ln 644 root bin
+f none usr/lib/smbsrv/smbd 555 root bin
+d none usr/sbin 755 root bin
+f none usr/sbin/smbadm 555 root bin
+f none usr/sbin/smbstat 555 root bin
+d none usr/lib/mdb 755 root sys
+d none usr/lib/mdb/kvm 755 root sys
+d none usr/lib/fs 755 root sys
+d none usr/lib/fs/smb 755 root sys
+f none usr/lib/fs/smb/libshare_smb.so.1 755 root bin
+s none usr/lib/fs/smb/libshare_smb.so=libshare_smb.so.1
+d none usr/lib/security 755 root bin
+f none usr/lib/security/pam_smb_passwd.so.1 755 root bin
+s none usr/lib/security/pam_smb_passwd.so=./pam_smb_passwd.so.1
diff --git a/usr/src/pkgdefs/SUNWsmbsu/prototype_i386 b/usr/src/pkgdefs/SUNWsmbsu/prototype_i386
new file mode 100644
index 0000000000..3417692201
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsu/prototype_i386
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+!include prototype_com
+f none usr/lib/mdb/kvm/smbsrv.so 555 root sys
+d none usr/lib/mdb/kvm/amd64 755 root sys
+f none usr/lib/mdb/kvm/amd64/smbsrv.so 555 root sys
+d none usr/lib/fs/smb/amd64 755 root sys
+f none usr/lib/fs/smb/amd64/libshare_smb.so.1 755 root bin
+s none usr/lib/fs/smb/amd64/libshare_smb.so=libshare_smb.so.1
diff --git a/usr/src/pkgdefs/SUNWsmbsu/prototype_sparc b/usr/src/pkgdefs/SUNWsmbsu/prototype_sparc
new file mode 100644
index 0000000000..2a8071982f
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWsmbsu/prototype_sparc
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+!include prototype_com
+d none usr/lib/mdb/kvm/sparcv9 755 root sys
+f none usr/lib/mdb/kvm/sparcv9/smbsrv.so 555 root sys
+d none usr/lib/fs/smb/sparcv9 755 root sys
+f none usr/lib/fs/smb/sparcv9/libshare_smb.so.1 755 root bin
+s none usr/lib/fs/smb/sparcv9/libshare_smb.so=libshare_smb.so.1
diff --git a/usr/src/pkgdefs/common_files/i.minorperm_i386 b/usr/src/pkgdefs/common_files/i.minorperm_i386
index c7bafd374c..510f62a139 100644
--- a/usr/src/pkgdefs/common_files/i.minorperm_i386
+++ b/usr/src/pkgdefs/common_files/i.minorperm_i386
@@ -315,6 +315,7 @@ asy:*
asy:*,cu
ucode:*
battery:*
+smbsrv:*
EOF
}
diff --git a/usr/src/pkgdefs/common_files/i.minorperm_sparc b/usr/src/pkgdefs/common_files/i.minorperm_sparc
index 4a00d39f27..c5a202a5d0 100644
--- a/usr/src/pkgdefs/common_files/i.minorperm_sparc
+++ b/usr/src/pkgdefs/common_files/i.minorperm_sparc
@@ -332,6 +332,7 @@ profile:profile
sdt:sdt
systrace:systrace
physmem:*
+smbsrv:*
EOF
}
diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386
index 58fc7ddd64..d1f9e0c85a 100644
--- a/usr/src/pkgdefs/etc/exception_list_i386
+++ b/usr/src/pkgdefs/etc/exception_list_i386
@@ -867,6 +867,8 @@ usr/lib/libshare.so i386
usr/lib/amd64/libshare.so i386
usr/lib/fs/nfs/libshare_nfs.so i386
usr/lib/fs/nfs/amd64/libshare_nfs.so i386
+usr/lib/fs/smb/libshare_smb.so i386
+usr/lib/fs/smb/amd64/libshare_smb.so i386
usr/include/libshare_impl.h i386
usr/include/scfutil.h i386
usr/sbin/i86/sharemgr i386
@@ -899,3 +901,108 @@ etc/flash/postdeployment/ttydefs.cleanup i386
# ppm/srn modules # and should not be in any package
#
usr/include/sys/srn.h i386
+#
+# Private/Internal header files of smbsrv. Do not ship.
+#
+usr/include/smbsrv i386
+usr/include/smbsrv/alloc.h i386
+usr/include/smbsrv/cifs.h i386
+usr/include/smbsrv/codepage.h i386
+usr/include/smbsrv/cp_cyrillic.h i386
+usr/include/smbsrv/cp_latin1.h i386
+usr/include/smbsrv/cp_latin2.h i386
+usr/include/smbsrv/cp_latin3.h i386
+usr/include/smbsrv/cp_latin4.h i386
+usr/include/smbsrv/cp_latin5.h i386
+usr/include/smbsrv/cp_latin6.h i386
+usr/include/smbsrv/cp_unicode.h i386
+usr/include/smbsrv/cp_usascii.h i386
+usr/include/smbsrv/crypt.h i386
+usr/include/smbsrv/ctype.h i386
+usr/include/smbsrv/doserror.h i386
+usr/include/smbsrv/hash_table.h i386
+usr/include/smbsrv/libmlrpc.h i386
+usr/include/smbsrv/libmlsvc.h i386
+usr/include/smbsrv/libsmb.h i386
+usr/include/smbsrv/libsmbns.h i386
+usr/include/smbsrv/libsmbrdr.h i386
+usr/include/smbsrv/lm.h i386
+usr/include/smbsrv/lmdfs.h i386
+usr/include/smbsrv/lmerr.h i386
+usr/include/smbsrv/lmshare.h i386
+usr/include/smbsrv/lmshare_door.h i386
+usr/include/smbsrv/lsalib.h i386
+usr/include/smbsrv/mac_cifs.h i386
+usr/include/smbsrv/mailslot.h i386
+usr/include/smbsrv/mbuf.h i386
+usr/include/smbsrv/mlrpc.h i386
+usr/include/smbsrv/mlsvc.h i386
+usr/include/smbsrv/mlsvc_util.h i386
+usr/include/smbsrv/msgbuf.h i386
+usr/include/smbsrv/ndr.h i386
+usr/include/smbsrv/netbios.h i386
+usr/include/smbsrv/netrauth.h i386
+usr/include/smbsrv/nmpipes.h i386
+usr/include/smbsrv/ntaccess.h i386
+usr/include/smbsrv/nterror.h i386
+usr/include/smbsrv/ntifs.h i386
+usr/include/smbsrv/ntlocale.h i386
+usr/include/smbsrv/ntsid.h i386
+usr/include/smbsrv/ntstatus.h i386
+usr/include/smbsrv/oem.h i386
+usr/include/smbsrv/samlib.h i386
+usr/include/smbsrv/smb.h i386
+usr/include/smbsrv/smb_common_door.h i386
+usr/include/smbsrv/smb_door_svc.h i386
+usr/include/smbsrv/smb_fsd.h i386
+usr/include/smbsrv/smb_fsops.h i386
+usr/include/smbsrv/smb_i18n.h i386
+usr/include/smbsrv/smb_idmap.h i386
+usr/include/smbsrv/smb_incl.h i386
+usr/include/smbsrv/smb_ioctl.h i386
+usr/include/smbsrv/smb_kproto.h i386
+usr/include/smbsrv/smb_privilege.h i386
+usr/include/smbsrv/smb_secdesc.h i386
+usr/include/smbsrv/smb_svc_sm.h i386
+usr/include/smbsrv/smb_token.h i386
+usr/include/smbsrv/smb_vops.h i386
+usr/include/smbsrv/smb_winpipe.h i386
+usr/include/smbsrv/smb_xdr.h i386
+usr/include/smbsrv/smbfmt.h i386
+usr/include/smbsrv/smbinfo.h i386
+usr/include/smbsrv/smbtrans.h i386
+usr/include/smbsrv/smbvar.h i386
+usr/include/smbsrv/string.h i386
+usr/include/smbsrv/svrapi.h i386
+usr/include/smbsrv/winioctl.h i386
+usr/include/smbsrv/winsvc.h i386
+usr/include/smbsrv/wintypes.h i386
+#
+# Private/Internal ndl files of smbsrv. Do not ship.
+#
+usr/include/smbsrv/ndl i386
+usr/include/smbsrv/ndl/dssetup.ndl i386
+usr/include/smbsrv/ndl/eventlog.ndl i386
+usr/include/smbsrv/ndl/llsrpc.ndl i386
+usr/include/smbsrv/ndl/lsarpc.ndl i386
+usr/include/smbsrv/ndl/ndrtypes.ndl i386
+usr/include/smbsrv/ndl/netdfs.ndl i386
+usr/include/smbsrv/ndl/netlogon.ndl i386
+usr/include/smbsrv/ndl/rpcpdu.ndl i386
+usr/include/smbsrv/ndl/samrpc.ndl i386
+usr/include/smbsrv/ndl/spoolss.ndl i386
+usr/include/smbsrv/ndl/srvsvc.ndl i386
+usr/include/smbsrv/ndl/svcctl.ndl i386
+usr/include/smbsrv/ndl/winreg.ndl i386
+#
+# Private/Internal dtrace scripts of smbsrv. Do not ship.
+#
+usr/lib/smbsrv/dtrace i386
+usr/lib/smbsrv/dtrace/msrpc.d i386
+usr/lib/smbsrv/dtrace/smbnode.d i386
+usr/lib/smbsrv/dtrace/smbvfs.d i386
+usr/lib/smbsrv/dtrace/stype.d i386
+#
+# Private dirent, extended to include flags, for use by SMB server
+#
+usr/include/sys/extdirent.h i386
diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc
index 2244b8a91f..3641342b77 100644
--- a/usr/src/pkgdefs/etc/exception_list_sparc
+++ b/usr/src/pkgdefs/etc/exception_list_sparc
@@ -943,6 +943,8 @@ usr/lib/libshare.so sparc
usr/lib/sparcv9/libshare.so sparc
usr/lib/fs/nfs/libshare_nfs.so sparc
usr/lib/fs/nfs/sparcv9/libshare_nfs.so sparc
+usr/lib/fs/smb/libshare_smb.so sparc
+usr/lib/fs/smb/sparcv9/libshare_smb.so sparc
usr/include/libshare_impl.h sparc
usr/include/scfutil.h sparc
usr/sbin/sparcv9/sharemgr sparc
@@ -983,3 +985,108 @@ usr/include/sys/kiconv_latin1.h sparc
# ppm/srn modules # and should not be in any package
#
usr/include/sys/srn.h sparc
+#
+# Private/Internal header files of smbsrv. Do not ship.
+#
+usr/include/smbsrv sparc
+usr/include/smbsrv/alloc.h sparc
+usr/include/smbsrv/cifs.h sparc
+usr/include/smbsrv/codepage.h sparc
+usr/include/smbsrv/cp_cyrillic.h sparc
+usr/include/smbsrv/cp_latin1.h sparc
+usr/include/smbsrv/cp_latin2.h sparc
+usr/include/smbsrv/cp_latin3.h sparc
+usr/include/smbsrv/cp_latin4.h sparc
+usr/include/smbsrv/cp_latin5.h sparc
+usr/include/smbsrv/cp_latin6.h sparc
+usr/include/smbsrv/cp_unicode.h sparc
+usr/include/smbsrv/cp_usascii.h sparc
+usr/include/smbsrv/crypt.h sparc
+usr/include/smbsrv/ctype.h sparc
+usr/include/smbsrv/doserror.h sparc
+usr/include/smbsrv/hash_table.h sparc
+usr/include/smbsrv/libmlrpc.h sparc
+usr/include/smbsrv/libmlsvc.h sparc
+usr/include/smbsrv/libsmb.h sparc
+usr/include/smbsrv/libsmbns.h sparc
+usr/include/smbsrv/libsmbrdr.h sparc
+usr/include/smbsrv/lm.h sparc
+usr/include/smbsrv/lmdfs.h sparc
+usr/include/smbsrv/lmerr.h sparc
+usr/include/smbsrv/lmshare.h sparc
+usr/include/smbsrv/lmshare_door.h sparc
+usr/include/smbsrv/lsalib.h sparc
+usr/include/smbsrv/mac_cifs.h sparc
+usr/include/smbsrv/mailslot.h sparc
+usr/include/smbsrv/mbuf.h sparc
+usr/include/smbsrv/mlrpc.h sparc
+usr/include/smbsrv/mlsvc.h sparc
+usr/include/smbsrv/mlsvc_util.h sparc
+usr/include/smbsrv/msgbuf.h sparc
+usr/include/smbsrv/ndr.h sparc
+usr/include/smbsrv/netbios.h sparc
+usr/include/smbsrv/netrauth.h sparc
+usr/include/smbsrv/nmpipes.h sparc
+usr/include/smbsrv/ntaccess.h sparc
+usr/include/smbsrv/nterror.h sparc
+usr/include/smbsrv/ntifs.h sparc
+usr/include/smbsrv/ntlocale.h sparc
+usr/include/smbsrv/ntsid.h sparc
+usr/include/smbsrv/ntstatus.h sparc
+usr/include/smbsrv/oem.h sparc
+usr/include/smbsrv/samlib.h sparc
+usr/include/smbsrv/smb.h sparc
+usr/include/smbsrv/smb_common_door.h sparc
+usr/include/smbsrv/smb_door_svc.h sparc
+usr/include/smbsrv/smb_fsd.h sparc
+usr/include/smbsrv/smb_fsops.h sparc
+usr/include/smbsrv/smb_i18n.h sparc
+usr/include/smbsrv/smb_idmap.h sparc
+usr/include/smbsrv/smb_incl.h sparc
+usr/include/smbsrv/smb_ioctl.h sparc
+usr/include/smbsrv/smb_kproto.h sparc
+usr/include/smbsrv/smb_privilege.h sparc
+usr/include/smbsrv/smb_secdesc.h sparc
+usr/include/smbsrv/smb_svc_sm.h sparc
+usr/include/smbsrv/smb_token.h sparc
+usr/include/smbsrv/smb_vops.h sparc
+usr/include/smbsrv/smb_winpipe.h sparc
+usr/include/smbsrv/smb_xdr.h sparc
+usr/include/smbsrv/smbfmt.h sparc
+usr/include/smbsrv/smbinfo.h sparc
+usr/include/smbsrv/smbtrans.h sparc
+usr/include/smbsrv/smbvar.h sparc
+usr/include/smbsrv/string.h sparc
+usr/include/smbsrv/svrapi.h sparc
+usr/include/smbsrv/winioctl.h sparc
+usr/include/smbsrv/winsvc.h sparc
+usr/include/smbsrv/wintypes.h sparc
+#
+# Private/Internal ndl files of smbsrv. Do not ship.
+#
+usr/include/smbsrv/ndl sparc
+usr/include/smbsrv/ndl/dssetup.ndl sparc
+usr/include/smbsrv/ndl/eventlog.ndl sparc
+usr/include/smbsrv/ndl/llsrpc.ndl sparc
+usr/include/smbsrv/ndl/lsarpc.ndl sparc
+usr/include/smbsrv/ndl/ndrtypes.ndl sparc
+usr/include/smbsrv/ndl/netdfs.ndl sparc
+usr/include/smbsrv/ndl/netlogon.ndl sparc
+usr/include/smbsrv/ndl/rpcpdu.ndl sparc
+usr/include/smbsrv/ndl/samrpc.ndl sparc
+usr/include/smbsrv/ndl/spoolss.ndl sparc
+usr/include/smbsrv/ndl/srvsvc.ndl sparc
+usr/include/smbsrv/ndl/svcctl.ndl sparc
+usr/include/smbsrv/ndl/winreg.ndl sparc
+#
+# Private/Internal dtrace scripts of smbsrv. Do not ship.
+#
+usr/lib/smbsrv/dtrace sparc
+usr/lib/smbsrv/dtrace/msrpc.d sparc
+usr/lib/smbsrv/dtrace/smbnode.d sparc
+usr/lib/smbsrv/dtrace/smbvfs.d sparc
+usr/lib/smbsrv/dtrace/stype.d sparc
+#
+# Private dirent, extended to include flags, for use by SMB server
+#
+usr/include/sys/extdirent.h sparc
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index 15c7ecefc9..26fb0ad277 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -167,6 +167,7 @@ all_zones_files="
etc/user_attr
etc/uucp/[A-Z]*
etc/vfstab
+ var/smb/*
var/spool/cron/crontabs/*
var/yp/Makefile
var/yp/aliases
diff --git a/usr/src/uts/Makefile b/usr/src/uts/Makefile
index ccba9de179..82b011f368 100644
--- a/usr/src/uts/Makefile
+++ b/usr/src/uts/Makefile
@@ -96,7 +96,7 @@ COMMON_HDRDIRS= common/des common/fs common/gssapi common/inet common/net \
common/netinet common/nfs common/rpc common/sys common/vm \
common/c2 common/pcmcia/sys common/rpcsvc common/inet/kssl \
common/inet/nca common/inet/ipf/netinet common/ipp common/idmap \
- common/sharefs
+ common/sharefs common/smbsrv
# These aren't the only headers in closed. But the other directories
# are simple enough that they can be driven from the src tree.
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index c86259c8b1..a4d01364f1 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -175,9 +175,9 @@ GENUNIX_OBJS += \
ioctl.o \
issetugid.o \
ippconf.o \
- kiconv.o \
- kdi.o \
kcpc.o \
+ kdi.o \
+ kiconv.o \
kmem.o \
ksyms_snapshot.o \
l_strplumb.o \
@@ -359,6 +359,8 @@ GENUNIX_OBJS += \
watchpoint.o \
yield.o \
scsi_confdata.o \
+ xattr.o \
+ xattr_common.o \
xdr_mblk.o \
xdr_mem.o \
xdr.o \
@@ -878,6 +880,120 @@ NFSSRV_OBJS += nfs_server.o nfs_srv.o nfs3_srv.o \
nfs4_srv_ns.o nfs4_db.o nfs4_srv_deleg.o \
nfs4_deleg_ops.o nfs4_srv_readdir.o nfs4_dispatch.o
+SMBSRV_SHARED_OBJS += \
+ smb_match.o \
+ smb_msgbuf.o \
+ smb_oem.o \
+ smb_opmlang.o \
+ smb_strcase.o \
+ smb_string.o \
+ smb_utf8.o \
+ smb_common_door_decode.o \
+ smb_xdr_utils.o \
+ smb_token.o \
+ smb_token_xdr.o \
+ smb_sid.o \
+ smb_status_xlat.o \
+ smb_native.o \
+ smb_netbios_util.o \
+ smb_share_door_decode.o
+
+SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \
+ smb_acl.o \
+ smb_alloc.o \
+ smb_books.o \
+ smb_check_directory.o \
+ smb_close.o \
+ smb_common_lock.o \
+ smb_common_open.o \
+ smb_common_search.o \
+ smb_common_transact.o \
+ smb_common_tree.o \
+ smb_copy.o \
+ smb_create.o \
+ smb_create_directory.o \
+ smb_delete.o \
+ smb_delete_directory.o \
+ smb_dispatch.o \
+ smb_echo.o \
+ smb_fem.o \
+ smb_find.o \
+ smb_find_notify_close.o \
+ smb_find_unique.o \
+ smb_flush.o \
+ smb_forward.o \
+ smb_fsd.o \
+ smb_fsops.o \
+ smb_init.o \
+ smb_kdoor_encdec.o \
+ smb_kdoor_ops.o \
+ smb_kdoor_clnt.o \
+ smb_kdoor_srv.o \
+ smb_lock_byte_range.o \
+ smb_lock_svc.o \
+ smb_locking_andx.o \
+ smb_logoff_andx.o \
+ smb_mangle_name.o \
+ smb_mbuf_marshaling.o \
+ smb_memory_manager.o \
+ smb_mbuf_util.o \
+ smb_move.o \
+ smb_negotiate.o \
+ smb_net.o \
+ smb_node.o \
+ smb_nt_cancel.o \
+ smb_nt_create_andx.o \
+ smb_nt_transact_create.o \
+ smb_nt_transact_ioctl.o \
+ smb_nt_transact_notify_change.o \
+ smb_nt_transact_security.o \
+ smb_odir.o \
+ smb_ofile.o \
+ smb_open_andx.o \
+ smb_path_name_reduction.o \
+ smb_print.o \
+ smb_process_exit.o \
+ smb_query_information.o \
+ smb_query_information2.o \
+ smb_query_information_disk.o \
+ smb_read.o \
+ smb_rename.o \
+ smb_rpc.o \
+ smb_sd.o \
+ smb_search.o \
+ smb_seek.o \
+ smb_session.o \
+ smb_session_setup_andx.o \
+ smb_svc_sm.o \
+ smb_set_information.o \
+ smb_set_information2.o \
+ smb_signing.o \
+ smb_share_kdoor_client.o \
+ smb_tree.o \
+ smb_trans2_create_directory.o \
+ smb_trans2_dfs.o \
+ smb_trans2_find.o \
+ smb_trans2_open2.o \
+ smb_trans2_query_file_info.o \
+ smb_trans2_query_fs_information.o \
+ smb_trans2_query_path_info.o \
+ smb_trans2_set_file_information.o \
+ smb_trans2_set_information.o \
+ smb_trans2_set_path_information.o \
+ smb_tree_connect.o \
+ smb_tree_connect_andx.o \
+ smb_tree_disconnect.o \
+ smb_unlock_byte_range.o \
+ smb_upcalls.o \
+ smb_user.o \
+ smb_util.o \
+ smb_vfs.o \
+ smb_vops.o \
+ smb_winpipe.o \
+ smb_write.o \
+ smb_write_raw.o \
+ smb_xlate.o
+
PCFS_OBJS += pc_alloc.o pc_dir.o pc_node.o pc_subr.o \
pc_vfsops.o pc_vnops.o
@@ -1006,6 +1122,7 @@ ZFS_OBJS += \
zfs_acl.o \
zfs_ctldir.o \
zfs_dir.o \
+ zfs_fuid.o \
zfs_ioctl.o \
zfs_log.o \
zfs_replay.o \
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index d843b1b9b4..9e7f6a84a5 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -222,6 +222,14 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/nfs/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(COMMONBASE)/smbsrv/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/smbsrv/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/objfs/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -270,6 +278,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/zfs/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(COMMONBASE)/xattr/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(COMMONBASE)/zfs/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1142,6 +1154,12 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/mntfs/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/namefs/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(COMMONBASE)/smbsrv/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/smbsrv/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/nfs/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
@@ -1184,6 +1202,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/ufs_log/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/zfs/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(COMMONBASE)/xattr/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(COMMONBASE)/zfs/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/brand/lx/autofs/lx_autofs.c b/usr/src/uts/common/brand/lx/autofs/lx_autofs.c
index b40b508625..c4c9e96815 100644
--- a/usr/src/uts/common/brand/lx/autofs/lx_autofs.c
+++ b/usr/src/uts/common/brand/lx/autofs/lx_autofs.c
@@ -442,7 +442,7 @@ i_fifo_lookup(pid_t pgrp, int fd, file_t **fpp_wr, file_t **fpp_rd)
}
/*
- * We need to drop fi_lock before we can try to aquire f_tlock
+ * We need to drop fi_lock before we can try to acquire f_tlock
* the good news is that the file pointers are protected because
* we're still holding uf_lock.
*/
@@ -707,7 +707,7 @@ i_bs_readdir(vnode_t *dvp, list_t *dir_stack, list_t *file_stack)
iov.iov_len = dlen;
(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
- if (VOP_READDIR(dvp, &uio, kcred, &eof) != 0) {
+ if (VOP_READDIR(dvp, &uio, kcred, &eof, NULL, 0) != 0) {
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
kmem_free(dbuf, dlen);
return (-1);
@@ -727,8 +727,8 @@ i_bs_readdir(vnode_t *dvp, list_t *dir_stack, list_t *file_stack)
if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
continue;
- if (VOP_LOOKUP(dvp,
- nm, &vp, NULL, 0, NULL, kcred) != 0) {
+ if (VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL) != 0) {
kmem_free(dbuf, dlen);
return (-1);
}
@@ -763,7 +763,8 @@ i_bs_destroy(vnode_t *dvp, char *path)
char *dpath, *fpath;
int ret;
- if (VOP_LOOKUP(dvp, path, &vp, NULL, 0, NULL, kcred) != 0) {
+ if (VOP_LOOKUP(dvp, path, &vp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL) != 0) {
/* A directory entry with this name doesn't actually exist. */
return;
}
@@ -771,7 +772,7 @@ i_bs_destroy(vnode_t *dvp, char *path)
if ((vp->v_type & VDIR) == 0) {
/* Easy, the directory entry is a file so delete it. */
VN_RELE(vp);
- (void) VOP_REMOVE(dvp, path, kcred);
+ (void) VOP_REMOVE(dvp, path, kcred, NULL, 0);
return;
}
@@ -796,7 +797,7 @@ i_bs_destroy(vnode_t *dvp, char *path)
if (i_bs_readdir(dvp, &search_stack, NULL) != 0)
goto exit;
- /* Save the current directory a seperate stack. */
+ /* Save the current directory a separate stack. */
i_stack_push(&dir_stack, (caddr_t)pdvp, (caddr_t)dvp, dpath);
}
@@ -818,7 +819,7 @@ i_bs_destroy(vnode_t *dvp, char *path)
while (i_stack_pop(&file_stack,
NULL, (caddr_t *)&vp, &fpath) == 0) {
VN_RELE(vp)
- ret = VOP_REMOVE(dvp, fpath, kcred);
+ ret = VOP_REMOVE(dvp, fpath, kcred, NULL, 0);
i_strfree(fpath);
if (ret != 0) {
i_strfree(dpath);
@@ -828,7 +829,7 @@ i_bs_destroy(vnode_t *dvp, char *path)
/* Delete this directory. */
VN_RELE(dvp);
- ret = VOP_RMDIR(pdvp, dpath, pdvp, kcred);
+ ret = VOP_RMDIR(pdvp, dpath, pdvp, kcred, NULL, 0);
i_strfree(dpath);
if (ret != 0)
goto exit;
@@ -862,7 +863,7 @@ i_bs_create(vnode_t *dvp, char *bs_name)
vattr.va_mode = 0755; /* u+rwx,og=rx */
vattr.va_mask = AT_TYPE|AT_MODE;
- if (VOP_MKDIR(dvp, bs_name, &vattr, &vp, kcred) != 0)
+ if (VOP_MKDIR(dvp, bs_name, &vattr, &vp, kcred, NULL, 0, NULL) != 0)
return (NULL);
return (vp);
}
@@ -1220,24 +1221,27 @@ static const fs_operation_def_t lx_autofs_vfstops[] = {
* the underlying filesystem we're mounted on.
*/
static int
-lx_autofs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+lx_autofs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ctp)
{
vnode_t *uvp = vp->v_data;
- return (VOP_CLOSE(uvp, flag, count, offset, cr));
+ return (VOP_CLOSE(uvp, flag, count, offset, cr, ctp));
}
static int
-lx_autofs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+lx_autofs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ctp, int flags)
{
vnode_t *uvp = vp->v_data;
- return (VOP_READDIR(uvp, uiop, cr, eofp));
+ return (VOP_READDIR(uvp, uiop, cr, eofp, ctp, flags));
}
static int
-lx_autofs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+lx_autofs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ctp)
{
vnode_t *uvp = vp->v_data;
- return (VOP_ACCESS(uvp, mode, flags, cr));
+ return (VOP_ACCESS(uvp, mode, flags, cr, ctp));
}
static int
@@ -1256,7 +1260,8 @@ lx_autofs_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
/*ARGSUSED*/
static int
-lx_autofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+lx_autofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ctp, int flags)
{
vnode_t *udvp = dvp->v_data;
@@ -1269,10 +1274,10 @@ lx_autofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
*/
if (vn_matchops(cdir, lx_autofs_vn_ops)) {
vnode_t *ucdir = cdir->v_data;
- return (VOP_RMDIR(udvp, nm, ucdir, cr));
+ return (VOP_RMDIR(udvp, nm, ucdir, cr, ctp, flags));
}
- return (VOP_RMDIR(udvp, nm, cdir, cr));
+ return (VOP_RMDIR(udvp, nm, cdir, cr, ctp, flags));
}
/*
@@ -1280,17 +1285,17 @@ lx_autofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
*
* For some VOP entry points we will first pass the request on to
* the underlying filesystem we're mounted on. If there's an error
- * then we immediatly return the error, but if the request succeedes
+ * then we immediately return the error, but if the request succeeds
* we have to do some extra work before returning.
*/
static int
-lx_autofs_open(vnode_t **vpp, int flag, cred_t *cr)
+lx_autofs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ctp)
{
vnode_t *ovp = *vpp;
vnode_t *uvp = ovp->v_data;
int error;
- if ((error = VOP_OPEN(&uvp, flag, cr)) != 0)
+ if ((error = VOP_OPEN(&uvp, flag, cr, ctp)) != 0)
return (error);
/* Check for clone opens. */
@@ -1304,12 +1309,13 @@ lx_autofs_open(vnode_t **vpp, int flag, cred_t *cr)
}
static int
-lx_autofs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+lx_autofs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ctp)
{
vnode_t *uvp = vp->v_data;
int error;
- if ((error = VOP_GETATTR(uvp, vap, flags, cr)) != 0)
+ if ((error = VOP_GETATTR(uvp, vap, flags, cr, ctp)) != 0)
return (error);
/* Update the attributes with our filesystem id. */
@@ -1319,13 +1325,14 @@ lx_autofs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
static int
lx_autofs_mkdir(vnode_t *dvp, char *nm, struct vattr *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ctp, int flags, vsecattr_t *vsecp)
{
vnode_t *udvp = dvp->v_data;
vnode_t *uvp = NULL;
int error;
- if ((error = VOP_MKDIR(udvp, nm, vap, &uvp, cr)) != 0)
+ if ((error = VOP_MKDIR(udvp, nm, vap, &uvp, cr,
+ ctp, flags, vsecp)) != 0)
return (error);
/* Update the attributes with our filesystem id. */
@@ -1341,7 +1348,7 @@ lx_autofs_mkdir(vnode_t *dvp, char *nm, struct vattr *vap, vnode_t **vpp,
*/
/*ARGSUSED*/
static void
-lx_autofs_inactive(struct vnode *vp, struct cred *cr)
+lx_autofs_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ctp)
{
lx_autofs_vfs_t *data = vp->v_vfsp->vfs_data;
@@ -1374,14 +1381,16 @@ lx_autofs_inactive(struct vnode *vp, struct cred *cr)
static int
lx_autofs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ctp,
+ int *direntflags, pathname_t *realpnp)
{
vnode_t *udvp = dvp->v_data;
vnode_t *uvp = NULL;
int error;
/* First try to lookup if this path component already exitst. */
- if ((error = VOP_LOOKUP(udvp, nm, &uvp, pnp, flags, rdir, cr)) == 0) {
+ if ((error = VOP_LOOKUP(udvp, nm, &uvp, pnp, flags, rdir, cr, ctp,
+ direntflags, realpnp)) == 0) {
*vpp = i_vn_alloc(dvp->v_vfsp, uvp);
return (0);
}
@@ -1395,7 +1404,8 @@ lx_autofs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
return (error);
/* Retry the lookup operation. */
- if ((error = VOP_LOOKUP(udvp, nm, &uvp, pnp, flags, rdir, cr)) == 0) {
+ if ((error = VOP_LOOKUP(udvp, nm, &uvp, pnp, flags, rdir, cr, ctp,
+ direntflags, realpnp)) == 0) {
*vpp = i_vn_alloc(dvp->v_vfsp, uvp);
return (0);
}
@@ -1405,7 +1415,7 @@ lx_autofs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
/*ARGSUSED*/
static int
lx_autofs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr,
- int *rvalp)
+ int *rvalp, caller_context_t *ctp)
{
vnode_t *uvp = vp->v_data;
@@ -1421,7 +1431,7 @@ lx_autofs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr,
}
/* Pass any remaining ioctl on. */
- return (VOP_IOCTL(uvp, cmd, arg, mode, cr, rvalp));
+ return (VOP_IOCTL(uvp, cmd, arg, mode, cr, rvalp, ctp));
}
/*
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
index a09f9fb2b7..588ca2e422 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
@@ -32,7 +32,7 @@
*
* In order to preserve Solaris' security policy. This file system's
* functionality does not override Solaris' security policies even if
- * that means breaking Linux compatability.
+ * that means breaking Linux compatibility.
*
* Linux has no concept of lwps so we only implement procs here as in the
* old /proc interface.
@@ -75,19 +75,23 @@ extern time_t boot_time;
*/
vnodeops_t *lxpr_vnodeops;
-static int lxpr_open(vnode_t **, int, cred_t *);
-static int lxpr_close(vnode_t *, int, int, offset_t, cred_t *);
+static int lxpr_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int lxpr_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
static int lxpr_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
-static int lxpr_getattr(vnode_t *, vattr_t *, int, cred_t *);
-static int lxpr_access(vnode_t *, int, int, cred_t *);
+static int lxpr_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
+static int lxpr_access(vnode_t *, int, int, cred_t *, caller_context_t *);
static int lxpr_lookup(vnode_t *, char *, vnode_t **,
- pathname_t *, int, vnode_t *, cred_t *);
-static int lxpr_readdir(vnode_t *, uio_t *, cred_t *, int *);
-static int lxpr_readlink(vnode_t *, uio_t *, cred_t *);
-static int lxpr_cmp(vnode_t *, vnode_t *);
-static int lxpr_realvp(vnode_t *, vnode_t **);
+ pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
+ pathname_t *);
+static int lxpr_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
+static int lxpr_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *);
+static int lxpr_cmp(vnode_t *, vnode_t *, caller_context_t *);
+static int lxpr_realvp(vnode_t *, vnode_t **, caller_context_t *);
static int lxpr_sync(void);
-static void lxpr_inactive(vnode_t *, cred_t *);
+static void lxpr_inactive(vnode_t *, cred_t *, caller_context_t *);
static vnode_t *lxpr_lookup_procdir(vnode_t *, char *);
static vnode_t *lxpr_lookup_piddir(vnode_t *, char *);
@@ -243,7 +247,7 @@ static lxpr_dirent_t netdir[] = {
* lxpr_open(): Vnode operation for VOP_OPEN()
*/
static int
-lxpr_open(vnode_t **vpp, int flag, cred_t *cr)
+lxpr_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *vp = *vpp;
lxpr_node_t *lxpnp = VTOLXP(vp);
@@ -272,7 +276,7 @@ lxpr_open(vnode_t **vpp, int flag, cred_t *cr)
* Need to hold rvp since VOP_OPEN() may release it.
*/
VN_HOLD(rvp);
- error = VOP_OPEN(&rvp, flag, cr);
+ error = VOP_OPEN(&rvp, flag, cr, ct);
if (error) {
VN_RELE(rvp);
} else {
@@ -317,7 +321,8 @@ lxpr_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
static int
-lxpr_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+lxpr_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
lxpr_node_t *lxpr = VTOLXP(vp);
lxpr_nodetype_t type = lxpr->lxpr_type;
@@ -705,7 +710,8 @@ lxpr_read_pid_maps(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
*buf = '\0';
if (pbuf->vp != NULL) {
vattr.va_mask = AT_FSID | AT_NODEID;
- if (VOP_GETATTR(pbuf->vp, &vattr, 0, CRED()) == 0) {
+ if (VOP_GETATTR(pbuf->vp, &vattr, 0, CRED(),
+ NULL) == 0) {
maj = getmajor(vattr.va_fsid);
min = getminor(vattr.va_fsid);
inode = vattr.va_nodeid;
@@ -2042,7 +2048,8 @@ lxpr_read_fd(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
* lxpr_getattr(): Vnode operation for VOP_GETATTR()
*/
static int
-lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
register lxpr_node_t *lxpnp = VTOLXP(vp);
lxpr_nodetype_t type = lxpnp->lxpr_type;
@@ -2060,14 +2067,14 @@ lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/*
* withold attribute information to owner or root
*/
- if ((error = VOP_ACCESS(rvp, 0, 0, cr)) != 0) {
+ if ((error = VOP_ACCESS(rvp, 0, 0, cr, ct)) != 0) {
return (error);
}
/*
* now its attributes
*/
- if ((error = VOP_GETATTR(rvp, vap, flags, cr)) != 0) {
+ if ((error = VOP_GETATTR(rvp, vap, flags, cr, ct)) != 0) {
return (error);
}
@@ -2122,7 +2129,7 @@ lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
* lxpr_access(): Vnode operation for VOP_ACCESS()
*/
static int
-lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
lxpr_node_t *lxpnp = VTOLXP(vp);
int shift = 0;
@@ -2162,7 +2169,7 @@ lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr)
/*
* For these we use the underlying vnode's accessibility.
*/
- return (VOP_ACCESS(lxpnp->lxpr_realvp, mode, flags, cr));
+ return (VOP_ACCESS(lxpnp->lxpr_realvp, mode, flags, cr, ct));
}
/* If user is root allow access regardless of permission bits */
@@ -2207,7 +2214,8 @@ lxpr_lookup_not_a_dir(vnode_t *dp, char *comp)
/* ARGSUSED */
static int
lxpr_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
lxpr_node_t *lxpnp = VTOLXP(dp);
lxpr_nodetype_t type = lxpnp->lxpr_type;
@@ -2227,7 +2235,7 @@ lxpr_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
/*
* restrict lookup permission to owner or root
*/
- if ((error = lxpr_access(dp, VEXEC, 0, cr)) != 0) {
+ if ((error = lxpr_access(dp, VEXEC, 0, cr, ct)) != 0) {
return (error);
}
@@ -2477,7 +2485,8 @@ lxpr_lookup_procdir(vnode_t *dp, char *comp)
*/
/* ARGSUSED */
static int
-lxpr_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp)
+lxpr_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
lxpr_node_t *lxpnp = VTOLXP(dp);
lxpr_nodetype_t type = lxpnp->lxpr_type;
@@ -2499,7 +2508,7 @@ lxpr_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp)
/*
* restrict readdir permission to owner or root
*/
- if ((error = lxpr_access(dp, VREAD, 0, cr)) != 0)
+ if ((error = lxpr_access(dp, VREAD, 0, cr, ct)) != 0)
return (error);
uoffset = uiop->uio_offset;
@@ -2909,7 +2918,7 @@ out:
*/
/* ARGSUSED */
static int
-lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
char bp[MAXPATHLEN + 1];
size_t buflen = sizeof (bp);
@@ -2924,7 +2933,7 @@ lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
/* Try to produce a symlink name for anything that has a realvp */
if (rvp != NULL) {
- if ((error = lxpr_access(vp, VREAD, 0, CRED())) != 0)
+ if ((error = lxpr_access(vp, VREAD, 0, CRED(), ct)) != 0)
return (error);
if ((error = vnodetopath(NULL, rvp, bp, buflen, CRED())) != 0)
return (error);
@@ -2971,7 +2980,7 @@ lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
*/
/* ARGSUSED */
static void
-lxpr_inactive(vnode_t *vp, cred_t *cr)
+lxpr_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
lxpr_freenode(VTOLXP(vp));
}
@@ -2995,7 +3004,7 @@ lxpr_sync()
* lxpr_cmp(): Vnode operation for VOP_CMP()
*/
static int
-lxpr_cmp(vnode_t *vp1, vnode_t *vp2)
+lxpr_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
vnode_t *rvp;
@@ -3007,7 +3016,7 @@ lxpr_cmp(vnode_t *vp1, vnode_t *vp2)
vp2 = rvp;
if (vn_matchops(vp1, lxpr_vnodeops) || vn_matchops(vp2, lxpr_vnodeops))
return (vp1 == vp2);
- return (VOP_CMP(vp1, vp2));
+ return (VOP_CMP(vp1, vp2, ct));
}
@@ -3015,13 +3024,13 @@ lxpr_cmp(vnode_t *vp1, vnode_t *vp2)
* lxpr_realvp(): Vnode operation for VOP_REALVP()
*/
static int
-lxpr_realvp(vnode_t *vp, vnode_t **vpp)
+lxpr_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
vnode_t *rvp;
if ((rvp = VTOLXP(vp)->lxpr_realvp) != NULL) {
vp = rvp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
}
diff --git a/usr/src/uts/common/c2/audit.c b/usr/src/uts/common/c2/audit.c
index 944c1e8a28..a01733a956 100644
--- a/usr/src/uts/common/c2/audit.c
+++ b/usr/src/uts/common/c2/audit.c
@@ -468,7 +468,7 @@ audit_addcomponent(struct pathname *pnp)
* flag = 1, path is absolute. Free any saved path and set flag to PAD_ABSPATH.
*
* If the (new) path is absolute, then we have to throw away whatever we have
- * already accumulated since it is being superceeded by new path which is
+ * already accumulated since it is being superseded by new path which is
* anchored at the root.
* Note that if the path is relative, this function does nothing
* TODO:
@@ -641,7 +641,7 @@ file_is_public(struct vattr *attr)
/*
* ROUTINE: AUDIT_ATTRIBUTES
- * PURPOSE: Audit the attributes so we can tell why the error occured
+ * PURPOSE: Audit the attributes so we can tell why the error occurred
* CALLBY: AUDIT_SAVEPATH
* AUDIT_VNCREATE_FINISH
* AUS_FCHOWN...audit_event.c...audit_path.c
@@ -659,7 +659,7 @@ audit_attributes(struct vnode *vp)
if (vp) {
attr.va_mask = AT_ALL;
- if (VOP_GETATTR(vp, &attr, 0, CRED()) != 0)
+ if (VOP_GETATTR(vp, &attr, 0, CRED(), NULL) != 0)
return;
if (file_is_public(&attr) && (tad->tad_ctrl & PAD_PUBLIC_EV)) {
@@ -1047,7 +1047,7 @@ audit_closef(struct file *fp)
*/
if ((vp = fp->f_vnode) != NULL) {
attr.va_mask = AT_ALL;
- getattr_ret = VOP_GETATTR(vp, &attr, 0, CRED());
+ getattr_ret = VOP_GETATTR(vp, &attr, 0, CRED(), NULL);
}
/*
@@ -1294,7 +1294,14 @@ audit_setfsat_path(int argnum)
t_audit_data_t *tad;
struct f_audit_data *fad;
p_audit_data_t *pad; /* current process */
-
+ struct a {
+ long id;
+ long arg1;
+ long arg2;
+ long arg3;
+ long arg4;
+ long arg5;
+ } *uap;
struct b {
long arg1;
long arg2;
@@ -1306,6 +1313,7 @@ audit_setfsat_path(int argnum)
if (clwp == NULL)
return;
uap1 = (struct b *)&clwp->lwp_ap[1];
+ uap = (struct a *)clwp->lwp_ap;
tad = U2A(u);
@@ -1334,6 +1342,10 @@ audit_setfsat_path(int argnum)
return;
}
+ if (uap->id == 9 && tad->tad_atpath != NULL) { /* openattrdir */
+ tad->tad_ctrl |= PAD_ATPATH;
+ return;
+ }
if (tad->tad_atpath != NULL) {
au_pathrele(tad->tad_atpath);
tad->tad_atpath = NULL;
@@ -1373,7 +1385,8 @@ audit_symlink_create(vnode_t *dvp, char *sname, char *target, int error)
if (error)
return;
- error = VOP_LOOKUP(dvp, sname, &vp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(dvp, sname, &vp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error == 0) {
audit_attributes(vp);
VN_RELE(vp);
@@ -1648,7 +1661,7 @@ audit_chdirec(vnode_t *vp, vnode_t **vpp)
* the same object, it will not panic our system
* QUESTION:
* where to decrement the f_count?????????????????
- * seems like I need to set a flag if f_count incrmented through audit_getf
+ * seems like I need to set a flag if f_count incremented through audit_getf
*/
/*ARGSUSED*/
@@ -1898,7 +1911,7 @@ audit_fdsend(fd, fp, error)
}
/*
- * Record privileges sucessfully used and we attempted to use but
+ * Record privileges successfully used and we attempted to use but
* didn't have.
*/
void
diff --git a/usr/src/uts/common/c2/audit_event.c b/usr/src/uts/common/c2/audit_event.c
index d9be55d304..e1ffc61c81 100644
--- a/usr/src/uts/common/c2/audit_event.c
+++ b/usr/src/uts/common/c2/audit_event.c
@@ -1040,6 +1040,9 @@ aui_fsat(au_event_t e)
case 7: /* renameat */
e = AUE_RENAMEAT;
break;
+ case 9: /* __openattrdirat */
+ tad->tad_ctrl |= PAD_SAVPATH;
+ /*FALLTHROUGH*/
default:
e = AUE_NULL;
break;
@@ -1866,7 +1869,7 @@ aus_close(struct t_audit_data *tad)
au_uwrite(au_to_path(fad->fad_aupath));
if ((vp = fp->f_vnode) != NULL) {
attr.va_mask = AT_ALL;
- if (VOP_GETATTR(vp, &attr, 0, CRED()) == 0) {
+ if (VOP_GETATTR(vp, &attr, 0, CRED(), NULL) == 0) {
/*
* When write was not used and the file can be
* considered public, skip the audit.
@@ -4585,7 +4588,7 @@ auf_sendto(struct t_audit_data *tad, int error, rval_t *rval)
}
/*
- * XXX socket(2) may be equivilent to open(2) on a unix domain
+ * XXX socket(2) may be equivalent to open(2) on a unix domain
* socket. This needs investigation.
*/
@@ -4910,7 +4913,7 @@ au_door_lookup(int did)
/*
* Use the underlying vnode (we may be namefs mounted)
*/
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp == NULL || vp->v_type != VDOOR) {
diff --git a/usr/src/uts/common/cpr/cpr_dump.c b/usr/src/uts/common/cpr/cpr_dump.c
index 28fee49bf9..709b50631e 100644
--- a/usr/src/uts/common/cpr/cpr_dump.c
+++ b/usr/src/uts/common/cpr/cpr_dump.c
@@ -1015,7 +1015,8 @@ cpr_write(vnode_t *vp, caddr_t buffer, size_t size)
}
do_polled_io = 1;
- error = VOP_DUMP(vp, cpr_buf, cpr_file_bn, cpr_buf_blocks);
+ error = VOP_DUMP(vp, cpr_buf, cpr_file_bn, cpr_buf_blocks,
+ NULL);
do_polled_io = 0;
CPR_DEBUG(CPR_DEBUG3, "done\n");
@@ -1045,7 +1046,7 @@ cpr_flush_write(vnode_t *vp)
nblk = btod(cpr_wptr - cpr_buf);
do_polled_io = 1;
- error = VOP_DUMP(vp, (caddr_t)cpr_buf, cpr_file_bn, nblk);
+ error = VOP_DUMP(vp, (caddr_t)cpr_buf, cpr_file_bn, nblk, NULL);
do_polled_io = 0;
cpr_file_bn += nblk;
diff --git a/usr/src/uts/common/cpr/cpr_main.c b/usr/src/uts/common/cpr/cpr_main.c
index 65e911cb11..96b1d29534 100644
--- a/usr/src/uts/common/cpr/cpr_main.c
+++ b/usr/src/uts/common/cpr/cpr_main.c
@@ -259,7 +259,7 @@ cpr_log_status(int enable, int *svstat, vnode_t *vp)
*/
if (enable == 0) {
if (error = VOP_IOCTL(vp, _FIOISLOG,
- (uintptr_t)&status, FKIOCTL, CRED(), NULL)) {
+ (uintptr_t)&status, FKIOCTL, CRED(), NULL, NULL)) {
mntpt = vfs_getmntpoint(vp->v_vfsp);
prom_printf("%s: \"%s\", cant get logging "
"status, error %d\n", str, refstr_value(mntpt),
@@ -287,7 +287,7 @@ cpr_log_status(int enable, int *svstat, vnode_t *vp)
*/
if (*svstat == 1) {
error = VOP_IOCTL(vp, cmd, (uintptr_t)&fl,
- FKIOCTL, CRED(), NULL);
+ FKIOCTL, CRED(), NULL, NULL);
if (error) {
mntpt = vfs_getmntpoint(vp->v_vfsp);
prom_printf("%s: \"%s\", cant %s logging, error %d\n",
@@ -338,7 +338,7 @@ cpr_ufs_logging(int enable)
return (error);
cpr_log_status(enable, &def_status, vp);
vfsp = vp->v_vfsp;
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
fname = cpr_build_statefile_path();
@@ -357,7 +357,7 @@ cpr_ufs_logging(int enable)
*/
if (vp->v_vfsp != vfsp && vp->v_type == VREG)
cpr_log_status(enable, &sf_status, vp);
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (0);
@@ -739,7 +739,7 @@ alloc_statefile:
rc = cpr_dump(C_VP);
/*
- * if any error occured during dump, more
+ * if any error occurred during dump, more
* special handling for reusable:
*/
if (rc && cpr_reusable_mode) {
diff --git a/usr/src/uts/common/cpr/cpr_misc.c b/usr/src/uts/common/cpr/cpr_misc.c
index 1ec0452c81..e35789b4a9 100644
--- a/usr/src/uts/common/cpr/cpr_misc.c
+++ b/usr/src/uts/common/cpr/cpr_misc.c
@@ -189,7 +189,7 @@ cpr_get_config(void)
}
err = cpr_rdwr(UIO_READ, vp, cf, sizeof (*cf));
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (err) {
cpr_err(CE_CONT, fmt, "read", config_path, err);
@@ -455,7 +455,7 @@ cpr_alloc_statefile(int alloc_retry)
if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG7))
prom_printf(str);
if (C_VP->v_type != VBLK)
- (void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL);
+ (void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL, NULL);
} else {
/*
* Open an exiting file for writing, the state file needs to be
@@ -501,7 +501,7 @@ cpr_alloc_statefile(int alloc_retry)
* Validate disk blocks allocation for the state file.
* Ask the file system prepare itself for the dump operation.
*/
- if (rc = VOP_DUMPCTL(C_VP, DUMP_ALLOC, NULL)) {
+ if (rc = VOP_DUMPCTL(C_VP, DUMP_ALLOC, NULL, NULL)) {
cpr_err(CE_CONT, "Error allocating "
"blocks for cpr statefile.");
return (rc);
@@ -730,8 +730,8 @@ cpr_statef_close(void)
{
if (C_VP) {
if (!cpr_reusable_mode)
- (void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL);
- (void) VOP_CLOSE(C_VP, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL, NULL);
+ (void) VOP_CLOSE(C_VP, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(C_VP);
C_VP = 0;
}
@@ -771,9 +771,9 @@ cpr_write_deffile(cdef_t *cdef)
if (rc = cpr_rdwr(UIO_WRITE, vp, cdef, sizeof (*cdef)))
str = "write";
- else if (rc = VOP_FSYNC(vp, FSYNC, CRED()))
+ else if (rc = VOP_FSYNC(vp, FSYNC, CRED(), NULL))
str = "fsync";
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (rc) {
@@ -799,7 +799,7 @@ cpr_clear_definfo(void)
return;
mini.magic = mini.reusable = 0;
(void) cpr_rdwr(UIO_WRITE, vp, &mini, sizeof (mini));
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
@@ -818,7 +818,7 @@ cpr_get_reusable_mode(void)
return (0);
rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini));
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (rc == 0 && mini.magic == CPR_DEFAULT_MAGIC)
return (mini.reusable);
diff --git a/usr/src/uts/common/fs/autofs/auto_vnops.c b/usr/src/uts/common/fs/autofs/auto_vnops.c
index 5ffcf57d83..9e1a6ef387 100644
--- a/usr/src/uts/common/fs/autofs/auto_vnops.c
+++ b/usr/src/uts/common/fs/autofs/auto_vnops.c
@@ -53,29 +53,39 @@
/*
* Vnode ops for autofs
*/
-static int auto_open(vnode_t **, int, cred_t *);
-static int auto_close(vnode_t *, int, int, offset_t, cred_t *);
-static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *);
+static int auto_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int auto_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
static int auto_setattr(vnode_t *, vattr_t *, int, cred_t *,
caller_context_t *);
-static int auto_access(vnode_t *, int, int, cred_t *);
+static int auto_access(vnode_t *, int, int, cred_t *, caller_context_t *);
static int auto_lookup(vnode_t *, char *, vnode_t **,
- pathname_t *, int, vnode_t *, cred_t *);
+ pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
+ pathname_t *);
static int auto_create(vnode_t *, char *, vattr_t *, vcexcl_t,
- int, vnode_t **, cred_t *, int);
-static int auto_remove(vnode_t *, char *, cred_t *);
-static int auto_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *);
-static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
-static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *);
-static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *);
-static int auto_readlink(vnode_t *, struct uio *, cred_t *);
-static int auto_fsync(vnode_t *, int, cred_t *);
-static void auto_inactive(vnode_t *, cred_t *);
+ int, vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
+static int auto_remove(vnode_t *, char *, cred_t *, caller_context_t *, int);
+static int auto_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
+ caller_context_t *, int, vsecattr_t *);
+static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
+static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int auto_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int auto_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static void auto_inactive(vnode_t *, cred_t *, caller_context_t *);
static int auto_rwlock(vnode_t *, int, caller_context_t *);
static void auto_rwunlock(vnode_t *vp, int, caller_context_t *);
-static int auto_seek(vnode_t *vp, offset_t, offset_t *);
+static int auto_seek(vnode_t *vp, offset_t, offset_t *, caller_context_t *);
static int auto_trigger_mount(vnode_t *, cred_t *, vnode_t **);
@@ -113,7 +123,7 @@ const fs_operation_def_t auto_vnodeops_template[] = {
/* ARGSUSED */
static int
-auto_open(vnode_t **vpp, int flag, cred_t *cred)
+auto_open(vnode_t **vpp, int flag, cred_t *cred, caller_context_t *ct)
{
vnode_t *newvp;
int error;
@@ -130,9 +140,9 @@ auto_open(vnode_t **vpp, int flag, cred_t *cred)
*/
VN_RELE(*vpp);
*vpp = newvp;
- error = VOP_ACCESS(*vpp, VREAD, 0, cred);
+ error = VOP_ACCESS(*vpp, VREAD, 0, cred, ct);
if (!error)
- error = VOP_OPEN(vpp, flag, cred);
+ error = VOP_OPEN(vpp, flag, cred, ct);
}
done:
@@ -143,13 +153,24 @@ done:
/* ARGSUSED */
static int
-auto_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cred)
+auto_close(
+ vnode_t *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ cred_t *cred,
+ caller_context_t *ct)
{
return (0);
}
static int
-auto_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cred)
+auto_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cred,
+ caller_context_t *ct)
{
fnnode_t *fnp = vntofn(vp);
vnode_t *newvp;
@@ -211,7 +232,7 @@ auto_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cred)
fnp->fn_thread = curthread;
fnp->fn_seen = newvp;
mutex_exit(&fnp->fn_lock);
- error = VOP_GETATTR(newvp, vap, flags, cred);
+ error = VOP_GETATTR(newvp, vap, flags, cred, ct);
VN_RELE(newvp);
mutex_enter(&fnp->fn_lock);
fnp->fn_seen = 0;
@@ -272,7 +293,7 @@ auto_setattr(
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_SETATTR(newvp, vap, flags, cred, NULL);
+ error = VOP_SETATTR(newvp, vap, flags, cred, ct);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -284,7 +305,12 @@ done:
/* ARGSUSED */
static int
-auto_access(vnode_t *vp, int mode, int flags, cred_t *cred)
+auto_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cred,
+ caller_context_t *ct)
{
fnnode_t *fnp = vntofn(vp);
vnode_t *newvp;
@@ -299,7 +325,7 @@ auto_access(vnode_t *vp, int mode, int flags, cred_t *cred)
/*
* Node is mounted on.
*/
- error = VOP_ACCESS(newvp, mode, 0, cred);
+ error = VOP_ACCESS(newvp, mode, 0, cred, ct);
VN_RELE(newvp);
} else {
int shift = 0;
@@ -333,7 +359,10 @@ auto_lookup(
pathname_t *pnp,
int flags,
vnode_t *rdir,
- cred_t *cred)
+ cred_t *cred,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
int error = 0;
vnode_t *newvp = NULL;
@@ -354,7 +383,7 @@ auto_lookup(
return (0);
}
- if (error = VOP_ACCESS(dvp, VEXEC, 0, cred))
+ if (error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct))
return (error);
if (nm[0] == '.' && nm[1] == 0) {
@@ -387,7 +416,8 @@ auto_lookup(
vp = dvp->v_vfsp->vfs_vnodecovered;
VN_HOLD(vp);
vfs_unlock(dvp->v_vfsp);
- error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred);
+ error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred,
+ ct, direntflags, realpnp);
VN_RELE(vp);
return (error);
} else {
@@ -434,7 +464,7 @@ top:
vn_vfsunlock(dvp);
if (!error) {
error = VOP_LOOKUP(newvp, nm, vpp, pnp,
- flags, rdir, cred);
+ flags, rdir, cred, ct, direntflags, realpnp);
VN_RELE(newvp);
}
return (error);
@@ -640,7 +670,9 @@ auto_create(
int mode,
vnode_t **vpp,
cred_t *cred,
- int flag)
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
vnode_t *newvp;
int error;
@@ -658,7 +690,7 @@ auto_create(
error = EROFS;
else
error = VOP_CREATE(newvp, nm, va, excl,
- mode, vpp, cred, flag);
+ mode, vpp, cred, flag, ct, vsecp);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -669,7 +701,12 @@ done:
}
static int
-auto_remove(vnode_t *dvp, char *nm, cred_t *cred)
+auto_remove(
+ vnode_t *dvp,
+ char *nm,
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *newvp;
int error;
@@ -686,7 +723,7 @@ auto_remove(vnode_t *dvp, char *nm, cred_t *cred)
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_REMOVE(newvp, nm, cred);
+ error = VOP_REMOVE(newvp, nm, cred, ct, flags);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -697,7 +734,13 @@ done:
}
static int
-auto_link(vnode_t *tdvp, vnode_t *svp, char *nm, cred_t *cred)
+auto_link(
+ vnode_t *tdvp,
+ vnode_t *svp,
+ char *nm,
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *newvp;
int error;
@@ -731,7 +774,7 @@ auto_link(vnode_t *tdvp, vnode_t *svp, char *nm, cred_t *cred)
goto done;
}
- error = VOP_LINK(newvp, svp, nm, cred);
+ error = VOP_LINK(newvp, svp, nm, cred, ct, flags);
VN_RELE(newvp);
done:
@@ -740,7 +783,14 @@ done:
}
static int
-auto_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+auto_rename(
+ vnode_t *odvp,
+ char *onm,
+ vnode_t *ndvp,
+ char *nnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *o_newvp, *n_newvp;
int error;
@@ -801,7 +851,7 @@ auto_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
goto done;
}
- error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr);
+ error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr, ct, flags);
VN_RELE(o_newvp);
if (n_newvp != ndvp)
VN_RELE(n_newvp);
@@ -812,7 +862,15 @@ done:
}
static int
-auto_mkdir(vnode_t *dvp, char *nm, vattr_t *va, vnode_t **vpp, cred_t *cred)
+auto_mkdir(
+ vnode_t *dvp,
+ char *nm,
+ vattr_t *va,
+ vnode_t **vpp,
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
vnode_t *newvp;
int error;
@@ -829,7 +887,8 @@ auto_mkdir(vnode_t *dvp, char *nm, vattr_t *va, vnode_t **vpp, cred_t *cred)
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_MKDIR(newvp, nm, va, vpp, cred);
+ error = VOP_MKDIR(newvp, nm, va, vpp, cred, ct,
+ flags, vsecp);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -840,7 +899,13 @@ done:
}
static int
-auto_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cred)
+auto_rmdir(
+ vnode_t *dvp,
+ char *nm,
+ vnode_t *cdir,
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *newvp;
int error;
@@ -857,7 +922,7 @@ auto_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cred)
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_RMDIR(newvp, nm, cdir, cred);
+ error = VOP_RMDIR(newvp, nm, cdir, cred, ct, flags);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -874,8 +939,15 @@ static int autofs_nobrowse = 0;
#endif
#define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
+/* ARGSUSED */
static int
-auto_readdir(vnode_t *vp, uio_t *uiop, cred_t *cred, int *eofp)
+auto_readdir(
+ vnode_t *vp,
+ uio_t *uiop,
+ cred_t *cred,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct autofs_rddirargs rda;
autofs_rddirres rd;
@@ -1161,7 +1233,9 @@ auto_symlink(
char *lnknm, /* new entry */
vattr_t *tva,
char *tnm, /* existing entry */
- cred_t *cred)
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *newvp;
int error;
@@ -1179,7 +1253,8 @@ auto_symlink(
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred);
+ error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred,
+ ct, flags);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -1191,7 +1266,7 @@ done:
/* ARGSUSED */
static int
-auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
{
fnnode_t *fnp = vntofn(vp);
int error;
@@ -1217,14 +1292,14 @@ auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
/* ARGSUSED */
static int
-auto_fsync(vnode_t *cp, int syncflag, cred_t *cred)
+auto_fsync(vnode_t *cp, int syncflag, cred_t *cred, caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static void
-auto_inactive(vnode_t *vp, cred_t *cred)
+auto_inactive(vnode_t *vp, cred_t *cred, caller_context_t *ct)
{
fnnode_t *fnp = vntofn(vp);
fnnode_t *dfnp = fnp->fn_parent;
@@ -1287,7 +1362,11 @@ auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
/* ARGSUSED */
static int
-auto_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+auto_seek(
+ struct vnode *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
{
/*
* Return 0 unconditionally, since we expect
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_cnode.c b/usr/src/uts/common/fs/cachefs/cachefs_cnode.c
index 2036c59f20..f57b732eb0 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_cnode.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_cnode.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -133,7 +132,7 @@ cachefs_cnode_idle(struct vnode *vp, cred_t *cr)
unlname, unlcred, vp);
}
- /* reaquire cnode lock */
+ /* reacquire cnode lock */
mutex_enter(&cp->c_statelock);
/* if a timeout occurred */
@@ -1340,7 +1339,7 @@ cachefs_cnode_move(cnode_t *cp)
make_ascii_name(&cp->c_id, oname);
make_ascii_name(&cid, nname);
error = VOP_RENAME(ofgp->fg_dirvp, oname, fgp->fg_dirvp,
- nname, kcred);
+ nname, kcred, NULL, 0);
if (error) {
ffnuke = 1;
#ifdef CFSDEBUG
@@ -1470,7 +1469,8 @@ cachefs_cnode_sync(cnode_t *cp)
cp->c_backvp) {
mutex_enter(&cp->c_statelock);
if (cp->c_backvp) {
- error = VOP_FSYNC(cp->c_backvp, FSYNC, kcred);
+ error = VOP_FSYNC(cp->c_backvp, FSYNC, kcred,
+ NULL);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -1554,7 +1554,7 @@ cachefs_cnode_lostfound(cnode_t *cp, char *rname)
else
namep = "lostfile";
error = VOP_LOOKUP(cachep->c_lostfoundvp, namep, &nvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0)
VN_RELE(nvp);
if (error != ENOENT) {
@@ -1569,7 +1569,7 @@ cachefs_cnode_lostfound(cnode_t *cp, char *rname)
else
namep = namebuf;
error = VOP_LOOKUP(cachep->c_lostfoundvp, namep, &nvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0)
VN_RELE(nvp);
if (error == ENOENT)
@@ -1587,7 +1587,7 @@ cachefs_cnode_lostfound(cnode_t *cp, char *rname)
/* rename the file into the lost+found directory */
error = VOP_RENAME(fgp->fg_dirvp, oname, cachep->c_lostfoundvp,
- namep, kcred);
+ namep, kcred, NULL, 0);
if (error) {
mutex_exit(&cachep->c_contentslock);
goto out;
@@ -1675,7 +1675,7 @@ cachefs_cnode_traverse(fscache_t *fscp, void (*routinep)(cnode_t *))
*/
(routinep)(cp);
- /* reaquire the cnode list lock */
+ /* reacquire the cnode list lock */
mutex_enter(&fgp->fg_cnodelock);
}
@@ -1687,7 +1687,7 @@ cachefs_cnode_traverse(fscache_t *fscp, void (*routinep)(cnode_t *))
VN_RELE(CTOV(ocp));
}
- /* reaquire the fscache lock */
+ /* reacquire the fscache lock */
mutex_enter(&fscp->fs_fslock);
}
@@ -1730,7 +1730,7 @@ cnode_enable_caching(struct cnode *cp)
iovp = cp->c_backvp;
if (iovp) {
(void) VOP_PUTPAGE(iovp, (offset_t)0,
- (uint_t)0, B_INVAL, kcred);
+ (uint_t)0, B_INVAL, kcred, NULL);
}
mutex_enter(&cp->c_statelock);
if (cp->c_backvp) {
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_cod.c b/usr/src/uts/common/fs/cachefs/cachefs_cod.c
index fac80de284..be60ec4f40 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_cod.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_cod.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -93,7 +92,7 @@ c_cod_init_cached_object(fscache_t *fscp, cnode_t *cp, vattr_t *vap,
/* get the attributes */
cp->c_attr.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, NULL);
if (error)
return (error);
} else {
@@ -170,7 +169,7 @@ again:
/* get the file attributes from the back fs */
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
backhit = 1;
if (error)
goto out;
@@ -210,7 +209,7 @@ again:
}
if ((CTOV(cp))->v_type == VREG) {
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error)
goto out;
}
@@ -295,7 +294,7 @@ c_cod_modify_cached_object(struct fscache *fscp, struct cnode *cp, cred_t *cr)
}
attrs.va_mask = AT_ALL;
ASSERT(cp->c_backvp != NULL);
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error) {
mdp->md_vattr.va_mtime.tv_sec = 0;
goto out;
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_dir.c b/usr/src/uts/common/fs/cachefs/cachefs_dir.c
index 8e586946a6..d77b4ab36a 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_dir.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_dir.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -108,7 +107,7 @@ cachefs_dir_look(cnode_t *dcp, char *nm, fid_t *cookiep, uint_t *flagp,
dvp = dcp->c_frontvp;
va.va_mask = AT_SIZE; /* XXX should save dir size */
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error) {
cachefs_inval_object(dcp);
error = ENOTDIR;
@@ -201,7 +200,7 @@ cachefs_dir_new(cnode_t *dcp, cnode_t *cp)
#ifdef CFSDEBUG
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred);
+ error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
if (error)
goto out;
ASSERT(va.va_size == 0);
@@ -307,7 +306,7 @@ cachefs_dir_enter(cnode_t *dcp, char *nm, fid_t *cookiep, cfs_cid_t *cidp,
* Get the current EOF for the directory(data file)
*/
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error) {
cachefs_inval_object(dcp);
error = ENOTDIR;
@@ -465,7 +464,7 @@ cachefs_dir_rmentry(cnode_t *dcp, char *nm)
ASSERT((dcp->c_flags & CN_NOCACHE) == 0);
ASSERT(dvp != NULL);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error) {
cachefs_inval_object(dcp);
error = ENOTDIR;
@@ -624,7 +623,7 @@ cachefs_dir_getentrys(struct cnode *dcp, u_offset_t beg_off,
gdp = (struct dirent64 *)buf;
*cntp = bufsize;
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error) {
*cntp = 0;
*last_offp = 0;
@@ -950,7 +949,7 @@ cachefs_dir_fill_common(cnode_t *dcp, cred_t *cr,
iov.iov_base = buf;
iov.iov_len = MAXBSIZE;
(void) VOP_RWLOCK(backvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(backvp, &uio, cr, &eof);
+ error = VOP_READDIR(backvp, &uio, cr, &eof, NULL, 0);
VOP_RWUNLOCK(backvp, V_WRITELOCK_FALSE, NULL);
if (error)
goto out;
@@ -1017,7 +1016,7 @@ cachefs_dir_empty(cnode_t *dcp)
return (ENOTDIR);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error)
return (ENOTDIR);
@@ -1258,7 +1257,7 @@ cachefs_dir_complete(fscache_t *fscp, vnode_t *backvp, vnode_t *frontvp,
*/
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(frontvp, &va, 0, cr);
+ error = VOP_GETATTR(frontvp, &va, 0, cr, NULL);
if (error)
goto out;
@@ -1296,7 +1295,7 @@ cachefs_dir_complete(fscache_t *fscp, vnode_t *backvp, vnode_t *frontvp,
error = VOP_LOOKUP(backvp, dep->d_name,
&entry_vp, (struct pathname *)NULL, 0,
- (vnode_t *)NULL, cr);
+ (vnode_t *)NULL, cr, NULL, NULL, NULL);
if (error) {
/* lookup on .. in / on coc gets ENOENT */
if (error == ENOENT) {
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_dlog.c b/usr/src/uts/common/fs/cachefs/cachefs_dlog.c
index e3ad1bc9de..5781d7a4d1 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_dlog.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_dlog.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -203,7 +202,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
/* see if the log file exists */
error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
- &fscp->fs_dlogfile, NULL, 0, NULL, kcred);
+ &fscp->fs_dlogfile, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error && (createfile == 0))
goto out;
@@ -217,7 +216,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
vattr.va_type = VREG;
vattr.va_mask = AT_TYPE|AT_MODE|AT_UID|AT_GID;
error = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
- &vattr, 0, 0666, &fscp->fs_dlogfile, kcred, 0);
+ &vattr, 0, 0666, &fscp->fs_dlogfile, kcred, 0, NULL, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -246,7 +245,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
vattr.va_type = VREG;
vattr.va_mask = AT_TYPE|AT_MODE|AT_UID|AT_GID;
error = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_DMAP_FILE,
- &vattr, 0, 0666, &fscp->fs_dmapfile, kcred, 0);
+ &vattr, 0, 0666, &fscp->fs_dmapfile, kcred, 0, NULL, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -272,7 +271,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
/* find the end of the log file */
vattr.va_mask = AT_ALL;
- error = VOP_GETATTR(fscp->fs_dlogfile, &vattr, 0, kcred);
+ error = VOP_GETATTR(fscp->fs_dlogfile, &vattr, 0, kcred, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -328,7 +327,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DMAP_FILE,
- &fscp->fs_dmapfile, NULL, 0, NULL, kcred);
+ &fscp->fs_dmapfile, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -339,7 +338,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
}
vattr.va_mask = AT_ALL;
- error = VOP_GETATTR(fscp->fs_dmapfile, &vattr, 0, kcred);
+ error = VOP_GETATTR(fscp->fs_dmapfile, &vattr, 0, kcred, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -359,13 +358,13 @@ out:
VN_RELE(fscp->fs_dlogfile);
fscp->fs_dlogfile = NULL;
(void) VOP_REMOVE(fscp->fs_fscdirvp,
- CACHEFS_DLOG_FILE, kcred);
+ CACHEFS_DLOG_FILE, kcred, NULL, 0);
}
if (fscp->fs_dmapfile) {
VN_RELE(fscp->fs_dmapfile);
fscp->fs_dmapfile = NULL;
(void) VOP_REMOVE(fscp->fs_fscdirvp,
- CACHEFS_DMAP_FILE, kcred);
+ CACHEFS_DMAP_FILE, kcred, NULL, 0);
}
}
if (lookupdone) {
@@ -528,7 +527,7 @@ out:
}
/*
- * Commmits a previously written dlog message.
+ * Commits a previously written dlog message.
*/
int
cachefs_dlog_commit(fscache_t *fscp, off_t offset, int error)
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c b/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c
index 2da9b2bfda..9e430fa0fb 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c
@@ -224,12 +224,12 @@ filegrp_create(struct fscache *fscp, cfs_cid_t *cidp)
fgp->fg_offsets = NULL;
fgp->fg_alloclist = NULL;
- fgp->fg_headersize = (u_int)sizeof (struct attrcache_header) +
- (fgsize * (u_int)sizeof (struct attrcache_index)) +
+ fgp->fg_headersize = (uint_t)sizeof (struct attrcache_header) +
+ (fgsize * (uint_t)sizeof (struct attrcache_index)) +
((fgsize + 7) >> 3);
fgp->fg_filesize = fgp->fg_headersize +
- (fgsize * (u_int)sizeof (struct cfs_cachefs_metadata));
+ (fgsize * (uint_t)sizeof (struct cfs_cachefs_metadata));
flags = fscp->fs_flags;
if (flags & CFS_FS_READ) {
@@ -324,7 +324,8 @@ filegrp_destroy(filegrp_t *fgp)
/* remove the attrcache file */
make_ascii_name(&fgp->fg_id, name);
fname = name;
- error = VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred);
+ error = VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred,
+ NULL, 0);
if (error) {
cmn_err(CE_WARN,
"cachefs: error in cache, run fsck");
@@ -452,7 +453,7 @@ filegrp_hold(filegrp_t *fgp)
* Returns:
* Preconditions:
* precond(fgp is a valid filegrp object)
- * precond(number of refrences to filegrp is > 0)
+ * precond(number of references to filegrp is > 0)
*/
void
@@ -498,7 +499,7 @@ filegrp_rele(filegrp_t *fgp)
* Returns 0 for success or a non-zero errno.
* Preconditions:
* precond(fgp is a valid filegrp object)
- * precond(number of refrences to filegrp is > 0)
+ * precond(number of references to filegrp is > 0)
* precond(filegrp is writable)
*/
@@ -586,7 +587,7 @@ out:
* Preconditions:
* precond(fgp is a valid filegrp object)
* precond(filegrp is writable)
- * precond(number of refrences to filegrp is > 0)
+ * precond(number of references to filegrp is > 0)
* precond(number of front file references is > 0)
*/
@@ -620,7 +621,7 @@ filegrp_ffrele(filegrp_t *fgp)
make_ascii_name(&fgp->fg_id, name);
fname = name;
error = VOP_RMDIR(fscp->fs_fscdirvp, fname,
- fscp->fs_fscdirvp, kcred);
+ fscp->fs_fscdirvp, kcred, NULL, 0);
if (error == 0) {
cachefs_freefile(fscp->fs_cache);
cachefs_freeblocks(fscp->fs_cache, 1,
@@ -687,7 +688,7 @@ filegrp_sync(filegrp_t *fgp)
kcred, NULL);
if (error == 0)
- error = VOP_FSYNC(fgp->fg_attrvp, FSYNC, kcred);
+ error = VOP_FSYNC(fgp->fg_attrvp, FSYNC, kcred, NULL);
if (error == 0)
fgp->fg_flags &= ~CFS_FG_UPDATED;
@@ -746,7 +747,7 @@ filegrp_read_metadata(filegrp_t *fgp, cfs_cid_t *cidp,
/* see if metadata was ever written */
- index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
+ index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
if (fgp->fg_offsets[index].ach_written == 0) {
mutex_exit(&fgp->fg_mutex);
return (ENOENT);
@@ -794,7 +795,7 @@ filegrp_create_metadata(filegrp_t *fgp, struct cachefs_metadata *md,
cachefscache_t *cachep = fscp->fs_cache;
int slot;
int bitno;
- u_char mask;
+ uchar_t mask;
int last;
int xx;
int index;
@@ -816,13 +817,13 @@ filegrp_create_metadata(filegrp_t *fgp, struct cachefs_metadata *md,
return (0);
}
- index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
+ index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
ASSERT(index < fgp->fg_fscp->fs_info.fi_fgsize);
last = (((fgp->fg_fscp->fs_info.fi_fgsize + 7) & ~(7)) / 8);
for (xx = 0; xx < last; xx++) {
- if (fgp->fg_alloclist[xx] != (u_char)0xff) {
+ if (fgp->fg_alloclist[xx] != (uchar_t)0xff) {
for (mask = 1, bitno = 0; bitno < 8; bitno++) {
if ((mask & fgp->fg_alloclist[xx]) == 0) {
slot = (xx * 8) + bitno;
@@ -948,7 +949,7 @@ filegrp_write_metadata(filegrp_t *fgp, cfs_cid_t *cidp,
}
/* mark metadata as having been written */
- index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
+ index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
fgp->fg_offsets[index].ach_written = 1;
/* update number of blocks used by the attrcache file */
@@ -983,7 +984,7 @@ filegrp_destroy_metadata(filegrp_t *fgp, cfs_cid_t *cidp)
{
int i;
int bitno;
- u_char mask = 1;
+ uchar_t mask = 1;
int slot;
@@ -1064,7 +1065,7 @@ filegrp_list_find(struct fscache *fscp, cfs_cid_t *cidp)
fileno = fxx * fgsize;
/* hash into array of file groups */
- findex = (int) (fxx & (CFS_FS_FGP_BUCKET_SIZE - 1));
+ findex = (int)(fxx & (CFS_FS_FGP_BUCKET_SIZE - 1));
/* search set of file groups for this hash bucket */
for (fgp = fscp->fs_filegrp[findex];
@@ -1106,7 +1107,7 @@ filegrp_list_add(struct fscache *fscp, filegrp_t *fgp)
ASSERT(fgp->fg_next == NULL);
/* hash into array of file groups */
- findex = (int) ((fgp->fg_id.cid_fileno / fgsize) &
+ findex = (int)((fgp->fg_id.cid_fileno / fgsize) &
(CFS_FS_FGP_BUCKET_SIZE - 1));
fgp->fg_next = fscp->fs_filegrp[findex];
@@ -1144,7 +1145,7 @@ filegrp_list_remove(struct fscache *fscp, filegrp_t *fgp)
ASSERT(MUTEX_HELD(&fscp->fs_fslock));
/* hash into array of file groups */
- findex = (int) ((fgp->fg_id.cid_fileno / fgsize) &
+ findex = (int)((fgp->fg_id.cid_fileno / fgsize) &
(CFS_FS_FGP_BUCKET_SIZE - 1));
fp = fscp->fs_filegrp[findex];
pfgp = &fscp->fs_filegrp[findex];
@@ -1360,7 +1361,7 @@ filegrpdir_find(filegrp_t *fgp)
make_ascii_name(&fgp->fg_id, name);
fname = name;
error = VOP_LOOKUP(fscp->fs_fscdirvp, fname, &dirvp, NULL,
- 0, NULL, kcred);
+ 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0) {
fgp->fg_dirvp = dirvp;
fgp->fg_flags &= ~CFS_FG_ALLOC_FILE;
@@ -1421,7 +1422,7 @@ filegrpattr_find(struct filegrp *fgp)
make_ascii_name(&fgp->fg_id, name);
fname = name;
error = VOP_LOOKUP(fscp->fs_fsattrdir, fname,
- &attrvp, NULL, 0, NULL, kcred);
+ &attrvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
return (error);
}
@@ -1442,7 +1443,7 @@ filegrpattr_find(struct filegrp *fgp)
fgp->fg_attrvp = attrvp;
fgp->fg_header = ahp;
fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
- fgp->fg_alloclist = ((u_char *)fgp->fg_offsets) +
+ fgp->fg_alloclist = ((uchar_t *)fgp->fg_offsets) +
(fscp->fs_info.fi_fgsize *
sizeof (struct attrcache_index));
fgp->fg_flags &= ~CFS_FG_ALLOC_ATTR;
@@ -1565,7 +1566,8 @@ filegrpdir_create(filegrp_t *fgp)
attrp->va_gid = 0;
attrp->va_type = VDIR;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
- error = VOP_MKDIR(fscp->fs_fscdirvp, fname, attrp, &dirvp, kcred);
+ error = VOP_MKDIR(fscp->fs_fscdirvp, fname, attrp, &dirvp, kcred, NULL,
+ 0, NULL);
if (error) {
fgp->fg_flags |= CFS_FG_NOCACHE;
cachefs_freefile(fscp->fs_cache);
@@ -1637,7 +1639,7 @@ filegrpattr_create(struct filegrp *fgp)
attrp->va_type = VREG;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
error = VOP_CREATE(fscp->fs_fsattrdir, fname, attrp, EXCL, 0666,
- &attrvp, kcred, 0);
+ &attrvp, kcred, 0, NULL, NULL);
if (error) {
cachefs_freefile(fscp->fs_cache);
goto out;
@@ -1664,7 +1666,7 @@ filegrpattr_create(struct filegrp *fgp)
(nblks * MAXBSIZE) - fgp->fg_headersize);
if (error)
goto out;
- error = VOP_FSYNC(attrvp, FSYNC, kcred);
+ error = VOP_FSYNC(attrvp, FSYNC, kcred, NULL);
if (error)
goto out;
@@ -1694,7 +1696,8 @@ out:
fgp->fg_flags |= CFS_FG_NOCACHE;
if (attrvp) {
VN_RELE(attrvp);
- (void) VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred);
+ (void) VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred,
+ NULL, 0);
cachefs_freefile(fscp->fs_cache);
}
if (nblks)
@@ -1709,7 +1712,7 @@ out:
fgp->fg_attrvp = attrvp;
fgp->fg_header = ahp;
fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
- fgp->fg_alloclist = ((u_char *)fgp->fg_offsets) +
+ fgp->fg_alloclist = ((uchar_t *)fgp->fg_offsets) +
(fscp->fs_info.fi_fgsize *
sizeof (struct attrcache_index));
ahp->ach_count = 0;
@@ -1751,7 +1754,7 @@ filegrp_cid_to_slot(filegrp_t *fgp, cfs_cid_t *cidp)
int slot;
int index;
- index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
+ index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
if (index > fgp->fg_fscp->fs_info.fi_fgsize) {
cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_fscache.c b/usr/src/uts/common/fs/cachefs/cachefs_fscache.c
index 28c3f1c36d..6dcb5430f2 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_fscache.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_fscache.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -257,7 +256,7 @@ fscache_setup(fscache_t *fscp, ino64_t fsid, char *namep,
return (error);
}
} else if (optp) {
- /* compare the options to make sure they are compatable */
+ /* compare the options to make sure they are compatible */
error = fscache_compare_options(fscp, optp);
if (error) {
cmn_err(CE_WARN,
@@ -507,8 +506,8 @@ out:
/*
* Compares fscache state with new mount options
- * to make sure compatable.
- * Returns ESRCH if not compatable or 0 for success.
+ * to make sure compatible.
+ * Returns ESRCH if not compatible or 0 for success.
*/
int
fscache_compare_options(fscache_t *fscp, struct cachefsoptions *optp)
@@ -811,7 +810,8 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
attrp->va_gid = 0;
attrp->va_type = VDIR;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
- error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred);
+ error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred,
+ NULL, 0, NULL);
if (error) {
cmn_err(CE_WARN, "Can't create fs cache directory");
goto out;
@@ -821,7 +821,7 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
* Created the directory. Get the fileno. That'll be the cachefs_fsid.
*/
attrp->va_mask = AT_NODEID;
- error = VOP_GETATTR(fscdirvp, attrp, 0, kcred);
+ error = VOP_GETATTR(fscdirvp, attrp, 0, kcred, NULL);
if (error) {
goto out;
}
@@ -832,7 +832,7 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
attrp->va_type = VREG;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
error = VOP_CREATE(fscdirvp, CACHEFS_FSINFO, attrp, EXCL,
- 0600, &infovp, kcred, 0);
+ 0600, &infovp, kcred, 0, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "Can't create fs option file");
goto out;
@@ -858,7 +858,7 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
cid.cid_fileno = fsid;
make_ascii_name(&cid, name);
error = VOP_RENAME(cachep->c_dirvp, namep, cachep->c_dirvp,
- name, kcred);
+ name, kcred, NULL, 0);
if (error) {
cmn_err(CE_WARN, "Can't rename cache directory");
goto out;
@@ -866,7 +866,8 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
attrp->va_mask = AT_MODE | AT_TYPE;
attrp->va_mode = 0777;
attrp->va_type = VLNK;
- error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred);
+ error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred, NULL,
+ 0);
if (error) {
cmn_err(CE_WARN, "Can't create cache directory symlink");
goto out;
@@ -880,7 +881,8 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
attrp->va_gid = 0;
attrp->va_type = VDIR;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
- error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred);
+ error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred, NULL,
+ 0, NULL);
if (error) {
cmn_err(CE_WARN, "Can't create attrcache dir for fscache");
goto out;
@@ -939,7 +941,7 @@ fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp)
/* try to find the directory */
error = VOP_LOOKUP(cachep->c_dirvp, dirname, &fscdirvp, NULL,
- 0, NULL, kcred);
+ 0, NULL, kcred, NULL, NULL, NULL);
if (error)
goto out;
@@ -953,7 +955,7 @@ fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp)
/* try to find the info file */
error = VOP_LOOKUP(fscdirvp, CACHEFS_FSINFO, &infovp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: fscdir_find_b: cache corruption"
" run fsck, %s", dirname);
@@ -975,7 +977,7 @@ fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp)
/* try to find the attrcache directory */
error = VOP_LOOKUP(fscdirvp, ATTRCACHE_NAME,
- &attrvp, NULL, 0, NULL, kcred);
+ &attrvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: fscdir_find_d: cache corruption"
" run fsck, %s", dirname);
@@ -1076,7 +1078,7 @@ fscache_name_to_fsid(cachefscache_t *cachep, char *namep, ino64_t *fsidp)
/* get the vnode of the name */
error = VOP_LOOKUP(cachep->c_dirvp, namep, &linkvp, NULL, 0, NULL,
- kcred);
+ kcred, NULL, NULL, NULL);
if (error)
goto out;
@@ -1096,7 +1098,7 @@ fscache_name_to_fsid(cachefscache_t *cachep, char *namep, ino64_t *fsidp)
uio.uio_loffset = 0;
uio.uio_fmode = 0;
uio.uio_extflg = UIO_COPY_CACHED;
- error = VOP_READLINK(linkvp, &uio, kcred);
+ error = VOP_READLINK(linkvp, &uio, kcred, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: Can't read filesystem cache link");
goto out;
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c b/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c
index 62c15fc35e..2a6b60a7a0 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -1123,7 +1122,7 @@ cachefs_io_getinfo(vnode_t *vp, void *dinp, void *doutp)
/* Get the length of the directory */
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred);
+ error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred, NULL);
if (error) {
error = 0;
goto out;
@@ -1248,7 +1247,7 @@ cachefs_io_getattrfid(vnode_t *vp, void *dinp, void *doutp)
cr = conj_cred(&gafid->cg_cred);
CACHEFS_TMPPTR_SET(attrp, &va, tmpvap, vattr_t);
tmpvap->va_mask = AT_ALL;
- error = VOP_GETATTR(backvp, tmpvap, 0, cr);
+ error = VOP_GETATTR(backvp, tmpvap, 0, cr, NULL);
CACHEFS_VATTR_COPYOUT(tmpvap, attrp, error);
crfree(cr);
@@ -1298,7 +1297,7 @@ cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp)
/* lookup the file name */
cr = conj_cred(&gap->cg_cred);
error = VOP_LOOKUP(pbackvp, gap->cg_name, &cbackvp,
- (struct pathname *)NULL, 0, (vnode_t *)NULL, cr);
+ (struct pathname *)NULL, 0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
if (error) {
crfree(cr);
VN_RELE(pbackvp);
@@ -1307,12 +1306,12 @@ cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp)
CACHEFS_TMPPTR_SET(&retp->cg_attr, &va, tmpvap, vattr_t);
tmpvap->va_mask = AT_ALL;
- error = VOP_GETATTR(cbackvp, tmpvap, 0, cr);
+ error = VOP_GETATTR(cbackvp, tmpvap, 0, cr, NULL);
CACHEFS_VATTR_COPYOUT(tmpvap, &retp->cg_attr, error);
if (!error) {
CACHEFS_TMPPTR_SET(&retp->cg_fid, &tmpfid, tmpfidp, fid_t);
tmpfidp->fid_len = MAXFIDSZ;
- error = VOP_FID(cbackvp, tmpfidp);
+ error = VOP_FID(cbackvp, tmpfidp, NULL);
CACHEFS_FID_COPYOUT(tmpfidp, &retp->cg_fid);
}
@@ -1415,7 +1414,7 @@ cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
}
/* do open so NFS gets correct creds on writes */
- error = VOP_OPEN(&backvp, FWRITE, cr);
+ error = VOP_OPEN(&backvp, FWRITE, cr, NULL);
if (error) {
mutex_exit(&cp->c_statelock);
goto out;
@@ -1450,9 +1449,9 @@ cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
off += amt;
}
- error = VOP_FSYNC(backvp, FSYNC, cr);
+ error = VOP_FSYNC(backvp, FSYNC, cr, NULL);
if (error == 0)
- error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr);
+ error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr, NULL);
if (error) {
mutex_exit(&cp->c_statelock);
goto out;
@@ -1469,7 +1468,7 @@ cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
* new ctime and mtimes.
*/
va.va_mask = AT_ALL;
- error = VOP_GETATTR(backvp, &va, 0, cr);
+ error = VOP_GETATTR(backvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->pb_ctime, error);
@@ -1527,21 +1526,21 @@ cachefs_io_create(vnode_t *vp, void *dinp, void *doutp)
CACHEFS_TMPPTR_SET(&crp->cr_va, &va, tmpvap, vattr_t);
CACHEFS_VATTR_COPYIN(&crp->cr_va, tmpvap);
error = VOP_CREATE(dvp, crp->cr_name, tmpvap,
- crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0);
+ crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0, NULL, NULL);
if (error)
goto out;
/* get the fid of the file */
CACHEFS_TMPPTR_SET(&retp->cr_newfid, &tmpfid, tmpfidp, fid_t);
tmpfidp->fid_len = MAXFIDSZ;
- error = VOP_FID(cvp, tmpfidp);
+ error = VOP_FID(cvp, tmpfidp, NULL);
if (error)
goto out;
CACHEFS_FID_COPYOUT(tmpfidp, &retp->cr_newfid);
/* get attributes for the file */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->cr_ctime, error);
@@ -1614,10 +1613,11 @@ cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
/* if the caller wants the ctime after the remove */
if (ctimep) {
- error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error == 0) {
child_fid.fid_len = MAXFIDSZ;
- error = VOP_FID(cvp, &child_fid);
+ error = VOP_FID(cvp, &child_fid, NULL);
VN_RELE(cvp);
}
if (error)
@@ -1625,7 +1625,7 @@ cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
}
/* do the remove */
- error = VOP_REMOVE(dvp, rmp->rm_name, cr);
+ error = VOP_REMOVE(dvp, rmp->rm_name, cr, NULL, 0);
if (error)
goto out;
@@ -1634,7 +1634,7 @@ cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
if (error == 0) {
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error == 0) {
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime,
ctimep, error);
@@ -1697,13 +1697,13 @@ cachefs_io_link(vnode_t *vp, void *dinp, void *doutp)
cr = conj_cred(&linkp->ln_cred);
/* do the link */
- error = VOP_LINK(dvp, lvp, linkp->ln_name, cr);
+ error = VOP_LINK(dvp, lvp, linkp->ln_name, cr, NULL, 0);
if (error)
goto out;
/* get the ctime */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(lvp, &va, 0, cr);
+ error = VOP_GETATTR(lvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, ctimep, error);
@@ -1771,14 +1771,14 @@ cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
/* if the caller wants the ctime of the target after deletion */
if (rnp->rn_del_getctime) {
error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error) {
cvp = NULL; /* paranoia */
goto out;
}
child_fid.fid_len = MAXFIDSZ;
- error = VOP_FID(cvp, &child_fid);
+ error = VOP_FID(cvp, &child_fid, NULL);
if (error)
goto out;
VN_RELE(cvp);
@@ -1786,17 +1786,19 @@ cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
}
/* do the rename */
- error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr);
+ error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr,
+ NULL, 0);
if (error)
goto out;
/* get the new ctime on the renamed file */
- error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error)
goto out;
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_ctime, error);
@@ -1815,7 +1817,7 @@ cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
goto out;
}
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_del_ctime,
@@ -1878,14 +1880,14 @@ cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp)
/* make the directory */
CACHEFS_TMPPTR_SET(&mdirp->md_vattr, &va, tmpvap, vattr_t);
CACHEFS_VATTR_COPYIN(&mdirp->md_vattr, tmpvap);
- error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr);
+ error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr, NULL, 0, NULL);
if (error) {
if (error != EEXIST)
goto out;
/* if the directory already exists, then use it */
error = VOP_LOOKUP(dvp, mdirp->md_name, &cvp,
- NULL, 0, NULL, cr);
+ NULL, 0, NULL, cr, NULL, NULL, NULL);
if (error) {
cvp = NULL;
goto out;
@@ -1899,14 +1901,14 @@ cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp)
/* get the fid of the directory */
CACHEFS_TMPPTR_SET(fidp, &tmpfid, tmpfidp, fid_t);
tmpfidp->fid_len = MAXFIDSZ;
- error = VOP_FID(cvp, tmpfidp);
+ error = VOP_FID(cvp, tmpfidp, NULL);
if (error)
goto out;
CACHEFS_FID_COPYOUT(tmpfidp, fidp);
/* get attributes of the directory */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
@@ -1969,7 +1971,7 @@ cachefs_io_rmdir(vnode_t *vp, void *dinp, void *doutp)
}
cr = conj_cred(&rdp->rd_cred);
- error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr);
+ error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr, NULL, 0);
crfree(cr);
VN_RELE(dvp);
@@ -2019,18 +2021,19 @@ cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp)
CACHEFS_TMPPTR_SET(&symp->sy_vattr, &va, tmpvap, vattr_t);
CACHEFS_VATTR_COPYIN(&symp->sy_vattr, tmpvap);
error = VOP_SYMLINK(dvp, symp->sy_name, tmpvap,
- symp->sy_link, cr);
+ symp->sy_link, cr, NULL, 0);
if (error)
goto out;
/* get the vnode for the symlink */
- error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error)
goto out;
/* get the attributes of the symlink */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(svp, &va, 0, cr);
+ error = VOP_GETATTR(svp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sy_ctime, error);
@@ -2041,7 +2044,7 @@ cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp)
/* get the fid */
CACHEFS_TMPPTR_SET(&retp->sy_newfid, &tmpfid, tmpfidp, fid_t);
tmpfidp->fid_len = MAXFIDSZ;
- error = VOP_FID(svp, tmpfidp);
+ error = VOP_FID(svp, tmpfidp, NULL);
if (error)
goto out;
CACHEFS_FID_COPYOUT(tmpfidp, &retp->sy_newfid);
@@ -2120,7 +2123,7 @@ cachefs_io_setattr(vnode_t *vp, void *dinp, void *doutp)
/* get the new ctime and mtime */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sa_ctime, error);
@@ -2181,14 +2184,14 @@ cachefs_io_setsecattr(vnode_t *vp, void *dinp, void *doutp)
/* set the ACL */
(void) VOP_RWLOCK(tvp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(tvp, &vsec, 0, cr);
+ error = VOP_SETSECATTR(tvp, &vsec, 0, cr, NULL);
VOP_RWUNLOCK(tvp, V_WRITELOCK_TRUE, NULL);
if (error != 0)
goto out;
/* get the new ctime and mtime */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(tvp, &va, 0, cr);
+ error = VOP_GETATTR(tvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sc_ctime, error);
@@ -2223,7 +2226,7 @@ drop_backvp(cnode_t *cp)
if (cp->c_backvp) {
/* dump any pages, may be a dirty one */
(void) VOP_PUTPAGE(cp->c_backvp, (offset_t)0, 0,
- B_INVAL | B_TRUNC, kcred);
+ B_INVAL | B_TRUNC, kcred, NULL);
}
mutex_exit(&cp->c_statelock);
}
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_log.c b/usr/src/uts/common/fs/cachefs/cachefs_log.c
index 8d0103cd39..76a6453ba6 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_log.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_log.c
@@ -57,7 +57,7 @@
/*
* cfs_time_t is an int in both LP64 and ILP32. To avoid compiler warnings
- * define its xdr here explicitely
+ * define its xdr here explicitly
*/
#define xdr_cfs_time_t(xdrs, p) xdr_int((xdrs), (int *)(p))
@@ -198,7 +198,8 @@ cachefs_log_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
bzero(lc, sizeof (*lc));
lc->lc_magic = CACHEFS_LOG_MAGIC;
lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
- (void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred);
+ (void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred, NULL,
+ 0);
return (0);
}
@@ -246,9 +247,9 @@ cachefs_log_save_lc(cachefscache_t *cachep)
attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
if (((error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &savevp,
- NULL, 0, NULL, kcred)) != 0) &&
+ NULL, 0, NULL, kcred, NULL, NULL, NULL)) != 0) &&
((error = VOP_CREATE(cachep->c_dirvp, LOG_STATUS_NAME, &attr, EXCL,
- 0600, &savevp, kcred, 0)) != 0))
+ 0600, &savevp, kcred, 0, NULL, NULL)) != 0))
return (error);
ASSERT(savevp != NULL);
if (savevp == NULL)
@@ -322,7 +323,7 @@ cachefs_log_destroy_cookie(cachefs_log_cookie_t *cl)
*
* opens the logfile, and stores the path string if its successful.
*
- * returns an errno if one occured.
+ * returns an errno if one occurred.
*
*/
@@ -406,7 +407,7 @@ out:
}
/*
- * called when an error occured during logging. send the error to
+ * called when an error occurred during logging. send the error to
* syslog, invalidate the logfile, and stop logging.
*/
@@ -437,7 +438,8 @@ cachefs_log_error(cachefscache_t *cachep, int error, int getlock)
lc->lc_magic = CACHEFS_LOG_MAGIC;
lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
if (writable)
- (void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred);
+ (void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred, NULL,
+ 0);
if (getlock)
mutex_exit(&cachep->c_log_mutex);
@@ -454,7 +456,7 @@ cachefs_log_write_header(struct vnode *vp, cachefscache_t *cachep, int error)
XDR xdrm;
attr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &attr, 0, kcred)) != 0)
+ if ((error = VOP_GETATTR(vp, &attr, 0, kcred, NULL)) != 0)
goto out;
if (attr.va_size != 0) {
error = vn_rdwr(UIO_READ, vp, buffy,
@@ -664,7 +666,7 @@ out:
cachefs_kmem_free(buffy, CACHEFS_LOG_ENCODE_SIZE);
/*
- * if an error occured, we need to free the buffers ourselves.
+ * if an error occurred, we need to free the buffers ourselves.
* cachefs_destory_cookie() can't do it.
*/
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_noopc.c b/usr/src/uts/common/fs/cachefs/cachefs_noopc.c
index 5b9c3d7062..245025bf0a 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_noopc.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_noopc.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -81,7 +80,7 @@ c_nop_init_cached_object(fscache_t *fscp, cnode_t *cp, vattr_t *vap,
/* get the attributes */
cp->c_attr.va_mask = AT_ALL;
ASSERT(cp->c_backvp != NULL);
- error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, NULL);
if (error)
return (error);
} else {
@@ -127,7 +126,7 @@ c_nop_check_cached_object(struct fscache *fscp, struct cnode *cp,
/* get the file attributes from the back fs */
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
backhit = 1;
if (error)
goto out;
@@ -181,7 +180,7 @@ c_nop_modify_cached_object(struct fscache *fscp, struct cnode *cp, cred_t *cr)
return;
}
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error)
return;
nlink = cp->c_attr.va_nlink;
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_resource.c b/usr/src/uts/common/fs/cachefs/cachefs_resource.c
index c250f7cef1..796d352237 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_resource.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_resource.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -76,7 +75,7 @@ static void cachefs_packed_pending(cachefscache_t *cachep);
(&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)]))
/*
- * This function moves an RL entry from whereever it currently is to
+ * This function moves an RL entry from wherever it currently is to
* the back of the requested list.
*/
void
@@ -989,7 +988,7 @@ cachefs_cachep_worker_thread(cachefscache_t *cachep)
fl.l_sysid = 0;
fl.l_pid = 0;
error = VOP_FRLOCK(cachep->c_lockvp, F_SETLK, &fl, FWRITE,
- (offset_t)0, NULL, kcred);
+ (offset_t)0, NULL, kcred, NULL);
if (error) {
cmn_err(CE_WARN,
"cachefs: Can't lock Cache Lock File(r); Error %d\n",
@@ -1058,7 +1057,7 @@ cachefs_cachep_worker_thread(cachefscache_t *cachep)
fl.l_sysid = 0;
fl.l_pid = 0;
error = VOP_FRLOCK(cachep->c_lockvp, F_SETLK, &fl,
- FWRITE, (offset_t)0, NULL, kcred);
+ FWRITE, (offset_t)0, NULL, kcred, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: Can't unlock lock file\n");
}
@@ -1407,7 +1406,7 @@ cachefs_gc_front_atime(cachefscache_t *cachep)
make_ascii_name(&dircid, namebuf);
if (VOP_LOOKUP(fscp->fs_fscdirvp, namebuf,
&dirvp, (struct pathname *)NULL, 0,
- (vnode_t *)NULL, kcred) == 0) {
+ (vnode_t *)NULL, kcred, NULL, NULL, NULL) == 0) {
make_ascii_name(&cid, namebuf);
reledir++;
} else {
@@ -1417,7 +1416,7 @@ cachefs_gc_front_atime(cachefscache_t *cachep)
}
if (dirvp && VOP_LOOKUP(dirvp, namebuf, &filevp,
(struct pathname *)NULL, 0,
- (vnode_t *)NULL, kcred) == 0) {
+ (vnode_t *)NULL, kcred, NULL, NULL, NULL) == 0) {
gotfile = 1;
}
if (reledir)
@@ -1426,7 +1425,7 @@ cachefs_gc_front_atime(cachefscache_t *cachep)
if (gotfile) {
va.va_mask = AT_ATIME;
- if (VOP_GETATTR(filevp, &va, 0, kcred) == 0)
+ if (VOP_GETATTR(filevp, &va, 0, kcred, NULL) == 0)
rc = va.va_atime.tv_sec;
VN_RELE(filevp);
}
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_strict.c b/usr/src/uts/common/fs/cachefs/cachefs_strict.c
index 75fd305760..9a4011b459 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_strict.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_strict.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -93,7 +92,7 @@ c_strict_init_cached_object(fscache_t *fscp, cnode_t *cp, vattr_t *vap,
/* get the attributes */
cp->c_attr.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, NULL);
if (error)
return (error);
} else {
@@ -146,7 +145,7 @@ c_strict_check_cached_object(struct fscache *fscp, struct cnode *cp,
if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
backhit = 1;
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error)
goto out;
cp->c_attr = attrs;
@@ -194,7 +193,7 @@ again:
/* get the file attributes from the back fs */
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
backhit = 1;
if (error)
goto out;
@@ -239,7 +238,7 @@ again:
}
if ((CTOV(cp))->v_type == VREG) {
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error)
goto out;
}
@@ -335,7 +334,7 @@ c_strict_modify_cached_object(struct fscache *fscp, struct cnode *cp,
attrs.va_mask = AT_ALL;
ASSERT(cp->c_backvp != NULL);
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error) {
mdp->md_vattr.va_mtime.tv_sec = 0;
goto out;
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_subr.c b/usr/src/uts/common/fs/cachefs/cachefs_subr.c
index b3aac88a35..1f82e638e6 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_subr.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_subr.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -277,7 +276,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* get the mode bits of the cache directory */
attrp->va_mask = AT_ALL;
- error = VOP_GETATTR(cdvp, attrp, 0, kcred);
+ error = VOP_GETATTR(cdvp, attrp, 0, kcred, NULL);
if (error)
goto out;
@@ -290,7 +289,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* Get the lock file */
error = VOP_LOOKUP(cdvp, CACHEFS_LOCK_FILE, &lockvp, NULL, 0, NULL,
- kcred);
+ kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: activate_a: cache corruption"
" run fsck.\n");
@@ -299,7 +298,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* Get the label file */
error = VOP_LOOKUP(cdvp, CACHELABEL_NAME, &labelvp, NULL, 0, NULL,
- kcred);
+ kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: activate_b: cache corruption"
" run fsck.\n");
@@ -324,7 +323,8 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
}
/* Open the resource file */
- error = VOP_LOOKUP(cdvp, RESOURCE_NAME, &rifvp, NULL, 0, NULL, kcred);
+ error = VOP_LOOKUP(cdvp, RESOURCE_NAME, &rifvp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: activate_d: cache corruption"
" run fsck.\n");
@@ -360,7 +360,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* Open the lost+found directory */
error = VOP_LOOKUP(cdvp, CACHEFS_LOSTFOUND_NAME, &lostfoundvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: activate_g: cache corruption"
" run fsck.\n");
@@ -389,7 +389,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* if the LOG_STATUS_NAME file exists, read it in and set up logging */
error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &statevp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0) {
int vnrw_error;
@@ -738,7 +738,7 @@ cachefs_cache_rssync(struct cachefscache *cachep)
if (error) {
cmn_err(CE_WARN, "cachefs: Can't Write Cache RL Info\n");
}
- error = VOP_FSYNC(cachep->c_resfilevp, FSYNC, kcred);
+ error = VOP_FSYNC(cachep->c_resfilevp, FSYNC, kcred, NULL);
return (error);
}
@@ -974,11 +974,11 @@ cachefs_createfrontfile(cnode_t *cp, struct filegrp *fgp)
if (cp->c_flags & CN_ASYNC_POP_WORKING) {
/* lookup the already created front file */
error = VOP_LOOKUP(fgp->fg_dirvp, name, &cp->c_frontvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
} else {
/* create the front file */
error = VOP_CREATE(fgp->fg_dirvp, name, attrp, EXCL, mode,
- &cp->c_frontvp, kcred, 0);
+ &cp->c_frontvp, kcred, 0, NULL, NULL);
}
if (error) {
#ifdef CFSDEBUG
@@ -992,7 +992,7 @@ cachefs_createfrontfile(cnode_t *cp, struct filegrp *fgp)
/* get a copy of the fid of the front file */
cp->c_metadata.md_fid.fid_len = MAXFIDSZ;
- error = VOP_FID(cp->c_frontvp, &cp->c_metadata.md_fid);
+ error = VOP_FID(cp->c_frontvp, &cp->c_metadata.md_fid, NULL);
if (error) {
/*
* If we get back ENOSPC then the fid we passed in was too
@@ -1013,7 +1013,7 @@ out:
if (error) {
if (cp->c_frontvp) {
VN_RELE(cp->c_frontvp);
- (void) VOP_REMOVE(fgp->fg_dirvp, name, kcred);
+ (void) VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0);
cp->c_frontvp = NULL;
}
if (ffrele)
@@ -1064,7 +1064,7 @@ cachefs_removefrontfile(cachefs_metadata_t *mdp, cfs_cid_t *cidp,
return;
}
make_ascii_name(cidp, name);
- error = VOP_REMOVE(fgp->fg_dirvp, name, kcred);
+ error = VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0);
if (error == ENOENT)
enoent = 1;
if ((error) && (error != ENOENT)) {
@@ -1074,7 +1074,7 @@ cachefs_removefrontfile(cachefs_metadata_t *mdp, cfs_cid_t *cidp,
if (mdp->md_flags & MD_ACLDIR) {
(void) strcat(name, ".d");
error = VOP_RMDIR(fgp->fg_dirvp, name, fgp->fg_dirvp,
- kcred);
+ kcred, NULL, 0);
if ((error) && (error != ENOENT)) {
cmn_err(CE_WARN, "frontfs rmdir error %s %d"
"; run fsck\n", name, error);
@@ -1210,7 +1210,7 @@ cachefs_getfrontfile(cnode_t *cp)
/* get modify time of the front file */
va.va_mask = AT_MTIME;
- error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred);
+ error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: gff2: front file"
" system error %d", error);
@@ -1721,7 +1721,7 @@ out:
/*
* due to compiler error we shifted cnode to the last argument slot.
- * occured during large files project - XXX.
+ * occurred during large files project - XXX.
*/
void
cachefs_cluster_allocmap(u_offset_t off, u_offset_t *popoffp,
@@ -1911,7 +1911,7 @@ cachefs_readlink_back(cnode_t *cp, cred_t *cr, caddr_t *bufp, int *buflenp)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_readlink (nfsv4): cnode %p, backvp %p\n",
cp, cp->c_backvp));
- error = VOP_READLINK(cp->c_backvp, &uio, cr);
+ error = VOP_READLINK(cp->c_backvp, &uio, cr, NULL);
if (error) {
cachefs_kmem_free(buf, MAXPATHLEN);
} else {
@@ -1980,7 +1980,7 @@ cachefs_getbackvp(struct fscache *fscp, struct cnode *cp)
flag |= FWRITE;
}
}
- error = VOP_OPEN(&cp->c_backvp, flag, cp->c_cred);
+ error = VOP_OPEN(&cp->c_backvp, flag, cp->c_cred, NULL);
if (error) {
VN_RELE(cp->c_backvp);
cp->c_backvp = NULL;
@@ -2028,7 +2028,7 @@ cachefs_getcookie(
* variable length fids we will need to change this.
*/
cookiep->fid_len = MAXFIDSZ;
- error = VOP_FID(vp, cookiep);
+ error = VOP_FID(vp, cookiep, NULL);
} else {
bzero(cookiep, sizeof (*cookiep));
}
@@ -2037,7 +2037,7 @@ cachefs_getcookie(
if (attrp) {
ASSERT(attrp != NULL);
attrp->va_mask = AT_ALL;
- error = VOP_GETATTR(vp, attrp, 0, cr);
+ error = VOP_GETATTR(vp, attrp, 0, cr, NULL);
}
} else {
if (error == ENOSPC) {
@@ -2254,7 +2254,7 @@ cachefs_async_putpage(struct cachefs_putpage_req *prp, cred_t *cr)
ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
(void) VOP_PUTPAGE(prp->cp_vp, prp->cp_off, prp->cp_len,
- prp->cp_flags, cr);
+ prp->cp_flags, cr, NULL);
mutex_enter(&cp->c_iomutex);
if (--cp->c_nio == 0)
@@ -2378,7 +2378,7 @@ cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
make_ascii_name(&cid, name);
(void) VOP_CREATE(fgp->fg_dirvp, name, attrp,
- EXCL, 0666, &frontvp, kcred, 0);
+ EXCL, 0666, &frontvp, kcred, 0, NULL, NULL);
cachefs_kmem_free(attrp,
sizeof (struct vattr));
@@ -2433,7 +2433,7 @@ cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
if (error != 0)
goto out;
- error = VOP_FSYNC(frontvp, FSYNC, cr);
+ error = VOP_FSYNC(frontvp, FSYNC, cr, NULL);
if (error != 0) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_ASYNCPOP)
@@ -2453,7 +2453,7 @@ cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
}
va.va_mask = AT_MTIME;
- error = VOP_GETATTR(cp->c_frontvp, &va, 0, cr);
+ error = VOP_GETATTR(cp->c_frontvp, &va, 0, cr, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_ASYNCPOP)
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c b/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c
index fd1ee0b4d8..26631b3380 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c
@@ -403,7 +403,7 @@ again:
}
fscache_list_add(cachep, fscp);
} else {
- /* compare the options to make sure they are compatable */
+ /* compare the options to make sure they are compatible */
error = fscache_compare_options(fscp, cfs_options);
if (error) {
cmn_err(CE_WARN,
@@ -426,7 +426,7 @@ again:
error = 0;
if (fscp->fs_fscdirvp) {
error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
- &tmpdirvp, NULL, 0, NULL, kcred);
+ &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
/*
* If a log file exists and the cache is being mounted without
@@ -550,7 +550,7 @@ again:
*/
error = VOP_PATHCONF(backrootvp, _PC_FILESIZEBITS, &maxfilesizebits,
- kcred);
+ kcred, NULL);
if (error) {
cmn_err(CE_WARN,
@@ -562,7 +562,8 @@ again:
mutex_exit(&fscp->fs_fslock);
/* remove the unmount file if it is there */
- (void) VOP_REMOVE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, kcred);
+ (void) VOP_REMOVE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, kcred, NULL,
+ 0);
/* wake up the cache worker if ANY packed pending work */
mutex_enter(&cachep->c_contentslock);
@@ -957,7 +958,7 @@ cachefs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
if (fscp->fs_fscdirvp != NULL)
xx = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, &attr,
- NONEXCL, 0600, &nmvp, kcred, 0);
+ NONEXCL, 0600, &nmvp, kcred, 0, NULL, NULL);
else
xx = ENOENT; /* for unmounting when NOCACHE */
if (xx == 0) {
@@ -1207,7 +1208,7 @@ cachefs_remount(struct vfs *vfsp, struct mounta *uap)
error = 0;
if (cachedirvp) {
error = VOP_LOOKUP(cachedirvp, CACHEFS_DLOG_FILE,
- &tmpdirvp, NULL, 0, NULL, kcred);
+ &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
}
cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_vnops.c b/usr/src/uts/common/fs/cachefs/cachefs_vnops.c
index 5451c20467..795c70dc3d 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_vnops.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_vnops.c
@@ -136,60 +136,71 @@ static int cachefs_readback_translate(cnode_t *cp, uio_t *uiop,
static int cachefs_setattr_common(vnode_t *vp, vattr_t *vap, int flags,
cred_t *cr, caller_context_t *ct);
-static int cachefs_open(struct vnode **, int, cred_t *);
+static int cachefs_open(struct vnode **, int, cred_t *,
+ caller_context_t *);
static int cachefs_close(struct vnode *, int, int, offset_t,
- cred_t *);
+ cred_t *, caller_context_t *);
static int cachefs_read(struct vnode *, struct uio *, int, cred_t *,
caller_context_t *);
static int cachefs_write(struct vnode *, struct uio *, int, cred_t *,
caller_context_t *);
static int cachefs_ioctl(struct vnode *, int, intptr_t, int, cred_t *,
- int *);
+ int *, caller_context_t *);
static int cachefs_getattr(struct vnode *, struct vattr *, int,
- cred_t *);
+ cred_t *, caller_context_t *);
static int cachefs_setattr(struct vnode *, struct vattr *,
int, cred_t *, caller_context_t *);
-static int cachefs_access(struct vnode *, int, int, cred_t *);
+static int cachefs_access(struct vnode *, int, int, cred_t *,
+ caller_context_t *);
static int cachefs_lookup(struct vnode *, char *, struct vnode **,
- struct pathname *, int, struct vnode *, cred_t *);
+ struct pathname *, int, struct vnode *, cred_t *,
+ caller_context_t *, int *, pathname_t *);
static int cachefs_create(struct vnode *, char *, struct vattr *,
- enum vcexcl, int, struct vnode **, cred_t *, int);
+ enum vcexcl, int, struct vnode **, cred_t *, int,
+ caller_context_t *, vsecattr_t *);
static int cachefs_create_connected(vnode_t *dvp, char *nm,
vattr_t *vap, enum vcexcl exclusive, int mode,
vnode_t **vpp, cred_t *cr);
static int cachefs_create_disconnected(vnode_t *dvp, char *nm,
vattr_t *vap, enum vcexcl exclusive, int mode,
vnode_t **vpp, cred_t *cr);
-static int cachefs_remove(struct vnode *, char *, cred_t *);
+static int cachefs_remove(struct vnode *, char *, cred_t *,
+ caller_context_t *, int);
static int cachefs_link(struct vnode *, struct vnode *, char *,
- cred_t *);
+ cred_t *, caller_context_t *, int);
static int cachefs_rename(struct vnode *, char *, struct vnode *,
- char *, cred_t *);
+ char *, cred_t *, caller_context_t *, int);
static int cachefs_mkdir(struct vnode *, char *, struct
- vattr *, struct vnode **, cred_t *);
+ vattr *, struct vnode **, cred_t *, caller_context_t *,
+ int, vsecattr_t *);
static int cachefs_rmdir(struct vnode *, char *, struct vnode *,
- cred_t *);
+ cred_t *, caller_context_t *, int);
static int cachefs_readdir(struct vnode *, struct uio *,
- cred_t *, int *);
+ cred_t *, int *, caller_context_t *, int);
static int cachefs_symlink(struct vnode *, char *, struct vattr *,
- char *, cred_t *);
-static int cachefs_readlink(struct vnode *, struct uio *, cred_t *);
+ char *, cred_t *, caller_context_t *, int);
+static int cachefs_readlink(struct vnode *, struct uio *, cred_t *,
+ caller_context_t *);
static int cachefs_readlink_connected(vnode_t *vp, uio_t *uiop, cred_t *cr);
static int cachefs_readlink_disconnected(vnode_t *vp, uio_t *uiop);
-static int cachefs_fsync(struct vnode *, int, cred_t *);
-static void cachefs_inactive(struct vnode *, cred_t *);
-static int cachefs_fid(struct vnode *, struct fid *);
+static int cachefs_fsync(struct vnode *, int, cred_t *,
+ caller_context_t *);
+static void cachefs_inactive(struct vnode *, cred_t *, caller_context_t *);
+static int cachefs_fid(struct vnode *, struct fid *, caller_context_t *);
static int cachefs_rwlock(struct vnode *, int, caller_context_t *);
static void cachefs_rwunlock(struct vnode *, int, caller_context_t *);
-static int cachefs_seek(struct vnode *, offset_t, offset_t *);
+static int cachefs_seek(struct vnode *, offset_t, offset_t *,
+ caller_context_t *);
static int cachefs_frlock(struct vnode *, int, struct flock64 *,
- int, offset_t, struct flk_callback *, cred_t *);
+ int, offset_t, struct flk_callback *, cred_t *,
+ caller_context_t *);
static int cachefs_space(struct vnode *, int, struct flock64 *, int,
offset_t, cred_t *, caller_context_t *);
-static int cachefs_realvp(struct vnode *, struct vnode **);
+static int cachefs_realvp(struct vnode *, struct vnode **,
+ caller_context_t *);
static int cachefs_getpage(struct vnode *, offset_t, size_t, uint_t *,
struct page *[], size_t, struct seg *, caddr_t,
- enum seg_rw, cred_t *);
+ enum seg_rw, cred_t *, caller_context_t *);
static int cachefs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
struct page *[], size_t, struct seg *, caddr_t,
enum seg_rw, cred_t *);
@@ -197,37 +208,42 @@ static int cachefs_getapage_back(struct vnode *, u_offset_t, size_t,
uint_t *, struct page *[], size_t, struct seg *, caddr_t,
enum seg_rw, cred_t *);
static int cachefs_putpage(struct vnode *, offset_t, size_t, int,
- cred_t *);
+ cred_t *, caller_context_t *);
static int cachefs_map(struct vnode *, offset_t, struct as *,
- caddr_t *, size_t, uchar_t, uchar_t, uint_t, cred_t *);
+ caddr_t *, size_t, uchar_t, uchar_t, uint_t, cred_t *,
+ caller_context_t *);
static int cachefs_addmap(struct vnode *, offset_t, struct as *,
- caddr_t, size_t, uchar_t, uchar_t, uint_t, cred_t *);
+ caddr_t, size_t, uchar_t, uchar_t, uint_t, cred_t *,
+ caller_context_t *);
static int cachefs_delmap(struct vnode *, offset_t, struct as *,
- caddr_t, size_t, uint_t, uint_t, uint_t, cred_t *);
+ caddr_t, size_t, uint_t, uint_t, uint_t, cred_t *,
+ caller_context_t *);
static int cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec,
- int flag, cred_t *cr);
+ int flag, cred_t *cr, caller_context_t *);
static int cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec,
- int flag, cred_t *cr);
+ int flag, cred_t *cr, caller_context_t *);
static int cachefs_shrlock(vnode_t *, int, struct shrlock *, int,
- cred_t *);
+ cred_t *, caller_context_t *);
static int cachefs_getsecattr_connected(vnode_t *vp, vsecattr_t *vsec, int flag,
cred_t *cr);
static int cachefs_getsecattr_disconnected(vnode_t *vp, vsecattr_t *vsec,
int flag, cred_t *cr);
-static int cachefs_dump(struct vnode *, caddr_t, int, int);
+static int cachefs_dump(struct vnode *, caddr_t, int, int,
+ caller_context_t *);
static int cachefs_pageio(struct vnode *, page_t *,
- u_offset_t, size_t, int, cred_t *);
+ u_offset_t, size_t, int, cred_t *, caller_context_t *);
static int cachefs_writepage(struct vnode *vp, caddr_t base,
int tcount, struct uio *uiop);
-static int cachefs_pathconf(vnode_t *, int, ulong_t *, cred_t *);
+static int cachefs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
static int cachefs_read_backfs_nfsv4(vnode_t *vp, uio_t *uiop, int ioflag,
cred_t *cr, caller_context_t *ct);
static int cachefs_write_backfs_nfsv4(vnode_t *vp, uio_t *uiop, int ioflag,
cred_t *cr, caller_context_t *ct);
static int cachefs_getattr_backfs_nfsv4(vnode_t *vp, vattr_t *vap,
- int flags, cred_t *cr);
+ int flags, cred_t *cr, caller_context_t *ct);
static int cachefs_remove_backfs_nfsv4(vnode_t *dvp, char *nm, cred_t *cr,
vnode_t *vp);
static int cachefs_getpage_backfs_nfsv4(struct vnode *vp, offset_t off,
@@ -305,7 +321,7 @@ cachefs_getvnodeops(void)
}
static int
-cachefs_open(vnode_t **vpp, int flag, cred_t *cr)
+cachefs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
int error = 0;
cnode_t *cp = VTOC(*vpp);
@@ -413,7 +429,7 @@ cachefs_open(vnode_t **vpp, int flag, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_open (nfsv4): cnode %p, "
"backvp %p\n", cp, cp->c_backvp));
- error = VOP_OPEN(&cp->c_backvp, flag, cr);
+ error = VOP_OPEN(&cp->c_backvp, flag, cr, ct);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -469,7 +485,8 @@ out:
/* ARGSUSED */
static int
-cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
int error = 0;
cnode_t *cp = VTOC(vp);
@@ -552,7 +569,7 @@ cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
("cachefs_close (nfsv4): cnode %p, "
"backvp %p\n", cp, cp->c_backvp));
error = VOP_CLOSE(cp->c_backvp, flag, count,
- offset, cr);
+ offset, cr, ct);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -627,7 +644,7 @@ cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
if (cp->c_backvp &&
(fscp->fs_cdconnected == CFS_CD_CONNECTED)) {
error = VOP_CLOSE(cp->c_backvp, flag, close_cnt,
- offset, cr);
+ offset, cr, ct);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -1706,7 +1723,8 @@ out:
/*ARGSUSED*/
static int
-cachefs_dump(struct vnode *vp, caddr_t foo1, int foo2, int foo3)
+cachefs_dump(struct vnode *vp, caddr_t foo1, int foo2, int foo3,
+ caller_context_t *ct)
{
return (ENOSYS); /* should we panic if we get here? */
}
@@ -1714,7 +1732,7 @@ cachefs_dump(struct vnode *vp, caddr_t foo1, int foo2, int foo3)
/*ARGSUSED*/
static int
cachefs_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, cred_t *cred,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
int error;
struct cnode *cp = VTOC(vp);
@@ -1989,7 +2007,8 @@ cachefs_fileno_conflict(fscache_t *fscp, ino64_t old)
/*ARGSUSED*/
static int
-cachefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+cachefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
struct cnode *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -2007,7 +2026,7 @@ cachefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* Call backfilesystem getattr if NFSv4 */
if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
- error = cachefs_getattr_backfs_nfsv4(vp, vap, flags, cr);
+ error = cachefs_getattr_backfs_nfsv4(vp, vap, flags, cr, ct);
goto out;
}
@@ -2175,7 +2194,7 @@ out:
*/
static int
cachefs_getattr_backfs_nfsv4(vnode_t *vp, vattr_t *vap,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -2198,7 +2217,7 @@ cachefs_getattr_backfs_nfsv4(vnode_t *vp, vattr_t *vap,
CFS_DPRINT_BACKFS_NFSV4(fscp, ("cachefs_getattr_backfs_nfsv4: cnode %p,"
" backvp %p\n", cp, backvp));
- error = VOP_GETATTR(backvp, vap, flags, cr);
+ error = VOP_GETATTR(backvp, vap, flags, cr, ct);
/* Update attributes */
cp->c_attr = *vap;
@@ -2252,7 +2271,7 @@ cachefs_setattr(
held = 0;
}
- /* aquire access to the file system */
+ /* acquire access to the file system */
error = cachefs_cd_access(fscp, connected, 1);
if (error)
break;
@@ -2461,7 +2480,7 @@ cachefs_setattr_connected(
/* XXX bob: given what modify_cobject does this seems unnecessary */
cp->c_attr.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, ct);
if (error)
goto out;
@@ -2719,7 +2738,8 @@ out:
/* ARGSUSED */
static int
-cachefs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+cachefs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -2842,7 +2862,7 @@ cachefs_access_connected(struct vnode *vp, int mode, int flags, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_access (nfsv4): cnode %p, backvp %p\n",
cp, cp->c_backvp));
- error = VOP_ACCESS(cp->c_backvp, mode, flags, cr);
+ error = VOP_ACCESS(cp->c_backvp, mode, flags, cr, NULL);
/*
* even though we don't `need' the ACL to do access
@@ -2873,8 +2893,9 @@ out:
* CFS has a fastsymlink scheme. If the size of the link is < C_FSL_SIZE, then
* the link is placed in the metadata itself (no front file is allocated).
*/
+/*ARGSUSED*/
static int
-cachefs_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+cachefs_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
int error = 0;
cnode_t *cp = VTOC(vp);
@@ -3125,7 +3146,7 @@ out:
/*ARGSUSED*/
static int
-cachefs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+cachefs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
int error = 0;
@@ -3215,7 +3236,8 @@ cachefs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_fsync (nfsv4): cnode %p, "
"backvp %p\n", cp, cp->c_backvp));
- error = VOP_FSYNC(cp->c_backvp, syncflag, cr);
+ error = VOP_FSYNC(cp->c_backvp, syncflag, cr,
+ ct);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -3304,13 +3326,13 @@ cachefs_sync_metadata(cnode_t *cp)
if (cp->c_flags & CN_NEED_FRONT_SYNC) {
if (cp->c_frontvp != NULL) {
- error = VOP_FSYNC(cp->c_frontvp, FSYNC, kcred);
+ error = VOP_FSYNC(cp->c_frontvp, FSYNC, kcred, NULL);
if (error) {
cp->c_metadata.md_timestamp.tv_sec = 0;
} else {
va.va_mask = AT_MTIME;
error = VOP_GETATTR(cp->c_frontvp, &va, 0,
- kcred);
+ kcred, NULL);
if (error)
goto out;
cp->c_metadata.md_timestamp = va.va_mtime;
@@ -3376,8 +3398,9 @@ out:
* calls cachefs_inactive.
* Because of the dnlc, it is not safe to grab most locks here.
*/
+/*ARGSUSED*/
static void
-cachefs_inactive(struct vnode *vp, cred_t *cr)
+cachefs_inactive(struct vnode *vp, cred_t *cr, caller_context_t *ct)
{
cnode_t *cp;
struct cachefs_req *rp;
@@ -3425,7 +3448,9 @@ cachefs_inactive(struct vnode *vp, cred_t *cr)
/* ARGSUSED */
static int
cachefs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp,
- struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr)
+ struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
+
{
int error = 0;
cnode_t *dcp = VTOC(dvp);
@@ -3740,13 +3765,13 @@ cachefs_lookup_back(vnode_t *dvp, char *nm, vnode_t **vpp,
("cachefs_lookup (nfsv4): dcp %p, dbackvp %p, name %s\n",
dcp, dcp->c_backvp, nm));
error = VOP_LOOKUP(dcp->c_backvp, nm, &backvp, (struct pathname *)NULL,
- 0, (vnode_t *)NULL, cr);
+ 0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
if (error)
goto out;
if (IS_DEVVP(backvp)) {
struct vnode *devvp = backvp;
- if (VOP_REALVP(devvp, &backvp) == 0) {
+ if (VOP_REALVP(devvp, &backvp, NULL) == 0) {
VN_HOLD(backvp);
VN_RELE(devvp);
}
@@ -3793,7 +3818,9 @@ out:
/*ARGSUSED7*/
static int
cachefs_create(vnode_t *dvp, char *nm, vattr_t *vap,
- vcexcl_t exclusive, int mode, vnode_t **vpp, cred_t *cr, int flag)
+ vcexcl_t exclusive, int mode, vnode_t **vpp, cred_t *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
+
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -3942,9 +3969,8 @@ cachefs_create_connected(vnode_t *dvp, char *nm, vattr_t *vap,
cachefs_access_connected(vp, mode, 0, cr)) == 0) {
if ((vap->va_mask & AT_SIZE) && (vp->v_type == VREG)) {
vap->va_mask = AT_SIZE;
- error =
- cachefs_setattr_common(vp, vap,
- 0, cr, NULL);
+ error = cachefs_setattr_common(vp, vap, 0,
+ cr, NULL);
}
}
if (error) {
@@ -3978,11 +4004,11 @@ cachefs_create_connected(vnode_t *dvp, char *nm, vattr_t *vap,
("cachefs_create (nfsv4): dcp %p, dbackvp %p,"
"name %s\n", dcp, dcp->c_backvp, nm));
error = VOP_CREATE(dcp->c_backvp, nm, vap, exclusive, mode,
- &devvp, cr, 0);
+ &devvp, cr, 0, NULL, NULL);
mutex_exit(&dcp->c_statelock);
if (error)
goto out;
- if (VOP_REALVP(devvp, &tvp) == 0) {
+ if (VOP_REALVP(devvp, &tvp, NULL) == 0) {
VN_HOLD(tvp);
VN_RELE(devvp);
} else {
@@ -4096,9 +4122,8 @@ cachefs_create_disconnected(vnode_t *dvp, char *nm, vattr_t *vap,
if ((vap->va_mask & AT_SIZE) &&
(vp->v_type == VREG)) {
vap->va_mask = AT_SIZE;
- error =
- cachefs_setattr_common(vp, vap,
- 0, cr, NULL);
+ error = cachefs_setattr_common(vp,
+ vap, 0, cr, NULL);
}
}
}
@@ -4264,8 +4289,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_remove(vnode_t *dvp, char *nm, cred_t *cr)
+cachefs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -4511,7 +4538,7 @@ cachefs_remove_connected(vnode_t *dvp, char *nm, cred_t *cr, vnode_t *vp)
}
/* perform the remove on the back fs */
- error = VOP_REMOVE(dcp->c_backvp, nm, cr);
+ error = VOP_REMOVE(dcp->c_backvp, nm, cr, NULL, 0);
if (error) {
mutex_exit(&dcp->c_statelock);
goto out;
@@ -4641,7 +4668,7 @@ cachefs_remove_backfs_nfsv4(vnode_t *dvp, char *nm, cred_t *cr, vnode_t *vp)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_remove (nfsv4): dcp %p, dbackvp %p, name %s\n",
dcp, dbackvp, nm));
- error = VOP_REMOVE(dbackvp, nm, cr);
+ error = VOP_REMOVE(dbackvp, nm, cr, NULL, 0);
if (error) {
mutex_exit(&cp->c_statelock);
goto out;
@@ -4789,8 +4816,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_link(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
+cachefs_link(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
fscache_t *fscp = VFS_TO_FSCACHE(tdvp->v_vfsp);
cnode_t *tdcp = VTOC(tdvp);
@@ -4813,7 +4842,7 @@ cachefs_link(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
if (fscp->fs_cache->c_flags & (CACHE_NOFILL | CACHE_NOCACHE))
ASSERT(tdcp->c_flags & CN_NOCACHE);
- if (VOP_REALVP(fvp, &realvp) == 0) {
+ if (VOP_REALVP(fvp, &realvp, ct) == 0) {
fvp = realvp;
}
@@ -4939,7 +4968,7 @@ cachefs_link_connected(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_link (nfsv4): tdcp %p, tdbackvp %p, "
"name %s\n", tdcp, tdcp->c_backvp, tnm));
- error = VOP_LINK(tdcp->c_backvp, backvp, tnm, cr);
+ error = VOP_LINK(tdcp->c_backvp, backvp, tnm, cr, NULL, 0);
if (error) {
mutex_exit(&tdcp->c_statelock);
goto out;
@@ -4973,7 +5002,7 @@ cachefs_link_connected(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
/* XXX bob: given what modify_cobject does this seems unnecessary */
fcp->c_attr.va_mask = AT_ALL;
- error = VOP_GETATTR(fcp->c_backvp, &fcp->c_attr, 0, cr);
+ error = VOP_GETATTR(fcp->c_backvp, &fcp->c_attr, 0, cr, NULL);
mutex_exit(&fcp->c_statelock);
out:
if (backvp)
@@ -5108,9 +5137,10 @@ out:
*/
kmutex_t cachefs_rename_lock;
+/*ARGSUSED*/
static int
cachefs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp,
- char *nnm, cred_t *cr)
+ char *nnm, cred_t *cr, caller_context_t *ct, int flags)
{
fscache_t *fscp = C_TO_FSCACHE(VTOC(odvp));
cachefscache_t *cachep = fscp->fs_cache;
@@ -5125,7 +5155,7 @@ cachefs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp,
if (getzoneid() != GLOBAL_ZONEID)
return (EPERM);
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
/*
@@ -5286,7 +5316,7 @@ cachefs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp,
bzero(&gone, sizeof (gone));
gone.fid_len = MAXFIDSZ;
if (delvp != NULL)
- (void) VOP_FID(delvp, &gone);
+ (void) VOP_FID(delvp, &gone, ct);
cachefs_log_rename(cachep, error, fscp->fs_cfsvfsp,
&gone, 0, (delvp != NULL), crgetuid(cr));
@@ -5407,7 +5437,8 @@ cachefs_rename_connected(vnode_t *odvp, char *onm, vnode_t *ndvp,
("cachefs_rename (nfsv4): odcp %p, odbackvp %p, "
" ndcp %p, ndbackvp %p, onm %s, nnm %s\n",
odcp, odcp->c_backvp, ndcp, ndcp->c_backvp, onm, nnm));
- error = VOP_RENAME(odcp->c_backvp, onm, ndcp->c_backvp, nnm, cr);
+ error = VOP_RENAME(odcp->c_backvp, onm, ndcp->c_backvp, nnm, cr, NULL,
+ 0);
if (error)
goto out;
@@ -5780,9 +5811,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
cachefs_mkdir(vnode_t *dvp, char *nm, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -5926,7 +5958,7 @@ cachefs_mkdir_connected(vnode_t *dvp, char *nm, vattr_t *vap,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_mkdir (nfsv4): dcp %p, dbackvp %p, "
"name %s\n", dcp, dcp->c_backvp, nm));
- error = VOP_MKDIR(dcp->c_backvp, nm, vap, &vp, cr);
+ error = VOP_MKDIR(dcp->c_backvp, nm, vap, &vp, cr, NULL, 0, NULL);
mutex_exit(&dcp->c_statelock);
if (error) {
goto out;
@@ -6150,8 +6182,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+cachefs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -6269,7 +6303,7 @@ cachefs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
}
/* must not be current dir */
- if (VOP_CMP(vp, cdir)) {
+ if (VOP_CMP(vp, cdir, ct)) {
error = EINVAL;
break;
}
@@ -6372,7 +6406,7 @@ cachefs_rmdir_connected(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_rmdir (nfsv4): dcp %p, dbackvp %p, "
"name %s\n", dcp, dcp->c_backvp, nm));
- error = VOP_RMDIR(dcp->c_backvp, nm, cdir, cr);
+ error = VOP_RMDIR(dcp->c_backvp, nm, cdir, cr, NULL, 0);
if (error)
goto out;
@@ -6507,9 +6541,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
cachefs_symlink(vnode_t *dvp, char *lnm, vattr_t *tva,
- char *tnm, cred_t *cr)
+ char *tnm, cred_t *cr, caller_context_t *ct, int flags)
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -6635,7 +6670,7 @@ cachefs_symlink_connected(vnode_t *dvp, char *lnm, vattr_t *tva,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_symlink (nfsv4): dcp %p, dbackvp %p, "
"lnm %s, tnm %s\n", dcp, dcp->c_backvp, lnm, tnm));
- error = VOP_SYMLINK(dcp->c_backvp, lnm, tva, tnm, cr);
+ error = VOP_SYMLINK(dcp->c_backvp, lnm, tva, tnm, cr, NULL, 0);
if (error) {
mutex_exit(&dcp->c_statelock);
goto out;
@@ -6650,7 +6685,8 @@ cachefs_symlink_connected(vnode_t *dvp, char *lnm, vattr_t *tva,
CFSOP_MODIFY_COBJECT(fscp, dcp, cr);
/* lookup the symlink we just created and get its fid and attrs */
- (void) VOP_LOOKUP(dcp->c_backvp, lnm, &backvp, NULL, 0, NULL, cr);
+ (void) VOP_LOOKUP(dcp->c_backvp, lnm, &backvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (backvp == NULL) {
if (CFS_ISFS_BACKFS_NFSV4(fscp) == 0)
cachefs_nocache(dcp);
@@ -6891,8 +6927,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+cachefs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
cnode_t *dcp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -7087,7 +7125,8 @@ cachefs_readdir_connected(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_readdir (nfsv4): "
"dcp %p, dbackvp %p\n", dcp, dcp->c_backvp));
- error = VOP_READDIR(dcp->c_backvp, uiop, cr, eofp);
+ error = VOP_READDIR(dcp->c_backvp, uiop, cr, eofp,
+ NULL, 0);
VOP_RWUNLOCK(dcp->c_backvp, V_WRITELOCK_FALSE, NULL);
}
@@ -7132,7 +7171,7 @@ cachefs_readback_translate(cnode_t *cp, uio_t *uiop, cred_t *cr, int *eofp)
uioin.uio_resid = buffysize;
(void) VOP_RWLOCK(cp->c_backvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(cp->c_backvp, &uioin, cr, eofp);
+ error = VOP_READDIR(cp->c_backvp, &uioin, cr, eofp, NULL, 0);
VOP_RWUNLOCK(cp->c_backvp, V_WRITELOCK_FALSE, NULL);
if (error != 0)
@@ -7186,8 +7225,9 @@ cachefs_readdir_disconnected(vnode_t *vp, uio_t *uiop, cred_t *cr,
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_fid(struct vnode *vp, struct fid *fidp)
+cachefs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
int error = 0;
struct cnode *cp = VTOC(vp);
@@ -7257,7 +7297,8 @@ cachefs_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-cachefs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+cachefs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
return (0);
}
@@ -7266,10 +7307,11 @@ static int cachefs_lostpage = 0;
/*
* Return all the pages from [off..off+len] in file
*/
+/*ARGSUSED*/
static int
cachefs_getpage(struct vnode *vp, offset_t off, size_t len,
uint_t *protp, struct page *pl[], size_t plsz, struct seg *seg,
- caddr_t addr, enum seg_rw rw, cred_t *cr)
+ caddr_t addr, enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
int error;
@@ -7441,7 +7483,7 @@ cachefs_getpage_backfs_nfsv4(struct vnode *vp, offset_t off, size_t len,
("cachefs_getpage_backfs_nfsv4: cnode %p, backvp %p\n",
cp, backvp));
error = VOP_GETPAGE(backvp, off, len, protp, pl, plsz, seg,
- addr, rw, cr);
+ addr, rw, cr, NULL);
return (error);
}
@@ -7507,7 +7549,7 @@ again:
}
error = VOP_GETPAGE(cp->c_backvp, off,
PAGESIZE, protp, ourpl, PAGESIZE, seg,
- addr, S_READ, cr);
+ addr, S_READ, cr, NULL);
/*
* backfs returns EFAULT when we are trying for a
* page beyond EOF but cachefs has the knowledge that
@@ -7588,13 +7630,14 @@ again:
/* else XXX assert CN_NOCACHE? */
error = VOP_GETPAGE(cp->c_backvp, (offset_t)off,
PAGESIZE, protp, ourpl, popsize,
- seg, addr, S_READ, cr);
+ seg, addr, S_READ, cr, NULL);
if (error)
goto out;
fscp->fs_stats.st_misses++;
} else {
if (cp->c_flags & CN_POPULATION_PENDING) {
- error = VOP_FSYNC(cp->c_frontvp, FSYNC, cr);
+ error = VOP_FSYNC(cp->c_frontvp, FSYNC, cr,
+ NULL);
cp->c_flags &= ~CN_POPULATION_PENDING;
if (error) {
cachefs_nocache(cp);
@@ -7608,7 +7651,7 @@ again:
*/
error = VOP_GETPAGE(cp->c_frontvp, (offset_t)off,
PAGESIZE, protp, ourpl, PAGESIZE, seg, addr,
- rw, cr);
+ rw, cr, NULL);
if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_GPFRONT))
cachefs_log_gpfront(cachep, error,
fscp->fs_cfsvfsp,
@@ -7718,7 +7761,7 @@ again:
}
error = VOP_GETPAGE(cp->c_backvp, (offset_t)off,
PAGESIZE, protp, ourpl, PAGESIZE, seg,
- addr, S_READ, cr);
+ addr, S_READ, cr, NULL);
if (error)
goto out;
@@ -7776,8 +7819,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+cachefs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
int error = 0;
@@ -7874,7 +7919,7 @@ cachefs_putpage_backfs_nfsv4(vnode_t *vp, offset_t off, size_t len, int flags,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_putpage_backfs_nfsv4: cnode %p, backvp %p\n",
cp, backvp));
- error = VOP_PUTPAGE(backvp, off, len, flags, cr);
+ error = VOP_PUTPAGE(backvp, off, len, flags, cr, NULL);
return (error);
}
@@ -8046,7 +8091,8 @@ again:
/*ARGSUSED*/
static int
cachefs_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, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8224,7 +8270,8 @@ cachefs_map_backfs_nfsv4(struct vnode *vp, offset_t off, struct as *as,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_map_backfs_nfsv4: cnode %p, backvp %p\n",
cp, backvp));
- error = VOP_MAP(backvp, off, as, addrp, len, prot, maxprot, flags, cr);
+ error = VOP_MAP(backvp, off, as, addrp, len, prot, maxprot, flags, cr,
+ NULL);
return (error);
}
@@ -8233,7 +8280,7 @@ cachefs_map_backfs_nfsv4(struct vnode *vp, offset_t off, struct as *as,
static int
cachefs_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,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8261,7 +8308,7 @@ cachefs_addmap(struct vnode *vp, offset_t off, struct as *as,
static int
cachefs_delmap(struct vnode *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)
+ cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8346,7 +8393,8 @@ cachefs_delmap(struct vnode *vp, offset_t off, struct as *as,
/* ARGSUSED */
static int
cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
struct cnode *cp = VTOC(vp);
int error;
@@ -8382,7 +8430,7 @@ cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
/* XXX bob: nfs does a bunch more checks than we do */
if (CFS_ISFS_LLOCK(fscp)) {
ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
for (;;) {
@@ -8441,7 +8489,7 @@ cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
if (bfp->l_type != F_UNLCK && cmd != F_GETLK &&
!CFS_ISFS_BACKFS_NFSV4(fscp)) {
error = cachefs_putpage(
- vp, (offset_t)0, 0, B_INVAL, cr);
+ vp, (offset_t)0, 0, B_INVAL, cr, ct);
if (error) {
error = ENOLCK;
VN_RELE(backvp);
@@ -8453,7 +8501,8 @@ cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_frlock (nfsv4): cp %p, backvp %p\n",
cp, backvp));
- error = VOP_FRLOCK(backvp, cmd, bfp, flag, offset, NULL, cr);
+ error = VOP_FRLOCK(backvp, cmd, bfp, flag, offset, NULL, cr,
+ ct);
VN_RELE(backvp);
if (CFS_TIMEOUT(fscp, error)) {
connected = 1;
@@ -8571,7 +8620,7 @@ cachefs_space_backfs_nfsv4(struct vnode *vp, int cmd, struct flock64 *bfp,
/*ARGSUSED*/
static int
-cachefs_realvp(struct vnode *vp, struct vnode **vpp)
+cachefs_realvp(struct vnode *vp, struct vnode **vpp, caller_context_t *ct)
{
return (EINVAL);
}
@@ -8579,7 +8628,7 @@ cachefs_realvp(struct vnode *vp, struct vnode **vpp)
/*ARGSUSED*/
static int
cachefs_pageio(struct vnode *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
return (ENOSYS);
}
@@ -8618,7 +8667,7 @@ cachefs_setsecattr_connected(cnode_t *cp,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_setsecattr (nfsv4): cp %p, backvp %p",
cp, cp->c_backvp));
- error = VOP_SETSECATTR(cp->c_backvp, vsec, flag, cr);
+ error = VOP_SETSECATTR(cp->c_backvp, vsec, flag, cr, NULL);
if (error) {
goto out;
}
@@ -8742,8 +8791,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr)
+cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8791,7 +8842,7 @@ cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr)
held = 0;
}
- /* aquire access to the file system */
+ /* acquire access to the file system */
error = cachefs_cd_access(fscp, connected, 1);
if (error)
break;
@@ -8883,7 +8934,8 @@ cachefs_acl2perm(cnode_t *cp, vsecattr_t *vsec)
}
static int
-cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr)
+cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8913,7 +8965,7 @@ cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr)
CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
if (fscp->fs_info.fi_mntflags & CFS_NOACL) {
- error = fs_fab_acl(vp, vsec, flag, cr);
+ error = fs_fab_acl(vp, vsec, flag, cr, ct);
goto out;
}
@@ -8974,7 +9026,8 @@ out:
}
static int
-cachefs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+cachefs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -9014,7 +9067,7 @@ cachefs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_shrlock (nfsv4): cp %p, backvp %p",
cp, backvp));
- error = VOP_SHRLOCK(backvp, cmd, shr, flag, cr);
+ error = VOP_SHRLOCK(backvp, cmd, shr, flag, cr, ct);
}
out:
@@ -9065,7 +9118,7 @@ cachefs_getsecattr_connected(vnode_t *vp, vsecattr_t *vsec, int flag,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_getsecattr (nfsv4): cp %p, backvp %p",
cp, cp->c_backvp));
- error = VOP_GETSECATTR(cp->c_backvp, vsec, flag, cr);
+ error = VOP_GETSECATTR(cp->c_backvp, vsec, flag, cr, NULL);
if (error)
goto out;
@@ -9178,7 +9231,7 @@ cachefs_cacheacl(cnode_t *cp, vsecattr_t *vsecp)
bzero(&vsec, sizeof (vsec));
vsecp->vsa_mask =
VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT;
- error = VOP_GETSECATTR(cp->c_backvp, vsecp, 0, kcred);
+ error = VOP_GETSECATTR(cp->c_backvp, vsecp, 0, kcred, NULL);
if (error != 0) {
goto out;
}
@@ -9256,7 +9309,7 @@ cachefs_cacheacl(cnode_t *cp, vsecattr_t *vsecp)
ASSERT(vp != NULL);
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(vp, vsecp, 0, kcred);
+ error = VOP_SETSECATTR(vp, vsecp, 0, kcred, NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
if (error != 0) {
#ifdef CFSDEBUG
@@ -9320,7 +9373,7 @@ cachefs_purgeacl(cnode_t *cp)
(void) strcat(name, ".d");
(void) VOP_RMDIR(cp->c_filegrp->fg_dirvp, name,
- cp->c_filegrp->fg_dirvp, kcred);
+ cp->c_filegrp->fg_dirvp, kcred, NULL, 0);
}
cp->c_metadata.md_flags &= ~(MD_ACL | MD_ACLDIR);
@@ -9345,7 +9398,7 @@ cachefs_getacldirvp(cnode_t *cp)
make_ascii_name(&cp->c_id, name);
(void) strcat(name, ".d");
error = VOP_LOOKUP(cp->c_filegrp->fg_dirvp,
- name, &cp->c_acldirvp, NULL, 0, NULL, kcred);
+ name, &cp->c_acldirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if ((error != 0) && (error != ENOENT))
goto out;
@@ -9360,7 +9413,7 @@ cachefs_getacldirvp(cnode_t *cp)
AT_UID | AT_GID;
error =
VOP_MKDIR(cp->c_filegrp->fg_dirvp,
- name, &va, &cp->c_acldirvp, kcred);
+ name, &va, &cp->c_acldirvp, kcred, NULL, 0, NULL);
if (error != 0)
goto out;
}
@@ -9432,7 +9485,7 @@ cachefs_getaclfromcache(cnode_t *cp, vsecattr_t *vsec)
}
if (vp != NULL) {
- if ((error = VOP_GETSECATTR(vp, vsec, 0, kcred)) != 0) {
+ if ((error = VOP_GETSECATTR(vp, vsec, 0, kcred, NULL)) != 0) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_VOPS)
printf("cachefs_getaclfromcache: error %d\n",
@@ -9858,7 +9911,8 @@ again:
error = ETIMEDOUT;
}
if (error == 0)
- error = VOP_GETSECATTR(cp->c_backvp, &vsec, 0, cr);
+ error = VOP_GETSECATTR(cp->c_backvp, &vsec, 0, cr,
+ NULL);
if (error != 0) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_VOPS)
@@ -10104,8 +10158,8 @@ cachefs_modified(cnode_t *cp)
/* identify file so fsck knows it is modified */
va.va_mode = 0766;
va.va_mask = AT_MODE;
- error = VOP_SETATTR(cp->c_frontvp, &va,
- 0, kcred, NULL);
+ error = VOP_SETATTR(cp->c_frontvp,
+ &va, 0, kcred, NULL);
if (error) {
cmn_err(CE_WARN,
"Cannot change ff mode.\n");
@@ -10184,7 +10238,8 @@ cachefs_vtype_aclok(vnode_t *vp)
}
static int
-cachefs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+cachefs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int error = 0;
fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
@@ -10202,7 +10257,7 @@ cachefs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
}
(*valp)++;
} else
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
return (error);
}
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_all.c b/usr/src/uts/common/fs/ctfs/ctfs_all.c
index 382f66da8a..6a0d080e56 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_all.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_all.c
@@ -50,7 +50,8 @@
static int ctfs_adir_do_readdir(vnode_t *, struct dirent64 *, int *, offset_t *,
offset_t *, void *);
-static int ctfs_adir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *);
+static int ctfs_adir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
+ cred_t *);
/*
* ctfs_create_adirnode
@@ -71,7 +72,12 @@ ctfs_create_adirnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_adir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_adir_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
int i, total;
@@ -89,8 +95,10 @@ ctfs_adir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
return (0);
}
+/* ARGSUSED */
static int
-ctfs_adir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop)
+ctfs_adir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
+ cred_t *cr)
{
int i;
contract_t *ct;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_cdir.c b/usr/src/uts/common/fs/ctfs/ctfs_cdir.c
index 4861f73244..0de17d43eb 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_cdir.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_cdir.c
@@ -95,7 +95,12 @@ ctfs_create_cdirnode(vnode_t *pvp, contract_t *ct)
*/
/* ARGSUSED */
static int
-ctfs_cdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_cdir_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
ctfs_cdirnode_t *cdirnode = vp->v_data;
@@ -129,7 +134,7 @@ ctfs_cdir_do_inode(vnode_t *vp, int index)
*/
/* ARGSUSED */
static void
-ctfs_cdir_inactive(vnode_t *vp, cred_t *cr)
+ctfs_cdir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *cct)
{
ctfs_cdirnode_t *cdirnode = vp->v_data;
contract_t *ct = cdirnode->ctfs_cn_contract;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_ctl.c b/usr/src/uts/common/fs/ctfs/ctfs_ctl.c
index da293cbb21..da2ac0b9c7 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_ctl.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_ctl.c
@@ -81,7 +81,12 @@ ctfs_create_ctlnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_ctl_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_ctl_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *cct)
{
ctfs_ctlnode_t *ctlnode = vp->v_data;
contract_t *ct = ctlnode->ctfs_ctl_contract;
@@ -108,17 +113,17 @@ ctfs_ctl_access(vnode_t *vp, int mode, int flags, cred_t *cr)
* constraints imposed by ctfs_ctl_access are met.
*/
static int
-ctfs_ctl_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_ctl_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
if (flag != (FWRITE | FOFFMAX))
return (EINVAL);
- return (ctfs_ctl_access(*vpp, VWRITE, 0, cr));
+ return (ctfs_ctl_access(*vpp, VWRITE, 0, cr, ct));
}
/*
* ctfs_ctl_common_getattr
- * Implements fucntionality common to ctl and status ctfs VOP_GETATTR
+ * Implements functionality common to ctl and status ctfs VOP_GETATTR
* entry points. It assumes vp->v_data is set
*/
static int
@@ -144,7 +149,8 @@ ctfs_ctl_common_getattr(vnode_t *vp, vattr_t *vap)
*/
/* ARGSUSED */
static int
-ctfs_ctl_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_ctl_getattr(vnode_t *vp, vattr_t *vap, int flags,
+ cred_t *cr, caller_context_t *ct)
{
vap->va_mode = 0222;
@@ -156,7 +162,8 @@ ctfs_ctl_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_stat_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_stat_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
vap->va_mode = 0444;
@@ -170,8 +177,14 @@ ctfs_stat_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_ctl_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_ctl_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *cct)
{
ctfs_ctlnode_t *ctlnode = vp->v_data;
contract_t *ct = ctlnode->ctfs_ctl_contract;
@@ -257,8 +270,14 @@ ctfs_create_statnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_stat_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_stat_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *cct)
{
ctfs_ctlnode_t *statnode = vp->v_data;
contract_t *ct = statnode->ctfs_ctl_contract;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_event.c b/usr/src/uts/common/fs/ctfs/ctfs_event.c
index ac4447e493..c9a99e85fb 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_event.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_event.c
@@ -191,7 +191,12 @@ ctfs_create_evnode(vnode_t *pvp)
*/
/*ARGSUSED*/
static int
-ctfs_ev_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_ev_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *cct)
{
ctfs_evnode_t *evnode = vp->v_data;
contract_t *ct = evnode->ctfs_ev_contract;
@@ -214,7 +219,7 @@ ctfs_ev_access(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_ev_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_ev_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *cct)
{
ctfs_evnode_t *evnode = (*vpp)->v_data;
contract_t *ct = evnode->ctfs_ev_contract;
@@ -235,7 +240,7 @@ ctfs_ev_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
static void
-ctfs_ev_inactive(vnode_t *vp, cred_t *cr)
+ctfs_ev_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
ctfs_evnode_t *evnode;
vnode_t *pvp = gfs_file_parent(vp);
@@ -258,7 +263,12 @@ ctfs_ev_inactive(vnode_t *vp, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_ev_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_ev_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
ctfs_evnode_t *evnode = vp->v_data;
@@ -281,8 +291,14 @@ ctfs_ev_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_ev_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_ev_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
ctfs_evnode_t *evnode = vp->v_data;
@@ -293,9 +309,15 @@ ctfs_ev_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
/*
* ctfs_ev_poll - VOP_POLL entry point
*/
+/*ARGSUSED*/
static int
-ctfs_ev_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **php)
+ctfs_ev_poll(
+ vnode_t *vp,
+ short events,
+ int anyyet,
+ short *reventsp,
+ pollhead_t **php,
+ caller_context_t *ct)
{
ctfs_evnode_t *evnode = vp->v_data;
@@ -361,7 +383,7 @@ ctfs_create_bundle(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_bu_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_bu_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
ctfs_bunode_t *bunode = (*vpp)->v_data;
@@ -379,7 +401,7 @@ ctfs_bu_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
static void
-ctfs_bu_inactive(vnode_t *vp, cred_t *cr)
+ctfs_bu_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
ctfs_bunode_t *bunode;
vnode_t *pvp = gfs_file_parent(vp);
@@ -400,7 +422,12 @@ ctfs_bu_inactive(vnode_t *vp, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_bu_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_bu_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
ctfs_bunode_t *bunode = vp->v_data;
@@ -424,8 +451,14 @@ ctfs_bu_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_bu_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_bu_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
ctfs_bunode_t *bunode = vp->v_data;
@@ -436,9 +469,15 @@ ctfs_bu_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
/*
* ctfs_bu_poll - VOP_POLL entry point
*/
+/*ARGSUSED*/
static int
-ctfs_bu_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **php)
+ctfs_bu_poll(
+ vnode_t *vp,
+ short events,
+ int anyyet,
+ short *reventsp,
+ pollhead_t **php,
+ caller_context_t *ct)
{
ctfs_bunode_t *bunode = vp->v_data;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_latest.c b/usr/src/uts/common/fs/ctfs/ctfs_latest.c
index 7d15dd494a..6a2bfc80f1 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_latest.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_latest.c
@@ -65,7 +65,7 @@ ctfs_create_latenode(vnode_t *pvp)
* ctfs_latest_getattr to obtain that file.
*/
static vnode_t *
-ctfs_latest_nested_open(vnode_t *vp)
+ctfs_latest_nested_open(vnode_t *vp, cred_t *cr)
{
contract_t *ct = ttolwp(curthread)->lwp_ct_latest[
gfs_file_index(gfs_file_parent(vp))];
@@ -77,7 +77,7 @@ ctfs_latest_nested_open(vnode_t *vp)
gfs_file_set_index(cvp, -1);
- VERIFY(gfs_dir_lookup(cvp, "status", &svp) == 0);
+ VERIFY(gfs_dir_lookup(cvp, "status", &svp, cr) == 0);
VN_RELE(cvp);
@@ -94,14 +94,19 @@ ctfs_latest_nested_open(vnode_t *vp)
*/
/* ARGSUSED */
static int
-ctfs_latest_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_latest_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vnode_t *nvp;
if (mode & (VEXEC | VWRITE))
return (EACCES);
- if (nvp = ctfs_latest_nested_open(vp)) {
+ if (nvp = ctfs_latest_nested_open(vp, cr)) {
VN_RELE(nvp);
return (0);
}
@@ -116,17 +121,17 @@ ctfs_latest_access(vnode_t *vp, int mode, int flags, cred_t *cr)
* the LWP's latest contract.
*/
static int
-ctfs_latest_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_latest_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *nvp;
if (flag != (FREAD | FOFFMAX))
return (EINVAL);
- if (nvp = ctfs_latest_nested_open(*vpp)) {
+ if (nvp = ctfs_latest_nested_open(*vpp, cr)) {
VN_RELE(*vpp);
*vpp = nvp;
- return (VOP_OPEN(vpp, flag, cr));
+ return (VOP_OPEN(vpp, flag, cr, ct));
}
return (ESRCH);
@@ -139,12 +144,17 @@ ctfs_latest_open(vnode_t **vpp, int flag, cred_t *cr)
* latest contract. Otherwise it fakes up something bland.
*/
static int
-ctfs_latest_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_latest_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vnode_t *nvp;
- if (nvp = ctfs_latest_nested_open(vp)) {
- int res = VOP_GETATTR(nvp, vap, flags, cr);
+ if (nvp = ctfs_latest_nested_open(vp, cr)) {
+ int res = VOP_GETATTR(nvp, vap, flags, cr, ct);
VN_RELE(nvp);
return (res);
}
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_root.c b/usr/src/uts/common/fs/ctfs/ctfs_root.c
index 1616a986cd..8861b6d73b 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_root.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_root.c
@@ -55,7 +55,7 @@
/*
* ctfs, the contract filesystem.
*
- * Exposes the constract subsystem to userland. The structure of the
+ * Exposes the construct subsystem to userland. The structure of the
* filesytem is a public interface, but the behavior of the files is
* private and unstable. Contract consumers are expected to use
* libcontract(3lib) to operate on ctfs file descriptors.
@@ -399,7 +399,7 @@ ctfs_common_getattr(vnode_t *vp, vattr_t *vap)
*/
/* ARGSUSED */
int
-ctfs_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
if ((flag & (FOFFMAX | FWRITE)) != FOFFMAX)
return (EINVAL);
@@ -414,7 +414,13 @@ ctfs_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+ctfs_close(
+ vnode_t *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -424,7 +430,12 @@ ctfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_access_dir(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_access_dir(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
if (mode & VWRITE)
return (EACCES);
@@ -437,7 +448,12 @@ ctfs_access_dir(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_access_readonly(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_access_readonly(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
if (mode & (VWRITE | VEXEC))
return (EACCES);
@@ -450,7 +466,12 @@ ctfs_access_readonly(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_access_readwrite(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_access_readwrite(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
if (mode & VEXEC)
return (EACCES);
@@ -463,7 +484,12 @@ ctfs_access_readwrite(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_root_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vap->va_type = VDIR;
vap->va_mode = 0555;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_sym.c b/usr/src/uts/common/fs/ctfs/ctfs_sym.c
index bf825ab366..571f8903b8 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_sym.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_sym.c
@@ -81,7 +81,12 @@ ctfs_create_symnode(vnode_t *pvp, contract_t *ct)
*/
/* ARGSUSED */
static int
-ctfs_sym_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_sym_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
ctfs_symnode_t *symnode = vp->v_data;
@@ -104,7 +109,7 @@ ctfs_sym_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_sym_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+ctfs_sym_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
ctfs_symnode_t *symnode = vp->v_data;
@@ -117,7 +122,7 @@ ctfs_sym_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
*/
/* ARGSUSED */
static void
-ctfs_sym_inactive(vnode_t *vp, cred_t *cr)
+ctfs_sym_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
ctfs_symnode_t *symnode;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_tdir.c b/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
index 2d47c72339..fd3c229c0f 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
@@ -58,7 +58,8 @@ static gfs_dirent_t ctfs_tdir_dirents[] = {
static int ctfs_tdir_do_readdir(vnode_t *, struct dirent64 *, int *, offset_t *,
offset_t *, void *);
-static int ctfs_tdir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *);
+static int ctfs_tdir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
+ cred_t *);
static ino64_t ctfs_tdir_do_inode(vnode_t *, int);
/*
@@ -77,7 +78,12 @@ ctfs_create_tdirnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_tdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_tdir_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vap->va_type = VDIR;
vap->va_mode = 0555;
@@ -124,8 +130,10 @@ ctfs_tdir_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
return (0);
}
+/* ARGSUSED */
static int
-ctfs_tdir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop)
+ctfs_tdir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
+ cred_t *cr)
{
int i;
contract_t *ct;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c b/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
index d99b8f56e8..1786d1d79f 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
@@ -75,7 +75,7 @@ ctfs_create_tmplnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_tmpl_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_tmpl_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
if (flag != (FREAD | FWRITE | FOFFMAX))
return (EINVAL);
@@ -88,7 +88,12 @@ ctfs_tmpl_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_tmpl_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_tmpl_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vap->va_type = VREG;
vap->va_mode = 0666;
@@ -109,8 +114,14 @@ ctfs_tmpl_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_tmpl_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_tmpl_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
ctfs_tmplnode_t *tmplnode = vp->v_data;
ct_param_t param;
@@ -158,7 +169,7 @@ ctfs_tmpl_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
*/
/* ARGSUSED */
static void
-ctfs_tmpl_inactive(vnode_t *vp, cred_t *cr)
+ctfs_tmpl_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
ctfs_tmplnode_t *tmplnode;
diff --git a/usr/src/uts/common/fs/dev/sdev_profile.c b/usr/src/uts/common/fs/dev/sdev_profile.c
index 290cce18ee..1756ac7115 100644
--- a/usr/src/uts/common/fs/dev/sdev_profile.c
+++ b/usr/src/uts/common/fs/dev/sdev_profile.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -75,13 +75,14 @@ prof_getattr(struct sdev_node *dir, char *name, struct vnode *gdv,
/* get attribute from shadow, if present; else get default */
advp = dir->sdev_attrvp;
- if (advp && VOP_LOOKUP(advp, name, avpp, NULL, 0, NULL, kcred) == 0) {
- (void) VOP_GETATTR(*avpp, vap, 0, kcred);
+ if (advp && VOP_LOOKUP(advp, name, avpp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL) == 0) {
+ (void) VOP_GETATTR(*avpp, vap, 0, kcred, NULL);
} else if (gdv == NULL || gdv->v_type == VDIR) {
/* always create shadow directory */
*vap = sdev_vattr_dir;
- if (advp && VOP_MKDIR(advp, name,
- &sdev_vattr_dir, avpp, kcred) != 0) {
+ if (advp && VOP_MKDIR(advp, name, &sdev_vattr_dir,
+ avpp, kcred, NULL, 0, NULL) != 0) {
*avpp = NULLVP;
sdcmn_err10(("prof_getattr: failed to create "
"shadow directory %s/%s\n", dir->sdev_path, name));
@@ -95,7 +96,7 @@ prof_getattr(struct sdev_node *dir, char *name, struct vnode *gdv,
* attr for device nodes.
*/
struct vnode *rvp;
- if (VOP_REALVP(gdv, &rvp) != 0)
+ if (VOP_REALVP(gdv, &rvp, NULL) != 0)
rvp = gdv;
devfs_get_defattr(rvp, vap, no_fs_perm);
*avpp = NULLVP;
@@ -209,7 +210,7 @@ prof_make_dir(char *name, struct sdev_node **gdirp, struct sdev_node **dirp)
/* find corresponding dir node in global dev */
if (gdir) {
error = VOP_LOOKUP(SDEVTOV(gdir), name, &gnewdir,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0) {
*gdirp = VTOSDEV(gnewdir);
} else { /* it's ok if there no global dir */
@@ -390,7 +391,8 @@ is_nonempty_dir(char *name, char *pathleft, struct sdev_node *dir)
struct vnode *gvp;
struct sdev_node *gdir = dir->sdev_origin;
- if (VOP_LOOKUP(SDEVTOV(gdir), name, &gvp, NULL, 0, NULL, kcred) != 0)
+ if (VOP_LOOKUP(SDEVTOV(gdir), name, &gvp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL) != 0)
return (0);
if (gvp->v_type != VDIR) {
@@ -502,7 +504,7 @@ walk_dir(struct vnode *dvp, void *arg, int (*callback)(char *, void *))
iov.iov_base = (char *)dbuf;
iov.iov_len = dlen;
(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dvp, &uio, kcred, &eof);
+ error = VOP_READDIR(dvp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
diff --git a/usr/src/uts/common/fs/dev/sdev_ptsops.c b/usr/src/uts/common/fs/dev/sdev_ptsops.c
index 4ee3a52857..f6d1fda64e 100644
--- a/usr/src/uts/common/fs/dev/sdev_ptsops.c
+++ b/usr/src/uts/common/fs/dev/sdev_ptsops.c
@@ -294,7 +294,8 @@ devpts_prunedir(struct sdev_node *ddv)
/*ARGSUSED3*/
static int
devpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
- struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred)
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
{
struct sdev_node *sdvp = VTOSDEV(dvp);
struct sdev_node *dv;
@@ -308,7 +309,7 @@ devpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
switch ((*vpp)->v_type) {
case VCHR:
dv = VTOSDEV(VTOS(*vpp)->s_realvp);
- ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp) == ENOSYS);
+ ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
break;
case VDIR:
dv = VTOSDEV(*vpp);
@@ -333,21 +334,23 @@ devpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
/*ARGSUSED2*/
static int
devpts_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
- int mode, struct vnode **vpp, struct cred *cred, int flag)
+ int mode, struct vnode **vpp, struct cred *cred, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
struct vnode *vp;
*vpp = NULL;
- error = devpts_lookup(dvp, nm, &vp, NULL, 0, NULL, cred);
+ error = devpts_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
+ NULL);
if (error == 0) {
if (excl == EXCL)
error = EEXIST;
else if (vp->v_type == VDIR && (mode & VWRITE))
error = EISDIR;
else
- error = VOP_ACCESS(vp, mode, 0, cred);
+ error = VOP_ACCESS(vp, mode, 0, cred, ct);
if (error) {
VN_RELE(vp);
@@ -365,9 +368,10 @@ devpts_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
* A /dev/pts entry will be created only after the first lookup of the slave
* device succeeds.
*/
+/*ARGSUSED4*/
static int
devpts_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
- int *eofp)
+ int *eofp, caller_context_t *ct, int flags)
{
struct sdev_node *sdvp = VTOSDEV(dvp);
if (uiop->uio_offset == 0) {
diff --git a/usr/src/uts/common/fs/dev/sdev_subr.c b/usr/src/uts/common/fs/dev/sdev_subr.c
index d6d92c2621..1075391d17 100644
--- a/usr/src/uts/common/fs/dev/sdev_subr.c
+++ b/usr/src/uts/common/fs/dev/sdev_subr.c
@@ -715,7 +715,7 @@ sdev_getlink(struct vnode *linkvp, char **link)
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_llimit = MAXOFFSET_T;
- err = VOP_READLINK(linkvp, &uio, kcred);
+ err = VOP_READLINK(linkvp, &uio, kcred, NULL);
if (err) {
cmn_err(CE_WARN, "readlink %s failed in dev\n", buf);
kmem_free(buf, MAXPATHLEN);
@@ -1155,7 +1155,7 @@ sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
timestruc_t now;
vattr.va_mask = AT_MODE|AT_UID|AT_GID;
- error = VOP_GETATTR(ovp, &vattr, 0, cred);
+ error = VOP_GETATTR(ovp, &vattr, 0, cred, NULL);
if (error)
return (error);
@@ -1227,7 +1227,7 @@ sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
(void) sdev_dirdelete(nddv, *ndvp);
*ndvp = NULL;
error = VOP_RMDIR(nddv->sdev_attrvp, nnm,
- nddv->sdev_attrvp, cred);
+ nddv->sdev_attrvp, cred, NULL, 0);
if (error)
goto err_out;
} else {
@@ -1249,7 +1249,7 @@ sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
*ndvp = NULL;
if (bkstore) {
error = VOP_REMOVE(nddv->sdev_attrvp,
- nnm, cred);
+ nnm, cred, NULL, 0);
if (error)
goto err_out;
}
@@ -1419,7 +1419,7 @@ devname_find_by_devpath(char *devpath, struct vattr *vattr)
}
if (vattr)
- (void) VOP_GETATTR(vp, vattr, 0, kcred);
+ (void) VOP_GETATTR(vp, vattr, 0, kcred, NULL);
return (vp);
}
@@ -1447,7 +1447,7 @@ devname_configure_by_path(char *physpath, struct vattr *vattr)
}
if (vattr)
- (void) VOP_GETATTR(vp, vattr, 0, kcred);
+ (void) VOP_GETATTR(vp, vattr, 0, kcred, NULL);
return (vp);
}
@@ -1462,7 +1462,8 @@ devname_backstore_lookup(struct sdev_node *ddv, char *nm, struct vnode **rvp)
ASSERT(rdvp);
- rval = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, kcred);
+ rval = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, kcred, NULL, NULL,
+ NULL);
return (rval);
}
@@ -1507,7 +1508,7 @@ sdev_filldir_from_store(struct sdev_node *ddv, int dlen, struct cred *cred)
iov.iov_base = (char *)dbuf;
iov.iov_len = dlen;
(void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dirvp, &uio, kcred, &eof);
+ error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -1552,7 +1553,7 @@ sdev_filldir_from_store(struct sdev_node *ddv, int dlen, struct cred *cred)
continue;
vattr.va_mask = AT_MODE|AT_UID|AT_GID;
- error = VOP_GETATTR(vp, &vattr, 0, cred);
+ error = VOP_GETATTR(vp, &vattr, 0, cred, NULL);
if (error)
continue;
@@ -1644,9 +1645,10 @@ sdev_shadow_node(struct sdev_node *dv, struct cred *cred)
lookup:
/* try to find it in the backing store */
- error = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, cred);
+ error = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, cred, NULL, NULL,
+ NULL);
if (error == 0) {
- if (VOP_REALVP(*rvp, &rrvp) == 0) {
+ if (VOP_REALVP(*rvp, &rrvp, NULL) == 0) {
VN_HOLD(rrvp);
VN_RELE(*rvp);
*rvp = rrvp;
@@ -1665,7 +1667,7 @@ lookup:
vap->va_mask |= AT_TYPE|AT_MODE;
switch (vap->va_type) {
case VDIR:
- error = VOP_MKDIR(rdvp, nm, vap, rvp, cred);
+ error = VOP_MKDIR(rdvp, nm, vap, rvp, cred, NULL, 0, NULL);
sdcmn_err9(("sdev_shadow_node: mkdir vp %p error %d\n",
(void *)(*rvp), error));
break;
@@ -1674,7 +1676,7 @@ lookup:
case VREG:
case VDOOR:
error = VOP_CREATE(rdvp, nm, vap, NONEXCL, VREAD|VWRITE,
- rvp, cred, 0);
+ rvp, cred, 0, NULL, NULL);
sdcmn_err9(("sdev_shadow_node: create vp %p, error %d\n",
(void *)(*rvp), error));
if (!error)
@@ -1682,7 +1684,8 @@ lookup:
break;
case VLNK:
ASSERT(dv->sdev_symlink);
- error = VOP_SYMLINK(rdvp, nm, vap, dv->sdev_symlink, cred);
+ error = VOP_SYMLINK(rdvp, nm, vap, dv->sdev_symlink, cred,
+ NULL, 0);
sdcmn_err9(("sdev_shadow_node: create symlink error %d\n",
error));
break;
@@ -1770,7 +1773,7 @@ sdev_cache_update(struct sdev_node *ddv, struct sdev_node **dv, char *nm,
}
/*
- * retrive the named entry from the directory cache
+ * retrieve the named entry from the directory cache
*/
struct sdev_node *
sdev_cache_lookup(struct sdev_node *ddv, char *nm)
@@ -2224,7 +2227,7 @@ tryagain:
"found attrvp %p for %s\n", (void *)rvp, nm));
vattr.va_mask = AT_MODE|AT_UID|AT_GID;
- error = VOP_GETATTR(rvp, &vattr, 0, cred);
+ error = VOP_GETATTR(rvp, &vattr, 0, cred, NULL);
if (error) {
rw_exit(&ddv->sdev_contents);
if (dv)
@@ -2583,10 +2586,10 @@ sdev_cleandir(struct sdev_node *ddv, char *expr, uint_t flags)
if (bkstore == 1) {
error = VOP_REMOVE(ddv->sdev_attrvp,
- bks_name, kcred);
+ bks_name, kcred, NULL, 0);
} else if (bkstore == 2) {
error = VOP_RMDIR(ddv->sdev_attrvp,
- bks_name, ddv->sdev_attrvp, kcred);
+ bks_name, ddv->sdev_attrvp, kcred, NULL, 0);
}
/* do not propagate the backing store errors */
@@ -2953,7 +2956,8 @@ sdev_modctl_lookup(const char *path, vnode_t **r_vp)
while (pn_pathleft(&pn)) {
ASSERT(vp->v_type == VDIR);
(void) pn_getcomponent(&pn, nm);
- error = VOP_LOOKUP(vp, nm, &cvp, NULL, 0, NULL, kcred);
+ error = VOP_LOOKUP(vp, nm, &cvp, NULL, 0, NULL, kcred, NULL,
+ NULL, NULL);
VN_RELE(vp);
if (error)
@@ -3065,7 +3069,7 @@ sdev_modctl_readdir(const char *dir, char ***dirlistp,
iov.iov_len = dlen;
(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(vp, &uio, kcred, &eof);
+ error = VOP_READDIR(vp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -3659,8 +3663,8 @@ devname_setattr_func(struct vnode *vp, struct vattr *vap, int flags,
* sdev_attr was allocated in sdev_mknode
*/
rw_enter(&dv->sdev_contents, RW_WRITER);
- error = secpolicy_vnode_setattr(cred, vp, vap, dv->sdev_attr,
- flags, sdev_unlocked_access, dv);
+ error = secpolicy_vnode_setattr(cred, vp, vap,
+ dv->sdev_attr, flags, sdev_unlocked_access, dv);
if (error) {
rw_exit(&dv->sdev_contents);
rw_exit(&parent->sdev_contents);
diff --git a/usr/src/uts/common/fs/dev/sdev_vfsops.c b/usr/src/uts/common/fs/dev/sdev_vfsops.c
index ca971fe30c..bde50de8a2 100644
--- a/usr/src/uts/common/fs/dev/sdev_vfsops.c
+++ b/usr/src/uts/common/fs/dev/sdev_vfsops.c
@@ -324,7 +324,7 @@ sdev_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
/* get acl flavor from attribute dir */
if (VOP_PATHCONF(avp, _PC_ACL_ENABLED, &sdev_data->sdev_acl_flavor,
- kcred) != 0 || sdev_data->sdev_acl_flavor == 0)
+ kcred, NULL) != 0 || sdev_data->sdev_acl_flavor == 0)
sdev_data->sdev_acl_flavor = _ACL_ACLENT_ENABLED;
args = NULL; /* so it won't be freed below */
diff --git a/usr/src/uts/common/fs/dev/sdev_vnops.c b/usr/src/uts/common/fs/dev/sdev_vnops.c
index 1d086c168a..de1d83e75a 100644
--- a/usr/src/uts/common/fs/dev/sdev_vnops.c
+++ b/usr/src/uts/common/fs/dev/sdev_vnops.c
@@ -76,7 +76,7 @@
/*ARGSUSED*/
static int
-sdev_open(struct vnode **vpp, int flag, struct cred *cred)
+sdev_open(struct vnode **vpp, int flag, struct cred *cred, caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(*vpp);
struct sdev_node *ddv = dv->sdev_dotdot;
@@ -98,7 +98,7 @@ sdev_open(struct vnode **vpp, int flag, struct cred *cred)
rw_exit(&ddv->sdev_contents);
return (ENOENT);
}
- error = VOP_OPEN(&(dv->sdev_attrvp), flag, cred);
+ error = VOP_OPEN(&(dv->sdev_attrvp), flag, cred, ct);
rw_exit(&ddv->sdev_contents);
return (error);
}
@@ -106,7 +106,7 @@ sdev_open(struct vnode **vpp, int flag, struct cred *cred)
/*ARGSUSED1*/
static int
sdev_close(struct vnode *vp, int flag, int count,
- offset_t offset, struct cred *cred)
+ offset_t offset, struct cred *cred, caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
@@ -124,7 +124,7 @@ sdev_close(struct vnode *vp, int flag, int count,
return (ENOTSUP);
ASSERT(dv->sdev_attrvp);
- return (VOP_CLOSE(dv->sdev_attrvp, flag, count, offset, cred));
+ return (VOP_CLOSE(dv->sdev_attrvp, flag, count, offset, cred, ct));
}
/*ARGSUSED*/
@@ -148,9 +148,9 @@ sdev_read(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
ASSERT(RW_READ_HELD(&VTOSDEV(vp)->sdev_contents));
ASSERT(dv->sdev_attrvp);
- (void) VOP_RWLOCK(dv->sdev_attrvp, 0, NULL);
+ (void) VOP_RWLOCK(dv->sdev_attrvp, 0, ct);
error = VOP_READ(dv->sdev_attrvp, uio, ioflag, cred, ct);
- VOP_RWUNLOCK(dv->sdev_attrvp, 0, NULL);
+ VOP_RWUNLOCK(dv->sdev_attrvp, 0, ct);
return (error);
}
@@ -175,9 +175,9 @@ sdev_write(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
ASSERT(dv->sdev_attrvp);
- (void) VOP_RWLOCK(dv->sdev_attrvp, 1, NULL);
+ (void) VOP_RWLOCK(dv->sdev_attrvp, 1, ct);
error = VOP_WRITE(dv->sdev_attrvp, uio, ioflag, cred, ct);
- VOP_RWUNLOCK(dv->sdev_attrvp, 1, NULL);
+ VOP_RWUNLOCK(dv->sdev_attrvp, 1, ct);
if (error == 0) {
sdev_update_timestamps(dv->sdev_attrvp, kcred,
AT_MTIME);
@@ -188,7 +188,7 @@ sdev_write(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
/*ARGSUSED*/
static int
sdev_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- struct cred *cred, int *rvalp)
+ struct cred *cred, int *rvalp, caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
@@ -200,11 +200,12 @@ sdev_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
return (EINVAL);
ASSERT(dv->sdev_attrvp);
- return (VOP_IOCTL(dv->sdev_attrvp, cmd, arg, flag, cred, rvalp));
+ return (VOP_IOCTL(dv->sdev_attrvp, cmd, arg, flag, cred, rvalp, ct));
}
static int
-sdev_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
+sdev_getattr(struct vnode *vp, struct vattr *vap, int flags,
+ struct cred *cr, caller_context_t *ct)
{
int error = 0;
struct sdev_node *dv = VTOSDEV(vp);
@@ -229,7 +230,7 @@ sdev_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
*/
if (dv->sdev_attrvp) {
rw_exit(&parent->sdev_contents);
- error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr);
+ error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr, ct);
sdev_vattr_merge(dv, vap);
} else if (dirops && (fn = dirops->devnops_getattr)) {
sdev_vattr_merge(dv, vap);
@@ -255,7 +256,7 @@ sdev_setattr(struct vnode *vp, struct vattr *vap, int flags,
static int
sdev_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
int error;
struct sdev_node *dv = VTOSDEV(vp);
@@ -267,20 +268,20 @@ sdev_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
(vsap->vsa_mask & (VSA_ACLCNT | VSA_DFACLCNT))) ||
(SDEV_ACL_FLAVOR(vp) == _ACL_ACE_ENABLED &&
(vsap->vsa_mask & (VSA_ACECNT | VSA_ACE))))
- return (fs_fab_acl(vp, vsap, flags, cr));
+ return (fs_fab_acl(vp, vsap, flags, cr, ct));
return (ENOSYS);
}
- (void) VOP_RWLOCK(avp, 1, NULL);
- error = VOP_GETSECATTR(avp, vsap, flags, cr);
- VOP_RWUNLOCK(avp, 1, NULL);
+ (void) VOP_RWLOCK(avp, 1, ct);
+ error = VOP_GETSECATTR(avp, vsap, flags, cr, ct);
+ VOP_RWUNLOCK(avp, 1, ct);
return (error);
}
static int
sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
int error;
struct sdev_node *dv = VTOSDEV(vp);
@@ -301,7 +302,7 @@ sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
*/
ASSERT(RW_WRITE_HELD(&dv->sdev_contents));
sdev_vattr_merge(dv, dv->sdev_attr);
- error = sdev_shadow_node(dv, cr);
+ error = sdev_shadow_node(dv, cr);
if (error) {
return (fs_nosys());
}
@@ -316,9 +317,9 @@ sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
}
ASSERT(avp);
- (void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(avp, vsap, flags, cr);
- VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, NULL);
+ (void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, ct);
+ error = VOP_SETSECATTR(avp, vsap, flags, cr, ct);
+ VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, ct);
return (error);
}
@@ -343,7 +344,8 @@ sdev_unlocked_access(void *vdv, int mode, struct cred *cr)
}
static int
-sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
int ret = 0;
@@ -351,7 +353,7 @@ sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr)
ASSERT(dv->sdev_attr || dv->sdev_attrvp);
if (dv->sdev_attrvp) {
- ret = VOP_ACCESS(dv->sdev_attrvp, mode, flags, cr);
+ ret = VOP_ACCESS(dv->sdev_attrvp, mode, flags, cr, ct);
} else if (dv->sdev_attr) {
rw_enter(&dv->sdev_contents, RW_READER);
ret = sdev_unlocked_access(dv, mode, cr);
@@ -369,7 +371,8 @@ sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr)
/*ARGSUSED3*/
static int
sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
- struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred)
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
{
struct sdev_node *parent;
int error;
@@ -378,7 +381,7 @@ sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
ASSERT(parent);
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
return (error);
if (!SDEV_IS_GLOBAL(parent))
@@ -389,7 +392,8 @@ sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
/*ARGSUSED2*/
static int
sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
- int mode, struct vnode **vpp, struct cred *cred, int flag)
+ int mode, struct vnode **vpp, struct cred *cred, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
struct vnode *vp = NULL;
struct vnode *avp;
@@ -421,11 +425,12 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
rw_exit(&parent->sdev_dotdot->sdev_contents);
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred, ct)) != 0)
return (error);
/* check existing name */
- error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
+ error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
/* name found */
if (error == 0) {
@@ -436,7 +441,7 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
/* allowing create/read-only an existing directory */
error = EISDIR;
} else {
- error = VOP_ACCESS(vp, mode, flag, cred);
+ error = VOP_ACCESS(vp, mode, flag, cred, ct);
}
if (error) {
@@ -449,7 +454,7 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
(vap->va_size == 0)) {
ASSERT(parent->sdev_attrvp);
error = VOP_CREATE(parent->sdev_attrvp,
- nm, vap, excl, mode, &avp, cred, flag);
+ nm, vap, excl, mode, &avp, cred, flag, ct, vsecp);
if (error) {
VN_RELE(vp);
@@ -505,7 +510,8 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
}
static int
-sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
+sdev_remove(struct vnode *dvp, char *nm, struct cred *cred,
+ caller_context_t *ct, int flags)
{
int error;
struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
@@ -535,7 +541,7 @@ sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
}
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0) {
rw_exit(&parent->sdev_contents);
return (error);
}
@@ -556,7 +562,7 @@ sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
}
/* write access is required to remove an entry */
- if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
rw_exit(&parent->sdev_contents);
VN_RELE(vp);
return (error);
@@ -601,7 +607,8 @@ sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
*/
if (bkstore) {
ASSERT(parent->sdev_attrvp);
- error = VOP_REMOVE(parent->sdev_attrvp, nm, cred);
+ error = VOP_REMOVE(parent->sdev_attrvp, nm, cred,
+ ct, flags);
/*
* do not report BUSY error
* because the backing store ref count is released
@@ -627,9 +634,10 @@ sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
* - both oldnm and newnm are in the scope of /dev file system,
* to simply the namespace management model.
*/
+/*ARGSUSED6*/
static int
sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
- struct cred *cred)
+ struct cred *cred, caller_context_t *ct, int flags)
{
struct sdev_node *fromparent = NULL;
struct vattr vattr;
@@ -690,7 +698,9 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
mutex_enter(&sdev_lock);
/* check existence of the source node */
- error = VOP_LOOKUP(odvp, onm, &ovp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
+ error = VOP_LOOKUP(odvp, onm, &ovp, NULL, 0, NULL, cred, ct,
+ NULL, NULL);
if (error) {
sdcmn_err2(("sdev_rename: the source node %s exists\n",
onm));
@@ -698,21 +708,23 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
return (error);
}
- if (VOP_REALVP(ovp, &realvp) == 0) {
+ if (VOP_REALVP(ovp, &realvp, ct) == 0) {
VN_HOLD(realvp);
VN_RELE(ovp);
ovp = realvp;
}
/* check existence of destination */
- error = VOP_LOOKUP(ndvp, nnm, &nvp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
+ error = VOP_LOOKUP(ndvp, nnm, &nvp, NULL, 0, NULL, cred, ct,
+ NULL, NULL);
if (error && (error != ENOENT)) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
return (error);
}
- if (nvp && (VOP_REALVP(nvp, &realvp) == 0)) {
+ if (nvp && (VOP_REALVP(nvp, &realvp, ct) == 0)) {
VN_HOLD(realvp);
VN_RELE(nvp);
nvp = realvp;
@@ -724,14 +736,14 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
*/
if (odvp != ndvp) {
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(odvp, &vattr, 0, cred)) {
+ if (error = VOP_GETATTR(odvp, &vattr, 0, cred, ct)) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
return (error);
}
fsid = vattr.va_fsid;
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(ndvp, &vattr, 0, cred)) {
+ if (error = VOP_GETATTR(ndvp, &vattr, 0, cred, ct)) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
return (error);
@@ -744,7 +756,7 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
}
/* make sure the old entry can be deleted */
- error = VOP_ACCESS(odvp, VWRITE, 0, cred);
+ error = VOP_ACCESS(odvp, VWRITE, 0, cred, ct);
if (error) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
@@ -754,7 +766,7 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
/* make sure the destination allows creation */
samedir = (fromparent == toparent);
if (!samedir) {
- error = VOP_ACCESS(ndvp, VEXEC|VWRITE, 0, cred);
+ error = VOP_ACCESS(ndvp, VEXEC|VWRITE, 0, cred, ct);
if (error) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
@@ -856,11 +868,13 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
if (bkstore) {
ASSERT(fromparent->sdev_attrvp);
if (type != VDIR) {
+/* XXXci - We may need to translate the C-I flags on VOP_REMOVE */
error = VOP_REMOVE(fromparent->sdev_attrvp,
- onm, kcred);
+ onm, kcred, ct, 0);
} else {
+/* XXXci - We may need to translate the C-I flags on VOP_RMDIR */
error = VOP_RMDIR(fromparent->sdev_attrvp,
- onm, fromparent->sdev_attrvp, kcred);
+ onm, fromparent->sdev_attrvp, kcred, ct, 0);
}
if (error) {
@@ -882,9 +896,10 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
* tnm - path, e.g. /devices/... or /dev/...
* lnm - dev_name
*/
+/*ARGSUSED6*/
static int
sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
- char *tnm, struct cred *cred)
+ char *tnm, struct cred *cred, caller_context_t *ct, int flags)
{
int error;
struct vnode *vp = NULL;
@@ -907,11 +922,12 @@ sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
rw_exit(&parent->sdev_dotdot->sdev_contents);
/* execute access is required to search a directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
return (error);
/* find existing name */
- error = VOP_LOOKUP(dvp, lnm, &vp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags here */
+ error = VOP_LOOKUP(dvp, lnm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
if (error == 0) {
ASSERT(vp);
VN_RELE(vp);
@@ -922,7 +938,7 @@ sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
return (error);
/* write access is required to create a symlink */
- if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0)
return (error);
/* put it into memory cache */
@@ -955,9 +971,10 @@ sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
return (0);
}
+/*ARGSUSED6*/
static int
sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
- struct cred *cred)
+ struct cred *cred, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
@@ -979,12 +996,13 @@ sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
rw_exit(&parent->sdev_dotdot->sdev_contents);
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0) {
return (error);
}
/* find existing name */
- error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
+ error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
if (error == 0) {
VN_RELE(vp);
return (EEXIST);
@@ -993,7 +1011,7 @@ sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
return (error);
/* require write access to create a directory */
- if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
return (error);
}
@@ -1030,7 +1048,8 @@ sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
*/
/*ARGSUSED*/
static int
-sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
+sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred,
+ caller_context_t *ct, int flags)
{
int error = 0;
struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
@@ -1053,7 +1072,7 @@ sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
rw_exit(&parent->sdev_dotdot->sdev_contents);
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
return (error);
/* check existing name */
@@ -1073,7 +1092,7 @@ sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
}
/* write access is required to remove a directory */
- if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
rw_exit(&parent->sdev_contents);
VN_RELE(vp);
return (error);
@@ -1132,7 +1151,7 @@ sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
if (SDEV_IS_PERSIST(parent)) {
ASSERT(parent->sdev_attrvp);
error = VOP_RMDIR(parent->sdev_attrvp, nm,
- parent->sdev_attrvp, kcred);
+ parent->sdev_attrvp, kcred, ct, flags);
sdcmn_err2(("sdev_rmdir: cleaning device %s is on"
" disk error %d\n", parent->sdev_path, error));
}
@@ -1148,7 +1167,8 @@ sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
* read the contents of a symbolic link
*/
static int
-sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
+sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred,
+ caller_context_t *ct)
{
struct sdev_node *dv;
int error = 0;
@@ -1159,7 +1179,7 @@ sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
if (dv->sdev_attrvp) {
/* non-NULL attrvp implys a persisted node at READY state */
- return (VOP_READLINK(dv->sdev_attrvp, uiop, cred));
+ return (VOP_READLINK(dv->sdev_attrvp, uiop, cred, ct));
} else if (dv->sdev_symlink != NULL) {
/* memory nodes, e.g. local nodes */
rw_enter(&dv->sdev_contents, RW_READER);
@@ -1173,14 +1193,16 @@ sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
return (ENOENT);
}
+/*ARGSUSED4*/
static int
-sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp)
+sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp,
+ caller_context_t *ct, int flags)
{
struct sdev_node *parent = VTOSDEV(dvp);
int error;
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
return (error);
ASSERT(parent);
@@ -1191,7 +1213,7 @@ sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp)
/*ARGSUSED1*/
static void
-sdev_inactive(struct vnode *vp, struct cred *cred)
+sdev_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
{
int clean;
struct sdev_node *dv = VTOSDEV(vp);
@@ -1250,8 +1272,9 @@ sdev_inactive(struct vnode *vp, struct cred *cred)
rw_exit(&ddv->sdev_contents);
}
+/*ARGSUSED2*/
static int
-sdev_fid(struct vnode *vp, struct fid *fidp)
+sdev_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
struct sdev_fid *sdev_fid;
@@ -1293,7 +1316,8 @@ sdev_rwunlock(struct vnode *vp, int write_flag, caller_context_t *ctp)
/*ARGSUSED1*/
static int
-sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
struct vnode *attrvp = VTOSDEV(vp)->sdev_attrvp;
@@ -1301,16 +1325,17 @@ sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
vp->v_type != VBLK && vp->v_type != VLNK);
if (vp->v_type == VDIR)
- return (fs_seek(vp, ooff, noffp));
+ return (fs_seek(vp, ooff, noffp, ct));
ASSERT(attrvp);
- return (VOP_SEEK(attrvp, ooff, noffp));
+ return (VOP_SEEK(attrvp, ooff, noffp, ct));
}
/*ARGSUSED1*/
static int
sdev_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, struct cred *cr)
+ offset_t offset, struct flk_callback *flk_cbp, struct cred *cr,
+ caller_context_t *ct)
{
int error;
struct sdev_node *dv = VTOSDEV(vp);
@@ -1318,23 +1343,25 @@ sdev_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
ASSERT(dv);
ASSERT(dv->sdev_attrvp);
error = VOP_FRLOCK(dv->sdev_attrvp, cmd, bfp, flag, offset,
- flk_cbp, cr);
+ flk_cbp, cr, ct);
return (error);
}
static int
-sdev_setfl(struct vnode *vp, int oflags, int nflags, cred_t *cr)
+sdev_setfl(struct vnode *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
ASSERT(dv);
ASSERT(dv->sdev_attrvp);
- return (VOP_SETFL(dv->sdev_attrvp, oflags, nflags, cr));
+ return (VOP_SETFL(dv->sdev_attrvp, oflags, nflags, cr, ct));
}
static int
-sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
switch (cmd) {
case _PC_ACL_ENABLED:
@@ -1342,7 +1369,7 @@ sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
return (0);
}
- return (fs_pathconf(vp, cmd, valp, cr));
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
}
vnodeops_t *sdev_vnodeops;
diff --git a/usr/src/uts/common/fs/devfs/devfs_subr.c b/usr/src/uts/common/fs/devfs/devfs_subr.c
index 4aa95bc321..eeaac94430 100644
--- a/usr/src/uts/common/fs/devfs/devfs_subr.c
+++ b/usr/src/uts/common/fs/devfs/devfs_subr.c
@@ -694,10 +694,11 @@ dv_shadow_node(
create_tried = 0;
lookup:
if (rdvp && (dv->dv_flags & DV_NO_FSPERM) == 0) {
- error = VOP_LOOKUP(rdvp, nm, &rvp, pnp, LOOKUP_DIR, rdir, cred);
+ error = VOP_LOOKUP(rdvp, nm, &rvp, pnp, LOOKUP_DIR, rdir, cred,
+ NULL, NULL, NULL);
/* factor out the snode since we only want the attribute node */
- if ((error == 0) && (VOP_REALVP(rvp, &rrvp) == 0)) {
+ if ((error == 0) && (VOP_REALVP(rvp, &rrvp, NULL) == 0)) {
VN_HOLD(rrvp);
VN_RELE(rvp);
rvp = rrvp;
@@ -760,7 +761,8 @@ lookup:
if ((error == ENOENT) && !create_tried) {
switch (vp->v_type) {
case VDIR:
- error = VOP_MKDIR(rdvp, nm, &vattr, &rvp, kcred);
+ error = VOP_MKDIR(rdvp, nm, &vattr, &rvp, kcred,
+ NULL, 0, NULL);
dsysdebug(error, ("vop_mkdir %s %s %d\n",
VTODV(dvp)->dv_name, nm, error));
create_tried = 1;
@@ -773,7 +775,7 @@ lookup:
*/
if (flags & DV_SHADOW_CREATE) {
error = VOP_CREATE(rdvp, nm, &vattr, NONEXCL,
- VREAD|VWRITE, &rvp, kcred, 0);
+ VREAD|VWRITE, &rvp, kcred, 0, NULL, NULL);
dsysdebug(error, ("vop_create %s %s %d\n",
VTODV(dvp)->dv_name, nm, error));
create_tried = 1;
@@ -1566,7 +1568,7 @@ devfs_remdrv_rmdir(vnode_t *dirvp, const char *dir, vnode_t *rvp)
iov.iov_len = dlen;
(void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dirvp, &uio, kcred, &eof);
+ error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -1582,8 +1584,8 @@ devfs_remdrv_rmdir(vnode_t *dirvp, const char *dir, vnode_t *rvp)
if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
continue;
- error = VOP_LOOKUP(dirvp,
- nm, &vp, NULL, 0, NULL, kcred);
+ error = VOP_LOOKUP(dirvp, nm,
+ &vp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
dsysdebug(error,
("rem_drv %s/%s lookup (%d)\n",
@@ -1599,13 +1601,14 @@ devfs_remdrv_rmdir(vnode_t *dirvp, const char *dir, vnode_t *rvp)
error = devfs_remdrv_rmdir(vp, nm, rvp);
if (error == 0) {
error = VOP_RMDIR(dirvp,
- (char *)nm, rvp, kcred);
+ (char *)nm, rvp, kcred, NULL, 0);
dsysdebug(error,
("rem_drv %s/%s rmdir (%d)\n",
dir, nm, error));
}
} else {
- error = VOP_REMOVE(dirvp, (char *)nm, kcred);
+ error = VOP_REMOVE(dirvp, (char *)nm, kcred,
+ NULL, 0);
dsysdebug(error,
("rem_drv %s/%s remove (%d)\n",
dir, nm, error));
@@ -1663,7 +1666,8 @@ devfs_remdrv_cleanup(const char *dir, const char *nodename)
ASSERT(dirvp->v_type == VDIR);
(void) pn_getcomponent(&pn, nm);
ASSERT((strcmp(nm, ".") != 0) && (strcmp(nm, "..") != 0));
- error = VOP_LOOKUP(dirvp, nm, &vp, NULL, 0, rvp, kcred);
+ error = VOP_LOOKUP(dirvp, nm, &vp, NULL, 0, rvp, kcred,
+ NULL, NULL, NULL);
if (error) {
dcmn_err5(("remdrv_cleanup %s lookup error %d\n",
nm, error));
@@ -1704,7 +1708,7 @@ devfs_remdrv_cleanup(const char *dir, const char *nodename)
iov.iov_len = dlen;
(void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dirvp, &uio, kcred, &eof);
+ error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -1724,7 +1728,7 @@ devfs_remdrv_cleanup(const char *dir, const char *nodename)
continue;
error = VOP_LOOKUP(dirvp, nm, &vp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
dsysdebug(error,
("rem_drv %s/%s lookup (%d)\n",
@@ -1739,14 +1743,15 @@ devfs_remdrv_cleanup(const char *dir, const char *nodename)
if (vp->v_type == VDIR) {
error = devfs_remdrv_rmdir(vp, nm, rvp);
if (error == 0) {
- error = VOP_RMDIR(dirvp,
- (char *)nm, rvp, kcred);
+ error = VOP_RMDIR(dirvp, (char *)nm,
+ rvp, kcred, NULL, 0);
dsysdebug(error,
("rem_drv %s/%s rmdir (%d)\n",
dir, nm, error));
}
} else {
- error = VOP_REMOVE(dirvp, (char *)nm, kcred);
+ error = VOP_REMOVE(dirvp, (char *)nm, kcred,
+ NULL, 0);
dsysdebug(error,
("rem_drv %s/%s remove (%d)\n",
dir, nm, error));
diff --git a/usr/src/uts/common/fs/devfs/devfs_vfsops.c b/usr/src/uts/common/fs/devfs/devfs_vfsops.c
index ddd006ab70..c6a6a2a896 100644
--- a/usr/src/uts/common/fs/devfs/devfs_vfsops.c
+++ b/usr/src/uts/common/fs/devfs/devfs_vfsops.c
@@ -556,7 +556,7 @@ devfs_devpolicy(vnode_t *vp, devplcy_t **dpp)
if (devfs_mntinfo == NULL)
return (rval);
- if (VOP_REALVP(vp, &rvp) == 0 && vn_matchops(rvp, dv_vnodeops)) {
+ if (VOP_REALVP(vp, &rvp, NULL) == 0 && vn_matchops(rvp, dv_vnodeops)) {
dvp = VTODV(rvp);
rw_enter(&dvp->dv_contents, RW_READER);
if (dvp->dv_priv) {
diff --git a/usr/src/uts/common/fs/devfs/devfs_vnops.c b/usr/src/uts/common/fs/devfs/devfs_vnops.c
index c55295b0f6..d459929000 100644
--- a/usr/src/uts/common/fs/devfs/devfs_vnops.c
+++ b/usr/src/uts/common/fs/devfs/devfs_vnops.c
@@ -72,7 +72,8 @@ extern dev_t rconsdev;
*/
/*ARGSUSED*/
static int
-devfs_open(struct vnode **vpp, int flag, struct cred *cred)
+devfs_open(struct vnode **vpp, int flag, struct cred *cred,
+ caller_context_t *ct)
{
struct dv_node *dv = VTODV(*vpp);
@@ -88,7 +89,7 @@ devfs_open(struct vnode **vpp, int flag, struct cred *cred)
/*ARGSUSED1*/
static int
devfs_close(struct vnode *vp, int flag, int count,
- offset_t offset, struct cred *cred)
+ offset_t offset, struct cred *cred, caller_context_t *ct)
{
struct dv_node *dv = VTODV(vp);
@@ -137,7 +138,7 @@ devfs_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cred,
/*ARGSUSED*/
static int
devfs_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- struct cred *cred, int *rvalp)
+ struct cred *cred, int *rvalp, caller_context_t *ct)
{
dcmn_err2(("devfs_ioctl %s\n", VTODV(vp)->dv_name));
ASSERT(vp->v_type == VDIR);
@@ -159,7 +160,8 @@ devfs_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
* memory based attributes.
*/
static int
-devfs_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
+devfs_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct dv_node *dv = VTODV(vp);
int error = 0;
@@ -189,7 +191,7 @@ devfs_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
vap->va_mask = mask;
} else {
/* obtain from attribute store and merge */
- error = VOP_GETATTR(dv->dv_attrvp, vap, flags, cr);
+ error = VOP_GETATTR(dv->dv_attrvp, vap, flags, cr, ct);
dsysdebug(error, ("vop_getattr %s %d\n", dv->dv_name, error));
dv_vattr_merge(dv, vap);
}
@@ -238,8 +240,8 @@ devfs_setattr_dir(
again: if (dv->dv_attr) {
- error = secpolicy_vnode_setattr(cr, vp, vap, dv->dv_attr,
- flags, devfs_unlocked_access, dv);
+ error = secpolicy_vnode_setattr(cr, vp, vap,
+ dv->dv_attr, flags, devfs_unlocked_access, dv);
if (error)
goto out;
@@ -296,8 +298,8 @@ again: if (dv->dv_attr) {
* read/write.
*/
vattr = dv_vattr_dir;
- if (VOP_GETATTR(dv->dv_attrvp, &vattr,
- flags, cr) == 0) {
+ if (VOP_GETATTR(dv->dv_attrvp,
+ &vattr, flags, cr, NULL) == 0) {
dv->dv_attr = kmem_alloc(
sizeof (struct vattr), KM_SLEEP);
*dv->dv_attr = vattr;
@@ -456,7 +458,7 @@ devfs_setattr(
ASSERT(dv->dv_attrvp);
ASSERT(vp->v_type != VDIR);
*vattrp = dv_vattr_file;
- error = VOP_GETATTR(dv->dv_attrvp, vattrp, 0, cr);
+ error = VOP_GETATTR(dv->dv_attrvp, vattrp, 0, cr, ct);
dsysdebug(error, ("vop_getattr %s %d\n",
dv->dv_name, error));
if (error)
@@ -514,7 +516,7 @@ devfs_setattr(
ddv = dv->dv_dotdot;
ASSERT(ddv->dv_attrvp);
error = VOP_REMOVE(ddv->dv_attrvp,
- dv->dv_name, cr);
+ dv->dv_name, cr, ct, 0);
dsysdebug(error,
("vop_remove %s %s %d\n",
ddv->dv_name, dv->dv_name, error));
@@ -573,7 +575,8 @@ out:
}
static int
-devfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+devfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
switch (cmd) {
case _PC_ACL_ENABLED:
@@ -587,11 +590,11 @@ devfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
*/
ASSERT(dvroot);
ASSERT(dvroot->dv_attrvp);
- return (VOP_PATHCONF(dvroot->dv_attrvp, cmd, valp, cr));
+ return (VOP_PATHCONF(dvroot->dv_attrvp, cmd, valp, cr, ct));
/*NOTREACHED*/
}
- return (fs_pathconf(vp, cmd, valp, cr));
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
}
/*
@@ -599,7 +602,7 @@ devfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
*/
static int
devfs_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
dvnode_t *dv = VTODV(vp);
struct vnode *avp;
@@ -614,12 +617,12 @@ devfs_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
/* fabricate the acl */
if (avp == NULL) {
- error = fs_fab_acl(vp, vsap, flags, cr);
+ error = fs_fab_acl(vp, vsap, flags, cr, ct);
rw_exit(&dv->dv_contents);
return (error);
}
- error = VOP_GETSECATTR(avp, vsap, flags, cr);
+ error = VOP_GETSECATTR(avp, vsap, flags, cr, ct);
dsysdebug(error, ("vop_getsecattr %s %d\n", VTODV(vp)->dv_name, error));
rw_exit(&dv->dv_contents);
return (error);
@@ -633,7 +636,7 @@ devfs_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
*/
static int
devfs_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
dvnode_t *dv = VTODV(vp);
struct vnode *avp;
@@ -672,7 +675,7 @@ devfs_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
* store before forwarding the ACL.
*/
(void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(avp, vsap, flags, cr);
+ error = VOP_SETSECATTR(avp, vsap, flags, cr, ct);
dsysdebug(error, ("vop_setsecattr %s %d\n", VTODV(vp)->dv_name, error));
VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, NULL);
@@ -717,7 +720,8 @@ devfs_unlocked_access(void *vdv, int mode, struct cred *cr)
}
static int
-devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct dv_node *dv = VTODV(vp);
int res;
@@ -739,7 +743,7 @@ devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
}
rw_exit(&dv->dv_contents);
}
- return (VOP_ACCESS(dv->dv_attrvp, mode, flags, cr));
+ return (VOP_ACCESS(dv->dv_attrvp, mode, flags, cr, ct));
}
/*
@@ -801,7 +805,8 @@ devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
/*ARGSUSED3*/
static int
devfs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
- struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred)
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
{
ASSERT(dvp->v_type == VDIR);
dcmn_err2(("devfs_lookup: %s\n", nm));
@@ -820,7 +825,8 @@ devfs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
/*ARGSUSED2*/
static int
devfs_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
- int mode, struct vnode **vpp, struct cred *cred, int flag)
+ int mode, struct vnode **vpp, struct cred *cred, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
struct vnode *vp;
@@ -833,7 +839,7 @@ devfs_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
else if (vp->v_type == VDIR && (mode & VWRITE))
error = EISDIR;
else
- error = VOP_ACCESS(vp, mode, 0, cred);
+ error = VOP_ACCESS(vp, mode, 0, cred, ct);
if (error) {
VN_RELE(vp);
@@ -850,8 +856,10 @@ devfs_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
* Otherwise, simply return cached dv_node's. Hotplug code always call
* devfs_clean() to invalid the dv_node cache.
*/
+/*ARGSUSED5*/
static int
-devfs_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp)
+devfs_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp,
+ caller_context_t *ct, int flags)
{
struct dv_node *ddv, *dv;
struct dirent64 *de, *bufp;
@@ -994,7 +1002,7 @@ full: dcmn_err3(("devfs_readdir: moving %lu bytes: "
va.va_mask = AT_ATIME;
gethrestime(&va.va_atime);
rw_exit(&ddv->dv_contents);
- (void) devfs_setattr(dvp, &va, 0, cred, NULL);
+ (void) devfs_setattr(dvp, &va, 0, cred, ct);
rw_enter(&ddv->dv_contents, RW_READER);
}
@@ -1004,7 +1012,8 @@ full: dcmn_err3(("devfs_readdir: moving %lu bytes: "
/*ARGSUSED*/
static int
-devfs_fsync(struct vnode *vp, int syncflag, struct cred *cred)
+devfs_fsync(struct vnode *vp, int syncflag, struct cred *cred,
+ caller_context_t *ct)
{
/*
* Message goes to console only. Otherwise, the message
@@ -1024,7 +1033,7 @@ devfs_fsync(struct vnode *vp, int syncflag, struct cred *cred)
*/
/*ARGSUSED1*/
static void
-devfs_inactive(struct vnode *vp, struct cred *cred)
+devfs_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
{
int destroy;
struct dv_node *dv = VTODV(vp);
@@ -1045,8 +1054,9 @@ devfs_inactive(struct vnode *vp, struct cred *cred)
* XXX Why do we need this? NFS mounted /dev directories?
* XXX Talk to peter staubach about this.
*/
+/*ARGSUSED2*/
static int
-devfs_fid(struct vnode *vp, struct fid *fidp)
+devfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct dv_node *dv = VTODV(vp);
struct dv_fid *dv_fid;
@@ -1095,7 +1105,8 @@ devfs_rwunlock(struct vnode *vp, int write_flag, caller_context_t *ct)
*/
/*ARGSUSED1*/
static int
-devfs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+devfs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
ASSERT(vp->v_type == VDIR);
dcmn_err2(("devfs_seek %s\n", VTODV(vp)->dv_name));
diff --git a/usr/src/uts/common/fs/doorfs/door_sys.c b/usr/src/uts/common/fs/doorfs/door_sys.c
index c139032e70..ec9d650d99 100644
--- a/usr/src/uts/common/fs/doorfs/door_sys.c
+++ b/usr/src/uts/common/fs/doorfs/door_sys.c
@@ -69,14 +69,14 @@
#include <sys/rctl.h>
/*
- * The maximum amount of data (in bytes) that will be transfered using
+ * The maximum amount of data (in bytes) that will be transferred using
* an intermediate kernel buffer. For sizes greater than this we map
* in the destination pages and perform a 1-copy transfer.
*/
size_t door_max_arg = 16 * 1024;
/*
- * Maximum amount of data that will be transfered in a reply to a
+ * Maximum amount of data that will be transferred in a reply to a
* door_upcall. Need to guard against a process returning huge amounts
* of data and getting the kernel stuck in kmem_alloc.
*/
@@ -168,7 +168,7 @@ _init(void)
cmn_err(CE_WARN, "door init: bad vfs ops");
return (error);
}
- vfs_setops(&door_vfs, door_vfsops);
+ VFS_INIT(&door_vfs, door_vfsops, NULL);
door_vfs.vfs_flag = VFS_RDONLY;
door_vfs.vfs_dev = doordev;
vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0);
@@ -1726,7 +1726,7 @@ door_insert(struct file *fp, door_desc_t *dp)
dp->d_data.d_desc.d_descriptor = fd;
/* Fill in the attributes */
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp && vp->v_type == VDOOR) {
if (VTOD(vp)->door_target == curproc)
@@ -1796,7 +1796,7 @@ door_get_server(door_node_t *dp)
if (!cv_wait_sig_swap_core(&pool->dp_cv, &door_knob,
&signalled)) {
/*
- * If we were signalled and the door is still
+ * If we were signaled and the door is still
* valid, pass the signal on to another waiter.
*/
if (signalled && !DOOR_INVALID(dp))
@@ -1905,7 +1905,7 @@ door_lookup(int did, file_t **fpp)
/*
* Use the underlying vnode (we may be namefs mounted)
*/
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp == NULL || vp->v_type != VDOOR) {
@@ -2562,7 +2562,7 @@ door_translate_in(void)
(void) closeandsetf(fd, NULL);
}
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
/* Set attributes */
@@ -3217,7 +3217,7 @@ shuttle_return:
struct file *fp;
fp = *fpp;
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
didpp->d_attributes = DOOR_HANDLE |
@@ -3297,7 +3297,7 @@ door_ki_upcall(door_handle_t dh, door_arg_t *param)
file_t *fp = DHTOF(dh);
vnode_t *realvp;
- if (VOP_REALVP(fp->f_vnode, &realvp))
+ if (VOP_REALVP(fp->f_vnode, &realvp, NULL))
realvp = fp->f_vnode;
return (door_upcall(realvp, param));
}
@@ -3365,7 +3365,7 @@ door_ki_open(char *pathname, door_handle_t *dhp)
if ((err = lookupname(pathname, UIO_SYSSPACE, FOLLOW, NULL, &vp)) != 0)
return (err);
- if (err = VOP_OPEN(&vp, FREAD, kcred)) {
+ if (err = VOP_OPEN(&vp, FREAD, kcred, NULL)) {
VN_RELE(vp);
return (err);
}
@@ -3389,7 +3389,7 @@ door_ki_info(door_handle_t dh, struct door_info *dip)
file_t *fp = DHTOF(dh);
vnode_t *vp;
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp->v_type != VDOOR)
return (EINVAL);
@@ -3419,7 +3419,7 @@ door_ki_setparam(door_handle_t dh, int type, size_t val)
file_t *fp = DHTOF(dh);
vnode_t *vp;
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp->v_type != VDOOR)
return (EINVAL);
@@ -3432,7 +3432,7 @@ door_ki_getparam(door_handle_t dh, int type, size_t *out)
file_t *fp = DHTOF(dh);
vnode_t *vp;
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp->v_type != VDOOR)
return (EINVAL);
diff --git a/usr/src/uts/common/fs/doorfs/door_vnops.c b/usr/src/uts/common/fs/doorfs/door_vnops.c
index 6d61c34f30..b50465f9c8 100644
--- a/usr/src/uts/common/fs/doorfs/door_vnops.c
+++ b/usr/src/uts/common/fs/doorfs/door_vnops.c
@@ -38,15 +38,17 @@
#include <sys/tsol/label.h>
kmutex_t door_knob;
-static int door_open(struct vnode **vpp, int flag, struct cred *cr);
+static int door_open(struct vnode **vpp, int flag, struct cred *cr,
+ caller_context_t *ct);
static int door_close(struct vnode *vp, int flag, int count,
- offset_t offset, struct cred *cr);
+ offset_t offset, struct cred *cr, caller_context_t *ct);
static int door_getattr(struct vnode *vp, struct vattr *vap,
- int flags, struct cred *cr);
-static void door_inactive(struct vnode *vp, struct cred *cr);
+ int flags, struct cred *cr, caller_context_t *ct);
+static void door_inactive(struct vnode *vp, struct cred *cr,
+ caller_context_t *ct);
static int door_access(struct vnode *vp, int mode, int flags,
- struct cred *cr);
-static int door_realvp(vnode_t *vp, vnode_t **vpp);
+ struct cred *cr, caller_context_t *ct);
+static int door_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct);
struct vfs door_vfs;
@@ -70,7 +72,7 @@ const fs_operation_def_t door_vnodeops_template[] = {
/* ARGSUSED */
static int
-door_open(struct vnode **vpp, int flag, struct cred *cr)
+door_open(struct vnode **vpp, int flag, struct cred *cr, caller_context_t *ct)
{
/*
* MAC policy for doors. Restrict cross-zone open()s so that only
@@ -103,7 +105,8 @@ door_close(
int flag,
int count,
offset_t offset,
- struct cred *cr
+ struct cred *cr,
+ caller_context_t *ct
)
{
door_node_t *dp = VTOD(vp);
@@ -142,7 +145,8 @@ door_close(
/* ARGSUSED */
static int
-door_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
+door_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr,
+ caller_context_t *ct)
{
static timestruc_t tzero = {0, 0};
extern dev_t doordev;
@@ -169,7 +173,7 @@ door_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
/* ARGSUSED */
static void
-door_inactive(struct vnode *vp, struct cred *cr)
+door_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
door_node_t *dp = VTOD(vp);
@@ -231,19 +235,20 @@ door_unbind_thread(door_node_t *dp)
mutex_exit(&vp->v_lock);
if (do_inactive)
- door_inactive(vp, NULL);
+ door_inactive(vp, NULL, NULL);
}
/* ARGSUSED */
static int
-door_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+door_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static int
-door_realvp(vnode_t *vp, vnode_t **vpp)
+door_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
*vpp = vp;
return (0);
diff --git a/usr/src/uts/common/fs/fd/fdops.c b/usr/src/uts/common/fs/fd/fdops.c
index 3033d0ae06..3288872146 100644
--- a/usr/src/uts/common/fs/fd/fdops.c
+++ b/usr/src/uts/common/fs/fd/fdops.c
@@ -82,7 +82,7 @@ static int fdget(vnode_t *, char *, vnode_t **);
/* ARGSUSED */
static int
-fdopen(vnode_t **vpp, int mode, cred_t *cr)
+fdopen(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct)
{
if ((*vpp)->v_type != VDIR) {
mutex_enter(&(*vpp)->v_lock);
@@ -94,7 +94,8 @@ fdopen(vnode_t **vpp, int mode, cred_t *cr)
/* ARGSUSED */
static int
-fdclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+fdclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -163,7 +164,8 @@ fdread(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
/* ARGSUSED */
static int
-fdgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+fdgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
vfs_t *vfsp = vp->v_vfsp;
timestruc_t now;
@@ -195,7 +197,7 @@ fdgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
static int
-fdaccess(vnode_t *vp, int mode, int flags, cred_t *cr)
+fdaccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
return (0);
}
@@ -203,7 +205,8 @@ fdaccess(vnode_t *vp, int mode, int flags, cred_t *cr)
/* ARGSUSED */
static int
fdlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
if (comp[0] == 0 || strcmp(comp, ".") == 0 || strcmp(comp, "..") == 0) {
VN_HOLD(dp);
@@ -216,14 +219,16 @@ fdlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pnp,
/* ARGSUSED */
static int
fdcreate(vnode_t *dvp, char *comp, vattr_t *vap, enum vcexcl excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
return (fdget(dvp, comp, vpp));
}
/* ARGSUSED */
static int
-fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, caller_context_t *ct,
+ int flags)
{
/* bp holds one dirent structure */
u_offset_t bp[DIRENT64_RECLEN(FDNSIZE) / sizeof (u_offset_t)];
@@ -300,7 +305,7 @@ fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
/* ARGSUSED */
static void
-fdinactive(vnode_t *vp, cred_t *cr)
+fdinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
mutex_enter(&vp->v_lock);
ASSERT(vp->v_count >= 1);
diff --git a/usr/src/uts/common/fs/fem.c b/usr/src/uts/common/fs/fem.c
index 04886984e4..fec6c3575a 100644
--- a/usr/src/uts/common/fs/fem.c
+++ b/usr/src/uts/common/fs/fem.c
@@ -428,7 +428,7 @@ fem_release(struct fem_list *sp)
*/
static int
-vhead_open(vnode_t **vpp, int mode, cred_t *cr)
+vhead_open(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -440,21 +440,22 @@ vhead_open(vnode_t **vpp, int mode, cred_t *cr)
func = (int (*)()) ((*vpp)->v_op->vop_open);
arg0 = (void *)vpp;
fem_unlock((*vpp)->v_femhead);
- errc = (*func)(arg0, mode, cr);
+ errc = (*func)(arg0, mode, cr, ct);
} else {
fem_addref(femsp);
fem_unlock((*vpp)->v_femhead);
farg.fa_vnode.vpp = vpp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_open, femop_open);
- errc = (*func)(arg0, mode, cr);
+ errc = (*func)(arg0, mode, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -466,14 +467,14 @@ vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_close);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, flag, count, offset, cr);
+ errc = (*func)(arg0, flag, count, offset, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_close, femop_close);
- errc = (*func)(arg0, flag, count, offset, cr);
+ errc = (*func)(arg0, flag, count, offset, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -481,7 +482,7 @@ vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
static int
vhead_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -508,7 +509,7 @@ vhead_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
static int
vhead_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -535,7 +536,7 @@ vhead_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
static int
vhead_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -547,21 +548,22 @@ vhead_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
func = (int (*)()) (vp->v_op->vop_ioctl);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, cmd, arg, flag, cr, rvalp);
+ errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_ioctl, femop_ioctl);
- errc = (*func)(arg0, cmd, arg, flag, cr, rvalp);
+ errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -573,21 +575,22 @@ vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_setfl);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, oflags, nflags, cr);
+ errc = (*func)(arg0, oflags, nflags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_setfl, femop_setfl);
- errc = (*func)(arg0, oflags, nflags, cr);
+ errc = (*func)(arg0, oflags, nflags, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -599,7 +602,7 @@ vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_getattr);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vap, flags, cr);
+ errc = (*func)(arg0, vap, flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -607,7 +610,7 @@ vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_getattr,
femop_getattr);
- errc = (*func)(arg0, vap, flags, cr);
+ errc = (*func)(arg0, vap, flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -642,7 +645,8 @@ vhead_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
}
static int
-vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -654,7 +658,7 @@ vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_access);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, mode, flags, cr);
+ errc = (*func)(arg0, mode, flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -662,7 +666,7 @@ vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_access,
femop_access);
- errc = (*func)(arg0, mode, flags, cr);
+ errc = (*func)(arg0, mode, flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -670,7 +674,8 @@ vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr)
static int
vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
femarg_t farg;
struct fem_list *femsp;
@@ -682,7 +687,8 @@ vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
func = (int (*)()) (dvp->v_op->vop_lookup);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr);
+ errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
+ direntflags, realpnp);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
@@ -690,7 +696,8 @@ vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_lookup,
femop_lookup);
- errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr);
+ errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
+ direntflags, realpnp);
fem_release(femsp);
}
return (errc);
@@ -698,7 +705,8 @@ vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
static int
vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
femarg_t farg;
struct fem_list *femsp;
@@ -710,7 +718,8 @@ vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
func = (int (*)()) (dvp->v_op->vop_create);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag);
+ errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag,
+ ct, vsecp);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
@@ -718,14 +727,16 @@ vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_create,
femop_create);
- errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag);
+ errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag,
+ ct, vsecp);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_remove(vnode_t *dvp, char *nm, cred_t *cr)
+vhead_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -737,7 +748,7 @@ vhead_remove(vnode_t *dvp, char *nm, cred_t *cr)
func = (int (*)()) (dvp->v_op->vop_remove);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, nm, cr);
+ errc = (*func)(arg0, nm, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
@@ -745,14 +756,15 @@ vhead_remove(vnode_t *dvp, char *nm, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_remove,
femop_remove);
- errc = (*func)(arg0, nm, cr);
+ errc = (*func)(arg0, nm, cr, ct, flags);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -764,14 +776,14 @@ vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
func = (int (*)()) (tdvp->v_op->vop_link);
arg0 = tdvp;
fem_unlock(tdvp->v_femhead);
- errc = (*func)(arg0, svp, tnm, cr);
+ errc = (*func)(arg0, svp, tnm, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(tdvp->v_femhead);
farg.fa_vnode.vp = tdvp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_link, femop_link);
- errc = (*func)(arg0, svp, tnm, cr);
+ errc = (*func)(arg0, svp, tnm, cr, ct, flags);
fem_release(femsp);
}
return (errc);
@@ -779,7 +791,7 @@ vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
static int
vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -791,7 +803,7 @@ vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
func = (int (*)()) (sdvp->v_op->vop_rename);
arg0 = sdvp;
fem_unlock(sdvp->v_femhead);
- errc = (*func)(arg0, snm, tdvp, tnm, cr);
+ errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(sdvp->v_femhead);
@@ -799,7 +811,7 @@ vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_rename,
femop_rename);
- errc = (*func)(arg0, snm, tdvp, tnm, cr);
+ errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags);
fem_release(femsp);
}
return (errc);
@@ -807,7 +819,7 @@ vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
static int
vhead_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
femarg_t farg;
struct fem_list *femsp;
@@ -819,21 +831,22 @@ vhead_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
func = (int (*)()) (dvp->v_op->vop_mkdir);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, dirname, vap, vpp, cr);
+ errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
farg.fa_vnode.vp = dvp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_mkdir, femop_mkdir);
- errc = (*func)(arg0, dirname, vap, vpp, cr);
+ errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -845,21 +858,22 @@ vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
func = (int (*)()) (dvp->v_op->vop_rmdir);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, nm, cdir, cr);
+ errc = (*func)(arg0, nm, cdir, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
farg.fa_vnode.vp = dvp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_rmdir, femop_rmdir);
- errc = (*func)(arg0, nm, cdir, cr);
+ errc = (*func)(arg0, nm, cdir, cr, ct, flags);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -871,7 +885,7 @@ vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
func = (int (*)()) (vp->v_op->vop_readdir);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, uiop, cr, eofp);
+ errc = (*func)(arg0, uiop, cr, eofp, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -879,7 +893,7 @@ vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_readdir,
femop_readdir);
- errc = (*func)(arg0, uiop, cr, eofp);
+ errc = (*func)(arg0, uiop, cr, eofp, ct, flags);
fem_release(femsp);
}
return (errc);
@@ -887,7 +901,7 @@ vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
static int
vhead_symlink(vnode_t *dvp, char *linkname, vattr_t *vap, char *target,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -899,7 +913,7 @@ vhead_symlink(vnode_t *dvp, char *linkname, vattr_t *vap, char *target,
func = (int (*)()) (dvp->v_op->vop_symlink);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, linkname, vap, target, cr);
+ errc = (*func)(arg0, linkname, vap, target, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
@@ -907,14 +921,14 @@ vhead_symlink(vnode_t *dvp, char *linkname, vattr_t *vap, char *target,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_symlink,
femop_symlink);
- errc = (*func)(arg0, linkname, vap, target, cr);
+ errc = (*func)(arg0, linkname, vap, target, cr, ct, flags);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -926,7 +940,7 @@ vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_readlink);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, uiop, cr);
+ errc = (*func)(arg0, uiop, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -934,14 +948,14 @@ vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_readlink,
femop_readlink);
- errc = (*func)(arg0, uiop, cr);
+ errc = (*func)(arg0, uiop, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+vhead_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -953,21 +967,21 @@ vhead_fsync(vnode_t *vp, int syncflag, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_fsync);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, syncflag, cr);
+ errc = (*func)(arg0, syncflag, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_fsync, femop_fsync);
- errc = (*func)(arg0, syncflag, cr);
+ errc = (*func)(arg0, syncflag, cr, ct);
fem_release(femsp);
}
return (errc);
}
static void
-vhead_inactive(vnode_t *vp, cred_t *cr)
+vhead_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -978,7 +992,7 @@ vhead_inactive(vnode_t *vp, cred_t *cr)
func = (void (*)()) (vp->v_op->vop_inactive);
arg0 = vp;
fem_unlock(vp->v_femhead);
- (*func)(arg0, cr);
+ (*func)(arg0, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -986,13 +1000,13 @@ vhead_inactive(vnode_t *vp, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, void, &arg0, vop_inactive,
femop_inactive);
- (*func)(arg0, cr);
+ (*func)(arg0, cr, ct);
fem_release(femsp);
}
}
static int
-vhead_fid(vnode_t *vp, fid_t *fidp)
+vhead_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1004,14 +1018,14 @@ vhead_fid(vnode_t *vp, fid_t *fidp)
func = (int (*)()) (vp->v_op->vop_fid);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, fidp);
+ errc = (*func)(arg0, fidp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_fid, femop_fid);
- errc = (*func)(arg0, fidp);
+ errc = (*func)(arg0, fidp, ct);
fem_release(femsp);
}
return (errc);
@@ -1070,7 +1084,7 @@ vhead_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
}
static int
-vhead_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+vhead_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1082,21 +1096,21 @@ vhead_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
func = (int (*)()) (vp->v_op->vop_seek);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, ooff, noffp);
+ errc = (*func)(arg0, ooff, noffp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_seek, femop_seek);
- errc = (*func)(arg0, ooff, noffp);
+ errc = (*func)(arg0, ooff, noffp, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_cmp(vnode_t *vp1, vnode_t *vp2)
+vhead_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1108,14 +1122,14 @@ vhead_cmp(vnode_t *vp1, vnode_t *vp2)
func = (int (*)()) (vp1->v_op->vop_cmp);
arg0 = vp1;
fem_unlock(vp1->v_femhead);
- errc = (*func)(arg0, vp2);
+ errc = (*func)(arg0, vp2, ct);
} else {
fem_addref(femsp);
fem_unlock(vp1->v_femhead);
farg.fa_vnode.vp = vp1;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_cmp, femop_cmp);
- errc = (*func)(arg0, vp2);
+ errc = (*func)(arg0, vp2, ct);
fem_release(femsp);
}
return (errc);
@@ -1123,7 +1137,8 @@ vhead_cmp(vnode_t *vp1, vnode_t *vp2)
static int
vhead_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1135,7 +1150,7 @@ vhead_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
func = (int (*)()) (vp->v_op->vop_frlock);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr);
+ errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1143,7 +1158,7 @@ vhead_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_frlock,
femop_frlock);
- errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr);
+ errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1177,7 +1192,7 @@ vhead_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
}
static int
-vhead_realvp(vnode_t *vp, vnode_t **vpp)
+vhead_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1189,7 +1204,7 @@ vhead_realvp(vnode_t *vp, vnode_t **vpp)
func = (int (*)()) (vp->v_op->vop_realvp);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vpp);
+ errc = (*func)(arg0, vpp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1197,7 +1212,7 @@ vhead_realvp(vnode_t *vp, vnode_t **vpp)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_realvp,
femop_realvp);
- errc = (*func)(arg0, vpp);
+ errc = (*func)(arg0, vpp, ct);
fem_release(femsp);
}
return (errc);
@@ -1206,7 +1221,7 @@ vhead_realvp(vnode_t *vp, vnode_t **vpp)
static int
vhead_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
struct page **plarr, size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1219,7 +1234,7 @@ vhead_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
arg0 = vp;
fem_unlock(vp->v_femhead);
errc = (*func)(arg0, off, len, protp, plarr, plsz, seg,
- addr, rw, cr);
+ addr, rw, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1228,14 +1243,15 @@ vhead_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
vsop_find(&farg, &func, int, &arg0, vop_getpage,
femop_getpage);
errc = (*func)(arg0, off, len, protp, plarr, plsz, seg,
- addr, rw, cr);
+ addr, rw, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1247,7 +1263,7 @@ vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_putpage);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, off, len, flags, cr);
+ errc = (*func)(arg0, off, len, flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1255,7 +1271,7 @@ vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_putpage,
femop_putpage);
- errc = (*func)(arg0, off, len, flags, cr);
+ errc = (*func)(arg0, off, len, flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1264,7 +1280,7 @@ vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
static int
vhead_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)
+ cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1277,7 +1293,7 @@ vhead_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
arg0 = vp;
fem_unlock(vp->v_femhead);
errc = (*func)(arg0, off, as, addrp, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1285,7 +1301,7 @@ vhead_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_map, femop_map);
errc = (*func)(arg0, off, as, addrp, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1294,7 +1310,7 @@ vhead_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
static int
vhead_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)
+ cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1307,7 +1323,7 @@ vhead_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
arg0 = vp;
fem_unlock(vp->v_femhead);
errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1316,7 +1332,7 @@ vhead_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
vsop_find(&farg, &func, int, &arg0, vop_addmap,
femop_addmap);
errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1324,7 +1340,8 @@ vhead_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
static int
vhead_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)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1337,7 +1354,7 @@ vhead_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
arg0 = vp;
fem_unlock(vp->v_femhead);
errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1346,7 +1363,7 @@ vhead_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
vsop_find(&farg, &func, int, &arg0, vop_delmap,
femop_delmap);
errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1354,7 +1371,7 @@ vhead_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
static int
vhead_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1366,21 +1383,21 @@ vhead_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
func = (int (*)()) (vp->v_op->vop_poll);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, events, anyyet, reventsp, phpp);
+ errc = (*func)(arg0, events, anyyet, reventsp, phpp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_poll, femop_poll);
- errc = (*func)(arg0, events, anyyet, reventsp, phpp);
+ errc = (*func)(arg0, events, anyyet, reventsp, phpp, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_dump(vnode_t *vp, caddr_t addr, int lbdn, int dblks)
+vhead_dump(vnode_t *vp, caddr_t addr, int lbdn, int dblks, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1392,21 +1409,22 @@ vhead_dump(vnode_t *vp, caddr_t addr, int lbdn, int dblks)
func = (int (*)()) (vp->v_op->vop_dump);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, addr, lbdn, dblks);
+ errc = (*func)(arg0, addr, lbdn, dblks, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_dump, femop_dump);
- errc = (*func)(arg0, addr, lbdn, dblks);
+ errc = (*func)(arg0, addr, lbdn, dblks, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1418,7 +1436,7 @@ vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_pathconf);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, cmd, valp, cr);
+ errc = (*func)(arg0, cmd, valp, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1426,7 +1444,7 @@ vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_pathconf,
femop_pathconf);
- errc = (*func)(arg0, cmd, valp, cr);
+ errc = (*func)(arg0, cmd, valp, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1434,7 +1452,7 @@ vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
static int
vhead_pageio(vnode_t *vp, struct page *pp, u_offset_t io_off,
- size_t io_len, int flags, cred_t *cr)
+ size_t io_len, int flags, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1446,7 +1464,7 @@ vhead_pageio(vnode_t *vp, struct page *pp, u_offset_t io_off,
func = (int (*)()) (vp->v_op->vop_pageio);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, pp, io_off, io_len, flags, cr);
+ errc = (*func)(arg0, pp, io_off, io_len, flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1454,14 +1472,14 @@ vhead_pageio(vnode_t *vp, struct page *pp, u_offset_t io_off,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_pageio,
femop_pageio);
- errc = (*func)(arg0, pp, io_off, io_len, flags, cr);
+ errc = (*func)(arg0, pp, io_off, io_len, flags, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_dumpctl(vnode_t *vp, int action, int *blkp)
+vhead_dumpctl(vnode_t *vp, int action, int *blkp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1473,7 +1491,7 @@ vhead_dumpctl(vnode_t *vp, int action, int *blkp)
func = (int (*)()) (vp->v_op->vop_dumpctl);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, action, blkp);
+ errc = (*func)(arg0, action, blkp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1481,14 +1499,15 @@ vhead_dumpctl(vnode_t *vp, int action, int *blkp)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_dumpctl,
femop_dumpctl);
- errc = (*func)(arg0, action, blkp);
+ errc = (*func)(arg0, action, blkp, ct);
fem_release(femsp);
}
return (errc);
}
static void
-vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr)
+vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1499,7 +1518,7 @@ vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr)
func = (void (*)()) (vp->v_op->vop_dispose);
arg0 = vp;
fem_unlock(vp->v_femhead);
- (*func)(arg0, pp, flag, dn, cr);
+ (*func)(arg0, pp, flag, dn, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1507,13 +1526,14 @@ vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, void, &arg0, vop_dispose,
femop_dispose);
- (*func)(arg0, pp, flag, dn, cr);
+ (*func)(arg0, pp, flag, dn, cr, ct);
fem_release(femsp);
}
}
static int
-vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
+vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1525,7 +1545,7 @@ vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_setsecattr);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vsap, flag, cr);
+ errc = (*func)(arg0, vsap, flag, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1533,14 +1553,15 @@ vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_setsecattr,
femop_setsecattr);
- errc = (*func)(arg0, vsap, flag, cr);
+ errc = (*func)(arg0, vsap, flag, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
+vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1552,7 +1573,7 @@ vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_getsecattr);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vsap, flag, cr);
+ errc = (*func)(arg0, vsap, flag, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1560,7 +1581,7 @@ vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_getsecattr,
femop_getsecattr);
- errc = (*func)(arg0, vsap, flag, cr);
+ errc = (*func)(arg0, vsap, flag, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1568,7 +1589,7 @@ vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
static int
vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1580,7 +1601,7 @@ vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag,
func = (int (*)()) (vp->v_op->vop_shrlock);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, cmd, shr, flag, cr);
+ errc = (*func)(arg0, cmd, shr, flag, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1588,14 +1609,15 @@ vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_shrlock,
femop_shrlock);
- errc = (*func)(arg0, cmd, shr, flag, cr);
+ errc = (*func)(arg0, cmd, shr, flag, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
+vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1607,7 +1629,7 @@ vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
func = (int (*)()) (vp->v_op->vop_vnevent);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vnevent, dvp, cname);
+ errc = (*func)(arg0, vnevent, dvp, cname, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1615,7 +1637,7 @@ vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_vnevent,
femop_vnevent);
- errc = (*func)(arg0, vnevent, dvp, cname);
+ errc = (*func)(arg0, vnevent, dvp, cname, ct);
fem_release(femsp);
}
return (errc);
@@ -1958,7 +1980,7 @@ static struct fs_operation_def fshead_vfs_spec[] = {
*/
int
-vnext_open(femarg_t *vf, int mode, cred_t *cr)
+vnext_open(femarg_t *vf, int mode, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -1968,11 +1990,12 @@ vnext_open(femarg_t *vf, int mode, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_open, femop_open);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, mode, cr));
+ return ((*func)(arg0, mode, cr, ct));
}
int
-vnext_close(femarg_t *vf, int flag, int count, offset_t offset, cred_t *cr)
+vnext_close(femarg_t *vf, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -1982,12 +2005,12 @@ vnext_close(femarg_t *vf, int flag, int count, offset_t offset, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_close, femop_close);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, flag, count, offset, cr));
+ return ((*func)(arg0, flag, count, offset, cr, ct));
}
int
vnext_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2002,7 +2025,7 @@ vnext_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
int
vnext_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2017,7 +2040,7 @@ vnext_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
int
vnext_ioctl(femarg_t *vf, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2027,11 +2050,12 @@ vnext_ioctl(femarg_t *vf, int cmd, intptr_t arg, int flag, cred_t *cr,
vsop_find(vf, &func, int, &arg0, vop_ioctl, femop_ioctl);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, cmd, arg, flag, cr, rvalp));
+ return ((*func)(arg0, cmd, arg, flag, cr, rvalp, ct));
}
int
-vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr)
+vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2041,11 +2065,12 @@ vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_setfl, femop_setfl);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, oflags, nflags, cr));
+ return ((*func)(arg0, oflags, nflags, cr, ct));
}
int
-vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr)
+vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2055,7 +2080,7 @@ vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_getattr, femop_getattr);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vap, flags, cr));
+ return ((*func)(arg0, vap, flags, cr, ct));
}
int
@@ -2074,7 +2099,8 @@ vnext_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
}
int
-vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr)
+vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2084,12 +2110,13 @@ vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_access, femop_access);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, mode, flags, cr));
+ return ((*func)(arg0, mode, flags, cr, ct));
}
int
vnext_lookup(femarg_t *vf, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2099,12 +2126,14 @@ vnext_lookup(femarg_t *vf, char *nm, vnode_t **vpp, pathname_t *pnp,
vsop_find(vf, &func, int, &arg0, vop_lookup, femop_lookup);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, nm, vpp, pnp, flags, rdir, cr));
+ return ((*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
+ direntflags, realpnp));
}
int
vnext_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2114,11 +2143,12 @@ vnext_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
vsop_find(vf, &func, int, &arg0, vop_create, femop_create);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, name, vap, excl, mode, vpp, cr, flag));
+ return ((*func)(arg0, name, vap, excl, mode, vpp, cr, flag, ct, vsecp));
}
int
-vnext_remove(femarg_t *vf, char *nm, cred_t *cr)
+vnext_remove(femarg_t *vf, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2128,11 +2158,12 @@ vnext_remove(femarg_t *vf, char *nm, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_remove, femop_remove);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, nm, cr));
+ return ((*func)(arg0, nm, cr, ct, flags));
}
int
-vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr)
+vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2142,11 +2173,12 @@ vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_link, femop_link);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, svp, tnm, cr));
+ return ((*func)(arg0, svp, tnm, cr, ct, flags));
}
int
-vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
+vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2156,12 +2188,12 @@ vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_rename, femop_rename);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, snm, tdvp, tnm, cr));
+ return ((*func)(arg0, snm, tdvp, tnm, cr, ct, flags));
}
int
vnext_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2171,11 +2203,12 @@ vnext_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
vsop_find(vf, &func, int, &arg0, vop_mkdir, femop_mkdir);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, dirname, vap, vpp, cr));
+ return ((*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp));
}
int
-vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr)
+vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2185,11 +2218,12 @@ vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_rmdir, femop_rmdir);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, nm, cdir, cr));
+ return ((*func)(arg0, nm, cdir, cr, ct, flags));
}
int
-vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp)
+vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2199,12 +2233,12 @@ vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp)
vsop_find(vf, &func, int, &arg0, vop_readdir, femop_readdir);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, uiop, cr, eofp));
+ return ((*func)(arg0, uiop, cr, eofp, ct, flags));
}
int
vnext_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2214,11 +2248,11 @@ vnext_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
vsop_find(vf, &func, int, &arg0, vop_symlink, femop_symlink);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, linkname, vap, target, cr));
+ return ((*func)(arg0, linkname, vap, target, cr, ct, flags));
}
int
-vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr)
+vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2228,11 +2262,11 @@ vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_readlink, femop_readlink);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, uiop, cr));
+ return ((*func)(arg0, uiop, cr, ct));
}
int
-vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr)
+vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2242,11 +2276,11 @@ vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_fsync, femop_fsync);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, syncflag, cr));
+ return ((*func)(arg0, syncflag, cr, ct));
}
void
-vnext_inactive(femarg_t *vf, cred_t *cr)
+vnext_inactive(femarg_t *vf, cred_t *cr, caller_context_t *ct)
{
void (*func)() = NULL;
void *arg0 = NULL;
@@ -2256,11 +2290,11 @@ vnext_inactive(femarg_t *vf, cred_t *cr)
vsop_find(vf, &func, void, &arg0, vop_inactive, femop_inactive);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- (*func)(arg0, cr);
+ (*func)(arg0, cr, ct);
}
int
-vnext_fid(femarg_t *vf, fid_t *fidp)
+vnext_fid(femarg_t *vf, fid_t *fidp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2270,7 +2304,7 @@ vnext_fid(femarg_t *vf, fid_t *fidp)
vsop_find(vf, &func, int, &arg0, vop_fid, femop_fid);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, fidp));
+ return ((*func)(arg0, fidp, ct));
}
int
@@ -2302,7 +2336,7 @@ vnext_rwunlock(femarg_t *vf, int write_lock, caller_context_t *ct)
}
int
-vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp)
+vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2312,11 +2346,11 @@ vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp)
vsop_find(vf, &func, int, &arg0, vop_seek, femop_seek);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, ooff, noffp));
+ return ((*func)(arg0, ooff, noffp, ct));
}
int
-vnext_cmp(femarg_t *vf, vnode_t *vp2)
+vnext_cmp(femarg_t *vf, vnode_t *vp2, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2326,12 +2360,13 @@ vnext_cmp(femarg_t *vf, vnode_t *vp2)
vsop_find(vf, &func, int, &arg0, vop_cmp, femop_cmp);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vp2));
+ return ((*func)(arg0, vp2, ct));
}
int
vnext_frlock(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2341,7 +2376,7 @@ vnext_frlock(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
vsop_find(vf, &func, int, &arg0, vop_frlock, femop_frlock);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr));
+ return ((*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
int
@@ -2360,7 +2395,7 @@ vnext_space(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
}
int
-vnext_realvp(femarg_t *vf, vnode_t **vpp)
+vnext_realvp(femarg_t *vf, vnode_t **vpp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2370,13 +2405,13 @@ vnext_realvp(femarg_t *vf, vnode_t **vpp)
vsop_find(vf, &func, int, &arg0, vop_realvp, femop_realvp);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vpp));
+ return ((*func)(arg0, vpp, ct));
}
int
vnext_getpage(femarg_t *vf, offset_t off, size_t len, uint_t *protp,
struct page **plarr, size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2387,12 +2422,12 @@ vnext_getpage(femarg_t *vf, offset_t off, size_t len, uint_t *protp,
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
return ((*func)(arg0, off, len, protp, plarr, plsz, seg, addr, rw,
- cr));
+ cr, ct));
}
int
vnext_putpage(femarg_t *vf, offset_t off, size_t len, int flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2402,13 +2437,13 @@ vnext_putpage(femarg_t *vf, offset_t off, size_t len, int flags,
vsop_find(vf, &func, int, &arg0, vop_putpage, femop_putpage);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, off, len, flags, cr));
+ return ((*func)(arg0, off, len, flags, cr, ct));
}
int
vnext_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2419,13 +2454,13 @@ vnext_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
return ((*func)(arg0, off, as, addrp, len, prot, maxprot, flags,
- cr));
+ cr, ct));
}
int
vnext_addmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2435,12 +2470,14 @@ vnext_addmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
vsop_find(vf, &func, int, &arg0, vop_addmap, femop_addmap);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags, cr));
+ return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags,
+ cr, ct));
}
int
vnext_delmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
- size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags,
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2450,12 +2487,13 @@ vnext_delmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
vsop_find(vf, &func, int, &arg0, vop_delmap, femop_delmap);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags, cr));
+ return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags,
+ cr, ct));
}
int
vnext_poll(femarg_t *vf, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2465,11 +2503,12 @@ vnext_poll(femarg_t *vf, short events, int anyyet, short *reventsp,
vsop_find(vf, &func, int, &arg0, vop_poll, femop_poll);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, events, anyyet, reventsp, phpp));
+ return ((*func)(arg0, events, anyyet, reventsp, phpp, ct));
}
int
-vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks)
+vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2479,11 +2518,12 @@ vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks)
vsop_find(vf, &func, int, &arg0, vop_dump, femop_dump);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, addr, lbdn, dblks));
+ return ((*func)(arg0, addr, lbdn, dblks, ct));
}
int
-vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr)
+vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2493,12 +2533,12 @@ vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_pathconf, femop_pathconf);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, cmd, valp, cr));
+ return ((*func)(arg0, cmd, valp, cr, ct));
}
int
vnext_pageio(femarg_t *vf, struct page *pp, u_offset_t io_off,
- size_t io_len, int flags, cred_t *cr)
+ size_t io_len, int flags, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2508,11 +2548,11 @@ vnext_pageio(femarg_t *vf, struct page *pp, u_offset_t io_off,
vsop_find(vf, &func, int, &arg0, vop_pageio, femop_pageio);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, pp, io_off, io_len, flags, cr));
+ return ((*func)(arg0, pp, io_off, io_len, flags, cr, ct));
}
int
-vnext_dumpctl(femarg_t *vf, int action, int *blkp)
+vnext_dumpctl(femarg_t *vf, int action, int *blkp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2522,11 +2562,12 @@ vnext_dumpctl(femarg_t *vf, int action, int *blkp)
vsop_find(vf, &func, int, &arg0, vop_dumpctl, femop_dumpctl);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, action, blkp));
+ return ((*func)(arg0, action, blkp, ct));
}
void
-vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn, cred_t *cr)
+vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn, cred_t *cr,
+ caller_context_t *ct)
{
void (*func)() = NULL;
void *arg0 = NULL;
@@ -2536,11 +2577,12 @@ vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn, cred_t *cr)
vsop_find(vf, &func, void, &arg0, vop_dispose, femop_dispose);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- (*func)(arg0, pp, flag, dn, cr);
+ (*func)(arg0, pp, flag, dn, cr, ct);
}
int
-vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr)
+vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2550,11 +2592,12 @@ vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_setsecattr, femop_setsecattr);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vsap, flag, cr));
+ return ((*func)(arg0, vsap, flag, cr, ct));
}
int
-vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr)
+vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2564,12 +2607,12 @@ vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_getsecattr, femop_getsecattr);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vsap, flag, cr));
+ return ((*func)(arg0, vsap, flag, cr, ct));
}
int
vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr, int flag,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2579,11 +2622,12 @@ vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr, int flag,
vsop_find(vf, &func, int, &arg0, vop_shrlock, femop_shrlock);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, cmd, shr, flag, cr));
+ return ((*func)(arg0, cmd, shr, flag, cr, ct));
}
int
-vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname)
+vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2593,7 +2637,7 @@ vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname)
vsop_find(vf, &func, int, &arg0, vop_vnevent, femop_vnevent);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vnevent, dvp, cname));
+ return ((*func)(arg0, vnevent, dvp, cname, ct));
}
int
diff --git a/usr/src/uts/common/fs/fifofs/fifosubr.c b/usr/src/uts/common/fs/fifofs/fifosubr.c
index f44b8b3874..0d3d802370 100644
--- a/usr/src/uts/common/fs/fifofs/fifosubr.c
+++ b/usr/src/uts/common/fs/fifofs/fifosubr.c
@@ -29,7 +29,7 @@
/*
* The routines defined in this file are supporting routines for FIFOFS
- * file sytem type.
+ * file system type.
*/
#include <sys/types.h>
#include <sys/param.h>
@@ -164,7 +164,7 @@ static void fifo_reinit_vp(vnode_t *);
* we can determine the fifodata address from any of its member fnodes.
* This is essential for fifo_inactive.
*
- * The fnode constructor is designed to handle any fifodata struture,
+ * The fnode constructor is designed to handle any fifodata structure,
* deducing the number of fnodes from the total size. Thus, the fnode
* constructor does most of the work for the pipe constructor.
*/
@@ -410,8 +410,9 @@ fifovp(vnode_t *vp, cred_t *crp)
* This way different fifo nodes sharing the same real vnode
* can use realvp for communication.
*/
- if (VOP_REALVP(vp, &rvp) == 0)
- vp = rvp;
+
+ if (VOP_REALVP(vp, &rvp, NULL) == 0)
+ vp = rvp;
fnp->fn_realvp = vp;
fnp->fn_wcnt = 0;
@@ -431,7 +432,7 @@ fifovp(vnode_t *vp, cred_t *crp)
* initialize the times from vp.
*/
va.va_mask = AT_TIMES;
- if (VOP_GETATTR(vp, &va, 0, crp) == 0) {
+ if (VOP_GETATTR(vp, &va, 0, crp, NULL) == 0) {
fnp->fn_atime = va.va_atime.tv_sec;
fnp->fn_mtime = va.va_mtime.tv_sec;
fnp->fn_ctime = va.va_ctime.tv_sec;
@@ -652,7 +653,7 @@ fifo_stropen(vnode_t **vpp, int flag, cred_t *crp, int dotwist, int lockheld)
* Create new pipe on behalf of connld
*/
if (error = fifo_connld(vpp, flag, crp)) {
- (void) fifo_close(oldvp, flag, 1, 0, crp);
+ (void) fifo_close(oldvp, flag, 1, 0, crp, NULL);
mutex_enter(&fn_lock->flk_lock);
goto out;
}
@@ -663,7 +664,7 @@ fifo_stropen(vnode_t **vpp, int flag, cred_t *crp, int dotwist, int lockheld)
* we were in fifo_connld(), so
* we want to make sure the close completes (yuk)
*/
- (void) fifo_close(oldvp, flag, 1, 0, crp);
+ (void) fifo_close(oldvp, flag, 1, 0, crp, NULL);
/*
* fifo_connld has changed the vp, so we
* need to re-initialize locals
@@ -1006,7 +1007,7 @@ out:
crhold(c);
(void) closef(filep);
VTOF(vp2)->fn_flag &= ~FIFOOPEN;
- (void) fifo_close(vp2, flag, 1, (offset_t)0, c);
+ (void) fifo_close(vp2, flag, 1, (offset_t)0, c, NULL);
crfree(c);
VN_RELE(vp2);
return (error);
diff --git a/usr/src/uts/common/fs/fifofs/fifovnops.c b/usr/src/uts/common/fs/fifofs/fifovnops.c
index afa01bb3ab..9756d13705 100644
--- a/usr/src/uts/common/fs/fifofs/fifovnops.c
+++ b/usr/src/uts/common/fs/fifofs/fifovnops.c
@@ -73,26 +73,33 @@
*/
static int fifo_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
static int fifo_write(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
-static int fifo_getattr(vnode_t *, vattr_t *, int, cred_t *);
+static int fifo_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
static int fifo_setattr(vnode_t *, vattr_t *, int, cred_t *,
caller_context_t *);
-static int fifo_realvp(vnode_t *, vnode_t **);
-static int fifo_access(vnode_t *, int, int, cred_t *);
+static int fifo_realvp(vnode_t *, vnode_t **, caller_context_t *);
+static int fifo_access(vnode_t *, int, int, cred_t *, caller_context_t *);
static int fifo_create(struct vnode *, char *, vattr_t *, enum vcexcl,
- int, struct vnode **, struct cred *, int);
-static int fifo_fid(vnode_t *, fid_t *);
-static int fifo_fsync(vnode_t *, int, cred_t *);
-static int fifo_seek(vnode_t *, offset_t, offset_t *);
-static int fifo_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
+ int, struct vnode **, struct cred *, int, caller_context_t *,
+ vsecattr_t *);
+static int fifo_fid(vnode_t *, fid_t *, caller_context_t *);
+static int fifo_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static int fifo_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
+static int fifo_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
static int fifo_fastioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
static int fifo_strioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
-static int fifo_poll(vnode_t *, short, int, short *, pollhead_t **);
-static int fifo_pathconf(vnode_t *, int, ulong_t *, cred_t *);
-static void fifo_inactive(vnode_t *, cred_t *);
+static int fifo_poll(vnode_t *, short, int, short *, pollhead_t **,
+ caller_context_t *);
+static int fifo_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+static void fifo_inactive(vnode_t *, cred_t *, caller_context_t *);
static int fifo_rwlock(vnode_t *, int, caller_context_t *);
static void fifo_rwunlock(vnode_t *, int, caller_context_t *);
-static int fifo_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
-static int fifo_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
+static int fifo_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
+static int fifo_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
/* functions local to this file */
static boolean_t fifo_stayfast_enter(fifonode_t *);
@@ -210,7 +217,7 @@ tsol_fifo_access(vnode_t *vp, int flag, cred_t *crp)
* Note: namefs pipes come through this routine too.
*/
int
-fifo_open(vnode_t **vpp, int flag, cred_t *crp)
+fifo_open(vnode_t **vpp, int flag, cred_t *crp, caller_context_t *ct)
{
vnode_t *vp = *vpp;
fifonode_t *fnp = VTOF(vp);
@@ -280,7 +287,7 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
* If we are opening for read (or writer)
* indicate that the reader (or writer) is done with open
* if there is a writer (or reader) waiting for us, wake them up
- * and indicate that at least 1 read (or write) open has occured
+ * and indicate that at least 1 read (or write) open has occurred
* this is need in the event the read (or write) side closes
* before the writer (or reader) has a chance to wake up
* i.e. it sees that a reader (or writer) was once there
@@ -289,7 +296,7 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
fnp->fn_rsynccnt--; /* reader done with open */
if (fnp->fn_flag & FIFOSYNC) {
/*
- * This indicates that a read open has occured
+ * This indicates that a read open has occurred
* Only need to set if writer is actually asleep
* Flag will be consumed by writer.
*/
@@ -301,7 +308,7 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
fnp->fn_wsynccnt--; /* writer done with open */
if (fnp->fn_flag & FIFOSYNC) {
/*
- * This indicates that a write open has occured
+ * This indicates that a write open has occurred
* Only need to set if reader is actually asleep
* Flag will be consumed by reader.
*/
@@ -347,20 +354,20 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
/*
* Last reader to wakeup clear writer
* Clear both writer and reader open
- * occured flag incase other end is O_RDWR
+ * occurred flag incase other end is O_RDWR
*/
if (--fnp->fn_insync == 0 &&
fnp->fn_flag & FIFOWOCR) {
fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
}
mutex_exit(&fnp->fn_lock->flk_lock);
- (void) fifo_close(*vpp, flag, 1, 0, crp);
+ (void) fifo_close(*vpp, flag, 1, 0, crp, ct);
error = EINTR;
goto done;
}
/*
- * Last reader to wakeup clear writer open occured flag
- * Clear both writer and reader open occured flag
+ * Last reader to wakeup clear writer open occurred flag
+ * Clear both writer and reader open occurred flag
* incase other end is O_RDWR
*/
if (--fnp->fn_insync == 0 &&
@@ -374,7 +381,7 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
fnp->fn_rcnt == fnp->fn_rsynccnt) {
if ((flag & (FNDELAY|FNONBLOCK)) && fnp->fn_rcnt == 0) {
mutex_exit(&fnp->fn_lock->flk_lock);
- (void) fifo_close(*vpp, flag, 1, 0, crp);
+ (void) fifo_close(*vpp, flag, 1, 0, crp, ct);
error = ENXIO;
goto done;
}
@@ -385,21 +392,21 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
/*
* Last writer to wakeup clear
* Clear both writer and reader open
- * occured flag in case other end is O_RDWR
+ * occurred flag in case other end is O_RDWR
*/
if (--fnp->fn_insync == 0 &&
(fnp->fn_flag & FIFOROCR) != 0) {
fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
}
mutex_exit(&fnp->fn_lock->flk_lock);
- (void) fifo_close(*vpp, flag, 1, 0, crp);
+ (void) fifo_close(*vpp, flag, 1, 0, crp, ct);
error = EINTR;
goto done;
}
/*
- * Last writer to wakeup clear reader open occured flag
+ * Last writer to wakeup clear reader open occurred flag
* Clear both writer and reader open
- * occured flag in case other end is O_RDWR
+ * occurred flag in case other end is O_RDWR
*/
if (--fnp->fn_insync == 0 &&
(fnp->fn_flag & FIFOROCR) != 0) {
@@ -425,7 +432,8 @@ done:
*/
/*ARGSUSED*/
int
-fifo_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp)
+fifo_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp,
+ caller_context_t *ct)
{
fifonode_t *fnp = VTOF(vp);
fifonode_t *fn_dest = fnp->fn_dest;
@@ -1079,7 +1087,7 @@ stream_mode:
done:
/*
* update vnode modification and change times
- * make sure there were no errors and some data was transfered
+ * make sure there were no errors and some data was transferred
*/
if (error == 0 && write_size != uiop->uio_resid) {
time_t now = gethrestime_sec();
@@ -1105,9 +1113,10 @@ epipe:
return (error);
}
+/*ARGSUSED6*/
static int
fifo_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
- cred_t *cr, int *rvalp)
+ cred_t *cr, int *rvalp, caller_context_t *ct)
{
/*
* Just a quick check
@@ -1430,7 +1439,8 @@ fifo_strioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
* the node information from the credentials structure.
*/
int
-fifo_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
+fifo_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
+ caller_context_t *ct)
{
int error = 0;
fifonode_t *fnp = VTOF(vp);
@@ -1442,7 +1452,7 @@ fifo_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
/*
* for FIFOs or mounted pipes
*/
- if (error = VOP_GETATTR(fnp->fn_realvp, vap, flags, crp))
+ if (error = VOP_GETATTR(fnp->fn_realvp, vap, flags, crp, ct))
return (error);
mutex_enter(&fn_lock->flk_lock);
/* set current times from fnode, even if older than vnode */
@@ -1537,10 +1547,10 @@ fifo_setattr(
* Otherwise, return 0 (allow all access).
*/
int
-fifo_access(vnode_t *vp, int mode, int flags, cred_t *crp)
+fifo_access(vnode_t *vp, int mode, int flags, cred_t *crp, caller_context_t *ct)
{
if (VTOF(vp)->fn_realvp)
- return (VOP_ACCESS(VTOF(vp)->fn_realvp, mode, flags, crp));
+ return (VOP_ACCESS(VTOF(vp)->fn_realvp, mode, flags, crp, ct));
else
return (0);
}
@@ -1552,13 +1562,14 @@ fifo_access(vnode_t *vp, int mode, int flags, cred_t *crp)
/*ARGSUSED*/
static int
fifo_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
- int mode, struct vnode **vpp, struct cred *cr, int flag)
+ int mode, struct vnode **vpp, struct cred *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
ASSERT(dvp && (dvp->v_flag & VROOT) && *name == '\0');
if (excl == NONEXCL) {
- if (mode && (error = fifo_access(dvp, mode, 0, cr)))
+ if (mode && (error = fifo_access(dvp, mode, 0, cr, ct)))
return (error);
VN_HOLD(dvp);
return (0);
@@ -1571,7 +1582,7 @@ fifo_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
* Otherwise, return 0.
*/
int
-fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
+fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp, caller_context_t *ct)
{
fifonode_t *fnp = VTOF(vp);
vattr_t va;
@@ -1581,7 +1592,7 @@ fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
bzero((caddr_t)&va, sizeof (va));
va.va_mask = AT_MTIME | AT_ATIME;
- if (VOP_GETATTR(fnp->fn_realvp, &va, 0, crp) == 0) {
+ if (VOP_GETATTR(fnp->fn_realvp, &va, 0, crp, ct) == 0) {
va.va_mask = 0;
if (fnp->fn_mtime > va.va_mtime.tv_sec) {
va.va_mtime.tv_sec = fnp->fn_mtime;
@@ -1592,9 +1603,9 @@ fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
va.va_mask |= AT_ATIME;
}
if (va.va_mask != 0)
- (void) VOP_SETATTR(fnp->fn_realvp, &va, 0, crp, NULL);
+ (void) VOP_SETATTR(fnp->fn_realvp, &va, 0, crp, ct);
}
- return (VOP_FSYNC(fnp->fn_realvp, syncflag, crp));
+ return (VOP_FSYNC(fnp->fn_realvp, syncflag, crp, ct));
}
/*
@@ -1602,7 +1613,7 @@ fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
* vnode. Sync the file system and free the fifonode.
*/
void
-fifo_inactive(vnode_t *vp, cred_t *crp)
+fifo_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
{
fifonode_t *fnp;
fifolock_t *fn_lock;
@@ -1630,7 +1641,7 @@ fifo_inactive(vnode_t *vp, cred_t *crp)
if (fnp->fn_realvp) {
(void) fiforemove(fnp);
mutex_exit(&ftable_lock);
- (void) fifo_fsync(vp, FSYNC, crp);
+ (void) fifo_fsync(vp, FSYNC, crp, ct);
VN_RELE(fnp->fn_realvp);
vp->v_vfsp = NULL;
} else
@@ -1684,10 +1695,10 @@ fifo_inactive(vnode_t *vp, cred_t *crp)
* Otherwise, return EINVAL.
*/
int
-fifo_fid(vnode_t *vp, fid_t *fidfnp)
+fifo_fid(vnode_t *vp, fid_t *fidfnp, caller_context_t *ct)
{
if (VTOF(vp)->fn_realvp)
- return (VOP_FID(VTOF(vp)->fn_realvp, fidfnp));
+ return (VOP_FID(VTOF(vp)->fn_realvp, fidfnp, ct));
else
return (EINVAL);
}
@@ -1716,7 +1727,7 @@ fifo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
*/
/*ARGSUSED*/
int
-fifo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+fifo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
return (ESPIPE);
}
@@ -1725,13 +1736,13 @@ fifo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
* If there is a realvp associated with vp, return it.
*/
int
-fifo_realvp(vnode_t *vp, vnode_t **vpp)
+fifo_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
vnode_t *rvp;
if ((rvp = VTOF(vp)->fn_realvp) != NULL) {
vp = rvp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
}
@@ -1742,9 +1753,10 @@ fifo_realvp(vnode_t *vp, vnode_t **vpp)
/*
* Poll for interesting events on a stream pipe
*/
+/* ARGSUSED */
int
fifo_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **phpp)
+ pollhead_t **phpp, caller_context_t *ct)
{
fifonode_t *fnp, *fn_dest;
fifolock_t *fn_lock;
@@ -1854,7 +1866,8 @@ stream_mode:
*/
/* ARGSUSED */
int
-fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
ulong_t val;
int error = 0;
@@ -1911,7 +1924,7 @@ fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
default:
if (VTOF(vp)->fn_realvp)
error = VOP_PATHCONF(VTOF(vp)->fn_realvp, cmd,
- &val, cr);
+ &val, cr, ct);
else
error = EINVAL;
break;
@@ -1927,7 +1940,8 @@ fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
* Otherwise, return NOSYS.
*/
int
-fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
+fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp,
+ caller_context_t *ct)
{
int error;
@@ -1937,9 +1951,10 @@ fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
* VOP_RWLOCK or VOP_RWUNLOCK, so we do it here instead.
*/
if (VTOF(vp)->fn_realvp) {
- (void) VOP_RWLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(VTOF(vp)->fn_realvp, vsap, flag, crp);
- VOP_RWUNLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, NULL);
+ (void) VOP_RWLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, ct);
+ error = VOP_SETSECATTR(VTOF(vp)->fn_realvp, vsap, flag,
+ crp, ct);
+ VOP_RWUNLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, ct);
return (error);
} else
return (fs_nosys());
@@ -1950,12 +1965,14 @@ fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
* an ACL from the permission bits that fifo_getattr() makes up.
*/
int
-fifo_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
+fifo_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp,
+ caller_context_t *ct)
{
if (VTOF(vp)->fn_realvp)
- return (VOP_GETSECATTR(VTOF(vp)->fn_realvp, vsap, flag, crp));
+ return (VOP_GETSECATTR(VTOF(vp)->fn_realvp, vsap, flag,
+ crp, ct));
else
- return (fs_fab_acl(vp, vsap, flag, crp));
+ return (fs_fab_acl(vp, vsap, flag, crp, ct));
}
diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c
index c88e8b3268..5afbced148 100644
--- a/usr/src/uts/common/fs/fs_subr.c
+++ b/usr/src/uts/common/fs/fs_subr.c
@@ -113,7 +113,8 @@ fs_nosys_map(struct vnode *vp,
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
return (ENOSYS);
}
@@ -128,7 +129,8 @@ fs_nosys_addmap(struct vnode *vp,
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
return (ENOSYS);
}
@@ -139,7 +141,8 @@ fs_nosys_poll(vnode_t *vp,
register short events,
int anyyet,
register short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
return (ENOSYS);
}
@@ -157,6 +160,38 @@ fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
}
/*
+ * 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 */
@@ -175,8 +210,9 @@ 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)
+fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
return (vp1 == vp2);
}
@@ -186,7 +222,7 @@ fs_cmp(vnode_t *vp1, vnode_t *vp2)
*/
/* ARGSUSED */
int
-fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
@@ -197,13 +233,15 @@ fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
/* ARGSUSED */
int
fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, flk_callback_t *flk_cbp, cred_t *cr)
+ offset_t offset, flk_callback_t *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
int frcmd;
int nlmid;
int error = 0;
flk_callback_t serialize_callback;
int serialize = 0;
+ v_mode_t mode;
switch (cmd) {
@@ -211,15 +249,13 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
case F_O_GETLK:
if (flag & F_REMOTELOCK) {
frcmd = RCMDLCK;
- break;
- }
- if (flag & F_PXFSLOCK) {
+ } else if (flag & F_PXFSLOCK) {
frcmd = PCMDLCK;
- break;
+ } else {
+ frcmd = 0;
+ bfp->l_pid = ttoproc(curthread)->p_pid;
+ bfp->l_sysid = 0;
}
- bfp->l_pid = ttoproc(curthread)->p_pid;
- bfp->l_sysid = 0;
- frcmd = 0;
break;
case F_SETLK_NBMAND:
@@ -238,6 +274,19 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
/*FALLTHROUGH*/
case F_SETLK:
+ if (flag & F_REMOTELOCK) {
+ frcmd = SETFLCK|RCMDLCK;
+ } else if (flag & F_PXFSLOCK) {
+ frcmd = SETFLCK|PCMDLCK;
+ } else {
+ frcmd = SETFLCK;
+ bfp->l_pid = ttoproc(curthread)->p_pid;
+ bfp->l_sysid = 0;
+ }
+ if (cmd == F_SETLK_NBMAND &&
+ (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
+ frcmd |= NBMLCK;
+ }
/*
* Check whether there is an NBMAND share reservation that
* conflicts with the lock request.
@@ -245,30 +294,31 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_WRITER);
serialize = 1;
+ if (frcmd & NBMLCK) {
+ mode = (bfp->l_type == F_RDLCK) ?
+ V_READ : V_RDANDWR;
+ if (vn_is_mapped(vp, mode)) {
+ error = EAGAIN;
+ goto done;
+ }
+ }
if (share_blocks_lock(vp, bfp)) {
error = EAGAIN;
goto done;
}
}
- if (flag & F_REMOTELOCK) {
- frcmd = SETFLCK|RCMDLCK;
- break;
- }
- if (flag & F_PXFSLOCK) {
- frcmd = SETFLCK|PCMDLCK;
- break;
- }
- bfp->l_pid = ttoproc(curthread)->p_pid;
- bfp->l_sysid = 0;
- frcmd = SETFLCK;
- if (cmd == F_SETLK_NBMAND &&
- (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
- /* would check here for conflict with mapped region */
- frcmd |= NBMLCK;
- }
break;
case F_SETLKW:
+ if (flag & F_REMOTELOCK) {
+ frcmd = SETFLCK|SLPFLCK|RCMDLCK;
+ } else if (flag & F_PXFSLOCK) {
+ frcmd = SETFLCK|SLPFLCK|PCMDLCK;
+ } else {
+ frcmd = SETFLCK|SLPFLCK;
+ bfp->l_pid = ttoproc(curthread)->p_pid;
+ bfp->l_sysid = 0;
+ }
/*
* If there is an NBMAND share reservation that conflicts
* with the lock request, block until the conflicting share
@@ -283,24 +333,13 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
goto done;
}
}
- if (flag & F_REMOTELOCK) {
- frcmd = SETFLCK|SLPFLCK|RCMDLCK;
- break;
- }
- if (flag & F_PXFSLOCK) {
- frcmd = SETFLCK|SLPFLCK|PCMDLCK;
- break;
- }
- bfp->l_pid = ttoproc(curthread)->p_pid;
- bfp->l_sysid = 0;
- frcmd = SETFLCK|SLPFLCK;
break;
case F_HASREMOTELOCKS:
nlmid = GETNLMID(bfp->l_sysid);
if (nlmid != 0) { /* booted as a cluster */
l_has_rmt(bfp) =
- cl_flk_has_remote_locks_for_nlmid(vp, nlmid);
+ cl_flk_has_remote_locks_for_nlmid(vp, nlmid);
} else { /* not booted as a cluster */
l_has_rmt(bfp) = flk_has_remote_locks(vp);
}
@@ -320,7 +359,7 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (serialize && (frcmd & SLPFLCK) != 0) {
flk_add_callback(&serialize_callback,
- frlock_serialize_blocked, vp, flk_cbp);
+ frlock_serialize_blocked, vp, flk_cbp);
flk_cbp = &serialize_callback;
}
@@ -358,7 +397,12 @@ frlock_serialize_blocked(flk_cb_when_t when, void *infop)
*/
/* ARGSUSED */
int
-fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+fs_setfl(
+ vnode_t *vp,
+ int oflags,
+ int nflags,
+ cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -375,7 +419,8 @@ fs_poll(vnode_t *vp,
register short events,
int anyyet,
register short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
*reventsp = 0;
if (events & POLLIN)
@@ -397,7 +442,12 @@ fs_poll(vnode_t *vp,
*/
/* ARGSUSED */
int
-fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+fs_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
{
register ulong_t val;
register int error = 0;
@@ -467,6 +517,19 @@ fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
val = 0;
break;
+ case _PC_CASE_BEHAVIOR:
+ val = _CASE_SENSITIVE;
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
+ val |= _CASE_INSENSITIVE;
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
+ val &= ~_CASE_SENSITIVE;
+ break;
+
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ val = 0;
+ break;
+
default:
error = EINVAL;
break;
@@ -482,7 +545,13 @@ fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
*/
/* ARGSUSED */
void
-fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr)
+fs_dispose(
+ struct vnode *vp,
+ page_t *pp,
+ int fl,
+ int dn,
+ struct cred *cr,
+ caller_context_t *ct)
{
ASSERT(fl == B_FREE || fl == B_INVAL);
@@ -495,7 +564,13 @@ fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr)
/* ARGSUSED */
void
-fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr)
+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");
}
@@ -505,30 +580,33 @@ fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr)
*/
/* ARGSUSED */
int
-fs_fab_acl(vp, vsecattr, flag, cr)
-vnode_t *vp;
-vsecattr_t *vsecattr;
-int flag;
-cred_t *cr;
+fs_fab_acl(
+ vnode_t *vp,
+ vsecattr_t *vsecattr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
{
aclent_t *aclentp;
ace_t *acep;
struct vattr vattr;
int error;
+ size_t aclsize;
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))
+ if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
return (error);
if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
+ aclsize = 4 * sizeof (aclent_t);
vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */
- vsecattr->vsa_aclentp = kmem_zalloc(4 * sizeof (aclent_t),
- KM_SLEEP);
+ vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
aclentp = vsecattr->vsa_aclentp;
aclentp->a_type = USER_OBJ; /* Owner */
@@ -550,9 +628,10 @@ cred_t *cr;
aclentp->a_perm = (ushort_t)(0007);
aclentp->a_id = (gid_t)-1; /* Really undefined */
} else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
+ aclsize = 6 * sizeof (ace_t);
vsecattr->vsa_aclcnt = 6;
- vsecattr->vsa_aclentp = kmem_zalloc(6 * sizeof (ace_t),
- KM_SLEEP);
+ vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
+ vsecattr->vsa_aclentsz = aclsize;
acep = vsecattr->vsa_aclentp;
(void) memcpy(acep, trivial_acl, sizeof (ace_t) * 6);
adjust_ace_pair(acep, (vattr.va_mode & 0700) >> 6);
@@ -568,7 +647,13 @@ cred_t *cr;
*/
/* ARGSUSED4 */
int
-fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+fs_shrlock(
+ struct vnode *vp,
+ int cmd,
+ struct shrlock *shr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
{
int error;
@@ -581,13 +666,12 @@ fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) ||
((shr->s_access & F_WRACC) && (flag & FWRITE) == 0))
return (EBADF);
- if (shr->s_deny & F_MANDDNY)
+ if (shr->s_access & (F_RMACC | F_MDACC))
+ return (EINVAL);
+ if (shr->s_deny & (F_MANDDNY | F_RMDNY))
return (EINVAL);
}
if (cmd == F_SHARE_NBMAND) {
- /* must have write permission to deny read access */
- if ((shr->s_deny & F_RDDNY) && (flag & FWRITE) == 0)
- return (EBADF);
/* make sure nbmand is allowed on the file */
if (!vp->v_vfsp ||
!(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
@@ -633,7 +717,8 @@ fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
/*ARGSUSED1*/
int
-fs_vnevent_nosupport(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
+fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
{
ASSERT(vp != NULL);
return (ENOTSUP);
@@ -641,7 +726,8 @@ fs_vnevent_nosupport(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
/*ARGSUSED1*/
int
-fs_vnevent_support(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
+fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
{
ASSERT(vp != NULL);
return (0);
@@ -667,7 +753,7 @@ fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
int isnontrivial;
/* determine the forms of ACLs maintained */
- error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr);
+ error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL);
/* clear bits we don't understand and establish default acl_style */
acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED);
@@ -691,7 +777,7 @@ fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
}
ASSERT(vsecattr.vsa_mask && acl_flavor);
- error = VOP_GETSECATTR(vp, &vsecattr, 0, cr);
+ error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL);
if (error == 0)
break;
@@ -739,3 +825,30 @@ fs_need_estale_retry(int retry_count)
else
return (0);
}
+
+
+static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL;
+
+/*
+ * Routine for anti-virus scanner to call to register its scanning routine.
+ */
+void
+fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int))
+{
+ fs_av_scan = av_scan;
+}
+
+/*
+ * Routine for file systems to call to initiate anti-virus scanning.
+ * Scanning will only be done on REGular files (currently).
+ */
+int
+fs_vscan(vnode_t *vp, cred_t *cr, int async)
+{
+ int ret = 0;
+
+ if (fs_av_scan && vp->v_type == VREG)
+ ret = (*fs_av_scan)(vp, cr, async);
+
+ return (ret);
+}
diff --git a/usr/src/uts/common/fs/fs_subr.h b/usr/src/uts/common/fs/fs_subr.h
index f0b536d0f0..a39e6ec764 100644
--- a/usr/src/uts/common/fs/fs_subr.h
+++ b/usr/src/uts/common/fs/fs_subr.h
@@ -56,32 +56,46 @@ extern int fs_nosys();
extern int fs_inval();
extern int fs_notdir();
extern int fs_nosys_map(struct vnode *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, struct cred *);
+ size_t, uchar_t, uchar_t, uint_t, struct cred *,
+ caller_context_t *);
extern int fs_nosys_addmap(struct vnode *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, struct cred *);
+ size_t, uchar_t, uchar_t, uint_t, struct cred *,
+ caller_context_t *);
extern int fs_nosys_poll(struct vnode *, short, int, short *,
- struct pollhead **);
-
+ struct pollhead **, caller_context_t *);
+extern int fs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
+extern int fs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+extern int fs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
extern int fs_sync(struct vfs *, short, cred_t *);
extern int fs_rwlock(vnode_t *, int, caller_context_t *);
extern void fs_rwunlock(vnode_t *, int, caller_context_t *);
-extern int fs_cmp(vnode_t *, vnode_t *);
-extern int fs_seek(vnode_t *, offset_t, offset_t *);
+extern int fs_cmp(vnode_t *, vnode_t *, caller_context_t *);
+extern int fs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
extern int fs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
-extern int fs_setfl(vnode_t *, int, int, cred_t *);
-extern int fs_poll(vnode_t *, short, int, short *, struct pollhead **);
-extern int fs_pathconf(struct vnode *, int, ulong_t *, struct cred *);
+ struct flk_callback *, cred_t *, caller_context_t *);
+extern int fs_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fs_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+extern int fs_pathconf(struct vnode *, int, ulong_t *, struct cred *,
+ caller_context_t *);
extern void clkset(time_t);
-extern void fs_dispose(struct vnode *, page_t *, int, int, struct cred *);
-extern void fs_nodispose(struct vnode *, page_t *, int, int, struct cred *);
-extern int fs_fab_acl(struct vnode *, vsecattr_t *, int flag, cred_t *);
+extern void fs_dispose(struct vnode *, page_t *, int, int, struct cred *,
+ caller_context_t *);
+extern void fs_nodispose(struct vnode *, page_t *, int, int, struct cred *,
+ caller_context_t *);
+extern int fs_fab_acl(struct vnode *, vsecattr_t *, int flag, cred_t *,
+ caller_context_t *);
extern int fs_shrlock(struct vnode *, int, struct shrlock *, int,
- cred_t *);
-extern int fs_vnevent_nosupport(vnode_t *, vnevent_t, vnode_t *, char *);
-extern int fs_vnevent_support(vnode_t *, vnevent_t, vnode_t *, char *);
+ cred_t *, caller_context_t *);
+extern int fs_vnevent_nosupport(vnode_t *, vnevent_t, vnode_t *dvp,
+ char *fnm, caller_context_t *);
+extern int fs_vnevent_support(vnode_t *, vnevent_t, vnode_t *dvp,
+ char *fnm, caller_context_t *);
extern int fs_acl_nontrivial(struct vnode *vp, struct cred *cr);
extern int fs_need_estale_retry(int);
+extern void fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int));
+extern int fs_vscan(vnode_t *, cred_t *, int);
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/fs/fsflush.c b/usr/src/uts/common/fs/fsflush.c
index d7b3ae1071..50b196ac17 100644
--- a/usr/src/uts/common/fs/fsflush.c
+++ b/usr/src/uts/common/fs/fsflush.c
@@ -100,7 +100,7 @@ fsf_stat_t fsf_total; /* total of counts */
ulong_t fsf_cycles; /* number of runs refelected in fsf_total */
/*
- * data used to determine when we can coalese consecutive free pages
+ * data used to determine when we can coalesce consecutive free pages
* into larger pages.
*/
#define MAX_PAGESIZES 32
@@ -131,7 +131,7 @@ fsflush_do_pages()
u_offset_t offset;
uint_t szc;
- page_t *coal_page = NULL; /* 1st page in group to coalese */
+ page_t *coal_page = NULL; /* 1st page in group to coalesce */
uint_t coal_szc = 0; /* size code, coal_page->p_szc */
uint_t coal_cnt = 0; /* count of pages seen */
@@ -288,7 +288,7 @@ fsflush_do_pages()
page_unlock(pp);
(void) VOP_PUTPAGE(vp, offset, PAGESIZE, B_ASYNC,
- kcred);
+ kcred, NULL);
VN_RELE(vp);
} else {
diff --git a/usr/src/uts/common/fs/gfs.c b/usr/src/uts/common/fs/gfs.c
index c3e05aeced..24f2ad2a7a 100644
--- a/usr/src/uts/common/fs/gfs.c
+++ b/usr/src/uts/common/fs/gfs.c
@@ -62,7 +62,7 @@
*
* These routines are designed to play a support role for existing
* pseudo-filesystems (such as procfs). They simplify common tasks,
- * without enforcing the filesystem to hand over management to GFS. The
+ * without forcing the filesystem to hand over management to GFS. The
* routines covered are:
*
* gfs_readdir_init()
@@ -538,7 +538,7 @@ gfs_file_inactive(vnode_t *vp)
gfs_dir_t *dp = NULL;
void *data;
- if (fp->gfs_parent == NULL)
+ if (fp->gfs_parent == NULL || (vp->v_flag & V_XATTRDIR))
goto found;
dp = fp->gfs_parent->v_data;
@@ -564,6 +564,9 @@ gfs_file_inactive(vnode_t *vp)
ge = NULL;
found:
+ if (vp->v_flag & V_XATTRDIR) {
+ mutex_enter(&fp->gfs_parent->v_lock);
+ }
mutex_enter(&vp->v_lock);
if (vp->v_count == 1) {
/*
@@ -577,13 +580,19 @@ found:
*/
ge->gfse_vnode = NULL;
}
+ if (vp->v_flag & V_XATTRDIR) {
+ fp->gfs_parent->v_xattrdir = NULL;
+ mutex_exit(&fp->gfs_parent->v_lock);
+ }
mutex_exit(&vp->v_lock);
/*
* Free vnode and release parent
*/
if (fp->gfs_parent) {
- gfs_dir_unlock(dp);
+ if (dp) {
+ gfs_dir_unlock(dp);
+ }
VN_RELE(fp->gfs_parent);
} else {
ASSERT(vp->v_vfsp != NULL);
@@ -594,6 +603,9 @@ found:
vp->v_count--;
data = NULL;
mutex_exit(&vp->v_lock);
+ if (vp->v_flag & V_XATTRDIR) {
+ mutex_exit(&fp->gfs_parent->v_lock);
+ }
if (dp)
gfs_dir_unlock(dp);
}
@@ -637,16 +649,17 @@ gfs_dir_inactive(vnode_t *vp)
* If no static entry is found, we invoke the lookup callback, if any. The
* arguments to this callback are:
*
- * int gfs_lookup_cb(vnode_t *pvp, const char *nm, vnode_t **vpp);
+ * int gfs_lookup_cb(vnode_t *pvp, const char *nm, vnode_t **vpp, cred_t *cr);
*
* pvp - parent vnode
* nm - name of entry
* vpp - pointer to resulting vnode
+ * cr - pointer to cred
*
* Returns 0 on success, non-zero on error.
*/
int
-gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp)
+gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cred_t *cr)
{
int i;
gfs_dirent_t *ge;
@@ -732,14 +745,22 @@ gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp)
* directory.
*/
gfs_dir_unlock(dp);
- ret = dp->gfsd_lookup(dvp, nm, &vp, &ino);
+ ret = dp->gfsd_lookup(dvp, nm, &vp, &ino, cr);
gfs_dir_lock(dp);
if (ret != 0)
goto out;
- fp = (gfs_file_t *)vp->v_data;
- fp->gfs_index = -1;
- fp->gfs_ino = ino;
+ /*
+ * The lookup_cb might be returning a non-GFS vnode.
+ * Currently this is true for extended attributes,
+ * where we're returning a vnode with v_data from an
+ * underlying fs.
+ */
+ if ((dvp->v_flag & V_XATTRDIR) == 0) {
+ fp = (gfs_file_t *)vp->v_data;
+ fp->gfs_index = -1;
+ fp->gfs_ino = ino;
+ }
} else {
/*
* No static entry found, and there is no lookup callback, so
@@ -803,21 +824,31 @@ out:
* Return 0 on success, or error on failure.
*/
int
-gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data)
+gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data, cred_t *cr,
+ caller_context_t *ct)
{
gfs_readdir_state_t gstate;
int error, eof = 0;
ino64_t ino, pino;
offset_t off, next;
gfs_dir_t *dp = dvp->v_data;
+ vnode_t *parent;
ino = dp->gfsd_file.gfs_ino;
+ parent = dp->gfsd_file.gfs_parent;
- if (dp->gfsd_file.gfs_parent == NULL)
+ if (parent == NULL)
pino = ino; /* root of filesystem */
- else
- pino = ((gfs_file_t *)
- (dp->gfsd_file.gfs_parent->v_data))->gfs_ino;
+ else if (dvp->v_flag & V_XATTRDIR) {
+ vattr_t va;
+
+ va.va_mask = AT_NODEID;
+ error = VOP_GETATTR(parent, &va, 0, cr, ct);
+ if (error)
+ return (error);
+ pino = va.va_nodeid;
+ } else
+ pino = ((gfs_file_t *)(parent->v_data))->gfs_ino;
if ((error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, uiop,
pino, ino)) != 0)
@@ -870,9 +901,10 @@ gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data)
/* ARGSUSED */
int
gfs_vop_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
- return (gfs_dir_lookup(dvp, nm, vpp));
+ return (gfs_dir_lookup(dvp, nm, vpp, cr));
}
/*
@@ -883,9 +915,10 @@ gfs_vop_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
*/
/* ARGSUSED */
int
-gfs_vop_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+gfs_vop_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
- return (gfs_dir_readdir(vp, uiop, eofp, NULL));
+ return (gfs_dir_readdir(vp, uiop, eofp, NULL, cr, ct));
}
@@ -901,7 +934,8 @@ gfs_vop_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
/* ARGSUSED */
int
gfs_vop_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 *cred)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cred,
+ caller_context_t *ct)
{
int rv;
ssize_t resid = len;
@@ -972,7 +1006,7 @@ gfs_vop_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
*/
/* ARGSUSED */
void
-gfs_vop_inactive(vnode_t *vp, cred_t *cr)
+gfs_vop_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
gfs_file_t *fp = vp->v_data;
void *data;
diff --git a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
index 132dc9f544..9c25cc5249 100644
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
@@ -407,7 +407,7 @@ hsfs_unmount(
mutex_exit(&hs_mounttab_lock);
hsfs_fini_kstats(fsp);
- (void) VOP_CLOSE(fsp->hsfs_devvp, FREAD, 1, (offset_t)0, cr);
+ (void) VOP_CLOSE(fsp->hsfs_devvp, FREAD, 1, (offset_t)0, cr, NULL);
VN_RELE(fsp->hsfs_devvp);
/* free path table space */
if (fsp->hsfs_ptbl != NULL)
@@ -626,7 +626,7 @@ hs_mountfs(
/*
* Open the target device (file) for read only.
*/
- if (error = VOP_OPEN(&devvp, FREAD, cr)) {
+ if (error = VOP_OPEN(&devvp, FREAD, cr, NULL)) {
VN_RELE(devvp);
return (error);
}
@@ -641,7 +641,7 @@ hs_mountfs(
}
vap.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(devvp, &vap, ATTR_COMM, cr)) != 0) {
+ if ((error = VOP_GETATTR(devvp, &vap, ATTR_COMM, cr, NULL)) != 0) {
cmn_err(CE_NOTE, "Cannot get attributes of the CD-ROM driver");
goto cleanup;
}
@@ -937,7 +937,7 @@ hs_mountfs(
return (0);
cleanup:
- (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, cr);
+ (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, cr, NULL);
VN_RELE(devvp);
if (fsp)
kmem_free(fsp, sizeof (*fsp));
@@ -1365,14 +1365,14 @@ hs_getmdev(struct vfs *vfsp, char *fspec, int flags, dev_t *pdev, mode_t *mode,
/*
* Can we read from the device?
*/
- if ((error = VOP_ACCESS(vp, VREAD, 0, cr)) != 0 ||
+ if ((error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0 ||
(error = secpolicy_spec_open(cr, vp, FREAD)) != 0) {
VN_RELE(vp);
return (error);
}
vap.va_mask = AT_MODE; /* get protection mode */
- (void) VOP_GETATTR(vp, &vap, 0, CRED());
+ (void) VOP_GETATTR(vp, &vap, 0, CRED(), NULL);
*mode = vap.va_mode;
dev = *pdev = vp->v_rdev;
@@ -1507,7 +1507,7 @@ hsfs_mountroot(struct vfs *vfsp, enum whymountroot why)
* multisession cd's.
*
* desc_sec is the same for high-sierra and iso 9660 formats, why
- * there are two differnt #defines used in the code for this is
+ * there are two different #defines used in the code for this is
* beyond me. These are standards, cast in concrete, right?
* To be general, however, this function supports passing in different
* values.
diff --git a/usr/src/uts/common/fs/hsfs/hsfs_vnops.c b/usr/src/uts/common/fs/hsfs/hsfs_vnops.c
index 29645bfe3e..bbd8afdd5a 100644
--- a/usr/src/uts/common/fs/hsfs/hsfs_vnops.c
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vnops.c
@@ -157,7 +157,10 @@ int hsched_invoke_strategy(struct hsfs *fsp);
/* ARGSUSED */
static int
-hsfs_fsync(vnode_t *cp, int syncflag, cred_t *cred)
+hsfs_fsync(vnode_t *cp,
+ int syncflag,
+ cred_t *cred,
+ caller_context_t *ct)
{
return (0);
}
@@ -165,7 +168,10 @@ hsfs_fsync(vnode_t *cp, int syncflag, cred_t *cred)
/*ARGSUSED*/
static int
-hsfs_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cred,
+hsfs_read(struct vnode *vp,
+ struct uio *uiop,
+ int ioflag,
+ struct cred *cred,
struct caller_context *ct)
{
caddr_t base;
@@ -299,7 +305,8 @@ hsfs_getattr(
struct vnode *vp,
struct vattr *vap,
int flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
struct hsnode *hp;
struct vfs *vfsp;
@@ -342,7 +349,10 @@ hsfs_getattr(
/*ARGSUSED*/
static int
-hsfs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
+hsfs_readlink(struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct hsnode *hp;
@@ -361,7 +371,9 @@ hsfs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
/*ARGSUSED*/
static void
-hsfs_inactive(struct vnode *vp, struct cred *cred)
+hsfs_inactive(struct vnode *vp,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct hsnode *hp;
struct hsfs *fsp;
@@ -427,7 +439,10 @@ hsfs_lookup(
struct pathname *pnp,
int flags,
struct vnode *rdir,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
int error;
int namelen = (int)strlen(nm);
@@ -456,10 +471,12 @@ hsfs_lookup(
/*ARGSUSED*/
static int
hsfs_readdir(
- struct vnode *vp,
- struct uio *uiop,
- struct cred *cred,
- int *eofp)
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cred,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct hsnode *dhp;
struct hsfs *fsp;
@@ -634,8 +651,9 @@ done:
return (error);
}
+/*ARGSUSED2*/
static int
-hsfs_fid(struct vnode *vp, struct fid *fidp)
+hsfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct hsnode *hp;
struct hsfid *fid;
@@ -658,7 +676,10 @@ hsfs_fid(struct vnode *vp, struct fid *fidp)
/*ARGSUSED*/
static int
-hsfs_open(struct vnode **vpp, int flag, struct cred *cred)
+hsfs_open(struct vnode **vpp,
+ int flag,
+ struct cred *cred,
+ caller_context_t *ct)
{
return (0);
}
@@ -670,7 +691,8 @@ hsfs_close(
int flag,
int count,
offset_t offset,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
(void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
cleanshares(vp, ttoproc(curthread)->p_pid);
@@ -679,7 +701,11 @@ hsfs_close(
/*ARGSUSED2*/
static int
-hsfs_access(struct vnode *vp, int mode, int flags, cred_t *cred)
+hsfs_access(struct vnode *vp,
+ int mode,
+ int flags,
+ cred_t *cred,
+ caller_context_t *ct)
{
return (hs_access(vp, (mode_t)mode, cred));
}
@@ -1531,6 +1557,7 @@ again:
return (err);
}
+/*ARGSUSED*/
static int
hsfs_getpage(
struct vnode *vp,
@@ -1542,7 +1569,8 @@ hsfs_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
int err;
uint_t filsiz;
@@ -1671,11 +1699,12 @@ hsfs_putapage(
/*ARGSUSED*/
static int
hsfs_putpage(
- struct vnode *vp,
- offset_t off,
- size_t len,
- int flags,
- struct cred *cr)
+ struct vnode *vp,
+ offset_t off,
+ size_t len,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
int error = 0;
@@ -1755,7 +1784,8 @@ hsfs_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error;
@@ -1821,7 +1851,8 @@ hsfs_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct hsnode *hp;
@@ -1846,7 +1877,8 @@ hsfs_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct hsnode *hp;
@@ -1863,7 +1895,11 @@ hsfs_delmap(
/* ARGSUSED */
static int
-hsfs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+hsfs_seek(
+ struct vnode *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
@@ -1877,7 +1913,8 @@ hsfs_frlock(
int flag,
offset_t offset,
struct flk_callback *flk_cbp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
struct hsnode *hp = VTOH(vp);
@@ -1892,7 +1929,7 @@ hsfs_frlock(
if (hp->hs_mapcnt > 0 && MANDLOCK(vp, hp->hs_dirent.mode))
return (EAGAIN);
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
static int
@@ -2360,7 +2397,11 @@ hsched_enqueue_io(struct hsfs *fsp, struct hio *hsio, int ra)
/* ARGSUSED */
static int
-hsfs_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
+hsfs_pathconf(struct vnode *vp,
+ int cmd,
+ ulong_t *valp,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct hsfs *fsp;
@@ -2378,7 +2419,7 @@ hsfs_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
break;
default:
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
return (error);
diff --git a/usr/src/uts/common/fs/lofs/lofs_vfsops.c b/usr/src/uts/common/fs/lofs/lofs_vfsops.c
index 8616e90cd6..8d654bcaeb 100644
--- a/usr/src/uts/common/fs/lofs/lofs_vfsops.c
+++ b/usr/src/uts/common/fs/lofs/lofs_vfsops.c
@@ -287,7 +287,7 @@ lo_mount(struct vfs *vfsp,
* intended filesystem, so we loopback mount the intended
* filesystem instead of the AUTOFS filesystem.
*/
- (void) VOP_ACCESS(realrootvp, 0, 0, cr);
+ (void) VOP_ACCESS(realrootvp, 0, 0, cr, NULL);
/*
* We're interested in the top most filesystem.
diff --git a/usr/src/uts/common/fs/lofs/lofs_vnops.c b/usr/src/uts/common/fs/lofs/lofs_vnops.c
index 85138187c1..dbe2c7a8b9 100644
--- a/usr/src/uts/common/fs/lofs/lofs_vnops.c
+++ b/usr/src/uts/common/fs/lofs/lofs_vnops.c
@@ -48,7 +48,7 @@
*/
static int
-lo_open(vnode_t **vpp, int flag, struct cred *cr)
+lo_open(vnode_t **vpp, int flag, struct cred *cr, caller_context_t *ct)
{
vnode_t *vp = *vpp;
vnode_t *rvp;
@@ -67,7 +67,7 @@ lo_open(vnode_t **vpp, int flag, struct cred *cr)
* decide to release it.
*/
VN_HOLD(vp);
- error = VOP_OPEN(&rvp, flag, cr);
+ error = VOP_OPEN(&rvp, flag, cr, ct);
if (!error && rvp != vp) {
/*
@@ -106,13 +106,14 @@ lo_close(
int flag,
int count,
offset_t offset,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_close vp %p realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_CLOSE(vp, flag, count, offset, cr));
+ return (VOP_CLOSE(vp, flag, count, offset, cr, ct));
}
static int
@@ -144,20 +145,21 @@ lo_ioctl(
intptr_t arg,
int flag,
struct cred *cr,
- int *rvalp)
+ int *rvalp,
+ caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_ioctl vp %p realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp));
+ return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp, ct));
}
static int
-lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_SETFL(vp, oflags, nflags, cr));
+ return (VOP_SETFL(vp, oflags, nflags, cr, ct));
}
static int
@@ -165,14 +167,15 @@ lo_getattr(
vnode_t *vp,
struct vattr *vap,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
int error;
#ifdef LODEBUG
lo_dprint(4, "lo_getattr vp %p realvp %p\n", vp, realvp(vp));
#endif
- if (error = VOP_GETATTR(realvp(vp), vap, flags, cr))
+ if (error = VOP_GETATTR(realvp(vp), vap, flags, cr, ct))
return (error);
return (0);
@@ -194,7 +197,12 @@ lo_setattr(
}
static int
-lo_access(vnode_t *vp, int mode, int flags, struct cred *cr)
+lo_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_access vp %p realvp %p\n", vp, realvp(vp));
@@ -204,22 +212,22 @@ lo_access(vnode_t *vp, int mode, int flags, struct cred *cr)
return (EROFS);
}
vp = realvp(vp);
- return (VOP_ACCESS(vp, mode, flags, cr));
+ return (VOP_ACCESS(vp, mode, flags, cr, ct));
}
static int
-lo_fsync(vnode_t *vp, int syncflag, struct cred *cr)
+lo_fsync(vnode_t *vp, int syncflag, struct cred *cr, caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_fsync vp %p realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_FSYNC(vp, syncflag, cr));
+ return (VOP_FSYNC(vp, syncflag, cr, ct));
}
/*ARGSUSED*/
static void
-lo_inactive(vnode_t *vp, struct cred *cr)
+lo_inactive(vnode_t *vp, struct cred *cr, caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_inactive %p, realvp %p\n", vp, realvp(vp));
@@ -229,13 +237,13 @@ lo_inactive(vnode_t *vp, struct cred *cr)
/* ARGSUSED */
static int
-lo_fid(vnode_t *vp, struct fid *fidp)
+lo_fid(vnode_t *vp, struct fid *fidp, caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_fid %p, realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_FID(vp, fidp));
+ return (VOP_FID(vp, fidp, ct));
}
/*
@@ -288,7 +296,10 @@ lo_lookup(
struct pathname *pnp,
int flags,
vnode_t *rdir,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
vnode_t *vp = NULL, *tvp = NULL, *nonlovp;
int error, is_indirectloop;
@@ -327,7 +338,8 @@ lo_lookup(
/*
* Do the normal lookup
*/
- if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr)) {
+ if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr,
+ ct, direntflags, realpnp)) {
vp = NULL;
goto out;
}
@@ -657,7 +669,9 @@ lo_create(
int mode,
vnode_t **vpp,
struct cred *cr,
- int flag)
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
vnode_t *vp = NULL;
@@ -670,7 +684,8 @@ lo_create(
vp = realvp(*vpp);
}
- error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag);
+ error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag,
+ ct, vsecp);
if (!error) {
*vpp = makelonode(vp, vtoli(dvp->v_vfsp), 0);
if (IS_DEVVP(*vpp)) {
@@ -688,17 +703,28 @@ lo_create(
}
static int
-lo_remove(vnode_t *dvp, char *nm, struct cred *cr)
+lo_remove(
+ vnode_t *dvp,
+ char *nm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
#ifdef LODEBUG
lo_dprint(4, "lo_remove vp %p realvp %p\n", dvp, realvp(dvp));
#endif
dvp = realvp(dvp);
- return (VOP_REMOVE(dvp, nm, cr));
+ return (VOP_REMOVE(dvp, nm, cr, ct, flags));
}
static int
-lo_link(vnode_t *tdvp, vnode_t *vp, char *tnm, struct cred *cr)
+lo_link(
+ vnode_t *tdvp,
+ vnode_t *vp,
+ char *tnm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *realvp;
@@ -737,7 +763,7 @@ lo_link(vnode_t *tdvp, vnode_t *vp, char *tnm, struct cred *cr)
*
* We use VOP_REALVP here to continue the search.
*/
- if (VOP_REALVP(vp, &realvp) == 0)
+ if (VOP_REALVP(vp, &realvp, ct) == 0)
vp = realvp;
while (vn_matchops(tdvp, lo_vnodeops)) {
@@ -745,7 +771,7 @@ lo_link(vnode_t *tdvp, vnode_t *vp, char *tnm, struct cred *cr)
}
if (vp->v_vfsp != tdvp->v_vfsp)
return (EXDEV);
- return (VOP_LINK(tdvp, vp, tnm, cr));
+ return (VOP_LINK(tdvp, vp, tnm, cr, ct, flags));
}
static int
@@ -754,7 +780,9 @@ lo_rename(
char *onm,
vnode_t *ndvp,
char *nnm,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *tnvp;
@@ -789,7 +817,13 @@ lo_rename(
*/
if (vn_matchops(ndvp, lo_vnodeops)) /* Not our problem. */
goto rename;
- if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr) != 0)
+
+ /*
+ * XXXci - Once case-insensitive behavior is implemented, it should
+ * be added here.
+ */
+ if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr,
+ ct, NULL, NULL) != 0)
goto rename;
if (tnvp->v_type != VDIR) {
VN_RELE(tnvp);
@@ -822,7 +856,7 @@ rename:
if (odvp->v_vfsp != ndvp->v_vfsp)
return (EXDEV);
}
- return (VOP_RENAME(odvp, onm, ndvp, nnm, cr));
+ return (VOP_RENAME(odvp, onm, ndvp, nnm, cr, ct, flags));
}
static int
@@ -831,21 +865,24 @@ lo_mkdir(
char *nm,
struct vattr *va,
vnode_t **vpp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
int error;
#ifdef LODEBUG
lo_dprint(4, "lo_mkdir vp %p realvp %p\n", dvp, realvp(dvp));
#endif
- error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr);
+ error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr, ct, flags, vsecp);
if (!error)
*vpp = makelonode(*vpp, vtoli(dvp->v_vfsp), 0);
return (error);
}
static int
-lo_realvp(vnode_t *vp, vnode_t **vpp)
+lo_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_realvp %p\n", vp);
@@ -853,7 +890,7 @@ lo_realvp(vnode_t *vp, vnode_t **vpp)
while (vn_matchops(vp, lo_vnodeops))
vp = realvp(vp);
- if (VOP_REALVP(vp, vpp) != 0)
+ if (VOP_REALVP(vp, vpp, ct) != 0)
*vpp = vp;
return (0);
}
@@ -863,7 +900,9 @@ lo_rmdir(
vnode_t *dvp,
char *nm,
vnode_t *cdir,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *rvp = cdir;
@@ -872,9 +911,9 @@ lo_rmdir(
#endif
/* if cdir is lofs vnode ptr get its real vnode ptr */
if (vn_matchops(dvp, vn_getops(rvp)))
- (void) lo_realvp(cdir, &rvp);
+ (void) lo_realvp(cdir, &rvp, ct);
dvp = realvp(dvp);
- return (VOP_RMDIR(dvp, nm, rvp, cr));
+ return (VOP_RMDIR(dvp, nm, rvp, cr, ct, flags));
}
static int
@@ -883,30 +922,42 @@ lo_symlink(
char *lnm,
struct vattr *tva,
char *tnm,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
#ifdef LODEBUG
lo_dprint(4, "lo_symlink vp %p realvp %p\n", dvp, realvp(dvp));
#endif
dvp = realvp(dvp);
- return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr));
+ return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr, ct, flags));
}
static int
-lo_readlink(vnode_t *vp, struct uio *uiop, struct cred *cr)
+lo_readlink(
+ vnode_t *vp,
+ struct uio *uiop,
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_READLINK(vp, uiop, cr));
+ return (VOP_READLINK(vp, uiop, cr, ct));
}
static int
-lo_readdir(vnode_t *vp, struct uio *uiop, struct cred *cr, int *eofp)
+lo_readdir(
+ vnode_t *vp,
+ struct uio *uiop,
+ struct cred *cr,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
#ifdef LODEBUG
lo_dprint(4, "lo_readdir vp %p realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_READDIR(vp, uiop, cr, eofp));
+ return (VOP_READDIR(vp, uiop, cr, eofp, ct, flags));
}
static int
@@ -924,20 +975,20 @@ lo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
}
static int
-lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_SEEK(vp, ooff, noffp));
+ return (VOP_SEEK(vp, ooff, noffp, ct));
}
static int
-lo_cmp(vnode_t *vp1, vnode_t *vp2)
+lo_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
while (vn_matchops(vp1, lo_vnodeops))
vp1 = realvp(vp1);
while (vn_matchops(vp2, lo_vnodeops))
vp2 = realvp(vp2);
- return (VOP_CMP(vp1, vp2));
+ return (VOP_CMP(vp1, vp2, ct));
}
static int
@@ -948,10 +999,11 @@ lo_frlock(
int flag,
offset_t offset,
struct flk_callback *flk_cbp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
static int
@@ -979,17 +1031,25 @@ lo_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr));
+ return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr,
+ ct));
}
static int
-lo_putpage(vnode_t *vp, offset_t off, size_t len, int flags, struct cred *cr)
+lo_putpage(
+ vnode_t *vp,
+ offset_t off,
+ size_t len,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_PUTPAGE(vp, off, len, flags, cr));
+ return (VOP_PUTPAGE(vp, off, len, flags, cr, ct));
}
static int
@@ -1002,10 +1062,11 @@ lo_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr));
+ return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr, ct));
}
static int
@@ -1018,10 +1079,12 @@ lo_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr));
+ return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr,
+ ct));
}
static int
@@ -1034,10 +1097,12 @@ lo_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr));
+ return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr,
+ ct));
}
static int
@@ -1046,24 +1111,30 @@ lo_poll(
short events,
int anyyet,
short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_POLL(vp, events, anyyet, reventsp, phpp));
+ return (VOP_POLL(vp, events, anyyet, reventsp, phpp, ct));
}
static int
-lo_dump(vnode_t *vp, caddr_t addr, int bn, int count)
+lo_dump(vnode_t *vp, caddr_t addr, int bn, int count, caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_DUMP(vp, addr, bn, count));
+ return (VOP_DUMP(vp, addr, bn, count, ct));
}
static int
-lo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, struct cred *cr)
+lo_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_PATHCONF(vp, cmd, valp, cr));
+ return (VOP_PATHCONF(vp, cmd, valp, cr, ct));
}
static int
@@ -1073,41 +1144,64 @@ lo_pageio(
u_offset_t io_off,
size_t io_len,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr));
+ return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct));
}
static void
-lo_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
+lo_dispose(
+ vnode_t *vp,
+ page_t *pp,
+ int fl,
+ int dn,
+ cred_t *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
if (vp != NULL && !VN_ISKAS(vp))
- VOP_DISPOSE(vp, pp, fl, dn, cr);
+ VOP_DISPOSE(vp, pp, fl, dn, cr, ct);
}
static int
-lo_setsecattr(vnode_t *vp, vsecattr_t *secattr, int flags, struct cred *cr)
+lo_setsecattr(
+ vnode_t *vp,
+ vsecattr_t *secattr,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
if (vn_is_readonly(vp))
return (EROFS);
vp = realvp(vp);
- return (VOP_SETSECATTR(vp, secattr, flags, cr));
+ return (VOP_SETSECATTR(vp, secattr, flags, cr, ct));
}
static int
-lo_getsecattr(vnode_t *vp, vsecattr_t *secattr, int flags, struct cred *cr)
+lo_getsecattr(
+ vnode_t *vp,
+ vsecattr_t *secattr,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_GETSECATTR(vp, secattr, flags, cr));
+ return (VOP_GETSECATTR(vp, secattr, flags, cr, ct));
}
static int
-lo_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+lo_shrlock(
+ vnode_t *vp,
+ int cmd,
+ struct shrlock *shr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_SHRLOCK(vp, cmd, shr, flag, cr));
+ return (VOP_SHRLOCK(vp, cmd, shr, flag, cr, ct));
}
/*
diff --git a/usr/src/uts/common/fs/lookup.c b/usr/src/uts/common/fs/lookup.c
index 8ef37c4313..d30a358283 100644
--- a/usr/src/uts/common/fs/lookup.c
+++ b/usr/src/uts/common/fs/lookup.c
@@ -209,6 +209,8 @@ lookuppnvp(
int error;
int nlink;
int lookup_flags;
+ struct pathname presrvd; /* case preserved name */
+ struct pathname *pp = NULL;
vnode_t *startvp;
vnode_t *zonevp = curproc->p_zone->zone_rootvp; /* zone root */
int must_be_directory = 0;
@@ -219,7 +221,14 @@ lookuppnvp(
cvp = NULL;
if (rpnp)
rpnp->pn_pathlen = 0;
+
lookup_flags = dirvpp ? LOOKUP_DIR : 0;
+ if (flags & FIGNORECASE) {
+ lookup_flags |= FIGNORECASE;
+ pn_alloc(&presrvd);
+ pp = &presrvd;
+ }
+
#ifdef C2_AUDIT
if (audit_active)
audit_anchorpath(pnp, vp == rootvp);
@@ -319,6 +328,8 @@ checkforroot:
(cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
vfs_unlock(vfsp);
VN_RELE(cvp);
+ if (pp)
+ pn_free(pp);
return (EIO);
}
VN_HOLD(vp);
@@ -346,14 +357,14 @@ checkforroot:
* be found.
*/
if ((flags & LOOKUP_CHECKREAD) &&
- (error = VOP_ACCESS(vp, VREAD, 0, cr)) != 0)
+ (error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0)
goto bad;
/*
* Perform a lookup in the current directory.
*/
error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags,
- rootvp, cr);
+ rootvp, cr, NULL, NULL, pp);
/*
* Retry with kcred - If crossing mount points & error is EACCES.
@@ -371,7 +382,7 @@ checkforroot:
*/
if ((error == EACCES) && retry_with_kcred)
error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags,
- rootvp, zone_kcred());
+ rootvp, zone_kcred(), NULL, NULL, pp);
cvp = tvp;
if (error) {
@@ -402,6 +413,8 @@ checkforroot:
*compvpp = NULL;
if (rootvp != rootdir)
VN_RELE(rootvp);
+ if (pp)
+ pn_free(pp);
return (0);
}
@@ -521,9 +534,19 @@ checkforroot:
if (rpnp->pn_pathlen != 0 &&
rpnp->pn_path[rpnp->pn_pathlen-1] != '/')
rpnp->pn_path[rpnp->pn_pathlen++] = '/';
- error = copystr(component,
- rpnp->pn_path + rpnp->pn_pathlen,
- rpnp->pn_bufsize - rpnp->pn_pathlen, &len);
+ if (flags & FIGNORECASE) {
+ /*
+ * Return the case-preserved name
+ * within the resolved path.
+ */
+ error = copystr(pp->pn_path,
+ rpnp->pn_path + rpnp->pn_pathlen,
+ rpnp->pn_bufsize - rpnp->pn_pathlen, &len);
+ } else {
+ error = copystr(component,
+ rpnp->pn_path + rpnp->pn_pathlen,
+ rpnp->pn_bufsize - rpnp->pn_pathlen, &len);
+ }
if (error) /* copystr() returns ENAMETOOLONG */
goto bad;
rpnp->pn_pathlen += (len - 1);
@@ -560,6 +583,8 @@ checkforroot:
VN_RELE(cvp);
if (rootvp != rootdir)
VN_RELE(rootvp);
+ if (pp)
+ pn_free(pp);
return (EINVAL);
}
#ifdef C2_AUDIT
@@ -592,6 +617,8 @@ checkforroot:
VN_RELE(cvp);
if (rootvp != rootdir)
VN_RELE(rootvp);
+ if (pp)
+ pn_free(pp);
return (0);
}
@@ -649,6 +676,8 @@ bad_noaudit:
VN_RELE(vp);
if (rootvp != rootdir)
VN_RELE(rootvp);
+ if (pp)
+ pn_free(pp);
return (error);
}
@@ -791,15 +820,15 @@ vnode_match(vnode_t *v1, vnode_t *v2, cred_t *cr)
* are currently in '/proc/self/fd', then '/proc/self/cwd' will compare
* as the same vnode.
*/
- if (VOP_GETATTR(v1, &v1attr, 0, cr) != 0 ||
- VOP_GETATTR(v2, &v2attr, 0, cr) != 0 ||
+ if (VOP_GETATTR(v1, &v1attr, 0, cr, NULL) != 0 ||
+ VOP_GETATTR(v2, &v2attr, 0, cr, NULL) != 0 ||
v1attr.va_type == VLNK || v2attr.va_type == VLNK)
return (0);
v1attr.va_mask = v2attr.va_mask = AT_TYPE | AT_FSID | AT_NODEID;
- if (VOP_GETATTR(v1, &v1attr, ATTR_REAL, cr) != 0 ||
- VOP_GETATTR(v2, &v2attr, ATTR_REAL, cr) != 0)
+ if (VOP_GETATTR(v1, &v1attr, ATTR_REAL, cr, NULL) != 0 ||
+ VOP_GETATTR(v2, &v2attr, ATTR_REAL, cr, NULL) != 0)
return (0);
return (v1attr.va_fsid == v2attr.va_fsid &&
@@ -839,7 +868,7 @@ dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
uio.uio_extflg = UIO_COPY_CACHED;
uio.uio_loffset = 0;
- if ((error = VOP_ACCESS(dvp, VREAD, 0, cr)) != 0)
+ if ((error = VOP_ACCESS(dvp, VREAD, 0, cr, NULL)) != 0)
return (error);
while (!eof) {
@@ -848,7 +877,7 @@ dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
iov.iov_len = dlen;
(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dvp, &uio, cr, &eof);
+ error = VOP_READDIR(dvp, &uio, cr, &eof, NULL, 0);
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -869,7 +898,7 @@ dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
}
error = VOP_LOOKUP(dvp, dp->d_name, &cmpvp, &pnp, 0,
- vrootp, cr);
+ vrootp, cr, NULL, NULL, NULL);
/*
* We only want to bail out if there was an error other
@@ -900,7 +929,8 @@ dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
* rare conditions (races and the special .zfs directory).
*/
if (error == 0) {
- error = VOP_LOOKUP(dvp, ".zfs", &cmpvp, &pnp, 0, vrootp, cr);
+ error = VOP_LOOKUP(dvp, ".zfs", &cmpvp, &pnp, 0, vrootp, cr,
+ NULL, NULL, NULL);
if (error == 0) {
if (vnode_match(tvp, cmpvp, cr)) {
(void) strcpy(dp->d_name, ".zfs");
@@ -955,7 +985,8 @@ localpath(char *path, struct vnode *vrootp, cred_t *cr)
if (vn_ismntpt(vp) && traverse(&vp) != 0)
break;
- if (VOP_LOOKUP(vp, component, &cvp, &pn, 0, rootdir, cr) != 0)
+ if (VOP_LOOKUP(vp, component, &cvp, &pn, 0, rootdir, cr,
+ NULL, NULL, NULL) != 0)
break;
VN_RELE(vp);
@@ -1087,8 +1118,8 @@ dirtopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr)
*/
if (vp->v_flag & VROOT)
vp = vn_under(vp);
- if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr))
- != 0)
+ if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr,
+ NULL, NULL, NULL)) != 0)
goto out;
/*
@@ -1210,10 +1241,10 @@ vnodetopath_common(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen,
* lofs. The only difference between procfs and lofs is that opening
* the file will return the underling vnode in the case of procfs.
*/
- if (vp->v_type == VDIR && VOP_REALVP(vp, &realvp) == 0 &&
+ if (vp->v_type == VDIR && VOP_REALVP(vp, &realvp, NULL) == 0 &&
realvp != vp) {
VN_HOLD(vp);
- if (VOP_OPEN(&vp, FREAD, cr) == 0)
+ if (VOP_OPEN(&vp, FREAD, cr, NULL) == 0)
doclose = 1;
else
VN_RELE(vp);
@@ -1314,7 +1345,7 @@ vnodetopath_common(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen,
pn_free(&rpn);
VN_RELE(vrootp);
if (doclose) {
- (void) VOP_CLOSE(vp, FREAD, 1, 0, cr);
+ (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
VN_RELE(vp);
}
return (0);
@@ -1356,7 +1387,7 @@ notcached:
VN_RELE(vrootp);
if (doclose) {
- (void) VOP_CLOSE(vp, FREAD, 1, 0, cr);
+ (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
VN_RELE(vp);
}
@@ -1394,7 +1425,7 @@ dogetcwd(char *buf, size_t buflen)
/*
* Make sure we have permission to access the current directory.
*/
- if ((ret = VOP_ACCESS(vp, VEXEC, 0, CRED())) != 0) {
+ if ((ret = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL)) != 0) {
if (cwd != NULL)
refstr_rele(cwd);
VN_RELE(vp);
diff --git a/usr/src/uts/common/fs/mntfs/mntvnops.c b/usr/src/uts/common/fs/mntfs/mntvnops.c
index 9083d5c5b2..9e519167cf 100644
--- a/usr/src/uts/common/fs/mntfs/mntvnops.c
+++ b/usr/src/uts/common/fs/mntfs/mntvnops.c
@@ -670,7 +670,7 @@ mntfs_getmntopts(struct vfs *vfsp, char **bufp, size_t *lenp)
/* ARGSUSED */
static int
-mntopen(vnode_t **vpp, int flag, cred_t *cr)
+mntopen(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *vp = *vpp;
mntnode_t *nmnp;
@@ -694,7 +694,8 @@ mntopen(vnode_t **vpp, int flag, cred_t *cr)
/* ARGSUSED */
static int
-mntclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+mntclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
@@ -767,7 +768,8 @@ mntread(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, caller_context_t *ct)
static int
-mntgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+mntgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
int error;
@@ -786,7 +788,7 @@ mntgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/*
* Attributes are same as underlying file with modifications
*/
- if (error = VOP_GETATTR(rvp, vap, flags, cr))
+ if (error = VOP_GETATTR(rvp, vap, flags, cr, ct))
return (error);
/*
@@ -830,7 +832,8 @@ mntgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
static int
-mntaccess(vnode_t *vp, int mode, int flags, cred_t *cr)
+mntaccess(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
@@ -840,7 +843,7 @@ mntaccess(vnode_t *vp, int mode, int flags, cred_t *cr)
/*
* Do access check on the underlying directory vnode.
*/
- return (VOP_ACCESS(mnp->mnt_mountvp, mode, flags, cr));
+ return (VOP_ACCESS(mnp->mnt_mountvp, mode, flags, cr, ct));
}
@@ -882,14 +885,14 @@ mntfreenode(mntnode_t *mnp)
/* ARGSUSED */
static int
-mntfsync(vnode_t *vp, int syncflag, cred_t *cr)
+mntfsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static void
-mntinactive(vnode_t *vp, cred_t *cr)
+mntinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
@@ -898,7 +901,8 @@ mntinactive(vnode_t *vp, cred_t *cr)
/* ARGSUSED */
static int
-mntseek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+mntseek(vnode_t *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
if (*noffp == 0)
VTOM(vp)->mnt_offset = 0;
@@ -913,7 +917,8 @@ mntseek(vnode_t *vp, offset_t ooff, offset_t *noffp)
*/
/* ARGSUSED */
static int
-mntpoll(vnode_t *vp, short ev, int any, short *revp, pollhead_t **phpp)
+mntpoll(vnode_t *vp, short ev, int any, short *revp, pollhead_t **phpp,
+ caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
mntsnap_t *snap = &mnp->mnt_read;
@@ -951,7 +956,7 @@ mntpoll(vnode_t *vp, short ev, int any, short *revp, pollhead_t **phpp)
/* ARGSUSED */
static int
mntioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+ cred_t *cr, int *rvalp, caller_context_t *ct)
{
uint_t *up = (uint_t *)arg;
mntnode_t *mnp = VTOM(vp);
diff --git a/usr/src/uts/common/fs/namefs/namevfs.c b/usr/src/uts/common/fs/namefs/namevfs.c
index 88bafaa135..a6a4e083a6 100644
--- a/usr/src/uts/common/fs/namefs/namevfs.c
+++ b/usr/src/uts/common/fs/namefs/namevfs.c
@@ -357,7 +357,7 @@ nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
*/
rvp = NULLVP;
if (vn_matchops(mvp, spec_getvnodeops()) &&
- VOP_REALVP(mvp, &rvp) == 0 && rvp &&
+ VOP_REALVP(mvp, &rvp, NULL) == 0 && rvp &&
vn_matchops(rvp, devpts_getvnodeops())) {
releasef(namefdp.fd);
return (ENOTSUP);
@@ -397,11 +397,11 @@ nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
mutex_init(&nodep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
vattrp = &nodep->nm_vattr;
vattrp->va_mask = AT_ALL;
- if (error = VOP_GETATTR(mvp, vattrp, 0, crp))
+ if (error = VOP_GETATTR(mvp, vattrp, 0, crp, NULL))
goto out;
filevattr.va_mask = AT_ALL;
- if (error = VOP_GETATTR(filevp, &filevattr, 0, crp))
+ if (error = VOP_GETATTR(filevp, &filevattr, 0, crp, NULL))
goto out;
/*
* Make sure the user is the owner of the mount point
@@ -652,7 +652,7 @@ nm_sync(vfs_t *vfsp, short flag, cred_t *crp)
if (flag & SYNC_CLOSE)
return (nm_umountall(nodep->nm_filevp, crp));
- return (VOP_FSYNC(nodep->nm_filevp, FSYNC, crp));
+ return (VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, NULL));
}
/*
diff --git a/usr/src/uts/common/fs/namefs/namevno.c b/usr/src/uts/common/fs/namefs/namevno.c
index ab4767e578..f62af2b7f2 100644
--- a/usr/src/uts/common/fs/namefs/namevno.c
+++ b/usr/src/uts/common/fs/namefs/namevno.c
@@ -77,7 +77,7 @@
* file system, with the parent being the initial mount.
*/
int
-nm_open(vnode_t **vpp, int flag, cred_t *crp)
+nm_open(vnode_t **vpp, int flag, cred_t *crp, caller_context_t *ct)
{
struct namenode *nodep = VTONM(*vpp);
int error = 0;
@@ -95,7 +95,7 @@ nm_open(vnode_t **vpp, int flag, cred_t *crp)
infilevp = outfilevp = nodep->nm_filevp;
VN_HOLD(outfilevp);
- if ((error = VOP_OPEN(&outfilevp, flag, crp)) != 0) {
+ if ((error = VOP_OPEN(&outfilevp, flag, crp, ct)) != 0) {
VN_RELE(outfilevp);
return (error);
}
@@ -163,16 +163,17 @@ gotit:
* the file descriptor.
*/
static int
-nm_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp)
+nm_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp,
+ caller_context_t *ct)
{
struct namenode *nodep = VTONM(vp);
int error = 0;
(void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
cleanshares(vp, ttoproc(curthread)->p_pid);
- error = VOP_CLOSE(nodep->nm_filevp, flag, count, offset, crp);
+ error = VOP_CLOSE(nodep->nm_filevp, flag, count, offset, crp, ct);
if (count == 1) {
- (void) VOP_FSYNC(nodep->nm_filevp, FSYNC, crp);
+ (void) VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, ct);
/*
* Before VN_RELE() we need to remove the vnode from
* the hash table. We should only do so in the NMNMNT case.
@@ -205,9 +206,10 @@ nm_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *crp,
}
static int
-nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp)
+nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp,
+ caller_context_t *ct)
{
- return (VOP_IOCTL(VTONM(vp)->nm_filevp, cmd, arg, mode, cr, rvalp));
+ return (VOP_IOCTL(VTONM(vp)->nm_filevp, cmd, arg, mode, cr, rvalp, ct));
}
/*
@@ -216,7 +218,8 @@ nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp)
*/
/* ARGSUSED */
static int
-nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
+nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
+ caller_context_t *ct)
{
struct namenode *nodep = VTONM(vp);
struct vattr va;
@@ -227,7 +230,7 @@ nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
mutex_exit(&nodep->nm_lock);
if ((va.va_mask = vap->va_mask & AT_SIZE) != 0) {
- if (error = VOP_GETATTR(nodep->nm_filevp, &va, flags, crp))
+ if (error = VOP_GETATTR(nodep->nm_filevp, &va, flags, crp, ct))
return (error);
vap->va_size = va.va_size;
}
@@ -336,7 +339,8 @@ out:
*/
/* ARGSUSED */
static int
-nm_access(vnode_t *vp, int mode, int flags, cred_t *crp)
+nm_access(vnode_t *vp, int mode, int flags, cred_t *crp,
+ caller_context_t *ct)
{
struct namenode *nodep = VTONM(vp);
int error;
@@ -345,7 +349,7 @@ nm_access(vnode_t *vp, int mode, int flags, cred_t *crp)
error = nm_access_unlocked(nodep, mode, crp);
mutex_exit(&nodep->nm_lock);
if (error == 0)
- return (VOP_ACCESS(nodep->nm_filevp, mode, flags, crp));
+ return (VOP_ACCESS(nodep->nm_filevp, mode, flags, crp, ct));
else
return (error);
}
@@ -358,13 +362,14 @@ nm_access(vnode_t *vp, int mode, int flags, cred_t *crp)
/*ARGSUSED*/
static int
nm_create(vnode_t *dvp, char *name, vattr_t *vap, enum vcexcl excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
ASSERT(dvp && *name == '\0');
if (excl == NONEXCL) {
- if (mode && (error = nm_access(dvp, mode, 0, cr)) != 0)
+ if (mode && (error = nm_access(dvp, mode, 0, cr, ct)) != 0)
return (error);
VN_HOLD(dvp);
return (0);
@@ -377,21 +382,22 @@ nm_create(vnode_t *dvp, char *name, vattr_t *vap, enum vcexcl excl,
*/
/*ARGSUSED*/
static int
-nm_link(vnode_t *tdvp, vnode_t *vp, char *tnm, cred_t *crp)
+nm_link(vnode_t *tdvp, vnode_t *vp, char *tnm, cred_t *crp,
+ caller_context_t *ct, int flags)
{
return (EXDEV);
}
static int
-nm_fsync(vnode_t *vp, int syncflag, cred_t *crp)
+nm_fsync(vnode_t *vp, int syncflag, cred_t *crp, caller_context_t *ct)
{
- return (VOP_FSYNC(VTONM(vp)->nm_filevp, syncflag, crp));
+ return (VOP_FSYNC(VTONM(vp)->nm_filevp, syncflag, crp, ct));
}
/* Free the namenode */
/* ARGSUSED */
static void
-nm_inactive(vnode_t *vp, cred_t *crp)
+nm_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
{
struct namenode *nodep = VTONM(vp);
@@ -413,9 +419,9 @@ nm_inactive(vnode_t *vp, cred_t *crp)
}
static int
-nm_fid(vnode_t *vp, struct fid *fidnodep)
+nm_fid(vnode_t *vp, struct fid *fidnodep, caller_context_t *ct)
{
- return (VOP_FID(VTONM(vp)->nm_filevp, fidnodep));
+ return (VOP_FID(VTONM(vp)->nm_filevp, fidnodep, ct));
}
static int
@@ -431,21 +437,21 @@ nm_rwunlock(vnode_t *vp, int write, caller_context_t *ctp)
}
static int
-nm_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+nm_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
- return (VOP_SEEK(VTONM(vp)->nm_filevp, ooff, noffp));
+ return (VOP_SEEK(VTONM(vp)->nm_filevp, ooff, noffp, ct));
}
/*
* Return the vnode representing the file descriptor in vpp.
*/
static int
-nm_realvp(vnode_t *vp, vnode_t **vpp)
+nm_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
struct vnode *rvp;
vp = VTONM(vp)->nm_filevp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
*vpp = vp;
return (0);
@@ -453,9 +459,10 @@ nm_realvp(vnode_t *vp, vnode_t **vpp)
static int
nm_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **phpp)
+ pollhead_t **phpp, caller_context_t *ct)
{
- return (VOP_POLL(VTONM(vp)->nm_filevp, events, anyyet, reventsp, phpp));
+ return (VOP_POLL(VTONM(vp)->nm_filevp, events, anyyet, reventsp,
+ phpp, ct));
}
struct vnodeops *nm_vnodeops;
diff --git a/usr/src/uts/common/fs/nbmlock.c b/usr/src/uts/common/fs/nbmlock.c
index bb9dd88722..add00c6b1f 100644
--- a/usr/src/uts/common/fs/nbmlock.c
+++ b/usr/src/uts/common/fs/nbmlock.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -133,13 +132,14 @@ 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 */
+ int svmand, /* System V mandatory locking */
+ caller_context_t *ct) /* caller context */
{
ASSERT(nbl_in_crit(vp));
ASSERT(op == NBL_READ || op == NBL_WRITE || op == NBL_RENAME ||
op == NBL_REMOVE || op == NBL_READWRITE);
- if (nbl_share_conflict(vp, op)) {
+ if (nbl_share_conflict(vp, op, ct)) {
return (1);
}
@@ -150,7 +150,7 @@ nbl_conflict(vnode_t *vp,
if (op == NBL_REMOVE || op == NBL_RENAME)
return (0);
- return (nbl_lock_conflict(vp, op, offset, length, svmand));
+ return (nbl_lock_conflict(vp, op, offset, length, svmand, ct));
}
/*
@@ -167,7 +167,7 @@ nbl_svmand(vnode_t *vp, cred_t *cr, int *svp)
int error;
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error != 0)
return (error);
diff --git a/usr/src/uts/common/fs/nfs/nfs3_srv.c b/usr/src/uts/common/fs/nfs/nfs3_srv.c
index 4f8276d75f..0660a85e59 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c
@@ -262,7 +262,8 @@ rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
offset = bva.va_size;
length = ava.va_size - bva.va_size;
}
- if (nbl_conflict(vp, NBL_WRITE, offset, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -298,7 +299,7 @@ rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
if (error)
goto out;
@@ -369,11 +370,11 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dva.va_mask = AT_ALL;
- dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva;
+ dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
}
#else
dva.va_mask = AT_ALL;
- dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva;
+ dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
#endif
if (args->what.name == nfs3nametoolong) {
@@ -438,7 +439,7 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
}
} else {
error = VOP_LOOKUP(dvp, args->what.name, &vp,
- NULL, 0, NULL, cr);
+ NULL, 0, NULL, cr, NULL, NULL, NULL);
}
if (is_system_labeled() && error == 0) {
@@ -463,12 +464,12 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dva.va_mask = AT_ALL;
- dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva;
+ dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
} else
dvap = NULL;
#else
dva.va_mask = AT_ALL;
- dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva;
+ dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
#endif
if (error)
@@ -585,7 +586,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
* as well be reflected to the server during the open.
*/
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error)
goto out;
@@ -618,7 +619,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
}
if (args->access & ACCESS3_READ) {
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -628,7 +629,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
resp->resok.access |= ACCESS3_READ;
}
if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -638,7 +639,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
}
if (checkwriteperm &&
(args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -650,7 +651,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
}
if (checkwriteperm &&
(args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -659,7 +660,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
resp->resok.access |= ACCESS3_DELETE;
}
if (args->access & ACCESS3_EXECUTE) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -726,7 +727,7 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
}
va.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error)
goto out;
@@ -773,17 +774,17 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
uio.uio_loffset = 0;
uio.uio_resid = MAXPATHLEN;
- error = VOP_READLINK(vp, &uio, cr);
+ error = VOP_READLINK(vp, &uio, cr, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
#if 0 /* notyet */
@@ -795,7 +796,7 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
if (error) {
@@ -895,7 +896,8 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0)) {
+ if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -905,7 +907,7 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
need_rwunlock = 1;
va.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
/*
* If we can't get the attributes, then we can't do the
@@ -927,11 +929,11 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
}
if (crgetuid(cr) != va.va_uid) {
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (error)
goto out;
}
@@ -1008,7 +1010,7 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
}
va.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
@@ -1036,7 +1038,7 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
if (in_crit)
@@ -1160,7 +1162,8 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -1169,7 +1172,7 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
bva.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &bva, 0, cr);
+ error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
/*
* If we can't get the attributes, then we can't do the
@@ -1201,7 +1204,7 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
}
if (crgetuid(cr) != bva.va_uid &&
- (error = VOP_ACCESS(vp, VWRITE, 0, cr)))
+ (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
goto out;
if (MANDLOCK(vp, bva.va_mode)) {
@@ -1282,7 +1285,7 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
kmem_free(iovp, sizeof (*iovp) * iovcnt);
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
#ifdef DEBUG
if (!rfs3_do_post_op_attr)
@@ -1375,12 +1378,12 @@ rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
} else
dbvap = NULL;
#else
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
#endif
davap = dbvap;
@@ -1452,7 +1455,7 @@ rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
* Does file already exist?
*/
error = VOP_LOOKUP(dvp, args->where.name, &tvp,
- NULL, 0, NULL, cr);
+ NULL, 0, NULL, cr, NULL, NULL, NULL);
/*
* Check to see if the file has been delegated
@@ -1479,7 +1482,8 @@ rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
in_crit = 1;
tva.va_mask = AT_SIZE;
- error = VOP_GETATTR(tvp, &tva, 0, cr);
+ error = VOP_GETATTR(tvp, &tva, 0, cr,
+ NULL);
/*
* Can't check for conflicts, so return
* error.
@@ -1493,7 +1497,7 @@ rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
va.va_size - tva.va_size :
tva.va_size - va.va_size;
if (nbl_conflict(tvp, NBL_WRITE,
- offset, len, 0)) {
+ offset, len, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1530,17 +1534,17 @@ tryagain:
* passed as part of the arguments.
*/
error = VOP_CREATE(dvp, args->where.name, &va, excl, VWRITE,
- &vp, cr, 0);
+ &vp, cr, 0, NULL, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
} else
davap = NULL;
#else
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
#endif
if (error) {
@@ -1561,7 +1565,7 @@ tryagain:
* Lookup the file so that we can get a vnode for it.
*/
error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error) {
/*
* We couldn't find the file that we thought that
@@ -1586,7 +1590,7 @@ tryagain:
}
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
mtime = (nfstime3 *)&args->how.createhow3_u.verf;
/* % with INT32_MAX to prevent overflows */
@@ -1615,7 +1619,7 @@ tryagain:
}
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
/*
* We need to check to make sure that the file got
@@ -1638,7 +1642,7 @@ tryagain:
va.va_size = reqsize;
(void) VOP_SETATTR(vp, &va, 0, cr, NULL);
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
}
}
@@ -1664,8 +1668,8 @@ tryagain:
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
VN_RELE(vp);
VN_RELE(dvp);
@@ -1730,12 +1734,12 @@ rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
} else
dbvap = NULL;
#else
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
#endif
davap = dbvap;
@@ -1781,23 +1785,23 @@ rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
va.va_mask |= AT_TYPE;
va.va_type = VDIR;
- error = VOP_MKDIR(dvp, args->where.name, &va, &vp, cr);
+ error = VOP_MKDIR(dvp, args->where.name, &va, &vp, cr, NULL, 0, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
} else
davap = NULL;
#else
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
if (error)
goto out;
@@ -1821,18 +1825,18 @@ rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -1886,12 +1890,12 @@ rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
} else
dbvap = NULL;
#else
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
#endif
davap = dbvap;
@@ -1943,28 +1947,29 @@ rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
va.va_type = VLNK;
error = VOP_SYMLINK(dvp, args->where.name, &va,
- args->symlink.symlink_data, cr);
+ args->symlink.symlink_data, cr, NULL, 0);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
} else
davap = NULL;
#else
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
#endif
if (error)
goto out;
- error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
VN_RELE(dvp);
@@ -1993,18 +1998,18 @@ rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -2059,12 +2064,12 @@ rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
} else
dbvap = NULL;
#else
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
#endif
davap = dbvap;
@@ -2152,23 +2157,23 @@ rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
mode = 0;
error = VOP_CREATE(dvp, args->where.name, &va, excl, mode,
- &vp, cr, 0);
+ &vp, cr, 0, NULL, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
} else
davap = NULL;
#else
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
if (error)
goto out;
@@ -2194,18 +2199,18 @@ rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
VN_RELE(vp);
@@ -2256,12 +2261,12 @@ rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
} else
bvap = NULL;
#else
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
#endif
avap = bvap;
@@ -2305,7 +2310,7 @@ rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
* reservation and V4 delegations
*/
error = VOP_LOOKUP(vp, args->object.name, &targvp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error != 0)
goto out;
@@ -2315,13 +2320,13 @@ rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
}
if (!nbl_need_check(targvp)) {
- error = VOP_REMOVE(vp, args->object.name, cr);
+ error = VOP_REMOVE(vp, args->object.name, cr, NULL, 0);
} else {
nbl_start_crit(targvp, RW_READER);
- if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
error = EACCES;
} else {
- error = VOP_REMOVE(vp, args->object.name, cr);
+ error = VOP_REMOVE(vp, args->object.name, cr, NULL, 0);
}
nbl_end_crit(targvp);
}
@@ -2331,18 +2336,18 @@ rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
} else
avap = NULL;
#else
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
if (error)
goto out;
@@ -2395,12 +2400,12 @@ rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
} else
bvap = NULL;
#else
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
#endif
avap = bvap;
@@ -2439,23 +2444,23 @@ rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
}
}
- error = VOP_RMDIR(vp, args->object.name, rootdir, cr);
+ error = VOP_RMDIR(vp, args->object.name, rootdir, cr, NULL, 0);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
} else
avap = NULL;
#else
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
if (error) {
/*
@@ -2544,12 +2549,12 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
fbva.va_mask = AT_ALL;
- fbvap = VOP_GETATTR(fvp, &fbva, 0, cr) ? NULL : &fbva;
+ fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
} else
fbvap = NULL;
#else
fbva.va_mask = AT_ALL;
- fbvap = VOP_GETATTR(fvp, &fbva, 0, cr) ? NULL : &fbva;
+ fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
#endif
favap = fbvap;
@@ -2575,12 +2580,12 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
tbva.va_mask = AT_ALL;
- tbvap = VOP_GETATTR(tvp, &tbva, 0, cr) ? NULL : &tbva;
+ tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
} else
tbvap = NULL;
#else
tbva.va_mask = AT_ALL;
- tbvap = VOP_GETATTR(tvp, &tbva, 0, cr) ? NULL : &tbva;
+ tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
#endif
tavap = tbvap;
@@ -2619,7 +2624,7 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
* reservation or V4 delegations.
*/
error = VOP_LOOKUP(fvp, args->from.name, &srcvp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error != 0)
goto out;
@@ -2638,7 +2643,8 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
* first to avoid VOP_LOOKUP if possible.
*/
if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
- VOP_LOOKUP(tvp, args->to.name, &targvp, NULL, 0, NULL, cr) == 0) {
+ VOP_LOOKUP(tvp, args->to.name, &targvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL) == 0) {
if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
VN_RELE(targvp);
@@ -2650,14 +2656,14 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
if (!nbl_need_check(srcvp)) {
error = VOP_RENAME(fvp, args->from.name, tvp,
- args->to.name, cr);
+ args->to.name, cr, NULL, 0);
} else {
nbl_start_crit(srcvp, RW_READER);
- if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0)) {
+ if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
error = EACCES;
} else {
error = VOP_RENAME(fvp, args->from.name, tvp,
- args->to.name, cr);
+ args->to.name, cr, NULL, 0);
}
nbl_end_crit(srcvp);
}
@@ -2680,25 +2686,25 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
fava.va_mask = AT_ALL;
- favap = VOP_GETATTR(fvp, &fava, 0, cr) ? NULL : &fava;
+ favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
tava.va_mask = AT_ALL;
- tavap = VOP_GETATTR(tvp, &tava, 0, cr) ? NULL : &tava;
+ tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
} else {
favap = NULL;
tavap = NULL;
}
#else
fava.va_mask = AT_ALL;
- favap = VOP_GETATTR(fvp, &fava, 0, cr) ? NULL : &fava;
+ favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
tava.va_mask = AT_ALL;
- tavap = VOP_GETATTR(tvp, &tava, 0, cr) ? NULL : &tava;
+ tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(fvp, 0, cr);
- (void) VOP_FSYNC(tvp, 0, cr);
+ (void) VOP_FSYNC(fvp, 0, cr, NULL);
+ (void) VOP_FSYNC(tvp, 0, cr, NULL);
if (error)
goto out;
@@ -2764,12 +2770,12 @@ rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
fh3 = &args->link.dir;
@@ -2809,12 +2815,12 @@ rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(dvp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
} else
bvap = NULL;
#else
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(dvp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
#endif
if (dvp->v_type != VDIR) {
@@ -2849,30 +2855,30 @@ rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
}
}
- error = VOP_LINK(dvp, vp, args->link.name, cr);
+ error = VOP_LINK(dvp, vp, args->link.name, cr, NULL, 0);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(dvp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
} else {
vap = NULL;
avap = NULL;
}
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(dvp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
if (error)
goto out;
@@ -2925,7 +2931,7 @@ rfs3_link_getfh(LINK3args *args)
* attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
* boolean - 1 * BYTES_PER_XDR_UNIT
* file id - 2 * BYTES_PER_XDR_UNIT
- * direcotory name length - 1 * BYTES_PER_XDR_UNIT
+ * directory name length - 1 * BYTES_PER_XDR_UNIT
* cookie - 2 * BYTES_PER_XDR_UNIT
* end of list - 1 * BYTES_PER_XDR_UNIT
* end of file - 1 * BYTES_PER_XDR_UNIT
@@ -2981,12 +2987,12 @@ rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
if (vp->v_type != VDIR) {
@@ -2994,7 +3000,7 @@ rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
goto out1;
}
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (error)
goto out;
@@ -3025,17 +3031,17 @@ rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
uio.uio_loffset = (offset_t)args->cookie;
uio.uio_resid = count;
- error = VOP_READDIR(vp, &uio, cr, &iseof);
+ error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
if (error) {
@@ -3108,7 +3114,7 @@ rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -3173,7 +3179,7 @@ rfs3_readdir_free(READDIR3res *resp)
* attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
* status byte for file handle - 1 * BYTES_PER_XDR_UNIT
* length of a file handle - 1 * BYTES_PER_XDR_UNIT
- * Maxmum length of a file handle (NFS3_MAXFHSIZE)
+ * Maximum length of a file handle (NFS3_MAXFHSIZE)
* name length of the entry to the nearest bytes
*/
#define NFS3_READDIRPLUS_ENTRY(namelen) \
@@ -3241,12 +3247,12 @@ rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
if (vp->v_type != VDIR) {
@@ -3254,7 +3260,7 @@ rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
goto out;
}
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (error)
goto out;
@@ -3323,7 +3329,7 @@ getmoredents:
uio.uio_resid = rd_unit;
prev_len = rd_unit;
- error = VOP_READDIR(vp, &uio, cr, &iseof);
+ error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
if (error) {
kmem_free(data, args->dircount);
@@ -3412,12 +3418,12 @@ good:
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
@@ -3437,7 +3443,8 @@ good:
infop[i].namelen = namlen[i];
- error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error) {
infop[i].attr.attributes = FALSE;
infop[i].fh.handle_follows = FALSE;
@@ -3485,7 +3492,7 @@ good:
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -3577,12 +3584,12 @@ rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
VN_RELE(vp);
@@ -3673,12 +3680,12 @@ rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
resp->status = NFS3_OK;
@@ -3696,7 +3703,7 @@ rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
* Large file spec: want maxfilesize based on limit of
* underlying filesystem. We can guess 2^31-1 if need be.
*/
- error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr);
+ error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
VN_RELE(vp);
@@ -3755,25 +3762,25 @@ rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
- error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
if (error)
goto out;
resp->resok.info.link_max = (uint32)val;
- error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
if (error)
goto out;
resp->resok.info.name_max = (uint32)val;
- error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
if (error)
goto out;
if (val == 1)
@@ -3781,7 +3788,7 @@ rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
else
resp->resok.info.no_trunc = FALSE;
- error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
if (error)
goto out;
if (val == 1)
@@ -3837,7 +3844,7 @@ rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
}
bva.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &bva, 0, cr);
+ error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
/*
* If we can't get the attributes, then we can't do the
@@ -3881,22 +3888,22 @@ rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
}
if (crgetuid(cr) != bva.va_uid &&
- (error = VOP_ACCESS(vp, VWRITE, 0, cr)))
+ (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
goto out;
- error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr);
+ error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL);
if (!error)
- error = VOP_FSYNC(vp, FNODSYNC, cr);
+ error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
} else
avap = NULL;
#else
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
#endif
if (error)
diff --git a/usr/src/uts/common/fs/nfs/nfs3_vnops.c b/usr/src/uts/common/fs/nfs/nfs3_vnops.c
index 39bdc1aa00..51306f52e8 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_vnops.c
@@ -101,7 +101,8 @@ static int nfs3create(vnode_t *, char *, struct vattr *, enum vcexcl,
static int nfs3excl_create_settimes(vnode_t *, struct vattr *, cred_t *);
static int nfs3mknod(vnode_t *, char *, struct vattr *, enum vcexcl,
int, vnode_t **, cred_t *);
-static int nfs3rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
+static int nfs3rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *);
static int do_nfs3readdir(vnode_t *, rddir_cache *, cred_t *);
static void nfs3readdir(vnode_t *, rddir_cache *, cred_t *);
static void nfs3readdirplus(vnode_t *, rddir_cache *, cred_t *);
@@ -160,59 +161,76 @@ static void nfs3_delmap_callback(struct as *, void *, uint_t);
* more details on rnode locking.
*/
-static int nfs3_open(vnode_t **, int, cred_t *);
-static int nfs3_close(vnode_t *, int, int, offset_t, cred_t *);
+static int nfs3_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int nfs3_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
static int nfs3_read(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
static int nfs3_write(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
-static int nfs3_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
-static int nfs3_getattr(vnode_t *, struct vattr *, int, cred_t *);
+static int nfs3_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
+static int nfs3_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
static int nfs3_setattr(vnode_t *, struct vattr *, int, cred_t *,
caller_context_t *);
-static int nfs3_access(vnode_t *, int, int, cred_t *);
-static int nfs3_readlink(vnode_t *, struct uio *, cred_t *);
-static int nfs3_fsync(vnode_t *, int, cred_t *);
-static void nfs3_inactive(vnode_t *, cred_t *);
+static int nfs3_access(vnode_t *, int, int, cred_t *, caller_context_t *);
+static int nfs3_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int nfs3_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static void nfs3_inactive(vnode_t *, cred_t *, caller_context_t *);
static int nfs3_lookup(vnode_t *, char *, vnode_t **,
- struct pathname *, int, vnode_t *, cred_t *);
+ struct pathname *, int, vnode_t *, cred_t *,
+ caller_context_t *, int *, pathname_t *);
static int nfs3_create(vnode_t *, char *, struct vattr *, enum vcexcl,
- int, vnode_t **, cred_t *, int);
-static int nfs3_remove(vnode_t *, char *, cred_t *);
-static int nfs3_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int nfs3_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-static int nfs3_mkdir(vnode_t *, char *, struct vattr *,
- vnode_t **, cred_t *);
-static int nfs3_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
+ int, vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+static int nfs3_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+ int);
+static int nfs3_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs3_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs3_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
+ cred_t *, caller_context_t *, int, vsecattr_t *);
+static int nfs3_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
static int nfs3_symlink(vnode_t *, char *, struct vattr *, char *,
- cred_t *);
-static int nfs3_readdir(vnode_t *, struct uio *, cred_t *, int *);
-static int nfs3_fid(vnode_t *, fid_t *);
+ cred_t *, caller_context_t *, int);
+static int nfs3_readdir(vnode_t *, struct uio *, cred_t *, int *,
+ caller_context_t *, int);
+static int nfs3_fid(vnode_t *, fid_t *, caller_context_t *);
static int nfs3_rwlock(vnode_t *, int, caller_context_t *);
static void nfs3_rwunlock(vnode_t *, int, caller_context_t *);
-static int nfs3_seek(vnode_t *, offset_t, offset_t *);
+static int nfs3_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
static int nfs3_getpage(vnode_t *, offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
- enum seg_rw, cred_t *);
-static int nfs3_putpage(vnode_t *, offset_t, size_t, int, cred_t *);
-static int nfs3_map(vnode_t *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-static int nfs3_addmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
+ enum seg_rw, cred_t *, caller_context_t *);
+static int nfs3_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+static int nfs3_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+static int nfs3_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
static int nfs3_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
+ struct flk_callback *, cred_t *, caller_context_t *);
static int nfs3_space(vnode_t *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
-static int nfs3_realvp(vnode_t *, vnode_t **);
-static int nfs3_delmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uint_t, uint_t, uint_t, cred_t *);
-static int nfs3_pathconf(vnode_t *, int, ulong_t *, cred_t *);
+static int nfs3_realvp(vnode_t *, vnode_t **, caller_context_t *);
+static int nfs3_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *, caller_context_t *);
+static int nfs3_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
static int nfs3_pageio(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static void nfs3_dispose(vnode_t *, page_t *, int, int, cred_t *);
-static int nfs3_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs3_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs3_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *);
+ cred_t *, caller_context_t *);
+static void nfs3_dispose(vnode_t *, page_t *, int, int, cred_t *,
+ caller_context_t *);
+static int nfs3_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+static int nfs3_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+static int nfs3_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
struct vnodeops *nfs3_vnodeops;
@@ -272,7 +290,7 @@ nfs3_getvnodeops(void)
/* ARGSUSED */
static int
-nfs3_open(vnode_t **vpp, int flag, cred_t *cr)
+nfs3_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
int error;
struct vattr va;
@@ -321,8 +339,10 @@ nfs3_open(vnode_t **vpp, int flag, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+nfs3_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
rnode_t *rp;
int error;
@@ -396,7 +416,8 @@ nfs3_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
*/
if ((flag & FWRITE) && vn_has_cached_data(vp)) {
if (VTOMI(vp)->mi_flags & MI_NOCTO) {
- error = nfs3_putpage(vp, (offset_t)0, 0, B_ASYNC, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, B_ASYNC,
+ cr, ct);
if (error == EAGAIN)
error = 0;
} else
@@ -1160,7 +1181,8 @@ nfs3read(vnode_t *vp, caddr_t base, offset_t offset, int count,
/* ARGSUSED */
static int
-nfs3_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
+nfs3_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp,
+ caller_context_t *ct)
{
if (nfs_zone() != VTOMI(vp)->mi_zone)
@@ -1173,8 +1195,10 @@ nfs3_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
}
}
+/* ARGSUSED */
static int
-nfs3_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+nfs3_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -1217,7 +1241,7 @@ nfs3_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
mutex_enter(&rp->r_statelock);
rp->r_gcount++;
mutex_exit(&rp->r_statelock);
- error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr, ct);
mutex_enter(&rp->r_statelock);
if (error && (error == ENOSPC || error == EDQUOT)) {
if (!rp->r_error)
@@ -1293,7 +1317,7 @@ nfs3setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
rp->r_count > 0 ||
rp->r_mapcnt > 0)) {
ASSERT(vp->v_type != VCHR);
- error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1446,12 +1470,12 @@ static int
nfs3_accessx(void *vp, int mode, cred_t *cr)
{
ASSERT(nfs_zone() == VTOMI((vnode_t *)vp)->mi_zone);
- return (nfs3_access(vp, mode, 0, cr));
+ return (nfs3_access(vp, mode, 0, cr, NULL));
}
/* ARGSUSED */
static int
-nfs3_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+nfs3_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
int error;
ACCESS3args args;
@@ -1584,8 +1608,9 @@ tryagain:
static int nfs3_do_symlink_cache = 1;
+/* ARGSUSED */
static int
-nfs3_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+nfs3_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
{
int error;
READLINK3args args;
@@ -1693,8 +1718,9 @@ nfs3_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
* metadata changes are not cached on the client before being
* sent to the server.
*/
+/* ARGSUSED */
static int
-nfs3_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+nfs3_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
int error;
@@ -1714,8 +1740,9 @@ nfs3_fsync(vnode_t *vp, int syncflag, cred_t *cr)
* operation while it was open, it got renamed instead. Here we
* remove the renamed file.
*/
+/* ARGSUSED */
static void
-nfs3_inactive(vnode_t *vp, cred_t *cr)
+nfs3_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
@@ -1775,7 +1802,8 @@ redo:
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_count > 0)) {
ASSERT(vp->v_type != VCHR);
- error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, 0,
+ cr, ct);
if (error) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1832,9 +1860,11 @@ redo:
* Remote file system operations having to do with directory manipulation.
*/
+/* ARGSUSED */
static int
nfs3_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
int error;
vnode_t *vp;
@@ -1957,7 +1987,7 @@ nfs3lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* just need to check access.
*/
if (strcmp(nm, ".") == 0) {
- error = nfs3_access(dvp, VEXEC, 0, cr);
+ error = nfs3_access(dvp, VEXEC, 0, cr, NULL);
if (error)
return (error);
VN_HOLD(dvp);
@@ -2018,7 +2048,7 @@ nfs3lookup_dnlc(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr)
return (error);
vp = dnlc_lookup(dvp, nm);
if (vp != NULL) {
- error = nfs3_access(dvp, VEXEC, 0, cr);
+ error = nfs3_access(dvp, VEXEC, 0, cr, NULL);
if (error) {
VN_RELE(vp);
return (error);
@@ -2134,7 +2164,8 @@ static int nfs3_create_misses = 0;
/* ARGSUSED */
static int
nfs3_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
- int mode, vnode_t **vpp, cred_t *cr, int lfaware)
+ int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
vnode_t *vp;
@@ -2171,7 +2202,7 @@ top:
* just need to check access.
*/
} else if (strcmp(nm, ".") == 0) {
- error = nfs3_access(dvp, VEXEC, 0, cr);
+ error = nfs3_access(dvp, VEXEC, 0, cr, ct);
if (error) {
nfs_rw_exit(&drp->r_rwlock);
return (error);
@@ -2200,7 +2231,7 @@ top:
vp = specvp(vp, vp->v_rdev, vp->v_type, cr);
VN_RELE(tempvp);
}
- if (!(error = VOP_ACCESS(vp, mode, 0, cr))) {
+ if (!(error = VOP_ACCESS(vp, mode, 0, cr, ct))) {
if ((vattr.va_mask & AT_SIZE) &&
vp->v_type == VREG) {
rp = VTOR(vp);
@@ -2230,7 +2261,7 @@ top:
/*
* existing file got truncated, notify.
*/
- vnevent_create(vp);
+ vnevent_create(vp, ct);
*vpp = vp;
}
return (error);
@@ -2438,7 +2469,7 @@ nfs3create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
*/
VN_RELE(vp);
(void) nfs3_remove(dvp,
- nm, cr);
+ nm, cr, NULL, 0);
return (error);
}
}
@@ -2515,7 +2546,7 @@ nfs3create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* application.
*/
VN_RELE(vp);
- (void) nfs3_remove(dvp, nm, cr);
+ (void) nfs3_remove(dvp, nm, cr, NULL, 0);
return (error);
}
}
@@ -2737,8 +2768,9 @@ nfs3mknod(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* we rename it instead of removing it and nfs_inactive
* will remove the new name.
*/
+/* ARGSUSED */
static int
-nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
+nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, int flags)
{
int error;
REMOVE3args args;
@@ -2792,7 +2824,7 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
(rp->r_unldvp == NULL || strcmp(nm, rp->r_unlname) == 0)) {
mutex_exit(&rp->r_statelock);
tmpname = newname();
- error = nfs3rename(dvp, nm, dvp, tmpname, cr);
+ error = nfs3rename(dvp, nm, dvp, tmpname, cr, ct);
if (error)
kmem_free(tmpname, MAXNAMELEN);
else {
@@ -2821,7 +2853,7 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
*/
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_count > 0)) {
- error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr, ct);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -2868,7 +2900,7 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
}
if (error == 0) {
- vnevent_remove(vp, dvp, nm);
+ vnevent_remove(vp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -2877,8 +2909,10 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
LINK3args args;
@@ -2891,7 +2925,7 @@ nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
if (nfs_zone() != VTOMI(tdvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(svp, &realvp) == 0)
+ if (VOP_REALVP(svp, &realvp, ct) == 0)
svp = realvp;
mi = VTOMI(svp);
@@ -2949,29 +2983,32 @@ nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
/*
* Notify the source file of this link operation.
*/
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
return (error);
}
+/* ARGSUSED */
static int
-nfs3_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs3_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
vnode_t *realvp;
if (nfs_zone() != VTOMI(odvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
- return (nfs3rename(odvp, onm, ndvp, nnm, cr));
+ return (nfs3rename(odvp, onm, ndvp, nnm, cr, ct));
}
/*
* nfs3rename does the real work of renaming in NFS Version 3.
*/
static int
-nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct)
{
int error;
RENAME3args args;
@@ -3106,10 +3143,10 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
* the server removing the file completely.
*/
tmpname = newname();
- error = nfs3_link(ndvp, nvp, tmpname, cr);
+ error = nfs3_link(ndvp, nvp, tmpname, cr, NULL, 0);
if (error == EOPNOTSUPP) {
error = nfs3_rename(ndvp, nnm, ndvp, tmpname,
- cr);
+ cr, NULL, 0);
}
if (error) {
kmem_free(tmpname, MAXNAMELEN);
@@ -3253,12 +3290,12 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
if (error == 0) {
if (nvp)
- vnevent_rename_dest(nvp, ndvp, nnm);
+ vnevent_rename_dest(nvp, ndvp, nnm, ct);
if (odvp != ndvp)
- vnevent_rename_dest_dir(ndvp);
+ vnevent_rename_dest_dir(ndvp, ct);
ASSERT(ovp != NULL);
- vnevent_rename_src(ovp, odvp, onm);
+ vnevent_rename_src(ovp, odvp, onm, ct);
}
if (nvp) {
@@ -3272,8 +3309,10 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
+nfs3_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr,
+ caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
MKDIR3args args;
@@ -3375,8 +3414,10 @@ nfs3_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
RMDIR3args args;
@@ -3469,7 +3510,7 @@ nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
}
if (error == 0) {
- vnevent_rmdir(vp, dvp, nm);
+ vnevent_rmdir(vp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -3478,8 +3519,10 @@ nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr)
+nfs3_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
SYMLINK3args args;
@@ -3607,8 +3650,10 @@ static int nfs3_shrinkreaddir = 0;
* may return only one block's worth of entries. Entries may be compressed
* on the server.
*/
+/* ARGSUSED */
static int
-nfs3_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp)
+nfs3_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int error;
size_t count;
@@ -4335,8 +4380,9 @@ nfs3_bio(struct buf *bp, stable_how *stab_comm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_fid(vnode_t *vp, fid_t *fidp)
+nfs3_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
rnode_t *rp;
@@ -4386,7 +4432,7 @@ nfs3_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-nfs3_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+nfs3_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
/*
@@ -4413,10 +4459,11 @@ static int nfs3_lostpage = 0; /* number of times we lost original page */
/*
* Return all the pages from [off..off+len) in file
*/
+/* ARGSUSED */
static int
nfs3_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
int error;
@@ -4879,8 +4926,10 @@ nfs3_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, struct seg *seg,
* len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
* (from pageout).
*/
+/* ARGSUSED */
static int
-nfs3_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+nfs3_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -5078,7 +5127,7 @@ nfs3_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
*/
if (!(flags & B_ASYNC)) {
error = nfs3_putpage(vp, io_off, io_len,
- B_INVAL | B_FORCE, cr);
+ B_INVAL | B_FORCE, cr, NULL);
}
} else {
if (error)
@@ -5096,9 +5145,11 @@ nfs3_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs3_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)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
+ cred_t *cr, caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error;
@@ -5197,7 +5248,8 @@ done:
/* ARGSUSED */
static int
nfs3_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)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
+ cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
@@ -5220,9 +5272,11 @@ nfs3_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
return (0);
}
+/* ARGSUSED */
static int
nfs3_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
netobj lm_fh3;
int rc;
@@ -5277,7 +5331,7 @@ nfs3_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (!lm_safelock(vp, bfp, cr))
return (EAGAIN);
}
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
rp = VTOR(vp);
@@ -5326,7 +5380,7 @@ nfs3_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
mutex_exit(&rp->r_statelock);
if (rc != 0)
goto done;
- error = nfs3_putpage(vp, (offset_t)0, 0, B_INVAL, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, B_INVAL, cr, ct);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
@@ -5407,7 +5461,7 @@ nfs3_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
/* ARGSUSED */
static int
-nfs3_realvp(vnode_t *vp, vnode_t **vpp)
+nfs3_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
return (EINVAL);
@@ -5426,7 +5480,8 @@ nfs3_realvp(vnode_t *vp, vnode_t **vpp)
/* ARGSUSED */
static int
nfs3_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)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags,
+ cred_t *cr, caller_context_t *ct)
{
int caller_found;
int error;
@@ -5556,7 +5611,7 @@ nfs3_delmap_callback(struct as *as, void *arg, uint_t event)
if ((mi->mi_flags & MI_NOCTO) ||
nfs_zone() != mi->mi_zone)
error = nfs3_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_ASYNC, dmapp->cr);
+ B_ASYNC, dmapp->cr, NULL);
else
error = nfs3_putpage_commit(dmapp->vp, dmapp->off,
dmapp->len, dmapp->cr);
@@ -5571,7 +5626,7 @@ nfs3_delmap_callback(struct as *as, void *arg, uint_t event)
if ((rp->r_flags & RDIRECTIO) || (mi->mi_flags & MI_DIRECTIO))
(void) nfs3_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_INVAL, dmapp->cr);
+ B_INVAL, dmapp->cr, NULL);
dmapp->caller->error = error;
(void) as_delete_callback(as, arg);
@@ -5585,8 +5640,10 @@ static int nfs3_pathconf_cache_hits = 0;
static int nfs3_pathconf_cache_misses = 0;
#endif
+/* ARGSUSED */
static int
-nfs3_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+nfs3_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int error;
PATHCONF3args args;
@@ -5795,9 +5852,10 @@ nfs3_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs3_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -5824,8 +5882,10 @@ nfs3_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static void
-nfs3_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
+nfs3_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -6362,7 +6422,7 @@ top:
write_verf = rp->r_verf;
mutex_exit(&rp->r_statelock);
- error = nfs3_putpage(vp, poff, plen, B_ASYNC, cr);
+ error = nfs3_putpage(vp, poff, plen, B_ASYNC, cr, NULL);
if (error == EAGAIN)
error = 0;
@@ -6373,7 +6433,7 @@ top:
* the asynchronous i/o's in that range are done as well.
*/
if (!error)
- error = nfs3_putpage(vp, poff, plen, 0, cr);
+ error = nfs3_putpage(vp, poff, plen, 0, cr, NULL);
if (error)
return (error);
@@ -6510,8 +6570,10 @@ nfs3_async_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count,
(void) nfs3_sync_commit(vp, plist, offset, count, cr);
}
+/* ARGSUSED */
static int
-nfs3_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs3_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo_t *mi;
@@ -6530,8 +6592,10 @@ nfs3_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (ENOSYS);
}
+/* ARGSUSED */
static int
-nfs3_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs3_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo_t *mi;
@@ -6547,11 +6611,13 @@ nfs3_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (error);
}
- return (fs_fab_acl(vp, vsecattr, flag, cr));
+ return (fs_fab_acl(vp, vsecattr, flag, cr, ct));
}
+/* ARGSUSED */
static int
-nfs3_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+nfs3_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
struct shrlock nshr;
@@ -6580,7 +6646,7 @@ nfs3_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
* request off to the local share code.
*/
if (VTOMI(vp)->mi_flags & MI_LLOCK)
- return (fs_shrlock(vp, cmd, shr, flag, cr));
+ return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
switch (cmd) {
case F_SHARE:
diff --git a/usr/src/uts/common/fs/nfs/nfs4_acl.c b/usr/src/uts/common/fs/nfs/nfs4_acl.c
index 77c9506dcb..7f5d28f037 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_acl.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_acl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -782,6 +782,7 @@ vs_aent_to_ace4(vsecattr_t *aclentacl, vsecattr_t *vs_ace4,
vs_ace4->vsa_aclcnt = 0;
vs_ace4->vsa_dfaclentp = NULL;
vs_ace4->vsa_dfaclcnt = 0;
+ vs_ace4->vsa_aclentsz = 0;
if (! (aclentacl->vsa_mask & (VSA_ACL | VSA_ACLCNT |
VSA_DFACL | VSA_DFACLCNT))) {
@@ -1922,10 +1923,11 @@ vs_ace4_to_acet(vsecattr_t *vs_ace4, vsecattr_t *vs_acet,
if ((vs_ace4->vsa_aclcnt == 0) || (vs_ace4->vsa_aclentp == NULL))
return (0);
- if (vs_ace4->vsa_aclcnt > 0)
+ if (vs_ace4->vsa_aclcnt > 0) {
vs_acet->vsa_aclentp = kmem_alloc(vs_ace4->vsa_aclcnt *
sizeof (ace_t), KM_SLEEP);
- else
+ vs_acet->vsa_aclentsz = vs_ace4->vsa_aclcnt * sizeof (ace_t);
+ } else
vs_acet->vsa_aclentp = NULL;
vs_acet->vsa_aclcnt = vs_ace4->vsa_aclcnt;
vs_acet->vsa_mask = VSA_ACE | VSA_ACECNT;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_callback.c b/usr/src/uts/common/fs/nfs/nfs4_callback.c
index 2bc2249e12..4c7d4e9b8c 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_callback.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_callback.c
@@ -1628,7 +1628,7 @@ nfs4delegreturn_impl(rnode4_t *rp, int flags, struct nfs4_callback_globals *ncg)
* before doing DELEGRETURN.
*/
if (flags & NFS4_DR_PUSH)
- (void) VOP_PUTPAGE(vp, 0, 0, 0, cr);
+ (void) VOP_PUTPAGE(vp, 0, 0, 0, cr, NULL);
/*
* Take r_deleg_recall_lock in WRITE mode, this will prevent
@@ -1989,7 +1989,7 @@ retry:
* We have already taken the 'r_deleg_recall_lock' as WRITER, which
* prevents new OPENs from going OTW (as start_fop takes this
* lock in READ mode); thus, no new open streams can be created
- * (which inheretly means no new delegation open streams are
+ * (which inherently means no new delegation open streams are
* being created).
*/
@@ -2096,7 +2096,7 @@ nfs4delegreturn_thread(struct cb_recall_pass *args)
mutex_exit(&rp->r_statelock);
if (rdirty) {
- error = VOP_PUTPAGE(vp, 0, 0, 0, cr);
+ error = VOP_PUTPAGE(vp, 0, 0, 0, cr, NULL);
if (error)
CB_WARN1("nfs4delegreturn_thread:"
@@ -2114,7 +2114,7 @@ nfs4delegreturn_thread(struct cb_recall_pass *args)
if (rip) {
- error = VOP_PUTPAGE(vp, 0, 0, B_INVAL, cr);
+ error = VOP_PUTPAGE(vp, 0, 0, B_INVAL, cr, NULL);
if (error)
CB_WARN1("nfs4delegreturn_thread: VOP_PUTPAGE: %d\n",
diff --git a/usr/src/uts/common/fs/nfs/nfs4_client.c b/usr/src/uts/common/fs/nfs/nfs4_client.c
index 85f68c5123..f18e46d3c3 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_client.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_client.c
@@ -351,7 +351,7 @@ flush_pages(vnode_t *vp, cred_t *cr)
int error;
rnode4_t *rp = VTOR4(vp);
- error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL);
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -858,7 +858,7 @@ nfs4_getattr_otw_norecovery(vnode_t *vp, nfs4_ga_res_t *garp,
/* getattr */
/*
* Unlike nfs version 2 and 3, where getattr returns all the
- * attributes, nfs version 4 returns only the ones explicitely
+ * attributes, nfs version 4 returns only the ones explicitly
* asked for. This creates problems, as some system functions
* (e.g. cache check) require certain attributes and if the
* cached node lacks some attributes such as uid/gid, it can
@@ -1566,7 +1566,7 @@ nfs4_async_stop(struct vfs *vfsp)
* Wait for all outstanding putpage operations and the inactive thread to
* complete. If a signal is delivered we will abort and return non-zero;
* otherwise return 0. Since this routine is called from nfs4_unmount, we
- * need to make it interruptable.
+ * need to make it interruptible.
*/
int
nfs4_async_stop_sig(struct vfs *vfsp)
@@ -2086,7 +2086,7 @@ nfs4_async_inactive(vnode_t *vp, cred_t *cr)
* set nfs4_max_threads to zero in /etc/system.
*
* The manager thread knows about this and is willing to create
- * at least one thread to accomodate us.
+ * at least one thread to accommodate us.
*/
mutex_enter(&mi->mi_async_lock);
if (mi->mi_inactive_thread == NULL) {
@@ -2404,7 +2404,7 @@ nfs4_putpages(vnode_t *vp, u_offset_t off, size_t len, int flags, cred_t *cr)
flags, cr);
/*
- * If an error occured and the file was marked as dirty
+ * If an error occurred and the file was marked as dirty
* before and we aren't forcibly invalidating pages, then
* reset the R4DIRTY flag.
*/
@@ -2716,7 +2716,7 @@ nfs4_map_lost_lock_conflict(vnode_t *vp)
if (lrp->lr_op != OP_LOCK && lrp->lr_op != OP_LOCKU)
continue;
ASSERT(lrp->lr_vp != NULL);
- if (!VOP_CMP(lrp->lr_vp, vp))
+ if (!VOP_CMP(lrp->lr_vp, vp, NULL))
continue; /* different file */
if (!SAFE_LOCK(*lrp->lr_flk)) {
conflict = TRUE;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c b/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c
index 27c9a9f300..b285807b3f 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c
@@ -54,16 +54,21 @@ int
deleg_rdopen(
femarg_t *arg,
int mode,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
clock_t rc;
rfs4_file_t *fp;
/*
+ * Now that the NFSv4 server calls VOP_OPEN, we need to check to
+ * to make sure it is not us calling open (like for DELEG_CUR) or
+ * we will end up panicing the system.
* Since this monitor is for a read delegated file, we know that
* only an open for write will cause a conflict.
*/
- if (mode & (FWRITE|FTRUNC)) {
+ if ((ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) &&
+ (mode & (FWRITE|FTRUNC))) {
fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
rfs4_recall_deleg(fp, FALSE, NULL);
rfs4_dbe_lock(fp->dbe);
@@ -79,7 +84,7 @@ deleg_rdopen(
rfs4_dbe_unlock(fp->dbe);
}
- return (vnext_open(arg, mode, cr));
+ return (vnext_open(arg, mode, cr, ct));
}
/* monitor for open on write delegated file */
@@ -87,31 +92,36 @@ int
deleg_wropen(
femarg_t *arg,
int mode,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
clock_t rc;
rfs4_file_t *fp;
- fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
-
/*
+ * Now that the NFSv4 server calls VOP_OPEN, we need to check to
+ * to make sure it is not us calling open (like for DELEG_CUR) or
+ * we will end up panicing the system.
* Since this monitor is for a write delegated file, we know that
* any open will cause a conflict.
*/
- rfs4_recall_deleg(fp, FALSE, NULL);
- rfs4_dbe_lock(fp->dbe);
- while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
- rc = rfs4_dbe_twait(fp->dbe,
- lbolt + SEC_TO_TICK(rfs4_lease_time));
- if (rc == -1) { /* timed out */
- rfs4_dbe_unlock(fp->dbe);
- rfs4_recall_deleg(fp, FALSE, NULL);
- rfs4_dbe_lock(fp->dbe);
+ if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
+ fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
+ rfs4_recall_deleg(fp, FALSE, NULL);
+ rfs4_dbe_lock(fp->dbe);
+ while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
+ rc = rfs4_dbe_twait(fp->dbe,
+ lbolt + SEC_TO_TICK(rfs4_lease_time));
+ if (rc == -1) { /* timed out */
+ rfs4_dbe_unlock(fp->dbe);
+ rfs4_recall_deleg(fp, FALSE, NULL);
+ rfs4_dbe_lock(fp->dbe);
+ }
}
+ rfs4_dbe_unlock(fp->dbe);
}
- rfs4_dbe_unlock(fp->dbe);
- return (vnext_open(arg, mode, cr));
+ return (vnext_open(arg, mode, cr, ct));
}
/*
@@ -319,7 +329,8 @@ deleg_setsecattr(
femarg_t *arg,
vsecattr_t *vsap,
int flag,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
clock_t rc;
rfs4_file_t *fp;
@@ -340,7 +351,7 @@ deleg_setsecattr(
}
rfs4_dbe_unlock(fp->dbe);
- return (vnext_setsecattr(arg, vsap, flag, cr));
+ return (vnext_setsecattr(arg, vsap, flag, cr, ct));
}
/* ARGSUSED */
@@ -349,7 +360,8 @@ deleg_vnevent(
femarg_t *arg,
vnevent_t vnevent,
vnode_t *dvp,
- char *name)
+ char *name,
+ caller_context_t *ct)
{
clock_t rc;
rfs4_file_t *fp;
@@ -380,5 +392,5 @@ deleg_vnevent(
default:
break;
}
- return (vnext_vnevent(arg, vnevent, dvp, name));
+ return (vnext_vnevent(arg, vnevent, dvp, name, ct));
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_rnode.c b/usr/src/uts/common/fs/nfs/nfs4_rnode.c
index 35d48fd750..5ae6dce3c8 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_rnode.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_rnode.c
@@ -101,7 +101,7 @@
* freelist and then trying to place them back on the freelist
* when their reference is released. This means that the when an
* rnode is looked up in the hash queues, then either the rnode
- * is removed from the freelist and that reference is tranfered to
+ * is removed from the freelist and that reference is transferred to
* the new reference or the vnode reference count must be incremented
* accordingly. The mutex for the freelist must be held in order to
* accurately test to see if the rnode is on the freelist or not.
@@ -211,7 +211,7 @@ r4flushpages(rnode4_t *rp, cred_t *cr)
if (nfs4_has_pages(vp)) {
ASSERT(vp->v_type != VCHR);
if ((rp->r_flags & R4DIRTY) && !rp->r_error) {
- error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, 0, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, 0, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1324,7 +1324,7 @@ toomany:
*/
while (cnt-- > 0) {
vp = vplist[cnt];
- (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr, NULL);
VN_RELE(vp);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c
index 4857af785b..c830396935 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c
@@ -922,7 +922,8 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
/*
* Get the vnode for the component "nm".
*/
- error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr);
+ error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr,
+ NULL, NULL, NULL);
if (error)
return (puterrno4(error));
@@ -1253,7 +1254,7 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* as well be reflected to the server during the open.
*/
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
return;
@@ -1283,7 +1284,7 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (args->access & ACCESS4_READ) {
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode) &&
(!is_system_labeled() || admin_low_client ||
bldominates(clabel, slabel)))
@@ -1291,7 +1292,7 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
resp->supported |= ACCESS4_READ;
}
if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (!error && (!is_system_labeled() || admin_low_client ||
bldominates(clabel, slabel)))
resp->access |= ACCESS4_LOOKUP;
@@ -1299,7 +1300,7 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (checkwriteperm &&
(args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode) &&
(!is_system_labeled() || admin_low_client ||
blequal(clabel, slabel)))
@@ -1310,14 +1311,14 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (checkwriteperm &&
(args->access & ACCESS4_DELETE) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (!error && (!is_system_labeled() || admin_low_client ||
blequal(clabel, slabel)))
resp->access |= ACCESS4_DELETE;
resp->supported |= ACCESS4_DELETE;
}
if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode) &&
(!is_system_labeled() || admin_low_client ||
bldominates(clabel, slabel)))
@@ -1358,7 +1359,7 @@ rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
va.va_mask = AT_UID;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
/*
* If we can't get the attributes, then we can't do the
@@ -1383,14 +1384,14 @@ rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (crgetuid(cr) != va.va_uid &&
- (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr))) {
+ (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr, NULL))) {
*cs->statusp = resp->status = puterrno4(error);
return;
}
- error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr);
+ error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL);
if (!error)
- error = VOP_FSYNC(vp, FNODSYNC, cr);
+ error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
@@ -1455,7 +1456,7 @@ do_rfs4_op_mknod(CREATE4args *args, CREATE4res *resp, struct svc_req *req,
mode = 0;
- error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0);
+ error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0, NULL, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
return (NULL);
@@ -1571,7 +1572,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/* Get "before" change value */
bva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bva, 0, cr);
+ error = VOP_GETATTR(dvp, &bva, 0, cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
kmem_free(nm, len);
@@ -1604,7 +1605,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
vap->va_mode = 0700; /* default: owner rwx only */
vap->va_mask |= AT_MODE;
}
- error = VOP_MKDIR(dvp, nm, vap, &vp, cr);
+ error = VOP_MKDIR(dvp, nm, vap, &vp, cr, NULL, 0, NULL);
if (error)
break;
@@ -1613,7 +1614,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* set to zero
*/
iva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &iva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
iva.va_seq = 0;
break;
case NF4LNK:
@@ -1645,7 +1646,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
return;
}
- error = VOP_SYMLINK(dvp, nm, vap, lnm, cr);
+ error = VOP_SYMLINK(dvp, nm, vap, lnm, cr, NULL, 0);
if (lnm != NULL)
kmem_free(lnm, llen);
if (error)
@@ -1656,10 +1657,11 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* set to zero
*/
iva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &iva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
iva.va_seq = 0;
- error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error)
break;
@@ -1668,7 +1670,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* if it has changed zero out iva to force atomic = FALSE.
*/
iva2.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &iva2, 0, cs->cr) ||
+ if (VOP_GETATTR(dvp, &iva2, 0, cs->cr, NULL) ||
iva2.va_seq != iva.va_seq)
iva.va_seq = 0;
break;
@@ -1698,7 +1700,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* set to zero
*/
iva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &iva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
iva.va_seq = 0;
break;
@@ -1712,7 +1714,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
if (resp->status != NFS4_OK) {
if (vp != NULL)
@@ -1728,7 +1730,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* before value.
*/
ava.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &ava, 0, cr)) {
+ if (VOP_GETATTR(dvp, &ava, 0, cr, NULL)) {
ava.va_ctime = bva.va_ctime;
ava.va_seq = 0;
}
@@ -1774,7 +1776,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
else
resp->cinfo.atomic = FALSE;
- (void) VOP_FSYNC(vp, syncval, cr);
+ (void) VOP_FSYNC(vp, syncval, cr, NULL);
if (resp->status != NFS4_OK) {
VN_RELE(vp);
@@ -2357,7 +2359,7 @@ rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/* Get "before" change value */
bdva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bdva, 0, cs->cr);
+ error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
kmem_free(nm, len);
@@ -2366,7 +2368,7 @@ rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
- error = VOP_LINK(dvp, vp, nm, cs->cr);
+ error = VOP_LINK(dvp, vp, nm, cs->cr, NULL, 0);
kmem_free(nm, len);
@@ -2374,14 +2376,14 @@ rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* Get the initial "after" sequence number, if it fails, set to zero
*/
idva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &idva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
idva.va_seq = 0;
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cs->cr);
- (void) VOP_FSYNC(dvp, 0, cs->cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
+ (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
@@ -2393,7 +2395,7 @@ rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* before value.
*/
adva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &adva, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
adva.va_ctime = bdva.va_ctime;
adva.va_seq = 0;
}
@@ -2484,7 +2486,8 @@ do_rfs4_op_lookup(char *nm, uint_t buflen, struct svc_req *req,
}
}
- error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr);
+ error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr,
+ NULL, NULL, NULL);
if (error)
return (puterrno4(error));
@@ -2806,14 +2809,15 @@ rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* checks from copen).
*/
- if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0) {
+ if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0 &&
+ !vfs_has_feature(cs->vp->v_vfsp, VFSFT_XVATTR)) {
error = ENOTSUP;
goto error_out;
}
- if ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr) != 0) &&
- (VOP_ACCESS(cs->vp, VWRITE, 0, cs->cr) != 0) &&
- (VOP_ACCESS(cs->vp, VEXEC, 0, cs->cr) != 0)) {
+ if ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr, NULL) != 0) &&
+ (VOP_ACCESS(cs->vp, VWRITE, 0, cs->cr, NULL) != 0) &&
+ (VOP_ACCESS(cs->vp, VEXEC, 0, cs->cr, NULL) != 0)) {
error = EACCES;
goto error_out;
}
@@ -2835,7 +2839,8 @@ rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (args->createdir && ! (exp_ro = rdonly4(cs->exi, cs->vp, req)))
lookup_flags |= CREATE_XATTR_DIR;
- error = VOP_LOOKUP(cs->vp, "", &avp, NULL, lookup_flags, NULL, cs->cr);
+ error = VOP_LOOKUP(cs->vp, "", &avp, NULL, lookup_flags, NULL, cs->cr,
+ NULL, NULL, NULL);
if (error) {
if (error == ENOENT && args->createdir && exp_ro)
@@ -2873,12 +2878,12 @@ error_out:
}
static int
-do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred)
+do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred,
+ caller_context_t *ct)
{
int error;
int i;
clock_t delaytime;
- caller_context_t ct;
delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
@@ -2888,21 +2893,17 @@ do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred)
*/
uio->uio_fmode = FNONBLOCK;
- ct.cc_sysid = 0;
- ct.cc_pid = 0;
- ct.cc_caller_id = nfs4_srv_caller_id;
-
for (i = 0; i < rfs4_maxlock_tries; i++) {
if (direction == FREAD) {
- (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
- error = VOP_READ(vp, uio, ioflag, cred, &ct);
- VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, ct);
+ error = VOP_READ(vp, uio, ioflag, cred, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, ct);
} else {
- (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
- error = VOP_WRITE(vp, uio, ioflag, cred, &ct);
- VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, ct);
+ error = VOP_WRITE(vp, uio, ioflag, cred, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, ct);
}
if (error != EAGAIN)
@@ -2936,6 +2937,7 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
int in_crit = 0;
mblk_t *mp;
int alloc_err = 0;
+ caller_context_t ct;
vp = cs->vp;
if (vp == NULL) {
@@ -2947,6 +2949,12 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
return;
}
+ if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE,
+ deleg, TRUE, &ct)) != NFS4_OK) {
+ *cs->statusp = resp->status = stat;
+ goto out;
+ }
+
/*
* Enter the critical region before calling VOP_RWLOCK
* to avoid a deadlock with write requests.
@@ -2954,20 +2962,21 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0)) {
+ if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
+ &ct)) {
*cs->statusp = resp->status = NFS4ERR_LOCKED;
goto out;
}
}
if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE,
- deleg, TRUE)) != NFS4_OK) {
+ deleg, TRUE, &ct)) != NFS4_OK) {
*cs->statusp = resp->status = stat;
goto out;
}
va.va_mask = AT_MODE|AT_SIZE|AT_UID;
- verror = VOP_GETATTR(vp, &va, 0, cs->cr);
+ verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
/*
* If we can't get the attributes, then we can't do the
@@ -2985,8 +2994,8 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (crgetuid(cs->cr) != va.va_uid &&
- (error = VOP_ACCESS(vp, VREAD, 0, cs->cr)) &&
- (error = VOP_ACCESS(vp, VEXEC, 0, cs->cr))) {
+ (error = VOP_ACCESS(vp, VREAD, 0, cs->cr, &ct)) &&
+ (error = VOP_ACCESS(vp, VEXEC, 0, cs->cr, &ct))) {
*cs->statusp = resp->status = puterrno4(error);
goto out;
}
@@ -3051,10 +3060,10 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
uio.uio_loffset = args->offset;
uio.uio_resid = args->count;
- error = do_io(FREAD, vp, &uio, 0, cs->cr);
+ error = do_io(FREAD, vp, &uio, 0, cs->cr, &ct);
va.va_mask = AT_SIZE;
- verror = VOP_GETATTR(vp, &va, 0, cs->cr);
+ verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
if (error) {
freeb(mp);
@@ -3477,7 +3486,7 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cs->cr);
+ error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
return;
@@ -3499,7 +3508,7 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
uio.uio_loffset = 0;
uio.uio_resid = MAXPATHLEN;
- error = VOP_READLINK(vp, &uio, cs->cr);
+ error = VOP_READLINK(vp, &uio, cs->cr, NULL);
if (error) {
kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1);
@@ -3683,7 +3692,8 @@ rfs4_lookup_and_findfile(vnode_t *dvp, char *nm, vnode_t **vpp,
if (vpp)
*vpp = NULL;
- if ((error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr)) == 0) {
+ if ((error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr, NULL, NULL,
+ NULL)) == 0) {
if (vp->v_type == VREG)
fp = rfs4_findfile(vp, NULL, &fcreate);
if (vpp)
@@ -3799,7 +3809,7 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0, NULL)) {
*cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
kmem_free(nm, len);
nbl_end_crit(vp);
@@ -3837,7 +3847,7 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/* Get dir "before" change value */
bdva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bdva, 0, cs->cr);
+ error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
kmem_free(nm, len);
@@ -3860,12 +3870,12 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* NFS4ERR_EXIST to NFS4ERR_NOTEMPTY to
* transmit over the wire.
*/
- if ((error = VOP_RMDIR(dvp, nm, rootdir, cs->cr))
- == EEXIST)
+ if ((error = VOP_RMDIR(dvp, nm, rootdir, cs->cr,
+ NULL, 0)) == EEXIST)
error = ENOTEMPTY;
}
} else {
- if ((error = VOP_REMOVE(dvp, nm, cs->cr)) == 0 &&
+ if ((error = VOP_REMOVE(dvp, nm, cs->cr, NULL, 0)) == 0 &&
fp != NULL) {
struct vattr va;
vnode_t *tvp;
@@ -3882,7 +3892,7 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* manipulating dvp.
*/
va.va_mask = AT_NLINK;
- if (!VOP_GETATTR(tvp, &va, 0, cs->cr) &&
+ if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) &&
va.va_nlink == 0) {
/* Remove state on file remove */
if (in_crit) {
@@ -3915,20 +3925,20 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* Get the initial "after" sequence number, if it fails, set to zero
*/
idva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &idva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
idva.va_seq = 0;
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cs->cr);
+ (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
/*
* Get "after" change value, if it fails, simply return the
* before value.
*/
adva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &adva, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
adva.va_ctime = bdva.va_ctime;
adva.va_seq = 0;
}
@@ -4120,7 +4130,7 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (nbl_need_check(srcvp)) {
nbl_start_crit(srcvp, RW_READER);
in_crit_src = 1;
- if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0)) {
+ if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
*cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
goto err_out;
}
@@ -4129,7 +4139,7 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (targvp && nbl_need_check(targvp)) {
nbl_start_crit(targvp, RW_READER);
in_crit_targ = 1;
- if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
*cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
goto err_out;
}
@@ -4137,10 +4147,10 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/* Get source "before" change value */
obdva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(odvp, &obdva, 0, cs->cr);
+ error = VOP_GETATTR(odvp, &obdva, 0, cs->cr, NULL);
if (!error) {
nbdva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(ndvp, &nbdva, 0, cs->cr);
+ error = VOP_GETATTR(ndvp, &nbdva, 0, cs->cr, NULL);
}
if (error) {
*cs->statusp = resp->status = puterrno4(error);
@@ -4150,7 +4160,7 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.before, obdva.va_ctime)
NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.before, nbdva.va_ctime)
- if ((error = VOP_RENAME(odvp, onm, ndvp, nnm, cs->cr)) == 0 &&
+ if ((error = VOP_RENAME(odvp, onm, ndvp, nnm, cs->cr, NULL, 0)) == 0 &&
fp != NULL) {
struct vattr va;
vnode_t *tvp;
@@ -4163,7 +4173,7 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (tvp) {
va.va_mask = AT_NLINK;
- if (!VOP_GETATTR(tvp, &va, 0, cs->cr) &&
+ if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) &&
va.va_nlink == 0) {
/* The file is gone and so should the state */
if (in_crit_targ) {
@@ -4213,18 +4223,18 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* Get the initial "after" sequence number, if it fails, set to zero
*/
oidva.va_mask = AT_SEQ;
- if (VOP_GETATTR(odvp, &oidva, 0, cs->cr))
+ if (VOP_GETATTR(odvp, &oidva, 0, cs->cr, NULL))
oidva.va_seq = 0;
nidva.va_mask = AT_SEQ;
- if (VOP_GETATTR(ndvp, &nidva, 0, cs->cr))
+ if (VOP_GETATTR(ndvp, &nidva, 0, cs->cr, NULL))
nidva.va_seq = 0;
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(odvp, 0, cs->cr);
- (void) VOP_FSYNC(ndvp, 0, cs->cr);
+ (void) VOP_FSYNC(odvp, 0, cs->cr, NULL);
+ (void) VOP_FSYNC(ndvp, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
@@ -4236,13 +4246,13 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* before value.
*/
oadva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(odvp, &oadva, 0, cs->cr)) {
+ if (VOP_GETATTR(odvp, &oadva, 0, cs->cr, NULL)) {
oadva.va_ctime = obdva.va_ctime;
oadva.va_seq = 0;
}
nadva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(odvp, &nadva, 0, cs->cr)) {
+ if (VOP_GETATTR(odvp, &nadva, 0, cs->cr, NULL)) {
nadva.va_ctime = nbdva.va_ctime;
nadva.va_seq = 0;
}
@@ -4282,7 +4292,8 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/*
* Already know that nnm will be a valid string
*/
- error = VOP_LOOKUP(ndvp, nnm, &vp, NULL, 0, NULL, cs->cr);
+ error = VOP_LOOKUP(ndvp, nnm, &vp, NULL, 0, NULL, cs->cr,
+ NULL, NULL, NULL);
kmem_free(nnm, nlen);
if (!error) {
add_volrnm_fh(cs->exi, vp);
@@ -4435,7 +4446,7 @@ rfs4_verify_attr(struct nfs4_svgetit_arg *sargp,
* on the incoming values.
*/
ret_error = VOP_GETATTR(sargp->cs->vp, sargp->vap, 0,
- sargp->cs->cr);
+ sargp->cs->cr, NULL);
if (ret_error) {
if (resp == NULL)
return (ret_error);
@@ -4710,7 +4721,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
vattr_t va;
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cs->cr);
+ error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
if (error) {
status = puterrno4(error);
goto done;
@@ -4726,15 +4737,15 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
if (sarg.vap->va_mask & AT_SIZE) {
trunc = (sarg.vap->va_size == 0);
status = rfs4_check_stateid(FWRITE, cs->vp, stateid,
- trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE);
+ trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct);
if (status != NFS4_OK)
goto done;
+ } else {
+ ct.cc_sysid = 0;
+ ct.cc_pid = 0;
+ ct.cc_caller_id = nfs4_srv_caller_id;
}
- ct.cc_sysid = 0;
- ct.cc_pid = 0;
- ct.cc_caller_id = nfs4_srv_caller_id;
-
/* XXX start of possible race with delegations */
/*
@@ -4776,7 +4787,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
}
bva.va_mask = AT_UID|AT_SIZE;
- if (error = VOP_GETATTR(vp, &bva, 0, cr)) {
+ if (error = VOP_GETATTR(vp, &bva, 0, cr, &ct)) {
status = puterrno4(error);
goto done;
}
@@ -4789,7 +4800,8 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
offset = bva.va_size;
length = sarg.vap->va_size - bva.va_size;
}
- if (nbl_conflict(vp, NBL_WRITE, offset, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
+ &ct)) {
status = NFS4ERR_LOCKED;
goto done;
}
@@ -4857,7 +4869,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
/*
* Set response bitmap
*/
@@ -5067,6 +5079,7 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
bool_t *deleg = &cs->deleg;
nfsstat4 stat;
int in_crit = 0;
+ caller_context_t ct;
vp = cs->vp;
if (vp == NULL) {
@@ -5080,6 +5093,12 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
cr = cs->cr;
+ if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE,
+ deleg, TRUE, &ct)) != NFS4_OK) {
+ *cs->statusp = resp->status = stat;
+ goto out;
+ }
+
/*
* We have to enter the critical region before calling VOP_RWLOCK
* to avoid a deadlock with ufs.
@@ -5088,20 +5107,14 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
nbl_start_crit(vp, RW_READER);
in_crit = 1;
if (nbl_conflict(vp, NBL_WRITE,
- args->offset, args->data_len, 0)) {
+ args->offset, args->data_len, 0, &ct)) {
*cs->statusp = resp->status = NFS4ERR_LOCKED;
goto out;
}
}
- if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE,
- deleg, TRUE)) != NFS4_OK) {
- *cs->statusp = resp->status = stat;
- goto out;
- }
-
bva.va_mask = AT_MODE | AT_UID;
- error = VOP_GETATTR(vp, &bva, 0, cr);
+ error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
/*
* If we can't get the attributes, then we can't do the
@@ -5124,7 +5137,7 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (crgetuid(cr) != bva.va_uid &&
- (error = VOP_ACCESS(vp, VWRITE, 0, cr))) {
+ (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct))) {
*cs->statusp = resp->status = puterrno4(error);
goto out;
}
@@ -5210,7 +5223,7 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
*/
savecred = curthread->t_cred;
curthread->t_cred = cr;
- error = do_io(FWRITE, vp, &uio, ioflag, cr);
+ error = do_io(FWRITE, vp, &uio, ioflag, cr, &ct);
curthread->t_cred = savecred;
if (iovp != iov)
@@ -5478,6 +5491,8 @@ static void lock_print(char *str, int operation, struct flock64 *flk)
break;
case F_SETLK: op = "F_SETLK";
break;
+ case F_SETLK_NBMAND: op = "F_SETLK_NBMAND";
+ break;
default: op = "F_UNKNOWN";
break;
}
@@ -5562,7 +5577,7 @@ rfs4_lookupfile(component4 *component, struct svc_req *req,
/* Get "before" change value */
bva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bva, 0, cs->cr);
+ error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL);
if (error)
return (puterrno4(error));
@@ -5580,7 +5595,7 @@ rfs4_lookupfile(component4 *component, struct svc_req *req,
* before value.
*/
ava.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &ava, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) {
ava.va_ctime = bva.va_ctime;
ava.va_seq = 0;
}
@@ -5590,7 +5605,7 @@ rfs4_lookupfile(component4 *component, struct svc_req *req,
* Validate the file is a file
*/
fva.va_mask = AT_TYPE|AT_MODE;
- error = VOP_GETATTR(cs->vp, &fva, 0, cs->cr);
+ error = VOP_GETATTR(cs->vp, &fva, 0, cs->cr, NULL);
if (error)
return (puterrno4(error));
@@ -5638,7 +5653,7 @@ tryagain:
*/
*created = TRUE;
- error = VOP_CREATE(dvp, nm, vap, EXCL, VWRITE, vpp, cr, 0);
+ error = VOP_CREATE(dvp, nm, vap, EXCL, VWRITE, vpp, cr, 0, NULL, NULL);
if (error) {
*created = FALSE;
@@ -5659,7 +5674,8 @@ tryagain:
status = puterrno4(error);
return (status);
}
- error = VOP_LOOKUP(dvp, nm, vpp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, nm, vpp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error) {
/*
@@ -5693,7 +5709,7 @@ tryagain:
/* Check for duplicate request */
ASSERT(mtime != 0);
va.va_mask = AT_MTIME;
- error = VOP_GETATTR(*vpp, &va, 0, cr);
+ error = VOP_GETATTR(*vpp, &va, 0, cr, NULL);
if (!error) {
/* We found the file */
if (va.va_mtime.tv_sec != mtime->tv_sec ||
@@ -5740,14 +5756,14 @@ check_open_access(uint32_t access,
return (NFS4ERR_ROFS);
if (access & OPEN4_SHARE_ACCESS_READ) {
- if ((VOP_ACCESS(vp, VREAD, 0, cr) != 0) &&
- (VOP_ACCESS(vp, VEXEC, 0, cr) != 0)) {
+ if ((VOP_ACCESS(vp, VREAD, 0, cr, NULL) != 0) &&
+ (VOP_ACCESS(vp, VEXEC, 0, cr, NULL) != 0)) {
return (NFS4ERR_ACCESS);
}
}
if (access & OPEN4_SHARE_ACCESS_WRITE) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (error)
return (NFS4ERR_ACCESS);
}
@@ -5821,7 +5837,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
}
bva.va_mask = AT_TYPE|AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bva, 0, cs->cr);
+ error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL);
if (error) {
kmem_free(nm, buflen);
return (puterrno4(error));
@@ -5968,7 +5984,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
* set to zero, time to before.
*/
iva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &iva, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) {
iva.va_seq = 0;
iva.va_ctime = bva.va_ctime;
}
@@ -5992,14 +6008,14 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
* The entry was created, we need to sync the
* directory metadata.
*/
- (void) VOP_FSYNC(dvp, 0, cs->cr);
+ (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
/*
* Get "after" change value, if it fails, simply return the
* before value.
*/
ava.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &ava, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) {
ava.va_ctime = bva.va_ctime;
ava.va_seq = 0;
}
@@ -6027,7 +6043,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
/* Assume the worst */
cs->mandlock = TRUE;
- if (VOP_GETATTR(vp, &cva, 0, cs->cr) == 0) {
+ if (VOP_GETATTR(vp, &cva, 0, cs->cr, NULL) == 0) {
cs->mandlock = MANDLOCK(cs->vp, cva.va_mode);
/*
@@ -6065,7 +6081,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
nbl_start_crit(vp, RW_READER);
if (nbl_conflict(vp, NBL_WRITE, 0,
- cva.va_size, 0)) {
+ cva.va_size, 0, NULL)) {
in_crit = 0;
nbl_end_crit(vp);
VN_RELE(vp);
@@ -6090,7 +6106,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cs->cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
if (error) {
VN_RELE(vp);
@@ -6127,7 +6143,7 @@ static void
rfs4_do_open(struct compound_state *cs, struct svc_req *req,
rfs4_openowner_t *oo, delegreq_t deleg,
uint32_t access, uint32_t deny,
- OPEN4res *resp)
+ OPEN4res *resp, int deleg_cur)
{
/* XXX Currently not using req */
rfs4_state_t *state;
@@ -6141,9 +6157,11 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
struct shr_locowner shr_loco;
sysid_t sysid;
nfsstat4 status;
+ caller_context_t ct;
int fflags = 0;
int recall = 0;
int err;
+ int cmd;
/* get the file struct and hold a lock on it during initial open */
file = rfs4_findfile_withlock(cs->vp, &cs->fh, &fcreate);
@@ -6175,6 +6193,12 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
return;
}
+ /* Calculate the fflags for this OPEN. */
+ if (access & OPEN4_SHARE_ACCESS_READ)
+ fflags |= FREAD;
+ if (access & OPEN4_SHARE_ACCESS_WRITE)
+ fflags |= FWRITE;
+
/*
* Calculate the new deny and access mode that this open is adding to
* the file for this open owner;
@@ -6203,13 +6227,8 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
shr.s_owner = (caddr_t)&shr_loco;
shr.s_own_len = sizeof (shr_loco);
- fflags = 0;
- if (access & OPEN4_SHARE_ACCESS_READ)
- fflags |= FREAD;
- if (access & OPEN4_SHARE_ACCESS_WRITE)
- fflags |= FWRITE;
-
- if ((err = vop_shrlock(cs->vp, F_SHARE, &shr, fflags)) != 0) {
+ cmd = nbl_need_check(cs->vp) ? F_SHARE_NBMAND : F_SHARE;
+ if ((err = vop_shrlock(cs->vp, cmd, &shr, fflags)) != 0) {
resp->status = err == EAGAIN ?
NFS4ERR_SHARE_DENIED : puterrno4(err);
@@ -6243,12 +6262,6 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
rfs4_dbe_unlock(state->dbe);
rfs4_file_rele(file);
rfs4_update_lease(state->owner->client);
- /* recalculate flags to match what was added */
- fflags = 0;
- if (amodes & OPEN4_SHARE_ACCESS_READ)
- fflags |= FREAD;
- if (amodes & OPEN4_SHARE_ACCESS_WRITE)
- fflags |= FWRITE;
(void) vop_shrlock(cs->vp, F_UNSHARE, &shr, fflags);
/* Not a fully formed open; "close" it */
if (screate == TRUE)
@@ -6258,6 +6271,49 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
return;
}
}
+ /*
+ * the share check passed and any delegation conflict has been
+ * taken care of, now call vop_open.
+ * if this is the first open then call vop_open with fflags.
+ * if not, call vn_open_upgrade with just the upgrade flags.
+ *
+ * if the file has been opened already, it will have the current
+ * access mode in the state struct. if it has no share access, then
+ * this is a new open.
+ *
+ * However, if this is open with CLAIM_DLEGATE_CUR, then don't
+ * call VOP_OPEN(), just do the open upgrade.
+ */
+ if (((state->share_access & OPEN4_SHARE_ACCESS_BOTH) == 0) &&
+ !deleg_cur) {
+ ct.cc_sysid = sysid;
+ ct.cc_pid = shr.s_pid;
+ ct.cc_caller_id = nfs4_srv_caller_id;
+ err = VOP_OPEN(&cs->vp, fflags, cs->cr, &ct);
+ if (err) {
+ rfs4_dbe_unlock(file->dbe);
+ rfs4_dbe_unlock(state->dbe);
+ rfs4_file_rele(file);
+ (void) vop_shrlock(cs->vp, F_UNSHARE, &shr, fflags);
+ /* Not a fully formed open; "close" it */
+ if (screate == TRUE)
+ rfs4_state_close(state, FALSE, FALSE, cs->cr);
+ rfs4_state_rele(state);
+ resp->status = NFS4ERR_SERVERFAULT;
+ return;
+ }
+ } else { /* open upgrade */
+ /*
+ * calculate the fflags for the new mode that is being added
+ * by this upgrade.
+ */
+ fflags = 0;
+ if (amodes & OPEN4_SHARE_ACCESS_READ)
+ fflags |= FREAD;
+ if (amodes & OPEN4_SHARE_ACCESS_WRITE)
+ fflags |= FWRITE;
+ vn_open_upgrade(cs->vp, fflags);
+ }
if (dmodes & OPEN4_SHARE_DENY_READ)
file->deny_read++;
@@ -6328,7 +6384,7 @@ rfs4_do_opennull(struct compound_state *cs, struct svc_req *req,
/* cs->vp cs->fh now reference the desired file */
rfs4_do_open(cs, req, oo, DELEG_ANY, args->share_access,
- args->share_deny, resp);
+ args->share_deny, resp, 0);
/*
* If rfs4_createfile set attrset, we must
@@ -6367,7 +6423,7 @@ rfs4_do_openprev(struct compound_state *cs, struct svc_req *req,
}
va.va_mask = AT_MODE|AT_UID;
- error = VOP_GETATTR(cs->vp, &va, 0, cs->cr);
+ error = VOP_GETATTR(cs->vp, &va, 0, cs->cr, NULL);
if (error) {
resp->status = puterrno4(error);
return;
@@ -6398,7 +6454,7 @@ rfs4_do_openprev(struct compound_state *cs, struct svc_req *req,
rfs4_do_open(cs, req, oo,
NFS4_DELEG4TYPE2REQTYPE(args->open_claim4_u.delegate_type),
- args->share_access, args->share_deny, resp);
+ args->share_access, args->share_deny, resp, 0);
}
static void
@@ -6452,7 +6508,7 @@ rfs4_do_opendelcur(struct compound_state *cs, struct svc_req *req,
dsp->finfo->dinfo->time_lastwrite = gethrestime_sec();
rfs4_deleg_state_rele(dsp);
rfs4_do_open(cs, req, oo, DELEG_NONE,
- args->share_access, args->share_deny, resp);
+ args->share_access, args->share_deny, resp, 1);
}
/*ARGSUSED*/
@@ -7043,6 +7099,7 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
nfsstat4 status;
rfs4_state_t *sp;
rfs4_file_t *fp;
+ int fflags = 0;
if (cs->vp == NULL) {
*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
@@ -7121,7 +7178,7 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
* Check that no invalid bits are set.
*/
if ((access & ~(OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WRITE)) ||
- (deny & ~(OPEN4_SHARE_DENY_READ | OPEN4_SHARE_DENY_READ))) {
+ (deny & ~(OPEN4_SHARE_DENY_READ | OPEN4_SHARE_DENY_WRITE))) {
*cs->statusp = resp->status = NFS4ERR_INVAL;
rfs4_update_open_sequence(sp->owner);
rfs4_dbe_unlock(sp->dbe);
@@ -7193,26 +7250,30 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
* If the current mode has access read and the new mode
* does not, decrement the number of access read mode bits
* and if it goes to zero turn off the access read bit
- * on the file.
+ * on the file. set fflags to FREAD for the call to
+ * vn_open_downgrade().
*/
if ((sp->share_access & OPEN4_SHARE_ACCESS_READ) &&
(access & OPEN4_SHARE_ACCESS_READ) == 0) {
fp->access_read--;
if (fp->access_read == 0)
fp->share_access &= ~OPEN4_SHARE_ACCESS_READ;
+ fflags |= FREAD;
}
/*
* If the current mode has access write and the new mode
* does not, decrement the number of access write mode bits
* and if it goes to zero turn off the access write bit
- * on the file.
+ * on the file. set fflags to FWRITE for the call to
+ * vn_open_downgrade().
*/
if ((sp->share_access & OPEN4_SHARE_ACCESS_WRITE) &&
(access & OPEN4_SHARE_ACCESS_WRITE) == 0) {
fp->access_write--;
if (fp->access_write == 0)
fp->share_deny &= ~OPEN4_SHARE_ACCESS_WRITE;
+ fflags |= FWRITE;
}
/* Set the new access and deny modes */
@@ -7224,12 +7285,21 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
rfs4_dbe_unlock(fp->dbe);
rfs4_dbe_unlock(sp->dbe);
+
if ((status = rfs4_share(sp)) != NFS4_OK) {
*cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
rfs4_update_open_sequence(sp->owner);
goto end;
}
+ /*
+ * we successfully downgraded the share lock, now we need to downgrade
+ * the open. it is possible that the downgrade was only for a deny
+ * mode and we have nothing else to do.
+ */
+ if ((fflags & (FREAD|FWRITE)) != 0)
+ vn_open_downgrade(cs->vp, fflags);
+
rfs4_dbe_lock(sp->dbe);
/* Update the stateid */
@@ -7719,7 +7789,7 @@ rfs4_release_share_lock_state(rfs4_state_t *sp, cred_t *cr,
flk.l_pid = 0;
(void) VOP_FRLOCK(sp->finfo->vp, F_SETLK, &flk,
F_REMOTELOCK | FREAD | FWRITE,
- (u_offset_t)0, NULL, CRED());
+ (u_offset_t)0, NULL, CRED(), NULL);
}
sp->owner->client->unlksys_completed = TRUE;
@@ -7757,6 +7827,8 @@ rfs4_release_share_lock_state(rfs4_state_t *sp, cred_t *cr,
shr.s_own_len = sizeof (shr_loco);
(void) vop_shrlock(sp->finfo->vp, F_UNSHARE, &shr, fflags);
}
+
+ (void) VOP_CLOSE(fp->vp, fflags, 1, (offset_t)0, cr, NULL);
}
/*
@@ -7819,14 +7891,16 @@ setlock(vnode_t *vp, struct flock64 *flock, int flag, cred_t *cred)
struct flock64 flk;
int i;
clock_t delaytime;
+ int cmd;
+ cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK;
retry:
delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
for (i = 0; i < rfs4_maxlock_tries; i++) {
- LOCK_PRINT(rfs4_debug, "setlock", F_SETLK, flock);
- error = VOP_FRLOCK(vp, F_SETLK,
- flock, flag, (u_offset_t)0, NULL, cred);
+ LOCK_PRINT(rfs4_debug, "setlock", cmd, flock);
+ error = VOP_FRLOCK(vp, cmd,
+ flock, flag, (u_offset_t)0, NULL, cred, NULL);
if (error != EAGAIN && error != EACCES)
break;
@@ -7841,8 +7915,8 @@ retry:
/* Get the owner of the lock */
flk = *flock;
LOCK_PRINT(rfs4_debug, "setlock", F_GETLK, &flk);
- if (VOP_FRLOCK(vp, F_GETLK,
- &flk, flag, (u_offset_t)0, NULL, cred) == 0) {
+ if (VOP_FRLOCK(vp, F_GETLK, &flk, flag,
+ (u_offset_t)0, NULL, cred, NULL) == 0) {
if (flk.l_type == F_UNLCK) {
/* No longer locked, retry */
goto retry;
@@ -8618,7 +8692,7 @@ retry:
goto out;
}
error = VOP_FRLOCK(cs->vp, F_GETLK, &flk, flag, (u_offset_t)0,
- NULL, cs->cr);
+ NULL, cs->cr, NULL);
/*
* N.B. We map error values to nfsv4 errors. This is differrent
@@ -8661,11 +8735,11 @@ vop_shrlock(vnode_t *vp, int cmd, struct shrlock *sp, int fflags)
if (cmd == F_UNSHARE && sp->s_deny == 0 && sp->s_access == 0)
return (0);
- err = VOP_SHRLOCK(vp, cmd, sp, fflags, CRED());
+ err = VOP_SHRLOCK(vp, cmd, sp, fflags, CRED(), NULL);
NFS4_DEBUG(rfs4_shrlock_debug,
(CE_NOTE, "rfs4_shrlock %s vp=%p acc=%d dny=%d sysid=%d "
- "pid=%d err=%d\n", cmd == F_SHARE ? "SHARE" : "UNSHR",
+ "pid=%d err=%d\n", cmd == F_UNSHARE ? "UNSHR" : "SHARE",
(void *) vp, sp->s_access, sp->s_deny, sp->s_sysid, sp->s_pid,
err));
@@ -8706,7 +8780,9 @@ rfs4_shrlock(rfs4_state_t *sp, int cmd)
static int
rfs4_share(rfs4_state_t *sp)
{
- return (rfs4_shrlock(sp, F_SHARE));
+ int cmd;
+ cmd = nbl_need_check(sp->finfo->vp) ? F_SHARE_NBMAND : F_SHARE;
+ return (rfs4_shrlock(sp, cmd));
}
void
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
index 9b5d9e2301..11a940f199 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,7 +37,7 @@ void rfs4_init_compound_state(struct compound_state *);
bitmap4 rfs4_supported_attrs;
int MSG_PRT_DEBUG = FALSE;
-/* If building with DEBUG enabled, enable mandattr tuneable by default */
+/* If building with DEBUG enabled, enable mandattr tunable by default */
#ifdef DEBUG
#ifndef RFS4_SUPPORT_MANDATTR_ONLY
#define RFS4_SUPPORT_MANDATTR_ONLY
@@ -575,7 +575,7 @@ rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
*/
if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
error = VOP_PATHCONF(sarg->cs->vp, _PC_XATTR_EXISTS,
- &val, sarg->cs->cr);
+ &val, sarg->cs->cr, NULL);
if (error)
break;
} else
@@ -592,7 +592,7 @@ rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
ASSERT(sarg->cs->vp != NULL);
if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
error = VOP_PATHCONF(sarg->cs->vp, _PC_XATTR_EXISTS,
- &val, sarg->cs->cr);
+ &val, sarg->cs->cr, NULL);
if (error)
break;
} else
@@ -863,7 +863,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* see which ACLs fs supports */
error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error != 0) {
/*
* If we got an error, then the filesystem
@@ -902,7 +902,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* get the ACL, and translate it into nfsace4 style */
error = VOP_GETSECATTR(vp, &vs_native,
- 0, sarg->cs->cr);
+ 0, sarg->cs->cr, NULL);
if (error != 0)
break;
if (whichacl & _ACL_ACE_ENABLED) {
@@ -942,7 +942,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
-
+ vs_ace4.vsa_aclentsz = vs_ace4.vsa_aclcnt * sizeof (ace_t);
/* make sure we have correct owner/group */
if ((vap->va_mask & (AT_UID | AT_GID)) !=
(AT_UID | AT_GID)) {
@@ -956,7 +956,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* see which ACLs the fs supports */
error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error != 0) {
/*
* If we got an error, then the filesystem
@@ -991,7 +991,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
break;
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
error = VOP_SETSECATTR(vp, &vs_native,
- 0, sarg->cs->cr);
+ 0, sarg->cs->cr, NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
vs_acet_destroy(&vs_native);
} else if (whichacl & _ACL_ACLENT_ENABLED) {
@@ -1002,7 +1002,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
break;
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
error = VOP_SETSECATTR(vp, &vs_native,
- 0, sarg->cs->cr);
+ 0, sarg->cs->cr, NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
vs_aent_destroy(&vs_native);
}
@@ -1097,7 +1097,7 @@ rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/*
* XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
- * case insenstive.
+ * case insensitive.
*/
/* ARGSUSED */
static int
@@ -1191,7 +1191,7 @@ rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp,
- _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr);
+ _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
if (error)
break;
@@ -1206,7 +1206,7 @@ rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp,
- _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr);
+ _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
if (error)
break;
if (na->chown_restricted != (val == 1))
@@ -1559,7 +1559,7 @@ rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error)
break;
if (val >= (sizeof (uint64_t) * 8))
@@ -1576,7 +1576,7 @@ rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error)
break;
if (val >= (sizeof (uint64_t) * 8))
@@ -1615,7 +1615,7 @@ rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error == 0) {
na->maxlink = val;
}
@@ -1629,7 +1629,7 @@ rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (!error && (na->maxlink != (uint32_t)val))
error = -1; /* no match */
break;
@@ -1662,7 +1662,7 @@ rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error == 0) {
na->maxname = val;
}
@@ -1676,7 +1676,7 @@ rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (!error && (na->maxname != val))
error = -1; /* no match */
break;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c b/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c
index 691711e5a5..4c150e248f 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c
@@ -805,7 +805,7 @@ rfs4_vop_getattr(vnode_t *vp, vattr_t *vap, int flag, cred_t *cr)
int error;
mask = vap->va_mask;
- error = VOP_GETATTR(vp, vap, flag, cr);
+ error = VOP_GETATTR(vp, vap, flag, cr, NULL);
/*
* Some file systems clobber va_mask. it is probably wrong of
* them to do so, nonethless we practice defensive coding.
@@ -825,7 +825,7 @@ rfs4_vop_getattr(vnode_t *vp, vattr_t *vap, int flag, cred_t *cr)
int
rfs4_delegated_getattr(vnode_t *vp, vattr_t *vap, int flag, cred_t *cr)
{
- return (VOP_GETATTR(vp, vap, flag, cr));
+ return (VOP_GETATTR(vp, vap, flag, cr, NULL));
}
/*
@@ -1547,6 +1547,8 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
rfs4_deleg_state_t *dsp;
vnode_t *vp;
int open_prev = *recall;
+ int ret;
+ int fflags = 0;
ASSERT(rfs4_dbe_islocked(sp->dbe));
ASSERT(rfs4_dbe_islocked(fp->dbe));
@@ -1605,14 +1607,27 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
vp = fp->vp;
/* vnevent_support returns 0 if file system supports vnevents */
- if (vnevent_support(vp)) {
+ if (vnevent_support(vp, NULL)) {
rfs4_deleg_state_rele(dsp);
return (NULL);
}
+ /* Calculate the fflags for this OPEN. */
+ if (sp->share_access & OPEN4_SHARE_ACCESS_READ)
+ fflags |= FREAD;
+ if (sp->share_access & OPEN4_SHARE_ACCESS_WRITE)
+ fflags |= FWRITE;
+
*recall = 0;
+ /*
+ * Before granting a delegation we need to know if anyone else has
+ * opened the file in a conflicting mode. However, first we need to
+ * know how we opened the file to check the counts properly.
+ */
if (dtype == OPEN_DELEGATE_READ) {
- if (vn_is_opened(vp, V_WRITE) || vn_is_mapped(vp, V_WRITE)) {
+ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
+ (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
+ vn_is_mapped(vp, V_WRITE)) {
if (open_prev) {
*recall = 1;
} else {
@@ -1620,9 +1635,11 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
return (NULL);
}
}
- (void) fem_install(vp, deleg_rdops, (void *)fp, OPUNIQ,
+ ret = fem_install(vp, deleg_rdops, (void *)fp, OPUNIQ,
rfs4_mon_hold, rfs4_mon_rele);
- if (vn_is_opened(vp, V_WRITE) || vn_is_mapped(vp, V_WRITE)) {
+ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
+ (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
+ vn_is_mapped(vp, V_WRITE)) {
if (open_prev) {
*recall = 1;
} else {
@@ -1632,8 +1649,24 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
return (NULL);
}
}
+ /*
+ * Because a client can hold onto a delegation after the
+ * file has been closed, we need to keep track of the
+ * access to this file. Otherwise the CIFS server would
+ * not know about the client accessing the file and could
+ * inappropriately grant an OPLOCK.
+ * fem_install() returns EBUSY when asked to install a
+ * OPUNIQ monitor more than once. Therefore, check the
+ * return code because we only want this done once.
+ */
+ if (ret == 0)
+ vn_open_upgrade(vp, FREAD);
} else { /* WRITE */
- if (vn_is_opened(vp, V_RDORWR) || vn_is_mapped(vp, V_RDORWR)) {
+ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
+ (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
+ ((fflags & FREAD) && vn_has_other_opens(vp, V_READ)) ||
+ (((fflags & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
+ vn_is_mapped(vp, V_RDORWR)) {
if (open_prev) {
*recall = 1;
} else {
@@ -1641,9 +1674,13 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
return (NULL);
}
}
- (void) fem_install(vp, deleg_wrops, (void *)fp, OPUNIQ,
+ ret = fem_install(vp, deleg_wrops, (void *)fp, OPUNIQ,
rfs4_mon_hold, rfs4_mon_rele);
- if (vn_is_opened(vp, V_RDORWR) || vn_is_mapped(vp, V_RDORWR)) {
+ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
+ (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
+ ((fflags & FREAD) && vn_has_other_opens(vp, V_READ)) ||
+ (((fflags & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
+ vn_is_mapped(vp, V_RDORWR)) {
if (open_prev) {
*recall = 1;
} else {
@@ -1653,6 +1690,18 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
return (NULL);
}
}
+ /*
+ * Because a client can hold onto a delegation after the
+ * file has been closed, we need to keep track of the
+ * access to this file. Otherwise the CIFS server would
+ * not know about the client accessing the file and could
+ * inappropriately grant an OPLOCK.
+ * fem_install() returns EBUSY when asked to install a
+ * OPUNIQ monitor more than once. Therefore, check the
+ * return code because we only want this done once.
+ */
+ if (ret == 0)
+ vn_open_upgrade(vp, FREAD|FWRITE);
}
/* Place on delegation list for file */
insque(&dsp->delegationlist, fp->delegationlist.prev);
@@ -1697,12 +1746,22 @@ rfs4_return_deleg(rfs4_deleg_state_t *dsp, bool_t revoked)
/* if file system was unshared, the vp will be NULL */
if (fp->vp != NULL) {
- if (dtypewas == OPEN_DELEGATE_READ)
+ /*
+ * Once a delegation is no longer held by any client,
+ * the monitor is uninstalled. At this point, the
+ * client must send OPEN otw, so we don't need the
+ * reference on the vnode anymore. The open
+ * downgrade removes the reference put on earlier.
+ */
+ if (dtypewas == OPEN_DELEGATE_READ) {
(void) fem_uninstall(fp->vp, deleg_rdops,
(void *)fp);
- else
+ vn_open_downgrade(fp->vp, FREAD);
+ } else if (dtypewas == OPEN_DELEGATE_WRITE) {
(void) fem_uninstall(fp->vp, deleg_wrops,
(void *)fp);
+ vn_open_downgrade(fp->vp, FREAD|FWRITE);
+ }
}
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
index 2d3cd81fba..d10f010be0 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
@@ -53,7 +53,7 @@ vop_fid_pseudo(vnode_t *vp, fid_t *fidp)
struct vattr va;
int error;
- error = VOP_FID(vp, fidp);
+ error = VOP_FID(vp, fidp, NULL);
/*
* XXX nfs4_fid() does nothing and returns EREMOTE.
@@ -68,7 +68,7 @@ vop_fid_pseudo(vnode_t *vp, fid_t *fidp)
(error == 0 && fidp->fid_len > NFS_FH4MAXDATA)) {
va.va_mask = AT_NODEID;
- error = VOP_GETATTR(vp, &va, 0, CRED());
+ error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
if (error)
return (error);
@@ -449,7 +449,7 @@ less_visible(struct exportinfo *exi, struct exp_visible *vis_head)
* PSEUDO - a pseudo node
* vis - visible list
* f# - security flavor#
- * (f#) - security flavor# propagated from its decendents
+ * (f#) - security flavor# propagated from its descendents
* "" - covered vnode
*
*
@@ -557,7 +557,7 @@ treeclimb_export(struct exportinfo *exip)
* for this vnode.
*/
va.va_mask = AT_NODEID;
- error = VOP_GETATTR(vp, &va, 0, CRED());
+ error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
if (error)
break;
@@ -579,7 +579,8 @@ treeclimb_export(struct exportinfo *exip)
/*
* Now, do a ".." to find parent dir of vp.
*/
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error == ENOTDIR && exportdir) {
dvp = exip->exi_dvp;
@@ -709,7 +710,8 @@ treeclimb_unexport(struct exportinfo *exip)
/*
* Do a ".." to find parent dir of vp.
*/
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error == ENOTDIR && exportdir) {
dvp = exip->exi_dvp;
@@ -813,7 +815,8 @@ get_root_export(struct exportinfo *exip)
/*
* Now, do a ".." to find parent dir of vp.
*/
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error) {
exi = NULL;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c b/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
index 70852fbbe0..3f810b96b3 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -115,7 +114,8 @@ nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp,
*vpp = vp = NULL;
- if (error = VOP_LOOKUP(dvp, d_name, &vp, NULL, 0, NULL, cs->cr))
+ if (error = VOP_LOOKUP(dvp, d_name, &vp, NULL, 0, NULL, cs->cr,
+ NULL, NULL, NULL))
return (error);
/* Is this object mounted upon? */
@@ -152,7 +152,7 @@ nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp,
* etc.), then return attrs for stub instead of VROOT object.
* If it fails for any other reason, then return the error.
*/
- if (error = VOP_FID(vp, &fid)) {
+ if (error = VOP_FID(vp, &fid, NULL)) {
if (ismntpt == 0) {
VN_RELE(vp);
return (error);
@@ -232,7 +232,8 @@ rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr)
if (ar & FATTR4_MAXFILESIZE_MASK) {
/* Maximum File Size */
- if (error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &pc_val, cr))
+ if (error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &pc_val, cr,
+ NULL))
return (error);
if (pc_val >= (sizeof (uint64_t) * 8))
@@ -243,7 +244,7 @@ rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr)
if (ar & FATTR4_MAXLINK_MASK) {
/* Maximum Link Count */
- if (error = VOP_PATHCONF(vp, _PC_LINK_MAX, &pc_val, cr))
+ if (error = VOP_PATHCONF(vp, _PC_LINK_MAX, &pc_val, cr, NULL))
return (error);
pce->maxlink = pc_val;
@@ -251,7 +252,7 @@ rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr)
if (ar & FATTR4_MAXNAME_MASK) {
/* Maximum Name Length */
- if (error = VOP_PATHCONF(vp, _PC_NAME_MAX, &pc_val, cr))
+ if (error = VOP_PATHCONF(vp, _PC_NAME_MAX, &pc_val, cr, NULL))
return (error);
pce->maxname = pc_val;
@@ -441,7 +442,7 @@ rfs4_op_readdir(nfs_argop4 *argop, nfs_resop4 *resop,
return;
}
- error = VOP_ACCESS(dvp, VREAD, 0, cs->cr);
+ error = VOP_ACCESS(dvp, VREAD, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
return;
@@ -610,7 +611,7 @@ readagain:
(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dvp, &uio, cs->cr, &iseofdir);
+ error = VOP_READDIR(dvp, &uio, cs->cr, &iseofdir, NULL, 0);
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
@@ -788,7 +789,7 @@ reencode_attrs:
} else {
va.va_mask = AT_ALL;
rddirattr_error =
- VOP_GETATTR(vp, &va, 0, cs->cr);
+ VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
if (rddirattr_error)
ae = ar & (FATTR4_RDATTR_ERROR_MASK |
FATTR4_MOUNTED_ON_FILEID_MASK);
@@ -877,7 +878,7 @@ reencode_attrs:
} else {
(void) VOP_PATHCONF(vp,
_PC_XATTR_EXISTS,
- &pc_val, cs->cr);
+ &pc_val, cs->cr, NULL);
}
isit = (pc_val ? TRUE : FALSE);
IXDR_PUT_U_INT32(ptr, isit);
@@ -965,7 +966,7 @@ reencode_attrs:
pc_val = FALSE;
(void) VOP_PATHCONF(vp,
_PC_CHOWN_RESTRICTED,
- &pc_val, cs->cr);
+ &pc_val, cs->cr, NULL);
isit = (pc_val ? TRUE : FALSE);
IXDR_PUT_U_INT32(ptr, isit);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_state.c b/usr/src/uts/common/fs/nfs/nfs4_state.c
index 2674fa8de7..5417ab3326 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_state.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_state.c
@@ -41,6 +41,7 @@
#include <sys/sdt.h>
#include <sys/nvpair.h>
+extern u_longlong_t nfs4_srv_caller_id;
extern time_t rfs4_start_time;
extern uint_t nfs4_srv_vkey;
@@ -493,17 +494,17 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
}
if (vp->v_type != VREG) {
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (NULL);
}
- err = VOP_ACCESS(vp, VREAD, 0, CRED());
+ err = VOP_ACCESS(vp, VREAD, 0, CRED(), NULL);
if (err) {
/*
* We don't have read access? better get the heck out.
*/
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (NULL);
}
@@ -513,17 +514,17 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
* get the file size to do some basic validation
*/
va.va_mask = AT_SIZE;
- err = VOP_GETATTR(vp, &va, 0, CRED());
+ err = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
kill_file = (va.va_size == 0 || va.va_size <
(NFS4_VERIFIER_SIZE + sizeof (uint_t)+1));
if (err || kill_file) {
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (kill_file) {
- (void) VOP_REMOVE(dvp, ss_pn->leaf, CRED());
+ (void) VOP_REMOVE(dvp, ss_pn->leaf, CRED(), NULL, 0);
}
return (NULL);
}
@@ -548,7 +549,7 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
if (err = VOP_READ(vp, &uio, FREAD, CRED(), NULL)) {
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
return (NULL);
@@ -565,11 +566,11 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
if (err || kill_file) {
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
if (kill_file) {
- (void) VOP_REMOVE(dvp, ss_pn->leaf, CRED());
+ (void) VOP_REMOVE(dvp, ss_pn->leaf, CRED(), NULL, 0);
}
return (NULL);
}
@@ -588,7 +589,7 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
if (err = VOP_READ(vp, &uio, FREAD, CRED(), NULL)) {
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
kmem_free(cl_ss->cl_id4.id_val, id_len);
kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
@@ -596,7 +597,7 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
}
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (cl_ss);
}
@@ -629,7 +630,7 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
if (vn_open(statedir, UIO_SYSSPACE, FREAD, 0, &dvp, 0, 0))
return;
- if (dvp->v_type != VDIR || VOP_ACCESS(dvp, VREAD, 0, CRED()))
+ if (dvp->v_type != VDIR || VOP_ACCESS(dvp, VREAD, 0, CRED(), NULL))
goto out;
dirt = kmem_alloc(RFS4_SS_DIRSIZE, KM_SLEEP);
@@ -647,7 +648,7 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
uio.uio_loffset = dirchunk_offset;
uio.uio_resid = RFS4_SS_DIRSIZE;
- err = VOP_READDIR(dvp, &uio, CRED(), &dir_eof);
+ err = VOP_READDIR(dvp, &uio, CRED(), &dir_eof, NULL, 0);
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
if (err)
goto out;
@@ -690,7 +691,7 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
}
out:
- (void) VOP_CLOSE(dvp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(dvp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(dvp);
if (dirt)
kmem_free((caddr_t)dirt, RFS4_SS_DIRSIZE);
@@ -1047,7 +1048,7 @@ rfs4_ss_clid_write_one(rfs4_client_t *cp, char *dss_path, char *leaf)
(void) VOP_WRITE(vp, &uio, ioflag, CRED(), NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
@@ -3425,11 +3426,11 @@ out:
/*
* Given the I/O mode (FREAD or FWRITE), the vnode, the stateid and whether
- * the file is being truncated, return NFS4_OK if allowed or approriate
+ * the file is being truncated, return NFS4_OK if allowed or appropriate
* V4 error if not. Note NFS4ERR_DELAY will be returned and a recall on
* the associated file will be done if the I/O is not consistent with any
* delegation in effect on the file. Should be holding VOP_RWLOCK, either
- * as reader or writer as appropriate. rfs4_op_open will accquire the
+ * as reader or writer as appropriate. rfs4_op_open will acquire the
* VOP_RWLOCK as writer when setting up delegation. If the stateid is bad
* this routine will return NFS4ERR_BAD_STATEID. In addition, through the
* deleg parameter, we will return whether a write delegation is held by
@@ -3441,7 +3442,7 @@ out:
nfsstat4
rfs4_check_stateid(int mode, vnode_t *vp,
stateid4 *stateid, bool_t trunc, bool_t *deleg,
- bool_t do_access)
+ bool_t do_access, caller_context_t *ct)
{
rfs4_file_t *fp;
bool_t create = FALSE;
@@ -3451,6 +3452,12 @@ rfs4_check_stateid(int mode, vnode_t *vp,
stateid_t *id = (stateid_t *)stateid;
nfsstat4 stat = NFS4_OK;
+ if (ct != NULL) {
+ ct->cc_sysid = 0;
+ ct->cc_pid = 0;
+ ct->cc_caller_id = nfs4_srv_caller_id;
+ }
+
if (ISSPECIAL(stateid)) {
fp = rfs4_findfile(vp, NULL, &create);
if (fp == NULL)
@@ -3504,6 +3511,10 @@ rfs4_check_stateid(int mode, vnode_t *vp,
return (NFS4ERR_BAD_STATEID);
}
}
+ if (ct != NULL) {
+ ct->cc_sysid = lsp->locker->client->sysidt;
+ ct->cc_pid = lsp->locker->pid;
+ }
rfs4_lo_state_rele(lsp, FALSE);
}
@@ -3832,13 +3843,19 @@ rfs4_file_walk_callout(rfs4_entry_t u_entry, void *e)
if (fp->vp) {
vnode_t *vp = fp->vp;
- /* don't leak monitors */
- if (fp->dinfo->dtype == OPEN_DELEGATE_READ)
+ /*
+ * don't leak monitors and remove the reference
+ * put on the vnode when the delegation was granted.
+ */
+ if (fp->dinfo->dtype == OPEN_DELEGATE_READ) {
(void) fem_uninstall(vp, deleg_rdops,
(void *)fp);
- else if (fp->dinfo->dtype == OPEN_DELEGATE_WRITE)
+ vn_open_downgrade(vp, FREAD);
+ } else if (fp->dinfo->dtype == OPEN_DELEGATE_WRITE) {
(void) fem_uninstall(vp, deleg_wrops,
(void *)fp);
+ vn_open_downgrade(vp, FREAD|FWRITE);
+ }
mutex_enter(&vp->v_lock);
(void) vsd_set(vp, nfs4_srv_vkey, NULL);
mutex_exit(&vp->v_lock);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
index c6893a13f3..92686ef99d 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
@@ -152,40 +152,52 @@ typedef struct domount_args {
/*
* The vnode ops functions for a trigger stub vnode
*/
-static int nfs4_trigger_open(vnode_t **, int, cred_t *);
-static int nfs4_trigger_getattr(vnode_t *, struct vattr *, int, cred_t *);
-static int nfs4_trigger_setattr(vnode_t *, struct vattr *, int, cred_t *,
- caller_context_t *);
-static int nfs4_trigger_access(vnode_t *, int, int, cred_t *);
-static int nfs4_trigger_readlink(vnode_t *, struct uio *, cred_t *);
-static int nfs4_trigger_lookup(vnode_t *, char *, vnode_t **,
- struct pathname *, int, vnode_t *, cred_t *);
-static int nfs4_trigger_create(vnode_t *, char *, struct vattr *,
- enum vcexcl, int, vnode_t **, cred_t *, int);
-static int nfs4_trigger_remove(vnode_t *, char *, cred_t *);
-static int nfs4_trigger_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int nfs4_trigger_rename(vnode_t *, char *, vnode_t *, char *,
- cred_t *);
-static int nfs4_trigger_mkdir(vnode_t *, char *, struct vattr *,
- vnode_t **, cred_t *);
-static int nfs4_trigger_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
-static int nfs4_trigger_symlink(vnode_t *, char *, struct vattr *, char *,
- cred_t *);
-static int nfs4_trigger_cmp(vnode_t *, vnode_t *);
+static int nfs4_trigger_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int nfs4_trigger_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+static int nfs4_trigger_setattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+static int nfs4_trigger_access(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+static int nfs4_trigger_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int nfs4_trigger_lookup(vnode_t *, char *, vnode_t **,
+ struct pathname *, int, vnode_t *, cred_t *, caller_context_t *,
+ int *, pathname_t *);
+static int nfs4_trigger_create(vnode_t *, char *, struct vattr *,
+ enum vcexcl, int, vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+static int nfs4_trigger_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+ int);
+static int nfs4_trigger_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs4_trigger_rename(vnode_t *, char *, vnode_t *, char *,
+ cred_t *, caller_context_t *, int);
+static int nfs4_trigger_mkdir(vnode_t *, char *, struct vattr *,
+ vnode_t **, cred_t *, caller_context_t *, int, vsecattr_t *vsecp);
+static int nfs4_trigger_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+static int nfs4_trigger_symlink(vnode_t *, char *, struct vattr *, char *,
+ cred_t *, caller_context_t *, int);
+static int nfs4_trigger_cmp(vnode_t *, vnode_t *, caller_context_t *);
/*
* Regular NFSv4 vnodeops that we need to reference directly
*/
-extern int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *);
-extern void nfs4_inactive(vnode_t *, cred_t *);
+extern int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+extern void nfs4_inactive(vnode_t *, cred_t *, caller_context_t *);
extern int nfs4_rwlock(vnode_t *, int, caller_context_t *);
extern void nfs4_rwunlock(vnode_t *, int, caller_context_t *);
extern int nfs4_lookup(vnode_t *, char *, vnode_t **,
- struct pathname *, int, vnode_t *, cred_t *);
-extern int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *);
-extern int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-extern int nfs4_fid(vnode_t *, fid_t *);
-extern int nfs4_realvp(vnode_t *, vnode_t **);
+ struct pathname *, int, vnode_t *, cred_t *,
+ caller_context_t *, int *, pathname_t *);
+extern int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+extern int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int nfs4_fid(vnode_t *, fid_t *, caller_context_t *);
+extern int nfs4_realvp(vnode_t *, vnode_t **, caller_context_t *);
static int nfs4_trigger_mount(vnode_t *, vnode_t **);
static int nfs4_trigger_domount(vnode_t *, domount_args_t *, vfs_t **,
@@ -305,7 +317,7 @@ const fs_operation_def_t nfs4_trigger_vnodeops_template[] = {
*/
static int
-nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr)
+nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
int error;
vnode_t *newvp;
@@ -321,7 +333,7 @@ nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr)
*vpp = newvp;
/* return with VN_HELD(newvp) */
- return (VOP_OPEN(vpp, flag, cr));
+ return (VOP_OPEN(vpp, flag, cr, ct));
}
/*
@@ -332,7 +344,8 @@ nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr)
* testing.
*/
static int
-nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
@@ -343,10 +356,10 @@ nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
if (error)
return (error);
- error = VOP_GETATTR(newvp, vap, flags, cr);
+ error = VOP_GETATTR(newvp, vap, flags, cr, ct);
VN_RELE(newvp);
} else {
- error = nfs4_getattr(vp, vap, flags, cr);
+ error = nfs4_getattr(vp, vap, flags, cr, ct);
}
return (error);
@@ -370,7 +383,8 @@ nfs4_trigger_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
}
static int
-nfs4_trigger_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+nfs4_trigger_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
vnode_t *newvp;
@@ -379,15 +393,16 @@ nfs4_trigger_access(vnode_t *vp, int mode, int flags, cred_t *cr)
if (error)
return (error);
- error = VOP_ACCESS(newvp, mode, flags, cr);
+ error = VOP_ACCESS(newvp, mode, flags, cr, ct);
VN_RELE(newvp);
return (error);
}
static int
-nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp,
+ struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr,
+ caller_context_t *ct, int *deflags, pathname_t *rpnp)
{
int error;
vnode_t *newdvp;
@@ -404,13 +419,15 @@ nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* we've triggered a mount.
*/
if (strcmp(nm, "..") == 0)
- return (nfs4_lookup(dvp, nm, vpp, pnp, flags, rdir, cr));
+ return (nfs4_lookup(dvp, nm, vpp, pnp, flags, rdir, cr,
+ ct, deflags, rpnp));
error = nfs4_trigger_mount(dvp, &newdvp);
if (error)
return (error);
- error = VOP_LOOKUP(newdvp, nm, vpp, pnp, flags, rdir, cr);
+ error = VOP_LOOKUP(newdvp, nm, vpp, pnp, flags, rdir, cr, ct,
+ deflags, rpnp);
VN_RELE(newdvp);
return (error);
@@ -418,8 +435,8 @@ nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
static int
nfs4_trigger_create(vnode_t *dvp, char *nm, struct vattr *va,
- enum vcexcl exclusive, int mode, vnode_t **vpp, cred_t *cr,
- int flags)
+ enum vcexcl exclusive, int mode, vnode_t **vpp, cred_t *cr,
+ int flags, caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
vnode_t *newdvp;
@@ -428,14 +445,16 @@ nfs4_trigger_create(vnode_t *dvp, char *nm, struct vattr *va,
if (error)
return (error);
- error = VOP_CREATE(newdvp, nm, va, exclusive, mode, vpp, cr, flags);
+ error = VOP_CREATE(newdvp, nm, va, exclusive, mode, vpp, cr,
+ flags, ct, vsecp);
VN_RELE(newdvp);
return (error);
}
static int
-nfs4_trigger_remove(vnode_t *dvp, char *nm, cred_t *cr)
+nfs4_trigger_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
int error;
vnode_t *newdvp;
@@ -444,14 +463,15 @@ nfs4_trigger_remove(vnode_t *dvp, char *nm, cred_t *cr)
if (error)
return (error);
- error = VOP_REMOVE(newdvp, nm, cr);
+ error = VOP_REMOVE(newdvp, nm, cr, ct, flags);
VN_RELE(newdvp);
return (error);
}
static int
-nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
vnode_t *newtdvp;
@@ -464,7 +484,7 @@ nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
* We don't check whether svp is a stub. Let the NFSv4 code
* detect that error, and return accordingly.
*/
- error = VOP_LINK(newtdvp, svp, tnm, cr);
+ error = VOP_LINK(newtdvp, svp, tnm, cr, ct, flags);
VN_RELE(newtdvp);
return (error);
@@ -472,7 +492,7 @@ nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
static int
nfs4_trigger_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
int error;
vnode_t *newsdvp;
@@ -501,16 +521,17 @@ nfs4_trigger_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
if (error)
return (error);
- error = VOP_RENAME(newsdvp, snm, tdvp, tnm, cr);
+ error = VOP_RENAME(newsdvp, snm, tdvp, tnm, cr, ct, flags);
VN_RELE(newsdvp);
return (error);
}
+/* ARGSUSED */
static int
nfs4_trigger_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
vnode_t *newdvp;
@@ -519,14 +540,15 @@ nfs4_trigger_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
if (error)
return (error);
- error = VOP_MKDIR(newdvp, nm, va, vpp, cr);
+ error = VOP_MKDIR(newdvp, nm, va, vpp, cr, ct, flags, vsecp);
VN_RELE(newdvp);
return (error);
}
static int
-nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
vnode_t *newdvp;
@@ -535,7 +557,7 @@ nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
if (error)
return (error);
- error = VOP_RMDIR(newdvp, nm, cdir, cr);
+ error = VOP_RMDIR(newdvp, nm, cdir, cr, ct, flags);
VN_RELE(newdvp);
return (error);
@@ -543,7 +565,7 @@ nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
static int
nfs4_trigger_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
int error;
vnode_t *newdvp;
@@ -552,14 +574,15 @@ nfs4_trigger_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm,
if (error)
return (error);
- error = VOP_SYMLINK(newdvp, lnm, tva, tnm, cr);
+ error = VOP_SYMLINK(newdvp, lnm, tva, tnm, cr, ct, flags);
VN_RELE(newdvp);
return (error);
}
static int
-nfs4_trigger_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+nfs4_trigger_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr,
+ caller_context_t *ct)
{
int error;
vnode_t *newvp;
@@ -568,7 +591,7 @@ nfs4_trigger_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
if (error)
return (error);
- error = VOP_READLINK(newvp, uiop, cr);
+ error = VOP_READLINK(newvp, uiop, cr, ct);
VN_RELE(newvp);
return (error);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_subr.c b/usr/src/uts/common/fs/nfs/nfs4_subr.c
index 16ce81e270..52a482f642 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_subr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_subr.c
@@ -2319,7 +2319,7 @@ nfs4_printfhandle(nfs4_fhandle_t *fhp)
* We provide a set of interfaces to allow the rest of the system to utilize
* a caching mechanism while encapsulating the details of the actual
* implementation. This should allow for better maintainability and
- * extensibilty by consolidating the implementation details in one location.
+ * extensibility by consolidating the implementation details in one location.
*/
/*
@@ -2875,7 +2875,7 @@ nfs4_directio(vnode_t *vp, int cmd, cred_t *cr)
if (nfs4_has_pages(vp) &&
((rp->r_flags & R4DIRTY) || rp->r_awcount > 0)) {
error = VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0,
- B_INVAL, cr);
+ B_INVAL, cr, NULL);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
index f788f16bef..d945efe97a 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
@@ -126,7 +126,8 @@ static int nfs4mknod(vnode_t *, char *, struct vattr *, enum vcexcl,
int, vnode_t **, cred_t *);
static int nfs4open_otw(vnode_t *, char *, struct vattr *, vnode_t **,
cred_t *, int, int, enum createmode4, int);
-static int nfs4rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
+static int nfs4rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *);
static int nfs4rename_persistent_fh(vnode_t *, char *, vnode_t *,
vnode_t *, char *, cred_t *, nfsstat4 *);
static int nfs4rename_volatile_fh(vnode_t *, char *, vnode_t *,
@@ -197,65 +198,82 @@ static void nfs4args_write(nfs_argop4 *, stable_how4, rnode4_t *, cred_t *,
* These are the vnode ops functions that implement the vnode interface to
* the networked file system. See more comments below at nfs4_vnodeops.
*/
-static int nfs4_open(vnode_t **, int, cred_t *);
-static int nfs4_close(vnode_t *, int, int, offset_t, cred_t *);
+static int nfs4_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int nfs4_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
static int nfs4_read(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
static int nfs4_write(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
-static int nfs4_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
+static int nfs4_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
static int nfs4_setattr(vnode_t *, struct vattr *, int, cred_t *,
caller_context_t *);
-static int nfs4_access(vnode_t *, int, int, cred_t *);
-static int nfs4_readlink(vnode_t *, struct uio *, cred_t *);
-static int nfs4_fsync(vnode_t *, int, cred_t *);
+static int nfs4_access(vnode_t *, int, int, cred_t *, caller_context_t *);
+static int nfs4_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int nfs4_fsync(vnode_t *, int, cred_t *, caller_context_t *);
static int nfs4_create(vnode_t *, char *, struct vattr *, enum vcexcl,
- int, vnode_t **, cred_t *, int);
-static int nfs4_remove(vnode_t *, char *, cred_t *);
-static int nfs4_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int nfs4_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-static int nfs4_mkdir(vnode_t *, char *, struct vattr *,
- vnode_t **, cred_t *);
-static int nfs4_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
+ int, vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+static int nfs4_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+ int);
+static int nfs4_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs4_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs4_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
+ cred_t *, caller_context_t *, int, vsecattr_t *);
+static int nfs4_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
static int nfs4_symlink(vnode_t *, char *, struct vattr *, char *,
- cred_t *);
-static int nfs4_readdir(vnode_t *, struct uio *, cred_t *, int *);
-static int nfs4_seek(vnode_t *, offset_t, offset_t *);
+ cred_t *, caller_context_t *, int);
+static int nfs4_readdir(vnode_t *, struct uio *, cred_t *, int *,
+ caller_context_t *, int);
+static int nfs4_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
static int nfs4_getpage(vnode_t *, offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
- enum seg_rw, cred_t *);
-static int nfs4_putpage(vnode_t *, offset_t, size_t, int, cred_t *);
-static int nfs4_map(vnode_t *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-static int nfs4_addmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-static int nfs4_cmp(vnode_t *, vnode_t *);
+ enum seg_rw, cred_t *, caller_context_t *);
+static int nfs4_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+static int nfs4_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+static int nfs4_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+static int nfs4_cmp(vnode_t *, vnode_t *, caller_context_t *);
static int nfs4_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
+ struct flk_callback *, cred_t *, caller_context_t *);
static int nfs4_space(vnode_t *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
-static int nfs4_delmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uint_t, uint_t, uint_t, cred_t *);
+static int nfs4_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *, caller_context_t *);
static int nfs4_pageio(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static void nfs4_dispose(vnode_t *, page_t *, int, int, cred_t *);
-static int nfs4_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs4_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *);
+ cred_t *, caller_context_t *);
+static void nfs4_dispose(vnode_t *, page_t *, int, int, cred_t *,
+ caller_context_t *);
+static int nfs4_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
/*
* These vnode ops are required to be called from outside this source file,
* e.g. by ephemeral mount stub vnode ops, and so may not be declared
* as static.
*/
-int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *);
-void nfs4_inactive(vnode_t *, cred_t *);
+int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+void nfs4_inactive(vnode_t *, cred_t *, caller_context_t *);
int nfs4_lookup(vnode_t *, char *, vnode_t **,
- struct pathname *, int, vnode_t *, cred_t *);
-int nfs4_fid(vnode_t *, fid_t *);
+ struct pathname *, int, vnode_t *, cred_t *,
+ caller_context_t *, int *, pathname_t *);
+int nfs4_fid(vnode_t *, fid_t *, caller_context_t *);
int nfs4_rwlock(vnode_t *, int, caller_context_t *);
void nfs4_rwunlock(vnode_t *, int, caller_context_t *);
-int nfs4_realvp(vnode_t *, vnode_t **);
-int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *);
-int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
+int nfs4_realvp(vnode_t *, vnode_t **, caller_context_t *);
+int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+int nfs4_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
/*
* Used for nfs4_commit_vp() to indicate if we should
@@ -580,11 +598,10 @@ nfs4_getvnodeops(void)
/*
* The OPEN operation opens a regular file.
- *
- * ARGSUSED
*/
+/*ARGSUSED3*/
static int
-nfs4_open(vnode_t **vpp, int flag, cred_t *cr)
+nfs4_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *dvp = NULL;
rnode4_t *rp, *drp;
@@ -862,10 +879,10 @@ nfs4open_otw(vnode_t *dvp, char *file_name, struct vattr *in_va,
*/
if (VTOR4(vpi)->r_deleg_type != OPEN_DELEGATE_NONE) {
if (open_flag & FREAD &&
- nfs4_access(vpi, VREAD, 0, cr) == 0)
+ nfs4_access(vpi, VREAD, 0, cr, NULL) == 0)
acc |= VREAD;
if (open_flag & FWRITE &&
- nfs4_access(vpi, VWRITE, 0, cr) == 0)
+ nfs4_access(vpi, VWRITE, 0, cr, NULL) == 0)
acc |= VWRITE;
}
}
@@ -1538,7 +1555,7 @@ recov_retry:
"nfs4open_otw: EXCLUSIVE4: error %d on SETATTR:"
" remove file", e.error));
VN_RELE(vp);
- (void) nfs4_remove(dvp, file_name, cr);
+ (void) nfs4_remove(dvp, file_name, cr, NULL, 0);
/*
* Since we've reled the vnode and removed
* the file we now need to return the error.
@@ -1635,7 +1652,7 @@ skip_update_dircaches:
* - failed_reopen : same as above, except that the file has already been
* marked dead, so no need to do it again.
* - bailout : reopen failed but we are able to recover and retry the reopen -
- * either within this function immediatley or via the calling function.
+ * either within this function immediately or via the calling function.
*/
void
@@ -2210,8 +2227,10 @@ nfs4_open_non_reg_file(vnode_t **vpp, int flag, cred_t *cr)
/*
* CLOSE a file
*/
+/* ARGSUSED */
static int
-nfs4_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+nfs4_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
rnode4_t *rp;
int error = 0;
@@ -3513,7 +3532,8 @@ recov_retry:
/* ARGSUSED */
static int
-nfs4_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
+nfs4_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp,
+ caller_context_t *ct)
{
if (nfs_zone() != VTOMI4(vp)->mi_zone)
return (EIO);
@@ -3525,8 +3545,10 @@ nfs4_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
}
}
+/* ARGSUSED */
int
-nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode4_t *rp = VTOR4(vp);
@@ -3575,7 +3597,7 @@ nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
mutex_exit(&rp->r_statelock);
error =
nfs4_putpage(vp, (u_offset_t)0,
- 0, 0, cr);
+ 0, 0, cr, NULL);
mutex_enter(&rp->r_statelock);
if (error && (error == ENOSPC ||
error == EDQUOT)) {
@@ -3696,7 +3718,7 @@ nfs4setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
rp->r_count > 0 ||
rp->r_mapcnt > 0)) {
ASSERT(vp->v_type != VCHR);
- e.error = nfs4_putpage(vp, (offset_t)0, 0, 0, cr);
+ e.error = nfs4_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
if (e.error && (e.error == ENOSPC || e.error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -4144,7 +4166,7 @@ recov_retry:
/* ARGSUSED */
static int
-nfs4_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+nfs4_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
COMPOUND4args_clnt args;
COMPOUND4res_clnt res;
@@ -4358,8 +4380,9 @@ out:
return (e.error);
}
+/* ARGSUSED */
static int
-nfs4_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+nfs4_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
{
COMPOUND4args_clnt args;
COMPOUND4res_clnt res;
@@ -4521,8 +4544,9 @@ recov_retry:
* metadata changes are not cached on the client before being
* sent to the server.
*/
+/* ARGSUSED */
static int
-nfs4_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+nfs4_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
int error;
@@ -4541,8 +4565,9 @@ nfs4_fsync(vnode_t *vp, int syncflag, cred_t *cr)
* operation while it was open, it got renamed instead. Here we
* remove the renamed file.
*/
+/* ARGSUSED */
void
-nfs4_inactive(vnode_t *vp, cred_t *cr)
+nfs4_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
rnode4_t *rp;
@@ -4709,7 +4734,7 @@ redo:
if (nfs4_has_pages(vp) &&
((rp->r_flags & R4DIRTY) || rp->r_count > 0)) {
ASSERT(vp->v_type != VCHR);
- e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr);
+ e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr, NULL);
if (e.error) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -4827,7 +4852,8 @@ recov_retry_remove:
/* ARGSUSED3 */
int
nfs4_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
int error;
vnode_t *vp, *avp = NULL;
@@ -4903,7 +4929,8 @@ nfs4lookup_xattr(vnode_t *dvp, char *nm, vnode_t **vpp, int flags, cred_t *cr)
mntinfo4_t *mi;
mi = VTOMI4(dvp);
- if (!(mi->mi_vfsp->vfs_flag & VFS_XATTR))
+ if (!(mi->mi_vfsp->vfs_flag & VFS_XATTR) &&
+ !vfs_has_feature(mi->mi_vfsp, VFSFT_XVATTR))
return (EINVAL);
drp = VTOR4(dvp);
@@ -4983,7 +5010,7 @@ nfs4lookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int skipdnlc)
* just need to check access.
*/
if (nm[0] == '.' && nm[1] == '\0') {
- error = nfs4_access(dvp, VEXEC, 0, cr);
+ error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (error)
return (error);
VN_HOLD(dvp);
@@ -5046,7 +5073,7 @@ nfs4lookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int skipdnlc)
/*
* The access cache should almost always hit
*/
- error = nfs4_access(dvp, VEXEC, 0, cr);
+ error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (error) {
VN_RELE(*vpp);
@@ -5346,7 +5373,7 @@ recov_retry:
* Somehow we must not have asked for enough
* so try a singleton ACCESS, should never happen.
*/
- e.error = nfs4_access(dvp, VEXEC, 0, cr);
+ e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (e.error) {
VN_RELE(*vpp);
*vpp = NULL;
@@ -5488,7 +5515,7 @@ recov_retry:
* and dnlc entry, we may not have access.
* This should almost always hit the cache.
*/
- e.error = nfs4_access(dvp, VEXEC, 0, cr);
+ e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (e.error) {
VN_RELE(*vpp);
*vpp = NULL;
@@ -5819,7 +5846,7 @@ recov_retry:
* Somehow we must not have asked for enough
* so try a singleton ACCESS should never happen
*/
- e.error = nfs4_access(dvp, VEXEC, 0, cr);
+ e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (e.error) {
sfh4_rele(&sfhp);
goto exit;
@@ -5855,7 +5882,7 @@ recov_retry:
* we may not have access.
* This should almost always hit the cache.
*/
- e.error = nfs4_access(dvp, VEXEC, 0, cr);
+ e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (e.error) {
sfh4_rele(&sfhp);
goto exit;
@@ -6375,7 +6402,8 @@ recov_retry:
/* ARGSUSED */
static int
nfs4_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
- int mode, vnode_t **vpp, cred_t *cr, int flags)
+ int mode, vnode_t **vpp, cred_t *cr, int flags, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
vnode_t *vp = NULL;
@@ -6461,7 +6489,7 @@ top:
vp = specvp(vp, vp->v_rdev, vp->v_type, cr);
VN_RELE(tempvp);
}
- if (!(error = VOP_ACCESS(vp, mode, 0, cr))) {
+ if (!(error = VOP_ACCESS(vp, mode, 0, cr, ct))) {
if ((vattr.va_mask & AT_SIZE) &&
vp->v_type == VREG) {
rp = VTOR4(vp);
@@ -6500,7 +6528,8 @@ top:
rp->r_count > 0 ||
rp->r_mapcnt > 0)) {
error = nfs4_putpage(vp,
- (offset_t)0, 0, 0, cr);
+ (offset_t)0, 0, 0, cr,
+ ct);
if (error && (error == ENOSPC ||
error == EDQUOT)) {
mutex_enter(
@@ -6537,7 +6566,7 @@ top:
if (IS_SHADOW(vp, trp))
tvp = RTOV4(trp);
}
- vnevent_create(tvp);
+ vnevent_create(tvp, ct);
*vpp = vp;
}
return (error);
@@ -6642,7 +6671,7 @@ create_otw:
trp = VTOR4(tvp);
if (IS_SHADOW(tvp, trp))
tvp = RTOV4(trp);
- vnevent_create(tvp);
+ vnevent_create(tvp, ct);
}
return (error);
}
@@ -6695,7 +6724,7 @@ call_nfs4_create_req(vnode_t *dvp, char *nm, void *data, struct vattr *va,
va->va_mode &= ~VSGID;
dva.va_mask = AT_MODE | AT_GID;
- if (VOP_GETATTR(dvp, &dva, 0, cr) == 0) {
+ if (VOP_GETATTR(dvp, &dva, 0, cr, NULL) == 0) {
/*
* If the parent's directory has the setgid bit set
@@ -7073,8 +7102,9 @@ nfs4mknod(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* we rename it instead of removing it and nfs_inactive
* will remove the new name.
*/
+/* ARGSUSED */
static int
-nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr)
+nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, int flags)
{
COMPOUND4args_clnt args;
COMPOUND4res_clnt res, *resp = NULL;
@@ -7152,7 +7182,7 @@ nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr)
(rp->r_unldvp == NULL || strcmp(nm, rp->r_unlname) == 0)) {
mutex_exit(&rp->r_statelock);
tmpname = newname();
- e.error = nfs4rename(dvp, nm, dvp, tmpname, cr);
+ e.error = nfs4rename(dvp, nm, dvp, tmpname, cr, ct);
if (e.error)
kmem_free(tmpname, MAXNAMELEN);
else {
@@ -7188,7 +7218,7 @@ nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr)
*/
if (nfs4_has_pages(vp) &&
((rp->r_flags & R4DIRTY) || rp->r_count > 0)) {
- e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr);
+ e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr, ct);
if (e.error && (e.error == ENOSPC || e.error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -7293,7 +7323,7 @@ recov_retry:
tvp = vp;
if (IS_SHADOW(vp, trp))
tvp = RTOV4(trp);
- vnevent_remove(tvp, dvp, nm);
+ vnevent_remove(tvp, dvp, nm, ct);
}
VN_RELE(vp);
return (e.error);
@@ -7306,8 +7336,10 @@ recov_retry:
* PUTFH(file), SAVEFH, PUTFH(targetdir), LINK, RESTOREFH,
* GETATTR(file)
*/
+/* ARGSUSED */
static int
-nfs4_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+nfs4_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
COMPOUND4args_clnt args;
COMPOUND4res_clnt res, *resp = NULL;
@@ -7332,7 +7364,7 @@ nfs4_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
if (nfs_zone() != VTOMI4(tdvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(svp, &realvp) == 0) {
+ if (VOP_REALVP(svp, &realvp, ct) == 0) {
svp = realvp;
ASSERT(nfs4_consistent_type(svp));
}
@@ -7514,7 +7546,7 @@ recov_retry:
tvp = svp;
if (IS_SHADOW(svp, trp))
tvp = RTOV4(trp);
- vnevent_link(tvp);
+ vnevent_link(tvp, ct);
}
out:
kmem_free(argop, argoplist_size);
@@ -7526,17 +7558,19 @@ out:
return (e.error);
}
+/* ARGSUSED */
static int
-nfs4_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs4_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
vnode_t *realvp;
if (nfs_zone() != VTOMI4(odvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
- return (nfs4rename(odvp, onm, ndvp, nnm, cr));
+ return (nfs4rename(odvp, onm, ndvp, nnm, cr, ct));
}
/*
@@ -7547,7 +7581,8 @@ nfs4_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
* based on the likelihood of the filehandle to change during rename.
*/
static int
-nfs4rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs4rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo4_t *mi;
@@ -7712,11 +7747,12 @@ link_call:
error = 0;
if (do_link) {
- error = nfs4_link(ndvp, nvp, tmpname, cr);
+ error = nfs4_link(ndvp, nvp, tmpname, cr,
+ NULL, 0);
}
if (error == EOPNOTSUPP || !do_link) {
error = nfs4_rename(ndvp, nnm, ndvp, tmpname,
- cr);
+ cr, NULL, 0);
did_link = 0;
} else {
did_link = 1;
@@ -7843,7 +7879,7 @@ link_call:
*/
VN_HOLD(nvp);
- (void) nfs4_remove(ndvp, tmpname, cr);
+ (void) nfs4_remove(ndvp, tmpname, cr, NULL, 0);
/* Undo the unlinked file naming stuff we just did */
mutex_enter(&rp->r_statelock);
@@ -7924,7 +7960,7 @@ link_call:
tvp = nvp;
if (IS_SHADOW(nvp, trp))
tvp = RTOV4(trp);
- vnevent_rename_dest(tvp, ndvp, nnm);
+ vnevent_rename_dest(tvp, ndvp, nnm, ct);
}
/*
@@ -7936,14 +7972,14 @@ link_call:
tvp = ndvp;
if (IS_SHADOW(ndvp, trp))
tvp = RTOV4(trp);
- vnevent_rename_dest_dir(tvp);
+ vnevent_rename_dest_dir(tvp, ct);
}
trp = VTOR4(ovp);
tvp = ovp;
if (IS_SHADOW(ovp, trp))
tvp = RTOV4(trp);
- vnevent_rename_src(tvp, odvp, onm);
+ vnevent_rename_src(tvp, odvp, onm, ct);
}
if (nvp) {
@@ -7967,7 +8003,7 @@ link_call:
* The compound op structure for persistent fh rename is:
* PUTFH(sourcdir), SAVEFH, PUTFH(targetdir), RENAME
* Rather than bother with the directory postop args, we'll simply
- * update that a change occured in the cache, so no post-op getattrs.
+ * update that a change occurred in the cache, so no post-op getattrs.
*/
static int
nfs4rename_persistent_fh(vnode_t *odvp, char *onm, vnode_t *renvp,
@@ -8432,8 +8468,10 @@ out:
return (e.error);
}
+/* ARGSUSED */
static int
-nfs4_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
+nfs4_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr,
+ caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
vnode_t *vp;
@@ -8469,8 +8507,10 @@ nfs4_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
* The compound op structure is:
* PUTFH(targetdir), REMOVE
*/
+/*ARGSUSED4*/
static int
-nfs4_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+nfs4_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int need_end_op = FALSE;
COMPOUND4args_clnt args;
@@ -8664,7 +8704,7 @@ recov_retry:
tvp = vp;
if (IS_SHADOW(vp, trp))
tvp = RTOV4(trp);
- vnevent_rmdir(tvp, dvp, nm);
+ vnevent_rmdir(tvp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -8672,8 +8712,10 @@ recov_retry:
return (e.error);
}
+/* ARGSUSED */
static int
-nfs4_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr)
+nfs4_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
vnode_t *vp;
@@ -8726,8 +8768,10 @@ nfs4_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr)
* may return only one block's worth of entries. Entries may be compressed
* on the server.
*/
+/* ARGSUSED */
static int
-nfs4_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp)
+nfs4_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int error;
uint_t count;
@@ -8809,7 +8853,7 @@ nfs4_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp)
nfs4readdir(vp, rdc, cr);
/*
- * Reaquire the lock, so that we can continue
+ * Reacquire the lock, so that we can continue
*/
mutex_enter(&rp->r_statelock);
/*
@@ -9483,7 +9527,7 @@ write_again:
/* ARGSUSED */
int
-nfs4_fid(vnode_t *vp, fid_t *fidp)
+nfs4_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
return (EREMOTE);
}
@@ -9522,7 +9566,7 @@ nfs4_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-nfs4_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+nfs4_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
if (nfs_zone() != VTOMI4(vp)->mi_zone)
return (EIO);
@@ -9543,10 +9587,11 @@ nfs4_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
/*
* Return all the pages from [off..off+len) in file
*/
+/* ARGSUSED */
static int
nfs4_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
rnode4_t *rp;
int error;
@@ -10022,8 +10067,10 @@ nfs4_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, struct seg *seg,
* len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
* (from pageout).
*/
+/* ARGSUSED */
static int
-nfs4_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+nfs4_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode4_t *rp;
@@ -10228,7 +10275,7 @@ nfs4_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
*/
if (!(flags & B_ASYNC)) {
error = nfs4_putpage(vp, io_off, io_len,
- B_INVAL | B_FORCE, cr);
+ B_INVAL | B_FORCE, cr, NULL);
}
} else {
if (error)
@@ -10251,9 +10298,11 @@ nfs4_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
int nfs4_force_open_before_mmap = 0;
#endif
+/* ARGSUSED */
static int
nfs4_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)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error = 0;
@@ -10529,7 +10578,8 @@ open_and_get_osp(vnode_t *map_vp, cred_t *cr, nfs4_open_stream_t **ospp)
/* ARGSUSED */
static int
nfs4_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)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
rnode4_t *rp;
int error = 0;
@@ -10633,16 +10683,19 @@ out:
return (error);
}
+/* ARGSUSED */
static int
-nfs4_cmp(vnode_t *vp1, vnode_t *vp2)
+nfs4_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
return (VTOR4(vp1) == VTOR4(vp2));
}
+/* ARGSUSED */
static int
nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
int rc;
u_offset_t start, end;
@@ -10698,7 +10751,7 @@ nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (!nfs4_safelock(vp, bfp, cr))
return (EAGAIN);
}
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
rp = VTOR4(vp);
@@ -10748,7 +10801,7 @@ nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
mutex_exit(&rp->r_statelock);
if (rc != 0)
goto done;
- error = nfs4_putpage(vp, (offset_t)0, 0, B_INVAL, cr);
+ error = nfs4_putpage(vp, (offset_t)0, 0, B_INVAL, cr, ct);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
@@ -10820,7 +10873,7 @@ nfs4_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
/* ARGSUSED */
int
-nfs4_realvp(vnode_t *vp, vnode_t **vpp)
+nfs4_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
rnode4_t *rp;
rp = VTOR4(vp);
@@ -10845,7 +10898,8 @@ nfs4_realvp(vnode_t *vp, vnode_t **vpp)
/* ARGSUSED */
static int
nfs4_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)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
int caller_found;
int error;
@@ -11043,7 +11097,7 @@ nfs4_delmap_callback(struct as *as, void *arg, uint_t event)
if ((rp->r_flags & R4DIRECTIO) || (mi->mi_flags & MI4_DIRECTIO))
(void) nfs4_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_INVAL, dmapp->cr);
+ B_INVAL, dmapp->cr, NULL);
if (e.error) {
e.stat = puterrno4(e.error);
@@ -11111,8 +11165,10 @@ fattr4_maxfilesize_to_bits(uint64_t ll)
return (l);
}
+/* ARGSUSED */
int
-nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int error;
hrtime_t t;
@@ -11140,7 +11196,7 @@ nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
* going otw with GETATTR(FATTR4_NAMED_ATTR). For now
* just drive the OTW getattr. This is required because
* _PC_XATTR_EXISTS can only return true if attributes
- * exist -- simply checking for existance of the attrdir
+ * exist -- simply checking for existence of the attrdir
* is not sufficient.
*
* pc4_xattr_valid can be only be trusted when r_xattr_dir
@@ -11262,9 +11318,10 @@ nfs4_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs4_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
int error;
rnode4_t *rp;
@@ -11292,8 +11349,10 @@ nfs4_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static void
-nfs4_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
+nfs4_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode4_t *rp;
@@ -11899,7 +11958,7 @@ top:
write_verf = rp->r_writeverf;
mutex_exit(&rp->r_statelock);
- error = nfs4_putpage(vp, poff, plen, B_ASYNC, cr);
+ error = nfs4_putpage(vp, poff, plen, B_ASYNC, cr, NULL);
if (error == EAGAIN)
error = 0;
@@ -11910,7 +11969,7 @@ top:
* the asynchronous i/o's in that range are done as well.
*/
if (!error)
- error = nfs4_putpage(vp, poff, plen, 0, cr);
+ error = nfs4_putpage(vp, poff, plen, 0, cr, NULL);
if (error)
return (error);
@@ -12067,7 +12126,8 @@ do_nfs4_async_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count,
/*ARGSUSED*/
static int
-nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error = 0;
mntinfo4_t *mi;
@@ -12113,8 +12173,10 @@ nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (ENOSYS);
}
+/* ARGSUSED */
int
-nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo4_t *mi;
@@ -12167,7 +12229,7 @@ nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
if (error) {
vs_ace4_destroy(&gar.n4g_vsa);
if (error == ENOTSUP || error == EOPNOTSUPP)
- error = fs_fab_acl(vp, vsecattr, flag, cr);
+ error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
return (error);
}
@@ -12177,7 +12239,7 @@ nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
* bitmap, neither was an acl.
*/
vs_ace4_destroy(&gar.n4g_vsa);
- error = fs_fab_acl(vp, vsecattr, flag, cr);
+ error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
return (error);
}
@@ -12193,11 +12255,11 @@ nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
if ((error) && (vsecattr->vsa_mask &
(VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT)) &&
(error != EACCES)) {
- error = fs_fab_acl(vp, vsecattr, flag, cr);
+ error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
}
return (error);
}
- error = fs_fab_acl(vp, vsecattr, flag, cr);
+ error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
return (error);
}
@@ -12322,8 +12384,10 @@ nfs4_create_getsecattr_return(vsecattr_t *filled_vsap, vsecattr_t *vsap,
return (0);
}
-static int
-nfs4_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+/* ARGSUSED */
+int
+nfs4_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
@@ -12348,7 +12412,7 @@ nfs4_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
* request off to the local share code.
*/
if (VTOMI4(vp)->mi_flags & MI4_LLOCK)
- return (fs_shrlock(vp, cmd, shr, flag, cr));
+ return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
switch (cmd) {
case F_SHARE:
@@ -13568,7 +13632,7 @@ nfs4frlock_recovery(int needrecov, nfs4_error_t *ep,
}
/*
- * Handles the succesful reply from the server for nfs4frlock.
+ * Handles the successful reply from the server for nfs4frlock.
*/
static void
nfs4frlock_results_ok(nfs4_lock_call_type_t ctype, int cmd, flock64_t *flk,
@@ -13855,7 +13919,7 @@ nfs4frlock_final_cleanup(nfs4_lock_call_type_t ctype, COMPOUND4args_clnt *argsp,
int error;
error = VOP_PUTPAGE(vp, (u_offset_t)0,
- 0, B_INVAL, cred);
+ 0, B_INVAL, cred, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
rnode4_t *rp = VTOR4(vp);
@@ -14345,7 +14409,7 @@ nfs4_safelock(vnode_t *vp, const struct flock64 *bfp, cred_t *cr)
/* mandatory locking and mapping don't mix */
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error != 0) {
NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock: "
"getattr error %d", error));
@@ -14502,7 +14566,8 @@ nfs4_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr)
ld.l_start = 0;
ld.l_len = 0; /* do entire file */
- ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL, cr);
+ ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL,
+ cr, NULL);
if (ret != 0) {
/*
@@ -15552,7 +15617,7 @@ locks_intersect(flock64_t *llfp, flock64_t *curfp)
}
/*
- * Determine what the interseting lock region is, and add that to the
+ * Determine what the intersecting lock region is, and add that to the
* 'nl_llpp' locklist in increasing order (by l_start).
*/
static void
diff --git a/usr/src/uts/common/fs/nfs/nfs4_xdr.c b/usr/src/uts/common/fs/nfs/nfs4_xdr.c
index 34fd0f11dd..ac08add502 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_xdr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_xdr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc.
+ * Copyright 2007 Sun Microsystems, Inc.
* All rights reserved. Use is subject to license terms.
*/
@@ -190,7 +190,7 @@ xdr_inline_decode_nfs_fh4(uint32_t *ptr, nfs_fh4_fmt_t *fhp, uint32_t fhsize)
fhsize -= 2 * BYTES_PER_XDR_UNIT + sizeof (ushort_t);
/*
- * For backwards compatability, the fid length may be less than
+ * For backwards compatibility, the fid length may be less than
* NFS_FHMAXDATA, but it was always encoded as NFS_FHMAXDATA bytes.
*/
dsize = fhp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_len;
@@ -849,6 +849,7 @@ xdr_ga_fattr_res(XDR *xdrs, struct nfs4_ga_res *garp, bitmap4 resbmap,
vsap->vsa_aclcnt = acl.fattr4_acl_len;
vsap->vsa_aclentp = acl.fattr4_acl_val;
vsap->vsa_mask = VSA_ACE | VSA_ACECNT;
+ vsap->vsa_aclentsz = vsap->vsa_aclcnt * sizeof (ace_t);
}
if (resbmap & FATTR4_ACLSUPPORT_MASK) {
diff --git a/usr/src/uts/common/fs/nfs/nfs_acl_srv.c b/usr/src/uts/common/fs/nfs/nfs_acl_srv.c
index b8d90196ef..f2ccc525fa 100644
--- a/usr/src/uts/common/fs/nfs/nfs_acl_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_acl_srv.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc.
+ * Copyright 2007 Sun Microsystems, Inc.
* All rights reserved.
* Use is subject to license terms.
*/
@@ -94,7 +94,7 @@ acl2_getacl(GETACL2args *args, GETACL2res *resp, struct exportinfo *exi,
resp->resok.acl.vsa_mask = args->mask;
- error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr);
+ error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr, NULL);
if (error == ENOSYS) {
/*
@@ -112,7 +112,7 @@ acl2_getacl(GETACL2args *args, GETACL2res *resp, struct exportinfo *exi,
* Note: if the fs_fab_acl() fails, we have other problems.
* This error should be returned to the caller.
*/
- error = fs_fab_acl(vp, &resp->resok.acl, 0, cr);
+ error = fs_fab_acl(vp, &resp->resok.acl, 0, cr, NULL);
}
if (error) {
@@ -211,7 +211,7 @@ acl2_setacl(SETACL2args *args, SETACL2res *resp, struct exportinfo *exi,
}
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(vp, &args->acl, 0, cr);
+ error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL);
if (error) {
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
VN_RELE(vp);
@@ -317,7 +317,7 @@ acl2_access(ACCESS2args *args, ACCESS2res *resp, struct exportinfo *exi,
* as well be reflected to the server during the open.
*/
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error) {
VN_RELE(vp);
resp->status = puterrno(error);
@@ -327,30 +327,30 @@ acl2_access(ACCESS2args *args, ACCESS2res *resp, struct exportinfo *exi,
resp->resok.access = 0;
if (args->access & ACCESS2_READ) {
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode))
resp->resok.access |= ACCESS2_READ;
}
if ((args->access & ACCESS2_LOOKUP) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (!error)
resp->resok.access |= ACCESS2_LOOKUP;
}
if (checkwriteperm &&
(args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND))) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode))
resp->resok.access |=
(args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND));
}
if (checkwriteperm &&
(args->access & ACCESS2_DELETE) && (vp->v_type == VDIR)) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (!error)
resp->resok.access |= ACCESS2_DELETE;
}
if (args->access & ACCESS2_EXECUTE) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode))
resp->resok.access |= ACCESS2_EXECUTE;
}
@@ -399,7 +399,7 @@ acl2_getxattrdir(GETXATTRDIR2args *args, GETXATTRDIR2res *resp,
flags |= CREATE_XATTR_DIR;
else {
ulong_t val = 0;
- error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr, NULL);
if (!error && val == 0) {
VN_RELE(vp);
resp->status = NFSERR_NOENT;
@@ -407,7 +407,8 @@ acl2_getxattrdir(GETXATTRDIR2args *args, GETXATTRDIR2res *resp,
}
}
- error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr);
+ error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr,
+ NULL, NULL, NULL);
if (!error && avp == vp) { /* lookup of "" on old FS? */
error = EINVAL;
VN_RELE(avp);
@@ -472,7 +473,7 @@ acl3_getacl(GETACL3args *args, GETACL3res *resp, struct exportinfo *exi,
resp->resok.acl.vsa_mask = args->mask;
- error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr);
+ error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr, NULL);
if (error == ENOSYS) {
/*
@@ -490,7 +491,7 @@ acl3_getacl(GETACL3args *args, GETACL3res *resp, struct exportinfo *exi,
* Note: if the fs_fab_acl() fails, we have other problems.
* This error should be returned to the caller.
*/
- error = fs_fab_acl(vp, &resp->resok.acl, 0, cr);
+ error = fs_fab_acl(vp, &resp->resok.acl, 0, cr, NULL);
}
if (error)
@@ -602,7 +603,7 @@ acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi,
goto out1;
}
- error = VOP_SETSECATTR(vp, &args->acl, 0, cr);
+ error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
@@ -666,7 +667,7 @@ acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp,
flags |= CREATE_XATTR_DIR;
else {
ulong_t val = 0;
- error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr, NULL);
if (!error && val == 0) {
VN_RELE(vp);
resp->status = NFS3ERR_NOENT;
@@ -674,7 +675,8 @@ acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp,
}
}
- error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr);
+ error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr,
+ NULL, NULL, NULL);
if (!error && avp == vp) { /* lookup of "" on old FS? */
error = EINVAL;
VN_RELE(avp);
diff --git a/usr/src/uts/common/fs/nfs/nfs_client.c b/usr/src/uts/common/fs/nfs/nfs_client.c
index b6a8a96f01..17ea954eea 100644
--- a/usr/src/uts/common/fs/nfs/nfs_client.c
+++ b/usr/src/uts/common/fs/nfs/nfs_client.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
@@ -232,7 +232,7 @@ nfs_purge_caches(vnode_t *vp, int purge_dnlc, cred_t *cr)
* Flush the page cache.
*/
if (vn_has_cached_data(vp)) {
- error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1807,7 +1807,7 @@ noasync:
void
nfs_async_inactive(vnode_t *vp, cred_t *cr,
- void (*inactive)(vnode_t *, cred_t *))
+ void (*inactive)(vnode_t *, cred_t *, caller_context_t *))
{
mntinfo_t *mi;
struct nfs_async_reqs *args;
@@ -1832,7 +1832,7 @@ nfs_async_inactive(vnode_t *vp, cred_t *cr,
* set nfs3_max_threads/nfs_max_threads to zero in /etc/system.
*
* The manager thread knows about this and is willing to create
- * at least one thread to accomodate us.
+ * at least one thread to accommodate us.
*/
mutex_enter(&mi->mi_async_lock);
if (mi->mi_manager_thread == NULL) {
@@ -2029,7 +2029,7 @@ nfs_async_start(struct vfs *vfsp)
args->a_nfs_offset, args->a_nfs_count,
args->a_cred);
} else if (args->a_io == NFS_INACTIVE) {
- (*args->a_nfs_inactive)(args->a_vp, args->a_cred);
+ (*args->a_nfs_inactive)(args->a_vp, args->a_cred, NULL);
}
/*
@@ -2066,7 +2066,7 @@ nfs_async_stop(struct vfs *vfsp)
* Wait for all outstanding putpage operation to complete. If a signal
* is deliver we will abort and return non-zero. If we can put all the
* pages we will return 0. This routine is called from nfs_unmount and
- * nfs3_unmount to make these operations interruptable.
+ * nfs3_unmount to make these operations interruptible.
*/
int
nfs_async_stop_sig(struct vfs *vfsp)
@@ -2329,7 +2329,7 @@ nfs_putpages(vnode_t *vp, u_offset_t off, size_t len, int flags, cred_t *cr)
flags, cr);
/*
- * If an error occured and the file was marked as dirty
+ * If an error occurred and the file was marked as dirty
* before and we aren't forcibly invalidating pages, then
* reset the RDIRTY flag.
*/
@@ -2762,7 +2762,8 @@ nfs_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr)
ld.l_whence = 0; /* unlock from start of file */
ld.l_start = 0;
ld.l_len = 0; /* do entire file */
- ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL, cr);
+ ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL, cr,
+ NULL);
if (ret != 0) {
/*
@@ -2802,7 +2803,7 @@ nfs_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr)
shr.s_sysid = 0;
shr.s_pid = curproc->p_pid;
- ret = VOP_SHRLOCK(vp, F_UNSHARE, &shr, flag, cr);
+ ret = VOP_SHRLOCK(vp, F_UNSHARE, &shr, flag, cr, NULL);
#ifdef DEBUG
if (ret != 0) {
nfs_perror(ret,
@@ -2975,7 +2976,7 @@ nfs_add_locking_id(vnode_t *vp, pid_t pid, int type, char *id, int len)
nowners++;
} else {
cmn_err(CE_PANIC, "nfs_add_locking_id: "
- "unrecognised lmpl_type %d",
+ "unrecognized lmpl_type %d",
cur->lmpl_type);
}
}
@@ -3055,7 +3056,7 @@ nfs_remove_locking_id(vnode_t *vp, int type, char *id, char *rid, int *rlen)
nowners++;
} else {
cmn_err(CE_PANIC,
- "nrli: unrecognised lmpl_type %d",
+ "nrli: unrecognized lmpl_type %d",
cur->lmpl_type);
}
}
diff --git a/usr/src/uts/common/fs/nfs/nfs_common.c b/usr/src/uts/common/fs/nfs/nfs_common.c
index ded7c5075c..c980d55aed 100644
--- a/usr/src/uts/common/fs/nfs/nfs_common.c
+++ b/usr/src/uts/common/fs/nfs/nfs_common.c
@@ -70,7 +70,7 @@
#include <rpc/svc.h>
/*
- * The psuedo NFS filesystem to allow diskless booting to dynamically
+ * The pseudo NFS filesystem to allow diskless booting to dynamically
* mount either a NFS V2, NFS V3, or NFS V4 filesystem. This only implements
* the VFS_MOUNTROOT op and is only intended to be used by the
* diskless booting code until the real root filesystem is mounted.
@@ -273,7 +273,7 @@ _info(struct modinfo *modinfop)
*/
/*
- * Returns the prefered transfer size in bytes based on
+ * Returns the preferred transfer size in bytes based on
* what network interfaces are available.
*/
int
@@ -287,7 +287,7 @@ nfstsize(void)
}
/*
- * Returns the prefered transfer size in bytes based on
+ * Returns the preferred transfer size in bytes based on
* what network interfaces are available.
*/
@@ -607,7 +607,7 @@ nfs_directio(vnode_t *vp, int cmd, cred_t *cr)
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_awcount > 0)) {
error = VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0,
- B_INVAL, cr);
+ B_INVAL, cr, NULL);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
diff --git a/usr/src/uts/common/fs/nfs/nfs_dump.c b/usr/src/uts/common/fs/nfs/nfs_dump.c
index 17cb8ba161..8fe224936d 100644
--- a/usr/src/uts/common/fs/nfs/nfs_dump.c
+++ b/usr/src/uts/common/fs/nfs/nfs_dump.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -96,8 +95,9 @@ nd_log(const char *fmt, ...)
}
}
+/* ARGSUSED */
int
-nfs_dump(vnode_t *dumpvp, caddr_t addr, int bn, int count)
+nfs_dump(vnode_t *dumpvp, caddr_t addr, int bn, int count, caller_context_t *ct)
{
static TIUSER *tiptr;
XDR xdrs;
diff --git a/usr/src/uts/common/fs/nfs/nfs_export.c b/usr/src/uts/common/fs/nfs/nfs_export.c
index 3b7725dd34..377b5bad18 100644
--- a/usr/src/uts/common/fs/nfs/nfs_export.c
+++ b/usr/src/uts/common/fs/nfs/nfs_export.c
@@ -617,7 +617,7 @@ pseudo_secinfo_remove(exportinfo_t *ancexi, exp_visible_t *ancpseudo)
*
* If there is more than 1 export reference to an old flavor (i.e. some
* of its children shared with this flavor), this flavor information
- * needs to be transfered to the new exportdata struct. A flavor in
+ * needs to be transferred to the new exportdata struct. A flavor in
* the old exportdata has descendant refs when s_refcnt > 1.
*
* Transferring descendant flavor refcnts happens in 2 passes:
@@ -749,7 +749,7 @@ srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt)
* When unsharing an old export node and the old node becomes a pseudo node,
* if there is more than 1 export reference to an old flavor (i.e. some of
* its children shared with this flavor), this flavor information needs to
- * be transfered to the new shared node.
+ * be transferred to the new shared node.
*
* This routine is used under the protection of exported_lock (RW_WRITER).
*/
@@ -928,7 +928,8 @@ srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd)
/*
* Now, do a ".." to find parent dir of vp.
*/
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error == ENOTDIR && exportdir) {
dvp = exip->exi_dvp;
@@ -1039,8 +1040,8 @@ nfs_exportinit(void)
}
/*
- * Finalization routine for export routines. Called to cleanup previoulsy
- * initializtion work when the NFS server module could not be loaded correctly.
+ * Finalization routine for export routines. Called to cleanup previously
+ * initialization work when the NFS server module could not be loaded correctly.
*/
void
nfs_exportfini(void)
@@ -1243,7 +1244,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
* intended filesystem, so we can share the intended
* filesystem instead of the AUTOFS filesystem.
*/
- (void) VOP_ACCESS(vp, 0, 0, cr);
+ (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
/*
* We're interested in the top most filesystem.
@@ -1266,7 +1267,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
*/
bzero(&fid, sizeof (fid));
fid.fid_len = MAXFIDSZ;
- error = VOP_FID(vp, &fid);
+ error = VOP_FID(vp, &fid, NULL);
fsid = vp->v_vfsp->vfs_fsid;
if (error) {
VN_RELE(vp);
@@ -1914,7 +1915,7 @@ nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
* intended filesystem, so we can share the intended
* filesystem instead of the AUTOFS filesystem.
*/
- (void) VOP_ACCESS(vp, 0, 0, cr);
+ (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
/*
* We're interested in the top most filesystem.
@@ -1952,7 +1953,7 @@ nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
i += sz;
/*
- * For backwards compatability, the
+ * For backwards compatibility, the
* fid length may be less than
* NFS_FHMAXDATA, but it was always
* encoded as NFS_FHMAXDATA bytes.
@@ -2091,7 +2092,8 @@ nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
* otherwise, look it up.
*/
if (dvp == NULL) {
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error)
break;
}
@@ -2141,7 +2143,7 @@ makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi)
*fh = exi->exi_fh; /* struct copy */
- error = VOP_FID(vp, (fid_t *)&fh->fh_len);
+ error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL);
if (error) {
/*
* Should be something other than EREMOTE
@@ -2245,7 +2247,7 @@ makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
bzero(&fid, sizeof (fid));
fid.fid_len = MAXFIDSZ;
- error = VOP_FID(vp, &fid);
+ error = VOP_FID(vp, &fid, NULL);
if (error)
return (EREMOTE);
diff --git a/usr/src/uts/common/fs/nfs/nfs_log.c b/usr/src/uts/common/fs/nfs/nfs_log.c
index 49d9d78f10..a52a6937a9 100644
--- a/usr/src/uts/common/fs/nfs/nfs_log.c
+++ b/usr/src/uts/common/fs/nfs/nfs_log.c
@@ -461,7 +461,7 @@ log_file_create(caddr_t origname, struct log_file **lfpp)
rfsl_log_file++;
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &va, 0, CRED());
+ error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
if (error) {
nfs_cmn_err(error, CE_WARN,
"log_file_create: Can not stat %s - error = %m", name);
@@ -510,7 +510,7 @@ out:
if (vp != NULL) {
int error1;
error1 = VOP_CLOSE(vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
- CRED());
+ CRED(), NULL);
if (error1) {
nfs_cmn_err(error1, CE_WARN,
"log_file_create: Can not close %s - "
@@ -561,7 +561,7 @@ log_file_rele(struct log_file *lfp)
ASSERT(lfp->lf_writers == 0);
if (error = VOP_CLOSE(lfp->lf_vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
- CRED())) {
+ CRED(), NULL)) {
nfs_cmn_err(error, CE_WARN,
"NFS: Could not close log buffer %s - error = %m",
lfp->lf_path);
@@ -825,7 +825,7 @@ nfslog_write_logrecords(struct log_file *lfp,
va.va_mask = AT_SIZE;
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); /* UIO_WRITE */
- if ((error = VOP_GETATTR(vp, &va, 0, CRED())) == 0) {
+ if ((error = VOP_GETATTR(vp, &va, 0, CRED(), NULL)) == 0) {
if ((len + va.va_size) < (MAXOFF32_T)) {
error = VOP_WRITE(vp, &uio, ioflag, CRED(), NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
@@ -1173,7 +1173,7 @@ nfsl_flush(struct nfsl_flush_args *args, model_t model)
* This is where buffer flushing would occur, but there is no buffering
* at this time.
* Possibly rename the log buffer for processing.
- * Sets tparams->ta_error equal to the value of the error that occured,
+ * Sets tparams->ta_error equal to the value of the error that occurred,
* 0 otherwise.
* Returns ENOENT if the buffer is not found.
*/
diff --git a/usr/src/uts/common/fs/nfs/nfs_server.c b/usr/src/uts/common/fs/nfs/nfs_server.c
index a65ae500d8..a99299aea3 100644
--- a/usr/src/uts/common/fs/nfs/nfs_server.c
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c
@@ -2555,7 +2555,7 @@ rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
* filesystem, so we can perform the lookup in the
* intended filesystem.
*/
- (void) VOP_ACCESS(*vpp, 0, 0, cr);
+ (void) VOP_ACCESS(*vpp, 0, 0, cr, NULL);
/*
* If vnode is covered, get the
@@ -2569,7 +2569,8 @@ rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
}
}
- if (VOP_REALVP(*vpp, &realvp) == 0 && realvp != *vpp) {
+ if (VOP_REALVP(*vpp, &realvp, NULL) == 0 &&
+ realvp != *vpp) {
/*
* If realvp is different from *vpp
* then release our reference on *vpp, so that
@@ -2603,7 +2604,8 @@ rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
}
}
- if (VOP_REALVP(mc_dvp, &realvp) == 0 && realvp != mc_dvp) {
+ if (VOP_REALVP(mc_dvp, &realvp, NULL) == 0 &&
+ realvp != mc_dvp) {
/*
* *vpp is a file, obtain realvp of the parent
* directory vnode.
@@ -2800,7 +2802,7 @@ MCLpath(char **path)
((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
/*
- * The implementation of URLparse gaurantees that the final string will
+ * The implementation of URLparse guarantees that the final string will
* fit in the original one. Replaces '%' occurrences followed by 2 characters
* with its corresponding hexadecimal character.
*/
diff --git a/usr/src/uts/common/fs/nfs/nfs_srv.c b/usr/src/uts/common/fs/nfs/nfs_srv.c
index e75bd68a7c..d2969930be 100644
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c
@@ -249,7 +249,7 @@ rfs_setattr(struct nfssaargs *args, struct nfsattrstat *ns,
bva.va_mask = AT_UID | AT_SIZE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &bva, 0, cr);
+ error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
if (in_crit)
@@ -272,7 +272,8 @@ rfs_setattr(struct nfssaargs *args, struct nfsattrstat *ns,
offset = bva.va_size;
length = va.va_size - bva.va_size;
}
- if (nbl_conflict(vp, NBL_WRITE, offset, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
+ NULL)) {
error = EACCES;
}
}
@@ -322,7 +323,7 @@ rfs_setattr(struct nfssaargs *args, struct nfsattrstat *ns,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
VN_RELE(vp);
@@ -426,7 +427,8 @@ rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
* Do a normal single component lookup.
*/
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_START, "vop_lookup_start:");
- error = VOP_LOOKUP(dvp, da->da_name, &vp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, da->da_name, &vp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_END, "vop_lookup_end:");
}
@@ -512,7 +514,7 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
va.va_mask = AT_MODE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
@@ -567,7 +569,7 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
* Do the readlink.
*/
TRACE_0(TR_FAC_NFS, TR_VOP_READLINK_START, "vop_readlink_start:");
- error = VOP_READLINK(vp, &uio, cr);
+ error = VOP_READLINK(vp, &uio, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_READLINK_END, "vop_readlink_end:");
#if 0 /* notyet */
@@ -579,7 +581,7 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -673,7 +675,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
if (nbl_conflict(vp, NBL_READ, ra->ra_offset, ra->ra_count,
- 0)) {
+ 0, NULL)) {
nbl_end_crit(vp);
VN_RELE(vp);
rr->rr_data = NULL;
@@ -691,7 +693,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
va.va_mask = AT_ALL;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
@@ -716,7 +718,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
*/
if (crgetuid(cr) != va.va_uid) {
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START, "vop_access_start:");
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END, "vop_access_end:");
if (error) {
/*
@@ -725,7 +727,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
*/
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START,
"vop_access_start:");
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END,
"vop_access_end:");
}
@@ -824,7 +826,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
*/
va.va_mask = AT_ALL;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
freeb(mp);
@@ -868,7 +870,7 @@ done:
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -970,7 +972,7 @@ rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
va.va_mask = AT_UID|AT_MODE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
@@ -988,7 +990,7 @@ rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
* is always allowed to write it.
*/
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START, "vop_access_start:");
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END, "vop_access_end:");
if (error) {
VN_RELE(vp);
@@ -1020,7 +1022,7 @@ rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
nbl_start_crit(vp, RW_READER);
in_crit = 1;
if (nbl_conflict(vp, NBL_WRITE, wa->wa_offset,
- wa->wa_count, 0)) {
+ wa->wa_count, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1125,7 +1127,7 @@ rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
*/
va.va_mask = AT_ALL; /* now we want everything */
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
/* check for overflows */
if (!error) {
@@ -1413,7 +1415,7 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
va.va_mask = AT_UID|AT_MODE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, rp->cr);
+ error = VOP_GETATTR(vp, &va, 0, rp->cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (!error) {
if (crgetuid(rp->cr) != va.va_uid) {
@@ -1425,7 +1427,7 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
*/
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START,
"vop_access_start:");
- error = VOP_ACCESS(vp, VWRITE, 0, rp->cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, rp->cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END,
"vop_access_end:");
}
@@ -1437,7 +1439,7 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
* Check for a conflict with a nbmand-locked region.
*/
if (in_crit && nbl_conflict(vp, NBL_WRITE, rp->wa->wa_offset,
- rp->wa->wa_count, 0)) {
+ rp->wa->wa_count, 0, NULL)) {
error = EACCES;
}
@@ -1598,7 +1600,7 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
va.va_mask = AT_ALL; /* now we want everything */
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START,
"vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, rp->cr);
+ error = VOP_GETATTR(vp, &va, 0, rp->cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END,
"vop_getattr_end:");
if (!error)
@@ -1629,12 +1631,12 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
*/
if (data_written) {
TRACE_0(TR_FAC_NFS, TR_VOP_PUTPAGE_START, "vop_putpage_start:");
- error = VOP_PUTPAGE(vp, (u_offset_t)off, len, 0, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)off, len, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_PUTPAGE_END, "vop_putpage_end:");
if (!error) {
TRACE_0(TR_FAC_NFS, TR_VOP_FSYNC_START,
"vop_fsync_start:");
- error = VOP_FSYNC(vp, FNODSYNC, cr);
+ error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_FSYNC_END, "vop_fsync_end:");
}
}
@@ -1777,7 +1779,8 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
mode = VWRITE;
if (!(va.va_mask & AT_SIZE) || va.va_type != VREG) {
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_START, "vop_lookup_start:");
- error = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_END, "vop_lookup_end:");
if (!error) {
struct vattr at;
@@ -1786,7 +1789,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
at.va_mask = AT_MODE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START,
"vop_getattr_start:");
- error = VOP_GETATTR(tvp, &at, 0, cr);
+ error = VOP_GETATTR(tvp, &at, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END,
"vop_getattr_end:");
if (!error)
@@ -1814,7 +1817,8 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
* are conflicting locks.
*/
if (!error && (va.va_type == VREG) && (va.va_mask & AT_SIZE)) {
- lookuperr = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr);
+ lookuperr = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (!lookuperr &&
rfs4_check_delegated(FWRITE, tvp, va.va_size == 0)) {
@@ -1837,7 +1841,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
in_crit = 1;
bva.va_mask = AT_SIZE;
- error = VOP_GETATTR(tvp, &bva, 0, cr);
+ error = VOP_GETATTR(tvp, &bva, 0, cr, NULL);
if (!error) {
if (va.va_size < bva.va_size) {
offset = va.va_size;
@@ -1848,7 +1852,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
}
if (length) {
if (nbl_conflict(tvp, NBL_WRITE,
- offset, length, 0)) {
+ offset, length, 0, NULL)) {
error = EACCES;
}
}
@@ -1873,7 +1877,8 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
va.va_mode &= ~(VSUID | VSGID);
TRACE_0(TR_FAC_NFS, TR_VOP_CREATE_START, "vop_create_start:");
- error = VOP_CREATE(dvp, name, &va, NONEXCL, mode, &vp, cr, 0);
+ error = VOP_CREATE(dvp, name, &va, NONEXCL, mode, &vp, cr, 0,
+ NULL, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_CREATE_END, "vop_create_end:");
if (!error) {
@@ -1891,7 +1896,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
va.va_mask = AT_ALL;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START,
"vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END,
"vop_getattr_end:");
/* check for overflows */
@@ -1906,7 +1911,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
VN_RELE(vp);
}
@@ -1919,7 +1924,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
out:
@@ -1979,7 +1984,8 @@ rfs_remove(struct nfsdiropargs *da, enum nfsstat *status,
/*
* Check for a conflict with a non-blocking mandatory share reservation.
*/
- error = VOP_LOOKUP(vp, da->da_name, &targvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(vp, da->da_name, &targvp, NULL, 0,
+ NULL, cr, NULL, NULL, NULL);
if (error != 0) {
VN_RELE(vp);
*status = puterrno(error);
@@ -2004,20 +2010,20 @@ rfs_remove(struct nfsdiropargs *da, enum nfsstat *status,
if (nbl_need_check(targvp)) {
nbl_start_crit(targvp, RW_READER);
in_crit = 1;
- if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
error = EACCES;
goto out;
}
}
TRACE_0(TR_FAC_NFS, TR_VOP_REMOVE_START, "vop_remove_start:");
- error = VOP_REMOVE(vp, da->da_name, cr);
+ error = VOP_REMOVE(vp, da->da_name, cr, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_REMOVE_END, "vop_remove_end:");
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
out:
if (in_crit)
@@ -2126,7 +2132,7 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
* Check for a conflict with a non-blocking mandatory share reservation.
*/
error = VOP_LOOKUP(fromvp, args->rna_from.da_name, &srcvp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error != 0) {
VN_RELE(tovp);
VN_RELE(fromvp);
@@ -2147,8 +2153,8 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
/* Check for delegation on the file being renamed over, if it exists */
if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
- VOP_LOOKUP(tovp, args->rna_to.da_name, &targvp, NULL, 0, NULL, cr)
- == 0) {
+ VOP_LOOKUP(tovp, args->rna_to.da_name, &targvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL) == 0) {
if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
VN_RELE(tovp);
@@ -2165,7 +2171,7 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
if (nbl_need_check(srcvp)) {
nbl_start_crit(srcvp, RW_READER);
in_crit = 1;
- if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0)) {
+ if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -2173,7 +2179,7 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
TRACE_0(TR_FAC_NFS, TR_VOP_RENAME_START, "vop_rename_start:");
error = VOP_RENAME(fromvp, args->rna_from.da_name,
- tovp, args->rna_to.da_name, cr);
+ tovp, args->rna_to.da_name, cr, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_RENAME_END, "vop_rename_end:");
if (error == 0) {
@@ -2193,8 +2199,8 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(tovp, 0, cr);
- (void) VOP_FSYNC(fromvp, 0, cr);
+ (void) VOP_FSYNC(tovp, 0, cr, NULL);
+ (void) VOP_FSYNC(fromvp, 0, cr, NULL);
out:
if (in_crit)
@@ -2295,14 +2301,14 @@ rfs_link(struct nfslinkargs *args, enum nfsstat *status,
}
TRACE_0(TR_FAC_NFS, TR_VOP_LINK_START, "vop_link_start:");
- error = VOP_LINK(tovp, fromvp, args->la_to.da_name, cr);
+ error = VOP_LINK(tovp, fromvp, args->la_to.da_name, cr, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_LINK_END, "vop_link_end:");
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(tovp, 0, cr);
- (void) VOP_FSYNC(fromvp, FNODSYNC, cr);
+ (void) VOP_FSYNC(tovp, 0, cr, NULL);
+ (void) VOP_FSYNC(fromvp, FNODSYNC, cr, NULL);
VN_RELE(tovp);
VN_RELE(fromvp);
@@ -2381,7 +2387,8 @@ rfs_symlink(struct nfsslargs *args, enum nfsstat *status,
va.va_mask |= AT_TYPE;
TRACE_0(TR_FAC_NFS, TR_VOP_SYMLINK_START, "vop_symlink_start:");
- error = VOP_SYMLINK(vp, args->sla_from.da_name, &va, args->sla_tnm, cr);
+ error = VOP_SYMLINK(vp, args->sla_from.da_name, &va, args->sla_tnm, cr,
+ NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_SYMLINK_END, "vop_symlink_end:");
/*
@@ -2389,17 +2396,17 @@ rfs_symlink(struct nfsslargs *args, enum nfsstat *status,
*/
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_START, "vop_lookup_start:");
lerror = VOP_LOOKUP(vp, args->sla_from.da_name, &svp, NULL,
- 0, NULL, cr);
+ 0, NULL, cr, NULL, NULL, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_END, "vop_lookup_end:");
if (!lerror) {
- (void) VOP_FSYNC(svp, 0, cr);
+ (void) VOP_FSYNC(svp, 0, cr, NULL);
VN_RELE(svp);
}
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -2477,7 +2484,7 @@ rfs_mkdir(struct nfscreatargs *args, struct nfsdiropres *dr,
va.va_mask |= AT_TYPE;
TRACE_0(TR_FAC_NFS, TR_VOP_MKDIR_START, "vop_mkdir_start:");
- error = VOP_MKDIR(vp, name, &va, &dvp, cr);
+ error = VOP_MKDIR(vp, name, &va, &dvp, cr, NULL, 0, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_MKDIR_END, "vop_mkdir_end:");
if (!error) {
@@ -2487,7 +2494,7 @@ rfs_mkdir(struct nfscreatargs *args, struct nfsdiropres *dr,
*/
va.va_mask = AT_ALL; /* We want everything */
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(dvp, &va, 0, cr);
+ error = VOP_GETATTR(dvp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
/* check for overflows */
if (!error) {
@@ -2500,14 +2507,14 @@ rfs_mkdir(struct nfscreatargs *args, struct nfsdiropres *dr,
/*
* Force new data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
VN_RELE(dvp);
}
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -2570,13 +2577,13 @@ rfs_rmdir(struct nfsdiropargs *da, enum nfsstat *status,
* remove.
*/
TRACE_0(TR_FAC_NFS, TR_VOP_RMDIR_START, "vop_rmdir_start:");
- error = VOP_RMDIR(vp, da->da_name, rootdir, cr);
+ error = VOP_RMDIR(vp, da->da_name, rootdir, cr, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_RMDIR_END, "vop_rmdir_end:");
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -2635,7 +2642,7 @@ rfs_readdir(struct nfsrddirargs *rda, struct nfsrddirres *rd,
TRACE_0(TR_FAC_NFS, TR_VOP_RWLOCK_END, "vop_rwlock_end:");
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START, "vop_access_start:");
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END, "vop_access_end:");
if (error) {
rd->rd_entries = NULL;
@@ -2673,7 +2680,7 @@ rfs_readdir(struct nfsrddirargs *rda, struct nfsrddirres *rd,
* read directory
*/
TRACE_0(TR_FAC_NFS, TR_VOP_READDIR_START, "vop_readdir_start:");
- error = VOP_READDIR(vp, &uio, cr, &iseof);
+ error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_READDIR_END, "vop_readdir_end:");
/*
@@ -2707,7 +2714,7 @@ bad:
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -2969,7 +2976,7 @@ acl_perm(struct vnode *vp, struct exportinfo *exi, struct vattr *va, cred_t *cr)
/* dont care default acl */
vsa.vsa_mask = (VSA_ACL | VSA_ACLCNT);
- error = VOP_GETSECATTR(vp, &vsa, 0, cr);
+ error = VOP_GETSECATTR(vp, &vsa, 0, cr, NULL);
if (!error) {
aclcnt = vsa.vsa_aclcnt;
diff --git a/usr/src/uts/common/fs/nfs/nfs_subr.c b/usr/src/uts/common/fs/nfs/nfs_subr.c
index d9ae64ddf2..10391a7f42 100644
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c
+++ b/usr/src/uts/common/fs/nfs/nfs_subr.c
@@ -105,7 +105,7 @@
* freelist and then trying to place them back on the freelist
* when their reference is released. This means that the when an
* rnode is looked up in the hash queues, then either the rnode
- * is removed from the freelist and that reference is tranfered to
+ * is removed from the freelist and that reference is transferred to
* the new reference or the vnode reference count must be incremented
* accordingly. The mutex for the freelist must be held in order to
* accurately test to see if the rnode is on the freelist or not.
@@ -2095,7 +2095,7 @@ setdirgid(vnode_t *dvp, gid_t *gidp, cred_t *cr)
struct vattr va;
va.va_mask = AT_MODE | AT_GID;
- error = VOP_GETATTR(dvp, &va, 0, cr);
+ error = VOP_GETATTR(dvp, &va, 0, cr, NULL);
if (error)
return (error);
@@ -2123,7 +2123,7 @@ setdirmode(vnode_t *dvp, mode_t *omp, cred_t *cr)
struct vattr va;
va.va_mask = AT_MODE;
- error = VOP_GETATTR(dvp, &va, 0, cr);
+ error = VOP_GETATTR(dvp, &va, 0, cr, NULL);
if (error)
return (error);
@@ -2189,7 +2189,7 @@ rinactive(rnode_t *rp, cred_t *cr)
if (vn_has_cached_data(vp)) {
ASSERT(vp->v_type != VCHR);
if ((rp->r_flags & RDIRTY) && !rp->r_error) {
- error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, 0, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, 0, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -3084,7 +3084,7 @@ toomany:
*/
while (cnt-- > 0) {
vp = vplist[cnt];
- (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr, NULL);
VN_RELE(vp);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs_vnops.c b/usr/src/uts/common/fs/nfs/nfs_vnops.c
index 96b7044e6a..befefa580f 100644
--- a/usr/src/uts/common/fs/nfs/nfs_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs_vnops.c
@@ -91,7 +91,8 @@ static int nfsread(vnode_t *, caddr_t, uint_t, int, size_t *, cred_t *);
static int nfssetattr(vnode_t *, struct vattr *, int, cred_t *);
static int nfslookup_dnlc(vnode_t *, char *, vnode_t **, cred_t *);
static int nfslookup_otw(vnode_t *, char *, vnode_t **, cred_t *, int);
-static int nfsrename(vnode_t *, char *, vnode_t *, char *, cred_t *);
+static int nfsrename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *);
static int nfsreaddir(vnode_t *, rddir_cache *, cred_t *);
static int nfs_bio(struct buf *, cred_t *);
static int nfs_getapage(vnode_t *, u_offset_t, size_t, uint_t *,
@@ -123,59 +124,75 @@ static void nfs_delmap_callback(struct as *, void *, uint_t);
* more details on rnode locking.
*/
-static int nfs_open(vnode_t **, int, cred_t *);
-static int nfs_close(vnode_t *, int, int, offset_t, cred_t *);
+static int nfs_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int nfs_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
static int nfs_read(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
static int nfs_write(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
-static int nfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
-static int nfs_getattr(vnode_t *, struct vattr *, int, cred_t *);
+static int nfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
+static int nfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
static int nfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
caller_context_t *);
-static int nfs_access(vnode_t *, int, int, cred_t *);
+static int nfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
static int nfs_accessx(void *, int, cred_t *);
-static int nfs_readlink(vnode_t *, struct uio *, cred_t *);
-static int nfs_fsync(vnode_t *, int, cred_t *);
-static void nfs_inactive(vnode_t *, cred_t *);
+static int nfs_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int nfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static void nfs_inactive(vnode_t *, cred_t *, caller_context_t *);
static int nfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
- int, vnode_t *, cred_t *);
+ int, vnode_t *, cred_t *, caller_context_t *,
+ int *, pathname_t *);
static int nfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
- int, vnode_t **, cred_t *, int);
-static int nfs_remove(vnode_t *, char *, cred_t *);
-static int nfs_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int nfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-static int nfs_mkdir(vnode_t *, char *, struct vattr *,
- vnode_t **, cred_t *);
-static int nfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
+ int, vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+static int nfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+ int);
+static int nfs_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
+ cred_t *, caller_context_t *, int, vsecattr_t *);
+static int nfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
static int nfs_symlink(vnode_t *, char *, struct vattr *, char *,
- cred_t *);
-static int nfs_readdir(vnode_t *, struct uio *, cred_t *, int *);
-static int nfs_fid(vnode_t *, fid_t *);
+ cred_t *, caller_context_t *, int);
+static int nfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
+ caller_context_t *, int);
+static int nfs_fid(vnode_t *, fid_t *, caller_context_t *);
static int nfs_rwlock(vnode_t *, int, caller_context_t *);
static void nfs_rwunlock(vnode_t *, int, caller_context_t *);
-static int nfs_seek(vnode_t *, offset_t, offset_t *);
+static int nfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
static int nfs_getpage(vnode_t *, offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
- enum seg_rw, cred_t *);
-static int nfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *);
-static int nfs_map(vnode_t *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-static int nfs_addmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
+ enum seg_rw, cred_t *, caller_context_t *);
+static int nfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+static int nfs_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+static int nfs_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
static int nfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
+ struct flk_callback *, cred_t *, caller_context_t *);
static int nfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
-static int nfs_realvp(vnode_t *, vnode_t **);
-static int nfs_delmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uint_t, uint_t, uint_t, cred_t *);
-static int nfs_pathconf(vnode_t *, int, ulong_t *, cred_t *);
+static int nfs_realvp(vnode_t *, vnode_t **, caller_context_t *);
+static int nfs_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *, caller_context_t *);
+static int nfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
static int nfs_pageio(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static int nfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *);
+ cred_t *, caller_context_t *);
+static int nfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+static int nfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+static int nfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
struct vnodeops *nfs_vnodeops;
@@ -233,7 +250,7 @@ nfs_getvnodeops(void)
/* ARGSUSED */
static int
-nfs_open(vnode_t **vpp, int flag, cred_t *cr)
+nfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
int error;
struct vattr va;
@@ -282,8 +299,10 @@ nfs_open(vnode_t **vpp, int flag, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+nfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
rnode_t *rp;
int error;
@@ -357,11 +376,12 @@ nfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
*/
if ((flag & FWRITE) && vn_has_cached_data(vp)) {
if ((VTOMI(vp)->mi_flags & MI_NOCTO)) {
- error = nfs_putpage(vp, (offset_t)0, 0, B_ASYNC, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, B_ASYNC,
+ cr, ct);
if (error == EAGAIN)
error = 0;
} else
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
if (!error) {
mutex_enter(&rp->r_statelock);
error = rp->r_error;
@@ -478,10 +498,10 @@ nfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
* Copy data.
*/
error = vpm_data_copy(vp, off + on, n, uiop,
- 1, NULL, 0, S_READ);
+ 1, NULL, 0, S_READ);
} else {
base = segmap_getmapflt(segkmap, vp, off + on, n,
- 1, S_READ);
+ 1, S_READ);
error = uiomove(base + on, n, UIO_READ, uiop);
}
@@ -679,23 +699,23 @@ nfs_fwrite:
if (segmap_kpm) {
int pon = uiop->uio_loffset & PAGEOFFSET;
size_t pn = MIN(PAGESIZE - pon,
- uiop->uio_resid);
+ uiop->uio_resid);
int pagecreate;
mutex_enter(&rp->r_statelock);
pagecreate = (pon == 0) && (pn == PAGESIZE ||
- uiop->uio_loffset + pn >= rp->r_size);
+ uiop->uio_loffset + pn >= rp->r_size);
mutex_exit(&rp->r_statelock);
base = segmap_getmapflt(segkmap, vp, off + on,
- pn, !pagecreate, S_WRITE);
+ pn, !pagecreate, S_WRITE);
error = writerp(rp, base + pon, n, uiop,
- pagecreate);
+ pagecreate);
} else {
base = segmap_getmapflt(segkmap, vp, off + on,
- n, 0, S_READ);
+ n, 0, S_READ);
error = writerp(rp, base + on, n, uiop, 0);
}
}
@@ -856,9 +876,10 @@ nfswrite(vnode_t *vp, caddr_t base, uint_t offset, int count, cred_t *cr)
offset += tsize;
if (mi->mi_io_kstats) {
mutex_enter(&mi->mi_lock);
- KSTAT_IO_PTR(mi->mi_io_kstats)->writes++;
- KSTAT_IO_PTR(mi->mi_io_kstats)->nwritten +=
- tsize;
+ KSTAT_IO_PTR(mi->mi_io_kstats)->
+ writes++;
+ KSTAT_IO_PTR(mi->mi_io_kstats)->
+ nwritten += tsize;
mutex_exit(&mi->mi_lock);
}
lwp_stat_update(LWP_STAT_OUBLK, 1);
@@ -995,7 +1016,8 @@ nfsread(vnode_t *vp, caddr_t base, uint_t offset, int count, size_t *residp,
/* ARGSUSED */
static int
-nfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
+nfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp,
+ caller_context_t *ct)
{
if (nfs_zone() != VTOMI(vp)->mi_zone)
@@ -1008,8 +1030,10 @@ nfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
}
}
+/* ARGSUSED */
static int
-nfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+nfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -1052,7 +1076,7 @@ nfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
mutex_enter(&rp->r_statelock);
rp->r_gcount++;
mutex_exit(&rp->r_statelock);
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
mutex_enter(&rp->r_statelock);
if (error && (error == ENOSPC || error == EDQUOT)) {
if (!rp->r_error)
@@ -1096,7 +1120,7 @@ nfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
return (error);
error = secpolicy_vnode_setattr(cr, vp, vap, &va, flags, nfs_accessx,
- vp);
+ vp);
if (error)
return (error);
@@ -1141,7 +1165,7 @@ nfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
rp->r_count > 0 ||
rp->r_mapcnt > 0)) {
ASSERT(vp->v_type != VCHR);
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1324,11 +1348,12 @@ static int
nfs_accessx(void *vp, int mode, cred_t *cr)
{
ASSERT(nfs_zone() == VTOMI((vnode_t *)vp)->mi_zone);
- return (nfs_access(vp, mode, 0, cr));
+ return (nfs_access(vp, mode, 0, cr, NULL));
}
+/* ARGSUSED */
static int
-nfs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+nfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
struct vattr va;
int error;
@@ -1387,8 +1412,9 @@ found:
static int nfs_do_symlink_cache = 1;
+/* ARGSUSED */
static int
-nfs_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+nfs_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
{
int error;
struct nfsrdlnres rl;
@@ -1483,8 +1509,9 @@ nfs_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
* metadata changes are not cached on the client before being
* sent to the server.
*/
+/* ARGSUSED */
static int
-nfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+nfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
int error;
@@ -1494,7 +1521,7 @@ nfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
if (nfs_zone() != VTOMI(vp)->mi_zone)
return (EIO);
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
if (!error)
error = VTOR(vp)->r_error;
return (error);
@@ -1506,8 +1533,9 @@ nfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
* operation while it was open, it got renamed instead. Here we
* remove the renamed file.
*/
+/* ARGSUSED */
static void
-nfs_inactive(vnode_t *vp, cred_t *cr)
+nfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
@@ -1566,7 +1594,8 @@ redo:
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_count > 0)) {
ASSERT(vp->v_type != VCHR);
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0,
+ cr, ct);
if (error) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1609,9 +1638,11 @@ redo:
* Remote file system operations having to do with directory manipulation.
*/
+/* ARGSUSED */
static int
nfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
int error;
vnode_t *vp;
@@ -1734,7 +1765,7 @@ nfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* just need to check access.
*/
if (strcmp(nm, ".") == 0) {
- error = nfs_access(dvp, VEXEC, 0, cr);
+ error = nfs_access(dvp, VEXEC, 0, cr, NULL);
if (error)
return (error);
VN_HOLD(dvp);
@@ -1789,7 +1820,7 @@ nfslookup_dnlc(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr)
return (error);
vp = dnlc_lookup(dvp, nm);
if (vp != NULL) {
- error = nfs_access(dvp, VEXEC, 0, cr);
+ error = nfs_access(dvp, VEXEC, 0, cr, NULL);
if (error) {
VN_RELE(vp);
return (error);
@@ -1884,7 +1915,8 @@ nfslookup_otw(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
/* ARGSUSED */
static int
nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
- int mode, vnode_t **vpp, cred_t *cr, int lfaware)
+ int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
struct nfscreatargs args;
@@ -1925,7 +1957,7 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* just need to check access.
*/
} else if (strcmp(nm, ".") == 0) {
- error = nfs_access(dvp, VEXEC, 0, cr);
+ error = nfs_access(dvp, VEXEC, 0, cr, ct);
if (error) {
nfs_rw_exit(&drp->r_rwlock);
return (error);
@@ -1954,7 +1986,7 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
vp = specvp(vp, vp->v_rdev, vp->v_type, cr);
VN_RELE(tempvp);
}
- if (!(error = VOP_ACCESS(vp, mode, 0, cr))) {
+ if (!(error = VOP_ACCESS(vp, mode, 0, cr, ct))) {
if ((vattr.va_mask & AT_SIZE) &&
vp->v_type == VREG) {
vattr.va_mask = AT_SIZE;
@@ -1969,7 +2001,7 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
/*
* existing file got truncated, notify.
*/
- vnevent_create(vp);
+ vnevent_create(vp, ct);
*vpp = vp;
}
return (error);
@@ -2130,8 +2162,9 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* we rename it instead of removing it and nfs_inactive
* will remove the new name.
*/
+/* ARGSUSED */
static int
-nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
+nfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, int flags)
{
int error;
struct nfsdiropargs da;
@@ -2184,7 +2217,7 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
(rp->r_unldvp == NULL || strcmp(nm, rp->r_unlname) == 0)) {
mutex_exit(&rp->r_statelock);
tmpname = newname();
- error = nfsrename(dvp, nm, dvp, tmpname, cr);
+ error = nfsrename(dvp, nm, dvp, tmpname, cr, ct);
if (error)
kmem_free(tmpname, MAXNAMELEN);
else {
@@ -2213,7 +2246,7 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
*/
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_count > 0)) {
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -2253,7 +2286,7 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
}
if (error == 0) {
- vnevent_remove(vp, dvp, nm);
+ vnevent_remove(vp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -2262,8 +2295,10 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
struct nfslinkargs args;
@@ -2274,7 +2309,7 @@ nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
if (nfs_zone() != VTOMI(tdvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(svp, &realvp) == 0)
+ if (VOP_REALVP(svp, &realvp, ct) == 0)
svp = realvp;
args.la_from = VTOFH(svp);
@@ -2310,29 +2345,32 @@ nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
/*
* Notify the source file of this link operation.
*/
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
return (error);
}
+/* ARGSUSED */
static int
-nfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
vnode_t *realvp;
if (nfs_zone() != VTOMI(odvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
- return (nfsrename(odvp, onm, ndvp, nnm, cr));
+ return (nfsrename(odvp, onm, ndvp, nnm, cr, ct));
}
/*
* nfsrename does the real work of renaming in NFS Version 2.
*/
static int
-nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct)
{
int error;
enum nfsstat status;
@@ -2465,10 +2503,10 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
* the server removing the file completely.
*/
tmpname = newname();
- error = nfs_link(ndvp, nvp, tmpname, cr);
+ error = nfs_link(ndvp, nvp, tmpname, cr, NULL, 0);
if (error == EOPNOTSUPP) {
error = nfs_rename(ndvp, nnm, ndvp, tmpname,
- cr);
+ cr, NULL, 0);
}
if (error) {
kmem_free(tmpname, MAXNAMELEN);
@@ -2570,7 +2608,7 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
if (rp->r_unldvp != NULL) {
if (strcmp(rp->r_unlname, onm) == 0) {
(void) strncpy(rp->r_unlname,
- nnm, MAXNAMELEN);
+ nnm, MAXNAMELEN);
rp->r_unlname[MAXNAMELEN - 1] = '\0';
if (ndvp != rp->r_unldvp) {
@@ -2595,13 +2633,13 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
if (error == 0) {
if (nvp)
- vnevent_rename_dest(nvp, ndvp, nnm);
+ vnevent_rename_dest(nvp, ndvp, nnm, ct);
if (odvp != ndvp)
- vnevent_rename_dest_dir(ndvp);
+ vnevent_rename_dest_dir(ndvp, ct);
ASSERT(ovp != NULL);
- vnevent_rename_src(ovp, odvp, onm);
+ vnevent_rename_src(ovp, odvp, onm, ct);
}
if (nvp) {
@@ -2615,8 +2653,10 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
+nfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr,
+ caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
struct nfscreatargs args;
@@ -2701,8 +2741,10 @@ nfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
enum nfsstat status;
@@ -2789,7 +2831,7 @@ nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
}
if (error == 0) {
- vnevent_rmdir(vp, dvp, nm);
+ vnevent_rmdir(vp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -2798,8 +2840,10 @@ nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr)
+nfs_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
struct nfsslargs args;
@@ -2868,8 +2912,10 @@ static int nfs_shrinkreaddir = 0;
* may return only one block's worth of entries. Entries may be compressed
* on the server.
*/
+/* ARGSUSED */
static int
-nfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp)
+nfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int error;
size_t count;
@@ -2980,7 +3026,7 @@ top:
*/
mutex_exit(&rp->r_statelock);
(void) nfs_rw_enter_sig(&rp->r_rwlock,
- RW_READER, FALSE);
+ RW_READER, FALSE);
rddir_cache_rele(rdc);
if (nrdc != NULL)
rddir_cache_rele(nrdc);
@@ -2988,7 +3034,7 @@ top:
}
mutex_exit(&rp->r_statelock);
(void) nfs_rw_enter_sig(&rp->r_rwlock,
- RW_READER, FALSE);
+ RW_READER, FALSE);
rddir_cache_rele(rdc);
goto top;
}
@@ -3434,8 +3480,9 @@ nfs_bio(struct buf *bp, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_fid(vnode_t *vp, fid_t *fidp)
+nfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
struct nfs_fid *fp;
rnode_t *rp;
@@ -3486,7 +3533,7 @@ nfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-nfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+nfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
/*
@@ -3514,10 +3561,11 @@ static int nfs_lostpage = 0; /* number of times we lost original page */
/*
* Return all the pages from [off..off+len) in file
*/
+/* ARGSUSED */
static int
nfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
int error;
@@ -3661,8 +3709,8 @@ reread:
else if (blkoff == rp->r_nextr)
readahead = nfs_nra;
else if (rp->r_nextr > blkoff &&
- ((ra_window = (rp->r_nextr - blkoff) / bsize)
- <= (nfs_nra - 1)))
+ ((ra_window = (rp->r_nextr - blkoff) / bsize)
+ <= (nfs_nra - 1)))
readahead = nfs_nra - ra_window;
else
readahead = 0;
@@ -3736,7 +3784,7 @@ again:
} else
blksize = rp->r_size - blkoff;
} else if ((off == 0) ||
- (off != rp->r_nextr && !readahead_issued)) {
+ (off != rp->r_nextr && !readahead_issued)) {
blksize = PAGESIZE;
blkoff = off; /* block = page here */
} else
@@ -3818,9 +3866,9 @@ again:
}
if (!readahead_issued && !error) {
- mutex_enter(&rp->r_statelock);
- rp->r_nextr = io_off + io_len;
- mutex_exit(&rp->r_statelock);
+ mutex_enter(&rp->r_statelock);
+ rp->r_nextr = io_off + io_len;
+ mutex_exit(&rp->r_statelock);
}
}
}
@@ -3970,8 +4018,10 @@ nfs_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, struct seg *seg,
* len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
* (from pageout).
*/
+/* ARGSUSED */
static int
-nfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+nfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -4172,7 +4222,7 @@ nfs_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
*/
if (!(flags & B_ASYNC)) {
error = nfs_putpage(vp, io_off, io_len,
- B_INVAL | B_FORCE, cr);
+ B_INVAL | B_FORCE, cr, NULL);
}
} else {
if (error)
@@ -4188,9 +4238,11 @@ nfs_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs_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)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error;
@@ -4292,7 +4344,8 @@ done:
/* ARGSUSED */
static int
nfs_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)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
rnode_t *rp;
@@ -4315,9 +4368,10 @@ nfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
return (0);
}
+/* ARGSUSED */
static int
-nfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+nfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
+ struct flk_callback *flk_cbp, cred_t *cr, caller_context_t *ct)
{
netobj lm_fh;
int rc;
@@ -4374,7 +4428,7 @@ nfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (!lm_safelock(vp, bfp, cr))
return (EAGAIN);
}
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
rp = VTOR(vp);
@@ -4404,26 +4458,27 @@ nfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (cmd != F_GETLK) {
mutex_enter(&rp->r_statelock);
while (rp->r_count > 0) {
- if (intr) {
- klwp_t *lwp = ttolwp(curthread);
+ if (intr) {
+ klwp_t *lwp = ttolwp(curthread);
- if (lwp != NULL)
- lwp->lwp_nostop++;
- if (cv_wait_sig(&rp->r_cv, &rp->r_statelock) == 0) {
+ if (lwp != NULL)
+ lwp->lwp_nostop++;
+ if (cv_wait_sig(&rp->r_cv, &rp->r_statelock)
+ == 0) {
+ if (lwp != NULL)
+ lwp->lwp_nostop--;
+ rc = EINTR;
+ break;
+ }
if (lwp != NULL)
lwp->lwp_nostop--;
- rc = EINTR;
- break;
- }
- if (lwp != NULL)
- lwp->lwp_nostop--;
- } else
+ } else
cv_wait(&rp->r_cv, &rp->r_statelock);
}
mutex_exit(&rp->r_statelock);
if (rc != 0)
goto done;
- error = nfs_putpage(vp, (offset_t)0, 0, B_INVAL, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, B_INVAL, cr, ct);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
@@ -4512,7 +4567,7 @@ nfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
/* ARGSUSED */
static int
-nfs_realvp(vnode_t *vp, vnode_t **vpp)
+nfs_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
return (EINVAL);
@@ -4531,7 +4586,8 @@ nfs_realvp(vnode_t *vp, vnode_t **vpp)
/* ARGSUSED */
static int
nfs_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)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
int caller_found;
int error;
@@ -4661,10 +4717,10 @@ nfs_delmap_callback(struct as *as, void *arg, uint_t event)
if ((mi->mi_flags & MI_NOCTO) ||
nfs_zone() != mi->mi_zone)
error = nfs_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_ASYNC, dmapp->cr);
+ B_ASYNC, dmapp->cr, NULL);
else
error = nfs_putpage(dmapp->vp, dmapp->off, dmapp->len,
- 0, dmapp->cr);
+ 0, dmapp->cr, NULL);
if (!error) {
mutex_enter(&rp->r_statelock);
error = rp->r_error;
@@ -4676,7 +4732,7 @@ nfs_delmap_callback(struct as *as, void *arg, uint_t event)
if ((rp->r_flags & RDIRECTIO) || (mi->mi_flags & MI_DIRECTIO))
(void) nfs_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_INVAL, dmapp->cr);
+ B_INVAL, dmapp->cr, NULL);
dmapp->caller->error = error;
(void) as_delete_callback(as, arg);
@@ -4685,7 +4741,8 @@ nfs_delmap_callback(struct as *as, void *arg, uint_t event)
/* ARGSUSED */
static int
-nfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+nfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int error = 0;
@@ -4748,7 +4805,7 @@ nfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
break;
}
return (error ? EINVAL : 0);
- }
+ }
case _PC_XATTR_EXISTS:
*valp = 0;
@@ -4806,9 +4863,10 @@ nfs_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -4837,8 +4895,10 @@ nfs_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
-nfs_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo_t *mi;
@@ -4856,8 +4916,10 @@ nfs_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (ENOSYS);
}
+/* ARGSUSED */
static int
-nfs_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo_t *mi;
@@ -4872,11 +4934,13 @@ nfs_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (error);
}
- return (fs_fab_acl(vp, vsecattr, flag, cr));
+ return (fs_fab_acl(vp, vsecattr, flag, cr, ct));
}
+/* ARGSUSED */
static int
-nfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+nfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
struct shrlock nshr;
@@ -4905,7 +4969,7 @@ nfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
* request off to the local share code.
*/
if (VTOMI(vp)->mi_flags & MI_LLOCK)
- return (fs_shrlock(vp, cmd, shr, flag, cr));
+ return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
switch (cmd) {
case F_SHARE:
diff --git a/usr/src/uts/common/fs/objfs/objfs_common.c b/usr/src/uts/common/fs/objfs/objfs_common.c
index 35252c0d91..bdce50353e 100644
--- a/usr/src/uts/common/fs/objfs/objfs_common.c
+++ b/usr/src/uts/common/fs/objfs/objfs_common.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,7 +36,8 @@
*/
/* ARGSUSED */
int
-objfs_dir_open(vnode_t **cpp, int flag, cred_t *cr)
+objfs_dir_open(vnode_t **cpp, int flag, cred_t *cr,
+ caller_context_t *ct)
{
if ((flag & (FOFFMAX | FWRITE)) != FOFFMAX)
return (EINVAL);
@@ -50,17 +50,19 @@ objfs_dir_open(vnode_t **cpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
int
-objfs_common_close(vnode_t *vp, int flag, int count, offset_t off, cred_t *cr)
+objfs_common_close(vnode_t *vp, int flag, int count, offset_t off, cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
/*
- * For directories, ensure we're not open for writting.
+ * For directories, ensure we're not open for writing.
*/
/* ARGSUSED */
int
-objfs_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+objfs_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
if (mode & VWRITE)
return (EACCES);
diff --git a/usr/src/uts/common/fs/objfs/objfs_data.c b/usr/src/uts/common/fs/objfs/objfs_data.c
index 4e050112fb..6777cd469e 100644
--- a/usr/src/uts/common/fs/objfs/objfs_data.c
+++ b/usr/src/uts/common/fs/objfs/objfs_data.c
@@ -455,7 +455,8 @@ objfs_create_data(vnode_t *pvp)
/* ARGSUSED */
static int
-objfs_data_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+objfs_data_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
struct module *mp;
timestruc_t now;
@@ -480,7 +481,8 @@ objfs_data_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
static int
-objfs_data_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+objfs_data_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
if (mode & (VWRITE|VEXEC))
return (EACCES);
@@ -490,7 +492,8 @@ objfs_data_access(vnode_t *vp, int mode, int flags, cred_t *cr)
/* ARGSUSED */
int
-objfs_data_open(vnode_t **cpp, int flag, cred_t *cr)
+objfs_data_open(vnode_t **cpp, int flag, cred_t *cr,
+ caller_context_t *ct)
{
if (flag & FWRITE)
return (EINVAL);
@@ -556,7 +559,7 @@ read_symtab(void *addr, size_t size, off_t offset, uio_t *uio)
/* ARGSUSED */
static int
objfs_data_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr,
- caller_context_t *ct)
+ caller_context_t *ct)
{
int error = 0;
objfs_datanode_t *dnode = vp->v_data;
@@ -745,7 +748,8 @@ error:
/* ARGSUSED */
static int
-objfs_data_seek(vnode_t *vp, offset_t off, offset_t *offp)
+objfs_data_seek(vnode_t *vp, offset_t off, offset_t *offp,
+ caller_context_t *ct)
{
return (0);
}
diff --git a/usr/src/uts/common/fs/objfs/objfs_odir.c b/usr/src/uts/common/fs/objfs/objfs_odir.c
index a7ef0ed502..9558061e83 100644
--- a/usr/src/uts/common/fs/objfs/objfs_odir.c
+++ b/usr/src/uts/common/fs/objfs/objfs_odir.c
@@ -63,7 +63,8 @@ objfs_create_odirnode(vnode_t *pvp, struct modctl *mp)
/* ARGSUSED */
static int
-objfs_odir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+objfs_odir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
timestruc_t now;
diff --git a/usr/src/uts/common/fs/objfs/objfs_root.c b/usr/src/uts/common/fs/objfs/objfs_root.c
index 1e9bb8c1f0..06f06d35f9 100644
--- a/usr/src/uts/common/fs/objfs/objfs_root.c
+++ b/usr/src/uts/common/fs/objfs/objfs_root.c
@@ -38,7 +38,8 @@
extern int last_module_id;
-static int objfs_root_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *);
+static int objfs_root_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
+ cred_t *);
static int objfs_root_do_readdir(vnode_t *, struct dirent64 *, int *,
offset_t *, offset_t *, void *);
@@ -54,7 +55,8 @@ objfs_create_root(vfs_t *vfsp)
/* ARGSUSED */
static int
-objfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+objfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
vap->va_type = VDIR;
vap->va_mode = 0555;
@@ -67,8 +69,10 @@ objfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
return (objfs_common_getattr(vp, vap));
}
+/* ARGSUSED */
static int
-objfs_root_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop)
+objfs_root_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
+ cred_t *cr)
{
int result = ENOENT;
struct modctl *mp;
@@ -148,11 +152,12 @@ objfs_root_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
/* ARGSUSED */
static int
-objfs_root_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+objfs_root_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
struct modctl *mp = &modules;
- return (gfs_dir_readdir(vp, uiop, eofp, &mp));
+ return (gfs_dir_readdir(vp, uiop, eofp, &mp, cr, ct));
}
const fs_operation_def_t objfs_tops_root[] = {
diff --git a/usr/src/uts/common/fs/pathname.c b/usr/src/uts/common/fs/pathname.c
index 904477f3a4..82d2e36973 100644
--- a/usr/src/uts/common/fs/pathname.c
+++ b/usr/src/uts/common/fs/pathname.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -210,7 +209,7 @@ pn_getsymlink(vnode_t *vp, struct pathname *pnp, cred_t *crp)
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_extflg = UIO_COPY_CACHED;
auio.uio_resid = pnp->pn_bufsize;
- if ((error = VOP_READLINK(vp, &auio, crp)) == 0) {
+ if ((error = VOP_READLINK(vp, &auio, crp, NULL)) == 0) {
pnp->pn_pathlen = pnp->pn_bufsize - auio.uio_resid;
if (pnp->pn_pathlen == pnp->pn_bufsize)
error = ENAMETOOLONG;
diff --git a/usr/src/uts/common/fs/pcfs/pc_dir.c b/usr/src/uts/common/fs/pcfs/pc_dir.c
index 616efe23cb..cc6d1a8fe4 100644
--- a/usr/src/uts/common/fs/pcfs/pc_dir.c
+++ b/usr/src/uts/common/fs/pcfs/pc_dir.c
@@ -387,7 +387,8 @@ pc_dirremove(
struct pcnode *dp,
char *namep,
struct vnode *cdir,
- enum vtype type)
+ enum vtype type,
+ caller_context_t *ctp)
{
struct pcslot slot;
struct pcnode *pcp;
@@ -467,9 +468,9 @@ pc_dirremove(
if (error == 0) {
if (type == VDIR) {
- vnevent_rmdir(PCTOV(pcp), vp, namep);
+ vnevent_rmdir(PCTOV(pcp), vp, namep, ctp);
} else {
- vnevent_remove(PCTOV(pcp), vp, namep);
+ vnevent_remove(PCTOV(pcp), vp, namep, ctp);
}
}
@@ -556,7 +557,8 @@ pc_rename(
struct pcnode *dp, /* parent directory */
struct pcnode *tdp, /* target directory */
char *snm, /* source file name */
- char *tnm) /* target file name */
+ char *tnm, /* target file name */
+ caller_context_t *ctp)
{
struct pcnode *pcp; /* pcnode we are trying to rename */
struct pcnode *tpcp; /* pcnode that's in our way */
@@ -633,7 +635,7 @@ top:
newisdir = tpcp->pc_entry.pcd_attr & PCA_DIR;
brelse(slot.sl_bp);
- vnevent_rename_dest(PCTOV(tpcp), PCTOV(tdp), tnm);
+ vnevent_rename_dest(PCTOV(tpcp), PCTOV(tdp), tnm, ctp);
VN_RELE(PCTOV(tpcp));
/*
@@ -648,7 +650,7 @@ top:
} else {
/* nondir/nondir, remove target */
error = pc_dirremove(tdp, tnm,
- (struct vnode *)NULL, VREG);
+ (struct vnode *)NULL, VREG, ctp);
if (error == 0) {
VN_RELE(PCTOV(pcp));
goto top;
@@ -657,7 +659,7 @@ top:
} else if (oldisdir) {
/* dir/dir, remove target */
error = pc_dirremove(tdp, tnm,
- (struct vnode *)NULL, VDIR);
+ (struct vnode *)NULL, VDIR, ctp);
if (error == 0) {
VN_RELE(PCTOV(pcp));
goto top;
@@ -815,9 +817,9 @@ top:
}
}
out:
- vnevent_rename_src(PCTOV(pcp), PCTOV(dp), snm);
+ vnevent_rename_src(PCTOV(pcp), PCTOV(dp), snm, ctp);
if (dp != tdp) {
- vnevent_rename_dest_dir(PCTOV(tdp));
+ vnevent_rename_dest_dir(PCTOV(tdp), ctp);
}
VN_RELE(PCTOV(pcp));
diff --git a/usr/src/uts/common/fs/pcfs/pc_node.c b/usr/src/uts/common/fs/pcfs/pc_node.c
index 6dbc28dbba..33d6fd2659 100644
--- a/usr/src/uts/common/fs/pcfs/pc_node.c
+++ b/usr/src/uts/common/fs/pcfs/pc_node.c
@@ -207,7 +207,8 @@ syncpcp(struct pcnode *pcp, int flags)
if (!vn_has_cached_data(PCTOV(pcp)))
err = 0;
else
- err = VOP_PUTPAGE(PCTOV(pcp), 0, 0, flags, kcred);
+ err = VOP_PUTPAGE(PCTOV(pcp), 0, 0, flags,
+ kcred, NULL);
return (err);
}
diff --git a/usr/src/uts/common/fs/pcfs/pc_vfsops.c b/usr/src/uts/common/fs/pcfs/pc_vfsops.c
index 378fb15954..3697041c88 100644
--- a/usr/src/uts/common/fs/pcfs/pc_vfsops.c
+++ b/usr/src/uts/common/fs/pcfs/pc_vfsops.c
@@ -415,7 +415,7 @@ devlookup_done:
error = ENXIO;
if ((error != 0) ||
- (error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 ||
+ (error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
(error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
VN_RELE(bvp);
return (error);
@@ -695,7 +695,7 @@ pcfs_mount(
return (EBUSY);
}
error = VOP_OPEN(&devvp,
- (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, cr);
+ (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, cr, NULL);
if (error) {
VN_RELE(devvp);
return (error);
@@ -770,7 +770,7 @@ pcfs_mount(
errout:
(void) VOP_CLOSE(devvp,
vfsp->vfs_flag & VFS_RDONLY ? FREAD : FREAD | FWRITE,
- 1, (offset_t)0, cr);
+ 1, (offset_t)0, cr, NULL);
VN_RELE(devvp);
mutex_destroy(&fsp->pcfs_lock);
kmem_free(fsp, sizeof (*fsp));
@@ -1100,7 +1100,7 @@ pc_invalfat(struct pcfs *fsp)
*/
(void) VOP_CLOSE(fsp->pcfs_devvp,
(PCFSTOVFS(fsp)->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE,
- 1, (offset_t)0, CRED());
+ 1, (offset_t)0, CRED(), NULL);
}
void
diff --git a/usr/src/uts/common/fs/pcfs/pc_vnops.c b/usr/src/uts/common/fs/pcfs/pc_vnops.c
index 0becbc9b3c..9f77542636 100644
--- a/usr/src/uts/common/fs/pcfs/pc_vnops.c
+++ b/usr/src/uts/common/fs/pcfs/pc_vnops.c
@@ -69,45 +69,57 @@
#include <fs/fs_subr.h>
-static int pcfs_open(struct vnode **, int, struct cred *);
-static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *);
+static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct);
+static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *,
+ caller_context_t *ct);
static int pcfs_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int pcfs_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
-static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *);
+ caller_context_t *);
+static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *,
+ caller_context_t *ct);
static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *,
caller_context_t *);
-static int pcfs_access(struct vnode *, int, int, struct cred *);
+static int pcfs_access(struct vnode *, int, int, struct cred *,
+ caller_context_t *ct);
static int pcfs_lookup(struct vnode *, char *, struct vnode **,
- struct pathname *, int, struct vnode *, struct cred *);
+ struct pathname *, int, struct vnode *, struct cred *,
+ caller_context_t *, int *, pathname_t *);
static int pcfs_create(struct vnode *, char *, struct vattr *,
- enum vcexcl, int mode, struct vnode **, struct cred *, int);
-static int pcfs_remove(struct vnode *, char *, struct cred *);
+ enum vcexcl, int mode, struct vnode **, struct cred *, int,
+ caller_context_t *, vsecattr_t *);
+static int pcfs_remove(struct vnode *, char *, struct cred *,
+ caller_context_t *, int);
static int pcfs_rename(struct vnode *, char *, struct vnode *, char *,
- struct cred *);
+ struct cred *, caller_context_t *, int);
static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **,
- struct cred *);
-static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *);
-static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *);
-static int pcfs_fsync(struct vnode *, int, struct cred *);
-static void pcfs_inactive(struct vnode *, struct cred *);
-static int pcfs_fid(struct vnode *vp, struct fid *fidp);
+ struct cred *, caller_context_t *, int, vsecattr_t *);
+static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *,
+ caller_context_t *, int);
+static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *,
+ caller_context_t *, int);
+static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *);
+static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *);
+static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *);
static int pcfs_space(struct vnode *, int, struct flock64 *, int,
offset_t, cred_t *, caller_context_t *);
static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[],
- size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
+ size_t, struct seg *, caddr_t, enum seg_rw, struct cred *,
+ caller_context_t *);
static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
-static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *);
+static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
+ caller_context_t *);
static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, struct cred *);
+ size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t,
- size_t, uint_t, uint_t, uint_t, struct cred *);
-static int pcfs_seek(struct vnode *, offset_t, offset_t *);
-static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *);
+ size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
+static int pcfs_seek(struct vnode *, offset_t, offset_t *,
+ caller_context_t *);
+static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *,
+ caller_context_t *);
int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int,
struct cred *);
@@ -175,7 +187,8 @@ static int
pcfs_open(
struct vnode **vpp,
int flag,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -191,7 +204,8 @@ pcfs_close(
int flag,
int count,
offset_t offset,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -537,7 +551,8 @@ pcfs_getattr(
struct vnode *vp,
struct vattr *vap,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcnode *pcp;
struct pcfs *fsp;
@@ -556,7 +571,7 @@ pcfs_getattr(
/*
* Note that we don't check for "invalid node" (PC_INVAL) here
* only in order to make stat() succeed. We allow no I/O on such
- * a node, but do allow to check for its existance.
+ * a node, but do allow to check for its existence.
*/
if ((pcp = VTOPC(vp)) == NULL) {
pc_unlockfs(fsp);
@@ -816,7 +831,8 @@ pcfs_access(
struct vnode *vp,
int mode,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcnode *pcp;
struct pcfs *fsp;
@@ -847,7 +863,8 @@ static int
pcfs_fsync(
struct vnode *vp,
int syncflag,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -875,7 +892,8 @@ pcfs_fsync(
static void
pcfs_inactive(
struct vnode *vp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcnode *pcp;
struct pcfs *fsp;
@@ -946,7 +964,10 @@ pcfs_lookup(
struct pathname *pnp,
int flags,
struct vnode *rdir,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -1001,7 +1022,9 @@ pcfs_create(
int mode,
struct vnode **vpp,
struct cred *cr,
- int flag)
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
struct pcnode *pcp;
@@ -1055,7 +1078,7 @@ pcfs_create(
error = EISDIR;
} else if (mode) {
error = pcfs_access(PCTOV(pcp), mode, 0,
- cr);
+ cr, ct);
} else {
error = 0;
}
@@ -1068,7 +1091,7 @@ pcfs_create(
if (error) {
VN_RELE(PCTOV(pcp));
} else {
- vnevent_create(PCTOV(pcp));
+ vnevent_create(PCTOV(pcp), ct);
}
}
}
@@ -1087,7 +1110,9 @@ static int
pcfs_remove(
struct vnode *vp,
char *nm,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -1109,7 +1134,7 @@ pcfs_remove(
return (EACCES);
}
}
- error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG);
+ error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct);
pc_unlockfs(fsp);
return (error);
}
@@ -1126,7 +1151,9 @@ pcfs_rename(
char *snm, /* old (source) entry name */
struct vnode *tdvp, /* new (target) parent vnode */
char *tnm, /* new (target) entry name */
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
struct pcfs *fsp;
struct pcnode *dp; /* parent pcnode */
@@ -1140,7 +1167,7 @@ pcfs_rename(
/*
* make sure we can muck with this directory.
*/
- error = pcfs_access(sdvp, VWRITE, 0, cr);
+ error = pcfs_access(sdvp, VWRITE, 0, cr, ct);
if (error) {
return (error);
}
@@ -1152,7 +1179,7 @@ pcfs_rename(
pc_unlockfs(fsp);
return (EIO);
}
- error = pc_rename(dp, tdp, snm, tnm);
+ error = pc_rename(dp, tdp, snm, tnm, ct);
pc_unlockfs(fsp);
return (error);
}
@@ -1164,7 +1191,10 @@ pcfs_mkdir(
char *nm,
struct vattr *vap,
struct vnode **vpp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -1206,7 +1236,9 @@ pcfs_rmdir(
struct vnode *dvp,
char *nm,
struct vnode *cdir,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -1230,7 +1262,7 @@ pcfs_rmdir(
}
}
- error = pc_dirremove(pcp, nm, cdir, VDIR);
+ error = pc_dirremove(pcp, nm, cdir, VDIR, ct);
pc_unlockfs(fsp);
return (error);
}
@@ -1246,7 +1278,9 @@ pcfs_readdir(
struct vnode *dvp,
struct uio *uiop,
struct cred *cr,
- int *eofp)
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct pcnode *pcp;
struct pcfs *fsp;
@@ -1517,6 +1551,7 @@ out:
/*
* Return all the pages from [off..off+len] in given file
*/
+/* ARGSUSED */
static int
pcfs_getpage(
struct vnode *vp,
@@ -1528,7 +1563,8 @@ pcfs_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
int err;
@@ -1574,7 +1610,8 @@ pcfs_putpage(
offset_t off,
size_t len,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcnode *pcp;
page_t *pp;
@@ -1814,7 +1851,8 @@ pcfs_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error;
@@ -1861,7 +1899,8 @@ static int
pcfs_seek(
struct vnode *vp,
offset_t ooff,
- offset_t *noffp)
+ offset_t *noffp,
+ caller_context_t *ct)
{
if (*noffp < 0)
return (EINVAL);
@@ -1882,7 +1921,8 @@ pcfs_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
if (vp->v_flag & VNOMAP)
return (ENOSYS);
@@ -1900,7 +1940,8 @@ pcfs_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
if (vp->v_flag & VNOMAP)
return (ENOSYS);
@@ -1916,7 +1957,8 @@ pcfs_pathconf(
struct vnode *vp,
int cmd,
ulong_t *valp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
ulong_t val;
int error = 0;
@@ -2018,7 +2060,7 @@ pcfs_space(
return (EINVAL);
vattr.va_mask = AT_SIZE;
vattr.va_size = bfp->l_start;
- error = VOP_SETATTR(vp, &vattr, 0, cr, ct);
+ error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct);
}
return (error);
}
@@ -2373,8 +2415,9 @@ pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
return (0);
}
+/* ARGSUSED */
static int
-pcfs_fid(struct vnode *vp, struct fid *fidp)
+pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct pc_fid *pcfid;
struct pcnode *pcp;
diff --git a/usr/src/uts/common/fs/portfs/port_fd.c b/usr/src/uts/common/fs/portfs/port_fd.c
index dd26b0af9c..c1f868ad11 100644
--- a/usr/src/uts/common/fs/portfs/port_fd.c
+++ b/usr/src/uts/common/fs/portfs/port_fd.c
@@ -171,7 +171,7 @@ port_cache_lookup_fp(port_fdcache_t *pcp, int fd, file_t *fp)
* will be submitted to the event port with port_send_event().
* Otherwise VOP_POLL does not return events but it delivers a pointer to a
* pollhead_t structure. In such a case the corresponding file system behind
- * VOP_POLL will use the pollwakeup() function to notify about exisiting
+ * VOP_POLL will use the pollwakeup() function to notify about existing
* events.
*/
int
@@ -314,7 +314,7 @@ port_associate_fd(port_t *pp, int source, uintptr_t object, int events,
* poll routine to change.
*/
curthread->t_pollcache = (pollcache_t *)pcp;
- error = VOP_POLL(fp->f_vnode, events, 0, &revents, &php);
+ error = VOP_POLL(fp->f_vnode, events, 0, &revents, &php, NULL);
curthread->t_pollcache = NULL;
/*
@@ -512,7 +512,7 @@ port_bind_pollhead(pollhead_t **php, polldat_t *pdp, short *revents)
pdp->pd_php = *php;
fp = pdp->pd_fp;
curthread->t_pollcache = (pollcache_t *)pdp->pd_pcache;
- error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0, revents, php);
+ error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0, revents, php, NULL);
curthread->t_pollcache = NULL;
return (error);
}
diff --git a/usr/src/uts/common/fs/portfs/port_fop.c b/usr/src/uts/common/fs/portfs/port_fop.c
index 8e07046236..d3530280d2 100644
--- a/usr/src/uts/common/fs/portfs/port_fop.c
+++ b/usr/src/uts/common/fs/portfs/port_fop.c
@@ -57,7 +57,7 @@
* The time stamps collected by a stat(2) call are passed in fo_atime,
* fo_mtime, fo_ctime. At the time a file events watch is registered, the
* time stamps passed in are compared with the current time stamps of the
- * file. If it has changed, relavant events are sent immediately. If the time
+ * file. If it has changed, relevant events are sent immediately. If the time
* stamps are all '0', they will not be compared.
*
*
@@ -206,33 +206,40 @@ static void port_close_fop(void *arg, int port, pid_t pid, int lastclose);
/*
* port fop functions that will be the fem hooks.
*/
-static int port_fop_open(femarg_t *vf, int mode, cred_t *cr);
+static int port_fop_open(femarg_t *vf, int mode, cred_t *cr,
+ caller_context_t *);
static int port_fop_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct);
+ struct caller_context *ct);
static int port_fop_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- caller_context_t *ct);
+ caller_context_t *ct);
static int port_fop_map(femarg_t *vf, offset_t off, struct as *as,
- caddr_t *addrp, size_t len, uchar_t prot, uchar_t maxport,
- uint_t flags, cred_t *cr);
+ caddr_t *addrp, size_t len, uchar_t prot, uchar_t maxport,
+ uint_t flags, cred_t *cr, caller_context_t *ct);
static int port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
- caller_context_t *ct);
+ caller_context_t *ct);
static int port_fop_create(femarg_t *vf, char *name, vattr_t *vap,
- vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cr,
- int flag);
-static int port_fop_remove(femarg_t *vf, char *nm, cred_t *cr);
-static int port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr);
+ vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp);
+static int port_fop_remove(femarg_t *vf, char *nm, cred_t *cr,
+ caller_context_t *ct, int flags);
+static int port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags);
static int port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct, int flags);
static int port_fop_mkdir(femarg_t *vf, char *dirname, vattr_t *vap,
- vnode_t **vpp, cred_t *cr);
-static int port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr);
-static int port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp);
+ vnode_t **vpp, cred_t *cr, caller_context_t *ct, int flags,
+ vsecattr_t *vsecp);
+static int port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags);
+static int port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags);
static int port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap,
- char *target, cred_t *cr);
+ char *target, cred_t *cr, caller_context_t *ct, int flags);
static int port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
+
static int port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp,
- char *cname);
+ char *cname, caller_context_t *ct);
static int port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr);
@@ -812,7 +819,7 @@ port_check_timestamp(vnode_t *vp, portfop_t *pfp, void *objptr)
if (fobj->fo_atime.tv_sec || fobj->fo_atime.tv_nsec ||
fobj->fo_mtime.tv_sec || fobj->fo_mtime.tv_nsec ||
fobj->fo_ctime.tv_sec || fobj->fo_ctime.tv_nsec) {
- if (VOP_GETATTR(vp, &vatt, 0, CRED())) {
+ if (VOP_GETATTR(vp, &vatt, 0, CRED(), NULL)) {
return;
}
} else {
@@ -828,7 +835,7 @@ port_check_timestamp(vnode_t *vp, portfop_t *pfp, void *objptr)
if (fobj32->fo_atime.tv_sec || fobj32->fo_atime.tv_nsec ||
fobj32->fo_mtime.tv_sec || fobj32->fo_mtime.tv_nsec ||
fobj32->fo_ctime.tv_sec || fobj32->fo_ctime.tv_nsec) {
- if (VOP_GETATTR(vp, &vatt, 0, CRED())) {
+ if (VOP_GETATTR(vp, &vatt, 0, CRED(), NULL)) {
return;
}
} else {
@@ -1182,7 +1189,7 @@ port_resolve_vp(vnode_t *vp)
* This should take care of lofs mounted fs systems and nfs4
* hardlinks.
*/
- if ((VOP_REALVP(vp, &rvp) == 0) && vp != rvp) {
+ if ((VOP_REALVP(vp, &rvp, NULL) == 0) && vp != rvp) {
VN_HOLD(rvp);
VN_RELE(vp);
vp = rvp;
@@ -1263,7 +1270,7 @@ port_associate_fop(port_t *pp, int source, uintptr_t object, int events,
vp = port_resolve_vp(vp);
- if (vp != NULL && vnevent_support(vp)) {
+ if (vp != NULL && vnevent_support(vp, NULL)) {
error = ENOTSUP;
goto errout;
}
@@ -1547,7 +1554,7 @@ port_close_fop(void *arg, int port, pid_t pid, int lastclose)
/*
* Given the list of associations(watches), it will send exception events,
* if still active, and discard them. The exception events are handled
- * seperately because, the pfp needs to be removed from the port cache and
+ * separately because, the pfp needs to be removed from the port cache and
* freed as the vnode's identity is changing or being removed. To remove
* the pfp from the port's cache, we need to hold the cache lock (pfc_lock).
* The lock order is pfc_lock -> pvp_mutex(vnode's) mutex and that is why
@@ -1809,7 +1816,7 @@ port_fop(vnode_t *vp, int op, int retval)
return;
/*
- * These events occuring on the watched file.
+ * These events occurring on the watched file.
*/
if (op & FOP_MODIFIED_MASK) {
event = FILE_MODIFIED;
@@ -1907,12 +1914,12 @@ port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr)
* The O_TRUNC operation is caught with the VOP_SETATTR(AT_SIZE) call.
*/
static int
-port_fop_open(femarg_t *vf, int mode, cred_t *cr)
+port_fop_open(femarg_t *vf, int mode, cred_t *cr, caller_context_t *ct)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_open(vf, mode, cr);
+ retval = vnext_open(vf, mode, cr, ct);
port_fop(vp, FOP_FILE_OPEN, retval);
return (retval);
}
@@ -1931,12 +1938,14 @@ port_fop_write(femarg_t *vf, struct uio *uiop, int ioflag, struct cred *cr,
static int
port_fop_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxport, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxport, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_map(vf, off, as, addrp, len, prot, maxport, flags, cr);
+ retval = vnext_map(vf, off, as, addrp, len, prot, maxport,
+ flags, cr, ct);
port_fop(vp, FOP_FILE_MAP, retval);
return (retval);
}
@@ -1980,7 +1989,8 @@ port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
int
port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int retval, got = 1;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
@@ -1993,13 +2003,14 @@ port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
* file was actually created.
*/
vatt.va_mask = AT_ATIME|AT_MTIME|AT_CTIME;
- if (VOP_GETATTR(vp, &vatt, 0, CRED())) {
+ if (VOP_GETATTR(vp, &vatt, 0, CRED(), ct)) {
got = 0;
}
- retval = vnext_create(vf, name, vap, excl, mode, vpp, cr, flag);
+ retval = vnext_create(vf, name, vap, excl, mode, vpp, cr,
+ flag, ct, vsecp);
vatt1.va_mask = AT_ATIME|AT_MTIME|AT_CTIME;
- if (got && !VOP_GETATTR(vp, &vatt1, 0, CRED())) {
+ if (got && !VOP_GETATTR(vp, &vatt1, 0, CRED(), ct)) {
if ((vatt1.va_mtime.tv_sec > vatt.va_mtime.tv_sec ||
(vatt1.va_mtime.tv_sec = vatt.va_mtime.tv_sec &&
vatt1.va_mtime.tv_nsec > vatt.va_mtime.tv_nsec))) {
@@ -2013,23 +2024,25 @@ port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
}
int
-port_fop_remove(femarg_t *vf, char *nm, cred_t *cr)
+port_fop_remove(femarg_t *vf, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_remove(vf, nm, cr);
+ retval = vnext_remove(vf, nm, cr, ct, flags);
port_fop(vp, FOP_FILE_REMOVE, retval);
return (retval);
}
int
-port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr)
+port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_link(vf, svp, tnm, cr);
+ retval = vnext_link(vf, svp, tnm, cr, ct, flags);
port_fop(vp, FOP_FILE_LINK, retval);
return (retval);
}
@@ -2041,58 +2054,61 @@ port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr)
* if the source dir != target dir.
*/
int
-port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
+port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_rename(vf, snm, tdvp, tnm, cr);
+ retval = vnext_rename(vf, snm, tdvp, tnm, cr, ct, flags);
port_fop(vp, FOP_FILE_RENAMESRC, retval);
return (retval);
}
int
port_fop_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_mkdir(vf, dirname, vap, vpp, cr);
+ retval = vnext_mkdir(vf, dirname, vap, vpp, cr, ct, flags, vsecp);
port_fop(vp, FOP_FILE_MKDIR, retval);
return (retval);
}
int
-port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr)
+port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_rmdir(vf, nm, cdir, cr);
+ retval = vnext_rmdir(vf, nm, cdir, cr, ct, flags);
port_fop(vp, FOP_FILE_RMDIR, retval);
return (retval);
}
int
-port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp)
+port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_readdir(vf, uiop, cr, eofp);
+ retval = vnext_readdir(vf, uiop, cr, eofp, ct, flags);
port_fop(vp, FOP_FILE_READDIR, retval);
return (retval);
}
int
port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_symlink(vf, linkname, vap, target, cr);
+ retval = vnext_symlink(vf, linkname, vap, target, cr, ct, flags);
port_fop(vp, FOP_FILE_SYMLINK, retval);
return (retval);
}
@@ -2101,11 +2117,12 @@ port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
* acl, facl call this.
*/
int
-port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flags, cred_t *cr)
+port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_setsecattr(vf, vsap, flags, cr);
+ retval = vnext_setsecattr(vf, vsap, flags, cr, ct);
port_fop(vp, FOP_FILE_SETSECATTR, retval);
return (retval);
}
@@ -2114,11 +2131,11 @@ port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flags, cred_t *cr)
* these are events on the watched file/directory
*/
int
-port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name)
+port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name,
+ caller_context_t *ct)
{
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
-
switch (vnevent) {
case VE_RENAME_SRC:
port_fop_sendevent(vp, FILE_RENAME_FROM, dvp, name);
@@ -2151,5 +2168,5 @@ port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name)
default:
break;
}
- return (vnext_vnevent(vf, vnevent, dvp, name));
+ return (vnext_vnevent(vf, vnevent, dvp, name, ct));
}
diff --git a/usr/src/uts/common/fs/portfs/port_vnops.c b/usr/src/uts/common/fs/portfs/port_vnops.c
index aa8bc952d2..00c1044dfa 100644
--- a/usr/src/uts/common/fs/portfs/port_vnops.c
+++ b/usr/src/uts/common/fs/portfs/port_vnops.c
@@ -36,13 +36,16 @@
#include <sys/port_impl.h>
/* local functions */
-static int port_open(struct vnode **, int, cred_t *);
-static int port_close(struct vnode *, int, int, offset_t, cred_t *);
-static int port_getattr(struct vnode *, struct vattr *, int, cred_t *);
-static int port_access(struct vnode *, int, int, cred_t *);
-static int port_realvp(vnode_t *, vnode_t **);
-static int port_poll(vnode_t *, short, int, short *, struct pollhead **);
-static void port_inactive(struct vnode *, cred_t *);
+static int port_open(struct vnode **, int, cred_t *, caller_context_t *);
+static int port_close(struct vnode *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+static int port_getattr(struct vnode *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+static int port_access(struct vnode *, int, int, cred_t *, caller_context_t *);
+static int port_realvp(vnode_t *, vnode_t **, caller_context_t *);
+static int port_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+static void port_inactive(struct vnode *, cred_t *, caller_context_t *);
const fs_operation_def_t port_vnodeops_template[] = {
VOPNAME_OPEN, { .vop_open = port_open },
@@ -62,7 +65,7 @@ const fs_operation_def_t port_vnodeops_template[] = {
/* ARGSUSED */
static int
-port_open(struct vnode **vpp, int flag, cred_t *cr)
+port_open(struct vnode **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
return (0);
}
@@ -146,7 +149,8 @@ port_close_events(port_queue_t *portq)
*/
/* ARGSUSED */
static int
-port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr)
+port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
port_t *pp;
port_queue_t *portq;
@@ -276,7 +280,7 @@ port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr)
/*ARGSUSED*/
static int
port_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
port_t *pp;
port_queue_t *portq;
@@ -308,7 +312,8 @@ port_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
/* ARGSUSED */
static int
-port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr)
+port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
port_t *pp;
extern dev_t portdev;
@@ -340,7 +345,7 @@ port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static void
-port_inactive(struct vnode *vp, cred_t *cr)
+port_inactive(struct vnode *vp, cred_t *cr, caller_context_t *ct)
{
port_t *pp = VTOEP(vp);
extern port_kstat_t port_kstat;
@@ -359,14 +364,15 @@ port_inactive(struct vnode *vp, cred_t *cr)
/* ARGSUSED */
static int
-port_access(struct vnode *vp, int mode, int flags, cred_t *cr)
+port_access(struct vnode *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static int
-port_realvp(vnode_t *vp, vnode_t **vpp)
+port_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
*vpp = vp;
return (0);
diff --git a/usr/src/uts/common/fs/proc/prcontrol.c b/usr/src/uts/common/fs/proc/prcontrol.c
index 9bbf929b5f..f4b20a4045 100644
--- a/usr/src/uts/common/fs/proc/prcontrol.c
+++ b/usr/src/uts/common/fs/proc/prcontrol.c
@@ -1460,7 +1460,7 @@ pr_setsig(prnode_t *pnp, siginfo_t *sip)
}
thread_lock(t);
if (ISWAKEABLE(t) || ISWAITING(t)) {
- /* Set signalled sleeping/waiting lwp running */
+ /* Set signaled sleeping/waiting lwp running */
setrun_locked(t);
} else if (t->t_state == TS_STOPPED && sig == SIGKILL) {
/* If SIGKILL, set stopped lwp running */
diff --git a/usr/src/uts/common/fs/proc/prioctl.c b/usr/src/uts/common/fs/proc/prioctl.c
index 1eb2861b0f..45fddda6f6 100644
--- a/usr/src/uts/common/fs/proc/prioctl.c
+++ b/usr/src/uts/common/fs/proc/prioctl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -127,14 +127,27 @@ prctioctl(prnode_t *pnp, int cmd, intptr_t arg, int flag, cred_t *cr)
/*
* Control operations (lots).
*/
+/*ARGSUSED*/
#ifdef _SYSCALL32_IMPL
static int
-prioctl64(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+prioctl64(
+ struct vnode *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
#else
int
-prioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+prioctl(
+ struct vnode *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
#endif /* _SYSCALL32_IMPL */
{
caddr_t cmaddr = (caddr_t)arg;
@@ -1657,9 +1670,16 @@ oprgetpsinfo32(proc_t *p, prpsinfo32_t *psp, kthread_t *tp)
}
}
+/*ARGSUSED*/
static int
-prioctl32(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+prioctl32(
+ struct vnode *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
caddr_t cmaddr = (caddr_t)arg;
proc_t *p;
@@ -3126,7 +3146,7 @@ propenm(prnode_t *pnp, caddr_t cmaddr, caddr_t va, int *rvalp, cred_t *cr)
prunlock(pnp);
if (error == 0) {
- if ((error = VOP_ACCESS(xvp, VREAD, 0, cr)) == 0)
+ if ((error = VOP_ACCESS(xvp, VREAD, 0, cr, NULL)) == 0)
error = fassign(&xvp, FREAD, &n);
if (error) {
VN_RELE(xvp);
@@ -3876,16 +3896,23 @@ again:
}
#endif /* _SYSCALL32_IMPL */
+/*ARGSUSED*/
#ifdef _SYSCALL32_IMPL
int
-prioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+prioctl(
+ struct vnode *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
switch (curproc->p_model) {
case DATAMODEL_ILP32:
- return (prioctl32(vp, cmd, arg, flag, cr, rvalp));
+ return (prioctl32(vp, cmd, arg, flag, cr, rvalp, ct));
case DATAMODEL_LP64:
- return (prioctl64(vp, cmd, arg, flag, cr, rvalp));
+ return (prioctl64(vp, cmd, arg, flag, cr, rvalp, ct));
default:
return (ENOSYS);
}
diff --git a/usr/src/uts/common/fs/proc/prsubr.c b/usr/src/uts/common/fs/proc/prsubr.c
index 60e541bb03..e716d3b0e3 100644
--- a/usr/src/uts/common/fs/proc/prsubr.c
+++ b/usr/src/uts/common/fs/proc/prsubr.c
@@ -1681,7 +1681,7 @@ prgetmap(proc_t *p, int reserved, list_t *iolhead)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
if (vp == p->p_exec)
(void) strcpy(mp->pr_mapname, "a.out");
else
@@ -1793,7 +1793,7 @@ prgetmap32(proc_t *p, int reserved, list_t *iolhead)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
if (vp == p->p_exec)
(void) strcpy(mp->pr_mapname, "a.out");
else
@@ -1996,7 +1996,7 @@ again:
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
if (vp == p->p_exec)
(void) strcpy(pmp->pr_mapname, "a.out");
else
@@ -2143,7 +2143,7 @@ again:
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
if (vp == p->p_exec)
(void) strcpy(pmp->pr_mapname, "a.out");
else
@@ -3678,7 +3678,7 @@ pr_getsegsize(struct seg *seg, int reserved)
if (SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
u_offset_t fsize = vattr.va_size;
u_offset_t offset = SEGOP_GETOFFSET(seg, seg->s_base);
@@ -3981,7 +3981,8 @@ prgetxmap(proc_t *p, list_t *iolhead)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(),
+ NULL) == 0) {
mp->pr_dev = vattr.va_fsid;
mp->pr_ino = vattr.va_nodeid;
if (vp == p->p_exec)
@@ -4164,7 +4165,8 @@ prgetxmap32(proc_t *p, list_t *iolhead)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(),
+ NULL) == 0) {
(void) cmpldev(&mp->pr_dev,
vattr.va_fsid);
mp->pr_ino = vattr.va_nodeid;
diff --git a/usr/src/uts/common/fs/proc/prvnops.c b/usr/src/uts/common/fs/proc/prvnops.c
index a8be6c151d..4b61f1cdcc 100644
--- a/usr/src/uts/common/fs/proc/prvnops.c
+++ b/usr/src/uts/common/fs/proc/prvnops.c
@@ -216,10 +216,10 @@ static prdirent_t lwpiddir[] = {
static void rebuild_objdir(struct as *);
static void prfreecommon(prcommon_t *);
-static int praccess(vnode_t *, int, int, cred_t *);
+static int praccess(vnode_t *, int, int, cred_t *, caller_context_t *);
static int
-propen(vnode_t **vpp, int flag, cred_t *cr)
+propen(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *vp = *vpp;
prnode_t *pnp = VTOP(vp);
@@ -259,7 +259,7 @@ propen(vnode_t **vpp, int flag, cred_t *cr)
* Need to hold rvp since VOP_OPEN() may release it.
*/
VN_HOLD(rvp);
- error = VOP_OPEN(&rvp, flag, cr);
+ error = VOP_OPEN(&rvp, flag, cr, ct);
if (error) {
VN_RELE(rvp);
} else {
@@ -403,7 +403,8 @@ out:
/* ARGSUSED */
static int
-prclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+prclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prcommon_t *pcp = pnp->pr_pcommon;
@@ -2692,7 +2693,8 @@ prwrite(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
}
static int
-prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prnodetype_t type = pnp->pr_type;
@@ -2742,13 +2744,13 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
if (!(flags & ATTR_REAL))
break;
/* restrict full knowledge of the attributes to owner or root */
- if ((error = praccess(vp, 0, 0, cr)) != 0)
+ if ((error = praccess(vp, 0, 0, cr, ct)) != 0)
return (error);
/* FALLTHROUGH */
case PR_OBJECT:
case PR_FD:
rvp = pnp->pr_realvp;
- error = VOP_GETATTR(rvp, vap, flags, cr);
+ error = VOP_GETATTR(rvp, vap, flags, cr, ct);
if (error)
return (error);
if (type == PR_FD) {
@@ -3093,7 +3095,7 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
}
static int
-praccess(vnode_t *vp, int mode, int flags, cred_t *cr)
+praccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prnodetype_t type = pnp->pr_type;
@@ -3126,7 +3128,7 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr)
(type == PR_FD && (vmode & mode) != mode &&
secpolicy_proc_access(cr) != 0))
return (EACCES);
- return (VOP_ACCESS(rvp, mode, flags, cr));
+ return (VOP_ACCESS(rvp, mode, flags, cr, ct));
case PR_PSINFO: /* these files can be read by anyone */
case PR_LPSINFO:
@@ -3166,7 +3168,7 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
VN_HOLD(xvp);
prunlock(pnp);
- error = VOP_ACCESS(xvp, VREAD, 0, cr);
+ error = VOP_ACCESS(xvp, VREAD, 0, cr, ct);
VN_RELE(xvp);
}
if (error)
@@ -3178,7 +3180,7 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr)
/*
* Final access check on the underlying directory vnode.
*/
- return (VOP_ACCESS(pnp->pr_realvp, mode, flags, cr));
+ return (VOP_ACCESS(pnp->pr_realvp, mode, flags, cr, ct));
}
/*
@@ -3255,7 +3257,8 @@ static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
static int
prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
prnode_t *pnp = VTOP(dp);
prnodetype_t type = pnp->pr_type;
@@ -3281,20 +3284,22 @@ prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
case PR_CURDIR:
case PR_ROOTDIR:
/* restrict lookup permission to owner or root */
- if ((error = praccess(dp, VEXEC, 0, cr)) != 0)
+ if ((error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
return (error);
/* FALLTHROUGH */
case PR_FD:
dp = pnp->pr_realvp;
- return (VOP_LOOKUP(dp, comp, vpp, pathp, flags, rdir, cr));
+ return (VOP_LOOKUP(dp, comp, vpp, pathp, flags, rdir, cr, ct,
+ direntflags, realpnp));
default:
break;
}
if ((type == PR_OBJECTDIR || type == PR_FDDIR || type == PR_PATHDIR) &&
- (error = praccess(dp, VEXEC, 0, cr)) != 0)
+ (error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
return (error);
+ /* XXX - Do we need to pass ct, direntflags, or realpnp? */
*vpp = (pr_lookup_function[type](dp, comp));
return ((*vpp == NULL) ? ENOENT : 0);
@@ -3303,11 +3308,13 @@ prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
/* ARGSUSED */
static int
prcreate(vnode_t *dp, char *comp, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
- if ((error = prlookup(dp, comp, vpp, NULL, 0, NULL, cr)) != 0) {
+ if ((error = prlookup(dp, comp, vpp, NULL, 0, NULL, cr,
+ ct, NULL, NULL)) != 0) {
if (error == ENOENT) /* can't O_CREAT nonexistent files */
error = EACCES; /* unwriteable directories */
} else {
@@ -3326,7 +3333,7 @@ prcreate(vnode_t *dp, char *comp, vattr_t *vap, vcexcl_t excl,
vp = VTOP(vp)->pr_realvp;
mask = vap->va_mask;
vap->va_mask = AT_SIZE;
- error = VOP_SETATTR(vp, vap, 0, cr, NULL);
+ error = VOP_SETATTR(vp, vap, 0, cr, ct);
vap->va_mask = mask;
}
}
@@ -3615,7 +3622,7 @@ pr_lookup_objectdir(vnode_t *dp, char *comp)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
char name[64];
if (vp == p->p_exec) /* "a.out" */
@@ -4067,8 +4074,8 @@ pr_lookup_pathdir(vnode_t *dp, char *comp)
SEGOP_GETVP(seg, seg->s_base, &vp)
== 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED())
- == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(),
+ NULL) == 0) {
char name[64];
if (vp == p->p_exec)
@@ -4513,7 +4520,7 @@ prfreenode(prnode_t *pnp)
}
/*
- * Free a prcommon structure, if the refrence count reaches zero.
+ * Free a prcommon structure, if the reference count reaches zero.
*/
static void
prfreecommon(prcommon_t *pcp)
@@ -4596,12 +4603,14 @@ static int (*pr_readdir_function[PR_NFILES])() = {
/* ARGSUSED */
static int
-prreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+prreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
prnode_t *pnp = VTOP(vp);
ASSERT(pnp->pr_type < PR_NFILES);
+ /* XXX - Do we need to pass ct and flags? */
return (pr_readdir_function[pnp->pr_type](pnp, uiop, eofp));
}
@@ -4764,7 +4773,7 @@ rebuild_objdir(struct as *as)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
for (i = 0; i < nentries; i++)
if (vp == dir[i])
break;
@@ -4920,7 +4929,8 @@ pr_readdir_objectdir(prnode_t *pnp, uio_t *uiop, int *eofp)
*/
vattr.va_mask = AT_FSID | AT_NODEID;
while (n < objdirsize && (((vp = obj_entry(as, n)) == NULL) ||
- (VOP_GETATTR(vp, &vattr, 0, CRED()) != 0))) {
+ (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)
+ != 0))) {
vattr.va_mask = AT_FSID | AT_NODEID;
n++;
}
@@ -5275,7 +5285,7 @@ pr_readdir_pathdir(prnode_t *pnp, uio_t *uiop, int *eofp)
if ((vp = obj_entry(as, obj)) == NULL)
continue;
vattr.va_mask = AT_FSID|AT_NODEID;
- if (VOP_GETATTR(vp, &vattr, 0, CRED()) != 0)
+ if (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) != 0)
continue;
if (vp == p->p_exec)
(void) strcpy(dirent->d_name, "a.out");
@@ -5429,7 +5439,7 @@ pr_readdir_ctdir(prnode_t *pnp, uio_t *uiop, int *eofp)
/* ARGSUSED */
static int
-prfsync(vnode_t *vp, int syncflag, cred_t *cr)
+prfsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
return (0);
}
@@ -5456,7 +5466,7 @@ pr_list_unlink(vnode_t *pvp, vnode_t **listp)
/* ARGSUSED */
static void
-prinactive(vnode_t *vp, cred_t *cr)
+prinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prnodetype_t type = pnp->pr_type;
@@ -5574,7 +5584,7 @@ prinactive(vnode_t *vp, cred_t *cr)
/* ARGSUSED */
static int
-prseek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+prseek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
return (0);
}
@@ -5706,7 +5716,7 @@ prreadlink_lookup(prnode_t *pnp, char *buf, size_t size, cred_t *cr)
/* ARGSUSED */
static int
-prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ctp)
{
prnode_t *pnp = VTOP(vp);
char *buf;
@@ -5754,8 +5764,9 @@ prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
return (ret);
}
+/*ARGSUSED2*/
static int
-prcmp(vnode_t *vp1, vnode_t *vp2)
+prcmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
prnode_t *pp1, *pp2;
@@ -5783,13 +5794,13 @@ prcmp(vnode_t *vp1, vnode_t *vp2)
}
static int
-prrealvp(vnode_t *vp, vnode_t **vpp)
+prrealvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
vnode_t *rvp;
if ((rvp = VTOP(vp)->pr_realvp) != NULL) {
vp = rvp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
}
@@ -5805,9 +5816,10 @@ prrealvp(vnode_t *vp, vnode_t **vpp)
* POLLERR /proc file descriptor is invalid
* POLLHUP process or lwp has terminated
*/
+/*ARGSUSED5*/
static int
prpoll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **phpp)
+ pollhead_t **phpp, caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prcommon_t *pcp = pnp->pr_common;
@@ -5922,7 +5934,8 @@ prpoll(vnode_t *vp, short events, int anyyet, short *reventsp,
}
/* in prioctl.c */
-extern int prioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
+extern int prioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
/*
* /proc vnode operations vector
diff --git a/usr/src/uts/common/fs/sharefs/sharefs_vnops.c b/usr/src/uts/common/fs/sharefs/sharefs_vnops.c
index 1818c4ee03..cbafc38150 100644
--- a/usr/src/uts/common/fs/sharefs/sharefs_vnops.c
+++ b/usr/src/uts/common/fs/sharefs/sharefs_vnops.c
@@ -158,7 +158,8 @@ error_fault:
/* ARGSUSED */
static int
-sharefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+sharefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
timestruc_t now;
shnode_t *sft = VTOSH(vp);
@@ -204,7 +205,8 @@ sharefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
static int
-sharefs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+sharefs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
if (mode & (VWRITE|VEXEC))
return (EROFS);
@@ -214,7 +216,7 @@ sharefs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
/* ARGSUSED */
int
-sharefs_open(vnode_t **vpp, int flag, cred_t *cr)
+sharefs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *vp;
vnode_t *ovp = *vpp;
@@ -267,7 +269,7 @@ sharefs_open(vnode_t **vpp, int flag, cred_t *cr)
/* ARGSUSED */
int
sharefs_close(vnode_t *vp, int flag, int count,
- offset_t off, cred_t *cr)
+ offset_t off, cred_t *cr, caller_context_t *ct)
{
shnode_t *sft = VTOSH(vp);
@@ -338,7 +340,7 @@ sharefs_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr,
/* ARGSUSED */
static void
-sharefs_inactive(vnode_t *vp, cred_t *cr)
+sharefs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *tx)
{
gfs_file_t *fp = vp->v_data;
shnode_t *sft;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_acl.c b/usr/src/uts/common/fs/smbsrv/smb_acl.c
new file mode 100644
index 0000000000..2617268d9e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_acl.c
@@ -0,0 +1,1310 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Platform SDK: Security
+ *
+ * ACE Inheritance Rules
+ *
+ * The system propagates inheritable ACEs to child objects according to a
+ * set of inheritance rules. The system places inherited ACEs in the child's
+ * DACL according to the preferred order of ACEs in a DACL. For Windows
+ * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
+ *
+ * The following table shows the ACEs inherited by container and noncontainer
+ * child objects for different combinations of inheritance flags. These
+ * inheritance rules work the same for both DACLs and SACLs.
+ *
+ * Parent ACE type Effect on Child ACL
+ * ----------------------- -------------------
+ * OBJECT_INHERIT_ACE only Noncontainer child objects:
+ * Inherited as an effective ACE.
+ * Container child objects:
+ * Containers inherit an inherit-only ACE
+ * unless the NO_PROPAGATE_INHERIT_ACE bit
+ * flag is also set.
+ *
+ * CONTAINER_INHERIT_ACE only Noncontainer child objects:
+ * No effect on the child object.
+ * Container child objects:
+ * The child object inherits an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ *
+ * CONTAINER_INHERIT_ACE and
+ * OBJECT_INHERIT_ACE Noncontainer child objects:
+ * Inherited as an effective ACE.
+ * Container child objects:
+ * The child object inherits an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * NO_PROPAGATE_INHERIT_ACE bit flag is also set
+ *
+ * No inheritance flags set No effect on child container or noncontainer
+ * objects.
+ *
+ * If an inherited ACE is an effective ACE for the child object, the system
+ * maps any generic rights to the specific rights for the child object.
+ * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
+ * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
+ * rights or generic SIDs are left unchanged so that they can be mapped
+ * appropriately when the ACE is inherited by the next generation of child
+ * objects.
+ *
+ * For a case in which a container object inherits an ACE that is both
+ * effective on the container and inheritable by its descendants, the
+ * container may inherit two ACEs. This occurs if the inheritable ACE
+ * contains generic information. The container inherits an inherit-only
+ * ACE containing the generic information and an effective-only ACE in
+ * which the generic information has been mapped.
+ */
+
+#include <sys/acl.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_idmap.h>
+
+#define ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE)
+
+#define ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER)
+#define ZACE_IS_OWNGRP(zace) \
+ ((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP))
+
+#define ZACE_IS_USER(zace) \
+ (((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace)))
+#define ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP)
+#define ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE)
+
+#define ZACE_IS_PROPAGATE(zace) \
+ ((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0)
+
+#define ZACE_IS_CREATOR_OWNER(zace) \
+ (ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID))
+
+#define ZACE_IS_CREATOR_GROUP(zace) \
+ (ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID))
+
+#define ZACE_IS_CREATOR(zace) \
+ (ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace))
+
+static int smb_ace_isvalid(smb_ace_hdr_t *ace, int which_acl);
+static int smb_ace_append_generic(smb_acl_t *acl, void *generic_ace);
+
+static int smb_ace_common_add(
+ smb_acl_t *acl,
+ uint8_t type,
+ uint8_t flags,
+ uint32_t access_mask,
+ nt_sid_t *sid);
+
+static void smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir);
+static uint16_t smb_ace_flags_tozfs(uint8_t c_flags, int isdir);
+static uint8_t smb_ace_flags_fromzfs(uint16_t z_flags);
+static void smb_acl_init(smb_acl_t *acl, uint16_t size, uint8_t rev);
+
+static int
+smb_ace_isvalid(smb_ace_hdr_t *ace, int which_acl)
+{
+ uint16_t min_len;
+ smb_ace_t *p;
+
+ min_len = sizeof (smb_ace_hdr_t);
+
+ if (ace->se_size < min_len)
+ return (0);
+
+ if (smb_ace_is_access(ace->se_type) &&
+ (which_acl != SMB_DACL_SECINFO)) {
+ return (0);
+ }
+
+ if (smb_ace_is_audit(ace->se_type) &&
+ (which_acl != SMB_SACL_SECINFO)) {
+ return (0);
+ }
+
+ if (smb_ace_is_generic(ace->se_type)) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ p = (smb_ace_t *)ace;
+
+ if (ace->se_size < sizeof (*p))
+ return (0); /* won't handle empty SubAuthority[] */
+
+ if (nt_sid_is_valid(&p->se_sid) == 0)
+ return (0);
+
+ min_len += sizeof (p->se_mask);
+ min_len += nt_sid_length(&p->se_sid);
+
+ if (ace->se_size < min_len)
+ return (0);
+ }
+
+ /*
+ * XXX object-specific ACE validation will be added later.
+ */
+ return (1);
+}
+
+int
+smb_acl_isvalid(smb_acl_t *acl, int which_acl)
+{
+ uint16_t min_len;
+ unsigned char *scan;
+ unsigned char *scan_end;
+ smb_ace_hdr_t *ace;
+ uint16_t count = 0;
+
+ min_len = sizeof (smb_acl_t);
+
+ if (acl->sl_size < min_len)
+ return (0);
+
+ if (acl->sl_revision != ACL_REVISION) {
+ /*
+ * XXX we are rejecting ACLs with object-specific ACEs for now
+ */
+ return (0);
+ }
+
+ scan = (unsigned char *) &acl[0];
+ scan_end = scan + acl->sl_size;
+ scan = (unsigned char *) &acl[1]; /* skip Acl header */
+
+ while (count < acl->sl_acecnt && scan < scan_end) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ace = (smb_ace_hdr_t *)scan;
+
+ if (scan + sizeof (smb_ace_hdr_t) >= scan_end)
+ return (0);
+
+ if (scan + ace->se_size > scan_end)
+ return (0); /* overflow */
+
+ if (!smb_ace_isvalid(ace, which_acl))
+ return (0);
+
+ scan += ace->se_size;
+ count++;
+ }
+
+ return (1);
+}
+
+
+static void
+smb_acl_init(smb_acl_t *acl, uint16_t size, uint8_t rev)
+{
+ bzero(acl, size);
+ acl->sl_revision = rev;
+ acl->sl_size = size;
+}
+
+uint16_t
+smb_acl_len(smb_acl_t *acl)
+{
+ smb_ace_hdr_t *ace;
+ unsigned char *scan_beg;
+ unsigned char *scan_end;
+ unsigned char *scan;
+ uint16_t length;
+ uint16_t count;
+
+ scan_beg = (unsigned char *) &acl[0];
+ scan_end = scan_beg + acl->sl_size;
+ scan = (unsigned char *) &acl[1];
+ length = sizeof (smb_acl_t);
+ count = 0;
+
+ while ((count < acl->sl_acecnt) && (scan < scan_end)) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ace = (smb_ace_hdr_t *)scan;
+ length += ace->se_size;
+ scan += ace->se_size;
+ count++;
+ }
+
+ return (length);
+}
+
+/*
+ * Append the generic ACE to the ACL. This is used to put any
+ * kind of ACE on the ACL so the argument is declared as a void*. We cast it
+ * to an ACCESS_ALLOWED_ACE just because there is no sense of a generic ACE.
+ */
+static int
+smb_ace_append_generic(smb_acl_t *acl, void *generic_ace)
+{
+ smb_ace_t *ace = (smb_ace_t *)generic_ace;
+ uint16_t acl_len = smb_acl_len(acl);
+ unsigned char *scan = (uchar_t *)acl;
+
+ if ((acl_len + ace->se_header.se_size) > acl->sl_size) {
+ /* no room in the acl for this ace */
+ return (0);
+ }
+
+ /* append the ace to the acl and inc ace count */
+ bcopy(ace, &scan[acl_len], ace->se_header.se_size);
+ acl->sl_acecnt++;
+
+ return (1);
+}
+
+/*
+ * Helper for the ACL sort routine
+ */
+typedef struct smb_ace_entry {
+ smb_ace_t *e_ace;
+ list_node_t e_node;
+} smb_ace_entry_t;
+
+/*
+ * ACE groups within a DACL
+ *
+ * This is from lower to higher ACE order priority
+ */
+#define SMB_AG_START 0
+#define SMB_AG_ALW_INHRT 0
+#define SMB_AG_DNY_INHRT 1
+#define SMB_AG_ALW_DRCT 2
+#define SMB_AG_DNY_DRCT 3
+#define SMB_AG_NUM 4
+
+/*
+ * smb_acl_do_sort
+ *
+ * Sorts the given ACL, acl, and returns the result
+ * in a newly allocated memory.
+ *
+ * The following is an excerpt from MSDN website.
+ *
+ * Order of ACEs in a DACL
+ *
+ * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
+ * is simple: In a DACL, all access-denied ACEs should precede any
+ * access-allowed ACEs.
+ *
+ * For Windows 2000 or later, the proper order of ACEs is more complicated
+ * because of the introduction of object-specific ACEs and automatic
+ * inheritance.
+ *
+ * The following describes the preferred order:
+ *
+ * To ensure that noninherited ACEs have precedence over inherited ACEs,
+ * place all noninherited ACEs in a group before any inherited ACEs. This
+ * ordering ensures, for example, that a noninherited access-denied ACE
+ * is enforced regardless of any inherited ACE that allows access.
+ * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
+ * according to ACE type, as the following shows:
+ * . Access-denied ACEs that apply to the object itself
+ * . Access-denied ACEs that apply to a subobject of the
+ * object, such as a property set or property
+ * . Access-allowed ACEs that apply to the object itself
+ * . Access-allowed ACEs that apply to a subobject of the object
+ *
+ * Of course, not all ACE types are required in an ACL.
+ */
+static smb_acl_t *
+smb_acl_do_sort(smb_acl_t *acl, list_t *ace_grps)
+{
+ smb_acl_t *sorted_acl;
+ smb_ace_entry_t *nae;
+ int i;
+
+ sorted_acl = kmem_alloc(acl->sl_size, KM_SLEEP);
+ *sorted_acl = *acl;
+
+ /* start with no ACE in the sorted ACL */
+ sorted_acl->sl_acecnt = 0;
+
+ /*
+ * start with highest priority ACE group and append
+ * the ACEs to the ACL.
+ */
+ for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
+ nae = list_head(&ace_grps[i]);
+ while (nae) {
+ if (!smb_ace_append_generic(sorted_acl, nae->e_ace)) {
+ kmem_free(sorted_acl, acl->sl_size);
+ return (NULL);
+ }
+ nae = list_next(&ace_grps[i], nae);
+ }
+ }
+
+ return (sorted_acl);
+}
+
+/*
+ * smb_acl_need_sort
+ *
+ * Here is the desired ACE order
+ *
+ * deny-direct, allow-direct, deny-inherited, allow-inherited
+ *
+ * If any ace has been encountered which belongs to a group
+ * with lower priority of the specified ace_grp then the acl
+ * should be sorted.
+ */
+static int
+smb_acl_need_sort(list_t *ace_grps, int ace_grp)
+{
+ int i;
+
+ for (i = SMB_AG_START; i < ace_grp; i++)
+ if (!list_is_empty(&ace_grps[i]))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * smb_acl_sort
+ *
+ * Returns NULL upon failure.
+ * Returns pointer to the passed (original) acl if no sort is required.
+ * Returns pointer to a new acl upon successful sort in which case the
+ * caller is responsible for freeing the allocated memory.
+ */
+smb_acl_t *
+smb_acl_sort(smb_acl_t *acl)
+{
+ smb_acl_t *sorted_acl;
+ smb_ace_t *ace;
+ smb_ace_entry_t *ace_list;
+ int ace_list_size;
+ list_t ace_grps[SMB_AG_NUM];
+ int ag;
+ int do_sort = 0;
+ uint16_t i;
+ uint8_t ace_flags;
+
+ ASSERT(acl);
+
+ if (acl->sl_acecnt == 0) {
+ /*
+ * ACL with no entry is a valid ACL and it means
+ * no access for anybody.
+ */
+ return (acl);
+ }
+
+ for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
+ list_create(&ace_grps[i], sizeof (smb_ace_entry_t),
+ offsetof(smb_ace_entry_t, e_node));
+ }
+
+ /*
+ * Allocate the helper entries to group the ACEs based on
+ * the desired priorities.
+ */
+ ace_list_size = sizeof (smb_ace_entry_t) * acl->sl_acecnt;
+ ace_list = kmem_alloc(ace_list_size, KM_SLEEP);
+
+ for (i = 0; i < acl->sl_acecnt; ++i) {
+ ace_list[i].e_ace = smb_ace_get(acl, i);
+ ace = ace_list[i].e_ace;
+ ASSERT(ace);
+
+ ace_flags = ace->se_header.se_flags;
+
+ switch (ace->se_header.se_type) {
+ case ACCESS_DENIED_ACE_TYPE:
+ if (ace_flags & INHERITED_ACE) {
+ ag = SMB_AG_DNY_INHRT;
+ do_sort |= smb_acl_need_sort(ace_grps, ag);
+ } else {
+ ag = SMB_AG_DNY_DRCT;
+ do_sort |= smb_acl_need_sort(ace_grps, ag);
+ }
+ break;
+
+ case ACCESS_ALLOWED_ACE_TYPE:
+ if (ace_flags & INHERITED_ACE) {
+ ag = SMB_AG_ALW_INHRT;
+ } else {
+ ag = SMB_AG_ALW_DRCT;
+ do_sort |= smb_acl_need_sort(ace_grps, ag);
+ }
+ break;
+
+ default:
+ /*
+ * This is the lowest priority group so we put
+ * evertything unknown here.
+ */
+ ag = SMB_AG_ALW_INHRT;
+ break;
+ }
+
+ /* Put the element on the appropriate list */
+ list_insert_tail(&ace_grps[ag], &ace_list[i]);
+ }
+
+ if (do_sort)
+ sorted_acl = smb_acl_do_sort(acl, ace_grps);
+ else
+ sorted_acl = acl;
+
+ for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
+ void *ent;
+ list_t *alist = &ace_grps[i];
+
+ while ((ent = list_head(alist)) != NULL)
+ list_remove(alist, ent);
+ list_destroy(alist);
+ }
+
+ kmem_free(ace_list, ace_list_size);
+
+ return (sorted_acl);
+}
+
+static int
+smb_ace_common_add(
+ smb_acl_t *acl,
+ uint8_t type,
+ uint8_t flags,
+ uint32_t access_mask,
+ nt_sid_t *sid)
+{
+ smb_ace_t *ace;
+ unsigned char *scan = (unsigned char *) acl;
+ uint16_t used = smb_acl_len(acl);
+ uint16_t sid_len = nt_sid_length(sid);
+ uint16_t size;
+
+ size = sizeof (ace->se_header) + sizeof (ace->se_mask) + sid_len;
+
+ if (size + used > acl->sl_size) {
+ /* won't fit */
+ return (0);
+ }
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ace = (smb_ace_t *)&scan[used];
+
+ ace->se_header.se_type = type;
+ ace->se_header.se_flags = flags;
+ ace->se_header.se_size = size;
+ ace->se_mask = access_mask;
+ bcopy(sid, &ace->se_sid, sid_len);
+
+ acl->sl_acecnt++;
+
+ return (1);
+}
+
+smb_ace_t *
+smb_ace_get(smb_acl_t *acl, uint16_t idx)
+{
+ smb_ace_t *ace;
+ unsigned char *scan_beg = (unsigned char *) &acl[0];
+ unsigned char *scan_end = scan_beg + acl->sl_size;
+ unsigned char *scan = (unsigned char *) &acl[1];
+ uint16_t count = 0;
+
+ if (idx >= acl->sl_acecnt)
+ return (NULL);
+
+ while (count <= idx && scan < scan_end) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ace = (smb_ace_t *)scan;
+
+ if (count == idx) {
+ return (ace);
+ }
+
+ scan += ace->se_header.se_size;
+ count++;
+ }
+
+ return (NULL);
+}
+
+int
+smb_acl_copy(uint16_t buflen, smb_acl_t *dst_acl, smb_acl_t *src_acl)
+{
+ smb_ace_hdr_t *dst_ace;
+ smb_ace_hdr_t *src_ace;
+ unsigned char *scan = (unsigned char *) &src_acl[1];
+ unsigned char *dest_beg = (unsigned char *) &dst_acl[0];
+ unsigned char *dest_end;
+ unsigned char *dest = (unsigned char *) &dst_acl[1];
+ uint16_t count = 0;
+ uint16_t n_bytes;
+
+ n_bytes = smb_acl_len(src_acl);
+ if (n_bytes > buflen)
+ return (0);
+
+ dest_end = dest_beg + n_bytes;
+
+ dst_acl->sl_revision = src_acl->sl_revision;
+ dst_acl->sl_sbz1 = 0;
+ dst_acl->sl_size = n_bytes;
+ dst_acl->sl_acecnt = 0;
+ dst_acl->sl_sbz2 = 0;
+
+ while (count < src_acl->sl_acecnt && dest < dest_end) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ src_ace = (smb_ace_hdr_t *)scan;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ dst_ace = (smb_ace_hdr_t *)dest;
+ bcopy(src_ace, dst_ace, src_ace->se_size);
+ dest += dst_ace->se_size;
+ dst_acl->sl_acecnt++;
+ scan += src_ace->se_size;
+ count++;
+ }
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (dest - dest_beg);
+}
+
+/*
+ * smb_ace_len
+ *
+ * Returns the length of an ACE with the given SID
+ *
+ * struct smb_ace {
+ * smb_ace_hdr_t se_header;
+ * uint32_t se_mask;
+ * nt_sid_t se_sid;
+ * };
+ */
+uint16_t
+smb_ace_len(nt_sid_t *sid)
+{
+ ASSERT(sid);
+
+ return (sizeof (smb_ace_hdr_t)
+ + sizeof (uint32_t) + nt_sid_length(sid));
+}
+
+/*
+ * smb_ace_mask_g2s
+ *
+ * Converts generic access bits in the given mask (if any)
+ * to file specific bits. Generic access masks shouldn't be
+ * stored in filesystem ACEs.
+ */
+uint32_t
+smb_ace_mask_g2s(DWORD mask)
+{
+ if (mask & GENERIC_ALL) {
+ mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
+ | GENERIC_EXECUTE);
+
+ mask |= FILE_ALL_ACCESS;
+ return (mask);
+ }
+
+ if (mask & GENERIC_READ) {
+ mask &= ~GENERIC_READ;
+ mask |= FILE_GENERIC_READ;
+ }
+
+ if (mask & GENERIC_WRITE) {
+ mask &= ~GENERIC_WRITE;
+ mask |= FILE_GENERIC_WRITE;
+ }
+
+ if (mask & GENERIC_EXECUTE) {
+ mask &= ~GENERIC_EXECUTE;
+ mask |= FILE_GENERIC_EXECUTE;
+ }
+
+ return (mask);
+}
+
+/*
+ * smb_acl_getsids
+ *
+ * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
+ */
+static idmap_stat
+smb_acl_getsids(smb_idmap_batch_t *sib, acl_t *zacl, uid_t uid, gid_t gid)
+{
+ ace_t *zace;
+ idmap_stat idm_stat;
+ smb_idmap_t *sim;
+ uid_t id;
+ int i, idtype;
+
+ sim = sib->sib_maps;
+
+ for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
+ zace++, i++, sim++) {
+ switch (zace->a_flags & ACE_TYPE_FLAGS) {
+ case ACE_OWNER:
+ id = uid;
+ idtype = SMB_IDMAP_USER;
+ break;
+
+ case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
+ /* owning group */
+ id = gid;
+ idtype = SMB_IDMAP_GROUP;
+ break;
+
+ case ACE_IDENTIFIER_GROUP:
+ /* regular group */
+ id = zace->a_who;
+ idtype = SMB_IDMAP_GROUP;
+ break;
+
+ case ACE_EVERYONE:
+ idtype = SMB_IDMAP_EVERYONE;
+ break;
+
+ default:
+ /* user entry */
+ id = zace->a_who;
+ idtype = SMB_IDMAP_USER;
+ }
+
+ idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
+ id, idtype);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (idm_stat);
+ }
+ }
+
+ idm_stat = smb_idmap_batch_getmappings(sib);
+ return (idm_stat);
+}
+
+/*
+ * smb_acl_grow
+ *
+ * Grow the acl size by given number of bytes in 'grow'
+ * Returns pointer to the newly allocated memory.
+ */
+static smb_acl_t *
+smb_acl_grow(smb_acl_t *acl, uint16_t grow)
+{
+ smb_acl_t *new_acl;
+ uint16_t smb_aclsz;
+
+ ASSERT(acl);
+
+ smb_aclsz = acl->sl_size;
+ new_acl = kmem_alloc(smb_aclsz + grow, KM_SLEEP);
+ (void) memcpy(new_acl, acl, smb_aclsz);
+ kmem_free(acl, smb_aclsz);
+ new_acl->sl_size = smb_aclsz + grow;
+
+ return (new_acl);
+}
+
+/*
+ * smb_acl_from_zfs
+ *
+ * Converts given ZFS ACL to a Windows ACL.
+ *
+ * A pointer to allocated memory for the Win ACL will be
+ * returned upon successful conversion.
+ */
+smb_acl_t *
+smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid)
+{
+ ace_t *zace;
+ int numaces;
+ smb_acl_t *acl;
+ uint16_t smb_aclsz;
+ smb_idmap_batch_t sib;
+ smb_idmap_t *sim;
+ idmap_stat idm_stat;
+ int status;
+
+ idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
+ SMB_IDMAP_ID2SID);
+ if (idm_stat != IDMAP_SUCCESS)
+ return (NULL);
+
+ if (smb_acl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) {
+ smb_idmap_batch_destroy(&sib);
+ return (NULL);
+ }
+
+ smb_aclsz = sizeof (smb_acl_t);
+
+ acl = kmem_alloc(smb_aclsz, KM_SLEEP);
+ smb_acl_init(acl, smb_aclsz, ACL_REVISION);
+
+ sim = sib.sib_maps;
+ for (numaces = 0, zace = zacl->acl_aclp;
+ numaces < zacl->acl_cnt;
+ zace++, numaces++, sim++) {
+ ASSERT(sim->sim_sid);
+ if (sim->sim_sid == NULL) {
+ kmem_free(acl, acl->sl_size);
+ acl = NULL;
+ break;
+ }
+
+ /* Make room for this ACE */
+ acl = smb_acl_grow(acl, smb_ace_len(sim->sim_sid));
+
+ status = smb_ace_common_add(acl,
+ zace->a_type,
+ smb_ace_flags_fromzfs(zace->a_flags),
+ zace->a_access_mask,
+ sim->sim_sid);
+
+ if (status == 0) {
+ kmem_free(acl, acl->sl_size);
+ acl = NULL;
+ break;
+ }
+ }
+
+ smb_idmap_batch_destroy(&sib);
+ return (acl);
+}
+
+/*
+ * SID for Everyone group: S-1-1-0.
+ */
+nt_sid_t everyone_sid = {
+ NT_SID_REVISION,
+ 1,
+ NT_SECURITY_WORLD_AUTH,
+ { 0 }
+};
+
+/*
+ * smb_acl_null_empty
+ *
+ * NULL DACL means everyone full-access
+ * Empty DACL means everyone full-deny
+ *
+ * ZFS ACL must have at least one entry so smb server has
+ * to simulate the aforementioned expected behavior by adding
+ * an entry in case the requested DACL is null or empty. Adding
+ * a everyone full-deny entry has proved to be problematic in
+ * tests since a deny entry takes precedence over allow entries.
+ * So, instead of adding a everyone full-deny, an owner ACE with
+ * owner implicit permissions will be set.
+ */
+acl_t *
+smb_acl_null_empty(int null)
+{
+ acl_t *zacl;
+ ace_t *zace;
+
+ zacl = smb_fsop_aclalloc(1, ACL_AUTO_INHERIT);
+ zace = zacl->acl_aclp;
+
+ zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ if (null) {
+ zace->a_access_mask = ACE_ALL_PERMS;
+ zace->a_flags = ACE_EVERYONE;
+ } else {
+ zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
+ ACE_READ_ATTRIBUTES;
+ zace->a_flags = ACE_OWNER;
+ }
+
+ return (zacl);
+}
+
+/*
+ * smb_acl_to_zfs
+ *
+ * Converts given Windows ACL to a ZFS ACL.
+ *
+ * fs_acl will contain a pointer to the created ZFS ACL.
+ * The allocated memory should be freed by calling
+ * smb_fsop_aclfree().
+ *
+ * Since the output parameter, fs_acl, is allocated in this
+ * function, the caller has to make sure *fs_acl is NULL which
+ * means it's not pointing to any memory.
+ */
+uint32_t
+smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
+{
+ smb_ace_t *ace;
+ acl_t *zacl;
+ ace_t *zace;
+ smb_idmap_batch_t sib;
+ smb_idmap_t *sim;
+ idmap_stat idm_stat;
+ int i, isdir;
+
+ ASSERT(fs_acl);
+ ASSERT(*fs_acl == NULL);
+
+ if (acl && !smb_acl_isvalid(acl, which_acl))
+ return (NT_STATUS_INVALID_ACL);
+
+ if ((acl == NULL) || (acl->sl_acecnt == 0)) {
+ if (which_acl == SMB_DACL_SECINFO) {
+ *fs_acl = smb_acl_null_empty(acl == NULL);
+ }
+
+ return (NT_STATUS_SUCCESS);
+ }
+
+ idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
+ SMB_IDMAP_SID2ID);
+ if (idm_stat != IDMAP_SUCCESS)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ isdir = ((flags & ACL_IS_DIR) == ACL_IS_DIR);
+
+ zacl = smb_fsop_aclalloc(acl->sl_acecnt, flags);
+
+ zace = zacl->acl_aclp;
+ sim = sib.sib_maps;
+
+ for (i = 0; ace = smb_ace_get(acl, i); i++, zace++, sim++) {
+ zace->a_type = ace->se_header.se_type & ACE_ALL_TYPES;
+ zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
+ zace->a_flags = smb_ace_flags_tozfs(ace->se_header.se_flags,
+ isdir);
+
+ if (nt_sid_is_equal(&ace->se_sid, &everyone_sid))
+ zace->a_flags |= ACE_EVERYONE;
+ else {
+ sim->sim_id = &zace->a_who;
+ idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
+ &ace->se_sid, -1);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_fsop_aclfree(zacl);
+ smb_idmap_batch_destroy(&sib);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+ }
+
+ idm_stat = smb_idmap_batch_getmappings(&sib);
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_fsop_aclfree(zacl);
+ smb_idmap_batch_destroy(&sib);
+ return (NT_STATUS_NONE_MAPPED);
+ }
+
+ /*
+ * Set the ACEs group flag based on the type of ID returned.
+ */
+ zace = zacl->acl_aclp;
+ sim = sib.sib_maps;
+ for (i = 0; i < acl->sl_acecnt; i++, zace++, sim++) {
+ if (zace->a_flags & ACE_EVERYONE)
+ continue;
+
+ if (sim->sim_idtype == SMB_IDMAP_GROUP)
+ zace->a_flags |= ACE_IDENTIFIER_GROUP;
+ }
+
+ smb_idmap_batch_destroy(&sib);
+
+ *fs_acl = zacl;
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_acl_inheritable
+ *
+ * Checks to see if there are any inheritable ACEs in the
+ * given ZFS ACL. Returns the number of inheritable ACEs.
+ *
+ * The inherited ACL could be different based on the type of
+ * new object (file/dir) specified by 'is_dir'.
+ *
+ * Note that the input ACL is a ZFS ACL not Windows ACL.
+ *
+ * Any ACE except creator owner/group:
+ *
+ * FI DI NP #F #D
+ * ---- ---- ---- ---- ----
+ * - - ? 0 0
+ * X - - 1 1
+ * X - X 1 0
+ * - X - 0 1
+ * - X X 0 1
+ * X X - 1 1
+ * X X X 1 1
+ *
+ * Creator owner/group ACE:
+ *
+ * FI DI NP #F #D
+ * ---- ---- ---- ---- ----
+ * - - ? 0 0
+ * X - - 1r 1c
+ * X - X 1r 0
+ * - X - 0 2
+ * - X X 0 1r
+ * X X - 1r 2
+ * X X X 1r 1r
+ *
+ * Legend:
+ *
+ * FI: File Inherit
+ * DI: Dir Inherit
+ * NP: No Propagate
+ * #F: #ACE for a new file
+ * #D: #ACE for a new dir
+ *
+ * X: bit is set
+ * -: bit is not set
+ * ?: don't care
+ *
+ * 1r: one owner/group ACE
+ * 1c: one creator owner/group ACE
+ */
+static int
+smb_acl_inheritable(acl_t *zacl, int is_dir)
+{
+ int numaces;
+ int num_inheritable = 0;
+ ace_t *zace;
+
+ if (zacl == NULL)
+ return (0);
+
+ for (numaces = 0, zace = zacl->acl_aclp;
+ numaces < zacl->acl_cnt;
+ zace++, numaces++) {
+ switch (zace->a_flags & ACE_FD_INHERIT_ACE) {
+ case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
+ /*
+ * Files inherit an effective ACE.
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
+ */
+ num_inheritable++;
+
+ if (is_dir && ZACE_IS_CREATOR(zace) &&
+ (ZACE_IS_PROPAGATE(zace))) {
+ num_inheritable++;
+ }
+ break;
+
+ case ACE_FILE_INHERIT_ACE:
+ /*
+ * Files inherit as an effective ACE.
+ *
+ * Dirs inherit an inherit-only ACE
+ * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
+ * flag is also set.
+ */
+ if (is_dir == 0)
+ num_inheritable++;
+ else if (ZACE_IS_PROPAGATE(zace))
+ num_inheritable++;
+ break;
+
+ case ACE_DIRECTORY_INHERIT_ACE:
+ /*
+ * No effect on files
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ */
+ if (is_dir == 0)
+ break;
+
+ num_inheritable++;
+
+ if (ZACE_IS_CREATOR(zace) &&
+ (ZACE_IS_PROPAGATE(zace)))
+ num_inheritable++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (num_inheritable);
+}
+
+#define DEFAULT_DACL_ACENUM 2
+/*
+ * Default ACL:
+ * owner: full access
+ * SYSTEM: full access
+ */
+static ace_t default_dacl[DEFAULT_DACL_ACENUM] = {
+ { (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
+ { IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
+ ACE_ACCESS_ALLOWED_ACE_TYPE }
+};
+
+/*
+ * smb_acl_inherit
+ *
+ * Manufacture the inherited ACL from the given ACL considering
+ * the new object type (file/dir) specified by 'is_dir'. The
+ * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
+ * This function implements Windows inheritance rules.
+ *
+ * Note that the in/our ACLs are ZFS ACLs not Windows ACLs
+ */
+acl_t *
+smb_acl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, uid_t owner_uid)
+{
+ boolean_t use_default = B_FALSE;
+ int num_inheritable = 0;
+ int numaces;
+ ace_t *dir_zace;
+ acl_t *new_zacl;
+ ace_t *new_zace;
+
+ num_inheritable = smb_acl_inheritable(dir_zacl, is_dir);
+
+ if (num_inheritable == 0) {
+ if (which_acl == SMB_DACL_SECINFO) {
+ /* No inheritable access ACEs -> default DACL */
+ num_inheritable = DEFAULT_DACL_ACENUM;
+ use_default = B_TRUE;
+ } else {
+ return (NULL);
+ }
+ }
+
+ new_zacl = smb_fsop_aclalloc(num_inheritable, ACL_AUTO_INHERIT);
+ new_zace = new_zacl->acl_aclp;
+
+ if (use_default) {
+ bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
+ new_zace->a_who = owner_uid;
+ return (new_zacl);
+ }
+
+ for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
+ numaces < dir_zacl->acl_cnt;
+ dir_zace++, numaces++) {
+ switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
+ case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
+ /*
+ * Files inherit an effective ACE.
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
+ */
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+
+ if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
+ (ZACE_IS_PROPAGATE(dir_zace))) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
+ break;
+
+ case ACE_FILE_INHERIT_ACE:
+ /*
+ * Files inherit as an effective ACE.
+ *
+ * Dirs inherit an inherit-only ACE
+ * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
+ * flag is also set.
+ */
+ if (is_dir == 0) {
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+ } else if (ZACE_IS_PROPAGATE(dir_zace)) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
+ break;
+
+ case ACE_DIRECTORY_INHERIT_ACE:
+ /*
+ * No effect on files
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ */
+ if (is_dir == 0)
+ break;
+
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+
+ if (ZACE_IS_CREATOR(dir_zace) &&
+ (ZACE_IS_PROPAGATE(dir_zace))) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (new_zacl);
+}
+
+static void
+smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir)
+{
+ *zace = *dir_zace;
+ if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace)))
+ zace->a_flags &= ~ACE_INHERIT_FLAGS;
+ zace->a_flags |= ACE_INHERITED_ACE;
+
+ /*
+ * Replace creator owner/group ACEs with
+ * actual owner/group ACEs.
+ */
+ if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
+ zace->a_who = (uid_t)-1;
+ zace->a_flags |= ACE_OWNER;
+ } else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
+ zace->a_who = (uid_t)-1;
+ zace->a_flags |= ACE_GROUP;
+ }
+}
+
+static uint16_t
+smb_ace_flags_tozfs(uint8_t c_flags, int isdir)
+{
+ uint16_t z_flags = 0;
+
+ if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
+ z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
+
+ if (c_flags & FAILED_ACCESS_ACE_FLAG)
+ z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
+
+ if (c_flags & INHERITED_ACE)
+ z_flags |= ACE_INHERITED_ACE;
+
+ /*
+ * ZFS doesn't like any inheritance flags to be set on a
+ * file's ACE, only directories. Windows doesn't care.
+ */
+ if (isdir)
+ z_flags |= (c_flags & ACE_INHERIT_FLAGS);
+
+ return (z_flags);
+}
+
+static uint8_t
+smb_ace_flags_fromzfs(uint16_t z_flags)
+{
+ uint8_t c_flags;
+
+ c_flags = z_flags & ACE_INHERIT_FLAGS;
+
+ if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
+ c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
+
+ if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
+ c_flags |= FAILED_ACCESS_ACE_FLAG;
+
+ if (z_flags & ACE_INHERITED_ACE)
+ c_flags |= INHERITED_ACE;
+
+ return (c_flags);
+}
+
+/*
+ * This is generic (ACL version 2) vs. object-specific
+ * (ACL version 4) ACE types.
+ */
+int
+smb_ace_is_generic(int type)
+{
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_ACE_TYPE:
+ case ACE_ACCESS_DENIED_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
+ return (1);
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+smb_ace_is_access(int type)
+{
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_ACE_TYPE:
+ case ACE_ACCESS_DENIED_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
+ return (1);
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+smb_ace_is_audit(int type)
+{
+ switch (type) {
+ case ACE_SYSTEM_AUDIT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
+ return (1);
+
+ default:
+ break;
+ }
+
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_alloc.c b/usr/src/uts/common/fs/smbsrv/smb_alloc.c
new file mode 100644
index 0000000000..24de6ea712
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_alloc.c
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/kmem.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+
+#include <smbsrv/alloc.h>
+
+#define MEM_HDR_SIZE 8
+static uint32_t mem_get_size(void *ptr);
+
+void *
+mem_malloc(uint32_t size)
+{
+ uint8_t *p;
+
+ size += MEM_HDR_SIZE;
+ p = kmem_alloc(size, KM_SLEEP);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ *(uint32_t *)p = size;
+ p += MEM_HDR_SIZE;
+
+ return (p);
+}
+
+void *
+mem_zalloc(uint32_t size)
+{
+ uint8_t *p;
+
+ p = mem_malloc(size);
+ (void) memset(p, 0, size);
+ return (p);
+}
+
+char *
+mem_strdup(const char *ptr)
+{
+ char *p;
+ size_t size;
+
+ size = strlen(ptr) + 1;
+ p = mem_malloc(size);
+ (void) memcpy(p, ptr, size);
+ return (p);
+}
+
+static uint32_t
+mem_get_size(void *ptr)
+{
+ uint32_t *p;
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ p = (uint32_t *)((uint8_t *)ptr - MEM_HDR_SIZE);
+
+ return (*p);
+}
+
+void *
+mem_realloc(void *ptr, uint32_t size)
+{
+ void *new_ptr;
+
+ if (ptr == NULL)
+ return (mem_malloc(size));
+
+ if (size == 0) {
+ smb_mem_free(ptr);
+ return (NULL);
+ }
+
+ new_ptr = mem_malloc(size);
+ (void) memcpy(new_ptr, ptr, mem_get_size(ptr));
+ smb_mem_free(ptr);
+
+ return (new_ptr);
+}
+
+void
+smb_mem_free(void *ptr)
+{
+ uint8_t *p;
+
+ if (ptr == 0)
+ return;
+
+ p = (uint8_t *)ptr - MEM_HDR_SIZE;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ kmem_free(p, *(uint32_t *)p);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_books.c b/usr/src/uts/common/fs/smbsrv/smb_books.c
new file mode 100644
index 0000000000..5e94d8a6f1
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_books.c
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains functions which destruct SMB session, tree, file,
+ * user and xa structures.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_kproto.h>
+
+/*
+ * If this user is found in the user list,
+ * return 1 on the first occurrence
+ * else return 0 if end of list is reached
+ */
+
+/*
+ * Return # of users
+ */
+uint32_t
+smb_user_get_num(void)
+{
+ smb_session_t *sn = NULL;
+ smb_llist_t *ulist;
+ uint32_t cnt = 0;
+
+ smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
+ while ((sn = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx, sn))
+ != NULL) {
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ ulist = &sn->s_user_list;
+ cnt += smb_llist_get_count(ulist);
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+ return (cnt);
+}
+
+static int
+smb_dr_user_create(smb_dr_user_ctx_t *uinfo, uint64_t sess_id, uint16_t uid,
+ char *domain, char *acct, char *workstation, uint32_t ipaddr,
+ int32_t native_os, time_t logon_time, uint32_t flags)
+{
+ if (!domain || !acct || !workstation)
+ return (-1);
+
+ uinfo->du_session_id = sess_id;
+ uinfo->du_uid = uid;
+
+ uinfo->du_domain_len = strlen(domain) + 1;
+ uinfo->du_domain = smb_kstrdup(domain, uinfo->du_domain_len);
+
+ uinfo->du_account_len = strlen(acct) + 1;
+ uinfo->du_account = smb_kstrdup(acct, uinfo->du_account_len);
+
+ uinfo->du_workstation_len = strlen(workstation) + 1;
+ uinfo->du_workstation = smb_kstrdup(workstation,
+ uinfo->du_workstation_len);
+
+ uinfo->du_native_os = native_os;
+ uinfo->du_ipaddr = ipaddr;
+ uinfo->du_logon_time = (int64_t)logon_time;
+ uinfo->du_flags = flags;
+
+ return (0);
+}
+
+void
+smb_dr_user_free(smb_dr_user_ctx_t *uinfo)
+{
+ if (!uinfo)
+ return;
+
+ if (uinfo->du_domain)
+ kmem_free(uinfo->du_domain, uinfo->du_domain_len);
+
+ if (uinfo->du_account)
+ kmem_free(uinfo->du_account, uinfo->du_account_len);
+
+ if (uinfo->du_workstation)
+ kmem_free(uinfo->du_workstation, uinfo->du_workstation_len);
+}
+
+void
+smb_dr_ulist_free(smb_dr_ulist_t *ulist)
+{
+ int i;
+
+ if (!ulist)
+ return;
+
+ for (i = 0; i < ulist->dul_cnt; i++) {
+ smb_dr_user_free(&ulist->dul_users[i]);
+ }
+}
+
+int
+smb_dr_ulist_get(int offset, smb_dr_ulist_t *dr_ulist)
+{
+ smb_session_t *sn = NULL;
+ smb_user_t *user;
+ smb_llist_t *ulist;
+ smb_dr_user_ctx_t *uinfo;
+ int cnt = 0, skip = 0;
+
+ if (!dr_ulist)
+ return (-1);
+
+ smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
+ while ((sn = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx, sn))
+ != NULL && cnt < SMB_DR_MAX_USERS) {
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ ulist = &sn->s_user_list;
+ smb_llist_enter(ulist, RW_READER);
+ user = smb_llist_head(ulist);
+ while (user && cnt < SMB_DR_MAX_USERS) {
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ mutex_enter(&user->u_mutex);
+ if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
+ if (skip++ < offset) {
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(ulist, user);
+ continue;
+ }
+
+ uinfo = &dr_ulist->dul_users[cnt++];
+ if (smb_dr_user_create(uinfo, sn->s_kid,
+ user->u_uid, user->u_domain, user->u_name,
+ sn->workstation, sn->ipaddr, sn->native_os,
+ user->u_logon_time, user->u_flags) != 0) {
+ cnt--;
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(ulist, user);
+ continue;
+ }
+ }
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(ulist, user);
+ }
+ smb_llist_exit(ulist);
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+ dr_ulist->dul_cnt = cnt;
+ return (cnt);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_check_directory.c b/usr/src/uts/common/fs/smbsrv/smb_check_directory.c
new file mode 100644
index 0000000000..d29e55eda6
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_check_directory.c
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: check_directory
+ *
+ * This SMB is used to verify that a path exists and is a directory. No
+ * error is returned if the given path exists and the client has read
+ * access to it. Client machines which maintain a concept of a "working
+ * directory" will find this useful to verify the validity of a "change
+ * working directory" command. Note that the servers do NOT have a concept
+ * of working directory for a particular client. The client must always
+ * supply full pathnames relative to the Tid in the SMB header.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryPath[]; Directory path
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * DOS clients, in particular, depend on the SMB_ERR_BAD_PATH return code
+ * if the directory is not found.
+ *
+ * 4.3.3.1 Errors
+ *
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRbadpath
+ * ERRDOS/ERRnoaccess
+ * ERRHRD/ERRdata
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ * ERRSRV/ERRaccess
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_check_directory(struct smb_request *sr)
+{
+ int rc;
+ struct smb_node *dnode;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
+ ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Release hold on dir_snode taken in smbd_fs_query()
+ */
+
+ smb_node_release(sr->arg.dirop.fqi.dir_snode);
+
+ dnode = sr->arg.dirop.fqi.last_snode;
+
+ if (sr->arg.dirop.fqi.last_attr.sa_vattr.va_type != VDIR) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ smbsr_raise_errno(sr, ENOTDIR);
+ /* NOTREACHED */
+ }
+
+ rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_TRAVERSE);
+
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ if (rc != 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_close.c b/usr/src/uts/common/fs/smbsrv/smb_close.c
new file mode 100644
index 0000000000..c4d129c2e4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_close.c
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * Close a file by fid. All locks or other resources held by the
+ * requesting process on the file should be released by the server.
+ * The requesting process can no longer use the fid for further
+ * file access requests.
+ *
+ * If LastWriteTime is non-zero, it should be used to set the file
+ * timestamp. Otherwise, file system should set the timestamp.
+ * Failure to set the timestamp, even if requested by the client,
+ * should not result in an error response from the server.
+ */
+int
+smb_com_close(struct smb_request *sr)
+{
+ uint32_t last_wtime;
+ int rc = 0;
+
+ rc = smbsr_decode_vwv(sr, "wl", &sr->smb_fid, &last_wtime);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ rc = smb_common_close(sr, last_wtime);
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Close the file represented by fid and then disconnect the
+ * associated tree.
+ */
+int
+smb_com_close_and_tree_disconnect(struct smb_request *sr)
+{
+ uint32_t last_wtime;
+ int rc = 0;
+
+ rc = smbsr_decode_vwv(sr, "wl", &sr->smb_fid, &last_wtime);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ rc = smb_common_close(sr, last_wtime);
+ smbsr_rq_notify(sr, sr->session, sr->tid_tree);
+ smb_tree_disconnect(sr->tid_tree);
+
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_common_close
+ *
+ * Common close function called by SmbClose, SmbWriteAndClose,
+ * and SMBCloseAndTreeDisconnect.
+ */
+int
+smb_common_close(struct smb_request *sr, uint32_t last_wtime)
+{
+ return (smb_ofile_close(sr->fid_ofile, last_wtime));
+}
+
+/*
+ * smb_commit_delete_on_close()
+ *
+ * Check for the DeleteOnClose flag on the smb file and set it on the
+ * smb node if it is not already set. This will inhibit subsequent
+ * open requests. The delete-on-close credentials should be set to the
+ * user credentials of the current open file instance.
+ *
+ * When DeleteOnClose is set on an smb_node, the common open code will
+ * reject subsequent open requests for the file. Observation of Windows
+ * 2000 indicates that subsequent opens should be allowed (assuming
+ * there would be no sharing violation) until the file is closed using
+ * the fid on which the DeleteOnClose was requested.
+ *
+ * If there are multiple opens with delete-on-close create options,
+ * whichever the first file handle is closed will trigger the node to be
+ * marked as delete-on-close. The credentials of that ofile will be used
+ * as the delete-on-close credentials of the node.
+ */
+void
+smb_commit_delete_on_close(struct smb_ofile *ofile)
+{
+ struct smb_node *node = ofile->f_node;
+
+ if (!(node->flags & NODE_FLAGS_DELETE_ON_CLOSE) &&
+ (ofile->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE)) {
+ node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
+ crhold(node->delete_on_close_cred = ofile->f_cr);
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_lock.c b/usr/src/uts/common/fs/smbsrv/smb_common_lock.c
new file mode 100644
index 0000000000..a11a321a7f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_lock.c
@@ -0,0 +1,424 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB Locking library functions.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * Oplock timeout configuration.
+ */
+#define OPLOCK_RETRIES 2
+time_t smb_oplock_timeout = OPLOCK_STD_TIMEOUT;
+
+
+/*
+ * Oplock functionality enable/disable (see smb_oplock_init).
+ */
+
+/*
+ * Magic 0xFF 'S' 'M' 'B'
+ * smb_com a byte, the "first" command
+ * Error a 4-byte union, ignored in a request
+ * smb_flg a one byte set of eight flags
+ * smb_flg2 a two byte set of 16 flags
+ * . twelve reserved bytes, have a role
+ * in connectionless transports (IPX, UDP?)
+ * smb_tid a 16-bit tree ID, a mount point sorta,
+ * 0xFFFF is this command does not have
+ * or require a tree context
+ * smb_pid a 16-bit process ID
+ * smb_uid a 16-bit user ID, specific to this "session"
+ * and mapped to a system (bona-fide) UID
+ * smb_mid a 16-bit multiplex ID, used to differentiate
+ * multiple simultaneous requests from the same
+ * process (pid) (ref RPC "xid")
+ *
+ * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 8
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Fid; File handle
+ * UCHAR LockType; See LockType table below
+ * UCHAR OplockLevel; The new oplock level
+ * ULONG Timeout; Milliseconds to wait for unlock
+ * USHORT NumberOfUnlocks; Num. unlock range structs following
+ * USHORT NumberOfLocks; Num. lock range structs following
+ * USHORT ByteCount; Count of data bytes
+ * LOCKING_ANDX_RANGE Unlocks[]; Unlock ranges
+ * LOCKING_ANDX_RANGE Locks[]; Lock ranges
+ *
+ * LockType Flag Name Value Description
+ * ============================ ===== ================================
+ *
+ * LOCKING_ANDX_SHARED_LOCK 0x01 Read-only lock
+ * LOCKING_ANDX_OPLOCK_RELEASE 0x02 Oplock break notification
+ * LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 Change lock type
+ * LOCKING_ANDX_CANCEL_LOCK 0x08 Cancel outstanding request
+ * LOCKING_ANDX_LARGE_FILES 0x10 Large file locking format
+ *
+ * LOCKING_ANDX_RANGE Format
+ * =====================================================================
+ *
+ * USHORT Pid; PID of process "owning" lock
+ * ULONG Offset; Offset to bytes to [un]lock
+ * ULONG Length; Number of bytes to [un]lock
+ *
+ * Large File LOCKING_ANDX_RANGE Format
+ * =====================================================================
+ *
+ * USHORT Pid; PID of process "owning" lock
+ * USHORT Pad; Pad to DWORD align (mbz)
+ * ULONG OffsetHigh; Offset to bytes to [un]lock
+ * (high)
+ * ULONG OffsetLow; Offset to bytes to [un]lock (low)
+ * ULONG LengthHigh; Number of bytes to [un]lock
+ * (high)
+ * ULONG LengthLow; Number of bytes to [un]lock (low)
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ */
+
+/*
+ * smb_acquire_oplock
+ *
+ * Attempt to acquire an oplock. Note that the oplock granted may be
+ * none, i.e. the oplock was not granted.
+ *
+ * We may have to break an oplock in order to acquire one, and depending
+ * on what action is taken by the other client (unlock or close), we may
+ * or may not end up with an oplock. The type of oplock being requested
+ * is passed in level_requested, the result is returned in level_granted
+ * and is only valid if the status is NT_STATUS_SUCCESS.
+ *
+ * The Returns NT status codes:
+ * NT_STATUS_SUCCESS
+ * NT_STATUS_CONNECTION_DISCONNECTED
+ */
+DWORD
+smb_acquire_oplock(
+ struct smb_request *sr,
+ struct smb_ofile *file,
+ unsigned int level_requested,
+ unsigned int *level_granted)
+{
+ struct smb_node *node = file->f_node;
+ unsigned int level;
+ int oplock_owner;
+ DWORD status;
+ smb_user_t *user;
+
+ user = sr->uid_user;
+ ASSERT(user);
+
+ level = level_requested & MYF_OPLOCK_MASK;
+ *level_granted = MYF_OPLOCK_NONE;
+
+ if (smb_info.si.skc_oplock_enable == 0)
+ return (NT_STATUS_SUCCESS);
+
+ if (fsd_chkcap(&sr->tid_tree->t_fsd, FSOLF_DISABLE_OPLOCKS) > 0)
+ return (NT_STATUS_SUCCESS);
+
+restart:
+ oplock_owner = 0;
+
+ /*
+ * I'm not convinced the client redirector will send multiple
+ * opens requesting a batch oplock for the same file. I think
+ * the client redirector will handle the multiple instances
+ * and only send a single open to the server. The the original
+ * implementation supported it, however, so I'll leave it here
+ * for now.
+ *
+ * Grant an oplock to the requester if this session is the
+ * only one that has the file open, regardless of the number
+ * of instances of the file opened by this session. We grant
+ * any oplock requested to the owner.
+ */
+ if (node->n_refcnt == 1 || oplock_owner == 1) {
+ if (MYF_IS_EXCLUSIVE_OPLOCK(level)) {
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->flags |= NODE_EXCLUSIVE_OPLOCK;
+ node->n_oplock.op_ofile = file;
+ } else if (MYF_IS_BATCH_OPLOCK(level)) {
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->flags |= NODE_BATCH_OPLOCK;
+ node->n_oplock.op_ofile = file;
+ } else {
+ level &= ~MYF_OPLOCK_MASK;
+ }
+
+ *level_granted = level;
+ return (NT_STATUS_SUCCESS);
+ }
+
+ /*
+ * Other clients have this file open but they do not have any
+ * oplocks in force, so we must reject this oplock request.
+ */
+ if (node->n_refcnt > 1 && OPLOCKS_IN_FORCE(node) == 0) {
+ return (NT_STATUS_SUCCESS);
+ }
+
+ /*
+ * Someone has an oplock, we need to break it.
+ */
+ if ((status = smb_break_oplock(sr, node)) == NT_STATUS_SUCCESS)
+ goto restart;
+
+ return (status);
+}
+
+
+/*
+ * smb_break_oplock
+ *
+ * The oplock break may succeed for multiple reasons: file close, oplock
+ * release, holder connection dropped, requesting client disconnect etc.
+ * Whatever the reason, the oplock should be broken when this function
+ * returns. The exceptions are when the client making this request gets
+ * disconnected or when another client is handling the break and it gets
+ * disconnected.
+ *
+ * Returns NT status codes:
+ * NT_STATUS_SUCCESS No oplock in force, i.e. the
+ * oplock has been broken.
+ * NT_STATUS_CONNECTION_DISCONNECTED Requesting client disconnected.
+ * NT_STATUS_INTERNAL_ERROR
+ */
+DWORD
+smb_break_oplock(struct smb_request *sr, struct smb_node *node)
+{
+ struct smb_session *sent_session;
+ struct smb_ofile *sent_ofile;
+ struct mbuf_chain mbc;
+ int retries = 0;
+ int tid;
+ unsigned short fid;
+ clock_t elapsed_time;
+ clock_t max_time;
+ boolean_t flag;
+ smb_user_t *user;
+
+ user = sr->uid_user;
+ ASSERT(user);
+
+ smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+
+ if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
+
+ elapsed_time = 0;
+ max_time = MSEC_TO_TICK(smb_oplock_timeout * OPLOCK_RETRIES);
+ /*
+ * Another client is already attempting to break the oplock.
+ * We wait for it to finish. If the caller was trying to
+ * acquire an oplock, he should retry in case the client's
+ * connection was dropped while trying to break the oplock.
+ *
+ * If the holder's connection has been dropped, we yield to
+ * allow the thread handling the break to detect it and set
+ * the flags.
+ */
+ while ((node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) &&
+ (elapsed_time < max_time)) {
+ clock_t timeleft;
+
+ timeleft = smb_rwx_rwwait(&node->n_lock, max_time);
+ if (timeleft == -1) {
+ elapsed_time = max_time;
+ } else {
+ elapsed_time += max_time - timeleft;
+ }
+ }
+ /*
+ * If there are no oplocks in force we're done.
+ * Otherwise fall through and break the oplock.
+ */
+ if (OPLOCKS_IN_FORCE(node) == 0) {
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_SUCCESS);
+ } else {
+ /*
+ * Should we clear the
+ * LOCK_BREAKING_OPLOCK flag?
+ */
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ /*
+ * No oplock break is in progress so we start one.
+ */
+ sent_ofile = node->n_oplock.op_ofile;
+ sent_session = sent_ofile->f_session;
+ ASSERT(sent_session);
+ /*
+ * If a client has an OPLOCK on a file it would not break it because
+ * another of its processes wants to open the same file. However, if
+ * a client were to behave like that it would create a deadlock in the
+ * code that follows. For now we leave the ASSERT(). Eventually the
+ * code will have to be more defensive.
+ */
+ ASSERT(sent_session != sr->session);
+ node->n_oplock.op_flags |= OPLOCK_FLAG_BREAKING;
+ smb_rwx_rwexit(&node->n_lock);
+
+ /*
+ * IR #104382
+ * What we could find from this panic was that the tree field
+ * of sent_ofile structure points to an invalid memory page,
+ * but we couldn't find why exactly this happened. So, this is
+ * a work around till we can find the real problem.
+ */
+ tid = sent_ofile->f_tree->t_tid;
+ fid = sent_ofile->f_fid;
+
+ max_time = MSEC_TO_TICK(smb_oplock_timeout);
+ do {
+ MBC_INIT(&mbc, MLEN);
+ (void) smb_encode_mbc(&mbc, "Mb19.wwwwbb3.ww10.",
+ SMB_COM_LOCKING_ANDX, /* Command */
+ tid, /* TID */
+ 0xffff, /* PID */
+ 0, /* UID */
+ 0xffff, /* MID oplock break */
+ 8, /* parameter words=8 */
+ 0xff, /* 0xFF=none */
+ fid, /* File handle */
+ LOCKING_ANDX_OPLOCK_RELEASE);
+
+ flag = B_TRUE;
+ smb_rwx_rwenter(&sent_session->s_lock, RW_WRITER);
+ while (flag) {
+ switch (sent_session->s_state) {
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ smb_rwx_rwexit(&sent_session->s_lock);
+ smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->n_oplock.op_flags &=
+ ~OPLOCK_FLAG_BREAKING;
+ node->n_oplock.op_ofile = NULL;
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_SUCCESS);
+
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ flag = B_FALSE;
+ break;
+
+ case SMB_SESSION_STATE_NEGOTIATED:
+ sent_session->s_state =
+ SMB_SESSION_STATE_OPLOCK_BREAKING;
+ flag = B_FALSE;
+ break;
+
+ default:
+ (void) smb_rwx_rwwait(&sent_session->s_lock,
+ -1);
+ break;
+ }
+ }
+ smb_rwx_rwexit(&sent_session->s_lock);
+
+ (void) smb_session_send(sent_session, 0, &mbc);
+
+ elapsed_time = 0;
+ smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ while ((node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) &&
+ (elapsed_time < max_time)) {
+ clock_t timeleft;
+
+ timeleft = smb_rwx_rwwait(&node->n_lock, max_time);
+ if (timeleft == -1) {
+ elapsed_time = max_time;
+ } else {
+ elapsed_time += max_time - timeleft;
+ }
+ }
+ if (OPLOCKS_IN_FORCE(node) == 0) {
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_SUCCESS);
+ }
+ } while (++retries < OPLOCK_RETRIES);
+
+ /*
+ * Retries exhausted and timed out.
+ * Cancel the oplock and continue.
+ */
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING;
+ node->n_oplock.op_ofile = 0;
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_SUCCESS);
+}
+
+
+/*
+ * smb_release_oplock
+ *
+ * The original code supported batch oplock inheritance but I'm not
+ * convinced the client redirector will open multiple instances of a
+ * file with batch oplocks on the server (see smb_acquire_oplock).
+ */
+void /*ARGSUSED*/
+smb_release_oplock(struct smb_ofile *file, int reason)
+{
+ struct smb_node *node = file->f_node;
+
+ smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ if ((node->n_oplock.op_ofile != file) || OPLOCKS_IN_FORCE(node) == 0) {
+ smb_rwx_rwexit(&node->n_lock);
+ return;
+ }
+
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->n_oplock.op_ofile = 0;
+
+ if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
+ node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING;
+ }
+ smb_rwx_rwexit(&node->n_lock);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
new file mode 100644
index 0000000000..30058e8f82
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -0,0 +1,982 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the common open functionality to the various
+ * open and create SMB interface functions.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smbinfo.h>
+#include <sys/fcntl.h>
+
+extern uint32_t smb_is_executable(char *path);
+
+#define DENY_READ(share_access) ((share_access & FILE_SHARE_READ) == 0)
+
+#define DENY_WRITE(share_access) ((share_access & FILE_SHARE_WRITE) == 0)
+
+#define DENY_DELETE(share_access) ((share_access & FILE_SHARE_DELETE) == 0)
+
+#define DENY_RW(share_access) \
+ ((share_access & (FILE_SHARE_READ | FILE_SHARE_WRITE)) == 0)
+
+#define DENY_ALL(share_access) (share_access == 0)
+
+#define DENY_NONE(share_access) (share_access == FILE_SHARE_ALL)
+
+/*
+ * The default stability mode is to perform the write-through
+ * behaviour requested by the client.
+ */
+int smb_stable_mode = 0;
+
+
+/*
+ * This macro is used to delete a newly created object
+ * if any error happens after creation of object.
+ */
+#define SMB_DEL_NEWOBJ(obj) \
+ if (created) { \
+ if (is_dir) \
+ (void) smb_fsop_rmdir(sr, sr->user_cr, \
+ obj.dir_snode, obj.last_comp, 0); \
+ else \
+ (void) smb_fsop_remove(sr, sr->user_cr, \
+ obj.dir_snode, obj.last_comp, 0); \
+ }
+
+/*
+ * smb_set_stability
+ *
+ * Set the default stability mode. Normal (mode is zero) means perform
+ * the write-through behaviour requested by the client. Synchronous
+ * (mode is non-zero) means journal everything regardless of the write
+ * through behaviour requested by the client.
+ */
+void
+smb_set_stability(int mode)
+{
+ smb_stable_mode = mode;
+}
+
+/*
+ * smb_access_generic_to_file
+ *
+ * Search MSDN for IoCreateFile to see following mapping.
+ *
+ * GENERIC_READ STANDARD_RIGHTS_READ, FILE_READ_DATA,
+ * FILE_READ_ATTRIBUTES and FILE_READ_EA
+ *
+ * GENERIC_WRITE STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA,
+ * FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
+ *
+ * GENERIC_EXECUTE STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE.
+ */
+uint32_t
+smb_access_generic_to_file(uint32_t desired_access)
+{
+ uint32_t access = 0;
+
+ if (desired_access & GENERIC_ALL)
+ return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
+
+ if (desired_access & GENERIC_EXECUTE) {
+ desired_access &= ~GENERIC_EXECUTE;
+ access |= (STANDARD_RIGHTS_EXECUTE |
+ SYNCHRONIZE | FILE_EXECUTE);
+ }
+
+ if (desired_access & GENERIC_WRITE) {
+ desired_access &= ~GENERIC_WRITE;
+ access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE);
+ }
+
+ if (desired_access & GENERIC_READ) {
+ desired_access &= ~GENERIC_READ;
+ access |= FILE_GENERIC_READ;
+ }
+
+ return (access | desired_access);
+}
+
+/*
+ * smb_omode_to_amask
+ *
+ * This function converts open modes used by Open and Open AndX
+ * commands to desired access bits used by NT Create AndX command.
+ */
+uint32_t
+smb_omode_to_amask(uint32_t desired_access)
+{
+ switch (desired_access & SMB_DA_ACCESS_MASK) {
+ case SMB_DA_ACCESS_READ:
+ return (FILE_GENERIC_READ);
+
+ case SMB_DA_ACCESS_WRITE:
+ return (FILE_GENERIC_WRITE);
+
+ case SMB_DA_ACCESS_READ_WRITE:
+ return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
+
+ case SMB_DA_ACCESS_EXECUTE:
+ return (FILE_GENERIC_EXECUTE);
+ }
+
+ /* invalid open mode */
+ return ((uint32_t)SMB_INVALID_AMASK);
+}
+
+/*
+ * smb_denymode_to_sharemode
+ *
+ * This function converts deny modes used by Open and Open AndX
+ * commands to share access bits used by NT Create AndX command.
+ */
+uint32_t
+smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
+{
+ switch (desired_access & SMB_DA_SHARE_MASK) {
+ case SMB_DA_SHARE_COMPATIBILITY:
+ if (smb_is_executable(fname))
+ return (FILE_SHARE_READ | FILE_SHARE_WRITE);
+ else {
+ if ((desired_access &
+ SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_READ)
+ return (FILE_SHARE_READ);
+ else
+ return (FILE_SHARE_NONE);
+ }
+
+ case SMB_DA_SHARE_EXCLUSIVE:
+ return (FILE_SHARE_NONE);
+
+ case SMB_DA_SHARE_DENY_WRITE:
+ return (FILE_SHARE_READ);
+
+ case SMB_DA_SHARE_DENY_READ:
+ return (FILE_SHARE_WRITE);
+
+ case SMB_DA_SHARE_DENY_NONE:
+ return (FILE_SHARE_READ | FILE_SHARE_WRITE);
+ }
+
+ /* invalid deny mode */
+ return ((uint32_t)SMB_INVALID_SHAREMODE);
+}
+
+/*
+ * smb_ofun_to_crdisposition
+ *
+ * This function converts open function values used by Open and Open AndX
+ * commands to create disposition values used by NT Create AndX command.
+ */
+uint32_t
+smb_ofun_to_crdisposition(uint16_t ofun)
+{
+ static int ofun_cr_map[3][2] =
+ {
+ { -1, FILE_CREATE },
+ { FILE_OPEN, FILE_OPEN_IF },
+ { FILE_OVERWRITE, FILE_OVERWRITE_IF }
+ };
+
+ int row = ofun & SMB_OFUN_OPEN_MASK;
+ int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
+
+ if (row == 3)
+ return ((uint32_t)SMB_INVALID_CRDISPOSITION);
+
+ return (ofun_cr_map[row][col]);
+}
+
+/*
+ * smb_open_share_check
+ *
+ * check file sharing rules for current open request
+ * against the given existing open.
+ *
+ * Returns NT_STATUS_SHARING_VIOLATION if there is any
+ * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
+ */
+uint32_t
+smb_open_share_check(struct smb_request *sr,
+ struct smb_node *node,
+ struct smb_ofile *open)
+{
+ uint32_t desired_access;
+ uint32_t share_access;
+
+ desired_access = sr->arg.open.desired_access;
+ share_access = sr->arg.open.share_access;
+
+ /*
+ * As far as I can tell share modes are not relevant to
+ * directories. The check for exclusive access (Deny RW)
+ * remains because I don't know whether or not it was here
+ * for a reason.
+ */
+ if (node->attr.sa_vattr.va_type == VDIR) {
+ if (DENY_RW(open->f_share_access) &&
+ (node->n_orig_uid != crgetuid(sr->user_cr))) {
+ return (NT_STATUS_SHARING_VIOLATION);
+ }
+
+ return (NT_STATUS_SUCCESS);
+ }
+
+ /* if it's just meta data */
+ if ((open->f_granted_access & FILE_DATA_ALL) == 0)
+ return (NT_STATUS_SUCCESS);
+
+ /*
+ * Check requested share access against the
+ * open granted (desired) access
+ */
+ if (DENY_DELETE(share_access) && (open->f_granted_access & DELETE))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ if (DENY_READ(share_access) &&
+ (open->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE)))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ if (DENY_WRITE(share_access) &&
+ (open->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ /* check requested desired access against the open share access */
+ if (DENY_DELETE(open->f_share_access) && (desired_access & DELETE))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ if (DENY_READ(open->f_share_access) &&
+ (desired_access & (FILE_READ_DATA | FILE_EXECUTE)))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ if (DENY_WRITE(open->f_share_access) &&
+ (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_file_share_check
+ *
+ * check file sharing rules for current open request
+ * against all existing opens for a file.
+ *
+ * Returns NT_STATUS_SHARING_VIOLATION if there is any
+ * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
+ */
+uint32_t
+smb_file_share_check(struct smb_request *sr, struct smb_node *node)
+{
+ struct smb_ofile *open;
+ uint32_t status;
+
+ if (node == 0 || node->n_refcnt <= 1)
+ return (NT_STATUS_SUCCESS);
+
+ /* if it's just meta data */
+ if ((sr->arg.open.desired_access & FILE_DATA_ALL) == 0)
+ return (NT_STATUS_SUCCESS);
+
+ smb_llist_enter(&node->n_ofile_list, RW_READER);
+ open = smb_llist_head(&node->n_ofile_list);
+ while (open) {
+ status = smb_open_share_check(sr, node, open);
+ if (status == NT_STATUS_SHARING_VIOLATION) {
+ smb_llist_exit(&node->n_ofile_list);
+ return (status);
+ }
+ open = smb_llist_next(&node->n_ofile_list, open);
+ }
+ smb_llist_exit(&node->n_ofile_list);
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_amask_to_amode
+ * Converts specific read/write access rights of access mask to access
+ * mode flags.
+ */
+int
+smb_amask_to_amode(unsigned long amask)
+{
+ if ((amask & FILE_READ_DATA) &&
+ (amask & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
+ return (O_RDWR);
+
+ if (amask & (FILE_WRITE_DATA | FILE_APPEND_DATA))
+ return (O_WRONLY);
+
+ return (O_RDONLY);
+}
+
+/*
+ * smb_open_subr
+ *
+ * Notes on write-through behaviour. It looks like pre-LM0.12 versions
+ * of the protocol specify the write-through mode when a file is opened,
+ * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose,
+ * SmbWriteAndUnlock) don't need to contain a write-through flag.
+ *
+ * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate)
+ * don't indicate which write-through mode to use. Instead the write
+ * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call
+ * basis.
+ *
+ * We don't care which open call was used to get us here, we just need
+ * to ensure that the write-through mode flag is copied from the open
+ * parameters to the node. We test the omode write-through flag in all
+ * write functions.
+ *
+ * This function will return NT status codes but it also raises errors,
+ * in which case it won't return to the caller. Be careful how you
+ * handle things in here.
+ */
+uint32_t
+smb_open_subr(struct smb_request *sr)
+{
+ int created = 0;
+ struct smb_node *node = 0;
+ struct smb_node *dnode = 0;
+ struct smb_node *cur_node;
+ struct open_param *op = &sr->arg.open;
+ int rc;
+ struct smb_ofile *of;
+ smb_attr_t new_attr;
+ int pathlen;
+ int max_requested = 0;
+ uint32_t max_allowed;
+ unsigned int granted_oplock;
+ uint32_t status = NT_STATUS_SUCCESS;
+ int is_dir;
+ smb_error_t err;
+ int is_stream;
+ int lookup_flags = SMB_FOLLOW_LINKS;
+ uint32_t daccess;
+
+ is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
+
+ if (is_dir) {
+ /*
+ * The file being created or opened is a directory file.
+ * With this flag, the Disposition parameter must be set to
+ * one of FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF
+ */
+ if ((op->create_disposition != FILE_CREATE) &&
+ (op->create_disposition != FILE_OPEN_IF) &&
+ (op->create_disposition != FILE_OPEN)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_ACCESS);
+ /* invalid open mode */
+ /* NOTREACHED */
+ }
+ }
+
+ if (op->desired_access & MAXIMUM_ALLOWED) {
+ max_requested = 1;
+ op->desired_access &= ~MAXIMUM_ALLOWED;
+ }
+ op->desired_access = smb_access_generic_to_file(op->desired_access);
+
+ if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) {
+
+ ASSERT(sr->uid_user);
+ cmn_err(CE_NOTE, "smbd[%s\\%s]: %s", sr->uid_user->u_domain,
+ sr->uid_user->u_name,
+ xlate_nt_status(NT_STATUS_TOO_MANY_OPENED_FILES));
+
+ smbsr_raise_cifs_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
+ ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
+ /* NOTREACHED */
+ }
+
+ /* This must be NULL at this point */
+ sr->fid_ofile = NULL;
+
+ op->devstate = 0;
+
+ switch (sr->tid_tree->t_res_type & STYPE_MASK) {
+ case STYPE_DISKTREE:
+ break;
+
+ case STYPE_IPC:
+ /*
+ * No further processing for IPC, we need to either
+ * raise an exception or return success here.
+ */
+ if ((rc = smb_rpc_open(sr)) != 0) {
+ smbsr_raise_nt_error(sr, rc);
+ /* NOTREACHED */
+ } else {
+ return (NT_STATUS_SUCCESS);
+ }
+ break;
+
+ default:
+ smbsr_raise_error(sr, ERRSRV, ERRinvdevice);
+ /* NOTREACHED */
+ break;
+ }
+
+ if ((pathlen = strlen(op->fqi.path)) >= MAXPATHLEN) {
+ smbsr_raise_error(sr, ERRSRV, ERRfilespecs);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Some clients pass null file names; NT interprets this as "\".
+ */
+ if (pathlen == 0) {
+ op->fqi.path = "\\";
+ pathlen = 1;
+ }
+
+ op->fqi.srch_attr = op->fqi.srch_attr;
+
+ if ((status = smb_validate_object_name(op->fqi.path, is_dir)) != 0) {
+ smbsr_raise_cifs_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
+ /* NOTREACHED */
+ }
+
+ cur_node = op->fqi.dir_snode ?
+ op->fqi.dir_snode : sr->tid_tree->t_snode;
+
+ if (rc = smb_pathname_reduce(sr, sr->user_cr, op->fqi.path,
+ sr->tid_tree->t_snode, cur_node, &op->fqi.dir_snode,
+ op->fqi.last_comp)) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ /*
+ * If the access mask has only DELETE set (ignore
+ * FILE_READ_ATTRIBUTES), then assume that this
+ * is a request to delete the link (if a link)
+ * and do not follow links. Otherwise, follow
+ * the link to the target.
+ */
+
+ daccess = op->desired_access & ~FILE_READ_ATTRIBUTES;
+
+ if (daccess == DELETE)
+ lookup_flags &= ~SMB_FOLLOW_LINKS;
+
+ rc = smb_fsop_lookup_name(sr, kcred, lookup_flags,
+ sr->tid_tree->t_snode, op->fqi.dir_snode, op->fqi.last_comp,
+ &op->fqi.last_snode, &op->fqi.last_attr);
+
+ if (rc == 0) {
+ op->fqi.last_comp_was_found = 1;
+ (void) strcpy(op->fqi.last_comp_od,
+ op->fqi.last_snode->od_name);
+ } else if (rc == ENOENT) {
+ op->fqi.last_comp_was_found = 0;
+ op->fqi.last_snode = NULL;
+ rc = 0;
+ } else {
+ smb_node_release(op->fqi.dir_snode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (op->fqi.last_comp_was_found) {
+ node = op->fqi.last_snode;
+ dnode = op->fqi.dir_snode;
+
+ /*
+ * Reject this request if the target is a directory
+ * and the client has specified that it must not be
+ * a directory (required by Lotus Notes).
+ */
+ if ((op->create_options & FILE_NON_DIRECTORY_FILE) &&
+ (op->fqi.last_attr.sa_vattr.va_type == VDIR)) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_FILE_IS_A_DIRECTORY,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
+ if ((sr->smb_com == SMB_COM_OPEN_ANDX) ||
+ (sr->smb_com == SMB_COM_OPEN)) {
+ /*
+ * Directories cannot be opened
+ * with the above commands
+ */
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_FILE_IS_A_DIRECTORY,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+ } else if (op->my_flags & MYF_MUST_BE_DIRECTORY) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr, NT_STATUS_NOT_A_DIRECTORY,
+ ERRDOS, ERROR_DIRECTORY);
+ /* NOTREACHED */
+ }
+
+ /*
+ * No more open should be accepted when "Delete on close"
+ * flag is set.
+ */
+ if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr, NT_STATUS_DELETE_PENDING,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Specified file already exists so the operation should fail.
+ */
+ if (op->create_disposition == FILE_CREATE) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_OBJECT_NAME_COLLISION, ERRDOS,
+ ERROR_ALREADY_EXISTS);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Windows seems to check read-only access before file
+ * sharing check.
+ */
+ if (NODE_IS_READONLY(node)) {
+ /* Files data only */
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ if (op->desired_access & (FILE_WRITE_DATA |
+ FILE_APPEND_DATA)) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_error(sr, ERRDOS,
+ ERRnoaccess);
+ /* NOTREACHED */
+ }
+ }
+ }
+
+ status = smb_file_share_check(sr, node);
+ if (status == NT_STATUS_SHARING_VIOLATION) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ return (status);
+ }
+
+ status = smb_fsop_access(sr, sr->user_cr, node,
+ op->desired_access);
+
+ if (status != NT_STATUS_SUCCESS) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
+ smbsr_raise_cifs_error(sr,
+ status,
+ ERRDOS,
+ ERROR_PRIVILEGE_NOT_HELD);
+ } else {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_ACCESS_DENIED,
+ ERRDOS,
+ ERROR_ACCESS_DENIED);
+ }
+ }
+
+ /*
+ * Break the oplock before share checks. If another client
+ * has the file open, this will force a flush or close,
+ * which may affect the outcome of any share checking.
+ */
+ if (OPLOCKS_IN_FORCE(node)) {
+ status = smb_break_oplock(sr, node);
+
+ if (status != NT_STATUS_SUCCESS) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr, status,
+ ERRDOS, ERROR_VC_DISCONNECTED);
+ /* NOTREACHED */
+ }
+ }
+
+ switch (op->create_disposition) {
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE_IF:
+ case FILE_OVERWRITE:
+ if (node->attr.sa_vattr.va_type == VDIR) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_ACCESS_DENIED, ERRDOS,
+ ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (node->attr.sa_vattr.va_size != op->dsize) {
+ node->flags &= ~NODE_FLAGS_SET_SIZE;
+ new_attr.sa_vattr.va_size = op->dsize;
+ new_attr.sa_mask = SMB_AT_SIZE;
+ if ((rc = smb_fsop_setattr(sr, sr->user_cr,
+ (&op->fqi)->last_snode, &new_attr,
+ &op->fqi.last_attr)) != 0) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ }
+
+ /*
+ * If file is being replaced,
+ * we should remove existing streams
+ */
+ if (SMB_IS_STREAM(node) == 0)
+ (void) smb_fsop_remove_streams(sr, sr->user_cr,
+ node);
+
+ op->action_taken = SMB_OACT_TRUNCATED;
+ break;
+
+ default:
+ /*
+ * FILE_OPEN or FILE_OPEN_IF.
+ */
+ op->action_taken = SMB_OACT_OPENED;
+ break;
+ }
+ } else {
+
+ /* Last component was not found. */
+ dnode = op->fqi.dir_snode;
+
+ if ((op->create_disposition == FILE_OPEN) ||
+ (op->create_disposition == FILE_OVERWRITE)) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+
+ is_stream = smb_stream_parse_name(op->fqi.path,
+ NULL, NULL);
+ /*
+ * The requested file not found so the operation should
+ * fail with these two dispositions
+ */
+ if (is_stream)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ else
+ smbsr_raise_error(sr, ERRDOS, ERRbadfile);
+ /* NOTREACHED */
+ }
+
+ /*
+ * lock the parent dir node in case another create
+ * request to the same parent directory comes in.
+ */
+ smb_rwx_rwenter(&dnode->n_lock, RW_WRITER);
+
+ bzero(&new_attr, sizeof (new_attr));
+ if (is_dir == 0) {
+ new_attr.sa_vattr.va_type = VREG;
+ new_attr.sa_vattr.va_mode = 0666;
+ new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE;
+ rc = smb_fsop_create(sr, sr->user_cr, dnode,
+ op->fqi.last_comp, &new_attr,
+ &op->fqi.last_snode, &op->fqi.last_attr);
+ if (rc != 0) {
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (op->dsize) {
+ new_attr.sa_vattr.va_size = op->dsize;
+ new_attr.sa_mask = SMB_AT_SIZE;
+ rc = smb_fsop_setattr(sr, sr->user_cr,
+ op->fqi.last_snode, &new_attr,
+ &op->fqi.last_attr);
+ if (rc != 0) {
+ smb_node_release(op->fqi.last_snode);
+ (void) smb_fsop_remove(sr, sr->user_cr,
+ dnode, op->fqi.last_comp, 0);
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ }
+
+ } else {
+ op->dattr |= SMB_FA_DIRECTORY;
+ new_attr.sa_vattr.va_type = VDIR;
+ new_attr.sa_vattr.va_mode = 0777;
+ new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE;
+ rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
+ op->fqi.last_comp, &new_attr,
+ &op->fqi.last_snode, &op->fqi.last_attr);
+ if (rc != 0) {
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ }
+
+ created = 1;
+ op->action_taken = SMB_OACT_CREATED;
+ }
+
+ if (node == 0) {
+ node = op->fqi.last_snode;
+ }
+
+ if ((op->fqi.last_attr.sa_vattr.va_type != VREG) &&
+ (op->fqi.last_attr.sa_vattr.va_type != VDIR) &&
+ (op->fqi.last_attr.sa_vattr.va_type != VLNK)) {
+ /* not allowed to do this */
+ SMB_DEL_NEWOBJ(op->fqi);
+ smb_node_release(node);
+ if (created)
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ if (max_requested) {
+ smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed);
+ op->desired_access |= max_allowed;
+ }
+
+ /*
+ * smb_ofile_open() will copy node to of->node. Hence
+ * the hold on node (i.e. op->fqi.last_snode) will be "transferred"
+ * to the "of" structure.
+ */
+
+ of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op->desired_access,
+ op->create_options, op->share_access, SMB_FTYPE_DISK, NULL, 0,
+ &err);
+
+ if (of == NULL) {
+ SMB_DEL_NEWOBJ(op->fqi);
+ smb_node_release(node);
+ if (created)
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr, err.status, err.errcls, err.errcode);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Propagate the write-through mode from the open params
+ * to the node: see the notes in the function header.
+ *
+ * IR #102318 Mirroring may force synchronous
+ * writes regardless of what we specify here.
+ */
+ if (smb_stable_mode || (op->create_options & FILE_WRITE_THROUGH))
+ node->flags |= NODE_FLAGS_WRITE_THROUGH;
+
+ op->fileid = op->fqi.last_attr.sa_vattr.va_nodeid;
+
+ if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
+ /* We don't oplock directories */
+ op->my_flags &= ~MYF_OPLOCK_MASK;
+ op->dsize = 0;
+ } else {
+ status = smb_acquire_oplock(sr, of, op->my_flags,
+ &granted_oplock);
+ op->my_flags &= ~MYF_OPLOCK_MASK;
+
+ if (status != NT_STATUS_SUCCESS) {
+ (void) smb_ofile_close(of, 0);
+ smb_ofile_release(of);
+ if (created)
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+
+ smbsr_raise_cifs_error(sr, status,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ }
+
+ op->my_flags |= granted_oplock;
+ op->dsize = op->fqi.last_attr.sa_vattr.va_size;
+ }
+
+ if (created) {
+ node->flags |= NODE_FLAGS_CREATED;
+ /*
+ * Clients may set the DOS readonly bit on create but they
+ * expect subsequent write operations on the open fid to
+ * succeed. Thus the DOS readonly bit is not set until the
+ * file is closed. The NODE_CREATED_READONLY flag will
+ * inhibit other attempts to open the file with write access
+ * and act as the indicator to set the DOS readonly bit on
+ * close.
+ */
+ if (op->dattr & SMB_FA_READONLY) {
+ node->flags |= NODE_CREATED_READONLY;
+ op->dattr &= ~SMB_FA_READONLY;
+ }
+ smb_node_set_dosattr(node, op->dattr | SMB_FA_ARCHIVE);
+ if (op->utime.tv_sec == 0 || op->utime.tv_sec == 0xffffffff)
+ (void) microtime(&op->utime);
+ smb_node_set_time(node, NULL, &op->utime, 0, 0, SMB_AT_MTIME);
+ (void) smb_sync_fsattr(sr, sr->user_cr, node);
+ } else {
+ /*
+ * If we reach here, it means that file already exists
+ * and if create disposition is one of: FILE_SUPERSEDE,
+ * FILE_OVERWRITE_IF, or FILE_OVERWRITE it
+ * means that client wants to overwrite (or truncate)
+ * the existing file. So we should overwrite the dos
+ * attributes of destination file with the dos attributes
+ * of source file.
+ */
+
+ switch (op->create_disposition) {
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE_IF:
+ case FILE_OVERWRITE:
+ smb_node_set_dosattr(node,
+ op->dattr | SMB_FA_ARCHIVE);
+ (void) smb_sync_fsattr(sr, sr->user_cr, node);
+ }
+ op->utime = *smb_node_get_crtime(node);
+ op->dattr = smb_node_get_dosattr(node);
+ }
+
+ /*
+ * Set up the file type in open_param for the response
+ */
+ op->ftype = SMB_FTYPE_DISK;
+ sr->smb_fid = of->f_fid;
+ sr->fid_ofile = of;
+
+ if (created) {
+ smb_rwx_rwexit(&dnode->n_lock);
+ }
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_validate_object_name
+ *
+ * Very basic file name validation. Directory validation is handed off
+ * to smb_validate_dirname. For filenames, we check for names of the
+ * form "AAAn:". Names that contain three characters, a single digit
+ * and a colon (:) are reserved as DOS device names, i.e. "COM1:".
+ *
+ * Returns NT status codes.
+ */
+uint32_t
+smb_validate_object_name(char *path, unsigned int ftype)
+{
+ char *filename;
+
+ if (path == 0)
+ return (0);
+
+ if (ftype)
+ return (smb_validate_dirname(path));
+
+ /*
+ * Basename with backslashes.
+ */
+ if ((filename = strrchr(path, '\\')) != 0)
+ ++filename;
+ else
+ filename = path;
+
+ if (strlen(filename) == 5 &&
+ mts_isdigit(filename[3]) &&
+ filename[4] == ':') {
+ return (NT_STATUS_OBJECT_NAME_INVALID);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_preset_delete_on_close
+ *
+ * Set the DeleteOnClose flag on the smb file. When the file is closed,
+ * the flag will be transferred to the smb node, which will commit the
+ * delete operation and inhibit subsequent open requests.
+ *
+ * When DeleteOnClose is set on an smb_node, the common open code will
+ * reject subsequent open requests for the file. Observation of Windows
+ * 2000 indicates that subsequent opens should be allowed (assuming
+ * there would be no sharing violation) until the file is closed using
+ * the fid on which the DeleteOnClose was requested.
+ */
+void
+smb_preset_delete_on_close(smb_ofile_t *file)
+{
+ mutex_enter(&file->f_mutex);
+ file->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
+ mutex_exit(&file->f_mutex);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_search.c b/usr/src/uts/common/fs/smbsrv/smb_common_search.c
new file mode 100644
index 0000000000..a17555669b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_search.c
@@ -0,0 +1,344 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Implementation of smb_rdir_open, smb_rdir_next and smb_rdir_close.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+/*
+ * smb_rdir_open
+ */
+int
+smb_rdir_open(smb_request_t *sr, char *path, unsigned short sattr)
+{
+ smb_odir_t *od;
+ smb_node_t *node;
+ char *last_component;
+ smb_session_t *session = sr->session;
+ unsigned int rc;
+ int erc;
+
+ last_component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode,
+ &node, last_component)) != 0) {
+ kmem_free(last_component, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((node->vp)->v_type != VDIR) {
+ smb_node_release(node);
+ kmem_free(last_component, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRbadpath);
+ /* NOTREACHED */
+ }
+
+ erc = smb_fsop_access(sr, sr->user_cr, node, FILE_LIST_DIRECTORY);
+ if (erc != 0) {
+ smb_node_release(node);
+ kmem_free(last_component, MAXNAMELEN);
+ if (sr->smb_com == SMB_COM_SEARCH) {
+ if (session->capabilities & CAP_STATUS32) {
+ smbsr_setup_nt_status(sr,
+ ERROR_SEVERITY_WARNING,
+ NT_STATUS_NO_MORE_FILES);
+ return (SDRC_NORMAL_REPLY);
+ } else {
+ smbsr_raise_error(sr,
+ ERRDOS, ERROR_NO_MORE_FILES);
+ /* NOTREACHED */
+ }
+ } else {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+ }
+
+ od = smb_odir_open(sr->tid_tree, node, last_component, sr->smb_pid,
+ sattr);
+ kmem_free(last_component, sizeof (od->d_pattern));
+ if (od == NULL) {
+ smb_node_release(node);
+ smbsr_raise_error(sr, ERRDOS, ERROR_NO_MORE_FILES);
+ /* NOTREACHED */
+ }
+
+ sr->smb_sid = od->d_sid;
+ sr->sid_odir = od;
+
+ return (-1);
+}
+
+
+/*
+ * smb_rdir_next
+ *
+ * Returns:
+ * 0 Found an entry
+ * ENOENT There is no (more) entry
+ * error code An error happened
+ */
+int
+smb_rdir_next(
+ smb_request_t *sr,
+ smb_node_t **rnode,
+ smb_odir_context_t *pc)
+{
+ struct smb_odir *dir;
+ ino64_t fileid;
+ int rc, n_name;
+ char last_component[MAXNAMELEN];
+ char namebuf[MAXNAMELEN];
+ smb_node_t *tmp_snode;
+ smb_node_t *dnode;
+ smb_node_t *fnode;
+ smb_attr_t ret_attr;
+
+ ASSERT(sr->sid_odir);
+ dir = sr->sid_odir;
+
+ if (dir->d_state == SMB_ODIR_STATE_CLOSED) {
+ return (ENOENT);
+ }
+
+ if (dir->d_wildcards == 0) {
+ /* There are no wildcards in pattern */
+ if (pc->dc_cookie != 0) {
+ /* Already found entry... */
+ return (ENOENT);
+ }
+
+ pc->dc_name[0] = '\0';
+ pc->dc_shortname[0] = '\0';
+ pc->dc_name83[0] = '\0';
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, 0,
+ sr->tid_tree->t_snode, dir->d_dir_snode, dir->d_pattern,
+ &fnode, &pc->dc_attr, pc->dc_shortname, pc->dc_name83);
+
+ if (rc != 0)
+ return (rc);
+
+ /*
+ * We are here if there was a successful lookup of the
+ * name. The name may be a mangled name. If it was,
+ * then shortname has the copy of it. So, we may
+ * not need to do mangling later.
+ *
+ * dir->name will contain the case-preserved name.
+ * If that name is not available (this should not
+ * happen), then copy dir->pattern into dir->name.
+ */
+
+ if (fnode->od_name) {
+ (void) strcpy(pc->dc_name, fnode->od_name);
+ } else {
+ (void) strcpy(pc->dc_name, dir->d_pattern);
+ }
+
+ /* Root of file system? */
+ if ((strcmp(dir->d_pattern, "..") == 0) &&
+ (dir->d_dir_snode == sr->tid_tree->t_snode)) {
+ smb_node_release(fnode);
+ smb_node_ref(sr->tid_tree->t_snode);
+ fnode = sr->tid_tree->t_snode;
+ } else if (pc->dc_attr.sa_vattr.va_type == VLNK) {
+ (void) strcpy(namebuf, dir->d_pattern);
+
+ tmp_snode = fnode;
+ rc = smb_pathname_reduce(sr, sr->user_cr, namebuf,
+ sr->tid_tree->t_snode, dir->d_dir_snode,
+ &dnode, last_component);
+
+ if (rc != 0) {
+ fnode = tmp_snode;
+ } else {
+ rc = smb_fsop_lookup(sr, sr->user_cr,
+ SMB_FOLLOW_LINKS, sr->tid_tree->t_snode,
+ dnode, last_component, &fnode, &ret_attr,
+ 0, 0);
+
+ smb_node_release(dnode);
+ if (rc != 0) {
+ fnode = tmp_snode;
+ } else {
+ pc->dc_attr = ret_attr;
+ smb_node_release(tmp_snode);
+ }
+ }
+ }
+
+ pc->dc_dattr = smb_node_get_dosattr(fnode);
+ /*
+ * If name not already mangled, do it.
+ *
+ * The name will only be mangled if smb_needs_mangle()
+ * determines that it is required. Mangling due to
+ * case-insensitive collisions is not necessary here.
+ */
+ if (pc->dc_name83[0] == '\0')
+ (void) smb_mangle_name(fnode->attr.sa_vattr.va_nodeid,
+ pc->dc_name, pc->dc_shortname, pc->dc_name83, 0);
+ if (rnode)
+ *rnode = fnode;
+ else
+ smb_node_release(fnode);
+
+ pc->dc_cookie = (uint32_t)-1;
+ return (0);
+ } /* No wild card search */
+
+ for (;;) {
+ if (dir->d_state == SMB_ODIR_STATE_CLOSED) {
+ return (ENOENT);
+ }
+
+ /* sizeof dir->name == 256 */
+ n_name = (sizeof (pc->dc_name)) - 1;
+
+ rc = smb_fsop_readdir(sr, sr->user_cr, dir->d_dir_snode,
+ &pc->dc_cookie, pc->dc_name, &n_name, &fileid, NULL,
+ NULL, NULL);
+ if (rc != 0) {
+ return (rc);
+ }
+
+ if (n_name == 0) /* EOF */
+ break;
+ pc->dc_name[n_name] = '\0';
+
+ /*
+ * Don't return "." or ".." unless SMB_FA_HIDDEN bit is set
+ * We have to code these specially since we cannot set the
+ * SMB_FA_HIDDEN bits in these because they are simply links to
+ * the real directory and the real directory is NOT hidden.
+ */
+ if (((dir->d_sattr & SMB_FA_HIDDEN) == 0) &&
+ ((strcmp(pc->dc_name, ".") == 0) ||
+ ((strcmp(pc->dc_name, "..") == 0)))) {
+ continue;
+ }
+
+ /* may match a mangled name or "real" name */
+ if (smb_component_match(sr, fileid, dir, pc) <= 0)
+ continue;
+
+ /* Look up the "real" name */
+ rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
+ dir->d_dir_snode, pc->dc_name, &fnode, &pc->dc_attr, 0, 0);
+
+ if (rc != 0) {
+ if (rc != ENOENT) {
+ return (rc);
+ }
+ else
+ continue;
+ /* NOTREACHED */
+ }
+
+ /* Root of file system? */
+ if ((strcmp(pc->dc_name, "..") == 0) &&
+ (dir->d_dir_snode == sr->tid_tree->t_snode)) {
+ smb_node_release(fnode);
+ smb_node_ref(sr->tid_tree->t_snode);
+ fnode = sr->tid_tree->t_snode;
+ } else if (pc->dc_attr.sa_vattr.va_type == VLNK) {
+ (void) strcpy(namebuf, pc->dc_name);
+
+ smb_node_release(fnode);
+ rc = smb_pathname_reduce(sr, sr->user_cr, namebuf,
+ sr->tid_tree->t_snode, dir->d_dir_snode, &dnode,
+ last_component);
+
+ if (rc != 0) {
+ continue;
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dnode, last_component,
+ &fnode, &ret_attr, 0, 0);
+
+ smb_node_release(dnode);
+ if (rc != 0) {
+ continue;
+ }
+ pc->dc_attr = ret_attr;
+ }
+
+ pc->dc_dattr = smb_node_get_dosattr(fnode);
+
+ /* Obey search attributes */
+ if ((pc->dc_dattr & SMB_FA_DIRECTORY) &&
+ !(dir->d_sattr & SMB_FA_DIRECTORY)) {
+ smb_node_release(fnode);
+ continue;
+ }
+
+ if ((pc->dc_dattr & SMB_FA_HIDDEN) &&
+ !(dir->d_sattr & SMB_FA_HIDDEN)) {
+ smb_node_release(fnode);
+ continue;
+ }
+
+ if ((pc->dc_dattr & SMB_FA_SYSTEM) &&
+ !(dir->d_sattr & SMB_FA_SYSTEM)) {
+ smb_node_release(fnode);
+ continue;
+ }
+
+ if (rnode)
+ *rnode = fnode;
+ else
+ smb_node_release(fnode);
+
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+/*
+ * smb_rdir_close
+ */
+void
+smb_rdir_close(struct smb_request *sr)
+{
+ smb_odir_t *od = sr->sid_odir;
+
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+ smb_odir_close(od);
+ smb_odir_release(od);
+ sr->sid_odir = NULL;
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
new file mode 100644
index 0000000000..2558716c5e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
@@ -0,0 +1,2485 @@
+/*
+ * 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.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/oem.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/mailslot.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/nterror.h>
+
+extern int smb_maxbufsize;
+
+#define MAX_SHARE_NAME_LEN 13
+#define SHARE_INFO_1_SIZE (MAX_SHARE_NAME_LEN + sizeof (char) + \
+ sizeof (short) + sizeof (uint32_t))
+
+/*
+ * count of bytes in server response packet
+ * except parameters and data. Note that setup
+ * word count is zero.
+ */
+#define RESP_HEADER_LEN 24
+
+/*
+ * NB. I started by using common functions for transaction/transaction2
+ * and transaction_secondary/transaction2_secondary because they
+ * are respectively so similar. However, it turned out to be a bad
+ * idea because of quirky differences. Be sure if you modify one
+ * of these four functions to check and see if the modification should
+ * be applied to its peer.
+ */
+
+int smb_trans_ready(struct smb_xa *xa);
+int smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa);
+int smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa);
+int smb_trans2_find(struct smb_request *sr, struct smb_xa *xa, int opcode);
+int smb_trans2_query_fs_info(struct smb_request *sr, struct smb_xa *xa);
+
+
+int smb_nt_transact_query_quota(struct smb_request *sr, struct smb_xa *xa);
+
+int
+smb_com_transaction(struct smb_request *sr)
+{
+ int rc;
+ unsigned char msrcnt, suwcnt;
+ uint16_t tpscnt, tdscnt, mprcnt, mdrcnt, flags;
+ uint16_t pscnt, psoff, dscnt, dsoff;
+ uint32_t timeo;
+ struct smb_xa *xa;
+ char *stn;
+ int ready;
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT,
+ &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &msrcnt, &flags,
+ &timeo, &pscnt, &psoff, &dscnt, &dsoff, &suwcnt);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
+ msrcnt, suwcnt);
+ if (xa == NULL) {
+ smbsr_raise_error(sr, ERRSRV, ERRnoroom);
+ /* NOTREACHED */
+ }
+
+ /* Should be some alignment stuff here in SMB? */
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) {
+ rc = smbsr_decode_data(sr, "%.U", sr, &stn);
+ } else {
+ rc = smbsr_decode_data(sr, "%s", sr, &stn);
+ }
+ if (rc != 0) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ xa->xa_smb_trans_name = MEM_STRDUP("smb", stn);
+
+ xa->smb_flags = flags;
+ xa->smb_timeout = timeo;
+ xa->req_disp_param = pscnt;
+ xa->req_disp_data = dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
+ sr->smb_vwv.chain_offset, suwcnt * 2)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ ready = smb_trans_ready(xa);
+
+ if (smb_xa_open(xa)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRsrverror);
+ /* NOTREACHED */
+ }
+ sr->r_xa = xa;
+
+ if (!ready) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (!smb_xa_complete(xa)) {
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ return (smb_trans_dispatch(sr, xa));
+}
+
+
+int
+smb_com_transaction_secondary(struct smb_request *sr)
+{
+ uint16_t tpscnt, tdscnt, pscnt, psdisp;
+ uint16_t dscnt, dsoff, dsdisp, psoff;
+ smb_xa_t *xa;
+ int rc;
+
+ if ((xa = smbsr_lookup_xa(sr)) == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRsrverror);
+ /* NOTREACHED */
+ }
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
+ if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ if (xa->smb_com != SMB_COM_TRANSACTION) {
+ return (SDRC_DROP_VC);
+ }
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANSSHDR_ED_FMT, &tpscnt, &tdscnt,
+ &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ mutex_enter(&xa->xa_mutex);
+ xa->smb_tpscnt = tpscnt; /* might have shrunk */
+ xa->smb_tdscnt = tdscnt; /* might have shrunk */
+ xa->req_disp_param = psdisp+pscnt;
+ xa->req_disp_data = dsdisp+dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ mutex_exit(&xa->xa_mutex);
+
+ if (!smb_trans_ready(xa))
+ return (SDRC_NO_REPLY);
+
+ if (!smb_xa_complete(xa))
+ return (SDRC_NO_REPLY);
+
+ return (smb_trans_dispatch(sr, xa));
+}
+
+
+int
+smb_com_ioctl(struct smb_request *sr)
+{
+ uint16_t fid, category, function, tpscnt, tdscnt, mprcnt;
+ uint16_t mdrcnt, pscnt, pdoff, dscnt, dsoff;
+ uint32_t timeout;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, "wwwwwwwl2.wwww", &fid, &category, &function,
+ &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &timeout, &pscnt,
+ &pdoff, &dscnt, &dsoff);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+int /*ARGSUSED*/
+smb_com_ioctl_secondary(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+int
+smb_com_transaction2(struct smb_request *sr)
+{
+ unsigned char msrcnt, suwcnt;
+ uint16_t tpscnt, tdscnt, mprcnt, mdrcnt, flags;
+ uint16_t pscnt, psoff, dscnt, dsoff;
+ uint32_t timeo;
+ smb_xa_t *xa;
+ int ready;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT, &tpscnt, &tdscnt,
+ &mprcnt, &mdrcnt, &msrcnt, &flags, &timeo, &pscnt, &psoff, &dscnt,
+ &dsoff, &suwcnt);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
+ msrcnt, suwcnt);
+ if (xa == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRnoroom);
+ /* NOTREACHED */
+ }
+
+ xa->smb_flags = flags;
+ xa->smb_timeout = timeo;
+ xa->req_disp_param = pscnt;
+ xa->req_disp_data = dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
+ sr->smb_vwv.chain_offset, suwcnt*2)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ ready = smb_trans_ready(xa);
+
+ if (smb_xa_open(xa)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRsrverror);
+ /* NOTREACHED */
+ }
+ sr->r_xa = xa;
+
+ if (!ready) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (!smb_xa_complete(xa)) {
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ return (smb_trans2_dispatch(sr, xa));
+}
+
+
+int
+smb_com_transaction2_secondary(struct smb_request *sr)
+{
+ uint16_t tpscnt, tdscnt, fid;
+ uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
+ smb_xa_t *xa;
+ int rc;
+
+ if ((xa = smbsr_lookup_xa(sr)) == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRsrverror);
+ /* NOTREACHED */
+ }
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
+ if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ if (xa->smb_com != SMB_COM_TRANSACTION2) {
+ return (SDRC_DROP_VC);
+ }
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
+ &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ mutex_enter(&xa->xa_mutex);
+ xa->smb_tpscnt = tpscnt; /* might have shrunk */
+ xa->smb_tdscnt = tdscnt; /* might have shrunk */
+ xa->xa_smb_fid = fid; /* overwrite rules? */
+ xa->req_disp_param = psdisp + pscnt;
+ xa->req_disp_data = dsdisp + dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ mutex_exit(&xa->xa_mutex);
+
+ if (!smb_trans_ready(xa))
+ return (SDRC_NO_REPLY);
+
+ if (!smb_xa_complete(xa))
+ return (SDRC_NO_REPLY);
+
+ return (smb_trans2_dispatch(sr, xa));
+}
+
+static int
+smb_nt_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+
+ n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
+ n_setup++;
+ n_setup = n_setup & ~0x0001;
+ n_param = (xa->smb_mprcnt < smb_maxbufsize)
+ ? xa->smb_mprcnt : smb_maxbufsize;
+ n_param++;
+ n_param = n_param & ~0x0001;
+ rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
+ n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
+ MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
+ MBC_INIT(&xa->rep_param_mb, n_param);
+ MBC_INIT(&xa->rep_data_mb, n_data);
+
+ switch (xa->smb_func) {
+ case NT_TRANSACT_CREATE:
+ rc = smb_nt_transact_create(sr, xa);
+ break;
+ case NT_TRANSACT_NOTIFY_CHANGE:
+ rc = smb_nt_transact_notify_change(sr, xa);
+ break;
+ case NT_TRANSACT_QUERY_SECURITY_DESC:
+ rc = smb_nt_transact_query_security_info(sr, xa);
+ break;
+ case NT_TRANSACT_SET_SECURITY_DESC:
+ rc = smb_nt_transact_set_security_info(sr, xa);
+ break;
+ case NT_TRANSACT_IOCTL:
+ rc = smb_nt_transact_ioctl(sr, xa);
+ break;
+
+ case NT_TRANSACT_QUERY_QUOTA:
+ (void) smb_nt_transact_query_quota(sr, xa);
+ smbsr_raise_error(sr, ERRSRV, ERRaccess);
+ /* NOTREACHED */
+
+ case NT_TRANSACT_SET_QUOTA:
+ smbsr_raise_error(sr, ERRSRV, ERRaccess);
+ /* NOTREACHED */
+
+ default:
+ smbsr_raise_error(sr, ERRSRV, ERRsmbcmd);
+ /* NOTREACHED */
+ }
+
+ switch (rc) {
+ case SDRC_NORMAL_REPLY:
+ break;
+
+ case SDRC_DROP_VC:
+ case SDRC_NO_REPLY:
+ case SDRC_ERROR_REPLY:
+ return (rc);
+
+ case SDRC_UNIMPLEMENTED:
+ case SDRC_UNSUPPORTED:
+ smbsr_raise_error(sr, ERRSRV, ERRsmbcmd);
+ /* NOTREACHED */
+
+ default:
+ break;
+ }
+
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&xa->rep_param_mb);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ if (xa->smb_msrcnt < n_setup ||
+ xa->smb_mprcnt < n_param ||
+ xa->smb_mdrcnt < n_data) {
+ smbsr_raise_error(sr, ERRSRV, ERRsmbcmd);
+ /* NOTREACHED */
+ }
+
+ /* neato, blast it over there */
+
+ n_setup = (n_setup + 1) / 2; /* Conver to setup words */
+ param_pad = 1; /* must be one */
+ param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
+ data_pad = (4 - ((param_off + n_param) & 3)) % 4; /* Pad to 4 byte */
+ data_off = param_off + n_param + data_pad; /* Param off from hdr */
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ smbsr_encode_result(sr, 18+n_setup, total_bytes,
+ "b 3. llllllllb C w #. C #. C",
+ 18 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ data_pad,
+ &xa->rep_data_mb);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_nt_transact_query_quota
+ *
+ * Stub to help debunk this function. There are 16 parameter bytes. The
+ * first parameter is definitely the fid. The second looks like a flags
+ * field. Then there are 12 bytes (probably 3 dwords) - all zero.
+ */
+int
+smb_nt_transact_query_quota(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t fid;
+ uint16_t flags;
+ int rc;
+
+ rc = smb_decode_mbc(&xa->req_param_mb, "%ww", sr, &fid, &flags);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+int
+smb_com_nt_transact(struct smb_request *sr)
+{
+ uint16_t Function;
+ unsigned char MaxSetupCount, SetupCount;
+ uint32_t TotalParameterCount, TotalDataCount;
+ uint32_t MaxParameterCount, MaxDataCount, pscnt;
+ uint32_t psoff, dscnt, dsoff;
+ smb_xa_t *xa;
+ int ready;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, SMB_NT_TRANSHDR_ED_FMT, &MaxSetupCount,
+ &TotalParameterCount, &TotalDataCount, &MaxParameterCount,
+ &MaxDataCount, &pscnt, &psoff, &dscnt,
+ &dsoff, &SetupCount, &Function);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ xa = smb_xa_create(sr->session, sr, TotalParameterCount, TotalDataCount,
+ MaxParameterCount, MaxDataCount, MaxSetupCount, SetupCount);
+ if (xa == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRnoroom);
+ /* NOTREACHED */
+ }
+
+ xa->smb_flags = 0;
+ xa->smb_timeout = 0;
+ xa->smb_func = Function;
+ xa->req_disp_param = pscnt;
+ xa->req_disp_data = dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
+ sr->smb_vwv.chain_offset, SetupCount * 2)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ ready = smb_trans_ready(xa);
+
+ if (smb_xa_open(xa)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRsrverror);
+ /* NOTREACHED */
+ }
+ sr->r_xa = xa;
+
+ if (!ready) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (!smb_xa_complete(xa)) {
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ return (smb_nt_trans_dispatch(sr, xa));
+}
+
+
+int
+smb_com_nt_transact_secondary(struct smb_request *sr)
+{
+ uint16_t tpscnt, tdscnt, fid;
+ uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
+ smb_xa_t *xa;
+ int rc;
+
+ if ((xa = smbsr_lookup_xa(sr)) == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRsrverror);
+ /* NOTREACHED */
+ }
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
+ if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ if (xa->smb_com != SMB_COM_TRANSACTION2) {
+ return (SDRC_DROP_VC);
+ }
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
+ &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ mutex_enter(&xa->xa_mutex);
+ xa->smb_tpscnt = tpscnt; /* might have shrunk */
+ xa->smb_tdscnt = tdscnt; /* might have shrunk */
+ xa->xa_smb_fid = fid; /* overwrite rules? */
+ xa->req_disp_param = psdisp+pscnt;
+ xa->req_disp_data = dsdisp+dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ mutex_exit(&xa->xa_mutex);
+
+ if (!smb_trans_ready(xa))
+ return (SDRC_NO_REPLY);
+
+ if (!smb_xa_complete(xa))
+ return (SDRC_NO_REPLY);
+
+ return (smb_nt_trans_dispatch(sr, xa));
+}
+
+int
+smb_trans_ready(struct smb_xa *xa)
+{
+ int rc;
+
+ mutex_enter(&xa->xa_mutex);
+ rc = xa->req_disp_data >= xa->smb_tdscnt &&
+ xa->req_disp_param >= xa->smb_tpscnt;
+ mutex_exit(&xa->xa_mutex);
+
+ return (rc);
+}
+
+
+/*
+ * smb_emit_SHARE_INFO_0
+ *
+ * This function will convert unicode chars to oem chars before
+ * and store the result in a fixed length, MAX_SHARE_NAME_LEN, buffer. If the
+ * length after conversion is longer than 12, -1 will be reported
+ * to indicate an error. The fixed length is a limitation of the
+ * smb protocol.
+ */
+static int
+smb_emit_SHARE_INFO_0(struct mbuf_chain *output, unsigned char *name)
+{
+ mts_wchar_t *unibuf;
+ char *tmpbuf;
+ unsigned int cpid = oem_get_smb_cpid();
+ unsigned int length;
+ char name_buf[MAX_SHARE_NAME_LEN];
+
+ if (name == 0)
+ tmpbuf = "";
+ else
+ tmpbuf = (char *)name;
+
+ length = strlen(tmpbuf) + 1;
+ unibuf = MEM_MALLOC("smb", length * sizeof (mts_wchar_t));
+
+ (void) mts_mbstowcs(unibuf, tmpbuf, length);
+ tmpbuf = MEM_MALLOC("smb", length);
+ if (unicodestooems(tmpbuf, unibuf, length, cpid) == 0)
+ (void) strcpy(tmpbuf, (char *)name);
+
+ if (strlen(tmpbuf) + 1 > MAX_SHARE_NAME_LEN) {
+ MEM_FREE("smb", unibuf);
+ MEM_FREE("smb", tmpbuf);
+ return (-1);
+ }
+
+ bzero(name_buf, sizeof (name_buf));
+ (void) strcpy(name_buf, tmpbuf);
+ (void) smb_encode_mbc(output, "13c", name_buf);
+
+ MEM_FREE("smb", unibuf);
+ MEM_FREE("smb", tmpbuf);
+
+ return (0);
+}
+
+static int
+smb_emit_SHARE_INFO_1(struct mbuf_chain *output, struct mbuf_chain *text,
+ unsigned char *name, uint16_t type,
+ unsigned char *comment)
+{
+ if (smb_emit_SHARE_INFO_0(output, name) < 0)
+ return (-1);
+
+ (void) smb_encode_mbc(output, ".wl", type, MBC_LENGTH(text));
+ (void) smb_encode_mbc(text, "s",
+ (comment ? comment : (unsigned char *)"No comment"));
+ return (0);
+}
+
+static void /*ARGSUSED*/
+smb_emit_SHARE_INFO_2(struct mbuf_chain *output, struct mbuf_chain *text,
+ struct smb_request *sr, unsigned char *name, uint16_t type,
+ unsigned char *comment, uint16_t access, char *path, char *password)
+{
+ unsigned char pword[9];
+
+ /*
+ * XXX PGD. Is there a bug here? We zero pword, copy password
+ * into pword then ignore it and use password for smb_encode_mbc?
+ */
+ bzero(pword, sizeof (pword));
+ (void) strncpy((char *)pword, password, sizeof (pword));
+ (void) smb_emit_SHARE_INFO_1(output, text, name, type, comment);
+ (void) smb_encode_mbc(output, "wwwl9c.",
+ access,
+ smb_info.si.skc_maxconnections,
+ smb_svcstate_session_count(&smb_info.si_svc_sm_ctx),
+ MBC_LENGTH(text),
+ password);
+ (void) smb_encode_mbc(text, "s", path);
+}
+
+/*
+ * is_long_sharename
+ *
+ * This function is extracted from smb_emit_SHARE_INFO_0 only for
+ * finding shares that their names are longer than MAX_SHARE_NAME_LEN.
+ *
+ * The function returns 1 for long share names and 0 when the length
+ * is Ok.
+ */
+static int
+is_long_sharename(unsigned char *name)
+{
+ mts_wchar_t *unibuf;
+ char *tmpbuf;
+ unsigned int cpid = oem_get_smb_cpid();
+ unsigned int length;
+
+ if (name == 0)
+ tmpbuf = "";
+ else
+ tmpbuf = (char *)name;
+
+ length = strlen(tmpbuf) + 1;
+ unibuf = MEM_MALLOC("smb", length * sizeof (mts_wchar_t));
+ (void) mts_mbstowcs(unibuf, tmpbuf, length);
+ tmpbuf = MEM_MALLOC("smb", length);
+ if (unicodestooems(tmpbuf, unibuf, length, cpid) == 0)
+ (void) strcpy(tmpbuf, (char *)name);
+
+ if (strlen(tmpbuf) + 1 > MAX_SHARE_NAME_LEN) {
+ MEM_FREE("smb", unibuf);
+ MEM_FREE("smb", tmpbuf);
+ return (1);
+ }
+
+ MEM_FREE("smb", unibuf);
+ MEM_FREE("smb", tmpbuf);
+
+ return (0);
+}
+
+/*
+ * This structure holds information about shares which will
+ * fit in the specified client buffer size.
+ *
+ * sei_bufsize: Client specified buffer size
+ * sei_count: Maximum number of shares that can be
+ * sent in the buffer.
+ *
+ * The return data section consists of a number of SHARE_INFO_1 structures.
+ * In case there are multiple SHARE_INFO_1 data structures to return this
+ * function put all fixed length part of these structures in the return buffer
+ * and then put all the variable length data (shares' comment) at the end of
+ * buffer.
+ *
+ * sei_info_len: Size of fixed length part of SHARE_INFO_1
+ * structures for sei_count shares
+ * sei_cmnt_len: Size of comments for sei_count shares
+ */
+typedef struct {
+ uint16_t sei_bufsize;
+ short sei_count;
+ int sei_infolen;
+ int sei_cmntlen;
+} smb_share_enum_t;
+
+/*
+ * smb_share_update_info
+ *
+ * Check to see if the given buffer has enough
+ * room to fit the information of the given share.
+ * If there is enough room update the passed max_???
+ * information.
+ *
+ * Return 1 if buffer is not full yet, 0 if it's full.
+ */
+static int
+smb_share_update_info(lmshare_info_t *si, smb_share_enum_t *shr_enum_info)
+{
+ int cmnt_len;
+ int new_info_len = shr_enum_info->sei_infolen;
+ int new_cmnt_len = shr_enum_info->sei_cmntlen;
+
+ if (lmshrd_is_special(si->share_name))
+ cmnt_len = 1;
+ else
+ cmnt_len = (strlen(si->comment) + 1);
+
+ new_info_len += SHARE_INFO_1_SIZE;
+ new_cmnt_len += cmnt_len;
+
+ if ((new_info_len + new_cmnt_len) < shr_enum_info->sei_bufsize) {
+ shr_enum_info->sei_count++;
+ shr_enum_info->sei_infolen = new_info_len;
+ shr_enum_info->sei_cmntlen = new_cmnt_len;
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_share_skip_share
+ *
+ * Determines whether the given share should be enumerated
+ * or not. The share will not be enumerated if its name is
+ * long or it's autohome share.
+ *
+ * Return 1 if the share should be skipped; otherwise returns
+ * 0
+ */
+static int
+smb_share_skip_share(lmshare_info_t *si)
+{
+ if (is_long_sharename((unsigned char *)si->share_name)) {
+ return (1);
+ }
+
+ /* Skip autohome share if autohome filter is enabled */
+ if (si->mode == LMSHRM_TRANS) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_share_add_autohome
+ *
+ * Determines if an autohome share should be added to shares' list
+ * for the given user.
+ * Autohome will be add when all the following conditions are true:
+ *
+ * 1. Autohome feature is enabled
+ * 2. A share with the same name as the given user exists
+ * 3. The share is not a permanent share
+ * 4. Share name is not longer than maximum allowed
+ */
+static int
+smb_share_add_autohome(char *username, lmshare_info_t *si)
+{
+ int do_add = 0;
+
+ do_add = (lmshrd_getinfo(username, si) == NERR_Success) &&
+ (si->mode & LMSHRM_TRANS) &&
+ (is_long_sharename((unsigned char *)(si->share_name)) == 0);
+
+ return (do_add);
+}
+
+/*
+ * smb_share_total_info
+ *
+ * This function calculates following informations
+ * - Maximum number of shares that can be sent for clients
+ * according to its buffer size (cli_bufsize)
+ * - length of fixed information about above shares
+ * - length of comments of above shares
+ * - total number of shares that their names are no longer
+ * than MAX_SHARE_NAME_LEN.
+ *
+ * Added SMB user object to the parameter list to filter out other
+ * user autohome shares.
+ */
+static void
+smb_share_total_info(smb_share_enum_t *shr_enum_info, short *tot_shares_num,
+ smb_user_t *user)
+{
+ uint64_t iterator;
+ lmshare_info_t *si;
+ struct lmshare_info *auto_si;
+ int more_room = 1;
+
+ si = kmem_zalloc(sizeof (lmshare_info_t), KM_SLEEP);
+ auto_si = kmem_zalloc(sizeof (struct lmshare_info), KM_SLEEP);
+
+ *tot_shares_num = 0;
+ shr_enum_info->sei_count = 0;
+ shr_enum_info->sei_infolen = 0;
+ shr_enum_info->sei_cmntlen = 0;
+
+ if (smb_share_add_autohome(user->u_name, auto_si)) {
+ (*tot_shares_num)++;
+ more_room = smb_share_update_info(auto_si, shr_enum_info);
+ }
+
+ iterator = lmshrd_open_iterator(LMSHRM_ALL);
+ if (iterator == 0) {
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si, sizeof (struct lmshare_info));
+ return;
+ }
+
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ (void) lmshrd_close_iterator(iterator);
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si, sizeof (struct lmshare_info));
+ return;
+ }
+
+ while (*si->share_name != 0) {
+ if (smb_share_skip_share(si)) {
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ (void) lmshrd_close_iterator(iterator);
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si,
+ sizeof (struct lmshare_info));
+ return;
+ }
+ continue;
+ }
+
+ (*tot_shares_num)++;
+
+ if (more_room) {
+ more_room = smb_share_update_info(si, shr_enum_info);
+ }
+
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ (void) lmshrd_close_iterator(iterator);
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si, sizeof (struct lmshare_info));
+ return;
+ }
+ }
+
+ (void) lmshrd_close_iterator(iterator);
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si, sizeof (struct lmshare_info));
+}
+
+/*
+ * smb_encode_SHARE_INFO_1
+ *
+ * This function is extracted from smb_emit_SHARE_INFO_1 and only
+ * encodes fixed part of SHARE_INFO_1 structure.
+ *
+ * The function returns -1 if encoding fails and 0 on success.
+ */
+static int
+smb_encode_SHARE_INFO_1(struct mbuf_chain *output, unsigned char *name,
+ uint16_t type, int cmnt_len)
+{
+ if (smb_emit_SHARE_INFO_0(output, name) < 0)
+ return (-1);
+ (void) smb_encode_mbc(output, ".wl", type, cmnt_len);
+ return (0);
+}
+
+/*
+ * collect_shares_info
+ *
+ * This function encodes information of shares_num of shares
+ * into data_mb and cmnt_str.
+ *
+ * Added SMB user object to the parameter list to filter out other
+ * user autohome shares.
+ *
+ */
+static void
+collect_shares_info(uint64_t iterator, int shares_num,
+ struct mbuf_chain *data_mb,
+ char *cmnt_str, int *cmnt_len,
+ smb_user_t *user, int first_resp)
+{
+ int i = 0;
+ lmshare_info_t *si;
+ struct lmshare_info *tsi;
+ int is_special;
+
+ si = kmem_zalloc(sizeof (lmshare_info_t), KM_SLEEP);
+ tsi = kmem_zalloc(sizeof (struct lmshare_info), KM_SLEEP);
+
+ if (first_resp && smb_share_add_autohome(user->u_name, tsi)) {
+ if (smb_encode_SHARE_INFO_1(data_mb,
+ (unsigned char *)tsi->share_name,
+ tsi->stype, *cmnt_len) == 0) {
+ (void) memcpy(cmnt_str+(*cmnt_len),
+ tsi->comment, strlen(tsi->comment)+1);
+ (*cmnt_len) += (strlen(tsi->comment) + 1);
+ i++;
+ }
+ }
+
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(tsi, sizeof (struct lmshare_info));
+ return;
+ }
+
+ while ((i < shares_num) && (*si->share_name != 0)) {
+ if (smb_share_skip_share(si)) {
+ goto next;
+ }
+
+
+ is_special = lmshrd_is_special(si->share_name);
+ /* check for door errors */
+ if (is_special == NERR_InternalError) {
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(tsi, sizeof (struct lmshare_info));
+ return;
+ }
+
+ if (is_special) {
+ si->stype |= STYPE_HIDDEN;
+ if (smb_encode_SHARE_INFO_1(data_mb,
+ (unsigned char *)si->share_name,
+ si->stype, *cmnt_len) < 0) {
+ goto next;
+ }
+ cmnt_str[*cmnt_len] = '\0';
+ (*cmnt_len)++;
+ } else {
+ if (smb_encode_SHARE_INFO_1(data_mb,
+ (unsigned char *)si->share_name, si->stype,
+ *cmnt_len) < 0) {
+ goto next;
+ }
+ (void) memcpy(cmnt_str+(*cmnt_len), si->comment,
+ strlen(si->comment)+1);
+ (*cmnt_len) += (strlen(si->comment) + 1);
+ }
+
+ next:
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(tsi, sizeof (struct lmshare_info));
+ return;
+ }
+ }
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(tsi, sizeof (struct lmshare_info));
+}
+
+int
+smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_share_enum_t shr_enum_info;
+ short left_shares_cnt; /* Number of shares not sent yet */
+
+ /*
+ * Number of shares that should be sent
+ * in the current response packet.
+ * It can be a number between 0 and
+ * max_share_scnt.
+ */
+ short shares_scnt;
+
+ /*
+ * Maximum number of shares that can be
+ * sent in one response packet regarding
+ * the maximum negotiated buffer size
+ * for SMB messages.
+ */
+ short max_shares_per_packet;
+
+ /*
+ * Total number of shares on the server
+ * that their name is not greater than
+ * MAX_SHARE_NAME_LEN
+ */
+ short shares_tot_num;
+
+ /*
+ * Size of total data (info + cmnt)
+ * that should be sent for client
+ */
+ int shares_tot_byte;
+
+ /*
+ * Maximum size of data that can be
+ * sent in one SMB transaction response
+ * according to the maximum negotiated
+ * buffer size for SMB packets
+ */
+ int data_buf_limit;
+
+ /*
+ * Number of comment bytes that will
+ * be sent in the current response
+ */
+ uint16_t cmnt_scnt;
+
+ /*
+ * Number of data bytes that will
+ * be sent in the current response
+ */
+ uint16_t data_scnt;
+
+ /*
+ * Total number of data bytes that
+ * are sent till now. This is only
+ * used for calculating current data
+ * displacement
+ */
+ uint16_t tot_data_scnt;
+
+ /*
+ * Number of parameter bytes should
+ * be sent for the current response.
+ * It is 8 for the 1st response and
+ * 0 for others
+ */
+ uint16_t param_scnt;
+
+ /* number of setup and parameter bytes */
+ uint16_t n_setup, n_param;
+
+ /* data and parameter displacement */
+ uint16_t data_disp, param_disp;
+
+ /* return status by the 1st reply */
+ uint16_t ret_stat;
+
+ /* parameter and data offset and pad */
+ int param_off, param_pad, data_off, data_pad;
+
+ /*
+ * total bytes of parameters and data
+ * in the packet, plus the pad bytes.
+ */
+ int tot_packet_bytes;
+
+ char first_resp;
+ uint16_t opcode, level, cli_bufsize;
+ unsigned char *r_fmt;
+ char fmt[10];
+ uint64_t iterator;
+ char *cmnt_str, *cmnt_start;
+ int cmnt_len;
+ struct mbuf_chain reply;
+ smb_user_t *user;
+
+ user = sr->uid_user;
+ ASSERT(user);
+
+ /*
+ * Initialize the mbuf chain of reply to zero. If it is not
+ * zero, code inside the while loop will try to free the chain.
+ */
+ bzero(&reply, sizeof (struct mbuf_chain));
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%wss(lev)w(size)w", sr,
+ &opcode, &r_fmt, &r_fmt, &level, &cli_bufsize) != 0)
+ return (SDRC_UNSUPPORTED);
+
+ if (level != 1) {
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
+ NERR_BadTransactConfig, 0, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ n_setup = 0; /* Setup count for NetShareEnum SMB is 0 */
+ n_param = 8;
+ data_buf_limit = sr->session->smb_msg_size -
+ (SMB_HEADER_ED_LEN + RESP_HEADER_LEN + n_param);
+
+ shr_enum_info.sei_bufsize = cli_bufsize;
+ smb_share_total_info(&shr_enum_info, &shares_tot_num, user);
+
+ shares_tot_byte = shr_enum_info.sei_infolen + shr_enum_info.sei_cmntlen;
+
+ /* Check buffer to have enough space */
+ if (shares_tot_byte == 0) {
+ return (SDRC_ERROR_REPLY);
+ }
+
+ max_shares_per_packet = data_buf_limit / SHARE_INFO_1_SIZE;
+
+ shares_scnt = (shr_enum_info.sei_count > max_shares_per_packet)
+ ? max_shares_per_packet : shr_enum_info.sei_count;
+
+ cmnt_str = MEM_MALLOC("smb", shr_enum_info.sei_cmntlen * sizeof (char));
+ cmnt_len = 0;
+ /* save start of buffer to free it at the end of function */
+ cmnt_start = cmnt_str;
+
+ iterator = lmshrd_open_iterator(LMSHRM_ALL);
+
+ if (iterator == NULL) {
+ MEM_FREE("smb", cmnt_str);
+ return (SDRC_DROP_VC);
+ }
+
+ /*
+ * The rep_setup_mb is already initialized in smb_trans_dispatch().
+ * Calling MBC_INIT() will initialized the structure and so the
+ * pointer to the mbuf chains will be lost. Therefore, we need
+ * to free the resources before calling MBC_INIT() again.
+ */
+ m_freem(xa->rep_setup_mb.chain);
+ MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
+
+ left_shares_cnt = shr_enum_info.sei_count;
+ tot_data_scnt = 0;
+ cmnt_scnt = 0;
+
+ first_resp = 1;
+ while (tot_data_scnt < shares_tot_byte) {
+ /*
+ * Calling MBC_INIT() will initialized the structure and so the
+ * pointer to the mbuf chains will be lost. Therefore, we need
+ * to free the resources if any before calling MBC_INIT().
+ */
+ m_freem(xa->rep_data_mb.chain);
+ MBC_INIT(&xa->rep_data_mb, data_buf_limit);
+ collect_shares_info(iterator, shares_scnt, &xa->rep_data_mb,
+ cmnt_str, &cmnt_len, user, first_resp);
+ data_scnt = shares_scnt * SHARE_INFO_1_SIZE;
+ left_shares_cnt -= shares_scnt;
+ if (left_shares_cnt < max_shares_per_packet)
+ shares_scnt = left_shares_cnt;
+ if (left_shares_cnt == 0) {
+ /*
+ * Now send comments.
+ * Append comments to the end of share_info_1
+ * structures.
+ */
+ cmnt_scnt = data_buf_limit -
+ MBC_LENGTH(&xa->rep_data_mb);
+ if (cmnt_scnt > shr_enum_info.sei_cmntlen) {
+ /*LINTED E_ASSIGN_NARROW_CONV*/
+ cmnt_scnt = shr_enum_info.sei_cmntlen;
+ }
+ (void) sprintf(fmt, "%dc", cmnt_scnt);
+ (void) smb_encode_mbc(&xa->rep_data_mb, fmt, cmnt_str);
+ cmnt_str += cmnt_scnt;
+ shr_enum_info.sei_cmntlen -= cmnt_scnt;
+ }
+ data_scnt += cmnt_scnt;
+ tot_data_scnt += data_scnt;
+
+ /* Only the 1st response packet contains parameters */
+ param_scnt = (first_resp) ? n_param : 0;
+ param_pad = 1; /* always one */
+ param_off = SMB_HEADER_ED_LEN + RESP_HEADER_LEN;
+ param_disp = (first_resp) ? 0 : n_param;
+
+ /*
+ * Calling MBC_INIT() will initialized the structure and so the
+ * pointer to the mbuf chains will be lost. Therefore, we need
+ * to free the resources if any before calling MBC_INIT().
+ */
+ m_freem(xa->rep_param_mb.chain);
+ MBC_INIT(&xa->rep_param_mb, param_scnt);
+ if (first_resp) {
+ first_resp = 0;
+ /* Prepare parameters for the 1st response packet */
+ ret_stat = (shares_tot_num > shr_enum_info.sei_count)
+ ? ERROR_MORE_DATA : 0;
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
+ ret_stat, -shr_enum_info.sei_infolen,
+ shr_enum_info.sei_count,
+ shares_tot_num);
+ }
+
+ data_pad = (param_off + n_param) & 1; /* Pad to short */
+
+ /* data off from hdr start */
+ data_off = param_off + param_scnt + data_pad;
+ data_disp = tot_data_scnt - data_scnt;
+ tot_packet_bytes = param_pad + param_scnt + data_pad +
+ data_scnt;
+
+ /*
+ * Calling MBC_INIT() will initialized the structure and so the
+ * pointer to the mbuf chains will be lost. Therefore, we need
+ * to free the resources if any before calling MBC_INIT().
+ */
+ m_freem(reply.chain);
+ MBC_INIT(&reply, SMB_HEADER_ED_LEN
+ + sizeof (uchar_t) /* word parameters count */
+ + 10*sizeof (ushort_t) /* word parameters */
+ + n_setup*sizeof (ushort_t) /* setup parameters */
+ + sizeof (ushort_t) /* total data byte count */
+ + tot_packet_bytes);
+
+ (void) smb_encode_mbc(&reply, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ (void) smb_encode_mbc(&reply,
+ "b ww 2. www www b . C w #. C #. C",
+ 10 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ shares_tot_byte, /* Total Data Bytes */
+ param_scnt, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ param_disp, /* Param displacement */
+ data_scnt, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ data_disp, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ tot_packet_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ data_pad,
+ &xa->rep_data_mb);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, NULL);
+
+ (void) smb_session_send(sr->session, 0, &reply);
+ }
+
+ (void) lmshrd_close_iterator(iterator);
+ MEM_FREE("smb", cmnt_start);
+ return (SDRC_NO_REPLY);
+}
+
+int
+smb_trans_net_share_get_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, max_bytes, access;
+ uint32_t type;
+ unsigned char *req_fmt;
+ unsigned char *rep_fmt;
+ struct mbuf_chain str_mb;
+ char *share;
+ char *path;
+ char *password;
+ char *comment;
+ lmshare_info_t si;
+ int shr_found;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%wsss(lev)w(size)w", sr,
+ &opcode, &req_fmt, &rep_fmt, &share, &level, &max_bytes) != 0)
+ return (SDRC_UNSUPPORTED);
+
+ (void) utf8_strlwr(share);
+ shr_found = lmshrd_getinfo(share, &si);
+ if (strcmp(share, "ipc$") == 0) {
+ type = STYPE_IPC;
+ path = "";
+ password = "";
+ access = SHARE_ACCESS_ALL;
+ } else if (shr_found) {
+ path = si.directory;
+ type = STYPE_DISKTREE;
+ if (path[strlen(path)] == '$')
+ type |= STYPE_HIDDEN;
+ password = "";
+ access = SHARE_ACCESS_ALL;
+ } else {
+ /* We have no idea what this share is... */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www",
+ NERR_NetNameNotFound, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (shr_found)
+ comment = si.comment;
+ else
+ comment = "";
+
+ password = "";
+
+ MBC_INIT(&str_mb, max_bytes);
+
+ switch (level) {
+ case 0 :
+ (void) smb_emit_SHARE_INFO_0(&xa->rep_data_mb,
+ (unsigned char *)share);
+ break;
+
+ case 1 :
+ (void) smb_emit_SHARE_INFO_1(&xa->rep_data_mb, &str_mb,
+ (unsigned char *)share, type,
+ (unsigned char *)comment);
+ break;
+
+ case 2 :
+ smb_emit_SHARE_INFO_2(&xa->rep_data_mb, &str_mb, sr,
+ (unsigned char *)share, type, (unsigned char *)comment,
+ access, path, password);
+ default:
+ m_freem(str_mb.chain);
+ return (SDRC_UNSUPPORTED);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
+ -MBC_LENGTH(&xa->rep_data_mb),
+ MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
+ m_freem(str_mb.chain);
+ return (SDRC_NORMAL_REPLY);
+}
+
+int
+smb_trans_net_workstation_get_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, max_bytes;
+ unsigned char *req_fmt;
+ unsigned char *rep_fmt;
+ struct mbuf_chain str_mb;
+ char *domain;
+ char *hostname;
+
+ if ((smb_decode_mbc(&xa->req_param_mb, "%wss(lev)w(size)w", sr,
+ &opcode, &req_fmt, &rep_fmt, &level, &max_bytes) != 0) ||
+ (level != 10)) {
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
+ NERR_BadTransactConfig, 0, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ domain = smb_info.si.skc_resource_domain;
+ hostname = smb_info.si.skc_hostname;
+
+ MBC_INIT(&str_mb, max_bytes);
+
+ (void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", hostname);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", "nobody");
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", domain);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "bbl",
+ SMB_VERSION_MAJOR, SMB_VERSION_MINOR, MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", domain);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", domain);
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
+ -MBC_LENGTH(&xa->rep_data_mb),
+ MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
+ m_freem(str_mb.chain);
+ return (SDRC_NORMAL_REPLY);
+}
+
+int
+smb_trans_net_user_get_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, max_bytes;
+ unsigned char *req_fmt;
+ unsigned char *rep_fmt;
+ unsigned char *user;
+ int rc;
+
+ rc = smb_decode_mbc(&xa->req_param_mb, "%wssww", sr,
+ &opcode,
+ &req_fmt,
+ &rep_fmt,
+ &user,
+ &level,
+ &max_bytes);
+
+ if (rc != 0)
+ return (SDRC_UNSUPPORTED);
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www",
+ NERR_UserNotFound, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+int
+smb_trans_server_get_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, buf_size;
+ char *req_fmt;
+ char *rep_fmt;
+ char server_name[16];
+ struct mbuf_chain str_mb;
+ char *hostname;
+ char *comment;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%wssww", sr,
+ &opcode, &req_fmt, &rep_fmt, &level, &buf_size) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ comment = smb_info.si.skc_system_comment;
+ hostname = smb_info.si.skc_hostname;
+
+ MBC_INIT(&str_mb, buf_size);
+
+ bzero(server_name, sizeof (server_name));
+ (void) strncpy(server_name, hostname, sizeof (server_name));
+
+ switch (level) {
+ case 0:
+ (void) smb_encode_mbc(&xa->rep_data_mb, "16c", server_name);
+ break;
+ case 1:
+ (void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "16cbbll", server_name,
+ SMB_VERSION_MAJOR, SMB_VERSION_MINOR,
+ MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", comment);
+ break;
+ case 2:
+ /* B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWz */
+ (void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
+ /* B16BBDz */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "16cbbll", server_name,
+ SMB_VERSION_MAJOR,
+ SMB_VERSION_MINOR, MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", comment);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "lllwwl",
+ (uint32_t)1,
+ (uint32_t)2,
+ (uint32_t)3,
+ (uint16_t)4,
+ (uint16_t)5,
+ MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", "str1");
+ (void) smb_encode_mbc(&xa->rep_data_mb, "wwwwwww21cbl",
+ (uint16_t)6,
+ (uint16_t)7,
+ (uint16_t)8,
+ (uint16_t)9,
+ (uint16_t)10,
+ (uint16_t)11,
+ (uint16_t)12,
+ "21 byte comment ",
+ (unsigned char)13,
+ MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", "str2");
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ "wwwwwwwwwwwwwwwwwwwwwwl",
+ (uint16_t)14,
+ (uint16_t)15,
+ (uint16_t)16,
+ (uint16_t)17,
+ (uint16_t)18,
+ (uint16_t)19,
+ (uint16_t)20,
+ (uint16_t)21,
+ (uint16_t)22,
+ (uint16_t)23,
+ (uint16_t)24,
+ (uint16_t)25,
+ (uint16_t)26,
+ (uint16_t)27,
+ (uint16_t)28,
+ (uint16_t)29,
+ (uint16_t)20,
+ (uint16_t)31,
+ (uint16_t)32,
+ (uint16_t)33,
+ (uint16_t)34,
+ (uint16_t)35,
+ MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", "str3");
+ break;
+ default:
+ m_freem(str_mb.chain);
+ return (SDRC_UNSUPPORTED);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
+ -MBC_LENGTH(&xa->rep_data_mb),
+ (MBC_LENGTH(&xa->rep_data_mb)) +
+ (MBC_LENGTH(&str_mb)));
+ (void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
+ m_freem(str_mb.chain);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * 6.4 The NetServerEnum2 RAP Service
+ *
+ * The NetServerEnum2 RAP service lists all computers of the specified type
+ * or types that are visible in the specified domains. It may also
+ * enumerate domains.
+ *
+ * The following definition uses the notation and terminology defined in
+ * the CIFS Remote Administration Protocol specification, which is required
+ * in order to make it well-defined. The definition is:
+ *
+ * uint16_t NetServerEnum2 (
+ * uint16_t sLevel,
+ * RCVBUF pbBuffer,
+ * RCVBUFLEN cbBuffer,
+ * ENTCOUNT pcEntriesRead,
+ * uint16_t *pcTotalAvail,
+ * uint32_t fServerType,
+ * char *pszDomain,
+ * );
+ *
+ * where:
+ *
+ * sLevel specifies the level of detail (0 or 1) requested.
+ *
+ * pbBuffer points to the buffer to receive the returned data. If the
+ * function is successful, the buffer contains a sequence of
+ * server_info_x structures, where x is 0 or 1, depending on the
+ * level of detail requested.
+ *
+ * cbBuffer specifies the size, in bytes, of the buffer pointed to by
+ * the pbBuffer parameter.
+ *
+ * pcEntriesRead points to a 16 bit variable that receives a count of
+ * the number of servers enumerated in the buffer. This count is
+ * valid only if NetServerEnum2 returns the NERR_Success or
+ * ERROR_MORE_DATA values.
+ *
+ * pcTotal Avail points to a 16 bit variable that receives a count of
+ * the total number of available entries. This count is valid only if
+ * NetServerEnum2 returns the NERR_Success or ERROR_MORE_DATA values.
+ *
+ * fServerType specifies the type or types of computers to enumerate.
+ * Computers that match at least one of the specified types are
+ * returned in the buffer. Possible values are defined in the request
+ * parameters section.
+ *
+ * pszDomain points to a null-terminated string that contains the
+ * name of the workgroup in which to enumerate computers of the
+ * specified type or types. If the pszDomain parameter is a null
+ * string or a null pointer, servers are enumerated for the current
+ * domain of the computer.
+ *
+ * 6.4.1 Transaction Request Parameters section
+ *
+ * The Transaction request parameters section in this instance contains:
+ * . The 16 bit function number for NetServerEnum2 which is 104.
+ * . The parameter descriptor string which is "WrLehDz".
+ * . The data descriptor string for the (returned) data which is "B16" for
+ * level detail 0 or "B16BBDz" for level detail 1.
+ * . The actual parameters as described by the parameter descriptor
+ * string.
+ *
+ * The parameters are:
+ * . A 16 bit integer with a value of 0 or 1 (corresponding to the "W" in
+ * the parameter descriptor string. This represents the level of detail
+ * the server is expected to return
+ * . A 16 bit integer that contains the size of the receive buffer.
+ * . A 32 bit integer that represents the type of servers the function
+ * should enumerate. The possible values may be any of the following or
+ * a combination of the following:
+ *
+ * SV_TYPE_WORKSTATION 0x00000001 All workstations
+ * SV_TYPE_SERVER 0x00000002 All servers
+ * SV_TYPE_SQLSERVER 0x00000004 Any server running with SQL
+ * server
+ * SV_TYPE_DOMAIN_CTRL 0x00000008 Primary domain controller
+ * SV_TYPE_DOMAIN_BAKCTRL 0x00000010 Backup domain controller
+ * SV_TYPE_TIME_SOURCE 0x00000020 Server running the timesource
+ * service
+ * SV_TYPE_AFP 0x00000040 Apple File Protocol servers
+ * SV_TYPE_NOVELL 0x00000080 Novell servers
+ * SV_TYPE_DOMAIN_MEMBER 0x00000100 Domain Member
+ * SV_TYPE_PRINTQ_SERVER 0x00000200 Server sharing print queue
+ * SV_TYPE_DIALIN_SERVER 0x00000400 Server running dialin service.
+ * SV_TYPE_XENIX_SERVER 0x00000800 Xenix server
+ * SV_TYPE_NT 0x00001000 NT server
+ * SV_TYPE_WFW 0x00002000 Server running Windows for
+ * Workgroups
+ * SV_TYPE_SERVER_NT 0x00008000 Windows NT non DC server
+ * SV_TYPE_POTENTIAL_BROWSER 0x00010000 Server that can run the browser
+ * service
+ * SV_TYPE_BACKUP_BROWSER 0x00020000 Backup browser server
+ * SV_TYPE_MASTER_BROWSER 0x00040000 Master browser server
+ * SV_TYPE_DOMAIN_MASTER 0x00080000 Domain Master Browser server
+ * SV_TYPE_LOCAL_LIST_ONLY 0x40000000 Enumerate only entries marked
+ * "local"
+ * SV_TYPE_DOMAIN_ENUM 0x80000000 Enumerate Domains. The pszDomain
+ * parameter must be NULL.
+ *
+ * . A null terminated ASCII string representing the pszDomain parameter
+ * described above
+ *
+ * 6.4.2 Transaction Request Data section
+ *
+ * There is no data or auxiliary data to send as part of the request.
+ *
+ * 6.4.3 Transaction Response Parameters section
+ *
+ * The transaction response parameters section consists of:
+ * . A 16 bit word indicating the return status. The possible values are:
+ *
+ * Code Value Description
+ * NERR_Success 0 No errors encountered
+ * ERROR_MORE_DATA 234 Additional data is available
+ * NERR_ServerNotStarted 2114 The RAP service on the remote computer
+ * is not running
+ * NERR_BadTransactConfig 2141 The server is not configured for
+ * transactions, IPC$ is not shared
+ *
+ * . A 16 bit "converter" word.
+ * . A 16 bit number representing the number of entries returned.
+ * . A 16 bit number representing the total number of available entries.
+ * If the supplied buffer is large enough, this will equal the number of
+ * entries returned.
+ *
+ * 6.4.4 Transaction Response Data section
+ *
+ * The return data section consists of a number of SERVER_INFO_1 structures.
+ * The number of such structures present is determined by the third entry
+ * (described above) in the return parameters section.
+ *
+ * At level detail 0, the Transaction response data section contains a
+ * number of SERVER_INFO_0 data structure. The number of such structures is
+ * equal to the 16 bit number returned by the server in the third parameter
+ * in the Transaction response parameter section. The SERVER_INFO_0 data
+ * structure is defined as:
+ *
+ * struct SERVER_INFO_0 {
+ * char sv0_name[16];
+ * };
+ *
+ * where:
+ *
+ * sv0_name is a null-terminated string that specifies the name of a
+ * computer or domain .
+ *
+ * At level detail 1, the Transaction response data section contains a
+ * number of SERVER_INFO_1 data structure. The number of such structures is
+ * equal to the 16 bit number returned by the server in the third parameter
+ * in the Transaction response parameter section. The SERVER_INFO_1 data
+ * structure is defined as:
+ *
+ * struct SERVER_INFO_1 {
+ * char sv1_name[16];
+ * char sv1_version_major;
+ * char sv1_version_minor;
+ * uint32_t sv1_type;
+ * char *sv1_comment_or_master_browser;
+ * };
+ *
+ * sv1_name contains a null-terminated string that specifies the name
+ * of a computer, or a domain name if SV_TYPE_DOMAIN_ENUM is set in
+ * sv1_type.
+ *
+ * sv1_version_major whatever was specified in the HostAnnouncement
+ * or DomainAnnouncement frame with which the entry was registered.
+ *
+ * sv1_version_minor whatever was specified in the HostAnnouncement
+ * or DomainAnnouncement frame with which the entry was registered.
+ *
+ * sv1_type specifies the type of software the computer is running.
+ * The member can be one or a combination of the values defined above
+ * in the Transaction request parameters section for fServerType.
+ *
+ *
+ * sv1_comment_or_master_browser points to a null-terminated string. If
+ * the sv1_type indicates that the entry is for a domain, this
+ * specifies the name of server running the domain master browser;
+ * otherwise, it specifies a comment describing the server. The comment
+ * can be a null string or the pointer may be a null pointer.
+ *
+ * In case there are multiple SERVER_INFO_1 data structures to
+ * return, the server may put all these fixed length structures in
+ * the return buffer, leave some space and then put all the variable
+ * length data (the actual value of the sv1_comment strings) at the
+ * end of the buffer.
+ *
+ * There is no auxiliary data to receive.
+ */
+
+int
+smb_trans_net_server_enum2(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, max_bytes;
+ uint32_t server_type;
+ unsigned char *domain;
+ struct mbuf_chain str_mb;
+ char *hostname, *s;
+ smb_kmod_cfg_t *si;
+
+ if (smb_decode_mbc(&xa->req_param_mb,
+ "%w s(request format) s(reply format) wwls", sr, &opcode, &s, &s,
+ &level, &max_bytes, &server_type, &domain) != 0)
+ return (SDRC_UNSUPPORTED);
+
+ si = &smb_info.si;
+
+ if (utf8_strcasecmp(si->skc_resource_domain, (char *)domain) != 0) {
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if ((server_type & MY_SERVER_TYPE) == 0) {
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ MBC_INIT(&str_mb, max_bytes);
+
+ hostname = si->skc_hostname;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "16c", hostname);
+ if (level == 1) {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "bbll",
+ SMB_VERSION_MAJOR, SMB_VERSION_MINOR,
+ MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", si->skc_system_comment);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0,
+ -MBC_LENGTH(&xa->rep_data_mb), 1, 1);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "m", str_mb.chain);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * is_supported_pipe
+ *
+ * Currently, just return 0 if the pipe is \\PIPE\repl otherwise
+ * return 1.
+ */
+int
+is_supported_pipe(char *pname)
+{
+ if (utf8_strcasecmp(pname, PIPE_REPL) == 0)
+ return (0);
+
+ return (1);
+}
+
+int
+smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc, pos;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+ uint16_t opcode;
+ uint16_t devstate;
+ char *req_fmt;
+ char *rep_fmt;
+ struct vardata_block vdb;
+
+ n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
+ n_setup++;
+ n_setup = n_setup & ~0x0001;
+ n_param = (xa->smb_mprcnt < smb_maxbufsize)
+ ? xa->smb_mprcnt : smb_maxbufsize;
+ n_param++;
+ n_param = n_param & ~0x0001;
+ rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
+ n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
+ MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
+ MBC_INIT(&xa->rep_param_mb, n_param);
+ MBC_INIT(&xa->rep_data_mb, n_data);
+
+ if (xa->smb_suwcnt > 0 && STYPE_ISIPC(sr->tid_tree->t_res_type)) {
+ rc = smb_decode_mbc(&xa->req_setup_mb, "ww", &opcode,
+ &sr->smb_fid);
+ if (rc != 0)
+ goto trans_err_not_supported;
+ switch (opcode) {
+ case TRANS_SET_NMPIPE_STATE:
+ if ((rc = smb_decode_mbc(&xa->req_param_mb, "w",
+ &devstate)) != 0)
+ goto trans_err_not_supported;
+
+ rc = SDRC_NORMAL_REPLY;
+ break;
+
+ case TRANS_TRANSACT_NMPIPE:
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ rc = smb_decode_mbc(&xa->req_data_mb, "#B",
+ xa->smb_tdscnt, &vdb);
+ if (rc != 0)
+ goto trans_err_not_supported;
+
+ rc = smb_rpc_transact(sr, &vdb.uio);
+ break;
+
+ case TRANS_WAIT_NMPIPE:
+ if (is_supported_pipe(xa->xa_smb_trans_name) == 0) {
+ smbsr_raise_error(sr, ERRDOS, ERRbadfile);
+ /* NOT REACHED */
+ }
+ rc = SDRC_NORMAL_REPLY;
+ break;
+
+ default:
+ goto trans_err_not_supported;
+ }
+ } else {
+ if ((utf8_strcasecmp(xa->xa_smb_trans_name,
+ PIPE_LANMAN) != 0) &&
+ (utf8_strcasecmp(
+ xa->xa_smb_trans_name, MAILSLOT_LANMAN) != 0) &&
+ (utf8_strcasecmp(
+ xa->xa_smb_trans_name, MAILSLOT_BROWSE) != 0) &&
+ (utf8_strcasecmp(
+ xa->xa_smb_trans_name, MAILSLOT_MSBROWSE) != 0))
+ goto trans_err_not_supported;
+
+ if ((rc = smb_decode_mbc(&xa->req_param_mb, "%wss\b", sr,
+ &opcode, &req_fmt, &rep_fmt)) != 0)
+ goto trans_err_not_supported;
+
+ /* for now, only respond to the */
+ switch (opcode) {
+ case API_WshareEnum:
+ rc = smb_trans_net_share_enum(sr, xa);
+ break;
+
+ case API_WshareGetInfo:
+ rc = smb_trans_net_share_get_info(sr, xa);
+ break;
+
+ case API_WserverGetInfo:
+ rc = smb_trans_server_get_info(sr, xa);
+ break;
+
+ case API_WUserGetInfo:
+ rc = smb_trans_net_user_get_info(sr, xa);
+ break;
+
+ case API_WWkstaGetInfo:
+ rc = smb_trans_net_workstation_get_info(sr, xa);
+ break;
+
+ case API_NetServerEnum2:
+ rc = smb_trans_net_server_enum2(sr, xa);
+ break;
+
+ default:
+ goto trans_err_not_supported;
+ }
+ }
+
+ switch (rc) {
+ case SDRC_NORMAL_REPLY:
+ break;
+
+ case SDRC_DROP_VC:
+ case SDRC_NO_REPLY:
+ case SDRC_ERROR_REPLY:
+ return (rc);
+
+ case SDRC_UNIMPLEMENTED:
+ case SDRC_UNSUPPORTED:
+ goto trans_err_not_supported;
+
+ default:
+ break;
+ }
+
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&xa->rep_param_mb);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ if (xa->smb_msrcnt < n_setup ||
+ xa->smb_mprcnt < n_param ||
+ xa->smb_mdrcnt < n_data) {
+ goto trans_err_too_small;
+ }
+
+ /* neato, blast it over there */
+
+ n_setup = (n_setup + 1) / 2; /* Convert to setup words */
+ param_pad = 1; /* always one */
+ param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
+ data_pad = (param_off + n_param) & 1; /* Pad to short */
+ /* Param off from hdr start */
+ data_off = param_off + n_param + data_pad;
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ smbsr_encode_result(sr, 10+n_setup, total_bytes,
+ "b ww 2. www www b . C w #. C #. C",
+ 10 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ data_pad,
+ &xa->rep_data_mb);
+ return (SDRC_NORMAL_REPLY);
+
+trans_err_too_small:
+ rc = NERR_BufTooSmall;
+ goto trans_err;
+
+trans_err_not_supported:
+ rc = ERROR_NOT_SUPPORTED;
+ goto trans_err;
+
+trans_err:
+ pos = MBC_LENGTH(&sr->reply) + 23;
+ smbsr_encode_result(sr, 10, 4, "b ww 2. www www b . w ww",
+ 10, /* wct */
+ 4, 0, /* tpscnt tdscnt */
+ 4, pos, 0, /* pscnt psoff psdisp */
+ 0, 0, 0, /* dscnt dsoff dsdisp */
+ 0, /* suwcnt */
+ 4, /* bcc */
+ rc,
+ 0); /* converter word? */
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+int
+smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc, pos;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+ uint16_t opcode;
+ uint16_t nt_unknown_secret = 0x0100;
+ char *fmt;
+
+ n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
+ n_setup++;
+ n_setup = n_setup & ~0x0001;
+ n_param = (xa->smb_mprcnt < smb_maxbufsize)
+ ? xa->smb_mprcnt : smb_maxbufsize;
+ n_param++;
+ n_param = n_param & ~0x0001;
+ rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
+ n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
+ MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
+ MBC_INIT(&xa->rep_param_mb, n_param);
+ MBC_INIT(&xa->rep_data_mb, n_data);
+
+ if (smb_decode_mbc(&xa->req_setup_mb, "w", &opcode) != 0)
+ goto trans_err_not_supported;
+
+ /*
+ * Save this for /proc to read later.
+ */
+ xa->smb_func = opcode;
+
+ /* for now, only respond to the */
+ switch (opcode) {
+ case TRANS2_CREATE_DIRECTORY:
+ rc = smb_com_trans2_create_directory(sr, xa);
+ break;
+
+ case TRANS2_FIND_FIRST2:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_find_first2(sr, xa);
+ break;
+
+ case TRANS2_FIND_NEXT2:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_find_next2(sr, xa);
+ break;
+
+ case TRANS2_QUERY_FS_INFORMATION:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_query_fs_information(sr, xa);
+ break;
+
+ case TRANS2_QUERY_PATH_INFORMATION:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_query_path_information(sr, xa);
+ break;
+
+ case TRANS2_QUERY_FILE_INFORMATION:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_query_file_information(sr, xa);
+ break;
+
+ case TRANS2_SET_PATH_INFORMATION:
+ rc = smb_com_trans2_set_path_information(sr, xa);
+ break;
+
+ case TRANS2_SET_FILE_INFORMATION:
+ rc = smb_com_trans2_set_file_information(sr, xa);
+ break;
+ default:
+ goto trans_err_not_supported;
+ }
+
+ switch (rc) {
+ case SDRC_NORMAL_REPLY:
+ break;
+
+ case SDRC_DROP_VC:
+ case SDRC_NO_REPLY:
+ case SDRC_ERROR_REPLY:
+ return (rc);
+
+ case SDRC_UNIMPLEMENTED:
+ case SDRC_UNSUPPORTED:
+ goto trans_err_not_supported;
+
+ default:
+ break;
+ }
+
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&xa->rep_param_mb);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ if (xa->smb_msrcnt < n_setup ||
+ xa->smb_mprcnt < n_param ||
+ xa->smb_mdrcnt < n_data) {
+ goto trans_err_too_small;
+ }
+
+ /* neato, blast it over there */
+
+ n_setup = (n_setup + 1) / 2; /* Conver to setup words */
+ param_pad = 1; /* must be one */
+ param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
+
+ /*
+ * Including the nt_unknown_secret value persuades netmon to
+ * display the correct data format for QueryPathInfo and
+ * QueryFileInfo.
+ */
+ if (opcode == TRANS2_QUERY_FILE_INFORMATION ||
+ opcode == TRANS2_QUERY_PATH_INFORMATION) {
+ data_pad = sizeof (uint16_t);
+ data_off = param_off + n_param + data_pad;
+ fmt = "b ww 2. www www b . C w #. C w C";
+ nt_unknown_secret = 0x0100;
+ }
+ else
+ {
+ data_pad = (param_off + n_param) & 1; /* Pad to short */
+ /* Param off from hdr start */
+ data_off = param_off + n_param + data_pad;
+ fmt = "b ww 2. www www b . C w #. C #. C";
+ /*LINTED E_ASSIGN_NARROW_CONV*/
+ nt_unknown_secret = data_pad;
+ }
+
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ smbsr_encode_result(sr, 10+n_setup, total_bytes,
+ fmt,
+ 10 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data /* + data_pad */, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data /* + data_pad */, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ nt_unknown_secret,
+ &xa->rep_data_mb);
+ return (SDRC_NORMAL_REPLY);
+
+trans_err_too_small:
+ rc = NERR_BufTooSmall;
+ goto trans_err;
+
+trans_err_not_supported:
+ rc = ERROR_NOT_SUPPORTED;
+ goto trans_err;
+
+trans_err:
+ pos = MBC_LENGTH(&sr->reply) + 23;
+ smbsr_encode_result(sr, 10, 4, "b ww 2. www www b . w ww",
+ 10, /* wct */
+ 4, 0, /* tpscnt tdscnt */
+ 4, pos, 0, /* pscnt psoff psdisp */
+ 0, 0, 0, /* dscnt dsoff dsdisp */
+ 0, /* suwcnt */
+ 4, /* bcc */
+ rc,
+ 0); /* converter word? */
+ return (SDRC_NORMAL_REPLY);
+}
+
+smb_xa_t *
+smb_xa_create(
+ smb_session_t *session,
+ smb_request_t *sr,
+ uint32_t total_parameter_count,
+ uint32_t total_data_count,
+ uint32_t max_parameter_count,
+ uint32_t max_data_count,
+ uint32_t max_setup_count,
+ uint32_t setup_word_count)
+{
+ smb_xa_t *xa, *nxa;
+ smb_llist_t *xlist;
+
+ xa = MEM_ZALLOC("xa", sizeof (smb_xa_t));
+ xa->xa_refcnt = 1;
+ xa->smb_com = sr->smb_com;
+ xa->smb_flg = sr->smb_flg;
+ xa->smb_flg2 = sr->smb_flg2;
+ xa->smb_tid = sr->smb_tid;
+ xa->smb_pid = sr->smb_pid;
+ xa->smb_uid = sr->smb_uid;
+ xa->xa_smb_mid = sr->smb_mid;
+ xa->reply_seqnum = sr->reply_seqnum;
+ xa->smb_tpscnt = total_parameter_count;
+ xa->smb_tdscnt = total_data_count;
+ xa->smb_mprcnt = max_parameter_count;
+ xa->smb_mdrcnt = max_data_count;
+ xa->smb_msrcnt = max_setup_count;
+ xa->smb_suwcnt = setup_word_count;
+ xa->xa_session = session;
+ xa->xa_magic = SMB_XA_MAGIC;
+
+ /*
+ * The new xa structure is checked against the current list to see
+ * if it exists already.
+ */
+ xlist = &session->s_xa_list;
+ smb_llist_enter(xlist, RW_WRITER);
+ nxa = smb_llist_head(xlist);
+ while (nxa) {
+ ASSERT(nxa->xa_magic == SMB_XA_MAGIC);
+ if (nxa->xa_smb_mid == xa->xa_smb_mid &&
+ nxa->smb_pid == xa->smb_pid &&
+ !SMB_XA_CLOSED(nxa) &&
+ !(nxa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
+ smb_llist_exit(xlist);
+ MEM_FREE("xa", xa);
+ return (NULL);
+ }
+ nxa = smb_llist_next(xlist, nxa);
+ }
+ smb_llist_insert_tail(xlist, xa);
+ smb_llist_exit(xlist);
+ return (xa);
+}
+
+void
+smb_xa_delete(smb_xa_t *xa)
+{
+ ASSERT(xa->xa_refcnt == 0);
+ ASSERT(SMB_XA_CLOSED(xa));
+
+ if (xa->xa_smb_trans_name)
+ MEM_FREE("smb", xa->xa_smb_trans_name);
+
+ if (xa->rep_setup_mb.chain != NULL)
+ m_freem(xa->rep_setup_mb.chain);
+ if (xa->rep_param_mb.chain != NULL)
+ m_freem(xa->rep_param_mb.chain);
+ if (xa->rep_data_mb.chain != NULL)
+ m_freem(xa->rep_data_mb.chain);
+
+ xa->xa_magic = (uint32_t)~SMB_XA_MAGIC;
+ MEM_FREE("xa", xa);
+}
+
+smb_xa_t *
+smb_xa_hold(smb_xa_t *xa)
+{
+ mutex_enter(&xa->xa_mutex);
+ xa->xa_refcnt++;
+ ASSERT(xa->xa_refcnt);
+ mutex_exit(&xa->xa_mutex);
+ return (xa);
+}
+
+void
+smb_xa_rele(smb_session_t *session, smb_xa_t *xa)
+{
+ mutex_enter(&xa->xa_mutex);
+ ASSERT(xa->xa_refcnt);
+ xa->xa_refcnt--;
+ if (SMB_XA_CLOSED(xa) && (xa->xa_refcnt == 0)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_llist_enter(&session->s_xa_list, RW_WRITER);
+ smb_llist_remove(&session->s_xa_list, xa);
+ smb_llist_exit(&session->s_xa_list);
+ smb_xa_delete(xa);
+ return;
+ }
+ mutex_exit(&xa->xa_mutex);
+}
+
+int
+smb_xa_open(smb_xa_t *xa)
+{
+ int rc;
+
+ mutex_enter(&xa->xa_mutex);
+
+ ASSERT((xa->xa_flags & SMB_XA_FLAG_OPEN) == 0);
+
+ if ((xa->xa_flags & SMB_XA_FLAG_CLOSE) == 0) {
+ xa->xa_flags |= SMB_XA_FLAG_OPEN;
+ rc = 0;
+ } else {
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ mutex_exit(&xa->xa_mutex);
+
+ return (rc);
+}
+
+void
+smb_xa_close(smb_xa_t *xa)
+{
+ mutex_enter(&xa->xa_mutex);
+ xa->xa_flags |= SMB_XA_FLAG_CLOSE;
+ xa->xa_flags &= ~SMB_XA_FLAG_OPEN;
+
+ if (xa->xa_refcnt == 0) {
+ mutex_exit(&xa->xa_mutex);
+ smb_llist_enter(&xa->xa_session->s_xa_list, RW_WRITER);
+ smb_llist_remove(&xa->xa_session->s_xa_list, xa);
+ smb_llist_exit(&xa->xa_session->s_xa_list);
+ smb_xa_delete(xa);
+ return;
+ }
+
+ mutex_exit(&xa->xa_mutex);
+}
+
+int
+smb_xa_complete(smb_xa_t *xa)
+{
+ int rc;
+
+ mutex_enter(&xa->xa_mutex);
+ if (xa->xa_flags & (SMB_XA_FLAG_COMPLETE | SMB_XA_FLAG_CLOSE)) {
+ rc = 0;
+ } else {
+ rc = 1;
+ xa->xa_flags |= SMB_XA_FLAG_COMPLETE;
+ }
+ mutex_exit(&xa->xa_mutex);
+ return (rc);
+}
+
+smb_xa_t *
+smb_xa_find(
+ smb_session_t *session,
+ uint16_t pid,
+ uint16_t mid)
+{
+ smb_xa_t *xa;
+ smb_llist_t *xlist;
+
+ xlist = &session->s_xa_list;
+ smb_llist_enter(xlist, RW_READER);
+ xa = smb_llist_head(xlist);
+ while (xa) {
+ mutex_enter(&xa->xa_mutex);
+ if (xa->xa_smb_mid == mid &&
+ xa->smb_pid == pid &&
+ !SMB_XA_CLOSED(xa) &&
+ !(xa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
+ xa->xa_refcnt++;
+ ASSERT(xa->xa_refcnt);
+ mutex_exit(&xa->xa_mutex);
+ break;
+ }
+ mutex_exit(&xa->xa_mutex);
+ xa = smb_llist_next(xlist, xa);
+ }
+ smb_llist_exit(xlist);
+ return (xa);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_tree.c b/usr/src/uts/common/fs/smbsrv/smb_common_tree.c
new file mode 100644
index 0000000000..7906233a35
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_tree.c
@@ -0,0 +1,397 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Common code for tree connections.
+ */
+
+#include <sys/errno.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_door_svc.h>
+
+
+#define SMB_TREE_EMSZ 64
+
+#define ADMINISTRATORS_SID "S-1-5-32-544"
+
+int smb_tcon_mute = 0;
+
+
+int smbsr_setup_share(struct smb_request *, char *, int32_t, char *);
+void smbsr_share_report(struct smb_request *, char *, char *, char *);
+int smb_get_stype(const char *, const char *, int32_t *);
+
+
+/*
+ * smbsr_connect_tree
+ *
+ * Set up a share. A Uniform Naming Convention (UNC) string is suppose to
+ * be in the form: \\HOST\SHARENAME. A sharename alone is also acceptable.
+ * We don't actually audit the host, we just ensure that the \ are present
+ * and extract the share name. Share names are case insensitive so we map
+ * the share name to lower-case. So it is important that all internal
+ * mechanisms (user interface, etc. use lower-case names.
+ */
+int
+smbsr_connect_tree(struct smb_request *sr)
+{
+ char errmsg[SMB_TREE_EMSZ];
+ char *sharename;
+ char *access_msg;
+ int32_t stype;
+ int rc;
+
+ errmsg[0] = '\0';
+ (void) utf8_strlwr(sr->arg.tcon.path);
+ sharename = sr->arg.tcon.path;
+
+ if (sharename[0] == '\\') {
+ /*
+ * Looks like a UNC path, make sure the format is correct.
+ */
+ if (sharename[1] != '\\') {
+ smbsr_raise_error(sr, ERRSRV, ERRinvnetname);
+ /* NOTREACHED */
+ }
+
+ if ((sharename = strchr(sharename+2, '\\')) == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRinvnetname);
+ /* NOTREACHED */
+ }
+
+ ++sharename;
+ } else if (strchr(sharename, '\\')) {
+ /*
+ * This should be a sharename: no embedded '\' allowed.
+ */
+ smbsr_raise_error(sr, ERRSRV, ERRinvnetname);
+ /* NOTREACHED */
+ }
+
+ if (smb_get_stype(sharename, sr->arg.tcon.service, &stype) != 0) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
+ ERRDOS, ERROR_BAD_DEV_TYPE);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smbsr_setup_share(sr, sharename, stype, errmsg)) != 0) {
+ access_msg = "access denied";
+ smbsr_share_report(sr, sharename, access_msg, errmsg);
+
+ /*
+ * W2K sometimes tries to connect to user shares using an
+ * anonymous IPC connection. NT returns access denied.
+ */
+ if (rc == ERRaccess)
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRSRV, ERRaccess);
+ else
+ smbsr_raise_error(sr, ERRSRV, rc);
+ /* NOTREACHED */
+ }
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ access_msg = "ro access granted";
+ else
+ access_msg = "rw access granted";
+
+ smbsr_share_report(sr, sharename, access_msg, errmsg);
+ }
+
+ return (rc);
+}
+
+
+/*
+ * smbsr_share_report
+ *
+ * Report share access result to syslog.
+ */
+/*ARGSUSED*/
+void
+smbsr_share_report(struct smb_request *sr, char *sharename,
+ char *access_msg, char *errmsg)
+{
+ smb_user_t *user;
+
+ user = sr->uid_user;
+ ASSERT(user);
+
+ if (smb_tcon_mute)
+ return;
+
+ if (user->u_name) {
+ /*
+ * Only report normal users, i.e. ignore W2K misuse
+ * of the IPC connection by filtering out internal
+ * names such as nobody and root.
+ */
+ if ((strcmp(user->u_name, "root") == 0) ||
+ (strcmp(user->u_name, "nobody") == 0)) {
+ return;
+ }
+ }
+
+ cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
+ user->u_domain, user->u_name, sharename, access_msg);
+}
+
+/*
+ * smbsr_setup_share
+ *
+ * This is where the real of setting up share is done. The main thing
+ * to note is that we resolve ambiguities by assuming that a directory is
+ * being requested. This function returns error codes, rather than calling
+ * smbsr_raise_error. We return 0 on success or a non-zero error code if
+ * there is a problem.
+ */
+int
+smbsr_setup_share(struct smb_request *sr, char *sharename, int32_t stype,
+ char *errmsg)
+{
+ smb_node_t *dir_snode = NULL;
+ smb_node_t *snode = NULL;
+ char last_component[MAXNAMELEN];
+ smb_tree_t *tree;
+ char *resource;
+ uint16_t access = SMB_TREE_READ_WRITE;
+ int rc;
+ lmshare_info_t si;
+ nt_sid_t *sid;
+ fsvol_attr_t vol_attr;
+ smb_attr_t attr;
+ int is_admin;
+ smb_user_t *user = sr->uid_user;
+ cred_t *u_cred;
+
+ ASSERT(user);
+ u_cred = user->u_cred;
+ ASSERT(u_cred);
+
+ bzero(&si, sizeof (lmshare_info_t));
+
+ /*
+ * XXX Host based access control check to go here.
+ */
+
+ if (STYPE_ISIPC(stype)) {
+ if ((user->u_flags & SMB_USER_FLAG_IPC) &&
+ smb_info.si.skc_restrict_anon) {
+ (void) strlcpy(errmsg, "anonymous access restricted",
+ SMB_TREE_EMSZ);
+ return (ERRaccess);
+ }
+
+ bzero(&vol_attr, sizeof (fsvol_attr_t));
+ resource = sharename;
+ sr->arg.tcon.service = "IPC";
+
+ tree = smb_tree_connect(sr->uid_user, access,
+ sharename, resource, stype, 0, &vol_attr);
+
+ if (tree == NULL)
+ return (ERRaccess);
+
+ sr->smb_tid = tree->t_tid;
+ sr->tid_tree = tree;
+ return (0);
+ }
+
+ /*
+ * From here on we can assume that this is a disk share.
+ */
+ ASSERT(STYPE_ISDSK(stype));
+
+ if (user->u_flags & SMB_USER_FLAG_IPC) {
+ (void) strlcpy(errmsg, "IPC only", SMB_TREE_EMSZ);
+ return (ERRaccess);
+ }
+
+ /*
+ * Handle the default administration shares: C$, D$ etc.
+ * Only a user with admin rights is allowed to map these
+ * shares.
+ */
+ if ((is_admin = lmshrd_is_admin(sharename)) == NERR_InternalError) {
+ (void) strlcpy(errmsg, "internal error", SMB_TREE_EMSZ);
+ return (ERRaccess);
+ }
+
+ if (is_admin) {
+ sid = nt_sid_strtosid(ADMINISTRATORS_SID);
+ if (sid) {
+ rc = smb_cred_is_member(u_cred, sid);
+ MEM_FREE("smbsrv", sid);
+ if (rc == 0) {
+ (void) strlcpy(errmsg,
+ "not administrator", SMB_TREE_EMSZ);
+ return (ERRaccess);
+ }
+ }
+ }
+
+ if (lmshrd_getinfo(sharename, &si) != NERR_Success) {
+ (void) strlcpy(errmsg, "share not found", SMB_TREE_EMSZ);
+ return (ERRinvnetname);
+ }
+
+ resource = si.directory;
+ sr->arg.tcon.service = "A:";
+
+#ifdef HOST_ACCESS
+ /*
+ * XXX This needs some sharemgr work
+ */
+ if (hostaccess == APRV_ACC_RO)
+ access = SMB_TREE_READ_ONLY;
+#endif /* HOST_ACCESS */
+
+ /*
+ * No password or password OK. Now check that the directory
+ * actually exists.
+ *
+ * The snode reference from smb_pathname_reduce() will not be
+ * released in this routine (except in an error path) because
+ * trees need a reference to their root node. The reference
+ * will be released upon tree deallocation.
+ */
+
+ rc = smb_pathname_reduce(sr, u_cred, resource, 0, 0, &dir_snode,
+ last_component);
+
+ if (rc) {
+ (void) strlcpy(errmsg, "smb_pathname_reduce", SMB_TREE_EMSZ);
+ return (ERRinvnetname);
+ }
+
+ rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS, 0, dir_snode,
+ last_component, &snode, &attr, 0, 0);
+
+ smb_node_release(dir_snode);
+
+ if (rc) {
+ (void) strlcpy(errmsg, "smb_fsop_lookup", SMB_TREE_EMSZ);
+ rc = ERRinvnetname;
+ goto error_out;
+ }
+
+ if ((rc = fsd_getattr(&snode->tree_fsd, &vol_attr)) != 0) {
+ (void) strlcpy(errmsg, "fsd_getattr", SMB_TREE_EMSZ);
+ rc = ERRinvnetname;
+ goto error_out;
+ }
+
+ tree = smb_tree_connect(sr->uid_user, access,
+ sharename, resource, stype, snode, &vol_attr);
+
+ if (tree == NULL) {
+ rc = ERRaccess;
+ goto error_out;
+ }
+
+ sr->smb_tid = tree->t_tid;
+ sr->tid_tree = tree;
+ return (0);
+
+error_out:
+ if (snode)
+ smb_node_release(snode);
+
+ return (rc);
+}
+
+/*
+ * smb_get_stype
+ *
+ * Map the service to a resource type. Valid values for service
+ * (CIFS/1.0 section 4.1.4) are:
+ *
+ * A: Disk share
+ * LPT1: Printer
+ * IPC Named pipe
+ * COMM Communications device
+ * ????? Any type of device (wildcard)
+ *
+ * We support IPC and disk shares; anything else is currently treated
+ * as an error. IPC$ is reserved as the named pipe share.
+ */
+int
+smb_get_stype(const char *sharename, const char *service, int32_t *stype_ret)
+{
+ const char *any = "?????";
+
+ if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) {
+ if (strcasecmp(sharename, "IPC$") == 0) {
+ *stype_ret = STYPE_IPC;
+ return (0);
+ }
+ }
+
+ if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) {
+ if (strcasecmp(sharename, "IPC$") == 0)
+ return (-1);
+
+ *stype_ret = STYPE_DISKTREE;
+ return (0);
+ }
+
+ return (-1);
+}
+
+/*
+ * smbsr_rq_notify
+ *
+ * Notify all requests, except sr, associated with the specified tree
+ * that it's time to complete.
+ * It's assumed that the tree has already been clipped from the session
+ * list so that no new requests can be added to the list while we're in
+ * here.
+ *
+ * Note that sr may be null.
+ *
+ * Returns:
+ */
+void
+smbsr_rq_notify(smb_request_t *sr, smb_session_t *session, smb_tree_t *tree)
+{
+ struct smb_request *asr;
+
+ smb_slist_enter(&session->s_req_list);
+ asr = smb_slist_head(&session->s_req_list);
+ while (asr) {
+ ASSERT(asr->sr_magic == SMB_REQ_MAGIC);
+ if ((asr != sr) && (asr->tid_tree == tree)) {
+ smb_request_cancel(asr);
+ }
+ asr = smb_slist_next(&session->s_req_list, asr);
+ }
+ smb_slist_exit(&session->s_req_list);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_copy.c b/usr/src/uts/common/fs/smbsrv/smb_copy.c
new file mode 100644
index 0000000000..4b33818eab
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_copy.c
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: copy_file
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 3
+ * USHORT Tid2; Second (target) path TID
+ * USHORT OpenFunction; What to do if target file exists
+ * USHORT Flags; Flags to control copy operation:
+ * bit 0 - target must be a file
+ * bit 1 - target must be a dir.
+ * bit 2 - copy target mode:
+ * 0 = binary, 1 = ASCII
+ * bit 3 - copy source mode:
+ * 0 = binary, 1 = ASCII
+ * bit 4 - verify all writes
+ * bit 5 - tree copy
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR SourceFileNameFormat; 0x04
+ * STRING SourceFileName; Pathname of source file
+ * UCHAR TargetFileNameFormat; 0x04
+ * STRING TargetFileName; Pathname of target file
+ *
+ * The file at SourceName is copied to TargetFileName, both of which must refer
+ * to paths on the same server.
+ *
+ * The Tid in the header is associated with the source while Tid2 is
+ * associated with the destination. These fields may contain the same or
+ * differing valid values. Tid2 can be set to -1 indicating that this is to
+ * be the same Tid as in the SMB header. This allows use of the move
+ * protocol with SMB_TREE_CONNECT_ANDX.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Count; Number of files copied
+ * USHORT ByteCount; Count of data bytes; min = 0
+ * UCHAR ErrorFileFormat; 0x04 (only if error)
+ * STRING ErrorFileName;
+ *
+ * The source path must refer to an existing file or files. Wildcards are
+ * permitted. Source files specified by wildcards are processed until an
+ * error is encountered. If an error is encountered, the expanded name of
+ * the file is returned in ErrorFileName. Wildcards are not permitted in
+ * TargetFileName. TargetFileName can refer to either a file or a direc-
+ * tory.
+ *
+ * The destination can be required to be a file or a directory by the bits
+ * in Flags. If neither bit0 nor bit1 are set, the destination may be
+ * either a file or a directory. Flags also controls the copy mode. In a
+ * ascii copy for the source, the copy stops the first time an EOF
+ * (control-Z) is encountered. In a ascii copy for the target, the server
+ *
+ * must make sure that there is exactly one EOF in the target file and that
+ * it is the last character of the file.
+ *
+ * If the destination is a file and the source contains wildcards, the
+ * destination file will either be truncated or appended to at the start of
+ * the operation depending on bits in OpenFunction (see section 3.7).
+ * Subsequent files will then be appended to the file.
+ *
+ * If the negotiated dialect is LM1.2X002 or later, bit5 of Flags is used
+ * to specify a tree copy on the remote server. When this option is
+ * selected the destination must not be an existing file and the source
+ * mode must be binary. A request with bit5 set and either bit0 or bit3
+ * set is therefore an error. When the tree copy mode is selected, the
+ * Count field in the server response is undefined.
+ *
+ * 4.2.13.1 Errors
+ *
+ * ERRDOS/ERRfilexists
+ * ERRDOS/ERRshare
+ * ERRDOS/ERRnofids
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRnofiles
+ * ERRDOS/ERRbadshare
+ * ERRSRV/ERRnoaccess
+ * ERRSRV/ERRinvdevice
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ * ERRSRV/ERRaccess
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*ARGSUSED*/
+int
+smb_com_copy(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create.c b/usr/src/uts/common/fs/smbsrv/smb_create.c
new file mode 100644
index 0000000000..fccdf5ba9e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_create.c
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+#define SMB_CREATE_NAMEBUF_SZ 16
+
+static uint32_t smb_common_create(struct smb_request *sr);
+
+/*
+ * Create a new file, or truncate an existing file to zero length,
+ * open the file and return a fid. The file is specified using a
+ * fully qualified name relative to the tree.
+ */
+int
+smb_com_create(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint32_t status;
+
+ bzero(op, sizeof (sr->arg.open));
+
+ if (smbsr_decode_vwv(sr, "wl", &op->dattr, &op->utime.tv_sec) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ op->create_disposition = FILE_OVERWRITE_IF;
+ status = smb_common_create(sr);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ break;
+
+ case NT_STATUS_SHARING_VIOLATION:
+ smbsr_raise_cifs_error(sr, NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ break;
+
+ default:
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ break;
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Create a new file and return a fid. The file is specified using
+ * a fully qualified name relative to the tree.
+ */
+int
+smb_com_create_new(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint32_t status;
+
+ bzero(op, sizeof (sr->arg.open));
+
+ if (smbsr_decode_vwv(sr, "wl", &op->dattr, &op->utime.tv_sec) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ op->create_disposition = FILE_CREATE;
+ status = smb_common_create(sr);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ break;
+
+ case NT_STATUS_SHARING_VIOLATION:
+ smbsr_raise_cifs_error(sr, NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ break;
+
+ default:
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ break;
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * Create a unique file in the specified directory relative to the
+ * current tree. No attributes are specified.
+ */
+int
+smb_com_create_temporary(struct smb_request *sr)
+{
+ static uint16_t tmp_id = 10000;
+ struct open_param *op = &sr->arg.open;
+ char name[SMB_CREATE_NAMEBUF_SZ];
+ char *buf;
+ uint32_t status;
+ uint16_t reserved;
+ uint16_t bcc;
+
+ bzero(op, sizeof (sr->arg.open));
+
+ if (smbsr_decode_vwv(sr, "wl", &reserved, &op->utime.tv_sec) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ++tmp_id;
+ bcc = 1; /* null terminator */
+ bcc += snprintf(name, SMB_CREATE_NAMEBUF_SZ, "tt%05d.tmp", tmp_id);
+
+ buf = smbsr_malloc(&sr->request_storage, MAXPATHLEN);
+ (void) snprintf(buf, MAXPATHLEN, "%s\\%s", op->fqi.path, name);
+ op->fqi.path = buf;
+ op->create_disposition = FILE_CREATE;
+ status = smb_common_create(sr);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ break;
+
+ case NT_STATUS_SHARING_VIOLATION:
+ smbsr_raise_cifs_error(sr, NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ break;
+
+ default:
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ break;
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bwwwbs", 1, sr->smb_fid, bcc, 4, name);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Common create file function. The file is opened in compatibility
+ * mode with read/write access.
+ */
+uint32_t
+smb_common_create(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint32_t status;
+
+ op->utime.tv_sec = smb_local_time_to_gmt(op->utime.tv_sec);
+ op->utime.tv_nsec = 0;
+ op->omode = SMB_DA_ACCESS_READ_WRITE | SMB_DA_SHARE_COMPATIBILITY;
+ op->desired_access = smb_omode_to_amask(op->omode);
+ op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
+
+ if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
+ (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->dsize = 0;
+
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
+ op->my_flags = MYF_BATCH_OPLOCK;
+ } else {
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ }
+ }
+
+ status = smb_open_subr(sr);
+
+ if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
+ sr->smb_flg &=
+ ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
+ }
+
+ return (status);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create_directory.c b/usr/src/uts/common/fs/smbsrv/smb_create_directory.c
new file mode 100644
index 0000000000..e369f59b47
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_create_directory.c
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: create_directory
+ *
+ * The create directory message is sent to create a new directory. The
+ * appropriate Tid and additional pathname are passed. The directory must
+ * not exist for it to be created.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryName[]; Directory name
+ *
+ * Servers require clients to have at least create permission for the
+ * subtree containing the directory in order to create a new directory.
+ * The creator's access rights to the new directory are be determined by
+ * local policy on the server.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ *
+ * USHORT ByteCount; Count of data bytes = 0
+ */
+
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+typedef struct smb_request SmbRequest;
+
+typedef struct {
+ char *sp_path; /* Original path */
+ char *sp_curp; /* Current pointer into the original path */
+ SmbRequest *sp_sr; /* Current request pointer */
+} SmbPath;
+
+
+extern int smb_common_create_directory(struct smb_request *sr);
+
+
+static int smbpath_next(SmbPath* spp);
+static SmbPath* smbpath_new(SmbRequest* sr);
+
+
+/*
+ * smb_com_create_directory
+ *
+ * It is possible to get a full pathname here and the client expects any
+ * or all of the components to be created if they don't already exist.
+ */
+int
+smb_com_create_directory(struct smb_request *sr)
+{
+ SmbPath* spp;
+ DWORD status;
+ int rc = 0;
+
+ if (smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((status = smb_validate_dirname(sr->arg.dirop.fqi.path)) != 0) {
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_raise_nt_error(sr, status);
+ else
+ smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_NAME);
+
+ /* NOTREACHED */
+ }
+
+ /*
+ * Try each component of the path. It is all right to get an EEXIST
+ * on each component except the last.
+ */
+ spp = smbpath_new(sr);
+
+ while (smbpath_next(spp)) {
+ rc = smb_common_create_directory(sr);
+ if (rc != 0 && rc != EEXIST)
+ smbsr_raise_errno(sr, rc);
+ }
+
+ /* We should have created one directory successfully! */
+ if (rc != 0)
+ smbsr_raise_errno(sr, rc);
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_validate_dirname
+ *
+ * Very basic directory name validation: checks for colons in a path.
+ * Need to skip the drive prefix since it contains a colon.
+ *
+ * Returns 0 if the name is valid, otherwise NT_STATUS_NOT_A_DIRECTORY.
+ */
+DWORD
+smb_validate_dirname(char *path)
+{
+ char *name;
+
+ if ((name = path) != 0) {
+ name += strspn(name, "\\");
+
+ if (strchr(name, ':') != 0)
+ return (NT_STATUS_NOT_A_DIRECTORY);
+ }
+
+ return (0);
+}
+
+
+/*
+ * smb_common_create_directory
+ *
+ * Currently called from:
+ * smb_com_create_directory
+ * smb_com_trans2_create_directory
+ *
+ * Returns errno values.
+ */
+int
+smb_common_create_directory(struct smb_request *sr)
+{
+ int rc;
+ smb_attr_t new_attr;
+ struct smb_node *dnode;
+ struct smb_node *node;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_NOT_EXIST);
+ if (rc)
+ return (rc);
+
+ /*
+ * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
+ * value, only fqi.dir_snode has a valid parameter (fqi.last_snode
+ * is NULL).
+ */
+ dnode = sr->arg.dirop.fqi.dir_snode;
+
+ bzero(&new_attr, sizeof (new_attr));
+ new_attr.sa_vattr.va_type = VDIR;
+ new_attr.sa_vattr.va_mode = 0777;
+ new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE;
+
+ if ((rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
+ sr->arg.dirop.fqi.last_comp, &new_attr,
+ &sr->arg.dirop.fqi.last_snode,
+ &sr->arg.dirop.fqi.last_attr)) != 0) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ return (rc);
+ }
+
+ node = sr->arg.dirop.fqi.last_snode;
+ node->flags |= NODE_FLAGS_CREATED;
+
+ sr->arg.open.create_options = FILE_DIRECTORY_FILE;
+
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ return (0);
+}
+
+SmbPath*
+smbpath_new(SmbRequest* sr)
+{
+ int pathLen;
+ char *xpath;
+ SmbPath *spp;
+
+ /* Malloc from the request storage area. This is freed automatically */
+ /* so we don't need to worry about freeing it later */
+ spp = smbsr_malloc(&sr->request_storage, sizeof (SmbPath));
+ spp->sp_path = sr->arg.dirop.fqi.path;
+ pathLen = strlen(spp->sp_path);
+ spp->sp_curp = spp->sp_path;
+ xpath = smbsr_malloc(&sr->request_storage, pathLen + 1);
+ sr->arg.dirop.fqi.path = xpath;
+ spp->sp_sr = sr;
+
+ return (spp);
+}
+
+/*
+ * Perhaps somewhat dangerous since everything happens as a side effect. The
+ * returns 1 if there is a valid component updated to the fqi, 0 otherwise.
+ */
+int
+smbpath_next(SmbPath* spp)
+{
+ char *xp;
+ int xlen;
+
+ if (spp == 0)
+ return (0);
+
+ /* Move the index to the "next" "\" and copy the path to the fqi */
+ /* path for the next component. */
+
+ /* First look for the next component */
+ while (*spp->sp_curp == '\\')
+ spp->sp_curp++;
+
+ /* Now get to the end of the component */
+ xp = spp->sp_curp; /* Remember from where we started */
+ while (*spp->sp_curp != '\0' && *spp->sp_curp != '\\') {
+ spp->sp_curp++;
+ }
+
+ /* If we made no progress, we are done */
+ if (xp == spp->sp_curp)
+ return (0);
+
+ /*
+ * Now copy the original path up to but not including our current
+ * pointer
+ */
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ xlen = spp->sp_curp - spp->sp_path;
+ (void) strncpy(spp->sp_sr->arg.dirop.fqi.path, spp->sp_path, xlen);
+
+ /* Now NULL terminate it */
+ spp->sp_sr->arg.dirop.fqi.path[xlen] = '\0';
+ return (1);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete.c b/usr/src/uts/common/fs/smbsrv/smb_delete.c
new file mode 100644
index 0000000000..f35e3c4273
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c
@@ -0,0 +1,354 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smbinfo.h>
+
+static DWORD smb_delete_check(struct smb_request *sr, struct smb_node *node,
+ uint16_t dattr, smb_error_t *smberr);
+static DWORD smb_delete_share_check(struct smb_node *node);
+
+/*
+ * smb_com_delete
+ *
+ * The delete file message is sent to delete a data file. The appropriate
+ * Tid and additional pathname are passed. Read only files may not be
+ * deleted, the read-only attribute must be reset prior to file deletion.
+ *
+ * NT supports a hidden permission known as File Delete Child (FDC). If
+ * the user has FullControl access to a directory, the user is permitted
+ * to delete any object in the directory regardless of the permissions
+ * on the object.
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT SearchAttributes;
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING FileName[]; File name
+ *
+ * Multiple files may be deleted in response to a single request as
+ * SMB_COM_DELETE supports wildcards
+ *
+ * SearchAttributes indicates the attributes that the target file(s) must
+ * have. If the attribute is zero then only normal files are deleted. If
+ * the system file or hidden attributes are specified then the delete is
+ * inclusive -both the specified type(s) of files and normal files are
+ * deleted. Attributes are described in the "Attribute Encoding" section
+ * of this document.
+ *
+ * If bit0 of the Flags2 field of the SMB header is set, a pattern is
+ * passed in, and the file has a long name, then the passed pattern much
+ * match the long file name for the delete to succeed. If bit0 is clear, a
+ * pattern is passed in, and the file has a long name, then the passed
+ * pattern must match the file's short name for the deletion to succeed.
+ *
+ * Server Response Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * 4.2.10.1 Errors
+ *
+ * ERRDOS/ERRbadpath
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRbadshare # returned by NT for files that are already open
+ * ERRHRD/ERRnowrite
+ * ERRSRV/ERRaccess
+ * ERRSRV/ERRinvdevice
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ */
+int
+smb_com_delete(struct smb_request *sr)
+{
+ int rc;
+ int od = 0;
+ int deleted = 0;
+ unsigned short sattr;
+ char *path;
+ struct smb_node *dir_snode;
+ struct smb_node *node = 0;
+ char *name;
+ char *fname;
+ char *sname;
+ char *fullname;
+ smb_error_t smberr;
+ int is_stream;
+ smb_odir_context_t *pc;
+
+ pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
+ fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+ if (smbsr_decode_vwv(sr, "w", &sattr) != 0) {
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ is_stream = smb_stream_parse_name(path, fname, sname);
+
+ (void) smb_rdir_open(sr, path, sattr);
+ dir_snode = sr->sid_odir->d_dir_snode;
+
+ /*
+ * This while loop is meant to deal with wildcards.
+ * It is not expected that wildcards will exist for
+ * streams. For the streams case, it is expected
+ * that the below loop will be executed only once.
+ */
+
+ while ((rc = smb_rdir_next(sr, &node, pc)) == 0) {
+ (void) strlcpy(name, pc->dc_name, MAXNAMELEN);
+
+ if (smb_delete_check(sr, node, pc->dc_dattr, &smberr)
+ != NT_STATUS_SUCCESS) {
+ smb_node_release(node);
+ goto delete_error;
+ }
+
+ smb_node_release(node);
+ node = NULL;
+
+ if (is_stream) {
+ /*
+ * It is assumed that fname does not contain
+ * any wildcards .
+ * smb_fsop_remove() requires filename+streamname
+ */
+ (void) snprintf(fullname, MAXPATHLEN, "%s%s",
+ fname, sname);
+ rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
+ fullname, 0);
+ } else {
+ /*
+ * name (i.e. pc->dc_name) is the on-disk name
+ * unless there is a case collision, in which
+ * case readdir will have returned a mangled name.
+ */
+ if (smb_maybe_mangled_name(name) == 0)
+ od = 1;
+
+ rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
+ name, od);
+ }
+
+ if (rc != 0) {
+ if (rc != ENOENT) {
+ smb_rdir_close(sr);
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ } else {
+ deleted++;
+ }
+ }
+
+ if ((rc != 0) && (rc != ENOENT)) {
+ /* rc returned by smb_rdir_next() */
+ smb_rdir_close(sr);
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (deleted == 0) {
+ smberr.errcls = ERRDOS;
+ smberr.errcode = ERROR_FILE_NOT_FOUND;
+ smberr.status = (sr->sid_odir->d_wildcards == 0)
+ ? NT_STATUS_OBJECT_NAME_NOT_FOUND : NT_STATUS_NO_SUCH_FILE;
+ goto delete_error;
+ }
+
+ smb_rdir_close(sr);
+
+ smbsr_encode_empty_result(sr);
+
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ return (SDRC_NORMAL_REPLY);
+
+delete_error:
+ smb_rdir_close(sr);
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_raise_cifs_error(sr,
+ smberr.status, smberr.errcls, smberr.errcode);
+ /* NOTREACHED */
+ return (SDRC_NORMAL_REPLY); /* compiler complains otherwise */
+}
+
+static DWORD
+smb_delete_check(
+ struct smb_request *sr,
+ struct smb_node *node,
+ uint16_t dattr,
+ smb_error_t *smberr)
+{
+ if (dattr & SMB_FA_DIRECTORY) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ smberr->status = NT_STATUS_FILE_IS_A_DIRECTORY;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ if ((dattr & SMB_FA_READONLY) ||
+ (node->flags & NODE_CREATED_READONLY)) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ smberr->status = NT_STATUS_CANNOT_DELETE;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * NT does not always close a file immediately, which
+ * can cause the share and access checking to fail
+ * (the node refcnt is greater than one), and the file
+ * doesn't get deleted. Breaking the oplock before
+ * share and access checking gives the client a chance
+ * to close the file.
+ */
+ if (OPLOCKS_IN_FORCE(node)) {
+ smberr->status = smb_break_oplock(sr, node);
+
+ if (smberr->status != NT_STATUS_SUCCESS) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_VC_DISCONNECTED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+ }
+
+ smberr->status = smb_delete_share_check(node);
+ if (smberr->status == NT_STATUS_SHARING_VIOLATION) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_SHARING_VIOLATION;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * This should be done after Share checking due to tests with
+ * W2K. I got sharing violation error trying to delete a
+ * locked file which is basically the same error if you
+ * try to delete a non-locked open file.
+ *
+ * One thing that I discovered during these tests is that
+ * W2K rejects lock requests on open files which are opened
+ * with Metadata open modes. The error is STATUS_ACCESS_DENIED.
+ */
+ if (smb_lock_range_access(sr, node, 0, 0, FILE_WRITE_DATA) !=
+ NT_STATUS_SUCCESS) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ smberr->status = NT_STATUS_ACCESS_DENIED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_delete_share_check
+ *
+ * An open file can be deleted only if opened for
+ * accessing meta data. Share modes aren't important
+ * in this case.
+ *
+ * NOTE: there is another mechanism for deleting an
+ * open file that NT clients usually use this method.
+ * That's setting "Delete on close" flag for an open
+ * file, in this way the file will be deleted after
+ * last close. This flag can be set by SmbTrans2SetFileInfo
+ * with FILE_DISPOSITION_INFO information level.
+ * For setting this flag file should be opened by
+ * DELETE access in the FID that is passed in the Trans2
+ * request.
+ */
+static DWORD
+smb_delete_share_check(struct smb_node *node)
+{
+ smb_ofile_t *file;
+
+ if (node == 0 || node->n_refcnt <= 1)
+ return (NT_STATUS_SUCCESS);
+
+ if (node->attr.sa_vattr.va_type == VDIR)
+ return (NT_STATUS_SUCCESS);
+
+ smb_llist_enter(&node->n_ofile_list, RW_READER);
+ file = smb_llist_head(&node->n_ofile_list);
+ while (file) {
+ ASSERT(file->f_magic == SMB_OFILE_MAGIC);
+ if (file->f_granted_access &
+ (FILE_READ_DATA |
+ FILE_WRITE_DATA |
+ FILE_APPEND_DATA |
+ FILE_EXECUTE |
+ DELETE)) {
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SHARING_VIOLATION);
+ }
+ file = smb_llist_next(&node->n_ofile_list, file);
+ }
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c b/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c
new file mode 100644
index 0000000000..e959b240b8
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smbinfo.h>
+
+/*
+ * smb_com_delete_directory
+ *
+ * The delete directory message is sent to delete an empty directory. The
+ * appropriate Tid and additional pathname are passed. The directory must
+ * be empty for it to be deleted.
+ *
+ * NT supports a hidden permission known as File Delete Child (FDC). If
+ * the user has FullControl access to a directory, the user is permitted
+ * to delete any object in the directory regardless of the permissions
+ * on the object.
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryName[]; Directory name
+ *
+ * The directory to be deleted cannot be the root of the share specified
+ * by Tid.
+ *
+ * Server Response Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ */
+int
+smb_com_delete_directory(struct smb_request *sr)
+{
+ smb_node_t *dnode;
+ int rc;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ dnode = sr->arg.dirop.fqi.last_snode;
+
+ if (dnode->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) {
+ smb_node_release(dnode);
+ smb_node_release(sr->arg.dirop.fqi.dir_snode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ smbsr_raise_cifs_error(sr, NT_STATUS_CANNOT_DELETE,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ smb_node_release(dnode);
+
+ dnode = sr->arg.dirop.fqi.dir_snode;
+
+ rc = smb_fsop_rmdir(sr, sr->user_cr, dnode,
+ sr->arg.dirop.fqi.last_comp_od, 1);
+ if (rc != 0) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
new file mode 100644
index 0000000000..96a23bb995
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
@@ -0,0 +1,1574 @@
+/*
+ * 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.
+ *
+ *
+ * Dispatching SMB requests.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ALMOST EVERYTHING YOU NEED TO KNOW ABOUT A SERVER MESSAGE BLOCK
+ *
+ * Request
+ * Header
+ * Magic 0xFF 'S' 'M' 'B'
+ * smb_com a byte, the "first" command
+ * Error a 4-byte union, ignored in a request
+ * smb_flg a one byte set of eight flags
+ * smb_flg2 a two byte set of 16 flags
+ * . twelve reserved bytes, have a role
+ * in connectionless transports (IPX, UDP?)
+ * smb_tid a 16-bit tree ID, a mount point sorta,
+ * 0xFFFF is this command does not have
+ * or require a tree context
+ * smb_pid a 16-bit process ID
+ * smb_uid a 16-bit user ID, specific to this "session"
+ * and mapped to a system (bona-fide) UID
+ * smb_mid a 16-bit multiplex ID, used to differentiate
+ * multiple simultaneous requests from the same
+ * process (pid) (ref RPC "xid")
+ *
+ * Chained (AndX) commands (0 or more)
+ * smb_wct a byte, number of 16-bit words containing
+ * command parameters, min 2 for chained command
+ * andx_com a byte, the "next" command, 0xFF for none
+ * . an unused byte
+ * andx_off a 16-bit offset, byte displacement from &Magic
+ * to the smb_wct field of the "next" command,
+ * ignore if andx_com is 0xFF, s/b 0 if no next
+ * smb_vwv[] 0 or more 16-bit (sorta) parameters for
+ * "this" command (i.e. smb_com if this is the
+ * first parameters, or the andx_com of the just
+ * previous block.
+ * smb_bcc a 16-bit count of smb_data[] bytes
+ * smb_data[] 0 or more bytes, format specific to commands
+ * padding[] Optional padding
+ *
+ * Last command
+ * smb_wct a byte, number of 16-bit words containing
+ * command parameters, min 0 for chained command
+ * smb_vwv[] 0 or more 16-bit (sorta) parameters for
+ * "this" command (i.e. smb_com if this is the
+ * first parameters, or the andx_com of the just
+ * previous block.
+ * smb_bcc a 16-bit count of smb_data[] bytes
+ * smb_data[] 0 or more bytes, format specific to commands
+ *
+ * Reply
+ * Header
+ * Magic 0xFF 'S' 'M' 'B'
+ * smb_com a byte, the "first" command, corresponds
+ * to request
+ * Error a 4-byte union, coding depends on dialect in use
+ * for "DOS" errors
+ * a byte for error class
+ * an unused byte
+ * a 16-bit word for error code
+ * for "NT" errors
+ * a 32-bit error code which
+ * is a packed class and specifier
+ * for "OS/2" errors
+ * I don't know
+ * The error information is specific to the
+ * last command in the reply chain.
+ * smb_flg a one byte set of eight flags, 0x80 bit set
+ * indicating this message is a reply
+ * smb_flg2 a two byte set of 16 flags
+ * . twelve reserved bytes, have a role
+ * in connectionless transports (IPX, UDP?)
+ * smb_tid a 16-bit tree ID, a mount point sorta,
+ * should be the same as the request
+ * smb_pid a 16-bit process ID, MUST BE the same as request
+ * smb_uid a 16-bit user ID, specific to this "session"
+ * and mapped to a system (bona-fide) UID,
+ * should be the same as request
+ * smb_mid a 16-bit multiplex ID, used to differentiate
+ * multiple simultaneous requests from the same
+ * process (pid) (ref RPC "xid"), MUST BE the
+ * same as request
+ * padding[] Optional padding
+ *
+ * Chained (AndX) commands (0 or more)
+ * smb_wct a byte, number of 16-bit words containing
+ * command parameters, min 2 for chained command,
+ * andx_com a byte, the "next" command, 0xFF for none,
+ * corresponds to request, if this is the chained
+ * command that had an error set to 0xFF
+ * . an unused byte
+ * andx_off a 16-bit offset, byte displacement from &Magic
+ * to the smb_wct field of the "next" command,
+ * ignore if andx_com is 0xFF, s/b 0 if no next
+ * smb_vwv[] 0 or more 16-bit (sorta) parameters for
+ * "this" command (i.e. smb_com if this is the
+ * first parameters, or the andx_com of the just
+ * previous block. Empty if an error.
+ * smb_bcc a 16-bit count of smb_data[] bytes
+ * smb_data[] 0 or more bytes, format specific to commands
+ * empty if an error.
+ *
+ * Last command
+ * smb_wct a byte, number of 16-bit words containing
+ * command parameters, min 0 for chained command
+ * smb_vwv[] 0 or more 16-bit (sorta) parameters for
+ * "this" command (i.e. smb_com if this is the
+ * first parameters, or the andx_com of the just
+ * previous block, empty if an error.
+ * smb_bcc a 16-bit count of smb_data[] bytes
+ * smb_data[] 0 or more bytes, format specific to commands,
+ * empty if an error.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <sys/sdt.h>
+
+#define SMB_ALL_DISPATCH_STAT_INCR(stat) atomic_inc_64(&stat);
+
+int smb_dispatch_diags = 0;
+static kstat_t *smb_dispatch_ksp = NULL;
+static kstat_named_t *smb_dispatch_kstat_data = NULL;
+static int smb_dispatch_kstat_size = 0;
+
+static int is_andx_com(unsigned char);
+
+extern void smbsr_decode_error(struct smb_request *sr);
+extern void smbsr_encode_error(struct smb_request *sr);
+extern void smbsr_check_result(struct smb_request *sr, int wct, int bcc);
+
+extern int smb_com_cancel_forward(struct smb_request *);
+extern int smb_com_check_directory(struct smb_request *);
+extern int smb_com_close(struct smb_request *);
+extern int smb_com_close_and_tree_disconnect(struct smb_request *);
+extern int smb_com_close_print_file(struct smb_request *);
+extern int smb_com_copy(struct smb_request *);
+extern int smb_com_create(struct smb_request *);
+extern int smb_com_create_directory(struct smb_request *);
+extern int smb_com_create_new(struct smb_request *);
+extern int smb_com_create_temporary(struct smb_request *);
+extern int smb_com_delete(struct smb_request *);
+extern int smb_com_delete_directory(struct smb_request *);
+extern int smb_com_echo(struct smb_request *);
+extern int smb_com_find(struct smb_request *);
+extern int smb_com_find_close(struct smb_request *);
+extern int smb_com_find_close2(struct smb_request *);
+extern int smb_com_find_notify_close(struct smb_request *);
+extern int smb_com_find_unique(struct smb_request *);
+extern int smb_com_flush(struct smb_request *);
+extern int smb_com_forward_user_name(struct smb_request *);
+extern int smb_com_get_machine_name(struct smb_request *);
+extern int smb_com_get_print_queue(struct smb_request *);
+extern int smb_com_invalid_command(struct smb_request *);
+extern int smb_com_ioctl(struct smb_request *);
+extern int smb_com_ioctl_secondary(struct smb_request *);
+extern int smb_com_lock_and_read(struct smb_request *);
+extern int smb_com_lock_byte_range(struct smb_request *);
+extern int smb_com_locking_andx(struct smb_request *);
+extern int smb_com_logoff_andx(struct smb_request *);
+extern int smb_com_move(struct smb_request *);
+extern int smb_com_negotiate(struct smb_request *);
+extern int smb_com_nt_cancel(struct smb_request *);
+extern int smb_com_nt_create_andx(struct smb_request *);
+extern int smb_com_nt_transact(struct smb_request *);
+extern int smb_com_nt_transact_secondary(struct smb_request *);
+extern int smb_com_open(struct smb_request *);
+extern int smb_com_open_andx(struct smb_request *);
+extern int smb_com_open_print_file(struct smb_request *);
+extern int smb_com_process_exit(struct smb_request *);
+extern int smb_com_query_information(struct smb_request *);
+extern int smb_com_query_information2(struct smb_request *);
+extern int smb_com_query_information_disk(struct smb_request *);
+extern int smb_com_read(struct smb_request *);
+extern int smb_com_read_andx(struct smb_request *);
+extern int smb_com_read_mpx(struct smb_request *);
+extern int smb_com_read_mpx_secondary(struct smb_request *);
+extern int smb_com_read_raw(struct smb_request *);
+extern int smb_com_rename(struct smb_request *);
+extern int smb_com_search(struct smb_request *);
+extern int smb_com_seek(struct smb_request *);
+extern int smb_com_send_broadcast_message(struct smb_request *);
+extern int smb_com_send_end_mb_message(struct smb_request *);
+extern int smb_com_send_single_message(struct smb_request *);
+extern int smb_com_send_start_mb_message(struct smb_request *);
+extern int smb_com_send_text_mb_message(struct smb_request *);
+extern int smb_com_session_setup_andx(struct smb_request *);
+extern int smb_com_set_information(struct smb_request *);
+extern int smb_com_set_information2(struct smb_request *);
+extern int smb_com_transaction(struct smb_request *);
+extern int smb_com_transaction2(struct smb_request *);
+extern int smb_com_transaction2_secondary(struct smb_request *);
+extern int smb_com_transaction_secondary(struct smb_request *);
+extern int smb_com_tree_connect(struct smb_request *);
+extern int smb_com_tree_connect_andx(struct smb_request *);
+extern int smb_com_tree_disconnect(struct smb_request *);
+extern int smb_com_unlock_byte_range(struct smb_request *);
+extern int smb_com_write(struct smb_request *);
+extern int smb_com_write_and_close(struct smb_request *);
+extern int smb_com_write_and_unlock(struct smb_request *);
+extern int smb_com_write_andx(struct smb_request *);
+extern int smb_com_write_complete(struct smb_request *);
+extern int smb_com_write_mpx(struct smb_request *);
+extern int smb_com_write_mpx_secondary(struct smb_request *);
+extern int smb_com_write_print_file(struct smb_request *);
+extern int smb_com_write_raw(struct smb_request *);
+
+static smb_dispatch_table_t dispatch[256] = {
+ { smb_com_create_directory, /* 0x00 000 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCreateDirectory", KSTAT_DATA_UINT64 } },
+ { smb_com_delete_directory, /* 0x01 001 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbDeleteDirectory", KSTAT_DATA_UINT64 } },
+ { smb_com_open, /* 0x02 002 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbOpen", KSTAT_DATA_UINT64 } },
+ { smb_com_create, /* 0x03 003 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCreate", KSTAT_DATA_UINT64 } },
+ { smb_com_close, /* 0x04 004 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbClose", KSTAT_DATA_UINT64 } },
+ { smb_com_flush, /* 0x05 005 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFlush", KSTAT_DATA_UINT64 } },
+ { smb_com_delete, /* 0x06 006 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbDelete", KSTAT_DATA_UINT64 } },
+ { smb_com_rename, /* 0x07 007 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbRename", KSTAT_DATA_UINT64 } },
+ { smb_com_query_information, /* 0x08 008 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbQueryInformation", KSTAT_DATA_UINT64 } },
+ { smb_com_set_information, /* 0x09 009 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSetInformation", KSTAT_DATA_UINT64 } },
+ { smb_com_read, /* 0x0A 010 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbRead", KSTAT_DATA_UINT64 } },
+ { smb_com_write, /* 0x0B 011 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWrite", KSTAT_DATA_UINT64 } },
+ { smb_com_lock_byte_range, /* 0x0C 012 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbLockByteRange", KSTAT_DATA_UINT64 } },
+ { smb_com_unlock_byte_range, /* 0x0D 013 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbUnlockByteRange", KSTAT_DATA_UINT64 } },
+ { smb_com_create_temporary, /* 0x0E 014 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCreateTemporary", KSTAT_DATA_UINT64 } },
+ { smb_com_create_new, /* 0x0F 015 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCreateNew", KSTAT_DATA_UINT64 } },
+ { smb_com_check_directory, /* 0x10 016 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCheckDirectory", KSTAT_DATA_UINT64 } },
+ { smb_com_process_exit, /* 0x11 017 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_READER,
+ { "SmbProcessExit", KSTAT_DATA_UINT64 } },
+ { smb_com_seek, /* 0x12 018 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSeek", KSTAT_DATA_UINT64 } },
+ { smb_com_lock_and_read, /* 0x13 019 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbLockAndRead", KSTAT_DATA_UINT64 } },
+ { smb_com_write_and_unlock, /* 0x14 020 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteAndUnlock", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0x15 021 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x16 022 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x17 023 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x18 024 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x19 025 */
+ { smb_com_read_raw, /* 0x1A 026 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_WRITER,
+ { "SmbReadRaw", KSTAT_DATA_UINT64 } },
+ { smb_com_read_mpx, /* 0x1B 027 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbReadMpx", KSTAT_DATA_UINT64 } },
+ { smb_com_read_mpx_secondary, /* 0x1C 028 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbReadMpxSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_write_raw, /* 0x1D 029 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW | SDDF_SUPPRESS_UNLEASH,
+ RW_WRITER,
+ { "SmbWriteRaw", KSTAT_DATA_UINT64 } },
+ { smb_com_write_mpx, /* 0x1E 030 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteMpx", KSTAT_DATA_UINT64 } },
+ { smb_com_write_mpx_secondary, /* 0x1F 031 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteMpxSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_write_complete, /* 0x20 032 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteComplete", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, 0, 0 }, /* 0x21 033 */
+ { smb_com_set_information2, /* 0x22 034 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSetInformation2", KSTAT_DATA_UINT64 } },
+ { smb_com_query_information2, /* 0x23 035 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbQueryInformation2", KSTAT_DATA_UINT64 } },
+ { smb_com_locking_andx, /* 0x24 036 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbLockingX", KSTAT_DATA_UINT64 } },
+ { smb_com_transaction, /* 0x25 037 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbTransaction", KSTAT_DATA_UINT64 } },
+ { smb_com_transaction_secondary, /* 0x26 038 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbTransactionSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_ioctl, /* 0x27 039 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbIoctl", KSTAT_DATA_UINT64 } },
+ { smb_com_ioctl_secondary, /* 0x28 040 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbIoctlSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_copy, /* 0x29 041 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCopy", KSTAT_DATA_UINT64 } },
+ { smb_com_move, /* 0x2A 042 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbMove", KSTAT_DATA_UINT64 } },
+ { smb_com_echo, /* 0x2B 043 */
+ LANMAN1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_READER,
+ { "SmbEcho", KSTAT_DATA_UINT64 } },
+ { smb_com_write_and_close, /* 0x2C 044 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteAndClose", KSTAT_DATA_UINT64 } },
+ { smb_com_open_andx, /* 0x2D 045 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbOpenX", KSTAT_DATA_UINT64 } },
+ { smb_com_read_andx, /* 0x2E 046 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbReadX", KSTAT_DATA_UINT64 } },
+ { smb_com_write_andx, /* 0x2F 047 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteX", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, 0, 0 }, /* 0x30 048 */
+ { smb_com_close_and_tree_disconnect, /* 0x31 049 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCloseAndTreeDisconnect", KSTAT_DATA_UINT64 } },
+ { smb_com_transaction2, /* 0x32 050 */
+ LM1_2X002, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbTransaction2", KSTAT_DATA_UINT64 } },
+ { smb_com_transaction2_secondary, /* 0x33 051 */
+ LM1_2X002, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbTransaction2Secondary", KSTAT_DATA_UINT64 } },
+ { smb_com_find_close2, /* 0x34 052 */
+ LM1_2X002, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFindClose2", KSTAT_DATA_UINT64 } },
+ { smb_com_find_notify_close, /* 0x35 053 */
+ LM1_2X002, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFindNotifyClose", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0x36 054 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x37 055 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x38 056 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x39 057 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3A 058 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3B 059 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3C 060 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3D 061 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3E 062 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3F 063 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x40 064 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x41 065 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x42 066 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x43 067 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x44 068 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x45 069 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x46 070 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x47 071 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x48 072 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x49 073 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4A 074 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4B 075 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4C 076 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4D 077 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4E 078 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4F 079 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x50 080 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x51 081 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x52 082 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x53 083 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x54 084 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x55 085 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x56 086 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x57 087 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x58 088 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x59 089 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5A 090 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5B 091 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5C 092 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5D 093 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5E 094 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5F 095 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x60 096 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x61 097 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x62 098 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x63 099 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x64 100 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x65 101 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x66 102 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x67 103 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x68 104 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x69 105 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6A 106 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6B 107 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6C 108 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6D 109 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6E 110 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6F 111 */
+ { smb_com_tree_connect, /* 0x70 112 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID,
+ RW_READER,
+ { "SmbTreeConnect", KSTAT_DATA_UINT64 } },
+ { smb_com_tree_disconnect, /* 0x71 113 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_READER,
+ { "SmbTreeDisconnect", KSTAT_DATA_UINT64 } },
+ { smb_com_negotiate, /* 0x72 114 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_WRITER,
+ { "SmbNegotiate", KSTAT_DATA_UINT64 } },
+ { smb_com_session_setup_andx, /* 0x73 115 */
+ LANMAN1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_READER,
+ { "SmbSessionSetupX", KSTAT_DATA_UINT64 } },
+ { smb_com_logoff_andx, /* 0x74 116 */
+ LM1_2X002, SDDF_SUPPRESS_TID,
+ RW_READER,
+ { "SmbLogoffX", KSTAT_DATA_UINT64 } },
+ { smb_com_tree_connect_andx, /* 0x75 117 */
+ LANMAN1_0, SDDF_SUPPRESS_TID,
+ RW_READER,
+ { "SmbTreeConnectX", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0x76 118 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x77 119 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x78 120 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x79 121 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7A 122 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7B 123 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7C 124 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7D 125 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7E 126 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7F 127 */
+ { smb_com_query_information_disk, /* 0x80 128 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbQueryInformationDisk", KSTAT_DATA_UINT64 } },
+ { smb_com_search, /* 0x81 129 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSearch", KSTAT_DATA_UINT64 } },
+ { smb_com_find, /* 0x82 130 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFind", KSTAT_DATA_UINT64 } },
+ { smb_com_find_unique, /* 0x83 131 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFindUnique", KSTAT_DATA_UINT64 } },
+ { smb_com_find_close, /* 0x84 132 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFindClose", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0x85 133 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x86 134 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x87 135 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x88 136 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x89 137 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8A 138 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8B 139 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8C 140 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8D 141 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8E 142 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8F 143 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x90 144 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x91 145 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x92 146 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x93 147 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x94 148 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x95 149 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x96 150 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x97 151 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x98 152 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x99 153 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9A 154 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9B 155 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9C 156 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9D 157 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9E 158 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9F 159 */
+ { smb_com_nt_transact, /* 0xA0 160 */
+ NT_LM_0_12, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbNtTransact", KSTAT_DATA_UINT64 } },
+ { smb_com_nt_transact_secondary, /* 0xA1 161 */
+ NT_LM_0_12, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbNtTransactSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_nt_create_andx, /* 0xA2 162 */
+ NT_LM_0_12, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbNtCreateX", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, 0, 0 }, /* 0xA3 163 */
+ { smb_com_nt_cancel, /* 0xA4 164 */
+ NT_LM_0_12, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbNtCancel", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA5 165 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA6 166 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA7 167 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA8 168 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA9 169 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAA 170 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAB 171 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAC 172 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAD 173 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAE 174 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAF 175 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB0 176 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB1 177 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB2 178 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB3 179 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB4 180 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB5 181 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB6 182 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB7 183 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB8 184 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB9 185 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBA 186 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBB 187 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBC 188 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBD 189 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBE 190 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBF 191 */
+ { smb_com_open_print_file, /* 0xC0 192 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbOpenPrintFile", KSTAT_DATA_UINT64 } },
+ { smb_com_write_print_file, /* 0xC1 193 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWritePrintFile", KSTAT_DATA_UINT64 } },
+ { smb_com_close_print_file, /* 0xC2 194 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbClosePrintFile", KSTAT_DATA_UINT64 } },
+ { smb_com_get_print_queue, /* 0xC3 195 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbGetPrintQueue", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC4 196 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC5 197 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC6 198 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC7 199 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC8 200 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC9 201 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCA 202 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCB 203 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCC 204 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCD 205 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCE 206 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCF 207 */
+ { smb_com_send_single_message, /* 0xD0 208 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendSingleMessage", KSTAT_DATA_UINT64 } },
+ { smb_com_send_broadcast_message, /* 0xD1 209 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendBroadcastMessage", KSTAT_DATA_UINT64 } },
+ { smb_com_forward_user_name, /* 0xD2 210 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbForwardUserName", KSTAT_DATA_UINT64 } },
+ { smb_com_cancel_forward, /* 0xD3 211 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCancelForward", KSTAT_DATA_UINT64 } },
+ { smb_com_get_machine_name, /* 0xD4 212 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbGetMachineName", KSTAT_DATA_UINT64 } },
+ { smb_com_send_start_mb_message, /* 0xD5 213 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendStartMbMessage", KSTAT_DATA_UINT64 } },
+ { smb_com_send_end_mb_message, /* 0xD6 214 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendEndMbMessage", KSTAT_DATA_UINT64 } },
+ { smb_com_send_text_mb_message, /* 0xD7 215 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendTextMbMessage", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0xD8 216 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xD9 217 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDA 218 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDB 219 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDC 220 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDD 221 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDE 222 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDF 223 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE0 224 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE1 225 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE2 226 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE3 227 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE4 228 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE5 229 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE6 230 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE7 231 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE8 232 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE9 233 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEA 234 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEB 235 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEC 236 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xED 237 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEE 238 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEF 239 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF0 240 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF1 241 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF2 242 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF3 243 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF4 244 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF5 245 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF6 246 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF7 247 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF8 248 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF9 249 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xFA 250 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xFB 251 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xFC 252 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xFD 253 */
+ { smb_com_invalid_command, /* 0xFE 254 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbInvalidCommand", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 } /* 0xFF 255 */
+};
+
+int smb_watch = -1;
+int smb_emit_sending = 0;
+
+/*
+ * smbsr_cleanup
+ *
+ * If any user/tree/file is used by given request then
+ * the reference count for that resource has been incremented.
+ * This function decrements the reference count and close
+ * the resource if it's needed.
+ */
+
+void
+smbsr_cleanup(struct smb_request *sr)
+{
+ ASSERT((sr->sr_state != SMB_REQ_STATE_CLEANED_UP) &&
+ (sr->sr_state != SMB_REQ_STATE_COMPLETED));
+
+ if (sr->fid_ofile)
+ smbsr_disconnect_file(sr);
+
+ if (sr->sid_odir)
+ smbsr_disconnect_dir(sr);
+
+ if (sr->tid_tree) {
+ smb_tree_release(sr->tid_tree);
+ sr->tid_tree = NULL;
+ }
+
+ if (sr->uid_user) {
+ smb_user_release(sr->uid_user);
+ sr->uid_user = NULL;
+ }
+
+ if (sr->r_xa) {
+ if (sr->r_xa->xa_flags & SMB_XA_FLAG_COMPLETE)
+ smb_xa_close(sr->r_xa);
+ smb_xa_rele(sr->session, sr->r_xa);
+ sr->r_xa = NULL;
+ }
+
+ /*
+ * Mark this request so we know that we've already cleaned it up.
+ * A request should only get cleaned up once so multiple calls to
+ * smbsr_cleanup for the same request indicate a bug.
+ */
+ mutex_enter(&sr->sr_mutex);
+ if (sr->sr_state != SMB_REQ_STATE_CANCELED)
+ sr->sr_state = SMB_REQ_STATE_CLEANED_UP;
+ mutex_exit(&sr->sr_mutex);
+}
+
+int
+smb_dispatch_request(struct smb_request *sr)
+{
+ int rc;
+ smb_dispatch_table_t *sdd;
+
+ ASSERT(sr->tid_tree == 0);
+ ASSERT(sr->uid_user == 0);
+ ASSERT(sr->fid_ofile == 0);
+ ASSERT(sr->sid_odir == 0);
+ sr->smb_fid = (uint16_t)-1;
+ sr->smb_sid = (uint16_t)-1;
+
+ /* temporary until we identify a user */
+ sr->user_cr = kcred;
+ sr->orig_request_hdr = sr->command.chain_offset;
+
+ /* If this connection is shutting down just kill request */
+ if (smb_decode_mbc(&sr->command, SMB_HEADER_ED_FMT,
+ &sr->smb_com,
+ &sr->smb_rcls,
+ &sr->smb_reh,
+ &sr->smb_err,
+ &sr->smb_flg,
+ &sr->smb_flg2,
+ &sr->smb_pid_high,
+ sr->smb_sig,
+ &sr->smb_tid,
+ &sr->smb_pid,
+ &sr->smb_uid,
+ &sr->smb_mid) != 0) {
+ return (-1);
+ }
+
+ /*
+ * The reply "header" is filled in now even though
+ * it most likely will be rewritten under reply_ready:
+ * below. Could just reserve the space. But this
+ * (for now) is convenient incase the dialect dispatcher
+ * has to send a special reply (like TRANSACT).
+ *
+ * Ensure that the 32-bit error code flag is turned off.
+ * Clients seem to set it in transact requests and they may
+ * get confused if we return success or a 16-bit SMB code.
+ */
+ sr->smb_rcls = 0;
+ sr->smb_reh = 0;
+ sr->smb_err = 0;
+ sr->smb_flg2 &= ~SMB_FLAGS2_NT_STATUS;
+
+ (void) smb_encode_mbc(&sr->reply, SMB_HEADER_ED_FMT,
+ sr->smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+ sr->first_smb_com = sr->smb_com;
+
+ /*
+ * Verify SMB signature if signing is enabled,
+ * dialiect is NT LM 0.12,
+ * signing was negotiated and authentication has occurred.
+ */
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
+ if (smb_sign_check_request(sr) != 0) {
+ /* Reply with ACCESS_DENIED */
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_setup_nt_status(sr, ERROR_SEVERITY_ERROR,
+ NT_STATUS_ACCESS_DENIED);
+ else {
+ sr->smb_rcls = ERRDOS;
+ sr->smb_err = ERRnoaccess;
+ }
+ rc = -1;
+ smb_rwx_rwenter(&sr->session->s_lock, RW_READER);
+ goto reply_error;
+ }
+ }
+
+andx_more:
+ sdd = &dispatch[sr->smb_com];
+
+ smb_rwx_rwenter(&sr->session->s_lock, sdd->sdt_slock_mode);
+
+ if (smb_decode_mbc(&sr->command, "b", &sr->smb_wct) != 0) {
+ rc = -3;
+ goto cant_decode;
+ }
+
+ (void) MBC_SHADOW_CHAIN(&sr->smb_vwv, &sr->command,
+ sr->command.chain_offset, sr->smb_wct * 2);
+
+ if (smb_decode_mbc(&sr->command, "#.w",
+ sr->smb_wct*2, &sr->smb_bcc) != 0) {
+ rc = -5;
+ goto cant_decode;
+ }
+
+ (void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command,
+ sr->command.chain_offset, sr->smb_bcc);
+
+ sr->command.chain_offset += sr->smb_bcc;
+ if (sr->command.chain_offset > sr->command.max_bytes) {
+ rc = -6;
+ goto cant_decode;
+ }
+
+ /* Store pointers for later */
+ sr->cur_reply_offset = sr->reply.chain_offset;
+
+ if (is_andx_com(sr->smb_com)) {
+ /* Peek ahead and don't disturb vwv */
+ if (smb_peek_mbc(&sr->smb_vwv, sr->smb_vwv.chain_offset, "b.w",
+ &sr->andx_com, &sr->andx_off) < 0) {
+ rc = -7;
+ goto cant_decode;
+ }
+ } else {
+ sr->andx_com = (unsigned char)-1;
+ }
+
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_SUBMITTED:
+ case SMB_REQ_STATE_CLEANED_UP:
+ sr->sr_state = SMB_REQ_STATE_ACTIVE;
+ break;
+ case SMB_REQ_STATE_CANCELED:
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+
+ if (sdd->sdt_function) {
+
+ if ((rc = setjmp(&sr->exjb))) {
+ /*
+ * Handle any errors from raw write.
+ */
+ if (sr->session->s_state ==
+ SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
+ /*
+ * Set state so that the netbios session
+ * daemon will start accepting data again.
+ */
+ sr->session->s_write_raw_status = 0;
+ sr->session->s_state =
+ SMB_SESSION_STATE_NEGOTIATED;
+ }
+
+ /*
+ * We should never have sr->sr_keep set here
+ * since this is the error path.
+ */
+ ASSERT(sr->sr_keep == 0);
+
+ smbsr_cleanup(sr);
+
+ if (sr->smb_com == smb_watch) {
+ smb_emit_sending = 1;
+ }
+ if (rc < 0) {
+ rc -= 1000;
+ goto cant_decode;
+ }
+ goto reply_error;
+ }
+
+ /*
+ * Setup UID and TID information (if required). Both functions
+ * will set the sr credentials. In domain mode, the user and
+ * tree credentials should be the same. In share mode, the
+ * tree credentials (defined in the share definition) should
+ * override the user credentials.
+ */
+ if (!(sdd->sdt_flags & SDDF_SUPPRESS_UID)) {
+ sr->uid_user = smb_user_lookup_by_uid(sr->session,
+ &sr->user_cr, sr->smb_uid);
+ if (sr->uid_user == NULL) {
+ smbsr_raise_error(sr, ERRSRV, ERRbaduid);
+ /* NOTREACHED */
+ }
+ if (!(sdd->sdt_flags & SDDF_SUPPRESS_TID)) {
+ sr->tid_tree = smb_tree_lookup_by_tid(
+ sr->uid_user, sr->smb_tid);
+ if (sr->tid_tree == NULL) {
+ smbsr_raise_error(sr, ERRSRV,
+ ERRinvnid);
+ /* NOTREACHED */
+ }
+ }
+ }
+
+ /*
+ * If the command is not a read raw request we can set the
+ * state of the session back to SMB_SESSION_STATE_NEGOTIATED
+ * (if the current state is SMB_SESSION_STATE_OPLOCK_BREAKING).
+ * Otherwise we let the read raw handler to deal with it.
+ */
+ if ((sr->session->s_state ==
+ SMB_SESSION_STATE_OPLOCK_BREAKING) &&
+ (sr->smb_com != SMB_COM_READ_RAW)) {
+ krw_t mode;
+ /*
+ * The lock may have to be upgraded because, at this
+ * point, we don't know how it was entered. We just
+ * know that it has to be entered in writer mode here.
+ * Whatever mode was used to enter the lock, it will
+ * be restored.
+ */
+ mode = smb_rwx_rwupgrade(&sr->session->s_lock);
+ if (sr->session->s_state ==
+ SMB_SESSION_STATE_OPLOCK_BREAKING) {
+ sr->session->s_state =
+ SMB_SESSION_STATE_NEGOTIATED;
+ }
+ smb_rwx_rwdowngrade(&sr->session->s_lock, mode);
+ }
+
+ DTRACE_PROBE1(smb__dispatch__com, struct smb_request_t *, sr);
+
+ /*
+ * Increment method invocation count. This value is exposed
+ * via kstats, and it represents a count of all the dispatched
+ * requests, including the ones that have a return value, other
+ * than SDRC_NORMAL_REPLY.
+ */
+ SMB_ALL_DISPATCH_STAT_INCR(sdd->sdt_dispatch_stats.value.ui64);
+
+ rc = (*sdd->sdt_function)(sr);
+
+ /*
+ * Only call smbsr_cleanup if smb->sr_keep is not set. The
+ * smb_nt_transact_notify_change function will set
+ * smb->sr_keep if it retains control of the request when
+ * it returns. In that case the notify change code
+ * will call smbsr_cleanup later when the request is finally
+ * completed.
+ */
+ if (sr->sr_keep == 0)
+ smbsr_cleanup(sr);
+ } else {
+ rc = SDRC_UNIMPLEMENTED; /* Unknown? */
+ }
+
+ if (rc != SDRC_NORMAL_REPLY) { /* normal case special & fast */
+ switch (rc) {
+ case SDRC_NORMAL_REPLY:
+ break;
+
+ case SDRC_ERROR_REPLY:
+ goto reply_error;
+
+ case SDRC_DROP_VC:
+ switch (sr->session->s_state) {
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ break;
+ default:
+ smb_soshutdown(sr->session->sock);
+ break;
+ }
+ goto reply_error;
+
+ case SDRC_NO_REPLY:
+ /* tricky. */
+ smb_rwx_rwexit(&sr->session->s_lock);
+ return (0);
+
+ case SDRC_UNIMPLEMENTED:
+ sr->smb_rcls = ERRDOS;
+ sr->smb_err = ERRbadfunc;
+ goto reply_error;
+
+ default:
+ sr->smb_rcls = ERRDOS;
+ sr->smb_err = ERRerror; /* need better */
+ goto reply_error;
+ }
+ }
+
+ if (sr->andx_com == 0xff)
+ goto reply_ready;
+
+ /* have to back-patch the AndXCommand and AndXOffset */
+ sr->andx_prev_wct = sr->cur_reply_offset;
+ (void) smb_poke_mbc(&sr->reply, sr->andx_prev_wct + 1, "b.w",
+ sr->andx_com, MBC_LENGTH(&sr->reply));
+
+ smb_rwx_rwexit(&sr->session->s_lock);
+
+ /* now it gets interesting */
+ sr->command.chain_offset = sr->orig_request_hdr + sr->andx_off;
+
+ sr->smb_com = sr->andx_com;
+
+ goto andx_more;
+
+reply_ready:
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr)) {
+ sr->smb_flg |= SMB_FLAGS_CASE_INSENSITIVE;
+ } else {
+ sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE;
+ }
+
+ (void) smb_poke_mbc(&sr->reply, 0, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, NULL);
+
+ if ((rc = smb_session_send(sr->session, 0, &sr->reply)) == 0)
+ sr->reply.chain = 0;
+
+ smb_rwx_rwexit(&sr->session->s_lock);
+
+ return (rc);
+
+cant_decode:
+reply_error:
+ sr->reply.chain_offset = sr->cur_reply_offset;
+ (void) smb_encode_mbc(&sr->reply, "bw", 0, 0);
+
+ sr->smb_wct = 0;
+ sr->smb_bcc = 0;
+
+ if (sr->smb_rcls == 0) {
+ sr->smb_rcls = ERRSRV;
+ sr->smb_err = ERRerror;
+ }
+ goto reply_ready;
+}
+
+
+void
+smbsr_encode_result(struct smb_request *sr, int wct,
+ int bcc, char *fmt, ...)
+{
+ va_list ap;
+
+ if (MBC_LENGTH(&sr->reply) != sr->cur_reply_offset) {
+ smbsr_encode_error(sr);
+ }
+
+ va_start(ap, fmt);
+ (void) smb_mbc_encode(&sr->reply, fmt, ap);
+ va_end(ap);
+
+ sr->smb_wct = (unsigned char)wct;
+ sr->smb_bcc = (uint16_t)bcc;
+
+ smbsr_check_result(sr, wct, bcc);
+}
+
+void
+smbsr_check_result(struct smb_request *sr, int wct, int bcc)
+{
+ int offset = sr->cur_reply_offset;
+ int total_bytes;
+ unsigned char temp, temp1;
+ struct mbuf *m;
+
+ total_bytes = 0;
+ m = sr->reply.chain;
+ while (m != 0) {
+ total_bytes += m->m_len;
+ m = m->m_next;
+ }
+
+ if ((offset + 3) > total_bytes) {
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+
+ (void) smb_peek_mbc(&sr->reply, offset, "b", &temp);
+ if (temp != wct) {
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((offset + (wct * 2 + 1)) > total_bytes) {
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /* reply wct & vwv seem ok, consider data now */
+ offset += wct * 2 + 1;
+
+ if ((offset + 2) > total_bytes) {
+ smbsr_encode_error(sr);
+ }
+
+ (void) smb_peek_mbc(&sr->reply, offset, "bb", &temp, &temp1);
+ if (bcc == VAR_BCC) {
+ if ((temp != 0xFF) || (temp1 != 0xFF)) {
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ } else {
+ bcc = (total_bytes - offset) - 2;
+ (void) smb_poke_mbc(&sr->reply, offset, "bb",
+ bcc, bcc >> 8);
+ }
+ } else {
+ if ((temp != (bcc&0xFF)) || (temp1 != ((bcc>>8)&0xFF))) {
+ smbsr_encode_error(sr);
+ }
+ }
+
+ offset += bcc + 2;
+
+ if (offset != total_bytes) {
+ smbsr_encode_error(sr);
+ }
+
+ sr->smb_wct = (unsigned char)wct;
+ sr->smb_bcc = (uint16_t)bcc;
+}
+
+int
+smbsr_decode_vwv(struct smb_request *sr, char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = smb_mbc_decode(&sr->smb_vwv, fmt, ap);
+ va_end(ap);
+
+ return (rc);
+}
+
+int
+smbsr_decode_data(struct smb_request *sr, char *fmt, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, fmt);
+ r = smb_mbc_decode(&sr->smb_data, fmt, ap);
+ va_end(ap);
+ return (r);
+}
+
+void
+smbsr_send_reply(struct smb_request *sr)
+{
+ (void) smb_poke_mbc(&sr->reply, 0, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, NULL);
+
+ (void) smb_session_send(sr->session, 0, &sr->reply);
+}
+
+
+void
+smbsr_decode_error(struct smb_request *sr)
+{
+ longjmp(&sr->exjb);
+}
+
+void
+smbsr_encode_error(struct smb_request *sr)
+{
+ longjmp(&sr->exjb);
+}
+
+void
+smbsr_encode_empty_result(struct smb_request *sr)
+{
+ smbsr_encode_result(sr, 0, 0, "bw", 0, 0);
+}
+
+/*
+ * cifs_raise_error
+ *
+ * Temporary workaround to the NT status versus Win32/SMB error codes
+ * decision: just report them both here.
+ */
+void
+smbsr_raise_cifs_error(struct smb_request *sr,
+ DWORD status,
+ int error_class,
+ int error_code)
+{
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_raise_nt_error(sr, status);
+ else
+ smbsr_raise_error(sr, error_class, error_code);
+
+ /* NOTREACHED */
+}
+
+void
+smbsr_raise_error(struct smb_request *sr, int errcls, int errcod)
+{
+ sr->smb_rcls = (unsigned char)errcls;
+ sr->smb_err = (uint16_t)errcod;
+ longjmp(&sr->exjb);
+}
+
+/*
+ * smbsr_setup_nt_status
+ *
+ * Set up an NT status in the smb_request but don't long jump or try
+ * to do any error handling. There are times when we need a status set
+ * up in the response to indicate that the request has either failed
+ * or, at least, is only partially complete (possibly indicated by the
+ * severity) but we also need to return some information to the client.
+ */
+void
+smbsr_setup_nt_status(struct smb_request *sr,
+ uint32_t severity,
+ uint32_t nt_status)
+{
+ nt_status |= severity;
+ sr->smb_rcls = nt_status & 0xff;
+ sr->smb_reh = (nt_status >> 8) & 0xff;
+ sr->smb_err = nt_status >> 16;
+ sr->smb_flg2 |= SMB_FLAGS2_NT_STATUS;
+}
+
+void
+smbsr_raise_nt_error(struct smb_request *sr, uint32_t errcod)
+{
+ errcod |= 0xc0000000;
+ sr->smb_rcls = errcod & 0xff;
+ sr->smb_reh = (errcod >> 8) & 0xff;
+ sr->smb_err = errcod >> 16;
+ sr->smb_flg2 |= SMB_FLAGS2_NT_STATUS;
+ longjmp(&sr->exjb);
+}
+
+
+/*
+ * Attempt to map errno values to SMB and NT status values.
+ * Note: ESRCH is used as special case to handle a lookup
+ * failure on streams.
+ */
+static struct {
+ int unix_errno;
+ int smb_error_class;
+ int smb_error_value;
+ DWORD nt_status;
+}
+smb_errno_map[] = {
+ { ENOSPC, ERRDOS, ERROR_DISK_FULL, NT_STATUS_DISK_FULL },
+ { EDQUOT, ERRDOS, ERROR_DISK_FULL, NT_STATUS_DISK_FULL },
+ { EPERM, ERRSRV, ERRaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOTDIR, ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND },
+ { EISDIR, ERRDOS, ERRbadpath, NT_STATUS_FILE_IS_A_DIRECTORY },
+ { ENOENT, ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE },
+ { ENOTEMPTY, ERRDOS, ERROR_DIR_NOT_EMPTY,
+ NT_STATUS_DIRECTORY_NOT_EMPTY },
+ { EACCES, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOMEM, ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY },
+ { EIO, ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR },
+ { EXDEV, ERRSRV, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE },
+ { EROFS, ERRHRD, ERRnowrite, NT_STATUS_ACCESS_DENIED },
+ { ESTALE, ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ { EBADF, ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ { EEXIST, ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ { ENXIO, ERRSRV, ERRinvdevice, NT_STATUS_BAD_DEVICE_TYPE},
+ { ESRCH, ERRDOS, ERROR_FILE_NOT_FOUND,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ /*
+ * It's not clear why smb_read_common effectively returns
+ * ERRnoaccess if a range lock prevents access and smb_write_common
+ * effectively returns ERRaccess. This table entry is used by
+ * smb_read_common and preserves the behavior that was there before.
+ */
+ { ERANGE, ERRDOS, ERRnoaccess, NT_STATUS_FILE_LOCK_CONFLICT }
+};
+
+void
+smb_errmap_unix2smb(int en, smb_error_t *smberr)
+{
+ int i;
+
+ smberr->status = NT_STATUS_UNSUCCESSFUL;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_GEN_FAILURE;
+
+ for (i = 0; i < sizeof (smb_errno_map)/sizeof (smb_errno_map[0]); ++i) {
+ if (smb_errno_map[i].unix_errno == en) {
+ smberr->status = smb_errno_map[i].nt_status;
+ smberr->errcls = smb_errno_map[i].smb_error_class;
+ smberr->errcode = smb_errno_map[i].smb_error_value;
+ return;
+ }
+ }
+}
+
+int
+smbsr_set_errno(struct smb_request *sr, int en)
+{
+ int i;
+
+ ASSERT(en != -1);
+
+ /*
+ * If the client supports 32-bit NT status values, check for
+ * an appropriate mapping and raise an NT error, control won't
+ * return here due to the longjmp in smbsr_raise_nt_error.
+ */
+ if (sr->session->capabilities & CAP_STATUS32) {
+ for (i = 0;
+ i < sizeof (smb_errno_map)/sizeof (smb_errno_map[0]);
+ ++i) {
+ if (smb_errno_map[i].unix_errno == en) {
+ smbsr_raise_nt_error(sr,
+ smb_errno_map[i].nt_status);
+ /* NOTREACHED */
+ }
+ }
+ } else {
+ for (i = 0;
+ i < sizeof (smb_errno_map)/sizeof (smb_errno_map[0]);
+ ++i) {
+ if (smb_errno_map[i].unix_errno == en) {
+ sr->smb_rcls = smb_errno_map[i].smb_error_class;
+ sr->smb_err = smb_errno_map[i].smb_error_value;
+ return (0);
+ }
+ }
+ }
+
+ sr->smb_rcls = ERRSRV;
+ sr->smb_err = ERRerror;
+ return (-1);
+}
+
+void
+smbsr_raise_errno(struct smb_request *sr, int en)
+{
+ if (smbsr_set_errno(sr, en) != 0) {
+ if (smb_dispatch_diags) {
+ cmn_err(CE_NOTE, "SmbErrno: errno=%d", en);
+ }
+ }
+
+ longjmp(&sr->exjb);
+ /* no return */
+}
+
+smb_xa_t *
+smbsr_lookup_xa(smb_request_t *sr)
+{
+ ASSERT(sr->r_xa == 0);
+
+ sr->r_xa = smb_xa_find(sr->session, sr->smb_pid, sr->smb_mid);
+ return (sr->r_xa);
+}
+
+void
+smbsr_disconnect_file(smb_request_t *sr)
+{
+ smb_ofile_t *of = sr->fid_ofile;
+
+ sr->fid_ofile = NULL;
+ (void) smb_ofile_release(of);
+}
+
+void
+smbsr_disconnect_dir(smb_request_t *sr)
+{
+ smb_odir_t *od = sr->sid_odir;
+
+ sr->sid_odir = NULL;
+ smb_odir_release(od);
+}
+
+static int
+is_andx_com(unsigned char com)
+{
+ switch (com) {
+ case SMB_COM_LOCKING_ANDX:
+ case SMB_COM_OPEN_ANDX:
+ case SMB_COM_READ_ANDX:
+ case SMB_COM_WRITE_ANDX:
+ case SMB_COM_SESSION_SETUP_ANDX:
+ case SMB_COM_LOGOFF_ANDX:
+ case SMB_COM_TREE_CONNECT_ANDX:
+ case SMB_COM_NT_CREATE_ANDX:
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Invalid command stub.
+ */
+/*ARGSUSED*/
+int
+smb_com_invalid_command(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * smb_kstat_update_dispatch
+ *
+ * This callback function updates the smb_dispatch_kstat_data when kstat
+ * command is invoked.
+ */
+/*ARGSUSED*/
+static int
+smb_kstat_update_dispatch(kstat_t *ksp, int rw)
+{
+ int i = 0, j = 0;
+
+ if (rw == KSTAT_WRITE) {
+ return (EACCES);
+ } else {
+ for (i = 0; i < 256; i++) {
+ if (dispatch[i].sdt_function) {
+ (void) memcpy(&smb_dispatch_kstat_data[j],
+ &(dispatch[i].sdt_dispatch_stats),
+ sizeof (kstat_named_t));
+ j++;
+ }
+ }
+ }
+ return (0);
+}
+
+/*
+ * smb_initialize_dispatch_kstat
+ *
+ * Initialize dispatch kstats.
+ */
+void
+smb_initialize_dispatch_kstat()
+{
+ int i = 0, alloc_size = 0;
+
+ for (i = 0; i < 256; i++) {
+ if (dispatch[i].sdt_function)
+ smb_dispatch_kstat_size++;
+ }
+
+ alloc_size = smb_dispatch_kstat_size * sizeof (kstat_named_t);
+ smb_dispatch_kstat_data = (kstat_named_t *)
+ kmem_zalloc(alloc_size, KM_SLEEP);
+
+ smb_dispatch_ksp = kstat_create("smb", 0, "smb_dispatch_all", "misc",
+ KSTAT_TYPE_NAMED, alloc_size/sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
+ if (smb_dispatch_ksp) {
+ smb_dispatch_ksp->ks_data = smb_dispatch_kstat_data;
+ smb_dispatch_ksp->ks_update = smb_kstat_update_dispatch;
+ kstat_install(smb_dispatch_ksp);
+ }
+}
+
+/*
+ * smb_remove_dispatch_kstat
+ *
+ * Remove dispatch kstats.
+ */
+void
+smb_remove_dispatch_kstat()
+{
+ if (smb_dispatch_kstat_data != NULL)
+ kmem_free(smb_dispatch_kstat_data,
+ smb_dispatch_kstat_size * sizeof (kstat_named_t));
+
+ if (smb_dispatch_ksp != NULL) {
+ kstat_delete(smb_dispatch_ksp);
+ smb_dispatch_ksp = NULL;
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_echo.c b/usr/src/uts/common/fs/smbsrv/smb_echo.c
new file mode 100644
index 0000000000..8a386c9959
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_echo.c
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * The echo request is used to test the connection to the server,
+ * and to see if the server is still responding. The tid is ignored,
+ * so this request may be sent to the server even if there are no
+ * tree connections to the server.
+ *
+ * Each response echoes the data sent, though ByteCount may indicate
+ * no data. If echo-count is zero, no response is sent.
+ */
+int
+smb_com_echo(struct smb_request *sr)
+{
+ unsigned short necho;
+ unsigned short nbytes;
+ unsigned short i;
+ struct mbuf_chain reply;
+ char *data;
+
+ if (smbsr_decode_vwv(sr, "w", &necho) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ nbytes = sr->smb_bcc;
+
+ data = smbsr_malloc(&sr->request_storage, nbytes);
+
+ (void) smb_decode_mbc(&sr->smb_data, "#c", nbytes, data);
+
+ for (i = 1; i <= necho; ++i) {
+
+ MBC_INIT(&reply, SMB_HEADER_ED_LEN + 10 + nbytes);
+
+ (void) smb_encode_mbc(&reply, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ (void) smb_encode_mbc(&reply, "bww#c", 1, i,
+ nbytes, nbytes, data);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, &reply);
+
+ (void) smb_session_send(sr->session, 0, &reply);
+ }
+
+ return (SDRC_NO_REPLY);
+}
+
+/*
+ * Broadcast messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_broadcast_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * Multi-block messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_end_mb_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * Single-block messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_single_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * Multi-block messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_start_mb_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * Multi-block messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_text_mb_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fem.c b/usr/src/uts/common/fs/smbsrv/smb_fem.c
new file mode 100644
index 0000000000..1248a0a66b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_fem.c
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <sys/sdt.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/fem.h>
+
+fem_t *smb_fcn_ops = NULL;
+
+int smb_fem_fcn_create(femarg_t *, char *, vattr_t *, vcexcl_t, int,
+ vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
+int smb_fem_fcn_remove(femarg_t *, char *, cred_t *,
+ caller_context_t *, int);
+int smb_fem_fcn_rename(femarg_t *, char *, vnode_t *, char *,
+ cred_t *, caller_context_t *, int);
+int smb_fem_fcn_mkdir(femarg_t *, char *, vattr_t *, vnode_t **,
+ cred_t *, caller_context_t *, int, vsecattr_t *);
+int smb_fem_fcn_rmdir(femarg_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+int smb_fem_fcn_link(femarg_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+int smb_fem_fcn_symlink(femarg_t *, char *, vattr_t *,
+ char *, cred_t *, caller_context_t *, int);
+
+static const fs_operation_def_t smb_fcn_tmpl[] = {
+ VOPNAME_CREATE, { .femop_create = smb_fem_fcn_create },
+ VOPNAME_REMOVE, {.femop_remove = smb_fem_fcn_remove},
+ VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
+ VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
+ VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
+ VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
+ VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
+ NULL, NULL
+};
+
+int
+smb_fem_init()
+{
+ return (fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops));
+}
+
+void
+smb_fem_shutdown()
+{
+ if (smb_fcn_ops)
+ fem_free(smb_fcn_ops);
+}
+
+void
+smb_fem_fcn_install(smb_node_t *node)
+{
+ (void) fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
+ (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
+}
+
+void
+smb_fem_fcn_uninstall(smb_node_t *node)
+{
+ (void) fem_uninstall(node->vp, smb_fcn_ops, (void *)node);
+}
+
+/*
+ * smb_fem_fcn_create()
+ *
+ * This monitor will catch only changes to VREG files and not to extended
+ * attribute files. This is fine because, for CIFS files, stream creates
+ * should not trigger any file change notification on the VDIR directory
+ * being monitored. Creates of any other kind of extended attribute in
+ * the directory will also not trigger any file change notification on the
+ * VDIR directory being monitored.
+ */
+
+int
+smb_fem_fcn_create(
+ femarg_t *arg,
+ char *name,
+ vattr_t *vap,
+ vcexcl_t excl,
+ int mode,
+ vnode_t **vpp,
+ cred_t *cr,
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_create(arg, name, vap, excl, mode, vpp, cr, flag,
+ ct, vsecp);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+/*
+ * smb_fem_fcn_remove()
+ *
+ * This monitor will catch only changes to VREG files and to not extended
+ * attribute files. This is fine because, for CIFS files, stream deletes
+ * should not trigger any file change notification on the VDIR directory
+ * being monitored. Deletes of any other kind of extended attribute in
+ * the directory will also not trigger any file change notification on the
+ * VDIR directory being monitored.
+ */
+
+int
+smb_fem_fcn_remove(
+ femarg_t *arg,
+ char *name,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_remove(arg, name, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_rename(
+ femarg_t *arg,
+ char *snm,
+ vnode_t *tdvp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_mkdir(
+ femarg_t *arg,
+ char *name,
+ vattr_t *vap,
+ vnode_t **vpp,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_rmdir(
+ femarg_t *arg,
+ char *name,
+ vnode_t *cdir,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_rmdir(arg, name, cdir, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_link(
+ femarg_t *arg,
+ vnode_t *svp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_link(arg, svp, tnm, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_symlink(
+ femarg_t *arg,
+ char *linkname,
+ vattr_t *vap,
+ char *target,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find.c b/usr/src/uts/common/fs/smbsrv/smb_find.c
new file mode 100644
index 0000000000..1492219714
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_find.c
@@ -0,0 +1,440 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_find
+ *
+ * Request Format: (same as core Search Protocol - "Find First" form)
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * BYTE smb_wct; value = 2
+ * WORD smb_count; max number of entries to find
+ * WORD smb_attr; search attribute
+ * WORD smb_bcc; minimum value = 5
+ * BYTE smb_ident1; ASCII (04)
+ * BYTE smb_pathname[]; filename (may contain global characters)
+ * BYTE smb_ident2; Variable Block (05)
+ * WORD smb_keylen; resume key length (zero if "Find First")
+ * BYTE smb_resumekey[*]; "Find Next" key, * = value of smb_keylen
+ *
+ * Response Format: (same as core Search Protocol)
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_wct; value = 1
+ * WORD smb_count; number of entries found
+ * WORD smb_bcc; minimum value = 3
+ * BYTE smb_ident; Variable Block (05)
+ * WORD smb_datalen; data length
+ * BYTE smb_data[*]; directory entries
+ *
+ * Directory Information Entry (dir_info) Format: (same as core Search Protocol)
+ *
+ * BYTE find_buf_reserved[21]; reserved (resume_key)
+ * BYTE find_buf_attr; attribute
+ * WORD find_buf_time; modification time (hhhhh mmmmmm xxxxx)
+ * where 'xxxxx' is in 2 second increments
+ * WORD find_buf_date; modification date (yyyyyyy mmmm ddddd)
+ * DWORD find_buf_size; file size
+ * STRING find_buf_pname[13]; file name -- ASCII (null terminated)
+ *
+ * The resume_key has the following format:
+ *
+ * BYTE sr_res; reserved:
+ * bit 7 - reserved for consumer use
+ * bit 5,6 - reserved for system use
+ * (must be preserved)
+ * bits 0-4 - reserved for server
+ * (must be preserved)
+ * BYTE sr_name[11]; pathname sought.
+ * Format: 1-8 character file name,
+ * left justified 0-3 character extension,
+ * BYTE sr_findid[1]; uniquely identifies find through
+ * find_close
+ * BYTE sr_server[4]; available for server use
+ * (must be non-zero)
+ * BYTE sr_res[4]; reserved for consumer use
+ *
+ * Service:
+ *
+ * The Find protocol finds the directory entry or group of entries matching the
+ * specified file pathname. The filename portion of the pathname may contain
+ * global (wild card) characters.
+ *
+ * The Find protocol is used to match the find OS/2 system call. The protocols
+ * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching)
+ * a directory. These protocols may be used in place of the core "Search"
+ * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases
+ * where the Search protocol will still be used.
+ *
+ * The format of the Find protocol is the same as the core "Search" protocol.
+ * The difference is that the directory is logically Opened with a Find protocol
+ * and logically closed with the Find Close protocol. This allows the Server to
+ * make better use of its resources. Search buffers are thus held (allowing
+ * search resumption via presenting a "resume_key") until a Find Close protocol
+ * is received. The sr_findid field of each resume key is a unique identifier
+ * (within the session) of the search from "Find" through "Find close". Thus if
+ * the consumer does "Find ahead", any find buffers containing resume keys with
+ * the matching find id may be released when the Find Close is requested.
+ *
+ * As is true of a failing open, if a Find request (Find "first" request where
+ * resume_key is null) fails (no entries are found), no find close protocol is
+ * expected.
+ *
+ * If no global characters are present, a "Find Unique" protocol should be used
+ * (only one entry is expected and find close need not be sent).
+ *
+ * The file path name in the request specifies the file to be sought. The
+ * attribute field indicates the attributes that the file must have. If the
+ * attribute is zero then only normal files are returned. If the system file,
+ * hidden or directory attributes are specified then the search is inclusive --
+ * both the specified type(s) of files and normal files are returned. If the
+ * volume label attribute is specified then the search is exclusive, and only
+ * the volume label entry is returned
+ *
+ * The max-count field specifies the number of directory entries to be returned.
+ * The response will contain zero or more directory entries as determined by the
+ * count-returned field. No more than max-count entries will be returned. Only
+ * entries that match the sought filename/attribute will be returned.
+ *
+ * The resume_key field must be null (length = 0) on the initial ("Find First")
+ * find request. Subsequent find requests intended to continue a search must
+ * contain the resume_key field extracted from the last directory entry of the
+ * previous response. The resume_key field is self-contained, for on calls
+ * containing a resume_key neither the attribute or pathname fields will be
+ * valid in the request. A find request will terminate when either the
+ * requested maximum number of entries that match the named file are found, or
+ * the end of directory is reached without the maximum number of matches being
+ * found. A response containing no entries indicates that no matching entries
+ * were found between the starting point of the search and the end of directory.
+ *
+ * There may be multiple matching entries in response to a single request as
+ * Find supports "wild cards" in the file name (last component of the pathname).
+ * "?" is the wild single characters, "*" or "null" will match any number of
+ * filename characters within a single part of the filename component. The
+ * filename is divided into two parts -- an eight character name and a three
+ * character extension. The name and extension are divided by a ".".
+ *
+ * If a filename part commences with one or more "?"s then exactly that number
+ * of characters will be matched by the Wild Cards, e.g., "??x" will equal "abx"
+ * but not "abcx" or "ax". When a filename part has trailing "?"s then it will
+ * match the specified number of characters or less, e.g., "x??" will match
+ * "xab", "xa" and "x", but not "xabc". If only "?"s are present in the filename
+ * part, then it is handled as for trailing "?"s "*" or "null" match entire
+ * pathname parts, thus "*.abc" or ".abc" will match any file with an extension
+ * of "abc". "*.*", "*" or "null" will match all files in a directory.
+ *
+ * Unprotected servers require the requester to have read permission on the
+ * subtree containing the directory searched (the share specifies read
+ * permission).
+ *
+ * Protected servers require the requester to have permission to search the
+ * specified directory.
+ *
+ * If a Find requests more data than can be placed in a message of the
+ * max-xmit-size for the TID specified, the server will return only the number
+ * of entries which will fit.
+ *
+ * The number of entries returned will be the minimum of:
+ * 1. The number of entries requested.
+ * 2. The number of (complete) entries that will fit in the negotiated SMB
+ * buffer.
+ * 3. The number of entries that match the requested name pattern and
+ * attributes.
+ *
+ * The error ERRnofiles set in smb_err field of the response header or a zero
+ * value in smb_count of the response indicates no matching entry was found.
+ *
+ * The resume search key returned along with each directory entry is a server
+ * defined key which when returned in the Find Next protocol, allows the
+ * directory search to be resumed at the directory entry fol lowing the one
+ * denoted by the resume search key.
+ *
+ * The date is in the following format:
+ * bits:
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * y y y y y y y m m m m d d d d d
+ * where:
+ * y - bit of year 0-119 (1980-2099)
+ * m - bit of month 1-12
+ * d - bit of day 1-31
+ *
+ * The time is in the following format:
+ * bits:
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * h h h h h m m m m m m x x x x x
+ * where:
+ * h - bit of hour (0-23)
+ * m - bit of minute (0-59)
+ * x - bit of 2 second increment
+ *
+ * Find may generate the following errors.
+ * ERRDOS/ERRnofiles
+ * ERRDOS/ERRbadpath
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRbadaccess
+ * ERRDOS/ERRbadshare
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRaccess
+ * ERRSRV/ERRinvnid
+ */
+int
+smb_com_find(struct smb_request *sr)
+{
+ int rc;
+ unsigned short sattr, count, maxcount;
+ char *path;
+ char filename[14];
+ uint32_t cookie;
+ struct smb_node *node;
+ unsigned char type;
+ unsigned short key_len;
+ smb_odir_context_t *pc;
+
+ if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len) != 0) ||
+ (type != 0x05)) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (key_len == 0) { /* begin search */
+ (void) smb_rdir_open(sr, path, sattr);
+ cookie = 0;
+ } else if (key_len == 21) {
+ sr->smb_sid = 0;
+ if (smb_decode_mbc(&sr->smb_data, SMB_RESUME_KEY_FMT,
+ filename, &sr->smb_sid, &cookie) != 0) {
+ /* We don't know which rdir to close */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
+ sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ cookie--; /* +1 when returned */
+ } else {
+ /* We don't know which rdir to close */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
+
+ pc = MEM_ZALLOC("smb", sizeof (*pc));
+ pc->dc_cookie = cookie;
+ count = 0;
+ node = (struct smb_node *)0;
+ rc = 0;
+ while (count < maxcount) {
+ if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
+ break;
+
+ (void) smb_encode_mbc(&sr->reply, ".8c3cbl4.bYl13c",
+ pc->dc_name83, pc->dc_name83+9, sr->smb_sid,
+ pc->dc_cookie+1, pc->dc_dattr,
+ smb_gmt_to_local_time(pc->dc_attr.sa_vattr.va_mtime.tv_sec),
+ (int32_t)smb_node_get_size(node, &pc->dc_attr),
+ (*pc->dc_shortname) ? pc->dc_shortname : pc->dc_name);
+ smb_node_release(node);
+ node = (struct smb_node *)0;
+ count++;
+ }
+ MEM_FREE("smb", pc);
+
+ if ((rc != 0) && (rc != ENOENT)) {
+ /* returned error by smb_rdir_next() */
+ smb_rdir_close(sr);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (count == 0) {
+ smb_rdir_close(sr);
+ smbsr_raise_error(sr, ERRDOS, ERRnofiles);
+ /* NOTREACHED */
+ }
+
+ rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
+ if (smb_poke_mbc(&sr->reply, sr->cur_reply_offset,
+ "bwwbw", 1, count, rc+3, 5, rc) < 0) {
+ smb_rdir_close(sr);
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_com_find_close
+ *
+ * Request Format: (same as core Search Protocol - "Find Next" form)
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * BYTE smb_wct; value = 2
+ * WORD smb_count; max number of entries to find
+ * WORD smb_attr; search attribute
+ * WORD smb_bcc; minimum value = 5
+ * BYTE smb_ident1; ASCII (04)
+ * BYTE smb_pathname[]; null (may contain only null)
+ * BYTE smb_ident2; Variable Block (05)
+ * WORD smb_keylen; resume (close) key length
+ * (may not be zero)
+ * BYTE smb_resumekey[*]; "Find Close" key
+ * (* = value of smb_keylen)
+ *
+ * Response Format: (same format as core Search Protocol)
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * BYTE smb_wct; value = 1
+ * WORD smb_reserved; reserved
+ * WORD smb_bcc; value = 3
+ * BYTE smb_ident; Variable Block (05)
+ * WORD smb_datalen; data length (value = 0)
+ *
+ * The resume_key (or close key) has the following format:
+ *
+ * BYTE sr_res; reserved:
+ * bit 7 - reserved for consumer use
+ * bit 5,6 - reserved for system use
+ * (must be preserved)
+ * bits 0-4 - rsvd for server
+ * (must be preserved by consumer)
+ * BYTE sr_name[11]; pathname sought.
+ * Format: 1-8 character file name,
+ * left justified 0-3 character extension,
+ * left justified (in last 3 chars)
+ * BYTE sr_findid[1]; uniquely identifies find
+ * through find_close
+ * BYTE sr_server[4]; available for server use
+ * (must be non-zero)
+ * BYTE sr_res[4]; reserved for consumer use
+ *
+ * Service:
+ *
+ * The Find_Close protocol closes the association between a Find id
+ * returned (in the resume_key) by the Find protocol and the directory
+ * search.
+ *
+ * Whereas the First Find protocol logically opens the directory,
+ * subsequent find protocols presenting a resume_key further "read" the
+ * directory, the Find Close protocol "closes" the directory allowing the
+ * server to free any resources held in support of the directory search.
+ *
+ * The Find Close protocol is used to match the find Close OS/2
+ * system call. The protocols "Find", "Find Unique" and "Find Close" are
+ * methods of reading (or searching) a directory. These protocols may
+ * be used in place of the core "Search" protocol when LANMAN 1.0 dialect has
+ * been negotiated. There may be cases where the Search protocol will still be
+ * used.
+ *
+ * Although only the find id portion the resume key should be
+ * required to identify the search being ter minated, the entire
+ * resume_key as returned in the previous Find, either a "Find First" or "Find
+ * Next" is sent to the server in this protocol.
+ *
+ * Find Close may generate the following errors:
+ *
+ * ERRDOS/ERRbadfid
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ */
+int
+smb_com_find_close(struct smb_request *sr)
+{
+ unsigned short sattr, maxcount;
+ char *path;
+ char filename[14];
+ uint32_t cookie;
+ unsigned char type;
+ unsigned short key_len;
+ int rc;
+
+ if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len);
+ if ((rc != 0) || (type != 0x05)) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (key_len == 0) { /* begin search */
+ smbsr_raise_error(sr, ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (key_len == 21) {
+ sr->smb_sid = 0;
+ if (smb_decode_mbc(&sr->smb_data, SMB_RESUME_KEY_FMT,
+ filename, &sr->smb_sid, &cookie) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
+ sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ cookie--; /* +1 when returned */
+ } else {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ smb_rdir_close(sr);
+ smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find_notify_close.c b/usr/src/uts/common/fs/smbsrv/smb_find_notify_close.c
new file mode 100644
index 0000000000..46a9953b55
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_find_notify_close.c
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Client Request Description
+ * ================================== =================================
+ *
+ * BYTE smb_cmd; FIND_NOTIFY_CLOSE
+ * BYTE smb_wct; value = 1
+ * WORD smb_handle; Find notify handle
+ * WORD smb_bcc; value = 0
+ *
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * BYTE smb_cmd; FIND_NOTIFY_CLOSE
+ * BYTE smb_wct; value = 0
+ * WORD smb_bcc; value = 0
+ *
+ * The FIND_NOTIFY_CLOSE request closes the association between a
+ * directory handle returned following a resource monitor, established
+ * using a TRANS2_FIND_NOTIFY_FIRST request to the server, and the
+ * resulting system directory monitor. This request allows the server
+ * to free any resources held in support of the open handle.
+ *
+ * The Find Close protocol is used to match the DosFindNotifyClose
+ * OS/2 system call.
+ *
+ * Find Notify Close may generate the following errors.
+ *
+ * ERRDOS/ERRbadfid
+ * ERRDOS/<implementation specific>
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ * ERRSRV/<implementation specific>
+ * ERRHRD/<implementation specific>
+ */
+
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_find_notify_close
+ *
+ * As far as I can tell, this part of the protocol is not implemented
+ * by NT server.
+ */
+int /*ARGSUSED*/
+smb_com_find_notify_close(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find_unique.c b/usr/src/uts/common/fs/smbsrv/smb_find_unique.c
new file mode 100644
index 0000000000..59f9ba12b2
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_find_unique.c
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * Request Format: (same as core Search Protocol - "Find First" form)
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * BYTE smb_wct; value = 2
+ * WORD smb_count; max number of entries to find
+ * WORD smb_attr; search attribute
+ * WORD smb_bcc; minimum value = 5
+ * BYTE smb_ident1; ASCII (04)
+ * BYTE smb_pathname[]; filename (may contain global characters)
+ * BYTE smb_ident2; Variable Block (05)
+ * WORD smb_keylen; must be zero ("Find First" only)
+ *
+ * Response Format: (same as core Search Protocol)
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_wct; value = 1
+ * WORD smb_count; number of entries found
+ * WORD smb_bcc; minimum value = 3
+ * BYTE smb_ident; Variable Block (05)
+ * WORD smb_datalen; data length
+ * BYTE smb_data[*]; directory entries
+ *
+ * Directory Information Entry (dir_info) Format: (same as core Search Protocol)
+ *
+ * BYTE find_buf_reserved[21]; reserved (resume_key)
+ * BYTE find_buf_attr; attribute
+ * WORD find_buf_time; modification time (hhhhh mmmmmm xxxxx)
+ * where 'xxxxx' is in 2 second increments
+ * WORD find_buf_date; modification date (yyyyyyy mmmm ddddd)
+ * DWORD find_buf_size; file size
+ * STRING find_buf_pname[13]; file name -- ASCII (null terminated)
+ *
+ * The resume_key has the following format:
+ *
+ * BYTE sr_res; reserved:
+ * bit 7 - reserved for consumer use
+ * bit 5,6 - reserved for system use
+ * (must be preserved)
+ * bits 0-4 - reserved for server
+ * (must be preserved)
+ * BYTE sr_name[11]; pathname sought.
+ * Format: 1-8 character file name,
+ * left justified 0-3 character extension,
+ * BYTE sr_findid[1]; uniquely identifies find through
+ * find_close
+ * BYTE sr_server[4]; available for server use
+ * (must be non-zero)
+ * BYTE sr_res[4]; reserved for consumer use
+ *
+ * Service:
+ *
+ * The Find protocol finds the directory entry or group of entries matching the
+ * specified file pathname. The filename portion of the pathname may contain
+ * global (wild card) characters. The search may not be resumed and no Find
+ * Close protocol is expected.
+ *
+ * The Find protocol is used to match the find OS/2 system call. The protocols
+ * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching)
+ * a directory. These protocols may be used in place of the core "Search"
+ * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases
+ * where the Search protocol will still be used.
+ *
+ * The format of the Find Unique protocol is the same as the core "Search"
+ * protocol. The difference is that the directory is logically opened ,
+ * any matching entries returned, and then the directory is logically
+ * closed.
+ *
+ * This allows the Server to make better use of its resources. No Search buffers
+ * are held (search resumption via presenting a "resume_key" will not be
+ * allowed).
+ *
+ * Only one buffer of entries is expected and find close need not be sent).
+ *
+ * The file path name in the request specifies the file to be
+ * sought. The attribute field indicates the attributes that the file
+ * must have. If the attribute is zero then only normal files are
+ * returned. If the system file, hidden or directory attributes are
+ * specified then the search is inclusive -- both the specified type(s)
+ * of files and normal files are returned. If the volume label attribute
+ * is specified then the search is exclusive, and only the volume label entry
+ * is returned
+ *
+ * The max-count field specifies the number of directory entries to be
+ * returned. The response will contain zero or more directory entries
+ * as determined by the count-returned field. No more than max-count
+ * entries will be returned. Only entries that match the sought
+ * filename/attribute will be returned.
+ *
+ * The resume_key field must be null (length = 0).
+ *
+ * A Find_Unique request will terminate when either the requested maximum
+ * number of entries that match the named file are found, or the end
+ * of directory is reached without the maximum number of matches being
+ * found. A response containing no entries indicates that no matching
+ * entries were found between the starting point of the search and the end of
+ * directory.
+ *
+ * There may be multiple matching entries in response to a single
+ * request as Find Unique supports "wild cards" in the file name (last
+ * component of the pathname). "?" is the wild card for single
+ * characters, "*" or "null" will match any number of filename characters
+ * within a single part of the filename component. The filename is
+ * divided into two parts -- an eight character name and a three
+ * character extension. The name and extension are divided by a ".".
+ *
+ * If a filename part commences with one or more "?"s then exactly
+ * that number of characters will be matched by the Wild Cards, e.g.,
+ * "??x" will equal "abx" but not "abcx" or "ax". When a filename part has
+ * trailing "?"s then it will match the specified number of characters
+ * or less, e.g., "x??" will match "xab", "xa" and "x", but not "xabc". If
+ * only "?"s are present in the filename part, then it is handled as
+ * for trailing "?"s
+ *
+ * "*" or "null" match entire pathname parts, thus "*.abc" or ".abc" will
+ * match any file with an extension of "abc". "*.*", "*" or "null" will
+ * match all files in a directory.
+ *
+ * Unprotected servers require the requester to have read permission on the
+ * subtree containing the directory searched, the share specifies read
+ * permission.
+ *
+ * Protected servers require the requester to have permission to search the
+ * specified directory.
+ *
+ * If a Find Unique requests more data than can be placed in a
+ * message of the max-xmit-size for the TID specified, the server will
+ * abort the virtual circuit to the consumer.
+ *
+ * The number of entries returned will be the minimum of:
+ *
+ * 1. The number of entries requested.
+ * 2. The number of complete entries that will fit in the
+ * negotiated SMB buffer.
+ * 3. The number of entries that match the requested name pattern and
+ * attributes.
+ *
+ * The error ERRnofiles set in smb_err field of the response header or a zero
+ * value in smb_count of the response indicates no matching entry was found.
+ *
+ * The resume search key returned along with each directory entry is a server
+ * defined key. This key will be returned as in the Find protocol and Search
+ * protocol however it may NOT be returned to continue the search.
+ *
+ * The date is in the following format:
+ * bits:
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * y y y y y y y m m m m d d d d d
+ * where:
+ * y - bit of year 0-119 (1980-2099)
+ * m - bit of month 1-12
+ * d - bit of day 1-31
+ *
+ * The time is in the following format:
+ * bits:
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * h h h h h m m m m m m x x x x x
+ * where:
+ * h - bit of hour (0-23)
+ * m - bit of minute (0-59)
+ * x - bit of 2 second increment
+ *
+ * Find Unique may generate the following errors.
+ * ERRDOS/ERRnofiles
+ * ERRDOS/ERRbadpath
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRbadaccess
+ * ERRDOS/ERRbadshare
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRaccess
+ * ERRSRV/ERRinvnid
+ */
+int
+smb_com_find_unique(struct smb_request *sr)
+{
+ int rc;
+ unsigned short sattr, count, maxcount;
+ char *path;
+ struct vardata_block *vdb;
+ struct smb_node *node;
+ smb_odir_context_t *pc;
+
+ vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
+ if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%AV", sr, &path, vdb) != 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (vdb->len != 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
+
+ /* begin search */
+ (void) smb_rdir_open(sr, path, sattr);
+
+ pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
+ pc->dc_cookie = 0;
+ count = 0;
+ node = (struct smb_node *)0;
+ rc = 0;
+ while (count < maxcount) {
+ if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
+ break;
+
+ (void) smb_encode_mbc(&sr->reply, ".8c3cbl4.bYl13c",
+ pc->dc_name83, pc->dc_name83+9, sr->smb_sid,
+ pc->dc_cookie+1, pc->dc_dattr,
+ smb_gmt_to_local_time(pc->dc_attr.sa_vattr.va_mtime.tv_sec),
+ (int32_t)smb_node_get_size(node, &pc->dc_attr),
+ (*pc->dc_shortname) ? pc->dc_shortname : pc->dc_name);
+ smb_node_release(node);
+ node = (struct smb_node *)0;
+ count++;
+ }
+ kmem_free(pc, sizeof (*pc));
+
+ smb_rdir_close(sr);
+
+ if ((rc != 0) && (rc != ENOENT)) {
+ /* returned error by smb_rdir_next() */
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (count == 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_raise_error(sr, ERRDOS, ERRnofiles);
+ /* NOTREACHED */
+ }
+
+ rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
+ if (smb_poke_mbc(&sr->reply, sr->cur_reply_offset,
+ "bwwbw", 1, count, rc+3, 5, rc) < 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+ kmem_free(vdb, sizeof (struct vardata_block));
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_flush.c b/usr/src/uts/common/fs/smbsrv/smb_flush.c
new file mode 100644
index 0000000000..b9cfb8c349
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_flush.c
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The flush SMB is sent to ensure all data and allocation information
+ * for the corresponding file has been written to stable storage. This
+ * is a synchronous request. The response should not be sent until the
+ * writes are complete.
+ *
+ * The SmbFlush request is described in CIFS/1.0 1996 Section 3.9.14.
+ *
+ * CIFS/1.0 June 13, 1996
+ * Heizer, et al
+ * draft-heizer-cifs-v1-spec-00.txt
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+
+static void smb_flush_file(struct smb_request *sr, struct smb_ofile *ofile);
+
+
+int smb_flush_required = 1;
+
+
+/*
+ * smb_commit_required
+ *
+ * Specify whether or not SmbFlush should send commit requests to the
+ * file system. If state is non-zero, commit requests will be sent to
+ * the file system. If state is zero, SmbFlush is a no-op.
+ */
+void
+smb_commit_required(int state)
+{
+ smb_flush_required = state;
+}
+
+
+/*
+ * smb_com_flush
+ *
+ * Flush any cached data for a specified file, or for all files that
+ * this client has open, to stable storage. If the fid is valid (i.e.
+ * not 0xFFFF), we flush only that file. Otherwise we flush all files
+ * associated with this client.
+ *
+ * We need to protect the list because there's a good chance we'll
+ * block during the flush operation.
+ */
+int
+smb_com_flush(smb_request_t *sr)
+{
+ smb_ofile_t *file;
+ smb_llist_t *flist;
+
+ if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smb_flush_required == 0) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (sr->smb_fid != 0xffff) {
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ smb_flush_file(sr, sr->fid_ofile);
+ } else {
+ flist = &sr->tid_tree->t_ofile_list;
+ smb_llist_enter(flist, RW_READER);
+ file = smb_llist_head(flist);
+ while (file) {
+ mutex_enter(&file->f_mutex);
+ smb_flush_file(sr, file);
+ mutex_exit(&file->f_mutex);
+ file = smb_llist_next(flist, file);
+ }
+ smb_llist_exit(flist);
+ }
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_flush_file
+ *
+ * If writes on this file are not synchronous, flush it using the NFSv3
+ * commit interface.
+ */
+static void smb_flush_file(struct smb_request *sr, struct smb_ofile *ofile)
+{
+ if ((ofile->f_node->flags & NODE_FLAGS_WRITE_THROUGH) == 0)
+ (void) smb_fsop_commit(sr, sr->user_cr, ofile->f_node);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_forward.c b/usr/src/uts/common/fs/smbsrv/smb_forward.c
new file mode 100644
index 0000000000..498e3bcaa7
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_forward.c
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the SMB ForwardUserName interface:
+ * smb_com_forward_user_name
+ * smb_com_cancel_forward
+ * smb_com_get_machine_name
+ *
+ * The description of this interface is taken verbatim from the netmon
+ * SMB protocol help. These functions are currently empty stubs that
+ * return SDRC_UNIMPLEMENTED.
+ */
+
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_forward_user_name
+ *
+ * This command informs the server that it should accept messages sent
+ * to the forwarded name. The name specified in this message does not
+ * include the one byte suffix ("03" or "05").
+ *
+ * Client Request Description
+ * ================================== =================================
+ * BYTE smb_com SMBfwdname
+ * BYTE smb_wct 0
+ * BYTE smb_bcc min = 2
+ * BYTE smb_buf[] ASCII -- 04
+ * forwarded name (max 15 bytes)
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_com SMBfwdname
+ * BYTE smb_wct 0
+ * BYTE smb_bcc 0
+ *
+ * ForwardUserName may generate the following errors.
+ * ERRDOS/<implementation specific>
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ * ERRSRV/ERRrmuns
+ * ERRSRV/<implementation specific>
+ * ERRHRD/<implementation specific>
+ */
+int /*ARGSUSED*/
+smb_com_forward_user_name(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * smb_com_cancel_forward
+ *
+ * The CancelForward command cancels the effect of a prior ForwardUserName
+ * command. The addressed server will no longer accept messages for the
+ * designated user name. The name specified in this message does not
+ * include the one byte suffix ("05").
+ *
+ * Client Request Description
+ * ================================== =================================
+ * BYTE smb_com SMBcancelf
+ * BYTE smb_wct 0
+ * BYTE smb_bcc min = 2
+ * BYTE smb_buf[] ASCII -- 04
+ * forwarded name (max 15 bytes)
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_com SMBcancelf
+ * BYTE smb_wct 0
+ * BYTE smb_bcc 0
+ *
+ * CancelForward may generate the following errors.
+ * ERRDOS/<implementation specific>
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ * ERRSRV/<implementation specific>
+ * ERRHRD/<implementation specific>
+ */
+int /*ARGSUSED*/
+smb_com_cancel_forward(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * smb_com_get_machine_name
+ *
+ * The GetMachineName command obtains the machine name of the target machine.
+ * It is used prior to the CancelForward command to determine to which
+ * machine the CancelForward command should be sent. GetMachineName is sent
+ * to the forwarded name to be canceled, and the server then returns the
+ * machine name to which the CancelForward command must be sent.
+ *
+ * Client Request Description
+ * ================================== =================================
+ * BYTE smb_com SMBgetmac
+ * BYTE smb_wct 0
+ * BYTE smb_bcc 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_com SMBgetmac
+ * BYTE smb_wct 0
+ * BYTE smb_bcc min = 2
+ * BYTE smb_buf[] ASCII -- 04
+ * machine name (max 15 bytes)
+ *
+ * GetMachineName may return the following errors.
+ * ERRRDOS/<implementation specific>
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ * ERRSRV/<implementation specific>
+ */
+int /*ARGSUSED*/
+smb_com_get_machine_name(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsd.c b/usr/src/uts/common/fs/smbsrv/smb_fsd.c
new file mode 100644
index 0000000000..354b7d3487
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsd.c
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/feature_tests.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/sdt.h>
+#include <smbsrv/string.h>
+#include <smbsrv/smb_vops.h>
+
+fs_desc_t null_fsd = {0, 0};
+extern vfs_t *rootvfs;
+
+static void fsd_getname(vfs_t *vfsp, fsvol_attr_t *vol_attr);
+static void fsd_getflags(vfs_t *vfsp, unsigned *flags);
+static void fsd_getseq(vfs_t *vfsp, uint32_t *fs_sequence);
+static void fsd_name_from_mntpoint(char *, const char *, size_t);
+
+/*
+ * The "pathname" parameter may be either a path name or a volume name.
+ * Kernel caller must call fsd_rele(vfsp).
+ * User space caller will not have a hold on the fs.
+ */
+
+void *
+fsd_lookup(char *name, unsigned flags, fs_desc_t *fsd)
+{
+ int (*func)(const char *, const char *);
+ struct vfs *vfsp, *vfs_found = NULL;
+ refstr_t *vfs_mntpoint;
+ char vfs_volname[VOL_NAME_MAX];
+ char volname[VOL_NAME_MAX];
+
+ if (fsd)
+ *fsd = null_fsd;
+
+ vfs_list_read_lock();
+ vfsp = rootvfs;
+
+ func = (flags & FSOLF_CASE_INSENSITIVE) ? utf8_strcasecmp : strcmp;
+
+ fsd_name_from_mntpoint(volname, name, VOL_NAME_MAX);
+
+ do {
+ vfs_mntpoint = vfsp->vfs_mntpt;
+ refstr_hold(vfs_mntpoint);
+
+ fsd_name_from_mntpoint(vfs_volname, vfs_mntpoint->rs_string,
+ VOL_NAME_MAX);
+
+ if (func(volname, vfs_volname) == 0) {
+ VFS_HOLD(vfsp);
+ vfs_found = vfsp;
+
+ if (fsd) {
+ *fsd = vfsp->vfs_fsid;
+ }
+ refstr_rele(vfs_mntpoint);
+ break;
+ } else {
+ refstr_rele(vfs_mntpoint);
+ }
+ vfsp = vfsp->vfs_next;
+
+ } while (vfsp != rootvfs);
+
+ vfs_list_unlock();
+ return (vfs_found);
+}
+
+/*
+ * Compare two volume descriptors to determine whether or not they
+ * refer to the same volume. Returns 0 if the descriptors refer to
+ * the same volume. Otherwise returns 1.
+ */
+
+int
+fsd_cmp(fs_desc_t *fsd1, fs_desc_t *fsd2)
+{
+ if ((fsd1->val[0] == fsd2->val[0]) && (fsd1->val[1] == fsd2->val[1])) {
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * fsd_getattr
+ *
+ * Obtain volume attributes. If the volume is mounted, the attributes
+ * are copied to vol_attr. Otherwise, vol_attr is zero'd.
+ *
+ * Returns 0 on success. Otherwise an errno is returned to indicate
+ * the error.
+ */
+
+int
+fsd_getattr(fs_desc_t *fsd, fsvol_attr_t *vol_attr)
+{
+ vfs_t *vfsp;
+
+ ASSERT(fsd);
+ ASSERT(vol_attr);
+
+ if ((vfsp = getvfs(fsd)) == NULL)
+ return (ESTALE);
+
+ bzero(vol_attr, sizeof (fsvol_attr_t));
+ fsd_getname(vfsp, vol_attr);
+ fsd_getflags(vfsp, &vol_attr->flags);
+ fsd_getseq(vfsp, &vol_attr->fs_sequence);
+
+ VFS_RELE(vfsp);
+ return (0);
+}
+
+/*
+ * Check whether or not a file system supports the features identified
+ * by flags. Flags can be any combination of the FSOLF flags.
+ * Returns 1 if all of the features are supported. Otherwise returns 0.
+ * Exception: Returns -1 if stale fsd.
+ */
+
+int
+fsd_chkcap(fs_desc_t *fsd, unsigned flags)
+{
+ vfs_t *vfsp = getvfs(fsd);
+ unsigned getflags = 0;
+
+ if (!vfsp) {
+ return (-1);
+ }
+
+ fsd_getflags(vfsp, &getflags);
+
+ VFS_RELE(vfsp);
+
+ if ((flags != 0) && (getflags & flags) == flags) {
+ return (1);
+ }
+
+ return (0);
+}
+
+void *
+fsd_hold(fs_desc_t *fsd)
+{
+ void *vfsp = getvfs(fsd);
+
+ return (vfsp);
+}
+
+void
+fsd_rele(void *vfsp)
+{
+ ASSERT(vfsp);
+
+ VFS_RELE((vfs_t *)vfsp);
+}
+
+/*
+ * Returns volume name.
+ * Also fills in vol_attr->fs_typename (needed for fsd_getattr()).
+ *
+ * File system types are hardcoded in uts/common/os/vfs_conf.c .
+ */
+
+static void
+fsd_getname(vfs_t *vfsp, fsvol_attr_t *vol_attr)
+{
+ refstr_t *vfs_mntpoint;
+
+ (void) strlcpy(vol_attr->fs_typename,
+ vfssw[vfsp->vfs_fstype].vsw_name, VOL_NAME_MAX);
+
+ vfs_mntpoint = vfs_getmntpoint(vfsp);
+ fsd_name_from_mntpoint(vol_attr->name, vfs_mntpoint->rs_string,
+ VOL_NAME_MAX);
+
+ refstr_rele(vfs_mntpoint);
+}
+
+/*
+ * Always set supports ACLs because the VFS will fake ACLs
+ * for file systems that don't support them.
+ */
+static void
+fsd_getflags(vfs_t *vfsp, uint_t *flags_ret)
+{
+ char *fsname = vfssw[vfsp->vfs_fstype].vsw_name;
+ uint_t flags = FSOLF_SUPPORTS_ACLS;
+
+ if (vfsp->vfs_flag & VFS_RDONLY)
+ flags |= FSOLF_READONLY;
+
+ if (vfsp->vfs_flag & VFS_XATTR)
+ flags |= FSOLF_STREAMS;
+
+ if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
+ flags |= FSOLF_NO_ATIME;
+
+ if (strcmp(fsname, "tmpfs") == 0)
+ flags |= FSOLF_NOEXPORT;
+
+ if (vfs_has_feature(vfsp, VFSFT_XVATTR))
+ flags |= FSOLF_XVATTR;
+
+ if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
+ flags |= FSOLF_CASE_INSENSITIVE;
+
+ if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
+ flags |= FSOLF_NO_CASE_SENSITIVE;
+
+ if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
+ flags |= FSOLF_DIRENTFLAGS;
+
+ DTRACE_PROBE1(smb__vfs__getflags, uint_t, flags);
+ *flags_ret = flags;
+}
+
+
+/* ARGSUSED */
+static void
+fsd_getseq(vfs_t *vfsp, uint32_t *fs_sequence)
+{
+ /*
+ * This function is more complicated if there is
+ * DAVE support, but we have excised that code for
+ * the moment.
+ */
+ *fs_sequence = 0;
+}
+
+/*
+ * This function parses out the first conponent of a mount path,
+ * used elsewhere as the volume name.
+ *
+ * For "/", the volume name is "" (i.e. ROOTVOL).
+ */
+
+static void
+fsd_name_from_mntpoint(char *name, const char *mntpnt, size_t name_sz)
+{
+ const char *s = mntpnt;
+ char *tmp = name;
+
+ s += strspn(s, "/");
+ (void) strlcpy(name, s, name_sz);
+ (void) strsep((char **)&tmp, "/");
+
+ DTRACE_PROBE2(smb__vfs__volume, char *, mntpnt, char *, name);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
new file mode 100644
index 0000000000..655e5ad3ff
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
@@ -0,0 +1,2595 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sid.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <acl/acl_common.h>
+
+u_longlong_t smb_caller_id;
+
+static int smb_fsop_amask_to_omode(uint32_t granted_access);
+
+extern uint32_t smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd);
+
+extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd,
+ uint32_t secinfo);
+
+extern int smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr,
+ int *aclbsize);
+
+static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode,
+ smb_fssd_t *fs_sd);
+
+static void smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl,
+ int which_acl);
+static acl_t *smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl);
+
+/*
+ * The smb_fsop_* functions have knowledge of CIFS semantics.
+ *
+ * The smb_vop_* functions have minimal knowledge of CIFS semantics and
+ * serve as an interface to the VFS layer.
+ *
+ * Hence, smb_request_t and smb_node_t structures should not be passed
+ * from the smb_fsop_* layer to the smb_vop_* layer.
+ *
+ * In general, CIFS service code should only ever call smb_fsop_*
+ * functions directly, and never smb_vop_* functions directly.
+ *
+ * smb_fsop_* functions should call smb_vop_* functions where possible, instead
+ * of their smb_fsop_* counterparts. However, there are times when
+ * this cannot be avoided.
+ */
+
+/*
+ * Note: Stream names cannot be mangled.
+ */
+
+int
+smb_fsop_start()
+{
+ int error;
+
+ smb_caller_id = fs_new_caller_id();
+ error = smb_node_root_init();
+
+ if (error == 0)
+ error = smb_fem_init();
+
+ return (error);
+}
+
+void
+smb_fsop_stop()
+{
+ smb_fem_shutdown();
+ smb_vfs_rele_all();
+ smb_node_root_fini();
+}
+
+int
+smb_fsop_open(smb_ofile_t *of)
+{
+ caller_context_t ct;
+ int mode;
+
+ mode = smb_fsop_amask_to_omode(of->f_granted_access);
+
+ smb_get_caller_context(NULL, &ct);
+
+ /*
+ * Assuming that same vnode is returned as we had before
+ * (i.e. no special vnodes)
+ */
+
+ return (smb_vop_open(&of->f_node->vp, mode, of->f_cr, &ct));
+}
+
+int
+smb_fsop_close(smb_ofile_t *of)
+{
+ caller_context_t ct;
+ int mode;
+
+ mode = smb_fsop_amask_to_omode(of->f_granted_access);
+
+ smb_get_caller_context(NULL, &ct);
+
+ return (smb_vop_close(of->f_node->vp, mode, of->f_cr, &ct));
+}
+
+static int
+smb_fsop_amask_to_omode(uint32_t granted_access)
+{
+ int mode = 0;
+
+ if (granted_access & (ACE_READ_DATA | ACE_EXECUTE))
+ mode |= FREAD;
+
+ if (granted_access & (ACE_WRITE_DATA | ACE_APPEND_DATA))
+ mode |= FWRITE;
+
+ if (granted_access & ACE_APPEND_DATA)
+ mode |= FAPPEND;
+
+ return (mode);
+}
+
+static int
+smb_fsop_create_with_sd(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *snode,
+ char *name,
+ smb_attr_t *attr,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr,
+ smb_fssd_t *fs_sd)
+{
+ caller_context_t ct;
+ vsecattr_t *vsap;
+ vsecattr_t vsecattr;
+ acl_t *acl, *dacl, *sacl;
+ smb_attr_t set_attr;
+ vnode_t *vp;
+ int aclbsize = 0; /* size of acl list in bytes */
+ int flags = 0;
+ int is_dir;
+ int rc;
+
+ ASSERT(fs_sd);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ ASSERT(cr);
+ smb_get_caller_context(sr, &ct);
+
+ is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0);
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACLONCREATE) {
+ if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
+ dacl = fs_sd->sd_zdacl;
+ sacl = fs_sd->sd_zsacl;
+ ASSERT(dacl || sacl);
+ if (dacl && sacl) {
+ acl = smb_fsop_aclmerge(dacl, sacl);
+ } else if (dacl) {
+ acl = dacl;
+ } else {
+ acl = sacl;
+ }
+
+ rc = smb_vop_acl_to_vsa(acl, &vsecattr, &aclbsize);
+
+ if (dacl && sacl)
+ acl_free(acl);
+
+ if (rc)
+ return (rc);
+
+ vsap = &vsecattr;
+ }
+ else
+ vsap = NULL;
+
+ if (is_dir) {
+ rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags,
+ cr, &ct, vsap);
+ } else {
+ rc = smb_vop_create(snode->vp, name, attr, &vp, flags,
+ cr, &ct, vsap);
+ }
+
+ if (vsap != NULL)
+ kmem_free(vsap->vsa_aclentp, aclbsize);
+
+ if (rc != 0)
+ return (rc);
+
+ set_attr.sa_mask = 0;
+
+ /*
+ * Ideally we should be able to specify the owner and owning
+ * group at create time along with the ACL. Since we cannot
+ * do that right now, kcred is passed to smb_vop_setattr so it
+ * doesn't fail due to lack of permission.
+ */
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
+ set_attr.sa_mask |= SMB_AT_UID;
+ }
+
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
+ set_attr.sa_mask |= SMB_AT_GID;
+ }
+
+ if (set_attr.sa_mask) {
+ rc = smb_vop_setattr(snode->vp, NULL, &set_attr,
+ 0, kcred, &ct);
+ }
+
+ } else {
+ /*
+ * For filesystems that don't support ACL-on-create, try
+ * to set the specified SD after create, which could actually
+ * fail because of conflicts between inherited security
+ * attributes upon creation and the specified SD.
+ *
+ * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
+ */
+
+ if (is_dir) {
+ rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags,
+ cr, &ct, NULL);
+ } else {
+ rc = smb_vop_create(snode->vp, name, attr, &vp, flags,
+ cr, &ct, NULL);
+ }
+
+ if (rc == 0)
+ rc = smb_fsop_sdwrite(sr, kcred, snode, fs_sd, 1);
+ }
+
+ if (rc == 0) {
+ *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, name,
+ snode, NULL, ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ }
+
+ return (rc);
+}
+
+
+/*
+ * smb_fsop_create
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * all the smb_vop_creates are performed with the appropriate credentials.
+ * Please document any direct calls to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ *
+ * *ret_snode is returned with a reference upon success. No reference is
+ * taken if an error is returned.
+ */
+
+int
+smb_fsop_create(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ char *name,
+ smb_attr_t *attr,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr)
+{
+ struct open_param *op = &sr->arg.open;
+ smb_node_t *fnode;
+ smb_attr_t file_attr;
+ caller_context_t ct;
+ vnode_t *xattrdirvp;
+ vnode_t *vp;
+ char *longname = NULL;
+ char *namep;
+ char *fname;
+ char *sname;
+ int is_stream;
+ int flags = 0;
+ int rc = 0;
+ smb_fssd_t fs_sd;
+ uint32_t secinfo;
+ uint32_t status;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(ret_snode);
+ *ret_snode = 0;
+
+ ASSERT(name);
+ if (*name == 0)
+ return (EINVAL);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ is_stream = smb_stream_parse_name(name, fname, sname);
+
+ if (is_stream)
+ namep = fname;
+ else
+ namep = name;
+
+ if (smb_maybe_mangled_name(namep)) {
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname,
+ MAXNAMELEN, NULL, NULL, 1);
+
+ if ((is_stream == 0) && (rc == 0))
+ rc = EEXIST;
+
+ if ((is_stream && rc) ||
+ ((is_stream == 0) && (rc != ENOENT))) {
+ kmem_free(longname, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ if (is_stream)
+ namep = longname;
+ else
+ kmem_free(longname, MAXNAMELEN);
+ }
+
+ if (is_stream) {
+ /*
+ * Look up the unnamed stream.
+ *
+ * Mangle processing in smb_fsop_lookup() for the unnamed
+ * stream won't be needed (as it was done above), but
+ * it may be needed on any link target (which
+ * smb_fsop_lookup() will provide).
+ */
+ rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr,
+ 0, 0);
+
+ if (longname) {
+ kmem_free(longname, MAXNAMELEN);
+ namep = NULL;
+ }
+
+ if (rc != 0) {
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ smb_get_caller_context(sr, &ct);
+
+ rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp,
+ &xattrdirvp, flags, cr, &ct);
+
+ if (rc != 0) {
+ smb_node_release(fnode);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
+ vp, sname, ret_attr);
+
+ smb_node_release(fnode);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(xattrdirvp);
+ VN_RELE(vp);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (ENOMEM);
+ }
+ } else {
+ if (op->sd_buf) {
+ /*
+ * SD sent by client in Windows format. Needs to be
+ * converted to FS format. No inheritance.
+ */
+ secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf);
+ smb_fsop_sdinit(&fs_sd, secinfo, 0);
+
+ status = smb_sd_tofs(op->sd_buf, &fs_sd);
+ if (status == NT_STATUS_SUCCESS) {
+ rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
+ name, attr, ret_snode, ret_attr, &fs_sd);
+ }
+ else
+ rc = EINVAL;
+ smb_fsop_sdterm(&fs_sd);
+ } else if (sr->tid_tree->t_acltype == ACE_T) {
+ /*
+ * No incoming SD and filesystem is ZFS
+ * Server applies Windows inheritance rules,
+ * see smb_fsop_sdinherit() comments as to why.
+ */
+ smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, 0);
+ rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd);
+ if (rc == 0) {
+ rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
+ name, attr, ret_snode, ret_attr, &fs_sd);
+ }
+
+ smb_fsop_sdterm(&fs_sd);
+ } else {
+ /*
+ * No incoming SD and filesystem is not ZFS
+ * let the filesystem handles the inheritance.
+ */
+ smb_get_caller_context(sr, &ct);
+ rc = smb_vop_create(dir_snode->vp, name, attr, &vp,
+ flags, cr, &ct, NULL);
+
+ if (rc == 0) {
+ *ret_snode = smb_node_lookup(sr, op, cr, vp,
+ name, dir_snode, NULL, ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ }
+
+ }
+ }
+
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+}
+
+/*
+ * smb_fsop_mkdir
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ *
+ * *ret_snode is returned with a reference upon success. No reference is
+ * taken if an error is returned.
+ */
+int
+smb_fsop_mkdir(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ char *name,
+ smb_attr_t *attr,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr)
+{
+ struct open_param *op = &sr->arg.open;
+ caller_context_t ct;
+ char *longname;
+ vnode_t *vp;
+ int flags = 0;
+ smb_fssd_t fs_sd;
+ uint32_t secinfo;
+ uint32_t status;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(ret_snode);
+ *ret_snode = 0;
+
+ ASSERT(name);
+ if (*name == 0)
+ return (EINVAL);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ if (smb_maybe_mangled_name(name)) {
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ rc = smb_unmangle_name(sr, cr, dir_snode, name, longname,
+ MAXNAMELEN, NULL, NULL, 1);
+
+ kmem_free(longname, MAXNAMELEN);
+
+ /*
+ * If the name passed in by the client has an unmangled
+ * equivalent that is found in the specified directory,
+ * then the mkdir cannot succeed. Return EEXIST.
+ *
+ * Only if ENOENT is returned will a mkdir be attempted.
+ */
+
+ if (rc == 0)
+ rc = EEXIST;
+
+ if (rc != ENOENT)
+ return (rc);
+ }
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ if (op->sd_buf) {
+ /*
+ * SD sent by client in Windows format. Needs to be
+ * converted to FS format. No inheritance.
+ */
+ secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf);
+ smb_fsop_sdinit(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
+
+ status = smb_sd_tofs(op->sd_buf, &fs_sd);
+ if (status == NT_STATUS_SUCCESS) {
+ rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
+ name, attr, ret_snode, ret_attr, &fs_sd);
+ }
+ else
+ rc = EINVAL;
+ smb_fsop_sdterm(&fs_sd);
+ } else if (sr->tid_tree->t_acltype == ACE_T) {
+ /*
+ * No incoming SD and filesystem is ZFS
+ * Server applies Windows inheritance rules,
+ * see smb_fsop_sdinherit() comments as to why.
+ */
+ smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
+ rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd);
+ if (rc == 0) {
+ rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
+ name, attr, ret_snode, ret_attr, &fs_sd);
+ }
+
+ smb_fsop_sdterm(&fs_sd);
+
+ } else {
+ rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr,
+ &ct, NULL);
+
+ if (rc == 0) {
+ *ret_snode = smb_node_lookup(sr, op, cr, vp, name,
+ dir_snode, NULL, ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ }
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_remove
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ *
+ * od: This means that the name passed in is an on-disk name.
+ * A null smb_request might be passed to this function.
+ */
+
+int
+smb_fsop_remove(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ char *name,
+ int od)
+{
+ smb_node_t *fnode;
+ smb_attr_t file_attr;
+ caller_context_t ct;
+ char *longname;
+ char *fname;
+ char *sname;
+ int flags = 0;
+ int rc;
+
+ ASSERT(cr);
+ /*
+ * The state of the node could be SMB_NODE_STATE_DESTROYING if this
+ * function is called during the deletion of the node (because of
+ * DELETE_ON_CLOSE).
+ */
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ smb_get_caller_context(sr, &ct);
+
+ fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (smb_stream_parse_name(name, fname, sname)) {
+
+ ASSERT(od == 0);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ /*
+ * Look up the unnamed stream (i.e. fname).
+ * Unmangle processing will be done on fname
+ * as well as any link target.
+ */
+
+ rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr,
+ 0, 0);
+
+ if (rc != 0) {
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ /*
+ * XXX
+ * Need to find out what permission is required by NTFS
+ * to remove a stream.
+ */
+ rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr, &ct);
+
+ smb_node_release(fnode);
+ } else {
+ /*
+ * If the passed-in name is an on-disk name,
+ * then we need to do a case-sensitive remove.
+ * This is important if the on-disk name
+ * corresponds to a mangled name passed in by
+ * the client. We want to make sure to remove
+ * the exact file specified by the client,
+ * instead of letting the underlying file system
+ * do a remove on the "first match."
+ */
+
+ if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ rc = smb_vop_remove(dir_snode->vp, name, flags, cr, &ct);
+
+ if (rc == ENOENT) {
+ if (smb_maybe_mangled_name(name) == 0) {
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_unmangle_name(sr, cr, dir_snode, name,
+ longname, MAXNAMELEN, NULL, NULL, 1);
+
+ if (rc == 0) {
+ /*
+ * We passed "1" as the "od" parameter
+ * to smb_unmangle_name(), such that longname
+ * is the real (case-sensitive) on-disk name.
+ * We make sure we do a remove on this exact
+ * name, as the name was mangled and denotes
+ * a unique file.
+ */
+ flags &= ~SMB_IGNORE_CASE;
+ rc = smb_vop_remove(dir_snode->vp, longname,
+ flags, cr, &ct);
+ }
+
+ kmem_free(longname, MAXNAMELEN);
+ }
+ }
+
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+}
+
+/*
+ * smb_fsop_remove_streams
+ *
+ * This function removes a file's streams without removing the
+ * file itself.
+ *
+ * It is assumed that snode is not a link.
+ */
+int
+smb_fsop_remove_streams(struct smb_request *sr, cred_t *cr,
+ smb_node_t *fnode)
+{
+ struct fs_stream_info stream_info;
+ caller_context_t ct;
+ uint32_t cookie = 0;
+ int flags = 0;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(fnode);
+ ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, fnode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ for (;;) {
+ rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info,
+ NULL, NULL, flags, cr, &ct);
+
+ if ((rc != 0) || (cookie == SMB_EOF))
+ break;
+
+ (void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags,
+ cr, &ct);
+ }
+ return (rc);
+}
+
+/*
+ * smb_fsop_rmdir
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ *
+ * od: This means that the name passed in is an on-disk name.
+ */
+
+int
+smb_fsop_rmdir(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ char *name,
+ int od)
+{
+ caller_context_t ct;
+ int rc;
+ int flags = 0;
+ char *longname;
+
+ ASSERT(cr);
+ /*
+ * The state of the node could be SMB_NODE_STATE_DESTROYING if this
+ * function is called during the deletion of the node (because of
+ * DELETE_ON_CLOSE).
+ */
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ /*
+ * If the passed-in name is an on-disk name,
+ * then we need to do a case-sensitive rmdir.
+ * This is important if the on-disk name
+ * corresponds to a mangled name passed in by
+ * the client. We want to make sure to remove
+ * the exact directory specified by the client,
+ * instead of letting the underlying file system
+ * do a rmdir on the "first match."
+ */
+
+ if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr, &ct);
+
+ if (rc == ENOENT) {
+ if (smb_maybe_mangled_name(name) == 0)
+ return (rc);
+
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_unmangle_name(sr, cr, dir_snode,
+ name, longname, MAXNAMELEN, NULL,
+ NULL, 1);
+
+ if (rc == 0) {
+ /*
+ * We passed "1" as the "od" parameter
+ * to smb_unmangle_name(), such that longname
+ * is the real (case-sensitive) on-disk name.
+ * We make sure we do a rmdir on this exact
+ * name, as the name was mangled and denotes
+ * a unique directory.
+ */
+ flags &= ~SMB_IGNORE_CASE;
+ rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr,
+ &ct);
+ }
+
+ kmem_free(longname, MAXNAMELEN);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_getattr
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+int
+smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ smb_attr_t *attr)
+{
+ smb_node_t *unnamed_node;
+ vnode_t *unnamed_vp = NULL;
+ caller_context_t ct;
+ uint32_t status;
+ uint32_t access = 0;
+ int flags = 0;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, snode) == 0)
+ return (EACCES);
+
+ if (sr->fid_ofile) {
+ /* if uid and/or gid is requested */
+ if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
+ access |= READ_CONTROL;
+
+ /* if anything else is also requested */
+ if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
+ access |= FILE_READ_ATTRIBUTES;
+
+ status = smb_ofile_access(sr->fid_ofile, cr, access);
+ if (status != NT_STATUS_SUCCESS)
+ return (EACCES);
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS)
+ flags = ATTR_NOACLCHECK;
+ }
+
+ smb_get_caller_context(sr, &ct);
+
+ unnamed_node = SMB_IS_STREAM(snode);
+
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ unnamed_vp = unnamed_node->vp;
+ }
+
+ return (smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr, &ct));
+}
+
+/*
+ * smb_fsop_readdir
+ *
+ * All SMB functions should use this smb_fsop_readdir wrapper to ensure that
+ * the smb_vop_readdir is performed with the appropriate credentials.
+ * Please document any direct call to smb_vop_readdir to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+int
+smb_fsop_readdir(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ uint32_t *cookie,
+ char *name,
+ int *namelen,
+ ino64_t *fileid,
+ struct fs_stream_info *stream_info,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr)
+{
+ caller_context_t ct;
+ smb_node_t *ret_snodep;
+ smb_node_t *fnode;
+ smb_attr_t tmp_attr;
+ vnode_t *xattrdirvp;
+ vnode_t *fvp;
+ vnode_t *vp = NULL;
+ char *od_name;
+ int rc;
+ int flags = 0;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (*cookie == SMB_EOF) {
+ *namelen = 0;
+ return (0);
+ }
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (stream_info) {
+ rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name,
+ SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr, &ct);
+
+ if (rc != 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode,
+ NULL, ret_attr);
+
+ kmem_free(od_name, MAXNAMELEN);
+
+ if (fnode == NULL) {
+ VN_RELE(fvp);
+ return (ENOMEM);
+ }
+
+ /*
+ * XXX
+ * Need to find out what permission(s) NTFS requires for getting
+ * a file's streams list.
+ *
+ * Might have to use kcred.
+ */
+ rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp,
+ &xattrdirvp, flags, cr, &ct);
+
+ if ((rc != 0) || (*cookie == SMB_EOF)) {
+ smb_node_release(fnode);
+ return (rc);
+ }
+
+ ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
+ vp, stream_info->name, &tmp_attr);
+
+ smb_node_release(fnode);
+
+ if (ret_snodep == NULL) {
+ VN_RELE(xattrdirvp);
+ VN_RELE(vp);
+ return (ENOMEM);
+ }
+
+ stream_info->size = tmp_attr.sa_vattr.va_size;
+
+ if (ret_attr)
+ *ret_attr = tmp_attr;
+
+ if (ret_snode)
+ *ret_snode = ret_snodep;
+ else
+ smb_node_release(ret_snodep);
+
+ } else {
+ rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen,
+ fileid, &vp, od_name, flags, cr, &ct);
+
+ if (rc != 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ if (*namelen) {
+ ASSERT(vp);
+ if (ret_attr || ret_snode) {
+ ret_snodep = smb_node_lookup(sr, NULL, cr, vp,
+ od_name, dir_snode, NULL, &tmp_attr);
+
+ if (ret_snodep == NULL) {
+ kmem_free(od_name, MAXNAMELEN);
+ VN_RELE(vp);
+ return (ENOMEM);
+ }
+
+ if (ret_attr)
+ *ret_attr = tmp_attr;
+
+ if (ret_snode)
+ *ret_snode = ret_snodep;
+ else
+ smb_node_release(ret_snodep);
+ }
+ }
+
+ kmem_free(od_name, MAXNAMELEN);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_getdents
+ *
+ * All SMB functions should use this smb_vop_getdents wrapper to ensure that
+ * the smb_vop_getdents is performed with the appropriate credentials.
+ * Please document any direct call to smb_vop_getdents to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+/*ARGSUSED*/
+int
+smb_fsop_getdents(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ uint32_t *cookie,
+ uint64_t *verifierp,
+ int32_t *maxcnt,
+ char *args,
+ char *pattern)
+{
+ caller_context_t ct;
+ int flags = 0;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern,
+ flags, sr, cr, &ct));
+}
+
+/*
+ * smb_fsop_rename
+ *
+ * All SMB functions should use this smb_vop_rename wrapper to ensure that
+ * the smb_vop_rename is performed with the appropriate credentials.
+ * Please document any direct call to smb_vop_rename to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that references exist on from_dir_snode and to_dir_snode coming
+ * into this routine.
+ */
+int
+smb_fsop_rename(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *from_dir_snode,
+ char *from_name,
+ smb_node_t *to_dir_snode,
+ char *to_name)
+{
+ smb_node_t *from_snode;
+ caller_context_t ct;
+ smb_attr_t tmp_attr;
+ vnode_t *from_vp;
+ int flags = 0;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(from_dir_snode);
+ ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(to_dir_snode);
+ ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, from_dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_ROOT_FS(sr, to_dir_snode) == 0)
+ return (EACCES);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ /*
+ * Note: There is no need to check SMB_TREE_CASE_INSENSITIVE(sr)
+ * here.
+ *
+ * A case-sensitive rename is always done in this routine
+ * because we are using the on-disk name from an earlier lookup.
+ * If a mangled name was passed in by the caller (denoting a
+ * deterministic lookup), then the exact file must be renamed
+ * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
+ * else the underlying file system might return a "first-match"
+ * on this on-disk name, possibly resulting in the wrong file).
+ */
+
+ /*
+ * XXX: Lock required through smb_node_release() below?
+ */
+
+ smb_get_caller_context(sr, &ct);
+
+ rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0,
+ NULL, cr, &ct);
+
+ if (rc != 0)
+ return (rc);
+
+ rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp,
+ to_name, flags, cr, &ct);
+
+ if (rc == 0) {
+ from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
+ from_dir_snode, NULL, &tmp_attr);
+
+ if (from_snode == NULL) {
+ VN_RELE(from_vp);
+ return (ENOMEM);
+ }
+
+ (void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode,
+ to_name);
+
+ smb_node_release(from_snode);
+ } else {
+ VN_RELE(from_vp);
+ }
+
+ /* XXX: unlock */
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_setattr
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ * A null smb_request might be passed to this function.
+ */
+int
+smb_fsop_setattr(
+ smb_request_t *sr,
+ cred_t *cr,
+ smb_node_t *snode,
+ smb_attr_t *set_attr,
+ smb_attr_t *ret_attr)
+{
+ smb_node_t *unnamed_node;
+ vnode_t *unnamed_vp = NULL;
+ caller_context_t ct;
+ uint32_t status;
+ uint32_t access = 0;
+ int rc = 0;
+ int flags = 0;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ /* sr could be NULL in some cases */
+ if (sr && sr->fid_ofile) {
+ /* if uid and/or gid is requested */
+ if (set_attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
+ access |= WRITE_OWNER;
+
+ /* if anything else is also requested */
+ if (set_attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
+ access |= FILE_WRITE_ATTRIBUTES;
+
+ status = smb_ofile_access(sr->fid_ofile, cr, access);
+ if (status != NT_STATUS_SUCCESS)
+ return (EACCES);
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS)
+ flags = ATTR_NOACLCHECK;
+ }
+
+ smb_get_caller_context(sr, &ct);
+
+ unnamed_node = SMB_IS_STREAM(snode);
+
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ unnamed_vp = unnamed_node->vp;
+ }
+
+ rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr, &ct);
+
+ if ((rc == 0) && ret_attr) {
+ /*
+ * This is an operation on behalf of CIFS service (to update
+ * smb node's attr) not on behalf of the user so it's done
+ * using kcred and the return value is intentionally ignored.
+ */
+ ret_attr->sa_mask = SMB_AT_ALL;
+ (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
+ kcred, &ct);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_read
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+int
+smb_fsop_read(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *snode,
+ uio_t *uio,
+ smb_attr_t *ret_attr)
+{
+ smb_node_t *unnamed_node;
+ vnode_t *unnamed_vp = NULL;
+ caller_context_t ct;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(sr);
+ ASSERT(sr->fid_ofile);
+
+ rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE);
+ if (rc != NT_STATUS_SUCCESS)
+ return (EACCES);
+ }
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ unnamed_vp = unnamed_node->vp;
+ /*
+ * Streams permission are checked against the unnamed stream,
+ * but in FS level they have their own permissions. To avoid
+ * rejection by FS due to lack of permission on the actual
+ * extended attr kcred is passed for streams.
+ */
+ cr = kcred;
+ }
+
+ smb_get_caller_context(sr, &ct);
+ rc = smb_vop_read(snode->vp, uio, cr, &ct);
+
+ if (rc == 0) {
+ /*
+ * This is an operation on behalf of CIFS service (to update
+ * smb node's attr) not on behalf of the user so it's done
+ * using kcred and the return value is intentionally ignored.
+ */
+ ret_attr->sa_mask = SMB_AT_ALL;
+ (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
+ kcred, &ct);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_write
+ *
+ * This is a wrapper function used for smb_write and smb_write_raw operations.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+int
+smb_fsop_write(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *snode,
+ uio_t *uio,
+ uint32_t *lcount,
+ smb_attr_t *ret_attr,
+ uint32_t *flag)
+{
+ smb_node_t *unnamed_node;
+ vnode_t *unnamed_vp = NULL;
+ caller_context_t ct;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ ASSERT(sr->fid_ofile);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+ /*
+ * XXX what if the file has been opened only with
+ * FILE_APPEND_DATA?
+ */
+ rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS)
+ return (EACCES);
+
+ smb_get_caller_context(sr, &ct);
+
+ unnamed_node = SMB_IS_STREAM(snode);
+
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ unnamed_vp = unnamed_node->vp;
+ /*
+ * Streams permission are checked against the unnamed stream,
+ * but in FS level they have their own permissions. To avoid
+ * rejection by FS due to lack of permission on the actual
+ * extended attr kcred is passed for streams.
+ */
+ cr = kcred;
+ }
+
+ rc = smb_vop_write(snode->vp, uio, flag, lcount, cr, &ct);
+
+ if (rc == 0) {
+ /*
+ * This is an operation on behalf of CIFS service (to update
+ * smb node's attr) not on behalf of the user so it's done
+ * using kcred and the return value is intentionally ignored.
+ */
+ ret_attr->sa_mask = SMB_AT_ALL;
+ (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
+ kcred, &ct);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_statfs
+ *
+ * This is a wrapper function used for stat operations.
+ */
+int
+smb_fsop_statfs(
+ cred_t *cr,
+ smb_node_t *snode,
+ struct statvfs64 *statp)
+{
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ return (smb_vop_statfs(snode->vp, statp, cr));
+}
+
+/*
+ * smb_fsop_access
+ */
+int
+smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t faccess)
+{
+ int access = 0;
+ int error;
+ vnode_t *dir_vp;
+ boolean_t acl_check = B_TRUE;
+ smb_node_t *unnamed_node;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (faccess == 0)
+ return (NT_STATUS_SUCCESS);
+
+ if (SMB_TREE_IS_READ_ONLY(sr)) {
+ if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
+ FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES|
+ DELETE|WRITE_DAC|WRITE_OWNER)) {
+ return (NT_STATUS_ACCESS_DENIED);
+ }
+ }
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ /*
+ * Streams authorization should be performed against the
+ * unnamed stream.
+ */
+ snode = unnamed_node;
+ }
+
+ if (faccess & ACCESS_SYSTEM_SECURITY) {
+ /*
+ * This permission is required for reading/writing SACL and
+ * it's not part of DACL. It's only granted via proper
+ * privileges.
+ */
+ if ((sr->uid_user->u_privileges &
+ (SMB_USER_PRIV_BACKUP |
+ SMB_USER_PRIV_RESTORE |
+ SMB_USER_PRIV_SECURITY)) == 0)
+ return (NT_STATUS_PRIVILEGE_NOT_HELD);
+
+ faccess &= ~ACCESS_SYSTEM_SECURITY;
+ }
+
+ /* Links don't have ACL */
+ if (((sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) == 0) ||
+ (snode->attr.sa_vattr.va_type == VLNK))
+ acl_check = B_FALSE;
+
+ if (acl_check) {
+ dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
+ error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
+ cr);
+ } else {
+ /*
+ * FS doesn't understand 32-bit mask, need to map
+ */
+ if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
+ access |= VWRITE;
+
+ if (faccess & FILE_READ_DATA)
+ access |= VREAD;
+
+ if (faccess & FILE_EXECUTE)
+ access |= VEXEC;
+
+ error = smb_vop_access(snode->vp, access, 0, NULL, cr);
+ }
+
+ return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_fsop_lookup_name()
+ *
+ * Sanity checks on dir_snode done in smb_fsop_lookup().
+ *
+ * Note: This function is called only from the open path.
+ * It will check if the file is a stream.
+ * It will also return an error if the looked-up file is in
+ * a child mount.
+ */
+
+int
+smb_fsop_lookup_name(
+ struct smb_request *sr,
+ cred_t *cr,
+ int flags,
+ smb_node_t *root_node,
+ smb_node_t *dir_snode,
+ char *name,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr)
+{
+ smb_node_t *fnode;
+ smb_attr_t file_attr;
+ caller_context_t ct;
+ vnode_t *xattrdirvp;
+ vnode_t *vp;
+ char *od_name;
+ char *fname;
+ char *sname;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ /*
+ * The following check is required for streams processing, below
+ */
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags |= SMB_IGNORE_CASE;
+
+ fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (smb_stream_parse_name(name, fname, sname)) {
+ /*
+ * Look up the unnamed stream (i.e. fname).
+ * Unmangle processing will be done on fname
+ * as well as any link target.
+ */
+ rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname,
+ &fnode, &file_attr, NULL, NULL);
+
+ if (rc != 0) {
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ /*
+ * od_name is the on-disk name of the stream, except
+ * without the prepended stream prefix (SMB_STREAM_PREFIX)
+ */
+
+ /*
+ * XXX
+ * What permissions NTFS requires for stream lookup if any?
+ */
+ rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name,
+ &xattrdirvp, flags, root_node->vp, cr, &ct);
+
+ if (rc != 0) {
+ smb_node_release(fnode);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
+ vp, od_name, ret_attr);
+
+ kmem_free(od_name, MAXNAMELEN);
+ smb_node_release(fnode);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(xattrdirvp);
+ VN_RELE(vp);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (ENOMEM);
+ }
+ } else {
+ rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name,
+ ret_snode, ret_attr, NULL, NULL);
+ }
+
+ if (rc == 0) {
+ ASSERT(ret_snode);
+ if (SMB_TREE_ROOT_FS(sr, *ret_snode) == 0) {
+ smb_node_release(*ret_snode);
+ *ret_snode = NULL;
+ rc = EACCES;
+ }
+ }
+
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_lookup
+ *
+ * All SMB functions should use this smb_vop_lookup wrapper to ensure that
+ * the smb_vop_lookup is performed with the appropriate credentials and using
+ * case insensitive compares. Please document any direct call to smb_vop_lookup
+ * to explain the reason for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on dir_snode coming into this routine
+ * (and that it is safe from deallocation).
+ *
+ * Same with the root_node.
+ *
+ * *ret_snode is returned with a reference upon success. No reference is
+ * taken if an error is returned.
+ *
+ * Note: The returned ret_snode may be in a child mount. This is ok for
+ * readdir and getdents.
+ *
+ * Other smb_fsop_* routines will call SMB_TREE_ROOT_FS() to prevent
+ * operations on files not in the parent mount.
+ */
+int
+smb_fsop_lookup(
+ struct smb_request *sr,
+ cred_t *cr,
+ int flags,
+ smb_node_t *root_node,
+ smb_node_t *dir_snode,
+ char *name,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr,
+ char *ret_shortname, /* Must be at least MANGLE_NAMELEN chars */
+ char *ret_name83) /* Must be at least MANGLE_NAMELEN chars */
+{
+ smb_node_t *lnk_target_node;
+ smb_node_t *lnk_dnode;
+ caller_context_t ct;
+ char *longname;
+ char *od_name;
+ vnode_t *vp;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (name == NULL)
+ return (EINVAL);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags |= SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags,
+ root_node ? root_node->vp : NULL, cr, &ct);
+
+ if (rc != 0) {
+ if (smb_maybe_mangled_name(name) == 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_unmangle_name(sr, cr, dir_snode, name, longname,
+ MAXNAMELEN, ret_shortname, ret_name83, 1);
+
+ if (rc != 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ kmem_free(longname, MAXNAMELEN);
+ return (rc);
+ }
+
+ /*
+ * We passed "1" as the "od" parameter
+ * to smb_unmangle_name(), such that longname
+ * is the real (case-sensitive) on-disk name.
+ * We make sure we do a lookup on this exact
+ * name, as the name was mangled and denotes
+ * a unique file.
+ */
+
+ if (flags & SMB_IGNORE_CASE)
+ flags &= ~SMB_IGNORE_CASE;
+
+ rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name,
+ flags, root_node ? root_node->vp : NULL, cr, &ct);
+
+ kmem_free(longname, MAXNAMELEN);
+
+ if (rc != 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+ }
+
+ if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) {
+
+ rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode,
+ &lnk_dnode, &lnk_target_node, cr);
+
+ if (rc != 0) {
+ /*
+ * The link is assumed to be for the last component
+ * of a path. Hence any ENOTDIR error will be returned
+ * as ENOENT.
+ */
+ if (rc == ENOTDIR)
+ rc = ENOENT;
+
+ VN_RELE(vp);
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ /*
+ * Release the original VLNK vnode
+ */
+
+ VN_RELE(vp);
+ vp = lnk_target_node->vp;
+
+ rc = smb_vop_traverse_check(&vp);
+
+ if (rc != 0) {
+ smb_node_release(lnk_dnode);
+ smb_node_release(lnk_target_node);
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ /*
+ * smb_vop_traverse_check() may have returned a different vnode
+ */
+
+ if (lnk_target_node->vp == vp) {
+ *ret_snode = lnk_target_node;
+ *ret_attr = (*ret_snode)->attr;
+ } else {
+ *ret_snode = smb_node_lookup(sr, NULL, cr, vp,
+ lnk_target_node->od_name, lnk_dnode, NULL,
+ ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ smb_node_release(lnk_target_node);
+ }
+
+ smb_node_release(lnk_dnode);
+
+ } else {
+
+ rc = smb_vop_traverse_check(&vp);
+ if (rc) {
+ VN_RELE(vp);
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
+ dir_snode, NULL, ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ }
+
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+}
+
+/*
+ * smb_fsop_stream_readdir()
+ *
+ * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in)
+ *
+ * This routine will return only NTFS streams. If an NTFS stream is not
+ * found at the offset specified, the directory will be read until an NTFS
+ * stream is found or until EOF.
+ *
+ * Note: Sanity checks done in caller
+ * (smb_fsop_readdir(), smb_fsop_remove_streams())
+ */
+
+int
+smb_fsop_stream_readdir(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
+ uint32_t *cookiep, struct fs_stream_info *stream_info,
+ smb_node_t **ret_snode, smb_attr_t *ret_attr)
+{
+ smb_node_t *ret_snodep = NULL;
+ caller_context_t ct;
+ smb_attr_t tmp_attr;
+ vnode_t *xattrdirvp;
+ vnode_t *vp;
+ int rc = 0;
+ int flags = 0;
+
+ /*
+ * XXX NTFS permission requirements if any?
+ */
+ ASSERT(cr);
+ ASSERT(fnode);
+ ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp,
+ &xattrdirvp, flags, cr, &ct);
+
+ if ((rc != 0) || *cookiep == SMB_EOF)
+ return (rc);
+
+ ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp,
+ stream_info->name, &tmp_attr);
+
+ if (ret_snodep == NULL) {
+ VN_RELE(xattrdirvp);
+ VN_RELE(vp);
+ return (ENOMEM);
+ }
+
+ stream_info->size = tmp_attr.sa_vattr.va_size;
+
+ if (ret_attr)
+ *ret_attr = tmp_attr;
+
+ if (ret_snode)
+ *ret_snode = ret_snodep;
+ else
+ smb_node_release(ret_snodep);
+
+ return (rc);
+}
+
+int /*ARGSUSED*/
+smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
+{
+ caller_context_t ct;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ smb_get_caller_context(sr, &ct);
+
+ return (smb_vop_commit(snode->vp, cr, &ct));
+}
+
+/*
+ * smb_fsop_sdinit
+ *
+ * Initializes the given FS SD structure.
+ */
+void
+smb_fsop_sdinit(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
+{
+ bzero(fs_sd, sizeof (smb_fssd_t));
+ fs_sd->sd_secinfo = secinfo;
+ fs_sd->sd_flags = flags;
+}
+
+/*
+ * smb_fsop_sdterm
+ *
+ * Frees allocated memory for acl fields.
+ */
+void
+smb_fsop_sdterm(smb_fssd_t *fs_sd)
+{
+ ASSERT(fs_sd);
+
+ smb_fsop_aclfree(fs_sd->sd_zdacl);
+ smb_fsop_aclfree(fs_sd->sd_zsacl);
+ bzero(fs_sd, sizeof (smb_fssd_t));
+}
+
+/*
+ * smb_fsop_aclread
+ *
+ * Retrieve filesystem ACL. Depends on requested ACLs in
+ * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
+ * fs_sd. Note that requesting a DACL/SACL doesn't mean that
+ * the corresponding field in fs_sd should be non-NULL upon
+ * return, since the target ACL might not contain that type of
+ * entries.
+ *
+ * Returned ACL is always in ACE_T (aka ZFS) format.
+ * If successful the allocated memory for the ACL should be freed
+ * using smb_fsop_aclfree() or smb_fsop_sdterm()
+ */
+int
+smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd)
+{
+ int error = 0;
+ int flags = 0;
+ int access = 0;
+ acl_t *acl;
+ caller_context_t ct;
+ smb_node_t *unnamed_node;
+
+ ASSERT(cr);
+
+ if (sr->fid_ofile) {
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
+ access = READ_CONTROL;
+
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
+ access |= ACCESS_SYSTEM_SECURITY;
+
+ error = smb_ofile_access(sr->fid_ofile, cr, access);
+ if (error != NT_STATUS_SUCCESS) {
+ return (EACCES);
+ }
+ }
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ /*
+ * Streams don't have ACL, any read ACL attempt on a stream
+ * should be performed on the unnamed stream.
+ */
+ snode = unnamed_node;
+ }
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS)
+ flags = ATTR_NOACLCHECK;
+
+ smb_get_caller_context(sr, &ct);
+ error = smb_vop_acl_read(snode->vp, &acl, flags,
+ sr->tid_tree->t_acltype, cr, &ct);
+ if (error != 0) {
+ return (error);
+ }
+
+ error = acl_translate(acl, _ACL_ACE_ENABLED,
+ (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid);
+
+ if (error == 0) {
+ smb_fsop_aclsplit(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
+ fs_sd->sd_secinfo);
+ }
+
+ acl_free(acl);
+ return (error);
+}
+
+/*
+ * smb_fsop_aclwrite
+ *
+ * Stores the filesystem ACL provided in fs_sd->sd_acl.
+ */
+int
+smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd)
+{
+ int target_flavor;
+ int error = 0;
+ int flags = 0;
+ int access = 0;
+ caller_context_t ct;
+ acl_t *acl, *dacl, *sacl;
+ smb_node_t *unnamed_node;
+
+ ASSERT(cr);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ if (sr->fid_ofile) {
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
+ access = WRITE_DAC;
+
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
+ access |= ACCESS_SYSTEM_SECURITY;
+
+ error = smb_ofile_access(sr->fid_ofile, cr, access);
+ if (error != NT_STATUS_SUCCESS)
+ return (EACCES);
+ }
+
+ switch (sr->tid_tree->t_acltype) {
+ case ACLENT_T:
+ target_flavor = _ACL_ACLENT_ENABLED;
+ break;
+
+ case ACE_T:
+ target_flavor = _ACL_ACE_ENABLED;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ /*
+ * Streams don't have ACL, any write ACL attempt on a stream
+ * should be performed on the unnamed stream.
+ */
+ snode = unnamed_node;
+ }
+
+ dacl = fs_sd->sd_zdacl;
+ sacl = fs_sd->sd_zsacl;
+
+ ASSERT(dacl || sacl);
+ if ((dacl == NULL) && (sacl == NULL))
+ return (EINVAL);
+
+ if (dacl && sacl)
+ acl = smb_fsop_aclmerge(dacl, sacl);
+ else if (dacl)
+ acl = dacl;
+ else
+ acl = sacl;
+
+ error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR),
+ fs_sd->sd_uid, fs_sd->sd_gid);
+ if (error == 0) {
+ smb_get_caller_context(sr, &ct);
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS)
+ flags = ATTR_NOACLCHECK;
+
+ error = smb_vop_acl_write(snode->vp, acl, flags, cr, &ct);
+ }
+
+ if (dacl && sacl)
+ acl_free(acl);
+
+ return (error);
+}
+
+acl_t *
+smb_fsop_aclalloc(int acenum, int flags)
+{
+ acl_t *acl;
+
+ acl = acl_alloc(ACE_T);
+ acl->acl_cnt = acenum;
+ acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
+ acl->acl_flags = flags;
+ return (acl);
+}
+
+void
+smb_fsop_aclfree(acl_t *acl)
+{
+ if (acl)
+ acl_free(acl);
+}
+
+/*
+ * smb_fsop_aclmerge
+ *
+ * smb_fsop_aclread/write routines which interact with filesystem
+ * work with single ACL. This routine merges given DACL and SACL
+ * which might have been created during CIFS to FS conversion into
+ * one single ACL.
+ */
+static acl_t *
+smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl)
+{
+ acl_t *acl;
+ int dacl_size;
+
+ ASSERT(dacl);
+ ASSERT(sacl);
+
+ acl = smb_fsop_aclalloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
+ dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
+ bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
+ bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
+ sacl->acl_cnt * sacl->acl_entry_size);
+
+ return (acl);
+}
+
+/*
+ * smb_fsop_aclsplit
+ *
+ * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
+ * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
+ * NULL even if they're specified in 'which_acl', which means the target
+ * doesn't have any access and/or audit ACEs.
+ */
+static void
+smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
+{
+ ace_t *zace;
+ ace_t *access_ace;
+ ace_t *audit_ace;
+ int naccess, naudit;
+ int get_dacl, get_sacl;
+ int i;
+
+ *dacl = *sacl = NULL;
+ naccess = naudit = 0;
+ get_dacl = (which_acl & SMB_DACL_SECINFO);
+ get_sacl = (which_acl & SMB_SACL_SECINFO);
+
+ for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
+ if (get_dacl && smb_ace_is_access(zace->a_type))
+ naccess++;
+ else if (get_sacl && smb_ace_is_audit(zace->a_type))
+ naudit++;
+ }
+
+ if (naccess) {
+ *dacl = smb_fsop_aclalloc(naccess, zacl->acl_flags);
+ access_ace = (*dacl)->acl_aclp;
+ }
+
+ if (naudit) {
+ *sacl = smb_fsop_aclalloc(naudit, zacl->acl_flags);
+ audit_ace = (*sacl)->acl_aclp;
+ }
+
+ for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
+ if (get_dacl && smb_ace_is_access(zace->a_type)) {
+ *access_ace = *zace;
+ access_ace++;
+ } else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
+ *audit_ace = *zace;
+ audit_ace++;
+ }
+ }
+}
+
+acl_type_t
+smb_fsop_acltype(smb_node_t *snode)
+{
+ return (smb_vop_acl_type(snode->vp));
+}
+
+/*
+ * smb_fsop_sdread
+ *
+ * Read the requested security descriptor items from filesystem.
+ * The items are specified in fs_sd->sd_secinfo.
+ */
+int
+smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd)
+{
+ int error = 0;
+ int getowner = 0;
+ cred_t *ga_cred;
+ smb_attr_t attr;
+
+ ASSERT(cr);
+ ASSERT(fs_sd);
+
+ /*
+ * File's uid/gid is fetched in two cases:
+ *
+ * 1. it's explicitly requested
+ *
+ * 2. target ACL is ACE_T (ZFS ACL). They're needed for
+ * owner@/group@ entries. In this case kcred should be used
+ * because uid/gid are fetched on behalf of smb server.
+ */
+ if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) {
+ getowner = 1;
+ ga_cred = cr;
+ } else if (sr->tid_tree->t_acltype == ACE_T) {
+ getowner = 1;
+ ga_cred = kcred;
+ }
+
+ if (getowner) {
+ /*
+ * Windows require READ_CONTROL to read owner/group SID since
+ * they're part of Security Descriptor.
+ * ZFS only requires read_attribute. Need to have a explicit
+ * access check here.
+ */
+ if (sr->fid_ofile == NULL) {
+ error = smb_fsop_access(sr, ga_cred, snode,
+ READ_CONTROL);
+ if (error)
+ return (error);
+ }
+
+ attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
+ error = smb_fsop_getattr(sr, ga_cred, snode, &attr);
+ if (error == 0) {
+ fs_sd->sd_uid = attr.sa_vattr.va_uid;
+ fs_sd->sd_gid = attr.sa_vattr.va_gid;
+ } else {
+ return (error);
+ }
+ }
+
+ if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
+ error = smb_fsop_aclread(sr, cr, snode, fs_sd);
+ }
+
+ return (error);
+}
+
+/*
+ * smb_fsop_sdmerge
+ *
+ * From SMB point of view DACL and SACL are two separate list
+ * which can be manipulated independently without one affecting
+ * the other, but entries for both DACL and SACL will end up
+ * in the same ACL if target filesystem supports ACE_T ACLs.
+ *
+ * So, if either DACL or SACL is present in the client set request
+ * the entries corresponding to the non-present ACL shouldn't
+ * be touched in the FS ACL.
+ *
+ * fs_sd parameter contains DACL and SACL specified by SMB
+ * client to be set on a file/directory. The client could
+ * specify both or one of these ACLs (if none is specified
+ * we don't get this far). When both DACL and SACL are given
+ * by client the existing ACL should be overwritten. If only
+ * one of them is specified the entries corresponding to the other
+ * ACL should not be touched. For example, if only DACL
+ * is specified in input fs_sd, the function reads audit entries
+ * of the existing ACL of the file and point fs_sd->sd_zsdacl
+ * pointer to the fetched SACL, this way when smb_fsop_sdwrite()
+ * function is called the passed fs_sd would point to the specified
+ * DACL by client and fetched SACL from filesystem, so the file
+ * will end up with correct ACL.
+ */
+static int
+smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
+{
+ smb_fssd_t cur_sd;
+ int error = 0;
+
+ if (sr->tid_tree->t_acltype != ACE_T)
+ /* Don't bother if target FS doesn't support ACE_T */
+ return (0);
+
+ if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) {
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+ /*
+ * Don't overwrite existing audit entries
+ */
+ smb_fsop_sdinit(&cur_sd, SMB_SACL_SECINFO,
+ fs_sd->sd_flags);
+
+ error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
+ if (error == 0) {
+ ASSERT(fs_sd->sd_zsacl == NULL);
+ fs_sd->sd_zsacl = cur_sd.sd_zsacl;
+ if (fs_sd->sd_zsacl && fs_sd->sd_zdacl)
+ fs_sd->sd_zsacl->acl_flags =
+ fs_sd->sd_zdacl->acl_flags;
+ }
+ } else {
+ /*
+ * Don't overwrite existing access entries
+ */
+ smb_fsop_sdinit(&cur_sd, SMB_DACL_SECINFO,
+ fs_sd->sd_flags);
+
+ error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
+ if (error == 0) {
+ ASSERT(fs_sd->sd_zdacl == NULL);
+ fs_sd->sd_zdacl = cur_sd.sd_zdacl;
+ if (fs_sd->sd_zdacl && fs_sd->sd_zsacl)
+ fs_sd->sd_zdacl->acl_flags =
+ fs_sd->sd_zsacl->acl_flags;
+ }
+ }
+
+ if (error)
+ smb_fsop_sdterm(&cur_sd);
+ }
+
+ return (error);
+}
+
+/*
+ * smb_fsop_sdwrite
+ *
+ * Stores the given uid, gid and acl in filesystem.
+ * Provided items in fs_sd are specified by fs_sd->sd_secinfo.
+ *
+ * A SMB security descriptor could contain owner, primary group,
+ * DACL and SACL. Setting an SD should be atomic but here it has to
+ * be done via two separate FS operations: VOP_SETATTR and
+ * VOP_SETSECATTR. Therefore, this function has to simulate the
+ * atomicity as well as it can.
+ */
+int
+smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd, int overwrite)
+{
+ int error = 0;
+ int access = 0;
+ smb_attr_t set_attr;
+ smb_attr_t orig_attr;
+
+ ASSERT(cr);
+ ASSERT(fs_sd);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ bzero(&set_attr, sizeof (smb_attr_t));
+
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
+ set_attr.sa_mask |= SMB_AT_UID;
+ }
+
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
+ set_attr.sa_mask |= SMB_AT_GID;
+ }
+
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
+ access |= WRITE_DAC;
+
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
+ access |= ACCESS_SYSTEM_SECURITY;
+
+ if (sr->fid_ofile)
+ error = smb_ofile_access(sr->fid_ofile, cr, access);
+ else
+ error = smb_fsop_access(sr, cr, snode, access);
+
+ if (error)
+ return (EACCES);
+
+ if (set_attr.sa_mask) {
+ /*
+ * Get the current uid, gid so if smb_fsop_aclwrite fails
+ * we can revert uid, gid changes.
+ *
+ * We use root cred here so the operation doesn't fail
+ * due to lack of permission for the user to read the attrs
+ */
+
+ orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
+ error = smb_fsop_getattr(sr, kcred, snode, &orig_attr);
+ if (error == 0)
+ error = smb_fsop_setattr(sr, cr, snode, &set_attr,
+ NULL);
+
+ if (error)
+ return (error);
+ }
+
+ if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
+ if (overwrite == 0) {
+ error = smb_fsop_sdmerge(sr, snode, fs_sd);
+ if (error)
+ return (error);
+ }
+
+ error = smb_fsop_aclwrite(sr, cr, snode, fs_sd);
+ if (error) {
+ /*
+ * Revert uid/gid changes if required.
+ */
+ if (set_attr.sa_mask) {
+ orig_attr.sa_mask = set_attr.sa_mask;
+ (void) smb_fsop_setattr(sr, kcred, snode,
+ &orig_attr, NULL);
+ }
+ }
+ }
+
+ return (error);
+}
+
+/*ARGSUSED*/
+void
+smb_get_caller_context(smb_request_t *sr, caller_context_t *ct)
+{
+ ct->cc_caller_id = smb_caller_id;
+ ct->cc_pid = 0; /* TBD */
+ ct->cc_sysid = 0; /* TBD */
+}
+
+/*
+ * smb_fsop_sdinherit
+ *
+ * Inherit the security descriptor from the parent container.
+ * This function is called after FS has created the file/folder
+ * so if this doesn't do anything it means FS inheritance is
+ * in place.
+ *
+ * Do inheritance for ZFS internally.
+ *
+ * If we want to let ZFS does the inheritance the
+ * following setting should be true:
+ *
+ * - aclinherit = passthrough
+ * - aclmode = passthrough
+ * - smbd umask = 0777
+ *
+ * This will result in right effective permissions but
+ * ZFS will always add 6 ACEs for owner, owning group
+ * and others to be POSIX compliant. This is not what
+ * Windows clients/users expect, so we decided that CIFS
+ * implements Windows rules and overwrite whatever ZFS
+ * comes up with. This way we also don't have to care
+ * about ZFS aclinherit and aclmode settings.
+ */
+static int
+smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
+{
+ int is_dir;
+ acl_t *dacl;
+ acl_t *sacl;
+ ksid_t *owner_sid;
+ int error;
+
+ ASSERT(fs_sd);
+
+ if (sr->tid_tree->t_acltype != ACE_T) {
+ /*
+ * No forced inheritance for non-ZFS filesystems.
+ */
+ fs_sd->sd_secinfo = 0;
+ return (0);
+ }
+
+
+ /* Fetch parent directory's ACL */
+ error = smb_fsop_sdread(sr, kcred, dnode, fs_sd);
+ if (error) {
+ return (error);
+ }
+
+ is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
+ owner_sid = crgetsid(sr->user_cr, KSID_OWNER);
+ ASSERT(owner_sid);
+ dacl = smb_acl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO,
+ owner_sid->ks_id);
+ sacl = smb_acl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO,
+ (uid_t)-1);
+
+ smb_fsop_aclfree(fs_sd->sd_zdacl);
+ smb_fsop_aclfree(fs_sd->sd_zsacl);
+
+ fs_sd->sd_zdacl = dacl;
+ fs_sd->sd_zsacl = sacl;
+
+ return (0);
+}
+
+/*
+ * smb_fsop_eaccess
+ *
+ * Returns the effective permission of the given credential for the
+ * specified object.
+ *
+ * This is just a workaround. We need VFS/FS support for this.
+ */
+void
+smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t *eaccess)
+{
+ int access = 0;
+ vnode_t *dir_vp;
+ smb_node_t *unnamed_node;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ /*
+ * Streams authorization should be performed against the
+ * unnamed stream.
+ */
+ snode = unnamed_node;
+ }
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) {
+ dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
+ smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
+ cr);
+ return;
+ }
+
+ /*
+ * FS doesn't understand 32-bit mask
+ */
+ smb_vop_eaccess(snode->vp, &access, 0, NULL, cr);
+
+ *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES;
+
+ if (access & VREAD)
+ *eaccess |= FILE_READ_DATA;
+
+ if (access & VEXEC)
+ *eaccess |= FILE_EXECUTE;
+
+ if (access & VWRITE)
+ *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
+ FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_init.c b/usr/src/uts/common/fs/smbsrv/smb_init.c
new file mode 100644
index 0000000000..1d3d8f39cb
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c
@@ -0,0 +1,796 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/strsubr.h>
+#include <sys/socketvar.h>
+#include <sys/modctl.h>
+#include <sys/cred.h>
+#include <sys/ioccom.h>
+#include <sys/priv.h>
+#include <sys/policy.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_ioctl.h>
+#include <smbsrv/smb_kproto.h>
+/*
+ * DDI entry points.
+ */
+static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t);
+static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t);
+static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int smb_drv_open(dev_t *, int, int, cred_t *);
+static int smb_drv_close(dev_t, int, int, cred_t *);
+static int smb_drv_busy(void);
+static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+/*
+ * module linkage info for the kernel
+ */
+static struct cb_ops cbops = {
+ smb_drv_open, /* cb_open */
+ smb_drv_close, /* cb_close */
+ nodev, /* cb_strategy */
+ nodev, /* cb_print */
+ nodev, /* cb_dump */
+ nodev, /* cb_read */
+ nodev, /* cb_write */
+ smb_drv_ioctl, /* cb_ioctl */
+ nodev, /* cb_devmap */
+ nodev, /* cb_mmap */
+ nodev, /* cb_segmap */
+ nochpoll, /* cb_chpoll */
+ ddi_prop_op, /* cb_prop_op */
+ NULL, /* cb_streamtab */
+ D_MP, /* cb_flag */
+ CB_REV, /* cb_rev */
+ nodev, /* cb_aread */
+ nodev, /* cb_awrite */
+};
+
+static struct dev_ops devops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ smb_drv_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify */
+ nulldev, /* devo_probe */
+ smb_drv_attach, /* devo_attach */
+ smb_drv_detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &cbops, /* devo_cb_ops */
+ NULL, /* devo_bus_ops */
+ NULL, /* devo_power */
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops, /* drv_modops */
+ "CIFS Server Protocol %I%", /* drv_linkinfo */
+ &devops,
+};
+
+static struct modlinkage modlinkage = {
+
+ MODREV_1, /* revision of the module, must be: MODREV_1 */
+ &modldrv, /* ptr to linkage structures */
+ NULL,
+};
+
+static int smb_info_init(struct smb_info *si);
+static void smb_info_fini(struct smb_info *si);
+
+extern int smb_fsop_start(void);
+extern void smb_fsop_stop(void);
+
+extern int nt_mapk_start(void);
+extern void nt_mapk_stop(void);
+
+
+extern int smb_get_kconfig(smb_kmod_cfg_t *cfg);
+
+extern void smb_notify_change_daemon(smb_thread_t *thread, void *arg);
+extern void smb_nbt_daemon(smb_thread_t *thread, void *arg);
+extern void smb_tcp_daemon(smb_thread_t *thread, void *arg);
+extern void smb_timers(smb_thread_t *thread, void *arg);
+extern void smb_session_worker(void *arg);
+
+extern int smb_maxbufsize;
+
+extern time_t smb_oplock_timeout;
+
+/* Debug logging level: 0=Disabled, 1=Quiet, 2=Verbose */
+int smbsrv_debug_level;
+
+struct smb_info smb_info;
+
+static dev_info_t *smb_drv_dip = NULL;
+static kmutex_t smb_drv_opencount_lock;
+static int smb_drv_opencount = 0;
+
+/*
+ * Kstat smb_info statistics.
+ */
+static struct smbinfo_stats {
+ kstat_named_t state;
+ kstat_named_t open_files;
+ kstat_named_t open_trees;
+ kstat_named_t open_users;
+} smbinfo_stats = {
+ { "state", KSTAT_DATA_UINT32 },
+ { "open_files", KSTAT_DATA_UINT32 },
+ { "connections", KSTAT_DATA_UINT32 },
+ { "sessions", KSTAT_DATA_UINT32 }
+};
+
+static int smb_kstat_init(void);
+static void smb_kstat_fini(void);
+static int smb_kstat_update_info(kstat_t *ksp, int rw);
+extern void smb_initialize_dispatch_kstat(void);
+extern void smb_remove_dispatch_kstat(void);
+
+static kstat_t *smbinfo_ksp = NULL;
+
+/*
+ * SMB pseudo-driver entry points
+ */
+
+
+
+int
+_init(void)
+{
+ int rc;
+
+ mutex_init(&smb_drv_opencount_lock, NULL, MUTEX_DRIVER, NULL);
+
+ if ((rc = mod_install(&modlinkage)) != 0) {
+ mutex_destroy(&smb_drv_opencount_lock);
+ cmn_err(CE_NOTE, "init: %d\n", rc);
+ return (rc);
+ }
+
+ return (0);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int rc;
+
+ mutex_enter(&smb_drv_opencount_lock);
+ if (smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EBUSY);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ if ((rc = mod_remove(&modlinkage)) == 0)
+ mutex_destroy(&smb_drv_opencount_lock);
+
+ return (rc);
+}
+
+/*
+ * DDI entry points.
+ */
+
+/* ARGSUSED */
+static int
+smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+ ulong_t instance = getminor((dev_t)arg);
+
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = smb_drv_dip;
+ return (DDI_SUCCESS);
+
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)instance;
+ return (DDI_SUCCESS);
+
+ default:
+ break;
+ }
+
+ return (DDI_FAILURE);
+}
+
+
+static int
+smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ if (cmd != DDI_ATTACH) {
+ return (DDI_FAILURE);
+ }
+
+ if (ddi_get_instance(dip) != 0) {
+ /* we only allow instance 0 to attach */
+ return (DDI_FAILURE);
+ }
+
+ smb_drv_dip = dip;
+
+ /* create the minor node */
+ if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
+ DDI_PSEUDO, 0) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "smb_drv_attach: failed creating minor node");
+ ddi_remove_minor_node(dip, NULL);
+ return (DDI_FAILURE);
+ }
+
+ if (smb_service_init() != 0) {
+ ddi_remove_minor_node(dip, NULL);
+ cmn_err(CE_WARN, "smb_drv_attach: failed to initialize "
+ "SMB service");
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+static int
+smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ if (cmd != DDI_DETACH)
+ return (DDI_FAILURE);
+
+ mutex_enter(&smb_drv_opencount_lock);
+ /*
+ * Service state value is not protected by a lock in this case but
+ * it shouldn't be possible for the service state machine to transition
+ * TO a busy state at a time when smb_drv_busy() would return false.
+ */
+ if (smb_drv_busy() || smb_svcstate_sm_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (DDI_FAILURE);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ smb_service_fini();
+
+ smb_drv_dip = NULL;
+ ddi_remove_minor_node(dip, NULL);
+
+ return (DDI_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
+ int *retval)
+{
+ int gmtoff;
+
+ switch (cmd) {
+
+ case SMB_IOC_GMTOFF:
+ if (ddi_copyin((int *)argp, &gmtoff, sizeof (int), flag))
+ return (EFAULT);
+ (void) smb_set_gmtoff((uint32_t)gmtoff);
+ break;
+
+ case SMB_IOC_CONFIG_REFRESH:
+#if 0
+ smb_svcstate_event(SMB_SVCEVT_CONFIG, NULL);
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+ int rc = 0;
+
+ /*
+ * Only allow one open at a time
+ */
+ mutex_enter(&smb_drv_opencount_lock);
+ if (smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EBUSY);
+ }
+ smb_drv_opencount++;
+ mutex_exit(&smb_drv_opencount_lock);
+
+ /*
+ * Check caller's privileges.
+ */
+ if (secpolicy_smb(credp) != 0) {
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EPERM);
+ }
+
+ /*
+ * Start SMB service state machine
+ */
+ rc = smb_svcstate_sm_start(&smb_info.si_svc_sm_ctx);
+
+ if (rc != 0) {
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+ return (rc);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ mutex_enter(&smb_drv_opencount_lock);
+ if (!smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (0);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ smb_svcstate_event(SMB_SVCEVT_CLOSE, NULL);
+
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+
+ return (0);
+}
+
+/*
+ * Convenience function - must be called with smb_drv_opencount_lock held.
+ */
+static int
+smb_drv_busy(void)
+{
+ ASSERT(mutex_owned(&smb_drv_opencount_lock));
+ return (smb_drv_opencount);
+}
+
+/*
+ * SMB Service initialization and startup functions
+ */
+
+int
+smb_service_init(void)
+{
+ int rc;
+
+ rc = smb_info_init(&smb_info);
+ if (rc != 0) {
+ return (rc);
+ }
+
+ rc = smb_svcstate_sm_init(&smb_info.si_svc_sm_ctx);
+ if (rc != 0) {
+ smb_info_fini(&smb_info);
+ return (rc);
+ }
+
+ rc = smb_kstat_init();
+ if (rc != 0) {
+ smb_kstat_fini();
+ return (rc);
+ }
+
+ smb_winpipe_init();
+
+ return (0);
+}
+
+void
+smb_service_fini(void)
+{
+ smb_winpipe_fini();
+
+ smb_kstat_fini();
+
+ smb_svcstate_sm_fini(&smb_info.si_svc_sm_ctx);
+
+ smb_info_fini(&smb_info);
+}
+
+/*
+ * Progress bits for smb_info.si_open_progress. For use only by
+ * smb_service_open/smb_service_close.
+ */
+#define SMB_FS_STARTED 0x01
+#define LMSHRD_KCLIENT_STARTED 0x02
+#define SMB_KDOOR_CLNT_STARTED 0x04
+#define SMB_KDOOR_SRV_STARTED 0x08
+#define SMB_THREADS_STARTED 0x10
+
+int
+smb_service_open(struct smb_info *si)
+{
+ int rc;
+ int size; /* XXX TEMPORARY (remove when kconfig is removed) */
+
+ /* Track progress so we can cleanup from a partial failure */
+ si->si_open_progress = 0;
+ si->si_connect_progress = 0;
+
+ /* XXX TEMPORARY */
+ if (smb_get_kconfig(&si->si) == 0) {
+ if (si->si.skc_sync_enable)
+ smb_set_stability(1);
+
+ if (si->si.skc_flush_required)
+ smb_commit_required(0);
+
+ if (si->si.skc_maxconnections == 0)
+ si->si.skc_maxconnections = 0xFFFFFFFF;
+
+ size = si->si.skc_maxbufsize;
+ if (size != 0) {
+ if (size < 37 || size > 64)
+ size = 37;
+ smb_maxbufsize = SMB_NT_MAXBUF(size);
+ }
+
+ /*
+ * XXX should not override configuration.
+ * For now, this disables server side
+ * signing regardless of configuration.
+ */
+ si->si.skc_signing_enable = 0;
+ si->si.skc_signing_required = 0;
+ si->si.skc_signing_check = 0;
+
+ smb_correct_keep_alive_values(si->si.skc_keepalive);
+
+ /*
+ * XXX The following code was pulled from smb_oplock_init.
+ * It should be combined with with the config process if
+ * this info will be stored with the configuration or with
+ * the smb_fsop_start function if the data will be stored
+ * in the root of the fs.
+ */
+
+ /*
+ * XXX oplock enable flag.
+ * Should be stored in extended attribute in root of fs
+ * or a ZFS user-defined property.
+ */
+ if (si->si.skc_oplock_enable == 0) {
+ cmn_err(CE_NOTE, "SmbOplocks: disabled");
+ }
+
+ smb_oplock_timeout = si->si.skc_oplock_timeout;
+
+ /*
+ * XXX oplock timeout. Can a customer configure this?
+ */
+ if (si->si.skc_oplock_timeout < OPLOCK_MIN_TIMEOUT)
+ smb_oplock_timeout = OPLOCK_MIN_TIMEOUT;
+
+ } else {
+ return (EIO); /* XXX Errno? */
+ }
+
+ if ((rc = smb_fsop_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_FS_STARTED;
+
+ if ((rc = lmshrd_kclient_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= LMSHRD_KCLIENT_STARTED;
+
+ if ((rc = smb_kdoor_clnt_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_KDOOR_CLNT_STARTED;
+
+ if ((rc = smb_kdoor_srv_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_KDOOR_SRV_STARTED;
+
+ if ((rc = smb_service_start_threads(si)) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_THREADS_STARTED;
+
+ return (0);
+}
+
+void
+smb_service_close(struct smb_info *si)
+{
+ if (si->si_open_progress & SMB_THREADS_STARTED)
+ smb_service_stop_threads(si);
+
+ if (si->si_open_progress & SMB_KDOOR_SRV_STARTED)
+ smb_kdoor_srv_stop();
+
+ if (si->si_open_progress & SMB_KDOOR_CLNT_STARTED)
+ smb_kdoor_clnt_stop();
+
+ if (si->si_open_progress & LMSHRD_KCLIENT_STARTED)
+ lmshrd_kclient_stop();
+
+ if (si->si_open_progress & SMB_FS_STARTED)
+ smb_fsop_stop();
+}
+
+/*
+ * Start the Netbios and TCP services.
+ *
+ * Awaken arguments are not known until thread starts.
+ *
+ * XXX We give up the NET_MAC_AWARE privilege because it keeps us from
+ * re-opening the connection when there are leftover TCP connections in
+ * TCPS_TIME_WAIT state. There seem to be some security ramifications
+ * around reestablishing a connection while possessing the NET_MAC_AWARE
+ * privilege.
+ *
+ * This approach may cause problems when we try to support zones. An
+ * alternative would be to retry the connection setup for a fixed period
+ * of time until the stale connections clear up but that implies we
+ * would be offline for a couple minutes every time the service is
+ * restarted with active connections.
+ */
+int
+smb_service_connect(struct smb_info *si)
+{
+ int rc1, rc2;
+
+ if ((rc1 = setpflags(NET_MAC_AWARE, 0, CRED())) != 0) {
+ cmn_err(CE_WARN, "Cannot remove NET_MAC_AWARE privilege");
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)rc1);
+ return (rc1);
+ }
+
+ rc1 = smb_thread_start(&si->si_nbt_daemon);
+ rc2 = smb_thread_start(&si->si_tcp_daemon);
+ if (rc2 != 0)
+ rc1 = rc2;
+ return (rc1);
+}
+
+void
+smb_service_disconnect(struct smb_info *si)
+{
+ smb_thread_stop(&si->si_nbt_daemon);
+ smb_thread_stop(&si->si_tcp_daemon);
+}
+
+/*
+ * Start any service-related kernel threads except for the NBT and TCP
+ * daemon threads. Those service daemon threads are handled separately.
+ *
+ * Returns 0 for success, non-zero for failure. If failure is returned the
+ * caller should call smb_service_stop_threads to cleanup any threads that
+ * were successfully started.
+ */
+int
+smb_service_start_threads(struct smb_info *si)
+{
+ int rval;
+
+ si->thread_pool = taskq_create(
+ "smb_workers",
+ si->si.skc_maxworkers,
+ SMB_WORKER_PRIORITY,
+ si->si.skc_maxworkers,
+ INT_MAX,
+ TASKQ_DYNAMIC|TASKQ_PREPOPULATE);
+ ASSERT(si->thread_pool != NULL);
+
+ rval = smb_thread_start(&si->si_thread_notify_change);
+ if (rval != 0)
+ return (rval);
+
+ rval = smb_thread_start(&si->si_thread_timers);
+ if (rval != 0) {
+ smb_thread_stop(&si->si_thread_notify_change);
+ return (rval);
+ }
+
+ return (0);
+}
+
+void
+smb_service_stop_threads(struct smb_info *si)
+{
+ smb_thread_stop(&si->si_thread_timers);
+ smb_thread_stop(&si->si_thread_notify_change);
+ taskq_destroy(si->thread_pool);
+}
+
+static int
+smb_info_init(struct smb_info *si)
+{
+ int i;
+
+ bzero(si, sizeof (smb_info));
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_llist_constructor(&si->node_hash_table[i],
+ sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
+ }
+
+ smb_llist_constructor(&si->si_vfs_list,
+ sizeof (smb_vfs_t), offsetof(smb_vfs_t, sv_lnd));
+
+ smb_slist_constructor(&si->si_ncr_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_ncr.nc_lnd));
+
+ smb_slist_constructor(&si->si_nce_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_ncr.nc_lnd));
+
+ si->si_cache_vfs = kmem_cache_create("smb_vfs_cache",
+ sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_request = kmem_cache_create("smb_request_cache",
+ sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_session = kmem_cache_create("smb_session_cache",
+ sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_user = kmem_cache_create("smb_user_cache",
+ sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_tree = kmem_cache_create("smb_tree_cache",
+ sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_ofile = kmem_cache_create("smb_ofile_cache",
+ sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_odir = kmem_cache_create("smb_odir_cache",
+ sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_node = kmem_cache_create("smb_smb_node_cache",
+ sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+
+ smb_thread_init(&si->si_nbt_daemon, "smb_nbt_daemon", smb_nbt_daemon,
+ si, NULL, NULL);
+ smb_thread_init(&si->si_tcp_daemon, "smb_tcp_daemon", smb_tcp_daemon,
+ si, NULL, NULL);
+ smb_thread_init(&si->si_thread_notify_change,
+ "smb_notify_change_daemon", smb_notify_change_daemon, &smb_info,
+ NULL, NULL);
+ smb_thread_init(&si->si_thread_timers, "smb_timers", smb_timers,
+ si, NULL, NULL);
+
+ return (0);
+}
+
+static void
+smb_info_fini(struct smb_info *si)
+{
+ int i;
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_node_t *node;
+
+ /*
+ * The following sequence is just intended for sanity check.
+ * This will have to be modified when the code goes into
+ * production.
+ *
+ * The SMB node hash table should be emtpy at this point. If the
+ * hash table is not empty all the nodes remaining are displayed
+ * (it should help figure out what actions led to this state)
+ * and "oops" will be set to B_TRUE which will trigger the
+ * ASSERT that follows.
+ *
+ * The reason why SMB nodes are still remaining in the hash
+ * table is problably due to a mismatch between calls to
+ * smb_node_lookup() and smb_node_release(). You must track that
+ * down.
+ *
+ * Now if you are reading this comment because you actually hit
+ * the ASSERT, the temptation to ignore it is going to be very
+ * strong. To help you make the right decision you should know
+ * that when the ASSERT happened a message containing you SunID
+ * has been sent to cifsgate. By now it has been logged into a
+ * special database.
+ *
+ * You are being watched...
+ */
+ node = smb_llist_head(&si->node_hash_table[i]);
+ ASSERT(node == NULL);
+ }
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_llist_destructor(&si->node_hash_table[i]);
+ }
+
+ smb_llist_destructor(&si->si_vfs_list);
+
+ kmem_cache_destroy(si->si_cache_vfs);
+ kmem_cache_destroy(si->si_cache_request);
+ kmem_cache_destroy(si->si_cache_session);
+ kmem_cache_destroy(si->si_cache_user);
+ kmem_cache_destroy(si->si_cache_tree);
+ kmem_cache_destroy(si->si_cache_ofile);
+ kmem_cache_destroy(si->si_cache_odir);
+ kmem_cache_destroy(si->si_cache_node);
+
+ smb_thread_destroy(&si->si_nbt_daemon);
+ smb_thread_destroy(&si->si_tcp_daemon);
+ smb_thread_destroy(&si->si_thread_notify_change);
+ smb_thread_destroy(&si->si_thread_timers);
+}
+
+static int
+smb_kstat_init()
+{
+
+ /* create and initialize smb kstats - smb_info stats */
+ smbinfo_ksp = kstat_create("smb", 0, "smb_info", "misc",
+ KSTAT_TYPE_NAMED, sizeof (smbinfo_stats) / sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL);
+ if (smbinfo_ksp) {
+ smbinfo_ksp->ks_data = (void *) &smbinfo_stats;
+ smbinfo_ksp->ks_update = smb_kstat_update_info;
+ kstat_install(smbinfo_ksp);
+ }
+
+ /* create and initialize smb kstats - smb_dispatch stats */
+ smb_initialize_dispatch_kstat();
+
+ return (0);
+}
+
+static void
+smb_kstat_fini()
+{
+ if (smbinfo_ksp != NULL) {
+ kstat_delete(smbinfo_ksp);
+ smbinfo_ksp = NULL;
+ }
+
+ smb_remove_dispatch_kstat();
+}
+
+/* ARGSUSED */
+static int
+smb_kstat_update_info(kstat_t *ksp, int rw)
+{
+ if (rw == KSTAT_WRITE) {
+ return (EACCES);
+ } else {
+ smbinfo_stats.state.value.ui32 =
+ smb_info.si_svc_sm_ctx.ssc_state;
+ smbinfo_stats.open_files.value.ui32 = smb_info.open_files;
+ smbinfo_stats.open_trees.value.ui32 = smb_info.open_trees;
+ smbinfo_stats.open_users.value.ui32 = smb_info.open_users;
+ }
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_kdoor_clnt.c b/usr/src/uts/common/fs/smbsrv/smb_kdoor_clnt.c
new file mode 100644
index 0000000000..df2cd5368b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor_clnt.c
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/door.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+
+door_handle_t smb_kdoor_clnt_dh;
+
+/*
+ * smb_kdoor_clnt_free
+ *
+ * This function should be invoked to free both the argument/result door buffer
+ * regardless of the status of the up-call.
+ *
+ * The doorfs allocates a new buffer if the result buffer passed by the client
+ * is too small. This function will deallocate that buffer as well.
+ */
+void
+smb_kdoor_clnt_free(char *argp, size_t arg_size, char *rbufp, size_t rbuf_size)
+{
+ if (argp) {
+ if (argp == rbufp) {
+ kmem_free(argp, arg_size);
+ } else if (rbufp) {
+ kmem_free(argp, arg_size);
+ kmem_free(rbufp, rbuf_size);
+ }
+ } else {
+ if (rbufp)
+ kmem_free(rbufp, rbuf_size);
+ }
+}
+
+/*
+ * smb_kdoor_clnt_start
+ *
+ * The SMB kernel module should invoke this function upon startup.
+ */
+int
+smb_kdoor_clnt_start()
+{
+ int rc = 0;
+
+ rc = door_ki_open(SMB_DR_SVC_NAME, &smb_kdoor_clnt_dh);
+
+ return (rc);
+}
+
+/*
+ * smb_kdoor_clnt_stop
+ *
+ * The SMB kernel module should invoke this function upon unload.
+ */
+void
+smb_kdoor_clnt_stop()
+{
+ door_ki_rele(smb_kdoor_clnt_dh);
+}
+
+/*
+ * smb_kdoor_clnt_upcall
+ *
+ * This function will make a door up-call to the server function
+ * associated with the door descriptor fp. The specified door
+ * request buffer (i.e. argp) will be passed as the argument to the
+ * door_ki_upcall(). Upon success, the result buffer is returned. Otherwise,
+ * NULL pointer is returned. The size of the result buffer is returned
+ * via rbufsize.
+ */
+char *
+smb_kdoor_clnt_upcall(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t desc_num, size_t *rbufsize)
+{
+ door_arg_t door_arg;
+ int err;
+
+ if (!argp) {
+ cmn_err(CE_WARN, "smb_kdoor_clnt_upcall: invalid parameter");
+ return (NULL);
+ }
+
+ door_arg.data_ptr = argp;
+ door_arg.data_size = arg_size;
+ door_arg.desc_ptr = dp;
+ door_arg.desc_num = desc_num;
+ door_arg.rbuf = argp;
+ door_arg.rsize = arg_size;
+
+ if ((err = door_ki_upcall(smb_kdoor_clnt_dh, &door_arg)) != 0) {
+ cmn_err(CE_WARN, "smb_kdoor_clnt_upcall: failed(%d)", err);
+ kmem_free(argp, arg_size);
+ argp = NULL;
+ return (NULL);
+ }
+
+ if (smb_dr_get_res_stat(door_arg.data_ptr, door_arg.rsize) !=
+ SMB_DR_OP_SUCCESS) {
+ smb_kdoor_clnt_free(argp, arg_size, door_arg.rbuf,
+ door_arg.rsize);
+ *rbufsize = 0;
+ return (NULL);
+ }
+ *rbufsize = door_arg.rsize;
+ return (door_arg.data_ptr);
+
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_kdoor_encdec.c b/usr/src/uts/common/fs/smbsrv/smb_kdoor_encdec.c
new file mode 100644
index 0000000000..701e587fbc
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor_encdec.c
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_xdr.h>
+
+
+/*
+ * smb_kdr_decode_common
+ *
+ * This function can be used for decoding both door request and result buffer.
+ * pre-condition: data is non-null pointer, and is bzero'd.
+ */
+int
+smb_kdr_decode_common(char *buf, size_t len, xdrproc_t proc, void *data)
+{
+ XDR xdrs;
+ int rc = 0;
+
+ if (!data) {
+ cmn_err(CE_WARN, "smb_kdr_decode_common: invalid param");
+ return (-1);
+ }
+
+ xdrmem_create(&xdrs, buf, len, XDR_DECODE);
+ if (!proc(&xdrs, data))
+ rc = -1;
+
+ xdr_destroy(&xdrs);
+ return (rc);
+}
+
+/*
+ * smb_kdr_encode_common
+ *
+ * This function is used for encoding both request/result door buffer.
+ * This function will first encode integer value 'reserved' (opcode/status),
+ * followed by the data (which will be encoded via the specified XDR routine.
+ *
+ * Returns encoded buffer upon success. Otherwise, returns NULL.
+ */
+char *
+smb_kdr_encode_common(uint_t reserved, void *data, xdrproc_t proc, size_t *len)
+{
+ XDR xdrs;
+ char *buf;
+
+ if (proc && !data) {
+ cmn_err(CE_WARN, "smb_kdr_encode_common: invalid param");
+ *len = 0;
+ return (NULL);
+ }
+
+ *len = xdr_sizeof(xdr_uint32_t, &reserved);
+ if (proc)
+ *len += xdr_sizeof(proc, data);
+ buf = kmem_alloc(*len, KM_SLEEP);
+ xdrmem_create(&xdrs, buf, *len, XDR_ENCODE);
+ if (!xdr_uint32_t(&xdrs, &reserved)) {
+ cmn_err(CE_WARN, "smb_kdr_encode_common: encode error 1");
+ kmem_free(buf, *len);
+ *len = 0;
+ xdr_destroy(&xdrs);
+ return (NULL);
+ }
+
+ if (proc && !proc(&xdrs, data)) {
+ cmn_err(CE_WARN, "smb_kdr_encode_common: encode error 2");
+ kmem_free(buf, *len);
+ buf = NULL;
+ *len = 0;
+ }
+
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+/*
+ * Get the opcode of the door argument buffer.
+ */
+int
+smb_dr_get_opcode(char *argp, size_t arg_size)
+{
+ int opcode;
+
+ if (smb_kdr_decode_common(argp, arg_size, xdr_uint32_t, &opcode) != 0)
+ opcode = -1;
+ return (opcode);
+}
+
+/*
+ * Set the opcode of the door argument buffer.
+ */
+char *
+smb_dr_set_opcode(uint32_t opcode, size_t *len)
+{
+ char *buf;
+
+ buf = smb_kdr_encode_common(opcode, NULL, NULL, len);
+ return (buf);
+}
+
+/*
+ * Get the status of the door result buffer.
+ */
+int
+smb_dr_get_res_stat(char *rbufp, size_t rbuf_size)
+{
+ int stat;
+ if (smb_kdr_decode_common(rbufp, rbuf_size, xdr_uint32_t, &stat) != 0)
+ stat = -1;
+ return (stat);
+}
+
+/*
+ * Set the status of the door result buffer.
+ */
+char *
+smb_dr_set_res_stat(uint32_t stat, size_t *len)
+{
+ char *buf;
+
+ buf = smb_kdr_encode_common(stat, NULL, NULL, len);
+ return (buf);
+}
+
+char *
+smb_dr_encode_arg_get_token(netr_client_t *clnt_info, size_t *len)
+{
+
+ char *buf;
+ smb_dr_bytes_t arg;
+ uint_t opcode = SMB_DR_USER_AUTH_LOGON;
+
+ arg.bytes_val = netr_client_mkselfrel(clnt_info,
+ &arg.bytes_len);
+
+ buf = smb_kdr_encode_common(opcode, &arg, xdr_smb_dr_bytes_t, len);
+ kmem_free(arg.bytes_val, arg.bytes_len);
+ return (buf);
+}
+
+smb_token_t *
+smb_dr_decode_res_token(char *buf, size_t len)
+{
+ smb_dr_bytes_t res;
+ smb_token_t *token;
+
+ bzero(&res, sizeof (smb_dr_bytes_t));
+ if (smb_kdr_decode_common(buf, len, xdr_smb_dr_bytes_t, &res) !=
+ 0) {
+ cmn_err(CE_WARN, "smb_dr_decode_res_token: failed");
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&res);
+ return (NULL);
+ }
+ token = smb_token_mkabsolute(res.bytes_val, res.bytes_len);
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&res);
+
+ return (token);
+}
+
+char *
+smb_dr_encode_string(uint32_t reserved, char *str, size_t *len)
+{
+ char *buf = NULL;
+ smb_dr_string_t res;
+
+ if (!str) {
+ *len = 0;
+ return (buf);
+ }
+
+ res.buf = str;
+ if ((buf = smb_kdr_encode_common(reserved, &res,
+ xdr_smb_dr_string_t, len)) == 0)
+ cmn_err(CE_WARN, "smb_dr_encode_string: failed");
+ return (buf);
+}
+
+/*
+ * smb_dr_decode_kshare()
+ *
+ * The kshare information arrives encoded in a flat buffer, so retrieve
+ * the flat buffer and convert it to an smb_dr_kshare structure.
+ */
+
+smb_dr_kshare_t *
+smb_dr_decode_kshare(char *buf, size_t len)
+{
+ smb_dr_bytes_t res;
+ smb_dr_kshare_t *kshare;
+
+ bzero(&res, sizeof (smb_dr_bytes_t));
+ if (smb_kdr_decode_common(buf, len, xdr_smb_dr_bytes_t, &res) !=
+ 0) {
+ cmn_err(CE_WARN, "smb_dr_decode_kshare: failed");
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&res);
+ return (NULL);
+ }
+ kshare = smb_share_mkabsolute(res.bytes_val, res.bytes_len);
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&res);
+
+ return (kshare);
+}
+
+/*
+ * smb_share_mkabsolute
+ *
+ * decode: flat buffer -> structure
+ */
+
+smb_dr_kshare_t *
+smb_share_mkabsolute(uint8_t *buf, uint32_t len)
+{
+ smb_dr_kshare_t *obj;
+ XDR xdrs;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
+ obj = kmem_zalloc(sizeof (smb_dr_kshare_t), KM_SLEEP);
+
+ if (!xdr_smb_dr_kshare_t(&xdrs, obj)) {
+ kmem_free(obj, sizeof (smb_dr_kshare_t));
+ obj = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (obj);
+}
+
+void
+smb_dr_kshare_free(smb_dr_kshare_t *kshare)
+{
+ if (!kshare)
+ return;
+
+ xdr_free(xdr_smb_dr_kshare_t, (char *)kshare);
+ kmem_free(kshare, sizeof (smb_dr_kshare_t));
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c b/usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c
new file mode 100644
index 0000000000..d6be914182
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Kernel door operations
+ */
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/smb_incl.h>
+
+/* SMB kernel module's door operation table */
+smb_kdr_op_t smb_kdoorsrv_optab[] =
+{
+ smb_kdr_op_user_num,
+ smb_kdr_op_users,
+ smb_kdr_op_share
+};
+
+int
+smb_kdr_is_valid_opcode(int opcode)
+{
+ if (opcode < 0 ||
+ opcode > (sizeof (smb_kdoorsrv_optab) / sizeof (smb_kdr_op_t)))
+ return (-1);
+ else
+ return (0);
+}
+
+/*ARGSUSED*/
+char *
+smb_kdr_op_user_num(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
+{
+ uint32_t num;
+ char *rbuf;
+
+ *errno = SMB_DR_OP_SUCCESS;
+ num = smb_user_get_num();
+ rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, &num, xdr_uint32_t,
+ rbufsize);
+ if (!rbuf) {
+ *errno = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ return (NULL);
+ }
+
+ return (rbuf);
+}
+
+char *
+smb_kdr_op_users(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
+{
+ smb_dr_ulist_t *ulist;
+ uint32_t offset;
+ char *rbuf = NULL;
+
+ *errno = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+ if (smb_kdr_decode_common(argp, arg_size, xdr_uint32_t, &offset) != 0) {
+ *errno = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ ulist = kmem_zalloc(sizeof (smb_dr_ulist_t), KM_SLEEP);
+ (void) smb_dr_ulist_get(offset, ulist);
+
+ if ((rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, ulist,
+ xdr_smb_dr_ulist_t, rbufsize)) == NULL) {
+ *errno = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ smb_dr_ulist_free(ulist);
+ kmem_free(ulist, sizeof (smb_dr_ulist_t));
+ return (rbuf);
+}
+
+/*
+ * smb_kdr_op_share()
+ *
+ * This function decodes an smb_dr_kshare_t structure from userland and
+ * calls smb_share() to take action depending on whether a share is being
+ * enabled or disabled.
+ */
+
+char *
+smb_kdr_op_share(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
+{
+ smb_dr_kshare_t *kshare;
+ char *rbuf = NULL;
+ int error = 0;
+
+ *errno = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ kshare = smb_dr_decode_kshare(argp, arg_size);
+
+ if (kshare == NULL) {
+ *errno = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ switch (kshare->k_op) {
+ case LMSHR_ADD:
+ error = smb_share_export(kshare->k_path);
+ break;
+ case LMSHR_DELETE:
+ error = smb_share_unexport(kshare->k_path, kshare->k_sharename);
+ break;
+ default:
+ ASSERT(0);
+ error = EINVAL;
+ break;
+ }
+
+ smb_dr_kshare_free(kshare);
+
+ if (error)
+ return (NULL);
+
+ rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, &error, xdr_int32_t,
+ rbufsize);
+
+ if (!rbuf) {
+ *errno = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ return (NULL);
+ }
+
+ return (rbuf);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c b/usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c
new file mode 100644
index 0000000000..7199aa62f4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Kernel door service
+ * It has dependency on the kernel door client interface because the downcall
+ * descriptor is required to be passed up to SMB daemon via door up-call.
+ */
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/door.h>
+#include <sys/kmem.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+
+door_handle_t smb_kdoor_hdl = NULL;
+
+/*
+ * Since the action performed by smb_kdoor_srv_callback might vary
+ * according to request type/opcode, the smb_kdoor_cookie will
+ * be set to the request type in the server procedure
+ * (i.e. smb_kdoor_svc). It will then be passed to the callback
+ * function when the kernel is done with the copyout operation.
+ */
+int smb_kdoor_cookie = -1;
+
+extern smb_kdr_op_t smb_kdoorsrv_optab[];
+
+/* forward declaration */
+void smb_kdoor_svc(void *data, door_arg_t *dap, void (**destfnp)(void *,
+ void *), void **destarg, int *error);
+
+/*
+ * smb_kdoor_srv_start
+ *
+ * When driver is opened, this function should be called to create the
+ * kernel door. The door descriptor will then be passed up to the
+ * user-space SMB daemon.
+ *
+ * Returns 0 upon success otherwise non-zero
+ */
+int
+smb_kdoor_srv_start()
+{
+ door_desc_t smb_kdoor_desc;
+ int err;
+ int res;
+ int opcode = SMB_DR_SET_DWNCALL_DESC;
+
+ if ((err = door_ki_create(smb_kdoor_svc,
+ &smb_kdoor_cookie, 0, &smb_kdoor_hdl)) != 0) {
+ cmn_err(CE_WARN, "SmbKdoorInit: door_create"
+ " failed(%d)", err);
+ return (err);
+ }
+
+ smb_kdoor_desc.d_attributes = DOOR_HANDLE;
+ smb_kdoor_desc.d_data.d_handle = smb_kdoor_hdl;
+
+ res = smb_upcall_set_dwncall_desc(opcode, &smb_kdoor_desc, 1);
+ if (res != SMB_DR_OP_SUCCESS) {
+ cmn_err(CE_WARN, "SmbKdoorInit: smbd failed to set the"
+ " downcall descriptor res=%d", res);
+ smb_kdoor_srv_stop();
+ return (EIO);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_kdoor_srv_stop
+ *
+ * This function will stop the kernel door service when the driver is closed.
+ */
+void
+smb_kdoor_srv_stop()
+{
+ if (smb_kdoor_hdl) {
+ door_ki_rele(smb_kdoor_hdl);
+ smb_kdoor_hdl = NULL;
+ }
+}
+
+/*
+ * smb_kdoor_srv_callback
+ *
+ * This callback function will be executed by the kernel after copyout()
+ * completes. Currently, this function only free the server buffer that
+ * was previously allocated in the smb_kdoor_srv(). It can be enhanced
+ * to perform any action based on the opcode if there is a need in the
+ * future.
+ */
+static void
+smb_kdoor_srv_callback(void *cookie, void *arg)
+{
+ /*LINTED E_FUNC_VAR_UNUSED*/
+ int *opcode;
+ smb_kdoor_cb_arg_t *cbarg;
+
+ if (cookie)
+ opcode = (int *)cookie;
+
+ if (!arg)
+ return;
+
+ cbarg = (smb_kdoor_cb_arg_t *)arg;
+ if (cbarg->rbuf)
+ kmem_free(cbarg->rbuf, cbarg->rbuf_size);
+
+ kmem_free(cbarg, sizeof (smb_kdoor_cb_arg_t));
+}
+
+
+void
+smb_kdoor_svc(void *cookie, door_arg_t *dap, void (**destfnp)(void *,
+ void *), void **destarg, int *error)
+{
+ int opcode;
+ smb_kdoor_cb_arg_t *cbarg;
+ size_t arg_size;
+ char *argp = NULL;
+ smb_kdr_op_t smbop;
+
+ /*
+ * Be aware that *destfnp cannot be NULL even if there isn't
+ * any additional work after the kernel completes copyout() operation.
+ */
+ *destfnp = smb_kdoor_srv_callback;
+ *destarg = NULL;
+ *error = 0;
+
+ if (!dap) {
+ cmn_err(CE_WARN, "SmbKdoorSvc: invalid arguments");
+ *error = EINVAL;
+ return;
+ }
+
+ arg_size = dap->data_size;
+ argp = kmem_alloc(arg_size, KM_SLEEP);
+ /* The data_ptr points to user data */
+ (void) copyin(dap->data_ptr, argp, dap->data_size);
+ /* initialize the returned data size to be 0 */
+ dap->data_size = 0;
+
+ opcode = smb_dr_get_opcode(argp, arg_size);
+ *((int *)cookie) = opcode;
+
+ if (smb_kdr_is_valid_opcode(opcode) != 0) {
+ cmn_err(CE_WARN, "SmbKdoorSvc: invalid opcode(%d)", opcode);
+ *error = EINVAL;
+ kmem_free(argp, arg_size);
+ return;
+
+ }
+
+ smbop = smb_kdoorsrv_optab[opcode];
+ cbarg = kmem_alloc(sizeof (smb_kdoor_cb_arg_t), KM_SLEEP);
+ if ((cbarg->rbuf = smbop(argp + sizeof (opcode),
+ arg_size - sizeof (opcode), &cbarg->rbuf_size, error)) == NULL) {
+ cmn_err(CE_WARN, "SmbKdoorSvc: door op failed");
+
+ switch (*error) {
+ case SMB_DR_OP_ERR_ENCODE:
+ *error = EINVAL;
+ cmn_err(CE_WARN, "SmbKdoorSvc: encode error");
+ break;
+ case SMB_DR_OP_ERR_DECODE:
+ *error = EINVAL;
+ cmn_err(CE_WARN, "SmbKdoorSvc: decode error");
+ break;
+ case SMB_DR_OP_ERR_EMPTYBUF:
+ if ((cbarg->rbuf = smb_dr_set_res_stat(
+ SMB_DR_OP_ERR_EMPTYBUF, &cbarg->rbuf_size))
+ == NULL) {
+ cmn_err(CE_WARN, "SmbKdoorSvc: return nothing");
+ *error = EINVAL;
+ }
+ *error = 0;
+ break;
+ default:
+ cmn_err(CE_WARN, "SmbKdoorSvc: unknown error");
+ }
+ }
+
+ kmem_free(argp, arg_size);
+ dap->data_size = cbarg->rbuf_size;
+ dap->rbuf = cbarg->rbuf;
+ *destarg = cbarg;
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
new file mode 100644
index 0000000000..53e8d0326e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: lock_byte_range
+ *
+ * The lock record message is sent to lock the given byte range. More than
+ * one non-overlapping byte range may be locked in a given file. Locks
+ * prevent attempts to lock, read or write the locked portion of the file
+ * by other clients or Pids. Overlapping locks are not allowed. Offsets
+ * beyond the current end of file may be locked. Such locks will not cause
+ * allocation of file space.
+ *
+ * Since Offset is a 32 bit quantity, this request is inappropriate for
+ * general locking within a very large file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 5
+ * USHORT Fid; File handle
+ * ULONG Count; Count of bytes to lock
+ * ULONG Offset; Offset from start of file
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Locks may only be unlocked by the Pid that performed the lock.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * This client request does not wait for the lock to be granted. If the
+ * lock can not be immediately granted (within 200-300 ms), the server
+ * should return failure to the client
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_lock_byte_range(struct smb_request *sr)
+{
+ uint32_t count;
+ uint32_t off;
+ DWORD result;
+
+ if (smbsr_decode_vwv(sr, "wll", &sr->smb_fid, &count, &off) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ /*
+ * The last parameter is lock type. This is dependent on
+ * lock flag (3rd parameter). Since the lock flag is
+ * set to be exclusive, lock type is passed as
+ * normal lock (write lock).
+ */
+ result = smb_lock_range(sr, sr->fid_ofile,
+ (off_t)off, (uint64_t)count, 0, SMB_LOCK_TYPE_READWRITE);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_lock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c b/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c
new file mode 100644
index 0000000000..e043472af5
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c
@@ -0,0 +1,709 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides range lock functionality for CIFS/SMB clients.
+ * Lock range service functions process SMB lock and and unlock
+ * requests for a file by applying lock rules and marks file range
+ * as locked if the lock is successful otherwise return proper
+ * error code.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+static int
+smb_lock_range_overlap(struct smb_lock *lock, uint64_t start, uint64_t length);
+
+static uint32_t smb_lock_range_lckrules(struct smb_request *sr,
+ smb_ofile_t *file, struct smb_node *node, smb_lock_t *dlock,
+ smb_lock_t **clockp);
+
+static uint32_t
+smb_lock_wait(struct smb_request *sr, smb_lock_t *b_lock, smb_lock_t *c_lock);
+
+static uint32_t
+smb_lock_range_ulckrules(struct smb_request *sr,
+ struct smb_node *node,
+ uint64_t start,
+ uint64_t length,
+ struct smb_lock **nodelock);
+
+static smb_lock_t *smb_lock_create(smb_request_t *sr,
+ uint64_t start, uint64_t length, uint32_t locktype, uint32_t timeout);
+static void smb_lock_destroy(smb_lock_t *lock);
+static void smb_lock_free(smb_lock_t *lock);
+
+/*
+ * smb_lock_range_overlap
+ *
+ * Checks if lock range(start, length) overlaps
+ * range in lock structure.
+ *
+ * return values:
+ * 0 - Lock range doesn't overlap
+ * 1 - Lock range overlaps.
+ */
+
+#define RANGE_NO_OVERLAP 0
+#define RANGE_OVERLAP 1
+
+static int
+smb_lock_range_overlap(struct smb_lock *lock, uint64_t start, uint64_t length)
+{
+ /* A zero-length range doesn't overlap anything */
+ if (length == 0 || lock->l_length == 0)
+ return (RANGE_NO_OVERLAP);
+
+ if (start < lock->l_start) {
+ if (start + length > lock->l_start)
+ return (RANGE_OVERLAP);
+ } else if (start < lock->l_start + lock->l_length)
+ return (RANGE_OVERLAP);
+
+ if (start + length > lock->l_start + lock->l_length) {
+ if (start < lock->l_start + lock->l_length)
+ return (RANGE_OVERLAP);
+ } else if (start + length > lock->l_start)
+ return (RANGE_OVERLAP);
+
+ /* Lock range doen't overlap */
+ return (RANGE_NO_OVERLAP);
+}
+
+/*
+ * smb_lock_range_lckrules
+ *
+ * Lock range rules:
+ * 1. Overlapping read locks are allowed if the
+ * current locks in the region are only read locks
+ * irrespective of pid of smb client issuing lock request.
+ *
+ * 2. Read lock in the overlapped region of write lock
+ * are allowed if the pervious lock is performed by the
+ * same pid and connection.
+ *
+ * return status:
+ * NT_STATUS_SUCCESS - Input lock range adapts to lock rules.
+ * NT_STATUS_LOCK_NOT_GRANTED - Input lock conflicts lock rules.
+ * NT_STATUS_CANCELLED - Error in processing lock rules
+ */
+static uint32_t
+smb_lock_range_lckrules(
+ struct smb_request *sr,
+ smb_ofile_t *file,
+ struct smb_node *node,
+ smb_lock_t *dlock,
+ smb_lock_t **clockp)
+{
+ smb_lock_t *lock;
+ uint32_t status = NT_STATUS_SUCCESS;
+
+ /* Check if file is closed */
+ if (!smb_ofile_is_open(file)) {
+ return (NT_STATUS_RANGE_NOT_LOCKED);
+ }
+
+ /* Caller must hold lock for node->n_lock_list */
+ for (lock = smb_llist_head(&node->n_lock_list);
+ lock != NULL;
+ lock = smb_llist_next(&node->n_lock_list, lock)) {
+
+ if (!smb_lock_range_overlap(lock, dlock->l_start,
+ dlock->l_length))
+ continue;
+
+ /*
+ * Check to see if lock in the overlapping record
+ * is only read lock. Current finding is read
+ * locks can overlapped irrespective of pids.
+ */
+ if ((lock->l_type == SMB_LOCK_TYPE_READONLY) &&
+ (dlock->l_type == SMB_LOCK_TYPE_READONLY)) {
+ continue;
+ }
+
+ /*
+ * When the read lock overlaps write lock, check if
+ * allowed.
+ */
+ if ((dlock->l_type == SMB_LOCK_TYPE_READONLY) &&
+ !(lock->l_type == SMB_LOCK_TYPE_READONLY)) {
+ if (lock->l_file == sr->fid_ofile &&
+ lock->l_session_kid == sr->session->s_kid &&
+ lock->l_pid == sr->smb_pid &&
+ lock->l_uid == sr->smb_uid) {
+ continue;
+ }
+ }
+
+ /* Conflict in overlapping lock element */
+ *clockp = lock;
+ status = NT_STATUS_LOCK_NOT_GRANTED;
+ break;
+ }
+
+ return (status);
+}
+
+/*
+ * smb_lock_wait
+ *
+ * Wait operation for smb overlapping lock to be released. Caller must hold
+ * write lock for node->n_lock_list so that the set of active locks can't
+ * change unexpectedly. The lock for node->n_lock_list will be released
+ * within this function during the sleep after the lock dependency has
+ * been recorded.
+ *
+ * return value
+ *
+ * NT_STATUS_CANCELLED Error occurred during wait operation
+ * NT_STATUS_SUCCESS Wait completed.
+ */
+static uint32_t
+smb_lock_wait(smb_request_t *sr, smb_lock_t *b_lock, smb_lock_t *c_lock)
+{
+ clock_t result;
+ uint32_t status = NT_STATUS_SUCCESS;
+
+ ASSERT(sr->sr_awaiting == NULL);
+
+ mutex_enter(&sr->sr_mutex);
+
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_ACTIVE:
+ /*
+ * Wait up till the timeout time keeping track of actual
+ * time waited for possible retry failure.
+ */
+ sr->sr_state = SMB_REQ_STATE_WAITING_LOCK;
+ sr->sr_awaiting = c_lock;
+ mutex_exit(&sr->sr_mutex);
+
+ mutex_enter(&c_lock->l_mutex);
+ /*
+ * The conflict list (l_conflict_list) for a lock contains
+ * all the locks that are blocked by and in conflict with
+ * that lock. Add the new lock to the conflict list for the
+ * active lock.
+ *
+ * l_conflict_list is currently a fancy way of representing
+ * the references/dependencies on a lock. It could be
+ * replaced with a reference count but this approach
+ * has the advantage that MDB can display the lock
+ * dependencies at any point in time. In the future
+ * we should be able to leverage the list to implement
+ * an asynchronous locking model.
+ *
+ * l_blocked_by is the reverse of the conflict list. It
+ * points to the lock that the new lock conflicts with.
+ * As currently implemented this value is purely for
+ * debug purposes -- there are windows of time when
+ * l_blocked_by may be non-NULL even though there is no
+ * conflict list
+ */
+ b_lock->l_blocked_by = c_lock;
+ smb_slist_insert_tail(&c_lock->l_conflict_list, b_lock);
+ smb_llist_exit(&c_lock->l_file->f_node->n_lock_list);
+
+ /*
+ * XXX Hack.. drop s_lock to avoid blocking subsequent SMBs
+ * that might affect the state of this lock (i.e.
+ * smb_com_close). We shouldn't sleep while holding
+ * locks anyway.
+ */
+ smb_rwx_rwexit(&sr->session->s_lock);
+
+ if (SMB_LOCK_INDEFINITE_WAIT(b_lock)) {
+ cv_wait(&c_lock->l_cv, &c_lock->l_mutex);
+ } else {
+ result = cv_timedwait(&c_lock->l_cv,
+ &c_lock->l_mutex, b_lock->l_end_time);
+ if (result == -1) {
+ status = NT_STATUS_CANCELLED;
+ }
+ }
+
+ /*
+ * XXX Hack continued from above... re-acquire s_lock
+ * OK to hardcode RW_READER since this is just a hack and
+ * we really should yank it out and do something else.
+ */
+ smb_rwx_rwenter(&sr->session->s_lock, RW_READER);
+
+ mutex_exit(&c_lock->l_mutex);
+
+ smb_llist_enter(&c_lock->l_file->f_node->n_lock_list,
+ RW_WRITER);
+ smb_slist_remove(&c_lock->l_conflict_list, b_lock);
+
+ mutex_enter(&sr->sr_mutex);
+ sr->sr_awaiting = NULL;
+ if (sr->sr_state == SMB_REQ_STATE_CANCELED) {
+ status = NT_STATUS_CANCELLED;
+ } else {
+ sr->sr_state = SMB_REQ_STATE_ACTIVE;
+ }
+ break;
+
+ case SMB_REQ_STATE_CANCELED:
+ status = NT_STATUS_CANCELLED;
+ mutex_exit(&sr->sr_mutex);
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ mutex_exit(&sr->sr_mutex);
+
+ return (status);
+}
+
+/*
+ * smb_lock_range_ulckrules
+ *
+ * 1. Unlock should be performed at exactly matching ends.
+ * This has been changed because overlapping ends is
+ * allowed and there is no other precise way of locating
+ * lock entity in node lock list.
+ *
+ * 2. Unlock is failed if there is no corresponding lock exists.
+ *
+ * Return values
+ *
+ * NT_STATUS_SUCCESS Unlock request matches lock record
+ * pointed by 'nodelock' lock structure.
+ *
+ * NT_STATUS_RANGE_NOT_LOCKED Unlock request doen't match any
+ * of lock record in node lock request or
+ * error in unlock range processing.
+ */
+static uint32_t
+smb_lock_range_ulckrules(
+ struct smb_request *sr,
+ struct smb_node *node,
+ uint64_t start,
+ uint64_t length,
+ struct smb_lock **nodelock)
+{
+ smb_lock_t *lock;
+ uint32_t status = NT_STATUS_RANGE_NOT_LOCKED;
+
+ /* Caller must hold lock for node->n_lock_list */
+ for (lock = smb_llist_head(&node->n_lock_list);
+ lock != NULL;
+ lock = smb_llist_next(&node->n_lock_list, lock)) {
+
+ if ((start == lock->l_start) &&
+ (length == lock->l_length) &&
+ lock->l_file == sr->fid_ofile &&
+ lock->l_session_kid == sr->session->s_kid &&
+ lock->l_pid == sr->smb_pid &&
+ lock->l_uid == sr->smb_uid) {
+ *nodelock = lock;
+ status = NT_STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ return (status);
+}
+
+
+/*
+ * smb_unlock_range
+ *
+ * locates lock range performed for corresponding to unlock request.
+ *
+ * NT_STATUS_SUCCESS - Lock range performed successfully.
+ * !NT_STATUS_SUCCESS - Error in unlock range operation.
+ */
+uint32_t
+smb_unlock_range(
+ struct smb_request *sr,
+ struct smb_node *node,
+ uint64_t start,
+ uint64_t length)
+{
+ struct smb_lock *lock = 0;
+ uint32_t status;
+
+ /* Apply unlocking rules */
+ smb_llist_enter(&node->n_lock_list, RW_WRITER);
+ status = smb_lock_range_ulckrules(sr, node, start, length, &lock);
+ if (status != NT_STATUS_SUCCESS) {
+ /*
+ * If lock range is not matching in the list
+ * return error.
+ */
+ ASSERT(lock == 0);
+ smb_llist_exit(&node->n_lock_list);
+ return (status);
+ }
+
+ smb_llist_remove(&node->n_lock_list, lock);
+ smb_llist_exit(&node->n_lock_list);
+
+ smb_lock_destroy(lock);
+
+ return (status);
+}
+
+/*
+ * smb_lock_range
+ *
+ * checks for integrity of
+ * file lock operation for the given range of file data.
+ * This is performed by applying lock rules with all
+ * the elements of the node lock list.
+ *
+ * The function returns with new lock added if lock
+ * request is non-conflicting with existing range
+ * lock for the file. Otherwise smb request is filed
+ * without returning.
+ *
+ * NT_STATUS_SUCCESS - Lock range performed successfully.
+ * !NT_STATUS_SUCCESS - Error in lock range operation.
+ */
+uint32_t
+smb_lock_range(
+ struct smb_request *sr,
+ smb_ofile_t *file,
+ uint64_t start,
+ uint64_t length,
+ uint32_t timeout,
+ uint32_t locktype)
+{
+ smb_node_t *node = file->f_node;
+ smb_lock_t *lock;
+ smb_lock_t *clock = 0;
+ uint32_t result = NT_STATUS_SUCCESS;
+
+ lock = smb_lock_create(sr, start, length, locktype, timeout);
+
+ smb_llist_enter(&node->n_lock_list, RW_WRITER);
+ for (;;) {
+ /* Apply locking rules */
+ result = smb_lock_range_lckrules(sr, file, node, lock, &clock);
+
+ if ((result == NT_STATUS_CANCELLED) ||
+ (result == NT_STATUS_SUCCESS) ||
+ (result == NT_STATUS_RANGE_NOT_LOCKED)) {
+ ASSERT(clock == 0);
+ break;
+ } else {
+ ASSERT(result == NT_STATUS_LOCK_NOT_GRANTED);
+ ASSERT(clock);
+ /*
+ * Call smb_lock_wait holding write lock for
+ * node lock list. smb_lock_wait will release
+ * this lock if it blocks.
+ */
+ ASSERT(node == clock->l_file->f_node);
+ if ((timeout == 0) ||
+ ((result = smb_lock_wait(sr, lock, clock)) !=
+ NT_STATUS_SUCCESS)) {
+ break;
+ }
+ clock = 0;
+ }
+ }
+
+ lock->l_blocked_by = NULL;
+
+ if (result != NT_STATUS_SUCCESS) {
+ /*
+ * Under certain conditions NT_STATUS_FILE_LOCK_CONFLICT
+ * should be returned instead of NT_STATUS_LOCK_NOT_GRANTED.
+ */
+ if (result == NT_STATUS_LOCK_NOT_GRANTED) {
+ /*
+ * Locks with timeouts always return
+ * NT_STATUS_FILE_LOCK_CONFLICT
+ */
+ if (timeout != 0) {
+ result = NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ /*
+ * Locks starting higher than 0xef000000 that do not
+ * have the MSB set always return
+ * NT_STATUS_FILE_LOCK_CONFLICT
+ */
+ if ((lock->l_start >= 0xef000000) &&
+ !(lock->l_start & (1ULL << 63))) {
+ result = NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ /*
+ * If the last lock attempt to fail on this file handle
+ * started at the same offset as this one then return
+ * NT_STATUS_FILE_LOCK_CONFLICT
+ */
+ mutex_enter(&file->f_mutex);
+ if ((file->f_flags & SMB_OFLAGS_LLF_POS_VALID) &&
+ (lock->l_start == file->f_llf_pos)) {
+ result = NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+ mutex_exit(&file->f_mutex);
+ }
+
+ /* Update last lock failed offset */
+ mutex_enter(&file->f_mutex);
+ file->f_llf_pos = lock->l_start;
+ file->f_flags |= SMB_OFLAGS_LLF_POS_VALID;
+ mutex_exit(&file->f_mutex);
+
+ smb_lock_free(lock);
+ } else {
+ smb_llist_insert_tail(&node->n_lock_list, lock);
+ }
+ smb_llist_exit(&node->n_lock_list);
+
+ return (result);
+}
+
+
+/*
+ * smb_lock_range_access
+ *
+ * scans node lock list
+ * to check if there is any overlapping lock. Overlapping
+ * lock is allowed only under same session and client pid.
+ *
+ * Return values
+ * NT_STATUS_SUCCESS lock access granted.
+ * NT_STATUS_FILE_LOCK_CONFLICT access denied due to lock conflict.
+ */
+int
+smb_lock_range_access(
+ struct smb_request *sr,
+ struct smb_node *node,
+ uint64_t start,
+ uint64_t length,
+ uint32_t desired_access)
+{
+ smb_lock_t *lock;
+ smb_llist_t *llist;
+ int status = NT_STATUS_SUCCESS;
+
+ ASSERT((desired_access & ~(FILE_READ_DATA | FILE_WRITE_DATA)) == 0);
+ ASSERT((desired_access & (FILE_READ_DATA | FILE_WRITE_DATA)) != 0);
+
+ llist = &node->n_lock_list;
+ smb_llist_enter(llist, RW_READER);
+ /* Search for any applicable lock */
+ for (lock = smb_llist_head(llist);
+ lock != 0;
+ lock = smb_llist_next(llist, lock)) {
+
+ if (!smb_lock_range_overlap(lock, start, length))
+ /* Lock does not overlap */
+ continue;
+
+ if (lock->l_type == SMB_LOCK_TYPE_READONLY &&
+ desired_access == FILE_READ_DATA)
+ continue;
+
+ if (lock->l_type == SMB_LOCK_TYPE_READWRITE &&
+ lock->l_session_kid == sr->session->s_kid &&
+ lock->l_pid == sr->smb_pid)
+ continue;
+
+ status = NT_STATUS_FILE_LOCK_CONFLICT;
+ break;
+ }
+ smb_llist_exit(llist);
+ return (status);
+}
+
+static smb_lock_t *
+smb_lock_create(
+ smb_request_t *sr,
+ uint64_t start,
+ uint64_t length,
+ uint32_t locktype,
+ uint32_t timeout)
+{
+ smb_lock_t *lock;
+
+ ASSERT(locktype == SMB_LOCK_TYPE_READWRITE ||
+ locktype == SMB_LOCK_TYPE_READONLY);
+
+ lock = kmem_zalloc(sizeof (smb_lock_t), KM_SLEEP);
+ lock->l_magic = SMB_LOCK_MAGIC;
+ lock->l_sr = sr; /* Invalid after lock is active */
+ lock->l_session_kid = sr->session->s_kid;
+ lock->l_session = sr->session;
+ lock->l_file = sr->fid_ofile;
+ lock->l_uid = sr->smb_uid;
+ lock->l_pid = sr->smb_pid;
+ lock->l_type = locktype;
+ lock->l_start = start;
+ lock->l_length = length;
+ /*
+ * Calculate the absolute end time so that we can use it
+ * in cv_timedwait.
+ */
+ lock->l_end_time = lbolt + MSEC_TO_TICK(timeout);
+ if (timeout == 0xffffffff) {
+ lock->l_flags |= SMB_LOCK_FLAG_INDEFINITE;
+ }
+ mutex_init(&lock->l_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&lock->l_cv, NULL, CV_DEFAULT, NULL);
+ smb_slist_constructor(&lock->l_conflict_list, sizeof (smb_lock_t),
+ offsetof(smb_lock_t, l_conflict_lnd));
+
+ return (lock);
+}
+
+static void
+smb_lock_free(smb_lock_t *lock)
+{
+ smb_slist_destructor(&lock->l_conflict_list);
+ cv_destroy(&lock->l_cv);
+ mutex_destroy(&lock->l_mutex);
+
+ kmem_free(lock, sizeof (smb_lock_t));
+}
+
+/*
+ * smb_lock_destroy
+ *
+ * Caller must hold node->n_lock_list
+ */
+static void
+smb_lock_destroy(smb_lock_t *lock)
+{
+ /*
+ * Caller must hold node->n_lock_list lock.
+ */
+ mutex_enter(&lock->l_mutex);
+ cv_broadcast(&lock->l_cv);
+ mutex_exit(&lock->l_mutex);
+
+ /*
+ * The cv_broadcast above should wake up any locks that previous
+ * had conflicts with this lock. Wait for the locking threads
+ * to remove their references to this lock.
+ */
+ smb_slist_wait_for_empty(&lock->l_conflict_list);
+
+ smb_lock_free(lock);
+}
+
+void
+smb_node_destroy_lock_by_ofile(smb_node_t *node, smb_ofile_t *file)
+{
+ smb_lock_t *lock;
+ smb_lock_t *nxtl;
+ list_t destroy_list;
+
+ ASSERT(node);
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+ ASSERT(node->n_refcnt);
+
+ /*
+ * Move locks matching the specified file from the node->n_lock_list
+ * to a temporary list (holding the lock the entire time) then
+ * destroy all the matching locks. We can't call smb_lock_destroy
+ * while we are holding the lock for node->n_lock_list because we will
+ * deadlock and we can't drop the lock because the list contents might
+ * change (for example nxtl might get removed on another thread).
+ */
+ list_create(&destroy_list, sizeof (smb_lock_t),
+ offsetof(smb_lock_t, l_lnd));
+
+ smb_llist_enter(&node->n_lock_list, RW_WRITER);
+ lock = smb_llist_head(&node->n_lock_list);
+ while (lock) {
+ nxtl = smb_llist_next(&node->n_lock_list, lock);
+ if (lock->l_file == file) {
+ smb_llist_remove(&node->n_lock_list, lock);
+ list_insert_tail(&destroy_list, lock);
+ }
+ lock = nxtl;
+ }
+ smb_llist_exit(&node->n_lock_list);
+
+ lock = list_head(&destroy_list);
+ while (lock) {
+ nxtl = list_next(&destroy_list, lock);
+ list_remove(&destroy_list, lock);
+ smb_lock_destroy(lock);
+ lock = nxtl;
+ }
+
+ list_destroy(&destroy_list);
+}
+
+void
+smb_lock_range_raise_error(smb_request_t *sr, uint32_t ntstatus)
+{
+ switch (ntstatus) {
+ case NT_STATUS_CANCELLED:
+ /*
+ * XXX What is the proper error here?
+ */
+ smbsr_raise_error(sr, ERRDOS, ERRlock);
+ /* NOTREACHED */
+ case NT_STATUS_FILE_LOCK_CONFLICT:
+ smbsr_raise_cifs_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
+ ERRDOS, ERRlock);
+ /* NOTREACHED */
+ case NT_STATUS_LOCK_NOT_GRANTED:
+ smbsr_raise_cifs_error(sr, NT_STATUS_LOCK_NOT_GRANTED,
+ ERRDOS, ERRlock);
+ /* NOTREACHED */
+ case NT_STATUS_RANGE_NOT_LOCKED:
+ smbsr_raise_cifs_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
+ ERRDOS, ERRlock);
+ /* NOTREACHED */
+ default:
+ ASSERT(0);
+ smbsr_raise_error(sr, ERRDOS, ntstatus);
+ /* NOTREACHED */
+ }
+}
+
+
+void
+smb_unlock_range_raise_error(smb_request_t *sr, uint32_t ntstatus)
+{
+ switch (ntstatus) {
+ case NT_STATUS_RANGE_NOT_LOCKED:
+ smbsr_raise_cifs_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
+ ERRDOS, ERRnotlocked);
+ /* NOTREACHED */
+ default:
+ ASSERT(0);
+ smbsr_raise_error(sr, ERRDOS, ntstatus);
+ /* NOTREACHED */
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
new file mode 100644
index 0000000000..0acf7922c4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
@@ -0,0 +1,378 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: locking_andx
+ *
+ * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 8
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Fid; File handle
+ * UCHAR LockType; See LockType table below
+ * UCHAR OplockLevel; The new oplock level
+ * ULONG Timeout; Milliseconds to wait for unlock
+ * USHORT NumberOfUnlocks; Num. unlock range structs following
+ * USHORT NumberOfLocks; Num. lock range structs following
+ * USHORT ByteCount; Count of data bytes
+ * LOCKING_ANDX_RANGE Unlocks[]; Unlock ranges
+ * LOCKING_ANDX_RANGE Locks[]; Lock ranges
+ *
+ * LockType Flag Name Value Description
+ * ============================ ===== ================================
+ *
+ * LOCKING_ANDX_SHARED_LOCK 0x01 Read-only lock
+ * LOCKING_ANDX_OPLOCK_RELEASE 0x02 Oplock break notification
+ * LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 Change lock type
+ * LOCKING_ANDX_CANCEL_LOCK 0x08 Cancel outstanding request
+ * LOCKING_ANDX_LARGE_FILES 0x10 Large file locking format
+ *
+ * LOCKING_ANDX_RANGE Format
+ * =====================================================================
+ *
+ * USHORT Pid; PID of process "owning" lock
+ * ULONG Offset; Offset to bytes to [un]lock
+ * ULONG Length; Number of bytes to [un]lock
+ *
+ * Large File LOCKING_ANDX_RANGE Format
+ * =====================================================================
+ *
+ * USHORT Pid; PID of process "owning" lock
+ * USHORT Pad; Pad to DWORD align (mbz)
+ * ULONG OffsetHigh; Offset to bytes to [un]lock
+ * (high)
+ * ULONG OffsetLow; Offset to bytes to [un]lock (low)
+ * ULONG LengthHigh; Number of bytes to [un]lock
+ * (high)
+ * ULONG LengthLow; Number of bytes to [un]lock (low)
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Locking is a simple mechanism for excluding other processes read/write
+ * access to regions of a file. The locked regions can be anywhere in the
+ * logical file. Locking beyond end-of-file is permitted. Any process
+ * using the Fid specified in this request's Fid has access to the locked
+ * bytes, other processes will be denied the locking of the same bytes.
+ *
+ * The proper method for using locks is not to rely on being denied read or
+ * write access on any of the read/write protocols but rather to attempt
+ * the locking protocol and proceed with the read/write only if the locks
+ * succeeded.
+ *
+ * Locking a range of bytes will fail if any subranges or overlapping
+ * ranges are locked. In other words, if any of the specified bytes are
+ * already locked, the lock will fail.
+ *
+ * If NumberOfUnlocks is non-zero, the Unlocks vector contains
+ * NumberOfUnlocks elements. Each element requests that a lock at Offset
+ * of Length be released. If NumberOfLocks is nonzero, the Locks vector
+ * contains NumberOfLocks elements. Each element requests the acquisition
+ * of a lock at Offset of Length.
+ *
+ * Timeout is the maximum amount of time to wait for the byte range(s)
+ * specified to become unlocked. A timeout value of 0 indicates that the
+ * server should fail immediately if any lock range specified is locked. A
+ *
+ * timeout value of -1 indicates that the server should wait as long as it
+ * takes for each byte range specified to become unlocked so that it may be
+ * again locked by this protocol. Any other value of smb_timeout specifies
+ * the maximum number of milliseconds to wait for all lock range(s)
+ * specified to become available.
+ *
+ * If any of the lock ranges timeout because of the area to be locked is
+ * already locked (or the lock fails), the other ranges in the protocol
+ * request which were successfully locked as a result of this protocol will
+ * be unlocked (either all requested ranges will be locked when this
+ * protocol returns to the client or none).
+ *
+ * If LockType has the LOCKING_ANDX_SHARED_LOCK flag set, the lock is
+ * specified as a shared lock. Locks for both read and write (where
+ * LOCKING_ANDX_SHARED_LOCK is clear) should be prohibited, but other
+ * shared locks should be permitted. If shared locks can not be supported
+ * by a server, the server should map the lock to a lock for both read and
+ * write. Closing a file with locks still in force causes the locks to be
+ * released in no defined order.
+ *
+ * If LockType has the LOCKING_ANDX_LARGE_FILES flag set and if the
+ * negotiated protocol is NT LM 0.12 or later, then the Locks and Unlocks
+ * vectors are in the Large File LOCKING_ANDX_RANGE format. This allows
+ * specification of 64 bit offsets for very large files.
+ *
+ * If the one and only member of the Locks vector has the
+ * LOCKING_ANDX_CANCEL_LOCK flag set in the LockType field, the client is
+ * requesting the server to cancel a previously requested, but not yet
+ * responded to, lock.
+ *
+ * If LockType has the LOCKING_ANDX_CHANGE_LOCKTYPE flag set, the client is
+ * requesting that the server atomically change the lock type from a shared
+ * lock to an exclusive lock or vice versa. If the server can not do this
+ * in an atomic fashion, the server must reject this request. NT and W95
+ * servers do not support this capability.
+ *
+ * Oplocks are described in the "Opportunistic Locks" section elsewhere in
+ * this document. A client requests an oplock by setting the appropriate
+ * bit in the SMB_COM_OPEN_ANDX request when the file is being opened in a
+ * mode which is not exclusive. The server responds by setting the
+ * appropriate bit in the response SMB indicating whether or not the oplock
+ * was granted. By granting the oplock, the server tells the client the
+ * file is currently only being used by this one client process at the
+ * current time. The client can therefore safely do read ahead and write
+ * behind as well as local caching of file locks knowing that the file will
+ * not be accessed/changed in any way by another process while the oplock
+ * is in effect. The client will be notified when any other process
+ * attempts to open or modify the oplocked file.
+ *
+ * When another user attempts to open or otherwise modify the file which a
+ * client has oplocked, the server delays the second attempt and notifies
+ * the client via an SMB_LOCKING_ANDX SMB asynchronously sent from the
+ * server to the client. This message has the LOCKING_ANDX_OPLOCK_RELEASE
+ * flag set indicating to the client that the oplock is being broken.
+ *
+ * OplockLevel indicates the type of oplock the client now owns. If
+ * OplockLevel is 0, the client possesses no oplocks on the file at all, if
+ * OplockLevel is 1 the client possesses a Level II oplock. The client is
+ * expected to flush any dirty buffers to the server, submit any file locks
+ * and respond to the server with either an SMB_LOCKING_ANDX SMB having the
+ * LOCKING_ANDX_OPLOCK_RELEASE flag set, or with a file close if the file
+ * is no longer in use by the client. If the client sends an
+ * SMB_LOCKING_ANDX SMB with the LOCKING_ANDX_OPLOCK_RELEASE flag set and
+ * NumberOfLocks is zero, the server does not send a response. Since a
+ * close being sent to the server and break oplock notification from the
+ * server could cross on the wire, if the client gets an oplock
+ * notification on a file which it does not have open, that notification
+ * should be ignored.
+ *
+ * Due to timing, the client could get an "oplock broken" notification in a
+ * user's data buffer as a result of this notification crossing on the wire
+ * with a SMB_COM_READ_RAW request. The client must detect this (use
+ * length of msg, "FFSMB", MID of -1 and Command of SMB_COM_LOCKING_ANDX)
+ * and honor the "oplock broken" notification as usual. The server must
+ * also note on receipt of an SMB_COM_READ_RAW request that there is an
+ * outstanding (unanswered) "oplock broken" notification to the client and
+ * return a zero length response denoting failure of the read raw request.
+ * The client should (after responding to the "oplock broken"
+ * notification), use a standard read protocol to redo the read request.
+ * This allows a file to actually contain data matching an "oplock broken"
+ * notification and still be read correctly.
+ *
+ * The entire message sent and received including the optional second
+ * protocol must fit in the negotiated maximum transfer size. The
+ * following are the only valid SMB commands for AndXCommand for
+ * SMB_COM_LOCKING_ANDX:
+ *
+ * SMB_COM_READ SMB_COM_READ_ANDX
+ * SMB_COM_WRITE SMB_COM_WRITE_ANDX
+ * SMB_COM_FLUSH
+ *
+ * 4.2.6.1 Errors
+ *
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRbadfid
+ * ERRDOS/ERRlock
+ * ERRDOS/ERRinvdevice
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_locking_andx(struct smb_request *sr)
+{
+ unsigned short i;
+ unsigned char lock_type; /* See lock_type table above */
+ unsigned char oplock_level; /* The new oplock level */
+ uint32_t timeout; /* Milliseconds to wait for lock */
+ unsigned short unlock_num; /* # unlock range structs */
+ unsigned short lock_num; /* # lock range structs */
+ unsigned short pid; /* Process Id of owner */
+ uint32_t offset32, length32;
+ uint64_t offset64;
+ uint64_t length64;
+ DWORD result;
+ int rc;
+ uint32_t ltype;
+
+ rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type,
+ &oplock_level, &timeout, &unlock_num, &lock_num);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (lock_type & LOCKING_ANDX_SHARED_LOCK)
+ ltype = SMB_LOCK_TYPE_READONLY;
+ else
+ ltype = SMB_LOCK_TYPE_READWRITE;
+
+ pid = sr->smb_pid; /* Save the original pid */
+
+ if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
+ smb_release_oplock(sr->fid_ofile, OPLOCK_RELEASE_LOCK_RELEASED);
+
+ /*
+ * According to the protocol:
+ *
+ * If the client sends an SMB_LOCKING_ANDX request with the
+ * LOCKING_ANDX_OPLOCK_RELEASE flag set
+ * and NumberOfLocks is zero,
+ * the server does not send a response.
+ *
+ * I'm not sure if it's going to break anything if I change
+ * it according to the protocol. So, I leave it unchanged
+ * for now.
+ */
+ if (unlock_num == 0 && lock_num == 0)
+ return (SDRC_NO_REPLY);
+ }
+
+ /*
+ * No support for changing locktype (although we could probably
+ * implement this)
+ */
+ if (lock_type & LOCKING_ANDX_CHANGE_LOCK_TYPE) {
+ smbsr_raise_error(sr, ERRDOS, ERRnoatomiclocks);
+ /* NOT REACHED */
+ }
+
+ /*
+ * No support for cancel lock (smbtorture expects this)
+ */
+ if (lock_type & LOCKING_ANDX_CANCEL_LOCK) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOT REACHED */
+ }
+
+ if (lock_type & LOCKING_ANDX_LARGE_FILES) {
+ /*
+ * negotiated protocol should be NT LM 0.12 or later
+ */
+ if (sr->session->dialect < NT_LM_0_12) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOT REACHED */
+ }
+
+ for (i = 0; i < unlock_num; i++) {
+ rc = smb_decode_mbc(&sr->smb_data, "w2.QQ",
+ &sr->smb_pid, &offset64, &length64);
+ if (rc) {
+ /*
+ * This is the error returned by a W2K system
+ * even when NT Status is negotiated.
+ */
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOT REACHED */
+ }
+
+ result = smb_unlock_range(sr, sr->fid_ofile->f_node,
+ offset64, length64);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_unlock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+ }
+
+ for (i = 0; i < lock_num; i++) {
+ rc = smb_decode_mbc(&sr->smb_data, "w2.QQ",
+ &sr->smb_pid, &offset64, &length64);
+ if (rc) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOT REACHED */
+ }
+
+ result = smb_lock_range(sr, sr->fid_ofile,
+ offset64, length64, timeout, ltype);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_lock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+ }
+ } else {
+ for (i = 0; i < unlock_num; i++) {
+ rc = smb_decode_mbc(&sr->smb_data, "wll", &sr->smb_pid,
+ &offset32, &length32);
+ if (rc) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOT REACHED */
+ }
+
+ result = smb_unlock_range(sr, sr->fid_ofile->f_node,
+ (uint64_t)offset32, (uint64_t)length32);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_unlock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+ }
+
+ for (i = 0; i < lock_num; i++) {
+ rc = smb_decode_mbc(&sr->smb_data, "wll", &sr->smb_pid,
+ &offset32, &length32);
+ if (rc) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOT REACHED */
+ }
+
+ result = smb_lock_range(sr, sr->fid_ofile,
+ (uint64_t)offset32,
+ (uint64_t)length32,
+ timeout, ltype);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_lock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+ }
+ }
+
+ sr->smb_pid = pid;
+ smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, 7, 0);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_logoff_andx.c b/usr/src/uts/common/fs/smbsrv/smb_logoff_andx.c
new file mode 100644
index 0000000000..278916b8fd
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_logoff_andx.c
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_logoff_andx
+ *
+ * This SMB is the inverse of SMB_COM_SESSION_SETUP_ANDX.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The user represented by Uid in the SMB header is logged off. The server
+ * closes all files currently open by this user, and invalidates any
+ * outstanding requests with this Uid.
+ *
+ * SMB_COM_SESSION_SETUP_ANDX is the only valid AndX command for this SMB.
+ *
+ * 4.1.3.1 Errors
+ *
+ * ERRSRV/invnid - TID was invalid
+ * ERRSRV/baduid - UID was invalid
+ */
+int
+smb_com_logoff_andx(struct smb_request *sr)
+{
+ if (sr->uid_user == NULL) {
+ cmn_err(CE_WARN, "SmbLogoffAndX: bad uid");
+ smbsr_raise_error(sr, ERRSRV, ERRbaduid);
+ /* NOTREACHED */
+ }
+
+ smb_user_logoff(sr->uid_user);
+
+ smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, -1, 0);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
new file mode 100644
index 0000000000..21a4b42939
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
@@ -0,0 +1,777 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/errno.h>
+#include <smbsrv/string.h>
+#include <smbsrv/ctype.h>
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+static int smb_match_unknown(char *name, char *pattern);
+static int smb_is_reserved_dos_name(char *name);
+static int smb_match_reserved(char *name, char *rsrv);
+
+/*
+ * smb_match_name
+ *
+ * This function will mangle the "name" field and save the resulted
+ * shortname to the "shortname" field and 8.3 name to "name83" field.
+ * The three fields, "name", "shortname" and "name83" will then be
+ * sent for pattern match with "pattern" field.
+ *
+ * The 0 is returned when the name is a reserved dos name, no match
+ * for the pattern or any type of failure. The 1 is returned when
+ * there is a match.
+ */
+int
+smb_match_name(ino64_t fileid, char *name, char *shortname,
+ char *name83, char *pattern, int ignore_case)
+{
+ int rc = 0;
+ int force;
+
+ /* Leading or trailing dots are disallowed */
+ if (smb_is_reserved_dos_name(name))
+ return (0);
+
+ for (force = 0; (force < 2 && rc == 0); force++) {
+ (void) smb_mangle_name(fileid, name, shortname, name83, force);
+
+ rc = smb_match_ci(pattern, name);
+
+ /* If no match, check for shortname (if any) */
+
+ if (rc == 0 && strchr(pattern, '~'))
+ if (*shortname != 0)
+ rc = smb_match_ci(pattern, shortname);
+
+ /*
+ * Sigh... DOS Shells use short name
+ * interchangeably with long case sensitive
+ * names. So check that too...
+ */
+ if ((rc == 0) && !ignore_case)
+ rc = smb_match83(pattern, name83);
+
+ /*
+ * Still not found and potentially a premangled name...
+ * Check to see if the butt-head programmer is
+ * assuming that we mangle names in the same manner
+ * as NT...
+ */
+ if (rc == 0)
+ rc = smb_match_unknown(name, pattern);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_match_unknown
+ *
+ * I couldn't figure out what the assumptions of this peice of
+ * code about the format of pattern and name are and so how
+ * it's trying to match them. I just cleaned it up a little bit!
+ *
+ * If anybody could figure out what this is doing, please put
+ * comment here and change the function's name!
+ */
+static int
+smb_match_unknown(char *name, char *pattern)
+{
+ int rc;
+ char nc, pc;
+ char *np, *pp;
+
+ rc = 0;
+ if (utf8_isstrupr(pattern) <= 0)
+ return (rc);
+
+ np = name;
+ pp = pattern;
+
+ pc = *pattern;
+ while ((nc = *np++) != 0) {
+ if (nc == ' ')
+ continue;
+
+ nc = mts_toupper(nc);
+ if ((pc = *pp++) != nc)
+ break;
+ }
+
+ if ((pc == '~') &&
+ (pp != (pattern + 1)) &&
+ ((pc = *pp++) != 0)) {
+ while (mts_isdigit(pc))
+ pc = *pp++;
+
+ if (pc == '.') {
+ while ((nc = *np++) != 0) {
+ if (nc == '.')
+ break;
+ }
+
+ while ((nc = *np++) != 0) {
+ nc = mts_toupper(nc);
+ if ((pc = *pp++) != nc)
+ break;
+ }
+ }
+
+ if (pc == 0)
+ rc = 1;
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_match_reserved
+ *
+ * Checks if the given name matches given
+ * DOS reserved name prefix.
+ *
+ * Returns 1 if match, 0 otherwise
+ */
+static int
+smb_match_reserved(char *name, char *rsrv)
+{
+ char ch;
+
+ int len = strlen(rsrv);
+ return (!utf8_strncasecmp(rsrv, name, len) &&
+ ((ch = *(name + len)) == 0 || ch == '.'));
+}
+
+/*
+ * smb_is_reserved_dos_name
+ *
+ * This function checks if the name is a reserved dos name.
+ *
+ * The function returns 1 when the name is a reserved dos name;
+ * otherwise, it returns 0.
+ */
+static int
+smb_is_reserved_dos_name(char *name)
+{
+ char ch;
+
+ /*
+ * Eliminate all names reserved by DOS and Windows.
+ */
+ ch = mts_toupper(*name);
+
+ switch (ch) {
+ case 'A':
+ if (smb_match_reserved(name, "AUX"))
+ return (1);
+ break;
+
+ case 'C':
+ if (smb_match_reserved(name, "CLOCK$") ||
+ smb_match_reserved(name, "COM1") ||
+ smb_match_reserved(name, "COM2") ||
+ smb_match_reserved(name, "COM3") ||
+ smb_match_reserved(name, "COM4") ||
+ smb_match_reserved(name, "CON")) {
+ return (1);
+ }
+
+ break;
+
+ case 'L':
+ if ((utf8_strncasecmp("LPT1", name, 4) == 0) ||
+ (utf8_strncasecmp("LPT2", name, 4) == 0) ||
+ (utf8_strncasecmp("LPT3", name, 4) == 0))
+ return (1);
+ break;
+
+ case 'N':
+ if (smb_match_reserved(name, "NUL"))
+ return (1);
+ break;
+
+ case 'P':
+ if (smb_match_reserved(name, "PRN"))
+ return (1);
+ }
+
+ /*
+ * If the server is configured to support Catia Version 5
+ * deployments, any filename that contains backslash will
+ * have already been translated to the UTF-8 encoding of
+ * Latin Small Letter Y with Diaeresis. Thus, the check
+ * for backslash in the filename is not necessary.
+ */
+#ifdef CATIA_SUPPORT
+ /* XXX Catia support */
+ if ((get_caps() & NFCAPS_CATIA) == 0) {
+ while (*name != 0) {
+ if (*name == '\\')
+ return (1);
+ name++;
+ }
+ }
+#endif /* CATIA_SUPPORT */
+
+ return (0);
+}
+
+/*
+ * Characters we don't allow in DOS file names.
+ * If a filename contains any of these chars, it should
+ * get mangled.
+ *
+ * '.' is also an invalid DOS char but since it's a special
+ * case it doesn't appear in the list.
+ */
+static char *invalid_dos_chars =
+ "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
+ "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+ " \"/\\:|<>*?";
+
+/*
+ * According to MSKB article #142982, Windows deletes invalid chars and
+ * spaces from file name in mangling process; and invalid chars include:
+ * ."/\[]:;=,
+ *
+ * But some of these chars and some other chars (e.g. +) are replaced
+ * with underscore (_). They are introduced here as special chars.
+ */
+static char *special_chars = "[];=,+";
+
+#define isinvalid(c) (strchr(invalid_dos_chars, c) || (c & 0x80))
+
+/*
+ * smb_needs_mangle
+ *
+ * Determines whether the given name needs to get mangled.
+ *
+ * Here are the (known) rules:
+ *
+ * 1st char is dot (.)
+ * name length > 12 chars
+ * # dots > 1
+ * # dots == 0 and length > 8
+ * # dots == 1 and name isn't 8.3
+ * contains illegal chars
+ */
+int
+smb_needs_mangle(char *name, char **dot_pos)
+{
+ int len, ndots;
+ char *namep;
+ char *last_dot;
+
+ /*
+ * Returning (1) for these cases forces consistency with how
+ * these names are treated (smb_mangle_name() will produce an 8.3 name
+ * for these)
+ */
+ if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
+ return (1);
+
+ /* skip the leading dots (if any) */
+ for (namep = name; *namep == '.'; namep++)
+ ;
+
+ len = ndots = 0;
+ last_dot = 0;
+ for (; *namep; namep++) {
+ len++;
+ if (*namep == '.') {
+ /* keep the position of last dot */
+ last_dot = namep;
+ ndots++;
+ }
+ }
+ *dot_pos = last_dot;
+
+ /* Windows mangles names like .a, .abc, or .abcd */
+ if (*name == '.')
+ return (1);
+
+ if (len > 12)
+ return (1);
+
+ switch (ndots) {
+ case 0:
+ /* no dot */
+ if (len > 8)
+ return (1);
+ break;
+
+ case 1:
+ /* just one dot */
+ /*LINTED E_PTR_DIFF_OVERFLOW*/
+ if (((last_dot - name) > 8) || /* name length > 8 */
+ (strlen(last_dot + 1) > 3)) /* extention > 3 */
+ return (1);
+ break;
+
+ default:
+ /* more than one dot */
+ return (1);
+ }
+
+ for (namep = name; *namep; namep++) {
+ if (!mts_isascii(*namep) ||
+ strchr(special_chars, *namep) ||
+ strchr(invalid_dos_chars, *namep))
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_needs_shortname
+ *
+ * Determine whether a shortname should be generated for a file name that is
+ * already in 8.3 format.
+ *
+ * Paramters:
+ * name - original file name
+ *
+ * Return:
+ * 1 - Shortname is required to be generated.
+ * 0 - No shortname needs to be generated.
+ *
+ * Note
+ * =======
+ * Windows NT server: shortname is created only if either
+ * the filename or extension portion of
+ * a file is made up of mixed case.
+ * Windows 2000 server: shortname is not created regardless
+ * of the case.
+ * Windows 2003 server: [Same as Windows NT server.]
+ *
+ * StorEdge will conform to the rule used by Windows NT/2003 server.
+ *
+ * For instance:
+ * File | Create shortname?
+ * ================================
+ * nf.txt | N
+ * NF.TXT | N
+ * NF.txt | N
+ * nf | N
+ * NF | N
+ * nF.txt | Y
+ * nf.TxT | Y
+ * Nf | Y
+ * nF | Y
+ *
+ */
+static int
+smb_needs_shortname(char *name)
+{
+ char buf[9];
+ int len;
+ int create = 0;
+ const char *dot_pos = 0;
+
+ dot_pos = strrchr(name, '.');
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ len = (!dot_pos) ? strlen(name) : (dot_pos - name);
+ /* First, examine the name portion of the file */
+ if (len) {
+ (void) snprintf(buf, len + 1, "%s", name);
+ /* if the name contains both lower and upper cases */
+ if (utf8_isstrupr(buf) == 0 && utf8_isstrlwr(buf) == 0) {
+ /* create shortname */
+ create = 1;
+ } else if (dot_pos) {
+ /* Next, examine the extension portion of the file */
+ (void) snprintf(buf, sizeof (buf), "%s", dot_pos + 1);
+ /*
+ * if the extension contains both lower and upper
+ * cases
+ */
+ if (utf8_isstrupr(buf) == 0 && utf8_isstrlwr(buf) == 0)
+ /* create shortname */
+ create = 1;
+ }
+ }
+
+ return (create);
+}
+
+/*
+ * smb_mangle_char
+ *
+ * If given char is an invalid DOS character or it's not an
+ * ascii char, it should be deleted from mangled and 8.3 name.
+ *
+ * If given char is one of special chars, it should be replaced
+ * with '_'.
+ *
+ * Otherwise just make it upper case.
+ */
+static unsigned char
+smb_mangle_char(unsigned char ch)
+{
+ if (isinvalid(ch))
+ return (0);
+
+ if (strchr(special_chars, ch))
+ return ('_');
+
+ return (mts_toupper(ch));
+}
+
+/*
+ * smb_generate_mangle
+ *
+ * Generates a mangle string which contains
+ * at least 2 (considering fileid cannot be 0)
+ * and at most 7 chars.
+ *
+ * Returns the number of chars in the generated mangle.
+ */
+static int
+smb_generate_mangle(ino64_t fileid, unsigned char *mangle_buf)
+{
+ /*
+ * 36**6 = 2176782336: more than enough to express inodes in 6
+ * chars
+ */
+ static char *base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ unsigned char *manglep = mangle_buf;
+
+ for (*manglep++ = '~'; fileid > 0; fileid /= 36)
+ *manglep++ = base36[fileid % 36];
+ *manglep = 0;
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (manglep - mangle_buf);
+}
+
+/*
+ * smb_maybe_mangled_name
+ *
+ * returns true if the passed name can possibly be a mangled name.
+ * mangled names should be valid dos file names hence less than 12 characters
+ * long and should contain at least one tilde character.
+ *
+ * note that this function can be further enhanced to check for invalid
+ * dos characters/character patterns (such as "file..1.c") but this version
+ * should be sufficient in most cases.
+ */
+int
+smb_maybe_mangled_name(char *name)
+{
+ int i, has_tilde = 0;
+
+ for (i = 0; *name && (i < 12); i++, name++) {
+ if ((*name == '~') && (i < 8))
+ has_tilde = 1;
+
+ if (*name == '.' && has_tilde == 0)
+ return (0);
+ }
+
+ return ((*name == 0) && has_tilde);
+}
+
+/*
+ * smb_mangle_name
+ *
+ * Microsoft knowledge base article #142982 describes how Windows
+ * generates 8.3 filenames from long file names. Some other details
+ * can be found in article #114816.
+ *
+ * The function first checks to see whether the given name needs mangling.
+ * If not, and the force parameter is not set, then no mangling is done,
+ * but both the shortname (if needed) and the 8.3 name are produced and
+ * returned.
+ *
+ * If the "force" parameter is set (as will be the case for case-insensitive
+ * collisions), then the name will be mangled.
+ *
+ * Whenever mangling is needed, both the shortname and the 8.3 names are
+ * produced and returned.
+ *
+ * For example, the xxx.xy in 8.3 format will be "xxx .xy ".
+ */
+
+int smb_mangle_name(
+ ino64_t fileid, /* inode number to generate unique mangle */
+ char *name, /* original file name */
+ char *shortname, /* mangled name (if applicable) */
+ char *name83, /* (mangled) name in 8.3 format */
+ int force) /* force mangling even if mangling is not */
+ /* needed according to standard algorithm */
+{
+ int avail;
+ unsigned char ch;
+ unsigned char mangle_buf[8];
+ unsigned char *namep;
+ unsigned char *manglep;
+ unsigned char *out_short;
+ unsigned char *out_83;
+ char *dot_pos = NULL;
+
+ /*
+ * NOTE:
+ * This function used to consider filename case
+ * in order to mangle. I removed those checks.
+ */
+
+ *shortname = *name83 = 0;
+
+ /* Allow dot and dot dot up front */
+ if (strcmp(name, ".") == 0) {
+ /* no shortname */
+ (void) strcpy(name83, ". . ");
+ return (1);
+ }
+
+ if (strcmp(name, "..") == 0) {
+ /* no shortname */
+ (void) strcpy(name83, ".. . ");
+ return (1);
+ }
+
+ out_short = (unsigned char *)shortname;
+ out_83 = (unsigned char *)name83;
+
+ if ((smb_needs_mangle(name, &dot_pos) == 0) && (force == 0)) {
+ /* no mangle */
+
+ /* check if shortname is required or not */
+ if (smb_needs_shortname(name)) {
+ namep = (unsigned char *)name;
+ while (*namep)
+ *out_short++ = mts_toupper(*namep++);
+ *out_short = '\0';
+ }
+
+ out_83 = (unsigned char *)name83;
+ (void) strcpy((char *)out_83, " . ");
+ while (*name && *name != '.')
+ *out_83++ = mts_toupper(*name++);
+
+ if (*name == '.') {
+ /* copy extension */
+ name++;
+ out_83 = (unsigned char *)name83 + 9;
+ while (*name)
+ *out_83++ = mts_toupper(*name++);
+ }
+ return (1);
+ }
+
+ avail = 8 - smb_generate_mangle(fileid, mangle_buf);
+
+ /*
+ * generated mangle part has always less than 8 chars, so
+ * use the chars before the first dot in filename
+ * and try to generate a full 8 char name.
+ */
+
+ /* skip the leading dots (if any) */
+ for (namep = (unsigned char *)name; *namep == '.'; namep++)
+ ;
+
+ for (; avail && *namep && (*namep != '.'); namep++) {
+ ch = smb_mangle_char(*namep);
+ if (ch == 0)
+ continue;
+ *out_short++ = *out_83++ = ch;
+ avail--;
+ }
+
+ /* Copy in mangled part */
+ manglep = mangle_buf;
+
+ while (*manglep)
+ *out_short++ = *out_83++ = *(manglep++);
+
+ /* Pad any leftover in 8.3 name with spaces */
+ while (avail--)
+ *out_83++ = ' ';
+
+ /* Work on extension now */
+ avail = 3;
+ *out_83++ = '.';
+ if (dot_pos) {
+ namep = (unsigned char *)dot_pos + 1;
+ if (*namep != 0) {
+ *out_short++ = '.';
+ for (; avail && *namep; namep++) {
+ ch = smb_mangle_char(*namep);
+ if (ch == 0)
+ continue;
+
+ *out_short++ = *out_83++ = ch;
+ avail--;
+ }
+ }
+ }
+
+ while (avail--)
+ *out_83++ = ' ';
+
+ *out_short = *out_83 = '\0';
+
+ return (1);
+}
+
+/*
+ * smb_unmangle_name
+ *
+ * Given a mangled name, try to find the real file name as it appears
+ * in the directory entry. If the name does not contain a ~, it is most
+ * likely not a mangled name but the caller can still try to get the
+ * actual on-disk name by setting the "od" parameter.
+ *
+ * Returns 0 if a name has been returned in real_name. There are three
+ * possible scenarios:
+ * 1. Name did not contain a ~ and "od" was not set, in which
+ * case, real_name contains name.
+ * 2. Name did not contain a ~ and "od" was set, in which
+ * case, real_name contains the actual directory entry name.
+ * 3. Name did contain a ~, in which case, name was mangled and
+ * real_name contains the actual directory entry name.
+ *
+ * EINVAL: a parameter was invalid.
+ * ENOENT: an unmangled name could not be found.
+ */
+
+int
+smb_unmangle_name(struct smb_request *sr, cred_t *cred, smb_node_t *dir_node,
+ char *name, char *real_name, int realname_size, char *shortname,
+ char *name83, int od)
+{
+ int err;
+ int len;
+ int force = 0;
+ ino64_t inode;
+ uint32_t cookie;
+ struct smb_node *snode = NULL;
+ smb_attr_t ret_attr;
+ char *dot_pos = NULL;
+ char *readdir_name;
+ char *shortp;
+ char xxx[MANGLE_NAMELEN];
+
+ if (dir_node == NULL || name == NULL || real_name == NULL ||
+ realname_size == 0)
+ return (EINVAL);
+
+ *real_name = '\0';
+ snode = NULL;
+
+ if (smb_maybe_mangled_name(name) == 0) {
+ if (od == 0) {
+ (void) strlcpy(real_name, name, realname_size);
+ return (0);
+ }
+
+ err = smb_fsop_lookup(sr, cred, 0, sr->tid_tree->t_snode,
+ dir_node, name, &snode, &ret_attr, NULL, NULL);
+
+ if (err != 0)
+ return (err);
+
+ (void) strlcpy(real_name, snode->od_name, realname_size);
+ smb_node_release(snode);
+ return (0);
+ }
+
+ if (shortname == 0)
+ shortname = xxx;
+ if (name83 == 0)
+ name83 = xxx;
+
+ cookie = 0;
+
+ readdir_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ snode = NULL;
+ while (cookie != 0x7FFFFFFF) {
+
+ len = realname_size - 1;
+
+ err = smb_fsop_readdir(sr, cred, dir_node, &cookie,
+ readdir_name, &len, &inode, NULL, &snode, &ret_attr);
+
+ if (err || (cookie == 0x7FFFFFFF))
+ break;
+
+ readdir_name[len] = 0;
+
+ /*
+ * smb_fsop_readdir() may return a mangled name if the
+ * name has a case collision.
+ *
+ * If readdir_name is not a mangled name, we mangle
+ * readdir_name to see if it will match the name the
+ * client passed in.
+ *
+ * If smb_needs_mangle() does not succeed, we try again
+ * using the force flag. It is possible that the client
+ * is using a mangled name that resulted from a prior
+ * case collision which no longer exists in the directory.
+ * smb_needs_mangle(), with the force flag, will produce
+ * a mangled name regardless of whether the name passed in
+ * meets standard DOS criteria for name mangling.
+ */
+
+ if (smb_maybe_mangled_name(readdir_name)) {
+ shortp = readdir_name;
+ } else {
+ if (smb_needs_mangle(readdir_name, &dot_pos) == 0)
+ force = 1;
+ (void) smb_mangle_name(inode, readdir_name, shortname,
+ name83, force);
+ shortp = shortname;
+ }
+
+ if (utf8_strcasecmp(name, shortp) == 0) {
+ kmem_free(readdir_name, MAXNAMELEN);
+ (void) strlcpy(real_name, snode->od_name,
+ realname_size);
+
+ smb_node_release(snode);
+
+ return (0);
+ } else {
+ smb_node_release(snode);
+ snode = NULL;
+ }
+ }
+
+ kmem_free(readdir_name, MAXNAMELEN);
+
+ return (ENOENT);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
new file mode 100644
index 0000000000..d97f410e8b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
@@ -0,0 +1,1659 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB mbuf marshaling encode/decode.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+#define MALLOC_QUANTUM 80
+
+#define DECODE_NO_ERROR 0
+#define DECODE_NO_MORE_DATA 1
+#define DECODE_ALLOCATION_ERROR 2
+#define DECODE_CONVERSION_ERROR 3
+
+
+/*
+ * Put data into mbuf chain allocating as needed.
+ * Adds room to end of mbuf chain if needed.
+ */
+
+int
+mbc_marshal_make_room(struct mbuf_chain *mbc, int32_t bytes_needed)
+{
+ struct mbuf *m;
+ struct mbuf *l;
+ int32_t bytes_available;
+
+ bytes_needed += mbc->chain_offset;
+ if (bytes_needed > mbc->max_bytes)
+ return (EMSGSIZE);
+
+ if ((m = mbc->chain) == 0) {
+ MGET(m, M_WAIT, MT_DATA);
+ m->m_len = 0;
+ if (mbc->max_bytes > MLEN)
+ MCLGET(m, M_WAIT);
+ mbc->chain = m;
+ /* xxxx */
+ /* ^ */
+ }
+
+ /* ---- ----- --xx ---xxx */
+ /* ^ */
+
+ l = 0;
+ while ((m != 0) && (bytes_needed >= m->m_len)) {
+ l = m;
+ bytes_needed -= m->m_len;
+ m = m->m_next;
+ }
+
+ if ((bytes_needed == 0) || (m != 0)) {
+ /* We have enough room already */
+ return (0);
+ }
+
+ /* ---- ----- --xx ---xxx */
+ /* ^ */
+ /* Back up to start of last mbuf */
+ m = l;
+ bytes_needed += m->m_len;
+
+ /* ---- ----- --xx ---xxx */
+ /* ^ */
+
+ bytes_available = (m->m_flags & M_EXT) ?
+ m->m_ext.ext_size : MLEN;
+
+ /* ---- ----- --xx ---xxx */
+ /* ^ */
+ while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
+ m->m_len = bytes_available;
+ bytes_needed -= m->m_len;
+ /* ---- ----- --xx ------ */
+ /* ^ */
+
+ MGET(m->m_next, M_WAIT, MT_DATA);
+ m = m->m_next;
+ m->m_len = 0;
+ if (bytes_needed > MLEN)
+ MCLGET(m, M_WAIT);
+
+ bytes_available = (m->m_flags & M_EXT) ?
+ m->m_ext.ext_size : MLEN;
+
+ /* ---- ----- --xx ------ xxxx */
+ /* ^ */
+ }
+
+ /* ---- ----- --xx ------ xxxx */
+ /* ^ */
+ /* Expand last tail as needed */
+ if (m->m_len <= bytes_needed) {
+ m->m_len = bytes_needed;
+ /* ---- ----- --xx ------ --xx */
+ /* ^ */
+ }
+
+ return (0);
+}
+
+
+void
+mbc_marshal_store_byte(struct mbuf_chain *mbc, unsigned char data)
+{
+ struct mbuf *m = mbc->chain;
+ int32_t cur_offset = mbc->chain_offset;
+
+ /*
+ * Scan forward looking for the last data currently in chain.
+ */
+ while (cur_offset >= m->m_len) {
+ cur_offset -= m->m_len;
+ m = m->m_next;
+ }
+ ((char *)m->m_data)[cur_offset] = data;
+ mbc->chain_offset++;
+}
+
+
+int
+mbc_marshal_put_char(struct mbuf_chain *mbc, unsigned char data)
+{
+ if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
+ return (DECODE_NO_MORE_DATA);
+ mbc_marshal_store_byte(mbc, data);
+ return (0);
+}
+
+
+int
+mbc_marshal_put_short(struct mbuf_chain *mbc, unsigned short data)
+{
+ if (mbc_marshal_make_room(mbc, sizeof (short)))
+ return (DECODE_NO_MORE_DATA);
+ mbc_marshal_store_byte(mbc, data);
+ mbc_marshal_store_byte(mbc, data >> 8);
+ return (0);
+}
+
+
+int
+mbc_marshal_put_long(struct mbuf_chain *mbc, uint32_t data)
+{
+ if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
+ return (DECODE_NO_MORE_DATA);
+ mbc_marshal_store_byte(mbc, data);
+ mbc_marshal_store_byte(mbc, data >> 8);
+ mbc_marshal_store_byte(mbc, data >> 16);
+ mbc_marshal_store_byte(mbc, data >> 24);
+ return (0);
+}
+
+
+int
+mbc_marshal_put_long_long(struct mbuf_chain *mbc, uint64_t data)
+{
+ if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
+ return (DECODE_NO_MORE_DATA);
+
+ mbc_marshal_store_byte(mbc, data);
+ mbc_marshal_store_byte(mbc, data >> 8);
+ mbc_marshal_store_byte(mbc, data >> 16);
+ mbc_marshal_store_byte(mbc, data >> 24);
+ mbc_marshal_store_byte(mbc, data >> 32);
+ mbc_marshal_store_byte(mbc, data >> 40);
+ mbc_marshal_store_byte(mbc, data >> 48);
+ mbc_marshal_store_byte(mbc, data >> 56);
+ return (0);
+}
+
+
+/*
+ * When need to convert from UTF-8 (internal format) to a single
+ * byte string (external format ) when marshalling a string.
+ */
+int
+mbc_marshal_put_ascii_string(struct mbuf_chain *mbc, char *mbs, int repc)
+{
+ mts_wchar_t wide_char;
+ int nbytes;
+ int length;
+
+ if ((length = mts_sbequiv_strlen(mbs)) == -1)
+ return (DECODE_NO_MORE_DATA);
+
+ length += sizeof (char);
+
+ if ((repc > 1) && (repc < length))
+ length = repc;
+ if (mbc_marshal_make_room(mbc, length))
+ return (DECODE_NO_MORE_DATA);
+
+ while (*mbs) {
+ /*
+ * We should restore oem chars here.
+ */
+ nbytes = mts_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
+ if (nbytes == -1)
+ return (DECODE_NO_MORE_DATA);
+
+ mbc_marshal_store_byte(mbc, (unsigned char)wide_char);
+
+ if (wide_char & 0xFF00)
+ mbc_marshal_store_byte(mbc, wide_char >> 8);
+
+ mbs += nbytes;
+ }
+
+ mbc_marshal_store_byte(mbc, 0);
+ return (0);
+}
+
+
+int
+mbc_marshal_put_alignment(struct mbuf_chain *mbc, unsigned int align)
+{
+ int32_t delta = mbc->chain_offset % align;
+
+ if (delta != 0) {
+ align -= delta;
+ if (mbc_marshal_make_room(mbc, align))
+ return (DECODE_NO_MORE_DATA);
+ while (align-- > 0)
+ mbc_marshal_store_byte(mbc, 0);
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_put_unicode_string(struct mbuf_chain *mbc, char *ascii, int repc)
+{
+ mts_wchar_t wchar;
+ int consumed;
+ int length;
+
+ if ((length = mts_wcequiv_strlen(ascii)) == -1)
+ return (DECODE_NO_MORE_DATA);
+
+ length += sizeof (mts_wchar_t);
+
+#if 0
+ if (mbc_marshal_put_alignment(mbc, sizeof (mts_wchar_t)) != 0)
+ return (DECODE_NO_MORE_DATA);
+#endif
+ if ((repc > 1) && (repc < length))
+ length = repc;
+
+ if (mbc_marshal_make_room(mbc, length))
+ return (DECODE_NO_MORE_DATA);
+ while (length > 0) {
+ consumed = mts_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
+ if (consumed == -1)
+ break; /* Invalid sequence */
+ /*
+ * Note that consumed will be 0 when the null terminator
+ * is encountered and ascii will not be advanced beyond
+ * that point. Length will continue to be decremented so
+ * we won't get stuck here.
+ */
+ ascii += consumed;
+ mbc_marshal_store_byte(mbc, wchar);
+ mbc_marshal_store_byte(mbc, wchar >> 8);
+ length -= sizeof (mts_wchar_t);
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_put_uio(struct mbuf_chain *mbc, struct uio *uio)
+{
+ struct mbuf **t;
+ struct mbuf *m = 0;
+ struct iovec *iov = uio->uio_iov;
+ int32_t i, iov_cnt = uio->uio_iovcnt;
+
+ iov = uio->uio_iov;
+ t = &mbc->chain;
+ for (i = 0; i < iov_cnt; i++) {
+ MGET(m, M_WAIT, MT_DATA);
+ m->m_ext.ext_buf = iov->iov_base;
+ m->m_ext.ext_ref = smb_noop;
+ m->m_data = m->m_ext.ext_buf;
+ m->m_flags |= M_EXT;
+ m->m_len = m->m_ext.ext_size = iov->iov_len;
+ mbc->max_bytes += m->m_len;
+ m->m_next = 0;
+ *t = m;
+ t = &m->m_next;
+ iov++;
+ }
+ return (0);
+}
+
+int
+mbc_marshal_put_mbufs(struct mbuf_chain *mbc, struct mbuf *m)
+{
+ struct mbuf *mt;
+ struct mbuf **t;
+ int bytes;
+
+ if (m != 0) {
+ mt = m;
+ bytes = mt->m_len;
+ while (mt->m_next != 0) {
+ mt = mt->m_next;
+ bytes += mt->m_len;
+ }
+ if (bytes != 0) {
+ t = &mbc->chain;
+ while (*t != 0) {
+ bytes += (*t)->m_len;
+ t = &(*t)->m_next;
+ }
+ *t = m;
+ mbc->chain_offset = bytes;
+ } else {
+ m_freem(m);
+ }
+ }
+ return (0);
+}
+
+int
+mbc_marshal_put_mbuf_chain(struct mbuf_chain *mbc, struct mbuf_chain *nmbc)
+{
+ if (nmbc->chain != 0) {
+ if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
+ return (DECODE_NO_MORE_DATA);
+ MBC_SETUP(nmbc, nmbc->max_bytes);
+ }
+ return (0);
+}
+
+int
+mbc_marshal_put_SID(struct mbuf_chain *mbc, nt_sid_t *pSid)
+{
+ int i;
+
+ if (mbc_marshal_put_char(mbc, pSid->Revision) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ if (mbc_marshal_put_char(mbc, pSid->SubAuthCount) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ for (i = 0; i < 6; i++) {
+ if (mbc_marshal_put_char(mbc,
+ pSid->Authority[i]) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ }
+
+ for (i = 0; i < pSid->SubAuthCount; i++) {
+ if (mbc_marshal_put_long(mbc, pSid->SubAuthority[i]) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_put_skip(struct mbuf_chain *mbc, unsigned int skip)
+{
+ if (mbc_marshal_make_room(mbc, skip))
+ return (DECODE_NO_MORE_DATA);
+ while (skip-- > 0)
+ mbc_marshal_store_byte(mbc, 0);
+ return (0);
+}
+
+unsigned char
+mbc_marshal_fetch_byte(struct mbuf_chain *mbc)
+{
+ unsigned char data;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ data = ((unsigned char *)m->m_data)[offset];
+ mbc->chain_offset++;
+ return (data);
+}
+
+
+int
+mbc_marshal_get_char(struct mbuf_chain *mbc, unsigned char *data)
+{
+ if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ *data = mbc_marshal_fetch_byte(mbc);
+ return (0);
+}
+
+
+int
+mbc_marshal_get_short(struct mbuf_chain *mbc, unsigned short *data)
+{
+ unsigned short tmp;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ if ((m->m_len - offset) >= sizeof (short)) {
+ *data = LE_IN16(m->m_data + offset);
+ mbc->chain_offset += sizeof (short);
+ } else {
+ tmp = (unsigned short)mbc_marshal_fetch_byte(mbc);
+ tmp |= ((unsigned short)mbc_marshal_fetch_byte(mbc)) << 8;
+ *data = tmp;
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_get_long(struct mbuf_chain *mbc, uint32_t *data)
+{
+ uint32_t tmp;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ if ((m->m_len - offset) >= sizeof (int32_t)) {
+ *data = LE_IN32(m->m_data + offset);
+ mbc->chain_offset += sizeof (int32_t);
+ } else {
+ tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
+ tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
+ tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
+ tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
+ *data = tmp;
+ }
+ return (0);
+}
+
+uint64_t
+qswap(uint64_t ll)
+{
+ uint64_t v;
+
+ v = ll >> 32;
+ v |= ll << 32;
+
+ return (v);
+}
+
+int
+mbc_marshal_get_odd_long_long(struct mbuf_chain *mbc, uint64_t *data)
+{
+ uint64_t tmp;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+
+ if ((m->m_len - offset) >= sizeof (int64_t)) {
+ *data = qswap(LE_IN64(m->m_data + offset));
+ mbc->chain_offset += sizeof (int64_t);
+ } else {
+ tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
+
+ *(uint64_t *)data = tmp;
+ }
+ return (0);
+}
+
+int
+mbc_marshal_get_long_long(struct mbuf_chain *mbc, uint64_t *data)
+{
+ uint64_t tmp;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ if ((m->m_len - offset) >= sizeof (int64_t)) {
+ *data = LE_IN64(m->m_data + offset);
+ mbc->chain_offset += sizeof (int64_t);
+ } else {
+ tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
+ *(uint64_t *)data = tmp;
+ }
+ return (0);
+}
+
+/*
+ * mbc_marshal_get_ascii_string
+ *
+ * The ascii string in smb includes oem chars. Since the
+ * system needs utf8 encodes unicode char, conversion is
+ * required to convert the oem char to unicode and then
+ * to encode the converted wchars to utf8 format.
+ * Therefore, the **ascii returned will be in such format
+ * instead of the real ASCII format.
+ */
+static int
+mbc_marshal_get_ascii_string(
+ struct smb_malloc_list *ml,
+ struct mbuf_chain *mbc,
+ unsigned char **ascii,
+ int max_ascii)
+{
+ char *rcvbuf;
+ char *ch;
+ mts_wchar_t *wtmpbuf;
+ int max;
+ int length = 0;
+ unsigned int cpid = oem_get_smb_cpid();
+
+ max = MALLOC_QUANTUM;
+ rcvbuf = smbsr_malloc(ml, max);
+
+ if (max_ascii == 0)
+ max_ascii = 0xffff;
+
+ ch = rcvbuf;
+ for (;;) {
+ while (length < max) {
+ if (max_ascii-- <= 0) {
+ *ch++ = 0;
+ goto multibyte_encode;
+ }
+ if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
+ goto multibyte_encode;
+ length++;
+ }
+ max += MALLOC_QUANTUM;
+ rcvbuf = smbsr_realloc(rcvbuf, max);
+ ch = rcvbuf + length;
+ }
+
+multibyte_encode:
+ /*
+ * UTF-8 encode the string for internal system use.
+ */
+ length = strlen(rcvbuf) + 1;
+ wtmpbuf = smbsr_malloc(ml, length*sizeof (mts_wchar_t));
+ *ascii = smbsr_malloc(ml, length * MTS_MB_CHAR_MAX);
+
+ if (oemstounicodes(wtmpbuf, rcvbuf, length, cpid) > 0)
+ (void) mts_wcstombs((char *)*ascii, wtmpbuf,
+ length * MTS_MB_CHAR_MAX);
+ else
+ (void) mts_stombs((char *)*ascii, rcvbuf, length * 2);
+ return (0);
+}
+
+
+int
+mbc_marshal_get_unicode_string(struct smb_malloc_list *ml,
+ struct mbuf_chain *mbc, unsigned char **ascii, int max_unicode)
+{
+ int max;
+ unsigned short wchar;
+ char *ch;
+ int emitted;
+ int length = 0;
+
+ if (max_unicode == 0)
+ max_unicode = 0xffff;
+
+ max = MALLOC_QUANTUM;
+ *ascii = smbsr_malloc(ml, max);
+
+ ch = (char *)*ascii;
+ for (;;) {
+ while ((length + MTS_MB_CHAR_MAX) < max) {
+ if (max_unicode <= 0)
+ goto done;
+ max_unicode -= 2;
+
+ if (mbc_marshal_get_short(mbc, &wchar) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ if (wchar == 0) goto done;
+
+ emitted = mts_wctomb(ch, wchar);
+ length += emitted;
+ ch += emitted;
+ }
+ max += MALLOC_QUANTUM;
+ *ascii = smbsr_realloc(*ascii, max);
+ ch = (char *)*ascii + length;
+ }
+done: *ch = 0;
+ return (0);
+}
+
+
+int /*ARGSUSED*/
+mbc_marshal_get_mbufs(struct mbuf_chain *mbc, int32_t bytes, struct mbuf **m)
+{
+ if (MBC_ROOM_FOR(mbc, bytes) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ return (0);
+}
+
+int
+mbc_marshal_get_mbuf_chain(struct mbuf_chain *mbc,
+ int32_t bytes, struct mbuf_chain *nmbc)
+{
+ int rc;
+ struct mbuf *m;
+
+ if (bytes == 0) {
+ /* Get all the rest */
+ bytes = mbc->max_bytes - mbc->chain_offset;
+ }
+
+ MBC_SETUP(nmbc, mbc->max_bytes);
+ if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
+ if (m)
+ m_freem(m);
+ return (rc);
+ }
+ nmbc->chain = m;
+ while (m != 0) {
+ bytes += m->m_len;
+ m = m->m_next;
+ }
+ nmbc->max_bytes = bytes;
+ return (0);
+}
+
+
+int
+mbc_marshal_get_uio(struct mbuf_chain *mbc, struct uio *uio)
+{
+ int i, offset;
+ int32_t bytes = uio->uio_resid;
+ int32_t remainder;
+ struct iovec *iov;
+ struct mbuf *m;
+
+ /*
+ * The residual count is tested because in the case of write requests
+ * with no data (smbtorture RAW-WRITE test will generate that type of
+ * request) this function is called with a residual count of zero
+ * bytes.
+ */
+ if (bytes) {
+ iov = uio->uio_iov;
+ uio->uio_segflg = UIO_SYSSPACE;
+
+ if (MBC_ROOM_FOR(mbc, bytes) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+
+ m = mbc->chain;
+ offset = mbc->chain_offset;
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ ASSERT((offset == 0) || (offset && m));
+ }
+
+ for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
+ iov[i].iov_base = &m->m_data[offset];
+ remainder = m->m_len - offset;
+ if (remainder >= bytes) {
+ iov[i].iov_len = bytes;
+ mbc->chain_offset += bytes;
+ break;
+ }
+ iov[i].iov_len = remainder;
+ mbc->chain_offset += remainder;
+ bytes -= remainder;
+ m = m->m_next;
+ offset = 0;
+ }
+ if (i == uio->uio_iovcnt) {
+ return (DECODE_NO_MORE_DATA);
+ }
+ uio->uio_iovcnt = i;
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_get_SID(struct mbuf_chain *mbc, nt_sid_t *pSid)
+{
+ int i;
+
+ if (mbc_marshal_get_char(mbc, &pSid->Revision) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ if (mbc_marshal_get_char(mbc, &pSid->SubAuthCount) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ for (i = 0; i < 6; i++) {
+ if (mbc_marshal_get_char(mbc,
+ &pSid->Authority[i]) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+
+ for (i = 0; i < pSid->SubAuthCount; i++) {
+ if (mbc_marshal_get_long(mbc, &pSid->SubAuthority[i]) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ return (0);
+}
+
+int
+mbc_marshal_get_skip(struct mbuf_chain *mbc, unsigned int skip)
+{
+ if (MBC_ROOM_FOR(mbc, skip) == 0)
+ return (DECODE_NO_MORE_DATA);
+ mbc->chain_offset += skip;
+ return (0);
+}
+
+int
+mbc_marshal_get_alignment(struct mbuf_chain *mbc, unsigned int align)
+{
+ int32_t delta = mbc->chain_offset % align;
+
+ if (delta != 0) {
+ align -= delta;
+ return (mbc_marshal_get_skip(mbc, delta));
+ }
+ return (0);
+}
+
+/*
+ * The mbuf chain passed in contains the data to be decoded.
+ *
+ * The format string provides a description of the parameters passed in as well
+ * as an action to be taken by smb_mbc_decode().
+ *
+ * \b Restore the mbuf chain offset to its initial value.
+ *
+ * % Pointer to an SMB request structure (smb_request_t *). There
+ * should be only one of these in the string.
+ *
+ * C Pointer to an mbuf chain. Copy to that mbuf chain the number of
+ * bytes specified (number preceding C).
+ *
+ * m Pointer to an mbuf. Copy to that mbuf the number of bytes
+ * specified (number preceding m).
+ *
+ * M Read the 32 bit value at the current location of the mbuf chain
+ * and check if it matches the signature of an SMB request (SMBX).
+ *
+ * b Pointer to a buffer. Copy to that buffer the number of bytes
+ * specified (number preceding b).
+ *
+ * c Same as 'b'.
+ *
+ * w Pointer to a word (16bit value). Copy the next 16bit value into
+ * that location.
+ *
+ * l Pointer to a long (32bit value). Copy the next 32bit value into
+ * that location.
+ *
+ * q Pointer to a quad (64bit value). Copy the next 64bit value into
+ * that location.
+ *
+ * Q Same as above with a call to qswap().
+ *
+ * B Pointer to a vardata_block structure. That structure is used to
+ * retrieve data from the mbuf chain (an iovec type structure is
+ * embedded in a vardata_block).
+ *
+ * D Pointer to a vardata_block structure. That structure is used to
+ * retrieve data from the mbuf chain, however, two fields of the
+ * vardata_block structure (tag and len) are first initialized
+ * using the mbuf chain itself.
+ *
+ * V Same as 'D'.
+ *
+ * L
+ *
+ * A
+ *
+ * P Same as 'A'
+ *
+ * S Same as 'A'
+ *
+ * u Pointer to a string pointer. Allocate memory and retrieve the
+ * string at the current location in the mbuf chain. Store the
+ * address to the buffer allocated at the address specified by
+ * the pointer. In addition if an sr was passed and it indicates
+ * that the string is an unicode string, convert it.
+ *
+ * s Same as 'u' without convertion.
+ *
+ * U Same as 'u'. The string to retrieve is unicode.
+ *
+ * R Not used anymore.
+ *
+ * y Pointer to a 32bit value. Read the dos time at the current mbuf
+ * chain location, convert it to unix time and store it at the
+ * location indicated by the pointer.
+ *
+ * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted.
+ *
+ * . Skip the number of bytes indicated by the number preceding '.'.
+ *
+ * , Same as '.' but take in account it is an unicode string.
+ *
+ * The parameters can be named in the format string. They have to appear between
+ * parenthesis (indicating they should be ignored bu the decoder).
+ */
+int
+smb_mbc_decode(struct mbuf_chain *mbc, char *fmt, va_list ap)
+{
+ unsigned char c, cval;
+ unsigned char *cvalp;
+ unsigned char **cvalpp;
+ unsigned short *wvalp;
+ unsigned int *ivalp;
+ uint32_t *lvalp;
+ uint64_t *llvalp;
+ struct vardata_block *vdp;
+ unsigned char name[32];
+ struct smb_request *sr = NULL;
+ uint32_t lval;
+ int unicode = 0;
+ int repc;
+ /*LINTED E_FUNC_SET_NOT_USED*/
+ enum {EVEN, UNALIGNED, ODD} alignment;
+ int32_t saved_chain_offset = mbc->chain_offset;
+
+ name[0] = 0;
+ while ((c = *fmt++) != 0) {
+ repc = 1;
+ alignment = EVEN;
+
+ if (c == ' ' || c == '\t') continue;
+ if (c == '(') {
+ char *nm = (char *)name;
+
+ while (((c = *fmt++) != 0) && c != ')') {
+ *nm++ = c;
+ }
+ *nm = 0;
+ if (!c) fmt--;
+ continue;
+ }
+
+ if (c == '{') {
+ unsigned char op[8];
+ char *nm = (char *)op;
+
+ while (((c = *fmt++) != 0) && c != '}') {
+ *nm++ = c;
+ }
+ *nm = 0;
+ if (!c) fmt--;
+ if (strcmp((char *)op, "SID") == 0) {
+ nt_sid_t *sidp;
+
+ sidp = va_arg(ap, nt_sid_t *);
+ (void) mbc_marshal_get_SID(mbc, sidp);
+ }
+ continue;
+ }
+
+ if ('0' <= c && c <= '9') {
+ repc = 0;
+ do {
+ repc = repc * 10 + c - '0';
+ c = *fmt++;
+ } while ('0' <= c && c <= '9');
+ } else if (c == '*') {
+ ivalp = va_arg(ap, unsigned int *);
+ repc = *(ivalp++);
+ c = *fmt++;
+ } else if (c == '!') {
+ alignment = ODD;
+ c = *fmt++;
+ } else if (c == '^') {
+ alignment = UNALIGNED;
+ c = *fmt++;
+ } else if (c == '#') {
+ repc = va_arg(ap, int);
+ c = *fmt++;
+ }
+
+ switch (c) {
+ default:
+ goto format_mismatch;
+
+ case '\b':
+ mbc->chain_offset = saved_chain_offset;
+ break;
+
+ case '%':
+ sr = va_arg(ap, struct smb_request *);
+ unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
+ break;
+
+ case 'C': /* Mbuf_chain */
+ if (mbc_marshal_get_mbuf_chain(mbc, repc,
+ va_arg(ap, struct mbuf_chain *)) != 0)
+ goto underflow;
+ break;
+
+ case 'm': /* struct_mbuf */
+ if (mbc_marshal_get_mbufs(mbc, repc,
+ va_arg(ap, struct mbuf **)) != 0)
+ goto underflow;
+ break;
+
+ case 'M':
+ if (mbc_marshal_get_long(mbc, &lval) != 0) {
+ /* Data will never be available */
+ goto underflow;
+ }
+ if (lval != 0x424D53FF) /* 0xFF S M B */
+ goto underflow;
+ break;
+
+ case 'b':
+ case 'c':
+ cvalp = va_arg(ap, unsigned char *);
+ if (MBC_ROOM_FOR(mbc, repc) == 0) {
+ /* Data will never be available */
+ goto underflow;
+ }
+ while (repc-- > 0)
+ *cvalp++ = mbc_marshal_fetch_byte(mbc);
+ break;
+
+ case 'w':
+ wvalp = va_arg(ap, unsigned short *);
+ while (repc-- > 0)
+ if (mbc_marshal_get_short(mbc, wvalp++) != 0)
+ goto underflow;
+ break;
+
+ case 'l':
+ lvalp = va_arg(ap, uint32_t *);
+ while (repc-- > 0)
+ if (mbc_marshal_get_long(mbc, lvalp++) != 0)
+ goto underflow;
+ break;
+
+ case 'q':
+ llvalp = va_arg(ap, uint64_t *);
+ while (repc-- > 0)
+ if (mbc_marshal_get_long_long(
+ mbc, llvalp++) != 0)
+ goto underflow;
+ break;
+
+ case 'Q':
+ llvalp = va_arg(ap, uint64_t *);
+ while (repc-- > 0)
+ if (mbc_marshal_get_odd_long_long(
+ mbc, llvalp++) != 0)
+ goto underflow;
+ break;
+
+ case 'B':
+ vdp = va_arg(ap, struct vardata_block *);
+ vdp->tag = 0;
+
+ /*LINTED E_ASSIGN_NARROW_CONV (BYTE)*/
+ vdp->len = repc;
+ vdp->uio.uio_iov = &vdp->iovec[0];
+ vdp->uio.uio_iovcnt = MAX_IOVEC;
+ vdp->uio.uio_resid = repc;
+ if (mbc_marshal_get_uio(mbc, &vdp->uio) != 0)
+ goto underflow;
+ break;
+
+ case 'D': case 'V':
+ vdp = va_arg(ap, struct vardata_block *);
+ if (mbc_marshal_get_char(mbc, &vdp->tag) != 0)
+ goto underflow;
+ if (mbc_marshal_get_short(mbc, &vdp->len) != 0)
+ goto underflow;
+ vdp->uio.uio_iov = &vdp->iovec[0];
+ vdp->uio.uio_iovcnt = MAX_IOVEC;
+ vdp->uio.uio_resid = vdp->len;
+ if (vdp->len != 0) {
+ if (mbc_marshal_get_uio(mbc, &vdp->uio) != 0)
+ goto underflow;
+ }
+ break;
+
+ case 'L':
+ if (mbc_marshal_get_char(mbc, &cval) != 0)
+ goto underflow;
+ if (cval != 2)
+ goto format_mismatch;
+ goto ascii_conversion;
+
+ case 'A': case 'P': case 'S':
+ if (mbc_marshal_get_char(mbc, &cval) != 0)
+ goto underflow;
+ if (((c == 'A' || c == 'S') && cval != 4) ||
+ (c == 'L' && cval != 2) || (c == 'P' && cval != 3))
+ goto format_mismatch;
+ /* FALLTHROUGH */
+
+ case 'u': /* Convert from unicode if flags are set */
+ if (unicode)
+ goto unicode_translation;
+ /* FALLTHROUGH */
+
+ case 's':
+ascii_conversion:
+ ASSERT(sr != NULL);
+ cvalpp = va_arg(ap, unsigned char **);
+ if (repc <= 1)
+ repc = 0;
+ if (mbc_marshal_get_ascii_string(&sr->request_storage,
+ mbc, cvalpp, repc) != 0)
+ goto underflow;
+ break;
+
+ case 'U': /* Convert from unicode */
+unicode_translation:
+ ASSERT(sr != 0);
+ cvalpp = va_arg(ap, unsigned char **);
+ if (repc <= 1)
+ repc = 0;
+ if (mbc->chain_offset & 1)
+ mbc->chain_offset++;
+ if (mbc_marshal_get_unicode_string(&sr->request_storage,
+ mbc, cvalpp, repc) != 0)
+ goto underflow;
+ break;
+
+ case 'R':
+ /*
+ * This was used to decode RPC format unicode strings
+ * prior to having a DCE RPC support. It is no longer
+ * required.
+ */
+ ASSERT(0);
+ break;
+
+ case 'Y': /* dos time to unix time tt/dd */
+ lvalp = va_arg(ap, uint32_t *);
+ while (repc-- > 0) {
+ short d, t;
+
+ if (mbc_marshal_get_short(mbc,
+ (unsigned short *)&t) != 0)
+ goto underflow;
+ if (mbc_marshal_get_short(mbc,
+ (unsigned short *)&d) != 0)
+ goto underflow;
+ *lvalp++ = dosfs_dos_to_ux_time(d, t);
+ }
+ break;
+
+ case 'y': /* dos time to unix time dd/tt */
+ lvalp = va_arg(ap, uint32_t *);
+ while (repc-- > 0) {
+ short d, t;
+
+ if (mbc_marshal_get_short(mbc,
+ (unsigned short *)&d) != 0)
+ goto underflow;
+ if (mbc_marshal_get_short(mbc,
+ (unsigned short *)&t) != 0)
+ goto underflow;
+ *lvalp++ = dosfs_dos_to_ux_time(d, t);
+ }
+ break;
+
+ case ',':
+ if (unicode)
+ repc *= 2;
+ /* FALLTHROUGH */
+
+ case '.':
+ if (mbc_marshal_get_skip(mbc, repc) != 0)
+ goto underflow;
+ break;
+ }
+ }
+ return (0);
+
+
+format_mismatch:
+ return (-1);
+
+underflow:
+ return (-1);
+}
+
+
+int
+smb_decode_mbc(struct mbuf_chain *mbc, char *fmt, ...)
+{
+ int xx;
+ va_list ap;
+
+ va_start(ap, fmt);
+ xx = smb_mbc_decode(mbc, fmt, ap);
+ va_end(ap);
+ return (xx);
+}
+
+
+int
+smb_decode_buf(unsigned char *buf, int n_buf, char *fmt, ...)
+{
+ int rc;
+ struct mbuf_chain mbc;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ MBC_ATTACH_BUF(&mbc, buf, n_buf);
+ rc = smb_mbc_decode(&mbc, fmt, ap);
+ m_freem(mbc.chain);
+ va_end(ap);
+ return (rc);
+}
+
+/*
+ * The mbuf chain passed in will receive the encoded data.
+ *
+ * The format string provides a description of the parameters passed in as well
+ * as an action to be taken by smb_mbc_encode().
+ *
+ * \b Restore the mbuf chain offset to its initial value.
+ *
+ * % Pointer to an SMB request structure (smb_request_t *). There
+ * should be only one of these in the string. If an sr in present
+ * it will be used to determine if unicode conversion should be
+ * applied to the strings.
+ *
+ * C Pointer to an mbuf chain. Copy that mbuf chain into the
+ * destination mbuf chain.
+ *
+ * D Pointer to a vardata_block structure. Copy the data described
+ * by that structure into the mbuf chain. The tag field is hard
+ * coded to '1'.
+ *
+ * M Write the SMB request signature ('SMBX') into the mbuf chain.
+ *
+ * T Pointer to a timestruc_t. Convert the content of the structure
+ * into NT time and store the result of the conversion in the
+ * mbuf chain.
+ *
+ * V Same as 'D' but the tag field is hard coded to '5'.
+ *
+ * b Byte. Store the byte or the nymber of bytes specified into the
+ * the mbuf chain. A format string like this "2b" would require 2
+ * bytes to be passed in.
+ *
+ * m Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
+ * chain.
+ *
+ * c Pointer to a buffer. Copy the buffer into the mbuf chain. The
+ * size of the buffer is indicated by the number preceding 'c'.
+ *
+ * w Word (16bit value). Store the word or the number of words
+ * specified into the the mbuf chain. A format string like this
+ * "2w" would require 2 words to be passed in.
+ *
+ * l Long (32bit value). Store the long or the number of longs
+ * specified into the the mbuf chain. A format string like this
+ * "2l" would require 2 longs to be passed in.
+ *
+ * q Quad (64bit value). Store the quad or the number of quads
+ * specified into the the mbuf chain. A format string like this
+ * "2q" would require 2 quads to be passed in.
+ *
+ * L Pointer to a string. Store the string passed in into the mbuf
+ * chain preceded with a tag value of '2'.
+ *
+ * S Pointer to a string. Store the string passed in into the mbuf
+ * chain preceded with a tag value of '4'. Applied a unicode
+ * conversion is appropriate.
+ *
+ * A Same as 'S'
+ *
+ * P Pointer to a string. Store the string passed in into the mbuf
+ * chain preceded with a tag value of '5'. Applied a unicode
+ * conversion is appropriate.
+ *
+ * u Pointer to a string. Store the string passed in into the mbuf
+ * chain. Applied a unicode conversion is appropriate.
+ *
+ * s Pointer to a string. Store the string passed in into the mbuf
+ * chain.
+ *
+ * Y Date/Time. Store the Date/Time or the number of Date/Time(s)
+ * specified into the the mbuf chain. A format string like this
+ * "2Y" would require 2 Date/Time values. The Date/Time is
+ * converted to DOS before storing.
+ *
+ * y Same as 'Y'. The order of Date and Time is reversed.
+ *
+ * , Character. Store the character or number of character specified
+ * into the mbuf chain. A format string like this "2c" would
+ * require 2 characters to be passed in. A unicode conversion is
+ * applied if appropriate.
+ *
+ * . Same as '`' without unicode conversion.
+ *
+ * U Align the offset of the mbuf chain on a 16bit boundary.
+ *
+ * Z Unicode string. Store the unicode string into the mbuf chain
+ * without alignment considerations.
+ *
+ * The parameters can be named in the format string. They have to appear between
+ * parenthesis (indicating they should be ignored bu the encoder).
+ */
+int
+smb_mbc_encode(struct mbuf_chain *mbc, char *fmt, va_list ap)
+{
+ unsigned char name[32];
+ unsigned char cval, c;
+ unsigned short wval;
+ uint64_t llval;
+ uint32_t lval;
+ unsigned int tag;
+ unsigned char *cvalp;
+ unsigned int *ivalp;
+ timestruc_t *tvp;
+ int64_t nt_time;
+ struct vardata_block *vdp;
+ struct smb_request *sr = 0;
+ int unicode = 0;
+ int repc = 1;
+ /*LINTED E_FUNC_SET_NOT_USED*/
+ enum {EVEN, UNALIGNED, ODD} alignment;
+
+ while ((c = *fmt++) != 0) {
+ name[0] = 0;
+ repc = 1;
+ alignment = EVEN;
+ if (c == ' ' || c == '\t') continue;
+ if (c == '(') {
+ char *nm = (char *)name;
+
+ while (((c = *fmt++) != 0) && c != ')') {
+ *nm++ = c;
+ }
+ *nm = 0;
+ if (!c) fmt--;
+ continue;
+ }
+
+ if (c == '{') {
+ unsigned char op[8];
+ char *nm = (char *)op;
+
+ while (((c = *fmt++) != 0) && c != '}') {
+ *nm++ = c;
+ }
+ *nm = 0;
+ if (!c) fmt--;
+ if (strcmp((char *)op, "SID") == 0) {
+ nt_sid_t *sidp;
+
+ sidp = va_arg(ap, nt_sid_t *);
+ (void) mbc_marshal_put_SID(mbc, sidp);
+ }
+ continue;
+ }
+
+ if ('0' <= c && c <= '9') {
+ repc = 0;
+ do {
+ repc = repc * 10 + c - '0';
+ c = *fmt++;
+ } while ('0' <= c && c <= '9');
+ } else if (c == '*') {
+ ivalp = va_arg(ap, unsigned int *);
+
+ repc = *ivalp;
+ c = *fmt++;
+ } else if (c == '!') {
+ alignment = ODD;
+ c = *fmt++;
+ } else if (c == '^') {
+ alignment = UNALIGNED;
+ c = *fmt++;
+ } else if (c == '#') {
+ repc = va_arg(ap, int);
+ c = *fmt++;
+ }
+
+ switch (c) {
+ default:
+ goto format_mismatch;
+
+ case '%':
+ sr = va_arg(ap, struct smb_request *);
+ unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
+ break;
+
+ case 'C': /* Mbuf_chain */
+ if (mbc_marshal_put_mbuf_chain(mbc,
+ va_arg(ap, struct mbuf_chain *)) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'D':
+ vdp = va_arg(ap, struct vardata_block *);
+
+ if (mbc_marshal_put_char(mbc, 1) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_short(mbc, vdp->len) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'M':
+ /* 0xFF S M B */
+ if (mbc_marshal_put_long(mbc, 0x424D53FF))
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'T':
+ tvp = va_arg(ap, timestruc_t *);
+ nt_time = unix_to_nt_time(tvp);
+ if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'V':
+ vdp = va_arg(ap, struct vardata_block *);
+
+ if (mbc_marshal_put_char(mbc, 5) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_short(mbc, vdp->len) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'b':
+ while (repc-- > 0) {
+ cval = va_arg(ap, int);
+ if (mbc_marshal_put_char(mbc, cval) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'm': /* struct_mbuf */
+ if (mbc_marshal_put_mbufs(mbc,
+ va_arg(ap, struct mbuf *)) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'c':
+ cvalp = va_arg(ap, unsigned char *);
+ while (repc-- > 0) {
+ if (mbc_marshal_put_char(mbc,
+ *cvalp++) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'w':
+ while (repc-- > 0) {
+ wval = va_arg(ap, int);
+ if (mbc_marshal_put_short(mbc, wval) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'l':
+ while (repc-- > 0) {
+ lval = va_arg(ap, uint32_t);
+ if (mbc_marshal_put_long(mbc, lval) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'q':
+ while (repc-- > 0) {
+ llval = va_arg(ap, uint64_t);
+ if (mbc_marshal_put_long_long(mbc, llval) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+
+ case 'L':
+ tag = 2;
+ goto ascii_conversion;
+
+ case 'S':
+ case 'A': tag = 4; goto tagged_str;
+ case 'P': tag = 3; goto tagged_str;
+ tagged_str:
+ if (mbc_marshal_put_char(mbc, tag) != 0)
+ return (DECODE_NO_MORE_DATA);
+ /* FALLTHROUGH */
+
+ case 'u': /* Convert from unicode if flags are set */
+ if (unicode)
+ goto unicode_translation;
+ /* FALLTHROUGH */
+
+ case 's': /* ASCII/multibyte string */
+ascii_conversion: cvalp = va_arg(ap, unsigned char *);
+ if (mbc_marshal_put_ascii_string(mbc,
+ (char *)cvalp, repc) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'Y': /* int32_t, encode dos date/time */
+ while (repc-- > 0) {
+ unsigned short d, t;
+
+ lval = va_arg(ap, uint32_t);
+ (void) dosfs_ux_to_dos_time(lval,
+ (short *)&d, (short *)&t);
+ if (mbc_marshal_put_short(mbc, t) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_short(mbc, d) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'y': /* int32_t, encode dos date/time */
+ while (repc-- > 0) {
+ unsigned short d, t;
+
+ lval = va_arg(ap, uint32_t);
+ (void) dosfs_ux_to_dos_time(lval,
+ (short *)&d, (short *)&t);
+ if (mbc_marshal_put_short(mbc, d) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_short(mbc, t) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case ',':
+ if (unicode)
+ repc *= 2;
+ /* FALLTHROUGH */
+
+ case '.':
+ while (repc-- > 0)
+ if (mbc_marshal_put_char(mbc, 0) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'R':
+ /*
+ * This was used to encode RPC format unicode strings
+ * prior to having a DCE RPC support. It is no longer
+ * required.
+ */
+ ASSERT(0);
+ break;
+
+ case 'U': /* Convert to unicode, align to word boundary */
+unicode_translation:
+ if (mbc->chain_offset & 1)
+ mbc->chain_offset++;
+ /* FALLTHROUGH */
+
+ case 'Z': /* Convert to unicode, no alignment adjustment */
+ cvalp = va_arg(ap, unsigned char *);
+ if (mbc_marshal_put_unicode_string(mbc,
+ (char *)cvalp, repc) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+ }
+ }
+ return (0);
+
+format_mismatch:
+ return (-1);
+}
+
+
+int
+smb_encode_mbc(struct mbuf_chain *mbc, char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = smb_mbc_encode(mbc, fmt, ap);
+ va_end(ap);
+ return (rc);
+}
+
+
+int
+smb_encode_buf(unsigned char *buf, int n_buf, char *fmt, ...)
+{
+ int rc;
+ struct mbuf_chain mbc;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ MBC_ATTACH_BUF(&mbc, buf, n_buf);
+ rc = smb_mbc_encode(&mbc, fmt, ap);
+ m_freem(mbc.chain);
+ va_end(ap);
+ return (rc);
+}
+
+
+int
+smb_decode_vwv(struct smb_request *sr, char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = smb_mbc_decode(&sr->smb_vwv, fmt, ap);
+ va_end(ap);
+ return (rc);
+}
+
+
+int
+smb_decode_data(struct smb_request *sr, char *fmt, ...)
+{
+ if (smb_decode_mbc(&sr->smb_data, fmt, (int *)(&fmt + 1)) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ return (0);
+}
+
+
+void
+smb_encode_header(struct smb_request *sr, int wct,
+ int bcc, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (smb_mbc_encode(&sr->reply, fmt, ap) != 0) {
+ va_end(ap);
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+ va_end(ap);
+ /*LINTED E_ASSIGN_NARROW_CONV*/
+ sr->smb_wct = wct;
+ /*LINTED E_ASSIGN_NARROW_CONV*/
+ sr->smb_bcc = bcc;
+}
+
+int
+smb_peek_mbc(struct mbuf_chain *mbc, int offset, char *fmt, ...)
+{
+ int xx;
+ struct mbuf_chain tmp;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
+ xx = smb_mbc_decode(&tmp, fmt, ap);
+ va_end(ap);
+ return (xx);
+}
+
+
+int
+smb_poke_mbc(struct mbuf_chain *mbc, int offset, char *fmt, ...)
+{
+ int xx;
+ struct mbuf_chain tmp;
+ va_list ap;
+
+ (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
+ va_start(ap, fmt);
+ xx = smb_mbc_encode(&tmp, fmt, ap);
+ va_end(ap);
+ return (xx);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c
new file mode 100644
index 0000000000..b8e45289cd
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c
@@ -0,0 +1,334 @@
+/*
+ * 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) 1982, 1986, 1988, 1991, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MLRPC server-side library processing. This is where we decode the
+ * request header to figure out what type of request is being made,
+ * call the server stub, if appropriate, and build the response header.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/mbuf.h>
+
+/*
+ * Fragment size (5680: NT style). Tuning parameter
+ * used during development of multiple fragment support.
+ */
+
+#define MLRPC_FRAG_SIZE 5680
+#define MLRPC_RSP_HDR_SIZE 24
+
+/*
+ * smb_mbuf_get
+ *
+ * Allocate mbufs to hold the amount of data specified.
+ * A pointer to the head of the mbuf list is returned.
+ */
+struct mbuf *
+smb_mbuf_get(uchar_t *buf, int nbytes)
+{
+ struct mbuf *mhead = 0;
+ struct mbuf *m = 0;
+ int count;
+ int offset = 0;
+
+ while (nbytes) {
+ count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
+ nbytes -= count;
+
+ if (mhead == 0) {
+ MGET(mhead, M_WAIT, MT_DATA);
+ m = mhead;
+ } else {
+ MGET(m->m_next, M_WAIT, MT_DATA);
+ m = m->m_next;
+ }
+
+ if (count > MLEN) {
+ MCLGET(m, M_WAIT);
+ }
+
+ m->m_len = count;
+ bcopy(buf + offset, m->m_data, count);
+ offset += count;
+ }
+ return (mhead);
+}
+
+/*
+ * Allocate enough mbufs to accommodate the residual count in a uio.
+ */
+struct mbuf *
+smb_mbuf_allocate(struct uio *uio)
+{
+ struct iovec *iovp;
+ struct mbuf *mhead = 0;
+ struct mbuf *m = 0;
+ int count, iovs, resid;
+
+ iovp = uio->uio_iov;
+ iovs = uio->uio_iovcnt;
+ resid = uio->uio_resid;
+
+ while ((resid > 0) && (iovs > 0)) {
+ count = (resid > MCLBYTES) ? MCLBYTES : resid;
+ resid -= count;
+
+ if (mhead == 0) {
+ MGET(mhead, M_WAIT, MT_DATA);
+ m = mhead;
+ } else {
+ MGET(m->m_next, M_WAIT, MT_DATA);
+ m = m->m_next;
+ }
+
+ if (count > MLEN) {
+ MCLGET(m, M_WAIT);
+ }
+
+ iovp->iov_base = m->m_data;
+ iovp->iov_len = m->m_len = count;
+ iovs--;
+ iovp++;
+ }
+
+ uio->uio_iovcnt -= iovs;
+ return (mhead);
+}
+
+/*
+ * Trim an mbuf chain to nbytes.
+ */
+void
+smb_mbuf_trim(struct mbuf *mhead, int nbytes)
+{
+ struct mbuf *m = mhead;
+
+ while (m != 0) {
+ if (nbytes <= m->m_len) {
+ m->m_len = nbytes;
+ if (m->m_next != 0) {
+ m_freem(m->m_next);
+ m->m_next = 0;
+ }
+ break;
+ }
+ nbytes -= m->m_len;
+ m = m->m_next;
+ }
+}
+
+int
+MBC_LENGTH(struct mbuf_chain *MBC)
+{
+ struct mbuf *m = (MBC)->chain;
+ int used = 0;
+
+ while (m != 0) {
+ used += m->m_len;
+ m = m->m_next;
+ }
+ return (used);
+}
+
+void
+MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
+{
+ bzero((MBC), sizeof (struct mbuf_chain));
+ (MBC)->max_bytes = max_bytes ? max_bytes : smb_maxbufsize;
+}
+
+void
+MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
+{
+ struct mbuf *m;
+
+ bzero((MBC), sizeof (struct mbuf_chain));
+
+ if (max_bytes != 0) {
+ MGET(m, M_WAIT, MT_DATA);
+ m->m_len = 0;
+ (MBC)->chain = m;
+ if (max_bytes > MINCLSIZE)
+ MCLGET(m, M_WAIT);
+ }
+ (MBC)->max_bytes = max_bytes;
+}
+
+void
+MBC_FLUSH(struct mbuf_chain *MBC)
+{
+ extern void m_freem(struct mbuf *);
+ struct mbuf *m;
+
+ while ((m = (MBC)->chain) != 0) {
+ (MBC)->chain = m->m_nextpkt;
+ m->m_nextpkt = 0;
+ m_freem(m);
+ }
+ MBC_SETUP(MBC, (MBC)->max_bytes);
+}
+
+void
+MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
+{
+ if (MBC->chain != 0)
+ MBC_FLUSH(MBC);
+
+ (MBC)->chain_offset = 0;
+ (MBC)->chain = (MBUF);
+}
+
+void
+MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
+{
+ struct mbuf *m;
+
+ if ((MBC)->chain == 0) {
+ (MBC)->chain = (MBUF);
+ } else {
+ m = (MBC)->chain;
+ while (m->m_next != 0)
+ m = m->m_next;
+ m->m_next = (MBUF);
+ }
+}
+
+
+void
+MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
+{
+ MGET((MBC)->chain, M_WAIT, MT_DATA);
+ (MBC)->chain_offset = 0;
+ (MBC)->chain->m_flags |= M_EXT;
+ (MBC)->chain->m_data = (caddr_t)(BUF);
+ (MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
+ (MBC)->chain->m_len = (LEN);
+ (MBC)->chain->m_ext.ext_size = (LEN);
+ (MBC)->chain->m_ext.ext_ref = smb_noop;
+ (MBC)->max_bytes = (LEN);
+}
+
+
+int
+MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC,
+ int OFF, int LEN)
+{
+ if (((OFF) + (LEN)) > (MBC)->max_bytes)
+ return (EMSGSIZE);
+
+ *(SUBMBC) = *(MBC);
+ (SUBMBC)->chain_offset = (OFF);
+ (SUBMBC)->max_bytes = (OFF) + (LEN);
+ (SUBMBC)->shadow_of = (MBC);
+ return (0);
+}
+
+/*
+ * Free a single mbuf structure. Calls m->m_ext.ext_ref() to free any
+ * associated external buffers if present (indicated by m->m_flags & M_EXT)
+ */
+struct mbuf *
+m_free(struct mbuf *m)
+{
+ struct mbuf *n;
+
+ MFREE(m, n);
+ return (n);
+}
+
+/*
+ * Free a list of mbufs. Each mbuf in the list is freed similarly to m_free.
+ */
+void
+m_freem(struct mbuf *m)
+{
+ struct mbuf *n;
+
+ if (m == NULL)
+ return;
+ /*
+ * Lint doesn't like the m = n assignment at the close of the loop
+ * but it is correct. MFREE assigns n = (m)->m_next so the loop
+ * is effectively assigning m = (m)->m_next then exiting when
+ * m == NULL
+ */
+ do {
+ MFREE(m, n);
+ } while ((m = n) != 0);
+}
+
+/*
+ * Mbuffer utility routines.
+ */
+
+int /*ARGSUSED*/
+mclref(caddr_t p, int size, int adj) /* size, adj are unused */
+{
+ MEM_FREE("mbuf", p);
+ return (0);
+}
+
+int /*ARGSUSED*/
+mclrefnoop(caddr_t p, int size, int adj) /* p, size, adj are unused */
+{
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_memory_manager.c b/usr/src/uts/common/fs/smbsrv/smb_memory_manager.c
new file mode 100644
index 0000000000..61e1066388
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_memory_manager.c
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Memory management functions.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * smbsr_malloc
+ *
+ * allocate a block of memory with the given size and
+ * add it to the given linked list. This function is
+ * used to allocate temporary memories which are needed
+ * during processing of a SMB request. These memories
+ * get freed when request processing is finished.
+ */
+void *
+smbsr_malloc(smb_malloc_list *list, size_t size)
+{
+ smb_malloc_list *element;
+
+ size += sizeof (smb_malloc_list);
+ element = MEM_MALLOC("smb", size);
+ element->forw = list->forw;
+ element->back = list;
+ list->forw->back = element;
+ list->forw = element;
+ return (void *)(element + 1); /* return address of data */
+}
+
+/*
+ * smbsr_realloc
+ *
+ * This function is used in conjunction with smbsr_malloc to
+ * resize an already allocated entity.
+ */
+void *
+smbsr_realloc(void *mem, size_t size)
+{
+ smb_malloc_list *element = (smb_malloc_list *)mem;
+ smb_malloc_list *new_entry;
+ smb_malloc_list *list;
+
+ element--;
+ list = element->back;
+ QUEUE_CLIP(element);
+ size += sizeof (smb_malloc_list);
+
+ new_entry = MEM_REALLOC("smb", element, size);
+ new_entry->forw = list->forw;
+ new_entry->back = list;
+ list->forw->back = new_entry;
+ list->forw = new_entry;
+ return (void *)(new_entry + 1); /* return address of new data */
+}
+
+/*
+ * smbsr_free_malloc_list
+ *
+ * Frees all memory block in the given linked list.
+ */
+void
+smbsr_free_malloc_list(smb_malloc_list *root)
+{
+ smb_malloc_list *element;
+
+ /*
+ * we initialize smb_request structure in smb_nt_notify_change
+ * function, so we should check root->forw to make sure it's
+ * not NULL.
+ */
+ while (root->forw && root->forw != root) {
+ element = root->forw;
+
+ element->forw->back = element->back;
+ element->back->forw = element->forw;
+
+ /* and release it... */
+ MEM_FREE("smb", element);
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_move.c b/usr/src/uts/common/fs/smbsrv/smb_move.c
new file mode 100644
index 0000000000..eb44e5a84d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_move.c
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: move
+ *
+ * The source file is copied to the destination and the source is
+ * subsequently deleted.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 3
+ * USHORT Tid2; Second (target) file id
+ * USHORT OpenFunction; what to do if target file exists
+ * USHORT Flags; Flags to control move operations:
+ * 0 - target must be a file
+ * 1 - target must be a directory
+ * 2 - reserved (must be 0)
+ * 3 - reserved (must be 0)
+ * 4 - verify all writes
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR Format1; 0x04
+ * STRING OldFileName[]; Old file name
+ * UCHAR FormatNew; 0x04
+ * STRING NewFileName[]; New file name
+ *
+ * OldFileName is copied to NewFileName, then OldFileName is deleted. Both
+ * OldFileName and NewFileName must refer to paths on the same server.
+ * NewFileName can refer to either a file or a directory. All file
+ * components except the last must exist; directories will not be created.
+ *
+ * NewFileName can be required to be a file or a directory by the Flags
+ * field.
+ *
+ * The Tid in the header is associated with the source while Tid2 is
+ * associated with the destination. These fields may contain the same or
+ * differing valid values. Tid2 can be set to -1 indicating that this is to
+ *
+ * be the same Tid as in the SMB header. This allows use of the move
+ * protocol with SMB_TREE_CONNECT_ANDX.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Count; Number of files moved
+ * USHORT ByteCount; Count of data bytes; min = 0
+ * UCHAR ErrorFileFormat; 0x04 (only if error)
+ * STRING ErrorFileName[]; Pathname of file where error
+ * occurred
+ *
+ * The source path must refer to an existing file or files. Wildcards are
+ * permitted. Source files specified by wildcards are processed until an
+ * error is encountered. If an error is encountered, the expanded name of
+ * the file is returned in ErrorFileName. Wildcards are not permitted in
+ * NewFileName.
+ *
+ * OpenFunction controls what should happen if the destination file exists.
+ * If (OpenFunction & 0x30) == 0, the operation should fail if the
+ * destination exists. If (OpenFunction & 0x30) == 0x20, the destination
+ * file should be overwritten.
+ *
+ * 4.2.12.1 Errors
+ *
+ * ERRDOS/ERRfilexists
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRnofiles
+ * ERRDOS/ERRbadshare
+ * ERRHRD/ERRnowrite
+ * ERRSRV/ERRnoaccess
+ * ERRSRV/ERRinvdevice
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ * ERRSRV/ERRnosupport
+ * ERRSRV/ERRaccess
+ */
+
+#include <smbsrv/smb_incl.h>
+/*ARGSUSED*/
+int
+smb_com_move(struct smb_request *sr)
+{
+ /* TODO move */
+ /* TODO move wildcards */
+ /* TODO move */
+
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
new file mode 100644
index 0000000000..844e84a889
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
@@ -0,0 +1,478 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Notes on the virtual circuit (VC) values in the SMB Negotiate
+ * response and SessionSetupAndx request.
+ *
+ * A virtual circuit (VC) represents a connection between a client and a
+ * server using a reliable, session oriented transport protocol, such as
+ * NetBIOS or TCP/IP. Originally, each SMB session was restricted to a
+ * single underlying transport connection, i.e. a single NetBIOS session,
+ * which limited performance for raw data transfers.
+ *
+ * The intention behind multiple VCs was to improve performance by
+ * allowing parallelism over each NetBIOS session. For example, raw data
+ * could be transmitted using a different VC from other types of SMB
+ * requests to remove the interleaving restriction while a raw transfer
+ * is in progress. So the MaxNumberVcs field was added to the negotiate
+ * response to make the number of VCs configurable and to allow servers
+ * to specify how many they were prepared to support per session
+ * connection. This turned out to be difficult to manage and, with
+ * technology improvements, it has become obsolete.
+ *
+ * Servers should set the MaxNumberVcs value in the Negotiate response
+ * to 1. Clients should probably ignore it. If a server receives a
+ * SessionSetupAndx with a VC value of 0, it should close all other
+ * VCs to that client. If it receives a non-zero VC, it should leave
+ * other VCs in tact.
+ *
+ */
+
+/*
+ * SMB: negotiate
+ *
+ * Client Request Description
+ * ============================ =======================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * struct {
+ * UCHAR BufferFormat; 0x02 -- Dialect
+ * UCHAR DialectName[]; ASCII null-terminated string
+ * } Dialects[];
+ *
+ * The Client sends a list of dialects that it can communicate with. The
+ * response is a selection of one of those dialects (numbered 0 through n)
+ * or -1 (hex FFFF) indicating that none of the dialects were acceptable.
+ * The negotiate message is binding on the virtual circuit and must be
+ * sent. One and only one negotiate message may be sent, subsequent
+ * negotiate requests will be rejected with an error response and no action
+ * will be taken.
+ *
+ * The protocol does not impose any particular structure to the dialect
+ * strings. Implementors of particular protocols may choose to include,
+ * for example, version numbers in the string.
+ *
+ * If the server does not understand any of the dialect strings, or if PC
+ * NETWORK PROGRAM 1.0 is the chosen dialect, the response format is
+ *
+ * Server Response Description
+ * ============================ =======================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT DialectIndex; Index of selected dialect
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * If the chosen dialect is greater than core up to and including
+ * LANMAN2.1, the protocol response format is
+ *
+ * Server Response Description
+ * ============================ =======================================
+ *
+ * UCHAR WordCount; Count of parameter words = 13
+ * USHORT DialectIndex; Index of selected dialect
+ * USHORT SecurityMode; Security mode:
+ * bit 0: 0 = share, 1 = user
+ * bit 1: 1 = use challenge/response
+ * authentication
+ * USHORT MaxBufferSize; Max transmit buffer size (>= 1024)
+ * USHORT MaxMpxCount; Max pending multiplexed requests
+ * USHORT MaxNumberVcs; Max VCs between client and server
+ * USHORT RawMode; Raw modes supported:
+ * bit 0: 1 = Read Raw supported
+ * bit 1: 1 = Write Raw supported
+ * ULONG SessionKey; Unique token identifying this session
+ * SMB_TIME ServerTime; Current time at server
+ * SMB_DATE ServerDate; Current date at server
+ * USHORT ServerTimeZone; Current time zone at server
+ * USHORT EncryptionKeyLength; MBZ if this is not LM2.1
+ * USHORT Reserved; MBZ
+ * USHORT ByteCount Count of data bytes
+ * UCHAR EncryptionKey[]; The challenge encryption key
+ * STRING PrimaryDomain[]; The server's primary domain
+ *
+ * MaxBufferSize is the size of the largest message which the client can
+ * legitimately send to the server
+ *
+ * If bit0 of the Flags field is set in the negotiate response, this
+ * indicates the server supports the SMB_COM_LOCK_AND_READ and
+ * SMB_COM_WRITE_AND_UNLOCK client requests.
+ *
+ * If the SecurityMode field indicates the server is running in user mode,
+ * the client must send appropriate SMB_COM_SESSION_SETUP_ANDX requests
+ * before the server will allow the client to access resources. If the
+ * SecurityMode fields indicates the client should use challenge/response
+ * authentication, the client should use the authentication mechanism
+ * specified in section 2.10.
+ *
+ * Clients should submit no more than MaxMpxCount distinct unanswered SMBs
+ * to the server when using multiplexed reads or writes (see sections 5.13
+ * and 5.25)
+ *
+ * Clients using the "MICROSOFT NETWORKS 1.03" dialect use a different
+ * form of raw reads than documented here, and servers are better off
+ * setting RawMode in this response to 0 for such sessions.
+ *
+ * If the negotiated dialect is "DOS LANMAN2.1" or "LANMAN2.1", then
+ * PrimaryDomain string should be included in this response.
+ *
+ * If the negotiated dialect is NT LM 0.12, the response format is
+ *
+ * Server Response Description
+ * ========================== =========================================
+ *
+ * UCHAR WordCount; Count of parameter words = 17
+ * USHORT DialectIndex; Index of selected dialect
+ * UCHAR SecurityMode; Security mode:
+ * bit 0: 0 = share, 1 = user
+ * bit 1: 1 = encrypt passwords
+ * USHORT MaxMpxCount; Max pending multiplexed requests
+ * USHORT MaxNumberVcs; Max VCs between client and server
+ * ULONG MaxBufferSize; Max transmit buffer size
+ * ULONG MaxRawSize; Maximum raw buffer size
+ * ULONG SessionKey; Unique token identifying this session
+ * ULONG Capabilities; Server capabilities
+ * ULONG SystemTimeLow; System (UTC) time of the server (low).
+ * ULONG SystemTimeHigh; System (UTC) time of the server (high).
+ * USHORT ServerTimeZone; Time zone of server (min from UTC)
+ * UCHAR EncryptionKeyLength; Length of encryption key.
+ * USHORT ByteCount; Count of data bytes
+ * UCHAR EncryptionKey[]; The challenge encryption key
+ * UCHAR OemDomainName[]; The name of the domain (in OEM chars)
+ *
+ * In addition to the definitions above, MaxBufferSize is the size of the
+ * largest message which the client can legitimately send to the server.
+ * If the client is using a connectionless protocol, MaxBufferSize must be
+ * set to the smaller of the server's internal buffer size and the amount
+ * of data which can be placed in a response packet.
+ *
+ * MaxRawSize specifies the maximum message size the server can send or
+ * receive for SMB_COM_WRITE_RAW or SMB_COM_READ_RAW.
+ *
+ * Connectionless clients must set Sid to 0 in the SMB request header.
+ *
+ * Capabilities allows the server to tell the client what it supports.
+ * The bit definitions defined in cifs.h. Bit 0x2000 used to be set in
+ * the negotiate response capabilities but it caused problems with
+ * Windows 2000. It is probably not valid, it doesn't appear in the
+ * CIFS spec.
+ *
+ * 4.1.1.1 Errors
+ *
+ * SUCCESS/SUCCESS
+ * ERRSRV/ERRerror
+ */
+#include <sys/types.h>
+#include <sys/strsubr.h>
+#include <sys/socketvar.h>
+#include <sys/socket.h>
+#include <sys/random.h>
+#include <netinet/in.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_i18n.h>
+
+
+/*
+ * Maximum buffer size for DOS: chosen to be the same as NT.
+ * Do not change this value, DOS is very sensitive to it.
+ */
+#define SMB_DOS_MAXBUF 0x1104
+
+/*
+ * Maximum buffer size for NT: configurable based on the client environment.
+ * IR104720 Experiments with Windows 2000 indicate that we achieve better
+ * SmbWriteX performance with a buffer size of 64KB instead of the 37KB
+ * used with Windows NT4.0. Previous experiments with NT4.0 resulted in
+ * directory listing problems so this buffer size is configurable based
+ * on the end-user environment. When in doubt use 37KB.
+ */
+int smb_maxbufsize = SMB_NT_MAXBUF(37);
+
+/*
+ * The DOS TCP rcvbuf is set to 8700 because DOS 6.1 seems to have problems
+ * with other values. DOS 6.1 seems to depend on a window value of 8700 to
+ * send the next set of data. If we return a window value of 40KB, after
+ * sending 8700 bytes of data, it will start the next set of data from 40KB
+ * instead of 8.7k. Why 8.7k? We have no idea; it is the value that NT uses.
+ * September 2000.
+ *
+ * IR104720 Increased smb_nt_tcp_rcvbuf from 40KB to just under 1MB to allow
+ * for a larger TCP window sizei based on observations of Windows 2000 and
+ * performance testing. March 2003.
+ */
+uint32_t smb_dos_tcp_rcvbuf = 8700;
+uint32_t smb_nt_tcp_rcvbuf = 1048560; /* scale factor of 4 */
+
+static void smb_get_security_info(
+ struct smb_request *sr,
+ unsigned short *secmode,
+ unsigned char *key,
+ unsigned char *keylen,
+ uint32_t *sesskey);
+
+/*
+ * Function: int smb_com_negotiate(struct smb_request *)
+ */
+
+int
+smb_com_negotiate(struct smb_request *sr)
+{
+ int dialect = 0;
+ int this_dialect;
+ unsigned char keylen;
+ int sel_pos = -1;
+ int pos;
+ char key[32];
+ char *p;
+ timestruc_t time_val;
+ unsigned short secmode;
+ uint32_t sesskey;
+ uint32_t capabilities = 0;
+
+ unsigned short max_mpx_count;
+ WORD tz_correction;
+ char ipaddr_buf[INET_ADDRSTRLEN];
+
+ if (sr->session->s_state != SMB_SESSION_STATE_ESTABLISHED) {
+ /* The protocol has already been negotiated. */
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+
+ for (pos = 0;
+ sr->smb_data.chain_offset < sr->smb_data.max_bytes;
+ pos++) {
+ if (smb_decode_mbc(&sr->smb_data, "%L", sr, &p) != 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+
+ this_dialect = smb_xlate_dialect_str_to_cd(p);
+
+ if (this_dialect < 0)
+ continue;
+
+ if (dialect < this_dialect) {
+ dialect = this_dialect;
+ sel_pos = pos;
+ }
+ }
+ if (sel_pos < 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+
+ smb_get_security_info(sr, &secmode, (unsigned char *)key,
+ &keylen, &sesskey);
+
+ (void) microtime(&time_val);
+
+ tz_correction = -(WORD)(smb_get_gmtoff() / 60); /* tz correct. (min) */
+
+ switch (dialect) {
+ case DIALECT_UNKNOWN:
+ case PC_NETWORK_PROGRAM_1_0: /* core */
+ (void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
+ (const void *)&smb_dos_tcp_rcvbuf,
+ sizeof (smb_dos_tcp_rcvbuf));
+ smbsr_encode_result(sr, 1, 0, "bww", 1, sel_pos, 0);
+ break;
+
+ case Windows_for_Workgroups_3_1a:
+ case PCLAN1_0:
+ case MICROSOFT_NETWORKS_1_03:
+ case MICROSOFT_NETWORKS_3_0:
+ case LANMAN1_0:
+ case LM1_2X002:
+ case DOS_LM1_2X002:
+ (void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
+ (const void *)&smb_dos_tcp_rcvbuf,
+ sizeof (smb_dos_tcp_rcvbuf));
+ sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK;
+ smbsr_encode_result(sr, 13, VAR_BCC,
+ "(wct) b" "(dix) w" "(sec) w" "(mbs) w"
+ "(mmc) w" "(mnv) w" "(raw) w" "(key) l"
+ "(tim/dat) Y" "(tz) w" "(ekl) w"
+ "(mbz) 2.""(bcc) w" "(key) #c",
+ 13, /* wct */
+ sel_pos, /* dialect index */
+ secmode, /* security mode */
+ SMB_DOS_MAXBUF, /* max buffer size */
+ 1, /* max MPX (temporary) */
+ 1, /* max VCs (temporary, ambiguous) */
+ 3, /* raw mode (s/b 3) */
+ sesskey, /* session key */
+ time_val.tv_sec, /* server time/date */
+ tz_correction, /* see smb_get_gmtoff */
+ (short)keylen, /* Encryption Key Length */
+ /* reserved field handled 2. */
+ VAR_BCC,
+ (int)keylen,
+ key); /* encryption key */
+ break;
+
+ case DOS_LANMAN2_1:
+ case LANMAN2_1:
+ (void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
+ (const void *)&smb_dos_tcp_rcvbuf,
+ sizeof (smb_dos_tcp_rcvbuf));
+ sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK;
+ smbsr_encode_result(sr, 13, VAR_BCC,
+ "(wct) b" "(dix) w" "(sec) w" "(mbs) w"
+ "(mmc) w" "(mnv) w" "(raw) w" "(key) l"
+ "(tim/dat) Y" "(tz) w" "(ekl) w"
+ "(mbz) 2.""(bcc) w" "(key) #c" "(dom) s",
+ 13, /* wct */
+ sel_pos, /* dialect index */
+ secmode, /* security mode */
+ SMB_DOS_MAXBUF, /* max buffer size */
+ 1, /* max MPX (temporary) */
+ 1, /* max VCs (temporary, ambiguous) */
+ 3, /* raw mode (s/b 3) */
+ sesskey, /* session key */
+ time_val.tv_sec, /* server time/date */
+ tz_correction,
+ (short)keylen, /* Encryption Key Length */
+ /* reserved field handled 2. */
+ VAR_BCC,
+ (int)keylen,
+ key, /* encryption key */
+ smb_info.si.skc_resource_domain);
+ break;
+
+ case NT_LM_0_12:
+ (void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
+ (const void *)&smb_nt_tcp_rcvbuf,
+ sizeof (smb_nt_tcp_rcvbuf));
+ capabilities = CAP_LARGE_FILES
+ | CAP_NT_SMBS
+ | CAP_STATUS32
+ | CAP_NT_FIND
+ | CAP_RAW_MODE
+ | CAP_LEVEL_II_OPLOCKS
+ | CAP_LOCK_AND_READ
+ | CAP_RPC_REMOTE_APIS
+ | CAP_LARGE_READX;
+
+ /*
+ * UNICODE support is required to enable support for long
+ * share names and long file names and streams.
+ */
+
+ capabilities |= CAP_UNICODE;
+
+
+ /*
+ * Turn off Extended Security Negotiation
+ */
+ sr->smb_flg2 &= ~SMB_FLAGS2_EXT_SEC;
+
+ /*
+ * Allow SMB signatures if security challenge response enabled
+ */
+ if ((secmode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
+ smb_info.si.skc_signing_enable) {
+ secmode |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
+ if (smb_info.si.skc_signing_required)
+ secmode |=
+ NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
+
+ sr->session->secmode = secmode;
+ }
+
+ (void) inet_ntop(AF_INET, (char *)&sr->session->ipaddr,
+ ipaddr_buf, sizeof (ipaddr_buf));
+ /*LINTED E_ASSIGN_NARROW_CONV (uint16_t)*/
+ max_mpx_count = smb_info.si.skc_maxworkers;
+
+ smbsr_encode_result(sr, 17, VAR_BCC,
+ "(wct) b" "(dix) w" "(sec) b" "(mmc) w"
+ "(mnv) w" "(mbs) l" "(raw) l" "(key) l"
+ "(cap) l" "(tim) T" "(tz) w" "(ekl) b"
+ "(bcc) w" "(key) #c" "(dom) Z",
+ 17, /* wct */
+ sel_pos, /* dialect index */
+ secmode, /* security mode */
+ max_mpx_count, /* max MPX (temporary) */
+ 1, /* max VCs (temporary, ambiguous) */
+ (DWORD)smb_maxbufsize, /* max buffer size */
+ 0xFFFF, /* max raw size */
+ sesskey, /* session key */
+ capabilities,
+ &time_val, /* system time */
+ tz_correction,
+ keylen, /* Encryption Key Length */
+ VAR_BCC,
+ (int)keylen,
+ key, /* encryption key */
+ smb_info.si.skc_resource_domain);
+ break;
+
+ default:
+ /* Just to make sure. */
+ ASSERT(0);
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Save the agreed dialect. Note that this value is also
+ * used to detect and reject attempts to re-negotiate.
+ */
+ sr->session->dialect = dialect;
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+ return (SDRC_NORMAL_REPLY);
+}
+
+static void
+smb_get_security_info(
+ struct smb_request *sr,
+ unsigned short *secmode,
+ unsigned char *key,
+ unsigned char *keylen,
+ uint32_t *sesskey)
+{
+ uchar_t tmp_key[8];
+
+ (void) random_get_pseudo_bytes(tmp_key, 8);
+ bcopy(tmp_key, &sr->session->challenge_key, 8);
+ sr->session->challenge_len = 8;
+ *keylen = 8;
+ bcopy(tmp_key, key, 8);
+
+ sr->session->secmode = NEGOTIATE_SECURITY_CHALLENGE_RESPONSE|
+ NEGOTIATE_SECURITY_USER_LEVEL;
+
+ (void) random_get_pseudo_bytes(tmp_key, 4);
+ sr->session->sesskey = tmp_key[0] | tmp_key[1] << 8 |
+ tmp_key[2] << 16 | tmp_key[3] << 24;
+
+ *secmode = sr->session->secmode;
+ *sesskey = sr->session->sesskey;
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_net.c b/usr/src/uts/common/fs/smbsrv/smb_net.c
new file mode 100644
index 0000000000..0c8f0a9db3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_net.c
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/cpuvar.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/time.h>
+#include <sys/varargs.h>
+#include <sys/modctl.h>
+#include <sys/pathname.h>
+#include <sys/fs/snode.h>
+#include <sys/fs/dv_node.h>
+#include <sys/vnode.h>
+#undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */
+
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smbvar.h>
+#include <smbsrv/smb_kproto.h>
+
+/*
+ * SMB Network Socket API
+ *
+ * smb_socreate: Creates an socket based on domain/type.
+ * smb_soshutdown: Disconnect a socket created with smb_socreate
+ * smb_sodestroy: Release resources associated with a socket
+ * smb_sosend: Send the contents of a buffer on a socket
+ * smb_sorecv: Receive data into a buffer from a socket
+ * smb_iov_sosend: Send the contents of an iovec on a socket
+ * smb_iov_sorecv: Receive data into an iovec from a socket
+ */
+
+struct sonode *
+smb_socreate(int domain, int type, int protocol)
+{
+ vnode_t *dvp = NULL;
+ vnode_t *vp = NULL;
+ struct snode *csp = NULL;
+ int err = 0;
+ major_t maj;
+
+ if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) {
+
+ /*
+ * solookup calls sogetvp if the vp is not found in the cache.
+ * Since the call to sogetvp is hardwired to use USERSPACE
+ * and declared static we'll do the work here instead.
+ */
+ err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp",
+ UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
+ if (err)
+ return (NULL);
+
+ /* Check that it is the correct vnode */
+ if (vp->v_type != VCHR) {
+ VN_RELE(vp);
+ return (NULL);
+ }
+
+ csp = VTOS(VTOS(vp)->s_commonvp);
+ if (!(csp->s_flag & SDIPSET)) {
+ char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+ err = ddi_dev_pathname(vp->v_rdev, S_IFCHR,
+ pathname);
+ if (err == 0) {
+ err = devfs_lookupname(pathname, NULLVPP,
+ &dvp);
+ }
+ VN_RELE(vp);
+ kmem_free(pathname, MAXPATHLEN);
+ if (err != 0) {
+ return (NULL);
+ }
+ vp = dvp;
+ }
+
+ maj = getmajor(vp->v_rdev);
+ if (!STREAMSTAB(maj)) {
+ VN_RELE(vp);
+ return (NULL);
+ }
+ }
+
+ return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err));
+}
+
+/*
+ * smb_soshutdown will disconnect the socket and prevent subsequent PDU
+ * reception and transmission. The sonode still exists but its state
+ * gets modified to indicate it is no longer connected. Calls to
+ * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used
+ * regain control of a thread stuck in smb_sorecv.
+ */
+void
+smb_soshutdown(struct sonode *so)
+{
+ (void) soshutdown(so, SHUT_RDWR);
+}
+
+/*
+ * smb_sodestroy releases all resources associated with a socket previously
+ * created with smb_socreate. The socket must be shutdown using smb_soshutdown
+ * before the socket is destroyed with smb_sodestroy, otherwise undefined
+ * behavior will result.
+ */
+void
+smb_sodestroy(struct sonode *so)
+{
+ vnode_t *vp = SOTOV(so);
+
+ (void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL);
+ VN_RELE(vp);
+}
+
+int
+smb_sosend(struct sonode *so, void *msg, size_t len)
+{
+ iovec_t iov;
+ int err;
+
+ ASSERT(so != NULL);
+ ASSERT(len != 0);
+
+ /*
+ * Fill in iovec and receive data
+ */
+ iov.iov_base = msg;
+ iov.iov_len = len;
+
+ if ((err = smb_iov_sosend(so, &iov, 1, len)) != 0) {
+ return (err);
+ }
+
+ /* Successful receive */
+ return (0);
+}
+
+int
+smb_sorecv(struct sonode *so, void *msg, size_t len)
+{
+ iovec_t iov;
+ int err;
+
+ ASSERT(so != NULL);
+ ASSERT(len != 0);
+
+ /*
+ * Fill in iovec and receive data
+ */
+ iov.iov_base = msg;
+ iov.iov_len = len;
+
+ if ((err = smb_iov_sorecv(so, &iov, 1, len)) != 0) {
+ return (err);
+ }
+
+ /* Successful receive */
+ return (0);
+}
+
+/*
+ * smb_iov_sosend - Sends an iovec on a connection.
+ *
+ * This function puts the data provided on the wire by calling sosendmsg.
+ * It will return only when all the data has been sent or if an error
+ * occurs.
+ *
+ * Returns 0 for success, the socket errno value if sosendmsg fails, and
+ * -1 if sosendmsg returns success but uio_resid != 0
+ */
+int
+smb_iov_sosend(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len)
+{
+ struct msghdr msg;
+ struct uio uio;
+ int error;
+
+ ASSERT(iop != NULL);
+
+ /* Initialization of the message header. */
+ bzero(&msg, sizeof (msg));
+ msg.msg_iov = iop;
+ msg.msg_flags = MSG_WAITALL;
+ msg.msg_iovlen = iovlen;
+
+ /* Initialization of the uio structure. */
+ bzero(&uio, sizeof (uio));
+ uio.uio_iov = iop;
+ uio.uio_iovcnt = iovlen;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_resid = total_len;
+
+ if ((error = sosendmsg(so, &msg, &uio)) == 0) {
+ /* Data sent */
+ if (uio.uio_resid == 0) {
+ /* All data sent. Success. */
+ return (0);
+ } else {
+ /* Not all data was sent. Failure */
+ return (-1);
+ }
+ }
+
+ /* Send failed */
+ return (error);
+}
+
+/*
+ * smb_iov_sorecv - Receives an iovec from a connection
+ *
+ * This function gets the data asked for from the socket. It will return
+ * only when all the requested data has been retrieved or if an error
+ * occurs.
+ *
+ * Returns 0 for success, the socket errno value if sorecvmsg fails, and
+ * -1 if sorecvmsg returns success but uio_resid != 0
+ */
+int
+smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len)
+{
+ struct msghdr msg;
+ struct uio uio;
+ int error;
+
+ ASSERT(iop != NULL);
+
+ /* Initialization of the message header. */
+ bzero(&msg, sizeof (msg));
+ msg.msg_iov = iop;
+ msg.msg_flags = MSG_WAITALL;
+ msg.msg_iovlen = iovlen;
+
+ /* Initialization of the uio structure. */
+ bzero(&uio, sizeof (uio));
+ uio.uio_iov = iop;
+ uio.uio_iovcnt = iovlen;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_resid = total_len;
+
+ if ((error = sorecvmsg(so, &msg, &uio)) == 0) {
+ /* Received data */
+ if (uio.uio_resid == 0) {
+ /* All requested data received. Success */
+ return (0);
+ } else {
+ /* Not all data was sent. Failure */
+ return (-1);
+ }
+ }
+
+ /* Receive failed */
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_node.c b/usr/src/uts/common/fs/smbsrv/smb_node.c
new file mode 100644
index 0000000000..5ea8c5f1c3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c
@@ -0,0 +1,770 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB Node State Machine
+ * ----------------------
+ *
+ * +----------------------------+ T0
+ * | SMB_NODE_STATE_AVAILABLE |<----------- Creation/Allocation
+ * +----------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +-----------------------------+ T2
+ * | SMB_NODE_STATE_DESTROYING |----------> Deletion/Free
+ * +-----------------------------+
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_node_lookup(). If the node looked for is
+ * not found in the has table a new node is created. The reference count is
+ * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_node_release(). If the reference count
+ * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
+ * reference count will be given out for that node.
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_node_release(). The structure is deleted.
+ *
+ * Comments
+ * --------
+ *
+ * The reason the smb node has 2 states is the following synchronization
+ * rule:
+ *
+ * There's a mutex embedded in the node used to protect its fields and
+ * there's a lock embedded in the bucket of the hash table the node belongs
+ * to. To increment or to decrement the reference count the mutex must be
+ * entered. To insert the node into the bucket and to remove it from the
+ * bucket the lock must be entered in RW_WRITER mode. When both (mutex and
+ * lock) have to be entered, the lock has always to be entered first then
+ * the mutex. This prevents a deadlock between smb_node_lookup() and
+ * smb_node_release() from occurring. However, in smb_node_release() when the
+ * reference count drops to zero and triggers the deletion of the node, the
+ * mutex has to be released before entering the lock of the bucket (to
+ * remove the node). This creates a window during which the node that is
+ * about to be freed could be given out by smb_node_lookup(). To close that
+ * window the node is moved to the state SMB_NODE_STATE_DESTROYING before
+ * releasing the mutex. That way, even if smb_node_lookup() finds it, the
+ * state will indicate that the node should be treated as non existent (of
+ * course the state of the node should be tested/updated under the
+ * protection of the mutex).
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <sys/pathname.h>
+#include <sys/sdt.h>
+
+uint32_t smb_is_executable(char *path);
+static void smb_node_delete_on_close(smb_node_t *node);
+
+uint32_t smb_node_hit = 0;
+uint32_t smb_node_miss = 0;
+uint32_t smb_node_alloc = 0;
+uint32_t smb_node_free = 0;
+
+#define VALIDATE_DIR_NODE(_dir_, _node_) \
+ ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
+ ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
+ ASSERT((_dir_)->dir_snode != (_node_));
+
+/*
+ * smb_node_lookup()
+ *
+ * NOTE: This routine should only be called by the file system interface layer,
+ * and not by SMB.
+ *
+ * smb_node_lookup() is called upon successful lookup, mkdir, and create
+ * (for both non-streams and streams). In each of these cases, a held vnode is
+ * passed into this routine. If an smb_node already exists for this vnode,
+ * the vp is released. Otherwise, a new smb_node will be created and the
+ * reference will be held until the refcnt on the node goes to 0 (see
+ * smb_node_release()).
+ *
+ * A reference is taken on the smb_node whether found in the hash table
+ * or newly created.
+ *
+ * If an smb_node needs to be created, a reference is also taken on the
+ * dir_snode (if passed in).
+ *
+ * See smb_node_release() for details on the release of these references.
+ */
+
+/*ARGSUSED*/
+smb_node_t *
+smb_node_lookup(
+ struct smb_request *sr,
+ struct open_param *op,
+ cred_t *cred,
+ vnode_t *vp,
+ char *od_name,
+ smb_node_t *dir_snode,
+ smb_node_t *unnamed_node,
+ smb_attr_t *attr)
+{
+ smb_llist_t *node_hdr;
+ smb_node_t *node;
+ uint32_t hashkey = 0;
+ fs_desc_t fsd;
+ int error;
+ krw_t lock_mode;
+ caller_context_t ct;
+ vnode_t *unnamed_vp = NULL;
+
+ /*
+ * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
+ * because the node may not yet exist. We also do not want to call
+ * it with the list lock held.
+ */
+
+ if (unnamed_node)
+ unnamed_vp = unnamed_node->vp;
+
+ /*
+ * This getattr is performed on behalf of the server
+ * that's why kcred is used not the user's cred
+ */
+ smb_get_caller_context(sr, &ct);
+ attr->sa_mask = SMB_AT_ALL;
+ error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred, &ct);
+ if (error)
+ return (NULL);
+
+ if (sr) {
+ if (sr->tid_tree) {
+ /*
+ * The fsd for a file is that of the tree, even
+ * if the file resides in a different mountpoint
+ * under the share.
+ */
+ fsd = sr->tid_tree->t_fsd;
+ } else {
+ /*
+ * This should be getting executed only for the
+ * tree's root smb_node.
+ */
+ fsd = vp->v_vfsp->vfs_fsid;
+ }
+ } else {
+ fsd = vp->v_vfsp->vfs_fsid;
+ }
+
+ hashkey = fsd.val[0] + attr->sa_vattr.va_nodeid;
+ hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
+ node_hdr = &smb_info.node_hash_table[(hashkey & SMBND_HASH_MASK)];
+ lock_mode = RW_READER;
+
+ smb_llist_enter(node_hdr, lock_mode);
+ for (;;) {
+ node = list_head(&node_hdr->ll_list);
+ while (node) {
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(node->n_hash_bucket == node_hdr);
+ if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
+ smb_rwx_xenter(&node->n_lock);
+ DTRACE_PROBE1(smb_node_lookup_hit,
+ smb_node_t *, node);
+ switch (node->n_state) {
+ case SMB_NODE_STATE_AVAILABLE:
+ /* The node was found. */
+ node->n_refcnt++;
+ if ((node->dir_snode == NULL) &&
+ (dir_snode != NULL) &&
+ (strcmp(od_name, "..") != 0) &&
+ (strcmp(od_name, ".") != 0)) {
+ VALIDATE_DIR_NODE(dir_snode,
+ node);
+ node->dir_snode = dir_snode;
+ smb_node_ref(dir_snode);
+ }
+ node->attr = *attr;
+
+ smb_audit_node(node);
+ smb_rwx_xexit(&node->n_lock);
+ smb_llist_exit(node_hdr);
+ VN_RELE(vp);
+ return (node);
+
+ case SMB_NODE_STATE_DESTROYING:
+ /*
+ * Although the node exists it is about
+ * to be destroyed. We act as it hasn't
+ * been found.
+ */
+ smb_rwx_xexit(&node->n_lock);
+ break;
+ default:
+ /*
+ * Although the node exists it is in an
+ * unknown state. We act as it hasn't
+ * been found.
+ */
+ ASSERT(0);
+ smb_rwx_xexit(&node->n_lock);
+ break;
+ }
+ }
+ node = smb_llist_next(node_hdr, node);
+ }
+ if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
+ lock_mode = RW_WRITER;
+ continue;
+ }
+ break;
+ }
+ node = kmem_cache_alloc(smb_info.si_cache_node, KM_SLEEP);
+ smb_node_alloc++;
+
+ bzero(node, sizeof (smb_node_t));
+
+ node->n_state = SMB_NODE_STATE_AVAILABLE;
+ node->n_hash_bucket = node_hdr;
+
+ if (fsd_chkcap(&fsd, FSOLF_READONLY) > 0) {
+ node->flags |= NODE_READ_ONLY;
+ }
+
+ smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
+ offsetof(smb_ofile_t, f_nnd));
+ smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
+ offsetof(smb_lock_t, l_lnd));
+ node->n_hashkey = hashkey;
+ node->n_refcnt = 1;
+
+ if (sr) {
+ node->n_orig_session_id = sr->session->s_kid;
+ node->n_orig_uid = crgetuid(sr->user_cr);
+ }
+
+ node->vp = vp;
+
+ ASSERT(od_name);
+ (void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
+ node->tree_fsd = fsd;
+
+ if (op)
+ node->flags |= smb_is_executable(op->fqi.last_comp);
+
+ if (dir_snode) {
+ smb_node_ref(dir_snode);
+ node->dir_snode = dir_snode;
+ ASSERT(dir_snode->dir_snode != node);
+ ASSERT((dir_snode->vp->v_xattrdir) ||
+ (dir_snode->vp->v_type == VDIR));
+ }
+
+ if (unnamed_node) {
+ smb_node_ref(unnamed_node);
+ node->unnamed_stream_node = unnamed_node;
+ }
+
+ node->attr = *attr;
+ node->flags |= NODE_FLAGS_ATTR_VALID;
+ node->n_size = node->attr.sa_vattr.va_size;
+
+ smb_rwx_init(&node->n_lock);
+ node->n_magic = SMB_NODE_MAGIC;
+ smb_audit_buf_node_create(node);
+
+ DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
+ smb_audit_node(node);
+ smb_llist_insert_head(node_hdr, node);
+ smb_llist_exit(node_hdr);
+ return (node);
+}
+
+/*
+ * smb_stream_node_lookup()
+ *
+ * Note: stream_name (the name that will be stored in the "od_name" field
+ * of a stream's smb_node) is the same as the on-disk name for the stream
+ * except that it does not have SMB_STREAM_PREFIX prepended.
+ */
+
+smb_node_t *
+smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
+ vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
+{
+ smb_node_t *xattrdir_node;
+ smb_node_t *snode;
+ smb_attr_t tmp_attr;
+
+ xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
+ fnode, NULL, &tmp_attr);
+
+ if (xattrdir_node == NULL)
+ return (NULL);
+
+ snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
+ fnode, ret_attr);
+
+ /*
+ * The following VN_HOLD is necessary because the caller will VN_RELE
+ * xattrdirvp in the case of an error. (xattrdir_node has the original
+ * hold on the vnode, which the smb_node_release() call below will
+ * release.)
+ */
+ if (snode == NULL) {
+ VN_HOLD(xattrdirvp);
+ }
+ (void) smb_node_release(xattrdir_node);
+ return (snode);
+}
+
+
+/*
+ * This function should be called whenever a reference is needed on an
+ * smb_node pointer. The copy of an smb_node pointer from one non-local
+ * data structure to another requires a reference to be taken on the smb_node
+ * (unless the usage is localized). Each data structure deallocation routine
+ * will call smb_node_release() on its smb_node pointers.
+ *
+ * In general, an smb_node pointer residing in a structure should never be
+ * stale. A node pointer may be NULL, however, and care should be taken
+ * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
+ * Care also needs to be taken with respect to racing deallocations of a
+ * structure.
+ */
+
+void
+smb_node_ref(smb_node_t *node)
+{
+ ASSERT(node);
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+
+ smb_rwx_xenter(&node->n_lock);
+ node->n_refcnt++;
+ ASSERT(node->n_refcnt);
+ DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
+ smb_audit_node(node);
+ smb_rwx_xexit(&node->n_lock);
+}
+
+/*
+ * smb_node_lookup() takes a hold on an smb_node, whether found in the
+ * hash table or newly created. This hold is expected to be released
+ * in the following manner.
+ *
+ * smb_node_lookup() takes an address of an smb_node pointer. This should
+ * be getting passed down via a lookup (whether path name or component), mkdir,
+ * create. If the original smb_node pointer resides in a data structure, then
+ * the deallocation routine for the data structure is responsible for calling
+ * smb_node_release() on the smb_node pointer. Alternatively,
+ * smb_node_release() can be called as soon as the smb_node pointer is no longer
+ * needed. In this case, callers are responsible for setting an embedded
+ * pointer to NULL if it is known that the last reference is being released.
+ *
+ * If the passed-in address of the smb_node pointer belongs to a local variable,
+ * then the caller with the local variable should call smb_node_release()
+ * directly.
+ *
+ * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
+ * as smb_node_lookup() takes a hold on dir_snode.
+ */
+
+void
+smb_node_release(smb_node_t *node)
+{
+ ASSERT(node);
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+
+ smb_rwx_xenter(&node->n_lock);
+ ASSERT(node->n_refcnt);
+ DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
+ if (--node->n_refcnt == 0) {
+ switch (node->n_state) {
+
+ case SMB_NODE_STATE_AVAILABLE:
+ node->n_state = SMB_NODE_STATE_DESTROYING;
+ smb_rwx_xexit(&node->n_lock);
+
+ smb_llist_enter(node->n_hash_bucket, RW_WRITER);
+ smb_llist_remove(node->n_hash_bucket, node);
+ smb_llist_exit(node->n_hash_bucket);
+
+ /*
+ * Check if the file was deleted
+ */
+ smb_node_delete_on_close(node);
+ node->n_magic = (uint32_t)~SMB_NODE_MAGIC;
+
+ /* These lists should be empty. */
+ smb_llist_destructor(&node->n_ofile_list);
+ smb_llist_destructor(&node->n_lock_list);
+
+ if (node->dir_snode) {
+ ASSERT(node->dir_snode->n_magic ==
+ SMB_NODE_MAGIC);
+ smb_node_release(node->dir_snode);
+ }
+
+ if (node->unnamed_stream_node) {
+ ASSERT(node->unnamed_stream_node->n_magic ==
+ SMB_NODE_MAGIC);
+ smb_node_release(node->unnamed_stream_node);
+ }
+
+ ASSERT(node->vp);
+ VN_RELE(node->vp);
+
+ smb_audit_buf_node_destroy(node);
+ smb_rwx_destroy(&node->n_lock);
+ kmem_cache_free(smb_info.si_cache_node, node);
+ ++smb_node_free;
+ return;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ }
+ smb_audit_node(node);
+ smb_rwx_xexit(&node->n_lock);
+}
+
+static void
+smb_node_delete_on_close(smb_node_t *node)
+{
+ smb_node_t *d_snode;
+ int rc = 0;
+
+ d_snode = node->dir_snode;
+ if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
+
+ node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
+ ASSERT(node->od_name != NULL);
+ if (node->attr.sa_vattr.va_type == VDIR)
+ rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
+ d_snode, node->od_name, 1);
+ else
+ rc = smb_fsop_remove(0, node->delete_on_close_cred,
+ d_snode, node->od_name, 1);
+ smb_cred_rele(node->delete_on_close_cred);
+ }
+ if (rc != 0)
+ cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
+ node->od_name, rc);
+ DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
+}
+
+/*
+ * smb_node_rename()
+ *
+ */
+int
+smb_node_rename(
+ smb_node_t *from_dir_snode,
+ smb_node_t *ret_snode,
+ smb_node_t *to_dir_snode,
+ char *to_name)
+{
+ ASSERT(from_dir_snode);
+ ASSERT(to_dir_snode);
+ ASSERT(ret_snode);
+ ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
+ ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
+ ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE);
+
+ smb_node_ref(to_dir_snode);
+ smb_rwx_xenter(&ret_snode->n_lock);
+ ret_snode->dir_snode = to_dir_snode;
+ smb_rwx_xexit(&ret_snode->n_lock);
+ ASSERT(to_dir_snode->dir_snode != ret_snode);
+ ASSERT((to_dir_snode->vp->v_xattrdir) ||
+ (to_dir_snode->vp->v_type == VDIR));
+ smb_node_release(from_dir_snode);
+
+ (void) strcpy(ret_snode->od_name, to_name);
+
+ /*
+ * XXX Need to update attributes?
+ */
+
+ return (0);
+}
+
+int
+smb_node_root_init()
+{
+ smb_attr_t va;
+
+ /*
+ * Take an explicit hold on rootdir. This goes with the
+ * corresponding release in smb_node_root_fini()/smb_node_release().
+ */
+
+ VN_HOLD(rootdir);
+
+ if ((smb_info.si_root_smb_node = smb_node_lookup(NULL, NULL, kcred,
+ rootdir, ROOTVOL, NULL, NULL, &va)) == NULL)
+ return (-1);
+ else
+ return (0);
+}
+
+void
+smb_node_root_fini()
+{
+ if (smb_info.si_root_smb_node) {
+ smb_node_release(smb_info.si_root_smb_node);
+ smb_info.si_root_smb_node = NULL;
+ }
+}
+
+/*
+ * smb_node_get_size
+ */
+uint64_t
+smb_node_get_size(
+ smb_node_t *node,
+ smb_attr_t *attr)
+{
+ uint64_t size;
+
+ if (attr->sa_vattr.va_type == VDIR)
+ return (0);
+
+ smb_rwx_xenter(&node->n_lock);
+ if (node && (node->flags & NODE_FLAGS_SET_SIZE))
+ size = node->n_size;
+ else
+ size = attr->sa_vattr.va_size;
+ smb_rwx_xexit(&node->n_lock);
+ return (size);
+}
+
+static int
+timeval_cmp(timestruc_t *a, timestruc_t *b)
+{
+ if (a->tv_sec < b->tv_sec)
+ return (-1);
+ if (a->tv_sec > b->tv_sec)
+ return (1);
+ /* Seconds are equal compare tv_nsec */
+ if (a->tv_nsec < b->tv_nsec)
+ return (-1);
+ return (a->tv_nsec > b->tv_nsec);
+}
+
+/*
+ * smb_node_set_time
+ *
+ * This function will update the time stored in the node and
+ * set the appropriate flags. If there is nothing to update
+ * or the node is readonly, the function would return without
+ * any updates. The update is only in the node level and the
+ * attribute in the file system will be updated when client
+ * close the file.
+ */
+void
+smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
+ struct timestruc *mtime, struct timestruc *atime,
+ struct timestruc *ctime, unsigned int what)
+{
+ smb_rwx_xenter(&node->n_lock);
+ if (node->flags & NODE_READ_ONLY || what == 0) {
+ smb_rwx_xexit(&node->n_lock);
+ return;
+ }
+
+ if ((what & SMB_AT_CRTIME && crtime == 0) ||
+ (what & SMB_AT_MTIME && mtime == 0) ||
+ (what & SMB_AT_ATIME && atime == 0) ||
+ (what & SMB_AT_CTIME && ctime == 0)) {
+ smb_rwx_xexit(&node->n_lock);
+ return;
+ }
+
+ if ((what & SMB_AT_CRTIME) &&
+ timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
+ crtime) != 0) {
+ node->what |= SMB_AT_CRTIME;
+ node->attr.sa_crtime = *((timestruc_t *)crtime);
+ }
+
+ if ((what & SMB_AT_MTIME) &&
+ timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
+ mtime) != 0) {
+ node->what |= SMB_AT_MTIME;
+ node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
+ }
+
+ if ((what & SMB_AT_ATIME) &&
+ timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
+ atime) != 0) {
+ node->what |= SMB_AT_ATIME;
+ node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
+ }
+
+ /*
+ * The ctime handling is trickier. It has three scenarios.
+ * 1. Only ctime need to be set and it is the same as the ctime
+ * stored in the node. (update not necessary)
+ * 2. The ctime is the same as the ctime stored in the node but
+ * is not the only time need to be set. (update required)
+ * 3. The ctime need to be set and is not the same as the ctime
+ * stored in the node. (update required)
+ * Unlike other time setting, the ctime needs to be set even when
+ * it is the same as the ctime in the node if there are other time
+ * needs to be set (#2). This will ensure the ctime not being
+ * updated when other times are being updated in the file system.
+ *
+ * Retained file rules:
+ *
+ * 1. Don't add SMB_AT_CTIME to node->what by default because the
+ * request will be rejected by filesystem
+ * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
+ * any request for changing ctime on these files should have
+ * been already rejected
+ */
+ node->what |= SMB_AT_CTIME;
+ if (what & SMB_AT_CTIME) {
+ if ((what == SMB_AT_CTIME) &&
+ timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
+ ctime) == 0) {
+ node->what &= ~SMB_AT_CTIME;
+ } else {
+ gethrestime(&node->attr.sa_vattr.va_ctime);
+ }
+ } else {
+ gethrestime(&node->attr.sa_vattr.va_ctime);
+ }
+ smb_rwx_xexit(&node->n_lock);
+}
+
+
+timestruc_t *
+smb_node_get_crtime(smb_node_t *node)
+{
+ return ((timestruc_t *)&node->attr.sa_crtime);
+}
+
+timestruc_t *
+smb_node_get_atime(smb_node_t *node)
+{
+ return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
+}
+
+timestruc_t *
+smb_node_get_ctime(smb_node_t *node)
+{
+ return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
+}
+
+timestruc_t *
+smb_node_get_mtime(smb_node_t *node)
+{
+ return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
+}
+
+/*
+ * smb_node_set_dosattr
+ *
+ * Parse the specified DOS attributes and, if they have been modified,
+ * update the node cache. This call should be followed by a
+ * smb_sync_fsattr() call to write the attribute changes to filesystem.
+ */
+void
+smb_node_set_dosattr(smb_node_t *node, uint32_t dos_attr)
+{
+ unsigned int mode; /* New mode */
+
+ mode = 0;
+
+ /* Handle the archive bit */
+ if (dos_attr & SMB_FA_ARCHIVE)
+ mode |= FILE_ATTRIBUTE_ARCHIVE;
+
+ /* Handle the readonly bit */
+ if (dos_attr & SMB_FA_READONLY)
+ mode |= FILE_ATTRIBUTE_READONLY;
+
+ /* Handle the hidden bit */
+ if (dos_attr & SMB_FA_HIDDEN)
+ mode |= FILE_ATTRIBUTE_HIDDEN;
+
+ /* Handle the system bit */
+ if (dos_attr & SMB_FA_SYSTEM)
+ mode |= FILE_ATTRIBUTE_SYSTEM;
+
+ smb_rwx_xenter(&node->n_lock);
+ if (node->attr.sa_dosattr != mode) {
+ node->attr.sa_dosattr = mode;
+ node->what |= SMB_AT_DOSATTR;
+ }
+ smb_rwx_xexit(&node->n_lock);
+}
+
+/*
+ * smb_node_get_dosattr
+ *
+ * This function will get dos attribute using the node.
+ */
+uint32_t
+smb_node_get_dosattr(smb_node_t *node)
+{
+ return (smb_mode_to_dos_attributes(&node->attr));
+}
+
+int
+smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
+{
+ int rc = -1;
+
+ smb_rwx_xenter(&node->n_lock);
+ if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
+ !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
+ crhold(cr);
+ node->delete_on_close_cred = cr;
+ node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
+ rc = 0;
+ }
+ smb_rwx_xexit(&node->n_lock);
+ return (rc);
+}
+
+void
+smb_node_reset_delete_on_close(smb_node_t *node)
+{
+ smb_rwx_xenter(&node->n_lock);
+ if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
+ node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
+ crfree(node->delete_on_close_cred);
+ node->delete_on_close_cred = NULL;
+ }
+ smb_rwx_xexit(&node->n_lock);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c
new file mode 100644
index 0000000000..79334395f0
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: nt_cancel
+ *
+ * This SMB allows a client to cancel a request currently pending at the
+ * server.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; No words are sent (== 0)
+ * USHORT ByteCount; No bytes (==0)
+ *
+ * The Sid, Uid, Pid, Tid, and Mid fields of the SMB are used to locate an
+ * pending server request from this session. If a pending request is
+ * found, it is "hurried along" which may result in success or failure of
+ * the original request. No other response is generated for this SMB.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_nt_cancel(struct smb_request *sr)
+{
+ struct smb_request *req;
+ struct smb_session *session;
+
+ session = sr->session;
+
+ smb_slist_enter(&session->s_req_list);
+ req = smb_slist_head(&session->s_req_list);
+ while (req) {
+ ASSERT(req->sr_magic == SMB_REQ_MAGIC);
+ if ((req != sr) &&
+ (req->smb_sid == sr->smb_sid) &&
+ (req->smb_uid == sr->smb_uid) &&
+ (req->smb_pid == sr->smb_pid) &&
+ (req->smb_tid == sr->smb_tid) &&
+ (req->smb_mid == sr->smb_mid)) {
+ smb_request_cancel(req);
+ }
+ req = smb_slist_next(&session->s_req_list, req);
+ }
+ smb_slist_exit(&session->s_req_list);
+
+ /* Now, search the notify change queue to find the request */
+
+ smb_reply_specific_cancel_request(sr);
+
+ return (SDRC_NO_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
new file mode 100644
index 0000000000..36a3df5992
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
@@ -0,0 +1,373 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This command is used to create or open a file or directory.
+ */
+
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_vops.h>
+
+/*
+ * smb_com_nt_create_andx
+ *
+ * This command is used to create or open a file or directory.
+ *
+ * Client Request Description
+ * ================================= ==================================
+ *
+ * UCHAR WordCount; Count of parameter words = 24
+ * UCHAR AndXCommand; Secondary command; 0xFF = None
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * UCHAR Reserved; Reserved (must be 0)
+ * USHORT NameLength; Length of Name[] in bytes
+ * ULONG Flags; Create bit set:
+ * 0x02 - Request an oplock
+ * 0x04 - Request a batch oplock
+ * 0x08 - Target of open must be
+ * directory
+ * ULONG RootDirectoryFid; If non-zero, open is relative to
+ * this directory
+ * ACCESS_MASK DesiredAccess; access desired
+ * LARGE_INTEGER AllocationSize; Initial allocation size
+ * ULONG ExtFileAttributes; File attributes
+ * ULONG ShareAccess; Type of share access
+ * ULONG CreateDisposition; Action to take if file exists or
+ * not
+ * ULONG CreateOptions; Options to use if creating a file
+ * ULONG ImpersonationLevel; Security QOS information
+ * UCHAR SecurityFlags; Security tracking mode flags:
+ * 0x1 - SECURITY_CONTEXT_TRACKING
+ * 0x2 - SECURITY_EFFECTIVE_ONLY
+ * USHORT ByteCount; Length of byte parameters
+ * STRING Name[]; File to open or create
+ *
+ * The DesiredAccess parameter is specified in section 3.7 on Access Mask
+ * Encoding.
+ *
+ * If no value is specified, it still allows an application to query
+ * attributes without actually accessing the file.
+ *
+ * The ExtFIleAttributes parameter specifies the file attributes and flags
+ * for the file. The parameter's value is the sum of allowed attributes and
+ * flags defined in section 3.11 on Extended File Attribute Encoding
+ *
+ * The ShareAccess field Specifies how this file can be shared. This
+ * parameter must be some combination of the following values:
+ *
+ * Name Value Meaning
+ * 0 Prevents the file from being shared.
+ * FILE_SHARE_READ 0x00000001 Other open operations can be performed on
+ * the file for read access.
+ * FILE_SHARE_WRITE 0x00000002 Other open operations can be performed on
+ * the file for write access.
+ * FILE_SHARE_DELETE 0x00000004 Other open operations can be performed on
+ * the file for delete access.
+ *
+ * The CreateDisposition parameter can contain one of the following values:
+ *
+ * CREATE_NEW Creates a new file. The function fails if the
+ * specified file already exists.
+ * CREATE_ALWAYS Creates a new file. The function overwrites the file
+ * if it exists.
+ * OPEN_EXISTING Opens the file. The function fails if the file does
+ * not exist.
+ * OPEN_ALWAYS Opens the file, if it exists. If the file does not
+ * exist, act like CREATE_NEW.
+ * TRUNCATE_EXISTING Opens the file. Once opened, the file is truncated so
+ * that its size is zero bytes. The calling process must
+ * open the file with at least GENERIC_WRITE access. The
+ * function fails if the file does not exist.
+ *
+ * The ImpersonationLevel parameter can contain one or more of the
+ * following values:
+ *
+ * SECURITY_ANONYMOUS Specifies to impersonate the client at the
+ * Anonymous impersonation level.
+ * SECURITY_IDENTIFICATION Specifies to impersonate the client at the
+ * Identification impersonation level.
+ * SECURITY_IMPERSONATION Specifies to impersonate the client at the
+ * Impersonation impersonation level.
+ * SECURITY_DELEGATION Specifies to impersonate the client at the
+ * Delegation impersonation level.
+ *
+ * The SecurityFlags parameter can have either of the following two flags
+ * set:
+ *
+ * SECURITY_CONTEXT_TRACKING Specifies that the security tracking mode is
+ * dynamic. If this flag is not specified,
+ * Security Tracking Mode is static.
+ * SECURITY_EFFECTIVE_ONLY Specifies that only the enabled aspects of
+ * the client's security context are available
+ * to the server. If you do not specify this
+ * flag, all aspects of the client's security
+ * context are available. This flag allows the
+ * client to limit the groups and privileges
+ * that a server can use while impersonating the
+ * client.
+ *
+ * The response is as follows:
+ *
+ * Server Response Description
+ * ================================= ==================================
+ *
+ * UCHAR WordCount; Count of parameter words = 26
+ * UCHAR AndXCommand; Secondary 0xFF = None
+ * command;
+ * UCHAR AndXReserved; MBZ
+ * USHORT AndXOffset; Offset to next command WordCount
+ * UCHAR OplockLevel; The oplock level granted
+ * 0 - No oplock granted
+ * 1 - Exclusive oplock granted
+ * 2 - Batch oplock granted
+ * 3 - Level II oplock granted
+ * USHORT Fid; The file ID
+ * ULONG CreateAction; The action taken
+ * TIME CreationTime; The time the file was created
+ * TIME LastAccessTime; The time the file was accessed
+ * TIME LastWriteTime; The time the file was last written
+ * TIME ChangeTime; The time the file was last changed
+ * ULONG ExtFileAttributes; The file attributes
+ * LARGE_INTEGER AllocationSize; The number of bytes allocated
+ * LARGE_INTEGER EndOfFile; The end of file offset
+ * USHORT FileType;
+ * USHORT DeviceState; state of IPC device (e.g. pipe)
+ * BOOLEAN Directory; TRUE if this is a directory
+ * USHORT ByteCount; = 0
+ *
+ * The following SMBs may follow SMB_COM_NT_CREATE_ANDX:
+ *
+ * SMB_COM_READ SMB_COM_READ_ANDX
+ * SMB_COM_IOCTL
+ */
+int
+smb_com_nt_create_andx(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ unsigned char OplockLevel;
+ unsigned char DirFlag;
+ unsigned char SecurityFlags;
+ uint32_t ExtFileAttributes;
+ uint32_t Flags;
+ uint32_t ImpersonationLevel;
+ uint32_t RootDirFid;
+ unsigned short NameLength;
+ smb_attr_t new_attr;
+ smb_node_t *node;
+ DWORD status;
+ int count;
+ int rc;
+
+ op->dsize = 0;
+
+ rc = smbsr_decode_vwv(sr, "5.wlllqlllllb",
+ &NameLength,
+ &Flags,
+ &RootDirFid,
+ &op->desired_access,
+ &op->dsize,
+ &ExtFileAttributes,
+ &op->share_access,
+ &op->create_disposition,
+ &op->create_options,
+ &ImpersonationLevel,
+ &SecurityFlags);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (NameLength >= MAXPATHLEN) {
+ smbsr_raise_nt_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%#u", sr, NameLength, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
+ !(op->desired_access & DELETE)) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->fqi.srch_attr = 0;
+ op->omode = 0;
+ op->utime.tv_sec = op->utime.tv_nsec = 0;
+ op->my_flags = 0;
+ op->dattr = ExtFileAttributes;
+
+ if (Flags) {
+ if (Flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
+ if (Flags & NT_CREATE_FLAG_REQUEST_OPBATCH) {
+ op->my_flags = MYF_BATCH_OPLOCK;
+ } else {
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ }
+ }
+ if (Flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)
+ op->my_flags |= MYF_MUST_BE_DIRECTORY;
+ }
+
+ if (ExtFileAttributes & FILE_FLAG_WRITE_THROUGH)
+ op->create_options |= FILE_WRITE_THROUGH;
+
+ if (ExtFileAttributes & FILE_FLAG_DELETE_ON_CLOSE)
+ op->create_options |= FILE_DELETE_ON_CLOSE;
+
+ if (RootDirFid == 0) {
+ op->fqi.dir_snode = sr->tid_tree->t_snode;
+ } else {
+ sr->smb_fid = (ushort_t)RootDirFid;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ op->fqi.dir_snode = sr->fid_ofile->f_node;
+ smbsr_disconnect_file(sr);
+ }
+
+ status = NT_STATUS_SUCCESS;
+ /*
+ * According to NT, when exclusive share access failed,
+ * instead of raising "access deny" error immediately,
+ * we should wait for the client holding the exclusive
+ * file to close the file. If the wait timed out, we
+ * report a sharing violation; otherwise, we grant access.
+ * smb_open_subr returns NT_STATUS_SHARING_VIOLATION when
+ * it encounters an exclusive share access deny: we wait
+ * and retry.
+ */
+ for (count = 0; count <= 4; count++) {
+ if (count) {
+ delay(MSEC_TO_TICK(400));
+ }
+
+ if ((status = smb_open_subr(sr)) == NT_STATUS_SUCCESS)
+ break;
+ }
+
+ if (status != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_SHARING_VIOLATION)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ else
+ smbsr_raise_nt_error(sr, status);
+
+ /* NOTREACHED */
+ }
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ switch (MYF_OPLOCK_TYPE(op->my_flags)) {
+ case MYF_EXCLUSIVE_OPLOCK :
+ OplockLevel = 1;
+ break;
+ case MYF_BATCH_OPLOCK :
+ OplockLevel = 2;
+ break;
+ case MYF_LEVEL_II_OPLOCK :
+ OplockLevel = 3;
+ break;
+ case MYF_OPLOCK_NONE :
+ default:
+ OplockLevel = 0;
+ break;
+ }
+
+ if (op->create_options & FILE_DELETE_ON_CLOSE)
+ smb_preset_delete_on_close(sr->fid_ofile);
+
+ /*
+ * Set up the directory flag and ensure that
+ * we don't return a stale file size.
+ */
+ node = sr->fid_ofile->f_node;
+ if (node->attr.sa_vattr.va_type == VDIR) {
+ DirFlag = 1;
+ new_attr.sa_vattr.va_size = 0;
+ } else {
+ DirFlag = 0;
+ new_attr.sa_mask = SMB_AT_SIZE;
+ (void) smb_fsop_getattr(sr, kcred, node, &new_attr);
+ node->attr.sa_vattr.va_size = new_attr.sa_vattr.va_size;
+ }
+
+ smbsr_encode_result(sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
+ 34,
+ sr->andx_com,
+ 0x67,
+ OplockLevel,
+ sr->smb_fid,
+ op->action_taken,
+ &node->attr.sa_crtime,
+ &node->attr.sa_vattr.va_atime,
+ &node->attr.sa_vattr.va_mtime,
+ &node->attr.sa_vattr.va_ctime,
+ op->dattr & FILE_ATTRIBUTE_MASK,
+ new_attr.sa_vattr.va_size,
+ new_attr.sa_vattr.va_size,
+ op->ftype,
+ op->devstate,
+ DirFlag,
+ 0);
+ } else {
+ /* Named PIPE */
+ OplockLevel = 0;
+ smbsr_encode_result(sr, 34, 0, "bb.wbwlqqqqlqqwwbw",
+ 34,
+ sr->andx_com,
+ 0x67,
+ OplockLevel,
+ sr->smb_fid,
+ op->action_taken,
+ 0LL,
+ 0LL,
+ 0LL,
+ 0LL,
+ SMB_FA_NORMAL,
+ 0x1000LL,
+ 0LL,
+ op->ftype,
+ op->devstate,
+ 0,
+ 0);
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
new file mode 100644
index 0000000000..63f1f81440
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This command is used to create or open a file or directory, when EAs
+ * or an SD must be applied to the file. The functionality is similar
+ * to SmbNtCreateAndx with the option to supply extended attributes or
+ * a security descriptor.
+ *
+ * Note: we don't decode the extended attributes because we don't
+ * support them at this time.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_vops.h>
+
+/*
+ * smb_nt_transact_create
+ *
+ * This command is used to create or open a file or directory, when EAs
+ * or an SD must be applied to the file. The request parameter block
+ * encoding, data block encoding and output parameter block encoding are
+ * described in CIFS section 4.2.2.
+ *
+ * The format of the command is SmbNtTransact but it is basically the same
+ * as SmbNtCreateAndx with the option to supply extended attributes or a
+ * security descriptor. For information not defined in CIFS section 4.2.2
+ * see section 4.2.1 (NT_CREATE_ANDX).
+ */
+int
+smb_nt_transact_create(struct smb_request *sr, struct smb_xa *xa)
+{
+ struct open_param *op = &sr->arg.open;
+ uint8_t OplockLevel;
+ uint8_t DirFlag;
+ uint8_t SecurityFlags;
+ uint32_t ExtFileAttributes;
+ uint32_t sd_len;
+ uint32_t EaLength;
+ uint32_t Flags;
+ uint32_t ImpersonationLevel;
+ uint32_t RootDirFid;
+ uint32_t NameLength;
+ smb_attr_t new_attr;
+ smb_node_t *node;
+ DWORD status;
+ int rc;
+
+ rc = smb_decode_mbc(&xa->req_param_mb, "%lllqllllllllb",
+ sr,
+ &Flags,
+ &RootDirFid,
+ &op->desired_access,
+ &op->dsize,
+ &ExtFileAttributes,
+ &op->share_access,
+ &op->create_disposition,
+ &op->create_options,
+ &sd_len,
+ &EaLength,
+ &NameLength,
+ &ImpersonationLevel,
+ &SecurityFlags);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /*
+ * If name length is zero, interpret as "\".
+ */
+ if (NameLength == 0) {
+ op->fqi.path = "\\";
+ } else {
+ rc = smb_decode_mbc(&xa->req_param_mb, "%#u",
+ sr, NameLength, &op->fqi.path);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ }
+
+ if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
+ !(op->desired_access & DELETE)) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ if (sd_len >= sizeof (smb_sdbuf_t)) {
+ /* ignore security setting for files on Unix volumes */
+ op->sd_buf = kmem_alloc(sd_len, KM_SLEEP);
+
+ if ((smb_decode_mbc(&xa->req_data_mb, "#c", sd_len,
+ (char *)op->sd_buf)) != 0) {
+ kmem_free(op->sd_buf, sd_len);
+ smbsr_raise_nt_error(sr, NT_STATUS_BUFFER_TOO_SMALL);
+ /* NOTREACHED */
+ }
+ } else {
+ op->sd_buf = 0;
+ }
+
+ op->fqi.srch_attr = 0;
+ op->omode = 0;
+
+ op->utime.tv_sec = op->utime.tv_nsec = 0;
+ op->my_flags = 0;
+
+ op->dattr = ExtFileAttributes;
+
+ if (Flags) {
+ if (Flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
+ if (Flags & NT_CREATE_FLAG_REQUEST_OPBATCH) {
+ op->my_flags = MYF_BATCH_OPLOCK;
+ } else {
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ }
+ }
+ if (Flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)
+ op->my_flags |= MYF_MUST_BE_DIRECTORY;
+ }
+
+ if (ExtFileAttributes & FILE_FLAG_WRITE_THROUGH)
+ op->create_options |= FILE_WRITE_THROUGH;
+
+ if (ExtFileAttributes & FILE_FLAG_DELETE_ON_CLOSE)
+ op->create_options |= FILE_DELETE_ON_CLOSE;
+
+ if (RootDirFid == 0) {
+ op->fqi.dir_snode = sr->tid_tree->t_snode;
+ } else {
+ sr->smb_fid = (ushort_t)RootDirFid;
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ /*
+ * XXX: ASSERT() for now but we should understand if the test
+ * of the return value is missing because it cannot happen.
+ */
+ ASSERT(sr->fid_ofile != NULL);
+ op->fqi.dir_snode = sr->fid_ofile->f_node;
+ smbsr_disconnect_file(sr);
+ }
+
+ status = smb_open_subr(sr);
+ if (op->sd_buf)
+ kmem_free(op->sd_buf, sd_len);
+
+ if (status != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_SHARING_VIOLATION)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ else
+ smbsr_raise_nt_error(sr, status);
+
+ /* NOTREACHED */
+ }
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ switch (MYF_OPLOCK_TYPE(op->my_flags)) {
+ case MYF_EXCLUSIVE_OPLOCK :
+ OplockLevel = 1;
+ break;
+ case MYF_BATCH_OPLOCK :
+ OplockLevel = 2;
+ break;
+ case MYF_LEVEL_II_OPLOCK :
+ OplockLevel = 3;
+ break;
+ case MYF_OPLOCK_NONE :
+ default:
+ OplockLevel = 0;
+ break;
+ }
+
+ if (op->create_options & FILE_DELETE_ON_CLOSE)
+ smb_preset_delete_on_close(sr->fid_ofile);
+
+ /*
+ * Set up the directory flag and ensure that
+ * we don't return a stale file size.
+ */
+ node = sr->fid_ofile->f_node;
+ if (node->attr.sa_vattr.va_type == VDIR) {
+ DirFlag = 1;
+ new_attr.sa_vattr.va_size = 0;
+ } else {
+ DirFlag = 0;
+ new_attr.sa_mask = SMB_AT_SIZE;
+ (void) smb_fsop_getattr(sr, kcred, node, &new_attr);
+ node->attr.sa_vattr.va_size = new_attr.sa_vattr.va_size;
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
+ OplockLevel,
+ sr->smb_fid,
+ op->action_taken,
+ 0, /* EaErrorOffset */
+ &node->attr.sa_crtime,
+ &node->attr.sa_vattr.va_atime,
+ &node->attr.sa_vattr.va_mtime,
+ &node->attr.sa_vattr.va_ctime,
+ op->dattr & FILE_ATTRIBUTE_MASK,
+ new_attr.sa_vattr.va_size,
+ new_attr.sa_vattr.va_size,
+ op->ftype,
+ op->devstate,
+ DirFlag);
+ } else {
+ /* Named PIPE */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
+ 0,
+ sr->smb_fid,
+ op->action_taken,
+ 0, /* EaErrorOffset */
+ 0LL,
+ 0LL,
+ 0LL,
+ 0LL,
+ op->dattr,
+ 0x1000LL,
+ 0LL,
+ op->ftype,
+ op->devstate,
+ 0);
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
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
new file mode 100644
index 0000000000..5725814a0f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/winioctl.h>
+#include <smbsrv/ntstatus.h>
+
+
+/*
+ * This table defines the list of IOCTL/FSCTL values for which we'll
+ * return a specific NT status code, based on observation of NT.
+ */
+static struct {
+ uint32_t fcode;
+ DWORD status;
+} ioctl_ret_tbl[] = {
+ {FSCTL_GET_OBJECT_ID, NT_STATUS_INVALID_PARAMETER},
+ {FSCTL_QUERY_ALLOCATED_RANGES, NT_STATUS_INVALID_PARAMETER}
+};
+
+
+/*
+ * smb_nt_transact_ioctl
+ *
+ * This command allows device and file system control functions to be
+ * transferred transparently from client to server. This is currently
+ * a stub to work out whether or not we need to return an NT status
+ * code.
+ *
+ * Setup Words Encoding Description
+ * =========================== =========================================
+ * ULONG FunctionCode; NT device or file system control code
+ * USHORT Fid; Handle for io or fs control. Unless BIT0
+ * of ISFLAGS is set.
+ * BOOLEAN IsFsctl; Indicates whether the command is a device
+ * control (FALSE) or a file system control
+ * (TRUE).
+ * UCHAR IsFlags; BIT0 - command is to be applied to share
+ * root handle. Share must be a DFS share.
+ *
+ * Data Block Encoding Description
+ * =========================== =========================================
+ * Data[ TotalDataCount ] Passed to the Fsctl or Ioctl
+ *
+ * Server Response Description
+ * =========================== ==================================
+ * SetupCount 1
+ * Setup[0] Length of information returned by
+ * io or fs control.
+ * DataCount Length of information returned by
+ * io or fs control.
+ * Data[ DataCount ] The results of the io or fs control.
+ */
+int
+smb_nt_transact_ioctl(struct smb_request *sr, struct smb_xa *xa)
+{
+ DWORD status = NT_STATUS_SUCCESS;
+ uint32_t fcode;
+ unsigned short fid;
+ unsigned char is_fsctl;
+ unsigned char is_flags;
+ int i;
+
+ if (smb_decode_mbc(&xa->req_setup_mb, "lwbb",
+ &fcode,
+ &fid,
+ &is_fsctl,
+ &is_flags) != 0) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ }
+
+ for (i = 0;
+ i < sizeof (ioctl_ret_tbl) / sizeof (ioctl_ret_tbl[0]);
+ i++) {
+ if (ioctl_ret_tbl[i].fcode == fcode) {
+ status = ioctl_ret_tbl[i].status;
+ break;
+ }
+ }
+
+ if (status != NT_STATUS_SUCCESS)
+ smbsr_raise_nt_error(sr, status);
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "l", 0);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
new file mode 100644
index 0000000000..d70ddf4fc0
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
@@ -0,0 +1,613 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * File Change Notification (FCN)
+ */
+
+/*
+ * SMB: nt_transact_notify_change
+ *
+ * Client Setup Words Description
+ * ================================== =================================
+ *
+ * ULONG CompletionFilter; Specifies operation to monitor
+ * USHORT Fid; Fid of directory to monitor
+ * BOOLEAN WatchTree; TRUE = watch all subdirectories too
+ * UCHAR Reserved; MBZ
+ *
+ * This command notifies the client when the directory specified by Fid is
+ * modified. It also returns the name(s) of the file(s) that changed. The
+ * command completes once the directory has been modified based on the
+ * supplied CompletionFilter. The command is a "single shot" and therefore
+ * needs to be reissued to watch for more directory changes.
+ *
+ * A directory file must be opened before this command may be used. Once
+ * the directory is open, this command may be used to begin watching files
+ * and subdirectories in the specified directory for changes. The first
+ * time the command is issued, the MaxParameterCount field in the transact
+ * header determines the size of the buffer that will be used at the server
+ * to buffer directory change information between issuances of the notify
+ * change commands.
+ *
+ * When a change that is in the CompletionFilter is made to the directory,
+ * the command completes. The names of the files that have changed since
+ * the last time the command was issued are returned to the client. The
+ * ParameterCount field of the response indicates the number of bytes that
+ * are being returned. If too many files have changed since the last time
+ * the command was issued, then zero bytes are returned and an alternate
+ * status code is returned in the Status field of the response.
+ *
+ * The CompletionFilter is a mask created as the sum of any of the
+ * following flags:
+ *
+ * FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
+ * FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
+ * FILE_NOTIFY_CHANGE_NAME 0x00000003
+ * FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
+ * FILE_NOTIFY_CHANGE_SIZE 0x00000008
+ * FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
+ * FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
+ * FILE_NOTIFY_CHANGE_CREATION 0x00000040
+ * FILE_NOTIFY_CHANGE_EA 0x00000080
+ * FILE_NOTIFY_CHANGE_SECURITY 0x00000100
+ * FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
+ * FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
+ * FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
+ *
+ * Server Response Description
+ * ================================== ================================
+ * ParameterCount # of bytes of change data
+ * Parameters[ ParameterCount ] FILE_NOTIFY_INFORMATION
+ * structures
+ *
+ * The response contains FILE_NOTIFY_INFORMATION structures, as defined
+ * below. The NextEntryOffset field of the structure specifies the offset,
+ * in bytes, from the start of the current entry to the next entry in the
+ * list. If this is the last entry in the list, this field is zero. Each
+ * entry in the list must be longword aligned, so NextEntryOffset must be a
+ * multiple of four.
+ *
+ * typedef struct {
+ * ULONG NextEntryOffset;
+ * ULONG Action;
+ * ULONG FileNameLength;
+ * WCHAR FileName[1];
+ * } FILE_NOTIFY_INFORMATION;
+ *
+ * Where Action describes what happened to the file named FileName:
+ *
+ * FILE_ACTION_ADDED 0x00000001
+ * FILE_ACTION_REMOVED 0x00000002
+ * FILE_ACTION_MODIFIED 0x00000003
+ * FILE_ACTION_RENAMED_OLD_NAME 0x00000004
+ * FILE_ACTION_RENAMED_NEW_NAME 0x00000005
+ * FILE_ACTION_ADDED_STREAM 0x00000006
+ * FILE_ACTION_REMOVED_STREAM 0x00000007
+ * FILE_ACTION_MODIFIED_STREAM 0x00000008
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <sys/sdt.h>
+
+/*
+ * smb_nt_transact_notify_change
+ *
+ * This function is responsible for processing NOTIFY CHANGE requests.
+ * Requests are stored in a global queue. This queue is processed when
+ * a monitored directory is changed or client cancels one of its already
+ * sent requests.
+ */
+int
+smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint32_t CompletionFilter;
+ unsigned char WatchTree;
+ smb_node_t *node;
+
+ if (smb_decode_mbc(&xa->req_setup_mb, "lwb",
+ &CompletionFilter, &sr->smb_fid, &WatchTree) != 0)
+ return (SDRC_UNSUPPORTED);
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ node = sr->fid_ofile->f_node;
+
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ /*
+ * notify change requests are only valid for
+ * directories
+ */
+ smbsr_raise_nt_error(sr, NT_STATUS_NOT_A_DIRECTORY);
+ /* NOTREACHED */
+ }
+
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_ACTIVE:
+ node->waiting_event++;
+ node->flags |= NODE_FLAGS_NOTIFY_CHANGE;
+ if ((node->flags & NODE_FLAGS_CHANGED) == 0) {
+ sr->sr_ncr.nc_node = node;
+ sr->sr_ncr.nc_flags = CompletionFilter;
+ if (WatchTree)
+ sr->sr_ncr.nc_flags |= NODE_FLAGS_WATCH_TREE;
+
+ sr->sr_keep = B_TRUE;
+ sr->sr_state = SMB_REQ_STATE_WAITING_EVENT;
+ smb_slist_insert_tail(&smb_info.si_ncr_list, sr);
+
+ /*
+ * Monitor events system-wide.
+ *
+ * XXX: smb_node_ref() and smb_node_release()
+ * take &node->n_lock. May need alternate forms
+ * of these routines if node->n_lock is taken
+ * around calls to smb_fem_fcn_install() and
+ * smb_fem_fcn_uninstall().
+ */
+
+ smb_fem_fcn_install(node);
+
+ mutex_exit(&sr->sr_mutex);
+ return (SDRC_NO_REPLY);
+ } else {
+ /* node already changed, reply immediately */
+ if (--node->waiting_event == 0)
+ node->flags &=
+ ~(NODE_FLAGS_NOTIFY_CHANGE |
+ NODE_FLAGS_CHANGED);
+ mutex_exit(&sr->sr_mutex);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ case SMB_REQ_STATE_CANCELED:
+ mutex_exit(&sr->sr_mutex);
+ smbsr_raise_nt_error(sr, NT_STATUS_CANCELLED);
+ /* NOTREACHED */
+ default:
+ ASSERT(0);
+ mutex_exit(&sr->sr_mutex);
+ return (SDRC_NORMAL_REPLY);
+ }
+}
+
+/*
+ * smb_reply_notify_change_request
+ *
+ * This function sends appropriate response to an already queued NOTIFY CHANGE
+ * request. If node is changed (reply == NODE_FLAGS_CHANGED), a normal reply is
+ * sent.
+ * If client cancels the request or session dropped, an NT_STATUS_CANCELED
+ * is sent in reply.
+ */
+int
+smb_reply_notify_change_request(
+ smb_request_t *sr)
+{
+ smb_node_t *node;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+ struct smb_xa *xa;
+
+ xa = sr->r_xa;
+ node = sr->sr_ncr.nc_node;
+
+ if (--node->waiting_event == 0) {
+ node->flags &= ~(NODE_FLAGS_NOTIFY_CHANGE | NODE_FLAGS_CHANGED);
+ smb_fem_fcn_uninstall(node);
+ }
+
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+
+ case SMB_REQ_STATE_EVENT_OCCURRED:
+ sr->sr_state = SMB_REQ_STATE_ACTIVE;
+
+ /* many things changed */
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0L);
+
+ /* setup the NT transact reply */
+
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&xa->rep_param_mb);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ n_setup = (n_setup + 1) / 2; /* Convert to setup words */
+ param_pad = 1; /* must be one */
+ param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
+ /* Pad to 4 bytes */
+ data_pad = (4 - ((param_off + n_param) & 3)) % 4;
+ /* Param off from hdr */
+ data_off = param_off + n_param + data_pad;
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ smbsr_encode_result(sr, 18+n_setup, total_bytes,
+ "b 3. llllllllb C w #. C #. C",
+ 18 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ data_pad,
+ &xa->rep_data_mb);
+ break;
+
+ case SMB_REQ_STATE_CANCELED:
+ /*
+ * an STATUS should be sent,
+ * we need an implementation of nt_raise_error
+ * but without long jump.
+ */
+ smbsr_setup_nt_status(sr, 0xc0000000, NT_STATUS_CANCELLED);
+ (void) smb_encode_mbc(&sr->reply, "bwbw",
+ (short)0, 0L, (short)0, 0L);
+ sr->smb_wct = 0;
+ sr->smb_bcc = 0;
+ break;
+ default:
+ ASSERT(0);
+ }
+ mutex_exit(&sr->sr_mutex);
+
+ /* Setup the header */
+ (void) smb_poke_mbc(&sr->reply, 0, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, NULL);
+
+ /* send the reply */
+ DTRACE_PROBE1(ncr__reply, struct smb_request *, sr)
+ (void) smb_session_send(sr->session, 0, &sr->reply);
+ smbsr_cleanup(sr);
+
+ mutex_enter(&sr->sr_mutex);
+ sr->sr_state = SMB_REQ_STATE_COMPLETED;
+ mutex_exit(&sr->sr_mutex);
+ smb_request_free(sr);
+ return (0);
+}
+
+/*
+ * smb_process_session_notify_change_queue
+ *
+ * This function traverses notify change request queue and sends
+ * cancel replies to all of requests that are related to a specific
+ * session.
+ */
+void
+smb_process_session_notify_change_queue(struct smb_session *session)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ boolean_t sig = B_FALSE;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&smb_info.si_ncr_list, sr);
+ if (sr->session == session) {
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_WAITING_EVENT:
+ smb_slist_obj_move(
+ &smb_info.si_nce_list,
+ &smb_info.si_ncr_list,
+ sr);
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+ sig = B_TRUE;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ }
+ sr = tmp;
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+ smb_slist_exit(&smb_info.si_ncr_list);
+ if (sig) {
+ smb_thread_signal(&smb_info.si_thread_notify_change);
+ }
+}
+
+/*
+ * smb_process_file_notify_change_queue
+ *
+ * This function traverses notify change request queue and sends
+ * cancel replies to all of requests that are related to the
+ * specified file.
+ */
+void
+smb_process_file_notify_change_queue(struct smb_ofile *of)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ boolean_t sig = B_FALSE;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&smb_info.si_ncr_list, sr);
+ if (sr->fid_ofile == of) {
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_WAITING_EVENT:
+ smb_slist_obj_move(
+ &smb_info.si_nce_list,
+ &smb_info.si_ncr_list,
+ sr);
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+ sig = B_TRUE;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ }
+ sr = tmp;
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+ smb_slist_exit(&smb_info.si_ncr_list);
+ if (sig) {
+ smb_thread_signal(&smb_info.si_thread_notify_change);
+ }
+}
+
+/*
+ * smb_reply_specific_cancel_request
+ *
+ * This function searches global request list for a specific request. If found,
+ * moves the request to event queue and kicks the notify change daemon.
+ */
+
+void
+smb_reply_specific_cancel_request(struct smb_request *zsr)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ boolean_t sig = B_FALSE;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&smb_info.si_ncr_list, sr);
+ if ((sr->session == zsr->session) &&
+ (sr->smb_sid == zsr->smb_sid) &&
+ (sr->smb_uid == zsr->smb_uid) &&
+ (sr->smb_pid == zsr->smb_pid) &&
+ (sr->smb_tid == zsr->smb_tid) &&
+ (sr->smb_mid == zsr->smb_mid)) {
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_WAITING_EVENT:
+ smb_slist_obj_move(
+ &smb_info.si_nce_list,
+ &smb_info.si_ncr_list,
+ sr);
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+ sig = B_TRUE;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ }
+ sr = tmp;
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+ smb_slist_exit(&smb_info.si_ncr_list);
+ if (sig) {
+ smb_thread_signal(&smb_info.si_thread_notify_change);
+ }
+}
+
+/*
+ * smb_process_node_notify_change_queue
+ *
+ * This function searches notify change request queue and sends
+ * 'NODE MODIFIED' reply to all requests which are related to a
+ * specific node.
+ * WatchTree flag: We handle this flag in a special manner just
+ * for DAVE clients. When something is changed, we notify all
+ * requests which came from DAVE clients on the same volume which
+ * has been modified. We don't care about the tree that they wanted
+ * us to monitor. any change in any part of the volume will lead
+ * to notifying all notify change requests from DAVE clients on the
+ * different parts of the volume hierarchy.
+ */
+void
+smb_process_node_notify_change_queue(struct smb_node *node)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ boolean_t sig = B_FALSE;
+
+ if (!(node->flags & NODE_FLAGS_NOTIFY_CHANGE))
+ return;
+
+ node->flags |= NODE_FLAGS_CHANGED;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&smb_info.si_ncr_list, sr);
+ /*
+ * send notify if:
+ * - it's a request for the same node or
+ * - it's a request from a DAVE client, its 'watch tree'
+ * flag is set and monitors a tree on the same volume.
+ */
+ if ((sr->sr_ncr.nc_node == node) ||
+ ((sr->sr_ncr.nc_flags & NODE_FLAGS_WATCH_TREE) &&
+ (sr->session->native_os == NATIVE_OS_MACOS) &&
+ !fsd_cmp(&sr->sr_ncr.nc_node->tree_fsd, &node->tree_fsd))) {
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_WAITING_EVENT:
+ smb_slist_obj_move(
+ &smb_info.si_nce_list,
+ &smb_info.si_ncr_list,
+ sr);
+ sr->sr_state = SMB_REQ_STATE_EVENT_OCCURRED;
+ sig = B_TRUE;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ }
+ sr = tmp;
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+ smb_slist_exit(&smb_info.si_ncr_list);
+ if (sig) {
+ smb_thread_signal(&smb_info.si_thread_notify_change);
+ }
+}
+
+/*
+ * smb_notify_change_daemon
+ *
+ * This function processes notify change event list and send appropriate
+ * responses to the requests. This function executes in the system as an
+ * indivdual thread.
+ */
+
+void
+smb_notify_change_daemon(smb_thread_t *thread, void *si_void)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ list_t sr_list;
+ smb_info_t *si = si_void;
+
+ list_create(&sr_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_ncr.nc_lnd));
+
+ ASSERT(si != NULL);
+
+ while (smb_thread_continue(thread)) {
+
+ while (smb_slist_move_tail(&sr_list, &si->si_nce_list)) {
+ sr = list_head(&sr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = list_next(&sr_list, sr);
+ list_remove(&sr_list, sr);
+ (void) smb_reply_notify_change_request(sr);
+ sr = tmp;
+ }
+ }
+ }
+
+ list_destroy(&sr_list);
+}
+
+/*
+ * smb_notify_change_event_queue_dump
+ *
+ * Dumps all requests in NCE queue to the system log.
+ */
+void
+smb_notify_change_event_queue_dump()
+{
+ smb_request_t *sr;
+ int i = 0;
+
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_nce_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ ASSERT((sr->sr_state == SMB_REQ_STATE_CANCELED) ||
+ (sr->sr_state == SMB_REQ_STATE_EVENT_OCCURRED));
+ i++;
+ sr = smb_slist_next(&smb_info.si_nce_list, sr);
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+}
+
+/*
+ * smb_notify_change_req_queue_dump
+ *
+ * Dumps all requests in NCR queue to the system log.
+ */
+void
+smb_notify_change_req_queue_dump()
+{
+ smb_request_t *sr;
+ int i = 0;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ ASSERT(sr->sr_state == SMB_REQ_STATE_WAITING_EVENT);
+ i++;
+ sr = smb_slist_next(&smb_info.si_ncr_list, sr);
+ }
+ smb_slist_exit(&smb_info.si_ncr_list);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
new file mode 100644
index 0000000000..70d8437cdf
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_secdesc.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+extern uint32_t smb_sd_read(smb_request_t *sr, smb_sdbuf_t **sr_sd,
+ uint32_t secinfo, uint32_t *buflen);
+extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd,
+ uint32_t secinfo);
+
+/*
+ * smb_nt_transact_query_security_info
+ *
+ * This command allows the client to retrieve the security descriptor
+ * on a file. The result of the call is returned to the client in the
+ * Data part of the transaction response.
+ *
+ * Some clients specify a non-zero maximum data return size (mdrcnt)
+ * for the SD and some specify zero. In either case, if the mdrcnt is
+ * too small we need to return NT_STATUS_BUFFER_TOO_SMALL and a buffer
+ * size hint. The client should then retry with the appropriate buffer
+ * size.
+ *
+ * Client Parameter Block Description
+ * ================================== =================================
+ *
+ * USHORT Fid; FID of target
+ * USHORT Reserved; MBZ
+ * ULONG secinfo; Fields of descriptor to set
+ *
+ * Data Block Encoding Description
+ * ================================== ==================================
+ *
+ * Data[TotalDataCount] Security Descriptor information
+ */
+
+int
+smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_sdbuf_t *sr_sd;
+ uint32_t secinfo;
+ uint32_t sr_sdlen;
+ uint32_t status;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "w2.l",
+ &sr->smb_fid, &secinfo) != 0) {
+ /*
+ * It's not clear why ERRnomem is returned here.
+ * This should rarely happen and we're not sure if
+ * it's going to break something if we change this
+ * error code, so we're going to keep it for now.
+ */
+ smbsr_raise_error(sr, ERRSRV, ERRnomem);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+
+ if ((sr->fid_ofile->f_node == NULL) ||
+ (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
+ smbsr_raise_nt_error(sr, NT_STATUS_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (sr->tid_tree->t_acltype != ACE_T) {
+ /*
+ * If target filesystem doesn't support ACE_T acls then
+ * don't process SACL
+ */
+ secinfo &= ~SMB_SACL_SECINFO;
+ }
+
+ sr_sdlen = xa->smb_mdrcnt;
+ status = smb_sd_read(sr, &sr_sd, secinfo, &sr_sdlen);
+
+ if (status != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_BUFFER_TOO_SMALL) {
+ /*
+ * The maximum data return count specified by the
+ * client is not big enough to hold the security
+ * descriptor. We have to return an error but we
+ * can provide a buffer size hint for the client.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "l", sr_sdlen);
+ smbsr_setup_nt_status(sr, ERROR_SEVERITY_ERROR,
+ NT_STATUS_BUFFER_TOO_SMALL);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ }
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "#c", (int)sr_sdlen, sr_sd);
+ (void) smb_encode_mbc(&xa->rep_param_mb, "l", sr_sdlen);
+
+ kmem_free(sr_sd, sr_sdlen);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_nt_transact_set_security_info
+ *
+ * This command allows the client to change the security descriptor on a
+ * file. All we do here is decode the parameters and the data. The data
+ * is passed directly to smb_nt_set_security_object, with the security
+ * information describing the information to set. There are no response
+ * parameters or data.
+ *
+ * Client Parameter Block Encoding Description
+ * ================================== ==================================
+ * USHORT Fid; FID of target
+ * USHORT Reserved; MBZ
+ * ULONG SecurityInformation; Fields of SD that to set
+ *
+ * Data Block Encoding Description
+ * ================================== ==================================
+ * Data[TotalDataCount] Security Descriptor information
+ */
+int
+smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_sdbuf_t *sd_buf;
+ uint32_t sec_info;
+ uint32_t status;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "w2.l",
+ &sr->smb_fid, &sec_info) != 0) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if ((sr->fid_ofile->f_node == NULL) ||
+ (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
+ smbsr_raise_nt_error(sr, NT_STATUS_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (sr->fid_ofile->f_node->flags & NODE_READ_ONLY) {
+ smbsr_raise_nt_error(sr, NT_STATUS_MEDIA_WRITE_PROTECTED);
+ /* NOTREACHED */
+ }
+
+ if (sr->tid_tree->t_acltype != ACE_T) {
+ /*
+ * If target filesystem doesn't support ACE_T acls then
+ * don't process SACL
+ */
+ sec_info &= ~SMB_SACL_SECINFO;
+ }
+
+ if ((sec_info & SMB_ALL_SECINFO) == 0) {
+ return (NT_STATUS_SUCCESS);
+ }
+
+ sd_buf = kmem_alloc(xa->smb_tdscnt, KM_SLEEP);
+
+ if ((smb_decode_mbc(&xa->req_data_mb, "#c",
+ xa->smb_tdscnt, (char *)sd_buf)) != 0) {
+ kmem_free(sd_buf, xa->smb_tdscnt);
+ smbsr_raise_nt_error(sr, NT_STATUS_BUFFER_TOO_SMALL);
+ /* NOTREACHED */
+ }
+
+ status = smb_sd_write(sr, sd_buf, sec_info);
+ kmem_free(sd_buf, xa->smb_tdscnt);
+
+ if (status != NT_STATUS_SUCCESS) {
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_odir.c b/usr/src/uts/common/fs/smbsrv/smb_odir.c
new file mode 100644
index 0000000000..43ecf7b023
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c
@@ -0,0 +1,456 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General Structures Layout
+ * -------------------------
+ *
+ * This is a simplified diagram showing the relationship between most of the
+ * main structures.
+ *
+ * +-------------------+
+ * | SMB_INFO |
+ * +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | SESSION |<----->| SESSION |......| SESSION |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | USER |<----->| USER |......| USER |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | TREE |<----->| TREE |......| TREE |
+ * +-------------------+ +-------------------+ +-------------------+
+ * | |
+ * | |
+ * | v
+ * | +-------+ +-------+ +-------+
+ * | | OFILE |<----->| OFILE |......| OFILE |
+ * | +-------+ +-------+ +-------+
+ * |
+ * |
+ * v
+ * +-------+ +------+ +------+
+ * | ODIR |<----->| ODIR |......| ODIR |
+ * +-------+ +------+ +------+
+ *
+ *
+ * Odir State Machine
+ * ------------------
+ *
+ * +-------------------------+ T0
+ * | SMB_ODIR_STATE_OPEN |<----------- Creation/Allocation
+ * +-------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +-------------------------+
+ * | SMB_ODIR_STATE_CLOSING |
+ * +-------------------------+
+ * |
+ * | T2
+ * |
+ * v
+ * +-------------------------+ T3
+ * | SMB_ODIR_STATE_CLOSED |----------> Deletion/Free
+ * +-------------------------+
+ *
+ * SMB_ODIR_STATE_OPEN
+ *
+ * While in this state:
+ * - The odir is queued in the list of odirs of its tree.
+ * - References will be given out if the odir is looked up.
+ *
+ * SMB_ODIR_STATE_CLOSING
+ *
+ * While in this state:
+ * - The odir is queued in the list of odirs of its tree.
+ * - References will not be given out if the odir is looked up.
+ * - The odir is closed.
+ * - The resources associated with the odir remain.
+ *
+ * SMB_ODIR_STATE_CLOSED
+ *
+ * While in this state:
+ * - The odir is queued in the list of odirs of its tree.
+ * - References will not be given out if the odir is looked up.
+ * - The resources associated with the odir remain.
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_odir_open(). A new odir is created and
+ * added to the list of odirs of a tree.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_odir_close().
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_odir_release(). The resources associated
+ * with the odir are freed as well as the odir structure. For the
+ * transition to occur, the odir must be in the SMB_ODIR_STATE_CLOSED
+ * state and the reference count be zero.
+ *
+ * Comments
+ * --------
+ *
+ * The state machine of the odir structures is controlled by 3 elements:
+ * - The list of odirs of the tree it belongs to.
+ * - The mutex embedded in the structure itself.
+ * - The reference count.
+ *
+ * There's a mutex embedded in the odir structure used to protect its fields
+ * and there's a lock embedded in the list of odirs of a tree. To
+ * increment or to decrement the reference count the mutex must be entered.
+ * To insert the odir into the list of odirs of the tree and to remove
+ * the odir from it, the lock must be entered in RW_WRITER mode.
+ *
+ * Rules of access to a odir structure:
+ *
+ * 1) In order to avoid deadlocks, when both (mutex and lock of the odir
+ * list) have to be entered, the lock must be entered first.
+ *
+ * 2) All actions applied to an odir require a reference count.
+ *
+ * 3) There are 2 ways of getting a reference count. One is when the odir
+ * is opened. The other when the odir is looked up. This translates
+ * into 2 functions: smb_odir_open() and smb_odir_lookup_by_fid().
+ *
+ * It should be noted that the reference count of an odir registers the
+ * number of references to the odir in other structures (such as an smb
+ * request). The reference count is not incremented in these 2 instances:
+ *
+ * 1) The odir is open. An odir is anchored by his state. If there's
+ * no activity involving an odir currently open, the reference count
+ * of that odir is zero.
+ *
+ * 2) The odir is queued in the list of odirs of its tree. The fact of
+ * being queued in that list is NOT registered by incrementing the
+ * reference count.
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_fsops.h>
+
+/* Static functions defined further down this file. */
+static void smb_odir_delete(smb_odir_t *of);
+static smb_odir_t *smb_odir_close_and_next(smb_odir_t *od);
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+/*
+ * smb_odir_open
+ */
+smb_odir_t *
+smb_odir_open(
+ smb_tree_t *tree,
+ smb_node_t *node,
+ char *pattern,
+ uint16_t pid,
+ unsigned short sattr)
+{
+ smb_odir_t *dir;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(node);
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(pattern);
+
+ if (strlen(pattern) >= sizeof (dir->d_pattern)) {
+ return (NULL);
+ }
+
+ dir = kmem_cache_alloc(smb_info.si_cache_odir, KM_SLEEP);
+ bzero(dir, sizeof (smb_odir_t));
+ dir->d_refcnt = 1;
+ dir->d_session = tree->t_session;
+ dir->d_user = tree->t_user;
+ dir->d_tree = tree;
+ (void) strlcpy(dir->d_pattern, pattern, sizeof (dir->d_pattern));
+ dir->d_wildcards = smb_convert_unicode_wildcards(pattern);
+ dir->d_state = SMB_ODIR_STATE_OPEN;
+
+ if (smb_idpool_alloc(&dir->d_tree->t_sid_pool, &dir->d_sid)) {
+ kmem_cache_free(smb_info.si_cache_odir, dir);
+ return (NULL);
+ }
+ mutex_init(&dir->d_mutex, NULL, MUTEX_DEFAULT, NULL);
+ dir->d_sattr = sattr;
+ dir->d_opened_by_pid = pid;
+ dir->d_dir_snode = node;
+ dir->d_state = SMB_ODIR_STATE_OPEN;
+ dir->d_magic = SMB_ODIR_MAGIC;
+
+ smb_llist_enter(&tree->t_odir_list, RW_WRITER);
+ smb_llist_insert_tail(&tree->t_odir_list, dir);
+ smb_llist_exit(&tree->t_odir_list);
+
+ atomic_inc_32(&tree->t_session->s_dir_cnt);
+ return (dir);
+}
+
+/*
+ * smb_odir_close
+ */
+void
+smb_odir_close(
+ smb_odir_t *od)
+{
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+ mutex_enter(&od->d_mutex);
+ ASSERT(od->d_refcnt);
+ switch (od->d_state) {
+ case SMB_ODIR_STATE_OPEN:
+ od->d_state = SMB_ODIR_STATE_CLOSED;
+ break;
+ case SMB_ODIR_STATE_CLOSING:
+ case SMB_ODIR_STATE_CLOSED:
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&od->d_mutex);
+}
+
+/*
+ * smb_odir_close_all
+ *
+ *
+ */
+void
+smb_odir_close_all(
+ smb_tree_t *tree)
+{
+ smb_odir_t *od;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ smb_llist_enter(&tree->t_odir_list, RW_READER);
+ od = smb_llist_head(&tree->t_odir_list);
+ while (od) {
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+ ASSERT(od->d_tree == tree);
+ od = smb_odir_close_and_next(od);
+ }
+ smb_llist_exit(&tree->t_odir_list);
+}
+
+/*
+ * smb_odir_close_all_by_pid
+ *
+ *
+ */
+void
+smb_odir_close_all_by_pid(
+ smb_tree_t *tree,
+ uint16_t pid)
+{
+ smb_odir_t *od;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ smb_llist_enter(&tree->t_odir_list, RW_READER);
+ od = smb_llist_head(&tree->t_odir_list);
+ while (od) {
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+ ASSERT(od->d_tree == tree);
+ if (od->d_opened_by_pid == pid) {
+ od = smb_odir_close_and_next(od);
+ } else {
+ od = smb_llist_next(&tree->t_odir_list, od);
+ }
+ }
+ smb_llist_exit(&tree->t_odir_list);
+}
+
+/*
+ * smb_odir_release
+ */
+void
+smb_odir_release(
+ smb_odir_t *od)
+{
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+ mutex_enter(&od->d_mutex);
+ ASSERT(od->d_refcnt);
+ od->d_refcnt--;
+ switch (od->d_state) {
+ case SMB_ODIR_STATE_CLOSING:
+ case SMB_ODIR_STATE_OPEN:
+ break;
+
+ case SMB_ODIR_STATE_CLOSED:
+ if (od->d_refcnt == 0) {
+ mutex_exit(&od->d_mutex);
+ smb_odir_delete(od);
+ return;
+ }
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&od->d_mutex);
+}
+
+/*
+ * smb_odir_lookup_by_sid
+ */
+smb_odir_t *
+smb_odir_lookup_by_sid(
+ smb_tree_t *tree,
+ uint16_t sid)
+{
+ smb_llist_t *od_list;
+ smb_odir_t *od;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ od_list = &tree->t_odir_list;
+
+ smb_llist_enter(od_list, RW_READER);
+ od = smb_llist_head(od_list);
+ while (od) {
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+ ASSERT(od->d_tree == tree);
+ if (od->d_sid == sid) {
+ mutex_enter(&od->d_mutex);
+ if (od->d_state != SMB_ODIR_STATE_OPEN) {
+ mutex_exit(&od->d_mutex);
+ smb_llist_exit(od_list);
+ return (NULL);
+ }
+ od->d_refcnt++;
+ mutex_exit(&od->d_mutex);
+ break;
+ }
+ od = smb_llist_next(od_list, od);
+ }
+ smb_llist_exit(od_list);
+ return (od);
+}
+
+/* *************************** Static Functions ***************************** */
+
+/*
+ * smb_odir_close_and_next
+ *
+ * This function closes the directory passed in (if appropriate) and returns the
+ * next directory in the list of directories of the tree of the directory passed
+ * in. It requires that the list of directories of the tree be entered in
+ * RW_READER mode before being called.
+ */
+static smb_odir_t *
+smb_odir_close_and_next(
+ smb_odir_t *od)
+{
+ smb_odir_t *next_od;
+ smb_tree_t *tree;
+
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+ mutex_enter(&od->d_mutex);
+ switch (od->d_state) {
+ case SMB_ODIR_STATE_OPEN:
+ /* The directory is still opened. */
+ od->d_refcnt++;
+ ASSERT(od->d_refcnt);
+ tree = od->d_tree;
+ mutex_exit(&od->d_mutex);
+ smb_llist_exit(&od->d_tree->t_odir_list);
+ smb_odir_close(od);
+ smb_odir_release(od);
+ smb_llist_enter(&tree->t_odir_list, RW_READER);
+ next_od = smb_llist_head(&tree->t_odir_list);
+ break;
+ case SMB_ODIR_STATE_CLOSING:
+ case SMB_ODIR_STATE_CLOSED:
+ /*
+ * The odir exists but is closed or is in the process
+ * of being closed.
+ */
+ mutex_exit(&od->d_mutex);
+ next_od = smb_llist_next(&od->d_tree->t_odir_list, od);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&od->d_mutex);
+ next_od = smb_llist_next(&od->d_tree->t_odir_list, od);
+ break;
+ }
+ return (next_od);
+}
+
+/*
+ * smb_odir_delete
+ */
+static void
+smb_odir_delete(
+ smb_odir_t *od)
+{
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+ ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
+ ASSERT(od->d_refcnt == 0);
+
+ /*
+ * Let's remove the odir from the list of odirs of the tree. This has
+ * to be done before any resources associated with the odir are
+ * released.
+ */
+ smb_llist_enter(&od->d_tree->t_odir_list, RW_WRITER);
+ smb_llist_remove(&od->d_tree->t_odir_list, od);
+ smb_llist_exit(&od->d_tree->t_odir_list);
+
+ smb_node_release(od->d_dir_snode);
+ atomic_dec_32(&od->d_tree->t_session->s_dir_cnt);
+ smb_idpool_free(&od->d_tree->t_sid_pool, od->d_sid);
+ mutex_destroy(&od->d_mutex);
+ kmem_cache_free(smb_info.si_cache_odir, od);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
new file mode 100644
index 0000000000..150262e28b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
@@ -0,0 +1,726 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General Structures Layout
+ * -------------------------
+ *
+ * This is a simplified diagram showing the relationship between most of the
+ * main structures.
+ *
+ * +-------------------+
+ * | SMB_INFO |
+ * +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | SESSION |<----->| SESSION |......| SESSION |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | USER |<----->| USER |......| USER |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | TREE |<----->| TREE |......| TREE |
+ * +-------------------+ +-------------------+ +-------------------+
+ * | |
+ * | |
+ * | v
+ * | +-------+ +-------+ +-------+
+ * | | OFILE |<----->| OFILE |......| OFILE |
+ * | +-------+ +-------+ +-------+
+ * |
+ * |
+ * v
+ * +-------+ +------+ +------+
+ * | ODIR |<----->| ODIR |......| ODIR |
+ * +-------+ +------+ +------+
+ *
+ *
+ * Ofile State Machine
+ * ------------------
+ *
+ * +-------------------------+ T0
+ * | SMB_OFILE_STATE_OPEN |<----------- Creation/Allocation
+ * +-------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +-------------------------+
+ * | SMB_OFILE_STATE_CLOSING |
+ * +-------------------------+
+ * |
+ * | T2
+ * |
+ * v
+ * +-------------------------+ T3
+ * | SMB_OFILE_STATE_CLOSED |----------> Deletion/Free
+ * +-------------------------+
+ *
+ * SMB_OFILE_STATE_OPEN
+ *
+ * While in this state:
+ * - The ofile is queued in the list of ofiles of its tree.
+ * - References will be given out if the ofile is looked up.
+ *
+ * SMB_OFILE_STATE_CLOSING
+ *
+ * While in this state:
+ * - The ofile is queued in the list of ofiles of its tree.
+ * - References will not be given out if the ofile is looked up.
+ * - The file is closed and the locks held are being released.
+ * - The resources associated with the ofile remain.
+ *
+ * SMB_OFILE_STATE_CLOSED
+ *
+ * While in this state:
+ * - The ofile is queued in the list of ofiles of its tree.
+ * - References will not be given out if the ofile is looked up.
+ * - The resources associated with the ofile remain.
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_ofile_open(). A new ofile is created and
+ * added to the list of ofiles of a tree.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_ofile_close().
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_ofile_release(). The resources associated
+ * with the ofile are freed as well as the ofile structure. For the
+ * transition to occur, the ofile must be in the SMB_OFILE_STATE_CLOSED
+ * state and the reference count be zero.
+ *
+ * Comments
+ * --------
+ *
+ * The state machine of the ofile structures is controlled by 3 elements:
+ * - The list of ofiles of the tree it belongs to.
+ * - The mutex embedded in the structure itself.
+ * - The reference count.
+ *
+ * There's a mutex embedded in the ofile structure used to protect its fields
+ * and there's a lock embedded in the list of ofiles of a tree. To
+ * increment or to decrement the reference count the mutex must be entered.
+ * To insert the ofile into the list of ofiles of the tree and to remove
+ * the ofile from it, the lock must be entered in RW_WRITER mode.
+ *
+ * Rules of access to a ofile structure:
+ *
+ * 1) In order to avoid deadlocks, when both (mutex and lock of the ofile
+ * list) have to be entered, the lock must be entered first.
+ *
+ * 2) All actions applied to an ofile require a reference count.
+ *
+ * 3) There are 2 ways of getting a reference count. One is when the ofile
+ * is opened. The other one when the ofile is looked up. This translates
+ * into 2 functions: smb_ofile_open() and smb_ofile_lookup_by_fid().
+ *
+ * It should be noted that the reference count of an ofile registers the
+ * number of references to the ofile in other structures (such as an smb
+ * request). The reference count is not incremented in these 2 instances:
+ *
+ * 1) The ofile is open. An ofile is anchored by his state. If there's
+ * no activity involving an ofile currently open, the reference count
+ * of that ofile is zero.
+ *
+ * 2) The ofile is queued in the list of ofiles of its tree. The fact of
+ * being queued in that list is NOT registered by incrementing the
+ * reference count.
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_fsops.h>
+
+/* Static functions defined further down this file. */
+static void smb_ofile_delete(smb_ofile_t *of);
+static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *of);
+
+/*
+ * smb_ofile_open
+ *
+ *
+ */
+smb_ofile_t *
+smb_ofile_open(
+ smb_tree_t *tree,
+ smb_node_t *node,
+ uint16_t pid,
+ uint32_t access_granted,
+ uint32_t create_options,
+ uint32_t share_access,
+ uint16_t ftype,
+ char *pipe_name,
+ uint32_t rpc_fid,
+ smb_error_t *err)
+{
+ smb_ofile_t *of;
+ uint16_t fid;
+
+ if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) {
+ err->status = NT_STATUS_TOO_MANY_OPENED_FILES;
+ err->errcls = ERRDOS;
+ err->errcode = ERROR_TOO_MANY_OPEN_FILES;
+ return (NULL);
+ }
+
+ of = kmem_cache_alloc(smb_info.si_cache_ofile, KM_SLEEP);
+ bzero(of, sizeof (smb_ofile_t));
+ of->f_magic = SMB_OFILE_MAGIC;
+ of->f_refcnt = 1;
+ of->f_fid = fid;
+ of->f_opened_by_pid = pid;
+ of->f_granted_access = access_granted;
+ of->f_share_access = share_access;
+ of->f_create_options = create_options;
+ of->f_cr = tree->t_user->u_cred;
+ crhold(of->f_cr);
+ of->f_ftype = ftype;
+ of->f_session = tree->t_user->u_session;
+ of->f_user = tree->t_user;
+ of->f_tree = tree;
+ of->f_node = node;
+ mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL);
+ of->f_state = SMB_OFILE_STATE_OPEN;
+
+ if (ftype == SMB_FTYPE_MESG_PIPE) {
+ of->f_pipe_info = kmem_alloc(sizeof (mlsvc_pipe_t), KM_SLEEP);
+ bzero(of->f_pipe_info, sizeof (mlsvc_pipe_t));
+ of->f_pipe_info->pipe_name = pipe_name;
+ of->f_pipe_info->fid = rpc_fid;
+ mutex_init(&of->f_pipe_info->mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&of->f_pipe_info->cv, NULL, CV_DEFAULT, NULL);
+ } else {
+ ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */
+ ASSERT(node);
+ if (crgetuid(of->f_cr) == node->attr.sa_vattr.va_uid) {
+ /*
+ * Add this bit for the file's owner even if it's not
+ * specified in the request (Windows behavior).
+ */
+ of->f_granted_access |= FILE_READ_ATTRIBUTES;
+ }
+
+ if ((node->vp->v_type == VREG) && (smb_fsop_open(of) != 0)) {
+ of->f_magic = 0;
+ mutex_destroy(&of->f_mutex);
+ crfree(of->f_cr);
+ smb_idpool_free(&tree->t_fid_pool, of->f_fid);
+ kmem_cache_free(smb_info.si_cache_ofile, of);
+ err->status = NT_STATUS_ACCESS_DENIED;
+ err->errcls = ERRDOS;
+ err->errcode = ERROR_ACCESS_DENIED;
+ return (NULL);
+ }
+ smb_llist_enter(&node->n_ofile_list, RW_WRITER);
+ smb_llist_insert_tail(&node->n_ofile_list, of);
+ smb_llist_exit(&node->n_ofile_list);
+ }
+ smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
+ smb_llist_insert_tail(&tree->t_ofile_list, of);
+ smb_llist_exit(&tree->t_ofile_list);
+ atomic_inc_32(&smb_info.open_files);
+ atomic_inc_32(&of->f_session->s_file_cnt);
+
+ return (of);
+}
+
+/*
+ * smb_ofile_close
+ *
+ *
+ */
+int
+smb_ofile_close(
+ smb_ofile_t *of,
+ uint32_t last_wtime)
+{
+ int rc = 0;
+
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+ ASSERT(of->f_refcnt);
+ switch (of->f_state) {
+ case SMB_OFILE_STATE_OPEN: {
+
+ of->f_state = SMB_OFILE_STATE_CLOSING;
+ mutex_exit(&of->f_mutex);
+
+ if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
+ smb_rpc_close(of);
+ } else {
+ if (of->f_node->vp->v_type == VREG)
+ (void) smb_fsop_close(of);
+
+ if (of->f_node->flags & NODE_CREATED_READONLY) {
+ smb_node_set_dosattr(of->f_node,
+ of->f_node->attr.sa_dosattr |
+ SMB_FA_READONLY);
+ of->f_node->flags &= ~NODE_CREATED_READONLY;
+ }
+
+ smb_ofile_close_timestamp_update(of, last_wtime);
+ rc = smb_sync_fsattr(NULL, of->f_cr, of->f_node);
+ smb_commit_delete_on_close(of);
+ smb_release_oplock(of, OPLOCK_RELEASE_FILE_CLOSED);
+ smb_commit_delete_on_close(of);
+ /*
+ * if there is any notify change request for
+ * this file then see if any of them is related
+ * to this open instance. If there is any then
+ * cancel them.
+ */
+ if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE)
+ smb_process_file_notify_change_queue(of);
+ smb_node_destroy_lock_by_ofile(of->f_node, of);
+ }
+ atomic_dec_32(&smb_info.open_files);
+
+ mutex_enter(&of->f_mutex);
+ ASSERT(of->f_refcnt);
+ ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
+ of->f_state = SMB_OFILE_STATE_CLOSED;
+ mutex_exit(&of->f_mutex);
+ return (rc);
+ }
+ case SMB_OFILE_STATE_CLOSED:
+ case SMB_OFILE_STATE_CLOSING:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&of->f_mutex);
+ return (rc);
+}
+
+/*
+ * smb_ofile_close_all
+ *
+ *
+ */
+void
+smb_ofile_close_all(
+ smb_tree_t *tree)
+{
+ smb_ofile_t *of;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ smb_llist_enter(&tree->t_ofile_list, RW_READER);
+ of = smb_llist_head(&tree->t_ofile_list);
+ while (of) {
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_tree == tree);
+ of = smb_ofile_close_and_next(of);
+ }
+ smb_llist_exit(&tree->t_ofile_list);
+}
+
+/*
+ * smb_ofiles_close_by_pid
+ *
+ *
+ */
+void
+smb_ofile_close_all_by_pid(
+ smb_tree_t *tree,
+ uint16_t pid)
+{
+ smb_ofile_t *of;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ smb_llist_enter(&tree->t_ofile_list, RW_READER);
+ of = smb_llist_head(&tree->t_ofile_list);
+ while (of) {
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_tree == tree);
+ if (of->f_opened_by_pid == pid) {
+ of = smb_ofile_close_and_next(of);
+ } else {
+ of = smb_llist_next(&tree->t_ofile_list, of);
+ }
+ }
+ smb_llist_exit(&tree->t_ofile_list);
+}
+
+/*
+ * smb_ofile_release
+ *
+ */
+void
+smb_ofile_release(
+ smb_ofile_t *of)
+{
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+ ASSERT(of->f_refcnt);
+ of->f_refcnt--;
+ switch (of->f_state) {
+ case SMB_OFILE_STATE_OPEN:
+ case SMB_OFILE_STATE_CLOSING:
+ break;
+
+ case SMB_OFILE_STATE_CLOSED:
+ if (of->f_refcnt == 0) {
+ mutex_exit(&of->f_mutex);
+ smb_ofile_delete(of);
+ return;
+ }
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&of->f_mutex);
+}
+
+/*
+ * smb_ofile_lookup_by_fid
+ *
+ * Find the open file whose fid matches the one specified in the request.
+ * If we can't find the fid or the shares (trees) don't match, we have a
+ * bad fid.
+ */
+smb_ofile_t *
+smb_ofile_lookup_by_fid(
+ smb_tree_t *tree,
+ uint16_t fid)
+{
+ smb_llist_t *of_list;
+ smb_ofile_t *of;
+
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ of_list = &tree->t_ofile_list;
+
+ smb_llist_enter(of_list, RW_READER);
+ of = smb_llist_head(of_list);
+ while (of) {
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_tree == tree);
+ if (of->f_fid == fid) {
+ mutex_enter(&of->f_mutex);
+ if (of->f_state != SMB_OFILE_STATE_OPEN) {
+ mutex_exit(&of->f_mutex);
+ smb_llist_exit(of_list);
+ return (NULL);
+ }
+ of->f_refcnt++;
+ mutex_exit(&of->f_mutex);
+ break;
+ }
+ of = smb_llist_next(of_list, of);
+ }
+ smb_llist_exit(of_list);
+ return (of);
+}
+
+/*
+ * smb_ofile_set_flags
+ *
+ * Return value:
+ *
+ * Current flags value
+ *
+ */
+void
+smb_ofile_set_flags(
+ smb_ofile_t *of,
+ uint32_t flags)
+{
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_refcnt);
+
+ mutex_enter(&of->f_mutex);
+ of->f_flags |= flags;
+ mutex_exit(&of->f_mutex);
+}
+/*
+ * smb_ofile_seek
+ *
+ * Return value:
+ *
+ * 0 Success
+ * EINVAL Unknown mode
+ * EOVERFLOW offset too big
+ *
+ */
+int
+smb_ofile_seek(
+ smb_ofile_t *of,
+ ushort_t mode,
+ int32_t off,
+ uint32_t *retoff)
+{
+ off_t newoff = 0;
+ int rc = 0;
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_refcnt);
+
+ mutex_enter(&of->f_mutex);
+ switch (mode) {
+ case SMB_SEEK_SET:
+ if (off < 0)
+ newoff = 0;
+ else
+ newoff = (off_t)off;
+ break;
+
+ case SMB_SEEK_CUR:
+ if (off < 0 && (-off) > of->f_seek_pos)
+ newoff = 0;
+ else
+ newoff = of->f_seek_pos + (off_t)off;
+ break;
+
+ case SMB_SEEK_END:
+ if (off < 0 && (-off) > of->f_node->attr.sa_vattr.va_size)
+ newoff = 0;
+ else
+ newoff = of->f_node->attr.sa_vattr.va_size + (off_t)off;
+ break;
+
+ default:
+ mutex_exit(&of->f_mutex);
+ return (EINVAL);
+ }
+
+ if (newoff > ULONG_MAX) {
+ rc = EOVERFLOW;
+ } else {
+ of->f_seek_pos = newoff;
+ *retoff = (uint32_t)newoff;
+ }
+ mutex_exit(&of->f_mutex);
+ return (rc);
+}
+
+/*
+ * smb_ofile_close_timestamp_update
+ *
+ *
+ */
+void
+smb_ofile_close_timestamp_update(
+ smb_ofile_t *of,
+ uint32_t last_wtime)
+{
+ smb_node_t *node;
+ timestruc_t mtime, atime;
+ unsigned int what = 0;
+
+ mtime.tv_sec = last_wtime;
+ mtime.tv_nsec = 0;
+
+ if (mtime.tv_sec != 0 && mtime.tv_sec != 0xFFFFFFFF) {
+ mtime.tv_sec = smb_local_time_to_gmt(mtime.tv_sec);
+ what |= SMB_AT_MTIME;
+ }
+
+ /*
+ * NODE_FLAGS_SYNCATIME is set whenever something is
+ * written to a file. Compliant volumes don't update
+ * atime upon write, so don't update the atime if the
+ * volume is compliant.
+ */
+ node = of->f_node;
+ if (node->flags & NODE_FLAGS_SYNCATIME) {
+ node->flags &= ~NODE_FLAGS_SYNCATIME;
+ what |= SMB_AT_ATIME;
+ (void) microtime(&atime);
+ }
+
+ smb_node_set_time(node, 0, &mtime, &atime, 0, what);
+}
+
+/*
+ * smb_ofile_is_open
+ *
+ */
+boolean_t
+smb_ofile_is_open(
+ smb_ofile_t *of)
+{
+ boolean_t rc = B_FALSE;
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+ if (of->f_state == SMB_OFILE_STATE_OPEN) {
+ rc = B_TRUE;
+ }
+ mutex_exit(&of->f_mutex);
+ return (rc);
+}
+
+/* *************************** Static Functions ***************************** */
+
+/*
+ * smb_ofile_close_and_next
+ *
+ * This function closes the file passed in (if appropriate) and returns the
+ * next open file in the list of open files of the tree of the open file passed
+ * in. It requires that the list of open files of the tree be entered in
+ * RW_READER mode before being called.
+ */
+static smb_ofile_t *
+smb_ofile_close_and_next(
+ smb_ofile_t *of)
+{
+ smb_ofile_t *next_of;
+ smb_tree_t *tree;
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+ switch (of->f_state) {
+ case SMB_OFILE_STATE_OPEN:
+ /* The file is still open. */
+ of->f_refcnt++;
+ ASSERT(of->f_refcnt);
+ tree = of->f_tree;
+ mutex_exit(&of->f_mutex);
+ smb_llist_exit(&of->f_tree->t_ofile_list);
+ (void) smb_ofile_close(of, 0);
+ smb_ofile_release(of);
+ smb_llist_enter(&tree->t_ofile_list, RW_READER);
+ next_of = smb_llist_head(&tree->t_ofile_list);
+ break;
+ case SMB_OFILE_STATE_CLOSING:
+ case SMB_OFILE_STATE_CLOSED:
+ /*
+ * The ofile exists but is closed or
+ * in the process being closed.
+ */
+ mutex_exit(&of->f_mutex);
+ next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&of->f_mutex);
+ next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
+ break;
+ }
+ return (next_of);
+}
+
+/*
+ * smb_ofile_delete
+ *
+ *
+ */
+static void
+smb_ofile_delete(
+ smb_ofile_t *of)
+{
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_refcnt == 0);
+ ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
+
+ /*
+ * Let's remove the ofile from the list of ofiles of the tree. This has
+ * to be done before any resources associated with the ofile are
+ * released.
+ */
+ smb_llist_enter(&of->f_tree->t_ofile_list, RW_WRITER);
+ smb_llist_remove(&of->f_tree->t_ofile_list, of);
+ smb_llist_exit(&of->f_tree->t_ofile_list);
+ atomic_dec_32(&of->f_session->s_file_cnt);
+
+ if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
+ kmem_free(of->f_pipe_info, sizeof (mlsvc_pipe_t));
+ of->f_pipe_info = NULL;
+ } else {
+ ASSERT(of->f_ftype == SMB_FTYPE_DISK);
+ ASSERT(of->f_node != NULL);
+ smb_llist_enter(&of->f_node->n_ofile_list, RW_WRITER);
+ smb_llist_remove(&of->f_node->n_ofile_list, of);
+ smb_llist_exit(&of->f_node->n_ofile_list);
+ smb_node_release(of->f_node);
+ }
+
+ of->f_magic = (uint32_t)~SMB_OFILE_MAGIC;
+ mutex_destroy(&of->f_mutex);
+ crfree(of->f_cr);
+ smb_idpool_free(&of->f_tree->t_fid_pool, of->f_fid);
+ kmem_cache_free(smb_info.si_cache_ofile, of);
+}
+
+/*
+ * smb_ofile_access
+ *
+ * This function will check to see if the access requested is granted.
+ * Returns NT status codes.
+ */
+uint32_t
+smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access)
+{
+
+ if ((of == NULL) || (cr == kcred))
+ return (NT_STATUS_SUCCESS);
+
+ /*
+ * If the request is for something
+ * I don't grant it is an error
+ */
+ if (~(of->f_granted_access) & access) {
+ if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) &&
+ (access & ACCESS_SYSTEM_SECURITY)) {
+ return (NT_STATUS_PRIVILEGE_NOT_HELD);
+ }
+ return (NT_STATUS_ACCESS_DENIED);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
new file mode 100644
index 0000000000..aa02274224
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
@@ -0,0 +1,431 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_vops.h>
+
+/*
+ * This module provides the common open functionality to the various
+ * open and create SMB interface functions.
+ */
+
+/*
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 15
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Flags; Additional information: bit set-
+ * 0 - return additional info
+ * 1 - exclusive oplock requested
+ * 2 - batch oplock requested
+ * USHORT DesiredAccess; File open mode
+ * USHORT SearchAttributes;
+ * USHORT FileAttributes;
+ * UTIME CreationTime; Creation timestamp for file if it
+ * gets created
+ * USHORT OpenFunction; Action to take if file exists
+ * ULONG AllocationSize; Bytes to reserve on create or
+ * truncate
+ * ULONG Reserved[2]; Must be 0
+ * USHORT ByteCount; Count of data bytes; min = 1
+ * UCHAR BufferFormat 0x04
+ * STRING FileName;
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 15
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Fid; File handle
+ * USHORT FileAttributes;
+ * UTIME LastWriteTime;
+ * ULONG DataSize; Current file size
+ * USHORT GrantedAccess; Access permissions actually
+ * allowed
+ * USHORT FileType; Type of file opened
+ * USHORT DeviceState; State of the named pipe
+ * USHORT Action; Action taken
+ * ULONG ServerFid; Server unique file id
+ * USHORT Reserved; Reserved (must be 0)
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * DesiredAccess describes the access the client desires for the file (see
+ * section 3.6 - Access Mode Encoding).
+ *
+ * OpenFunction specifies the action to be taken depending on whether or
+ * not the file exists (see section 3.8 - Open Function Encoding). Action
+ *
+ * in the response specifies the action as a result of the Open request
+ * (see section 3.9 - Open Action Encoding).
+ *
+ * SearchAttributes indicates the attributes that the file must have to be
+ * found while searching to see if it exists. The encoding of this field
+ * is described in the "File Attribute Encoding" section elsewhere in this
+ * document. If SearchAttributes is zero then only normal files are
+ * returned. If the system file, hidden or directory attributes are
+ * specified then the search is inclusive -- both the specified type(s) of
+ * files and normal files are returned.
+ *
+ * FileType returns the kind of resource actually opened:
+ *
+ * Name Value Description
+ * ========================== ====== ==================================
+ *
+ * FileTypeDisk 0 Disk file or directory as defined
+ * in the attribute field
+ * FileTypeByteModePipe 1 Named pipe in byte mode
+ * FileTypeMessageModePipe 2 Named pipe in message mode
+ * FileTypePrinter 3 Spooled printer
+ * FileTypeUnknown 0xFFFF Unrecognized resource type
+ *
+ * If bit0 of Flags is clear, the FileAttributes, LastWriteTime, DataSize,
+ * FileType, and DeviceState have indeterminate values in the response.
+ *
+ * This SMB can request an oplock on the opened file. Oplocks are fully
+ * described in the "Oplocks" section elsewhere in this document, and there
+ * is also discussion of oplocks in the SMB_COM_LOCKING_ANDX SMB
+ * description. Bit1 and bit2 of the Flags field are used to request
+ * oplocks during open.
+ *
+ * The following SMBs may follow SMB_COM_OPEN_ANDX:
+ *
+ * SMB_COM_READ SMB_COM_READ_ANDX
+ * SMB_COM_IOCTL
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * SMB: open
+ *
+ * This message is sent to obtain a file handle for a data file. This
+ * returned Fid is used in subsequent client requests such as read, write,
+ * close, etc.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT DesiredAccess; Mode - read/write/share
+ * USHORT SearchAttributes;
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING FileName[]; File name
+ *
+ * FileName is the fully qualified file name, relative to the root of the
+ * share specified in the Tid field of the SMB header. If Tid in the SMB
+ * header refers to a print share, this SMB creates a new file which will
+ * be spooled to the printer when closed. In this case, FileName is
+ * ignored.
+ *
+ * SearchAttributes specifies the type of file desired. The encoding is
+ * described in the "File Attribute Encoding" section.
+ *
+ * DesiredAccess controls the mode under which the file is opened, and the
+ * file will be opened only if the client has the appropriate permissions.
+ * The encoding of DesiredAccess is discussed in the section entitled
+ * "Access Mode Encoding".
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 7
+ * USHORT Fid; File handle
+ * USHORT FileAttributes; Attributes of opened file
+ * UTIME LastWriteTime; Time file was last written
+ * ULONG DataSize; File size
+ * USHORT GrantedAccess; Access allowed
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Fid is the handle value which should be used for subsequent file
+ * operations.
+ *
+ * FileAttributes specifies the type of file obtained. The encoding is
+ * described in the "File Attribute Encoding" section.
+ *
+ * GrantedAccess indicates the access permissions actually allowed, and may
+ * have one of the following values:
+ *
+ * 0 read-only
+ * 1 write-only
+ * 2 read/write
+ *
+ * File Handles (Fids) are scoped per client. A Pid may reference any Fid
+ * established by itself or any other Pid on the client (so far as the
+ * server is concerned). The actual accesses allowed through the Fid
+ * depends on the open and deny modes specified when the file was opened
+ * (see below).
+ *
+ * The MS-DOS compatibility mode of file open provides exclusion at the
+ * client level. A file open in compatibility mode may be opened (also in
+ * compatibility mode) any number of times for any combination of reading
+ * and writing (subject to the user's permissions) by any Pid on the same
+ * client. If the first client has the file open for writing, then the
+ * file may not be opened in any way by any other client. If the first
+ * client has the file open only for reading, then other clients may open
+ * the file, in compatibility mode, for reading.. The above
+ * notwithstanding, if the filename has an extension of .EXE, .DLL, .SYM,
+ * or .COM other clients are permitted to open the file regardless of
+ * read/write open modes of other compatibility mode opens. However, once
+ * multiple clients have the file open for reading, no client is permitted
+ * to open the file for writing and no other client may open the file in
+ * any mode other than compatibility mode.
+ *
+ * The other file exclusion modes (Deny read/write, Deny write, Deny read,
+ * Deny none) provide exclusion at the file level. A file opened in any
+ * "Deny" mode may be opened again only for the accesses allowed by the
+ * Deny mode (subject to the user's permissions). This is true regardless
+ * of the identity of the second opener -a different client, a Pid from the
+ * same client, or the Pid that already has the file open. For example, if
+ * a file is open in "Deny write" mode a second open may only obtain read
+ * permission to the file.
+ *
+ * Although Fids are available to all Pids on a client, Pids other than the
+ * owner may not have the full access rights specified in the open mode by
+ * the Fid's creator. If the open creating the Fid specified a deny mode,
+ * then any Pid using the Fid, other than the creating Pid, will have only
+ * those access rights determined by "anding" the open mode rights and the
+ * deny mode rights, i.e., the deny mode is checked on all file accesses.
+ * For example, if a file is opened for Read/Write in Deny write mode, then
+ * other clients may only read the file and cannot write; if a file is
+ * opened for Read in Deny read mode, then the other clients can neither
+ * read nor write the file.
+ */
+
+int
+smb_com_open(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint16_t file_attr;
+ DWORD status;
+
+ bzero(op, sizeof (sr->arg.open));
+ if (smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.srch_attr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ op->desired_access = smb_omode_to_amask(op->omode);
+ op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
+
+ if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
+ (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->dsize = 0; /* Don't set spurious size */
+ op->utime.tv_sec = op->utime.tv_nsec = 0;
+ op->create_disposition = FILE_OPEN;
+ op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
+ ? FILE_WRITE_THROUGH : 0;
+
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
+ op->my_flags = MYF_BATCH_OPLOCK;
+ } else {
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ }
+ }
+
+ if ((status = smb_open_subr(sr)) != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_SHARING_VIOLATION)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ else
+ smbsr_raise_nt_error(sr, status);
+
+ /* NOTREACHED */
+ }
+
+ if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
+ sr->smb_flg &=
+ ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
+ }
+
+ if (op->dsize > 0xffffffff)
+ smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
+
+ file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
+
+ smbsr_encode_result(sr, 7, 0, "bwwllww",
+ 7,
+ sr->smb_fid,
+ file_attr,
+ smb_gmt_to_local_time(op->utime.tv_sec),
+ (uint32_t)op->dsize,
+ op->omode & SMB_DA_ACCESS_MASK,
+ (uint16_t)0); /* bcc */
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+int
+smb_com_open_andx(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint16_t flags;
+ uint32_t CreationTime;
+ uint16_t granted_access;
+ uint16_t ofun;
+ uint16_t file_attr;
+ int count;
+ DWORD status;
+ int rc;
+
+ bzero(op, sizeof (sr->arg.open));
+ op->dsize = 0;
+ rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com,
+ &sr->andx_off, &flags, &op->omode, &op->fqi.srch_attr,
+ &file_attr, &CreationTime, &ofun, &op->dsize, &op->timeo);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%u", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ op->desired_access = smb_omode_to_amask(op->omode);
+ op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
+
+ if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
+ (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->dattr = file_attr;
+ op->create_disposition = smb_ofun_to_crdisposition(ofun);
+ if (op->create_disposition == ((uint32_t)SMB_INVALID_CRDISPOSITION)) {
+ smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
+ ? FILE_WRITE_THROUGH : 0;
+
+ if (flags & 2)
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ else if (flags & 4)
+ op->my_flags = MYF_BATCH_OPLOCK;
+
+ if ((CreationTime != 0) && (CreationTime != 0xffffffff))
+ op->utime.tv_sec = smb_local_time_to_gmt(CreationTime);
+ op->utime.tv_nsec = 0;
+
+ status = NT_STATUS_SUCCESS;
+ /*
+ * According to NT, when exclusive share access failed,
+ * instead of raising "access deny" error immediately,
+ * we should wait for the client holding the exclusive
+ * file to close the file. If the wait timed out, we
+ * report a sharing violation; otherwise, we grant access.
+ * smb_open_subr returns NT_STATUS_SHARING_VIOLATION when
+ * it encounters an exclusive share access deny: we wait
+ * and retry.
+ */
+ for (count = 0; count <= 4; count++) {
+ if (count) {
+ delay(MSEC_TO_TICK(400));
+ }
+
+ if ((status = smb_open_subr(sr)) == NT_STATUS_SUCCESS)
+ break;
+ }
+
+ if (status != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_SHARING_VIOLATION)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ else
+ smbsr_raise_nt_error(sr, status);
+
+ /* NOTREACHED */
+ }
+
+ if (op->dsize > 0xffffffff)
+ smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
+
+ if (MYF_OPLOCK_TYPE(op->my_flags) != MYF_OPLOCK_NONE) {
+ op->action_taken |= SMB_OACT_LOCK;
+ } else {
+ op->action_taken &= ~SMB_OACT_LOCK;
+ }
+
+ granted_access = (sr->tid_tree->t_access == SMB_TREE_READ_ONLY)
+ ? SMB_DA_ACCESS_READ : op->omode & SMB_DA_ACCESS_MASK;
+
+ file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smb_node_t *node = sr->fid_ofile->f_node;
+ smbsr_encode_result(sr, 15, 0,
+ "b b.w w wll www wl 2. w",
+ 15,
+ sr->andx_com, VAR_BCC,
+ sr->smb_fid,
+ file_attr,
+ smb_gmt_to_local_time(node->attr.sa_vattr.va_mtime.tv_sec),
+ (uint32_t)op->dsize,
+ granted_access, op->ftype,
+ op->devstate,
+ op->action_taken, op->fileid,
+ 0);
+ } else {
+ smbsr_encode_result(sr, 15, 0,
+ "b b.w w wll www wl 2. w",
+ 15,
+ sr->andx_com, VAR_BCC,
+ sr->smb_fid,
+ file_attr,
+ 0L,
+ 0L,
+ granted_access, op->ftype,
+ op->devstate,
+ op->action_taken, op->fileid,
+ 0);
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
new file mode 100644
index 0000000000..cacbbb3e9d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
@@ -0,0 +1,539 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <sys/pathname.h>
+#include <sys/sdt.h>
+
+uint32_t
+smb_is_executable(char *path)
+{
+ char extension[5];
+ int len = strlen(path);
+
+ if ((len >= 4) && (path[len - 4] == '.')) {
+ (void) strcpy(extension, &path[len - 3]);
+ (void) utf8_strupr(extension);
+
+ if (strcmp(extension, "EXE") == 0)
+ return (NODE_FLAGS_EXECUTABLE);
+
+ if (strcmp(extension, "COM") == 0)
+ return (NODE_FLAGS_EXECUTABLE);
+
+ if (strcmp(extension, "DLL") == 0)
+ return (NODE_FLAGS_EXECUTABLE);
+
+ if (strcmp(extension, "SYM") == 0)
+ return (NODE_FLAGS_EXECUTABLE);
+ }
+
+ return (0);
+}
+
+/*
+ * smbd_fs_query
+ *
+ * This function has been changed to return errors instead of using
+ * smbsr_raise_errno to longjmp round the calling code. This allows
+ * the caller to release resources when an error occurs.
+ *
+ * Upon success, the caller will need to call smb_node_release() on
+ * fqi.last_snode (if it isn't already set to NULL by this routine) and
+ * and fqi.dir_snode. These pointers will not be used after the caller
+ * is done with them and should be released immediately. (The position
+ * of smb_fqi in a union in the smb_request structure makes it difficult
+ * to free these pointers at smb_request deallocation time.)
+ *
+ * If smbd_fs_query() returns error, no smb_nodes will need to be released
+ * by callers as a result of references taken in this routine, and
+ * fqi.last_snode and fqi.dir_snode will be set to NULL.
+ */
+
+int
+smbd_fs_query(struct smb_request *sr, struct smb_fqi *fqi, int fqm)
+{
+ int rc;
+
+ fqi->last_comp_was_found = 0;
+
+ rc = smb_pathname_reduce(sr, sr->user_cr, fqi->path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &fqi->dir_snode,
+ fqi->last_comp);
+
+ if (rc)
+ return (rc);
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, fqi->dir_snode, fqi->last_comp,
+ &fqi->last_snode, &fqi->last_attr, 0, 0);
+
+ if (rc == 0) {
+ fqi->last_comp_was_found = 1;
+ (void) strcpy(fqi->last_comp_od,
+ fqi->last_snode->od_name);
+
+ if (fqm == FQM_PATH_MUST_NOT_EXIST) {
+ smb_node_release(fqi->dir_snode);
+ smb_node_release(fqi->last_snode);
+ SMB_NULL_FQI_NODES(*fqi);
+ return (EEXIST);
+ }
+
+ return (0);
+ }
+
+ if (fqm == FQM_PATH_MUST_EXIST) {
+ smb_node_release(fqi->dir_snode);
+ SMB_NULL_FQI_NODES(*fqi);
+ return (rc);
+ }
+
+ if (rc == ENOENT) {
+ fqi->last_snode = NULL;
+ return (0);
+ }
+
+ smb_node_release(fqi->dir_snode);
+ SMB_NULL_FQI_NODES(*fqi);
+
+ return (rc);
+}
+
+/*
+ * smb_pathname_reduce
+ *
+ * smb_pathname_reduce() takes a path and returns the smb_node for the
+ * second-to-last component of the path. It also returns the name of the last
+ * component. Pointers for both of these fields must be supplied by the caller.
+ *
+ * Upon success, 0 is returned.
+ *
+ * Upon error, *dir_node will be set to 0.
+ *
+ * *sr (in)
+ * ---
+ * smb_request structure pointer
+ *
+ * *cred (in)
+ * -----
+ * credential
+ *
+ * *path (in)
+ * -----
+ * pathname to be looked up
+ *
+ * *share_root_node (in)
+ * ----------------
+ * File operations which are share-relative should pass sr->tid_tree->t_snode.
+ * If the call is not for a share-relative operation, this parameter must be 0
+ * (e.g. the call from smbsr_setup_share()). (Such callers will have path
+ * operations done using root_smb_node.) This parameter is used to determine
+ * whether mount points can be crossed.
+ *
+ * share_root_node should have at least one reference on it. This reference
+ * will stay intact throughout this routine.
+ *
+ * *cur_node (in)
+ * ---------
+ * The smb_node for the current directory (for relative paths).
+ * cur_node should have at least one reference on it.
+ * This reference will stay intact throughout this routine.
+ *
+ * **dir_node (out)
+ * ----------
+ * Directory for the penultimate component of the original path.
+ * (Note that this is not the same as the parent directory of the ultimate
+ * target in the case of a link.)
+ *
+ * The directory smb_node is returned held. The caller will need to release
+ * the hold or otherwise make sure it will get released (e.g. in a destroy
+ * routine if made part of a global structure).
+ *
+ * last_component (out)
+ * --------------
+ * The last component of the path. (This may be different from the name of any
+ * link target to which the last component may resolve.)
+ *
+ *
+ * ____________________________
+ *
+ * The CIFS server lookup path needs to have logic equivalent to that of
+ * smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the
+ * following areas:
+ *
+ * - non-traversal of child mounts (handled by smb_pathname_reduce)
+ * - unmangling (handled in smb_pathname)
+ * - "chroot" behavior of share root (handled by lookuppnvp)
+ *
+ * In addition, it needs to replace backslashes with forward slashes. It also
+ * ensures that link processing is done correctly, and that directory
+ * information requested by the caller is correctly returned (i.e. for paths
+ * with a link in the last component, the directory information of the
+ * link and not the target needs to be returned).
+ */
+
+int
+smb_pathname_reduce(
+ smb_request_t *sr,
+ cred_t *cred,
+ const char *path,
+ smb_node_t *share_root_node,
+ smb_node_t *cur_node,
+ smb_node_t **dir_node,
+ char *last_component)
+{
+ smb_node_t *root_node;
+ struct pathname ppn;
+ char *usepath;
+ int lookup_flags = FOLLOW;
+ int trailing_slash = 0;
+ int err = 0;
+ int len;
+
+ ASSERT(dir_node);
+ ASSERT(last_component);
+
+ *dir_node = NULL;
+ *last_component = '\0';
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ lookup_flags |= FIGNORECASE;
+
+ if (path == NULL)
+ return (EINVAL);
+
+ if (*path == '\0')
+ return (ENOENT);
+
+ usepath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+ if ((len = strlcpy(usepath, path, MAXPATHLEN)) >= MAXPATHLEN) {
+ kmem_free(usepath, MAXPATHLEN);
+ return (ENAMETOOLONG);
+ }
+
+ (void) strsubst(usepath, '\\', '/');
+
+ if (usepath[len - 1] == '/')
+ trailing_slash = 1;
+
+ (void) strcanon(usepath, "/");
+
+ if (share_root_node)
+ root_node = share_root_node;
+ else
+ root_node = smb_info.si_root_smb_node;
+
+ if (cur_node == NULL)
+ cur_node = root_node;
+
+ (void) pn_alloc(&ppn);
+
+ if ((err = pn_set(&ppn, usepath)) != 0) {
+ (void) pn_free(&ppn);
+ kmem_free(usepath, MAXPATHLEN);
+ return (err);
+ }
+
+ /*
+ * If a path does not have a trailing slash, strip off the
+ * last component. (We only need to return an smb_node for
+ * the second to last component; a name is returned for the
+ * last component.)
+ */
+
+ if (trailing_slash) {
+ (void) strlcpy(last_component, ".", MAXNAMELEN);
+ } else {
+ (void) pn_setlast(&ppn);
+ (void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
+ ppn.pn_path[0] = '\0';
+ }
+
+ if (strcmp(ppn.pn_buf, "/") == 0) {
+ smb_node_ref(root_node);
+ *dir_node = root_node;
+ } else if (ppn.pn_buf[0] == '\0') {
+ smb_node_ref(cur_node);
+ *dir_node = cur_node;
+ } else {
+ err = smb_pathname(sr, ppn.pn_buf, lookup_flags, root_node,
+ cur_node, NULL, dir_node, cred);
+ }
+
+ (void) pn_free(&ppn);
+ kmem_free(usepath, MAXPATHLEN);
+
+ /*
+ * Prevent access to anything outside of the share root, except
+ * when mapping a share because that may require traversal from
+ * / to a mounted file system. share_root_node is NULL when
+ * mapping a share.
+ *
+ * Note that we disregard whether the traversal of the path went
+ * outside of the file system and then came back (say via a link).
+ */
+
+ if ((err == 0) && share_root_node) {
+ if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp)
+ err = EACCES;
+ }
+
+ if (err) {
+ if (*dir_node) {
+ (void) smb_node_release(*dir_node);
+ *dir_node = NULL;
+ }
+ *last_component = 0;
+ }
+
+ return (err);
+}
+
+/*
+ * smb_pathname() - wrapper to lookuppnvp(). Handles name unmangling.
+ *
+ * *dir_node is the true directory of the target *node.
+ *
+ * If any component but the last in the path is not found, ENOTDIR instead of
+ * ENOENT will be returned.
+ *
+ * Path components are processed one at a time so that smb_nodes can be
+ * created for each component. This allows the dir_snode field in the
+ * smb_node to be properly populated.
+ *
+ * Mangle checking is also done on each component.
+ */
+
+int
+smb_pathname(
+ smb_request_t *sr,
+ char *path,
+ int flags,
+ smb_node_t *root_node,
+ smb_node_t *cur_node,
+ smb_node_t **dir_node,
+ smb_node_t **ret_node,
+ cred_t *cred)
+{
+ char *component = NULL;
+ char *real_name = NULL;
+ char *namep;
+ struct pathname pn;
+ struct pathname rpn;
+ struct pathname upn;
+ struct pathname link_pn;
+ smb_node_t *dnode = NULL;
+ smb_node_t *fnode = NULL;
+ vnode_t *rootvp;
+ vnode_t *dvp;
+ vnode_t *vp = NULL;
+ smb_attr_t attr;
+ size_t pathleft;
+ int err = 0;
+ int nlink = 0;
+ int local_flags;
+
+ if (path == NULL)
+ return (EINVAL);
+
+ ASSERT(root_node);
+ ASSERT(cur_node);
+ ASSERT(ret_node);
+
+ *ret_node = NULL;
+
+ if (dir_node)
+ *dir_node = NULL;
+
+ (void) pn_alloc(&upn);
+
+ if ((err = pn_set(&upn, path)) != 0) {
+ (void) pn_free(&upn);
+ return (err);
+ }
+
+ (void) pn_alloc(&pn);
+ (void) pn_alloc(&rpn);
+
+ component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ dnode = cur_node;
+ smb_node_ref(dnode);
+
+ rootvp = (vnode_t *)root_node->vp;
+
+ /*
+ * Instead of passing the FOLLOW flag to lookuppnvp(), process links in
+ * this routine. This allows smb_nodes to be created for each component
+ * of a link.
+ */
+ local_flags = flags & FIGNORECASE;
+
+ /*
+ * Path components are processed one at a time so that smb_nodes
+ * can be created for each component. This allows the dir_snode
+ * field in the smb_node to be properly populated.
+ *
+ * Mangle checking is also done on each component.
+ */
+ while ((pathleft = pn_pathleft(&upn)) != 0) {
+ if (fnode) {
+ smb_node_release(dnode);
+ dnode = fnode;
+ fnode = NULL;
+ }
+
+ if ((err = pn_getcomponent(&upn, component)) != 0)
+ break;
+
+ if (smb_maybe_mangled_name(component)) {
+ if ((err = smb_unmangle_name(sr, cred, dnode,
+ component, real_name, MAXNAMELEN, 0, 0,
+ 1)) != 0)
+ break;
+
+ namep = real_name;
+ } else {
+ namep = component;
+ }
+
+ if ((err = pn_set(&pn, namep)) != 0)
+ break;
+
+ /*
+ * Holds on dvp and rootvp (if not rootdir) are
+ * required by lookuppnvp() and will be released within
+ * that routine.
+ */
+ vp = NULL;
+ dvp = dnode->vp;
+
+ VN_HOLD(dvp);
+ if (rootvp != rootdir)
+ VN_HOLD(rootvp);
+
+ err = lookuppnvp(&pn, &rpn, local_flags, NULL, &vp, rootvp, dvp,
+ cred);
+
+ if (err)
+ break;
+
+ if ((vp->v_type == VLNK) &&
+ ((flags & FOLLOW) || pn_pathleft(&upn))) {
+
+ if (++nlink > MAXSYMLINKS) {
+ err = ELOOP;
+ break;
+ }
+
+ (void) pn_alloc(&link_pn);
+ err = pn_getsymlink(vp, &link_pn, cred);
+
+ if (err) {
+ (void) pn_free(&link_pn);
+ break;
+ }
+
+ if (pn_pathleft(&link_pn) == 0)
+ (void) pn_set(&link_pn, ".");
+ err = pn_insert(&upn, &link_pn, strlen(namep));
+ pn_free(&link_pn);
+
+ if (err)
+ break;
+
+ if (upn.pn_pathlen == 0) {
+ err = ENOENT;
+ break;
+ }
+
+ if (upn.pn_path[0] == '/') {
+ fnode = root_node;
+ smb_node_ref(fnode);
+ }
+
+ if (pn_fixslash(&upn))
+ flags |= FOLLOW;
+
+ } else {
+ if (flags & FIGNORECASE) {
+ if (strcmp(rpn.pn_path, "/") != 0)
+ pn_setlast(&rpn);
+
+ namep = rpn.pn_path;
+ } else
+ namep = pn.pn_path;
+
+ fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
+ dnode, NULL, &attr);
+
+ if (fnode == NULL) {
+ err = ENOMEM;
+ break;
+ }
+ }
+
+ while (upn.pn_path[0] == '/') {
+ upn.pn_path++;
+ upn.pn_pathlen--;
+ }
+ }
+
+ /*
+ * Since no parent vp was passed to lookuppnvp(), all
+ * ENOENT errors are returned as ENOENT
+ */
+
+ if ((pathleft) && (err == ENOENT))
+ err = ENOTDIR;
+
+ if (err) {
+ if (fnode)
+ smb_node_release(fnode);
+ if (dnode)
+ smb_node_release(dnode);
+ } else {
+ *ret_node = fnode;
+
+ if (dir_node)
+ *dir_node = dnode;
+ else
+ smb_node_release(dnode);
+ }
+
+ kmem_free(component, MAXNAMELEN);
+ kmem_free(real_name, MAXNAMELEN);
+ (void) pn_free(&pn);
+ (void) pn_free(&rpn);
+ (void) pn_free(&upn);
+
+ return (err);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_print.c b/usr/src/uts/common/fs/smbsrv/smb_print.c
new file mode 100644
index 0000000000..13f3746b06
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_print.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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB print interface.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_open_print_file
+ *
+ * This message is sent to create a new printer file which will be deleted
+ * once it has been closed and printed.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT SetupLength; Length of printer setup data
+ * USHORT Mode; 0 = Text mode (DOS expands TABs)
+ * 1 = Graphics mode
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING IdentifierString[]; Identifier string
+ *
+ * Tid in the SMB header must refer to a printer resource type.
+ *
+ * SetupLength is the number of bytes in the first part of the resulting
+ * print spool file which contains printer-specific control strings.
+ *
+ * Mode can have the following values:
+ *
+ * 0 Text mode. The server may optionally
+ * expand tabs to a series of spaces.
+ * 1 Graphics mode. No conversion of data
+ * should be done by the server.
+ *
+ * IdentifierString can be used by the server to provide some sort of per-
+ * client identifying component to the print file.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Fid; File handle
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Fid is the returned handle which may be used by subsequent write and
+ * close operations. When the file is finally closed, it will be sent to
+ * the spooler and printed.
+ *
+ * 4.5.1.1 Errors
+ *
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRnofids
+ * ERRSRV/ERRinvdevice
+ * ERRSRV/ERRbaduid
+ * ERRSRV/ERRqfull
+ * ERRSRV/ERRqtoobig
+ */
+int /*ARGSUSED*/
+smb_com_open_print_file(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * smb_com_close_print_file
+ *
+ *
+ * This message invalidates the specified file handle and queues the file
+ * for printing.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Fid; File handle
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Fid refers to a file previously created with SMB_COM_OPEN_PRINT_FILE.
+ * On successful completion of this request, the file is queued for
+ * printing by the server.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Servers which negotiate dialects of LANMAN1.0 and newer allow all the
+ * other types of Fid closing requests to invalidate the Fid and begin
+ * spooling.
+ */
+int /*ARGSUSED*/
+smb_com_close_print_file(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * smb_com_get_print_queue
+ *
+ * This message obtains a list of the elements currently in the print queue
+ * on the server.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT MaxCount; Max number of entries to return
+ * USHORT StartIndex; First queue entry to return
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * StartIndex specifies the first entry in the queue to return.
+ *
+ * MaxCount specifies the maximum number of entries to return, this may be
+ * a positive or negative number. A positive number requests a forward
+ * search, a negative number indicates a backward search.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT Count; Number of entries returned
+ * USHORT RestartIndex; Index of entry after last
+ * returned
+ * USHORT ByteCount; Count of data bytes; min = 3
+ * UCHAR BufferFormat; 0x01 -- Data block
+ * USHORT DataLength; Length of data
+ * UCHAR Data[]; Queue elements
+ *
+ * Count indicates how many entries were actually returned. RestartIndex
+ * is the index of the entry following the last entry returned; it may be
+ * used as the StartIndex in a subsequent request to resume the queue
+ * listing.
+ *
+ * The format of each returned queue element is:
+ *
+ * Queue Element Member Description
+ * ================================ ===================================
+ *
+ * SMB_DATE FileDate; Date file was queued
+ * SMB_TIME FileTime; Time file was queued
+ * UCHAR Status; Entry status. One of:
+ * 01 = held or stopped
+ * 02 = printing
+ * 03 = awaiting print
+ * 04 = in intercept
+ * 05 = file had error
+ * 06 = printer error
+ * 07-FF = reserved
+ * USHORT SpoolFileNumber; Assigned by the spooler
+ * ULONG SpoolFileSize; Number of bytes in spool file
+ * UCHAR Reserved;
+ * UCHAR SpoolFileName[16]; Client which created the spool file
+ *
+ * SMB_COM_GET_PRINT_QUEUE will return less than the requested number of
+ * elements only when the top or end of the queue is encountered.
+ *
+ * Support for this SMB is server optional. In particular, no current
+ * Microsoft client software issues this request.
+ *
+ * 4.5.2.1 Errors
+ *
+ * ERRHRD/ERRnotready
+ * ERRHRD/ERRerror
+ * ERRSRV/ERRbaduid
+ */
+int
+smb_com_get_print_queue(struct smb_request *sr)
+{
+ unsigned short max_count, start_ix;
+
+ if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_com_write_print_file
+ *
+ * This message is sent to write bytes into a print spool file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Fid; File handle
+ * USHORT ByteCount; Count of data bytes; min = 4
+ * UCHAR BufferFormat; 0x01 -- Data block
+ * USHORT DataLength; Length of data
+ * UCHAR Data[]; Data
+ *
+ * Fid indicates the print spool file to be written, it must refer to a
+ * print spool file.
+ *
+ * ByteCount specifies the number of bytes to be written, and must be less
+ * than MaxBufferSize for the Tid specified.
+ *
+ * Data contains the bytes to append to the print spool file. The first
+ * SetupLength bytes in the resulting print spool file contain printer
+ * setup data. SetupLength is specified in the SMB_COM_OPEN_PRINT_FILE SMB
+ * request.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Servers which negotiate a protocol dialect of LANMAN1.0 or later also
+ * support the application of normal write requests to print spool files.
+ *
+ */
+int /*ARGSUSED*/
+smb_com_write_print_file(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_process_exit.c b/usr/src/uts/common/fs/smbsrv/smb_process_exit.c
new file mode 100644
index 0000000000..40d49ea17f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_process_exit.c
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: process_exit
+ *
+ * This command informs the server that a client process has terminated.
+ * The server must close all files opened by Pid in the SMB header. This
+ * must automatically release all locks the process holds.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * This SMB should not generate any errors from the server, unless the
+ * server is a user mode server and Uid in the SMB header is invalid.
+ *
+ * Clients are not required to send this SMB, they can do all cleanup
+ * necessary by sending close SMBs to the server to release resources. In
+ * fact, clients who have negotiated LANMAN 1.0 and later probably do not
+ * send this message at all.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_process_exit(struct smb_request *sr)
+{
+ sr->uid_user = smb_user_lookup_by_uid(sr->session, &sr->user_cr,
+ sr->smb_uid);
+ if (sr->uid_user == NULL) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ /*
+ * If request has a valid tree ID, only look for the PID within
+ * that tree. Otherwise look in all the trees. smbtorture seems
+ * to be the only thing that sends this request these days and
+ * it doesn't provide a TID.
+ */
+ sr->tid_tree = smb_tree_lookup_by_tid(sr->uid_user, sr->smb_tid);
+ if (sr->tid_tree != NULL) {
+ smb_ofile_close_all_by_pid(sr->tid_tree, sr->smb_pid);
+ smb_odir_close_all_by_pid(sr->tid_tree, sr->smb_pid);
+ } else {
+ smb_tree_close_all_by_pid(sr->uid_user, sr->smb_pid);
+ }
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information.c b/usr/src/uts/common/fs/smbsrv/smb_query_information.c
new file mode 100644
index 0000000000..8cb636aaa9
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information.c
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: query_information
+ *
+ * This request is sent to obtain information about a file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING FileName[]; File name
+ *
+ * FileName is the fully qualified name of the file relative to the Tid in
+ * the header.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 10
+ * USHORT FileAttributes;
+ * UTIME LastWriteTime; Time of last write
+ * ULONG FileSize; File size
+ * USHORT Reserved [5]; Reserved - client should ignore
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * FileAttributes are as described in the "Attributes Encoding" section of
+ * this document.
+ *
+ * Note that FileSize is limited to 32 bits, this request is inappropriate
+ * for files whose size is too large.
+ *
+ * NOTES:
+ * Some clients send a NULL file name. Right now we return ERRbadfile
+ * until we find out what a MS client would send...
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_query_information(struct smb_request *sr)
+{
+ int rc;
+ unsigned short dattr;
+ uint32_t write_time, file_size;
+ char *path;
+ struct smb_node *dir_node;
+ struct smb_node *node;
+ smb_attr_t attr;
+ char *name;
+ timestruc_t *mtime;
+
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Some MS clients pass NULL file names
+ * NT interprets this as "\"
+ */
+ if (strlen(path) == 0) path = "\\";
+
+ if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
+ != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_node, name, &node, &attr, 0, 0)) != 0) {
+ smb_node_release(dir_node);
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smb_node_release(dir_node);
+
+ dattr = smb_node_get_dosattr(node);
+ mtime = smb_node_get_mtime(node);
+ write_time = smb_gmt_to_local_time(mtime->tv_sec);
+ file_size = (uint32_t)smb_node_get_size(node, &node->attr);
+
+ smb_node_release(node);
+
+ smbsr_encode_result(sr, 10, 0, "bwll10.w",
+ 10, /* wct */
+ dattr,
+ write_time, /* Last write time */
+ file_size, /* FileSize */
+ 0); /* bcc */
+
+ kmem_free(name, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
new file mode 100644
index 0000000000..a1324aa74e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: query_information2
+ *
+ * This SMB is gets information about the file represented by Fid.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT Fid; File handle
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 11
+ * SMB_DATE CreationDate;
+ * SMB_TIME CreationTime;
+ * SMB_DATE LastAccessDate;
+ * SMB_TIME LastAccessTime;
+ * SMB_DATE LastWriteDate;
+ * SMB_TIME LastWriteTime;
+ * ULONG FileDataSize; File end of data
+ * ULONG FileAllocationSize; File allocation size
+ * USHORT FileAttributes;
+ * USHORT ByteCount; Count of data bytes; min = 0
+ *
+ * The file being interrogated is specified by Fid, which must possess at
+ * least read permission.
+ *
+ * FileAttributes are described in the "File Attribute Encoding" section
+ * elsewhere in this document.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_query_information2(struct smb_request *sr)
+{
+ smb_node_t *node;
+ smb_attr_t *attr;
+ uint32_t dsize, dasize;
+ unsigned short dattr;
+
+ if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+
+ if (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
+ cmn_err(CE_NOTE, "SmbQueryInfo2: access denied");
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ node = sr->fid_ofile->f_node;
+ attr = &node->attr;
+
+ dattr = smb_node_get_dosattr(node);
+ dasize = attr->sa_vattr.va_blksize * attr->sa_vattr.va_nblocks;
+ dsize = (dattr & SMB_FA_DIRECTORY) ? 0 : attr->sa_vattr.va_size;
+
+ smbsr_encode_result(sr, 11, 0, "byyyllww",
+ 11, /* wct */
+ smb_gmt_to_local_time(attr->sa_crtime.tv_sec),
+ /* LastAccessTime */
+ smb_gmt_to_local_time(attr->sa_vattr.va_atime.tv_sec),
+ /* LastWriteTime */
+ smb_gmt_to_local_time(attr->sa_vattr.va_mtime.tv_sec),
+ dsize,
+ dasize,
+ dattr, /* FileAttributes */
+ 0); /* bcc */
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information_disk.c b/usr/src/uts/common/fs/smbsrv/smb_query_information_disk.c
new file mode 100644
index 0000000000..4c69d8516e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information_disk.c
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: query_information_disk
+ *
+ * The SMB_COM_QUERY_INFORMATION_DISK command is used to determine the
+ * capacity and remaining free space on the drive hosting the directory
+ * structure indicated by Tid in the SMB header.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 5
+ * USHORT TotalUnits; Total allocation units per server
+ * USHORT BlocksPerUnit; Blocks per allocation unit
+ * USHORT BlockSize; Block size (in bytes)
+ * USHORT FreeUnits; Number of free units
+ * USHORT Reserved; Reserved (client should ignore)
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The blocking/allocation units used in this response may be independent
+ * of the actual physical or logical blocking/allocation algorithm(s) used
+ * internally by the server. However, they must accurately reflect the
+ * amount of space on the server.
+ *
+ * This SMB only returns 16 bits of information for each field, which may
+ * not be large enough for some disk systems. In particular TotalUnits is
+ * commonly > 64K. Fortunately, it turns out the all the client cares
+ * about is the total disk size, in bytes, and the free space, in bytes.
+ * So, it is reasonable for a server to adjust the relative values of
+ * BlocksPerUnit and BlockSize to accommodate. If after all adjustment,
+ * the numbers are still too high, the largest possible values for
+ * TotalUnit or FreeUnits (i.e. 0xFFFF) should be returned.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_query_information_disk(struct smb_request *sr)
+{
+ int rc;
+ struct statvfs64 df;
+ fsblkcnt64_t total_blocks, free_blocks;
+ unsigned long block_size, unit_size;
+ unsigned short blocks_per_unit, bytes_per_block;
+ unsigned short total_units, free_units;
+
+ if ((rc = smb_fsop_statfs(sr->user_cr, sr->tid_tree->t_snode, &df))
+ != 0)
+ smbsr_raise_errno(sr, rc);
+
+ unit_size = 1;
+ block_size = df.f_frsize;
+ total_blocks = df.f_blocks;
+ free_blocks = df.f_bavail;
+
+ /*
+ * It seems that DOS clients cannot handle block sizes
+ * bigger than 512 KB. So we have to set the block size at
+ * most to 512
+ */
+
+ while (block_size > 512) {
+ block_size >>= 1;
+ unit_size <<= 1;
+ }
+
+ /* adjust blocks and sizes until they fit into a word */
+
+ while (total_blocks >= 0xFFFF) {
+ total_blocks >>= 1;
+ free_blocks >>= 1;
+ if ((unit_size <<= 1) > 0xFFFF) {
+ unit_size >>= 1;
+ total_blocks = 0xFFFF;
+ free_blocks <<= 1;
+ break;
+ }
+ }
+
+ total_units = (total_blocks >= 0xFFFF) ?
+ 0xFFFF : (unsigned short)total_blocks;
+ free_units = (free_blocks >= 0xFFFF) ?
+ 0xFFFF : (unsigned short)free_blocks;
+ bytes_per_block = (unsigned short)block_size;
+ blocks_per_unit = (unsigned short)unit_size;
+
+ smbsr_encode_result(sr, 5, 0, "bwwww2.w",
+ 5,
+ total_units, /* total_units */
+ blocks_per_unit, /* blocks_per_unit */
+ bytes_per_block, /* blocksize */
+ free_units, /* free_units */
+ 0); /* bcc */
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_read.c b/usr/src/uts/common/fs/smbsrv/smb_read.c
new file mode 100644
index 0000000000..6554c07014
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_read.c
@@ -0,0 +1,456 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/syslog.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+
+typedef struct smb_read_param {
+ uint64_t r_offset;
+ uint16_t r_count;
+ uint16_t r_mincnt;
+} smb_read_param_t;
+
+
+int smb_common_read(struct smb_request *sr, smb_read_param_t *param);
+
+
+/*
+ * Read bytes from a file or named pipe (SMB Core).
+ *
+ * The requested count specifies the number of bytes desired. Offset
+ * is limited to 32 bits, so this client request is inappropriate for
+ * files with 64 bit offsets.
+ *
+ * On return, count is the number of bytes actually being returned, which
+ * may be less than the count requested only if a read specifies bytes
+ * beyond the current file size. In this case only the bytes that exist
+ * are returned. A read completely beyond the end of file results in a
+ * response of length zero. This is the only circumstance when a zero
+ * length response is generated. A count returned which is less than the
+ * count requested is the end of file indicator.
+ */
+int
+smb_com_read(struct smb_request *sr)
+{
+ smb_read_param_t param;
+ uint32_t off_low;
+ uint16_t remcnt;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
+ &param.r_count, &off_low, &remcnt);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param.r_offset = (uint64_t)off_low;
+ param.r_mincnt = 0;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_common_read(sr, &param)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
+ 5, param.r_count, VAR_BCC, 0x01, param.r_count, &sr->raw_data);
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/
+ * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
+ * attempt to use it on non-disk shares.
+ *
+ * The requested count specifies the number of bytes desired. Offset
+ * specifies the offset in the file of the first byte to be locked then
+ * read. Note that offset is limited to 32 bits, so this client request
+ * is inappropriate for files with 64 bit offsets.
+ *
+ * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
+ * immediately an error should be returned to the client. If an error
+ * occurs on the lock, the bytes should not be read.
+ *
+ * On return, count is the number of bytes actually being returned, which
+ * may be less than the count requested only if a read specifies bytes
+ * beyond the current file size. In this case only the bytes that exist
+ * are returned. A read completely beyond the end of file results in a
+ * response of length zero. This is the only circumstance when a zero
+ * length response is generated. A count returned which is less than the
+ * count requested is the end of file indicator.
+ */
+int
+smb_com_lock_and_read(struct smb_request *sr)
+{
+ smb_read_param_t param;
+ uint16_t remcnt;
+ uint32_t off_low;
+ DWORD result;
+ int rc;
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
+ &param.r_count, &off_low, &remcnt);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param.r_offset = (uint64_t)off_low;
+ param.r_mincnt = 0;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ result = smb_lock_range(sr, sr->fid_ofile, param.r_offset,
+ (uint64_t)param.r_count, 0xffffffff, SMB_LOCK_TYPE_READWRITE);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_lock_range_raise_error(sr, result);
+ }
+
+ if ((rc = smb_common_read(sr, &param)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
+ 5, param.r_count, VAR_BCC, 0x1, param.r_count, &sr->raw_data);
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
+ * SMB Core Plus to maximize performance when reading a large block
+ * of data from a server. This request was extended in LM 0.12 to
+ * support 64-bit offsets; the server can indicate support by setting
+ * CAP_LARGE_FILES in the negotiated capabilities.
+ *
+ * The client must guarantee that there is (and will be) no other request
+ * to the server for the duration of the SMB_COM_READ_RAW, since the
+ * server response has no header or trailer. To help ensure that there
+ * are no interruptions, we block all I/O for the session during read raw.
+ *
+ * If this is the first SMB request received since we sent an oplock break
+ * to this client, we don't know if it's safe to send the raw data because
+ * the requests may have crossed on the wire and the client may have
+ * interpreted the oplock break as part of the raw data. To avoid problems,
+ * we send a zero length session packet, which will force the client to
+ * retry the read.
+ *
+ * Read errors are handled by sending a zero length response.
+ */
+int
+smb_com_read_raw(struct smb_request *sr)
+{
+ smb_read_param_t param;
+ smb_node_t *node;
+ uint32_t off_low;
+ uint32_t off_high;
+ uint32_t timeout;
+ int rc;
+
+ switch (sr->session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ if (sr->smb_wct == 8) {
+ rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
+ &off_low, &param.r_count, &param.r_mincnt,
+ &timeout);
+ param.r_offset = (uint64_t)off_low;
+ } else {
+ rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
+ &off_low, &param.r_count, &param.r_mincnt, &timeout,
+ &off_high);
+ param.r_offset = ((uint64_t)off_high << 32) | off_low;
+ }
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ rc = smb_common_read(sr, &param);
+ /*
+ * XXX Do we need to handle errors here? What if we have an
+ * access error (either permissions or range lock violations?
+ */
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ node = sr->fid_ofile->f_node;
+ if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
+ rc = EAGAIN;
+ }
+ }
+
+ if (rc != 0) {
+ (void) smb_session_send(sr->session, 0, NULL);
+ m_freem(sr->raw_data.chain);
+ sr->raw_data.chain = 0;
+ } else {
+ (void) smb_session_send(sr->session, 0, &sr->raw_data);
+ }
+ return (SDRC_NO_REPLY);
+
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ (void) smb_session_send(sr->session, 0, NULL);
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+ return (SDRC_NO_REPLY);
+
+ case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
+ ASSERT(0);
+ return (SDRC_DROP_VC);
+
+ case SMB_SESSION_STATE_TERMINATED:
+ ASSERT(0);
+ return (SDRC_NO_REPLY);
+
+ case SMB_SESSION_STATE_DISCONNECTED:
+ return (SDRC_NO_REPLY);
+
+ case SMB_SESSION_STATE_CONNECTED:
+ case SMB_SESSION_STATE_ESTABLISHED:
+ default:
+ ASSERT(0);
+ return (SDRC_DROP_VC);
+ }
+}
+
+/*
+ * Read bytes from a file (SMB Core). This request was extended in
+ * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
+ * 12 and including additional offset information.
+ */
+int
+smb_com_read_andx(struct smb_request *sr)
+{
+ smb_read_param_t param;
+ uint32_t off_low;
+ uint32_t off_high;
+ uint16_t remcnt;
+ uint16_t offset2;
+ uint8_t secondary;
+ int rc;
+
+ if (sr->smb_wct == 12) {
+ rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &secondary,
+ &sr->smb_fid, &off_low, &param.r_count, &remcnt, &off_high);
+
+ param.r_offset = ((uint64_t)off_high << 32) | off_low;
+ } else {
+ rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &secondary,
+ &sr->smb_fid, &off_low, &param.r_count, &remcnt);
+
+ param.r_offset = (uint64_t)off_low;
+ }
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param.r_mincnt = 0;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_common_read(sr, &param)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Ensure that the next response offset is zero
+ * if there is no secondary command.
+ */
+ offset2 = (secondary == 0xFF) ? 0 : param.r_count + 59;
+
+ /*
+ * The STYPE_IPC response format is different.
+ * The unknown value (2) may be to indicate that it
+ * is a follow-up to an earlier RPC transaction.
+ */
+ if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
+ smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC",
+ 12, /* wct */
+ secondary, /* Secondary andx command */
+ offset2, /* offset to next */
+ 0, /* must be 0 */
+ param.r_count, /* data byte count */
+ 60, /* Offset from start to data */
+ VAR_BCC, /* BCC marker */
+ 0x02, /* unknown */
+ &sr->raw_data);
+ } else {
+ smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC",
+ 12, /* wct */
+ secondary, /* Secondary andx command */
+ offset2, /* offset to next */
+ -1, /* must be -1 */
+ param.r_count, /* data byte count */
+ 59, /* Offset from start to data */
+ VAR_BCC, /* BCC marker */
+ &sr->raw_data);
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Common function for reading files or IPC/MSRPC named pipes. All
+ * protocol read functions should lookup the fid before calling this
+ * function. We can't move the fid lookup here because lock-and-read
+ * requires the fid to do locking before attempting the read.
+ *
+ * Returns errno values.
+ */
+int
+smb_common_read(struct smb_request *sr, smb_read_param_t *param)
+{
+ smb_ofile_t *ofile = sr->fid_ofile;
+ smb_node_t *node;
+ struct vardata_block *vdb;
+ struct mbuf *top;
+ int rc;
+
+ vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
+ vdb->tag = 0;
+ vdb->uio.uio_iov = &vdb->iovec[0];
+ vdb->uio.uio_iovcnt = MAX_IOVEC;
+ vdb->uio.uio_resid = param->r_count;
+ vdb->uio.uio_offset = param->r_offset;
+ vdb->uio.uio_segflg = UIO_SYSSPACE;
+
+ switch (sr->tid_tree->t_res_type & STYPE_MASK) {
+ case STYPE_DISKTREE:
+ node = ofile->f_node;
+
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ rc = smb_lock_range_access(sr, node, param->r_offset,
+ param->r_count, FILE_READ_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ rc = ERANGE;
+ break;
+ }
+ }
+
+ (void) smb_sync_fsattr(sr, sr->user_cr, node);
+
+ sr->raw_data.max_bytes = vdb->uio.uio_resid;
+ top = smb_mbuf_allocate(&vdb->uio);
+
+ rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio,
+ &node->attr);
+
+ sr->raw_data.max_bytes -= vdb->uio.uio_resid;
+ smb_mbuf_trim(top, sr->raw_data.max_bytes);
+ MBC_ATTACH_MBUF(&sr->raw_data, top);
+ break;
+
+ case STYPE_IPC:
+ rc = smb_rpc_read(sr, &vdb->uio);
+ break;
+
+ default:
+ rc = EACCES;
+ break;
+ }
+
+ param->r_count -= vdb->uio.uio_resid;
+ kmem_free(vdb, sizeof (struct vardata_block));
+
+ if (rc != 0)
+ return (rc);
+
+ if (param->r_mincnt != 0 && param->r_count < param->r_mincnt) {
+ /*
+ * mincnt is only used by read-raw and is typically
+ * zero. If mincnt is greater than zero and the
+ * number of bytes read is less than mincnt, tell
+ * the client that we read nothing.
+ */
+ param->r_count = 0;
+ }
+
+ param->r_offset += param->r_count;
+ mutex_enter(&sr->fid_ofile->f_mutex);
+ ofile->f_seek_pos = param->r_offset;
+ mutex_exit(&sr->fid_ofile->f_mutex);
+ return (rc);
+}
+
+/*
+ * The Read Block Multiplexed protocol is used to maximize performance
+ * when reading a large block of data from server to client while still
+ * allowing other operations to take place between the client and server
+ * in parallel.
+ *
+ * The mpx sub protocol is not supported because we support only
+ * connection oriented transports and NT supports SMB_COM_READ_MPX
+ * only over connectionless transports.
+ */
+/*ARGSUSED*/
+int
+smb_com_read_mpx(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*ARGSUSED*/
+int
+smb_com_read_mpx_secondary(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rename.c b/usr/src/uts/common/fs/smbsrv/smb_rename.c
new file mode 100644
index 0000000000..f22e7187de
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c
@@ -0,0 +1,347 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/nterror.h>
+#include <sys/synch.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+static int smb_do_rename(struct smb_request *sr,
+ struct smb_fqi *src_fqi,
+ struct smb_fqi *dst_fqi);
+
+
+/*
+ * smb_com_rename
+ *
+ * Rename a file. Files OldFileName must exist and NewFileName must not.
+ * Both pathnames must be relative to the Tid specified in the request.
+ * Open files may be renamed.
+ *
+ * Multiple files may be renamed in response to a single request as Rename
+ * File supports wildcards in the file name (last component of the path).
+ * NOTE: we don't support rename with wildcards.
+ *
+ * SearchAttributes indicates the attributes that the target file(s) must
+ * have. If SearchAttributes is zero then only normal files are renamed.
+ * If the system file or hidden attributes are specified then the rename
+ * is inclusive - both the specified type(s) of files and normal files are
+ * renamed. The encoding of SearchAttributes is described in section 3.10
+ * - File Attribute Encoding.
+ */
+int
+smb_com_rename(struct smb_request *sr)
+{
+ static kmutex_t mutex;
+ struct smb_fqi *src_fqi;
+ struct smb_fqi *dst_fqi;
+ struct smb_node *dst_node;
+ int rc;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ src_fqi = &sr->arg.dirop.fqi;
+ dst_fqi = &sr->arg.dirop.dst_fqi;
+
+ if (smbsr_decode_vwv(sr, "w", &src_fqi->srch_attr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->path, &dst_fqi->path);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ dst_fqi->srch_attr = 0;
+
+ mutex_enter(&mutex);
+ rc = smb_do_rename(sr, src_fqi, dst_fqi);
+ mutex_exit(&mutex);
+
+ if (rc != 0) {
+ /*
+ * ERROR_FILE_EXISTS doesn't work for Windows98 clients.
+ *
+ * Windows95 clients don't see this problem because the target
+ * is deleted before the rename request.
+ *
+ * The following values are based on observed WFWG, Win9x,
+ * NT and W2K client behaviour.
+ */
+ if (rc == EEXIST) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_OBJECT_NAME_COLLISION,
+ ERRDOS, ERROR_ALREADY_EXISTS);
+ /* NOTREACHED */
+ }
+
+ if (rc == EPIPE) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ }
+
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (src_fqi->dir_snode)
+ smb_node_release(src_fqi->dir_snode);
+
+ dst_node = dst_fqi->dir_snode;
+ if (dst_node) {
+ if (dst_node->flags & NODE_FLAGS_NOTIFY_CHANGE) {
+ dst_node->flags |= NODE_FLAGS_CHANGED;
+ smb_process_node_notify_change_queue(dst_node);
+ }
+ smb_node_release(dst_node);
+ }
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_rename_share_check
+ *
+ * An open file can be renamed if
+ *
+ * 1. isn't opened for data writing or deleting
+ *
+ * 2. Opened with "Deny Delete" share mode
+ * But not opened for data reading or executing
+ * (opened for accessing meta data)
+ */
+DWORD
+smb_rename_share_check(struct smb_node *node)
+{
+ struct smb_ofile *open;
+
+ if (node == 0 || node->n_refcnt <= 1)
+ return (NT_STATUS_SUCCESS);
+
+ smb_llist_enter(&node->n_ofile_list, RW_READER);
+ open = smb_llist_head(&node->n_ofile_list);
+ while (open) {
+ if (open->f_granted_access &
+ (FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE)) {
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SHARING_VIOLATION);
+ }
+
+ if ((open->f_share_access & FILE_SHARE_DELETE) == 0) {
+ if (open->f_granted_access &
+ (FILE_READ_DATA | FILE_EXECUTE)) {
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SHARING_VIOLATION);
+ }
+ }
+ open = smb_llist_next(&node->n_ofile_list, open);
+ }
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SUCCESS);
+}
+
+
+/*
+ * smb_do_rename
+ *
+ * Backend to smb_com_rename to ensure that the rename operation is atomic.
+ * This function should be called within a mutual exclusion region. If the
+ * source and destination are identical, we don't actually do a rename, we
+ * just check that the conditions are right. If the source and destination
+ * files differ only in case, we a case-sensitive rename. Otherwise, we do
+ * a full case-insensitive rename.
+ *
+ * This function should always return errno values.
+ *
+ * Upon success, the last_snode's and dir_snode's of both src_fqi and dst_fqi
+ * are not released in this routine but in smb_com_rename().
+ */
+static int
+smb_do_rename(
+ struct smb_request *sr,
+ struct smb_fqi *src_fqi,
+ struct smb_fqi *dst_fqi)
+{
+ struct smb_node *src_node;
+ char *dstname;
+ DWORD status;
+ int rc;
+ int count;
+
+ if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) {
+ return (rc);
+ }
+
+ src_node = src_fqi->last_snode;
+
+ /*
+ * Break the oplock before access checks. If a client
+ * has a file open, this will force a flush or close,
+ * which may affect the outcome of any share checking.
+ */
+ if (OPLOCKS_IN_FORCE(src_node)) {
+ status = smb_break_oplock(sr, src_node);
+
+ if (status != NT_STATUS_SUCCESS) {
+ smb_node_release(src_node);
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (EACCES);
+ }
+ }
+
+ status = smb_lock_range_access(sr, src_node, 0, 0, FILE_WRITE_DATA);
+ if (status != NT_STATUS_SUCCESS) {
+ smb_node_release(src_node);
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (EACCES);
+ }
+
+
+ for (count = 0; count <= 3; count++) {
+ if (count)
+ delay(MSEC_TO_TICK(400));
+ status = smb_rename_share_check(src_node);
+ if (status != NT_STATUS_SHARING_VIOLATION)
+ break;
+ }
+
+ smb_node_release(src_node);
+
+ if (status == NT_STATUS_SHARING_VIOLATION) {
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (EPIPE); /* = ERRbadshare */
+ }
+
+ if (utf8_strcasecmp(src_fqi->path, dst_fqi->path) == 0) {
+ if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) {
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (rc);
+ }
+
+ /*
+ * Because the fqm parameter to smbd_fs_query() was 0,
+ * a successful return value means that dst_fqi->last_snode
+ * may be NULL.
+ */
+ if (dst_fqi->last_snode)
+ smb_node_release(dst_fqi->last_snode);
+
+ rc = strcmp(src_fqi->last_comp_od, dst_fqi->last_comp);
+ if (rc == 0) {
+ smb_node_release(src_fqi->dir_snode);
+ smb_node_release(dst_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (0);
+ }
+
+ rc = smb_fsop_rename(sr, sr->user_cr,
+ src_fqi->dir_snode,
+ src_fqi->last_comp_od,
+ dst_fqi->dir_snode,
+ dst_fqi->last_comp);
+
+ if (rc != 0) {
+ smb_node_release(src_fqi->dir_snode);
+ smb_node_release(dst_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ }
+ return (rc);
+ }
+
+ rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST);
+ if (rc != 0) {
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (rc);
+ }
+
+ /*
+ * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
+ * value, only dst_fqi->dir_snode is valid (dst_fqi->last_snode
+ * is NULL).
+ */
+
+ /*
+ * Use the unmangled form of the destination name if the
+ * source and destination names are the same and the source
+ * name is mangled. (We are taking a chance here, assuming
+ * that this is what the user wants.)
+ */
+
+ if ((smb_maybe_mangled_name(src_fqi->last_comp)) &&
+ (strcmp(src_fqi->last_comp, dst_fqi->last_comp) == 0)) {
+ dstname = src_fqi->last_comp_od;
+ } else {
+ dstname = dst_fqi->last_comp;
+ }
+
+ rc = smb_fsop_rename(sr, sr->user_cr,
+ src_fqi->dir_snode,
+ src_fqi->last_comp_od,
+ dst_fqi->dir_snode,
+ dstname);
+
+ if (rc != 0) {
+ smb_node_release(src_fqi->dir_snode);
+ smb_node_release(dst_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ }
+
+ return (rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rpc.c b/usr/src/uts/common/fs/smbsrv/smb_rpc.c
new file mode 100644
index 0000000000..394c5addbe
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_rpc.c
@@ -0,0 +1,532 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides a set of wrapper functions to interface to the
+ * RPC layer. Although this interface was originally implemented as a
+ * single transaction using an input buffer and an output buffer, it
+ * turns out that it really should have been a stream/pipe interface.
+ * This was first discovered when we noticed that Windows2000 was using
+ * smb_rpc_write and smb_rpc_read instead of smb_rpc_transact and then
+ * later when we tried to return a larger number of shares than would
+ * fit in a single transaction buffer.
+ *
+ * The interface is still limited by the buffers passed between this
+ * module and the RPC module but now it will support a buffer overflow
+ * and allow the client to read the remaining data on subsequent
+ * requests. Also note that the smb_rpc_write and smb_rpc_read calls
+ * are basically emulating the smb_rpc_transact function.
+ */
+
+#include <sys/ksynch.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/mlsvc.h>
+
+
+/*
+ * This is the list of well-known RPC named pipes that we support.
+ * The full pipe path will be in the form \\PIPE\\SERVICE. The first
+ * part can be assumed, so all we need here are the service names.
+ */
+static char *rpc_named_pipes[] = {
+ "\\LSARPC",
+ "\\NETLOGON",
+ "\\SAMR",
+ "\\SPOOLSS",
+ "\\SRVSVC",
+ "\\SVCCTL",
+ "\\WINREG",
+ "\\WKSSVC",
+ "\\EVENTLOG"
+};
+
+
+/*
+ * This is a list of the port addresses for the named pipes above.
+ * We need to check that these are correct but nothing appears to
+ * rely on them so this is low priority.
+ */
+#if 0
+static char *rpc_np_ports[] = {
+ "\\PIPE\\",
+ "\\PIPE\\lsass",
+ "\\PIPE\\lsass",
+ "\\PIPE\\spoolss",
+ "\\PIPE\\ntsvcs",
+ "\\PIPE\\ntsvcs",
+ "\\PIPE\\winreg",
+ "\\PIPE\\ntsvcs",
+ "\\PIPE\\ntsvcs"
+};
+#endif
+
+
+static int smb_rpc_initialize(struct smb_request *sr, char *pipe_name);
+static uint32_t smb_rpc_fid(void);
+
+
+/*
+ * Named pipe I/O is serialized to ensure that each request has exclusive
+ * access to the in and out pipe data for the duration of the request.
+ */
+static void
+smb_rpc_enter(mlsvc_pipe_t *pi)
+{
+ mutex_enter(&pi->mutex);
+
+ while (pi->busy)
+ cv_wait(&pi->cv, &pi->mutex);
+
+ pi->busy = 1;
+ mutex_exit(&pi->mutex);
+}
+
+static void
+smb_rpc_exit(mlsvc_pipe_t *pi)
+{
+ mutex_enter(&pi->mutex);
+ pi->busy = 0;
+ cv_signal(&pi->cv);
+ mutex_exit(&pi->mutex);
+}
+
+/*
+ * smb_rpc_lookup
+ *
+ * Lookup a path to see if it's a well-known RPC named pipe.
+ *
+ * Returns a pointer to the pipe name (without any leading \'s) if the path
+ * refers to a well-known RPC named pipe. Otherwise returns a null pointer.
+ */
+char *
+smb_rpc_lookup(char *path)
+{
+ int i;
+ char *pipe_name;
+
+ if (path == 0) {
+ cmn_err(CE_WARN, "smb_rpc_lookup: invalid parameter");
+ return (0);
+ }
+
+ /*
+ * Skip past the static part of the pipe
+ * name if it appears in the path.
+ */
+ if (utf8_strncasecmp(path, "\\PIPE\\", 6) == 0)
+ path += 5;
+
+ for (i = 0;
+ i < sizeof (rpc_named_pipes) / sizeof (rpc_named_pipes[0]);
+ ++i) {
+ if (utf8_strcasecmp(path, rpc_named_pipes[i]) == 0) {
+ pipe_name = rpc_named_pipes[i];
+ pipe_name += strspn(pipe_name, "\\");
+
+ return (pipe_name);
+ }
+ }
+ return (0);
+}
+
+/*
+ * smb_rpc_open
+ *
+ * Open a well-known RPC named pipe. This routine should be called if
+ * a file open is requested on a share of type STYPE_IPC. If we
+ * recognize the pipe, we initialize the session data. This will setup
+ * a new ofile and insert it into the session file list.
+ *
+ * Returns 0 on success, Otherwise an NT status is returned to indicate
+ * an error.
+ */
+int
+smb_rpc_open(struct smb_request *sr)
+{
+ struct open_param *op;
+ char *pipe_name;
+ int status;
+
+ if (smb_winpipe_open() != 0)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ op = &sr->arg.open;
+
+ if ((pipe_name = smb_rpc_lookup(op->fqi.path)) != 0) {
+ if ((status = smb_rpc_initialize(sr, pipe_name)) != 0)
+ return (status);
+
+ return (NT_STATUS_SUCCESS);
+ }
+
+ return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
+}
+
+
+/*
+ * smb_rpc_initialize
+ *
+ * Initialize various parts of the session data for a named pipe: open
+ * parameters and the ofile. There are a number of magic numbers in
+ * here that we need to identify but largely these values are ignored
+ * by the rest of the code. Insert the ofile into the session file list.
+ *
+ * Returns 0 on success, Otherwise an NT status is returned to indicate
+ * an error.
+ */
+static int
+smb_rpc_initialize(struct smb_request *sr, char *pipe_name)
+{
+ struct open_param *op;
+ struct smb_ofile *of;
+ smb_error_t err;
+
+ op = &sr->arg.open;
+ of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid,
+ op->desired_access, 0, op->share_access,
+ SMB_FTYPE_MESG_PIPE, pipe_name, smb_rpc_fid(), &err);
+ if (of == NULL)
+ return (err.status);
+
+ op->dsize = 0x01000;
+ op->utime.tv_sec = 0;
+ op->utime.tv_nsec = 0;
+ op->dattr = SMB_FA_NORMAL;
+ op->ftype = SMB_FTYPE_MESG_PIPE;
+ op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
+ op->devstate = SMB_PIPE_READMODE_MESSAGE
+ | SMB_PIPE_TYPE_MESSAGE
+ | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
+ op->fileid = of->f_fid;
+ op->create_options = 0;
+
+ sr->smb_fid = of->f_fid;
+ sr->fid_ofile = of;
+ return (0);
+}
+
+/*
+ * smb_rpc_transact
+ *
+ * This is the entry point for RPC transactions to provide a wrapper for
+ * the RPC layer. The SMB decoding and encoding is handled here so that
+ * the RPC layer doesn't have to deal with it. Both bind operations and
+ * RPC requests are handled here. The connection_fid is an arbitrary id
+ * used to associate RPC requests with a particular binding handle.
+ *
+ * The RPC library expects the input stream to contain the request data.
+ * It will build the output stream.
+ *
+ * If the data to be returned is larger than the client expects, we
+ * return as much as the client can handle and report a buffer overflow
+ * warning to inform the client that we have more data to return. The
+ * residual data remains in the output stream until the client claims
+ * it or closes the pipe.
+ */
+int
+smb_rpc_transact(struct smb_request *sr, struct uio *uio)
+{
+ struct smb_xa *xa;
+ mlsvc_pipe_t *pipe_info;
+ mlsvc_stream_t *streamin;
+ struct mbuf *mhead;
+ int mdrcnt;
+ int nbytes;
+ int rc;
+
+ ASSERT(sr->fid_ofile);
+ ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ASSERT(sr->fid_ofile->f_pipe_info != NULL);
+
+ xa = sr->r_xa;
+ mdrcnt = xa->smb_mdrcnt;
+ pipe_info = sr->fid_ofile->f_pipe_info;
+
+ smb_rpc_enter(pipe_info);
+
+ if (pipe_info->fid == 0) {
+ smb_rpc_exit(pipe_info);
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERROR_INVALID_HANDLE);
+ /* NOTREACHED */
+ }
+
+ streamin = &pipe_info->input;
+ streamin->uio.uio_iov = uio->uio_iov;
+ streamin->uio.uio_iovcnt = uio->uio_iovcnt;
+ streamin->uio.uio_offset = 0;
+ streamin->uio.uio_resid = uio->uio_resid;
+ streamin->uio.uio_segflg = UIO_SYSSPACE;
+
+ nbytes = mdrcnt;
+
+ rc = smb_winpipe_call(sr, pipe_info, streamin, SMB_RPC_TRANSACT,
+ (uint32_t *)&nbytes);
+
+ if (rc != 0) {
+ smb_rpc_exit(pipe_info);
+ smbsr_raise_nt_error(sr,
+ NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID);
+ /* NOTREACHED */
+ }
+
+ /*
+ * We need to zero the input stream so that we don't try to
+ * flush it on close: the mbuf chain belongs to the SMB XA.
+ * Then reassign the stream to refer to the output/response.
+ */
+ if (nbytes > mdrcnt) {
+ /*
+ * We have more data to return than the client expects in the
+ * response to this request. So we send as much as the client
+ * can handle, mdrcnt, and store the rest in the output chain.
+ * The buffer overflow warning informs the client that we
+ * have more data to send. Typically, the client will call
+ * SmbRead&X, which will call smb_rpc_read, to get the data.
+ */
+
+ mhead = smb_mbuf_get(pipe_info->output, mdrcnt);
+ xa->rep_data_mb.max_bytes = mdrcnt;
+ MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
+
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_setup_nt_status(sr, ERROR_SEVERITY_WARNING,
+ NT_STATUS_BUFFER_OVERFLOW);
+ else {
+ sr->smb_rcls = ERRDOS;
+ sr->smb_err = ERRmoredata;
+ }
+ } else {
+ /*
+ * The client has provided enough buffer space, all
+ * we have to do is attach the output stream to the
+ * transaction response and zero out the stream.
+ */
+ if (nbytes != 0) {
+ mhead = smb_mbuf_get(pipe_info->output, nbytes);
+ xa->rep_data_mb.max_bytes = nbytes;
+ MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
+ }
+ }
+
+ if (pipe_info->output) {
+ kmem_free(pipe_info->output, pipe_info->outlen);
+ pipe_info->output = NULL;
+ pipe_info->outlen = 0;
+ }
+
+ smb_rpc_exit(pipe_info);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_rpc_fid
+ *
+ * The connection_fid is an arbitrary id used to associate RPC requests
+ * with a particular binding handle. This routine provides a new fid on
+ * each call. It will not assign 0 or -1 so that those values can
+ * remain available as sentinels.
+ */
+static uint32_t
+smb_rpc_fid(void)
+{
+ static uint32_t connection_fid;
+ static kmutex_t smb_rpc_fid_mutex;
+
+ mutex_enter(&smb_rpc_fid_mutex);
+
+ if (connection_fid == 0)
+ connection_fid = lbolt << 11;
+
+ do {
+ ++connection_fid;
+ } while (connection_fid == 0 || connection_fid == (uint32_t)-1);
+
+ mutex_exit(&smb_rpc_fid_mutex);
+
+ return (connection_fid);
+}
+
+
+/*
+ * smb_rpc_close
+ *
+ * This function should be called whenever an IPC file/pipe is closed.
+ * All remaining I/O is flushed and the RPC layer is informed so that
+ * it can release the resources being used for this connection.
+ */
+void
+smb_rpc_close(struct smb_ofile *of)
+{
+ mlsvc_pipe_t *pipe_info;
+ uint32_t nbytes = 0;
+
+ ASSERT(of);
+ ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ASSERT(of->f_pipe_info != NULL);
+
+ pipe_info = of->f_pipe_info;
+ smb_rpc_enter(pipe_info);
+
+ if (pipe_info->fid != 0) {
+ (void) smb_winpipe_call(0, pipe_info, 0, SMB_RPC_FLUSH,
+ &nbytes);
+ pipe_info->fid = 0;
+ }
+
+ if (pipe_info->output) {
+ kmem_free(pipe_info->output, pipe_info->outlen);
+ pipe_info->output = NULL;
+ pipe_info->outlen = 0;
+ }
+
+ smb_rpc_exit(pipe_info);
+
+ cv_destroy(&pipe_info->cv);
+ mutex_destroy(&pipe_info->mutex);
+}
+
+/*
+ * smb_rpc_write
+ *
+ * This interface is an alternative to smb_rpc_transact. We set up the
+ * connection fid, as required, and copy the input data to the input
+ * stream. The input stream is created by allocating enough mbufs to
+ * hold the incoming data and doing a uio transfer. It is then up
+ * to the client to call smb_rpc_read to actually make the transaction
+ * happen.
+ *
+ * Returns 0 on success or an errno on failure.
+ */
+int
+smb_rpc_write(struct smb_request *sr, struct uio *uio)
+{
+ mlsvc_pipe_t *pipe_info;
+ mlsvc_stream_t *streamin;
+ uint32_t mdrcnt;
+ int rc;
+
+ ASSERT(sr->fid_ofile);
+ ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ASSERT(sr->fid_ofile->f_pipe_info != NULL);
+
+ pipe_info = sr->fid_ofile->f_pipe_info;
+ smb_rpc_enter(pipe_info);
+
+ if (pipe_info->fid == 0) {
+ smb_rpc_exit(pipe_info);
+ return (EBADF);
+ }
+
+ streamin = &pipe_info->input;
+ streamin->uio.uio_iov = uio->uio_iov;
+ streamin->uio.uio_iovcnt = uio->uio_iovcnt;
+ streamin->uio.uio_offset = 0;
+ streamin->uio.uio_resid = uio->uio_resid;
+ streamin->uio.uio_segflg = UIO_SYSSPACE;
+ mdrcnt = (uint32_t)uio->uio_resid;
+
+ rc = smb_winpipe_call(sr, pipe_info, streamin, SMB_RPC_WRITE,
+ &mdrcnt);
+
+ smb_rpc_exit(pipe_info);
+
+ return ((rc == 0) ? 0 : EIO);
+}
+
+/*
+ * smb_rpc_read
+ *
+ * This interface may be called because smb_rpc_transact could not return
+ * all of the data in the original transaction or to form the second half
+ * of a transaction set up using smb_rpc_write. If there is data in the
+ * output stream, we return it. Otherwise we assume that there is data
+ * in the input stream that will provide the context to perform an RPC
+ * transaction. The connection fid (pipe_info->fid) will provide the
+ * context for mlsvc_rpc_process.
+ *
+ * The response data is encoded into raw_data as required by the smb_read
+ * functions. The uio_resid value indicates the number of bytes read.
+ */
+/*ARGSUSED*/
+int
+smb_rpc_read(struct smb_request *sr, struct uio *uio)
+{
+ mlsvc_pipe_t *pinfo;
+ mlsvc_stream_t *streamin;
+ struct mbuf *mhead;
+ int mdrcnt;
+ int nbytes;
+ int rc = 0;
+
+ ASSERT(sr->fid_ofile);
+ ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ASSERT(sr->fid_ofile->f_pipe_info != NULL);
+
+ pinfo = sr->fid_ofile->f_pipe_info;
+ smb_rpc_enter(pinfo);
+
+ if (pinfo->fid == 0) {
+ rc = EBADF;
+ goto smb_rpc_read_exit;
+ }
+
+ /*
+ * if there is data left in the outpipe return it now
+ */
+ streamin = 0;
+ mdrcnt = uio->uio_resid;
+ nbytes = mdrcnt;
+
+ rc = smb_winpipe_call(sr, pinfo, streamin, SMB_RPC_READ,
+ (uint32_t *)&nbytes);
+
+ if (rc != 0 || nbytes == 0) {
+ rc = EIO;
+ goto smb_rpc_read_exit;
+ }
+ if (nbytes > mdrcnt) {
+ nbytes = mdrcnt;
+ }
+
+ mhead = smb_mbuf_get(pinfo->output, nbytes);
+ MBC_SETUP(&sr->raw_data, nbytes);
+ MBC_ATTACH_MBUF(&sr->raw_data, mhead);
+
+ uio->uio_resid -= nbytes;
+
+smb_rpc_read_exit:
+ if (pinfo->output) {
+ kmem_free(pinfo->output, pinfo->outlen);
+ pinfo->output = NULL;
+ pinfo->outlen = 0;
+ }
+
+ smb_rpc_exit(pinfo);
+ return (rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_sd.c b/usr/src/uts/common/fs/smbsrv/smb_sd.c
new file mode 100644
index 0000000000..4afa258b9a
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_sd.c
@@ -0,0 +1,862 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides Security Descriptor handling functions.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_idmap.h>
+
+#define AS_DWORD(X) (*(uint32_t *)&(X))
+#define SELF_REL(P, M, T) (T *)(((char *)(P)) + AS_DWORD((P)->M))
+
+void smb_fmt_sid(char *buf, nt_sid_t *sid);
+
+void
+smb_sd_init(smb_sd_t *sd, uint8_t revision)
+{
+ bzero(sd, sizeof (smb_sd_t));
+ sd->sd_hdr.sd_revision = revision;
+}
+
+/*
+ * smb_sd_term
+ *
+ * Free non-NULL members of 'sd' which has to be in
+ * absolute (pointer) form.
+ */
+void
+smb_sd_term(smb_sd_t *sd)
+{
+ ASSERT(sd);
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ if (sd->sd_owner)
+ MEM_FREE("libnt", sd->sd_owner);
+
+ if (sd->sd_group)
+ MEM_FREE("libnt", sd->sd_group);
+
+ if (sd->sd_dacl)
+ kmem_free(sd->sd_dacl, sd->sd_dacl->sl_size);
+
+ if (sd->sd_sacl)
+ kmem_free(sd->sd_sacl, sd->sd_sacl->sl_size);
+
+ bzero(sd, sizeof (smb_sd_t));
+}
+
+/*
+ * Hmmm. For all of these smb_sd_set_xxx() functions,
+ * what do we do if the affected member is already set?
+ * Should we free() it? For now, punt and risk a memory leak.
+ */
+
+void
+smb_sd_set_owner(smb_sd_t *sd, nt_sid_t *owner, int defaulted)
+{
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ sd->sd_owner = owner;
+ if (defaulted)
+ sd->sd_hdr.sd_control |= SE_OWNER_DEFAULTED;
+ else
+ sd->sd_hdr.sd_control &= ~SE_OWNER_DEFAULTED;
+}
+
+void
+smb_sd_set_group(smb_sd_t *sd, nt_sid_t *group, int defaulted)
+{
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ sd->sd_group = group;
+ if (defaulted)
+ sd->sd_hdr.sd_control |= SE_GROUP_DEFAULTED;
+ else
+ sd->sd_hdr.sd_control &= ~SE_GROUP_DEFAULTED;
+}
+
+void
+smb_sd_set_dacl(smb_sd_t *sd, int present, smb_acl_t *acl, int flags)
+{
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ sd->sd_dacl = acl;
+
+ if (flags & ACL_DEFAULTED)
+ sd->sd_hdr.sd_control |= SE_DACL_DEFAULTED;
+ if (flags & ACL_AUTO_INHERIT)
+ sd->sd_hdr.sd_control |= SE_DACL_AUTO_INHERITED;
+ if (flags & ACL_PROTECTED)
+ sd->sd_hdr.sd_control |= SE_DACL_PROTECTED;
+
+ if (present)
+ sd->sd_hdr.sd_control |= SE_DACL_PRESENT;
+}
+
+void
+smb_sd_set_sacl(smb_sd_t *sd, int present, smb_acl_t *acl, int flags)
+{
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ sd->sd_sacl = acl;
+
+ if (flags & ACL_DEFAULTED)
+ sd->sd_hdr.sd_control |= SE_SACL_DEFAULTED;
+ if (flags & ACL_AUTO_INHERIT)
+ sd->sd_hdr.sd_control |= SE_SACL_AUTO_INHERITED;
+ if (flags & ACL_PROTECTED)
+ sd->sd_hdr.sd_control |= SE_SACL_PROTECTED;
+
+ if (present)
+ sd->sd_hdr.sd_control |= SE_SACL_PRESENT;
+}
+
+nt_sid_t *
+smb_sd_get_owner(void *sd, int *defaulted)
+{
+ smb_sdbuf_t *sr_sd;
+ smb_sd_hdr_t *sd_hdr;
+ nt_sid_t *sid;
+
+ sd_hdr = (smb_sd_hdr_t *)sd;
+ if (defaulted != NULL)
+ *defaulted = (sd_hdr->sd_control & SE_OWNER_DEFAULTED) ? 1 : 0;
+
+ if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
+ sr_sd = ((smb_sdbuf_t *)sd);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ sid = SELF_REL(sr_sd, sd_owner_offs, nt_sid_t);
+ }
+ else
+ sid = ((smb_sd_t *)sd)->sd_owner;
+
+ return (sid);
+}
+
+nt_sid_t *
+smb_sd_get_group(void *sd, int *defaulted)
+{
+ smb_sdbuf_t *sr_sd;
+ smb_sd_hdr_t *sd_hdr;
+ nt_sid_t *sid;
+
+ sd_hdr = (smb_sd_hdr_t *)sd;
+ if (defaulted != NULL)
+ *defaulted = (sd_hdr->sd_control & SE_GROUP_DEFAULTED) ? 1 : 0;
+
+ if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
+ sr_sd = ((smb_sdbuf_t *)sd);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ sid = SELF_REL(sr_sd, sd_group_offs, nt_sid_t);
+ }
+ else
+ sid = ((smb_sd_t *)sd)->sd_group;
+
+ return (sid);
+}
+
+smb_acl_t *
+smb_sd_get_dacl(void *sd, int *present, int *defaulted)
+{
+ smb_sdbuf_t *sr_sd;
+ smb_sd_hdr_t *sd_hdr;
+ smb_acl_t *acl = NULL;
+
+ sd_hdr = (smb_sd_hdr_t *)sd;
+ if (present != NULL)
+ *present = (sd_hdr->sd_control & SE_DACL_PRESENT) ? 1 : 0;
+
+ if (defaulted != NULL)
+ *defaulted = (sd_hdr->sd_control & SE_DACL_DEFAULTED) ? 1 : 0;
+
+ if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
+ sr_sd = ((smb_sdbuf_t *)sd);
+ if (sr_sd->sd_dacl_offs) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ acl = SELF_REL(sr_sd, sd_dacl_offs, smb_acl_t);
+ }
+ }
+ else
+ acl = ((smb_sd_t *)sd)->sd_dacl;
+
+ return (acl);
+}
+
+smb_acl_t *
+smb_sd_get_sacl(void *sd, int *present, int *defaulted)
+{
+ smb_sdbuf_t *sr_sd;
+ smb_sd_hdr_t *sd_hdr;
+ smb_acl_t *acl = NULL;
+
+ sd_hdr = (smb_sd_hdr_t *)sd;
+ if (present != NULL)
+ *present = (sd_hdr->sd_control & SE_SACL_PRESENT) ? 1 : 0;
+
+ if (defaulted != NULL)
+ *defaulted = (sd_hdr->sd_control & SE_SACL_DEFAULTED) ? 1 : 0;
+
+ if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
+ sr_sd = ((smb_sdbuf_t *)sd);
+ if (sr_sd->sd_sacl_offs) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ acl = SELF_REL(sr_sd, sd_sacl_offs, smb_acl_t);
+ }
+ }
+ else
+ acl = ((smb_sd_t *)sd)->sd_sacl;
+
+ return (acl);
+}
+
+uint32_t
+smb_sd_len(void *sd, uint32_t secinfo)
+{
+ uint32_t length = 0;
+ nt_sid_t *sid;
+ smb_acl_t *acl;
+ int present;
+
+ /* SD Header */
+ length += sizeof (smb_sdbuf_t);
+
+ /* Owner */
+ if (secinfo & SMB_OWNER_SECINFO) {
+ sid = smb_sd_get_owner(sd, NULL);
+ if (sid)
+ length += nt_sid_length(sid);
+ }
+
+
+ /* Group */
+ if (secinfo & SMB_GROUP_SECINFO) {
+ sid = smb_sd_get_group(sd, NULL);
+ if (sid)
+ length += nt_sid_length(sid);
+ }
+
+
+ /* DACL */
+ if (secinfo & SMB_DACL_SECINFO) {
+ acl = smb_sd_get_dacl(sd, &present, NULL);
+ if (present && acl)
+ length += smb_acl_len(acl);
+ }
+
+ /* SACL */
+ if (secinfo & SMB_SACL_SECINFO) {
+ acl = smb_sd_get_sacl(sd, &present, NULL);
+ if (present && acl)
+ length += smb_acl_len(acl);
+ }
+
+ return (length);
+}
+
+/*
+ * smb_sd_get_secinfo
+ *
+ * Return the security information mask for the specified security
+ * descriptor.
+ */
+uint32_t
+smb_sd_get_secinfo(void *sd)
+{
+ uint32_t sec_info = 0;
+ smb_acl_t *acl;
+ int present;
+
+ if (sd == 0)
+ return (0);
+
+ if (smb_sd_get_owner(sd, NULL) != 0)
+ sec_info |= SMB_OWNER_SECINFO;
+
+ if (smb_sd_get_group(sd, NULL) != 0)
+ sec_info |= SMB_GROUP_SECINFO;
+
+ acl = smb_sd_get_dacl(sd, &present, NULL);
+ if (acl && present)
+ sec_info |= SMB_DACL_SECINFO;
+
+ acl = smb_sd_get_sacl(sd, &present, NULL);
+ if (acl && present)
+ sec_info |= SMB_SACL_SECINFO;
+
+ return (sec_info);
+}
+
+/*
+ * smb_sd_abs2selfrel
+ *
+ * This function takes an absolute SD (sd) and make a self relative
+ * SD which will be returned in srel_sd.
+ *
+ * srel_sdsz contains the size of buffer which srel_sd points to.
+ *
+ * Do not add new error codes here without checking the impact on
+ * all callers of this function.
+ *
+ * Returns NT status codes:
+ * NT_STATUS_SUCCESS
+ * NT_STATUS_BUFFER_TOO_SMALL
+ * NT_STATUS_INVALID_SECURITY_DESCR
+ */
+static uint32_t
+smb_sd_abs2selfrel(
+ smb_sd_t *sd,
+ uint32_t secinfo,
+ smb_sdbuf_t *srel_sd,
+ uint32_t srel_sdsz)
+{
+ uint32_t avail_len = srel_sdsz;
+ uint32_t length = 0;
+ unsigned char *scan_beg = (unsigned char *) srel_sd;
+ unsigned char *scan = scan_beg;
+ unsigned char *scan_end;
+ nt_sid_t *sid;
+ smb_acl_t *acl;
+ int present, defaulted;
+
+ length = smb_sd_len(sd, secinfo);
+
+ if (length == 0)
+ return (NT_STATUS_INVALID_SECURITY_DESCR);
+
+ if (avail_len < length)
+ return (NT_STATUS_BUFFER_TOO_SMALL);
+
+ bzero(srel_sd, length);
+ scan_end = scan_beg + length;
+
+ /* SD Header */
+ length = sizeof (smb_sdbuf_t);
+ srel_sd->sd_hdr.sd_revision = sd->sd_hdr.sd_revision;
+ srel_sd->sd_hdr.sd_control = SE_SELF_RELATIVE;
+ scan += length;
+
+ if (secinfo & SMB_OWNER_SECINFO) {
+ /* Owner */
+ sid = smb_sd_get_owner(sd, &defaulted);
+
+ if (defaulted)
+ srel_sd->sd_hdr.sd_control |= SE_OWNER_DEFAULTED;
+
+ if (sid) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ length = nt_sid_copy((void*)scan, sid, scan_end - scan);
+ if (length == 0)
+ goto fail;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ srel_sd->sd_owner_offs = scan - scan_beg;
+ scan += length;
+ }
+ }
+
+ if (secinfo & SMB_GROUP_SECINFO) {
+ /* Group */
+ sid = smb_sd_get_group(sd, &defaulted);
+
+ if (defaulted)
+ srel_sd->sd_hdr.sd_control |= SE_GROUP_DEFAULTED;
+
+ if (sid) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ length = nt_sid_copy((void*)scan, sid, scan_end - scan);
+ if (length == 0)
+ goto fail;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ srel_sd->sd_group_offs = scan - scan_beg;
+ scan += length;
+ }
+ }
+
+
+ if (secinfo & SMB_DACL_SECINFO) {
+ /* Dacl */
+ acl = smb_sd_get_dacl(sd, &present, &defaulted);
+
+ srel_sd->sd_hdr.sd_control |=
+ (sd->sd_hdr.sd_control & SE_DACL_INHERITANCE_MASK);
+
+ if (defaulted)
+ srel_sd->sd_hdr.sd_control |= SE_DACL_DEFAULTED;
+
+ if (present)
+ srel_sd->sd_hdr.sd_control |= SE_DACL_PRESENT;
+
+ if (present && acl) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ length = smb_acl_copy(scan_end - scan,
+ (void*) scan, acl);
+ if (length == 0)
+ goto fail;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ srel_sd->sd_dacl_offs = scan - scan_beg;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ acl = (smb_acl_t *)scan;
+ acl->sl_size = (WORD)length; /* set the size */
+ scan += length;
+ }
+ }
+
+ if (secinfo & SMB_SACL_SECINFO) {
+ /* Sacl */
+ acl = smb_sd_get_sacl(sd, &present, &defaulted);
+
+ srel_sd->sd_hdr.sd_control |=
+ (sd->sd_hdr.sd_control & SE_SACL_INHERITANCE_MASK);
+
+ if (defaulted)
+ srel_sd->sd_hdr.sd_control |= SE_SACL_DEFAULTED;
+
+ if (present)
+ srel_sd->sd_hdr.sd_control |= SE_SACL_PRESENT;
+
+ if (present && acl) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ length = smb_acl_copy(scan_end - scan,
+ (void*) scan, acl);
+ if (length == 0)
+ goto fail;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ srel_sd->sd_sacl_offs = scan - scan_beg;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ acl = (smb_acl_t *)scan;
+ acl->sl_size = (WORD)length; /* set the size */
+ scan += length;
+ }
+ }
+
+ return (NT_STATUS_SUCCESS);
+
+fail:
+ return (NT_STATUS_INVALID_SECURITY_DESCR);
+}
+
+/*
+ * smb_sd_fromfs
+ *
+ * Makes an Windows style security descriptor in absolute form
+ * based on the given filesystem security information.
+ *
+ * Should call smb_sd_term() for the returned sd to free allocated
+ * members.
+ */
+static uint32_t
+smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
+{
+ uint32_t status = NT_STATUS_SUCCESS;
+ smb_acl_t *acl = NULL;
+ smb_acl_t *sorted_acl;
+ nt_sid_t *sid;
+ idmap_stat idm_stat;
+
+ ASSERT(fs_sd);
+ ASSERT(sd);
+
+ smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
+
+ /* Owner */
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
+ SMB_IDMAP_USER, &sid);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (NT_STATUS_NONE_MAPPED);
+ }
+
+ smb_sd_set_owner(sd, sid, 0);
+ }
+
+ /* Group */
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
+ SMB_IDMAP_GROUP, &sid);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_sd_term(sd);
+ return (NT_STATUS_NONE_MAPPED);
+ }
+
+ smb_sd_set_group(sd, sid, 0);
+ }
+
+ /* DACL */
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+ if (fs_sd->sd_zdacl != NULL) {
+ acl = smb_acl_from_zfs(fs_sd->sd_zdacl, fs_sd->sd_uid,
+ fs_sd->sd_gid);
+ if (acl == NULL) {
+ smb_sd_term(sd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ /*
+ * Need to sort the ACL before send it to Windows
+ * clients. Winodws GUI is sensitive about the order
+ * of ACEs.
+ */
+ sorted_acl = smb_acl_sort(acl);
+ if (sorted_acl && (sorted_acl != acl)) {
+ kmem_free(acl, acl->sl_size);
+ acl = sorted_acl;
+ }
+ smb_sd_set_dacl(sd, 1, acl, fs_sd->sd_zdacl->acl_flags);
+ } else {
+ smb_sd_set_dacl(sd, 0, NULL, 0);
+ }
+ }
+
+ /* SACL */
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
+ if (fs_sd->sd_zsacl != NULL) {
+ acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
+ fs_sd->sd_gid);
+ if (acl == NULL) {
+ smb_sd_term(sd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ smb_sd_set_sacl(sd, 1, acl, fs_sd->sd_zsacl->acl_flags);
+ } else {
+ smb_sd_set_sacl(sd, 0, NULL, 0);
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * smb_sd_tofs
+ *
+ * Creates a filesystem security structure based on the given
+ * Windows security descriptor.
+ */
+uint32_t
+smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
+{
+ nt_sid_t *sid;
+ smb_acl_t *acl;
+ uint32_t status = NT_STATUS_SUCCESS;
+ uint16_t sd_control;
+ idmap_stat idm_stat;
+ int present;
+ int idtype;
+ int flags = 0;
+
+ sd_control = sr_sd->sd_hdr.sd_control;
+
+ /*
+ * ZFS only has one set of flags so for now only
+ * Windows DACL flags are taken into account.
+ */
+ if (sd_control & SE_DACL_DEFAULTED)
+ flags |= ACL_DEFAULTED;
+ if (sd_control & SE_DACL_AUTO_INHERITED)
+ flags |= ACL_AUTO_INHERIT;
+ if (sd_control & SE_DACL_PROTECTED)
+ flags |= ACL_PROTECTED;
+
+ if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
+ flags |= ACL_IS_DIR;
+
+ /* Owner */
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ sid = smb_sd_get_owner(sr_sd, NULL);
+ if (nt_sid_is_valid(sid) == 0) {
+ return (NT_STATUS_INVALID_SID);
+ }
+
+ idtype = SMB_IDMAP_UNKNOWN;
+ idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (NT_STATUS_NONE_MAPPED);
+ }
+ }
+
+ /* Group */
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ sid = smb_sd_get_group(sr_sd, NULL);
+ if (nt_sid_is_valid(sid) == 0) {
+ return (NT_STATUS_INVALID_SID);
+ }
+
+ idtype = SMB_IDMAP_UNKNOWN;
+ idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (NT_STATUS_NONE_MAPPED);
+ }
+ }
+
+ /* DACL */
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+ acl = smb_sd_get_dacl(sr_sd, &present, NULL);
+ if (present) {
+ status = smb_acl_to_zfs(acl, flags,
+ SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
+ if (status != NT_STATUS_SUCCESS)
+ return (status);
+ }
+ else
+ return (NT_STATUS_INVALID_ACL);
+ }
+
+ /* SACL */
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
+ acl = smb_sd_get_sacl(sr_sd, &present, NULL);
+ if (present) {
+ status = smb_acl_to_zfs(acl, flags,
+ SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
+ if (status != NT_STATUS_SUCCESS) {
+ return (status);
+ }
+ } else {
+ return (NT_STATUS_INVALID_ACL);
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * smb_sd_read
+ *
+ * Read uid, gid and ACL from filesystem. The returned ACL from read
+ * routine is always in ZFS format. Convert the ZFS acl to a Win acl
+ * and return the Win SD in relative form.
+ *
+ * NOTE: upon successful return caller MUST free the memory allocated
+ * for the returned SD by calling kmem_free(). The length of the allocated
+ * buffer is returned in 'buflen'.
+ */
+uint32_t
+smb_sd_read(smb_request_t *sr, smb_sdbuf_t **sr_sd,
+ uint32_t secinfo, uint32_t *buflen)
+{
+ smb_sd_t sd;
+ smb_fssd_t fs_sd;
+ smb_error_t smb_err;
+ smb_sdbuf_t *sdbuf;
+ smb_node_t *node;
+ uint32_t sdlen;
+ uint32_t status = NT_STATUS_SUCCESS;
+ uint32_t sd_flags;
+ int error;
+
+ *sr_sd = NULL;
+
+ node = sr->fid_ofile->f_node;
+ sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
+ smb_fsop_sdinit(&fs_sd, secinfo, sd_flags);
+
+ error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
+ if (error) {
+ smb_errmap_unix2smb(error, &smb_err);
+ return (smb_err.status);
+ }
+
+ status = smb_sd_fromfs(&fs_sd, &sd);
+ smb_fsop_sdterm(&fs_sd);
+
+ if (status != NT_STATUS_SUCCESS)
+ return (status);
+
+ sdlen = smb_sd_len(&sd, secinfo);
+
+ if (*buflen < sdlen) {
+ /* return the required size */
+ *buflen = sdlen;
+ smb_sd_term(&sd);
+ return (NT_STATUS_BUFFER_TOO_SMALL);
+ }
+
+ sdbuf = kmem_alloc(sdlen, KM_SLEEP);
+ status = smb_sd_abs2selfrel(&sd, secinfo, sdbuf, sdlen);
+ smb_sd_term(&sd);
+
+ if (status == NT_STATUS_SUCCESS) {
+ *sr_sd = sdbuf;
+ *buflen = sdlen;
+ }
+ else
+ kmem_free(sdbuf, sdlen);
+
+ return (status);
+}
+
+/*
+ * smb_sd_write
+ *
+ * Takes a Win SD in self-relative form, convert it to
+ * ZFS format and write it to filesystem. The write routine
+ * converts ZFS acl to Posix acl if required.
+ */
+uint32_t
+smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd, uint32_t secinfo)
+{
+ smb_node_t *node;
+ smb_fssd_t fs_sd;
+ smb_error_t smb_err;
+ uint32_t status;
+ uint32_t sd_flags;
+ int error;
+
+ node = sr->fid_ofile->f_node;
+ sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
+ smb_fsop_sdinit(&fs_sd, secinfo, sd_flags);
+
+ status = smb_sd_tofs(sr_sd, &fs_sd);
+ if (status != NT_STATUS_SUCCESS) {
+ smb_fsop_sdterm(&fs_sd);
+ return (status);
+ }
+
+ error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
+ smb_fsop_sdterm(&fs_sd);
+
+ if (error) {
+ smb_errmap_unix2smb(error, &smb_err);
+ return (smb_err.status);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_fmt_sid
+ *
+ * Make an string SID and copy the result into the specified buffer.
+ */
+void
+smb_fmt_sid(char *buf, nt_sid_t *sid)
+{
+ char *sid_str;
+
+ sid_str = nt_sid_format(sid);
+ if (sid_str) {
+ (void) strcpy(buf, sid_str);
+ MEM_FREE("smb", sid_str);
+ } else {
+ (void) strcpy(buf, "<invalid SID>");
+ }
+}
+
+/*
+ * smb_sd_log
+ *
+ * log the given Windows style security descriptor information
+ * in system log. This is for debugging purposes.
+ */
+void
+smb_sd_log(void *sd)
+{
+ smb_acl_t *acl;
+ smb_ace_t *ace;
+ nt_sid_t *sid;
+ int present, defaulted;
+ char entry[128];
+ char *inherit;
+ char *type;
+ int ix_dacl;
+
+ sid = smb_sd_get_owner(sd, &defaulted);
+ if (sid)
+ smb_fmt_sid(entry, sid);
+ else
+ (void) strcpy(entry, "NULL");
+
+ cmn_err(CE_NOTE, " Owner: %s", entry);
+
+ sid = smb_sd_get_group(sd, &defaulted);
+ if (sid)
+ smb_fmt_sid(entry, sid);
+ else
+ (void) strcpy(entry, "NULL");
+
+ cmn_err(CE_NOTE, " Primary Group: %s", entry);
+
+ acl = smb_sd_get_dacl(sd, &present, &defaulted);
+
+ if (!present || !acl) {
+ cmn_err(CE_NOTE, " No DACL");
+ return;
+ }
+
+ for (ix_dacl = 0;
+ ace = smb_ace_get(acl, ix_dacl);
+ ix_dacl++) {
+ /*
+ * Make sure the ACE type is something we grok.
+ * All ACE, now and in the future, have a valid
+ * header. Can't access fields passed the Header
+ * until we're sure it's right.
+ */
+ switch (ace->se_header.se_type) {
+ case ACCESS_ALLOWED_ACE_TYPE:
+ type = "(Allow)";
+ break;
+ case ACCESS_DENIED_ACE_TYPE:
+ type = "(Deny)";
+ break;
+
+ case SYSTEM_AUDIT_ACE_TYPE:
+ default:
+ /* Ignore unrecognized/misplaced ACE */
+ continue;
+ }
+
+ smb_fmt_sid(entry, &ace->se_sid);
+
+ switch (ace->se_header.se_flags & INHERIT_MASK_ACE) {
+ case OBJECT_INHERIT_ACE:
+ inherit = "(OI)";
+ break;
+ case CONTAINER_INHERIT_ACE:
+ inherit = "(CI)";
+ break;
+ case INHERIT_ONLY_ACE:
+ inherit = "(IO)";
+ break;
+ case NO_PROPOGATE_INHERIT_ACE:
+ inherit = "(NP)";
+ break;
+ default:
+ inherit = "";
+ }
+
+ (void) snprintf(entry + strlen(entry), sizeof (entry),
+ ":%s 0x%X %s", inherit, ace->se_mask, type);
+
+ cmn_err(CE_NOTE, " %s", entry);
+ }
+
+ cmn_err(CE_NOTE, " %d ACE(s)", ix_dacl);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_search.c b/usr/src/uts/common/fs/smbsrv/smb_search.c
new file mode 100644
index 0000000000..0700b8fd2d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_search.c
@@ -0,0 +1,289 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: search
+ *
+ * This command is used to search directories.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT MaxCount; Number of dir. entries to return
+ * USHORT SearchAttributes;
+ * USHORT ByteCount; Count of data bytes; min = 5
+ * UCHAR BufferFormat1; 0x04 -- ASCII
+ * UCHAR FileName[]; File name, may be null
+ * UCHAR BufferFormat2; 0x05 -- Variable block
+ * USHORT ResumeKeyLength; Length of resume key, may be 0
+ * UCHAR ResumeKey[]; Resume key
+ *
+ * FileName specifies the file to be sought. SearchAttributes indicates
+ * the attributes that the file must have, and is described in the "File
+ * Attribute Encoding" section of this document. If SearchAttributes is
+ * zero then only normal files are returned. If the system file, hidden or
+ * directory attributes are specified then the search is inclusive@both the
+ * specified type(s) of files and normal files are returned. If the volume
+ * label attribute is specified then the search is exclusive, and only the
+ * volume label entry is returned.
+ *
+ * MaxCount specifies the number of directory entries to be returned.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Count; Number of entries returned
+ * USHORT ByteCount; Count of data bytes; min = 3
+ * UCHAR BufferFormat; 0x05 -- Variable block
+ * USHORT DataLength; Length of data
+ * UCHAR DirectoryInformationData[]; Data
+ *
+ * The response will contain one or more directory entries as determined by
+ * the Count field. No more than MaxCount entries will be returned. Only
+ * entries that match the sought FileName and SearchAttributes combination
+ * will be returned.
+ *
+ * ResumeKey must be null (length = 0) on the initial search request.
+ * Subsequent search requests intended to continue a search must contain
+ * the ResumeKey field extracted from the last directory entry of the
+ * previous response. ResumeKey is self-contained, for on calls containing
+ * a non-zero ResumeKey neither the SearchAttributes or FileName fields
+ * will be valid in the request. ResumeKey has the following format:
+ *
+ * Resume Key Field Description
+ * ================================== =================================
+ *
+ * UCHAR Reserved; bit 7 - consumer use
+ * bits 5,6 - system use (must
+ * preserve)
+ * bits 0-4 - server use (must
+ * preserve)
+ * UCHAR FileName[11]; Name of the returned file
+ * UCHAR ReservedForServer[5]; Client must not modify
+ * UCHAR ReservedForConsumer[4]; Server must not modify
+ *
+ * FileName is 8.3 format, with the three character extension left
+ * justified into FileName[9-11]. If the client is prior to the LANMAN1.0
+ * dialect, the returned FileName should be uppercased.
+ *
+ * SMB_COM_SEARCH terminates when either the requested maximum number of
+ * entries that match the named file are found, or the end of directory is
+ * reached without the maximum number of matches being found. A response
+ * containing no entries indicates that no matching entries were found
+ * between the starting point of the search and the end of directory.
+ *
+ * There may be multiple matching entries in response to a single request
+ * as SMB_COM_SEARCH supports wildcards in the last component of FileName
+ * of the initial request.
+ *
+ * Returned directory entries in the DirectoryInformationData field of the
+ * response each have the following format:
+ *
+ * Directory Information Field Description
+ * ================================== =================================
+ *
+ * SMB_RESUME_KEY ResumeKey; Described above
+ * UCHAR FileAttributes; Attributes of the found file
+ * SMB_TIME LastWriteTime; Time file was last written
+ * SMB_DATE LastWriteDate; Date file was last written
+ * ULONG FileSize; Size of the file
+ * UCHAR FileName[13]; ASCII, space-filled null
+ * terminated
+ *
+ * FileName must conform to 8.3 rules, and is padded after the extension
+ * with 0x20 characters if necessary. If the client has negotiated a
+ * dialect prior to the LANMAN1.0 dialect, or if bit0 of the Flags2 SMB
+ * header field of the request is clear, the returned FileName should be
+ * uppercased.
+ *
+ * As can be seen from the above structure, SMB_COM_SEARCH can not return
+ * long filenames, and can not return UNICODE filenames. Files which have
+ * a size greater than 2^32 bytes should have the least significant 32 bits
+ * of their size returned in FileSize.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_search(struct smb_request *sr)
+{
+ int rc;
+ unsigned short sattr, count, maxcount;
+ char *path;
+ uint32_t cookie;
+ char name[14];
+ unsigned char resume_char;
+ uint32_t resume_key;
+ struct smb_node *node;
+ unsigned char type;
+ unsigned short key_len;
+ fsvol_attr_t vol_attr;
+ smb_odir_context_t *pc;
+
+ /* We only handle 8.3 name here */
+ sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES;
+ sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE;
+
+ if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len) != 0) ||
+ (type != 0x05)) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((rc = fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ count = 0;
+
+ if ((sattr == SMB_FA_VOLUME) && (key_len != 21)) {
+ (void) memset(name, ' ', sizeof (name));
+ (void) strncpy(name, vol_attr.name, sizeof (name));
+
+ if (key_len >= 21) {
+ (void) smb_decode_mbc(&sr->smb_data, "17.l",
+ &resume_key);
+ } else {
+ resume_key = 0;
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "bwwbwb11c5.lb8.13c",
+ 1, 0, VAR_BCC, 5, 0, 0, path+1,
+ resume_key, sattr, name);
+ count++;
+ } else {
+ cookie = 0;
+ if (key_len == 0) { /* begin search */
+ /*
+ * Some MS clients pass NULL file names
+ * NT interprets this as "\"
+ */
+ if (strlen(path) == 0) path = "\\";
+
+ rc = smb_rdir_open(sr, path, sattr);
+ if (rc == SDRC_NORMAL_REPLY) {
+ sr->reply.chain_offset = sr->cur_reply_offset;
+ (void) smb_encode_mbc(&sr->reply, "bw", 0, 0);
+ return (rc);
+ }
+ resume_char = 0;
+ resume_key = 0;
+ } else if (key_len == 21) {
+ if (smb_decode_mbc(&sr->smb_data, "b12.wwl",
+ &resume_char, &cookie, &sr->smb_sid,
+ &resume_key) != 0) {
+ /* We don't know which search to close! */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
+ sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+ } else {
+ /* We don't know which search to close! */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
+
+ pc = MEM_ZALLOC("smb", sizeof (*pc));
+ pc->dc_cookie = cookie;
+ node = (struct smb_node *)0;
+ rc = 0;
+ while (count < maxcount) {
+ if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
+ break;
+ if ((strcmp(pc->dc_name, ".") == 0) ||
+ (strcmp(pc->dc_name, "..") == 0)) {
+ if (node) {
+ smb_node_release(node);
+ node = (struct smb_node *)0;
+ }
+ continue;
+ }
+
+ (void) memset(name, ' ', sizeof (name));
+ if (*pc->dc_shortname)
+ (void) strncpy(name, pc->dc_shortname, 13);
+ else {
+ (void) strncpy(name, pc->dc_name, 13);
+ if ((sr->session->dialect <= LANMAN1_0) ||
+ ((sr->smb_flg2 &
+ SMB_FLAGS2_KNOWS_LONG_NAMES) == 0))
+ (void) utf8_strupr(name);
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "b8c3c.wwlbYl13c",
+ resume_char,
+ pc->dc_name83, pc->dc_name83+9,
+ pc->dc_cookie, sr->smb_sid,
+ resume_key,
+ pc->dc_dattr & 0xff,
+ pc->dc_attr.sa_vattr.va_mtime.tv_sec,
+ (int32_t)smb_node_get_size(node, &pc->dc_attr),
+ name);
+ smb_node_release(node);
+ node = (struct smb_node *)0;
+ count++;
+ }
+ MEM_FREE("smb", pc);
+
+ if ((rc != 0) && (rc != ENOENT)) {
+ /* returned error by smb_rdir_next() */
+ smb_rdir_close(sr);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (count == 0) {
+ smb_rdir_close(sr);
+ smbsr_raise_error(sr, ERRDOS, ERRnofiles);
+ /* NOTREACHED */
+ }
+ }
+
+ rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8;
+ (void) smb_poke_mbc(&sr->reply, sr->cur_reply_offset, "bwwbw",
+ 1, count, rc+3, 5, rc);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_seek.c b/usr/src/uts/common/fs/smbsrv/smb_seek.c
new file mode 100644
index 0000000000..a120a26a9d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_seek.c
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The seek message is sent to set the current file pointer for FID.
+ * This request should generally only be used by clients wishing to
+ * find the size of a file, since all read and write requests include
+ * the read or write file position as part of the SMB. This request
+ * is inappropriate for large files, as the offsets specified are only
+ * 32 bits.
+ *
+ * The CIFS/1.0 (1996) spec contains the following incomplete statement:
+ *
+ * "A seek which results in an Offset which can not be expressed
+ * in 32 bits returns the least significant."
+ *
+ * It would probably be a mistake to make an assumption about what this
+ * statement means. So, for now, we return an error if the resultant
+ * file offset is beyond the 32-bit limit.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_seek
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 4
+ * USHORT Fid; File handle
+ * USHORT Mode; Seek mode: 0, 1 or 2
+ * LONG Offset; Relative offset
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The starting point of the seek is set by Mode:
+ *
+ * 0 seek from start of file
+ * 1 seek from current current position
+ * 2 seek from end of file
+ *
+ * The "current position" reflects the offset plus data length specified in
+ * the previous read, write or seek request, and the pointer set by this
+ * command will be replaced by the offset specified in the next read, write
+ * or seek command.
+ *
+ * Server Response Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 2
+ * ULONG Offset; Offset from start of file
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The response returns the new file pointer in Offset, which is expressed
+ * as the offset from the start of the file, and may be beyond the current
+ * end of file. An attempt to seek before the start of the file sets the
+ * current file pointer to the start of the file.
+ */
+int
+smb_com_seek(struct smb_request *sr)
+{
+ ushort_t mode;
+ int32_t off;
+ uint32_t off_ret;
+ int rc;
+
+ if (smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &mode, &off) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (mode == SMB_SEEK_END) {
+ (void) smb_set_file_size(sr);
+ }
+
+ rc = smb_ofile_seek(sr->fid_ofile, mode, off, &off_ret);
+ if (rc == 0) {
+ smbsr_encode_result(sr, 2, 0, "blw", 2, off_ret, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+ if (rc == EINVAL) {
+ smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
+ /* NOTREACHED */
+ }
+ if (rc == EOVERFLOW) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+ ASSERT(0);
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+
+ /*
+ * Although smbsr_raise_error() doesn't return and the compiler is
+ * told so in smb_kproto.h it still has a problem if it doesn't
+ * find here a return instruction with a value.
+ */
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c
new file mode 100644
index 0000000000..3be7eaab1f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c
@@ -0,0 +1,1252 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/atomic.h>
+#include <sys/strsubr.h>
+#include <sys/synch.h>
+#include <sys/types.h>
+#include <sys/socketvar.h>
+#include <sys/sdt.h>
+#include <smbsrv/netbios.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_i18n.h>
+
+extern int smb_maxbufsize;
+
+extern unsigned int smb_nt_tcp_rcvbuf;
+
+uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT;
+uint32_t smb_send_retries = 0;
+uint32_t smb_receive_retries = 0;
+
+static int smb_session_message(smb_session_t *);
+static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
+ uint8_t *, size_t);
+
+void smb_request_init_command_mbuf(smb_request_t *sr);
+static void smb_session_wakeup_daemon(smb_thread_t *thread, void *so_void);
+
+
+void
+smb_timers(smb_thread_t *thread, void *si_void)
+{
+ smb_info_t *si = si_void;
+ smb_session_t *sn;
+
+ ASSERT(si != NULL);
+
+ while (smb_thread_continue_timedwait(thread, 1 /* Seconds */)) {
+ /*
+ * Walk through the table and decrement each keep_alive
+ * timer that has not timed out yet. (keepalive > 0)
+ */
+ smb_svcstate_lock_read(&si->si_svc_sm_ctx);
+
+ sn = NULL;
+ while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx,
+ sn)) != NULL) {
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ if (sn->keep_alive && (sn->keep_alive != (uint32_t)-1))
+ sn->keep_alive--;
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+
+ }
+}
+
+/*
+ * smb_reconnection_check
+ *
+ * This function is called when a client indicates its current connection
+ * should be the only one it has with the server, as indicated by VC=0 in
+ * a SessionSetupX request. We go through the session list and destroy any
+ * stale connections for that client.
+ *
+ * Clients don't associate IP addresses and servers. So a client may make
+ * independent connections (i.e. with VC=0) to a server with multiple
+ * IP addresses. So, when checking for a reconnection, we need to include
+ * the local IP address, to which the client is connecting, when checking
+ * for stale sessions.
+ *
+ * Also check the server's NetBIOS name to support simultaneous access by
+ * multiple clients behind a NAT server. This will only work for SMB over
+ * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because
+ * there is no NetBIOS name. See also Knowledge Base article Q301673.
+ */
+void
+smb_reconnection_check(struct smb_session *session)
+{
+ smb_info_t *si = &smb_info;
+ smb_session_t *sn;
+
+ smb_svcstate_lock_read(&si->si_svc_sm_ctx);
+
+ sn = NULL;
+ while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, sn))
+ != NULL) {
+
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ if ((sn != session) &&
+ (sn->ipaddr == session->ipaddr) &&
+ (sn->local_ipaddr == session->local_ipaddr) &&
+ (strcasecmp(sn->workstation, session->workstation) == 0) &&
+ (sn->opentime <= session->opentime) &&
+ (sn->s_kid < session->s_kid)) {
+ smb_thread_stop(&sn->s_thread);
+ }
+ }
+
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+}
+
+
+void
+smb_correct_keep_alive_values(uint32_t new_keep_alive)
+{
+ smb_info_t *si = &smb_info;
+ smb_session_t *sn;
+
+ if (new_keep_alive == smb_keep_alive)
+ return;
+ /*
+ * keep alive == 0 means do not drop connection if it's idle
+ */
+ smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
+
+ /*
+ * Walk through the table and set each session to the new keep_alive
+ * value if they have not already timed out. Block clock interrupts.
+ */
+ smb_svcstate_lock_read(&si->si_svc_sm_ctx);
+
+ sn = NULL;
+ while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, sn))
+ != NULL) {
+ if (sn->keep_alive)
+ sn->keep_alive = new_keep_alive;
+ }
+
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+}
+
+/*
+ * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
+ *
+ * The mbuf chain is copied into a contiguous buffer so that the whole
+ * message is submitted to smb_sosend as a single request. This should
+ * help Ethereal/Wireshark delineate the packets correctly even though
+ * TCP_NODELAY has been set on the socket.
+ *
+ * If an mbuf chain is provided, it will be freed and set to NULL here.
+ */
+int
+smb_session_send(smb_session_t *session, uint8_t type, struct mbuf_chain *mbc)
+{
+ struct mbuf *m = 0;
+ uint8_t *buf;
+ smb_xprt_t hdr;
+ int count = 0;
+ int rc;
+
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ if ((mbc != NULL) && (mbc->chain != NULL)) {
+ m_freem(mbc->chain);
+ mbc->chain = NULL;
+ mbc->flags = 0;
+ }
+ return (ENOTCONN);
+ default:
+ break;
+ }
+
+ buf = kmem_alloc(NETBIOS_REQ_MAX_SIZE, KM_SLEEP);
+
+ if ((mbc != NULL) && (mbc->chain != NULL)) {
+ count = NETBIOS_HDR_SZ; /* Account for the NBT header. */
+ m = mbc->chain;
+
+ while (m) {
+ if ((count + m->m_len) > NETBIOS_REQ_MAX_SIZE) {
+ kmem_free(buf, NETBIOS_REQ_MAX_SIZE);
+ m_freem(mbc->chain);
+ mbc->chain = NULL;
+ mbc->flags = 0;
+ return (EMSGSIZE);
+ }
+ bcopy(m->m_data, buf + count, m->m_len);
+ count += m->m_len;
+ m = m->m_next;
+ }
+
+ m_freem(mbc->chain);
+ mbc->chain = NULL;
+ mbc->flags = 0;
+ count -= NETBIOS_HDR_SZ;
+ }
+
+ hdr.xh_type = type;
+ hdr.xh_length = count;
+
+ rc = smb_session_xprt_puthdr(session, &hdr, buf, NETBIOS_HDR_SZ);
+ if (rc == 0) {
+ count += NETBIOS_HDR_SZ;
+ rc = smb_sosend(session->sock, buf, count);
+ }
+
+ kmem_free(buf, NETBIOS_REQ_MAX_SIZE);
+ return (rc);
+}
+
+/*
+ * Read, process and respond to a NetBIOS session request.
+ *
+ * A NetBIOS session must be established for SMB-over-NetBIOS. Validate
+ * the calling and called name format and save the client NetBIOS name,
+ * which is used when a NetBIOS session is established to check for and
+ * cleanup leftover state from a previous session.
+ *
+ * Session requests are not valid for SMB-over-TCP, which is unfortunate
+ * because without the client name leftover state cannot be cleaned up
+ * if the client is behind a NAT server.
+ */
+static int
+smb_session_request(struct smb_session *session)
+{
+ int rc;
+ char *calling_name;
+ char *called_name;
+ char client_name[NETBIOS_NAME_SZ];
+ struct mbuf_chain mbc;
+ char *names = NULL;
+ mts_wchar_t *wbuf = NULL;
+ smb_xprt_t hdr;
+ char *p;
+ unsigned int cpid = oem_get_smb_cpid();
+ int rc1, rc2;
+
+ session->keep_alive = smb_keep_alive;
+
+ if (smb_session_xprt_gethdr(session, &hdr) != 0)
+ return (EINVAL);
+
+ DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session,
+ smb_xprt_t *, &hdr);
+
+ if ((hdr.xh_type != SESSION_REQUEST) ||
+ (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) {
+ DTRACE_PROBE1(receive__session__req__failed,
+ struct session *, session);
+ return (EINVAL);
+ }
+
+ names = kmem_alloc(hdr.xh_length, KM_SLEEP);
+
+ if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) {
+ kmem_free(names, hdr.xh_length);
+ DTRACE_PROBE1(receive__session__req__failed,
+ struct session *, session);
+ return (rc);
+ }
+
+ DTRACE_PROBE3(receive__session__req__data, struct session *, session,
+ char *, names, uint32_t, hdr.xh_length);
+
+ called_name = &names[0];
+ calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2];
+
+ rc1 = netbios_name_isvalid(called_name, 0);
+ rc2 = netbios_name_isvalid(calling_name, client_name);
+
+ if (rc1 == 0 || rc2 == 0) {
+
+ DTRACE_PROBE3(receive__invalid__session__req,
+ struct session *, session, char *, names,
+ uint32_t, hdr.xh_length);
+
+ kmem_free(names, hdr.xh_length);
+ MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH);
+ (void) smb_encode_mbc(&mbc, "b",
+ DATAGRAM_INVALID_SOURCE_NAME_FORMAT);
+ (void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE,
+ &mbc);
+ return (EINVAL);
+ }
+
+ DTRACE_PROBE3(receive__session__req__calling__decoded,
+ struct session *, session,
+ char *, calling_name, char *, client_name);
+
+ /*
+ * The client NetBIOS name is in oem codepage format.
+ * We need to convert it to unicode and store it in
+ * multi-byte format. We also need to strip off any
+ * spaces added as part of the NetBIOS name encoding.
+ */
+ wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (mts_wchar_t)), KM_SLEEP);
+ (void) oemstounicodes(wbuf, client_name, SMB_PI_MAX_HOST, cpid);
+ (void) mts_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST);
+ kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (mts_wchar_t)));
+
+ if ((p = strchr(session->workstation, ' ')) != 0)
+ *p = '\0';
+
+ kmem_free(names, hdr.xh_length);
+ return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL));
+}
+
+/*
+ * Read 4-byte header from the session socket and build an in-memory
+ * session transport header. See smb_xprt_t definition for header
+ * format information.
+ *
+ * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445. The
+ * first byte of the four-byte header must be 0 and the next three
+ * bytes contain the length of the remaining data.
+ */
+int
+smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr)
+{
+ unsigned char buf[NETBIOS_HDR_SZ];
+
+ if (smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ) != 0)
+ return (-1);
+
+ switch (session->s_local_port) {
+ case SSN_SRVC_TCP_PORT:
+ ret_hdr->xh_type = buf[0];
+ ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) |
+ ((uint32_t)buf[2] << 8) |
+ ((uint32_t)buf[3]);
+ break;
+
+ case SMB_SRVC_TCP_PORT:
+ ret_hdr->xh_type = buf[0];
+
+ if (ret_hdr->xh_type != 0) {
+ cmn_err(CE_WARN, "0x%08x: invalid type (%u)",
+ session->ipaddr, ret_hdr->xh_type);
+ return (-1);
+ }
+
+ ret_hdr->xh_length = ((uint32_t)buf[1] << 16) |
+ ((uint32_t)buf[2] << 8) |
+ ((uint32_t)buf[3]);
+ break;
+
+ default:
+ cmn_err(CE_WARN, "0x%08x: invalid port %u",
+ session->ipaddr, session->s_local_port);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Encode a transport session packet header into a 4-byte buffer.
+ * See smb_xprt_t definition for header format information.
+ */
+static int
+smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr,
+ uint8_t *buf, size_t buflen)
+{
+ if (session == NULL || hdr == NULL ||
+ buf == NULL || buflen < NETBIOS_HDR_SZ) {
+ return (-1);
+ }
+
+ switch (session->s_local_port) {
+ case SSN_SRVC_TCP_PORT:
+ buf[0] = hdr->xh_type;
+ buf[1] = ((hdr->xh_length >> 16) & 1);
+ buf[2] = (hdr->xh_length >> 8) & 0xff;
+ buf[3] = hdr->xh_length & 0xff;
+ break;
+
+ case SMB_SRVC_TCP_PORT:
+ buf[0] = hdr->xh_type;
+ buf[1] = (hdr->xh_length >> 16) & 0xff;
+ buf[2] = (hdr->xh_length >> 8) & 0xff;
+ buf[3] = hdr->xh_length & 0xff;
+ break;
+
+ default:
+ cmn_err(CE_WARN, "0x%08x: invalid port (%u)",
+ session->ipaddr, session->s_local_port);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_request_alloc
+ *
+ * Allocate an smb_request_t structure from the kmem_cache. Partially
+ * initialize the found/new request.
+ *
+ * Returns pointer to a request
+ */
+smb_request_t *
+smb_request_alloc(struct smb_session *session, int req_length)
+{
+ struct smb_request *sr;
+
+ sr = kmem_cache_alloc(smb_info.si_cache_request, KM_SLEEP);
+
+ /*
+ * Future: Use constructor to pre-initialize some fields. For now
+ * there are so many fields that it is easiest just to zero the
+ * whole thing and start over.
+ */
+ bzero(sr, sizeof (smb_request_t));
+
+ mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
+ sr->session = session;
+ sr->request_storage.forw = &sr->request_storage;
+ sr->request_storage.back = &sr->request_storage;
+ sr->command.max_bytes = req_length;
+ sr->reply.max_bytes = smb_maxbufsize;
+ sr->sr_req_length = req_length;
+ sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
+ sr->sr_magic = SMB_REQ_MAGIC;
+ sr->sr_state = SMB_REQ_STATE_INITIALIZING;
+ smb_slist_insert_tail(&session->s_req_list, sr);
+ return (sr);
+}
+
+void
+smb_request_init_command_mbuf(smb_request_t *sr)
+{
+ MGET(sr->command.chain, 0, MT_DATA);
+
+ /*
+ * Setup mbuf, mimic MCLGET but use the complete packet buffer.
+ */
+ sr->command.chain->m_ext.ext_buf = sr->sr_request_buf;
+ sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf;
+ sr->command.chain->m_len = sr->sr_req_length;
+ sr->command.chain->m_flags |= M_EXT;
+ sr->command.chain->m_ext.ext_size = sr->sr_req_length;
+ sr->command.chain->m_ext.ext_ref = &mclrefnoop;
+
+ /*
+ * Initialize the rest of the mbuf_chain fields
+ */
+ sr->command.flags = 0;
+ sr->command.shadow_of = 0;
+ sr->command.max_bytes = sr->sr_req_length;
+ sr->command.chain_offset = 0;
+}
+
+/*
+ * smb_request_cancel
+ *
+ * Handle a cancel for a request properly depending on the current request
+ * state.
+ */
+void
+smb_request_cancel(smb_request_t *sr)
+{
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+
+ case SMB_REQ_STATE_SUBMITTED:
+ case SMB_REQ_STATE_ACTIVE:
+ case SMB_REQ_STATE_CLEANED_UP:
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+ break;
+
+ case SMB_REQ_STATE_WAITING_LOCK:
+ /*
+ * This request is waiting on a lock. Wakeup everything
+ * waiting on the lock so that the relevant thread regains
+ * control and notices that is has been canceled. The
+ * other lock request threads waiting on this lock will go
+ * back to sleep when they discover they are still blocked.
+ */
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+
+ ASSERT(sr->sr_awaiting != NULL);
+ mutex_enter(&sr->sr_awaiting->l_mutex);
+ cv_broadcast(&sr->sr_awaiting->l_cv);
+ mutex_exit(&sr->sr_awaiting->l_mutex);
+
+ break;
+
+ case SMB_REQ_STATE_WAITING_EVENT:
+ case SMB_REQ_STATE_EVENT_OCCURRED:
+ /*
+ * Cancellations for these states are handled by the
+ * notify-change code
+ */
+ break;
+
+ case SMB_REQ_STATE_COMPLETED:
+ case SMB_REQ_STATE_CANCELED:
+ /*
+ * No action required for these states since the request
+ * is completing.
+ */
+ break;
+ /*
+ * Cases included:
+ * SMB_REQ_STATE_FREE:
+ * SMB_REQ_STATE_INITIALIZING:
+ */
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+}
+
+/*
+ * smb_request_free
+ *
+ * release the memories which have been allocated for a smb request.
+ */
+void
+smb_request_free(smb_request_t *sr)
+{
+ ASSERT(sr->session);
+
+ ASSERT(sr->fid_ofile == NULL);
+ ASSERT(sr->sid_odir == NULL);
+ ASSERT(sr->tid_tree == NULL);
+ ASSERT(sr->uid_user == NULL);
+ ASSERT(sr->r_xa == NULL);
+
+ smb_slist_remove(&sr->session->s_req_list, sr);
+
+ sr->session = 0;
+
+ /* Release any temp storage */
+ smbsr_free_malloc_list(&sr->request_storage);
+
+ if (sr->sr_request_buf)
+ kmem_free(sr->sr_request_buf, sr->sr_req_length);
+ if (sr->command.chain)
+ m_freem(sr->command.chain);
+ if (sr->reply.chain)
+ m_freem(sr->reply.chain);
+ if (sr->raw_data.chain)
+ m_freem(sr->raw_data.chain);
+
+ sr->sr_magic = (uint32_t)~SMB_REQ_MAGIC;
+ mutex_destroy(&sr->sr_mutex);
+ kmem_cache_free(smb_info.si_cache_request, sr);
+}
+
+/*ARGSUSED*/
+void
+smb_wakeup_session_daemon(smb_thread_t *thread, void *session_void)
+{
+ struct smb_session *session = session_void;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_TERMINATED:
+ case SMB_SESSION_STATE_DISCONNECTED:
+ break;
+ default:
+ smb_soshutdown(session->sock);
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+}
+
+/*
+ * This is the entry point for processing SMB messages over NetBIOS or
+ * SMB-over-TCP.
+ *
+ * NetBIOS connections require a session request to establish a session
+ * on which to send session messages.
+ *
+ * Session requests are not valid on SMB-over-TCP. We don't need to do
+ * anything here as session requests will be treated as an error when
+ * handling session messages.
+ */
+/*ARGSUSED*/
+void
+smb_session_daemon(smb_thread_t *thread, void *session_void)
+{
+ struct smb_session *session = session_void;
+ int rc = 0;
+
+ ASSERT(session != NULL);
+
+ if (session->s_local_port == SSN_SRVC_TCP_PORT)
+ rc = smb_session_request(session);
+
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+
+ if ((rc == 0) || (session->s_local_port == SMB_SRVC_TCP_PORT))
+ session->s_state = SMB_SESSION_STATE_ESTABLISHED;
+ else
+ session->s_state = SMB_SESSION_STATE_DISCONNECTED;
+
+ while (session->s_state != SMB_SESSION_STATE_DISCONNECTED) {
+ smb_rwx_rwexit(&session->s_lock);
+
+ rc = smb_session_message(session);
+
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+
+ if (rc != 0)
+ break;
+ }
+
+ smb_soshutdown(session->sock);
+ session->s_state = SMB_SESSION_STATE_DISCONNECTED;
+ smb_rwx_rwexit(&session->s_lock);
+
+ DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
+
+ smb_session_cancel(session);
+
+ /*
+ * At this point everything related to the session should have been
+ * cleaned up and we expect that nothing will attempt to use the
+ * socket.
+ */
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ session->s_state = SMB_SESSION_STATE_TERMINATED;
+ smb_sodestroy(session->sock);
+ session->sock = NULL;
+ smb_rwx_rwexit(&session->s_lock);
+
+ /*
+ * Notify SMB service state machine so it can cleanup the session
+ */
+ smb_svcstate_event(SMB_SVCEVT_SESSION_DELETE, (uintptr_t)session);
+}
+
+/*
+ * Read and process SMB requests.
+ *
+ * Returns:
+ * 0 Success
+ * 1 Unable to read transport header
+ * 2 Invalid transport header type
+ * 3 Invalid SMB length (too small)
+ * 4 Unable to read SMB header
+ * 5 Invalid SMB header (bad magic number)
+ * 6 Unable to read SMB data
+ * 2x Write raw failed
+ */
+static int
+smb_session_message(smb_session_t *session)
+{
+ struct smb_request *sr = NULL;
+ smb_xprt_t hdr;
+ uint8_t *req_buf;
+ uint32_t resid;
+ int rc;
+
+ if (smb_session_xprt_gethdr(session, &hdr) != 0)
+ return (1);
+
+ DTRACE_PROBE2(session__receive__xprthdr, struct session *, session,
+ smb_xprt_t *, &hdr);
+
+ if (hdr.xh_type != SESSION_MESSAGE) {
+ /*
+ * Anything other than SESSION_MESSAGE or SESSION_KEEP_ALIVE
+ * is an error. A SESSION_REQUEST may indicate a new session
+ * request but we need to close this session and we can treat
+ * it as an error here.
+ */
+ if (hdr.xh_type == SESSION_KEEP_ALIVE) {
+ session->keep_alive = smb_keep_alive;
+ return (0);
+ }
+
+ return (2);
+ }
+
+ if (hdr.xh_length < SMB_HEADER_LEN)
+ return (3);
+
+ session->keep_alive = smb_keep_alive;
+
+ /*
+ * Allocate a request context, read the SMB header and validate it.
+ * The sr includes a buffer large enough to hold the SMB request
+ * payload. If the header looks valid, read any remaining data.
+ */
+ sr = smb_request_alloc(session, hdr.xh_length);
+
+ req_buf = (uint8_t *)sr->sr_request_buf;
+ resid = hdr.xh_length;
+
+ if (smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN) != 0) {
+ smb_request_free(sr);
+ return (4);
+ }
+
+ if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
+ smb_request_free(sr);
+ return (5);
+ }
+
+ if (resid > SMB_HEADER_LEN) {
+ req_buf += SMB_HEADER_LEN;
+ resid -= SMB_HEADER_LEN;
+
+ if (smb_sorecv(session->sock, req_buf, resid) != 0) {
+ smb_request_free(sr);
+ return (6);
+ }
+ }
+
+ /*
+ * Initialize command MBC to represent the received data.
+ */
+ smb_request_init_command_mbuf(sr);
+
+ DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
+
+ /*
+ * If this is a raw write, hand off the request. The handler
+ * will retrieve the remaining raw data and process the request.
+ */
+ if (SMB_IS_WRITERAW(sr)) {
+ rc = smb_handle_write_raw(session, sr);
+ /* XXX smb_request_free(sr); ??? */
+ return (rc);
+ }
+
+ sr->sr_state = SMB_REQ_STATE_SUBMITTED;
+ (void) taskq_dispatch(smb_info.thread_pool, smb_session_worker,
+ sr, TQ_SLEEP);
+ return (0);
+}
+
+/*
+ * smb_session_wakeup_daemon
+ *
+ * When the smbsrv kernel module/driver gets unloaded, chances are the
+ * smb_nbt_daemon and smb_tcp_daemon threads are blocked in soaccept.
+ * We can't get control of the threads until they return from soaccept.
+ * This function will attempt to connect to the SMB service via
+ * "localhost" to wake up the threads.
+ */
+/*ARGSUSED*/
+static void
+smb_session_wakeup_daemon(smb_thread_t *thread, void *so_void)
+{
+ struct sonode *so = so_void;
+
+ ASSERT(so != NULL);
+
+ mutex_enter(&so->so_lock);
+ so->so_error = EINTR;
+ cv_signal(&so->so_connind_cv);
+ mutex_exit(&so->so_lock);
+}
+
+/*
+ * SMB-over-NetBIOS service.
+ *
+ * Traditional SMB service over NetBIOS (port 139), which requires
+ * that a NetBIOS session be established.
+ */
+void
+smb_nbt_daemon(smb_thread_t *thread, void *arg)
+{
+ /* XXX Defaults for these values should come from smbd and SMF */
+ uint32_t txbuf_size = 128*1024;
+ uint32_t on = 1;
+ struct smb_session *session;
+ struct sonode *l_so, *s_so;
+ struct sockaddr_in sin;
+ int error;
+ smb_info_t *si = arg;
+
+ ASSERT(si != NULL);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(SSN_SRVC_TCP_PORT);
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ l_so = smb_socreate(AF_INET, SOCK_STREAM, 0);
+ if (l_so == NULL) {
+ cmn_err(CE_WARN, "NBT: socket create failed");
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)ENOMEM);
+ return;
+ }
+
+ (void) sosetsockopt(l_so, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&on, sizeof (on));
+
+ if ((error = sobind(l_so, (struct sockaddr *)&sin, sizeof (sin),
+ 0, 0)) != 0) {
+ cmn_err(CE_WARN, "NBT: bind failed");
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+ return;
+ }
+ if ((error = solisten(l_so, 20)) < 0) {
+ cmn_err(CE_WARN, "NBT: listen failed");
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+ return;
+ }
+
+ smb_thread_set_awaken(thread, smb_session_wakeup_daemon, l_so);
+ si->si_connect_progress |= SMB_SI_NBT_CONNECTED;
+ smb_svcstate_event(SMB_SVCEVT_CONNECT, NULL);
+
+ while (smb_thread_continue_nowait(thread)) {
+ DTRACE_PROBE1(so__wait__accept, struct sonode *, l_so);
+
+ error = soaccept(l_so, 0, &s_so);
+ if (error) {
+ DTRACE_PROBE1(so__accept__error, int, error);
+ if (error == EINTR) {
+ continue;
+ }
+
+ break;
+ }
+
+ DTRACE_PROBE1(so__accept, struct sonode *, s_so);
+
+ (void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY,
+ (const void *)&on, sizeof (on));
+ (void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE,
+ (const void *)&on, sizeof (on));
+ (void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
+ (const void *)&txbuf_size, sizeof (txbuf_size));
+
+ /*
+ * Create a session for this connection and notify the SMB
+ * service state machine. The service state machine may
+ * start a session thread or reject the session depending
+ * on the current service state or number of connections.
+ */
+ session = smb_session_create(s_so, SSN_SRVC_TCP_PORT);
+ smb_svcstate_event(SMB_SVCEVT_SESSION_CREATE,
+ (uintptr_t)session);
+
+ }
+
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ si->si_connect_progress &= ~SMB_SI_NBT_CONNECTED;
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+}
+
+/*
+ * SMB-over-TCP (or NetBIOS-less SMB) service.
+ *
+ * SMB service natively over TCP (port 445), i.e. no NetBIOS support.
+ */
+void
+smb_tcp_daemon(smb_thread_t *thread, void *arg)
+{
+ /* XXX Defaults for these values should come from smbd and SMF */
+ uint32_t txbuf_size = 128*1024;
+ uint32_t on = 1;
+ struct smb_session *session;
+ struct sonode *l_so, *s_so;
+ struct sockaddr_in sin;
+ int error;
+ smb_info_t *si = arg;
+
+ ASSERT(si != NULL);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(SMB_SRVC_TCP_PORT);
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ l_so = smb_socreate(AF_INET, SOCK_STREAM, 0);
+ if (l_so == NULL) {
+ cmn_err(CE_WARN, "TCP: socket create failed");
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)ENOMEM);
+ return;
+ }
+
+ (void) sosetsockopt(l_so, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&on, sizeof (on));
+
+ if ((error = sobind(l_so, (struct sockaddr *)&sin, sizeof (sin),
+ 0, 0)) != 0) {
+ cmn_err(CE_WARN, "TCP: bind failed");
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+ return;
+ }
+ if ((error = solisten(l_so, 20)) < 0) {
+ cmn_err(CE_WARN, "TCP: listen failed");
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+ return;
+ }
+
+ smb_thread_set_awaken(thread, smb_session_wakeup_daemon, l_so);
+ si->si_connect_progress |= SMB_SI_TCP_CONNECTED;
+ smb_svcstate_event(SMB_SVCEVT_CONNECT, NULL);
+
+ while (smb_thread_continue_nowait(thread)) {
+ DTRACE_PROBE1(so__wait__accept, struct sonode *, l_so);
+
+ error = soaccept(l_so, 0, &s_so);
+ if (error) {
+ DTRACE_PROBE1(so__accept__error, int, error);
+ if (error == EINTR) {
+ continue;
+ }
+
+ break;
+ }
+
+ DTRACE_PROBE1(so__accept, struct sonode *, s_so);
+
+ (void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY,
+ (const void *)&on, sizeof (on));
+ (void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE,
+ (const void *)&on, sizeof (on));
+ (void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
+ (const void *)&txbuf_size, sizeof (txbuf_size));
+
+ /*
+ * Create a session for this connection and notify the SMB
+ * service state machine. The service state machine may
+ * start a session thread or reject the session depending
+ * on the current service state or number of connections.
+ */
+ session = smb_session_create(s_so, SMB_SRVC_TCP_PORT);
+ smb_svcstate_event(SMB_SVCEVT_SESSION_CREATE,
+ (uintptr_t)session);
+
+ }
+
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ si->si_connect_progress &= ~SMB_SI_TCP_CONNECTED;
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+}
+
+/*
+ * smb_session_reject
+ *
+ * Build and send a NEGATIVE_SESSION_RESPONSE on the specified socket.
+ * The reason is written to the log.
+ */
+/*ARGSUSED*/
+void
+smb_session_reject(smb_session_t *session, char *reason)
+{
+ unsigned char reply[8];
+
+ smb_rwx_rwenter(&session->s_lock, RW_READER);
+ if (session->sock != NULL) {
+ reply[0] = NEGATIVE_SESSION_RESPONSE;
+ reply[1] = 0;
+ reply[2] = 0;
+ reply[3] = 1;
+ reply[4] = SESSION_INSUFFICIENT_RESOURCES;
+
+ (void) smb_sosend(session->sock, reply, 5);
+ }
+ smb_rwx_rwexit(&session->s_lock);
+}
+
+/*
+ * Port will be SSN_SRVC_TCP_PORT or SMB_SRVC_TCP_PORT.
+ */
+smb_session_t *
+smb_session_create(struct sonode *new_so, uint16_t port)
+{
+ uint32_t ipaddr;
+ uint32_t local_ipaddr;
+ struct sockaddr_in sin;
+ smb_session_t *session;
+
+ session = kmem_cache_alloc(smb_info.si_cache_session, KM_SLEEP);
+ bzero(session, sizeof (smb_session_t));
+
+ if (smb_idpool_constructor(&session->s_uid_pool)) {
+ kmem_cache_free(smb_info.si_cache_session, session);
+ return (NULL);
+ }
+
+ session->s_kid = SMB_NEW_KID();
+ session->s_state = SMB_SESSION_STATE_DISCONNECTED;
+ session->native_os = NATIVE_OS_UNKNOWN;
+ session->opentime = lbolt64;
+ session->keep_alive = smb_keep_alive;
+ session->activity_timestamp = lbolt64;
+
+ smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_session_lnd));
+
+ smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
+ offsetof(smb_user_t, u_lnd));
+
+ smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
+ offsetof(smb_xa_t, xa_lnd));
+
+ smb_thread_init(&session->s_thread, "smb_session", &smb_session_daemon,
+ session, smb_wakeup_session_daemon, session);
+
+ smb_rwx_init(&session->s_lock);
+
+ bcopy(new_so->so_faddr_sa, &sin, new_so->so_faddr_len);
+ ipaddr = sin.sin_addr.s_addr;
+
+ bcopy(new_so->so_laddr_sa, &sin, new_so->so_faddr_len);
+ local_ipaddr = sin.sin_addr.s_addr;
+
+ session->s_local_port = port;
+ session->ipaddr = ipaddr;
+ session->local_ipaddr = local_ipaddr;
+ session->sock = new_so;
+
+ session->s_magic = SMB_SESSION_MAGIC;
+ return (session);
+}
+
+void
+smb_session_delete(smb_session_t *session)
+{
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+
+ session->s_magic = (uint32_t)~SMB_SESSION_MAGIC;
+
+ smb_rwx_destroy(&session->s_lock);
+ smb_thread_destroy(&session->s_thread);
+ smb_slist_destructor(&session->s_req_list);
+ smb_llist_destructor(&session->s_user_list);
+ smb_llist_destructor(&session->s_xa_list);
+
+ ASSERT(session->s_tree_cnt == 0);
+ ASSERT(session->s_file_cnt == 0);
+ ASSERT(session->s_dir_cnt == 0);
+
+ smb_idpool_destructor(&session->s_uid_pool);
+ kmem_cache_free(smb_info.si_cache_session, session);
+}
+
+void
+smb_session_cancel(smb_session_t *session)
+{
+ smb_xa_t *xa, *nextxa;
+
+ /* All the request currently being treated must be canceled. */
+ smb_session_cancel_requests(session);
+
+ /*
+ * We wait for the completion of all the requests associated with
+ * this session.
+ */
+ smb_slist_wait_for_empty(&session->s_req_list);
+
+ /*
+ * At this point the reference count of the users, trees, files,
+ * directories should be zero. It should be possible to destroy them
+ * without any problem.
+ */
+ xa = smb_llist_head(&session->s_xa_list);
+ while (xa) {
+ nextxa = smb_llist_next(&session->s_xa_list, xa);
+ smb_xa_close(xa);
+ xa = nextxa;
+ }
+ smb_user_logoff_all(session);
+}
+
+void
+smb_session_cancel_requests(
+ smb_session_t *session)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+
+ /* All the SMB requests on the notification queue are canceled. */
+ smb_process_session_notify_change_queue(session);
+
+ smb_slist_enter(&session->s_req_list);
+ sr = smb_slist_head(&session->s_req_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&session->s_req_list, sr);
+
+ smb_request_cancel(sr);
+
+ sr = tmp;
+ }
+ smb_slist_exit(&session->s_req_list);
+}
+
+void
+smb_session_worker(
+ void *arg)
+{
+ smb_request_t *sr;
+
+ sr = (smb_request_t *)arg;
+
+ ASSERT(sr != NULL);
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_SUBMITTED:
+ mutex_exit(&sr->sr_mutex);
+ if (smb_dispatch_request(sr) < 0) {
+ smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
+ if (sr->session->s_state !=
+ SMB_SESSION_STATE_DISCONNECTED) {
+ smb_soshutdown(sr->session->sock);
+ sr->session->s_state =
+ SMB_SESSION_STATE_DISCONNECTED;
+ }
+ smb_rwx_rwexit(&sr->session->s_lock);
+ }
+ mutex_enter(&sr->sr_mutex);
+ if (!sr->sr_keep) {
+ sr->sr_state = SMB_REQ_STATE_COMPLETED;
+ mutex_exit(&sr->sr_mutex);
+ smb_request_free(sr);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ break;
+
+ default:
+ ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
+ sr->sr_state = SMB_REQ_STATE_COMPLETED;
+ mutex_exit(&sr->sr_mutex);
+ smb_request_free(sr);
+ break;
+ }
+}
+
+/*
+ * smb_session_disconnect_share
+ *
+ * Disconnects the specified share. This function should be called after the
+ * share passed in has been made unavailable by the "share manager".
+ */
+void
+smb_session_disconnect_share(char *sharename)
+{
+ smb_session_t *session;
+
+ smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
+
+ session = NULL;
+ while ((session = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx,
+ session)) != NULL) {
+
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ smb_rwx_rwenter(&session->s_lock, RW_READER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
+ smb_user_t *user;
+ smb_user_t *next;
+
+ user = smb_user_lookup_by_state(session, NULL);
+ while (user) {
+ smb_user_disconnect_share(user, sharename);
+ next = smb_user_lookup_by_state(session, user);
+ smb_user_release(user);
+ user = next;
+ }
+ break;
+
+ }
+ default:
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+}
+
+/*
+ * smb_session_disconnect_volume
+ *
+ * This function is called when a volume is deleted. We need to ensure
+ * all trees with a reference to the volume are destroyed before we
+ * discard the fs_online. Before destroying each tree, we notify any
+ * in-progress requests and give them a chance to complete.
+ *
+ * NOTE:
+ * We shouldn't be accepting any new connection on this volume while
+ * we are in this function.
+ */
+void
+smb_session_disconnect_volume(fs_desc_t *fsd)
+{
+ smb_session_t *session;
+
+ smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
+
+ session = NULL;
+ while ((session = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx,
+ session)) != NULL) {
+
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ smb_rwx_rwenter(&session->s_lock, RW_READER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
+ smb_user_t *user;
+ smb_user_t *next;
+
+ user = smb_user_lookup_by_state(session, NULL);
+ while (user) {
+ smb_user_disconnect_volume(user, fsd);
+ next = smb_user_lookup_by_state(session, user);
+ smb_user_release(user);
+ user = next;
+ }
+ break;
+
+ }
+ default:
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
new file mode 100644
index 0000000000..b7217cf78b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
@@ -0,0 +1,516 @@
+/*
+ * 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.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * SMB: session_setup_andx
+ *
+ * This SMB is used to further "Set up" the session normally just
+ * established via the negotiate protocol.
+ *
+ * One primary function is to perform a "user logon" in the case where the
+ * server is in user level security mode. The Uid in the SMB header is set
+ * by the client to be the userid desired for the AccountName and validated
+ * by the AccountPassword.
+ *
+ * If the negotiated protocol is prior to NT LM 0.12, the format of
+ * SMB_COM_SESSION_SETUP_ANDX is:
+ *
+ * Client Request Description
+ * ============================== =====================================
+ *
+ * UCHAR WordCount; Count of parameter words = 10
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT MaxBufferSize; Client maximum buffer size
+ * USHORT MaxMpxCount; Actual maximum multiplexed pending
+ * requests
+ * USHORT VcNumber; 0 = first (only), nonzero=additional
+ * VC number
+ * ULONG SessionKey; Session key (valid iff VcNumber != 0)
+ * USHORT PasswordLength; Account password size
+ * ULONG Reserved; Must be 0
+ * USHORT ByteCount; Count of data bytes; min = 0
+ * UCHAR AccountPassword[]; Account Password
+ * STRING AccountName[]; Account Name
+ * STRING PrimaryDomain[]; Client's primary domain
+ * STRING NativeOS[]; Client's native operating system
+ * STRING NativeLanMan[]; Client's native LAN Manager type
+ *
+ * and the response is:
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 3
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Action; Request mode:
+ * bit0 = logged in as GUEST
+ * USHORT ByteCount; Count of data bytes
+ * STRING NativeOS[]; Server's native operating system
+ * STRING NativeLanMan[]; Server's native LAN Manager type
+ * STRING PrimaryDomain[]; Server's primary domain
+ *
+ * If the server is in "share level security mode", the account name and
+ * passwd should be ignored by the server.
+ *
+ * If challenge/response authentication is not being used, AccountPassword
+ * should be a null terminated ASCII string with PasswordLength set to the
+ * string size including the null; the password will case insensitive. If
+ * challenge/response authentication is being used (see section 2.10), then
+ * AccountPassword will be the response to the server's challenge, and
+ * PasswordLength should be set to its length.
+ *
+ * The server validates the name and password supplied and if valid, it
+ * registers the user identifier on this session as representing the
+ * specified AccountName. The Uid field in the SMB header will then be
+ * used to validate access on subsequent SMB requests. The SMB requests
+ * where permission checks are required are those which refer to a
+ * symbolically named resource such as SMB_COM_OPEN, SMB_COM_RENAME,
+ * SMB_COM_DELETE, etc.. The value of the Uid is relative to a specific
+ * client/server session so it is possible to have the same Uid value
+ * represent two different users on two different sessions at the server.
+ *
+ * Multiple session setup commands may be sent to register additional users
+ * on this session. If the server receives an additional
+ * SMB_COM_SESSION_SETUP_ANDX, only the Uid, AccountName and
+ * AccountPassword fields need contain valid values (the server MUST ignore
+ * the other fields).
+ *
+ * The client writes the name of its domain in PrimaryDomain if it knows
+ * what the domain name is. If the domain name is unknown, the client
+ * either encodes it as a NULL string, or as a question mark.
+ *
+ * If bit0 of Action is set, this informs the client that although the
+ * server did not recognize the AccountName, it logged the user in as a
+ * guest. This is optional behavior by the server, and in any case one
+ * would ordinarily expect guest privileges to limited.
+ *
+ * Another function of the Session Set Up protocol is to inform the server
+ * of the maximum values which will be utilized by this client. Here
+ * MaxBufferSize is the maximum message size which the client can receive.
+ * Thus although the server may support 16k buffers (as returned in the
+ * SMB_COM_NEGOTIATE response), if the client only has 4k buffers, the
+ * value of MaxBufferSize here would be 4096. The minimum allowable value
+ * for MaxBufferSize is 1024. The SMB_COM_NEGOTIATE response includes the
+ * server buffer size supported. Thus this is the maximum SMB message size
+ * which the client can send to the server. This size may be larger than
+ * the size returned to the server from the client via the
+ * SMB_COM_SESSION_SETUP_AND X protocol which is the maximum SMB message
+ * size which the server may send to the client. Thus if the server's
+ * buffer size were 4k and the client's buffer size were only 2K, the
+ * client could send up to 4k (standard) write requests but must only
+ * request up to 2k for (standard) read requests.
+ *
+ * The field, MaxMpxCount informs the server of the maximum number of
+ * requests which the client will have outstanding to the server
+ * simultaneously (see sections 5.13 and 5.25).
+ *
+ * The VcNumber field specifies whether the client wants this to be the
+ * first VC or an additional VC. If the the SMB_COM_SESSION_SETUP_ANDX
+ * request contains a VcNumber of 0 and other VCs are still connected to
+ * that client, they should be aborted to free any resources held by the
+ * server. This condition could occur if the client was rebooted and
+ * reconnected to the server before the transport level had informed the
+ * server of the previous VC termination. There is more information on
+ * VCs in smb_negotiate.c.
+ *
+ * The values for MaxBufferSize, MaxMpxCount, and VcNumber must be less
+ * than or equal to the maximum values supported by the server as returned
+ * in the SMB_COM_NEGOTIATE response.
+ *
+ * If the negotiated SMB dialect is "NT LM 0.12" or later, the format of
+ * the response SMB is unchanged, but the request is:
+ *
+ * Client Request Description
+ * ============================== =====================================
+ *
+ * UCHAR WordCount; Count of parameter words = 13
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT MaxBufferSize; Client's maximum buffer size
+ * USHORT MaxMpxCount; Actual maximum multiplexed pending
+ * requests
+ * USHORT VcNumber; 0 = first (only), nonzero=additional
+ * VC number
+ * ULONG SessionKey; Session key (valid iff VcNumber != 0)
+ * USHORT Account password size, ANSI
+ * CaseInsensitivePasswordLength;
+ * USHORT Account password size, Unicode
+ * CaseSensitivePasswordLength;
+ * ULONG Reserved; must be 0
+ * ULONG Capabilities; Client capabilities
+ * USHORT ByteCount; Count of data bytes; min = 0
+ * UCHAR Account Password, ANSI
+ * CaseInsensitivePassword[];
+ * UCHAR CaseSensitivePassword[]; Account Password, Unicode
+ * STRING AccountName[]; Account Name, Unicode
+ * STRING PrimaryDomain[]; Client's primary domain, Unicode
+ * STRING NativeOS[]; Client's native operating system,
+ * Unicode
+ * STRING NativeLanMan[]; Client's native LAN Manager type,
+ * Unicode
+ *
+ * The client expresses its capabilities to the server encoded in the
+ * Capabilities field:
+ *
+ * Capability Name Encoding Description
+ * ======================== ========= ================================
+ *
+ * CAP_UNICODE 0x0004 The client can use UNICODE
+ * strings
+ * CAP_LARGE_FILES 0x0008 The client can deal with files
+ * having 64 bit offsets
+ * CAP_NT_SMBS 0x0010 The client understands the SMBs
+ * introduced with the NT LM 0.12
+ * dialect. Implies CAP_NT_FIND.
+ * CAP_NT_FIND 0x0200
+ * CAP_STATUS32 0x0040 The client can receive 32 bit
+ * errors encoded in Status.Status
+ * CAP_LEVEL_II_OPLOCKS 0x0080 The client understands Level II
+ * oplocks
+ *
+ * The entire message sent and received including the optional ANDX SMB
+ * must fit in the negotiated maximum transfer size. The following are the
+ * only valid SMB commands for AndXCommand for SMB_COM_SESSION_SETUP_ANDX
+ *
+ * SMB_COM_TREE_CONNECT_ANDX SMB_COM_OPEN
+ * SMB_COM_OPEN_ANDX SMB_COM_CREATE
+ * SMB_COM_CREATE_NEW SMB_COM_CREATE_DIRECTORY
+ * SMB_COM_DELETE SMB_COM_DELETE_DIRECTORY
+ * SMB_COM_FIND SMB_COM_FIND_UNIQUE
+ * SMB_COM_COPY SMB_COM_RENAME
+ * SMB_COM_NT_RENAME SMB_COM_CHECK_DIRECTORY
+ * SMB_COM_QUERY_INFORMATION SMB_COM_SET_INFORMATION
+ * SMB_COM_NO_ANDX_COMMAND SMB_COM_OPEN_PRINT_FILE
+ * SMB_COM_GET_PRINT_QUEUE SMB_COM_TRANSACTION
+ *
+ * 4.1.2.1 Errors
+ *
+ * ERRSRV/ERRerror - no NEG_PROT issued
+ * ERRSRV/ERRbadpw - password not correct for given user name
+ * ERRSRV/ERRtoomanyuids - maximum number of users per session exceeded
+ * ERRSRV/ERRnosupport - chaining of this request to the previous one is
+ * not supported
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_token.h>
+#include <smbsrv/smb_door_svc.h>
+
+int
+smb_com_session_setup_andx(struct smb_request *sr)
+{
+ uint16_t maxbufsize, maxmpxcount, vcnumber = 0;
+ uint32_t sesskey;
+ uint32_t capabilities = 0;
+ char *account_name = "";
+ char *primary_domain = "";
+ char *native_os = "";
+ char *native_lanman = "";
+ char *hostname = smb_info.si.skc_hostname;
+ smb_token_t *usr_token = NULL;
+ smb_user_t *user = NULL;
+ int security = smb_info.si.skc_secmode;
+
+ uint16_t ci_pwlen = 0;
+ unsigned char *ci_password = NULL;
+ uint16_t cs_pwlen = 0;
+ unsigned char *cs_password = NULL;
+
+ netr_client_t clnt_info;
+ smb_session_key_t *session_key = NULL;
+ int rc;
+
+ if (sr->session->dialect >= NT_LM_0_12) {
+ rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com,
+ &sr->andx_off, &maxbufsize, &maxmpxcount, &vcnumber,
+ &sesskey, &ci_pwlen, &cs_pwlen, &capabilities);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ci_password = kmem_alloc(ci_pwlen + 1, KM_SLEEP);
+ cs_password = kmem_alloc(cs_pwlen + 1, KM_SLEEP);
+
+ /*
+ * The padding between the Native OS and Native LM is a
+ * bit strange. On NT4.0, there is a 2 byte pad between
+ * the OS (Windows NT 1381) and LM (Windows NT 4.0).
+ * On Windows 2000, there is no padding between the OS
+ * (Windows 2000 2195) and LM (Windows 2000 5.0).
+ *
+ * If the padding is removed from this decode string
+ * the NT4.0 LM comes out as an empty string.
+ *
+ * So if the client's native OS is Win NT we consider
+ * the padding otherwise we don't.
+ */
+ rc = smbsr_decode_data(sr, "%#c#cuuu",
+ sr,
+ ci_pwlen, ci_password,
+ cs_pwlen, cs_password,
+ &account_name,
+ &primary_domain,
+ &native_os);
+
+ if (rc != 0) {
+ kmem_free(ci_password, ci_pwlen + 1);
+ kmem_free(cs_password, cs_pwlen + 1);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ci_password[ci_pwlen] = 0;
+ cs_password[cs_pwlen] = 0;
+
+ sr->session->native_os = smbnative_os_value(native_os);
+
+ if (sr->session->native_os == NATIVE_OS_WINNT)
+ rc = smbsr_decode_data(sr, "%,u", sr, &native_lanman);
+ else
+ rc = smbsr_decode_data(sr, "%u", sr, &native_lanman);
+
+ /*
+ * Native Lanman could be null so we really don't care
+ * if above decode fails, but to have a valid value for
+ * the field we set it to Win NT.
+ */
+ if (rc != 0)
+ native_lanman = "NT LAN Manager 4.0";
+
+ } else {
+ rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com,
+ &sr->andx_off, &maxbufsize, &maxmpxcount,
+ &vcnumber, &sesskey, &ci_pwlen);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ci_password = kmem_alloc(ci_pwlen + 1, KM_SLEEP);
+ rc = smbsr_decode_data(sr, "%#c", sr, ci_pwlen, ci_password);
+ if (rc != 0) {
+ kmem_free(ci_password, ci_pwlen + 1);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ci_password[ci_pwlen] = 0;
+
+ /*
+ * Despite the CIFS/1.0 spec, the rest of this message is
+ * not always present. We need to try to get the account
+ * name and the primary domain but we don't care about the
+ * the native OS or native LanMan fields.
+ */
+ if (smbsr_decode_data(sr, "%u", sr, &account_name) != 0)
+ account_name = "";
+
+ if (smbsr_decode_data(sr, "%u", sr, &primary_domain) != 0)
+ primary_domain = "";
+
+ sr->session->native_os = NATIVE_OS_UNKNOWN;
+ }
+
+ /*
+ * If the vcnumber is zero, we can discard any
+ * other connections associated with this client.
+ */
+ sr->session->vcnumber = vcnumber;
+ if (vcnumber == 0)
+ smb_reconnection_check(sr->session);
+
+ sr->session->smb_msg_size = maxbufsize;
+
+ bzero(&clnt_info, sizeof (netr_client_t));
+
+ if (*primary_domain == 0)
+ primary_domain = smb_info.si.skc_resource_domain;
+
+ if ((cs_pwlen == 0) &&
+ (ci_pwlen == 0 || (ci_pwlen == 1 && *ci_password == 0))) {
+ /* anonymous user */
+ clnt_info.flags |= NETR_CFLG_ANON;
+ account_name = "nobody";
+ } else if (*account_name == '\0') {
+ if (ci_password)
+ kmem_free(ci_password, ci_pwlen + 1);
+ if (cs_password)
+ kmem_free(cs_password, cs_pwlen + 1);
+ smbsr_raise_error(sr, ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ } else if (utf8_strcasecmp(primary_domain, hostname) == 0) {
+ /*
+ * When domain name is equal to hostname, it means
+ * the user is local even if system is running in
+ * domain mode, so perform a local logon.
+ */
+ clnt_info.flags |= NETR_CFLG_LOCAL;
+ } else if (security == SMB_SECMODE_DOMAIN) {
+ clnt_info.flags |= NETR_CFLG_DOMAIN;
+ } else if (security == SMB_SECMODE_WORKGRP) {
+ clnt_info.flags |= NETR_CFLG_LOCAL;
+ }
+
+ (void) utf8_strupr(primary_domain);
+
+ /*
+ * If this is an additional setup for an existing user
+ * on this session, duplicate the authenticated user.
+ * Otherwise authenticate as new user.
+ */
+ user = smb_user_lookup_by_name(sr->session, primary_domain,
+ account_name);
+
+ if (user) {
+ smb_user_t *orig_user = user;
+
+ user = smb_user_dup(orig_user);
+ smb_user_release(orig_user);
+ } else {
+ cred_t *cr;
+ uint32_t privileges;
+
+ clnt_info.logon_level = NETR_NETWORK_LOGON;
+ clnt_info.domain = primary_domain;
+ clnt_info.username = account_name;
+ clnt_info.workstation = sr->session->workstation;
+ clnt_info.ipaddr = sr->session->ipaddr;
+ clnt_info.local_ipaddr = sr->session->local_ipaddr;
+ clnt_info.challenge_key.challenge_key_val =
+ sr->session->challenge_key;
+ clnt_info.challenge_key.challenge_key_len =
+ sr->session->challenge_len;
+ clnt_info.nt_password.nt_password_val = cs_password;
+ clnt_info.nt_password.nt_password_len = cs_pwlen;
+ clnt_info.lm_password.lm_password_val = ci_password;
+ clnt_info.lm_password.lm_password_len = ci_pwlen;
+ clnt_info.native_os = sr->session->native_os;
+ clnt_info.native_lm = smbnative_lm_value(native_lanman);
+ clnt_info.local_port = sr->session->s_local_port;
+
+ DTRACE_PROBE1(smb__sessionsetup__clntinfo, netr_client_t *,
+ &clnt_info);
+
+ usr_token = smb_upcall_get_token(&clnt_info);
+ if (usr_token == 0) {
+ if (ci_password)
+ kmem_free(ci_password, ci_pwlen + 1);
+ if (cs_password)
+ kmem_free(cs_password, cs_pwlen + 1);
+ smbsr_raise_error(sr, ERRSRV, ERRbadpw);
+ /* NOTREACHED */
+ }
+
+ if (usr_token->tkn_session_key) {
+ session_key = kmem_alloc(sizeof (smb_session_key_t),
+ KM_SLEEP);
+ (void) memcpy(session_key, usr_token->tkn_session_key,
+ sizeof (smb_session_key_t));
+ }
+
+ cr = smb_cred_create(usr_token, &privileges);
+ if (cr != NULL) {
+ user = smb_user_login(sr->session, cr,
+ usr_token->tkn_domain_name,
+ usr_token->tkn_account_name,
+ usr_token->tkn_flags,
+ privileges,
+ usr_token->tkn_audit_sid);
+ smb_cred_rele(cr);
+ }
+ smb_token_free(usr_token);
+ }
+
+ if (ci_password)
+ kmem_free(ci_password, ci_pwlen + 1);
+ if (cs_password)
+ kmem_free(cs_password, cs_pwlen + 1);
+
+ if (user == NULL) {
+ if (session_key)
+ kmem_free(session_key, sizeof (smb_session_key_t));
+ smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_HANDLE);
+ /* no return */
+ }
+
+ sr->user_cr = user->u_cred;
+ sr->smb_uid = user->u_uid;
+ sr->uid_user = user;
+ sr->session->capabilities = capabilities;
+
+ /*
+ * Check to see if SMB signing is enable, but if it is already turned
+ * on leave it.
+ * The first authenticated logon provides the MAC key and sequence
+ * numbers for signing all further session on the
+ * same network connection.
+ */
+ if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) &&
+ (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) &&
+ (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
+ session_key)
+ smb_sign_init(sr, session_key, (char *)cs_password, cs_pwlen);
+
+ if (session_key)
+ kmem_free(session_key, sizeof (smb_session_key_t));
+
+ /*
+ * NT systems use different native OS and native LanMan values
+ * dependent on whether they are acting as a client or a server.
+ * As a server, NT 4.0 responds with the following values:
+ *
+ * NativeOS: Windows NT 4.0
+ * NativeLM: NT LAN Manager 4.0
+ *
+ * We should probably use the same values as NT but this code has
+ * been using the product name and "Windows NT 4.0" for a long time
+ * and I don't know if a change would cause any problems (see the
+ * conditional test below).
+ */
+ smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu",
+ 3,
+ sr->andx_com,
+ -1, /* andx_off */
+ ((user->u_flags & SMB_USER_FLAG_GUEST) ? 1 : 0),
+ VAR_BCC,
+ sr,
+ "Windows NT 4.0",
+ "NT LAN Manager 4.0",
+ smb_info.si.skc_resource_domain);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_set_information.c
new file mode 100644
index 0000000000..728c86b8cd
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information.c
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: set_information
+ *
+ * This message is sent to change the information about a file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 8
+ * USHORT FileAttributes; Attributes of the file
+ * UTIME LastWriteTime; Time of last write
+ * USHORT Reserved [5]; Reserved (must be 0)
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING FileName[]; File name
+ *
+ * FileName is the fully qualified name of the file relative to the Tid.
+ *
+ * Support of all parameters is optional. A server which does not
+ * implement one of the parameters will ignore that field. If the
+ * LastWriteTime field contain zero then the file's time is not changed.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_set_information(struct smb_request *sr)
+{
+ int rc;
+ unsigned short dattr;
+ timestruc_t utime;
+ char *path;
+ struct smb_node *dir_node;
+ smb_attr_t attr;
+ struct smb_node *node;
+ char *name;
+
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ if (smbsr_decode_vwv(sr, "wl10.", &dattr, &utime.tv_sec) != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ utime.tv_nsec = 0;
+
+ if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
+ != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_node, name, &node, &attr, 0, 0)) != 0) {
+ smb_node_release(dir_node);
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smb_node_release(dir_node);
+
+ smb_node_set_dosattr(node, dattr);
+
+ /*
+ * IR101794 The behaviour when the time field is set to -1
+ * is not documented, so we'll assume it should be treated
+ * like 0. We ignore utime.tv_nsec is assumed to be 0 here.
+ */
+ if (utime.tv_sec != 0 && utime.tv_sec != -1) {
+ utime.tv_sec = smb_local_time_to_gmt(utime.tv_sec);
+ smb_node_set_time(node, 0, &utime, 0, 0, SMB_AT_MTIME);
+ }
+
+ rc = smb_sync_fsattr(sr, sr->user_cr, node);
+ smb_node_release(node);
+ if (rc) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+ kmem_free(name, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
new file mode 100644
index 0000000000..1510f7228a
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information2.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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: set_information2
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 7
+ * USHORT Fid; File handle
+ * SMB_DATE CreationDate;
+ * SMB_TIME CreationTime;
+ * SMB_DATE LastAccessDate;
+ * SMB_TIME LastAccessTime;
+ * SMB_DATE LastWriteDate;
+ * SMB_TIME LastWriteTime;
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * SMB_COM_SET_INFORMATION2 sets information about the file represented by
+ * Fid. The target file is updated from the values specified. A date or
+ * time value or zero indicates to leave that specific date and time
+ * unchanged.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Fid must be open with (at least) write permission.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_set_information2(struct smb_request *sr)
+{
+ unsigned short la_ddate, la_dtime;
+ unsigned short lw_ddate, lw_dtime;
+ unsigned short cr_ddate, cr_dtime;
+ timestruc_t crtime, mtime, atime;
+ unsigned int what = 0;
+ struct smb_node *node;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, "wwwwwww", &sr->smb_fid, &cr_ddate, &cr_dtime,
+ &la_ddate, &la_dtime, &lw_ddate, &lw_dtime);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ node = sr->fid_ofile->f_node;
+
+ if (node == 0 || sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
+ cmn_err(CE_NOTE, "SmbSetInfo2: access denied");
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ crtime.tv_nsec = mtime.tv_nsec = atime.tv_nsec = 0;
+
+ if (cr_ddate || cr_dtime) {
+ crtime.tv_sec = smb_local_time_to_gmt(
+ dosfs_dos_to_ux_time(cr_ddate, cr_dtime));
+ what |= SMB_AT_CRTIME;
+ }
+
+ if (lw_ddate || lw_dtime) {
+ mtime.tv_sec = smb_local_time_to_gmt(
+ dosfs_dos_to_ux_time(lw_ddate, lw_dtime));
+ what |= SMB_AT_MTIME;
+ }
+
+ if (la_ddate || la_dtime) {
+ atime.tv_sec = smb_local_time_to_gmt(
+ dosfs_dos_to_ux_time(la_ddate, la_dtime));
+ what |= SMB_AT_ATIME;
+ }
+
+ smb_node_set_time(node, &crtime, &mtime, &atime, 0, what);
+ rc = smb_sync_fsattr(sr, sr->user_cr, node);
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_share_kdoor_client.c b/usr/src/uts/common/fs/smbsrv/smb_share_kdoor_client.c
new file mode 100644
index 0000000000..63a7f5d314
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_share_kdoor_client.c
@@ -0,0 +1,730 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Kernel door client for LanMan share management.
+ */
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/door.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/smbinfo.h>
+
+door_handle_t lmshrd_dh;
+int lmshrd_init = 0;
+kmutex_t lmshrd_dh_mtx;
+
+
+char *lmshrd_desc[] = {
+ "",
+ "LmshrkOpenIter",
+ "LmshrkCloseIter",
+ "LmshrkIterate",
+ "LmshrkNumShares",
+ "",
+ "",
+ "LmshrkGetinfo",
+ "",
+ "",
+ "LmshrkExists",
+ "LmshrkIsSpecial",
+ "LmshrkIsRestricted",
+ "LmshrkIsAdmin",
+ "LmshrkIsValid",
+ "LmshrkIsDir",
+ "LmshrkList",
+ "LmshrkListTrans",
+ "LmshrkNumTrans",
+ "SmbGetKConfig",
+ 0
+};
+
+
+static int
+lmshrd_kclient_open()
+{
+ int err = 0;
+
+ mutex_enter(&lmshrd_dh_mtx);
+ if (lmshrd_init == 0) {
+ if ((err = door_ki_open(LMSHR_DOOR_NAME, &lmshrd_dh)) != 0)
+ cmn_err(CE_WARN, "lmshrd_kclient: open %s failed",
+ LMSHR_DOOR_NAME);
+ else
+ lmshrd_init = 1;
+ }
+ mutex_exit(&lmshrd_dh_mtx);
+
+ return (err);
+}
+
+static void
+lmshrd_kclient_close()
+{
+ mutex_enter(&lmshrd_dh_mtx);
+ if (lmshrd_init) {
+ door_ki_rele(lmshrd_dh);
+ lmshrd_init = 0;
+ }
+ mutex_exit(&lmshrd_dh_mtx);
+}
+
+/*
+ * lmshrd_kclient_start
+ *
+ * The SMB kernel module should invoke this function upon startup.
+ */
+int
+lmshrd_kclient_start()
+{
+ int rc;
+
+ mutex_init(&lmshrd_dh_mtx, NULL, MUTEX_DEFAULT, NULL);
+ rc = lmshrd_kclient_open();
+
+ return (rc);
+}
+
+/*
+ * lmshrd_kclient_stop
+ *
+ * The SMB kernel module should invoke this function upon unload.
+ */
+void
+lmshrd_kclient_stop()
+{
+ lmshrd_kclient_close();
+ mutex_destroy(&lmshrd_dh_mtx);
+}
+
+/*
+ * Return 0 upon success. Otherwise, -1.
+ */
+static int
+lmshrd_door_check_srv_status(int opcode, smb_dr_ctx_t *dec_ctx)
+{
+ int status = smb_dr_get_int32(dec_ctx);
+ int err;
+ int rc = -1;
+
+ switch (status) {
+ case LMSHR_DOOR_SRV_SUCCESS:
+ rc = 0;
+ break;
+
+ case LMSHR_DOOR_SRV_ERROR:
+ err = smb_dr_get_uint32(dec_ctx);
+ cmn_err(CE_WARN, "%s: Encountered door server error %d",
+ lmshrd_desc[opcode], err);
+ break;
+
+ default:
+ cmn_err(CE_WARN, "%s: Unknown door server status",
+ lmshrd_desc[opcode]);
+ }
+
+ if (rc != 0) {
+ if ((err = smb_dr_decode_finish(dec_ctx)) != 0)
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], err);
+ }
+
+ return (rc);
+}
+
+uint64_t
+lmshrd_open_iterator(int mode)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ uint64_t lmshr_iter = 0;
+
+ int opcode = LMSHR_DOOR_OPEN_ITERATOR;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (lmshr_iter);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (lmshr_iter);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_int32(enc_ctx, mode);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (lmshr_iter);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (lmshr_iter);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (lmshr_iter);
+ }
+
+ lmshr_iter = smb_dr_get_lmshr_iterator(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (lmshr_iter);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (lmshr_iter);
+}
+
+
+DWORD
+lmshrd_close_iterator(uint64_t iterator)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ int opcode = LMSHR_DOOR_CLOSE_ITERATOR;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshr_iterator(enc_ctx, iterator);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_Success);
+}
+
+DWORD
+lmshrd_iterate(uint64_t iterator, lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ int opcode = LMSHR_DOOR_ITERATE;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ bzero(si, sizeof (lmshare_info_t));
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshr_iterator(enc_ctx, iterator);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_Success);
+}
+
+int
+lmshrd_num_shares(void)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ DWORD num_shares;
+ int opcode = LMSHR_DOOR_NUM_SHARES;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (-1);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (-1);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (-1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ num_shares = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (num_shares);
+}
+
+DWORD
+lmshrd_getinfo(char *share_name, lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_GETINFO;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (rc);
+}
+
+int
+lmshrd_check(char *share_name, int opcode)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status, rc;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_int32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (rc);
+}
+
+int
+lmshrd_exists(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_EXISTS));
+}
+
+int
+lmshrd_is_special(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_SPECIAL));
+}
+
+int
+lmshrd_is_restricted(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_RESTRICTED));
+}
+
+int
+lmshrd_is_admin(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_ADMIN));
+}
+
+int
+lmshrd_is_valid(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_VALID));
+}
+
+int
+lmshrd_is_dir(char *path)
+{
+ return (lmshrd_check(path, LMSHR_DOOR_IS_DIR));
+}
+
+int
+smb_get_kconfig(smb_kmod_cfg_t *cfg)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ int opcode = SMB_GET_KCONFIG;
+
+ if (!lmshrd_init && lmshrd_kclient_start() != 0)
+ return (-1);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (-1);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (-1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ smb_dr_get_kconfig(dec_ctx, cfg);
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (0);
+}
+
+/*
+ * This is a special interface that will be utilized by ZFS to cause
+ * a share to be added/removed
+ *
+ * arg is either a lmshare_info_t or share_name from userspace.
+ * It will need to be copied into the kernel. It is lmshare_info_t
+ * for add operations and share_name for delete operations.
+ */
+int
+lmshrd_share_upcall(void *arg, boolean_t add_share)
+{
+ door_arg_t doorarg = { 0 };
+ char *buf = NULL;
+ char *str = NULL;
+ int error;
+ int rc;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ lmshare_info_t *lmshare = NULL;
+ int opcode;
+
+ opcode = add_share == B_TRUE ? LMSHR_DOOR_ADD : LMSHR_DOOR_DELETE;
+
+ /* Return error if server isn't up and running */
+ if (!lmshrd_init)
+ return (NERR_ServerNotStarted);
+
+ if (lmshrd_kclient_open())
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_share_upcall", LMSHR_DOOR_SIZE);
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+
+ switch (opcode) {
+ case LMSHR_DOOR_ADD:
+ lmshare = MEM_MALLOC("lmshrd_share_upcall",
+ sizeof (lmshare_info_t));
+
+ if (error = xcopyin(arg, lmshare, sizeof (lmshare_info_t))) {
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ MEM_FREE("lmshrd_share_upcall", buf);
+ return (error);
+ }
+ smb_dr_put_lmshare(enc_ctx, lmshare);
+ break;
+
+ case LMSHR_DOOR_DELETE:
+ str = MEM_MALLOC("lmshrd_share_upcall", MAXPATHLEN);
+ if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ MEM_FREE("lmshrd_share_upcall", str);
+ return (error);
+ }
+ smb_dr_put_string(enc_ctx, str);
+ MEM_FREE("lmshrd_share_upcall", str);
+ break;
+ }
+
+ if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return (NERR_InternalError);
+ }
+
+ doorarg.data_ptr = buf;
+ doorarg.data_size = used;
+ doorarg.rbuf = buf;
+ doorarg.rsize = LMSHR_DOOR_SIZE;
+
+ if (error = door_ki_upcall(lmshrd_dh, &doorarg)) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return (error);
+ }
+
+ dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if (opcode == LMSHR_DOOR_ADD)
+ smb_dr_get_lmshare(dec_ctx, lmshare);
+
+ if (smb_dr_decode_finish(dec_ctx)) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_signing.c b/usr/src/uts/common/fs/smbsrv/smb_signing.c
new file mode 100644
index 0000000000..2b079c193b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_signing.c
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * These routines provide the SMB MAC signing for the SMB server.
+ * The routines calculate the signature of a SMB message in an mbuf chain.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/msgbuf.h>
+#include <sys/crypto/api.h>
+#include <smbsrv/smb_incl.h>
+
+#define SMB_SIG_SIZE 8
+#define SMB_SIG_OFFS 14
+
+/* This holds the MD5 mechanism */
+static crypto_mechanism_t crypto_mech = {CRYPTO_MECHANISM_INVALID, 0, 0};
+
+/*
+ * smb_sign_init
+ *
+ * Intializes MAC key based on the user session key and
+ * NTLM response and store it in the signing structure.
+ */
+void
+smb_sign_init(struct smb_request *req, smb_session_key_t *session_key,
+ char *resp, int resp_len)
+{
+ struct smb_sign *sign = &req->session->signing;
+
+ /*
+ * Initialise the crypto mechanism to MD5 if it not
+ * already initialised.
+ */
+ if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) {
+ crypto_mech.cm_type = crypto_mech2id(SUN_CKM_MD5);
+ if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) {
+ /*
+ * There is no MD5 crypto mechanism
+ * so turn off signing
+ */
+ smb_info.si.skc_signing_enable = 0;
+ req->session->secmode &=
+ (~NEGOTIATE_SECURITY_SIGNATURES_ENABLED);
+ cmn_err(CE_WARN,
+ "SmbSignInit: signing disabled (no MD5)");
+ return;
+ }
+ }
+
+ /* MAC key = concat (SessKey, NTLMResponse) */
+
+ bcopy(session_key, sign->mackey, sizeof (smb_session_key_t));
+ bcopy(resp, &(sign->mackey[sizeof (smb_session_key_t)]),
+ resp_len);
+ sign->mackey_len = sizeof (smb_session_key_t) + resp_len;
+
+ req->reply_seqnum = 1;
+ sign->seqnum = 2;
+ sign->flags = SMB_SIGNING_ENABLED;
+
+ if (smb_info.si.skc_signing_check)
+ sign->flags |= SMB_SIGNING_CHECK;
+
+}
+
+/*
+ * smb_sign_calc
+ *
+ * Calculates MAC signature for the given buffer and returns
+ * it in the mac_sign parameter.
+ *
+ * The sequence number is placed in the first four bytes of the signature
+ * field of the signature and the other 4 bytes are zeroed.
+ * The signature is the first 8 bytes of the MD5 result of the
+ * concatenated MAC key and the SMB message.
+ *
+ * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8)
+ *
+ * where
+ *
+ * MACKey = concat( UserSessionKey, NTLMResp )
+ *
+ * and
+ *
+ * SMBMsg is the SMB message containing the sequence number.
+ *
+ * Return 0 if success else -1
+ *
+ */
+static int
+smb_sign_calc(struct mbuf_chain *mbc,
+ struct smb_sign *sign,
+ uint32_t seqnum,
+ unsigned char *mac_sign)
+{
+ uint32_t seq_buf[2] = {0, 0};
+ unsigned char mac[16];
+ struct mbuf *mbuf = mbc->chain;
+ int offset = mbc->chain_offset;
+ int size;
+ int status;
+
+ crypto_data_t data;
+ crypto_data_t digest;
+ crypto_context_t crypto_ctx;
+
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_offset = 0;
+ data.cd_length = (size_t)-1;
+ data.cd_miscdata = 0;
+
+ digest.cd_format = CRYPTO_DATA_RAW;
+ digest.cd_offset = 0;
+ digest.cd_length = (size_t)-1;
+ digest.cd_miscdata = 0;
+ digest.cd_raw.iov_base = (char *)mac;
+ digest.cd_raw.iov_len = sizeof (mac);
+
+ status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ /*
+ * Put the sequence number into the first 4 bytes
+ * of the signature field in little endian format.
+ * We are using a buffer to represent the signature
+ * rather than modifying the SMB message.
+ */
+#ifdef __sparc
+ {
+ uint32_t temp;
+ ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3];
+ ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2];
+ ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1];
+ ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0];
+
+ seq_buf[0] = temp;
+ }
+#else
+ seq_buf[0] = seqnum;
+#endif
+
+ /* Digest the MACKey */
+ data.cd_raw.iov_base = (char *)sign->mackey;
+ data.cd_raw.iov_len = sign->mackey_len;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ /* Find start of data in chain */
+ while (offset >= mbuf->m_len) {
+ offset -= mbuf->m_len;
+ mbuf = mbuf->m_next;
+ }
+
+ /* Digest the SMB packet up to the signature field */
+ size = SMB_SIG_OFFS;
+ while (size >= mbuf->m_len - offset) {
+ data.cd_raw.iov_base = &mbuf->m_data[offset];
+ data.cd_raw.iov_len = mbuf->m_len - offset;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ size -= mbuf->m_len - offset;
+ mbuf = mbuf->m_next;
+ offset = 0;
+ }
+ if (size > 0) {
+ data.cd_raw.iov_base = &mbuf->m_data[offset];
+ data.cd_raw.iov_len = size;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ offset += size;
+ }
+
+ /*
+ * Digest in the seq_buf instead of the signature
+ * which has the sequence number
+ */
+
+ data.cd_raw.iov_base = (char *)seq_buf;
+ data.cd_raw.iov_len = SMB_SIG_SIZE;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ /* Find the end of the signature field */
+ offset += SMB_SIG_SIZE;
+ while (offset >= mbuf->m_len) {
+ offset -= mbuf->m_len;
+ mbuf = mbuf->m_next;
+ }
+ /* Digest the rest of the SMB packet */
+ while (mbuf) {
+ data.cd_raw.iov_base = &mbuf->m_data[offset];
+ data.cd_raw.iov_len = mbuf->m_len - offset;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ mbuf = mbuf->m_next;
+ offset = 0;
+ }
+
+ status = crypto_digest_final(&crypto_ctx, &digest, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ bcopy(mac, mac_sign, SMB_SIG_SIZE);
+
+ return (0);
+error:
+ cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status);
+ return (-1);
+
+}
+
+
+/*
+ * smb_sign_check_request
+ *
+ * Calculates MAC signature for the request mbuf chain
+ * using the next expected sequence number and compares
+ * it to the given signature.
+ *
+ * Note it does not check the signature for secondary transactions
+ * as their sequence number is the same as the original request.
+ *
+ * Return 0 if the signature verifies, otherwise, returns -1;
+ *
+ */
+int
+smb_sign_check_request(struct smb_request *req)
+{
+ struct mbuf_chain command = req->command;
+ unsigned char mac_sig[SMB_SIG_SIZE];
+ struct smb_sign *sign = &req->session->signing;
+ int rtn = 0;
+
+ /*
+ * Don't check secondary transactions - we dont know the sequence
+ * number.
+ */
+ if (req->smb_com == SMB_COM_TRANSACTION_SECONDARY ||
+ req->smb_com == SMB_COM_TRANSACTION2_SECONDARY ||
+ req->smb_com == SMB_COM_NT_TRANSACT_SECONDARY)
+ return (0);
+
+ if (sign->flags & SMB_SIGNING_CHECK) {
+
+ /* Reset the offset to begining of header */
+ command.chain_offset = req->orig_request_hdr;
+
+ /* calculate mac signature */
+ if (smb_sign_calc(&command, sign, sign->seqnum, mac_sig) != 0)
+ return (-1);
+
+ /* compare the signatures */
+ if (memcmp(mac_sig, req->smb_sig, SMB_SIG_SIZE) != 0) {
+ cmn_err(CE_WARN, "SmbSignCheckRequest: "
+ "bad signature %x %x %x %x %x %x %x %x",
+ req->smb_sig[0], req->smb_sig[1],
+ req->smb_sig[2], req->smb_sig[3],
+ req->smb_sig[4], req->smb_sig[5],
+ req->smb_sig[6], req->smb_sig[7]);
+#ifdef DBG_VERBOSE
+ /* Debug code to hunt for the sequence number */
+ for (i = sign->seqnum - 6; i <= sign->seqnum + 6; i++) {
+ smb_sign_calc(&command, sign, i, mac_sig);
+ if (memcmp(mac_sig, req->smb_sig,
+ SMB_SIG_SIZE) == 0) {
+ sign->seqnum = i;
+ goto ok;
+ }
+ }
+#endif
+ rtn = -1;
+ }
+ }
+ok:
+ /*
+ * Increament the sequence number for the reply, save the reply
+ * and set it for the next expect command.
+ * There is no reply for NT Cancel so just increament it for the
+ * next expected command.
+ */
+ sign->seqnum++;
+
+ if (req->smb_com == SMB_COM_NT_CANCEL)
+ req->reply_seqnum = 0;
+ else
+ req->reply_seqnum = sign->seqnum++;
+
+ return (rtn);
+}
+
+/*
+ * smb_sign_check_secondary
+ *
+ * Calculates MAC signature for the secondary transaction mbuf chain
+ * and compares it to the given signature.
+ * Return 0 if the signature verifies, otherwise, returns -1;
+ *
+ */
+int
+smb_sign_check_secondary(struct smb_request *req, unsigned int reply_seqnum)
+{
+ struct mbuf_chain command = req->command;
+ unsigned char mac_sig[SMB_SIG_SIZE];
+ struct smb_sign *sign = &req->session->signing;
+ int rtn = 0;
+
+ if (sign->flags & SMB_SIGNING_CHECK) {
+ /* Reset the offset to begining of header */
+ command.chain_offset = req->orig_request_hdr;
+
+ /* calculate mac signature */
+ if (smb_sign_calc(&command, sign, reply_seqnum - 1,
+ mac_sig) != 0)
+ return (-1);
+
+
+ /* compare the signatures */
+ if (memcmp(mac_sig, req->smb_sig, SMB_SIG_SIZE) != 0) {
+ cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature");
+ rtn = -1;
+ }
+ }
+ /* Save the reply sequence number */
+ req->reply_seqnum = reply_seqnum;
+
+ return (rtn);
+}
+
+
+
+
+/*
+ * smb_sign_reply
+ *
+ * Calculates MAC signature for the given mbuf chain,
+ * and write it to the signature field in the mbuf.
+ *
+ */
+void
+smb_sign_reply(struct smb_request *req, struct mbuf_chain *reply)
+{
+ struct mbuf_chain resp;
+ struct smb_sign *sign = &req->session->signing;
+ unsigned char signature[SMB_SIG_SIZE];
+ struct mbuf *mbuf;
+ int size = SMB_SIG_SIZE;
+ unsigned char *sig_ptr = signature;
+ int offset = 0;
+
+ if (reply)
+ resp = *reply;
+ else
+ resp = req->reply;
+
+ /* Reset offset to start of reply */
+ resp.chain_offset = 0;
+ mbuf = resp.chain;
+
+ /*
+ * Calculate MAC signature
+ */
+ if (smb_sign_calc(&resp, sign, req->reply_seqnum, signature) != 0)
+ return;
+
+ /*
+ * Put signature in the response
+ *
+ * First find start of signature in chain (offset + signature offset)
+ */
+ offset += SMB_SIG_OFFS;
+ while (offset >= mbuf->m_len) {
+ offset -= mbuf->m_len;
+ mbuf = mbuf->m_next;
+ }
+
+ while (size >= mbuf->m_len - offset) {
+ (void) memcpy(&mbuf->m_data[offset],
+ sig_ptr, mbuf->m_len - offset);
+ offset = 0;
+ sig_ptr += mbuf->m_len - offset;
+ size -= mbuf->m_len - offset;
+ mbuf = mbuf->m_next;
+ }
+ if (size > 0) {
+ (void) memcpy(&mbuf->m_data[offset], sig_ptr, size);
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_svc_sm.c b/usr/src/uts/common/fs/smbsrv/smb_svc_sm.c
new file mode 100644
index 0000000000..b43388cccd
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_svc_sm.c
@@ -0,0 +1,1301 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB Service State Machine
+ *
+ * _____________
+ * T21 | | T1
+ * +---------------->| INIT |------------------+
+ * | |_____________| |
+ * ______|_____ /|\ _____\|/_____
+ * | | T14| T22 | |
+ * | ERROR | +------------ | -----------------| OPENING |
+ * |____________| | | |_____________|
+ * /|\ | ______|______ |
+ * | | | | T23 |
+ * |T20 | +-->| CLOSING |<--------+ | T2
+ * | | | |_____________|<-------+| |
+ * _______|_______ | | /|\ || _____\|/_____
+ * | |<-+ |T19 | || | |
+ * | ERROR CLOSING |-----+ T13| |+-| CONFIG WAIT |
+ * |_______________| | | |_____________|
+ * /|\ | | |
+ * | _______|_______ | |
+ * | | | | |
+ * | +---------->| SESSION CLOSE |--+ | |
+ * | | |_______________| | | | T3
+ * | | /|\ /|\ | |T24 |
+ * | | T11| |T12 | | |
+ * | | | +-----+ | |
+ * | | _______|_______ | ____\|/_____
+ * | | | | | | |
+ * | | | DISCONNECTING | +---| CONNECTING |
+ * |T18 |T17 |_______________| |____________|
+ * | | /|\ /|\ |
+ * | | | | | T4
+ * | | | | |
+ * ______|____|___ | | T9 ___\|/___
+ * | | | +---------------| |
+ * | ERROR SESSION | |T10 | ONLINE |<-+
+ * +->| CLOSE | | +-------------->|_________| |
+ * | |_______________| | | T8 | | | |
+ * |T16 | /|\ /|\ ______|____|_ | | |____| T5
+ * +-----+ | | T25 | | | |
+ * | +-------------| RECONFIGURE |<--------------+ |
+ * | +----|_____________| T6 |
+ * | | /|\ |
+ * | T7| | |
+ * | +------+ |
+ * | T15 |
+ * +--------------------------------------------------+
+ *
+ *
+ * State Descriptions:
+ *
+ * Init
+ *
+ * Ready for device open. This is the initial service state and the
+ * service returns to this state when cleanup has completed after a
+ * device close. The pseudo-driver can only be unloaded or opened in
+ * this state.
+ *
+ * Opening
+ *
+ * The pseudo-driver has been opened and SMB initialization is underway
+ *
+ * Config Wait
+ *
+ * Waiting for smbd to provide configuration information. XXX Today
+ * the kernel/user sychronization is not completely implemented and
+ * some changes might be appropriate in the future. The current
+ * code pulls configuration from smbd (see smb_get_kconfig). For
+ * dynamic configuration updates smbd will need to push config information
+ * to the kernel. This could be handled with either an ioctl or a door
+ * call. When this change is made we should change the state machine so
+ * that it also relies on the pull model. One way to handle this is to
+ * have the state machine end up in "config wait" instead of "online"
+ * when the open of the pseudo-device returns. Smbd will then know
+ * to push the current config after it has successfully opened the
+ * device. Such a change would require tweaks to the handling of
+ * svc_sm->ssc_started.
+ *
+ * Connecting
+ *
+ * Connecting to SMB port and starting service listener thread
+ *
+ * Online
+ *
+ * Online and accepting SMB sessions
+ *
+ * Reconfiguring
+ *
+ * Updating configuration after receiving a config update from smbd. This
+ * state is very similar to "online" state except that new session requests
+ * get place on a queue and initialization for those requests is deferred
+ * until configuration is complete. XXX Since dymamic configuration
+ * updates have not been implemented this state is never exercised.
+ * It's possible that we could completely eliminate it by simply grabbing
+ * a mutex for the duration of the config update. If the config update
+ * will take a long time or require sleeping then this state will
+ * be useful.
+ *
+ * Disconnecting
+ *
+ * Disconnecting from the SMB port and stopping the service listener
+ * thread.
+ *
+ * Session Close
+ *
+ * Waiting for any open sessions to close
+ *
+ * Closing
+ *
+ * Quiesce service and release any associated resources. This is the
+ * inverse of the "opening" state.
+ *
+ * Error Session Close
+ *
+ * The connection was unexpectedly dropped due to an error of some kind.
+ * Waiting for any open session to close (identical to Session Close
+ * except that we enter this state involuntarily)
+ *
+ * Error Closing
+ *
+ * Similar to Closing except that we enter this state as the result of
+ * an error (either during initialization or runtime)
+ *
+ * Error
+ *
+ * An error occurred that caused the service to shutdown but the
+ * pseudo-device is still open.
+ *
+ *
+ * State Transitions:
+ *
+ * T1 - The state machine is started by a call to smb_svcstate_sm_start. This
+ * causes a SMB_SVCEVT_OPEN event which forces a transition to "opening"
+ * state.
+ *
+ * T2 - SMB_SVCEVT_OPEN_SUCCESS indicates that the open actions completed
+ * successfully and the state machine transitions to "config wait" state.
+ *
+ * T3 - Configuration received from smbd (SMB_SVCEVT_CONFIG_SUCCESS)
+ *
+ * T4 - SMB service listener thread started and successfully bound to the
+ * socket (SMB_SVCEVT_CONNECT).
+ *
+ * T5 - Any SMB_SVCEVT_SESSION_CREATE/SMB_SVCEVT_SESSION_DELETE events are
+ * tracked on the svc_sm->ssc_active_sessions list and reflected in
+ * the svc_sm->ssc_active_session_count but we stay in "online" state
+ *
+ * T6 - Reconfiguration event (SMB_SVCEVT_CONFIG) cause a transition to
+ * "reconfiguring" state.
+ *
+ * T7 - SMB_SVCEVT_SESSION_CREATE/SMB_SVCEVT_SESSION_DELETE
+ *
+ * T8 - Configuration received from smbd (SMB_SVCEVT_CONFIG_SUCCESS) drives us
+ * back to "online" state.
+ *
+ * T9 - SMB_SVCEVT_CLOSE starts the shutdown process, starting with
+ * "disconnecting" state.
+ *
+ * T10 - SMB_SVCEVT_CLOSE starts the shutdown process, starting with
+ * "disconnecting" state.
+ *
+ * T11 - After socket disconnect SMB_SVCEVT_DISCONNECT drives the state machine
+ * to "session close" state.
+ *
+ * T12 - SMB_SVCEVT_SESSION_CLOSE does not cause a state transition if more
+ * sessions remain.
+ *
+ * T13 - When no more session remain SMB_SVCEVT_SESSION_CLOSE causes a
+ * transition to "closing" state.
+ *
+ * T14 - All close actions completed successfully (SMB_SVCEVT_CLOSE_SUCCESS).
+ * Close operations are not allowed to fail so the transition from
+ * "closing" to "init" is guaranteed.
+ *
+ * T15 - If the SMB service connection is unexpectedly dropped,
+ * SMB_SVCEVT_DISCONNECT drives the state machine to
+ * "error session close" state.
+ *
+ * T16 - SMB_SVCEVT_SESSION_CLOSE does not cause a state transition if more
+ * sessions remain.
+ *
+ * T17 - SMB_SVCEVT_CLOSE causes a state change to "session close" state. The
+ * difference between "error session close" and "session close" state is
+ * whether the pseudo device is open.
+ *
+ * T18 - When no more session remain SMB_SVCEVT_SESSION_CLOSE causes a
+ * transition to "error closing" state.
+ *
+ * T19 - SMB_SVCEVT_CLOSE causes a state change to "closing" state. The
+ * difference between "error closing" and "closing" state is
+ * whether the pseudo device is open.
+ *
+ * T20 - All close actions completed successfully (SMB_SVCEVT_CLOSE_SUCCESS).
+ * Close operations are not allowed to fail so the transition from
+ * "error closing" to "error" is guaranteed.
+ *
+ * T21 - SMB_SVCEVT_CLOSE moves everything back to "init" state
+ *
+ * T22 - SMB_SVCEVT_OPEN_FAILED causes a state change to "error closing".
+ * Moving to "error closing" state instead of "closing" causes the
+ * state machine to ultimately stop in "error" state (instead of
+ * "init").
+ *
+ * T23 - SMB_SVCEVT_CLOSE
+ *
+ * T24 - SMB_SVCEVT_CLOSE in "connecting" state causes a transition
+ * to "closing" state since the connection has not yet been established.
+ *
+ * T25 - If the SMB service connection is unexpectedly dropped,
+ * SMB_SVCEVT_DISCONNECT drives the state machine to
+ * "error session close" state.
+ *
+ * Overview:
+ *
+ * When the SMB pseudo-device gets open the state machine gets started with a
+ * call to smb_svcstate_sm_start which will block until initialization either
+ * succeeds or fails.
+ *
+ * SMB code external to the state machine generates events (defined above) by
+ * calling smb_svcstate_event and the state machine determines the new state
+ * based on the events and the current state.
+ *
+ * When the pseudo-device is closed, the state machine gets stopped with
+ * a call to smb_svcstate_sm_stop.
+ *
+ * This state machine also keeps track of the active session list. The
+ * list of sessions can be queried using the following services:
+ *
+ * smb_svcstate_lock_read(svc_sm);
+ * smb_svcstate_session_getnext(svc_sm, prev_session);
+ * (repeat until NULL is returned)
+ * smb_svcstate_unlock(svc_sm);
+ *
+ *
+ * Implemention Details:
+ *
+ * States are named SMB_SVCSTATE_<state name>
+ *
+ * Events are named SMB_SVCEVT_<event name>
+ *
+ * Each state has an associated function: smb_svcstate_<state name>
+ *
+ * This state machine implements four types of actions:
+ *
+ * State entry actions - State-specific actions that are taken when a
+ * state is entered (transitions like T5 that do not result in a real
+ * state change are not actually coded as state transitions (no call to
+ * smb_svcstate_update) and therefore will not cause state entry actions.
+ * These actions are implemented in smb_svcstate_update.
+ *
+ * Immediate event actions - An action specific to a particular event
+ * that is taken immediately, before the event is placed on the task
+ * queue. The action does not depend on the current state. These should
+ * only be implemented when absolutely necessary since the code path for
+ * immediate actions is multithreaded (smb_svcstate_event_locked).
+ *
+ * Deferred event actions - An action specific to a particular event
+ * that is handled by the taskq thread. The action does not depend on
+ * the current state and the code implementing the actions is single
+ * threaded since the taskq only has one thread. Implemented in
+ * smb_svcstate_event_handler.
+ *
+ * State specific event actions - Actions specific to events that
+ * depend on the current state. These actions are implemented
+ * in the state-specific event handler functions
+ * (smb_svcstate_<event name>)
+ *
+ * The description above makes things sound more complicated than they really
+ * are. Deferred event actions are really just a special case of state
+ * specific event actions. To find out what happens when a specific event
+ * occurs in a specific state:
+ *
+ * 1. Look at smb_svcstate_event_locked and find matching event actions (rare)
+ * 2. Look at smb_svcstate_event_handler and find matching event actions
+ * 3. Look at smb_svcstate_<current state> and find matching event actions
+ *
+ * If the event causes a state transition (this will always be found in
+ * smb_svcstate_<current_state>) then look up the new state in
+ * smb_svcstate_update which will show the state entry actions for the new
+ * state.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <sys/note.h>
+#include <sys/sdt.h>
+
+static void smb_svcstate_event_locked(smb_svc_sm_ctx_t *svc_sm,
+ smb_svcevt_t event, uintptr_t event_info);
+
+static void smb_svcstate_event_handler(void *event_ctx);
+
+static void smb_svcstate_init(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_opening(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_config_wait(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_connecting(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_online(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_reconfiguring(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_disconnecting(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_session_close(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_error_session_close(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_closing(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_error_closing(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_error(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_update(smb_svc_sm_ctx_t *svc_sm,
+ smb_svcstate_t newstate);
+
+static void smb_svcstate_set_started(smb_svc_sm_ctx_t *svc_sm,
+ int started);
+
+static void smb_svcstate_session_start(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *new_session);
+
+static void smb_svcstate_session_defer(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *new_session);
+
+static void smb_svcstate_session_reject_active(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *session, char *reason);
+
+static void
+smb_svcstate_start_deferred_sessions(smb_svc_sm_ctx_t *svc_sm);
+
+static void
+smb_svcstate_reject_deferred_sessions(smb_svc_sm_ctx_t *svc_sm);
+
+static void
+smb_svcstate_close_active_sessions(smb_svc_sm_ctx_t *svc_sm);
+
+extern void smb_wakeup_session_daemon(smb_thread_t *thread, void *arg);
+extern void smb_session_daemon(smb_thread_t *thread, void *arg);
+extern int smb_get_kconfig(smb_kmod_cfg_t *cfg);
+
+char *smb_svcstate_event_name[SMB_SVCEVT_MAX_EVENT];
+char *smb_svcstate_state_name[SMB_SVCSTATE_MAX_STATE];
+
+/*
+ * SMB Service State Machine
+ */
+
+#define SMB_STOPPED 0
+#define SMB_START_SUCCESS 1
+#define SMB_START_FAILED 2
+
+int
+smb_svcstate_sm_init(smb_svc_sm_ctx_t *svc_sm)
+{
+ bzero(svc_sm, sizeof (*svc_sm));
+
+ /* Protects state context except for ssc_state and ssc_last_state */
+ rw_init(&svc_sm->ssc_state_rwlock, NULL, RW_DEFAULT, NULL);
+
+ /* Protects ssc_state and ssc_last_state */
+ mutex_init(&svc_sm->ssc_state_cv_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&svc_sm->ssc_state_cv, NULL, CV_DEFAULT, NULL);
+
+ svc_sm->ssc_state = SMB_SVCSTATE_INIT;
+ svc_sm->ssc_last_state = SMB_SVCSTATE_INIT;
+
+ list_create(&svc_sm->ssc_active_sessions, sizeof (smb_session_t),
+ offsetof(smb_session_t, s_lnd));
+ list_create(&svc_sm->ssc_deferred_sessions, sizeof (smb_session_t),
+ offsetof(smb_session_t, s_lnd));
+
+ /* Service state machine is single threaded by design */
+ svc_sm->ssc_taskq = taskq_create("smb_svc_sm", 1, minclsyspri,
+ 1, 1, 0);
+ if (svc_sm->ssc_taskq == NULL) {
+ return (ENOMEM);
+ }
+
+ /*
+ * Setup event and state name tables. Use for debug logging
+ * and/or dtrace scripts
+ */
+ smb_svcstate_event_name[SMB_SVCEVT_UNDEFINED] = "UNDEFINED";
+ smb_svcstate_event_name[SMB_SVCEVT_OPEN] = "OPEN";
+ smb_svcstate_event_name[SMB_SVCEVT_CLOSE] = "CLOSE";
+ smb_svcstate_event_name[SMB_SVCEVT_OPEN_SUCCESS] = "OPEN_SUCCESS";
+ smb_svcstate_event_name[SMB_SVCEVT_OPEN_FAILED] = "OPEN_FAILED";
+ smb_svcstate_event_name[SMB_SVCEVT_CLOSE_SUCCESS] = "CLOSE_SUCCESS";
+ smb_svcstate_event_name[SMB_SVCEVT_CONNECT] = "CONNECT";
+ smb_svcstate_event_name[SMB_SVCEVT_DISCONNECT] = "DISCONNECT";
+ smb_svcstate_event_name[SMB_SVCEVT_CONFIG] = "CONFIG";
+ smb_svcstate_event_name[SMB_SVCEVT_CONFIG_SUCCESS] = "CONFIG_SUCCESS";
+ smb_svcstate_event_name[SMB_SVCEVT_CONFIG_FAILED] = "CONFIG_FAILED";
+ smb_svcstate_event_name[SMB_SVCEVT_SESSION_CREATE] = "SESSION_CREATE";
+ smb_svcstate_event_name[SMB_SVCEVT_SESSION_DELETE] = "SESSION_DELETE";
+
+ smb_svcstate_state_name[SMB_SVCSTATE_UNDEFINED] = "UNDEFINED";
+ smb_svcstate_state_name[SMB_SVCSTATE_INIT] = "INIT";
+ smb_svcstate_state_name[SMB_SVCSTATE_OPENING] = "OPENING";
+ smb_svcstate_state_name[SMB_SVCSTATE_CONFIG_WAIT] = "CONFIG_WAIT";
+ smb_svcstate_state_name[SMB_SVCSTATE_CONNECTING] = "CONNECTING";
+ smb_svcstate_state_name[SMB_SVCSTATE_ONLINE] = "ONLINE";
+ smb_svcstate_state_name[SMB_SVCSTATE_RECONFIGURING] = "RECONFIGURING";
+ smb_svcstate_state_name[SMB_SVCSTATE_DISCONNECTING] = "DISCONNECTING";
+ smb_svcstate_state_name[SMB_SVCSTATE_SESSION_CLOSE] = "SESSION_CLOSE";
+ smb_svcstate_state_name[SMB_SVCSTATE_ERROR_SESSION_CLOSE] =
+ "ERROR_SESSION_CLOSE";
+ smb_svcstate_state_name[SMB_SVCSTATE_CLOSING] = "CLOSING";
+ smb_svcstate_state_name[SMB_SVCSTATE_ERROR_CLOSING] = "ERROR_CLOSING";
+ smb_svcstate_state_name[SMB_SVCSTATE_ERROR] = "ERROR";
+
+ return (0);
+}
+
+void
+smb_svcstate_sm_fini(smb_svc_sm_ctx_t *svc_sm)
+{
+ taskq_destroy(svc_sm->ssc_taskq);
+
+ list_destroy(&svc_sm->ssc_deferred_sessions);
+ list_destroy(&svc_sm->ssc_active_sessions);
+
+ cv_destroy(&svc_sm->ssc_state_cv);
+ mutex_destroy(&svc_sm->ssc_state_cv_mutex);
+ rw_destroy(&svc_sm->ssc_state_rwlock);
+}
+
+int
+smb_svcstate_sm_start(smb_svc_sm_ctx_t *svc_sm)
+{
+ clock_t wait_result;
+ int result;
+
+ /*
+ * Make sure state machine is idle and ready to be started.
+ */
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ while (svc_sm->ssc_started) {
+ /*
+ * Already started, possibly because we're still trying to
+ * shutdown. Wait for up to 30 seconds then return EBUSY.
+ */
+ wait_result = cv_timedwait(&svc_sm->ssc_state_cv,
+ &svc_sm->ssc_state_cv_mutex,
+ lbolt + SEC_TO_TICK(30));
+ if (wait_result == -1) {
+ /* Timeout */
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+ return (EBUSY);
+ }
+ }
+
+ /*
+ * SMB_SVCEVT_OPEN will get the state machine moving
+ */
+ smb_svcstate_event_locked(svc_sm, SMB_SVCEVT_OPEN, NULL);
+
+ /*
+ * Wait for the state machine to signal either a successful
+ * start or a start failure.
+ */
+ while (!svc_sm->ssc_started) {
+ cv_wait(&svc_sm->ssc_state_cv, &svc_sm->ssc_state_cv_mutex);
+ }
+
+ result = (svc_sm->ssc_started == SMB_START_FAILED) ?
+ svc_sm->ssc_start_error : 0;
+
+ /*
+ * If the open failed we will end up in "Error" state. Since we
+ * are returning failure to the open request on the pseudo-device
+ * we will never see a close so we need to force the device closed.
+ *
+ * A careful look at the state machine will should that we could
+ * avoid this step by transitioning from opening --> closing
+ * instead of opening --> error_closing when there is an initialization
+ * problem. The reason we shouldn't do this is because
+ * smb_svcstate_sm_busy returns "false" (not busy) when the state
+ * machine is in init state and we don't want to mistakenly indicate
+ * that we are not busy.
+ */
+ if (result != 0) {
+ smb_svcstate_event_locked(svc_sm, SMB_SVCEVT_CLOSE, NULL);
+ }
+
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+
+ return (result);
+}
+
+/*ARGSUSED*/
+void
+smb_svcstate_sm_stop(smb_svc_sm_ctx_t *svc_sm)
+{
+ smb_svcstate_event(SMB_SVCEVT_CLOSE, NULL);
+}
+
+boolean_t
+smb_svcstate_sm_busy(void)
+{
+ return (smb_info.si_svc_sm_ctx.ssc_state != SMB_SVCSTATE_INIT);
+}
+
+void
+smb_svcstate_event(smb_svcevt_t event, uintptr_t event_info)
+{
+ smb_svc_sm_ctx_t *svc_sm = &smb_info.si_svc_sm_ctx;
+
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ smb_svcstate_event_locked(svc_sm, event, event_info);
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+}
+
+void
+smb_svcstate_lock_read(smb_svc_sm_ctx_t *svc_sm)
+{
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_READER);
+
+}
+
+void
+smb_svcstate_unlock(smb_svc_sm_ctx_t *svc_sm)
+{
+ rw_exit(&svc_sm->ssc_state_rwlock);
+}
+
+smb_session_t *
+smb_svcstate_session_getnext(smb_svc_sm_ctx_t *svc_sm, smb_session_t *prev)
+{
+ smb_session_t *result;
+
+ /* Skip sessions in "terminated" state */
+ do {
+ if (prev == NULL) {
+ result = list_head(&svc_sm->ssc_active_sessions);
+ } else {
+ result = list_next(&svc_sm->ssc_active_sessions, prev);
+ }
+ prev = result;
+ } while ((result != NULL) &&
+ (result->s_state == SMB_SESSION_STATE_TERMINATED));
+
+ return (result);
+}
+
+int
+smb_svcstate_session_count(smb_svc_sm_ctx_t *svc_sm)
+{
+ return (svc_sm->ssc_active_session_count);
+}
+
+/*
+ * Internal use only by state machine code
+ */
+
+static void
+smb_svcstate_event_locked(smb_svc_sm_ctx_t *svc_sm,
+ smb_svcevt_t event, uintptr_t event_info)
+{
+ smb_event_ctx_t *event_ctx;
+
+ event_ctx = kmem_zalloc(sizeof (*event_ctx), KM_SLEEP);
+ event_ctx->sec_event = event;
+ event_ctx->sec_info = event_info;
+
+ /*
+ * Immediate event actions that are independent of state.
+ * This code is multi-threaded and is in the context of
+ * the thread that generated the event.
+ *
+ * Don't generate events from this function (recursive mutex
+ * enter).
+ */
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /*
+ * We don't necessarily want to reflect this session in the
+ * session count just yet. We do, however, want to know
+ * that its waiting so that we can properly close down
+ * all the outstanding session as we are closing the service.
+ * The ssc_session_creates_waiting counter represents
+ * the sessions that have been dispatched to the taskq
+ * but not yet processed.
+ *
+ * Session delete events don't have the same issue because
+ * the session count won't go to zero until they are all
+ * processed.
+ */
+ svc_sm->ssc_session_creates_waiting++;
+ break;
+ default:
+ break;
+ }
+
+ (void) taskq_dispatch(svc_sm->ssc_taskq, &smb_svcstate_event_handler,
+ event_ctx, TQ_SLEEP);
+}
+
+/*
+ * Task queue gets created with only one thread so this code is inherently
+ * single threaded. State changes should still be protected with a mutex
+ * since other threads might read the state value.
+ */
+static void
+smb_svcstate_event_handler(void *event_ctx_opaque)
+{
+ smb_svc_sm_ctx_t *svc_sm = &smb_info.si_svc_sm_ctx;
+ smb_event_ctx_t *event_ctx = event_ctx_opaque;
+ smb_session_t *session;
+
+ DTRACE_PROBE2(service__event,
+ smb_svc_sm_ctx_t *, svc_sm, smb_event_ctx_t *, event_ctx);
+
+ /*
+ * Validate event
+ */
+ ASSERT(event_ctx->sec_event != SMB_SVCEVT_UNDEFINED);
+ ASSERT3U(event_ctx->sec_event, <, SMB_SVCEVT_MAX_EVENT);
+
+ /*
+ * Validate current state
+ */
+ ASSERT(svc_sm->ssc_state != SMB_SVCSTATE_UNDEFINED);
+ ASSERT3U(svc_sm->ssc_state, <, SMB_SVCSTATE_MAX_STATE);
+
+ /*
+ * Deferred event actions that are independent of state.
+ * This code is single-threaded and is in the context of
+ * the task-queue thread.
+ */
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_DISCONNECT:
+ svc_sm->ssc_disconnect_error = (int)event_ctx->sec_info;
+ break;
+ case SMB_SVCEVT_SESSION_CREATE:
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ svc_sm->ssc_session_creates_waiting--;
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+ break;
+ case SMB_SVCEVT_SESSION_DELETE:
+ session = (smb_session_t *)event_ctx->sec_info;
+ ASSERT(session->s_state == SMB_SESSION_STATE_TERMINATED);
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_WRITER);
+ list_remove(&svc_sm->ssc_active_sessions, session);
+ svc_sm->ssc_active_session_count--;
+ rw_exit(&svc_sm->ssc_state_rwlock);
+
+ /*
+ * Make sure thread has exited
+ */
+ smb_thread_stop(&session->s_thread);
+
+ smb_session_delete(session);
+
+ /*
+ * State specific handlers will also process the event
+ * but the event info (session) is no longer valid.
+ */
+ event_ctx->sec_info = NULL;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Call state-specific event handler.
+ */
+ switch (svc_sm->ssc_state) {
+ case SMB_SVCSTATE_INIT:
+ smb_svcstate_init(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_OPENING:
+ smb_svcstate_opening(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_CONFIG_WAIT:
+ smb_svcstate_config_wait(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_CONNECTING:
+ smb_svcstate_connecting(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_ONLINE:
+ smb_svcstate_online(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_RECONFIGURING:
+ smb_svcstate_reconfiguring(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_DISCONNECTING:
+ smb_svcstate_disconnecting(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_SESSION_CLOSE:
+ smb_svcstate_session_close(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_ERROR_SESSION_CLOSE:
+ smb_svcstate_error_session_close(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_CLOSING:
+ smb_svcstate_closing(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_ERROR_CLOSING:
+ smb_svcstate_error_closing(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_ERROR:
+ smb_svcstate_error(svc_sm, event_ctx);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ kmem_free(event_ctx, sizeof (*event_ctx));
+}
+
+static void
+smb_svcstate_init(smb_svc_sm_ctx_t *svc_sm, smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_OPEN:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_OPENING);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+smb_svcstate_opening(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_OPEN_SUCCESS:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CONFIG_WAIT);
+ break;
+ case SMB_SVCEVT_OPEN_FAILED:
+ /*
+ * Go to error_closed state, cleanup anything we did in open
+ * and then back to init state. We want to end up in "error"
+ * state instead of "init" state.
+ */
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR_CLOSING);
+ smb_svcstate_set_started(svc_sm, SMB_START_FAILED);
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_config_wait(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CONFIG:
+ /*
+ * Update our configuration. A successful config update
+ * will trigger SMB_SVCEVT_CONFIG_SUCCESS and drive us
+ * into online state.
+ */
+ (void) smb_get_kconfig(&smb_info.si); /* XXX */
+ break;
+ case SMB_SVCEVT_CONFIG_SUCCESS:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CONNECTING);
+ break;
+ case SMB_SVCEVT_CONFIG_FAILED:
+ /* Don't care, wait for another config attempt */
+ break;
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_CLOSING);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_connecting(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CONNECT:
+ /*
+ * Wait until both NBT and TCP transport services
+ * are connected before going online.
+ */
+ if ((smb_info.si_connect_progress & SMB_SI_NBT_CONNECTED) &&
+ (smb_info.si_connect_progress & SMB_SI_TCP_CONNECTED)) {
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ONLINE);
+ smb_svcstate_set_started(svc_sm, SMB_START_SUCCESS);
+ }
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ svc_sm->ssc_start_error = svc_sm->ssc_disconnect_error;
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR_CLOSING);
+ smb_svcstate_set_started(svc_sm, SMB_START_FAILED);
+ break;
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CLOSING);
+ break;
+ case SMB_SVCEVT_SESSION_CREATE:
+ smb_svcstate_session_defer(svc_sm,
+ (smb_session_t *)event_ctx->sec_info);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_online(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ smb_session_t *new_session;
+
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /* Event context is the new socket */
+ new_session = (smb_session_t *)event_ctx->sec_info;
+#if 0 /* XXX PGD */
+ smb_session_config(new_session);
+#endif
+ smb_svcstate_session_start(svc_sm, new_session);
+ break;
+ case SMB_SVCEVT_CONNECT:
+ case SMB_SVCEVT_SESSION_DELETE:
+ /* No state-specific action required */
+ break;
+ case SMB_SVCEVT_CONFIG:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_RECONFIGURING);
+ break;
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_DISCONNECTING);
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ /*
+ * The session service daemon unexpectedly stopped. Looks
+ * like we're done talking SMB for the day.
+ */
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR_SESSION_CLOSE);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_reconfiguring(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ smb_session_t *new_session;
+
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /* Event context is the new socket */
+ new_session = (smb_session_t *)event_ctx->sec_info;
+ smb_svcstate_session_defer(svc_sm, new_session);
+ break;
+ case SMB_SVCEVT_SESSION_DELETE:
+ /* No state-specific action required */
+ break;
+ case SMB_SVCEVT_CONFIG:
+ /* Hopefully this won't happen but if it does we ignore it */
+ break;
+ case SMB_SVCEVT_CONFIG_SUCCESS:
+ case SMB_SVCEVT_CONFIG_FAILED:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ONLINE);
+ break;
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_DISCONNECTING);
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ /*
+ * The session service daemon unexpectedly stopped. Looks
+ * like we're done talking SMB for the day.
+ */
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR_SESSION_CLOSE);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_disconnecting(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ smb_session_t *session;
+
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /* Event context is the new socket */
+ session = (smb_session_t *)event_ctx->sec_info;
+
+ /* We're not online so reject the connection */
+ smb_session_reject(session, "SMB service is shutting down.");
+ smb_session_delete(session);
+ break;
+ case SMB_SVCEVT_CONNECT:
+ case SMB_SVCEVT_SESSION_DELETE:
+ /* No state-specific action required */
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_SESSION_CLOSE);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_session_close(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ smb_session_t *session;
+
+ /*
+ * We continue to accept "session creates" because we might
+ * accept a connection while the SMB_SVCEVT_CLOSE is
+ * queued but not yet handled.
+ */
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /* Event context is the new socket */
+ session = (smb_session_t *)event_ctx->sec_info;
+
+ /* We're not online so reject the connection */
+ smb_session_reject(session, "Not configured");
+ smb_session_delete(session);
+ /*FALLTHROUGH*/
+ case SMB_SVCEVT_SESSION_DELETE:
+ if ((svc_sm->ssc_active_session_count == 0) &&
+ (svc_sm->ssc_session_creates_waiting == 0)) {
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_CLOSING);
+ }
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ /* No state-specific action required */
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_error_session_close(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ /*
+ * Since our connection dropped we shouldn't see any more
+ * "creates" in this state
+ */
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_SESSION_CLOSE);
+ break;
+ case SMB_SVCEVT_SESSION_DELETE:
+ if ((svc_sm->ssc_active_session_count == 0) &&
+ (svc_sm->ssc_session_creates_waiting == 0)) {
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_ERROR_CLOSING);
+ }
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_closing(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CLOSE_SUCCESS:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_INIT);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+smb_svcstate_error_closing(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CLOSING);
+ break;
+ case SMB_SVCEVT_CLOSE_SUCCESS:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+smb_svcstate_error(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ ASSERT(event_ctx->sec_event == SMB_SVCEVT_CLOSE);
+
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_INIT);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+smb_svcstate_update(smb_svc_sm_ctx_t *svc_sm, smb_svcstate_t new_state_arg)
+{
+ smb_svcstate_t new_state;
+ int error;
+
+ /*
+ * Validate new state
+ */
+ ASSERT(new_state_arg != SMB_SVCSTATE_UNDEFINED);
+ ASSERT3U(new_state_arg, <, SMB_SVCSTATE_MAX_STATE);
+
+ /*
+ * Update state in context. We protect this with a mutex
+ * even though the state machine code is single threaded so that
+ * other threads can check the state value atomically.
+ */
+ new_state = (new_state_arg < SMB_SVCSTATE_MAX_STATE) ?
+ new_state_arg: SMB_SVCSTATE_UNDEFINED;
+
+ DTRACE_PROBE2(service__state__change,
+ smb_svc_sm_ctx_t *, svc_sm, smb_svcstate_t, new_state);
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ svc_sm->ssc_last_state = svc_sm->ssc_state;
+ svc_sm->ssc_state = new_state;
+ cv_signal(&svc_sm->ssc_state_cv);
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+
+ /*
+ * Now perform the appropiate actions for the new state
+ */
+ switch (new_state) {
+ case SMB_SVCSTATE_INIT:
+ smb_svcstate_set_started(svc_sm, SMB_STOPPED);
+ break;
+ case SMB_SVCSTATE_OPENING:
+ /*
+ * Start all SMB subsystems and connect to socket
+ */
+ svc_sm->ssc_start_error = smb_service_open(&smb_info);
+ if (svc_sm->ssc_start_error != 0) {
+ smb_svcstate_event(SMB_SVCEVT_OPEN_FAILED, NULL);
+ } else {
+ /* Open actions successful */
+ smb_svcstate_event(SMB_SVCEVT_OPEN_SUCCESS, NULL);
+ }
+ break;
+ case SMB_SVCSTATE_CONFIG_WAIT:
+ /*
+ * Nothing in particular to do here except to note the
+ * state change. Now we wait for smbd to provide
+ * our configuration.
+ */
+ /*
+ * XXX For now this is done as part of smb_service_open()
+ * so just send the "success" event.
+ */
+ smb_svcstate_event(SMB_SVCEVT_CONFIG_SUCCESS, NULL);
+ break;
+ case SMB_SVCSTATE_CONNECTING:
+ /*
+ * When we move to a userland thread model we will rely
+ * on smbd to start the SMB socket service thread.
+ */
+ error = smb_service_connect(&smb_info);
+ if (error != 0)
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT,
+ (uintptr_t)error);
+ break;
+ case SMB_SVCSTATE_ONLINE:
+ smb_svcstate_start_deferred_sessions(svc_sm);
+ /* No actions */
+ break;
+ case SMB_SVCSTATE_RECONFIGURING:
+ (void) smb_get_kconfig(&smb_info.si); /* XXX */
+ break;
+ case SMB_SVCSTATE_DISCONNECTING:
+ smb_svcstate_reject_deferred_sessions(svc_sm);
+ smb_service_disconnect(&smb_info);
+ break;
+ case SMB_SVCSTATE_ERROR_SESSION_CLOSE:
+ smb_svcstate_reject_deferred_sessions(svc_sm);
+ if ((svc_sm->ssc_active_session_count == 0) &&
+ (svc_sm->ssc_session_creates_waiting == 0)) {
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_ERROR_CLOSING);
+ } else {
+ smb_svcstate_close_active_sessions(svc_sm);
+ }
+ break;
+ case SMB_SVCSTATE_SESSION_CLOSE:
+ if ((svc_sm->ssc_active_session_count == 0) &&
+ (svc_sm->ssc_session_creates_waiting == 0)) {
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CLOSING);
+ } else {
+ smb_svcstate_close_active_sessions(svc_sm);
+ }
+ break;
+ case SMB_SVCSTATE_ERROR_CLOSING:
+ case SMB_SVCSTATE_CLOSING:
+ smb_service_close(&smb_info);
+ smb_svcstate_event(SMB_SVCEVT_CLOSE_SUCCESS, NULL);
+ break;
+ case SMB_SVCSTATE_ERROR:
+ /* No actions */
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_set_started(smb_svc_sm_ctx_t *svc_sm, int started)
+{
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ /* Make sure we have an error code if we failed to start */
+ ASSERT(started != SMB_START_FAILED || svc_sm->ssc_start_error != 0);
+ svc_sm->ssc_started = started;
+ cv_signal(&svc_sm->ssc_state_cv);
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+}
+
+static void
+smb_svcstate_session_start(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *new_session)
+{
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_WRITER);
+ if (svc_sm->ssc_active_session_count >=
+ smb_info.si.skc_maxconnections) {
+ svc_sm->ssc_error_no_resources++;
+ rw_exit(&svc_sm->ssc_state_rwlock);
+
+ smb_session_reject(new_session, "Too many open sessions");
+ smb_session_delete(new_session);
+ } else {
+ new_session->s_state = SMB_SESSION_STATE_CONNECTED;
+ list_insert_tail(&svc_sm->ssc_active_sessions, new_session);
+ svc_sm->ssc_active_session_count++;
+ rw_exit(&svc_sm->ssc_state_rwlock);
+
+ /*
+ * Blocks until thread has started
+ */
+ if (smb_thread_start(&new_session->s_thread) != 0) {
+ smb_svcstate_session_reject_active(svc_sm, new_session,
+ "Session thread creation failed");
+ } else {
+ DTRACE_PROBE1(session__create,
+ struct session *, new_session);
+ }
+ }
+}
+
+static void
+smb_svcstate_session_defer(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *new_session)
+{
+ list_insert_tail(&svc_sm->ssc_deferred_sessions, new_session);
+ svc_sm->ssc_deferred_session_count++;
+}
+
+/*ARGSUSED*/
+static void
+smb_svcstate_session_reject_active(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *session, char *reason)
+{
+ smb_session_reject(session, reason);
+
+ smb_svcstate_event(SMB_SVCEVT_SESSION_DELETE, (uintptr_t)session);
+}
+
+static void
+smb_svcstate_start_deferred_sessions(smb_svc_sm_ctx_t *svc_sm)
+{
+ smb_session_t *session, *next_session;
+
+ /*
+ * svc_sm->ssc_deferred_sessions is private to the (single-threaded)
+ * state machine so we don't need to lock it.
+ */
+ session = list_head(&svc_sm->ssc_deferred_sessions);
+ while (session != NULL) {
+ next_session =
+ list_next(&svc_sm->ssc_deferred_sessions, session);
+ list_remove(&svc_sm->ssc_deferred_sessions, session);
+ svc_sm->ssc_deferred_session_count--;
+ smb_svcstate_session_start(svc_sm, session);
+ session = next_session;
+ }
+}
+
+static void
+smb_svcstate_reject_deferred_sessions(smb_svc_sm_ctx_t *svc_sm)
+{
+ smb_session_t *session, *next_session;
+
+
+ /*
+ * svc_sm->ssc_deferred_sessions is private to the (single-threaded)
+ * state machine so we don't need to lock it.
+ */
+ session = list_head(&svc_sm->ssc_deferred_sessions);
+ while (session != NULL) {
+ next_session =
+ list_next(&svc_sm->ssc_deferred_sessions, session);
+ list_remove(&svc_sm->ssc_deferred_sessions, session);
+ svc_sm->ssc_deferred_session_count--;
+ smb_svcstate_session_reject_active(svc_sm, session,
+ "SMB service is shutting down (deferred)");
+ session = next_session;
+ }
+}
+
+static void
+smb_svcstate_close_active_sessions(smb_svc_sm_ctx_t *svc_sm)
+{
+ smb_session_t *session;
+
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_WRITER);
+ for (session = list_head(&svc_sm->ssc_active_sessions);
+ session != NULL;
+ session = list_next(&svc_sm->ssc_active_sessions, session)) {
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ rw_exit(&svc_sm->ssc_state_rwlock);
+
+ /*
+ * As each session thread terminates it will generate
+ * a "session delete" event.
+ */
+ smb_thread_stop(&session->s_thread);
+
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_WRITER);
+ }
+ rw_exit(&svc_sm->ssc_state_rwlock);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_create_directory.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_create_directory.c
new file mode 100644
index 0000000000..6ef6691df3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_create_directory.c
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_create_directory
+ *
+ * This requests the server to create a directory relative to Tid in the
+ * SMB header, optionally assigning extended attributes to it.
+ *
+ * Client Request Value
+ * ========================== =========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_CREATE_DIRECTORY
+ *
+ * Parameter Block Encoding Description
+ * ========================== =========================================
+ *
+ * ULONG Reserved; Reserved--must be zero
+ * STRING Name[]; Directory name to create
+ * UCHAR Data[]; Optional FEAList for the new directory
+ *
+ * Response Parameter Block Description
+ * ========================== =========================================
+ *
+ * USHORT EaErrorOffset Offset into FEAList of first error which
+ * occurred while setting EAs
+ */
+
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smb_incl.h>
+
+
+extern int smb_common_create_directory(struct smb_request *sr);
+
+
+/*
+ * smb_com_trans2_create_directory
+ */
+int
+smb_com_trans2_create_directory(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc;
+ DWORD status;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%4.s",
+ sr, &sr->arg.dirop.fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((status = smb_validate_dirname(sr->arg.dirop.fqi.path)) != 0) {
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_raise_nt_error(sr, status);
+ else
+ smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_NAME);
+
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_common_create_directory(sr)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (smb_encode_mbc(&xa->rep_param_mb, "w", 0) < 0)
+ smbsr_encode_error(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
new file mode 100644
index 0000000000..2afbcc6786
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * trans2_get_dfs_referral
+ *
+ * The client sends this request to ask the server to convert
+ * RequestFilename into an alternate name for this file. This request can
+ * be sent to the server if the server response to the NEGOTIATE SMB
+ * included the CAP_DFS capability. The TID of the request must be IPC$.
+ * Bit15 of Flags2 in the SMB header must be set, indicating this is a
+ * UNICODE request.
+ *
+ * Client Request Description
+ * ========================== =========================================
+ * WordCount 15
+ * TotalDataCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_GET_DFS_REFERRAL
+ *
+ * Parameter Block Encoding Description
+ * ========================== =========================================
+ * USHORT MaxReferralLevel Latest referral version number understood
+ * WCHAR RequestFileName; DFS name of file for which referral is
+ * sought
+ *
+ * Response Data Block Description
+ * ========================== =========================================
+ * USHORT PathConsumed; Number of RequestFilename bytes client
+ * USHORT NumberOfReferrals; Number of referrals contained in this
+ * response
+ * USHORT Flags; bit0 - The servers in Referrals are
+ * capable of fielding
+ * TRANS2_GET_DFS_REFERRAL.
+ * bit1 - The servers in Referrals should
+ * hold the storage for the requested file.
+ * REFERRAL_LIST Referrals[] Set of referrals for this file
+ * UNICODESTRINGE Strings Used to hold the strings pointed to by
+ * Version 2 Referrals in REFERRALS.
+ *
+ * The server response is a list of Referrals which inform the client where
+ * it should resubmit the request to obtain access to the file.
+ * PathConsumed in the response indicates to the client how many characters
+ * of RequestFilename have been consumed by the server. When the client
+ * chooses one of the referrals to use for file access, the client may need
+ * to strip the leading PathConsumed characters from the front of
+ * RequestFileName before submitting the name to the target server.
+ * Whether or not the pathname should be trimmed is indicated by the
+ * individual referral as detailed below.
+ *
+ * Flags indicates how this referral should be treated. If bit0 is clear,
+ * any entity in the Referrals list holds the storage for RequestFileName.
+ * If bit0 is set, any entity in the Referrals list has further referral
+ * information for RequestFilename – a TRANS2_GET_DFS_REFERRAL request
+ * should be sent to an entity in the Referrals list for further
+ * resolution.
+ *
+ * The format of an individual referral contains version and length
+ * information allowing the client to skip referrals it does not
+ * understand. MaxReferralLevel indicates to the server the latest version
+ * of referral which the client can digest. Since each referral has a
+ * uniform element, MaxReferralLevel is advisory only. Each element in
+ * Referrals has this envelope:
+ *
+ * REFERRAL_LIST element
+ * ======================================================================
+ *
+ * USHORT VersionNumber Version of this referral element
+ *
+ * USHORT ReferralSize Size of this referral element
+ *
+ * The following referral element versions are defined:
+ *
+ * Version 1 Referral Element Format
+ * ======================================================================
+ *
+ * USHORT ServerType Type of Node handling referral:
+ * 0 - Don't know
+ * 1 - SMB Server
+ * 2 - Netware Server
+ * 3 - Domain
+ *
+ * USHORT ReferralFlags Flags which describe this referral:
+ * 01 - Strip off PathConsumed characters
+ * before submitting RequestFileName to Node
+ *
+ * UNICODESTRING Node Name of entity to visit next
+ *
+ * Version 2 Referral Element Format
+ * ======================================================================
+ *
+ * USHORT ServerType Type of Node handling referral:
+ * 0 - Don't know
+ * 1 - SMB Server
+ * 2 - Netware Server
+ * 3 - Domain
+ *
+ * USHORT ReferralFlags Flags which describe this referral:
+ * 01 - Strip off PathConsumed characters
+ * before submitting RequestFileName to
+ * Node
+ *
+ * ULONG Proximity A hint describing the proximity of this
+ * server to the client. 0 indicates the
+ * closest, higher numbers indicate
+ * increasingly "distant" servers. The
+ * number is only relevant within the
+ * context of the servers listed in this
+ * particular SMB.
+ *
+ * ULONG TimeToLive Number of seconds for which the client
+ * can cache this referral.
+ *
+ * USHORT DfsPathOffset Offset, in bytes from the beginning of
+ * this referral, of the DFS Path that
+ * matched PathConsumed bytes of the
+ * RequestFileName.
+ *
+ * USHORT DfsAlternatePathOffset Offset, in bytes from the beginning of
+ * this referral, of an alternate name
+ * (8.3 format) of the DFS Path that
+ * matched PathConsumed bytes of the
+ * RequestFileName.
+ *
+ * USHORT NetworkAddressOffset Offset, in bytes from the beginning of
+ * this referral, of the entity to visit
+ * next.
+ *
+ * The CIFS protocol imposes no referral selection policy.
+ */
+int /*ARGSUSED*/
+smb_com_trans2_get_dfs_referral(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * SMB: trans2_report_dfs_inconsistency
+ *
+ * As part of the Distributed Name Resolution algorithm, a DFS client may
+ * discover a knowledge inconsistency between the referral server (i.e.,
+ * the server that handed out a referral), and the storage server (i.e.,
+ * the server to which the client was redirected to by the referral
+ * server). When such an inconsistency is discovered, the DFS client
+ * optionally sends this SMB to the referral server, allowing the referral
+ * server to take corrective action.
+ *
+ * Client Request Description
+ * ================================== ==================================
+ * WordCount 15
+ * MaxParameterCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_REPORT_DFS_INCONSISTENCY
+ *
+ * Parameter Block Encoding Description
+ * ================================== ==================================
+ *
+ * UNICODESTRING RequestFileName; DFS Name of file for which
+ * referral was sought
+ *
+ * The data part of this request contains the referral element (Version 1
+ * format only) believed to be in error. These are encoded as described in
+ * the TRANS2_GET_DFS_REFERRAL response. If the server returns success,
+ * the client can resubmit the TRANS2_GET_DFS_REFERRAL request to this
+ * server to get a new referral. It is not mandatory for the DFS knowledge
+ * to be automatically repaired – the client must be prepared to receive
+ * further errant referrals and must not wind up looping between this
+ * request and the TRANS2_GET_DFS_REFERRAL request.
+ *
+ * Bit15 of Flags2 in the SMB header must be set, indicating this is a
+ * UNICODE request.
+ */
+int /*ARGSUSED*/
+smb_com_trans2_report_dfs_inconsistency(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
new file mode 100644
index 0000000000..3ab7076102
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
@@ -0,0 +1,1142 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides functions for TRANS2_FIND_FIRST2 and
+ * TRANS2_FIND_NEXT2 requests. The requests allow the client to search
+ * for the file(s) which match the file specification. The search is
+ * started with TRANS2_FIND_FIRST2 and can be continued if necessary with
+ * TRANS2_FIND_NEXT2. There are numerous levels of information which may be
+ * obtained for the returned files, the desired level is specified in the
+ * InformationLevel field of the requests.
+ *
+ * InformationLevel Name Value
+ * ================================= ================
+ *
+ * SMB_INFO_STANDARD 1
+ * SMB_INFO_QUERY_EA_SIZE 2
+ * SMB_INFO_QUERY_EAS_FROM_LIST 3
+ * SMB_FIND_FILE_DIRECTORY_INFO 0x101
+ * SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
+ * SMB_FIND_FILE_NAMES_INFO 0x103
+ * SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
+ *
+ * The following sections detail the data returned for each
+ * InformationLevel. The requested information is placed in the Data
+ * portion of the transaction response. Note: a client which does not
+ * support long names can only request SMB_INFO_STANDARD.
+ *
+ * A four-byte resume key precedes each data item (described below) if bit
+ * 2 in the Flags field is set, i.e. if the request indicates the server
+ * should return resume keys. Note: it is not always the case. If the
+ * data item already includes the resume key, the resume key should not be
+ * added again.
+ *
+ * 4.3.4.1 SMB_INFO_STANDARD
+ *
+ * Response Field Description
+ * ================================ ==================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation unit
+ * USHORT Attributes; File Attributes
+ * UCHAR FileNameLength; Length of filename in bytes
+ * STRING FileName; Name of found file
+ *
+ * 4.3.4.2 SMB_INFO_QUERY_EA_SIZE
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation unit
+ * USHORT Attributes; File Attributes
+ * ULONG EaSize; Size of file's EA information
+ * UCHAR FileNameLength; Length of filename in bytes
+ * STRING FileName; Name of found file
+ *
+ * 4.3.4.3 SMB_INFO_QUERY_EAS_FROM_LIST
+ *
+ * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but
+ * only for files which have an EA list which match the EA information in
+ * the Data part of the request.
+ *
+ * 4.3.4.4 SMB_FIND_FILE_DIRECTORY_INFO
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * ULONG NextEntryOffset; Offset from this structure to
+ * beginning of next one
+ * ULONG FileIndex;
+ * LARGE_INTEGER CreationTime; file creation time
+ * LARGE_INTEGER LastAccessTime; last access time
+ * LARGE_INTEGER LastWriteTime; last write time
+ * LARGE_INTEGER ChangeTime; last attribute change time
+ * LARGE_INTEGER EndOfFile; file size
+ * LARGE_INTEGER AllocationSize; size of filesystem allocation information
+ * ULONG ExtFileAttributes; Extended file attributes
+ * (see section 3.11)
+ * ULONG FileNameLength; Length of filename in bytes
+ * STRING FileName; Name of the file
+ *
+ * 4.3.4.5 SMB_FIND_FILE_FULL_DIRECTORY_INFO
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * ULONG NextEntryOffset; Offset from this structure to
+ * beginning of next one
+ * ULONG FileIndex;
+ * LARGE_INTEGER CreationTime; file creation time
+ * LARGE_INTEGER LastAccessTime; last access time
+ * LARGE_INTEGER LastWriteTime; last write time
+ * LARGE_INTEGER ChangeTime; last attribute change time
+ * LARGE_INTEGER EndOfFile; file size
+ * LARGE_INTEGER AllocationSize; size of filesystem allocation information
+ * ULONG ExtFileAttributes; Extended file attributes
+ * (see section 3.11)
+ * ULONG FileNameLength; Length of filename in bytes
+ * ULONG EaSize; Size of file's extended attributes
+ * STRING FileName; Name of the file
+ *
+ * 4.3.4.6 SMB_FIND_FILE_BOTH_DIRECTORY_INFO
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * ULONG NextEntryOffset; Offset from this structure to
+ * beginning of next one
+ * ULONG FileIndex;
+ * LARGE_INTEGER CreationTime; file creation time
+ * LARGE_INTEGER LastAccessTime; last access time
+ * LARGE_INTEGER LastWriteTime; last write time
+ * LARGE_INTEGER ChangeTime; last attribute change time
+ * LARGE_INTEGER EndOfFile; file size
+ * LARGE_INTEGER AllocationSize; size of filesystem allocation information
+ * ULONG ExtFileAttributes; Extended file attributes
+ * (see section 3.11)
+ * ULONG FileNameLength; Length of FileName in bytes
+ * ULONG EaSize; Size of file's extended attributes
+ * UCHAR ShortNameLength; Length of file's short name in bytes
+ * UCHAR Reserved
+ * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode
+ * STRING FileName; Files full length name
+ *
+ * 4.3.4.7 SMB_FIND_FILE_NAMES_INFO
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * ULONG NextEntryOffset; Offset from this structure to
+ * beginning of next one
+ * ULONG FileIndex;
+ * ULONG FileNameLength; Length of FileName in bytes
+ * STRING FileName; Files full length name
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/msgbuf.h>
+#include <smbsrv/smbtrans.h>
+#include <smbsrv/smb_fsops.h>
+
+int smb_trans2_find_get_maxdata(struct smb_request *, unsigned short,
+ unsigned short);
+
+int smb_trans2_find_get_dents(struct smb_request *, struct smb_xa *,
+ unsigned short, unsigned short, int, struct smb_node *,
+ unsigned short, uint32_t, int, char *, uint32_t *, int *, int *);
+
+int smb_gather_dents_info(char *, ino_t, int, char *, uint32_t, int32_t *,
+ smb_attr_t *, struct smb_node *, char *, char *);
+
+int smb_trans2_find_process_ients(struct smb_request *, struct smb_xa *,
+ smb_dent_info_hdr_t *, unsigned short, unsigned short, int,
+ struct smb_node *, int *, uint32_t *);
+
+int smb_trans2_find_mbc_encode(struct smb_request *, struct smb_xa *,
+ smb_dent_info_t *, int, unsigned short, unsigned short,
+ unsigned int, struct smb_node *, struct smb_node *);
+
+/*
+ * Support for Catia Version 5 Deployment
+ */
+static int (*catia_callback)(unsigned char *, unsigned char *, int) = NULL;
+void smb_register_catia_callback(
+ int (*catia_v4tov5)(unsigned char *, unsigned char *, int));
+void smb_unregister_catia_callback();
+
+/*
+ * Patchable parameter for find maximum count
+ */
+int max_find_count = 64;
+
+/*
+ * smb_register_catia_callback
+ *
+ * This function will be invoked by the catia module to register its
+ * function that translates filename in version 4 to a format that is
+ * compatible to version 5.
+ */
+void
+smb_register_catia_callback(
+ int (*catia_v4tov5)(unsigned char *, unsigned char *, int))
+{
+ catia_callback = catia_v4tov5;
+}
+
+/*
+ * smb_unregister_catia_callback
+ *
+ * This function will unregister the catia callback prior to the catia
+ * module gets unloaded.
+ */
+void
+smb_unregister_catia_callback()
+{
+ catia_callback = 0;
+}
+
+/*
+ * smb_com_trans2_find_first2
+ *
+ * Client Request Value
+ * ============================ ==================================
+ *
+ * UCHAR WordCount 15
+ * UCHAR TotalDataCount Total size of extended attribute list
+ * UCHAR SetupCount 1
+ * UCHAR Setup[0] TRANS2_FIND_FIRST2
+ *
+ * Parameter Block Encoding Description
+ * ============================ ==================================
+ * USHORT SearchAttributes;
+ * USHORT SearchCount; Maximum number of entries to return
+ * USHORT Flags; Additional information:
+ * Bit 0 - close search after this request
+ * Bit 1 - close search if end of search
+ * reached
+ * Bit 2 - return resume keys for each
+ * entry found
+ * Bit 3 - continue search from previous
+ * ending place
+ * Bit 4 - find with backup intent
+ * USHORT InformationLevel; See below
+ * ULONG SearchStorageType;
+ * STRING FileName; Pattern for the search
+ * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is
+ * QUERY_EAS_FROM_LIST
+ *
+ * Response Parameter Block Description
+ * ============================ ==================================
+ *
+ * USHORT Sid; Search handle
+ * USHORT SearchCount; Number of entries returned
+ * USHORT EndOfSearch; Was last entry returned?
+ * USHORT EaErrorOffset; Offset into EA list if EA error
+ * USHORT LastNameOffset; Offset into data to file name of last
+ * entry, if server needs it to resume
+ * search; else 0
+ * UCHAR Data[ TotalDataCount ] Level dependent info about the matches
+ * found in the search
+ */
+int
+smb_com_trans2_find_first2(struct smb_request *sr, struct smb_xa *xa)
+{
+ int more = 0, rc;
+ unsigned short sattr, fflag, infolev;
+ int maxdata;
+ int count, maxcount = 0, wildcards;
+ uint32_t cookie;
+ char *path;
+ struct smb_node *dir_snode;
+ char *pattern;
+ unsigned short sid;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%wwww4.u", sr,
+ &sattr, &maxcount, &fflag, &infolev, &path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
+
+ if (maxdata == 0) {
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ }
+
+ /* Convert name to our form */
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) {
+ (void) smb_convert_unicode_wildcards(path);
+ }
+ (void) smb_rdir_open(sr, path, sattr);
+
+ /*
+ * Get a copy of information
+ */
+ pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ dir_snode = sr->sid_odir->d_dir_snode;
+ (void) strcpy(pattern, sr->sid_odir->d_pattern);
+ /* this is funky */
+ if (strcmp(pattern, "*.*") == 0)
+ (void) strncpy(pattern, "*", sizeof (pattern));
+ wildcards = sr->sid_odir->d_wildcards;
+ sattr = sr->sid_odir->d_sattr;
+ cookie = 0;
+
+ rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
+ dir_snode, sattr, maxcount, wildcards,
+ pattern, &cookie, &more, &count);
+
+ if (!count)
+ rc = ENOENT;
+
+ if (rc) {
+ smb_rdir_close(sr);
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Save the sid here because search might get closed
+ * and sr->smb_sid becomes invalid.
+ * This might not seem important because the search
+ * is going to be finished anyways, but it's just for
+ * the sake of compatibility with Windows.
+ */
+ sid = sr->smb_sid;
+
+ if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
+ (!more && fflag & SMB_FIND_CLOSE_AT_EOS))
+ smb_rdir_close(sr);
+ else {
+ mutex_enter(&sr->sid_odir->d_mutex);
+ sr->sid_odir->d_cookie = cookie;
+ mutex_exit(&sr->sid_odir->d_mutex);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwwww",
+ sid, count, (more ? 0 : 1), 0, 0);
+
+ kmem_free(pattern, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+
+/*
+ * smb_com_trans2_find_next2
+ *
+ * Client Request Value
+ * ================================== =================================
+ *
+ * WordCount 15
+ * SetupCount 1
+ * Setup[0] TRANS2_FIND_NEXT2
+ *
+ * Parameter Block Encoding Description
+ * ================================== =================================
+ *
+ * USHORT Sid; Search handle
+ * USHORT SearchCount; Maximum number of entries to
+ * return
+ * USHORT InformationLevel; Levels described in
+ * TRANS2_FIND_FIRST2 request
+ * ULONG ResumeKey; Value returned by previous find2
+ * call
+ * USHORT Flags; Additional information: bit set-
+ * 0 - close search after this
+ * request
+ * 1 - close search if end of search
+ * reached
+ * 2 - return resume keys for each
+ * entry found
+ * 3 - resume/continue from previous
+ * ending place
+ * 4 - find with backup intent
+ * STRING FileName; Resume file name
+ *
+ * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
+ * call. If Bit3 of Flags is set, then FileName may be the NULL string,
+ * since the search is continued from the previous TRANS2_FIND request.
+ * Otherwise, FileName must not be more than 256 characters long.
+ *
+ * Response Field Description
+ * ================================== =================================
+ *
+ * USHORT SearchCount; Number of entries returned
+ * USHORT EndOfSearch; Was last entry returned?
+ * USHORT EaErrorOffset; Offset into EA list if EA error
+ * USHORT LastNameOffset; Offset into data to file name of
+ * last entry, if server needs it to
+ * resume search; else 0
+ * UCHAR Data[TotalDataCount] Level dependent info about the
+ * matches found in the search
+ */
+int
+smb_com_trans2_find_next2(struct smb_request *sr, struct smb_xa *xa)
+{
+ unsigned short fflag, infolev;
+ int maxdata, count, wildcards, more = 0, rc;
+ uint32_t cookie;
+ uint32_t maxcount = 0;
+ struct smb_node *dir_snode;
+ char *pattern;
+ unsigned short sattr;
+
+ pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ /*
+ * There is a path field as the last piece of input information:
+ *
+ * smb_decode_mbc(&xa->req_param_mb, "%www lwu", sr,
+ * &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &path)
+ *
+ * This feild has been removed because it's causing problem
+ * with Mac OS 10 and it's not used anyways.
+ * The problem is that code expects to see a 2-byte null
+ * because the strings are supposed to be Unicode, but
+ * Max OS 10 sends a 1-byte null which leads to decode error.
+ */
+ if (smb_decode_mbc(&xa->req_param_mb, "%www lw", sr,
+ &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) {
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (maxdata == 0) {
+ smb_rdir_close(sr);
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Get a copy of information
+ */
+ dir_snode = sr->sid_odir->d_dir_snode;
+ (void) strcpy(pattern, sr->sid_odir->d_pattern);
+ wildcards = sr->sid_odir->d_wildcards;
+ sattr = sr->sid_odir->d_sattr;
+ if (fflag & SMB_FIND_CONTINUE_FROM_LAST) {
+ mutex_enter(&sr->sid_odir->d_mutex);
+ cookie = sr->sid_odir->d_cookie;
+ mutex_exit(&sr->sid_odir->d_mutex);
+ }
+
+ /*
+ * XXX this is an optimization made for SFS2 filesystem, it might
+ * not be required for ZFS
+ *
+ * Break the count to smaller counts (less than the default 150)
+ * to reduce the number of transaction failures
+ * which may cause excessive delays and eventually a SMB staled
+ * connection.
+ */
+ maxcount = (maxcount > max_find_count) ? max_find_count : maxcount;
+
+ rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
+ dir_snode, sattr, maxcount, wildcards, pattern, &cookie,
+ &more, &count);
+
+ if (rc) {
+ smb_rdir_close(sr);
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
+ (!more && fflag & SMB_FIND_CLOSE_AT_EOS))
+ smb_rdir_close(sr);
+ else {
+ mutex_enter(&sr->sid_odir->d_mutex);
+ sr->sid_odir->d_cookie = cookie;
+ mutex_exit(&sr->sid_odir->d_mutex);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
+ count, (more ? 0 : 1), 0, 0);
+
+ kmem_free(pattern, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_trans2_find_get_maxdata
+ *
+ * This function calculates the minimum space requirement for the
+ * base on information level and fflag.
+ *
+ * When success, minimum space requirement will be returned; otherwise,
+ * 0 will be returned.
+ */
+int
+smb_trans2_find_get_maxdata(
+ struct smb_request *sr,
+ unsigned short infolev,
+ unsigned short fflag)
+{
+ int maxdata;
+
+ maxdata = smb_ascii_or_unicode_null_len(sr);
+
+ switch (infolev) {
+ case SMB_INFO_STANDARD :
+ if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+ maxdata += sizeof (int32_t);
+ maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+ maxdata += sizeof (int32_t);
+ maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ maxdata += 4 + 4 + 4;
+ break;
+
+ case SMB_MAC_FIND_BOTH_HFS_INFO:
+ maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 +
+ 4 + 32 + 4 + 1 + 1 + 24 + 4;
+ break;
+
+ default:
+ maxdata = 0;
+ }
+
+ return (maxdata);
+}
+
+
+
+/*
+ * smb_trans2_find_get_dents
+ *
+ * This function will get all the directory entry information and mbc
+ * encode it in the xa. If there is an error, it will be returned;
+ * otherwise, 0 is returned.
+ *
+ * The more field will be updated. If the value returned is one, it means
+ * there are more entries; otherwise, the returned value will be zero. The
+ * cookie will also be updated to indicate the next start point for the
+ * search. The count value will also be updated to stores the total entries
+ * encoded.
+ */
+int smb_trans2_find_get_dents(
+ smb_request_t *sr,
+ smb_xa_t *xa,
+ unsigned short fflag,
+ unsigned short infolev,
+ int maxdata,
+ smb_node_t *dir_snode,
+ unsigned short sattr,
+ uint32_t maxcount,
+ int wildcards,
+ char *pattern,
+ uint32_t *cookie,
+ int *more,
+ int *count)
+{
+ smb_dent_info_hdr_t *ihdr;
+ smb_dent_info_t *ient;
+ int dent_buf_size;
+ int i;
+ int total;
+ int maxentries;
+ int rc;
+
+ ihdr = kmem_zalloc(sizeof (smb_dent_info_hdr_t), KM_SLEEP);
+ *count = 0;
+
+ if (!wildcards)
+ maxentries = maxcount = 1;
+ else {
+ maxentries = (xa->rep_data_mb.max_bytes -
+ xa->rep_data_mb.chain_offset) / maxdata;
+ if (maxcount > SMB_MAX_DENTS_IOVEC)
+ maxcount = SMB_MAX_DENTS_IOVEC;
+ if (maxentries > maxcount)
+ maxentries = maxcount;
+ }
+
+ /* Each entry will need to be aligned so add _POINTER_ALIGNMENT */
+ dent_buf_size =
+ maxentries * (SMB_MAX_DENT_INFO_SIZE + _POINTER_ALIGNMENT);
+ ihdr->iov->iov_base = kmem_alloc(dent_buf_size, KM_SLEEP);
+
+ ihdr->sattr = sattr;
+ ihdr->pattern = pattern;
+ ihdr->sr = sr;
+
+ ihdr->uio.uio_iovcnt = maxcount;
+ ihdr->uio.uio_resid = dent_buf_size;
+ ihdr->uio.uio_iov = ihdr->iov;
+ ihdr->uio.uio_offset = 0;
+
+ rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more);
+ if (rc != 0) {
+ goto out;
+ }
+
+ if (ihdr->iov->iov_len == 0)
+ *count = 0;
+ else
+ *count = smb_trans2_find_process_ients(sr, xa, ihdr, fflag,
+ infolev, maxdata, dir_snode, more, cookie);
+ rc = 0;
+
+out:
+
+ total = maxcount - ihdr->uio.uio_iovcnt;
+ ASSERT((total >= 0) && (total <= SMB_MAX_DENTS_IOVEC));
+ for (i = 0; i < total; i++) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ient = (smb_dent_info_t *)ihdr->iov[i].iov_base;
+ ASSERT(ient);
+ smb_node_release(ient->snode);
+ }
+
+ kmem_free(ihdr->iov->iov_base, dent_buf_size);
+ kmem_free(ihdr, sizeof (smb_dent_info_hdr_t));
+ return (0);
+}
+
+
+
+/*
+ * smb_get_dents
+ *
+ * This function utilizes "smb_fsop_getdents()" to get dir entries.
+ * The "smb_gather_dents_info()" is the call back function called
+ * inside the file system. It is very important that the function
+ * does not sleep or yield since it is processed inside a file
+ * system transaction.
+ *
+ * The function returns 0 when successful and error code when failed.
+ * If more is provided, the return value of 1 is returned indicating
+ * more entries; otherwise, 0 is returned.
+ */
+int smb_get_dents(
+ smb_request_t *sr,
+ uint32_t *cookie,
+ smb_node_t *dir_snode,
+ unsigned int wildcards,
+ smb_dent_info_hdr_t *ihdr,
+ int *more)
+{
+ int rc;
+ char *namebuf;
+ smb_node_t *snode;
+ smb_attr_t file_attr;
+ uint32_t maxcnt = ihdr->uio.uio_iovcnt;
+ char shortname[MANGLE_NAMELEN], name83[MANGLE_NAMELEN];
+ fsvol_attr_t vol_attr;
+
+ namebuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+ if (more)
+ *more = 0;
+
+ if ((rc = fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr)) != 0) {
+ kmem_free(namebuf, MAXNAMELEN);
+ return (rc);
+ }
+
+ if (!wildcards) {
+ /* Already found entry? */
+ if (*cookie != 0)
+ return (0);
+ shortname[0] = '\0';
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
+ dir_snode, ihdr->pattern, &snode, &file_attr, shortname,
+ name83);
+
+ if (rc) {
+ kmem_free(namebuf, MAXNAMELEN);
+ return (rc);
+ }
+
+ (void) strlcpy(namebuf, ihdr->pattern, MAXNAMELEN);
+
+ /*
+ * It is not necessary to set the "force" flag (i.e. to
+ * take into account mangling for case-insensitive collisions)
+ */
+
+ if (shortname[0] == '\0')
+ (void) smb_mangle_name(snode->attr.sa_vattr.va_nodeid,
+ namebuf, shortname, name83, 0);
+ (void) smb_gather_dents_info((char *)ihdr,
+ snode->attr.sa_vattr.va_nodeid,
+ strlen(namebuf), namebuf, -1, (int *)&maxcnt,
+ &snode->attr, snode, shortname, name83);
+ kmem_free(namebuf, MAXNAMELEN);
+ return (0);
+ }
+
+ if ((rc = smb_fsop_getdents(sr, sr->user_cr, dir_snode, cookie,
+ 0, (int *)&maxcnt, (char *)ihdr, ihdr->pattern)) != 0) {
+ if (rc == ENOENT) {
+ kmem_free(namebuf, MAXNAMELEN);
+ return (0);
+ }
+ kmem_free(namebuf, MAXNAMELEN);
+ return (rc);
+ }
+
+ if (*cookie != 0x7FFFFFFF && more)
+ *more = 1;
+
+ kmem_free(namebuf, MAXNAMELEN);
+ return (0);
+}
+
+
+
+
+/*
+ * smb_gather_dents_info
+ *
+ * The function will accept information of each directory entry and put
+ * the needed information in the buffer. It is passed as the call back
+ * function for smb_fsop_getdents() to gather trans2 find info.
+ *
+ * If the buffer space is not enough, -1 will be returned. Regardless
+ * of valid entry or not, 0 will be returned; however, only valid entry
+ * will be stored in the buffer.
+ */
+int /*ARGSUSED*/
+smb_gather_dents_info(
+ char *args,
+ ino_t fileid,
+ int namelen,
+ char *name,
+ uint32_t cookie,
+ int32_t *countp,
+ smb_attr_t *attr,
+ smb_node_t *snode,
+ char *shortname,
+ char *name83)
+{
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)args;
+ smb_dent_info_t *ient;
+ unsigned char *v5_name = NULL;
+ unsigned char *np = (unsigned char *)name;
+ int reclen = sizeof (smb_dent_info_t) + namelen;
+
+ v5_name = kmem_alloc(MAXNAMELEN-1, KM_SLEEP);
+
+ if (!ihdr->uio.uio_iovcnt || ihdr->uio.uio_resid < reclen) {
+ kmem_free(v5_name, MAXNAMELEN-1);
+ smb_node_release(snode);
+ return (-1);
+ }
+
+ if (!smb_sattr_check(attr, name, ihdr->sattr)) {
+ kmem_free(v5_name, MAXNAMELEN-1);
+ smb_node_release(snode);
+ return (0);
+ }
+
+ /*
+ * If StorEdge is configured to support Catia Version 5 deployments,
+ * any directory entry whose name contains the special Unix character
+ * that is considered to be illegal in Windows environement will be
+ * translated based on the following
+ * Special Character Translation Table.
+ *
+ * ---------------------------
+ * Unix-char | Windows-char
+ * ---------------------------
+ * " | (0x00a8) Diaeresis
+ * * | (0x00a4) Currency Sign
+ * : | (0x00f7) Division Sign
+ * < | (0x00ab) Left-Pointing Double Angle Quotation Mark
+ * > | (0x00bb) Right-Pointing Double Angle Quotation Mark
+ * ? | (0x00bf) Inverted Question mark
+ * \ | (0x00ff) Latin Small Letter Y with Diaeresis
+ * | | (0x00a6) Broken Bar
+ */
+ if (catia_callback) {
+ /* XXX 255 should be max name len or something */
+ catia_callback(v5_name, (unsigned char *)name, 255);
+ np = v5_name;
+ reclen = sizeof (smb_dent_info_t) + strlen((char *)v5_name);
+ }
+
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ /*
+ * Each entry needs to be properly aligned or we may get an alignment
+ * fault on sparc.
+ */
+ ihdr->uio.uio_offset = (off_t)PTRALIGN(ihdr->uio.uio_offset);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_offset];
+
+ ient->cookie = cookie;
+ ient->attr = *attr;
+ ient->snode = snode;
+
+ (void) strcpy(ient->name, (char *)np);
+ (void) strcpy(ient->shortname, shortname);
+ (void) strcpy(ient->name83, name83);
+ ihdr->uio.uio_iov->iov_base = (char *)ient;
+ ihdr->uio.uio_iov->iov_len = reclen;
+
+ ihdr->uio.uio_iov++;
+ ihdr->uio.uio_iovcnt--;
+ ihdr->uio.uio_resid -= reclen;
+ ihdr->uio.uio_offset += reclen;
+
+ kmem_free(v5_name, MAXNAMELEN-1);
+ return (0);
+}
+
+
+
+/*
+ * smb_trans2_find_process_ients
+ *
+ * This function encodes the directory entry information store in
+ * the iov structure of the ihdr structure.
+ *
+ * The total entries encoded will be returned. If the entries encoded
+ * is less than the total entries in the iov, the more field will
+ * be updated to 1. Also, the next cookie wil be updated as well.
+ */
+int
+smb_trans2_find_process_ients(
+ struct smb_request *sr,
+ struct smb_xa *xa,
+ smb_dent_info_hdr_t *ihdr,
+ unsigned short fflag,
+ unsigned short infolev,
+ int maxdata,
+ struct smb_node *dir_snode,
+ int *more,
+ uint32_t *cookie)
+{
+ int i, err = 0;
+ smb_dent_info_t *ient;
+ uint32_t mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
+ ? SMB_MSGBUF_UNICODE : 0;
+
+ for (i = 0; i < SMB_MAX_DENTS_IOVEC; i++) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ if ((ient = (smb_dent_info_t *)ihdr->iov[i].iov_base) == 0)
+ break;
+
+ /*
+ * FYI: Some observed differences between our response and
+ * Windows response which hasn't caused problem yet!
+ *
+ * 1. The NextEntryOffset field for the last entry should be 0
+ * This code always calculate the record length and put the
+ * result in this field.
+ *
+ * 2. The FileIndex field is always 0. This code put the cookie
+ * in this field.
+ */
+ err = smb_trans2_find_mbc_encode(sr, xa, ient, maxdata, infolev,
+ fflag, mb_flags, dir_snode, NULL);
+
+ if (err)
+ break;
+ }
+
+ /*
+ * Not enough space to store all the entries returned; therefore,
+ * update the more to 1.
+ */
+ if (more && err < 0) {
+ *more = 1;
+
+ /*
+ * Assume the space will be at least enough for 1 entry.
+ */
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ient = (smb_dent_info_t *)ihdr->iov[i-1].iov_base;
+ *cookie = ient->cookie;
+ }
+ return (i);
+}
+
+
+
+/*
+ * smb_trans2_find_mbc_encode
+ *
+ * This function encodes the mbc for one directory entry.
+ *
+ * The function returns -1 when the max data requested by client
+ * is reached. If the entry is valid and successful encoded, 0
+ * will be returned; otherwise, 1 will be returned.
+ */
+int smb_trans2_find_mbc_encode(
+ struct smb_request *sr,
+ struct smb_xa *xa,
+ smb_dent_info_t *ient,
+ int maxdata,
+ unsigned short infolev,
+ unsigned short fflag,
+ unsigned int mb_flags,
+ struct smb_node *dir_snode, /*LINTED E_FUNC_ARG_UNUSED*/
+ struct smb_node *sd_snode)
+{
+ int uni_namelen;
+ int sl, rl;
+ char buf83[26];
+ smb_msgbuf_t mb;
+ uint32_t dattr = 0;
+ uint32_t size32 = 0;
+ uint64_t size64 = 0;
+ struct smb_node *lnk_snode;
+ smb_attr_t lnkattr;
+ int rc;
+
+ uni_namelen = smb_ascii_or_unicode_strlen(sr, ient->name);
+
+ if (uni_namelen == -1)
+ return (1);
+
+ if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + uni_namelen)) == 0)
+ return (-1);
+
+ if (ient->attr.sa_vattr.va_type == VLNK) {
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_snode, ient->name, &lnk_snode,
+ &lnkattr, 0, 0);
+
+ /*
+ * IR 104598
+ *
+ * We normally want to resolve the object to which a symlink
+ * refers so that CIFS clients can access sub-directories and
+ * find the correct association for files. This causes a
+ * problem, however, if a symlink in a sub-directory points
+ * to a parent directory (some UNIX GUI's create a symlink in
+ * $HOME/.desktop that points to the user's home directory).
+ * Some Windows applications (i.e. virus scanning) loop/hang
+ * trying to follow this recursive path and there is little
+ * we can do because the path is constructed on the client.
+ * So we've added a flag that allows an end-user to disable
+ * symlinks to directories. Symlinks to other object types
+ * should be unaffected.
+ */
+ if (rc == 0) {
+ if (smb_info.si.skc_dirsymlink_enable ||
+ (lnkattr.sa_vattr.va_type != VDIR)) {
+ smb_node_release(ient->snode);
+ ient->snode = lnk_snode;
+ ient->attr = lnkattr;
+ } else {
+ smb_node_release(lnk_snode);
+ }
+ }
+ }
+
+ if (infolev != SMB_FIND_FILE_NAMES_INFO) {
+ size64 = smb_node_get_size(ient->snode, &ient->attr);
+ size32 = (size64 > 0xFFFFFFFF) ? 0xFFFFFFFF : (uint32_t)size64;
+ dattr = smb_mode_to_dos_attributes(&ient->attr);
+ }
+
+ /*
+ * we don't send the '.stream' to client. User shouldn't
+ * see this directory.
+ */
+ switch (infolev) {
+ case SMB_INFO_STANDARD:
+ if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l",
+ ient->cookie);
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwbu", sr,
+ ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec :
+ ient->attr.sa_vattr.va_mtime.tv_sec,
+ ient->attr.sa_vattr.va_atime.tv_sec,
+ ient->attr.sa_vattr.va_mtime.tv_sec,
+ size32,
+ size32,
+ dattr,
+ uni_namelen,
+ ient->name);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ "l", ient->cookie);
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwlbu", sr,
+ ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec :
+ ient->attr.sa_vattr.va_mtime.tv_sec,
+ ient->attr.sa_vattr.va_atime.tv_sec,
+ ient->attr.sa_vattr.va_mtime.tv_sec,
+ size32,
+ size32,
+ dattr,
+ 0L, /* EA Size */
+ uni_namelen,
+ ient->name);
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ /* Use maxdata instead */
+ rl = maxdata + uni_namelen;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%llTTTTqqllu", sr,
+ rl,
+ ient->cookie,
+ ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
+ &ient->attr.sa_vattr.va_mtime,
+ &ient->attr.sa_vattr.va_atime,
+ &ient->attr.sa_vattr.va_mtime,
+ &ient->attr.sa_vattr.va_ctime,
+ size64,
+ size64,
+ dattr,
+ uni_namelen,
+ ient->name);
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ /* Use maxdata instead */
+ rl = maxdata + uni_namelen;
+ bzero(buf83, sizeof (buf83));
+ smb_msgbuf_init(&mb, (unsigned char *)buf83, sizeof (buf83),
+ mb_flags);
+ if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) {
+ smb_msgbuf_term(&mb);
+ return (-1);
+ }
+ sl = smb_ascii_or_unicode_strlen(sr, ient->shortname);
+
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ "%llTTTTqqlllb.24cu", sr,
+ rl,
+ ient->cookie,
+ ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
+ &ient->attr.sa_vattr.va_mtime,
+ &ient->attr.sa_vattr.va_atime,
+ &ient->attr.sa_vattr.va_mtime,
+ &ient->attr.sa_vattr.va_ctime,
+ size64,
+ size64,
+ dattr,
+ uni_namelen,
+ 0L,
+ sl,
+ buf83,
+ ient->name);
+
+ smb_msgbuf_term(&mb);
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ rl = maxdata + uni_namelen;
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lllu", sr,
+ rl,
+ ient->cookie,
+ uni_namelen,
+ ient->name);
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Close a search started by a Trans2FindFirst2 request.
+ */
+int
+smb_com_find_close2(struct smb_request *sr)
+{
+ if (smbsr_decode_vwv(sr, "w", &sr->smb_sid) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ smb_rdir_close(sr);
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_open2.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_open2.c
new file mode 100644
index 0000000000..64fc11c3fc
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_open2.c
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_open2
+ *
+ * This transaction is used to open or create a file having extended
+ * attributes.
+ *
+ * Client Request Value
+ * ============================ =======================================
+ *
+ * WordCount 15
+ * TotalDataCount Total size of extended attribute list
+ * DataOffset Offset to extended attribute list in
+ * this request
+ * SetupCount 1
+ * Setup[0] TRANS2_OPEN2
+ *
+ * Parameter Block Encoding Description
+ * ============================ =======================================
+ *
+ * USHORT Flags; Additional information: bit set-
+ * 0 - return additional info
+ * 1 - exclusive oplock requested
+ * 2 - batch oplock requested
+ * 3 - return total length of EAs
+ * USHORT DesiredAccess; Requested file access
+ * USHORT Reserved1; Ought to be zero. Ignored by the
+ * server.
+ * USHORT FileAttributes; Attributes for file if create
+ * SMB_TIME CreationTime; Creation time to apply to file if
+ * create
+ * SMB_DATE CreationDate; Creation date to apply to file if
+ * create
+ * USHORT OpenFunction; Open function
+ * ULONG AllocationSize; Bytes to reserve on create or truncate
+ * USHORT Reserved [5]; Must be zero
+ * STRING FileName; Name of file to open or create
+ * UCHAR Data[ TotalDataCount ] FEAList structure for file to be
+ * created
+ *
+ * If secondary requests are required, they must contain 0 parameter bytes,
+ * and the Fid in the secondary request is 0xFFFF.
+ *
+ * DesiredAccess is encoded as described in the "Access Mode Encoding"
+ * section elsewhere in this document.
+ *
+ * FileAttributes are encoded as described in the "File Attribute Encoding"
+ * section elsewhere in this document.
+ *
+ * OpenFunction specifies the action to be taken depending on whether or
+ * not the file exists (see section 3.7) .
+ *
+ * Action in the response specifies the action as a result of this request
+ * (see section 3.8).
+ *
+ * Response Parameter Block Description
+ * ========================== =========================================
+ *
+ * USHORT Fid; File handle
+ * USHORT FileAttributes; Attributes of file
+ * SMB_TIME CreationTime; Last modification time
+ * SMB_DATE CreationDate; Last modification date
+ * ULONG DataSize; Current file size
+ * USHORT GrantedAccess; Access permissions actually allowed
+ * USHORT FileType; Type of file
+ * USHORT DeviceState; State of IPC device (e.g. pipe)
+ * USHORT Action; Action taken
+ * ULONG Reserved;
+ * USHORT EaErrorOffset; Offset into EA list if EA error
+ * ULONG EaLength; Total EA length for opened file
+ *
+ * FileType returns the kind of resource actually opened:
+ *
+ * Name Value Description
+ * ======================= ====== =====================================
+ *
+ * FileTypeDisk 0 Disk file or directory as defined in
+ * the attribute field
+ * FileTypeByteModePipe 1 Named pipe in byte mode
+ * FileTypeMessageModePipe 2 Named pipe in message mode
+ * FileTypePrinter 3 Spooled printer
+ * FileTypeUnknown 0xFFFF Unrecognized resource type
+ *
+ * DeviceState is applicable only if the FileType is FileTypeByteModePipe
+ * or FileTypeMessageModePipe and is encoded as in section 3.9.
+ *
+ * If an error was detected in the incoming EA list, the offset of the
+ * error is returned in EaErrorOffset.
+ *
+ * If bit0 of Flags in the request is clear, the FileAttributes,
+ * CreationTime, CreationDate, DataSize, GrantedAccess, FileType, and
+ * DeviceState have indeterminate values in the response. Similarly, if
+ *
+ * bit3 of the request is clear, EaLength in the response has an
+ * indeterminate value in the response.
+ *
+ * This SMB can request an oplock on the opened file. Oplocks are fully
+ * described in the "Oplocks" section elsewhere in this document, and there
+ * is also discussion of oplocks in the SMB_COM_LOCKING_ANDX SMB
+ * description. Bit1 and bit2 of the Flags field are used to request
+ * oplocks during open.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int /*ARGSUSED*/
+smb_com_trans2_open2(struct smb_request *sr)
+{
+ /* TODO: smb_com_trans2_open2 */
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
new file mode 100644
index 0000000000..2d488b7f2c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
@@ -0,0 +1,559 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_query_file_information
+ *
+ * This request is used to get information about a specific file or
+ * subdirectory given a handle to it.
+ *
+ * Client Request Value
+ * ========================== ==========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_QUERY_FILE_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ========================== ==========================================
+ *
+ * USHORT Fid; Handle of file for request
+ * USHORT InformationLevel; Level of information requested
+ *
+ * The available information levels, as well as the format of the response
+ * are identical to TRANS2_QUERY_PATH_INFORMATION.
+ */
+
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+uint32_t smb_pad_align(uint32_t offset, uint32_t align);
+
+
+/*
+ * smb_com_trans2_query_file_information
+ *
+ * Observation of Windows 2000 indicates the following:
+ *
+ * 1) If a file is opened with delete-on-close create options, the
+ * delete-on-close status returned by the Trans2QueryFileInfo will not
+ * be set. The delete-on-close status will only be set when the above
+ * file handle is closed.
+ *
+ * 2) If a file is not opened with delete-on-close create options but the
+ * delete-on-close is set via Trans2SetFileInfo/DispositionInfo, the
+ * delete-on-close status returned by Trans2QueryFileInfo will be set
+ * immediately.
+ */
+
+int
+smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ static smb_attr_t pipe_attr;
+ unsigned short infolev, dattr = 0;
+ off_t dsize = 0, dused = 0;
+ smb_attr_t *ap = NULL;
+ char *namep = NULL;
+ char *filename = NULL, *alt_nm_ptr = NULL;
+ int filename_len = 0;
+ struct smb_node *dir_snode = NULL;
+ timestruc_t *creation_time = NULL;
+ unsigned char delete_on_close = 0;
+ unsigned char is_dir = 0;
+ char *filebuf = NULL;
+
+ /*
+ * buffer for mangled name and shortname are allocated
+ * much higher than required space. Optimization
+ * here should be performed along with mangled_name & shortname
+ * of query path information.
+ */
+ char *mangled_name = 0;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "ww", &sr->smb_fid,
+ &infolev) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ switch (sr->fid_ofile->f_ftype) {
+ case SMB_FTYPE_DISK:
+ {
+ /*
+ * The node is only valid for SMB_FTYPE_DISK files.
+ */
+ struct smb_node *node = sr->fid_ofile->f_node;
+
+ /*
+ * For some reason NT will not show the security tab in the root
+ * directory of a mapped drive unless the filename length is
+ * greater than one.
+ * This may be a NT vs Windows9x UNICODE check.
+ * So we hack the length here to persuade NT to show the tab. It
+ * should be safe because of the null terminator character.
+ */
+ /* be careful here we need od_name now rather than node_name */
+ /* do we want to use node_name in the case of softlinks ?? */
+ namep = node->od_name;
+ filename = namep;
+ filename_len = smb_ascii_or_unicode_strlen(sr, filename);
+ if (strcmp(namep, ".") == 0 && filename_len == 1)
+ filename_len = 2;
+
+ creation_time = smb_node_get_crtime(node);
+ dattr = smb_node_get_dosattr(node);
+
+ ap = &node->attr;
+ if (ap->sa_vattr.va_type == VDIR) {
+ is_dir = 1;
+ dsize = dused = 0;
+ } else {
+ is_dir = 0;
+ dsize = ap->sa_vattr.va_size;
+ dused = ap->sa_vattr.va_blksize *
+ ap->sa_vattr.va_nblocks;
+ }
+
+ dir_snode = node->dir_snode;
+ delete_on_close =
+ (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
+ }
+ break;
+
+ case SMB_FTYPE_MESG_PIPE:
+ {
+ /*
+ * The pipe is only valid for SMB_FTYPE_MESG_PIPE files.
+ */
+ mlsvc_pipe_t *pipe_info = sr->fid_ofile->f_pipe_info;
+ namep = pipe_info->pipe_name;
+
+ filename = namep;
+ filename_len = smb_ascii_or_unicode_strlen(sr, filename);
+
+ ap = &pipe_attr;
+ creation_time = (timestruc_t *)&ap->sa_vattr.va_ctime;
+ dattr = SMB_FA_NORMAL;
+ dsize = dused = 0;
+
+ delete_on_close = 0;
+ is_dir = 0;
+ }
+ break;
+
+ default:
+ smbsr_raise_error(sr, ERRDOS, ERRbadfile);
+ /* NOTREACHED */
+ break;
+ }
+
+ filebuf = kmem_alloc(MAXNAMELEN+1, KM_SLEEP);
+ mangled_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (infolev > SMB_INFO_PASSTHROUGH)
+ infolev -= SMB_INFO_PASSTHROUGH;
+
+ switch (infolev) {
+ case FileAccessInformation:
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l",
+ sr->fid_ofile->f_granted_access);
+ break;
+
+ case SMB_INFO_STANDARD:
+ if (dsize > 0xffffffff)
+ dsize = 0xffffffff;
+ if (dused > 0xffffffff)
+ dused = 0xffffffff;
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95)
+ ? "YYYllw" : "yyyllw"),
+ smb_gmt_to_local_time(creation_time->tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_atime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_mtime.tv_sec),
+ (uint32_t)dsize,
+ (uint32_t)dused,
+ dattr);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ if (dsize > 0xffffffff)
+ dsize = 0xffffffff;
+ if (dused > 0xffffffff)
+ dused = 0xffffffff;
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95)
+ ? "YYYllwl" : "yyyllwl"),
+ smb_gmt_to_local_time(creation_time->tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_atime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_mtime.tv_sec),
+ (uint32_t)dsize,
+ (uint32_t)dused,
+ dattr, 0);
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ case SMB_INFO_QUERY_ALL_EAS:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_INFO_IS_NAME_VALID:
+ break;
+
+ case SMB_QUERY_FILE_BASIC_INFO:
+ /*
+ * NT includes 6 undocumented bytes at the end of this
+ * response, which are required by NetBench 5.01.
+ * Similar change in smb_trans2_query_path_information.c.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "TTTTw6.",
+ creation_time,
+ &ap->sa_vattr.va_atime,
+ &ap->sa_vattr.va_mtime,
+ &ap->sa_vattr.va_ctime,
+ dattr);
+ break;
+
+ case SMB_QUERY_FILE_STANDARD_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w",
+ SMB_QUERY_FILE_STANDARD_INFO);
+ /*
+ * Add 2 bytes to pad data to long. It is
+ * necessary because Win2k expects the padded bytes.
+ */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "qqlbb2.",
+ dused,
+ dsize,
+ ap->sa_vattr.va_nlink,
+ delete_on_close,
+ is_dir);
+ break;
+
+ case SMB_QUERY_FILE_EA_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_QUERY_FILE_NAME_INFO:
+ /*
+ * It looks like NT doesn't know what to do with the name "."
+ * so we convert it to "\\" to indicate the root directory.
+ *
+ * If the leading \ is missing, add it.
+ */
+ if (strcmp(namep, ".") == 0) {
+ filename = "\\";
+ filename_len = 2;
+ } else if (*namep != '\\') {
+ filename = filebuf;
+ (void) snprintf(filename, MAXNAMELEN + 1, "\\%s",
+ namep);
+ filename_len =
+ smb_ascii_or_unicode_strlen(sr, filename);
+ } else {
+ filename = namep;
+ filename_len =
+ smb_ascii_or_unicode_strlen(sr, filename);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ filename_len, filename);
+ break;
+
+ case SMB_QUERY_FILE_ALL_INFO:
+ /*
+ * The reply of this information level on the
+ * wire doesn't match with protocol specification.
+ * This is what spec. needs: "TTTTwqqlbbqllqqll"
+ * But this is actually is sent on the wire:
+ * "TTTTw6.qqlbb2.l"
+ * So, there is a 6-byte pad between Attributes and
+ * AllocationSize. Also there is a 2-byte pad After
+ * Directory field. Between Directory and FileNameLength
+ * there is just 4 bytes that it seems is AlignmentRequirement.
+ * There are 6 other fields between Directory and
+ * AlignmentRequirement in spec. that aren't sent
+ * on the wire.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
+ creation_time,
+ &ap->sa_vattr.va_atime,
+ &ap->sa_vattr.va_mtime,
+ &ap->sa_vattr.va_ctime,
+ dattr,
+ (int64_t)dused,
+ (int64_t)dsize,
+ ap->sa_vattr.va_nlink,
+ delete_on_close,
+ is_dir,
+ 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu",
+ sr, filename_len, filename);
+ break;
+
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ /*
+ * Conform to the rule used by Windows NT/2003 servers.
+ * Shortname is created only if either the
+ * filename or extension portion of a file is made up of
+ * mixed case. This is handled in os/libnt/nt_mangle_name.c.
+ *
+ * If the shortname is generated, it will be returned as
+ * the alternative name. Otherwise, converts the original
+ * name to all upper-case and returns it as the alternative
+ * name. This is how Windows NT/2003 servers behave. However,
+ * Windows 2000 seems to preserve the case of the original
+ * name, and returns it as the alternative name.
+ */
+ alt_nm_ptr = (*mangled_name == 0) ?
+ utf8_strupr(filename) : mangled_name;
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ smb_ascii_or_unicode_strlen(sr, alt_nm_ptr), alt_nm_ptr);
+ break;
+
+ case SMB_QUERY_FILE_STREAM_INFO:
+ {
+ struct smb_node *node = sr->fid_ofile->f_node;
+ if (dir_snode == NULL) {
+ kmem_free(filebuf, MAXNAMELEN+1);
+ kmem_free(mangled_name, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRbadfile);
+ /* NOT REACHED */
+ }
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ if (SMB_IS_STREAM(node)) {
+ ASSERT(node->unnamed_stream_node);
+ ASSERT(node->unnamed_stream_node->n_magic ==
+ SMB_NODE_MAGIC);
+ ASSERT(node->unnamed_stream_node->n_state !=
+ SMB_NODE_STATE_DESTROYING);
+
+ (void) smb_encode_stream_info(sr, xa,
+ node->unnamed_stream_node, ap);
+ } else {
+ (void) smb_encode_stream_info(sr, xa, node, ap);
+ }
+ break;
+ }
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "qwbbb3.",
+ dsize, 0, 0, 0, 0);
+ break;
+
+ default:
+ kmem_free(filebuf, MAXNAMELEN+1);
+ kmem_free(mangled_name, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ break;
+ }
+
+ kmem_free(filebuf, MAXNAMELEN+1);
+ kmem_free(mangled_name, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_encode_stream_info
+ *
+ * This function encodes the streams information for both T2QueryFileInfo
+ * and T2QueryPathInfo. The rules about how to do this are not documented.
+ * They have been derived using observed NT behaviour and the IR's listed
+ * below.
+ *
+ * IR101680: ArcServe2000 problem. ArcServe doesn't like the null-
+ * stream data on directories that don't have any associated streams.
+ *
+ * IR103484 and KB article Q234765: Citrix problem. If there are no
+ * streams, only return the unnamed stream data if the target is a
+ * file. The Citrix Metaframe cdm.sys driver crashes the Windows server,
+ * on which it's running, if it receives the unexpected stream data
+ * for a directory.
+ *
+ * If there are streams, on files or directories, we need to return
+ * them to support Mac/DAVE clients. Mac clients make this request
+ * to see if there is a comment stream. If we don't provide the
+ * information, the client won't try to access the comment stream.
+ *
+ * If the target is a file:
+ * 1. If there are no named streams, the response should still contain
+ * an entry for the unnamed stream.
+ * 2. If there are named streams, the response should contain an entry
+ * for the unnamed stream followed by the entries for the named
+ * streams.
+ *
+ * If the target is a directory:
+ * 1. If there are no streams, the response is complete. Directories
+ * do not report the unnamed stream.
+ * 2. If there are streams, the response should contain entries for
+ * those streams but there should not be an entry for the unnamed
+ * stream.
+ *
+ * Note that the stream name lengths exclude the null terminator but
+ * the field lengths (i.e. next offset calculations) need to include
+ * the null terminator and be padded to a multiple of 8 bytes. The
+ * last entry does not seem to need any padding.
+ */
+
+void
+smb_encode_stream_info(
+ struct smb_request *sr,
+ struct smb_xa *xa,
+ struct smb_node *snode,
+ smb_attr_t *attr)
+{
+ char *stream_name;
+ uint32_t next_offset;
+ uint32_t stream_nlen;
+ uint32_t pad;
+ off_t dsize;
+ int is_dir;
+ uint32_t cookie = 0;
+ struct fs_stream_info *stream_info;
+ struct fs_stream_info *stream_info_next;
+ int rc = 0;
+ int done = 0;
+ char *fname;
+
+ stream_info = kmem_alloc(sizeof (struct fs_stream_info), KM_SLEEP);
+ stream_info_next = kmem_alloc(sizeof (struct fs_stream_info), KM_SLEEP);
+ is_dir = (attr->sa_vattr.va_type == VDIR) ? 1 : 0;
+ dsize = attr->sa_vattr.va_size;
+ fname = MEM_MALLOC("smb", MAXPATHLEN);
+
+ rc = smb_fsop_stream_readdir(sr, kcred, snode, &cookie, stream_info,
+ NULL, NULL);
+
+ if ((cookie == 0x7FFFFFFF) || (rc == EACCES) || (rc == ENOENT)) {
+ if (is_dir == 0) {
+ stream_name = "::$DATA";
+ stream_nlen =
+ smb_ascii_or_unicode_strlen(sr, stream_name);
+ next_offset = 0;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%llqqu",
+ sr, next_offset, stream_nlen, dsize, dsize,
+ stream_name);
+ }
+ /* No named streams, we're done */
+ kmem_free(stream_info, sizeof (struct fs_stream_info));
+ kmem_free(stream_info_next, sizeof (struct fs_stream_info));
+ MEM_FREE("smb", fname);
+ return;
+ }
+
+ if (is_dir == 0) {
+ stream_name = "::$DATA";
+ stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
+
+ /*
+ * Offset calculation:
+ * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
+ */
+ next_offset = 24 + stream_nlen +
+ smb_ascii_or_unicode_null_len(sr);
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%llqqu", sr,
+ next_offset, stream_nlen, dsize, dsize, stream_name);
+ }
+
+ while (!done) {
+ /*
+ * Named streams.
+ */
+ stream_nlen = smb_ascii_or_unicode_strlen(sr,
+ stream_info->name);
+ next_offset = 0;
+ pad = 0;
+
+ /*
+ * this is a little kludgy, since we use a cookie now and last
+ * packet does not have a pad we need to check the next item
+ * before we encode the current one
+ */
+ stream_info_next->name[0] = 0;
+ rc = smb_fsop_stream_readdir(sr, kcred, snode, &cookie,
+ stream_info_next, NULL, NULL);
+ if (cookie == 0x7FFFFFFF) {
+ done = 1;
+ } else {
+ if (cookie == 0) {
+ break;
+ }
+ next_offset = 24 + stream_nlen +
+ smb_ascii_or_unicode_null_len(sr);
+ pad = smb_pad_align(next_offset, 8);
+ next_offset += pad;
+ }
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%llqqu#.",
+ sr, next_offset, stream_nlen,
+ stream_info->size, stream_info->size,
+ stream_info->name, pad);
+
+ (void) memcpy(stream_info, stream_info_next,
+ sizeof (struct fs_stream_info));
+ }
+ kmem_free(stream_info, sizeof (struct fs_stream_info));
+ kmem_free(stream_info_next, sizeof (struct fs_stream_info));
+ MEM_FREE("smb", fname);
+}
+
+/*
+ * smb_pad_align
+ *
+ * Returns the number of bytes required to get pad an offset to the
+ * specified alignment.
+ */
+uint32_t
+smb_pad_align(uint32_t offset, uint32_t align)
+{
+ uint32_t pad = offset % align;
+
+ if (pad != 0)
+ pad = align - pad;
+
+ return (pad);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c
new file mode 100644
index 0000000000..aa7cc15343
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c
@@ -0,0 +1,434 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_query_fs_information
+ *
+ * This transaction requests information about a filesystem on the server.
+ *
+ * Client Request Value
+ * ================================== =================================
+ *
+ * WordCount; 15
+ * TotalParameterCount; 2 or 4
+ * MaxSetupCount; 0
+ * SetupCount; 1 or 2
+ * Setup[0]; TRANS2_QUERY_FS_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ================================== =================================
+ *
+ * USHORT Information Level; Level of information requested
+ *
+ * The filesystem is identified by Tid in the SMB header.
+ *
+ * MaxDataCount in the transaction request must be large enough to
+ * accommodate the response.
+ *
+ * The encoding of the response parameter block depends on the
+ * InformationLevel requested. Information levels whose values are greater
+ * than 0x102 are mapped to corresponding calls to
+ * NtQueryVolumeInformationFile calls by the server. The two levels below
+ * 0x102 are described below. The requested information is placed in the
+ * Data portion of the transaction response.
+ *
+ * InformationLevel Value
+ *
+ * ============================= ======
+ *
+ * SMB_INFO_ALLOCATION 1
+ * SMB_INFO_VOLUME 2
+ * SMB_QUERY_FS_VOLUME_INFO 0x102
+ * SMB_QUERY_FS_SIZE_INFO 0x103
+ * SMB_QUERY_FS_DEVICE_INFO 0x104
+ * SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
+ *
+ * The following sections describe the InformationLevel dependent encoding
+ * of the data part of the transaction response.
+ *
+ * 4.1.6.1 SMB_INFO_ALLOCATION
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * ULONG idFileSystem; File system identifier. NT server always
+ * returns 0
+ * ULONG cSectorUnit; Number of sectors per allocation unit
+ * ULONG cUnit; Total number of allocation units
+ * ULONG cUnitAvail; Total number of available allocation units
+ * USHORT cbSector; Number of bytes per sector
+ *
+ * 4.1.6.2 SMB_INFO_VOLUME
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * ULONG ulVsn; Volume serial number
+ * UCHAR cch; Number of characters in Label
+ * STRING Label; The volume label
+ *
+ * 4.1.6.3 SMB_QUERY_FS_VOLUME_INFO
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * LARGE_INTEGER Volume Creation Time
+ * ULONG Volume Serial Number
+ * ULONG Length of Volume Label in bytes
+ *
+ * BYTE Reserved
+ *
+ * BYTE Reserved
+ *
+ * STRING Label; The volume label
+ *
+ * 4.1.6.4 SMB_QUERY_FS_SIZE_INFO
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * LARGE_INTEGER Total Number of Allocation units on the Volume
+ * LARGE_INTEGER Number of free Allocation units on the Volume
+ * ULONG Number of sectors in each Allocation unit
+ *
+ * ULONG Number of bytes in each sector
+ *
+ * 4.1.6.5 SMB_QUERY_FS_DEVICE_INFO
+ *
+ * Data Block Encoding Value
+ * ==================== ===============================================
+ *
+ * ULONG DeviceType; Values as specified below
+ * ULONG Characteristics of the device; Values as
+ * specified below
+ *
+ * For DeviceType, note that the values 0-32767 are reserved for the
+ * exclusive use of Microsoft Corporation. The following device types are
+ * currently defined:
+ *
+ * FILE_DEVICE_BEEP 0x00000001
+ *
+ * FILE_DEVICE_CD_ROM 0x00000002
+ * FILE_DEVICE_CD_ROM_FILE_SYST 0x00000003
+ * EM
+ * FILE_DEVICE_CONTROLLER 0x00000004
+ * FILE_DEVICE_DATALINK 0x00000005
+ * FILE_DEVICE_DFS 0x00000006
+ * FILE_DEVICE_DISK 0x00000007
+ * FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+ * FILE_DEVICE_FILE_SYSTEM 0x00000009
+ * FILE_DEVICE_INPORT_PORT 0x0000000a
+ * FILE_DEVICE_KEYBOARD 0x0000000b
+ * FILE_DEVICE_MAILSLOT 0x0000000c
+ * FILE_DEVICE_MIDI_IN 0x0000000d
+ * FILE_DEVICE_MIDI_OUT 0x0000000e
+ * FILE_DEVICE_MOUSE 0x0000000f
+ * FILE_DEVICE_MULTI_UNC_PROVID 0x00000010
+ * ER
+ * FILE_DEVICE_NAMED_PIPE 0x00000011
+ * FILE_DEVICE_NETWORK 0x00000012
+ * FILE_DEVICE_NETWORK_BROWSER 0x00000013
+ * FILE_DEVICE_NETWORK_FILE_SYS 0x00000014
+ * TEM
+ * FILE_DEVICE_NULL 0x00000015
+ * FILE_DEVICE_PARALLEL_PORT 0x00000016
+ * FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
+ * FILE_DEVICE_PRINTER 0x00000018
+ * FILE_DEVICE_SCANNER 0x00000019
+ * FILE_DEVICE_SERIAL_MOUSE_POR 0x0000001a
+ * T
+ * FILE_DEVICE_SERIAL_PORT 0x0000001b
+ * FILE_DEVICE_SCREEN 0x0000001c
+ * FILE_DEVICE_SOUND 0x0000001d
+ * FILE_DEVICE_STREAMS 0x0000001e
+ * FILE_DEVICE_TAPE 0x0000001f
+ * FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+ * FILE_DEVICE_TRANSPORT 0x00000021
+ * FILE_DEVICE_UNKNOWN 0x00000022
+ * FILE_DEVICE_VIDEO 0x00000023
+ * FILE_DEVICE_VIRTUAL_DISK 0x00000024
+ * FILE_DEVICE_WAVE_IN 0x00000025
+ * FILE_DEVICE_WAVE_OUT 0x00000026
+ * FILE_DEVICE_8042_PORT 0x00000027
+ * FILE_DEVICE_NETWORK_REDIRECT 0x00000028
+ * OR
+ * FILE_DEVICE_BATTERY 0x00000029
+ * FILE_DEVICE_BUS_EXTENDER 0x0000002a
+ * FILE_DEVICE_MODEM 0x0000002b
+ * FILE_DEVICE_VDM 0x0000002c
+ *
+ * Some of these device types are not currently accessible over the network
+ * and may never be accessible over the network. Some may change to be
+ *
+ * accessible over the network. The values for device types that may never
+ * be accessible over the network may be redefined to be just reserved at
+ * some date in the future.
+ *
+ * Characteristics is the sum of any of the following:
+ *
+ * FILE_REMOVABLE_MEDIA 0x00000001
+ * FILE_READ_ONLY_DEVICE 0x00000002
+ * FILE_FLOPPY_DISKETTE 0x00000004
+ * FILE_WRITE_ONE_MEDIA 0x00000008
+ * FILE_REMOTE_DEVICE 0x00000010
+ * FILE_DEVICE_IS_MOUNTED 0x00000020
+ * FILE_VIRTUAL_VOLUME 0x00000040
+ *
+ * 4.1.6.6 SMB_QUERY_FS_ATTRIBUTE_INFO
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * ULONG File System Attributes; possible values
+ * described below
+ * LONG Maximum length of each file name component in
+ * number of bytes
+ * ULONG Length, in bytes, of the name of the file system
+ *
+ * STRING Name of the file system
+ *
+ * Where FileSystemAttributes is the sum of any of the following:
+ *
+ * FILE_CASE_SENSITIVE_SEARCH 0x00000001
+ * FILE_CASE_PRESERVED_NAMES 0x00000002
+ * FILE_PRSISTENT_ACLS 0x00000004
+ * FILE_FILE_COMPRESSION 0x00000008
+ * FILE_VOLUME_QUOTAS 0x00000010
+ * FILE_DEVICE_IS_MOUNTED 0x00000020
+ * FILE_VOLUME_IS_COMPRESSED 0x00008000
+ *
+ * 4.1.6.7 Errors
+ *
+ * ERRSRV/invnid - TID was invalid
+ * ERRSRV/baduid - UID was invalid
+ * ERRHRD/ERRnotready - the file system has been removed
+ * ERRHRD/ERRdata - disk I/O error
+ * ERRSRV/ERRaccess - user does not have the right to perform this
+ * operation
+ * ERRSRV/ERRinvdevice - resource identified by TID is not a file system
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smbinfo.h>
+
+char ntfs[] = "NTFS";
+
+
+/*
+ * is_dot_or_dotdot
+ *
+ * Inline function to detect the "." and ".." entries in a directory.
+ * Returns 1 is the name is "." or "..". Otherwise returns 0.
+ */
+int
+is_dot_or_dotdot(char *name)
+{
+ if (*name != '.')
+ return (0);
+
+ if ((name[1] == 0) || (name[1] == '.' && name[2] == 0))
+ return (1);
+
+ return (0);
+}
+
+
+/*
+ * smb_com_trans2_query_fs_information
+ */
+int
+smb_com_trans2_query_fs_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc;
+ uint32_t flags;
+ char *encode_str;
+ uint64_t max_int;
+ unsigned short infolev;
+ struct statvfs64 df;
+ int sect_per_unit, length;
+ uint32_t total_units, avail_units;
+ struct smb_node *snode;
+ char *fsname = "NTFS";
+ fsvol_attr_t vol_attr;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "w", &infolev) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ snode = sr->tid_tree->t_snode;
+ if (fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr) != 0) {
+ smbsr_raise_errno(sr, ESTALE);
+ /* NOTREACHED */
+ }
+
+ switch (infolev) {
+ case SMB_INFO_ALLOCATION:
+ if ((rc = smb_fsop_statfs(sr->user_cr, snode, &df)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ max_int = 0xffffffffLL;
+
+ if (df.f_blocks > max_int)
+ df.f_blocks = max_int;
+
+ if (df.f_bavail > max_int)
+ df.f_bavail = max_int;
+
+ total_units = (uint32_t)df.f_blocks;
+ avail_units = (uint32_t)df.f_bavail;
+ length = 512;
+ sect_per_unit = df.f_frsize >> 9;
+
+ if (avail_units > total_units)
+ avail_units = 0;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "llllw",
+ 0, /* file system ID. NT rets 0 */
+ sect_per_unit, /* sectors/unit */
+ total_units, /* total units */
+ avail_units, /* avail units */
+ length); /* bytes/sector */
+ break;
+
+ case SMB_INFO_VOLUME:
+ length = strlen(vol_attr.name);
+ encode_str = "%lbs";
+ /*
+ * tree_fsd.val[0] is the 32-bit dev for the file system
+ * of the share's root smb_node.
+ *
+ * Together with tree_fsd.val[1] (the file system type), it
+ * comprises a system-wide unique file system ID.
+ */
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, encode_str, sr,
+ snode->tree_fsd.val[0], length, vol_attr.name);
+ break;
+
+ case SMB_QUERY_FS_VOLUME_INFO:
+ if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) ||
+ (sr->session->native_os == NATIVE_OS_WIN95)) {
+ length = mts_wcequiv_strlen(vol_attr.name);
+ encode_str = "%qllb.U";
+ } else {
+ length = strlen(vol_attr.name); /* label length */
+ encode_str = "%qllb.s";
+ }
+
+ /*
+ * NT has the "supports objects" flag set to 1.
+ */
+
+ /*
+ * tree_fsd.val[0] is the 32-bit dev for the file system
+ * of the share's root smb_node.
+ *
+ * Together with tree_fsd.val[1] (the file system type), it
+ * comprises a system-wide unique file system ID.
+ */
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, encode_str, sr,
+ 0ll, /* Volume creation time */
+ snode->tree_fsd.val[0], /* Volume serial number */
+ length, /* label length */
+ 0, /* Supports objects */
+ vol_attr.name);
+ break;
+
+ case SMB_QUERY_FS_SIZE_INFO:
+ if ((rc = smb_fsop_statfs(sr->user_cr, snode, &df)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ length = 512;
+ sect_per_unit = df.f_frsize >> 9;
+
+ if (df.f_bavail > df.f_blocks)
+ df.f_bavail = 0;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "qqll",
+ df.f_blocks, /* total units */
+ df.f_bavail, /* avail units */
+ sect_per_unit, /* sectors/unit */
+ length); /* bytes/sector */
+ break;
+ case SMB_QUERY_FS_DEVICE_INFO:
+ (void) smb_encode_mbc(&xa->rep_data_mb, "ll",
+ FILE_DEVICE_FILE_SYSTEM,
+ FILE_DEVICE_IS_MOUNTED);
+ break;
+
+ case SMB_QUERY_FS_ATTRIBUTE_INFO:
+
+ if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) ||
+ (sr->session->native_os == NATIVE_OS_WINNT) ||
+ (sr->session->native_os == NATIVE_OS_WIN2000) ||
+ (sr->session->native_os == NATIVE_OS_WIN95) ||
+ (sr->session->native_os == NATIVE_OS_MACOS)) {
+ length = mts_wcequiv_strlen(fsname);
+ encode_str = "%lllU";
+ sr->smb_flg2 |= SMB_FLAGS2_UNICODE;
+ } else {
+ length = strlen(fsname);
+ encode_str = "%llls";
+ }
+
+ flags = FILE_CASE_PRESERVED_NAMES;
+ /* flags |= FILE_UNICODE_ON_DISK; */
+
+ if (vol_attr.flags & FSOLF_SUPPORTS_ACLS)
+ flags |= FILE_PERSISTENT_ACLS;
+
+ if ((vol_attr.flags & FSOLF_CASE_INSENSITIVE) == 0)
+ flags |= FILE_CASE_SENSITIVE_SEARCH;
+
+ if (vol_attr.flags & FSOLF_STREAMS)
+ flags |= FILE_NAMED_STREAMS;
+
+ if (smb_info.si.skc_announce_quota)
+ flags |= FILE_VOLUME_QUOTAS;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, encode_str, sr,
+ flags,
+ MAXNAMELEN, /* max name */
+ length, /* label length */
+ fsname);
+ break;
+
+ default:
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ break;
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
new file mode 100644
index 0000000000..1a80d6a2c4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
@@ -0,0 +1,588 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_query_path_information
+ *
+ * This request is used to get information about a specific file or
+ * subdirectory.
+ *
+ * Client Request Value
+ * ========================== =========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_QUERY_PATH_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ========================== =========================================
+ *
+ * USHORT InformationLevel; Level of information requested
+ * ULONG Reserved; Must be zero
+ * STRING FileName; File or directory name
+ *
+ * The following InformationLevels may be requested:
+ *
+ * Information Level Value
+ *
+ * ================================ =====
+ *
+ * SMB_INFO_STANDARD 1
+ * SMB_INFO_QUERY_EA_SIZE 2
+ * SMB_INFO_QUERY_EAS_FROM_LIST 3
+ * SMB_INFO_QUERY_ALL_EAS 4
+ * SMB_INFO_IS_NAME_VALID 6
+ * SMB_QUERY_FILE_BASIC_INFO 0x101
+ * SMB_QUERY_FILE_STANDARD_INFO 0x102
+ * SMB_QUERY_FILE_EA_INFO 0x103
+ * SMB_QUERY_FILE_NAME_INFO 0x104
+ * SMB_QUERY_FILE_ALL_INFO 0x107
+ * SMB_QUERY_FILE_ALT_NAME_INFO 0x108
+ * SMB_QUERY_FILE_STREAM_INFO 0x109
+ * SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
+ *
+ * The requested information is placed in the Data portion of the
+ * transaction response. For the information levels greater than 0x100,
+ * the transaction response has 1 parameter word which should be ignored by
+ * the client.
+ *
+ * The following sections describe the InformationLevel dependent encoding
+ * of the data part of the transaction response.
+ *
+ * 4.2.14.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation unit
+ * USHORT Attributes; File Attributes
+ * ULONG EaSize; Size of file's EA information
+ * (SMB_INFO_QUERY_EA_SIZE)
+ *
+ * 4.2.14.2 SMB_INFO_QUERY_EAS_FROM_LIST & SMB_INFO_QUERY_ALL_EAS
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * MaxDataCount Length of EAlist found (minimum value is 4)
+ *
+ * Parameter Block Description
+ * Encoding ===============================================
+ * ====================
+ *
+ * USHORT EaErrorOffset Offset into EAList of EA error
+ *
+ * Data Block Encoding Description
+ * ==================== ===============================================
+ *
+ * ULONG ListLength; Length of the remaining data
+ * UCHAR EaList[] The extended attributes list
+ *
+ * 4.2.14.3 SMB_INFO_IS_NAME_VALID
+ *
+ * This requests checks to see if the name of the file contained in the
+ * request's Data field has a valid path syntax. No parameters or data are
+ * returned on this information request. An error is returned if the syntax
+ * of the name is incorrect. Success indicates the server accepts the path
+ * syntax, but it does not ensure the file or directory actually exists.
+ *
+ * 4.2.14.4 SMB_QUERY_FILE_BASIC_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * LARGE_INTEGER CreationTime; Time when file was created
+ * LARGE_INTEGER LastAccessTime; Time of last file access
+ * LARGE_INTEGER LastWriteTime; Time of last write to the file
+ * LARGE_INTEGER ChangeTime Time when file was last changed
+ * USHORT Attributes; File Attributes
+ *
+ * 4.2.14.5 SMB_QUERY_FILE_STANDARD_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * LARGE_INTEGER AllocationSize Allocated size of the file in number
+ * of bytes
+ * LARGE_INTEGER EndofFile; Offset to the first free byte in the
+ * file
+ * ULONG NumberOfLinks Number of hard links to the file
+ * BOOLEAN DeletePending Indicates whether the file is marked
+ * for deletion
+ * BOOLEAN Directory Indicates whether the file is a
+ * directory
+ *
+ * 4.2.14.6 SMB_QUERY_FILE_EA_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * ULONG EASize Size of the file's extended
+ * attributes in number of bytes
+ *
+ * 4.2.14.7 SMB_QUERY_FILE_NAME_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * ULONG FileNameLength Length of the file name in number of
+ * bytes
+ * STRING FileName Name of the file
+ *
+ * 4.2.14.8 SMB_QUERY_FILE_ALL_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * LARGE_INTEGER CreationTime; Time when file was created
+ * LARGE_INTEGER LastAccessTime; Time of last file access
+ * LARGE_INTEGER LastWriteTime; Time of last write to the file
+ * LARGE_INTEGER ChangeTime Time when file was last changed
+ * USHORT Attributes; File Attributes
+ * LARGE_INTEGER AllocationSize Allocated size of the file in number
+ * of bytes
+ * LARGE_INTEGER EndofFile; Offset to the first free byte in the
+ * file
+ * ULONG NumberOfLinks Number of hard links to the file
+ * BOOLEAN DeletePending Indicates whether the file is marked
+ * for deletion
+ * BOOLEAN Directory Indicates whether the file is a
+ * directory
+ * LARGE_INTEGER Index Number A file system unique identifier
+ * ULONG EASize Size of the file's extended
+ * attributes in number of bytes
+ * ULONG AccessFlags Access that a caller has to the
+ * file; Possible values and meanings
+ * are specified below
+ * LARGE_INTEGER Index Number A file system unique identifier
+ * LARGE_INTEGER CurrentByteOffset Current byte offset within the file
+ * ULONG Mode Current Open mode of the file handle
+ * to the file; possible values and
+ * meanings are detailed below
+ * ULONG AlignmentRequirement Buffer Alignment required by device;
+ * possible values detailed below
+ * ULONG FileNameLength Length of the file name in number of
+ * bytes
+ * STRING FileName Name of the file
+ *
+ * The AccessFlags specifies the access permissions a caller has to the
+ * file and can have any suitable combination of the following values:
+ *
+ * Value Meaning
+ *
+ * ILE_READ_DATA 0x00000001 Data can be read from the file
+ * ILE_WRITE_DATA 0x00000002 Data can be written to the file
+ * ILE_APPEND_DATA 0x00000004 Data can be appended to the file
+ * ILE_READ_EA 0x00000008 Extended attributes associated
+ * with the file can be read
+ * ILE_WRITE_EA 0x00000010 Extended attributes associated
+ * with the file can be written
+ * ILE_EXECUTE 0x00000020 Data can be read into memory from
+ * the file using system paging I/O
+ * ILE_READ_ATTRIBUTES 0x00000080 Attributes associated with the
+ * file can be read
+ * ILE_WRITE_ATTRIBUTES 0x00000100 Attributes associated with the
+ * file can be written
+ * ELETE 0x00010000 The file can be deleted
+ * EAD_CONTROL 0x00020000 The access control list and
+ * ownership associated with the
+ * file can be read
+ * RITE_DAC 0x00040000 The access control list and
+ * ownership associated with the
+ * file can be written.
+ * RITE_OWNER 0x00080000 Ownership information associated
+ * with the file can be written
+ * YNCHRONIZE 0x00100000 The file handle can waited on to
+ * synchronize with the completion
+ * of an input/output request
+ *
+ * The Mode field specifies the mode in which the file is currently opened.
+ * The possible values may be a suitable and logical combination of the
+ * following:
+ *
+ * Value Meaning
+ *
+ * FILE_WRITE_THROUGH 0x00000002 File is opened in mode
+ * where data is written to
+ * file before the driver
+ * completes a write request
+ * FILE_SEQUENTIAL_ONLY 0x00000004 All access to the file is
+ * sequential
+ * FILE_SYNCHRONOUS_IO_ALERT 0x00000010 All operations on the
+ * file are performed
+ * synchronously
+ * FILE_SYNCHRONOUS_IO_NONALER 0x00000020 All operations on the
+ * T file are to be performed
+ * synchronously. Waits in
+ * the system to synchronize
+ * I/O queuing and
+ * completion are not
+ * subject to alerts.
+ *
+ * The AlignmentRequirement field specifies buffer alignment required by
+ * the device and can have any one of the following values:
+ *
+ * Value Meaning
+ *
+ * FILE_BYTE_ALIGNMENT 0x00000000 The buffer needs to be aligned
+ * on a byte boundary
+ * FILE_WORD_ALIGNMENT 0x00000001 The buffer needs to be aligned
+ * on a word boundary
+ * FILE_LONG_ALIGNMENT 0x00000003 The buffer needs to be aligned
+ * on a 4 byte boundary
+ * FILE_QUAD_ALIGNMENT 0x00000007 The buffer needs to be aligned
+ * on an 8 byte boundary
+ * FILE_OCTA_ALIGNMENT 0x0000000f The buffer needs to be aligned
+ * on a 16 byte boundary
+ * FILE_32_BYTE_ALIGNMENT 0x0000001f The buffer needs to be aligned
+ * on a 32 byte boundary
+ * FILE_64_BYTE_ALIGNMENT 0x0000003f The buffer needs to be aligned
+ * on a 64 byte boundary
+ * FILE_128_BYTE_ALIGNMENT 0x0000007f The buffer needs to be aligned
+ * on a 128 byte boundary
+ * FILE_256_BYTE_ALIGNMENT 0x000000ff The buffer needs to be aligned
+ * on a 256 byte boundary
+ * FILE_512_BYTE_ALIGNMENT 0x000001ff The buffer needs to be aligned
+ * on a 512 byte boundary
+ *
+ * 4.2.14.9 SMB_QUERY_FILE_ALT_NAME_INFO
+ *
+ * Data Block Encoding Description
+ * ===================== =================================
+ * ULONG FileNameLength Length of the file name in number of bytes
+ * STRING FileName Name of the file
+ *
+ * 4.2.14.10 SMB_QUERY_FILE_STREAM_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ * ULONG NextEntryOffset Offset to the next entry (in bytes)
+ * ULONG StreamNameLength Length of the stream name in # of bytes
+ * LARGE_INTEGER StreamSize Size of the stream in number of bytes
+ * LARGE_INTEGER AllocationSize Allocated size of stream in bytes
+ * STRING FileName Name of the stream
+ *
+ * 4.2.14.11 SMB_QUERY_FILE_COMPRESSION_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ * LARGE_INTEGER Size of the compressed file in
+ * CompressedFileSize number of bytes
+ * USHORT CompressionFormat compression algorithm used
+ * UCHAR CompressionUnitShift Size of the stream in number of bytes
+ * UCHAR ChunkShift Allocated size of the stream in # of bytes
+ * UCHAR ClusterShift Allocated size of the stream in # of bytes
+ * UCHAR Reserved[3] Name of the stream
+ *
+ * typedef struct {
+ * LARGE_INTEGER CompressedFileSize;
+ * USHORT CompressionFormat;
+ * UCHAR CompressionUnitShift;
+ * UCHAR ChunkShift;
+ * UCHAR ClusterShift;
+ * UCHAR Reserved[3];
+ * } FILE_COMPRESSION_INFORMATION;
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/msgbuf.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_fsops.h>
+
+/*
+ * Function: int smb_com_trans2_query_path_information(struct smb_request *)
+ */
+int
+smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ char *path, *alt_nm_ptr;
+ int rc;
+ off_t dsize, dused;
+ unsigned short infolev, dattr;
+ smb_attr_t *ap, ret_attr;
+ struct smb_node *dir_node;
+ struct smb_node *node;
+ char *name;
+ char *short_name;
+ char *name83;
+ unsigned char is_dir;
+ int len;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
+ ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ short_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ name83 = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%w4.u", sr,
+ &infolev, &path) != 0) {
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Some MS clients pass NULL file names
+ * NT interprets this as "\"
+ */
+ if ((len = strlen(path)) == 0)
+ path = "\\";
+ else {
+ if ((len > 1) && (path[len - 1] == '\\')) {
+ /*
+ * Remove the terminating slash to prevent
+ * sending back '.' instead of path name.
+ */
+ path[len - 1] = 0;
+ }
+ }
+
+ ap = &ret_attr;
+ if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
+ != 0) {
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_node, name, &node, ap, short_name,
+ name83)) != 0) {
+ smb_node_release(dir_node);
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ smb_node_release(dir_node);
+ (void) strcpy(name, node->od_name);
+
+ dattr = smb_node_get_dosattr(node);
+ if (ap->sa_vattr.va_type == VDIR) {
+ is_dir = 1;
+ /*
+ * Win2K and NT reply with the size of directory
+ * file.
+ */
+ dsize = dused = 0;
+ } else {
+ is_dir = 0;
+ dsize = ap->sa_vattr.va_size;
+ dused = ap->sa_vattr.va_blksize * ap->sa_vattr.va_nblocks;
+ }
+
+ switch (infolev) {
+ case SMB_INFO_STANDARD:
+ if (dsize > 0xffffffff)
+ dsize = 0xffffffff;
+ if (dused > 0xffffffff)
+ dused = 0xffffffff;
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95)
+ ? "YYYllw" : "yyyllw"),
+ smb_gmt_to_local_time(ap->sa_crtime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_atime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_mtime.tv_sec),
+ (uint32_t)dsize,
+ (uint32_t)dused,
+ dattr);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ if (dsize > 0xffffffff)
+ dsize = 0xffffffff;
+ if (dused > 0xffffffff)
+ dused = 0xffffffff;
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95)
+ ? "YYYllwl" : "yyyllwl"),
+ smb_gmt_to_local_time(ap->sa_crtime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_atime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_mtime.tv_sec),
+ (uint32_t)dsize,
+ (uint32_t)dused,
+ dattr, 0);
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ case SMB_INFO_QUERY_ALL_EAS:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_INFO_IS_NAME_VALID:
+ break;
+
+ case SMB_QUERY_FILE_BASIC_INFO:
+ /*
+ * NT includes 6 undocumented bytes at the end of this
+ * response, which are required by NetBench 5.01.
+ * Similar change in smb_trans2_query_file_information.c.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "TTTTw6.",
+ &ap->sa_crtime,
+ &ap->sa_vattr.va_atime,
+ &ap->sa_vattr.va_mtime,
+ &ap->sa_vattr.va_ctime,
+ dattr);
+ break;
+
+ case SMB_QUERY_FILE_STANDARD_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ /*
+ * Add 2 bytes to pad data to long. It is
+ * necessary because Win2k expects the padded bytes.
+ */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "qqlbb2.",
+ dused,
+ dsize,
+ ap->sa_vattr.va_nlink,
+ (node && (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0),
+ (char)(ap->sa_vattr.va_type == VDIR));
+ break;
+
+ case SMB_QUERY_FILE_EA_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_QUERY_FILE_NAME_INFO:
+ /*
+ * If you have problems here, see the changes
+ * in smb_trans2_query_file_information.c.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ smb_ascii_or_unicode_strlen(sr, name), name);
+ break;
+
+ case SMB_QUERY_FILE_ALL_INFO:
+ /*
+ * The reply of this information level on the
+ * wire doesn't match with protocol specification.
+ * This is what spec. needs: "TTTTwqqlbbqllqqll"
+ * But this is actually is sent on the wire:
+ * "TTTTw6.qqlbb2.l"
+ * So, there is a 6-byte pad between Attributes and
+ * AllocationSize. Also there is a 2-byte pad After
+ * Directory field. Between Directory and FileNameLength
+ * there is just 4 bytes that it seems is AlignmentRequirement.
+ * There are 6 other fields between Directory and
+ * AlignmentRequirement in spec. that aren't sent
+ * on the wire.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
+ &ap->sa_crtime,
+ &ap->sa_vattr.va_atime,
+ &ap->sa_vattr.va_mtime,
+ &ap->sa_vattr.va_ctime,
+ dattr,
+ dused,
+ dsize,
+ ap->sa_vattr.va_nlink,
+ 0,
+ is_dir,
+ 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ smb_ascii_or_unicode_strlen(sr, name), name);
+ break;
+
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ /*
+ * Conform to the rule used by Windows NT/2003 servers.
+ * Shortname is created only if either the filename or
+ * extension portion of a file is made up of mixed case.
+ *
+ * If the shortname is generated, it will be returned as
+ * the alternative name. Otherwise, converts the original
+ * name to all upper-case and returns it as the alternative
+ * name. This is how Windows NT/2003 servers behave. However,
+ * Windows 2000 seems to preserve the case of the original
+ * name, and returns it as the alternative name.
+ *
+ * Note: The shortname is returned by smb_fsop_lookup(), above.
+ * In the case that the name used by the client was originally
+ * generated in response to a case-insensitive collision, the
+ * short_name and the 8.3 name will reflect this.
+ */
+ alt_nm_ptr = ((*short_name == 0) ?
+ utf8_strupr(name) : short_name);
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ smb_ascii_or_unicode_strlen(sr, alt_nm_ptr), alt_nm_ptr);
+ break;
+
+ case SMB_QUERY_FILE_STREAM_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ smb_encode_stream_info(sr, xa, node, ap);
+ break;
+
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ "qwbbb3.", dsize, 0, 0, 0, 0);
+ break;
+
+ default:
+ smb_node_release(node);
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ break;
+ }
+ smb_node_release(node);
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
new file mode 100644
index 0000000000..094032da1c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_set_file_information
+ *
+ * This request is used to set information about a specific file or
+ * subdirectory given a handle to the file or subdirectory.
+ *
+ * Client Request Value
+ * ========================== ==========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_SET_FILE_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ========================== ==========================================
+ *
+ * USHORT Fid; Handle of file for request
+ * USHORT InformationLevel; Level of information requested
+ * USHORT Reserved; Ignored by the server
+ *
+ * The following InformationLevels may be set:
+ *
+ * Information Level Value
+ * ================================ =====
+ *
+ * SMB_INFO_STANDARD 1
+ * SMB_INFO_QUERY_EA_SIZE 2
+ * SMB_SET_FILE_BASIC_INFO 0x101
+ * SMB_SET_FILE_DISPOSITION_INFO 0x102
+ * SMB_SET_FILE_ALLOCATION_INFO 0x103
+ * SMB_SET_FILE_END_OF_FILE_INFO 0x104
+ *
+ * The two levels below 0x101 are as described in the
+ * NT_SET_PATH_INFORMATION transaction. The requested information is
+ * placed in the Data portion of the transaction response. For the
+ * information levels greater than 0x100, the transaction response has 1
+ * parameter word which should be ignored by the client.
+ *
+ * 4.2.17.1 SMB_FILE_DISPOSITION_INFO
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * BOOLEAN A boolean which is TRUE if the file is marked
+ * FileIsDeleted for deletion
+ *
+ * 4.2.17.2 SMB_FILE_ALLOCATION_INFO
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * LARGE_INTEGER File Allocation size in number of bytes
+ *
+ * 4.2.17.3 SMB_FILE_END_OF_FILE_INFO
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * LARGE_INTEGER The total number of bytes that need to be
+ * traversed from the beginning of the file in
+ * order to locate the end of the file
+ *
+ * Undocumented things:
+ * Poorly documented information levels. Information must be infered
+ * from other commands.
+ *
+ * NULL Attributes means don't set them. NT sets the high bit to
+ * set attributes to 0.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * smb_com_trans2_set_file_information
+ */
+int
+smb_com_trans2_set_file_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_trans2_setinfo_t *info;
+ smb_error_t smberr;
+ DWORD status;
+ int rc;
+
+ info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
+ info->ts_xa = xa;
+
+ rc = smb_decode_mbc(&xa->req_param_mb, "ww", &sr->smb_fid,
+ &info->level);
+ if (rc != 0) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type) ||
+ SMB_TREE_IS_READ_ONLY(sr)) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ info->node = sr->fid_ofile->f_node;
+
+ if (info->node == 0 ||
+ !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
+ cmn_err(CE_NOTE, "SmbT2SetFileInfo: access denied");
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ status = smb_trans2_set_information(sr, info, &smberr);
+ if (status == NT_STATUS_DATA_ERROR) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ } else if (status == NT_STATUS_UNSUCCESSFUL) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, smberr.status,
+ smberr.errcls, smberr.errcode);
+ /* NOTREACHED */
+ }
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
new file mode 100644
index 0000000000..b41e1c426d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
@@ -0,0 +1,414 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains the common code used by
+ * Trans2SetFileInfo and Trans2SetPathInfo SMBs.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+static DWORD smb_set_standard_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+static DWORD smb_set_basic_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+static DWORD smb_set_disposition_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+static DWORD smb_set_alloc_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD smb_set_mac_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD smb_set_mac_addappl(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD smb_set_mac_rmvappl(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD smb_set_mac_addicon(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+static unsigned short smb_info_passthru(unsigned short infolevel);
+
+/*
+ * smb_trans2_set_information
+ *
+ * This is a common function called by both Trans2SetFileInfo
+ * and Trans2SetPathInfo.
+ */
+DWORD
+smb_trans2_set_information(
+ struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ info->level = smb_info_passthru(info->level);
+
+ switch (info->level) {
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
+ return (smb_set_standard_info(sr, info, smberr));
+
+ case SMB_INFO_QUERY_ALL_EAS:
+ /* This info level is not supported */
+ return (NT_STATUS_SUCCESS);
+
+ case SMB_SET_FILE_BASIC_INFO:
+ return (smb_set_basic_info(sr, info, smberr));
+
+ case SMB_SET_FILE_DISPOSITION_INFO:
+ return (smb_set_disposition_info(sr, info, smberr));
+
+ case SMB_SET_FILE_END_OF_FILE_INFO:
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ return (smb_set_alloc_info(sr, info, smberr));
+
+ default:
+ smberr->status = NT_STATUS_INVALID_INFO_CLASS;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_INVALID_PARAMETER;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * smb_info_passthru
+ *
+ * SMB_INFO_PASSTHROUGH
+ * If the server supports information level request passing through,
+ * the client may add the information level with SMB_INFO_PASSTHROUGH
+ * and submit the file information in NT data format instead of SMB
+ * data format. Please refer to MSDN for related NT file information
+ * data structure.
+ *
+ * SMB_INFO_PASSTHROUGH (1000) is defined in win32/cifs.h and the file
+ * information class values are defined in win32/ntifs.h. we have
+ * observed:
+ * 0x3EC = SMB_INFO_PASSTHROUGH + FileBasicInformation (4)
+ * 0x3F5 = SMB_INFO_PASSTHROUGH + FileDispositionInformation (13)
+ * 0x3FC = SMB_INFO_PASSTHROUGH + FileEndOfFileInformation (20)
+ *
+ * Based on network traces between two Win2K systems:
+ * FileBasicInformation <=> SMB_SET_FILE_BASIC_INFO
+ * FileDispositionInformation <=> SMB_SET_FILE_DISPOSITION_INFO
+ * FileEndOfFileInformation <=> SMB_SET_FILE_END_OF_FILE_INFO
+ */
+static unsigned short
+smb_info_passthru(unsigned short infolevel)
+{
+ if (infolevel <= SMB_INFO_PASSTHROUGH)
+ return (infolevel);
+
+ infolevel -= SMB_INFO_PASSTHROUGH;
+
+ switch (infolevel) {
+ case FileBasicInformation:
+ return (SMB_SET_FILE_BASIC_INFO);
+
+ case FileDispositionInformation:
+ return (SMB_SET_FILE_DISPOSITION_INFO);
+
+ case FileEndOfFileInformation:
+ return (SMB_SET_FILE_END_OF_FILE_INFO);
+ }
+
+ return (infolevel);
+}
+
+/*
+ * smb_set_standard_info
+ *
+ * SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
+ *
+ * Data Block Encoding Description
+ * ================================== =================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation
+ * unit
+ * USHORT Attributes; File Attributes
+ * ULONG EaSize; Size of file's EA information
+ * (SMB_INFO_QUERY_EA_SIZE)
+ */
+static DWORD
+smb_set_standard_info(
+ struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ uint32_t Creation, LastAccess, LastWrite; /* times */
+ uint32_t DataSize, AllocationSize;
+ unsigned short Attributes;
+ unsigned int what = 0;
+ timestruc_t crtime, mtime, atime;
+ DWORD status = NT_STATUS_SUCCESS;
+ struct smb_node *node = info->node;
+ int rc;
+
+ if (smb_decode_mbc(&info->ts_xa->req_data_mb, "yyyllw",
+ &Creation, /* CreationDate/Time */
+ &LastAccess, /* LastAccessDate/Time */
+ &LastWrite, /* LastWriteDate/Time */
+ &DataSize, /* File Size */
+ &AllocationSize, /* Block Size */
+ &Attributes) != 0) { /* File Attributes */
+ return (NT_STATUS_DATA_ERROR);
+ }
+
+ if (DataSize != 0) {
+ node->flags |= NODE_FLAGS_SET_SIZE;
+ node->n_size = DataSize;
+ }
+
+ /*
+ * IR101794 The behaviour when the time field is set to -1
+ * is not documented, so we'll assume it should be treated
+ * like 0.
+ */
+ crtime.tv_nsec = mtime.tv_nsec = atime.tv_nsec = 0;
+ if (LastWrite != 0 && LastWrite != (uint32_t)-1) {
+ mtime.tv_sec = smb_local_time_to_gmt(LastWrite);
+ node->set_mtime = mtime;
+ what |= SMB_AT_MTIME;
+ }
+
+ if (Creation != 0 && Creation != (uint32_t)-1) {
+ crtime.tv_sec = smb_local_time_to_gmt(Creation);
+ what |= SMB_AT_CRTIME;
+ }
+
+ if (LastAccess != 0 && LastAccess != (uint32_t)-1) {
+ atime.tv_sec = smb_local_time_to_gmt(LastAccess);
+ what |= SMB_AT_ATIME;
+ }
+
+ if (Attributes != 0)
+ smb_node_set_dosattr(node, Attributes);
+
+ smb_node_set_time(node, &crtime, &mtime, &atime, 0, what);
+ rc = smb_sync_fsattr(sr, sr->user_cr, node);
+ if (rc) {
+ smb_errmap_unix2smb(rc, smberr);
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return (status);
+}
+
+/*
+ * smb_set_basic_info
+ *
+ * Sets basic file/path information.
+ */
+static DWORD
+smb_set_basic_info(
+ struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ uint64_t NT_Creation, NT_LastAccess, NT_LastWrite, NT_Change;
+ unsigned short Attributes;
+ unsigned int what = 0;
+ timestruc_t crtime, mtime, atime, ctime;
+ struct smb_node *node = info->node;
+ DWORD status = NT_STATUS_SUCCESS;
+ int rc;
+
+ if (smb_decode_mbc(&info->ts_xa->req_data_mb, "qqqqw",
+ &NT_Creation, /* CreationDate/Time */
+ &NT_LastAccess, /* LastAccessDate/Time */
+ &NT_LastWrite, /* LastWriteDate/Time */
+ &NT_Change, /* LastWriteDate/Time */
+ &Attributes) != 0) { /* File Attributes */
+ return (NT_STATUS_DATA_ERROR);
+ }
+
+ /*
+ * IR101794 The behaviour when the time field is set to -1
+ * is not documented, so we'll assume it should be treated
+ * like 0.
+ */
+ if (NT_Change != 0 && NT_Change != (uint64_t)-1) {
+ (void) nt_to_unix_time(NT_Change, &ctime);
+ what |= SMB_AT_CTIME;
+ }
+
+ if (NT_Creation != 0 && NT_Creation != (uint64_t)-1) {
+ (void) nt_to_unix_time(NT_Creation, &crtime);
+ what |= SMB_AT_CRTIME;
+ }
+
+ if (NT_LastWrite != 0 && NT_LastWrite != (uint64_t)-1) {
+ (void) nt_to_unix_time(NT_LastWrite, &mtime);
+ node->set_mtime = mtime;
+ what |= SMB_AT_MTIME;
+ }
+
+ if (NT_LastAccess != 0 && NT_LastAccess != (uint64_t)-1) {
+ (void) nt_to_unix_time(NT_LastAccess, &atime);
+ what |= SMB_AT_ATIME;
+ }
+
+ if (Attributes != 0)
+ smb_node_set_dosattr(node, Attributes);
+
+ smb_node_set_time(node, &crtime, &mtime, &atime, &ctime, what);
+ rc = smb_sync_fsattr(sr, sr->user_cr, node);
+ if (rc) {
+ smb_errmap_unix2smb(rc, smberr);
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return (status);
+}
+
+
+/*
+ * smb_set_alloc_info
+ *
+ * Sets file allocation/end_of_file info
+ */
+static DWORD
+smb_set_alloc_info(
+ struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ uint64_t DataSize;
+ DWORD status = NT_STATUS_SUCCESS;
+ struct smb_node *node = info->node;
+ int rc;
+
+ if (sr->fid_ofile == NULL) {
+ smberr->status = NT_STATUS_ACCESS_DENIED;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ if (smb_decode_mbc(&info->ts_xa->req_data_mb, "q", &DataSize) != 0)
+ return (NT_STATUS_DATA_ERROR);
+
+ if (node->attr.sa_vattr.va_size != DataSize) {
+ node->flags |= NODE_FLAGS_SET_SIZE;
+ node->n_size = (off_t)DataSize;
+
+ /*
+ * Ensure that the FS is consistent with the node cache
+ * because the size flag can get cleared by subsequent
+ * write requests without the inode ever being updated.
+ */
+ if ((rc = smb_set_file_size(sr)) != 0) {
+ smb_errmap_unix2smb(rc, smberr);
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * smb_set_disposition_info
+ *
+ * Set/Clear DELETE_ON_CLOSE flag for an open file.
+ * File should have been opened with DELETE access otherwise
+ * the operation is not permitted.
+ *
+ * NOTE: The node should be marked delete-on-close upon the receipt
+ * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
+ * It is different than both SmbNtCreateAndX and SmbNtTransact, which
+ * set delete-on-close on the ofile and defer setting the flag on the
+ * node until the file is closed.
+ *
+ * Observation of Windows 2000 indicates the following:
+ *
+ * 1) If a file is not opened with delete-on-close create options and
+ * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
+ * using that open file handle, any subsequent open requests will fail
+ * with DELETE_PENDING.
+ *
+ * 2) If a file is opened with delete-on-close create options and the
+ * client attempts to unset delete-on-close via Trans2SetFileInfo
+ * (SetDispositionInfo) prior to the file close, any subsequent open
+ * requests will still fail with DELETE_PENDING after the file is closed.
+ *
+ * 3) If a file is opened with delete-on-close create options and that
+ * file handle (not the last open handle and the only file handle
+ * with delete-on-close set) is closed. Any subsequent open requests
+ * will fail with DELETE_PENDING. Unsetting delete-on-close via
+ * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
+ * node delete-on-close flag, which will result in the file not being
+ * removed even after the last file handle is closed.
+ */
+static DWORD
+smb_set_disposition_info(
+ smb_request_t *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ unsigned char mark_delete;
+
+ if (smb_decode_mbc(&info->ts_xa->req_data_mb, "b", &mark_delete) != 0)
+ return (NT_STATUS_DATA_ERROR);
+
+ if ((sr->fid_ofile == NULL) ||
+ !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
+ smberr->status = NT_STATUS_ACCESS_DENIED;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ if (mark_delete) {
+ if (smb_node_set_delete_on_close(info->node,
+ sr->user_cr)) {
+ smberr->status = NT_STATUS_CANNOT_DELETE;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+ } else {
+ smb_node_reset_delete_on_close(info->node);
+ }
+ return (NT_STATUS_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
new file mode 100644
index 0000000000..02be8c53cb
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_set_path_information
+ *
+ * This request is used to set information about a specific file or
+ * subdirectory.
+ *
+ * Client Request Value
+ * ========================== =========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_SET_PATH_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ========================== =========================================
+ *
+ * USHORT InformationLevel; Level of information to set
+ * ULONG Reserved; Must be zero
+ * STRING FileName; File or directory name
+ *
+ * The following InformationLevels may be set:
+ *
+ * Information Level Value
+ * ========================== =========================================
+ *
+ * SMB_INFO_STANDARD 1
+ * SMB_INFO_QUERY_EA_SIZE 2
+ * SMB_INFO_QUERY_ALL_EAS 4
+ *
+ * The response formats are:
+ *
+ * 4.2.16.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
+ *
+ * Parameter Block Encoding Description
+ * ================================== =================================
+ *
+ * USHORT Reserved 0
+ *
+ * Data Block Encoding Description
+ * ================================== =================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation
+ * unit
+ * USHORT Attributes; File Attributes
+ * ULONG EaSize; Size of file's EA information
+ * (SMB_INFO_QUERY_EA_SIZE)
+ *
+ * 4.2.16.2 SMB_INFO_QUERY_ALL_EAS
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * MaxDataCount Length of FEAlist found (minimum value is 4)
+ *
+ * Parameter Block Description
+ * Encoding ===============================================
+ * ====================
+ *
+ * USHORT EaErrorOffset Offset into EAList of EA error
+ *
+ * Data Block Encoding Description
+ * ==================== ===============================================
+ *
+ * ULONG ListLength; Length of the remaining data
+ * UCHAR EaList[] The extended attributes list
+ *
+ * Undocumented things:
+ * Poorly documented information levels. Information must be infered
+ * from other commands.
+ *
+ * NULL Attributes means don't set them. NT sets the high bit to
+ * set attributes to 0.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_trans2_set_path_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_trans2_setinfo_t *info;
+ smb_attr_t ret_attr;
+ struct smb_node *dir_node;
+ struct smb_node *ret_snode;
+ smb_error_t smberr;
+ DWORD status;
+ int rc = 0;
+
+ info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
+ info->ts_xa = xa;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%w4.u", sr, &info->level,
+ &info->path) != 0) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type) ||
+ SMB_TREE_IS_READ_ONLY(sr)) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ rc = smb_pathname_reduce(sr, sr->user_cr, info->path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode,
+ &dir_node, info->name);
+
+ if (rc != 0) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_node, info->name, &ret_snode, &ret_attr,
+ 0, 0);
+
+ smb_node_release(dir_node);
+
+ if (rc != 0) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_errno(sr, rc);
+ }
+
+ info->node = ret_snode;
+ status = smb_trans2_set_information(sr, info, &smberr);
+ info->node = NULL;
+ smb_node_release(ret_snode);
+ if (status == NT_STATUS_DATA_ERROR) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ } else if (status == NT_STATUS_UNSUCCESSFUL) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, smberr.status,
+ smberr.errcls, smberr.errcode);
+ /* NOTREACHED */
+ }
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c
new file mode 100644
index 0000000000..85d663c88c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c
@@ -0,0 +1,733 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General Structures Layout
+ * -------------------------
+ *
+ * This is a simplified diagram showing the relationship between most of the
+ * main structures.
+ *
+ * +-------------------+
+ * | SMB_INFO |
+ * +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | SESSION |<----->| SESSION |......| SESSION |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | USER |<----->| USER |......| USER |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | TREE |<----->| TREE |......| TREE |
+ * +-------------------+ +-------------------+ +-------------------+
+ * | |
+ * | |
+ * | v
+ * | +-------+ +-------+ +-------+
+ * | | OFILE |<----->| OFILE |......| OFILE |
+ * | +-------+ +-------+ +-------+
+ * |
+ * |
+ * v
+ * +-------+ +------+ +------+
+ * | ODIR |<----->| ODIR |......| ODIR |
+ * +-------+ +------+ +------+
+ *
+ *
+ * Tree State Machine
+ * ------------------
+ *
+ * +-----------------------------+ T0
+ * | SMB_TREE_STATE_CONNECTED |<----------- Creation/Allocation
+ * +-----------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +------------------------------+
+ * | SMB_TREE_STATE_DISCONNECTING |
+ * +------------------------------+
+ * |
+ * | T2
+ * |
+ * v
+ * +-----------------------------+ T3
+ * | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free
+ * +-----------------------------+
+ *
+ * SMB_TREE_STATE_CONNECTED
+ *
+ * While in this state:
+ * - The tree is queued in the list of trees of its user.
+ * - References will be given out if the tree is looked up.
+ * - Files under that tree can be accessed.
+ *
+ * SMB_TREE_STATE_DISCONNECTING
+ *
+ * While in this state:
+ * - The tree is queued in the list of trees of its user.
+ * - References will not be given out if the tree is looked up.
+ * - The files and directories open under the tree are being closed.
+ * - The resources associated with the tree remain.
+ *
+ * SMB_TREE_STATE_DISCONNECTED
+ *
+ * While in this state:
+ * - The tree is queued in the list of trees of its user.
+ * - References will not be given out if the tree is looked up.
+ * - The tree has no more files and directories opened.
+ * - The resources associated with the tree remain.
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_tree_connect(). A new tree is created and
+ * added to the list of trees of a user.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_tree_disconnect().
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_tree_release(). The resources associated
+ * with the tree are freed as well as the tree structure. For the transition
+ * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and
+ * the reference count be zero.
+ *
+ * Comments
+ * --------
+ *
+ * The state machine of the tree structures is controlled by 3 elements:
+ * - The list of trees of the user it belongs to.
+ * - The mutex embedded in the structure itself.
+ * - The reference count.
+ *
+ * There's a mutex embedded in the tree structure used to protect its fields
+ * and there's a lock embedded in the list of trees of a user. To
+ * increment or to decrement the reference count the mutex must be entered.
+ * To insert the tree into the list of trees of the user and to remove
+ * the tree from it, the lock must be entered in RW_WRITER mode.
+ *
+ * Rules of access to a tree structure:
+ *
+ * 1) In order to avoid deadlocks, when both (mutex and lock of the user
+ * list) have to be entered, the lock must be entered first.
+ *
+ * 2) All actions applied to a tree require a reference count.
+ *
+ * 3) There are 2 ways of getting a reference count. One is when the tree
+ * is connected. The other when the user is looked up. This translates
+ * into 2 functions: smb_tree_connect() and smb_tree_lookup_by_tid().
+ *
+ * It should be noted that the reference count of a tree registers the
+ * number of references to the tree in other structures (such as an smb
+ * request). The reference count is not incremented in these 2 instances:
+ *
+ * 1) The tree is connected. An tree is anchored by his state. If there's
+ * no activity involving a tree currently connected, the reference
+ * count of that tree is zero.
+ *
+ * 2) The tree is queued in the list of trees of the user. The fact of
+ * being queued in that list is NOT registered by incrementing the
+ * reference count.
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+/* Static functions defined further down this file. */
+static void smb_tree_delete(smb_tree_t *);
+static smb_tree_t *smb_tree_lookup_head(smb_llist_t *);
+static smb_tree_t *smb_tree_lookup_next(smb_llist_t *, smb_tree_t *);
+
+/*
+ * smb_tree_connect
+ */
+smb_tree_t *
+smb_tree_connect(
+ smb_user_t *user,
+ uint16_t access_flags,
+ char *sharename,
+ char *resource,
+ int32_t stype,
+ smb_node_t *snode,
+ fsvol_attr_t *vol_attr)
+{
+ smb_tree_t *tree;
+ uint16_t tid;
+
+ if (smb_idpool_alloc(&user->u_tid_pool, &tid)) {
+ return (NULL);
+ }
+
+ tree = kmem_cache_alloc(smb_info.si_cache_tree, KM_SLEEP);
+ bzero(tree, sizeof (smb_tree_t));
+
+ if (smb_idpool_constructor(&tree->t_fid_pool)) {
+ smb_idpool_free(&user->u_tid_pool, tid);
+ kmem_cache_free(smb_info.si_cache_tree, tree);
+ return (NULL);
+ }
+
+ if (smb_idpool_constructor(&tree->t_sid_pool)) {
+ smb_idpool_destructor(&tree->t_fid_pool);
+ smb_idpool_free(&user->u_tid_pool, tid);
+ kmem_cache_free(smb_info.si_cache_tree, tree);
+ return (NULL);
+ }
+
+ smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
+ offsetof(smb_ofile_t, f_lnd));
+
+ smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
+ offsetof(smb_odir_t, d_lnd));
+
+ (void) strlcpy(tree->t_sharename, sharename,
+ sizeof (tree->t_sharename));
+ (void) strlcpy(tree->t_resource, resource, sizeof (tree->t_resource));
+
+ mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
+
+ tree->t_user = user;
+ tree->t_session = user->u_session;
+ tree->t_refcnt = 1;
+ tree->t_tid = tid;
+ tree->t_access = access_flags;
+ tree->t_res_type = stype;
+ tree->t_snode = snode;
+ tree->t_state = SMB_TREE_STATE_CONNECTED;
+ tree->t_magic = SMB_TREE_MAGIC;
+
+ switch (stype & STYPE_MASK) {
+ case STYPE_DISKTREE:
+ tree->t_fsd = snode->tree_fsd;
+
+ (void) strlcpy(tree->t_typename, vol_attr->fs_typename,
+ SMB_TREE_TYPENAME_SZ);
+ (void) utf8_strupr((char *)tree->t_typename);
+
+ if (vol_attr->flags & FSOLF_READONLY)
+ tree->t_access = SMB_TREE_READ_ONLY;
+
+ tree->t_acltype = smb_fsop_acltype(snode);
+
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACLONCREATE)) {
+ tree->t_flags |= SMB_TREE_FLAG_ACLONCREATE;
+ }
+
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACEMASKONACCESS)) {
+ tree->t_flags |= SMB_TREE_FLAG_ACEMASKONACCESS;
+ }
+
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_CASEINSENSITIVE)) {
+ tree->t_flags |= SMB_TREE_FLAG_IGNORE_CASE;
+ }
+ break;
+
+ case STYPE_IPC:
+ default:
+ tree->t_typename[0] = '\0';
+ break;
+ }
+
+ smb_llist_enter(&user->u_tree_list, RW_WRITER);
+ smb_llist_insert_head(&user->u_tree_list, tree);
+ smb_llist_exit(&user->u_tree_list);
+ atomic_inc_32(&user->u_session->s_tree_cnt);
+ atomic_inc_32(&smb_info.open_trees);
+
+ return (tree);
+}
+
+/*
+ * smb_tree_disconnect
+ *
+ *
+ */
+void
+smb_tree_disconnect(
+ smb_tree_t *tree)
+{
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ mutex_enter(&tree->t_mutex);
+ ASSERT(tree->t_refcnt);
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_CONNECTED: {
+ /*
+ * The tree is moved into a state indicating that the disconnect
+ * process has started.
+ */
+ tree->t_state = SMB_TREE_STATE_DISCONNECTING;
+ mutex_exit(&tree->t_mutex);
+ atomic_dec_32(&smb_info.open_trees);
+ /*
+ * The files opened under this tree are closed.
+ */
+ smb_ofile_close_all(tree);
+ /*
+ * The directories opened under this tree are closed.
+ */
+ smb_odir_close_all(tree);
+ mutex_enter(&tree->t_mutex);
+ tree->t_state = SMB_TREE_STATE_DISCONNECTED;
+ /*FALLTHRU*/
+ }
+ case SMB_TREE_STATE_DISCONNECTED:
+ case SMB_TREE_STATE_DISCONNECTING:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&tree->t_mutex);
+}
+
+/*
+ * smb_tree_disconnect_all
+ *
+ *
+ */
+void
+smb_tree_disconnect_all(
+ smb_user_t *user)
+{
+ smb_tree_t *tree;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ tree = smb_tree_lookup_head(&user->u_tree_list);
+ while (tree) {
+ ASSERT(tree->t_user == user);
+ smb_tree_disconnect(tree);
+ smb_tree_release(tree);
+ tree = smb_tree_lookup_head(&user->u_tree_list);
+ }
+}
+
+/*
+ * smb_tree_close_all_by_pid
+ *
+ *
+ */
+void
+smb_tree_close_all_by_pid(
+ smb_user_t *user,
+ uint16_t pid)
+{
+ smb_tree_t *tree;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ tree = smb_tree_lookup_head(&user->u_tree_list);
+ while (tree) {
+ smb_tree_t *next;
+ ASSERT(tree->t_user == user);
+ smb_ofile_close_all_by_pid(tree, pid);
+ smb_odir_close_all_by_pid(tree, pid);
+ next = smb_tree_lookup_next(&user->u_tree_list, tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+}
+
+/*
+ * smb_tree_release
+ *
+ *
+ */
+void
+smb_tree_release(
+ smb_tree_t *tree)
+{
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ mutex_enter(&tree->t_mutex);
+ ASSERT(tree->t_refcnt);
+ tree->t_refcnt--;
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_DISCONNECTED:
+ if (tree->t_refcnt == 0) {
+ mutex_exit(&tree->t_mutex);
+ smb_tree_delete(tree);
+ return;
+ }
+ break;
+
+ case SMB_TREE_STATE_CONNECTED:
+ case SMB_TREE_STATE_DISCONNECTING:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&tree->t_mutex);
+}
+
+/*
+ * Find the appropriate tree for this request. The request credentials
+ * set here override those set during uid lookup. In domain mode, the
+ * user and tree credentials should be the same. In share mode, the
+ * tree credentials (defined in the share definition) should override
+ * the user credentials.
+ */
+smb_tree_t *
+smb_tree_lookup_by_tid(
+ smb_user_t *user,
+ uint16_t tid)
+{
+ smb_tree_t *tree;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ smb_llist_enter(&user->u_tree_list, RW_READER);
+ tree = smb_llist_head(&user->u_tree_list);
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ if (tree->t_tid == tid) {
+ mutex_enter(&tree->t_mutex);
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_CONNECTED:
+ /* The tree exists and is still connected. */
+ tree->t_refcnt++;
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (tree);
+ case SMB_TREE_STATE_DISCONNECTING:
+ case SMB_TREE_STATE_DISCONNECTED:
+ /*
+ * The tree exists but is diconnected or is in
+ * the process of being destroyed.
+ */
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+ default:
+ ASSERT(0);
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+ }
+ }
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ }
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+}
+
+/*
+ * smb_tree_lookup_first_by_name
+ *
+ * This function returns the first tree in the connected state that matches the
+ * sharename passed in. If the tree provided is NULL the search starts from
+ * the beginning of the list of trees of the user. It a tree is provided the
+ * search starts just after that tree.
+ */
+smb_tree_t *
+smb_tree_lookup_by_name(
+ smb_user_t *user,
+ char *sharename,
+ smb_tree_t *tree)
+{
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(sharename);
+
+ smb_llist_enter(&user->u_tree_list, RW_READER);
+
+ if (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ } else {
+ tree = smb_llist_head(&user->u_tree_list);
+ }
+
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ if (strcmp(tree->t_sharename, sharename) == 0) {
+ mutex_enter(&tree->t_mutex);
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_CONNECTED:
+ /* The tree exists and is still connected. */
+ tree->t_refcnt++;
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (tree);
+ case SMB_TREE_STATE_DISCONNECTING:
+ case SMB_TREE_STATE_DISCONNECTED:
+ /*
+ * The tree exists but is diconnected or is in
+ * the process of being destroyed.
+ */
+ mutex_exit(&tree->t_mutex);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&tree->t_mutex);
+ break;
+ }
+ }
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ }
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+}
+
+/*
+ * smb_tree_lookup_first_by_fsd
+ *
+ * This function returns the first tree in the connected state that matches the
+ * fsd passed in. If the tree provided is NULL the search starts from
+ * the beginning of the list of trees of the user. It a tree is provided the
+ * search starts just after that tree.
+ */
+smb_tree_t *
+smb_tree_lookup_by_fsd(
+ smb_user_t *user,
+ fs_desc_t *fsd,
+ smb_tree_t *tree)
+{
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(fsd);
+
+ smb_llist_enter(&user->u_tree_list, RW_READER);
+
+ if (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ } else {
+ tree = smb_llist_head(&user->u_tree_list);
+ }
+
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ if (fsd_cmp(&tree->t_fsd, fsd) == 0) {
+ mutex_enter(&tree->t_mutex);
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_CONNECTED:
+ /* The tree exists and is still connected. */
+ tree->t_refcnt++;
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (tree);
+ case SMB_TREE_STATE_DISCONNECTING:
+ case SMB_TREE_STATE_DISCONNECTED:
+ /*
+ * The tree exists but is diconnected or is in
+ * the process of being destroyed.
+ */
+ mutex_exit(&tree->t_mutex);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&tree->t_mutex);
+ break;
+ }
+ }
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ }
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+}
+
+/* *************************** Static Functions ***************************** */
+
+/*
+ * smb_tree_delete
+ *
+ * This function releases all the resources associated with a tree. It also
+ * removes the tree the caller passes from the list of trees of the user.
+ *
+ * The tree to destroy must be in the "destroying state" and the reference count
+ * must be zero. This function assumes it's single threaded i.e. only one
+ * thread will attempt to destroy a specific tree (this condition should be met
+ * if the tree is is the "destroying state" and has a reference count of zero).
+ *
+ * Entry:
+ * tree Tree to destroy
+ *
+ * Exit:
+ * Nothing
+ *
+ * Return:
+ * Nothing
+ */
+static void
+smb_tree_delete(smb_tree_t *tree)
+{
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
+ ASSERT(tree->t_refcnt == 0);
+
+ /*
+ * Let's remove the tree from the list of trees of the
+ * user. This has to be done before any resources
+ * associated with the tree are released.
+ */
+ smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER);
+ smb_llist_remove(&tree->t_user->u_tree_list, tree);
+ smb_llist_exit(&tree->t_user->u_tree_list);
+
+ tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
+ smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid);
+ atomic_dec_32(&tree->t_session->s_tree_cnt);
+
+ if (tree->t_snode) {
+ smb_node_release(tree->t_snode);
+ }
+ mutex_destroy(&tree->t_mutex);
+ /*
+ * The list of open files and open directories should be empty.
+ */
+ smb_llist_destructor(&tree->t_ofile_list);
+ smb_llist_destructor(&tree->t_odir_list);
+ smb_idpool_destructor(&tree->t_fid_pool);
+ smb_idpool_destructor(&tree->t_sid_pool);
+ kmem_cache_free(smb_info.si_cache_tree, tree);
+}
+
+/*
+ * smb_tree_lookup_head
+ *
+ * This function returns the first tree in the list that is in the
+ * SMB_TREE_STATE_CONNECTED. A reference is taken on the tree and
+ * smb_tree_release() will have to be called for the tree returned.
+ *
+ * Entry:
+ * lst List of trees (usually the list of trees of a user)
+ *
+ * Exit:
+ * Nothing
+ *
+ * Return:
+ * NULL No tree in the SMB_TREE_STATE_CONNECTED state was found.
+ * !NULL First tree in the list in the SMB_TREE_STATE_CONNECTED state.
+ */
+static smb_tree_t *
+smb_tree_lookup_head(
+ smb_llist_t *lst)
+{
+ smb_tree_t *tree;
+
+ smb_llist_enter(lst, RW_READER);
+ tree = smb_llist_head(lst);
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ mutex_enter(&tree->t_mutex);
+ if (tree->t_state == SMB_TREE_STATE_CONNECTED) {
+ tree->t_refcnt++;
+ mutex_exit(&tree->t_mutex);
+ break;
+ } else if ((tree->t_state == SMB_TREE_STATE_DISCONNECTING) ||
+ (tree->t_state == SMB_TREE_STATE_DISCONNECTED)) {
+ mutex_exit(&tree->t_mutex);
+ tree = smb_llist_next(lst, tree);
+ } else {
+ ASSERT(0);
+ mutex_exit(&tree->t_mutex);
+ tree = smb_llist_next(lst, tree);
+ }
+ }
+ smb_llist_exit(lst);
+
+ return (tree);
+}
+
+/*
+ * smb_tree_lookup_next
+ *
+ * This function returns the next tree in the list that is in the
+ * SMB_TREE_STATE_CONNECTED. A reference is taken on the tree and
+ * smb_tree_release() will have to be called for the tree returned.
+ *
+ * Entry:
+ * lst List of trees (usually the list of trees of a user).
+ * tree Starting tree.
+ *
+ * Exit:
+ * Nothing
+ *
+ * Return:
+ * NULL No tree in the SMB_TREE_STATE_CONNECTED state was found.
+ * !NULL Next tree in the list in the SMB_TREE_STATE_CONNECTED state.
+ */
+static smb_tree_t *
+smb_tree_lookup_next(
+ smb_llist_t *lst,
+ smb_tree_t *tree)
+{
+ smb_tree_t *next;
+
+ ASSERT(lst);
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_refcnt);
+
+ smb_llist_enter(lst, RW_READER);
+ next = smb_llist_next(lst, tree);
+ while (next) {
+ ASSERT(next->t_magic == SMB_TREE_MAGIC);
+ mutex_enter(&next->t_mutex);
+ if (next->t_state == SMB_TREE_STATE_CONNECTED) {
+ next->t_refcnt++;
+ mutex_exit(&next->t_mutex);
+ break;
+ } else if ((next->t_state == SMB_TREE_STATE_DISCONNECTING) ||
+ (next->t_state == SMB_TREE_STATE_DISCONNECTED)) {
+ mutex_exit(&next->t_mutex);
+ next = smb_llist_next(lst, next);
+ } else {
+ ASSERT(0);
+ mutex_exit(&next->t_mutex);
+ next = smb_llist_next(lst, next);
+ }
+ }
+ smb_llist_exit(lst);
+
+ return (next);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
new file mode 100644
index 0000000000..9f8d15807e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: tree_connect
+ *
+ * When a client connects to a server resource, an SMB_COM_TREE_CONNECT
+ * message is generated to the server. This command is almost exactly like
+ * SMB_COM_TREE_CONNECT_ANDX, except that no AndX command may follow; see
+ * section 4.1.4.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 4
+ * UCHAR BufferFormat1; 0x04
+ * STRING Path[]; Server name and share name
+ * UCHAR BufferFormat2; 0x04
+ * STRING Password[]; Password
+ * UCHAR BufferFormat3; 0x04
+ * STRING Service[]; Service name
+ *
+ * The CIFS server responds with:
+ *
+ * Server Response Description
+ * ================================ =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT MaxBufferSize; Max size message the server handles
+ * USHORT Tid; Tree ID
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * If the negotiated dialect is MICROSOFT NETWORKS 1.03 or earlier,
+ * MaxBufferSize in the response message indicates the maximum size message
+ * that the server can handle. The client should not generate messages,
+ * nor expect to receive responses, larger than this. This must be
+ * constant for a given server. For newer dialects, this field is ignored.
+ *
+ * Tid should be included in any future SMBs referencing this tree
+ * connection.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_tree_connect(struct smb_request *sr)
+{
+ /*
+ * I'm not sure it this should be "%A.sA"
+ * now that unicode is enabled.
+ */
+ if (smbsr_decode_data(sr, "%AAA", sr, &sr->arg.tcon.path,
+ &sr->arg.tcon.password, &sr->arg.tcon.service) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->arg.tcon.flags = 0;
+
+ /*
+ * If the negotiated dialect is MICROSOFT NETWORKS 1.03
+ * or earlier, MaxBufferSize in the response message
+ * indicates the maximum size message that the server can
+ * handle. The client should not generate messages, nor
+ * expect to receive responses, larger than this. This
+ * must be constant for a given server. For newer dialects,
+ * this field is ignored.
+ *
+ * The reason for this is that the maximum buffer size is
+ * established during the NEGOTIATE.
+ */
+
+ (void) smbsr_connect_tree(sr);
+
+ smbsr_encode_result(sr, 2, 0, "bwww",
+ 2, /* wct */
+ (WORD)smb_maxbufsize, /* MaxBufferSize */
+ sr->smb_tid, /* TID */
+ 0); /* bcc */
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree_connect_andx.c b/usr/src/uts/common/fs/smbsrv/smb_tree_connect_andx.c
new file mode 100644
index 0000000000..436ecf906c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect_andx.c
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: tree_connect_andx
+ *
+ * Client Request Description
+ * ================================= =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 4
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Flags; Additional information
+ * bit 0 set = disconnect Tid
+ * USHORT PasswordLength; Length of Password[]
+ * USHORT ByteCount; Count of data bytes; min = 3
+ * UCHAR Password[]; Password
+ * STRING Path[]; Server name and share name
+ * STRING Service[]; Service name
+ *
+ * The serving machine verifies the combination and returns an error code
+ * or an identifier. The full name is included in this request message and
+ * the identifier identifying the connection is returned in the Tid field
+ * of the SMB header. The Tid field in the client request is ignored. The
+ * meaning of this identifier (Tid) is server specific; the client must not
+ * associate any specific meaning to it.
+ *
+ * If the negotiated dialect is LANMAN1.0 or later, then it is a protocol
+ * violation for the client to send this message prior to a successful
+ * SMB_COM_SESSION_SETUP_ANDX, and the server ignores Password.
+ *
+ * If the negotiated dialect is prior to LANMAN1.0 and the client has not
+ * sent a successful SMB_COM_SESSION_SETUP_ANDX request when the tree
+ * connect arrives, a user level security mode server must nevertheless
+ * validate the client's credentials as discussed earlier in this document.
+ *
+ * Path follows UNC style syntax, that is to say it is encoded as
+ * \\server\share and it indicates the name of the resource to which the
+ * client wishes to connect.
+ *
+ * Because Password may be an authentication response, it is a variable
+ * length field with the length specified by PasswordLength. If
+ * authentication is not being used, Password should be a null terminated
+ * ASCII string with PasswordLength set to the string size including the
+ * terminating null.
+ *
+ * The server can enforce whatever policy it desires to govern share
+ * access. Typically, if the server is paused, administrative privilege is
+ * required to connect to any share; if the server is not paused,
+ * administrative privilege is required only for administrative shares (C$,
+ * etc.). Other such policies may include valid times of day, software
+ * usage license limits, number of simultaneous server users or share
+ * users, etc.
+ *
+ * The Service component indicates the type of resource the client intends
+ * to access. Valid values are:
+ *
+ * Service Description Earliest Dialect Allowed
+ * ======== ======================== ================================
+ *
+ * A: disk share PC NETWORK PROGRAM 1.0
+ * LPT1: printer PC NETWORK PROGRAM 1.0
+ * IPC named pipe MICROSOFT NETWORKS 3.0
+ * COMM communications device MICROSOFT NETWORKS 3.0
+ * ????? any type of device MICROSOFT NETWORKS 3.0
+ *
+ * If bit0 of Flags is set, the tree connection to Tid in the SMB header
+ * should be disconnected. If this tree disconnect fails, the error should
+ * be ignored.
+ *
+ * If the negotiated dialect is earlier than DOS LANMAN2.1, the response to
+ * this SMB is:
+ *
+ * Server Response Description
+ * ================================ ===================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes; min = 3
+ *
+ * If the negotiated is DOS LANMAN2.1 or later, the response to this SMB
+ * is:
+ *
+ * Server Response Description
+ * ================================ ===================================
+ *
+ * UCHAR WordCount; Count of parameter words = 3
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT OptionalSupport; Optional support bits
+ * USHORT ByteCount; Count of data bytes; min = 3
+ * UCHAR Service[]; Service type connected to. Always
+ * ANSII.
+ * STRING NativeFileSystem[]; Native file system for this tree
+ *
+ * NativeFileSystem is the name of the filesystem; values to be expected
+ * include FAT, NTFS, etc.
+ *
+ * OptionalSupport bits has the encoding:
+ *
+ * Name Encoding Description
+ * ============================= ========= ==========================
+ *
+ * SMB_SUPPORT_SEARCH_BITS 0x0001
+ *
+ * SMB_SHARE_IS_IN_DFS 0x0002
+ *
+ * Some servers negotiate "DOS LANMAN2.1" dialect or later and still send
+ * the "downlevel" (i.e. wordcount==2) response. Valid AndX following
+ * commands are
+ *
+ * SMB_COM_OPEN SMB_COM_OPEN_ANDX SMB_COM_CREATE
+ * SMB_COM_CREATE_NEW SMB_COM_CREATE_DIRECTORY SMB_COM_DELETE
+ * SMB_COM_DELETE_DIRECTORY SMB_COM_FIND SMB_COM_COPY
+ * SMB_COM_FIND_UNIQUE SMB_COM_RENAME
+ * SMB_COM_CHECK_DIRECTORY SMB_COM_QUERY_INFORMATION
+ * SMB_COM_GET_PRINT_QUEUE SMB_COM_OPEN_PRINT_FILE
+ * SMB_COM_TRANSACTION SMB_COM_NO_ANDX_CMD
+ * SMB_COM_SET_INFORMATION SMB_COM_NT_RENAME
+ *
+ * 4.1.4.1 Errors
+ *
+ * ERRDOS/ERRnomem
+ * ERRDOS/ERRbadpath
+ *
+ * ERRDOS/ERRinvdevice
+ * ERRSRV/ERRaccess
+ * ERRSRV/ERRbadpw
+ * ERRSRV/ERRinvnetname
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_tree_connect_andx(struct smb_request *sr)
+{
+ unsigned char *pwbuf = NULL;
+ unsigned short pwlen = 0;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, "b.www", &sr->andx_com, &sr->andx_off,
+ &sr->arg.tcon.flags, &pwlen);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (pwlen != 0) {
+ pwbuf = (unsigned char *)smbsr_malloc(&sr->request_storage,
+ pwlen);
+ bzero(pwbuf, pwlen);
+ }
+
+ if (smbsr_decode_data(sr, "%#cus", sr, pwlen, pwbuf,
+ &sr->arg.tcon.path, &sr->arg.tcon.service) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->arg.tcon.pwdlen = pwlen;
+ sr->arg.tcon.password = (char *)pwbuf;
+
+ (void) smbsr_connect_tree(sr);
+
+ if (sr->session->dialect < NT_LM_0_12) {
+ smbsr_encode_result(sr, 2, VAR_BCC, "bb.wwss",
+ (char)2, /* wct */
+ sr->andx_com,
+ VAR_BCC,
+ VAR_BCC,
+ sr->arg.tcon.service,
+ sr->tid_tree->t_typename);
+ } else {
+ smbsr_encode_result(sr, 3, VAR_BCC, "bb.wwws%u",
+ (char)3, /* wct */
+ sr->andx_com,
+ (short)64,
+ (short)SMB_TREE_SUPPORT_SEARCH_BITS,
+ VAR_BCC,
+ sr->arg.tcon.service,
+ sr,
+ sr->tid_tree->t_typename);
+ }
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree_disconnect.c b/usr/src/uts/common/fs/smbsrv/smb_tree_disconnect.c
new file mode 100644
index 0000000000..9139930a4d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_disconnect.c
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: tree_disconnect
+ *
+ * This message informs the server that the client no longer wishes to
+ * access the resource connected to with a prior SMB_COM_TREE_CONNECT or
+ * SMB_COM_TREE_CONNECT_ANDX.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The resource sharing connection identified by Tid in the SMB header is
+ * logically disconnected from the server. Tid is invalidated; it will not
+ * be recognized if used by the client for subsequent requests. All locks,
+ * open files, etc. created on behalf of Tid are released.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * 4.1.5.1 Errors
+ *
+ * ERRSRV/ERRinvnid
+ * ERRSRV/ERRbaduid
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * Function: int smb_com_tree_disconnect(struct smb_request *)
+ *
+ * Please note the SDDF_SUPPRESS_UID is set for this operation;
+ * therefore, the uid_user field in sr is invalid. Do not use it
+ * or the system would panic.
+ *
+ * Please also note that in some cases, the client would not send
+ * tree disconnect call. An example of that is, the return of invalid
+ * uid for a client request i.e. read_andx, when the used has logged
+ * off. This will cause a minor memory leak for the share and some
+ * files would remain open. When the session is destroyed, the leaked
+ * and remained open files will be freed/closed. We will need to
+ * address this problem by re-architecting user/tree structures.
+ * For the time being, we will leave it till we have time.
+ */
+
+int
+smb_com_tree_disconnect(struct smb_request *sr)
+{
+ /*
+ * A Tree Disconnect request requires a valid user ID as well as a
+ * valid tree ID. However, some clients logoff a user and then try to
+ * disconnect the trees connected using the user they just logged off.
+ * There's a problem with that behavior and the tree representation
+ * of the different contexts (session, user, tree, file...). In order
+ * to find a tree a valid user has to be provided. This means, with
+ * the behavior described above, a client would receive a negative
+ * response to the TreeDisconnect request with an error code saying
+ * ERRbaduid. That response breaks some clients. To prevent that
+ * from happening, the dispatch table indicates that, for the
+ * TreeDisconnect request, the UID and the TID shouldn't be looked up
+ * in the dispatch routine. The lookup is done here. If the user or
+ * the tree cannot be identified a negative response is sent back with
+ * the error code ERRinvnid.
+ */
+ sr->uid_user = smb_user_lookup_by_uid(sr->session, &sr->user_cr,
+ sr->smb_uid);
+ if (sr->uid_user != NULL)
+ sr->tid_tree = smb_tree_lookup_by_tid(sr->uid_user,
+ sr->smb_tid);
+
+ if (sr->uid_user == NULL || sr->tid_tree == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRinvnid);
+ }
+ smbsr_rq_notify(sr, sr->session, sr->tid_tree);
+ smb_tree_disconnect(sr->tid_tree);
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
new file mode 100644
index 0000000000..420c26a250
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: unlock_byte_range
+ *
+ * This message is sent to unlock the given byte range. Offset, Count, and
+ * Pid must be identical to that specified in a prior successful lock. If
+ *
+ * an unlock references an address range that is not locked, no error is
+ * generated.
+ *
+ * Since Offset is a 32 bit quantity, this request is inappropriate for
+ * general locking within a very large file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 5
+ * USHORT Fid; File handle
+ * ULONG Count; Count of bytes to unlock
+ * ULONG Offset; Offset from start of file
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_unlock_byte_range(struct smb_request *sr)
+{
+ uint32_t Length;
+ uint32_t Offset;
+ DWORD result;
+
+ if (smbsr_decode_vwv(sr, "wll", &sr->smb_fid, &Length, &Offset) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ result = smb_unlock_range(sr, sr->fid_ofile->f_node,
+ (off_t)Offset, (uint64_t)Length);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_unlock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_upcalls.c b/usr/src/uts/common/fs/smbsrv/smb_upcalls.c
new file mode 100644
index 0000000000..a421640b1b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_upcalls.c
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smb_vops.h>
+#include <sys/stat.h>
+
+
+void
+smb_user_nonauth_logon(uint32_t audit_sid)
+{
+ char *arg, *rsp;
+ size_t arg_size, rsp_size;
+
+ arg = smb_kdr_encode_common(SMB_DR_USER_NONAUTH_LOGON,
+ &audit_sid, xdr_uint32_t, &arg_size);
+
+ if (arg != NULL) {
+ rsp = smb_kdoor_clnt_upcall(arg, arg_size, NULL, 0, &rsp_size);
+ smb_kdoor_clnt_free(arg, arg_size, rsp, rsp_size);
+ }
+}
+
+void
+smb_user_auth_logoff(uint32_t audit_sid)
+{
+ char *arg, *rsp;
+ size_t arg_size, rsp_size;
+
+ arg = smb_kdr_encode_common(SMB_DR_USER_AUTH_LOGOFF,
+ &audit_sid, xdr_uint32_t, &arg_size);
+
+ if (arg != NULL) {
+ rsp = smb_kdoor_clnt_upcall(arg, arg_size, NULL, 0, &rsp_size);
+ smb_kdoor_clnt_free(arg, arg_size, rsp, rsp_size);
+ }
+}
+
+smb_token_t *
+smb_upcall_get_token(netr_client_t *clnt_info)
+{
+ char *argp, *rbufp;
+ size_t arg_size, rbuf_size;
+ smb_token_t *token = NULL;
+
+ argp = smb_dr_encode_arg_get_token(clnt_info, &arg_size);
+ rbufp = smb_kdoor_clnt_upcall(argp, arg_size, NULL, 0, &rbuf_size);
+ if (rbufp)
+ token = smb_dr_decode_res_token(rbufp + SMB_DR_DATA_OFFSET,
+ rbuf_size - SMB_DR_DATA_OFFSET);
+
+ smb_kdoor_clnt_free(argp, arg_size, rbufp, rbuf_size);
+ return (token);
+
+}
+
+int
+smb_upcall_set_dwncall_desc(uint32_t opcode, door_desc_t *dp, uint_t n_desc)
+{
+ char *argp, *rbufp;
+ size_t arg_size, rbuf_size;
+
+ argp = smb_dr_set_opcode(opcode, &arg_size);
+ if (argp == NULL) {
+ return (SMB_DR_OP_ERR_ENCODE);
+ }
+
+ rbufp = smb_kdoor_clnt_upcall(argp, arg_size, dp, n_desc, &rbuf_size);
+ if (rbufp == NULL) {
+ return (SMB_DR_OP_ERR);
+ }
+
+ smb_kdoor_clnt_free(argp, arg_size, rbufp, rbuf_size);
+
+ return (SMB_DR_OP_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_user.c b/usr/src/uts/common/fs/smbsrv/smb_user.c
new file mode 100644
index 0000000000..bfea00768e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c
@@ -0,0 +1,619 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General Structures Layout
+ * -------------------------
+ *
+ * This is a simplified diagram showing the relationship between most of the
+ * main structures.
+ *
+ * +-------------------+
+ * | SMB_INFO |
+ * +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | SESSION |<----->| SESSION |......| SESSION |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | USER |<----->| USER |......| USER |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | TREE |<----->| TREE |......| TREE |
+ * +-------------------+ +-------------------+ +-------------------+
+ * | |
+ * | |
+ * | v
+ * | +-------+ +-------+ +-------+
+ * | | OFILE |<----->| OFILE |......| OFILE |
+ * | +-------+ +-------+ +-------+
+ * |
+ * |
+ * v
+ * +-------+ +------+ +------+
+ * | ODIR |<----->| ODIR |......| ODIR |
+ * +-------+ +------+ +------+
+ *
+ *
+ * User State Machine
+ * ------------------
+ *
+ * +-----------------------------+ T0
+ * | SMB_USER_STATE_LOGGED_IN |<----------- Creation/Allocation
+ * +-----------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +-----------------------------+
+ * | SMB_USER_STATE_LOGGING_OFF |
+ * +-----------------------------+
+ * |
+ * | T2
+ * |
+ * v
+ * +-----------------------------+ T3
+ * | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free
+ * +-----------------------------+
+ *
+ * SMB_USER_STATE_LOGGED_IN
+ *
+ * While in this state:
+ * - The user is queued in the list of users of his session.
+ * - References will be given out if the user is looked up.
+ * - The user can access files and pipes.
+ *
+ * SMB_USER_STATE_LOGGING_OFF
+ *
+ * While in this state:
+ * - The user is queued in the list of users of his session.
+ * - References will not be given out if the user is looked up.
+ * - The trees the user connected are being disconnected.
+ * - The resources associated with the user remain.
+ *
+ * SMB_USER_STATE_LOGGING_OFF
+ *
+ * While in this state:
+ * - The user is queued in the list of users of his session.
+ * - References will not be given out if the user is looked up.
+ * - The user has no more trees connected.
+ * - The resources associated with the user remain.
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_user_login(). A new user is created and
+ * added to the list of users of a session.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_user_logoff().
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_user_release(). The resources associated
+ * with the user are deleted as well as the user. For the transition to
+ * occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
+ * reference count be zero.
+ *
+ * Comments
+ * --------
+ *
+ * The state machine of the user structures is controlled by 3 elements:
+ * - The list of users of the session he belongs to.
+ * - The mutex embedded in the structure itself.
+ * - The reference count.
+ *
+ * There's a mutex embedded in the user structure used to protect its fields
+ * and there's a lock embedded in the list of users of a session. To
+ * increment or to decrement the reference count the mutex must be entered.
+ * To insert the user into the list of users of the session and to remove
+ * the user from it, the lock must be entered in RW_WRITER mode.
+ *
+ * Rules of access to a user structure:
+ *
+ * 1) In order to avoid deadlocks, when both (mutex and lock of the session
+ * list) have to be entered, the lock must be entered first.
+ *
+ * 2) All actions applied to a user require a reference count.
+ *
+ * 3) There are 2 ways of getting a reference count. One is when the user
+ * logs in. The other when the user is looked up. This translates into
+ * 3 functions: smb_user_login(), smb_user_lookup_by_uid() and
+ * smb_user_lookup_by_credentials.
+ *
+ * It should be noted that the reference count of a user registers the
+ * number of references to the user in other structures (such as an smb
+ * request). The reference count is not incremented in these 2 instances:
+ *
+ * 1) The user is logged in. An user is anchored by his state. If there's
+ * no activity involving a user currently logged in, the reference
+ * count of that user is zero.
+ *
+ * 2) The user is queued in the list of users of the session. The fact of
+ * being queued in that list is NOT registered by incrementing the
+ * reference count.
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_door_svc.h>
+
+/* Static functions defined further down this file. */
+static void smb_user_delete(smb_user_t *user);
+
+/*
+ * smb_user_login
+ *
+ *
+ */
+smb_user_t *
+smb_user_login(
+ smb_session_t *session,
+ cred_t *cr,
+ char *domain_name,
+ char *account_name,
+ uint32_t flags,
+ uint32_t privileges,
+ uint32_t audit_sid)
+{
+ smb_user_t *user;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ ASSERT(cr);
+ ASSERT(account_name);
+ ASSERT(domain_name);
+
+ user = kmem_cache_alloc(smb_info.si_cache_user, KM_SLEEP);
+ bzero(user, sizeof (smb_user_t));
+ user->u_refcnt = 1;
+ user->u_session = session;
+ user->u_logon_time = gethrestime_sec();
+ user->u_flags = flags;
+ user->u_privileges = privileges;
+ user->u_name_len = strlen(account_name) + 1;
+ user->u_domain_len = strlen(domain_name) + 1;
+ user->u_name = smb_kstrdup(account_name, user->u_name_len);
+ user->u_domain = smb_kstrdup(domain_name, user->u_domain_len);
+ user->u_cred = cr;
+ user->u_audit_sid = audit_sid;
+
+ if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
+ if (!smb_idpool_constructor(&user->u_tid_pool)) {
+ smb_llist_constructor(&user->u_tree_list,
+ sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd));
+ mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
+ crhold(cr);
+ user->u_state = SMB_USER_STATE_LOGGED_IN;
+ user->u_magic = SMB_USER_MAGIC;
+ smb_llist_enter(&session->s_user_list, RW_WRITER);
+ smb_llist_insert_tail(&session->s_user_list, user);
+ smb_llist_exit(&session->s_user_list);
+ atomic_inc_32(&smb_info.open_users);
+ return (user);
+ }
+ smb_idpool_free(&session->s_uid_pool, user->u_uid);
+ }
+ kmem_free(user->u_name, (size_t)user->u_name_len);
+ kmem_free(user->u_domain, (size_t)user->u_domain_len);
+ kmem_cache_free(smb_info.si_cache_user, user);
+ return (NULL);
+}
+
+/*
+ * Create a new user based on an existing user, used to support
+ * additional SessionSetupX requests for a user on a session.
+ *
+ * Assumes the caller has a reference on the original user from
+ * a user_lookup_by_x call.
+ */
+smb_user_t *
+smb_user_dup(
+ smb_user_t *orig_user)
+{
+ smb_user_t *user;
+
+ ASSERT(orig_user->u_magic == SMB_USER_MAGIC);
+ ASSERT(orig_user->u_refcnt);
+
+ user = smb_user_login(orig_user->u_session, orig_user->u_cred,
+ orig_user->u_domain, orig_user->u_name, orig_user->u_flags,
+ orig_user->u_privileges, orig_user->u_audit_sid);
+
+ if (user)
+ smb_user_nonauth_logon(orig_user->u_audit_sid);
+
+ return (user);
+}
+
+/*
+ * smb_user_logoff
+ *
+ *
+ */
+void
+smb_user_logoff(
+ smb_user_t *user)
+{
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ mutex_enter(&user->u_mutex);
+ ASSERT(user->u_refcnt);
+ switch (user->u_state) {
+ case SMB_USER_STATE_LOGGED_IN: {
+ /*
+ * The user is moved into a state indicating that the log off
+ * process has started.
+ */
+ user->u_state = SMB_USER_STATE_LOGGING_OFF;
+ mutex_exit(&user->u_mutex);
+ atomic_dec_32(&smb_info.open_users);
+ /*
+ * All the trees hanging off of this user are disconnected.
+ */
+ smb_tree_disconnect_all(user);
+ smb_user_auth_logoff(user->u_audit_sid);
+ mutex_enter(&user->u_mutex);
+ user->u_state = SMB_USER_STATE_LOGGED_OFF;
+ break;
+ }
+ case SMB_USER_STATE_LOGGED_OFF:
+ case SMB_USER_STATE_LOGGING_OFF:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&user->u_mutex);
+}
+
+/*
+ * smb_user_logoff_all
+ *
+ *
+ */
+void
+smb_user_logoff_all(
+ smb_session_t *session)
+{
+ smb_user_t *user;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+
+ smb_llist_enter(&session->s_user_list, RW_READER);
+ user = smb_llist_head(&session->s_user_list);
+ while (user) {
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_session == session);
+ mutex_enter(&user->u_mutex);
+ switch (user->u_state) {
+ case SMB_USER_STATE_LOGGED_IN:
+ /* The user is still logged in. */
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+ smb_llist_exit(&session->s_user_list);
+ smb_user_logoff(user);
+ smb_user_release(user);
+ smb_llist_enter(&session->s_user_list, RW_READER);
+ user = smb_llist_head(&session->s_user_list);
+ break;
+ case SMB_USER_STATE_LOGGING_OFF:
+ case SMB_USER_STATE_LOGGED_OFF:
+ /*
+ * The user is logged off or logging off.
+ */
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(&session->s_user_list, user);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(&session->s_user_list, user);
+ break;
+ }
+ }
+ smb_llist_exit(&session->s_user_list);
+}
+
+/*
+ * smb_user_release
+ *
+ *
+ */
+void
+smb_user_release(
+ smb_user_t *user)
+{
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ mutex_enter(&user->u_mutex);
+ ASSERT(user->u_refcnt);
+ user->u_refcnt--;
+ switch (user->u_state) {
+ case SMB_USER_STATE_LOGGED_OFF:
+ if (user->u_refcnt == 0) {
+ mutex_exit(&user->u_mutex);
+ smb_user_delete(user);
+ return;
+ }
+ break;
+
+ case SMB_USER_STATE_LOGGED_IN:
+ case SMB_USER_STATE_LOGGING_OFF:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&user->u_mutex);
+}
+
+/*
+ * smb_user_lookup_by_uid
+ *
+ * Find the appropriate user for this request. The request credentials
+ * set here may be overridden by the tree credentials. In domain mode,
+ * the user and tree credentials should be the same. In share mode, the
+ * tree credentials (defined in the share definition) should override
+ * the user credentials.
+ */
+smb_user_t *
+smb_user_lookup_by_uid(
+ smb_session_t *session,
+ cred_t **cr,
+ uint16_t uid)
+{
+ smb_user_t *user;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ ASSERT(cr);
+
+ smb_llist_enter(&session->s_user_list, RW_READER);
+ user = smb_llist_head(&session->s_user_list);
+ while (user) {
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_session == session);
+ if (user->u_uid == uid) {
+ mutex_enter(&user->u_mutex);
+ switch (user->u_state) {
+
+ case SMB_USER_STATE_LOGGED_IN:
+ /* The user exists and is still logged in. */
+ *cr = user->u_cred;
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+ smb_llist_exit(&session->s_user_list);
+ return (user);
+
+ case SMB_USER_STATE_LOGGING_OFF:
+ case SMB_USER_STATE_LOGGED_OFF:
+ /*
+ * The user exists but has logged off or is in
+ * the process of logging off.
+ */
+ mutex_exit(&user->u_mutex);
+ smb_llist_exit(&session->s_user_list);
+ return (NULL);
+
+ default:
+ ASSERT(0);
+ mutex_exit(&user->u_mutex);
+ smb_llist_exit(&session->s_user_list);
+ return (NULL);
+ }
+ }
+ user = smb_llist_next(&session->s_user_list, user);
+ }
+ smb_llist_exit(&session->s_user_list);
+ return (NULL);
+}
+
+/*
+ * smb_user_lookup_by_name
+ */
+smb_user_t *
+smb_user_lookup_by_name(smb_session_t *session, char *domain, char *name)
+{
+ smb_user_t *user;
+ smb_llist_t *ulist;
+
+ ulist = &session->s_user_list;
+ smb_llist_enter(ulist, RW_READER);
+ user = smb_llist_head(ulist);
+ while (user) {
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ if (!utf8_strcasecmp(user->u_name, name) &&
+ !utf8_strcasecmp(user->u_domain, domain)) {
+ mutex_enter(&user->u_mutex);
+ if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+ break;
+ }
+ mutex_exit(&user->u_mutex);
+ }
+ user = smb_llist_next(ulist, user);
+ }
+ smb_llist_exit(ulist);
+
+ return (user);
+}
+
+/*
+ * smb_user_lookup_by_state
+ *
+ * This function returns the first user in the logged in state. If the user
+ * provided is NULL the search starts from the beginning of the list passed
+ * in. It a user is provided the search starts just after that user.
+ */
+smb_user_t *
+smb_user_lookup_by_state(
+ smb_session_t *session,
+ smb_user_t *user)
+{
+ smb_llist_t *lst;
+ smb_user_t *next;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+
+ lst = &session->s_user_list;
+
+ smb_llist_enter(lst, RW_READER);
+ if (user) {
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_refcnt);
+ next = smb_llist_next(lst, user);
+ } else {
+ next = smb_llist_head(lst);
+ }
+ while (next) {
+ ASSERT(next->u_magic == SMB_USER_MAGIC);
+ ASSERT(next->u_session == session);
+ mutex_enter(&next->u_mutex);
+ if (next->u_state == SMB_USER_STATE_LOGGED_IN) {
+ next->u_refcnt++;
+ mutex_exit(&next->u_mutex);
+ break;
+ } else {
+ ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) ||
+ (next->u_state == SMB_USER_STATE_LOGGED_OFF));
+ mutex_exit(&next->u_mutex);
+ next = smb_llist_next(lst, next);
+ }
+ }
+ smb_llist_exit(lst);
+
+ return (next);
+}
+
+/*
+ * smb_user_disconnect_share
+ *
+ * This function disconnects all the trees that have the sharename passed in.
+ */
+void
+smb_user_disconnect_share(
+ smb_user_t *user,
+ char *sharename)
+{
+ smb_tree_t *tree;
+ smb_tree_t *next;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_refcnt);
+
+ tree = smb_tree_lookup_by_name(user, sharename, NULL);
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ smb_tree_disconnect(tree);
+ smbsr_rq_notify(NULL, user->u_session, tree);
+ next = smb_tree_lookup_by_name(user, sharename,
+ tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+}
+
+/*
+ * smb_user_disconnect_share
+ *
+ * This function disconnects all the trees that match fsd passed in.
+ */
+void
+smb_user_disconnect_volume(
+ smb_user_t *user,
+ fs_desc_t *fsd)
+{
+ smb_tree_t *tree;
+ smb_tree_t *next;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_refcnt);
+
+ tree = smb_tree_lookup_by_fsd(user, fsd, NULL);
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ smb_tree_disconnect(tree);
+ smbsr_rq_notify(NULL, user->u_session, tree);
+ next = smb_tree_lookup_by_fsd(user, fsd, tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+}
+
+/* *************************** Static Functions ***************************** */
+
+/*
+ * smb_user_delete
+ *
+ *
+ */
+static void
+smb_user_delete(
+ smb_user_t *user)
+{
+ smb_session_t *session;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_refcnt == 0);
+ ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
+
+ session = user->u_session;
+ /*
+ * Let's remove the user from the list of users of the session. This
+ * has to be done before any resources associated with the user are
+ * deleted.
+ */
+ smb_llist_enter(&session->s_user_list, RW_WRITER);
+ smb_llist_remove(&session->s_user_list, user);
+ smb_llist_exit(&session->s_user_list);
+
+ user->u_magic = (uint32_t)~SMB_USER_MAGIC;
+ mutex_destroy(&user->u_mutex);
+ smb_llist_destructor(&user->u_tree_list);
+ smb_idpool_destructor(&user->u_tid_pool);
+ smb_idpool_free(&session->s_uid_pool, user->u_uid);
+ crfree(user->u_cred);
+ kmem_free(user->u_name, (size_t)user->u_name_len);
+ kmem_free(user->u_domain, (size_t)user->u_domain_len);
+ kmem_cache_free(smb_info.si_cache_user, user);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_util.c b/usr/src/uts/common/fs/smbsrv/smb_util.c
new file mode 100644
index 0000000000..beb39a6e51
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_util.c
@@ -0,0 +1,2172 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/tzfile.h>
+#include <sys/atomic.h>
+#include <sys/kidmap.h>
+#include <sys/time.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/string.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_vops.h>
+
+#include <smbsrv/smb_idmap.h>
+
+#include <sys/sid.h>
+#include <sys/priv_names.h>
+
+#ifdef DEBUG
+uint_t smb_tsd_key;
+#endif
+
+static boolean_t
+smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks);
+
+time_t tzh_leapcnt = 0;
+
+struct tm
+*smb_gmtime_r(time_t *clock, struct tm *result);
+
+time_t
+smb_timegm(struct tm *tm);
+
+struct tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+static int days_in_month[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+int
+smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str)
+{
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
+ return (mts_wcequiv_strlen(str));
+ return (strlen(str));
+}
+
+int
+smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str)
+{
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
+ return (mts_wcequiv_strlen(str) + 2);
+ return (strlen(str) + 1);
+}
+
+int
+smb_ascii_or_unicode_null_len(struct smb_request *sr)
+{
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
+ return (2);
+ return (1);
+}
+
+void
+smb_set_gmtoff(uint32_t goff)
+{
+ (void) atomic_swap_32(&smb_info.si_gmtoff, goff);
+}
+
+uint32_t
+smb_get_gmtoff(void)
+{
+ return (atomic_or_32_nv(&smb_info.si_gmtoff, 0));
+}
+
+uint32_t
+smb_gmt_to_local_time(uint32_t gmt)
+{
+ return (gmt + smb_get_gmtoff());
+}
+
+uint32_t
+smb_local_time_to_gmt(uint32_t local)
+{
+ return (local - smb_get_gmtoff());
+}
+
+
+int
+smb_component_match(
+ struct smb_request *sr,
+ ino64_t fileid,
+ struct smb_odir *od,
+ smb_odir_context_t *pc)
+{
+ int ci = (fsd_chkcap(&sr->tid_tree->t_fsd, FSOLF_CASE_INSENSITIVE) > 0);
+
+ int ignore_case = (ci || (SMB_TREE_CASE_INSENSITIVE(sr)));
+
+ return (smb_match_name(fileid, pc->dc_name, pc->dc_shortname,
+ pc->dc_name83, od->d_pattern, ignore_case));
+}
+
+int
+smb_convert_unicode_wildcards(char *path)
+{
+ int wildcards = 0;
+ char *ptr = path;
+ char nch;
+
+ /*
+ * Special case "<" for "dir *."
+ */
+ if (strcmp(path, "<") == 0) {
+ return (1);
+ }
+ while (*ptr) {
+ nch = *(ptr + 1);
+ switch (*ptr) {
+ case '*' : /* Count non-unicode wildcards while we're at it */
+ case '?' :
+ wildcards++;
+ break;
+ case '<' :
+ if (nch == '.') {
+ *(ptr++) = '*';
+ wildcards++;
+ }
+ break;
+ case '>' :
+ *ptr = '?';
+ wildcards++;
+ break;
+ case '\"' :
+ *ptr = '.';
+ break;
+ }
+ ptr++;
+ }
+ /* NT DOS wildcards... */
+ if (strcmp(path, "????????.???") == 0) {
+ (void) strcpy(path, "*");
+ } else if (strncmp(path, "????????.", 9) == 0) {
+ *path = '*';
+ (void) strcpy(path+1, path+8);
+ }
+
+ return (wildcards);
+}
+
+
+
+/*
+ * smb_mode_to_dos_attributes
+ *
+ * This function converts unix mode from smb_attr_t structure to dos attr.
+ *
+ * The reason dos_attr is returned as uint32_t, unlike sattr as
+ * unsigned short is the smb_trans_find_first2/next encodes dattr in
+ * BOTH DIR info as long.
+ */
+uint32_t
+smb_mode_to_dos_attributes(smb_attr_t *ap)
+{
+ uint32_t dos_attr = 0;
+
+ dos_attr = ap->sa_dosattr;
+ if (dos_attr == 0)
+ dos_attr = SMB_FA_NORMAL;
+
+ return (dos_attr);
+}
+
+
+
+/*
+ * smb_sattr_check
+ *
+ * This function checks if the file has the attributes indicated by
+ * the search attribute, "sattr". The normal files, which includes
+ * FSA_READONLY and FSA_ARCHIVE, should always pass the check. If the
+ * special attributes: SMB_FA_DIRECTORY, SMB_FA_HIDDEN or
+ * SMB_FA_SYSTEM are set, then the special mode FSA_DIR, FSA_HIDDEN,
+ * and FSA_SYSTEM will also pass accordingly. The following
+ * examples will show how this works:
+ *
+ * fileA: FSA_READONLY
+ * fileB: 0 (no attributes = normal file)
+ * fileC: FSA_READONLY, FSA_ARCHIVE
+ * fileD: FSA_HIDDEN
+ * fileE: FSA_READONLY, FSA_HIDDEN, FSA_SYSTEM
+ * dirA: FSA_DIRECTORY
+ *
+ * *search attribute: 0
+ * Returns: fileA, fileB and fileC.
+ * *search attribute: SMB_FA_HIDDEN
+ * Returns: fileA, fileB, fileC and fileD.
+ * *search attribute: SMB_FA_SYSTEM
+ * Returns: fileA, fileB and fileC.
+ * *search attribute: SMB_FA_DIRECTORY
+ * Returns: fileA, fileB, fileC and dirA.
+ * *search attribute: SMB_FA_HIDDEN and SMB_FA_SYSTEM
+ * Returns: fileA, fileB, fileC, fileD and fileE.
+ *
+ * As you can see, the special attributes are inclusive, which means the
+ * files that has all their special attributes included in the search
+ * attribute and normal files will be returned. The FSA_READONLY and
+ * FSA_ARCHIVE attributes are completely ignored since they are being
+ * treated as normal file.
+ *
+ * If check passed, 1 is returned; otherwise, 0 is returned.
+ */
+int
+smb_sattr_check(smb_attr_t *ap, char *name, unsigned short sattr)
+{
+ if (name) {
+ if (is_dot_or_dotdot(name) && !(sattr & SMB_FA_HIDDEN))
+ return (0);
+ }
+
+ /*
+ * The FSA_READONLY and FSA_ARCHIVE bits are being treated
+ * as normal file; therefore, they are ignored.
+ */
+
+ if ((ap->sa_vattr.va_type == VDIR) && !(sattr & SMB_FA_DIRECTORY))
+ return (0);
+
+ if ((ap->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
+ !(sattr & SMB_FA_HIDDEN))
+ return (0);
+
+ if ((ap->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
+ !(sattr & SMB_FA_SYSTEM))
+ return (0);
+
+ return (1);
+}
+
+
+/*
+ * smb_stream_parse_name
+ *
+ * calling function is responsible for passing valid buffers with
+ * adequate sizes.
+ *
+ * path is a NULL terminated string which could be a
+ * stream path. If it's a stream path it could be
+ * in one of the following formats:
+ * . path:stream
+ * . path:stream:$DATA
+ * unnamed stream is part of the path and there is
+ * exactly one ':' in between the unamed and name
+ * streams
+ *
+ * u_stream_name will contain the unamed stream portion upon
+ * successful return.
+ * this is the portion between last '\' and
+ * the first ':'
+ *
+ * stream_name will contain the named stream portion upon
+ * successful return.
+ * this is the portion between the first ':' and the
+ * end of the 'name' string.
+ *
+ * '::' - is a non-stream and is commonly used by Windows to designate
+ * the unamed stream in the form "::$DATA"
+ *
+ * on return the named stream always has a ":$DATA" appended if there
+ * isn't one already
+ *
+ * Return Codes:
+ *
+ * 0 - given path doesn't contain any streams
+ * 1 - given path had a stream
+ */
+int
+smb_stream_parse_name(char *path, char *u_stream_name,
+ char *stream_name)
+{
+ char *colonp;
+ char *slashp;
+
+ if (path == 0)
+ return (0);
+
+ /*
+ * if there is no colon in the path or it's the last char
+ * then it's not a stream name
+ */
+ colonp = strchr(path, ':');
+ if ((colonp == 0) || (*(colonp+1) == 0))
+ return (0);
+
+ /* "::" always means the unamed stream */
+ if (strstr(path, "::"))
+ return (0);
+
+ if (stream_name) {
+ /*
+ * stream name is the portion between ':' and the
+ * end of 'path' string (including the starting ':')
+ */
+ (void) strcpy(stream_name, colonp);
+
+ if (strstr(stream_name, ":$DATA") == 0)
+ (void) strcat(stream_name, ":$DATA");
+ }
+
+ if (u_stream_name) {
+ /*
+ * uname stream is the portion between last '\'
+ * and the ':'
+ */
+ slashp = strrchr(path, '\\');
+ slashp = (slashp == 0) ? path : slashp + 1;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ (void) strlcpy(u_stream_name, slashp, colonp - slashp + 1);
+ }
+ return (1);
+}
+
+int
+microtime(timestruc_t *tvp)
+{
+ tvp->tv_sec = gethrestime_sec();
+ tvp->tv_nsec = 0;
+ return (0);
+}
+
+int32_t
+clock_get_milli_uptime()
+{
+ return (TICK_TO_MSEC(lbolt));
+}
+
+int /*ARGSUSED*/
+smb_noop(void *p, size_t size, int foo)
+{
+ return (0);
+}
+
+/*
+ * smb_idpool_increment
+ *
+ * This function increments the ID pool by doubling the current size. This
+ * function assumes the caller entered the mutex of the pool.
+ */
+static int
+smb_idpool_increment(
+ smb_idpool_t *pool)
+{
+ uint8_t *new_pool;
+ uint32_t new_size;
+
+ ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
+
+ new_size = pool->id_size * 2;
+ if (new_size <= SMB_IDPOOL_MAX_SIZE) {
+ new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP);
+ if (new_pool) {
+ bzero(new_pool, new_size / 8);
+ bcopy(pool->id_pool, new_pool, pool->id_size / 8);
+ kmem_free(pool->id_pool, pool->id_size / 8);
+ pool->id_pool = new_pool;
+ pool->id_free_counter += new_size - pool->id_size;
+ pool->id_max_free_counter += new_size - pool->id_size;
+ pool->id_size = new_size;
+ pool->id_idx_msk = (new_size / 8) - 1;
+ if (new_size >= SMB_IDPOOL_MAX_SIZE) {
+ /* id -1 made unavailable */
+ pool->id_pool[pool->id_idx_msk] = 0x80;
+ pool->id_free_counter--;
+ pool->id_max_free_counter--;
+ }
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * smb_idpool_constructor
+ *
+ * This function initializes the pool structure provided.
+ */
+int
+smb_idpool_constructor(
+ smb_idpool_t *pool)
+{
+
+ ASSERT(pool->id_magic != SMB_IDPOOL_MAGIC);
+
+ pool->id_size = SMB_IDPOOL_MIN_SIZE;
+ pool->id_idx_msk = (SMB_IDPOOL_MIN_SIZE / 8) - 1;
+ pool->id_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
+ pool->id_max_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
+ pool->id_bit = 0x02;
+ pool->id_bit_idx = 1;
+ pool->id_idx = 0;
+ pool->id_pool = (uint8_t *)kmem_alloc((SMB_IDPOOL_MIN_SIZE / 8),
+ KM_SLEEP);
+ bzero(pool->id_pool, (SMB_IDPOOL_MIN_SIZE / 8));
+ /* -1 id made unavailable */
+ pool->id_pool[0] = 0x01; /* id 0 made unavailable */
+ mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL);
+ pool->id_magic = SMB_IDPOOL_MAGIC;
+ return (0);
+}
+
+/*
+ * smb_idpool_destructor
+ *
+ * This function tears down and frees the resources associated with the
+ * pool provided.
+ */
+void
+smb_idpool_destructor(
+ smb_idpool_t *pool)
+{
+ ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
+ ASSERT(pool->id_free_counter == pool->id_max_free_counter);
+ pool->id_magic = (uint32_t)~SMB_IDPOOL_MAGIC;
+ mutex_destroy(&pool->id_mutex);
+ kmem_free(pool->id_pool, (size_t)(pool->id_size / 8));
+}
+
+/*
+ * smb_idpool_alloc
+ *
+ * This function allocates an ID from the pool provided.
+ */
+int
+smb_idpool_alloc(
+ smb_idpool_t *pool,
+ uint16_t *id)
+{
+ uint32_t i;
+ uint8_t bit;
+ uint8_t bit_idx;
+ uint8_t byte;
+
+ ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
+
+ mutex_enter(&pool->id_mutex);
+ if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) {
+ mutex_exit(&pool->id_mutex);
+ return (-1);
+ }
+
+ i = pool->id_size;
+ while (i) {
+ bit = pool->id_bit;
+ bit_idx = pool->id_bit_idx;
+ byte = pool->id_pool[pool->id_idx];
+ while (bit) {
+ if (byte & bit) {
+ bit = bit << 1;
+ bit_idx++;
+ continue;
+ }
+ pool->id_pool[pool->id_idx] |= bit;
+ *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx);
+ pool->id_free_counter--;
+ pool->id_bit = bit;
+ pool->id_bit_idx = bit_idx;
+ mutex_exit(&pool->id_mutex);
+ return (0);
+ }
+ pool->id_bit = 1;
+ pool->id_bit_idx = 0;
+ pool->id_idx++;
+ pool->id_idx &= pool->id_idx_msk;
+ --i;
+ }
+ /*
+ * This section of code shouldn't be reached. If there are IDs
+ * available and none could be found there's a problem.
+ */
+ ASSERT(0);
+ mutex_exit(&pool->id_mutex);
+ return (-1);
+}
+
+/*
+ * smb_idpool_free
+ *
+ * This function frees the ID provided.
+ */
+void
+smb_idpool_free(
+ smb_idpool_t *pool,
+ uint16_t id)
+{
+ ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
+ ASSERT(id != 0);
+ ASSERT(id != 0xFFFF);
+
+ mutex_enter(&pool->id_mutex);
+ if (pool->id_pool[id >> 3] & (1 << (id & 7))) {
+ pool->id_pool[id >> 3] &= ~(1 << (id & 7));
+ pool->id_free_counter++;
+ ASSERT(pool->id_free_counter <= pool->id_max_free_counter);
+ mutex_exit(&pool->id_mutex);
+ return;
+ }
+ /* Freeing a free ID. */
+ ASSERT(0);
+ mutex_exit(&pool->id_mutex);
+}
+
+/*
+ * smb_llist_constructor
+ *
+ * This function initializes a locked list.
+ */
+void
+smb_llist_constructor(
+ smb_llist_t *ll,
+ size_t size,
+ size_t offset)
+{
+ rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL);
+ list_create(&ll->ll_list, size, offset);
+ ll->ll_count = 0;
+ ll->ll_wrop = 0;
+}
+
+/*
+ * smb_llist_destructor
+ *
+ * This function destroys a locked list.
+ */
+void
+smb_llist_destructor(
+ smb_llist_t *ll)
+{
+ ASSERT(ll->ll_count == 0);
+
+ rw_destroy(&ll->ll_lock);
+ list_destroy(&ll->ll_list);
+}
+
+/*
+ * smb_llist_upgrade
+ *
+ * This function tries to upgrade the lock of the locked list. It assumes the
+ * locked has already been entered in RW_READER mode. It first tries using the
+ * Solaris function rw_tryupgrade(). If that call fails the lock is released
+ * and reentered in RW_WRITER mode. In that last case a window is opened during
+ * which the contents of the list may have changed. The return code indicates
+ * whether or not the list was modified when the lock was exited.
+ */
+int smb_llist_upgrade(
+ smb_llist_t *ll)
+{
+ uint64_t wrop;
+
+ if (rw_tryupgrade(&ll->ll_lock) != 0) {
+ return (0);
+ }
+ wrop = ll->ll_wrop;
+ rw_exit(&ll->ll_lock);
+ rw_enter(&ll->ll_lock, RW_WRITER);
+ return (wrop != ll->ll_wrop);
+}
+
+/*
+ * smb_llist_insert_head
+ *
+ * This function inserts the object passed a the beginning of the list. This
+ * function assumes the lock of the list has already been entered.
+ */
+void
+smb_llist_insert_head(
+ smb_llist_t *ll,
+ void *obj)
+{
+ list_insert_head(&ll->ll_list, obj);
+ ++ll->ll_wrop;
+ ++ll->ll_count;
+}
+
+/*
+ * smb_llist_insert_tail
+ *
+ * This function appends to the object passed to the list. This function assumes
+ * the lock of the list has already been entered.
+ *
+ */
+void
+smb_llist_insert_tail(
+ smb_llist_t *ll,
+ void *obj)
+{
+ list_insert_tail(&ll->ll_list, obj);
+ ++ll->ll_wrop;
+ ++ll->ll_count;
+}
+
+/*
+ * smb_llist_remove
+ *
+ * This function removes the object passed from the list. This function assumes
+ * the lock of the list has already been entered.
+ */
+void
+smb_llist_remove(
+ smb_llist_t *ll,
+ void *obj)
+{
+ list_remove(&ll->ll_list, obj);
+ ++ll->ll_wrop;
+ --ll->ll_count;
+}
+
+/*
+ * smb_llist_get_count
+ *
+ * This function returns the number of elements in the specified list.
+ */
+uint32_t
+smb_llist_get_count(
+ smb_llist_t *ll)
+{
+ return (ll->ll_count);
+}
+
+/*
+ * smb_slist_constructor
+ *
+ * Synchronized list constructor.
+ */
+void
+smb_slist_constructor(
+ smb_slist_t *sl,
+ size_t size,
+ size_t offset)
+{
+ mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL);
+ list_create(&sl->sl_list, size, offset);
+ sl->sl_count = 0;
+ sl->sl_waiting = B_FALSE;
+}
+
+/*
+ * smb_slist_destructor
+ *
+ * Synchronized list destructor.
+ */
+void
+smb_slist_destructor(
+ smb_slist_t *sl)
+{
+ ASSERT(sl->sl_count == 0);
+
+ mutex_destroy(&sl->sl_mutex);
+ cv_destroy(&sl->sl_cv);
+ list_destroy(&sl->sl_list);
+}
+
+/*
+ * smb_slist_insert_head
+ *
+ * This function inserts the object passed a the beginning of the list.
+ */
+void
+smb_slist_insert_head(
+ smb_slist_t *sl,
+ void *obj)
+{
+ mutex_enter(&sl->sl_mutex);
+ list_insert_head(&sl->sl_list, obj);
+ ++sl->sl_count;
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_slist_insert_tail
+ *
+ * This function appends the object passed to the list.
+ */
+void
+smb_slist_insert_tail(
+ smb_slist_t *sl,
+ void *obj)
+{
+ mutex_enter(&sl->sl_mutex);
+ list_insert_tail(&sl->sl_list, obj);
+ ++sl->sl_count;
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_llist_remove
+ *
+ * This function removes the object passed by the caller from the list.
+ */
+void
+smb_slist_remove(
+ smb_slist_t *sl,
+ void *obj)
+{
+ mutex_enter(&sl->sl_mutex);
+ list_remove(&sl->sl_list, obj);
+ if ((--sl->sl_count == 0) && (sl->sl_waiting)) {
+ sl->sl_waiting = B_FALSE;
+ cv_broadcast(&sl->sl_cv);
+ }
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_slist_move_tail
+ *
+ * This function transfers all the contents of the synchronized list to the
+ * list_t provided. It returns the number of objects transferred.
+ */
+uint32_t
+smb_slist_move_tail(
+ list_t *lst,
+ smb_slist_t *sl)
+{
+ uint32_t rv;
+
+ mutex_enter(&sl->sl_mutex);
+ rv = sl->sl_count;
+ if (sl->sl_count) {
+ list_move_tail(lst, &sl->sl_list);
+ sl->sl_count = 0;
+ if (sl->sl_waiting) {
+ sl->sl_waiting = B_FALSE;
+ cv_broadcast(&sl->sl_cv);
+ }
+ }
+ mutex_exit(&sl->sl_mutex);
+ return (rv);
+}
+
+/*
+ * smb_slist_obj_move
+ *
+ * This function moves an object from one list to the end of the other list. It
+ * assumes the mutex of each list has been entered.
+ */
+void
+smb_slist_obj_move(
+ smb_slist_t *dst,
+ smb_slist_t *src,
+ void *obj)
+{
+ ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset);
+ ASSERT(dst->sl_list.list_size == src->sl_list.list_size);
+
+ list_remove(&src->sl_list, obj);
+ list_insert_tail(&dst->sl_list, obj);
+ dst->sl_count++;
+ src->sl_count--;
+ if ((src->sl_count == 0) && (src->sl_waiting)) {
+ src->sl_waiting = B_FALSE;
+ cv_broadcast(&src->sl_cv);
+ }
+}
+
+/*
+ * smb_slist_wait_for_empty
+ *
+ * This function waits for a list to be emptied.
+ */
+void
+smb_slist_wait_for_empty(
+ smb_slist_t *sl)
+{
+ mutex_enter(&sl->sl_mutex);
+ while (sl->sl_count) {
+ sl->sl_waiting = B_TRUE;
+ cv_wait(&sl->sl_cv, &sl->sl_mutex);
+ }
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_slist_exit
+ *
+ * This function exits the muetx of the list and signal the condition variable
+ * if the list is empty.
+ */
+void
+smb_slist_exit(smb_slist_t *sl)
+{
+ if ((sl->sl_count == 0) && (sl->sl_waiting)) {
+ sl->sl_waiting = B_FALSE;
+ cv_broadcast(&sl->sl_cv);
+ }
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_thread_entry_point
+ *
+ * Common entry point for all the threads created through smb_thread_start. The
+ * state of teh thread is set to "running" at the beginning and moved to
+ * "exiting" just before calling thread_exit(). The condition variable is
+ * also signaled.
+ */
+static void
+smb_thread_entry_point(
+ smb_thread_t *thread)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+ mutex_enter(&thread->sth_mtx);
+ ASSERT(thread->sth_state == SMB_THREAD_STATE_STARTING);
+ thread->sth_th = curthread;
+ thread->sth_did = thread->sth_th->t_did;
+
+ if (!thread->sth_kill) {
+ thread->sth_state = SMB_THREAD_STATE_RUNNING;
+ cv_signal(&thread->sth_cv);
+ mutex_exit(&thread->sth_mtx);
+ thread->sth_ep(thread, thread->sth_ep_arg);
+ mutex_enter(&thread->sth_mtx);
+ }
+ thread->sth_th = NULL;
+ thread->sth_state = SMB_THREAD_STATE_EXITING;
+ cv_broadcast(&thread->sth_cv);
+ mutex_exit(&thread->sth_mtx);
+ thread_exit();
+}
+
+/*
+ * smb_thread_init
+ */
+void
+smb_thread_init(
+ smb_thread_t *thread,
+ char *name,
+ smb_thread_ep_t ep,
+ void *ep_arg,
+ smb_thread_aw_t aw,
+ void *aw_arg)
+{
+ ASSERT(thread->sth_magic != SMB_THREAD_MAGIC);
+
+ bzero(thread, sizeof (*thread));
+
+ (void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name));
+ thread->sth_ep = ep;
+ thread->sth_ep_arg = ep_arg;
+ thread->sth_aw = aw;
+ thread->sth_aw_arg = aw_arg;
+ thread->sth_state = SMB_THREAD_STATE_EXITED;
+ mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL);
+ thread->sth_magic = SMB_THREAD_MAGIC;
+}
+
+/*
+ * smb_thread_destroy
+ */
+void
+smb_thread_destroy(
+ smb_thread_t *thread)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+ ASSERT(thread->sth_state == SMB_THREAD_STATE_EXITED);
+ thread->sth_magic = 0;
+ mutex_destroy(&thread->sth_mtx);
+ cv_destroy(&thread->sth_cv);
+}
+
+/*
+ * smb_thread_start
+ *
+ * This function starts a thread with the parameters provided. It waits until
+ * the state of the thread has been moved to running.
+ */
+/*ARGSUSED*/
+int
+smb_thread_start(
+ smb_thread_t *thread)
+{
+ int rc = 0;
+ kthread_t *tmpthread;
+
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ switch (thread->sth_state) {
+ case SMB_THREAD_STATE_EXITED:
+ thread->sth_state = SMB_THREAD_STATE_STARTING;
+ mutex_exit(&thread->sth_mtx);
+ tmpthread = thread_create(NULL, 0, smb_thread_entry_point,
+ thread, 0, &p0, TS_RUN, minclsyspri);
+ ASSERT(tmpthread != NULL);
+ mutex_enter(&thread->sth_mtx);
+ while (thread->sth_state == SMB_THREAD_STATE_STARTING)
+ cv_wait(&thread->sth_cv, &thread->sth_mtx);
+ if (thread->sth_state != SMB_THREAD_STATE_RUNNING)
+ rc = -1;
+ break;
+ default:
+ ASSERT(0);
+ rc = -1;
+ break;
+ }
+ mutex_exit(&thread->sth_mtx);
+ return (rc);
+}
+
+/*
+ * smb_thread_stop
+ *
+ * This function signals a thread to kill itself and waits until the "exiting"
+ * state has been reached.
+ */
+void
+smb_thread_stop(
+ smb_thread_t *thread)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ switch (thread->sth_state) {
+ case SMB_THREAD_STATE_RUNNING:
+ case SMB_THREAD_STATE_STARTING:
+ if (!thread->sth_kill) {
+ thread->sth_kill = B_TRUE;
+ if (thread->sth_aw)
+ thread->sth_aw(thread, thread->sth_aw_arg);
+ cv_broadcast(&thread->sth_cv);
+ while (thread->sth_state != SMB_THREAD_STATE_EXITING)
+ cv_wait(&thread->sth_cv, &thread->sth_mtx);
+ mutex_exit(&thread->sth_mtx);
+ thread_join(thread->sth_did);
+ mutex_enter(&thread->sth_mtx);
+ thread->sth_state = SMB_THREAD_STATE_EXITED;
+ thread->sth_did = 0;
+ thread->sth_kill = B_FALSE;
+ cv_broadcast(&thread->sth_cv);
+ break;
+ }
+ /*FALLTHRU*/
+
+ case SMB_THREAD_STATE_EXITING:
+ if (thread->sth_kill) {
+ while (thread->sth_state != SMB_THREAD_STATE_EXITED)
+ cv_wait(&thread->sth_cv, &thread->sth_mtx);
+ } else {
+ thread->sth_state = SMB_THREAD_STATE_EXITED;
+ thread->sth_did = 0;
+ }
+ break;
+
+ case SMB_THREAD_STATE_EXITED:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&thread->sth_mtx);
+}
+
+/*
+ * smb_thread_signal
+ *
+ * This function signals a thread.
+ */
+void
+smb_thread_signal(
+ smb_thread_t *thread)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ switch (thread->sth_state) {
+ case SMB_THREAD_STATE_RUNNING:
+ if (thread->sth_aw)
+ thread->sth_aw(thread, thread->sth_aw_arg);
+ cv_signal(&thread->sth_cv);
+ break;
+
+ default:
+ break;
+ }
+ mutex_exit(&thread->sth_mtx);
+}
+
+boolean_t
+smb_thread_continue(smb_thread_t *thread)
+{
+ boolean_t result;
+
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ result = smb_thread_continue_timedwait_locked(thread, 0);
+ mutex_exit(&thread->sth_mtx);
+
+ return (result);
+}
+
+boolean_t
+smb_thread_continue_nowait(smb_thread_t *thread)
+{
+ boolean_t result;
+
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ /*
+ * Setting ticks=-1 requests a non-blocking check. We will
+ * still block if the thread is in "suspend" state.
+ */
+ result = smb_thread_continue_timedwait_locked(thread, -1);
+ mutex_exit(&thread->sth_mtx);
+
+ return (result);
+}
+
+boolean_t
+smb_thread_continue_timedwait(smb_thread_t *thread, int seconds)
+{
+ boolean_t result;
+
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ result = smb_thread_continue_timedwait_locked(thread,
+ SEC_TO_TICK(seconds));
+ mutex_exit(&thread->sth_mtx);
+
+ return (result);
+}
+
+/*
+ * smb_thread_continue_timedwait_locked
+ *
+ * Internal only. Ticks==-1 means don't block, Ticks == 0 means wait
+ * indefinitely
+ */
+static boolean_t
+smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks)
+{
+ boolean_t result;
+ clock_t finish_time = lbolt + ticks;
+
+ /* -1 means don't block */
+ if (ticks != -1 && !thread->sth_kill) {
+ if (ticks == 0) {
+ cv_wait(&thread->sth_cv, &thread->sth_mtx);
+ } else {
+ (void) cv_timedwait(&thread->sth_cv, &thread->sth_mtx,
+ finish_time);
+ }
+ }
+ result = (thread->sth_kill == 0);
+
+ return (result);
+}
+
+void
+smb_thread_set_awaken(smb_thread_t *thread, smb_thread_aw_t new_aw_fn,
+ void *new_aw_arg)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ thread->sth_aw = new_aw_fn;
+ thread->sth_aw_arg = new_aw_arg;
+ mutex_exit(&thread->sth_mtx);
+}
+
+/*
+ * smb_rwx_init
+ */
+void
+smb_rwx_init(
+ smb_rwx_t *rwx)
+{
+ bzero(rwx, sizeof (smb_rwx_t));
+ cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL);
+ mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL);
+ rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL);
+}
+
+/*
+ * smb_rwx_destroy
+ */
+void
+smb_rwx_destroy(
+ smb_rwx_t *rwx)
+{
+ mutex_destroy(&rwx->rwx_mutex);
+ cv_destroy(&rwx->rwx_cv);
+ rw_destroy(&rwx->rwx_lock);
+}
+
+/*
+ * smb_rwx_rwexit
+ */
+void
+smb_rwx_rwexit(
+ smb_rwx_t *rwx)
+{
+ if (rw_write_held(&rwx->rwx_lock)) {
+ ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
+ mutex_enter(&rwx->rwx_mutex);
+ if (rwx->rwx_waiting) {
+ rwx->rwx_waiting = B_FALSE;
+ cv_broadcast(&rwx->rwx_cv);
+ }
+ mutex_exit(&rwx->rwx_mutex);
+ }
+ rw_exit(&rwx->rwx_lock);
+}
+
+/*
+ * smb_rwx_rwupgrade
+ */
+krw_t
+smb_rwx_rwupgrade(
+ smb_rwx_t *rwx)
+{
+ if (rw_write_held(&rwx->rwx_lock)) {
+ ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
+ return (RW_WRITER);
+ }
+ if (!rw_tryupgrade(&rwx->rwx_lock)) {
+ rw_exit(&rwx->rwx_lock);
+ rw_enter(&rwx->rwx_lock, RW_WRITER);
+ }
+ return (RW_READER);
+}
+
+/*
+ * smb_rwx_rwrestore
+ */
+void
+smb_rwx_rwdowngrade(
+ smb_rwx_t *rwx,
+ krw_t mode)
+{
+ ASSERT(rw_write_held(&rwx->rwx_lock));
+ ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
+
+ if (mode == RW_WRITER) {
+ return;
+ }
+ ASSERT(mode == RW_READER);
+ mutex_enter(&rwx->rwx_mutex);
+ if (rwx->rwx_waiting) {
+ rwx->rwx_waiting = B_FALSE;
+ cv_broadcast(&rwx->rwx_cv);
+ }
+ mutex_exit(&rwx->rwx_mutex);
+ rw_downgrade(&rwx->rwx_lock);
+}
+
+/*
+ * smb_rwx_wait
+ *
+ * This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER
+ * mode. It will:
+ *
+ * 1) release the lock and save its current mode.
+ * 2) wait until the condition variable is signaled. This can happen for
+ * 2 reasons: When a writer releases the lock or when the time out (if
+ * provided) expires.
+ * 3) re-acquire the lock in the mode saved in (1).
+ */
+int
+smb_rwx_rwwait(
+ smb_rwx_t *rwx,
+ clock_t timeout)
+{
+ int rc;
+ krw_t mode;
+
+ mutex_enter(&rwx->rwx_mutex);
+ rwx->rwx_waiting = B_TRUE;
+ mutex_exit(&rwx->rwx_mutex);
+
+ if (rw_write_held(&rwx->rwx_lock)) {
+ ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
+ mode = RW_WRITER;
+ } else {
+ ASSERT(rw_read_held(&rwx->rwx_lock));
+ mode = RW_READER;
+ }
+ rw_exit(&rwx->rwx_lock);
+
+ mutex_enter(&rwx->rwx_mutex);
+ if (rwx->rwx_waiting) {
+ if (timeout == -1) {
+ rc = 1;
+ cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex);
+ } else {
+ rc = cv_timedwait(&rwx->rwx_cv, &rwx->rwx_mutex,
+ lbolt + timeout);
+ }
+ }
+ mutex_exit(&rwx->rwx_mutex);
+
+ rw_enter(&rwx->rwx_lock, mode);
+ return (rc);
+}
+
+/*
+ * SMB ID mapping
+ *
+ * Solaris ID mapping service (aka Winchester) works with domain SIDs
+ * and RIDs where domain SIDs are in string format. CIFS service works
+ * with binary SIDs understandable by CIFS clients. A layer of SMB ID
+ * mapping functions are implemeted to hide the SID conversion details
+ * and also hide the handling of array of batch mapping requests.
+ */
+
+static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
+
+/*
+ * smb_idmap_getid
+ *
+ * Maps the given Windows SID to a Solaris ID using the
+ * simple mapping API.
+ */
+idmap_stat
+smb_idmap_getid(nt_sid_t *sid, uid_t *id, int *idtype)
+{
+ smb_idmap_t sim;
+ nt_sid_t *tmpsid;
+
+ tmpsid = nt_sid_dup(sid);
+ (void) nt_sid_split(tmpsid, &sim.sim_rid);
+ sim.sim_domsid = nt_sid_format(tmpsid);
+ MEM_FREE("smbsrv", tmpsid);
+ sim.sim_id = id;
+
+ switch (*idtype) {
+ case SMB_IDMAP_USER:
+ sim.sim_stat = kidmap_getuidbysid(sim.sim_domsid,
+ sim.sim_rid, sim.sim_id);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ sim.sim_stat = kidmap_getgidbysid(sim.sim_domsid,
+ sim.sim_rid, sim.sim_id);
+ break;
+
+ case SMB_IDMAP_UNKNOWN:
+ sim.sim_stat = kidmap_getpidbysid(sim.sim_domsid,
+ sim.sim_rid, sim.sim_id, &sim.sim_idtype);
+ break;
+
+ default:
+ ASSERT(0);
+ return (IDMAP_ERR_ARG);
+ }
+
+ *idtype = sim.sim_idtype;
+ MEM_FREE("smbsrv", sim.sim_domsid);
+
+ return (sim.sim_stat);
+}
+
+/*
+ * smb_idmap_getsid
+ *
+ * Maps the given Solaris ID to a Windows SID using the
+ * simple mapping API.
+ */
+idmap_stat
+smb_idmap_getsid(uid_t id, int idtype, nt_sid_t **sid)
+{
+ smb_idmap_t sim;
+
+ switch (idtype) {
+ case SMB_IDMAP_USER:
+ sim.sim_stat = kidmap_getsidbyuid(id,
+ (const char **)&sim.sim_domsid, &sim.sim_rid);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ sim.sim_stat = kidmap_getsidbygid(id,
+ (const char **)&sim.sim_domsid, &sim.sim_rid);
+ break;
+
+ case SMB_IDMAP_EVERYONE:
+ /* Everyone S-1-1-0 */
+ sim.sim_domsid = "S-1-1";
+ sim.sim_rid = 0;
+ sim.sim_stat = IDMAP_SUCCESS;
+ break;
+
+ default:
+ ASSERT(0);
+ return (IDMAP_ERR_ARG);
+ }
+
+ if (sim.sim_stat != IDMAP_SUCCESS)
+ return (sim.sim_stat);
+
+ if (sim.sim_domsid == NULL) {
+ return (IDMAP_ERR_NOMAPPING);
+ }
+
+ sim.sim_sid = nt_sid_strtosid(sim.sim_domsid);
+ if (sim.sim_sid == NULL) {
+ return (IDMAP_ERR_INTERNAL);
+ }
+
+ *sid = nt_sid_splice(sim.sim_sid, sim.sim_rid);
+ MEM_FREE("smbsrv", sim.sim_sid);
+ if (*sid == NULL)
+ sim.sim_stat = IDMAP_ERR_INTERNAL;
+
+ return (sim.sim_stat);
+}
+
+/*
+ * smb_idmap_batch_create
+ *
+ * Creates and initializes the context for batch ID mapping.
+ */
+idmap_stat
+smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
+{
+ ASSERT(sib);
+
+ bzero(sib, sizeof (smb_idmap_batch_t));
+
+ sib->sib_idmaph = kidmap_get_create();
+ if (sib->sib_idmaph == NULL)
+ return (IDMAP_ERR_INTERNAL);
+
+ sib->sib_flags = flags;
+ sib->sib_nmap = nmap;
+ sib->sib_size = nmap * sizeof (smb_idmap_t);
+ sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
+
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * smb_idmap_batch_destroy
+ *
+ * Frees the batch ID mapping context.
+ * If ID mapping is Solaris -> Windows it frees memories
+ * allocated for binary SIDs.
+ */
+void
+smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
+{
+ nt_sid_t *sid;
+ char *domsid;
+ int i;
+
+ ASSERT(sib);
+ ASSERT(sib->sib_maps);
+
+ if (sib->sib_idmaph)
+ kidmap_get_destroy(sib->sib_idmaph);
+
+ if (sib->sib_flags & SMB_IDMAP_ID2SID) {
+ /*
+ * SIDs are allocated only when mapping
+ * UID/GID to SIDs
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ sid = sib->sib_maps[i].sim_sid;
+ if (sid)
+ MEM_FREE("smbsrv", sid);
+ }
+ } else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
+ /*
+ * SID prefixes are allocated only when mapping
+ * SIDs to UID/GID
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ domsid = sib->sib_maps[i].sim_domsid;
+ if (domsid)
+ MEM_FREE("smbsrv", domsid);
+ }
+ }
+
+ if (sib->sib_size && sib->sib_maps)
+ kmem_free(sib->sib_maps, sib->sib_size);
+}
+
+/*
+ * smb_idmap_batch_getid
+ *
+ * Queue a request to map the given SID to a UID or GID.
+ *
+ * sim->sim_id should point to variable that's supposed to
+ * hold the returned UID/GID. This needs to be setup by caller
+ * of this function.
+ *
+ * If requested ID type is known, it's passed as 'idtype',
+ * if it's unknown it'll be returned in sim->sim_idtype.
+ */
+idmap_stat
+smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
+ nt_sid_t *sid, int idtype)
+{
+ nt_sid_t *tmpsid;
+ idmap_stat idm_stat;
+
+ ASSERT(idmaph);
+ ASSERT(sim);
+ ASSERT(sid);
+
+ tmpsid = nt_sid_dup(sid);
+ (void) nt_sid_split(tmpsid, &sim->sim_rid);
+ sim->sim_domsid = nt_sid_format(tmpsid);
+ MEM_FREE("smbsrv", tmpsid);
+
+ switch (idtype) {
+ case SMB_IDMAP_USER:
+ idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, sim->sim_id, &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, sim->sim_id, &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_UNKNOWN:
+ idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, sim->sim_id, &sim->sim_idtype,
+ &sim->sim_stat);
+ break;
+
+ default:
+ ASSERT(0);
+ return (IDMAP_ERR_ARG);
+ }
+
+ return (idm_stat);
+}
+
+/*
+ * smb_idmap_batch_getsid
+ *
+ * Queue a request to map the given UID/GID to a SID.
+ *
+ * sim->sim_domsid and sim->sim_rid will contain the mapping
+ * result upon successful process of the batched request.
+ */
+idmap_stat
+smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
+ uid_t id, int idtype)
+{
+ idmap_stat idm_stat;
+
+ switch (idtype) {
+ case SMB_IDMAP_USER:
+ idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
+ (const char **)&sim->sim_domsid, &sim->sim_rid,
+ &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ idm_stat = kidmap_batch_getsidbygid(idmaph, id,
+ (const char **)&sim->sim_domsid, &sim->sim_rid,
+ &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_EVERYONE:
+ /* Everyone S-1-1-0 */
+ sim->sim_domsid = "S-1-1";
+ sim->sim_rid = 0;
+ sim->sim_stat = IDMAP_SUCCESS;
+ idm_stat = IDMAP_SUCCESS;
+ break;
+
+ default:
+ ASSERT(0);
+ return (IDMAP_ERR_ARG);
+ }
+
+ return (idm_stat);
+}
+
+/*
+ * smb_idmap_batch_binsid
+ *
+ * Convert sidrids to binary sids
+ *
+ * Returns 0 if successful and non-zero upon failure.
+ */
+static int
+smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
+{
+ nt_sid_t *sid;
+ smb_idmap_t *sim;
+ int i;
+
+ if (sib->sib_flags & SMB_IDMAP_SID2ID)
+ /* This operation is not required */
+ return (0);
+
+ sim = sib->sib_maps;
+ for (i = 0; i < sib->sib_nmap; sim++, i++) {
+ ASSERT(sim->sim_domsid);
+ if (sim->sim_domsid == NULL) {
+ return (1);
+ }
+
+ sid = nt_sid_strtosid(sim->sim_domsid);
+ if (sid == NULL) {
+ return (1);
+ }
+
+ sim->sim_sid = nt_sid_splice(sid, sim->sim_rid);
+ MEM_FREE("smbsrv", sid);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_idmap_batch_getmappings
+ *
+ * trigger ID mapping service to get the mappings for queued
+ * requests.
+ *
+ * Checks the result of all the queued requests.
+ * If this is a Solaris -> Windows mapping it generates
+ * binary SIDs from returned (domsid, rid) pairs.
+ */
+idmap_stat
+smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
+{
+ idmap_stat idm_stat = IDMAP_SUCCESS;
+ int i;
+
+ idm_stat = kidmap_get_mappings(sib->sib_idmaph);
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (idm_stat);
+ }
+
+ /*
+ * Check the status for all the queued requests
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS) {
+ return (sib->sib_maps[i].sim_stat);
+ }
+ }
+
+ if (smb_idmap_batch_binsid(sib) != 0) {
+ idm_stat = IDMAP_ERR_OTHER;
+ }
+
+ return (idm_stat);
+}
+
+uint64_t
+unix_to_nt_time(timestruc_t *unix_time)
+{
+ uint64_t nt_time;
+
+ nt_time = unix_time->tv_sec;
+ nt_time *= 10000000; /* seconds to 100ns */
+ nt_time += unix_time->tv_nsec / 100;
+ return (nt_time + NT_TIME_BIAS);
+}
+
+uint32_t
+nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time)
+{
+ uint32_t seconds;
+
+ nt_time -= NT_TIME_BIAS;
+ seconds = nt_time / 10000000;
+ if (unix_time) {
+ unix_time->tv_sec = seconds;
+ unix_time->tv_nsec = (nt_time % 10000000) * 100;
+ }
+ return (seconds);
+}
+
+int32_t /*ARGSUSED*/
+dosfs_dos_to_ux_time(int32_t date, int time)
+{
+ struct tm atm;
+
+ atm.tm_year = ((date >> 9) & 0x3F) + 80;
+ atm.tm_mon = ((date >> 5) & 0x0F) - 1;
+ atm.tm_mday = ((date >> 0) & 0x1F);
+ atm.tm_hour = ((time >> 11) & 0x1F);
+ atm.tm_min = ((time >> 5) & 0x3F);
+ atm.tm_sec = ((time >> 0) & 0x1F) << 1;
+
+ return (smb_timegm(&atm));
+}
+
+int32_t /*ARGSUSED*/
+dosfs_ux_to_dos_time(int32_t ux_time, short *date_p, short *time_p)
+{
+ struct tm atm;
+ int i;
+ time_t tmp_time;
+
+ tmp_time = (time_t)ux_time;
+ (void) smb_gmtime_r(&tmp_time, &atm);
+
+ if (date_p) {
+ i = 0;
+ i += atm.tm_year - 80;
+ i <<= 4;
+ i += atm.tm_mon + 1;
+ i <<= 5;
+ i += atm.tm_mday;
+
+ *date_p = (short)i;
+ }
+ if (time_p) {
+ i = 0;
+ i += atm.tm_hour;
+ i <<= 6;
+ i += atm.tm_min;
+ i <<= 5;
+ i += atm.tm_sec >> 1;
+
+ *time_p = (short)i;
+ }
+ return (ux_time);
+}
+
+
+/*
+ * smb_gmtime_r
+ *
+ * Thread-safe version of smb_gmtime. Returns a null pointer if either
+ * input parameter is a null pointer. Otherwise returns a pointer
+ * to result.
+ *
+ * Day of the week calculation: the Epoch was a thursday.
+ *
+ * There are no timezone corrections so tm_isdst and tm_gmtoff are
+ * always zero, and the zone is always WET.
+ */
+struct tm *
+smb_gmtime_r(time_t *clock, struct tm *result)
+{
+ time_t tsec;
+ int year;
+ int month;
+ int sec_per_month;
+
+ if (clock == 0 || result == 0)
+ return (0);
+
+ bzero(result, sizeof (struct tm));
+ tsec = *clock;
+ tsec -= tzh_leapcnt;
+
+ result->tm_wday = tsec / SECSPERDAY;
+ result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK;
+
+ year = EPOCH_YEAR;
+ while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) :
+ (SECSPERDAY * DAYSPERNYEAR))) {
+ if (isleap(year))
+ tsec -= SECSPERDAY * DAYSPERLYEAR;
+ else
+ tsec -= SECSPERDAY * DAYSPERNYEAR;
+
+ ++year;
+ }
+
+ result->tm_year = year - TM_YEAR_BASE;
+ result->tm_yday = tsec / SECSPERDAY;
+
+ for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) {
+ sec_per_month = days_in_month[month] * SECSPERDAY;
+
+ if (month == TM_FEBRUARY && isleap(year))
+ sec_per_month += SECSPERDAY;
+
+ if (tsec < sec_per_month)
+ break;
+
+ tsec -= sec_per_month;
+ }
+
+ result->tm_mon = month;
+ result->tm_mday = (tsec / SECSPERDAY) + 1;
+ tsec %= SECSPERDAY;
+ result->tm_sec = tsec % 60;
+ tsec /= 60;
+ result->tm_min = tsec % 60;
+ tsec /= 60;
+ result->tm_hour = (int)tsec;
+
+ return (result);
+}
+
+
+/*
+ * smb_timegm
+ *
+ * Converts the broken-down time in tm to a time value, i.e. the number
+ * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is
+ * not a POSIX or ANSI function. Per the man page, the input values of
+ * tm_wday and tm_yday are ignored and, as the input data is assumed to
+ * represent GMT, we force tm_isdst and tm_gmtoff to 0.
+ *
+ * Before returning the clock time, we use smb_gmtime_r to set up tm_wday
+ * and tm_yday, and bring the other fields within normal range. I don't
+ * think this is really how it should be done but it's convenient for
+ * now.
+ */
+time_t
+smb_timegm(struct tm *tm)
+{
+ time_t tsec;
+ int dd;
+ int mm;
+ int yy;
+ int year;
+
+ if (tm == 0)
+ return (-1);
+
+ year = tm->tm_year + TM_YEAR_BASE;
+ tsec = tzh_leapcnt;
+
+ for (yy = EPOCH_YEAR; yy < year; ++yy) {
+ if (isleap(yy))
+ tsec += SECSPERDAY * DAYSPERLYEAR;
+ else
+ tsec += SECSPERDAY * DAYSPERNYEAR;
+ }
+
+ for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) {
+ dd = days_in_month[mm] * SECSPERDAY;
+
+ if (mm == TM_FEBRUARY && isleap(year))
+ dd += SECSPERDAY;
+
+ tsec += dd;
+ }
+
+ tsec += (tm->tm_mday - 1) * SECSPERDAY;
+ tsec += tm->tm_sec;
+ tsec += tm->tm_min * SECSPERMIN;
+ tsec += tm->tm_hour * SECSPERHOUR;
+
+ tm->tm_isdst = 0;
+ (void) smb_gmtime_r(&tsec, tm);
+ return (tsec);
+}
+
+#ifdef DEBUG
+uint32_t smb_audit_flags = SMB_AUDIT_NODE;
+#else
+uint32_t smb_audit_flags = 0;
+#endif
+
+void
+smb_audit_buf_node_create(smb_node_t *node)
+{
+ smb_audit_buf_node_t *abn;
+
+ if (smb_audit_flags & SMB_AUDIT_NODE) {
+ abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), KM_SLEEP);
+ abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
+ node->n_audit_buf = abn;
+ }
+}
+
+void
+smb_audit_buf_node_destroy(smb_node_t *node)
+{
+ smb_audit_buf_node_t *abn;
+
+ abn = node->n_audit_buf;
+
+ if (abn) {
+ node->n_audit_buf = NULL;
+ kmem_free(abn, sizeof (smb_audit_buf_node_t));
+ }
+}
+
+/*
+ * smb_cred_set_sid
+ *
+ * Initialize the ksid based on the given smb_id_t.
+ */
+static void
+smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
+{
+ nt_sid_t *domain_sid = NULL;
+ char *domain_sid_buf = NULL;
+ int rc;
+
+ ASSERT(id);
+ ASSERT(id->i_sidattr.sid);
+
+ ksid->ks_id = id->i_id;
+ domain_sid = nt_sid_dup(id->i_sidattr.sid);
+ rc = nt_sid_split(domain_sid, &ksid->ks_rid);
+ ASSERT(rc == 0);
+
+ ksid->ks_attr = id->i_sidattr.attrs;
+ domain_sid_buf = nt_sid_format(domain_sid);
+ ksid->ks_domain = ksid_lookupdomain(domain_sid_buf);
+ MEM_FREE("smbsrv", domain_sid);
+ MEM_FREE("smbsrv", domain_sid_buf);
+}
+
+/*
+ * smb_cred_set_sidlist
+ *
+ * Allocate and initialize the ksidlist based on the Windows group list of the
+ * access token.
+ */
+static ksidlist_t *
+smb_cred_set_sidlist(smb_win_grps_t *token_grps)
+{
+ int i;
+ ksidlist_t *lp;
+
+ lp = kmem_zalloc(KSIDLIST_MEM(token_grps->wg_count), KM_SLEEP);
+ lp->ksl_ref = 1;
+ lp->ksl_nsid = token_grps->wg_count;
+ lp->ksl_neid = 0;
+
+ for (i = 0; i < lp->ksl_nsid; i++) {
+ smb_cred_set_sid(&token_grps->wg_groups[i],
+ &lp->ksl_sids[i]);
+ if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
+ lp->ksl_neid++;
+ }
+
+ return (lp);
+}
+
+/*
+ * smb_cred_create
+ *
+ * The credential of the given SMB user will be allocated and initialized based
+ * on the given access token.
+ */
+cred_t *
+smb_cred_create(smb_token_t *token, uint32_t *privileges)
+{
+ ksid_t ksid;
+ ksidlist_t *ksidlist = NULL;
+ smb_posix_grps_t *posix_grps;
+ cred_t *cr;
+
+ ASSERT(token);
+ ASSERT(token->tkn_posix_grps);
+ ASSERT(privileges);
+
+ cr = crget();
+ ASSERT(cr != NULL);
+
+ posix_grps = token->tkn_posix_grps;
+ if (crsetugid(cr, token->tkn_user->i_id,
+ token->tkn_primary_grp->i_id) != 0) {
+ crfree(cr);
+ return (NULL);
+ }
+
+ if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
+ crfree(cr);
+ return (NULL);
+ }
+
+ smb_cred_set_sid(token->tkn_user, &ksid);
+ crsetsid(cr, &ksid, KSID_USER);
+ smb_cred_set_sid(token->tkn_primary_grp, &ksid);
+ crsetsid(cr, &ksid, KSID_GROUP);
+ smb_cred_set_sid(token->tkn_owner, &ksid);
+ crsetsid(cr, &ksid, KSID_OWNER);
+ ksidlist = smb_cred_set_sidlist(token->tkn_win_grps);
+ crsetsidlist(cr, ksidlist);
+
+ *privileges = 0;
+
+ /*
+ * Support for backup and restore privileges will be disabled until
+ * the BACKUP_SEMANTICS and backup intent attributes are supported.
+ */
+#ifdef SUPPORT_FILE_OPEN_FOR_BACKUP
+ if (smb_token_query_privilege(token, SE_BACKUP_LUID)) {
+ *privileges |= SMB_USER_PRIV_BACKUP;
+ (void) crsetpriv(cr, PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
+ }
+
+ if (smb_token_query_privilege(token, SE_RESTORE_LUID)) {
+ *privileges |= SMB_USER_PRIV_RESTORE;
+ (void) crsetpriv(cr, PRIV_FILE_DAC_WRITE,
+ PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
+ PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
+ PRIV_FILE_OWNER, PRIV_FILE_SETID, PRIV_SYS_LINKDIR,
+ PRIV_SYS_MOUNT, NULL);
+ }
+#endif /* SUPPORT_FILE_OPEN_FOR_BACKUP */
+
+ if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) {
+ *privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
+ (void) crsetpriv(cr, PRIV_FILE_CHOWN, NULL);
+ }
+
+ if (smb_token_query_privilege(token, SE_SECURITY_LUID)) {
+ *privileges |= SMB_USER_PRIV_SECURITY;
+ }
+ return (cr);
+}
+
+/*
+ * smb_cred_rele
+ *
+ * The reference count of the user's credential will get decremented if it
+ * is non-zero. Otherwise, the credential will be freed.
+ */
+void
+smb_cred_rele(cred_t *cr)
+{
+ ASSERT(cr);
+ crfree(cr);
+}
+
+/*
+ * smb_cred_is_member
+ *
+ * Same as smb_token_is_member. The only difference is that
+ * we compare the given SID against user SID and the ksidlist
+ * of the user's cred.
+ */
+int
+smb_cred_is_member(cred_t *cr, nt_sid_t *sid)
+{
+ ksidlist_t *ksidlist;
+ ksid_t ksid1, *ksid2;
+ smb_id_t id;
+ int i, rc = 0;
+
+ ASSERT(cr);
+
+ bzero(&id, sizeof (smb_id_t));
+ id.i_sidattr.sid = sid;
+ smb_cred_set_sid(&id, &ksid1);
+
+ ksidlist = crgetsidlist(cr);
+ ASSERT(ksidlist);
+ ASSERT(ksid1.ks_domain);
+ ASSERT(ksid1.ks_domain->kd_name);
+
+ i = 0;
+ ksid2 = crgetsid(cr, KSID_USER);
+ do {
+ ASSERT(ksid2->ks_domain);
+ ASSERT(ksid2->ks_domain->kd_name);
+
+ if (strcmp(ksid1.ks_domain->kd_name,
+ ksid2->ks_domain->kd_name) == 0 &&
+ ksid1.ks_rid == ksid2->ks_rid) {
+ rc = 1;
+ break;
+ }
+
+ ksid2 = &ksidlist->ksl_sids[i];
+ } while (i++ < ksidlist->ksl_nsid);
+
+ ksid_rele(&ksid1);
+ return (rc);
+}
+
+/*
+ * smb_kstrdup
+ *
+ * Duplicate the given string s.
+ */
+char *
+smb_kstrdup(const char *s, size_t n)
+{
+ char *s2;
+
+ ASSERT(s);
+ ASSERT(n);
+ s2 = kmem_alloc(n, KM_SLEEP);
+ (void) strcpy(s2, s);
+ return (s2);
+}
+
+/*
+ * smb_sync_fsattr
+ *
+ * Sync file's attributes with file system.
+ * The sync takes place based on node->what and node->flags
+ * values.
+ */
+int
+smb_sync_fsattr(struct smb_request *sr, cred_t *cr, smb_node_t *node)
+{
+ uint32_t what;
+ int rc = 0;
+
+ if (node->flags & NODE_READ_ONLY)
+ return (0);
+
+ if (node->flags & NODE_FLAGS_SET_SIZE) {
+ node->flags &= ~NODE_FLAGS_SET_SIZE;
+ node->what |= SMB_AT_SIZE;
+ node->attr.sa_vattr.va_size = node->n_size;
+ }
+
+ if (node->what) {
+ /*
+ * This is to prevent another thread from starting
+ * a setattr should this one go to sleep
+ */
+ what = node->what;
+ node->what = 0;
+
+ node->attr.sa_mask = what;
+
+ rc = smb_fsop_setattr(sr, cr, node, &node->attr, &node->attr);
+
+ if (rc) {
+ /* setattr failed, restore the dirty state? */
+ node->what = what;
+ }
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_share_export()
+ *
+ * This function handles kernel processing at share enable time.
+ *
+ * At share-enable time (LMSHRD_ADD), the file system corresponding to
+ * the share is checked for characteristics that are required for SMB
+ * sharing. If this check passes, then a hold is taken on the root vnode
+ * of the file system (or a reference count on the corresponding smb_vfs_t
+ * is bumped), preventing an unmount. (See smb_vfs_hold()).
+ */
+
+int
+smb_share_export(char *path)
+{
+ int error;
+ smb_node_t *fnode = NULL;
+ smb_node_t *dnode;
+ smb_attr_t ret_attr;
+ char last_comp[MAXNAMELEN];
+
+ error = smb_pathname_reduce(NULL, kcred, path, NULL, NULL, &dnode,
+ last_comp);
+
+ if (error)
+ return (error);
+
+ error = smb_fsop_lookup(NULL, kcred, SMB_FOLLOW_LINKS, NULL, dnode,
+ last_comp, &fnode, &ret_attr, NULL, NULL);
+
+ smb_node_release(dnode);
+
+ if (error)
+ return (error);
+
+ ASSERT(fnode->vp && fnode->vp->v_vfsp);
+
+#ifdef SMB_ENFORCE_NODEV
+ if (vfs_optionisset(fnode->vp->v_vfsp, MNTOPT_NODEVICES, NULL) == 0)
+ return (EINVAL);
+#endif /* SMB_ENFORCE_NODEV */
+
+ if (!smb_vfs_hold(fnode->vp->v_vfsp)) {
+ smb_node_release(fnode);
+ return (ENOMEM);
+ }
+
+ /*
+ * The refcount on the smb_vfs has been incremented.
+ * If it wasn't already, a hold has also been taken
+ * on the root vnode of the file system.
+ */
+
+ smb_node_release(fnode);
+ return (0);
+}
+
+/*
+ * smb_share_unexport()
+ *
+ * This function handles kernel processing at share disable time.
+ *
+ * At share-disable time (LMSHRD_DELETE), the reference count on the
+ * corresponding smb_vfs_t is decremented. If this is the last share
+ * on the file system, the hold on the root vnode of the file system
+ * will be released. (See smb_vfs_rele().)
+ */
+
+int
+smb_share_unexport(char *path, char *sharename)
+{
+ int error;
+ smb_node_t *fnode = NULL;
+ smb_node_t *dnode;
+ smb_attr_t ret_attr;
+ char last_comp[MAXNAMELEN];
+
+ error = smb_pathname_reduce(NULL, kcred, path, NULL, NULL, &dnode,
+ last_comp);
+
+ if (error)
+ return (error);
+
+ error = smb_fsop_lookup(NULL, kcred, SMB_FOLLOW_LINKS, NULL, dnode,
+ last_comp, &fnode, &ret_attr, NULL, NULL);
+
+ smb_node_release(dnode);
+
+ if (error)
+ return (error);
+
+ ASSERT(fnode->vp && fnode->vp->v_vfsp);
+
+ smb_session_disconnect_share(sharename);
+ smb_vfs_rele(fnode->vp->v_vfsp);
+ smb_node_release(fnode);
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vfs.c b/usr/src/uts/common/fs/smbsrv/smb_vfs.c
new file mode 100644
index 0000000000..38928bfe2a
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_vfs.c
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <sys/vfs.h>
+
+static smb_vfs_t *smb_vfs_lookup(vnode_t *);
+
+/*
+ * smb_vfs_hold
+ *
+ * Increments the reference count of the fs passed in. If no smb_vfs_t structure
+ * has been created yet for the fs passed in it is created.
+ */
+boolean_t
+smb_vfs_hold(vfs_t *vfsp)
+{
+ smb_vfs_t *smb_vfs;
+ vnode_t *rootvp;
+
+ if ((vfsp == NULL) || VFS_ROOT(vfsp, &rootvp))
+ return (B_FALSE);
+
+ smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
+ smb_vfs = smb_vfs_lookup(rootvp);
+ if (smb_vfs) {
+ DTRACE_PROBE1(smb_vfs_hold_hit, smb_vfs_t *, smb_vfs);
+ smb_llist_exit(&smb_info.si_vfs_list);
+ VN_RELE(rootvp);
+ return (B_TRUE);
+ }
+ smb_vfs = kmem_cache_alloc(smb_info.si_cache_vfs, KM_SLEEP);
+
+ bzero(smb_vfs, sizeof (smb_vfs_t));
+
+ smb_vfs->sv_magic = SMB_VFS_MAGIC;
+ smb_vfs->sv_refcnt = 1;
+ smb_vfs->sv_vfsp = vfsp;
+ /*
+ * We have a hold on the root vnode of the file system
+ * from the VFS_ROOT call above.
+ */
+ smb_vfs->sv_rootvp = rootvp;
+ smb_llist_insert_head(&smb_info.si_vfs_list, smb_vfs);
+ DTRACE_PROBE1(smb_vfs_hold_miss, smb_vfs_t *, smb_vfs);
+ smb_llist_exit(&smb_info.si_vfs_list);
+ return (B_TRUE);
+}
+
+/*
+ * smb_vfs_rele
+ *
+ * Decrements the reference count of the fs passed in. If the reference count
+ * drops to zero the smb_vfs_t structure associated with the fs is freed.
+ */
+void
+smb_vfs_rele(vfs_t *vfsp)
+{
+ smb_vfs_t *smb_vfs;
+ vnode_t *rootvp;
+
+ ASSERT(vfsp);
+
+ if (VFS_ROOT(vfsp, &rootvp))
+ return;
+
+ smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
+ smb_vfs = smb_vfs_lookup(rootvp);
+ DTRACE_PROBE2(smb_vfs_release, smb_vfs_t *, smb_vfs, vnode_t *, rootvp);
+ VN_RELE(rootvp);
+ if (smb_vfs) {
+ --smb_vfs->sv_refcnt;
+ ASSERT(smb_vfs->sv_refcnt);
+ if (--smb_vfs->sv_refcnt == 0) {
+ smb_llist_remove(&smb_info.si_vfs_list, smb_vfs);
+ smb_llist_exit(&smb_info.si_vfs_list);
+ ASSERT(rootvp == smb_vfs->sv_rootvp);
+ VN_RELE(smb_vfs->sv_rootvp);
+ smb_vfs->sv_magic = (uint32_t)~SMB_VFS_MAGIC;
+ kmem_cache_free(smb_info.si_cache_vfs, smb_vfs);
+ return;
+ }
+ }
+ smb_llist_exit(&smb_info.si_vfs_list);
+}
+
+/*
+ * smb_vfs_rele_all()
+ *
+ * Release all holds on root vnodes of file systems which were taken
+ * due to the existence of at least one enabled share on the file system.
+ * Called at driver close time.
+ */
+void
+smb_vfs_rele_all()
+{
+ smb_vfs_t *smb_vfs;
+
+ smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
+ while ((smb_vfs = smb_llist_head(&smb_info.si_vfs_list)) != NULL) {
+
+ ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC);
+ DTRACE_PROBE1(smb_vfs_rele_all_hit, smb_vfs_t *, smb_vfs);
+ smb_llist_remove(&smb_info.si_vfs_list, smb_vfs);
+ VN_RELE(smb_vfs->sv_rootvp);
+ kmem_cache_free(smb_info.si_cache_vfs, smb_vfs);
+ }
+ smb_llist_exit(&smb_info.si_vfs_list);
+}
+
+/*
+ * smb_vfs_lookup
+ *
+ * Goes through the list of smb_vfs_t structure and returns the one matching
+ * the vnode passed in. If no match is found a NULL pointer is returned.
+ *
+ * The list of smb_vfs_t structures has to have been entered prior calling
+ * this function.
+ */
+static smb_vfs_t *
+smb_vfs_lookup(vnode_t *rootvp)
+{
+ smb_vfs_t *smb_vfs;
+
+ smb_vfs = smb_llist_head(&smb_info.si_vfs_list);
+ while (smb_vfs) {
+ ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC);
+ if (smb_vfs->sv_rootvp == rootvp) {
+ smb_vfs->sv_refcnt++;
+ ASSERT(smb_vfs->sv_refcnt);
+ return (smb_vfs);
+ }
+ smb_vfs = smb_llist_next(&smb_info.si_vfs_list, smb_vfs);
+ }
+ return (NULL);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vops.c b/usr/src/uts/common/fs/smbsrv/smb_vops.c
new file mode 100644
index 0000000000..b71174e9d5
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c
@@ -0,0 +1,1878 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/statvfs.h>
+#include <sys/vnode.h>
+#include <sys/thread.h>
+#include <sys/pathname.h>
+#include <sys/cred.h>
+#include <sys/extdirent.h>
+#include <acl/acl_common.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/string.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/smbtrans.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+static int
+smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count,
+ cred_t *cr, caller_context_t *ct, int flags);
+
+static int
+smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen,
+ ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr,
+ caller_context_t *ct, char *dirbuf, int num_bytes);
+
+static int
+smb_vop_getdents_entries(smb_node_t *dir_snode, uint32_t *cookiep,
+ int32_t *dircountp, char *arg, uint32_t flags, struct smb_request *sr,
+ cred_t *cr, caller_context_t *ct, char *dirbuf, int *maxentries,
+ int num_bytes, char *);
+
+extern int
+smb_gather_dents_info(char *args, ino_t fileid, int namelen,
+ char *name, uint32_t cookie, int32_t *countp,
+ smb_attr_t *attr, struct smb_node *snode,
+ char *shortname, char *name83);
+
+static void
+smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp);
+
+#define SMB_AT_MAX 16
+static uint_t smb_attrmap[SMB_AT_MAX] = {
+ 0,
+ 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
+};
+
+int
+smb_vop_open(vnode_t **vpp, int mode, cred_t *cred, caller_context_t *ct)
+{
+ return (VOP_OPEN(vpp, mode, cred, ct));
+}
+
+int
+smb_vop_close(vnode_t *vp, int mode, cred_t *cred, caller_context_t *ct)
+{
+ return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, ct));
+}
+
+/*
+ * The smb_vop_* functions have minimal knowledge of CIFS semantics and
+ * serve as an interface to the VFS layer.
+ *
+ * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
+ * (Higher-level CIFS service code should never skip the smb_fsop_* layer
+ * to call smb_vop_* layer functions directly.)
+ */
+
+/*
+ * XXX - Extended attributes support in the file system assumed.
+ * This is needed for full NT Streams functionality.
+ */
+
+int
+smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
+{
+ int error;
+
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READ(vp, uiop, 0, cr, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ return (error);
+}
+
+int
+smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount,
+ cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ int ioflag = 0;
+
+ *lcount = uiop->uio_resid;
+
+ if (*flag == FSSTAB_FILE_SYNC)
+ ioflag = FSYNC;
+
+ uiop->uio_llimit = MAXOFFSET_T;
+
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ error = VOP_WRITE(vp, uiop, ioflag, cr, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
+
+ *lcount -= uiop->uio_resid;
+
+ return (error);
+}
+
+/*
+ * smb_vop_getattr()
+ *
+ * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
+ * service (instead of calling VOP_GETATTR directly) to retrieve attributes
+ * due to special processing needed for streams files.
+ *
+ * All attributes are retrieved.
+ *
+ * A named stream's attributes (as far as CIFS is concerned) are those of the
+ * unnamed (i.e. data) stream (minus the size attribute), and the size of the
+ * named stream. Though the file system may store attributes other than size
+ * with the named stream, these should not be used by CIFS for any purpose.
+ *
+ * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
+ * the corresponding unnamed stream).
+ */
+
+int
+smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
+ int flags, cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ vnode_t *use_vp;
+ smb_attr_t tmp_attr;
+ xvattr_t tmp_xvattr;
+ xoptattr_t *xoap = NULL;
+
+ if (unnamed_vp)
+ use_vp = unnamed_vp;
+ else
+ use_vp = vp;
+
+ if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
+ xva_init(&tmp_xvattr);
+ xoap = xva_getxoptattr(&tmp_xvattr);
+
+ ASSERT(xoap);
+
+ smb_sa_to_va_mask(ret_attr->sa_mask,
+ &tmp_xvattr.xva_vattr.va_mask);
+
+ XVA_SET_REQ(&tmp_xvattr, XAT_READONLY);
+ XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN);
+ XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM);
+ XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
+ XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
+
+ if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags,
+ cr, ct)) != 0)
+ return (error);
+
+ ret_attr->sa_vattr = tmp_xvattr.xva_vattr;
+
+ /*
+ * Copy special attributes to ret_attr parameter
+ */
+
+ ret_attr->sa_dosattr = 0;
+
+ ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR);
+
+ xoap = xva_getxoptattr(&tmp_xvattr);
+ ASSERT(xoap);
+
+ if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) {
+ if (xoap->xoa_readonly)
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) {
+ if (xoap->xoa_hidden)
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN;
+ }
+
+ if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) {
+ if (xoap->xoa_system)
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM;
+ }
+
+ if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) {
+ if (xoap->xoa_archive)
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
+ }
+
+ ret_attr->sa_crtime = xoap->xoa_createtime;
+
+ if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
+ /*
+ * Retrieve stream size attribute into temporary
+ * structure, in case the underlying file system
+ * returns attributes other than the size (we do not
+ * want to have ret_attr's other fields get
+ * overwritten).
+ *
+ * Note that vp is used here, and not use_vp.
+ * Also, only AT_SIZE is needed.
+ */
+
+ tmp_xvattr.xva_vattr.va_mask = AT_SIZE;
+
+ if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr,
+ flags, cr, ct)) != 0)
+ return (error);
+
+ ret_attr->sa_vattr.va_size =
+ tmp_xvattr.xva_vattr.va_size;
+
+ }
+
+ if (ret_attr->sa_vattr.va_type == VDIR) {
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ return (error);
+ }
+
+ /*
+ * Support for file systems without VFSFT_XVATTR
+ */
+
+ smb_sa_to_va_mask(ret_attr->sa_mask,
+ &ret_attr->sa_vattr.va_mask);
+
+ error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, ct);
+
+ if (error != 0)
+ return (error);
+
+ /*
+ * "Fake" DOS attributes and create time, filesystem doesn't support
+ * them.
+ */
+
+ ret_attr->sa_dosattr = 0;
+ ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime;
+
+ if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
+ /*
+ * Retrieve stream size attribute into temporary structure,
+ * in case the underlying file system returns attributes
+ * other than the size (we do not want to have ret_attr's
+ * other fields get overwritten).
+ *
+ * Note that vp is used here, and not use_vp.
+ * Also, only AT_SIZE is needed.
+ */
+
+ tmp_attr.sa_vattr.va_mask = AT_SIZE;
+ error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, ct);
+
+ if (error != 0)
+ return (error);
+
+
+ ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
+ }
+
+ if (ret_attr->sa_vattr.va_type == VDIR) {
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ return (error);
+}
+
+/*
+ * smb_vop_setattr()
+ *
+ * smb_fsop_setattr()/smb_vop_setattr() should always be called from the CIFS
+ * service to set attributes due to special processing for streams files.
+ *
+ * When smb_vop_setattr() is called on a named stream file, all indicated
+ * attributes except the size are set on the unnamed stream file. The size
+ * (if indicated) is set on the named stream file.
+ */
+
+int
+smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
+ int flags, cred_t *cr, caller_context_t *ct)
+{
+ int error = 0;
+ int at_size = 0;
+ vnode_t *use_vp;
+ xvattr_t tmp_xvattr;
+ xoptattr_t *xoap = NULL;
+ uint_t xva_mask;
+
+ if (unnamed_vp) {
+ use_vp = unnamed_vp;
+ if (set_attr->sa_mask & SMB_AT_SIZE) {
+ at_size = 1;
+ set_attr->sa_mask &= ~SMB_AT_SIZE;
+ }
+ } else {
+ use_vp = vp;
+ }
+
+ /*
+ * The caller should not be setting sa_vattr.va_mask,
+ * but rather sa_mask.
+ */
+
+ set_attr->sa_vattr.va_mask = 0;
+
+ if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
+ /*
+ * Initialize xvattr, including bzero
+ */
+ xva_init(&tmp_xvattr);
+ xoap = xva_getxoptattr(&tmp_xvattr);
+
+ ASSERT(xoap);
+
+ /*
+ * Copy caller-specified classic attributes to tmp_xvattr.
+ * First save tmp_xvattr's mask (set in xva_init()).
+ * This is |'d in later.
+ */
+
+ xva_mask = tmp_xvattr.xva_vattr.va_mask;
+ tmp_xvattr.xva_vattr = set_attr->sa_vattr;
+
+ smb_sa_to_va_mask(set_attr->sa_mask,
+ &tmp_xvattr.xva_vattr.va_mask);
+
+ /*
+ * "|" in the original xva_mask.
+ */
+
+ tmp_xvattr.xva_vattr.va_mask |= xva_mask;
+
+ if (set_attr->sa_mask & SMB_AT_DOSATTR) {
+ XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
+ XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM);
+ XVA_SET_REQ(&tmp_xvattr, XAT_READONLY);
+ XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN);
+
+ /*
+ * set_attr->sa_dosattr: If a given bit is not set,
+ * that indicates that the corresponding field needs
+ * to be updated with a "0" value. This is done
+ * implicitly as the xoap->xoa_* fields were bzero'd.
+ */
+
+ if (set_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE)
+ xoap->xoa_archive = 1;
+
+ if (set_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM)
+ xoap->xoa_system = 1;
+
+ if (set_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY)
+ xoap->xoa_readonly = 1;
+
+ if (set_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN)
+ xoap->xoa_hidden = 1;
+ }
+
+ if (set_attr->sa_mask & SMB_AT_CRTIME) {
+ XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
+ xoap->xoa_createtime = set_attr->sa_crtime;
+ }
+
+ if ((error = VOP_SETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags,
+ cr, ct)) != 0)
+ return (error);
+
+ /*
+ * If the size of the stream needs to be set, set it on
+ * the stream file directly. (All other indicated attributes
+ * are set on the stream's unnamed stream, above.)
+ */
+
+ if (at_size) {
+ /*
+ * set_attr->sa_vattr.va_size already contains the
+ * size as set by the caller
+ *
+ * Note that vp is used here, and not use_vp.
+ * Also, only AT_SIZE is needed.
+ */
+
+ set_attr->sa_vattr.va_mask = AT_SIZE;
+ error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags,
+ cr, ct);
+ }
+
+ return (error);
+ }
+
+ /*
+ * Support for file systems without VFSFT_XVATTR
+ */
+
+ smb_sa_to_va_mask(set_attr->sa_mask, &set_attr->sa_vattr.va_mask);
+
+ /*
+ * set_attr->sa_vattr already contains new values
+ * as set by the caller
+ */
+
+ error = VOP_SETATTR(use_vp, &set_attr->sa_vattr, flags, cr, ct);
+
+ if (error != 0)
+ return (error);
+
+ if (at_size) {
+ /*
+ * set_attr->sa_vattr.va_size already contains the
+ * size as set by the caller
+ *
+ * Note that vp is used here, and not use_vp.
+ * Also, only AT_SIZE is needed.
+ */
+
+ set_attr->sa_vattr.va_mask = AT_SIZE;
+ error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, ct);
+ }
+
+ return (error);
+}
+
+/*
+ * smb_vop_access
+ *
+ * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
+ * against file's ACL or Unix permissions. CIFS on the other hand needs to
+ * know if the requested operation can succeed for the given object, this
+ * requires more checks in case of DELETE bit since permissions on the parent
+ * directory are important as well. Based on Windows rules if parent's ACL
+ * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
+ * permissions.
+ */
+int
+smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
+{
+ int error = 0;
+
+ if (mode == 0)
+ return (0);
+
+ if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) {
+ if (dir_vp) {
+ error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
+ cr, NULL);
+
+ if (error == 0)
+ mode &= ~ACE_DELETE;
+ }
+ }
+
+ if (mode) {
+ error = VOP_ACCESS(vp, mode, flags, cr, NULL);
+ }
+
+ return (error);
+}
+
+/*
+ * smb_vop_lookup
+ *
+ * dvp: directory vnode (in)
+ * name: name of file to be looked up (in)
+ * vpp: looked-up vnode (out)
+ * od_name: on-disk name of file (out).
+ * This parameter is optional. If a pointer is passed in, it
+ * must be allocated with MAXNAMELEN bytes
+ * rootvp: vnode of the tree root (in)
+ * This parameter is always passed in non-NULL except at the time
+ * of share set up.
+ */
+
+int
+smb_vop_lookup(vnode_t *dvp, char *name, vnode_t **vpp, char *od_name,
+ int flags, vnode_t *rootvp, cred_t *cr, caller_context_t *ct)
+{
+ int error = 0;
+ int option_flags = 0;
+ pathname_t rpn;
+
+ if (*name == '\0')
+ return (EINVAL);
+
+ ASSERT(vpp);
+ *vpp = NULL;
+
+ if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) {
+ if (rootvp && (dvp == rootvp)) {
+ VN_HOLD(dvp);
+ *vpp = dvp;
+ return (0);
+ }
+
+ if (dvp->v_flag & VROOT) {
+ vfs_t *vfsp;
+ vnode_t *cvp = dvp;
+
+ /*
+ * Set dvp and check for races with forced unmount
+ * (see lookuppnvp())
+ */
+
+ vfsp = cvp->v_vfsp;
+ vfs_rlock_wait(vfsp);
+ if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
+ (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
+ vfs_unlock(vfsp);
+ return (EIO);
+ }
+ vfs_unlock(vfsp);
+ }
+ }
+
+
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ pn_alloc(&rpn);
+
+ error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr,
+ ct, NULL, &rpn);
+
+ if ((error == 0) && od_name) {
+ bzero(od_name, MAXNAMELEN);
+ if (option_flags == FIGNORECASE)
+ (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN);
+ else
+ (void) strlcpy(od_name, name, MAXNAMELEN);
+ }
+
+ pn_free(&rpn);
+ return (error);
+}
+
+int
+smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
+ int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap)
+{
+ int error;
+ int option_flags = 0;
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
+
+ error = VOP_CREATE(dvp, name, &attr->sa_vattr, EXCL,
+ attr->sa_vattr.va_mode, vpp, cr, option_flags, ct, vsap);
+
+ return (error);
+}
+
+int
+smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+ int option_flags = 0;
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ error = VOP_REMOVE(dvp, name, cr, ct, option_flags);
+
+ return (error);
+}
+
+/*
+ * smb_vop_rename()
+ *
+ * The rename is for files in the same tree (identical TID) only.
+ */
+
+int
+smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp,
+ char *to_name, int flags, cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ int option_flags = 0;
+
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr,
+ ct, option_flags);
+
+ return (error);
+}
+
+int
+smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
+ int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap)
+{
+ int error;
+ int option_flags = 0;
+
+
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
+
+ error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, ct,
+ option_flags, vsap);
+
+ return (error);
+}
+
+/*
+ * smb_vop_rmdir()
+ *
+ * Only simple rmdir supported, consistent with NT semantics
+ * (can only remove an empty directory).
+ *
+ */
+
+int
+smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+ int option_flags = 0;
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ /*
+ * Comments adapted from rfs_rmdir().
+ *
+ * VOP_RMDIR now takes a new third argument (the current
+ * directory of the process). That's because rmdir
+ * wants to return EINVAL if one tries to remove ".".
+ * Of course, SMB servers do not know what their
+ * clients' current directories are. We fake it by
+ * supplying a vnode known to exist and illegal to
+ * remove.
+ */
+
+ error = VOP_RMDIR(dvp, name, rootdir, cr, ct, option_flags);
+ return (error);
+}
+
+int
+smb_vop_commit(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+ return (VOP_FSYNC(vp, 1, cr, ct));
+}
+
+/*
+ * smb_vop_readdir()
+ *
+ * Upon return, the "name" field will contain either the on-disk name or, if
+ * it needs mangling or has a case-insensitive collision, the mangled
+ * "shortname."
+ *
+ * vpp is an optional parameter. If non-NULL, it will contain a pointer to
+ * the vnode for the name that is looked up (the vnode will be returned held).
+ *
+ * od_name is an optional parameter (NULL can be passed if the on-disk name
+ * is not needed by the caller).
+ */
+
+int
+smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen,
+ ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int num_bytes;
+ int error = 0;
+ char *dirbuf = NULL;
+
+ ASSERT(dvp);
+ ASSERT(cookiep);
+ ASSERT(name);
+ ASSERT(namelen);
+ ASSERT(inop);
+ ASSERT(cr);
+ ASSERT(ct);
+
+ if (dvp->v_type != VDIR) {
+ *namelen = 0;
+ return (ENOTDIR);
+ }
+
+ if (vpp)
+ *vpp = NULL;
+
+ dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP);
+ num_bytes = SMB_MINLEN_RDDIR_BUF;
+
+ /*
+ * The goal is to retrieve the first valid entry from *cookiep
+ * forward. smb_vop_readdir_readpage() collects an
+ * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information.
+ * smb_vop_readdir_entry() attempts to find the first valid entry
+ * in that page.
+ */
+
+ while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep,
+ &num_bytes, cr, ct, flags)) == 0) {
+
+ if (num_bytes <= 0)
+ break;
+
+ name[0] = '\0';
+
+ error = smb_vop_readdir_entry(dvp, cookiep, name, namelen,
+ inop, vpp, od_name, flags, cr, ct, dirbuf,
+ num_bytes);
+
+ if (error)
+ break;
+
+ if (*name)
+ break;
+
+ bzero(dirbuf, SMB_MINLEN_RDDIR_BUF);
+ num_bytes = SMB_MINLEN_RDDIR_BUF;
+ }
+
+
+ if (error) {
+ kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
+ *namelen = 0;
+ return (error);
+ }
+
+ if (num_bytes == 0) { /* EOF */
+ kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
+ *cookiep = SMB_EOF;
+ *namelen = 0;
+ return (0);
+ }
+
+ kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
+ return (0);
+}
+
+/*
+ * smb_vop_readdir_readpage()
+ *
+ * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The
+ * directory entries are returned in an fs-independent format by the
+ * underlying file system. That is, the "page" of information returned is
+ * not literally stored on-disk in the format returned.)
+ *
+ * Much of the following is borrowed from getdents64()
+ *
+ * MAXGETDENTS_SIZE is defined in getdents.c
+ */
+
+#define MAXGETDENTS_SIZE (64 * 1024)
+
+static int
+smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count,
+ cred_t *cr, caller_context_t *ct, int flags)
+{
+ int error = 0;
+ int rdirent_flags = 0;
+ int sink;
+ struct uio auio;
+ struct iovec aiov;
+
+ if (vp->v_type != VDIR)
+ return (ENOTDIR);
+
+ /* entflags not working for streams so don't try to use them */
+ if (!(flags & SMB_STREAM_RDDIR) &&
+ (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) {
+ /*
+ * Setting V_RDDIR_ENTFLAGS will cause the buffer to
+ * be filled with edirent_t structures (instead of
+ * dirent64_t structures).
+ */
+ rdirent_flags = V_RDDIR_ENTFLAGS;
+
+ if (*count < sizeof (edirent_t))
+ return (EINVAL);
+ } else {
+ if (*count < sizeof (dirent64_t))
+ return (EINVAL);
+ }
+
+ if (*count > MAXGETDENTS_SIZE)
+ *count = MAXGETDENTS_SIZE;
+
+ aiov.iov_base = buf;
+ aiov.iov_len = *count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_loffset = (uint64_t)offset;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_resid = *count;
+ auio.uio_fmode = 0;
+
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READDIR(vp, &auio, cr, &sink, ct, rdirent_flags);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
+
+ if (error) {
+ if (error == ENOENT) {
+ /* Fake EOF if offset is bad due to dropping of lock */
+ *count = 0;
+ return (0);
+ } else {
+ return (error);
+ }
+ }
+
+ /*
+ * Windows cannot handle an offset > SMB_EOF.
+ * Pretend we are at EOF.
+ */
+
+ if (auio.uio_loffset > SMB_EOF) {
+ *count = 0;
+ return (0);
+ }
+
+ *count = *count - auio.uio_resid;
+ return (0);
+}
+
+/*
+ * smb_vop_readdir_entry()
+ *
+ * This function retrieves the first valid entry from the
+ * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage()
+ * to smb_vop_readdir().
+ *
+ * Both dirent64_t and edirent_t structures need to be handled. The former is
+ * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter
+ * is required for proper handling of case collisions on file systems that
+ * support case-insensitivity. edirent_t structures are also used for
+ * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported.
+ */
+
+static int
+smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen,
+ ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr,
+ caller_context_t *ct, char *dirbuf, int num_bytes)
+{
+ uint32_t next_cookie;
+ int ebufsize;
+ int error = 0;
+ int len;
+ int rc;
+ char shortname[MANGLE_NAMELEN];
+ char name83[MANGLE_NAMELEN];
+ char *ebuf = NULL;
+ edirent_t *edp;
+ dirent64_t *dp = NULL;
+ vnode_t *vp = NULL;
+
+ ASSERT(dirbuf);
+
+ /*
+ * Use edirent_t structure for both
+ * entflags not working for streams so don't try to use them
+ */
+ if (!(flags & SMB_STREAM_RDDIR) &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ edp = (edirent_t *)dirbuf;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ dp = (dirent64_t *)dirbuf;
+ ebufsize = EDIRENT_RECLEN(MAXNAMELEN);
+ ebuf = kmem_zalloc(ebufsize, KM_SLEEP);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ edp = (edirent_t *)ebuf;
+ }
+
+ while (edp) {
+ if (dp)
+ DP_TO_EDP(dp, edp);
+
+ next_cookie = (uint32_t)edp->ed_off;
+ if (edp->ed_ino == 0) {
+ *cookiep = next_cookie;
+
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf, num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf, num_bytes);
+ }
+ continue;
+ }
+
+ len = strlen(edp->ed_name);
+
+ if (*namelen < len) {
+ *namelen = 0;
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (EOVERFLOW);
+ }
+
+ /*
+ * Do not pass SMB_IGNORE_CASE to smb_vop_lookup
+ */
+
+ error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp,
+ od_name, 0, NULL, cr, ct);
+
+ if (error) {
+ if (error == ENOENT) {
+ *cookiep = (uint32_t)next_cookie;
+
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf, num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf, num_bytes);
+ }
+ continue;
+ }
+
+
+ *namelen = 0;
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (error);
+ }
+
+ if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) {
+ rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
+ shortname, name83, 1);
+
+ if (rc == 1) { /* success */
+ (void) strlcpy(name, shortname, *namelen + 1);
+ *namelen = strlen(shortname);
+ } else {
+ (void) strlcpy(name, edp->ed_name,
+ *namelen + 1);
+ name[*namelen] = '\0';
+ }
+
+ } else {
+ (void) strlcpy(name, edp->ed_name, *namelen + 1);
+ *namelen = len;
+ }
+
+ if (vpp == NULL)
+ VN_RELE(vp);
+
+ if (inop)
+ *inop = edp->ed_ino;
+
+ *cookiep = (uint32_t)next_cookie;
+ break;
+ }
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (error);
+}
+
+/*
+ * smb_sa_to_va_mask
+ *
+ * Set va_mask by running through the SMB_AT_* #define's and
+ * setting those bits that correspond to the SMB_AT_* bits
+ * set in sa_mask.
+ */
+
+void
+smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp)
+{
+ int i;
+ uint_t smask;
+
+ smask = (sa_mask);
+ for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) {
+ if (smask & 1)
+ *(va_maskp) |= smb_attrmap[i];
+
+ smask >>= 1;
+ }
+}
+
+/*
+ * smb_vop_getdents()
+ *
+ * Upon success, the smb_node corresponding to each entry returned will
+ * have a reference taken on it. These will be released in
+ * smb_trans2_find_get_dents().
+ *
+ * If an error is returned from this routine, a list of already processed
+ * entries will be returned. The smb_nodes corresponding to these entries
+ * will be referenced, and will be released in smb_trans2_find_get_dents().
+ *
+ * The returned dp->d_name field will contain either the on-disk name or, if
+ * it needs mangling or has a case-insensitive collision, the mangled
+ * "shortname." In this case, the on-disk name can be retrieved from the
+ * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()).
+ */
+
+int /*ARGSUSED*/
+smb_vop_getdents(
+ smb_node_t *dir_snode,
+ uint32_t *cookiep,
+ uint64_t *verifierp,
+ int32_t *dircountp,
+ char *arg,
+ char *pattern,
+ uint32_t flags,
+ smb_request_t *sr,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int error = 0;
+ int maxentries;
+ int num_bytes;
+ int resid;
+ char *dirbuf = NULL;
+ vnode_t *dvp;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg;
+
+ dvp = dir_snode->vp;
+
+ resid = ihdr->uio.uio_resid;
+ maxentries = resid / SMB_MAX_DENT_INFO_SIZE;
+
+ bzero(ihdr->iov->iov_base, resid);
+
+ dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP);
+
+ while (maxentries) {
+
+ bzero(dirbuf, SMB_MINLEN_RDDIR_BUF);
+
+ num_bytes = SMB_MINLEN_RDDIR_BUF;
+ error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep,
+ &num_bytes, cr, ct, flags);
+
+ if (error || (num_bytes <= 0))
+ break;
+
+ error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp,
+ arg, flags, sr, cr, ct, dirbuf, &maxentries, num_bytes,
+ pattern);
+
+ if (error)
+ goto out;
+ }
+
+ if (num_bytes < 0) {
+ error = -1;
+ } else if (num_bytes == 0) {
+ *cookiep = SMB_EOF;
+ error = 0;
+ } else {
+ error = 0;
+ }
+
+out:
+ if (dirbuf)
+ kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
+
+ return (error);
+}
+
+/*
+ * smb_vop_getdents_entries()
+ *
+ * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer
+ * returned by smb_vop_readdir_readpage() to smb_vop_getdents().
+ *
+ * Both dirent64_t and edirent_t structures need to be handled. The former is
+ * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter
+ * is required for properly handling case collisions on file systems that
+ * support case-insensitivity. edirent_t is also used on case-sensitive
+ * file systems where VFSFT_DIRENTFLAGS is available.
+ */
+
+static int
+smb_vop_getdents_entries(
+ smb_node_t *dir_snode,
+ uint32_t *cookiep,
+ int32_t *dircountp,
+ char *arg,
+ uint32_t flags,
+ struct smb_request *sr,
+ cred_t *cr,
+ caller_context_t *ct,
+ char *dirbuf,
+ int *maxentries,
+ int num_bytes,
+ char *pattern)
+{
+ uint32_t next_cookie;
+ int ebufsize;
+ char *tmp_name;
+ int error;
+ int rc;
+ char shortname[MANGLE_NAMELEN];
+ char name83[MANGLE_NAMELEN];
+ char *ebuf = NULL;
+ dirent64_t *dp = NULL;
+ edirent_t *edp;
+ smb_node_t *ret_snode;
+ smb_attr_t ret_attr;
+ vnode_t *dvp;
+ vnode_t *fvp;
+
+ ASSERT(dirbuf);
+
+ dvp = dir_snode->vp;
+
+ if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ edp = (edirent_t *)dirbuf;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ dp = (dirent64_t *)dirbuf;
+ ebufsize = EDIRENT_RECLEN(MAXNAMELEN);
+ ebuf = kmem_zalloc(ebufsize, KM_SLEEP);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ edp = (edirent_t *)ebuf;
+ }
+
+ while (edp) {
+ if (dp)
+ DP_TO_EDP(dp, edp);
+
+ if (*maxentries == 0)
+ break;
+
+ next_cookie = (uint32_t)edp->ed_off;
+
+ if (edp->ed_ino == 0) {
+ *cookiep = next_cookie;
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf, num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf, num_bytes);
+ }
+ continue;
+ }
+
+ error = smb_vop_lookup(dvp, edp->ed_name, &fvp,
+ NULL, 0, NULL, cr, ct);
+
+ if (error) {
+ if (error == ENOENT) {
+ *cookiep = next_cookie;
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf,
+ num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf,
+ num_bytes);
+ }
+ continue;
+ }
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (error);
+ }
+
+ ret_snode = smb_node_lookup(sr, NULL, cr, fvp,
+ edp->ed_name, dir_snode, NULL, &ret_attr);
+
+ if (ret_snode == NULL) {
+ VN_RELE(fvp);
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (ENOMEM);
+ }
+
+ if (smb_match_name(edp->ed_ino, edp->ed_name, shortname,
+ name83, pattern, (flags & SMB_IGNORE_CASE))) {
+
+ tmp_name = edp->ed_name;
+
+ if ((flags & SMB_IGNORE_CASE) &&
+ ED_CASE_CONFLICTS(edp)) {
+ rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
+ shortname, name83, 1);
+ if (rc == 1)
+ tmp_name = shortname;
+ } else {
+ rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
+ shortname, name83, 0);
+ }
+
+ if (rc != 1) {
+ (void) strlcpy(shortname, edp->ed_name,
+ MANGLE_NAMELEN);
+ (void) strlcpy(name83, edp->ed_name,
+ MANGLE_NAMELEN);
+ shortname[MANGLE_NAMELEN - 1] = '\0';
+ name83[MANGLE_NAMELEN - 1] = '\0';
+ }
+
+ error = smb_gather_dents_info(arg, edp->ed_ino,
+ strlen(tmp_name), tmp_name, next_cookie, dircountp,
+ &ret_attr, ret_snode, shortname, name83);
+
+ if (error > 0) {
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+ return (error);
+ }
+
+ /*
+ * Treat errors from smb_gather_dents_info() that are
+ * < 0 the same as EOF.
+ */
+ if (error < 0) {
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+ *maxentries = 0;
+ return (0);
+ }
+ (*maxentries)--;
+ } else {
+ smb_node_release(ret_snode);
+ }
+
+ *cookiep = next_cookie;
+
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf, num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf, num_bytes);
+ }
+ }
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (0);
+}
+
+/*
+ * smb_vop_stream_lookup()
+ *
+ * The name returned in od_name is the on-disk name of the stream with the
+ * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN
+ * by the caller.
+ */
+
+int
+smb_vop_stream_lookup(vnode_t *fvp, char *stream_name, vnode_t **vpp,
+ char *od_name, vnode_t **xattrdirvpp, int flags, vnode_t *rootvp,
+ cred_t *cr, caller_context_t *ct)
+{
+ char *solaris_stream_name;
+ char *name;
+ int error;
+
+ if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp,
+ LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0)
+ return (error);
+
+ /*
+ * Prepend SMB_STREAM_PREFIX to stream name
+ */
+
+ solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
+ stream_name);
+
+ /*
+ * "name" will hold the on-disk name returned from smb_vop_lookup
+ * for the stream, including the SMB_STREAM_PREFIX.
+ */
+
+ name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+
+ if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp,
+ name, flags, rootvp, cr, ct)) != 0) {
+ VN_RELE(*xattrdirvpp);
+ } else {
+ (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]),
+ MAXNAMELEN);
+ }
+
+ kmem_free(solaris_stream_name, MAXNAMELEN);
+ kmem_free(name, MAXNAMELEN);
+
+ return (error);
+}
+
+int
+smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr,
+ vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ char *solaris_stream_name;
+ int error;
+
+ if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp,
+ LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0)
+ return (error);
+
+ /*
+ * Prepend SMB_STREAM_PREFIX to stream name
+ */
+
+ solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
+ stream_name);
+
+ if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr,
+ vpp, flags, cr, ct, NULL)) != 0)
+ VN_RELE(*xattrdirvpp);
+
+ kmem_free(solaris_stream_name, MAXNAMELEN);
+
+ return (error);
+}
+
+int
+smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ char *solaris_stream_name;
+ vnode_t *xattrdirvp;
+ int error;
+
+ if ((error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr,
+ ct)) != 0)
+ return (error);
+
+ /*
+ * Prepend SMB_STREAM_PREFIX to stream name
+ */
+
+ solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
+ stream_name);
+
+ /* XXX might have to use kcred */
+ error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr, ct);
+
+ kmem_free(solaris_stream_name, MAXNAMELEN);
+
+ return (error);
+}
+
+/*
+ * smb_vop_stream_readdir()
+ *
+ * Note: stream_info.size is not filled in in this routine.
+ * It needs to be filled in by the caller due to the parameters for getattr.
+ *
+ * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX
+ * removed.
+ */
+
+int
+smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep,
+ struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp,
+ int flags, cred_t *cr, caller_context_t *ct)
+{
+ int nsize = MAXNAMELEN-1;
+ int error = 0;
+ ino64_t ino;
+ char *tmp_name;
+ vnode_t *xattrdirvp;
+ vnode_t *vp;
+
+ if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR,
+ cr, ct)) != 0)
+ return (error);
+
+ bzero(stream_info->name, sizeof (stream_info->name));
+ stream_info->size = 0;
+
+ tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+
+ for (;;) {
+ error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize,
+ &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr, ct);
+
+ if (error || (*cookiep == SMB_EOF))
+ break;
+
+ if (strncmp(tmp_name, SMB_STREAM_PREFIX,
+ SMB_STREAM_PREFIX_LEN)) {
+ VN_RELE(vp);
+ continue;
+ }
+
+ tmp_name[nsize] = '\0';
+ (void) strlcpy(stream_info->name,
+ &(tmp_name[SMB_STREAM_PREFIX_LEN]),
+ sizeof (stream_info->name));
+
+ nsize -= SMB_STREAM_PREFIX_LEN;
+ break;
+ }
+
+ if ((error == 0) && nsize) {
+ if (vpp)
+ *vpp = vp;
+ else
+ VN_RELE(vp);
+
+ if (xattrdirvpp)
+ *xattrdirvpp = xattrdirvp;
+ else
+ VN_RELE(xattrdirvp);
+
+ }
+
+ kmem_free(tmp_name, MAXNAMELEN);
+
+ return (error);
+}
+
+int
+smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags,
+ cred_t *cr, caller_context_t *ct)
+{
+ int error;
+
+ error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, ct,
+ NULL, NULL);
+ return (error);
+}
+
+/*
+ * smb_vop_traverse_check()
+ *
+ * This function checks to see if the passed-in vnode has a file system
+ * mounted on it. If it does, the mount point is "traversed" and the
+ * vnode for the root of the file system is returned.
+ */
+
+int
+smb_vop_traverse_check(vnode_t **vpp)
+{
+ int error;
+
+ if (vn_mountedvfs(*vpp) == 0)
+ return (0);
+
+ /*
+ * traverse() may return a different held vnode, even in the error case.
+ * If it returns a different vnode, it will have released the original.
+ */
+
+ error = traverse(vpp);
+
+ return (error);
+}
+
+int /*ARGSUSED*/
+smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr)
+{
+ int error;
+
+ error = VFS_STATVFS(vp->v_vfsp, statp);
+
+ return (error);
+}
+
+/*
+ * smb_vop_acl_from_vsa
+ *
+ * Converts given vsecattr_t structure to a acl_t structure.
+ *
+ * The allocated memory for retuned acl_t should be freed by
+ * calling acl_free().
+ */
+static acl_t *
+smb_vop_acl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
+{
+ int aclbsize = 0; /* size of acl list in bytes */
+ int dfaclbsize = 0; /* size of default acl list in bytes */
+ int numacls;
+ acl_t *acl_info;
+
+ ASSERT(vsecattr);
+
+ acl_info = acl_alloc(acl_type);
+ if (acl_info == NULL)
+ return (NULL);
+
+ acl_info->acl_flags = 0;
+
+ switch (acl_type) {
+
+ case ACLENT_T:
+ numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
+ aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
+ dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
+
+ acl_info->acl_cnt = numacls;
+ acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
+ KM_SLEEP);
+ (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
+ aclbsize);
+ (void) memcpy((char *)acl_info->acl_aclp + aclbsize,
+ vsecattr->vsa_dfaclentp, dfaclbsize);
+
+ if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
+ acl_info->acl_flags |= ACL_IS_TRIVIAL;
+
+ break;
+
+ case ACE_T:
+ aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ acl_info->acl_cnt = vsecattr->vsa_aclcnt;
+ acl_info->acl_flags = vsecattr->vsa_aclflags;
+ acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
+ (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
+ aclbsize);
+ if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
+ acl_info->acl_flags |= ACL_IS_TRIVIAL;
+
+ break;
+
+ default:
+ acl_free(acl_info);
+ return (NULL);
+ }
+
+ if (aclbsize && vsecattr->vsa_aclentp)
+ kmem_free(vsecattr->vsa_aclentp, aclbsize);
+ if (dfaclbsize && vsecattr->vsa_dfaclentp)
+ kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
+
+ return (acl_info);
+}
+
+/*
+ * smb_vop_acl_to_vsa
+ *
+ * Converts given acl_t structure to a vsecattr_t structure.
+ *
+ * IMPORTANT:
+ * Upon successful return the memory allocated for vsa_aclentp
+ * should be freed by calling kmem_free(). The size is returned
+ * in aclbsize.
+ */
+int
+smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
+{
+ int error = 0;
+ int numacls;
+ aclent_t *aclp;
+
+ ASSERT(acl_info);
+ ASSERT(vsecattr);
+ ASSERT(aclbsize);
+
+ bzero(vsecattr, sizeof (vsecattr_t));
+ *aclbsize = 0;
+
+ switch (acl_info->acl_type) {
+ case ACLENT_T:
+ numacls = acl_info->acl_cnt;
+ /*
+ * Minimum ACL size is three entries so might as well
+ * bail out here. Also limit request size to prevent user
+ * from allocating too much kernel memory. Maximum size
+ * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
+ * for the default ACL part.
+ */
+ if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
+ error = EINVAL;
+ break;
+ }
+
+ vsecattr->vsa_mask = VSA_ACL;
+
+ vsecattr->vsa_aclcnt = numacls;
+ *aclbsize = numacls * sizeof (aclent_t);
+ vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
+ (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
+ *aclbsize);
+
+ /* Sort the acl list */
+ ksort((caddr_t)vsecattr->vsa_aclentp,
+ vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
+
+ /* Break into acl and default acl lists */
+ for (numacls = 0, aclp = vsecattr->vsa_aclentp;
+ numacls < vsecattr->vsa_aclcnt;
+ aclp++, numacls++) {
+ if (aclp->a_type & ACL_DEFAULT)
+ break;
+ }
+
+ /* Find where defaults start (if any) */
+ if (numacls < vsecattr->vsa_aclcnt) {
+ vsecattr->vsa_mask |= VSA_DFACL;
+ vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
+ vsecattr->vsa_dfaclentp = aclp;
+ vsecattr->vsa_aclcnt = numacls;
+ }
+
+ /* Adjust if they're all defaults */
+ if (vsecattr->vsa_aclcnt == 0) {
+ vsecattr->vsa_mask &= ~VSA_ACL;
+ vsecattr->vsa_aclentp = NULL;
+ }
+
+ /* Only directories can have defaults */
+ if (vsecattr->vsa_dfaclcnt &&
+ (acl_info->acl_flags & ACL_IS_DIR)) {
+ error = ENOTDIR;
+ }
+
+ break;
+
+ case ACE_T:
+ if (acl_info->acl_cnt < 1 ||
+ acl_info->acl_cnt > MAX_ACL_ENTRIES) {
+ error = EINVAL;
+ break;
+ }
+
+ vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+ vsecattr->vsa_aclcnt = acl_info->acl_cnt;
+ vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
+ *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ vsecattr->vsa_aclentsz = *aclbsize;
+ vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
+ (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
+ *aclbsize);
+
+ break;
+
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+/*
+ * smb_vop_acl_read
+ *
+ * Reads the ACL of the specified file into 'aclp'.
+ * acl_type is the type of ACL which the filesystem supports.
+ *
+ * Caller has to free the allocated memory for aclp by calling
+ * acl_free().
+ */
+int
+smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type,
+ cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ vsecattr_t vsecattr;
+
+ ASSERT(vp);
+ ASSERT(aclp);
+
+ *aclp = NULL;
+ bzero(&vsecattr, sizeof (vsecattr_t));
+
+ switch (acl_type) {
+ case ACLENT_T:
+ vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
+ VSA_DFACLCNT;
+ break;
+
+ case ACE_T:
+ vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, ct))
+ return (error);
+
+ *aclp = smb_vop_acl_from_vsa(&vsecattr, acl_type);
+ if (vp->v_type == VDIR)
+ (*aclp)->acl_flags |= ACL_IS_DIR;
+
+ return (0);
+}
+
+/*
+ * smb_vop_acl_write
+ *
+ * Writes the given ACL in aclp for the specified file.
+ */
+int
+smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+ vsecattr_t vsecattr;
+ int aclbsize;
+
+ ASSERT(vp);
+ ASSERT(aclp);
+
+ error = smb_vop_acl_to_vsa(aclp, &vsecattr, &aclbsize);
+
+ if (error == 0) {
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ }
+
+ if (aclbsize && vsecattr.vsa_aclentp)
+ kmem_free(vsecattr.vsa_aclentp, aclbsize);
+
+ return (error);
+}
+
+/*
+ * smb_vop_acl_type
+ *
+ * Determines the ACL type for the given vnode.
+ * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL.
+ */
+acl_type_t
+smb_vop_acl_type(vnode_t *vp)
+{
+ int error;
+ ulong_t whichacl;
+
+ error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL);
+ if (error != 0) {
+ /*
+ * If we got an error, then the filesystem
+ * likely does not understand the _PC_ACL_ENABLED
+ * pathconf. In this case, we fall back to trying
+ * POSIX-draft (aka UFS-style) ACLs.
+ */
+ whichacl = _ACL_ACLENT_ENABLED;
+ }
+
+ if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) {
+ /*
+ * If the file system supports neither ACE nor
+ * ACLENT ACLs we will fall back to UFS-style ACLs
+ * like we did above if there was an error upon
+ * calling VOP_PATHCONF.
+ *
+ * ACE and ACLENT type ACLs are the only interfaces
+ * supported thus far. If any other bits are set on
+ * 'whichacl' upon return from VOP_PATHCONF, we will
+ * ignore them.
+ */
+ whichacl = _ACL_ACLENT_ENABLED;
+ }
+
+ if (whichacl == _ACL_ACLENT_ENABLED)
+ return (ACLENT_T);
+
+ return (ACE_T);
+}
+
+static int zfs_perms[] = {
+ ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS,
+ ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD,
+ ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL,
+ ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE
+};
+
+static int unix_perms[] = { VREAD, VWRITE, VEXEC };
+/*
+ * smb_vop_eaccess
+ *
+ * Returns the effective permission of the given credential for the
+ * specified object.
+ *
+ * This is just a workaround. We need VFS/FS support for this.
+ */
+void
+smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr)
+{
+ int error, i;
+ int pnum;
+
+ *mode = 0;
+
+ if (flags == V_ACE_MASK) {
+ pnum = sizeof (zfs_perms) / sizeof (int);
+
+ for (i = 0; i < pnum; i++) {
+ error = smb_vop_access(vp, zfs_perms[i], flags,
+ dir_vp, cr);
+ if (error == 0)
+ *mode |= zfs_perms[i];
+ }
+ } else {
+ pnum = sizeof (unix_perms) / sizeof (int);
+
+ for (i = 0; i < pnum; i++) {
+ error = smb_vop_access(vp, unix_perms[i], flags,
+ dir_vp, cr);
+ if (error == 0)
+ *mode |= unix_perms[i];
+ }
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_winpipe.c b/usr/src/uts/common/fs/smbsrv/smb_winpipe.c
new file mode 100755
index 0000000000..361485783c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_winpipe.c
@@ -0,0 +1,431 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contain routines to initialize the doors interfaces for
+ * CIFS winpipe calls.
+ */
+
+#define START_UPDOOR_SIZE 16384
+#define START_INPIPE_SIZE 16384
+
+#include <smbsrv/smb_incl.h>
+
+#include <sys/stat.h>
+#include <sys/door.h>
+#include <sys/door_data.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/ndr.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <sys/uio.h>
+
+
+static door_handle_t *smb_winpipe_dh = NULL;
+static uint64_t smb_winpipe_ncall = 0;
+static kmutex_t smb_winpipe_mutex;
+static kcondvar_t smb_winpipe_cv;
+
+static int smb_winpipe_upcall(mlsvc_pipe_t *, smb_dr_user_ctx_t *,
+ mlsvc_stream_t *, uint16_t, uint32_t, unsigned char *, smb_pipe_t *);
+
+static smb_dr_user_ctx_t *smb_winpipe_ctx_alloc(struct smb_request *);
+static void smb_winpipe_ctx_free(smb_dr_user_ctx_t *);
+static uint8_t *smb_winpipe_ctx_mkselfrel(smb_dr_user_ctx_t *, uint32_t *);
+
+
+void
+smb_winpipe_init(void)
+{
+ mutex_init(&smb_winpipe_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&smb_winpipe_cv, NULL, CV_DEFAULT, NULL);
+}
+
+void
+smb_winpipe_fini(void)
+{
+ smb_winpipe_close();
+ cv_destroy(&smb_winpipe_cv);
+ mutex_destroy(&smb_winpipe_mutex);
+}
+
+int
+smb_winpipe_open(void)
+{
+ door_handle_t *dh;
+ int rc;
+
+ mutex_enter(&smb_winpipe_mutex);
+
+ if (smb_winpipe_dh == NULL) {
+ dh = kmem_zalloc(sizeof (door_handle_t), KM_SLEEP);
+
+ rc = door_ki_open(SMB_WINPIPE_DOOR_UP_PATH, dh);
+ if (rc) {
+ kmem_free(dh, sizeof (door_handle_t));
+ mutex_exit(&smb_winpipe_mutex);
+ cmn_err(CE_WARN, "smb_winpipe_open: rc=%d", rc);
+ return (-1);
+ }
+
+ smb_winpipe_ncall = 0;
+ smb_winpipe_dh = dh;
+ }
+
+ mutex_exit(&smb_winpipe_mutex);
+ return (0);
+}
+
+void
+smb_winpipe_close(void)
+{
+ mutex_enter(&smb_winpipe_mutex);
+
+ while (smb_winpipe_ncall > 0)
+ cv_wait(&smb_winpipe_cv, &smb_winpipe_mutex);
+
+ if (smb_winpipe_dh) {
+ kmem_free(smb_winpipe_dh, sizeof (door_handle_t));
+ smb_winpipe_dh = NULL;
+ }
+
+ mutex_exit(&smb_winpipe_mutex);
+}
+
+/*
+ * Winpipe call interface: called by smb_rpc_transact and smb_rpc_read.
+ * Serialization and call reference accounting handled here.
+ *
+ * The sr will be null on a flush operation, which will result in ctx
+ * being null. A null ctx must be handled by smb_winpipe_upcall.
+ */
+int
+smb_winpipe_call(struct smb_request *sr,
+ mlsvc_pipe_t *pi,
+ mlsvc_stream_t *streamin,
+ uint16_t call_type,
+ uint32_t *nbytes)
+{
+ smb_dr_user_ctx_t *ctx;
+ unsigned char *lbuf;
+ smb_pipe_t *pp;
+ int rc;
+
+ mutex_enter(&smb_winpipe_mutex);
+
+ if (smb_winpipe_dh == NULL) {
+ mutex_exit(&smb_winpipe_mutex);
+ return (-1);
+ }
+
+ ++smb_winpipe_ncall;
+ mutex_exit(&smb_winpipe_mutex);
+
+ lbuf = kmem_zalloc(START_UPDOOR_SIZE, KM_SLEEP);
+ pp = kmem_zalloc(START_INPIPE_SIZE, KM_SLEEP);
+ ctx = smb_winpipe_ctx_alloc(sr);
+
+ rc = smb_winpipe_upcall(pi, ctx, streamin, call_type, *nbytes,
+ lbuf, pp);
+
+ if (rc == 0) {
+ switch (call_type) {
+ case SMB_RPC_TRANSACT:
+ case SMB_RPC_READ:
+ case SMB_RPC_FLUSH:
+ *nbytes = pp->sp_datalen;
+ break;
+
+ default:
+ /*
+ * A write just queues the data and returns.
+ */
+ break;
+ }
+ }
+
+ smb_winpipe_ctx_free(ctx);
+ kmem_free(pp, START_INPIPE_SIZE);
+ kmem_free(lbuf, START_UPDOOR_SIZE);
+
+ mutex_enter(&smb_winpipe_mutex);
+ --smb_winpipe_ncall;
+ cv_signal(&smb_winpipe_cv);
+ mutex_exit(&smb_winpipe_mutex);
+ return (rc);
+}
+
+/*
+ * Door upcall wrapper - handles data marshalling.
+ * This function should only be called by smb_winpipe_call.
+ */
+static int
+smb_winpipe_upcall(mlsvc_pipe_t *pipe_info,
+ smb_dr_user_ctx_t *user_ctx,
+ mlsvc_stream_t *streamin,
+ uint16_t call_type,
+ uint32_t req_cnt,
+ unsigned char *lbuf,
+ smb_pipe_t *pp)
+{
+ door_arg_t da;
+ int user_ctx_bytes;
+ mlsvc_door_hdr_t mdhin, mdhout;
+ smb_pipe_t newpipe;
+ int total_bytes = 0;
+ int cnt;
+ int bytes_off = 0;
+ ulong_t save_resid;
+ uint32_t tmp_resid;
+ uint8_t *user_ctx_selfrel;
+
+ /*
+ * copy the pipe hdr into flat buf, this contains the thread id,
+ * version and a couple of reserved fields for future expansion
+ */
+ mdhin.md_tid = (uint64_t)curthread->t_did;
+ mdhin.md_version = SMB_MLSVC_DOOR_VERSION;
+ /*
+ * rpc_transact, rpc_read or rpc_write
+ */
+ mdhin.md_call_type = call_type;
+ mdhin.md_length = req_cnt;
+ mdhin.md_reserved = 0;
+ bcopy(&mdhin.md_tid, lbuf, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ bcopy(&mdhin.md_version, lbuf + bytes_off, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(&mdhin.md_call_type, lbuf + bytes_off, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(&mdhin.md_length, lbuf + bytes_off, sizeof (uint32_t));
+ bytes_off += sizeof (uint32_t);
+ bcopy(&mdhin.md_reserved, lbuf + bytes_off, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ total_bytes = bytes_off;
+
+ /*
+ * Most of the marshalling isn't needed for flush.
+ * The pipe-id is needed to find the rpc_context and
+ * free the input and output pipes.
+ */
+ if (call_type == SMB_RPC_FLUSH) {
+ bcopy(&pipe_info->fid, lbuf + total_bytes, sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+ } else {
+ user_ctx_selfrel = smb_winpipe_ctx_mkselfrel(user_ctx,
+ (uint32_t *)&cnt);
+
+ if (user_ctx_selfrel == NULL) {
+ return (-1);
+ }
+
+ bcopy(user_ctx_selfrel, lbuf + total_bytes, cnt);
+ kmem_free(user_ctx_selfrel, cnt);
+ total_bytes += cnt;
+ /*
+ * based on uio stuff and smb_pipe_t size
+ * calculate size of buffer needed
+ */
+ newpipe.sp_pipeid = pipe_info->fid;
+ (void) strlcpy(newpipe.sp_pipename, pipe_info->pipe_name,
+ SMB_MAX_PIPENAMELEN);
+ bcopy(newpipe.sp_pipename, lbuf + total_bytes,
+ SMB_MAX_PIPENAMELEN);
+ bcopy(&newpipe.sp_pipeid, lbuf + total_bytes +
+ SMB_MAX_PIPENAMELEN, sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t) + SMB_MAX_PIPENAMELEN;
+ }
+
+ /* copy the pipe data len into flat buf */
+ if ((mdhin.md_call_type == SMB_RPC_TRANSACT) ||
+ (mdhin.md_call_type == SMB_RPC_WRITE)) {
+ /* we only want the least 4 significant bytes here */
+ tmp_resid = (uint32_t)streamin->uio.uio_resid;
+ bcopy(&tmp_resid, lbuf + total_bytes, sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+ save_resid = streamin->uio.uio_resid;
+ (void) uiomove((caddr_t)(lbuf + total_bytes),
+ streamin->uio.uio_resid, UIO_WRITE, &streamin->uio);
+ total_bytes += (save_resid - streamin->uio.uio_resid);
+ } else if (mdhin.md_call_type == SMB_RPC_READ) {
+ bzero(lbuf + total_bytes, sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+ }
+
+ da.data_ptr = (char *)lbuf;
+ da.data_size = total_bytes;
+ da.desc_ptr = NULL;
+ da.desc_num = 0;
+ da.rbuf = (char *)lbuf;
+ da.rsize = START_UPDOOR_SIZE;
+
+ if (door_ki_upcall(*smb_winpipe_dh, &da) != 0) {
+ return (-1);
+ }
+ /* RPC_WRITE just queues the data and returns */
+ if (mdhin.md_call_type == SMB_RPC_WRITE) {
+ return (0);
+ }
+ bytes_off = 0;
+ bcopy(da.data_ptr, &mdhout.md_tid, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ bcopy(da.data_ptr+bytes_off, &mdhout.md_version, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(da.data_ptr+bytes_off, &mdhout.md_call_type, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(da.data_ptr+bytes_off, &mdhout.md_length, sizeof (uint32_t));
+ bytes_off += sizeof (uint32_t);
+ bcopy(da.data_ptr+bytes_off, &mdhout.md_reserved, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ user_ctx_bytes = 0;
+ total_bytes = user_ctx_bytes + bytes_off;
+
+ bzero(pp, START_INPIPE_SIZE);
+ bcopy(da.data_ptr+total_bytes, pp->sp_pipename, SMB_MAX_PIPENAMELEN);
+ total_bytes += SMB_MAX_PIPENAMELEN;
+ bcopy(da.data_ptr+total_bytes, &(pp->sp_pipeid), sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+ bcopy(da.data_ptr + total_bytes, &(pp->sp_datalen), sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+
+ if (pp->sp_datalen > 0) {
+ pipe_info->outlen = pp->sp_datalen;
+ pipe_info->output = kmem_alloc(pipe_info->outlen, KM_SLEEP);
+ bcopy((char *)(da.data_ptr + total_bytes),
+ pipe_info->output, pipe_info->outlen);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Allocate a user context structure and initialize it based on the
+ * specified SMB request data. Resources allocated here must be
+ * released using smb_winpipe_ctx_free.
+ *
+ * If sr is null, a null pointer is returned.
+ */
+static smb_dr_user_ctx_t *
+smb_winpipe_ctx_alloc(struct smb_request *sr)
+{
+ smb_session_t *session;
+ smb_user_t *user;
+ smb_dr_user_ctx_t *ctx;
+
+ if (sr == NULL)
+ return (NULL);
+
+ user = sr->uid_user;
+ session = user->u_session;
+
+ ASSERT(user);
+ ASSERT(user->u_domain);
+ ASSERT(user->u_name);
+ ASSERT(session);
+ ASSERT(session->workstation);
+
+ ctx = kmem_zalloc(sizeof (smb_dr_user_ctx_t), KM_SLEEP);
+
+ ctx->du_session_id = session->s_kid;
+ ctx->du_native_os = session->native_os;
+ ctx->du_ipaddr = session->ipaddr;
+ ctx->du_uid = user->u_uid;
+ ctx->du_logon_time = user->u_logon_time;
+ ctx->du_flags = user->u_flags;
+
+ ctx->du_domain_len = user->u_domain_len;
+ ctx->du_domain = kmem_alloc(ctx->du_domain_len, KM_SLEEP);
+ (void) strlcpy(ctx->du_domain, user->u_domain, ctx->du_domain_len);
+
+ ctx->du_account_len = user->u_name_len;
+ ctx->du_account = kmem_alloc(ctx->du_account_len, KM_SLEEP);
+ (void) strlcpy(ctx->du_account, user->u_name, ctx->du_account_len);
+
+ ctx->du_workstation_len = strlen(session->workstation) + 1;
+ ctx->du_workstation = kmem_alloc(ctx->du_workstation_len,
+ KM_SLEEP);
+ (void) strlcpy(ctx->du_workstation, session->workstation,
+ ctx->du_workstation_len);
+
+ return (ctx);
+}
+
+
+/*
+ * Free resources associated with a user context structure.
+ */
+static void
+smb_winpipe_ctx_free(smb_dr_user_ctx_t *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ ASSERT(ctx->du_domain);
+ ASSERT(ctx->du_account);
+ ASSERT(ctx->du_workstation);
+
+ kmem_free(ctx->du_domain, ctx->du_domain_len);
+ kmem_free(ctx->du_account, ctx->du_account_len);
+ kmem_free(ctx->du_workstation, ctx->du_workstation_len);
+ kmem_free(ctx, sizeof (smb_dr_user_ctx_t));
+}
+
+/*
+ * Convert a user context structure from absolute to self-relative format.
+ *
+ * On success, a pointer to an allocated XDR encoded buffer is returned,
+ * with the buffer size in ret_len. The caller is responsible for freeing
+ * this buffer when it is no longer required. If the return value is NULL,
+ * it is not valid to interpret ret_len.
+ */
+static uint8_t *
+smb_winpipe_ctx_mkselfrel(smb_dr_user_ctx_t *ctx, uint32_t *ret_len)
+{
+ XDR xdrs;
+ uint8_t *buf;
+ uint32_t len;
+
+ if (ctx == NULL || ret_len == NULL) {
+ return (NULL);
+ }
+
+ len = xdr_sizeof(xdr_smb_dr_user_ctx_t, ctx);
+ buf = kmem_zalloc(len, KM_SLEEP);
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_ENCODE);
+
+ if (!xdr_smb_dr_user_ctx_t(&xdrs, ctx)) {
+ kmem_free(buf, len);
+ len = 0;
+ buf = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ *ret_len = len;
+ return (buf);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write.c b/usr/src/uts/common/fs/smbsrv/smb_write.c
new file mode 100644
index 0000000000..e6874397b4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_write.c
@@ -0,0 +1,565 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sdt.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/netbios.h>
+
+
+#define SMB_WRMODE_WRITE_THRU 0x0001
+#define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU)
+
+
+typedef struct smb_write_param {
+ struct vardata_block w_vdb;
+ uint64_t w_offset;
+ uint16_t w_mode;
+ uint16_t w_count;
+} smb_write_param_t;
+
+
+int smb_write_common(struct smb_request *sr, smb_write_param_t *param);
+int smb_write_truncate(struct smb_request *sr, smb_write_param_t *param);
+int smb_set_file_size(struct smb_request *sr);
+
+
+/*
+ * Write count bytes at the specified offset in a file. The offset is
+ * limited to 32-bits. If the count is zero, the file is truncated to
+ * the length specified by the offset.
+ *
+ * The response count indicates the actual number of bytes written, which
+ * will equal the requested count on success. If request and response
+ * counts differ but there is no error, the client will assume that the
+ * server encountered a resource issue.
+ */
+int
+smb_com_write(struct smb_request *sr)
+{
+ smb_write_param_t *param;
+ uint32_t off;
+ int rc;
+
+ param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
+
+ rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &param->w_count, &off);
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ param->w_offset = (uint64_t)off;
+ param->w_vdb.uio.uio_offset = param->w_offset;
+
+ if (param->w_count == 0) {
+ rc = smb_write_truncate(sr, param);
+ } else {
+ rc = smbsr_decode_data(sr, "D", &param->w_vdb);
+
+ if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param->w_vdb.uio.uio_offset = param->w_offset;
+
+ rc = smb_write_common(sr, param);
+ }
+
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
+ kmem_free(param, sizeof (smb_write_param_t));
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Write count bytes to a file and then close the file. This function
+ * can only be used to write to 32-bit offsets and the client must set
+ * WordCount (6 or 12) correctly in order to locate the data to be
+ * written. If an error occurs on the write, the file should still be
+ * closed. If Count is 0, the file is truncated (or extended) to offset.
+ *
+ * If the last_write time is non-zero, last_write should be used to set
+ * the mtime. Otherwise the file system stamps the mtime. Failure to
+ * set mtime should not result in an error response.
+ */
+int
+smb_com_write_and_close(struct smb_request *sr)
+{
+ smb_write_param_t *param;
+ uint32_t last_write;
+ uint32_t off;
+ int rc = 0;
+
+ param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
+
+ if (sr->smb_wct == 12) {
+ rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
+ &param->w_count, &off, &last_write);
+ } else {
+ rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
+ &param->w_count, &off, &last_write);
+ }
+
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ param->w_offset = (uint64_t)off;
+
+ if (param->w_count == 0) {
+ rc = smb_write_truncate(sr, param);
+ } else {
+ /*
+ * There may be a bug here: should this be "3.#B"?
+ */
+ rc = smbsr_decode_data(sr, ".#B", param->w_count,
+ &param->w_vdb);
+
+ if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param->w_vdb.uio.uio_offset = param->w_offset;
+
+ rc = smb_write_common(sr, param);
+ }
+
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_common_close(sr, last_write)) != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
+ kmem_free(param, sizeof (smb_write_param_t));
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Write count bytes to a file at the specified offset and then unlock
+ * them. Write behind is safe because the client should have the range
+ * locked and this request is allowed to extend the file - note that
+ * offest is limited to 32-bits. It is an error for count to be zero.
+ *
+ * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk
+ * files. Reject any attempt to use it on other shares.
+ *
+ * The response count indicates the actual number of bytes written, which
+ * will equal the requested count on success. If request and response
+ * counts differ but there is no error, the client will assume that the
+ * server encountered a resource issue.
+ */
+int
+smb_com_write_and_unlock(struct smb_request *sr)
+{
+ smb_write_param_t *param;
+ uint32_t off;
+ uint32_t result;
+ uint16_t remcnt;
+ int rc = 0;
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
+
+ rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &param->w_count, &off,
+ &remcnt);
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (param->w_count == 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_data(sr, "D", &param->w_vdb);
+
+ if ((rc != 0) || (param->w_count != param->w_vdb.len)) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param->w_offset = (uint64_t)off;
+ param->w_vdb.uio.uio_offset = (off_t)param->w_offset;
+
+ if ((rc = smb_write_common(sr, param)) != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ result = smb_unlock_range(sr, sr->fid_ofile->f_node, param->w_offset,
+ (uint64_t)param->w_count);
+ if (result != NT_STATUS_SUCCESS) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smb_unlock_range_raise_error(sr, result);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
+ kmem_free(param, sizeof (smb_write_param_t));
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Write bytes to a file (SMB Core). This request was extended in
+ * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
+ * 14, instead of 12, and including additional offset information.
+ *
+ * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
+ * to truncate a file. A zero length merely transfers zero bytes.
+ *
+ * If bit 0 of WriteMode is set, Fid must refer to a disk file and
+ * the data must be on stable storage before responding.
+ */
+int
+smb_com_write_andx(struct smb_request *sr)
+{
+ smb_write_param_t *param;
+ uint32_t off_low;
+ uint32_t off_high;
+ uint16_t data_offset;
+ uint16_t remcnt;
+ int rc = 0;
+
+ param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
+
+ if (sr->smb_wct == 14) {
+ rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid,
+ &off_low, &param->w_mode, &remcnt, &param->w_count,
+ &data_offset, &off_high);
+
+ data_offset -= 63;
+ param->w_offset = ((uint64_t)off_high << 32) | off_low;
+ } else {
+ rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid,
+ &off_low, &param->w_mode, &remcnt, &param->w_count,
+ &data_offset);
+
+ param->w_offset = (uint64_t)off_low;
+ data_offset -= 59;
+ }
+
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (SMB_WRMODE_IS_STABLE(param->w_mode) &&
+ STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_error(sr, ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_data(sr, "#.#B", data_offset, param->w_count,
+ &param->w_vdb);
+ if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param->w_vdb.uio.uio_offset = param->w_offset;
+
+ if (param->w_count != 0) {
+ if ((rc = smb_write_common(sr, param)) != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ }
+
+ smbsr_encode_result(sr, 6, 0, "bb1.ww6.w",
+ 6, sr->andx_com, 15, param->w_count, 0);
+
+ kmem_free(param, sizeof (smb_write_param_t));
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Common function for writing files or IPC/MSRPC named pipes.
+ *
+ * Returns errno values.
+ */
+int
+smb_write_common(struct smb_request *sr, smb_write_param_t *param)
+{
+ struct smb_ofile *ofile = sr->fid_ofile;
+ smb_node_t *node;
+ uint32_t stability = FSSTAB_UNSTABLE;
+ uint32_t lcount;
+ int rc = 0;
+
+ switch (sr->tid_tree->t_res_type & STYPE_MASK) {
+ case STYPE_DISKTREE:
+ node = ofile->f_node;
+
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ rc = smb_lock_range_access(sr, node, param->w_offset,
+ param->w_count, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ smbsr_raise_cifs_error(sr, rc,
+ ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ if (SMB_WRMODE_IS_STABLE(param->w_mode) ||
+ (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
+ stability = FSSTAB_FILE_SYNC;
+ }
+
+ rc = smb_fsop_write(sr, sr->user_cr, node,
+ &param->w_vdb.uio, &lcount, &node->attr, &stability);
+
+ if (rc)
+ return (rc);
+
+ node->flags |= NODE_FLAGS_SYNCATIME;
+
+ if (node->flags & NODE_FLAGS_SET_SIZE) {
+ if ((param->w_offset + lcount) >= node->n_size) {
+ node->flags &= ~NODE_FLAGS_SET_SIZE;
+ node->n_size = param->w_offset + lcount;
+ }
+ }
+
+ param->w_count = (uint16_t)lcount;
+ break;
+
+ case STYPE_IPC:
+ param->w_count = (uint16_t)param->w_vdb.uio.uio_resid;
+
+ if ((rc = smb_rpc_write(sr, &param->w_vdb.uio)) != 0)
+ param->w_count = 0;
+ break;
+
+ default:
+ rc = EACCES;
+ break;
+ }
+
+ if (rc != 0)
+ return (rc);
+
+ mutex_enter(&ofile->f_mutex);
+ ofile->f_seek_pos = param->w_offset + param->w_count;
+ mutex_exit(&ofile->f_mutex);
+ return (rc);
+}
+
+/*
+ * Truncate a disk file to the specified offset.
+ * Typically, w_count will be zero here.
+ *
+ * Returns errno values.
+ */
+int
+smb_write_truncate(struct smb_request *sr, smb_write_param_t *param)
+{
+ struct smb_ofile *ofile = sr->fid_ofile;
+ smb_node_t *node = ofile->f_node;
+ int rc;
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0)
+ return (0);
+
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ rc = smb_lock_range_access(sr, node, param->w_offset,
+ param->w_count, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ smbsr_raise_cifs_error(sr, rc,
+ ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ /*
+ * XXX what if the file has been opened only with
+ * FILE_APPEND_DATA?
+ */
+ rc = smb_ofile_access(ofile, sr->user_cr, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ node->flags |= NODE_FLAGS_SET_SIZE;
+ node->n_size = param->w_offset;
+
+ if ((rc = smb_set_file_size(sr)) != 0)
+ return (rc);
+
+ mutex_enter(&ofile->f_mutex);
+ ofile->f_seek_pos = param->w_offset + param->w_count;
+ mutex_exit(&ofile->f_mutex);
+ return (0);
+}
+
+/*
+ * Set the file size using the value in the node. The file will only be
+ * updated if NODE_FLAGS_SET_SIZE is set. It is safe to pass a null node
+ * pointer, we just return success.
+ *
+ * The node attributes are refreshed here from the file system. So any
+ * attributes that are affected by file size changes, i.e. the mtime,
+ * will be current.
+ *
+ * Note that smb_write_andx cannot be used to reduce the file size so,
+ * if this is required, smb_write is called with a count of zero and
+ * the appropriate file length in offset. The file should be resized
+ * to the length specified by the offset.
+ *
+ * Returns 0 on success. Otherwise returns EACCES.
+ */
+int
+smb_set_file_size(struct smb_request *sr)
+{
+ struct smb_node *node;
+ smb_attr_t new_attr;
+ uint32_t dosattr;
+
+ if ((node = sr->fid_ofile->f_node) == 0)
+ return (0);
+
+ if ((node->flags & NODE_FLAGS_SET_SIZE) == 0)
+ return (0);
+
+ node->flags &= ~NODE_FLAGS_SET_SIZE;
+
+ dosattr = smb_node_get_dosattr(node);
+
+ if (dosattr & SMB_FA_READONLY) {
+ if (((node->flags & NODE_FLAGS_CREATED) == 0) ||
+ (sr->session->s_kid != node->n_orig_session_id))
+ return (EACCES);
+ }
+
+ bzero(&new_attr, sizeof (new_attr));
+ new_attr.sa_vattr.va_size = node->n_size;
+ new_attr.sa_mask = SMB_AT_SIZE;
+
+ (void) smb_fsop_setattr(sr, sr->user_cr, node, &new_attr,
+ &node->attr);
+
+ return (0);
+}
+
+/*
+ * write_complete is sent acknowledge completion of raw write requests.
+ * We never send raw write commands to other servers so, if we receive a
+ * write_complete, we treat it as an error.
+ */
+int
+smb_com_write_complete(struct smb_request *sr)
+{
+ smbsr_decode_error(sr);
+ /* NOT REACHED */
+ return (0);
+}
+
+/*
+ * The Write Block Multiplexed protocol is used to maximize performance
+ * when writing a large block of data.
+ *
+ * The mpx sub protocol is not supported because we support only
+ * connection oriented transports and NT supports SMB_COM_READ_MPX
+ * only over connectionless transports.
+ */
+int /*ARGSUSED*/
+smb_com_write_mpx(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+int /*ARGSUSED*/
+smb_com_write_mpx_secondary(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
new file mode 100644
index 0000000000..5d02179cc2
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
@@ -0,0 +1,606 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: write_raw
+ * 5.27 WRITE_RAW: Write Raw Bytes
+ *
+ * The Write Block Raw protocol is used to maximize the performance of
+ * writing a large block of data from the client to the server. The Write
+ * Block Raw command's scope includes files, Named Pipes, and spooled
+ * output (can be used in place COM_WRITE_PRINT_FILE ).
+ *
+ * Client Request Description
+ * ========================== =========================================
+ *
+ * UCHAR WordCount; Count of parameter words = 12
+ * USHORT Fid; File handle
+ * USHORT Count; Total bytes, including this buffer
+ * USHORT Reserved;
+ * ULONG Offset; Offset in file to begin write
+ * ULONG Timeout;
+ * USHORT WriteMode; Write mode:
+ * bit 0 - complete write to disk and send
+ * final result response
+ * bit 1 - return Remaining (pipe/dev)
+ * (see WriteAndX for #defines)
+ * ULONG Reserved2;
+ * USHORT DataLength; Number of data bytes this buffer
+ * USHORT DataOffset; Offset (from header start) to data
+ * USHORT ByteCount; Count of data bytes
+ * UCHAR Pad[]; Pad to SHORT or LONG
+ * UCHAR Data[]; Data (# = DataLength)
+ *
+ * First Server Response Description
+ * ============================== =====================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Remaining; Bytes remaining to be read if pipe
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Final Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR Command (in SMB header) SMB_COM_WRITE_COMPLETE
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Count; Total number of bytes written
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The first response format will be that of the final server response in
+ * the case where the server gets an error while writing the data sent
+ * along with the request. Thus Count is the number of bytes which did get
+ * written any time an error is returned. If an error occurs after the
+ * first response has been sent allowing the client to send the remaining
+ * data, the final response should not be sent unless write through is set.
+ * Rather the server should return this "write behind" error on the next
+ * access to the Fid.
+ *
+ * The client must guarantee that there is (and will be) no other request
+ * on the connection for the duration of this request. The server will
+ * reserve enough resources to receive the data and respond with a response
+ * SMB as defined above. The client then sends the raw data in one send.
+ * Thus the server is able to receive up to 65,535 bytes of data directly
+ * into the server buffer. The amount of data transferred is expected to
+ * be larger than the negotiated buffer size for this protocol.
+ *
+ * The reason that no other requests can be active on the connection for
+ * the duration of the request is that if other receives are present on the
+ * connection, there is normally no way to guarantee that the data will be
+ * received into the correct server buffer, rather the data may fill one
+ * (or more) of the other buffers. Also if the client is sending other
+ * requests on the connection, a request may land in the buffer that the
+ * server has allocated for the this SMB's data.
+ *
+ * Whether or not SMB_COM_WRITE_RAW is supported is returned in the
+ * response to SMB_COM_NEGOTIATE. SMB_COM_WRITE_RAW is not supported for
+ * connectionless clients.
+ *
+ * When write through is not specified ((WriteMode & 01) == 0) this SMB is
+ * assumed to be a form of write behind. The transport layer guarantees
+ * delivery of all secondary requests from the client. Thus no "got the
+ * data you sent" SMB is needed. If an error should occur at the server
+ * end, all bytes must be received and thrown away. If an error occurs
+ * while writing data to disk such as disk full, the next access of the
+ * file handle (another write, close, read, etc.) will return the fact that
+ * the error occurred.
+ *
+ * If write through is specified ((WriteMode & 01) != 0), the server will
+ * receive the data, write it to disk and then send a final response
+ * indicating the result of the write. The total number of bytes written
+ * is also returned in this response in the Count field.
+ *
+ * The flow for the SMB_COM_WRITE_RAW SMB is:
+ *
+ * client -----> SMB_COM_WRITE_RAW request (optional data) >-------> server
+ * client <------------------< OK send (more) data <---------------- server
+ * client ----------------------> raw data >----------------------> server
+ * client <---< data on disk or error (write through only) <------- server
+ *
+ * This protocol is set up such that the SMB_COM_WRITE_RAW request may also
+ * carry data. This is an optimization in that up to the server's buffer
+ * size (MaxCount from SMB_COM_NEGOTIATE response), minus the size of the
+ * SMB_COM_WRITE_RAW SMB request, may be sent along with the request. Thus
+ * if the server is busy and unable to support the raw write of the
+ * remaining data, the data sent along with the request has been delivered
+ * and need not be sent again. The server will write any data sent in the
+ * request (and wait for it to be on the disk or device if write through is
+ * set), prior to sending the response.
+ *
+ * The specific responses error class ERRSRV, error codes ERRusempx and
+ * ERRusestd, indicate that the server is temporarily out of the resources
+ *
+ * needed to support the raw write of the remaining data, but that any data
+ * sent along with the request has been successfully written. The client
+ * should then write the remaining data using a different type of SMB write
+ * request, or delay and retry using SMB_COM_WRITE_RAW. If a write error
+ * occurs writing the initial data, it will be returned and the write raw
+ * request is implicitly denied.
+ *
+ * The return field Remaining is returned for named pipes only. It is used
+ * to return the number of bytes currently available in the pipe. This
+ * information can then be used by the client to know when a subsequent
+ * (non blocking) read of the pipe may return some data. Of course when
+ * the read request is actually received by the server there may be more or
+ * less actual data in the pipe (more data has been written to the pipe /
+ * device or another reader drained it). If the information is currently
+ * not available or the request is NOT for a pipe or the server does not
+ * support this feature, a -1 value should be returned.
+ *
+ * If the negotiated dialect is NT LM 0.12 or later, and the response to
+ * the SMB_COM_NEGOTIATE SMB has CAP_LARGE_FILES set in the Capabilities
+ * field, an additional request format is allowed which accommodates very
+ * large files having 64 bit offsets:
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 14
+ * USHORT Fid; File handle
+ * USHORT Count; Total bytes, including this
+ * buffer
+ * USHORT Reserved;
+ * ULONG Offset; Offset in file to begin write
+ * ULONG Timeout;
+ * USHORT WriteMode; Write mode:
+ * bit 0 - complete write to disk
+ * and send final result response
+ * bit 1 - return Remaining
+ * (pipe/dev)
+ * ULONG Reserved2;
+ * USHORT DataLength; Number of data bytes this buffer
+ * USHORT DataOffset; Offset (from header start) to
+ * data
+ * ULONG OffsetHigh; Upper 32 bits of offset
+ * USHORT ByteCount; Count of data bytes
+ * UCHAR Pad[]; Pad to SHORT or LONG
+ * UCHAR Data[]; Data (# = DataLength)
+ *
+ * In this case the final offset in the file is formed by combining
+ * OffsetHigh and Offset, the resulting offset must not be negative.
+ */
+
+#include <sys/sdt.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/netbios.h>
+
+extern uint32_t smb_keep_alive;
+
+static int smb_write_raw_helper(struct smb_request *sr, struct uio *uiop,
+ unsigned int stability, offset_t *offp, uint32_t *lcountp);
+
+static int smb_transfer_write_raw_data(smb_request_t *sr,
+ uint16_t addl_xfer_count);
+
+#define WR_MODE_WR_THRU 1
+
+int
+smb_com_write_raw(struct smb_request *sr)
+{
+ int rc = 0;
+ int session_send_rc = 0;
+ unsigned short addl_xfer_count;
+ unsigned short count;
+ unsigned short write_mode, data_offset, data_length;
+ offset_t off;
+ uint32_t off_low, off_high, timeout;
+ uint32_t lcount = 0;
+ uint32_t addl_lcount = 0;
+ struct uio uio;
+ iovec_t iovec;
+ unsigned int stability;
+ struct mbuf_chain reply;
+ smb_node_t *fnode;
+
+ if (sr->session->s_state != SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
+ return (SDRC_DROP_VC);
+ }
+
+ if (sr->smb_wct == 12) {
+ off_high = 0;
+ rc = smbsr_decode_vwv(sr, "ww2.llw4.ww", &sr->smb_fid, &count,
+ &off_low, &timeout, &write_mode, &data_length,
+ &data_offset);
+ data_offset -= 59;
+ } else {
+ rc = smbsr_decode_vwv(sr, "ww2.llw4.wwl", &sr->smb_fid, &count,
+ &off_low, &timeout, &write_mode, &data_length,
+ &data_offset, &off_high);
+ data_offset -= 63;
+ }
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ off = ((offset_t)off_high << 32) | off_low;
+ addl_xfer_count = count - data_length;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ fnode = sr->fid_ofile->f_node;
+ stability = ((write_mode & WR_MODE_WR_THRU) ||
+ (fnode->flags & NODE_FLAGS_WRITE_THROUGH)) ?
+ FSSTAB_FILE_SYNC : FSSTAB_UNSTABLE;
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ /*
+ * See comments in smb_write.c
+ */
+ if (fnode->attr.sa_vattr.va_type != VDIR) {
+ rc = smb_lock_range_access(sr, fnode, off,
+ count, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ smbsr_raise_cifs_error(sr, rc,
+ ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ }
+ }
+ }
+
+ /*
+ * Make sure any raw write data that is supposed to be
+ * contained in this SMB is actually present.
+ */
+ if (sr->smb_data.chain_offset + data_offset + data_length >
+ sr->smb_data.max_bytes) {
+ /* Error handling code will wake up the session daemon */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Init uio (resid will get filled in later)
+ */
+ uio.uio_iov = &iovec;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_loffset = off;
+
+ /*
+ * Send response if there is additional data to transfer. This
+ * will prompt the client to send the remaining data.
+ */
+ if (addl_xfer_count != 0) {
+ MBC_INIT(&reply, MLEN);
+ (void) smb_encode_mbc(&reply, SMB_HEADER_ED_FMT "bww",
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid, 1, -1, 0);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, &reply);
+
+ session_send_rc = smb_session_send(sr->session, 0, &reply);
+
+ /*
+ * If the session response failed we're not going to
+ * return an error just yet -- we can still write the
+ * data we received along with the SMB even if the
+ * response failed. If it failed, we need to force the
+ * stability level to "write-through".
+ */
+ stability =
+ (session_send_rc == 0) ? stability : FSSTAB_FILE_SYNC;
+ }
+
+ /*
+ * While the response is in flight (and the data begins to arrive)
+ * write out the first data segment. Start by setting up the
+ * iovec list for the first transfer.
+ */
+ iovec.iov_base = sr->smb_data.chain->m_data +
+ sr->smb_data.chain_offset + data_offset;
+ iovec.iov_len = data_length;
+ uio.uio_resid = data_length;
+
+ /*
+ * smb_write_raw_helper will call smb_rpc_write or
+ * smb_fsop_write as appropriate, handle the NODE_FLAGS_SET_SIZE
+ * flag (if set) and update the other f_node fields. It's possible
+ * that data_length may be 0 for this transfer but we still want
+ * process it since it will update the file state (seek position,
+ * file size (possibly), etc).
+ */
+ rc = smb_write_raw_helper(sr, &uio, stability, &off, &lcount);
+
+ /*
+ * If our initial session response failed then we're done. Return
+ * failure. The client will know we wrote some of the data because
+ * of the transfer count (count - lcount) in the response.
+ */
+ if (session_send_rc != 0) {
+ sr->smb_rcls = ERRSRV;
+ sr->smb_err = ERRusestd;
+ goto write_raw_transfer_failed;
+ }
+
+ /*
+ * If we have more data to read then go get it
+ */
+ if (addl_xfer_count) {
+ /*
+ * This is the only place where a worker thread should
+ * directly read from the session socket. If the data
+ * is read successfully then the buffer (sr->sr_raw_data_buf)
+ * will need to be freed after the data is written.
+ */
+ if (smb_transfer_write_raw_data(sr, addl_xfer_count) != 0) {
+ /*
+ * Raw data transfer failed
+ */
+ goto write_raw_transfer_failed;
+ }
+
+ /*
+ * Fill in next iov entry
+ */
+ iovec.iov_base = sr->sr_raw_data_buf;
+ iovec.iov_len = addl_xfer_count;
+ uio.uio_resid = addl_xfer_count;
+ }
+
+ /*
+ * Wake up session daemon since we now have all of our data and
+ * it's safe for the session daemon to resume processing SMB's.
+ */
+ sr->session->s_write_raw_status = 0;
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+
+ /*
+ * If we didn't write all the data from the first segment then
+ * there's not much point in continuing (we still wanted to
+ * read any additional data above since we don't necessarily
+ * want to drop the connection and we need to read through
+ * to the next SMB).
+ */
+ if ((rc != 0) || (lcount != data_length)) {
+ goto notify_write_raw_complete;
+ }
+
+ /*
+ * Write any additional data
+ */
+ if (addl_xfer_count) {
+ rc = smb_write_raw_helper(sr, &uio, stability, &off,
+ &addl_lcount);
+ }
+
+ /*
+ * If we were called in "Write-behind" mode ((write_mode & 1) == 0)
+ * and the transfer was successful then we don't need to send
+ * any further response. If we were called in "Write-Through" mode
+ * ((write_mode & 1) == 1) or if the transfer failed we need to
+ * send a completion notification. The "count" value will indicate
+ * whether the transfer was successful.
+ */
+ if ((rc != 0) || (write_mode & WR_MODE_WR_THRU) ||
+ (lcount + addl_lcount != count)) {
+ goto notify_write_raw_complete;
+ }
+
+ /*
+ * Free raw write buffer (allocated in smb_transfer_write_raw_data)
+ */
+ kmem_free(sr->sr_raw_data_buf, sr->sr_raw_data_length);
+
+ (void) smb_session_send(sr->session, SESSION_KEEP_ALIVE, NULL);
+ return (SDRC_NO_REPLY);
+
+write_raw_transfer_failed:
+ /*
+ * Raw data transfer failed, wake up session
+ * daemon
+ */
+ sr->session->s_write_raw_status = 20;
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+
+notify_write_raw_complete:
+ /*
+ * If we had an error fill in the appropriate error code
+ */
+ if (rc != 0) {
+ (void) smbsr_set_errno(sr, rc);
+ }
+ /*
+ * Free raw write buffer if present (from smb_transfer_write_raw_data)
+ */
+ if (sr->sr_raw_data_buf != NULL) {
+ kmem_free(sr->sr_raw_data_buf, sr->sr_raw_data_length);
+ }
+ /* Write complete notification */
+ sr->first_smb_com = SMB_COM_WRITE_COMPLETE;
+ smbsr_encode_result(sr, 1, 0, "bww", 1,
+ count - (lcount + addl_lcount), 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+
+/*
+ * smb_write_raw_helper
+ *
+ * This function will call smb_rpc_write or smb_fsop_write as appropriate,
+ * handle the NODE_FLAGS_SET_SIZE flag (if set) and update the other f_node
+ * fields. It's possible that data_length may be 0 for this transfer but
+ * we still want process it since it will update the file state (seek
+ * position, file size (possibly), etc).
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+static int
+smb_write_raw_helper(struct smb_request *sr, struct uio *uiop,
+ unsigned int stability, offset_t *offp, uint32_t *lcountp)
+{
+ smb_node_t *fnode;
+ int rc = 0;
+
+ if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
+ *lcountp = uiop->uio_resid;
+
+ if ((rc = smb_rpc_write(sr, uiop)) != 0)
+ *lcountp = 0;
+ } else {
+ fnode = sr->fid_ofile->f_node;
+ rc = smb_fsop_write(sr, sr->user_cr, fnode,
+ uiop, lcountp, &fnode->attr, &stability);
+
+ if (rc == 0) {
+
+ fnode->flags |= NODE_FLAGS_SYNCATIME;
+
+ if (fnode->flags & NODE_FLAGS_SET_SIZE) {
+ if ((*offp + *lcountp) >= fnode->n_size) {
+ fnode->flags &= ~NODE_FLAGS_SET_SIZE;
+ fnode->n_size = *offp + *lcountp;
+ }
+ }
+ }
+ }
+
+ *offp += *lcountp;
+ mutex_enter(&sr->fid_ofile->f_mutex);
+ sr->fid_ofile->f_seek_pos = *offp;
+ mutex_exit(&sr->fid_ofile->f_mutex);
+
+ return (rc);
+}
+
+
+/*
+ * smb_handle_write_raw
+ *
+ * Called from smb_session_daemon() when the SMB command is SMB_COM_WRITE_RAW.
+ * Dispatches the command to the worker thread and waits until the worker
+ * has completed processing the command.
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+int
+smb_handle_write_raw(smb_session_t *session, smb_request_t *sr)
+{
+ int drop_reason = 0;
+
+ /*
+ * Set flag to indicate that we are waiting for raw data. The
+ * worker thread will actually retrieve the raw data directly
+ * from the socket. This should be the only case when a worker
+ * thread reads from the session socket. When the data is read
+ * the worker will clear the flag.
+ */
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ session->s_state = SMB_SESSION_STATE_WRITE_RAW_ACTIVE;
+ smb_rwx_rwexit(&session->s_lock);
+ sr->sr_state = SMB_REQ_STATE_SUBMITTED;
+ (void) taskq_dispatch(smb_info.thread_pool, smb_session_worker,
+ sr, TQ_SLEEP);
+ smb_rwx_rwenter(&session->s_lock, RW_READER);
+ while (session->s_state == SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
+ (void) smb_rwx_rwwait(&session->s_lock, -1);
+ }
+ drop_reason = session->s_write_raw_status;
+ break;
+ default:
+ drop_reason = 21;
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+ return (drop_reason);
+}
+
+/*
+ * smb_transfer_write_raw_data
+ *
+ * Handles the second transfer phase of SMB_COM_WRITE_RAW. smb_com_write_raw()
+ * will process the parameters and data from the SMB and send the initial
+ * SMB response. This function reads the remaining data from the socket
+ * as it arrives from the client.
+ *
+ * Clients may send KEEP_ALIVE messages (when using NBT) between the first
+ * and second parts of write raw requests. The only session transport
+ * types accepted here are SESSION_MESSAGE or SESSION_KEEP_ALIVE.
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+int
+smb_transfer_write_raw_data(smb_request_t *sr, uint16_t addl_xfer_count)
+{
+ smb_session_t *session = sr->session;
+ smb_xprt_t hdr;
+ uint8_t *data_buf;
+
+ do {
+ if (smb_session_xprt_gethdr(session, &hdr) != 0)
+ return (-1);
+
+ if ((hdr.xh_type == SESSION_MESSAGE) ||
+ (hdr.xh_type == SESSION_KEEP_ALIVE)) {
+ session->keep_alive = smb_keep_alive;
+ } else {
+ return (-1);
+ }
+ } while (hdr.xh_type == SESSION_KEEP_ALIVE);
+
+ if (hdr.xh_length < addl_xfer_count) {
+ /*
+ * Less data than we were expecting.
+ */
+ return (-1);
+ }
+
+ data_buf = kmem_alloc(hdr.xh_length, KM_SLEEP);
+
+ if (smb_sorecv(session->sock, data_buf, hdr.xh_length) != 0) {
+ kmem_free(data_buf, hdr.xh_length);
+ sr->sr_raw_data_buf = NULL;
+ sr->sr_raw_data_length = 0;
+ return (-1);
+ }
+
+ sr->sr_raw_data_buf = data_buf;
+ sr->sr_raw_data_length = hdr.xh_length;
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_xlate.c b/usr/src/uts/common/fs/smbsrv/smb_xlate.c
new file mode 100644
index 0000000000..ffe1aa199d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_xlate.c
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+struct xlate_table {
+ int code;
+ char *str;
+};
+
+struct xlate_table smb_xlate_com[] = {
+ { SMB_COM_CREATE_DIRECTORY, "CREATE_DIRECTORY" },
+ { SMB_COM_DELETE_DIRECTORY, "DELETE_DIRECTORY" },
+ { SMB_COM_OPEN, "OPEN" },
+ { SMB_COM_CREATE, "COM_CREATE" },
+ { SMB_COM_CLOSE, "CLOSE" },
+ { SMB_COM_FLUSH, "FLUSH" },
+ { SMB_COM_DELETE, "DELETE" },
+ { SMB_COM_RENAME, "RENAME" },
+ { SMB_COM_QUERY_INFORMATION, "QUERY_INFORMATION" },
+ { SMB_COM_SET_INFORMATION, "SET_INFORMATION" },
+ { SMB_COM_READ, "READ" },
+ { SMB_COM_WRITE, "WRITE" },
+ { SMB_COM_LOCK_BYTE_RANGE, "LOCK_BYTE_RANGE" },
+ { SMB_COM_UNLOCK_BYTE_RANGE, "UNLOCK_BYTE_RANGE" },
+ { SMB_COM_CREATE_TEMPORARY, "CREATE_TEMPORARY" },
+ { SMB_COM_CREATE_NEW, "CREATE_NEW" },
+ { SMB_COM_CHECK_DIRECTORY, "CHECK_DIRECTORY" },
+ { SMB_COM_PROCESS_EXIT, "PROCESS_EXIT" },
+ { SMB_COM_SEEK, "SEEK" },
+ { SMB_COM_LOCK_AND_READ, "LOCK_AND_READ" },
+ { SMB_COM_WRITE_AND_UNLOCK, "WRITE_AND_UNLOCK" },
+ { SMB_COM_READ_RAW, "READ_RAW" },
+ { SMB_COM_READ_MPX, "READ_MPX" },
+ { SMB_COM_READ_MPX_SECONDARY, "READ_MPX_SECONDARY" },
+ { SMB_COM_WRITE_RAW, "WRITE_RAW" },
+ { SMB_COM_WRITE_MPX, "WRITE_MPX" },
+ { SMB_COM_WRITE_COMPLETE, "WRITE_COMPLETE" },
+ { SMB_COM_SET_INFORMATION2, "SET_INFORMATION2" },
+ { SMB_COM_QUERY_INFORMATION2, "QUERY_INFORMATION2" },
+ { SMB_COM_LOCKING_ANDX, "LOCKING_ANDX" },
+ { SMB_COM_TRANSACTION, "TRANSACTION" },
+ { SMB_COM_TRANSACTION_SECONDARY, "TRANSACTION_SECONDARY" },
+ { SMB_COM_IOCTL, "IOCTL" },
+ { SMB_COM_IOCTL_SECONDARY, "IOCTL_SECONDARY" },
+ { SMB_COM_COPY, "COPY" },
+ { SMB_COM_MOVE, "MOVE" },
+ { SMB_COM_ECHO, "ECHO" },
+ { SMB_COM_WRITE_AND_CLOSE, "WRITE_AND_CLOSE" },
+ { SMB_COM_OPEN_ANDX, "OPEN_ANDX" },
+ { SMB_COM_READ_ANDX, "READ_ANDX" },
+ { SMB_COM_WRITE_ANDX, "WRITE_ANDX" },
+ { SMB_COM_CLOSE_AND_TREE_DISC, "CLOSE_AND_TREE_DISC" },
+ { SMB_COM_TRANSACTION2, "TRANSACTION2" },
+ { SMB_COM_TRANSACTION2_SECONDARY, "TRANSACTION2_SECONDARY" },
+ { SMB_COM_FIND_CLOSE2, "FIND_CLOSE2" },
+ { SMB_COM_FIND_NOTIFY_CLOSE, "FIND_NOTIFY_CLOSE" },
+ { SMB_COM_TREE_CONNECT, "TREE_CONNECT" },
+ { SMB_COM_TREE_DISCONNECT, "TREE_DISCONNECT" },
+ { SMB_COM_NEGOTIATE, "NEGOTIATE" },
+ { SMB_COM_SESSION_SETUP_ANDX, "SESSION_SETUP_ANDX" },
+ { SMB_COM_LOGOFF_ANDX, "LOGOFF_ANDX" },
+ { SMB_COM_TREE_CONNECT_ANDX, "TREE_CONNECT_ANDX" },
+ { SMB_COM_QUERY_INFORMATION_DISK, "QUERY_INFORMATION_DISK" },
+ { SMB_COM_SEARCH, "SEARCH" },
+ { SMB_COM_FIND, "FIND" },
+ { SMB_COM_FIND_UNIQUE, "FIND_UNIQUE" },
+ { SMB_COM_NT_TRANSACT, "NT_TRANSACT" },
+ { SMB_COM_NT_TRANSACT_SECONDARY, "NT_TRANSACT_SECONDARY" },
+ { SMB_COM_NT_CREATE_ANDX, "NT_CREATE_ANDX" },
+ { SMB_COM_NT_CANCEL, "NT_CANCEL" },
+ { SMB_COM_OPEN_PRINT_FILE, "OPEN_PRINT_FILE" },
+ { SMB_COM_WRITE_PRINT_FILE, "WRITE_PRINT_FILE" },
+ { SMB_COM_CLOSE_PRINT_FILE, "CLOSE_PRINT_FILE" },
+ { SMB_COM_GET_PRINT_QUEUE, "GET_PRINT_QUEUE" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_rcls[] = {
+ { SUCCESS, "SUCCESS" },
+ { ERRDOS, "ERRDOS" },
+ { ERRSRV, "ERRSRV" },
+ { ERRHRD, "ERRHRD" },
+ { ERRCMD, "ERRCMD" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_errdos[] = {
+ { ERRbadfunc, "ERRbadfunc" },
+ { ERRbadfile, "ERRbadfile" },
+ { ERRbadpath, "ERRbadpath" },
+ { ERRnofids, "ERRnofids" },
+ { ERRnoaccess, "ERRnoaccess" },
+ { ERRbadfid, "ERRbadfid" },
+ { ERRbadmcb, "ERRbadmcb" },
+ { ERRnomem, "ERRnomem" },
+ { ERRbadmem, "ERRbadmem" },
+ { ERRbadenv, "ERRbadenv" },
+ { ERRbadformat, "ERRbadformat" },
+ { ERRbadaccess, "ERRbadaccess" },
+ { ERRbaddata, "ERRbaddata" },
+ { ERRbaddrive, "ERRbaddrive" },
+ { ERRremcd, "ERRremcd" },
+ { ERRdiffdevice, "ERRdiffdevice" },
+ { ERRnofiles, "ERRnofiles" },
+ { ERRbadshare, "ERRbadshare" },
+ { ERRlock, "ERRlock" },
+ { ERRfilexists, "ERRfilexists" },
+ { ERRbadpipe, "ERRbadpipe" },
+ { ERRpipebusy, "ERRpipebusy" },
+ { ERRpipeclosing, "ERRpipeclosing" },
+ { ERRnotconnected, "ERRnotconnected" },
+ { ERRmoredata, "ERRmoredata" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_errsrv[] = {
+ { ERRerror, "ERRerror" },
+ { ERRbadpw, "ERRbadpw" },
+ { ERRaccess, "ERRaccess" },
+ { ERRinvnid, "ERRinvnid" },
+ { ERRinvnetname, "ERRinvnetname" },
+ { ERRinvdevice, "ERRinvdevice" },
+ { ERRqfull, "ERRqfull" },
+ { ERRqtoobig, "ERRqtoobig" },
+ { ERRqeof, "ERRqeof" },
+ { ERRinvpfid, "ERRinvpfid" },
+ { ERRsmbcmd, "ERRsmbcmd" },
+ { ERRsrverror, "ERRsrverror" },
+ { ERRfilespecs, "ERRfilespecs" },
+ { ERRbadpermits, "ERRbadpermits" },
+ { ERRsetattrmode, "ERRsetattrmode" },
+ { ERRpaused, "ERRpaused" },
+ { ERRmsgoff, "ERRmsgoff" },
+ { ERRnoroom, "ERRnoroom" },
+ { ERRrmuns, "ERRrmuns" },
+ { ERRtimeout, "ERRtimeout" },
+ { ERRnoresource, "ERRnoresource" },
+ { ERRtoomanyuids, "ERRtoomanyuids" },
+ { ERRbaduid, "ERRbaduid" },
+ { ERRusempx, "ERRusempx" },
+ { ERRusestd, "ERRusestd" },
+ { ERRcontmpx, "ERRcontmpx" },
+ { ERRnosupport, "ERRnosupport" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_errhrd[] = {
+ { ERRnowrite, "ERRnowrite" },
+ { ERRbadunit, "ERRbadunit" },
+ { ERRnotready, "ERRnotready" },
+ { ERRbadcmd, "ERRbadcmd" },
+ { ERRdata, "ERRdata" },
+ { ERRbadreq, "ERRbadreq" },
+ { ERRseek, "ERRseek" },
+ { ERRbadmedia, "ERRbadmedia" },
+ { ERRbadsector, "ERRbadsector" },
+ { ERRnopaper, "ERRnopaper" },
+ { ERRwrite, "ERRwrite" },
+ { ERRread, "ERRread" },
+ { ERRgeneral, "ERRgeneral" },
+ { ERRbadshare, "ERRbadshare" },
+ { ERRlock, "ERRlock" },
+ { ERRwrongdisk, "ERRwrongdisk" },
+ { ERRFCBUnavail, "ERRFCBUnavail" },
+ { ERRsharebufexc, "ERRsharebufexc" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_dialect[] = {
+ { DIALECT_UNKNOWN, "DIALECT_UNKNOWN" },
+ { PC_NETWORK_PROGRAM_1_0, "PC NETWORK PROGRAM 1.0" },
+ { PCLAN1_0, "PCLAN1.0" },
+ { MICROSOFT_NETWORKS_1_03, "MICROSOFT NETWORKS 1.03" },
+ { MICROSOFT_NETWORKS_3_0, "MICROSOFT NETWORKS 3.0" },
+ { LANMAN1_0, "LANMAN1.0" },
+ { LM1_2X002, "LM1.2X002" },
+ { DOS_LM1_2X002, "DOS LM1.2X002" },
+ { DOS_LANMAN2_1, "DOS LANMAN2.1" },
+ { LANMAN2_1, "LANMAN2.1" },
+ { Windows_for_Workgroups_3_1a, "Windows for Workgroups 3.1a" },
+ { NT_LM_0_12, "NT LM 0.12" },
+ { 0 }
+};
+
+static char *
+smb_xlate_cd_to_str(struct xlate_table *xl, int cd)
+{
+ static char no_answer[32];
+
+ for (; xl->str; xl++)
+ if (xl->code == cd)
+ return (xl->str);
+
+ (void) sprintf(no_answer, "-%x-", cd);
+
+ return (no_answer);
+}
+
+static int
+smb_xlate_str_to_cd(struct xlate_table *xl, char *str)
+{
+ for (; xl->str; xl++)
+ if (strcmp(xl->str, str) == 0)
+ return (xl->code);
+ return (-1);
+}
+
+
+char *
+smb_xlate_com_cd_to_str(int com)
+{
+ return (smb_xlate_cd_to_str(smb_xlate_com, com));
+}
+
+char *
+smb_xlate_dialect_cd_to_str(int dialect)
+{
+ return (smb_xlate_cd_to_str(smb_xlate_dialect, dialect));
+}
+
+int
+smb_xlate_dialect_str_to_cd(char *str)
+{
+ return (smb_xlate_str_to_cd(smb_xlate_dialect, str));
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smbsrv.conf b/usr/src/uts/common/fs/smbsrv/smbsrv.conf
new file mode 100644
index 0000000000..11ecccbccf
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smbsrv.conf
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+name="smbsrv" parent="pseudo";
diff --git a/usr/src/uts/common/fs/sockfs/nl7c.c b/usr/src/uts/common/fs/sockfs/nl7c.c
index 19900ed654..002d111c3a 100644
--- a/usr/src/uts/common/fs/sockfs/nl7c.c
+++ b/usr/src/uts/common/fs/sockfs/nl7c.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,21 +31,21 @@
* (Hypertext Transfer Protocol, see HTTP/1.1 RFC2616) in a semantically
* transparent manner.
*
- * Neither the requesting user agent (client, e.g. web broweser) nor the
+ * Neither the requesting user agent (client, e.g. web browser) nor the
* origin server (e.g. webserver) that provided the response cached by
* NL7C are impacted in any way.
*
* Note, currently NL7C only processes HTTP messages via the embedded
* URI of scheme http (not https nor any other), additional scheme are
- * intended to be supproted as is practical such that much of the NL7C
- * framework may appear more gerneral purpose then would be needed just
+ * intended to be supported as is practical such that much of the NL7C
+ * framework may appear more general purpose then would be needed just
* for an HTTP gateway cache.
*
* NL7C replaces NCA (Network Cache and Accelerator) and in the future
* NCAS (NCA/SSL).
*
* Further, NL7C uses all NCA configuration files, see "/etc/nca/", the
- * NCA socket API, "AF_NCA", and "ndd /dev/nca" for backwards compatability.
+ * NCA socket API, "AF_NCA", and "ndd /dev/nca" for backwards compatibility.
*/
#include <sys/systm.h>
@@ -351,7 +351,7 @@ inet_atob(char *s, nl7c_addr_t *p)
* IPaddr - an IPv4 numeric dot address (e.g. 192.168.84.71) or '*' for
* INADDR_ANY, or an IPv6 numeric address or "::" for IN6ADDR_ANY.
*
- * / - IPaddr/Port seperator.
+ * / - IPaddr/Port separator.
*
* Port - a TCP decimal port number.
*
@@ -517,7 +517,7 @@ ncaportconf_read(void)
if (addrp != NULL) {
kmem_free(addrp, sizeof (*addrp));
}
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
@@ -620,7 +620,7 @@ ncakmodconf_read(void)
}
done:
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
@@ -797,7 +797,7 @@ ncalogdconf_read(void)
/* Opening delimiter, skip */
/*EMPTY*/;
} else if (c == '"' || c == ' ') {
- /* List delim or filename seperator */
+ /* List delim or filename separator */
*fnvp++ = strdup(file);
fp = file;
} else if (fp < &file[sizeof (file) - 1]) {
@@ -820,7 +820,7 @@ ncalogdconf_read(void)
}
done:
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (nl7c_logd_enabled) {
@@ -912,7 +912,7 @@ nl7c_init()
*
* 2) URI scheme not reqcognized.
*
- * 3) A request which can't be procesed.
+ * 3) A request which can't be processed.
*
* 4) A request which could be processed but NL7C dosen't currently have
* the response data. In which case NL7C will parse the returned response
@@ -980,9 +980,9 @@ nl7c_process(struct sonode *so, boolean_t nonblocking)
* First time through, if no data left over from a previous
* kstrgetmsg() then try to get some, else just process it.
*
- * Thereafter, rmp = NULL after the successfull kstrgetmsg()
+ * Thereafter, rmp = NULL after the successful kstrgetmsg()
* so try to get some new data and append to list (i.e. until
- * enough fragments are collected for a successfull parse).
+ * enough fragments are collected for a successful parse).
*/
if (rmp == NULL) {
diff --git a/usr/src/uts/common/fs/sockfs/nl7clogd.c b/usr/src/uts/common/fs/sockfs/nl7clogd.c
index f7a1a8afe9..1580a08c6c 100644
--- a/usr/src/uts/common/fs/sockfs/nl7clogd.c
+++ b/usr/src/uts/common/fs/sockfs/nl7clogd.c
@@ -57,7 +57,7 @@ static void logit_flush(void *);
* in the "/var/nca" directory.
*
* NL7C reuses the NCA logging APIs defined in <inet/nca/ncalogd.h>, at
- * some future date (when NCA is depricated or improvements are needed)
+ * some future date (when NCA is deprecated or improvements are needed)
* these need to be moved into NL7C.
*
* NL7C implements logging differently in 2 ways, 1st the initialization
@@ -278,7 +278,7 @@ next:
mutex_exit(lock);
/* Close current file */
ret = VOP_CLOSE(nca_fio_vp(&fio), FCREAT|FWRITE|FAPPEND|FTRUNC,
- 1, (offset_t)0, kcred);
+ 1, (offset_t)0, kcred, NULL);
nca_fio_vp(&fio) = NULL;
if (ret) {
cmn_err(CE_WARN, "nl7c_logd: close of %s failed (error %d)",
@@ -319,13 +319,13 @@ next:
/* Turn on directio */
(void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO,
- DIRECTIO_ON, 0, kcred, NULL);
+ DIRECTIO_ON, 0, kcred, NULL, NULL);
/* Start writing from the begining of the file */
nca_fio_offset(&fio) = 0;
/* Remove the current symlink */
- (void) VOP_REMOVE(nca_fio_dvp(&fio), symlink, kcred);
+ (void) VOP_REMOVE(nca_fio_dvp(&fio), symlink, kcred, NULL, 0);
attr.va_mask = AT_MODE | AT_TYPE;
attr.va_mode = 0777;
@@ -333,7 +333,7 @@ next:
/* Create symlink to the new log file */
ret = VOP_SYMLINK(nca_fio_dvp(&fio), symlink,
- &attr, nca_fio_name(&fio), kcred);
+ &attr, nca_fio_name(&fio), kcred, NULL, 0);
if (ret) {
cmn_err(CE_WARN, "nl7c_logd: symlink of %s to %s failed",
symlink, nca_fio_name(&fio));
@@ -469,9 +469,9 @@ nl7c_logd_init(int fsz, caddr_t *fnv)
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_loffset = 0;
uio.uio_fmode = 0;
- ret = VOP_READLINK(svp, &uio, kcred);
+ ret = VOP_READLINK(svp, &uio, kcred, NULL);
if (ret) {
- (void) VOP_REMOVE(dvp, symlink, kcred);
+ (void) VOP_REMOVE(dvp, symlink, kcred, NULL, 0);
goto fresh_start;
}
@@ -498,9 +498,9 @@ nl7c_logd_init(int fsz, caddr_t *fnv)
goto error;
}
nca_fio_vp(&fio) = vp;
- (void) VOP_IOCTL(vp, _FIODIRECTIO, DIRECTIO_ON, 0, kcred, NULL);
+ (void) VOP_IOCTL(vp, _FIODIRECTIO, DIRECTIO_ON, 0, kcred, NULL, NULL);
attr.va_mask = AT_SIZE;
- ret = VOP_GETATTR(nca_fio_vp(&fio), &attr, 0, 0);
+ ret = VOP_GETATTR(nca_fio_vp(&fio), &attr, 0, NULL, NULL);
if (ret) {
cmn_err(CE_WARN, "nl7c_logd_init: getattr of %s failed", *fnp);
goto error;
@@ -520,8 +520,9 @@ fresh_start:
attr.va_mask = AT_MODE | AT_TYPE;
attr.va_mode = 0777;
attr.va_type = VLNK;
- (void) VOP_REMOVE(dvp, symlink, kcred);
- ret = VOP_SYMLINK(dvp, symlink, &attr, nca_fio_name(&fio), kcred);
+ (void) VOP_REMOVE(dvp, symlink, kcred, NULL, 0);
+ ret = VOP_SYMLINK(dvp, symlink, &attr, nca_fio_name(&fio), kcred, NULL,
+ 0);
if (ret) {
cmn_err(CE_WARN, "nl7c_logd_init: symlink of %s to %s failed",
symlink_path, nca_fio_name(&fio));
@@ -537,7 +538,7 @@ fresh_start:
/* Turn on directio */
(void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO,
- DIRECTIO_ON, 0, kcred, NULL);
+ DIRECTIO_ON, 0, kcred, NULL, NULL);
finish:
log_buf_kmc = kmem_cache_create("NL7C_log_buf_kmc", sizeof (log_buf_t),
diff --git a/usr/src/uts/common/fs/sockfs/socksctp.c b/usr/src/uts/common/fs/sockfs/socksctp.c
index fbaf68195e..68212f5d15 100644
--- a/usr/src/uts/common/fs/sockfs/socksctp.c
+++ b/usr/src/uts/common/fs/sockfs/socksctp.c
@@ -403,7 +403,7 @@ sosctp_create(vnode_t *accessvp, int domain, int type, int protocol,
*/
if ((cr = CRED()) == NULL)
cr = kcred;
- if ((error = VOP_OPEN(&vp, soflags, cr)) != 0) {
+ if ((error = VOP_OPEN(&vp, soflags, cr, NULL)) != 0) {
VN_RELE(vp);
*errorp = error;
return (NULL);
@@ -457,7 +457,7 @@ sosctp_free(struct sonode *so)
mp->b_next = NULL;
nso = *(struct sonode **)mp->b_rptr;
- (void) VOP_CLOSE(SOTOV(nso), 0, 1, 0, CRED());
+ (void) VOP_CLOSE(SOTOV(nso), 0, 1, 0, CRED(), NULL);
vn_invalid(SOTOV(nso));
VN_RELE(SOTOV(nso));
@@ -531,7 +531,7 @@ sosctp_accept(struct sonode *lso, int fflag, struct sonode **nsop)
if (error != 0) {
vnode_t *nvp;
nvp = SOTOV(nso);
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
/*
@@ -1104,7 +1104,7 @@ sosctp_uiomove(mblk_t *hdr_mp, ssize_t count, ssize_t blk_size, int wroff,
/*
* As a message can be splitted up and sent in different
* packets, each mblk will have the extra space before
- * data to accomodate what SCTP wants to put in there.
+ * data to accommodate what SCTP wants to put in there.
*/
while ((mp = allocb_cred(size + wroff, cr)) == NULL) {
if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
diff --git a/usr/src/uts/common/fs/sockfs/socksctpvnops.c b/usr/src/uts/common/fs/sockfs/socksctpvnops.c
index ea3c49ce6e..214cf4f859 100644
--- a/usr/src/uts/common/fs/sockfs/socksctpvnops.c
+++ b/usr/src/uts/common/fs/sockfs/socksctpvnops.c
@@ -64,19 +64,21 @@
/*
* SCTP sockfs vnode operations
*/
-static int socksctpv_open(struct vnode **, int, struct cred *);
+static int socksctpv_open(struct vnode **, int, struct cred *,
+ caller_context_t *);
static int socksctpv_close(struct vnode *, int, int, offset_t,
- struct cred *);
+ struct cred *, caller_context_t *);
static int socksctpv_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socksctpv_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socksctpv_ioctl(struct vnode *, int, intptr_t, int,
- struct cred *, int32_t *);
-static int socksctp_setfl(vnode_t *, int, int, cred_t *);
-static void socksctpv_inactive(struct vnode *, struct cred *);
+ struct cred *, int32_t *, caller_context_t *);
+static int socksctp_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+static void socksctpv_inactive(struct vnode *, struct cred *,
+ caller_context_t *);
static int socksctpv_poll(struct vnode *, short, int, short *,
- struct pollhead **);
+ struct pollhead **, caller_context_t *);
const fs_operation_def_t socksctp_vnodeops_template[] = {
VOPNAME_OPEN, { .vop_open = socksctpv_open },
@@ -98,8 +100,10 @@ const fs_operation_def_t socksctp_vnodeops_template[] = {
};
struct vnodeops *socksctp_vnodeops;
+/*ARGSUSED3*/
static int
-socksctpv_open(struct vnode **vpp, int flag, struct cred *cr)
+socksctpv_open(struct vnode **vpp, int flag, struct cred *cr,
+ caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
@@ -157,7 +161,7 @@ socksctpv_open(struct vnode **vpp, int flag, struct cred *cr)
/*ARGSUSED*/
static int
socksctpv_close(struct vnode *vp, int flag, int count, offset_t offset,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
@@ -244,7 +248,7 @@ socksctpv_close(struct vnode *vp, int flag, int count, offset_t offset,
/*ARGSUSED2*/
static int
socksctpv_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
struct nmsghdr lmsg;
@@ -267,7 +271,7 @@ socksctpv_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
/*ARGSUSED2*/
static int
socksctpv_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sctp_sonode *ss;
struct sonode *so;
@@ -361,7 +365,7 @@ error_ret:
/*ARGSUSED4*/
static int
socksctpv_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
- struct cred *cr, int32_t *rvalp)
+ struct cred *cr, int32_t *rvalp, caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
@@ -720,7 +724,8 @@ peelerr:
*/
/* ARGSUSED */
static int
-socksctp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+socksctp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
struct sonode *so;
@@ -741,7 +746,7 @@ socksctp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
/*ARGSUSED*/
static void
-socksctpv_inactive(struct vnode *vp, struct cred *cr)
+socksctpv_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
@@ -804,9 +809,10 @@ socksctpv_inactive(struct vnode *vp, struct cred *cr)
/*
* Check socktpi_poll() on why so_lock is not held in this function.
*/
+/*ARGSUSED5*/
static int
socksctpv_poll(struct vnode *vp, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
diff --git a/usr/src/uts/common/fs/sockfs/socksdp.c b/usr/src/uts/common/fs/sockfs/socksdp.c
index fab7c9d861..09ab4d0b49 100755
--- a/usr/src/uts/common/fs/sockfs/socksdp.c
+++ b/usr/src/uts/common/fs/sockfs/socksdp.c
@@ -345,7 +345,7 @@ sosdp_create(vnode_t *accessvp, int domain, int type, int protocol,
*/
if ((cr = CRED()) == NULL)
cr = kcred;
- if ((error = VOP_OPEN(&vp, soflags, cr)) != 0) {
+ if ((error = VOP_OPEN(&vp, soflags, cr, NULL)) != 0) {
VN_RELE(vp);
*errorp = error;
return (NULL);
@@ -391,7 +391,7 @@ sosdp_free(struct sonode *so)
mp->b_next = NULL;
nso = *(struct sonode **)mp->b_rptr;
- (void) VOP_CLOSE(SOTOV(nso), 0, 1, 0, CRED());
+ (void) VOP_CLOSE(SOTOV(nso), 0, 1, 0, CRED(), NULL);
vn_invalid(SOTOV(nso));
VN_RELE(SOTOV(nso));
diff --git a/usr/src/uts/common/fs/sockfs/socksdpvnops.c b/usr/src/uts/common/fs/sockfs/socksdpvnops.c
index 667010ddea..0993bff6a4 100755
--- a/usr/src/uts/common/fs/sockfs/socksdpvnops.c
+++ b/usr/src/uts/common/fs/sockfs/socksdpvnops.c
@@ -63,19 +63,21 @@
/*
* SDP sockfs vnode operations
*/
-static int socksdpv_open(struct vnode **, int, struct cred *);
+static int socksdpv_open(struct vnode **, int, struct cred *,
+ caller_context_t *);
static int socksdpv_close(struct vnode *, int, int, offset_t,
- struct cred *);
+ struct cred *, caller_context_t *);
static int socksdpv_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socksdpv_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socksdpv_ioctl(struct vnode *, int, intptr_t, int,
- struct cred *, int32_t *);
-static int socksdp_setfl(vnode_t *, int, int, cred_t *);
-static void socksdpv_inactive(struct vnode *, struct cred *);
+ struct cred *, int32_t *, caller_context_t *);
+static int socksdp_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+static void socksdpv_inactive(struct vnode *, struct cred *,
+ caller_context_t *);
static int socksdpv_poll(struct vnode *, short, int, short *,
- struct pollhead **);
+ struct pollhead **, caller_context_t *);
const fs_operation_def_t socksdp_vnodeops_template[] = {
VOPNAME_OPEN, { .vop_open = socksdpv_open },
@@ -97,8 +99,10 @@ const fs_operation_def_t socksdp_vnodeops_template[] = {
};
struct vnodeops *socksdp_vnodeops;
+/*ARGSUSED3*/
static int
-socksdpv_open(struct vnode **vpp, int flag, struct cred *cr)
+socksdpv_open(struct vnode **vpp, int flag, struct cred *cr,
+ caller_context_t *ct)
{
struct sonode *so;
struct sdp_sonode *ss;
@@ -149,7 +153,7 @@ socksdpv_open(struct vnode **vpp, int flag, struct cred *cr)
/*ARGSUSED*/
static int
socksdpv_close(struct vnode *vp, int flag, int count, offset_t offset,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
int sendsig = 0;
int error = 0;
@@ -212,7 +216,7 @@ socksdpv_close(struct vnode *vp, int flag, int count, offset_t offset,
/*ARGSUSED2*/
static int
socksdpv_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
struct nmsghdr lmsg;
@@ -235,7 +239,7 @@ socksdpv_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
/*ARGSUSED2*/
static int
socksdpv_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sonode *so;
ssize_t count;
@@ -281,7 +285,7 @@ socksdpv_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
/*ARGSUSED4*/
static int
socksdpv_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
- struct cred *cr, int32_t *rvalp)
+ struct cred *cr, int32_t *rvalp, caller_context_t *ct)
{
struct sonode *so;
struct sdp_sonode *ss;
@@ -400,7 +404,8 @@ socksdpv_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
*/
/* ARGSUSED */
static int
-socksdp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+socksdp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
struct sonode *so;
@@ -421,7 +426,7 @@ socksdp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
/*ARGSUSED*/
static void
-socksdpv_inactive(struct vnode *vp, struct cred *cr)
+socksdpv_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
struct sonode *so;
@@ -457,9 +462,10 @@ socksdpv_inactive(struct vnode *vp, struct cred *cr)
/*
* Check socktpi_poll() on why so_lock is not held in this function.
*/
+/*ARGSUSED5*/
static int
socksdpv_poll(struct vnode *vp, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
struct sonode *so;
struct sdp_sonode *ss;
diff --git a/usr/src/uts/common/fs/sockfs/socksubr.c b/usr/src/uts/common/fs/sockfs/socksubr.c
index ad90f21a36..cbacac2495 100644
--- a/usr/src/uts/common/fs/sockfs/socksubr.c
+++ b/usr/src/uts/common/fs/sockfs/socksubr.c
@@ -918,7 +918,7 @@ so_ux_lookup(struct sonode *so, struct sockaddr_un *soun, int checkaccess,
* vnode. This check is not done in BSD but it is required
* by X/Open.
*/
- if (error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED())) {
+ if (error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL)) {
eprintsoline(so, error);
goto done2;
}
diff --git a/usr/src/uts/common/fs/sockfs/socksyscalls.c b/usr/src/uts/common/fs/sockfs/socksyscalls.c
index 757a353982..90ddae2a95 100644
--- a/usr/src/uts/common/fs/sockfs/socksyscalls.c
+++ b/usr/src/uts/common/fs/sockfs/socksyscalls.c
@@ -185,7 +185,7 @@ so_socket(int domain, int type, int protocol, char *devpath, int version)
&protocol,
(t_uscalar_t)sizeof (protocol));
if (error) {
- (void) VOP_CLOSE(vp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(vp, 0, 1, 0, CRED(), NULL);
VN_RELE(vp);
/*
* Setsockopt often fails with ENOPROTOOPT but socket()
@@ -199,7 +199,7 @@ so_socket(int domain, int type, int protocol, char *devpath, int version)
}
}
if (error = falloc(vp, FWRITE|FREAD, &fp, &fd)) {
- (void) VOP_CLOSE(vp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(vp, 0, 1, 0, CRED(), NULL);
VN_RELE(vp);
return (set_errno(error));
}
@@ -533,14 +533,14 @@ so_socketpair(int sv[2])
mutex_exit(&so2->so_lock);
nvp = SOTOV(nso);
if (error != 0) {
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
eprintsoline(so2, error);
goto done;
}
if (error = falloc(nvp, FWRITE|FREAD, &nfp, &nfd)) {
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
eprintsoline(nso, error);
goto done;
@@ -720,13 +720,13 @@ accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
nso->so_faddr_sa, (socklen_t)nso->so_faddr_len);
if (error) {
setf(nfd, NULL);
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
return (set_errno(error));
}
if (error = falloc(NULL, FWRITE|FREAD, &nfp, NULL)) {
setf(nfd, NULL);
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
eprintsoline(so, error);
return (set_errno(error));
@@ -754,7 +754,8 @@ accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
* This code is a simplification of the F_SETFL code in fcntl()
* Ignore any errors from VOP_SETFL.
*/
- if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred)) != 0) {
+ if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred, NULL))
+ != 0) {
eprintsoline(so, error);
error = 0;
} else {
@@ -1734,7 +1735,7 @@ done:
* processed by a thread, it produces a number of mblk_t structures to
* be consumed by the sendfile thread. snf_deque and snf_enque are
* used for consuming and producing mblks. Size of the filesystem
- * read is determined by the tuneable (sendfile_read_size). A single
+ * read is determined by the tunable (sendfile_read_size). A single
* mblk holds sendfile_read_size worth of data (except the last
* read of the file) which is sent down as a whole to the network.
* sendfile_read_size is set to 1 MB as this seems to be the optimal
@@ -1752,7 +1753,7 @@ done:
* a) One of the threads need to clean the mblks.
* b) When one thread encounters an error, the other should stop.
*
- * For (a), we don't want to penalise the reader thread as it could do
+ * For (a), we don't want to penalize the reader thread as it could do
* some useful work processing other requests. For (b), the error can
* be detected by examining sr_read_error or sr_write_error.
* sr_lock protects sr_read_error and sr_write_error. If both reader and
@@ -1795,7 +1796,7 @@ done:
* control, it would take 25ms to get new data ready for transmission.
* We have to make sure that network is not idling, while we are initiating
* new transfers. So, at 100MB/sec, to keep network busy we would need
- * 2.5MB of data. Roundig off, we keep the low water mark to be 3MB of data.
+ * 2.5MB of data. Rounding off, we keep the low water mark to be 3MB of data.
* We need to pick a high water mark so that the woken up thread would
* do considerable work before blocking again to prevent thrashing. Currently,
* we pick this to be 10 times that of the low water mark.
@@ -1946,7 +1947,7 @@ snf_async_read(snf_req_t *sr)
* Ignore the error for filesystems that doesn't support DIRECTIO.
*/
(void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_ON, 0,
- kcred, NULL);
+ kcred, NULL, NULL);
while ((size != 0) && (sr->sr_write_error == 0)) {
@@ -1970,7 +1971,7 @@ snf_async_read(snf_req_t *sr)
fileoff += ret_size;
}
(void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_OFF, 0,
- kcred, NULL);
+ kcred, NULL, NULL);
mutex_enter(&sr->sr_lock);
sr->sr_read_error = error;
sr->sr_read_error |= SR_READ_DONE;
@@ -2301,7 +2302,7 @@ snf_segmap(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(fvp, &va, 0, kcred);
+ error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
if (error)
break;
/* Read as much as possible. */
@@ -2401,7 +2402,7 @@ snf_cache(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
fileoff += iosize;
(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(fvp, &va, 0, kcred);
+ error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
if (error)
break;
/* Read as much as possible. */
@@ -2466,7 +2467,7 @@ sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
goto out;
}
fvp = rfp->f_vnode;
- if (VOP_REALVP(fvp, &realvp) == 0)
+ if (VOP_REALVP(fvp, &realvp, NULL) == 0)
fvp = realvp;
/*
* Grab the lock as a reader to prevent the file size
@@ -2474,7 +2475,7 @@ sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
*/
(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(fvp, &va, 0, kcred);
+ error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
va_size = va.va_size;
if ((error != 0) || (va_size == 0) || (sfv_off >= va_size)) {
VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
@@ -2560,7 +2561,7 @@ sendto32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
#endif /* _SYSCALL32_IMPL */
/*
- * Function wrappers (mostly arround the sonode switch) for
+ * Function wrappers (mostly around the sonode switch) for
* backward compatibility.
*/
diff --git a/usr/src/uts/common/fs/sockfs/socktpi.c b/usr/src/uts/common/fs/sockfs/socktpi.c
index 65a10f0690..a198c17176 100644
--- a/usr/src/uts/common/fs/sockfs/socktpi.c
+++ b/usr/src/uts/common/fs/sockfs/socktpi.c
@@ -287,14 +287,14 @@ sotpi_create(vnode_t *accessvp, int domain, int type, int protocol, int version,
so->so_kssl_ent = NULL;
so->so_kssl_ctx = NULL;
- if (error = socktpi_open(&vp, flags, CRED())) {
+ if (error = socktpi_open(&vp, flags, CRED(), NULL)) {
VN_RELE(vp);
*errorp = error;
return (NULL);
}
if (error = so_strinit(so, tso)) {
- (void) VOP_CLOSE(vp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(vp, 0, 1, 0, CRED(), NULL);
VN_RELE(vp);
*errorp = error;
return (NULL);
@@ -1753,7 +1753,7 @@ again:
*/
mutex_exit(&nso->so_lock);
(void) VOP_CLOSE(nvp, 0, 1, (offset_t)0,
- CRED());
+ CRED(), NULL);
VN_RELE(nvp);
goto again;
}
@@ -1900,7 +1900,7 @@ e_disc_unl:
pr_disc_vp_unl:
eprintsoline(so, error);
disconnect_vp_unlocked:
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
disconnect_unlocked:
(void) sodisconnect(so, SEQ_number, 0);
@@ -1912,7 +1912,7 @@ disconnect_vp:
(void) sodisconnect(so, SEQ_number, _SODISCONNECT_LOCK_HELD);
so_unlock_single(so, SOLOCKED);
mutex_exit(&so->so_lock);
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
return (error);
diff --git a/usr/src/uts/common/fs/sockfs/sockvnops.c b/usr/src/uts/common/fs/sockfs/sockvnops.c
index 3ab7626e6f..6c122c679d 100644
--- a/usr/src/uts/common/fs/sockfs/sockvnops.c
+++ b/usr/src/uts/common/fs/sockfs/sockvnops.c
@@ -95,16 +95,17 @@
#include <inet/kssl/ksslapi.h>
-static int socktpi_close(struct vnode *, int, int, offset_t, struct cred *);
+static int socktpi_close(struct vnode *, int, int, offset_t, struct cred *,
+ caller_context_t *);
static int socktpi_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socktpi_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socktpi_plumbioctl(struct vnode *, int, intptr_t, int, struct cred *,
int32_t *);
-static void socktpi_inactive(struct vnode *, struct cred *);
+static void socktpi_inactive(struct vnode *, struct cred *, caller_context_t *);
static int socktpi_poll(struct vnode *, short, int, short *,
- struct pollhead **);
+ struct pollhead **, caller_context_t *);
struct vnodeops *socktpi_vnodeops;
@@ -148,7 +149,8 @@ boolean_t socktpi_direct = B_TRUE;
* open/closes for a given vnode which is probably not needed.
*/
int
-socktpi_open(struct vnode **vpp, int flag, struct cred *cr)
+socktpi_open(struct vnode **vpp, int flag, struct cred *cr,
+ caller_context_t *ct)
{
major_t maj;
dev_t newdev;
@@ -196,7 +198,7 @@ socktpi_open(struct vnode **vpp, int flag, struct cred *cr)
* this is a post SVR4 tty driver - a socket can not
* be a controlling terminal. Fail the open.
*/
- (void) socktpi_close(vp, flag, 1, (offset_t)0, cr);
+ (void) socktpi_close(vp, flag, 1, (offset_t)0, cr, ct);
return (ENOTTY); /* XXX */
}
@@ -249,7 +251,7 @@ socktpi_open(struct vnode **vpp, int flag, struct cred *cr)
_SIOCSOCKFALLBACK, 0, 0, K_TO_K,
CRED(), &rval)) != 0) {
(void) socktpi_close(vp, flag,
- 1, (offset_t)0, cr);
+ 1, (offset_t)0, cr, ct);
return (error);
}
}
@@ -273,7 +275,7 @@ socktpi_open(struct vnode **vpp, int flag, struct cred *cr)
so_unlock_single(so, SOLOCKED);
mutex_exit(&so->so_lock);
(void) socktpi_close(vp, flag, 1,
- (offset_t)0, cr);
+ (offset_t)0, cr, ct);
return (error);
/*NOTREACHED*/
}
@@ -297,7 +299,8 @@ socktpi_close(
int flag,
int count,
offset_t offset,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct sonode *so;
dev_t dev;
@@ -402,7 +405,7 @@ socktpi_read(
struct uio *uiop,
int ioflag,
struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
struct nmsghdr lmsg;
@@ -428,11 +431,11 @@ socktpi_read(
/* ARGSUSED2 */
static int
socktpi_write(
- struct vnode *vp,
- struct uio *uiop,
- int ioflag,
- struct cred *cr,
- struct caller_context *ct)
+ struct vnode *vp,
+ struct uio *uiop,
+ int ioflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
int so_state;
@@ -531,9 +534,10 @@ so_copyout(const void *from, void *to, size_t size, int tokernel)
return (xcopyout(from, to, size));
}
+/*ARGSUSED6*/
int
socktpi_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
- struct cred *cr, int32_t *rvalp)
+ struct cred *cr, int32_t *rvalp, caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
int error = 0;
@@ -941,7 +945,8 @@ socktpi_plumbioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
*/
/* ARGSUSED */
int
-socktpi_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+socktpi_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
struct sonode *so;
int error = 0;
@@ -1003,7 +1008,8 @@ socktpi_getattr(
struct vnode *vp,
struct vattr *vap,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
dev_t fsid;
struct sonode *so;
@@ -1081,7 +1087,7 @@ socktpi_setattr(
struct vattr *vap,
int flags,
struct cred *cr,
- caller_context_t *ct)
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
@@ -1101,13 +1107,14 @@ socktpi_setattr(
}
int
-socktpi_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+socktpi_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *accessvp;
struct sonode *so = VTOSO(vp);
if ((accessvp = so->so_accessvp) != NULL)
- return (VOP_ACCESS(accessvp, mode, flags, cr));
+ return (VOP_ACCESS(accessvp, mode, flags, cr, ct));
else
return (0); /* Allow all access. */
}
@@ -1120,14 +1127,15 @@ socktpi_access(struct vnode *vp, int mode, int flags, struct cred *cr)
*/
/* ARGSUSED */
int
-socktpi_fsync(struct vnode *vp, int syncflag, struct cred *cr)
+socktpi_fsync(struct vnode *vp, int syncflag, struct cred *cr,
+ caller_context_t *ct)
{
return (EINVAL);
}
/* ARGSUSED */
static void
-socktpi_inactive(struct vnode *vp, struct cred *cr)
+socktpi_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
@@ -1156,7 +1164,7 @@ socktpi_inactive(struct vnode *vp, struct cred *cr)
/* ARGSUSED */
int
-socktpi_fid(struct vnode *vp, struct fid *fidp)
+socktpi_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
return (EINVAL);
}
@@ -1167,7 +1175,8 @@ socktpi_fid(struct vnode *vp, struct fid *fidp)
*/
/*ARGSUSED*/
int
-socktpi_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+socktpi_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
return (ESPIPE);
}
@@ -1202,13 +1211,15 @@ socktpi_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
* for SS_HASCONNIND and set appropriate events to ensure poll_common()
* will not sleep.
*/
+/*ARGSUSED5*/
static int
socktpi_poll(
struct vnode *vp,
short events,
int anyyet,
short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
short origevents = events;
struct sonode *so = VTOSO(vp);
diff --git a/usr/src/uts/common/fs/specfs/specsubr.c b/usr/src/uts/common/fs/specfs/specsubr.c
index 85d9089b82..de5bf62e44 100644
--- a/usr/src/uts/common/fs/specfs/specsubr.c
+++ b/usr/src/uts/common/fs/specfs/specsubr.c
@@ -142,7 +142,7 @@ specvp(
* been required if the snode is in the cache.
*/
va.va_mask = AT_FSID | AT_TIMES;
- rc = VOP_GETATTR(vp, &va, 0, cr); /* XXX may block! */
+ rc = VOP_GETATTR(vp, &va, 0, cr, NULL); /* XXX may block! */
mutex_enter(&stable_lock);
if ((sp = sfind(dev, type, vp)) == NULL) {
@@ -465,7 +465,7 @@ devi_stillreferenced(dev_info_t *dip)
/*
* Given an snode, returns the open count and the dip
* associated with that snode
- * Assumes the caller holds the approriate locks
+ * Assumes the caller holds the appropriate locks
* to prevent snode and/or dip from going away.
* Returns:
* -1 No associated dip
@@ -862,7 +862,7 @@ device_close(struct vnode *vp, int flag, struct cred *cr)
* can, for example, change floppy disks.
*/
(void) spec_putpage(cvp, (offset_t)0,
- (size_t)0, B_INVAL|B_FORCE, cr);
+ (size_t)0, B_INVAL|B_FORCE, cr, NULL);
bflush(dev);
binval(dev);
error = dev_close(dev, flag, OTYP_BLK, cr);
diff --git a/usr/src/uts/common/fs/specfs/specvfsops.c b/usr/src/uts/common/fs/specfs/specvfsops.c
index e943a700a0..98342f4424 100644
--- a/usr/src/uts/common/fs/specfs/specvfsops.c
+++ b/usr/src/uts/common/fs/specfs/specvfsops.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -98,7 +97,7 @@ _info(struct modinfo *modinfop)
* N.B.
* No _fini routine. This module cannot be unloaded once loaded.
* The NO_UNLOAD_STUB in modstub.s must change if this module ever
- * is modififed to become unloadable.
+ * is modified to become unloadable.
*/
kmutex_t spec_syncbusy; /* initialized in specinit() */
@@ -158,7 +157,8 @@ spec_sync(struct vfs *vfsp,
for (sp = sync_list; sp != NULL; sp = spnext) {
spnext = sp->s_list;
vp = STOV(sp);
- (void) VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0, B_ASYNC, cr,
+ NULL);
VN_RELE(vp); /* Release our hold on vnode */
}
mutex_exit(&spec_syncbusy);
diff --git a/usr/src/uts/common/fs/specfs/specvnops.c b/usr/src/uts/common/fs/specfs/specvnops.c
index 07b5e6106d..d452246135 100644
--- a/usr/src/uts/common/fs/specfs/specvnops.c
+++ b/usr/src/uts/common/fs/specfs/specvnops.c
@@ -96,50 +96,59 @@
#include <sys/contract/device_impl.h>
-static int spec_open(struct vnode **, int, struct cred *);
-static int spec_close(struct vnode *, int, int, offset_t, struct cred *);
+static int spec_open(struct vnode **, int, struct cred *, caller_context_t *);
+static int spec_close(struct vnode *, int, int, offset_t, struct cred *,
+ caller_context_t *);
static int spec_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int spec_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
-static int spec_ioctl(struct vnode *, int, intptr_t, int, struct cred *, int *);
-static int spec_getattr(struct vnode *, struct vattr *, int, struct cred *);
+ caller_context_t *);
+static int spec_ioctl(struct vnode *, int, intptr_t, int, struct cred *, int *,
+ caller_context_t *);
+static int spec_getattr(struct vnode *, struct vattr *, int, struct cred *,
+ caller_context_t *);
static int spec_setattr(struct vnode *, struct vattr *, int, struct cred *,
caller_context_t *);
-static int spec_access(struct vnode *, int, int, struct cred *);
-static int spec_create(struct vnode *, char *, vattr_t *, enum vcexcl,
- int, struct vnode **, struct cred *, int);
-static int spec_fsync(struct vnode *, int, struct cred *);
-static void spec_inactive(struct vnode *, struct cred *);
-static int spec_fid(struct vnode *, struct fid *);
-static int spec_seek(struct vnode *, offset_t, offset_t *);
+static int spec_access(struct vnode *, int, int, struct cred *,
+ caller_context_t *);
+static int spec_create(struct vnode *, char *, vattr_t *, enum vcexcl, int,
+ struct vnode **, struct cred *, int, caller_context_t *, vsecattr_t *);
+static int spec_fsync(struct vnode *, int, struct cred *, caller_context_t *);
+static void spec_inactive(struct vnode *, struct cred *, caller_context_t *);
+static int spec_fid(struct vnode *, struct fid *, caller_context_t *);
+static int spec_seek(struct vnode *, offset_t, offset_t *, caller_context_t *);
static int spec_frlock(struct vnode *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, struct cred *);
-static int spec_realvp(struct vnode *, struct vnode **);
+ struct flk_callback *, struct cred *, caller_context_t *);
+static int spec_realvp(struct vnode *, struct vnode **, caller_context_t *);
static int spec_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t **,
- size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
+ size_t, struct seg *, caddr_t, enum seg_rw, struct cred *,
+ caller_context_t *);
static int spec_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int,
struct cred *);
static struct buf *spec_startio(struct vnode *, page_t *, u_offset_t, size_t,
int);
static int spec_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
- page_t **, size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
+ page_t **, size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
static int spec_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int spec_addmap(struct vnode *, offset_t, struct as *, caddr_t, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int spec_delmap(struct vnode *, offset_t, struct as *, caddr_t, size_t,
- uint_t, uint_t, uint_t, struct cred *);
+ uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
-static int spec_poll(struct vnode *, short, int, short *, struct pollhead **);
-static int spec_dump(struct vnode *, caddr_t, int, int);
+static int spec_poll(struct vnode *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+static int spec_dump(struct vnode *, caddr_t, int, int, caller_context_t *);
static int spec_pageio(struct vnode *, page_t *, u_offset_t, size_t, int,
- cred_t *);
+ cred_t *, caller_context_t *);
-static int spec_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
-static int spec_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
-static int spec_pathconf(struct vnode *, int, ulong_t *, struct cred *);
+static int spec_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
+static int spec_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
+static int spec_pathconf(struct vnode *, int, ulong_t *, struct cred *,
+ caller_context_t *);
#define SN_HOLD(csp) { \
mutex_enter(&csp->s_lock); \
@@ -549,7 +558,7 @@ spec_clone(struct vnode **vpp, dev_t newdev, int vtype, struct stdata *stp)
}
static int
-spec_open(struct vnode **vpp, int flag, struct cred *cr)
+spec_open(struct vnode **vpp, int flag, struct cred *cr, caller_context_t *cc)
{
major_t maj;
dev_t dev, newdev;
@@ -785,7 +794,7 @@ streams_open:
/* STREAM is of type S_IFCHR */
if (contract_device_open(newdev, S_IFCHR, &ct) != 0) {
UNLOCK_CSP(csp);
- (void) spec_close(vp, flag, 1, 0, cr);
+ (void) spec_close(vp, flag, 1, 0, cr, cc);
return (EIO);
}
}
@@ -807,7 +816,7 @@ streams_open:
ASSERT(ttoproc(curthread));
(void) contract_abandon(ct, ttoproc(curthread), 0);
}
- (void) spec_close(vp, flag, 1, 0, cr);
+ (void) spec_close(vp, flag, 1, 0, cr, cc);
return (EINTR);
}
@@ -826,7 +835,7 @@ streams_open:
mutex_exit(&stp->sd_lock);
UNLOCK_CSP(csp);
- (void) spec_close(vp, flag, 1, 0, cr);
+ (void) spec_close(vp, flag, 1, 0, cr, cc);
} else {
UNLOCK_CSP(csp);
SN_RELE(csp);
@@ -842,7 +851,8 @@ spec_close(
int flag,
int count,
offset_t offset,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *cvp;
struct snode *sp, *csp;
@@ -943,7 +953,7 @@ spec_read(
struct uio *uiop,
int ioflag,
struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int error;
struct snode *sp = VTOS(vp);
@@ -1049,7 +1059,7 @@ spec_write(
struct uio *uiop,
int ioflag,
struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int error;
struct snode *sp = VTOS(vp);
@@ -1214,9 +1224,10 @@ spec_write(
return (error);
}
+/*ARGSUSED6*/
static int
spec_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode, struct cred *cr,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
struct snode *sp;
dev_t dev;
@@ -1242,7 +1253,12 @@ spec_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode, struct cred *cr,
}
static int
-spec_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
+spec_getattr(
+ struct vnode *vp,
+ struct vattr *vap,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
int error;
struct snode *sp;
@@ -1302,7 +1318,7 @@ spec_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
*/
vap->va_nblocks = 0;
} else {
- error = VOP_GETATTR(realvp, vap, flags, cr);
+ error = VOP_GETATTR(realvp, vap, flags, cr, ct);
if (error != 0)
return (error);
}
@@ -1331,7 +1347,7 @@ spec_setattr(
struct vattr *vap,
int flags,
struct cred *cr,
- caller_context_t *ctp)
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct vnode *realvp;
@@ -1353,7 +1369,7 @@ spec_setattr(
if ((realvp = sp->s_realvp) == NULL)
error = 0; /* no real vnode to update */
else
- error = VOP_SETATTR(realvp, vap, flags, cr, ctp);
+ error = VOP_SETATTR(realvp, vap, flags, cr, ct);
if (error == 0) {
/*
* If times were changed, update snode.
@@ -1371,7 +1387,12 @@ spec_setattr(
}
static int
-spec_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+spec_access(
+ struct vnode *vp,
+ int mode,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *realvp;
struct snode *sp = VTOS(vp);
@@ -1381,7 +1402,7 @@ spec_access(struct vnode *vp, int mode, int flags, struct cred *cr)
return (ENXIO);
if ((realvp = sp->s_realvp) != NULL)
- return (VOP_ACCESS(realvp, mode, flags, cr));
+ return (VOP_ACCESS(realvp, mode, flags, cr, ct));
else
return (0); /* Allow all access. */
}
@@ -1392,8 +1413,17 @@ spec_access(struct vnode *vp, int mode, int flags, struct cred *cr)
*/
/*ARGSUSED*/
static int
-spec_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
- int mode, struct vnode **vpp, struct cred *cr, int flag)
+spec_create(
+ struct vnode *dvp,
+ char *name,
+ vattr_t *vap,
+ enum vcexcl excl,
+ int mode,
+ struct vnode **vpp,
+ struct cred *cr,
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
struct snode *sp = VTOS(dvp);
@@ -1404,7 +1434,7 @@ spec_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
ASSERT(dvp && (dvp->v_flag & VROOT) && *name == '\0');
if (excl == NONEXCL) {
- if (mode && (error = spec_access(dvp, mode, 0, cr)))
+ if (mode && (error = spec_access(dvp, mode, 0, cr, ct)))
return (error);
VN_HOLD(dvp);
return (0);
@@ -1418,7 +1448,11 @@ spec_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
* already set in the vnode.
*/
static int
-spec_fsync(struct vnode *vp, int syncflag, struct cred *cr)
+spec_fsync(
+ struct vnode *vp,
+ int syncflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct vnode *realvp;
@@ -1440,7 +1474,7 @@ spec_fsync(struct vnode *vp, int syncflag, struct cred *cr)
if (vp->v_type == VBLK && cvp != vp && vn_has_cached_data(cvp) &&
(cvp->v_flag & VISSWAP) == 0)
- (void) VOP_PUTPAGE(cvp, (offset_t)0, 0, 0, cr);
+ (void) VOP_PUTPAGE(cvp, (offset_t)0, 0, 0, cr, ct);
/*
* For devices that support it, force write cache to stable storage.
@@ -1473,7 +1507,7 @@ spec_fsync(struct vnode *vp, int syncflag, struct cred *cr)
return (0);
vatmp.va_mask = AT_ATIME|AT_MTIME;
- if (VOP_GETATTR(realvp, &vatmp, 0, cr) == 0) {
+ if (VOP_GETATTR(realvp, &vatmp, 0, cr, ct) == 0) {
mutex_enter(&sp->s_lock);
if (vatmp.va_atime.tv_sec > sp->s_atime)
@@ -1491,15 +1525,15 @@ spec_fsync(struct vnode *vp, int syncflag, struct cred *cr)
mutex_exit(&sp->s_lock);
va.va_mask = AT_ATIME|AT_MTIME;
- (void) VOP_SETATTR(realvp, &va, 0, cr, NULL);
+ (void) VOP_SETATTR(realvp, &va, 0, cr, ct);
}
- (void) VOP_FSYNC(realvp, syncflag, cr);
+ (void) VOP_FSYNC(realvp, syncflag, cr, ct);
return (0);
}
/*ARGSUSED*/
static void
-spec_inactive(struct vnode *vp, struct cred *cr)
+spec_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct vnode *cvp;
@@ -1550,7 +1584,7 @@ spec_inactive(struct vnode *vp, struct cred *cr)
* The user may not own the device, but we
* want to update the attributes anyway.
*/
- if (VOP_GETATTR(rvp, &vatmp, 0, kcred) == 0) {
+ if (VOP_GETATTR(rvp, &vatmp, 0, kcred, ct) == 0) {
if (vatmp.va_atime.tv_sec > sp->s_atime)
va.va_atime = vatmp.va_atime;
else {
@@ -1565,7 +1599,7 @@ spec_inactive(struct vnode *vp, struct cred *cr)
}
va.va_mask = AT_ATIME|AT_MTIME;
- (void) VOP_SETATTR(rvp, &va, 0, kcred, NULL);
+ (void) VOP_SETATTR(rvp, &va, 0, kcred, ct);
}
}
}
@@ -1619,20 +1653,24 @@ spec_inactive(struct vnode *vp, struct cred *cr)
}
static int
-spec_fid(struct vnode *vp, struct fid *fidp)
+spec_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct vnode *realvp;
struct snode *sp = VTOS(vp);
if ((realvp = sp->s_realvp) != NULL)
- return (VOP_FID(realvp, fidp));
+ return (VOP_FID(realvp, fidp, ct));
else
return (EINVAL);
}
/*ARGSUSED1*/
static int
-spec_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+spec_seek(
+ struct vnode *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
{
offset_t maxoff = spec_maxoffset(vp);
@@ -1650,7 +1688,8 @@ spec_frlock(
int flag,
offset_t offset,
struct flk_callback *flk_cbp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct snode *csp;
@@ -1662,17 +1701,17 @@ spec_frlock(
if (csp->s_mapcnt > 0)
return (EAGAIN);
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
static int
-spec_realvp(struct vnode *vp, struct vnode **vpp)
+spec_realvp(struct vnode *vp, struct vnode **vpp, caller_context_t *ct)
{
struct vnode *rvp;
if ((rvp = VTOS(vp)->s_realvp) != NULL) {
vp = rvp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
}
@@ -1684,6 +1723,7 @@ spec_realvp(struct vnode *vp, struct vnode **vpp)
* Return all the pages from [off..off + len] in block
* or character device.
*/
+/*ARGSUSED*/
static int
spec_getpage(
struct vnode *vp,
@@ -1695,7 +1735,8 @@ spec_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
int err;
@@ -1942,13 +1983,15 @@ again:
* len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
* (from pageout).
*/
+/*ARGSUSED5*/
int
spec_putpage(
struct vnode *vp,
offset_t off,
size_t len,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct vnode *cvp;
@@ -2142,13 +2185,14 @@ spec_poll(
short events,
int anyyet,
short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
dev_t dev;
int error;
if (vp->v_type == VBLK)
- error = fs_poll(vp, events, anyyet, reventsp, phpp);
+ error = fs_poll(vp, events, anyyet, reventsp, phpp, ct);
else {
ASSERT(vp->v_type == VCHR);
dev = vp->v_rdev;
@@ -2159,7 +2203,7 @@ spec_poll(
} else if (devopsp[getmajor(dev)]->devo_cb_ops->cb_chpoll) {
error = cdev_poll(dev, events, anyyet, reventsp, phpp);
} else {
- error = fs_poll(vp, events, anyyet, reventsp, phpp);
+ error = fs_poll(vp, events, anyyet, reventsp, phpp, ct);
}
}
return (error);
@@ -2310,6 +2354,7 @@ spec_char_map(
maxprot, flags, cred));
}
+/*ARGSUSED9*/
static int
spec_map(
struct vnode *vp,
@@ -2320,7 +2365,8 @@ spec_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
int error = 0;
struct snode *sp = VTOS(vp);
@@ -2405,7 +2451,8 @@ spec_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
int error = 0;
struct snode *csp = VTOS(vp);
@@ -2443,7 +2490,8 @@ spec_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
struct snode *csp = VTOS(vp);
ulong_t npages;
@@ -2498,8 +2546,14 @@ spec_delmap(
return (0);
}
+/*ARGSUSED4*/
static int
-spec_dump(struct vnode *vp, caddr_t addr, int bn, int count)
+spec_dump(
+ struct vnode *vp,
+ caddr_t addr,
+ int bn,
+ int count,
+ caller_context_t *ct)
{
/* allow dump to succeed even if device fenced off */
@@ -2522,7 +2576,8 @@ spec_pageio(
u_offset_t io_off,
size_t io_len,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
struct buf *bp = NULL;
int err = 0;
@@ -2546,7 +2601,12 @@ spec_pageio(
* Set ACL on underlying vnode if one exists, or return ENOSYS otherwise.
*/
int
-spec_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
+spec_setsecattr(
+ struct vnode *vp,
+ vsecattr_t *vsap,
+ int flag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *realvp;
struct snode *sp = VTOS(vp);
@@ -2564,9 +2624,9 @@ spec_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
* here privately to avoid serializing specfs reads and writes.
*/
if ((realvp = sp->s_realvp) != NULL) {
- (void) VOP_RWLOCK(realvp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(realvp, vsap, flag, cr);
- (void) VOP_RWUNLOCK(realvp, V_WRITELOCK_TRUE, NULL);
+ (void) VOP_RWLOCK(realvp, V_WRITELOCK_TRUE, ct);
+ error = VOP_SETSECATTR(realvp, vsap, flag, cr, ct);
+ (void) VOP_RWUNLOCK(realvp, V_WRITELOCK_TRUE, ct);
return (error);
} else
return (fs_nosys());
@@ -2577,7 +2637,12 @@ spec_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
* the permissions returned by spec_getattr() otherwise.
*/
int
-spec_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
+spec_getsecattr(
+ struct vnode *vp,
+ vsecattr_t *vsap,
+ int flag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *realvp;
struct snode *sp = VTOS(vp);
@@ -2587,13 +2652,18 @@ spec_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
return (ENXIO);
if ((realvp = sp->s_realvp) != NULL)
- return (VOP_GETSECATTR(realvp, vsap, flag, cr));
+ return (VOP_GETSECATTR(realvp, vsap, flag, cr, ct));
else
- return (fs_fab_acl(vp, vsap, flag, cr));
+ return (fs_fab_acl(vp, vsap, flag, cr, ct));
}
int
-spec_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+spec_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
{
vnode_t *realvp;
struct snode *sp = VTOS(vp);
@@ -2603,7 +2673,7 @@ spec_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
return (ENXIO);
if ((realvp = sp->s_realvp) != NULL)
- return (VOP_PATHCONF(realvp, cmd, valp, cr));
+ return (VOP_PATHCONF(realvp, cmd, valp, cr, ct));
else
- return (fs_pathconf(vp, cmd, valp, cr));
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
}
diff --git a/usr/src/uts/common/fs/swapfs/swap_subr.c b/usr/src/uts/common/fs/swapfs/swap_subr.c
index e589c38073..dbbf57a50a 100644
--- a/usr/src/uts/common/fs/swapfs/swap_subr.c
+++ b/usr/src/uts/common/fs/swapfs/swap_subr.c
@@ -257,7 +257,7 @@ swap_sync(struct vfs *vfsp, short flag, struct cred *cr)
if (vp) {
VN_HOLD(vp);
(void) VOP_PUTPAGE(vp, (offset_t)0, 0,
- (B_ASYNC | B_FREE), kcred);
+ (B_ASYNC | B_FREE), kcred, NULL);
VN_RELE(vp);
}
}
diff --git a/usr/src/uts/common/fs/swapfs/swap_vnops.c b/usr/src/uts/common/fs/swapfs/swap_vnops.c
index 53bdae350c..4e69206084 100644
--- a/usr/src/uts/common/fs/swapfs/swap_vnops.c
+++ b/usr/src/uts/common/fs/swapfs/swap_vnops.c
@@ -55,13 +55,14 @@
* Define the routines within this file.
*/
static int swap_getpage(struct vnode *vp, offset_t off, size_t len,
- uint_t *protp, struct page **plarr, size_t plsz,
- struct seg *seg, caddr_t addr, enum seg_rw rw, struct cred *cr);
+ uint_t *protp, struct page **plarr, size_t plsz, struct seg *seg,
+ caddr_t addr, enum seg_rw rw, struct cred *cr, caller_context_t *ct);
static int swap_putpage(struct vnode *vp, offset_t off, size_t len,
- int flags, struct cred *cr);
-static void swap_inactive(struct vnode *vp, struct cred *cr);
+ int flags, struct cred *cr, caller_context_t *ct);
+static void swap_inactive(struct vnode *vp, struct cred *cr,
+ caller_context_t *ct);
static void swap_dispose(vnode_t *vp, page_t *pp, int fl, int dn,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
static int swap_getapage(struct vnode *vp, u_offset_t off, size_t len,
uint_t *protp, page_t **plarr, size_t plsz,
@@ -94,7 +95,8 @@ vnodeops_t *swap_vnodeops;
static void
swap_inactive(
struct vnode *vp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
SWAPFS_PRINT(SWAP_VOPS, "swap_inactive: vp %x\n", vp, 0, 0, 0, 0);
}
@@ -102,6 +104,7 @@ swap_inactive(
/*
* Return all the pages from [off..off+len] in given file
*/
+/*ARGSUSED*/
static int
swap_getpage(
struct vnode *vp,
@@ -113,7 +116,8 @@ swap_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
int err;
@@ -236,7 +240,7 @@ again:
flags = (pl == NULL ? B_ASYNC|B_READ : B_READ);
err = VOP_PAGEIO(pvp, pp, poff,
- PAGESIZE, flags, cr);
+ PAGESIZE, flags, cr, NULL);
if (!err) {
ahm = &anonhash_lock[AH_LOCK(vp, off)];
@@ -412,7 +416,8 @@ swap_getconpage(
}
if (pvp) {
- err = VOP_PAGEIO(pvp, pp, poff, PAGESIZE, B_READ, cr);
+ err = VOP_PAGEIO(pvp, pp, poff, PAGESIZE, B_READ, cr,
+ NULL);
} else {
pagezero(pp, 0, PAGESIZE);
}
@@ -464,7 +469,8 @@ swap_putpage(
offset_t off,
size_t len,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
page_t *pp;
u_offset_t io_off;
@@ -709,7 +715,7 @@ swap_putapage(
}
err = VOP_PAGEIO(klvp, pplist, klstart, klsz,
- B_WRITE | flags, cr);
+ B_WRITE | flags, cr, NULL);
if ((flags & B_ASYNC) == 0)
pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
@@ -731,7 +737,13 @@ out:
}
static void
-swap_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
+swap_dispose(
+ vnode_t *vp,
+ page_t *pp,
+ int fl,
+ int dn,
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
u_offset_t off = pp->p_offset;
@@ -751,7 +763,7 @@ swap_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
err = swap_getphysname(vp, off, &pvp, &poff);
if (!err && pvp != NULL)
- VOP_DISPOSE(pvp, pp, fl, dn, cr);
+ VOP_DISPOSE(pvp, pp, fl, dn, cr, ct);
else
- fs_dispose(vp, pp, fl, dn, cr);
+ fs_dispose(vp, pp, fl, dn, cr, ct);
}
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_dir.c b/usr/src/uts/common/fs/tmpfs/tmp_dir.c
index 682cac326b..f6621c8097 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_dir.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_dir.c
@@ -237,7 +237,8 @@ tdirenter(
struct tmpnode *tp, /* source tmpnode, if link/rename */
struct vattr *va,
struct tmpnode **tpp, /* return tmpnode, if create/mkdir */
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ctp)
{
struct tdirent *tdp;
struct tmpnode *found = NULL;
@@ -346,7 +347,7 @@ tdirenter(
if (error == 0) {
if (found != NULL) {
vnevent_rename_dest(TNTOV(found),
- TNTOV(dir), name);
+ TNTOV(dir), name, ctp);
}
}
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
index f798cb8ed4..4ee833094f 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
@@ -338,7 +338,7 @@ tmp_mount(
* Get the mode, uid, and gid from the underlying mount point.
*/
rattr.va_mask = AT_MODE|AT_UID|AT_GID; /* Hint to getattr */
- got_attrs = VOP_GETATTR(mvp, &rattr, 0, cr);
+ got_attrs = VOP_GETATTR(mvp, &rattr, 0, cr, NULL);
rw_enter(&tp->tn_rwlock, RW_WRITER);
TNTOV(tp)->v_flag |= VROOT;
@@ -371,6 +371,9 @@ tmp_mount(
error = 0;
out:
+ if (error == 0)
+ vfs_set_feature(vfsp, VFSFT_XVATTR);
+
return (error);
}
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
index c2d921bba9..7be9c2bdda 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
@@ -73,7 +73,7 @@ static int tmp_putapage(struct vnode *, page_t *, u_offset_t *, size_t *,
/* ARGSUSED1 */
static int
-tmp_open(struct vnode **vpp, int flag, struct cred *cred)
+tmp_open(struct vnode **vpp, int flag, struct cred *cred, caller_context_t *ct)
{
/*
* swapon to a tmpfs file is not supported so access
@@ -86,8 +86,13 @@ tmp_open(struct vnode **vpp, int flag, struct cred *cred)
/* ARGSUSED1 */
static int
-tmp_close(struct vnode *vp, int flag, int count,
- offset_t offset, struct cred *cred)
+tmp_close(
+ struct vnode *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ struct cred *cred,
+ caller_context_t *ct)
{
cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
cleanshares(vp, ttoproc(curthread)->p_pid);
@@ -269,7 +274,7 @@ wrtmp(
/*
* We have to drop the contents lock to allow the VM
- * system to reaquire it in tmp_getpage()
+ * system to reacquire it in tmp_getpage()
*/
rw_exit(&tp->tn_contents);
@@ -496,7 +501,7 @@ rdtmp(
/*
* We have to drop the contents lock to prevent the VM
- * system from trying to reaquire it in tmp_getpage()
+ * system from trying to reacquire it in tmp_getpage()
* should the uiomove cause a pagefault.
*/
rw_exit(&tp->tn_contents);
@@ -621,15 +626,26 @@ tmp_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cred,
/* ARGSUSED */
static int
-tmp_ioctl(struct vnode *vp, int com, intptr_t data, int flag,
- struct cred *cred, int *rvalp)
+tmp_ioctl(
+ struct vnode *vp,
+ int com,
+ intptr_t data,
+ int flag,
+ struct cred *cred,
+ int *rvalp,
+ caller_context_t *ct)
{
return (ENOTTY);
}
/* ARGSUSED2 */
static int
-tmp_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cred)
+tmp_getattr(
+ struct vnode *vp,
+ struct vattr *vap,
+ int flags,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
struct vnode *mvp;
@@ -651,7 +667,7 @@ tmp_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cred)
mutex_exit(&tp->tn_tlock);
bzero(&va, sizeof (struct vattr));
va.va_mask = AT_UID|AT_GID;
- attrs = VOP_GETATTR(mvp, &va, 0, cred);
+ attrs = VOP_GETATTR(mvp, &va, 0, cred, ct);
} else {
mutex_exit(&tp->tn_tlock);
}
@@ -703,7 +719,7 @@ tmp_setattr(
/*
* Cannot set these attributes
*/
- if (vap->va_mask & AT_NOSET)
+ if ((vap->va_mask & AT_NOSET) || (vap->va_mask & AT_XVATTR))
return (EINVAL);
mutex_enter(&tp->tn_tlock);
@@ -763,7 +779,12 @@ out1:
/* ARGSUSED2 */
static int
-tmp_access(struct vnode *vp, int mode, int flags, struct cred *cred)
+tmp_access(
+ struct vnode *vp,
+ int mode,
+ int flags,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
int error;
@@ -783,7 +804,10 @@ tmp_lookup(
struct pathname *pnp,
int flags,
struct vnode *rdir,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(dvp);
struct tmpnode *ntp = NULL;
@@ -795,6 +819,12 @@ tmp_lookup(
struct tmpnode *xdp;
struct tmount *tm;
+ /*
+ * don't allow attributes if not mounted XATTR support
+ */
+ if (!(dvp->v_vfsp->vfs_flag & VFS_XATTR))
+ return (EINVAL);
+
if (tp->tn_flags & ISXATTR)
/* No attributes on attributes */
return (EINVAL);
@@ -894,7 +924,9 @@ tmp_create(
int mode,
struct vnode **vpp,
struct cred *cred,
- int flag)
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
struct tmpnode *parent;
struct tmount *tm;
@@ -977,7 +1009,7 @@ again:
}
if (error == 0) {
- vnevent_create(*vpp);
+ vnevent_create(*vpp, ct);
}
return (0);
}
@@ -988,7 +1020,7 @@ again:
rw_enter(&parent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, parent, nm, DE_CREATE,
(struct tmpnode *)NULL, (struct tmpnode *)NULL,
- vap, &self, cred);
+ vap, &self, cred, ct);
rw_exit(&parent->tn_rwlock);
if (error) {
@@ -1026,8 +1058,14 @@ again:
return (0);
}
+/* ARGSUSED3 */
static int
-tmp_remove(struct vnode *dvp, char *nm, struct cred *cred)
+tmp_remove(
+ struct vnode *dvp,
+ char *nm,
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
int error;
@@ -1047,7 +1085,7 @@ tmp_remove(struct vnode *dvp, char *nm, struct cred *cred)
rw_exit(&tp->tn_rwlock);
rw_exit(&parent->tn_rwlock);
- vnevent_remove(TNTOV(tp), dvp, nm);
+ vnevent_remove(TNTOV(tp), dvp, nm, ct);
tmpnode_rele(tp);
TRACE_3(TR_FAC_TMPFS, TR_TMPFS_REMOVE,
@@ -1055,8 +1093,15 @@ tmp_remove(struct vnode *dvp, char *nm, struct cred *cred)
return (error);
}
+/* ARGSUSED4 */
static int
-tmp_link(struct vnode *dvp, struct vnode *srcvp, char *tnm, struct cred *cred)
+tmp_link(
+ struct vnode *dvp,
+ struct vnode *srcvp,
+ char *tnm,
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *parent;
struct tmpnode *from;
@@ -1065,7 +1110,7 @@ tmp_link(struct vnode *dvp, struct vnode *srcvp, char *tnm, struct cred *cred)
struct tmpnode *found = NULL;
struct vnode *realvp;
- if (VOP_REALVP(srcvp, &realvp) == 0)
+ if (VOP_REALVP(srcvp, &realvp, ct) == 0)
srcvp = realvp;
parent = (struct tmpnode *)VTOTN(dvp);
@@ -1095,21 +1140,24 @@ tmp_link(struct vnode *dvp, struct vnode *srcvp, char *tnm, struct cred *cred)
rw_enter(&parent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, parent, tnm, DE_LINK, (struct tmpnode *)NULL,
- from, NULL, (struct tmpnode **)NULL, cred);
+ from, NULL, (struct tmpnode **)NULL, cred, ct);
rw_exit(&parent->tn_rwlock);
if (error == 0) {
- vnevent_link(srcvp);
+ vnevent_link(srcvp, ct);
}
return (error);
}
+/* ARGSUSED5 */
static int
tmp_rename(
struct vnode *odvp, /* source parent vnode */
char *onm, /* source name */
struct vnode *ndvp, /* destination parent vnode */
char *nnm, /* destination name */
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *fromparent;
struct tmpnode *toparent;
@@ -1119,7 +1167,7 @@ tmp_rename(
int samedir = 0; /* set if odvp == ndvp */
struct vnode *realvp;
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
fromparent = (struct tmpnode *)VTOTN(odvp);
@@ -1178,7 +1226,7 @@ tmp_rename(
rw_enter(&toparent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, toparent, nnm, DE_RENAME,
fromparent, fromtp, (struct vattr *)NULL,
- (struct tmpnode **)NULL, cred);
+ (struct tmpnode **)NULL, cred, ct);
rw_exit(&toparent->tn_rwlock);
if (error) {
@@ -1191,14 +1239,14 @@ tmp_rename(
error = 0;
goto done;
}
- vnevent_rename_src(TNTOV(fromtp), odvp, onm);
+ vnevent_rename_src(TNTOV(fromtp), odvp, onm, ct);
/*
* Notify the target directory if not same as
* source directory.
*/
if (ndvp != odvp) {
- vnevent_rename_dest_dir(ndvp);
+ vnevent_rename_dest_dir(ndvp, ct);
}
/*
@@ -1232,13 +1280,17 @@ done:
return (error);
}
+/* ARGSUSED5 */
static int
tmp_mkdir(
struct vnode *dvp,
char *nm,
struct vattr *va,
struct vnode **vpp,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
struct tmpnode *self = NULL;
@@ -1269,7 +1321,7 @@ tmp_mkdir(
rw_enter(&parent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, parent, nm, DE_MKDIR,
(struct tmpnode *)NULL, (struct tmpnode *)NULL, va,
- &self, cred);
+ &self, cred, ct);
if (error) {
rw_exit(&parent->tn_rwlock);
if (self)
@@ -1281,12 +1333,15 @@ tmp_mkdir(
return (0);
}
+/* ARGSUSED4 */
static int
tmp_rmdir(
struct vnode *dvp,
char *nm,
struct vnode *cdir,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
struct tmpnode *self = NULL;
@@ -1354,16 +1409,21 @@ done:
done1:
rw_exit(&self->tn_rwlock);
rw_exit(&parent->tn_rwlock);
- vnevent_rmdir(TNTOV(self), dvp, nm);
+ vnevent_rmdir(TNTOV(self), dvp, nm, ct);
tmpnode_rele(self);
return (error);
}
/* ARGSUSED2 */
-
static int
-tmp_readdir(struct vnode *vp, struct uio *uiop, struct cred *cred, int *eofp)
+tmp_readdir(
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cred,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
struct tdirent *tdp;
@@ -1467,13 +1527,16 @@ tmp_readdir(struct vnode *vp, struct uio *uiop, struct cred *cred, int *eofp)
return (error);
}
+/* ARGSUSED5 */
static int
tmp_symlink(
struct vnode *dvp,
char *lnm,
struct vattr *tva,
char *tnm,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
struct tmpnode *self = (struct tmpnode *)NULL;
@@ -1503,7 +1566,7 @@ tmp_symlink(
rw_enter(&parent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, parent, lnm, DE_CREATE, (struct tmpnode *)NULL,
- (struct tmpnode *)NULL, tva, &self, cred);
+ (struct tmpnode *)NULL, tva, &self, cred, ct);
rw_exit(&parent->tn_rwlock);
if (error) {
@@ -1527,7 +1590,11 @@ tmp_symlink(
/* ARGSUSED2 */
static int
-tmp_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
+tmp_readlink(
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
int error = 0;
@@ -1546,14 +1613,18 @@ tmp_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
/* ARGSUSED */
static int
-tmp_fsync(struct vnode *vp, int syncflag, struct cred *cred)
+tmp_fsync(
+ struct vnode *vp,
+ int syncflag,
+ struct cred *cred,
+ caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static void
-tmp_inactive(struct vnode *vp, struct cred *cred)
+tmp_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
struct tmount *tm = (struct tmount *)VFSTOTM(vp->v_vfsp);
@@ -1634,8 +1705,9 @@ top:
tmp_memfree(tp, sizeof (struct tmpnode));
}
+/* ARGSUSED2 */
static int
-tmp_fid(struct vnode *vp, struct fid *fidp)
+tmp_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
struct tfid *tfid;
@@ -1659,6 +1731,7 @@ tmp_fid(struct vnode *vp, struct fid *fidp)
/*
* Return all the pages from [off..off+len] in given file
*/
+/* ARGSUSED */
static int
tmp_getpage(
struct vnode *vp,
@@ -1670,7 +1743,8 @@ tmp_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
int err = 0;
struct tmpnode *tp = VTOTN(vp);
@@ -1788,7 +1862,7 @@ again:
if (pvp) {
flags = (pl == NULL ? B_ASYNC|B_READ : B_READ);
err = VOP_PAGEIO(pvp, pp, (u_offset_t)poff, PAGESIZE,
- flags, cr);
+ flags, cr, NULL);
if (flags & B_ASYNC)
pp = NULL;
} else if (rw != S_CREATE) {
@@ -1820,7 +1894,8 @@ tmp_putpage(
offset_t off,
size_t len,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
register page_t *pp;
u_offset_t io_off;
@@ -2037,7 +2112,7 @@ tmp_putapage(
/* Do i/o on the remaining kluster */
err = VOP_PAGEIO(pvp, pplist, (u_offset_t)pstart, io_len,
- B_WRITE | flags, cr);
+ B_WRITE | flags, cr, NULL);
if ((flags & B_ASYNC) == 0) {
pvn_write_done(pplist, ((err) ? B_ERROR : 0) | B_WRITE | flags);
@@ -2056,6 +2131,7 @@ out:
return (err);
}
+/* ARGSUSED */
static int
tmp_map(
struct vnode *vp,
@@ -2066,7 +2142,8 @@ tmp_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
@@ -2139,7 +2216,8 @@ tmp_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
return (0);
}
@@ -2155,7 +2233,8 @@ tmp_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
return (0);
}
@@ -2243,7 +2322,11 @@ tmp_space(
/* ARGSUSED */
static int
-tmp_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+tmp_seek(
+ struct vnode *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
@@ -2272,7 +2355,12 @@ tmp_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
}
static int
-tmp_pathconf(struct vnode *vp, int cmd, ulong_t *valp, cred_t *cr)
+tmp_pathconf(
+ struct vnode *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
{
struct tmpnode *tp = NULL;
int error;
@@ -2296,8 +2384,14 @@ tmp_pathconf(struct vnode *vp, int cmd, ulong_t *valp, cred_t *cr)
error = EINVAL;
}
break;
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ *valp = vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) &&
+ (vp->v_type == VREG || vp->v_type == VDIR);
+ error = 0;
+ break;
default:
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
return (error);
}
diff --git a/usr/src/uts/common/fs/udfs/udf_dir.c b/usr/src/uts/common/fs/udfs/udf_dir.c
index d470a2588a..40b0a7d4aa 100644
--- a/usr/src/uts/common/fs/udfs/udf_dir.c
+++ b/usr/src/uts/common/fs/udfs/udf_dir.c
@@ -327,9 +327,16 @@ done:
}
int
-ud_direnter(struct ud_inode *tdp,
- char *namep, enum de_op op, struct ud_inode *sdp, struct ud_inode *sip,
- struct vattr *vap, struct ud_inode **ipp, struct cred *cr)
+ud_direnter(
+ struct ud_inode *tdp,
+ char *namep,
+ enum de_op op,
+ struct ud_inode *sdp,
+ struct ud_inode *sip,
+ struct vattr *vap,
+ struct ud_inode **ipp,
+ struct cred *cr,
+ caller_context_t *ctp)
{
struct udf_vfs *udf_vfsp;
struct ud_inode *tip;
@@ -556,11 +563,11 @@ out:
if (err == 0) {
if (tip) {
vnevent_rename_dest(ITOV(tip), ITOV(tdp),
- namep);
+ namep, ctp);
}
if (sdp != tdp) {
- vnevent_rename_dest_dir(ITOV(tdp));
+ vnevent_rename_dest_dir(ITOV(tdp), ctp);
}
}
@@ -594,9 +601,14 @@ out2:
* function seems to be really weird
*/
int
-ud_dirremove(struct ud_inode *dp,
- char *namep, struct ud_inode *oip, struct vnode *cdir,
- enum dr_op op, struct cred *cr)
+ud_dirremove(
+ struct ud_inode *dp,
+ char *namep,
+ struct ud_inode *oip,
+ struct vnode *cdir,
+ enum dr_op op,
+ struct cred *cr,
+ caller_context_t *ctp)
{
struct udf_vfs *udf_vfsp;
int32_t namelen, err = 0;
@@ -852,9 +864,9 @@ out_novfs:
*/
if (err == 0) {
if (op == DR_REMOVE) {
- vnevent_remove(ITOV(ip), ITOV(dp), namep);
+ vnevent_remove(ITOV(ip), ITOV(dp), namep, ctp);
} else if (op == DR_RMDIR) {
- vnevent_rmdir(ITOV(ip), ITOV(dp), namep);
+ vnevent_rmdir(ITOV(ip), ITOV(dp), namep, ctp);
}
}
VN_RELE(ITOV(ip));
diff --git a/usr/src/uts/common/fs/udfs/udf_subr.c b/usr/src/uts/common/fs/udfs/udf_subr.c
index b8ab49457f..dd06e0d884 100644
--- a/usr/src/uts/common/fs/udfs/udf_subr.c
+++ b/usr/src/uts/common/fs/udfs/udf_subr.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -223,7 +222,7 @@ ud_xlate_to_daddr(struct udf_vfs *udf_vfsp,
continue;
}
if ((end_req < begin_bad) ||
- (begin_req >= end_bad)) {
+ (begin_req >= end_bad)) {
continue;
}
@@ -232,7 +231,7 @@ ud_xlate_to_daddr(struct udf_vfs *udf_vfsp,
end_req = begin_bad;
} else {
retblkno = SWAP_32(te->sent_ml) +
- begin_req - begin_bad;
+ begin_req - begin_bad;
if (end_req < end_bad) {
*count = end_req - begin_req;
} else {
@@ -319,10 +318,10 @@ ud_ip_off2bno(struct ud_inode *ip, uint32_t offset, uint32_t *bno)
for (i = 0; i < ip->i_ext_used; i++) {
iext = &ip->i_ext[i];
if ((iext->ib_offset <= offset) &&
- (offset < (iext->ib_offset + iext->ib_count))) {
+ (offset < (iext->ib_offset + iext->ib_count))) {
*bno = iext->ib_block +
- ((offset - iext->ib_offset) >>
- ip->i_udf->udf_l2b_shift);
+ ((offset - iext->ib_offset) >>
+ ip->i_udf->udf_l2b_shift);
break;
}
}
@@ -338,8 +337,6 @@ static uint32_t cum_sec_leap[] = {
0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680
};
-#define SECS_PER_MIN 60
-#define SECS_PER_HOUR 3600
#define DAYS_PER_YEAR 365
#define SEC_PER_DAY 0x15180
@@ -363,8 +360,8 @@ ud_dtime2utime(struct timespec32 *utime,
utime->tv_sec = cp[dtime->ts_month - 1];
utime->tv_sec += (dtime->ts_day - 1) * SEC_PER_DAY;
utime->tv_sec += ((dtime->ts_hour * 60) +
- dtime->ts_min) * 60 +
- dtime->ts_sec;
+ dtime->ts_min) * 60 +
+ dtime->ts_sec;
tzone = SWAP_16(dtime->ts_tzone);
if ((tzone & TMODE) == 0x1000) {
@@ -384,15 +381,15 @@ ud_dtime2utime(struct timespec32 *utime,
}
utime->tv_nsec = ((((dtime->ts_csec * 100) +
- dtime->ts_husec) * 100) +
- dtime->ts_usec) * 1000;
+ dtime->ts_husec) * 100) +
+ dtime->ts_usec) * 1000;
if (year >= 1970) {
utime->tv_sec += (year - 1970) * SEC_PER_YEAR;
utime->tv_sec += ((year - 1969) / 4) * SEC_PER_DAY;
} else {
utime->tv_sec = ((1970 - year) * SEC_PER_YEAR +
- ((1972 - year) / 4) * SEC_PER_DAY -
- utime->tv_sec) * -1;
+ ((1972 - year) / 4) * SEC_PER_DAY -
+ utime->tv_sec) * -1;
if (utime->tv_nsec) {
utime->tv_sec++;
utime->tv_nsec = 1000 * 1000 * 1000 - utime->tv_nsec;
@@ -498,7 +495,7 @@ ud_syncip(struct ud_inode *ip, int32_t flags, int32_t waitfor)
} else {
rw_exit(&ip->i_contents);
error = VOP_PUTPAGE(vp, (offset_t)0,
- (uint32_t)0, flags, CRED());
+ (uint32_t)0, flags, CRED(), NULL);
rw_enter(&ip->i_contents, RW_WRITER);
}
@@ -561,10 +558,10 @@ ud_sbwrite(struct udf_vfs *udf_vfsp)
ud_update_regid(&iu->lvidiu_regid);
ud_make_tag(udf_vfsp, &lvid->lvid_tag,
- UD_LOG_VOL_INT, udf_vfsp->udf_iseq_loc,
- sizeof (struct log_vol_int_desc) - 8 +
- 8 * udf_vfsp->udf_npart +
- SWAP_32(lvid->lvid_liu));
+ UD_LOG_VOL_INT, udf_vfsp->udf_iseq_loc,
+ sizeof (struct log_vol_int_desc) - 8 +
+ 8 * udf_vfsp->udf_npart +
+ SWAP_32(lvid->lvid_liu));
/*
* Don't release the buffer after writing to the disk
@@ -627,7 +624,7 @@ ud_update(int32_t flag)
*/
mutex_enter(&udf_vfs_mutex);
for (udfsp = udf_vfs_instances;
- udfsp != NULL; udfsp = udfsp->udf_next) {
+ udfsp != NULL; udfsp = udfsp->udf_next) {
vfsp = udfsp->udf_vfs;
if (vfs_lock(vfsp) != 0) {
continue;
@@ -762,7 +759,7 @@ ud_still_mounted(struct check_node *checkp)
mutex_enter(&udf_vfs_mutex);
for (udf_vfsp = udf_vfs_instances;
- udf_vfsp != NULL; udf_vfsp = udf_vfsp->udf_next) {
+ udf_vfsp != NULL; udf_vfsp = udf_vfsp->udf_next) {
if (udf_vfsp != checkp->udf_vfs) {
continue;
}
@@ -802,7 +799,7 @@ ud_checkclean(struct vfs *vfsp,
* ignore if buffers or inodes are busy
*/
if ((bcheck(dev, udf_vfsp->udf_iseq)) ||
- (ud_icheck(udf_vfsp))) {
+ (ud_icheck(udf_vfsp))) {
return;
}
mutex_enter(&udf_vfsp->udf_lock);
@@ -856,8 +853,8 @@ ud_flushi(int32_t flag)
lip = NULL;
for (ip = ih->ih_chain[0], lip = NULL;
- ip && ip != (struct ud_inode *)ih;
- ip = ip->i_forw) {
+ ip && ip != (struct ud_inode *)ih;
+ ip = ip->i_forw) {
int flag = ip->i_flag;
vp = ITOV(ip);
@@ -867,9 +864,9 @@ ud_flushi(int32_t flag)
* Skip read-only vnodes
*/
if ((flag & IREF) == 0 ||
- (!vn_has_cached_data(vp) &&
- ((flag & (IMOD|IACC|IUPD|ICHG)) == 0)) ||
- (vp->v_vfsp == NULL) || vn_is_readonly(vp)) {
+ (!vn_has_cached_data(vp) &&
+ ((flag & (IMOD|IACC|IUPD|ICHG)) == 0)) ||
+ (vp->v_vfsp == NULL) || vn_is_readonly(vp)) {
continue;
}
@@ -1010,7 +1007,7 @@ ud_get_next_fid(struct ud_inode *ip, struct fbuf **fbp, uint32_t offset,
if ((offset % lbsize) ||
- (offset == 0)) {
+ (offset == 0)) {
sz = end - beg;
} else {
sz = 0;
@@ -1276,14 +1273,14 @@ ud_verify_tag_and_desc(struct tag *tag, uint16_t id, uint32_t blockno,
eah = (struct ext_attr_hdr *)tag;
if (SWAP_32(eah->eah_aal) > desc_len) {
cmn_err(CE_NOTE,
- "eah_all(0x%x) exceeds desc. len(0x%x) blockno 0x%x\n",
+ "eah_all(0x%x) exceeds desc. len(0x%x) blockno 0x%x\n",
SWAP_32(eah->eah_aal), desc_len, blockno);
- return (1);
+ return (1);
}
ea_off = GET_32(&eah->eah_ial);
if (ea_off >= desc_len) {
cmn_err(CE_NOTE,
- "ea_off(0x%x) is not less than ea_len(0x%x) blockno 0x%x\n",
+ "ea_off(0x%x) is not less than ea_len(0x%x) blockno 0x%x\n",
ea_off, desc_len, blockno);
return (1);
}
@@ -1293,8 +1290,8 @@ ud_verify_tag_and_desc(struct tag *tag, uint16_t id, uint32_t blockno,
}
if (SWAP_32(blockno) != tag->tag_loc) {
cmn_err(CE_NOTE,
- "Tag Location mismatch blockno %x tag_blockno %x\n",
- blockno, SWAP_32(tag->tag_loc));
+ "Tag Location mismatch blockno %x tag_blockno %x\n",
+ blockno, SWAP_32(tag->tag_loc));
return (1);
}
return (0);
@@ -1455,41 +1452,41 @@ ud_utf82utf16(uint8_t *s_8, uint16_t *c_16, int32_t count)
c_32 = *s_8 & 0x7F;
} else if (extra_bytes == 1) {
if (((*s_8 & 0xE0) != 0xC0) ||
- ((*(s_8 + 1) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x1F;
} else if (extra_bytes == 2) {
if (((*s_8 & 0xF0) != 0xE0) ||
- ((*(s_8 + 1) & 0xC0) != 0x80) ||
- ((*(s_8 + 2) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80) ||
+ ((*(s_8 + 2) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x0F;
} else if (extra_bytes == 3) {
if (((*s_8 & 0xF8) != 0xF0) ||
- ((*(s_8 + 1) & 0xC0) != 0x80) ||
- ((*(s_8 + 2) & 0xC0) != 0x80) ||
- ((*(s_8 + 3) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80) ||
+ ((*(s_8 + 2) & 0xC0) != 0x80) ||
+ ((*(s_8 + 3) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x07;
} else if (extra_bytes == 4) {
if (((*s_8 & 0xFC) != 0xF8) ||
- ((*(s_8 + 1) & 0xC0) != 0x80) ||
- ((*(s_8 + 2) & 0xC0) != 0x80) ||
- ((*(s_8 + 3) & 0xC0) != 0x80) ||
- ((*(s_8 + 4) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80) ||
+ ((*(s_8 + 2) & 0xC0) != 0x80) ||
+ ((*(s_8 + 3) & 0xC0) != 0x80) ||
+ ((*(s_8 + 4) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x03;
} else if (extra_bytes == 5) {
if (((*s_8 & 0xFE) != 0xFC) ||
- ((*(s_8 + 1) & 0xC0) != 0x80) ||
- ((*(s_8 + 2) & 0xC0) != 0x80) ||
- ((*(s_8 + 3) & 0xC0) != 0x80) ||
- ((*(s_8 + 4) & 0xC0) != 0x80) ||
- ((*(s_8 + 5) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80) ||
+ ((*(s_8 + 2) & 0xC0) != 0x80) ||
+ ((*(s_8 + 3) & 0xC0) != 0x80) ||
+ ((*(s_8 + 4) & 0xC0) != 0x80) ||
+ ((*(s_8 + 5) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x01;
@@ -1560,7 +1557,7 @@ ud_compress(int32_t in_len, int32_t *out_len,
comp_id = 8;
for (in_index = 0; in_index < in_len; in_index += c_tx_sz) {
if ((c_tx_sz = ud_utf82utf16(&in_str[in_index],
- &w2_char, in_len - in_index)) == 0) {
+ &w2_char, in_len - in_index)) == 0) {
error = EINVAL;
goto end;
}
@@ -1576,7 +1573,7 @@ ud_compress(int32_t in_len, int32_t *out_len,
w2_str[out_index++] = w2_char;
}
if (((comp_id == 0x10) && (out_index > ((out_str_len - 2)/2))) ||
- ((comp_id == 0x8) && (out_index > (out_str_len - 2)))) {
+ ((comp_id == 0x8) && (out_index > (out_str_len - 2)))) {
error = ENAMETOOLONG;
goto end;
}
@@ -1669,9 +1666,9 @@ ud_utf162utf8(uint16_t c_16, uint8_t *s_8)
}
/*
- * Convert to a form that can be transfered to the user
+ * Convert to a form that can be transferred to the user
* Assumption's
- * in_length < 256, out_str is atleast 255 bytes long
+ * in_length < 256, out_str is at least 255 bytes long
* The converted byte stream length is returned in out_len
*/
#define MAX_ALLOWABLE_STRING 250
@@ -1703,16 +1700,16 @@ ud_uncompress(int32_t in_len, int32_t *out_len,
*/
if (comp_id == 8) {
if ((in_str[1] == DOT) &&
- ((in_len == 2) || ((in_len == 3) &&
- (in_str[2] == DOT)))) {
+ ((in_len == 2) || ((in_len == 3) &&
+ (in_str[2] == DOT)))) {
out_str[k++] = UNDERBAR;
len_till_now = 1;
goto make_append_crc;
}
} else if (comp_id == 0x10) {
if (((in_str[1] << 8 | in_str[2]) == DOT) &&
- ((in_len == 3) || ((in_len == 5) &&
- ((in_str[3] << 8 | in_str[4]) == DOT)))) {
+ ((in_len == 3) || ((in_len == 5) &&
+ ((in_str[3] << 8 | in_str[4]) == DOT)))) {
out_str[k++] = UNDERBAR;
len_till_now = 1;
goto make_append_crc;
@@ -1746,12 +1743,12 @@ ud_uncompress(int32_t in_len, int32_t *out_len,
* Get rid of invalid characters
*/
if ((w2_char == SLASH) ||
- (w2_char == NULL)) {
+ (w2_char == NULL)) {
make_crc = 1;
if (((comp_id == 8) &&
- (lic != (index - 1))) ||
- (comp_id == 0x10) &&
- (lic != (index - 2))) {
+ (lic != (index - 1))) ||
+ (comp_id == 0x10) &&
+ (lic != (index - 2))) {
w2_char = UNDERBAR;
lic = index;
} else {
@@ -1776,13 +1773,13 @@ ud_uncompress(int32_t in_len, int32_t *out_len,
* the maximum allowed string length
*/
if ((crc_start_loc == 0) &&
- ((len_till_now + c_tx_sz) > MAX_ALLOWABLE_STRING)) {
+ ((len_till_now + c_tx_sz) > MAX_ALLOWABLE_STRING)) {
crc_start_loc = len_till_now;
}
if ((len_till_now + c_tx_sz) < MAXNAMELEN) {
(void) strncpy((caddr_t)&out_str[len_till_now],
- (caddr_t)utf8, c_tx_sz);
+ (caddr_t)utf8, c_tx_sz);
len_till_now += c_tx_sz;
} else {
break;
@@ -1835,7 +1832,7 @@ begin:
bp = bread(dev, blkno, bsize);
if (((bp->b_flags & B_ERROR) == 0) &&
- (bp->b_bcount != bsize)) {
+ (bp->b_bcount != bsize)) {
/*
* Buffer cache returned a
* wrong number of bytes
diff --git a/usr/src/uts/common/fs/udfs/udf_vfsops.c b/usr/src/uts/common/fs/udfs/udf_vfsops.c
index 79e76d2715..95f98d6229 100644
--- a/usr/src/uts/common/fs/udfs/udf_vfsops.c
+++ b/usr/src/uts/common/fs/udfs/udf_vfsops.c
@@ -282,7 +282,7 @@ udf_mount(struct vfs *vfsp, struct vnode *mvp,
oflag = FREAD | FWRITE;
aflag = VREAD | VWRITE;
}
- if ((error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 ||
+ if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
(error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
goto out;
}
@@ -365,8 +365,8 @@ udf_unmount(struct vfs *vfsp, int fflag, struct cred *cr)
ud_destroy_fsp(udf_vfsp);
- (void) VOP_PUTPAGE(bvp, (offset_t)0, (uint32_t)0, B_INVAL, cr);
- (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr);
+ (void) VOP_PUTPAGE(bvp, (offset_t)0, (uint32_t)0, B_INVAL, cr, NULL);
+ (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr, NULL);
(void) bfinval(vfsp->vfs_dev, 1);
VN_RELE(bvp);
@@ -555,7 +555,7 @@ udf_mountroot(struct vfs *vfsp, enum whymountroot why)
(void) dnlc_purge_vfsp(vfsp, 0);
vp = common_specvp(vp);
(void) VOP_PUTPAGE(vp, (offset_t)0,
- (uint32_t)0, B_INVAL, CRED());
+ (uint32_t)0, B_INVAL, CRED(), NULL);
binval(vfsp->vfs_dev);
ovflags = vfsp->vfs_flag;
@@ -566,7 +566,7 @@ udf_mountroot(struct vfs *vfsp, enum whymountroot why)
ud_update(0);
vp = ((struct udf_vfs *)vfsp->vfs_data)->udf_devvp;
(void) VOP_CLOSE(vp, FREAD|FWRITE, 1,
- (offset_t)0, CRED());
+ (offset_t)0, CRED(), NULL);
return (0);
}
@@ -630,7 +630,8 @@ ud_mountfs(struct vfs *vfsp,
* operations.
*/
error = VOP_OPEN(&devvp,
- (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, cr);
+ (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE,
+ cr, NULL);
if (error) {
goto out;
}
@@ -677,7 +678,7 @@ ud_mountfs(struct vfs *vfsp,
if (udf_vfsp->udf_flags & UDF_FL_RDONLY) {
(void) dnlc_purge_vfsp(vfsp, 0);
(void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0,
- B_INVAL, CRED());
+ B_INVAL, CRED(), NULL);
(void) ud_iflush(vfsp);
bflush(dev);
binval(dev);
@@ -769,7 +770,7 @@ remountout:
* they really should be using the raw device.
*/
(void) VOP_PUTPAGE(common_specvp(devvp), (offset_t)0,
- (uint32_t)0, B_INVAL, cr);
+ (uint32_t)0, B_INVAL, cr, NULL);
/*
@@ -936,7 +937,7 @@ out:
ud_destroy_fsp(udf_vfsp);
if (needclose) {
(void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ?
- FREAD : FREAD|FWRITE, 1, (offset_t)0, cr);
+ FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
bflush(dev);
binval(dev);
}
diff --git a/usr/src/uts/common/fs/udfs/udf_vnops.c b/usr/src/uts/common/fs/udfs/udf_vnops.c
index defbd544f5..2a2822eb3f 100644
--- a/usr/src/uts/common/fs/udfs/udf_vnops.c
+++ b/usr/src/uts/common/fs/udfs/udf_vnops.c
@@ -84,70 +84,79 @@
#include <sys/fs/udf_inode.h>
static int32_t udf_open(struct vnode **,
- int32_t, struct cred *);
+ int32_t, struct cred *, caller_context_t *);
static int32_t udf_close(struct vnode *,
- int32_t, int32_t, offset_t, struct cred *);
+ int32_t, int32_t, offset_t, struct cred *, caller_context_t *);
static int32_t udf_read(struct vnode *,
- struct uio *, int32_t, struct cred *, struct caller_context *);
+ struct uio *, int32_t, struct cred *, caller_context_t *);
static int32_t udf_write(struct vnode *,
- struct uio *, int32_t, struct cred *, struct caller_context *);
+ struct uio *, int32_t, struct cred *, caller_context_t *);
static int32_t udf_ioctl(struct vnode *,
- int32_t, intptr_t, int32_t, struct cred *, int32_t *);
+ int32_t, intptr_t, int32_t, struct cred *, int32_t *,
+ caller_context_t *);
static int32_t udf_getattr(struct vnode *,
- struct vattr *, int32_t, struct cred *);
+ struct vattr *, int32_t, struct cred *, caller_context_t *);
static int32_t udf_setattr(struct vnode *,
struct vattr *, int32_t, struct cred *, caller_context_t *);
static int32_t udf_access(struct vnode *,
- int32_t, int32_t, struct cred *);
+ int32_t, int32_t, struct cred *, caller_context_t *);
static int32_t udf_lookup(struct vnode *,
char *, struct vnode **, struct pathname *,
- int32_t, struct vnode *, struct cred *);
+ int32_t, struct vnode *, struct cred *,
+ caller_context_t *, int *, pathname_t *);
static int32_t udf_create(struct vnode *,
char *, struct vattr *, enum vcexcl,
- int32_t, struct vnode **, struct cred *, int32_t);
+ int32_t, struct vnode **, struct cred *, int32_t,
+ caller_context_t *, vsecattr_t *);
static int32_t udf_remove(struct vnode *,
- char *, struct cred *);
+ char *, struct cred *, caller_context_t *, int);
static int32_t udf_link(struct vnode *,
- struct vnode *, char *, struct cred *);
+ struct vnode *, char *, struct cred *, caller_context_t *, int);
static int32_t udf_rename(struct vnode *,
- char *, struct vnode *, char *, struct cred *);
+ char *, struct vnode *, char *, struct cred *, caller_context_t *, int);
static int32_t udf_mkdir(struct vnode *,
- char *, struct vattr *, struct vnode **, struct cred *);
+ char *, struct vattr *, struct vnode **, struct cred *,
+ caller_context_t *, int, vsecattr_t *);
static int32_t udf_rmdir(struct vnode *,
- char *, struct vnode *, struct cred *);
+ char *, struct vnode *, struct cred *, caller_context_t *, int);
static int32_t udf_readdir(struct vnode *,
- struct uio *, struct cred *, int32_t *);
+ struct uio *, struct cred *, int32_t *, caller_context_t *, int);
static int32_t udf_symlink(struct vnode *,
- char *, struct vattr *, char *, struct cred *);
+ char *, struct vattr *, char *, struct cred *, caller_context_t *, int);
static int32_t udf_readlink(struct vnode *,
- struct uio *, struct cred *);
+ struct uio *, struct cred *, caller_context_t *);
static int32_t udf_fsync(struct vnode *,
- int32_t, struct cred *);
+ int32_t, struct cred *, caller_context_t *);
static void udf_inactive(struct vnode *,
- struct cred *);
-static int32_t udf_fid(struct vnode *, struct fid *);
+ struct cred *, caller_context_t *);
+static int32_t udf_fid(struct vnode *, struct fid *, caller_context_t *);
static int udf_rwlock(struct vnode *, int32_t, caller_context_t *);
static void udf_rwunlock(struct vnode *, int32_t, caller_context_t *);
-static int32_t udf_seek(struct vnode *, offset_t, offset_t *);
+static int32_t udf_seek(struct vnode *, offset_t, offset_t *,
+ caller_context_t *);
static int32_t udf_frlock(struct vnode *, int32_t,
- struct flock64 *, int32_t, offset_t, struct flk_callback *, cred_t *);
+ struct flock64 *, int32_t, offset_t, struct flk_callback *, cred_t *,
+ caller_context_t *);
static int32_t udf_space(struct vnode *, int32_t,
struct flock64 *, int32_t, offset_t, cred_t *, caller_context_t *);
static int32_t udf_getpage(struct vnode *, offset_t,
size_t, uint32_t *, struct page **, size_t,
- struct seg *, caddr_t, enum seg_rw, struct cred *);
+ struct seg *, caddr_t, enum seg_rw, struct cred *, caller_context_t *);
static int32_t udf_putpage(struct vnode *, offset_t,
- size_t, int32_t, struct cred *);
+ size_t, int32_t, struct cred *, caller_context_t *);
static int32_t udf_map(struct vnode *, offset_t, struct as *,
- caddr_t *, size_t, uint8_t, uint8_t, uint32_t, struct cred *);
+ caddr_t *, size_t, uint8_t, uint8_t, uint32_t, struct cred *,
+ caller_context_t *);
static int32_t udf_addmap(struct vnode *, offset_t, struct as *,
- caddr_t, size_t, uint8_t, uint8_t, uint32_t, struct cred *);
+ caddr_t, size_t, uint8_t, uint8_t, uint32_t, struct cred *,
+ caller_context_t *);
static int32_t udf_delmap(struct vnode *, offset_t, struct as *,
- caddr_t, size_t, uint32_t, uint32_t, uint32_t, struct cred *);
+ caddr_t, size_t, uint32_t, uint32_t, uint32_t, struct cred *,
+ caller_context_t *);
static int32_t udf_l_pathconf(struct vnode *, int32_t,
- ulong_t *, struct cred *);
+ ulong_t *, struct cred *, caller_context_t *);
static int32_t udf_pageio(struct vnode *, struct page *,
- u_offset_t, size_t, int32_t, struct cred *);
+ u_offset_t, size_t, int32_t, struct cred *, caller_context_t *);
int32_t ud_getpage_miss(struct vnode *, u_offset_t,
size_t, struct seg *, caddr_t, page_t *pl[],
@@ -227,7 +236,11 @@ const fs_operation_def_t udf_vnodeops_template[] = {
/* ARGSUSED */
static int32_t
-udf_open(struct vnode **vpp, int32_t flag, struct cred *cr)
+udf_open(
+ struct vnode **vpp,
+ int32_t flag,
+ struct cred *cr,
+ caller_context_t *ct)
{
ud_printf("udf_open\n");
@@ -236,8 +249,13 @@ udf_open(struct vnode **vpp, int32_t flag, struct cred *cr)
/* ARGSUSED */
static int32_t
-udf_close(struct vnode *vp, int32_t flag,
- int32_t count, offset_t offset, struct cred *cr)
+udf_close(
+ struct vnode *vp,
+ int32_t flag,
+ int32_t count,
+ offset_t offset,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -265,9 +283,14 @@ udf_close(struct vnode *vp, int32_t flag,
return (0);
}
+/* ARGSUSED */
static int32_t
-udf_read(struct vnode *vp, struct uio *uiop,
- int32_t ioflag, struct cred *cr, struct caller_context *ct)
+udf_read(
+ struct vnode *vp,
+ struct uio *uiop,
+ int32_t ioflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
int32_t error;
@@ -309,9 +332,14 @@ int32_t ud_HW = 96 * 1024;
int32_t ud_LW = 64 * 1024;
int32_t ud_throttles = 0;
+/* ARGSUSED */
static int32_t
-udf_write(struct vnode *vp, struct uio *uiop,
- int32_t ioflag, struct cred *cr, struct caller_context *ct)
+udf_write(
+ struct vnode *vp,
+ struct uio *uiop,
+ int32_t ioflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
int32_t error = 0;
@@ -369,16 +397,26 @@ end:
/* ARGSUSED */
static int32_t
-udf_ioctl(struct vnode *vp, int32_t cmd, intptr_t arg,
- int32_t flag, struct cred *cr, int32_t *rvalp)
+udf_ioctl(
+ struct vnode *vp,
+ int32_t cmd,
+ intptr_t arg,
+ int32_t flag,
+ struct cred *cr,
+ int32_t *rvalp,
+ caller_context_t *ct)
{
return (ENOTTY);
}
/* ARGSUSED */
static int32_t
-udf_getattr(struct vnode *vp,
- struct vattr *vap, int32_t flags, struct cred *cr)
+udf_getattr(
+ struct vnode *vp,
+ struct vattr *vap,
+ int32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -566,8 +604,12 @@ update_inode:
/* ARGSUSED */
static int32_t
-udf_access(struct vnode *vp,
- int32_t mode, int32_t flags, struct cred *cr)
+udf_access(
+ struct vnode *vp,
+ int32_t mode,
+ int32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
int32_t error;
@@ -587,9 +629,17 @@ int32_t udfs_stickyhack = 1;
/* ARGSUSED */
static int32_t
-udf_lookup(struct vnode *dvp,
- char *nm, struct vnode **vpp, struct pathname *pnp,
- int32_t flags, struct vnode *rdir, struct cred *cr)
+udf_lookup(
+ struct vnode *dvp,
+ char *nm,
+ struct vnode **vpp,
+ struct pathname *pnp,
+ int32_t flags,
+ struct vnode *rdir,
+ struct cred *cr,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
int32_t error;
struct vnode *vp;
@@ -656,9 +706,17 @@ out:
/* ARGSUSED */
static int32_t
-udf_create(struct vnode *dvp,
- char *name, struct vattr *vap, enum vcexcl excl,
- int32_t mode, struct vnode **vpp, struct cred *cr, int32_t flag)
+udf_create(
+ struct vnode *dvp,
+ char *name,
+ struct vattr *vap,
+ enum vcexcl excl,
+ int32_t mode,
+ struct vnode **vpp,
+ struct cred *cr,
+ int32_t flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int32_t error;
struct ud_inode *ip = VTOI(dvp), *xip;
@@ -679,8 +737,8 @@ udf_create(struct vnode *dvp,
xip = NULL;
rw_enter(&ip->i_rwlock, RW_WRITER);
error = ud_direnter(ip, name, DE_CREATE,
- (struct ud_inode *)0, (struct ud_inode *)0,
- vap, &xip, cr);
+ (struct ud_inode *)0, (struct ud_inode *)0,
+ vap, &xip, cr, ct);
rw_exit(&ip->i_rwlock);
ITIMES(ip);
ip = xip;
@@ -732,7 +790,7 @@ udf_create(struct vnode *dvp,
(void) ud_itrunc(ip, 0, 0, cr);
rw_exit(&ip->i_rwlock);
}
- vnevent_create(ITOV(ip));
+ vnevent_create(ITOV(ip), ct);
}
}
@@ -769,8 +827,14 @@ out:
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_remove(struct vnode *vp, char *nm, struct cred *cr)
+udf_remove(
+ struct vnode *vp,
+ char *nm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error;
struct ud_inode *ip = VTOI(vp);
@@ -779,16 +843,22 @@ udf_remove(struct vnode *vp, char *nm, struct cred *cr)
rw_enter(&ip->i_rwlock, RW_WRITER);
error = ud_dirremove(ip, nm,
- (struct ud_inode *)0, (struct vnode *)0, DR_REMOVE, cr);
+ (struct ud_inode *)0, (struct vnode *)0, DR_REMOVE, cr, ct);
rw_exit(&ip->i_rwlock);
ITIMES(ip);
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_link(struct vnode *tdvp,
- struct vnode *svp, char *tnm, struct cred *cr)
+udf_link(
+ struct vnode *tdvp,
+ struct vnode *svp,
+ char *tnm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error;
struct vnode *realvp;
@@ -796,7 +866,7 @@ udf_link(struct vnode *tdvp,
struct ud_inode *tdp;
ud_printf("udf_link\n");
- if (VOP_REALVP(svp, &realvp) == 0) {
+ if (VOP_REALVP(svp, &realvp, ct) == 0) {
svp = realvp;
}
@@ -816,13 +886,13 @@ udf_link(struct vnode *tdvp,
rw_enter(&tdp->i_rwlock, RW_WRITER);
error = ud_direnter(tdp, tnm, DE_LINK, (struct ud_inode *)0,
- sip, (struct vattr *)0, (struct ud_inode **)0, cr);
+ sip, (struct vattr *)0, (struct ud_inode **)0, cr, ct);
rw_exit(&tdp->i_rwlock);
ITIMES(sip);
ITIMES(tdp);
if (error == 0) {
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
return (error);
@@ -830,9 +900,14 @@ udf_link(struct vnode *tdvp,
/* ARGSUSED */
static int32_t
-udf_rename(struct vnode *sdvp,
- char *snm, struct vnode *tdvp,
- char *tnm, struct cred *cr)
+udf_rename(
+ struct vnode *sdvp,
+ char *snm,
+ struct vnode *tdvp,
+ char *tnm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error = 0;
struct udf_vfs *udf_vfsp;
@@ -842,7 +917,7 @@ udf_rename(struct vnode *sdvp,
ud_printf("udf_rename\n");
- if (VOP_REALVP(tdvp, &realvp) == 0) {
+ if (VOP_REALVP(tdvp, &realvp, ct) == 0) {
tdvp = realvp;
}
@@ -906,7 +981,7 @@ udf_rename(struct vnode *sdvp,
*/
rw_enter(&tdp->i_rwlock, RW_WRITER);
if (error = ud_direnter(tdp, tnm, DE_RENAME, sdp, sip,
- (struct vattr *)0, (struct ud_inode **)0, cr)) {
+ (struct vattr *)0, (struct ud_inode **)0, cr, ct)) {
/*
* ESAME isn't really an error; it indicates that the
* operation should not be done because the source and target
@@ -918,7 +993,7 @@ udf_rename(struct vnode *sdvp,
rw_exit(&tdp->i_rwlock);
goto errout;
}
- vnevent_rename_src(ITOV(sip), sdvp, snm);
+ vnevent_rename_src(ITOV(sip), sdvp, snm, ct);
rw_exit(&tdp->i_rwlock);
rw_enter(&sdp->i_rwlock, RW_WRITER);
@@ -930,7 +1005,7 @@ udf_rename(struct vnode *sdvp,
* the source inode.
*/
if ((error = ud_dirremove(sdp, snm, sip, (struct vnode *)0,
- DR_RENAME, cr)) == ENOENT) {
+ DR_RENAME, cr, ct)) == ENOENT) {
error = 0;
}
rw_exit(&sdp->i_rwlock);
@@ -943,10 +1018,17 @@ errout:
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_mkdir(struct vnode *dvp,
- char *dirname, struct vattr *vap,
- struct vnode **vpp, struct cred *cr)
+udf_mkdir(
+ struct vnode *dvp,
+ char *dirname,
+ struct vattr *vap,
+ struct vnode **vpp,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
int32_t error;
struct ud_inode *ip;
@@ -959,7 +1041,7 @@ udf_mkdir(struct vnode *dvp,
ip = VTOI(dvp);
rw_enter(&ip->i_rwlock, RW_WRITER);
error = ud_direnter(ip, dirname, DE_MKDIR,
- (struct ud_inode *)0, (struct ud_inode *)0, vap, &xip, cr);
+ (struct ud_inode *)0, (struct ud_inode *)0, vap, &xip, cr, ct);
rw_exit(&ip->i_rwlock);
ITIMES(ip);
if (error == 0) {
@@ -974,9 +1056,15 @@ udf_mkdir(struct vnode *dvp,
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_rmdir(struct vnode *vp,
- char *nm, struct vnode *cdir, struct cred *cr)
+udf_rmdir(
+ struct vnode *vp,
+ char *nm,
+ struct vnode *cdir,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error;
struct ud_inode *ip = VTOI(vp);
@@ -984,7 +1072,8 @@ udf_rmdir(struct vnode *vp,
ud_printf("udf_rmdir\n");
rw_enter(&ip->i_rwlock, RW_WRITER);
- error = ud_dirremove(ip, nm, (struct ud_inode *)0, cdir, DR_RMDIR, cr);
+ error = ud_dirremove(ip, nm, (struct ud_inode *)0, cdir, DR_RMDIR,
+ cr, ct);
rw_exit(&ip->i_rwlock);
ITIMES(ip);
@@ -993,8 +1082,13 @@ udf_rmdir(struct vnode *vp,
/* ARGSUSED */
static int32_t
-udf_readdir(struct vnode *vp,
- struct uio *uiop, struct cred *cr, int32_t *eofp)
+udf_readdir(
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cr,
+ int32_t *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct ud_inode *ip;
struct dirent64 *nd;
@@ -1142,9 +1236,14 @@ end:
/* ARGSUSED */
static int32_t
-udf_symlink(struct vnode *dvp,
- char *linkname, struct vattr *vap,
- char *target, struct cred *cr)
+udf_symlink(
+ struct vnode *dvp,
+ char *linkname,
+ struct vattr *vap,
+ char *target,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error = 0, outlen;
uint32_t ioflag = 0;
@@ -1161,7 +1260,7 @@ udf_symlink(struct vnode *dvp,
rw_enter(&dip->i_rwlock, RW_WRITER);
error = ud_direnter(dip, linkname, DE_CREATE,
- (struct ud_inode *)0, (struct ud_inode *)0, vap, &ip, cr);
+ (struct ud_inode *)0, (struct ud_inode *)0, vap, &ip, cr, ct);
rw_exit(&dip->i_rwlock);
if (error == 0) {
dname = kmem_zalloc(1024, KM_SLEEP);
@@ -1246,7 +1345,7 @@ udf_symlink(struct vnode *dvp,
rw_exit(&ip->i_contents);
rw_enter(&dip->i_rwlock, RW_WRITER);
(void) ud_dirremove(dip, linkname, (struct ud_inode *)0,
- (struct vnode *)0, DR_REMOVE, cr);
+ (struct vnode *)0, DR_REMOVE, cr, ct);
rw_exit(&dip->i_rwlock);
goto update_inode;
}
@@ -1271,8 +1370,11 @@ update_inode:
/* ARGSUSED */
static int32_t
-udf_readlink(struct vnode *vp,
- struct uio *uiop, struct cred *cr)
+udf_readlink(
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cr,
+ caller_context_t *ct)
{
int32_t error = 0, off, id_len, size, len;
int8_t *dname = NULL, *uname = NULL;
@@ -1374,8 +1476,11 @@ end:
/* ARGSUSED */
static int32_t
-udf_fsync(struct vnode *vp,
- int32_t syncflag, struct cred *cr)
+udf_fsync(
+ struct vnode *vp,
+ int32_t syncflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
int32_t error = 0;
struct ud_inode *ip = VTOI(vp);
@@ -1397,15 +1502,16 @@ udf_fsync(struct vnode *vp,
/* ARGSUSED */
static void
-udf_inactive(struct vnode *vp, struct cred *cr)
+udf_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
ud_printf("udf_iinactive\n");
ud_iinactive(VTOI(vp), cr);
}
+/* ARGSUSED */
static int32_t
-udf_fid(struct vnode *vp, struct fid *fidp)
+udf_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct udf_fid *udfidp;
struct ud_inode *ip = VTOI(vp);
@@ -1466,15 +1572,21 @@ udf_rwunlock(struct vnode *vp, int32_t write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int32_t
-udf_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+udf_seek(struct vnode *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
static int32_t
-udf_frlock(struct vnode *vp, int32_t cmd, struct flock64 *bfp,
- int32_t flag, offset_t offset, struct flk_callback *flk_cbp,
- cred_t *cr)
+udf_frlock(
+ struct vnode *vp,
+ int32_t cmd,
+ struct flock64 *bfp,
+ int32_t flag,
+ offset_t offset,
+ struct flk_callback *flk_cbp,
+ cred_t *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -1492,7 +1604,7 @@ udf_frlock(struct vnode *vp, int32_t cmd, struct flock64 *bfp,
return (EAGAIN);
}
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
/*ARGSUSED6*/
@@ -1521,10 +1633,18 @@ udf_space(
/* ARGSUSED */
static int32_t
-udf_getpage(struct vnode *vp, offset_t off,
- size_t len, uint32_t *protp, struct page **plarr,
- size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, struct cred *cr)
+udf_getpage(
+ struct vnode *vp,
+ offset_t off,
+ size_t len,
+ uint32_t *protp,
+ struct page **plarr,
+ size_t plsz,
+ struct seg *seg,
+ caddr_t addr,
+ enum seg_rw rw,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
int32_t error, has_holes, beyond_eof, seqmode, dolock;
@@ -1798,8 +1918,13 @@ int32_t ud_delay = 1;
/* ARGSUSED */
static int32_t
-udf_putpage(struct vnode *vp, offset_t off,
- size_t len, int32_t flags, struct cred *cr)
+udf_putpage(
+ struct vnode *vp,
+ offset_t off,
+ size_t len,
+ int32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip;
int32_t error = 0;
@@ -1879,11 +2004,19 @@ out:
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_map(struct vnode *vp, offset_t off,
- struct as *as, caddr_t *addrp, size_t len,
- uint8_t prot, uint8_t maxprot, uint32_t flags,
- struct cred *cr)
+udf_map(
+ struct vnode *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t *addrp,
+ size_t len,
+ uint8_t prot,
+ uint8_t maxprot,
+ uint32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int32_t error = 0;
@@ -1949,10 +2082,16 @@ end:
/* ARGSUSED */
static int32_t
-udf_addmap(struct vnode *vp, offset_t off,
- struct as *as, caddr_t addr, size_t len,
- uint8_t prot, uint8_t maxprot, uint32_t flags,
- struct cred *cr)
+udf_addmap(struct vnode *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uint8_t prot,
+ uint8_t maxprot,
+ uint32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -1971,10 +2110,16 @@ udf_addmap(struct vnode *vp, offset_t off,
/* ARGSUSED */
static int32_t
-udf_delmap(struct vnode *vp, offset_t off,
- struct as *as, caddr_t addr, size_t len,
- uint32_t prot, uint32_t maxprot, uint32_t flags,
- struct cred *cr)
+udf_delmap(
+ struct vnode *vp, offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uint32_t prot,
+ uint32_t maxprot,
+ uint32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -1992,9 +2137,14 @@ udf_delmap(struct vnode *vp, offset_t off,
return (0);
}
+/* ARGSUSED */
static int32_t
-udf_l_pathconf(struct vnode *vp, int32_t cmd,
- ulong_t *valp, struct cred *cr)
+udf_l_pathconf(
+ struct vnode *vp,
+ int32_t cmd,
+ ulong_t *valp,
+ struct cred *cr,
+ caller_context_t *ct)
{
int32_t error = 0;
@@ -2010,7 +2160,7 @@ udf_l_pathconf(struct vnode *vp, int32_t cmd,
*/
*valp = 41;
} else {
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
return (error);
@@ -2027,9 +2177,14 @@ _NOTE(SCHEME_PROTECTS_DATA("safe sharing", ud_pageio_writes))
*/
/* ARGSUSED */
static int32_t
-udf_pageio(struct vnode *vp, struct page *pp,
- u_offset_t io_off, size_t io_len,
- int32_t flags, struct cred *cr)
+udf_pageio(
+ struct vnode *vp,
+ struct page *pp,
+ u_offset_t io_off,
+ size_t io_len,
+ int32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
daddr_t bn;
struct buf *bp;
diff --git a/usr/src/uts/common/fs/ufs/quotacalls.c b/usr/src/uts/common/fs/ufs/quotacalls.c
index 6474acbfff..4c97cd9149 100644
--- a/usr/src/uts/common/fs/ufs/quotacalls.c
+++ b/usr/src/uts/common/fs/ufs/quotacalls.c
@@ -271,7 +271,7 @@ opendq(
" from quota file\n");
rw_exit(&qip->i_contents);
(void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)qip->i_size,
- B_INVAL, kcred);
+ B_INVAL, kcred, NULL);
} else {
rw_exit(&qip->i_contents);
}
@@ -642,7 +642,7 @@ setquota(int cmd, uid_t uid, struct ufsvfs *ufsvfsp,
rw_exit(&qip->i_contents);
(void) VOP_PUTPAGE(ITOV(qip), dqoff(dqp->dq_uid) & ~qip->i_fs->fs_bmask,
- qip->i_fs->fs_bsize, B_INVAL, kcred);
+ qip->i_fs->fs_bsize, B_INVAL, kcred, NULL);
/*
* We must set the dq_mof even if not we are not logging in case
diff --git a/usr/src/uts/common/fs/ufs/ufs_directio.c b/usr/src/uts/common/fs/ufs/ufs_directio.c
index b60537ba75..7e908772bc 100644
--- a/usr/src/uts/common/fs/ufs/ufs_directio.c
+++ b/usr/src/uts/common/fs/ufs/ufs_directio.c
@@ -600,7 +600,8 @@ skip_alloc:
rw_exit(&ip->i_contents);
rw_enter(&ip->i_contents, RW_WRITER);
}
- (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL, cr);
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
+ B_INVAL, cr, NULL);
if (vn_has_cached_data(vp))
goto errout;
if (!exclusive)
@@ -737,7 +738,7 @@ skip_alloc:
rw_exit(&ip->i_contents);
rw_enter(&ip->i_contents, RW_WRITER);
(void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
- B_INVAL, cr);
+ B_INVAL, cr, NULL);
ufs_directio_kstats.nflushes.value.ui64++;
rw_downgrade(&ip->i_contents);
}
@@ -912,7 +913,8 @@ ufs_directio_read(struct inode *ip, uio_t *uio, cred_t *cr, int *statusp)
if (vn_has_cached_data(vp)) {
rw_exit(&ip->i_contents);
rw_enter(&ip->i_contents, RW_WRITER);
- (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL, cr);
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
+ B_INVAL, cr, NULL);
if (vn_has_cached_data(vp))
return (0);
rw_downgrade(&ip->i_contents);
diff --git a/usr/src/uts/common/fs/ufs/ufs_extvnops.c b/usr/src/uts/common/fs/ufs/ufs_extvnops.c
index 4533f8db07..08ece1de79 100644
--- a/usr/src/uts/common/fs/ufs/ufs_extvnops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_extvnops.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -244,7 +243,7 @@ ufs_alloc_data(
size_t done_len, io_len;
int contig;
u_offset_t uoff, io_off;
- int error = 0; /* No error occured */
+ int error = 0; /* No error occurred */
int offsetn; /* Start point this IO */
int nbytes; /* Number bytes in this IO */
daddr_t bn;
@@ -502,7 +501,7 @@ ufs_alloc_data(
* was written.
*
*/
- (void) VOP_PUTPAGE(vnodep, 0, 0, B_INVAL, credp);
+ (void) VOP_PUTPAGE(vnodep, 0, 0, B_INVAL, credp, NULL);
rw_exit(&ip->i_contents);
rw_exit(&ip->i_ufsvfs->vfs_dqrwlock);
diff --git a/usr/src/uts/common/fs/ufs/ufs_filio.c b/usr/src/uts/common/fs/ufs/ufs_filio.c
index 6a6bc4c421..04a68104ff 100644
--- a/usr/src/uts/common/fs/ufs/ufs_filio.c
+++ b/usr/src/uts/common/fs/ufs/ufs_filio.c
@@ -171,10 +171,10 @@ ufs_fioio(
* Adapted from vn_open: check access and then open the file
*/
vpio = ITOV(ipio);
- if (error = VOP_ACCESS(vpio, VREAD, 0, cr))
+ if (error = VOP_ACCESS(vpio, VREAD, 0, cr, NULL))
goto errout;
- if (error = VOP_OPEN(&vpio, FREAD, cr))
+ if (error = VOP_OPEN(&vpio, FREAD, cr, NULL))
goto errout;
/*
diff --git a/usr/src/uts/common/fs/ufs/ufs_lockfs.c b/usr/src/uts/common/fs/ufs/ufs_lockfs.c
index 6055532000..b7a7179c28 100644
--- a/usr/src/uts/common/fs/ufs/ufs_lockfs.c
+++ b/usr/src/uts/common/fs/ufs/ufs_lockfs.c
@@ -367,7 +367,7 @@ ufs_flush(struct vfs *vfsp)
* flush w/invalidate block device pages and buf cache
*/
if ((error = VOP_PUTPAGE(common_specvp(ufsvfsp->vfs_devvp),
- (offset_t)0, 0, B_INVAL, CRED())) > 0)
+ (offset_t)0, 0, B_INVAL, CRED(), NULL)) > 0)
saverror = error;
(void) bflush((dev_t)vfsp->vfs_dev);
diff --git a/usr/src/uts/common/fs/ufs/ufs_subr.c b/usr/src/uts/common/fs/ufs/ufs_subr.c
index f6daee5dc1..e2d1f6577b 100644
--- a/usr/src/uts/common/fs/ufs/ufs_subr.c
+++ b/usr/src/uts/common/fs/ufs/ufs_subr.c
@@ -489,7 +489,8 @@ ufs_syncip(struct inode *ip, int flags, int waitfor, top_t topid)
TRANS_BEGIN_ASYNC(ufsvfsp, TOP_PUTPAGE,
TOP_PUTPAGE_SIZE(ip));
}
- error = VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, flags, CRED());
+ error = VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
+ flags, CRED(), NULL);
if (dotrans) {
TRANS_END_ASYNC(ufsvfsp, TOP_PUTPAGE,
TOP_PUTPAGE_SIZE(ip));
diff --git a/usr/src/uts/common/fs/ufs/ufs_vfsops.c b/usr/src/uts/common/fs/ufs/ufs_vfsops.c
index 23c2d1798a..80151eaa32 100644
--- a/usr/src/uts/common/fs/ufs/ufs_vfsops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_vfsops.c
@@ -361,7 +361,7 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
oflag = FREAD | FWRITE;
aflag = VREAD | VWRITE;
}
- if ((error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 ||
+ if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
(error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
pn_free(&dpn);
VN_RELE(bvp);
@@ -407,6 +407,8 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
if (error) {
VN_RELE(bvp);
}
+ if (error == 0)
+ vfs_set_feature(vfsp, VFSFT_XVATTR);
return (error);
}
/*
@@ -449,7 +451,8 @@ ufs_mountroot(struct vfs *vfsp, enum whymountroot why)
vp = ((struct ufsvfs *)vfsp->vfs_data)->vfs_devvp;
(void) dnlc_purge_vfsp(vfsp, 0);
vp = common_specvp(vp);
- (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL, CRED());
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL,
+ CRED(), NULL);
(void) bfinval(vfsp->vfs_dev, 0);
fsp = getfs(vfsp);
@@ -484,7 +487,7 @@ ufs_mountroot(struct vfs *vfsp, enum whymountroot why)
vp = ((struct ufsvfs *)vfsp->vfs_data)->vfs_devvp;
(void) VOP_CLOSE(vp, FREAD|FWRITE, 1,
- (offset_t)0, CRED());
+ (offset_t)0, CRED(), NULL);
return (0);
}
error = vfs_lock(vfsp);
@@ -496,10 +499,10 @@ ufs_mountroot(struct vfs *vfsp, enum whymountroot why)
/* If RO media, don't call clkset() (see below) */
doclkset = 1;
if (why == ROOT_INIT) {
- error = VOP_OPEN(&devvp, FREAD|FWRITE, CRED());
+ error = VOP_OPEN(&devvp, FREAD|FWRITE, CRED(), NULL);
if (error == 0) {
(void) VOP_CLOSE(devvp, FREAD|FWRITE, 1,
- (offset_t)0, CRED());
+ (offset_t)0, CRED(), NULL);
} else {
doclkset = 0;
}
@@ -788,7 +791,8 @@ mountfs(struct vfs *vfsp, enum whymountroot why, struct vnode *devvp,
* operations.
*/
error = VOP_OPEN(&devvp,
- (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, cr);
+ (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE,
+ cr, NULL);
if (error)
goto out;
needclose = 1;
@@ -822,7 +826,7 @@ mountfs(struct vfs *vfsp, enum whymountroot why, struct vnode *devvp,
* they really should be using the raw device.
*/
(void) VOP_PUTPAGE(common_specvp(devvp), (offset_t)0,
- (size_t)0, B_INVAL, cr);
+ (size_t)0, B_INVAL, cr, NULL);
/*
* read in superblock
@@ -1321,7 +1325,7 @@ out:
}
if (needclose) {
(void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ?
- FREAD : FREAD|FWRITE, 1, (offset_t)0, cr);
+ FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
bflush(dev);
(void) bfinval(dev, 1);
}
@@ -1628,8 +1632,8 @@ ufs_unmount(struct vfs *vfsp, int fflag, struct cred *cr)
brelse(bp); /* free the superblock buf */
(void) VOP_PUTPAGE(common_specvp(bvp), (offset_t)0, (size_t)0,
- B_INVAL, cr);
- (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr);
+ B_INVAL, cr, NULL);
+ (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr, NULL);
bflush(dev);
(void) bfinval(dev, 1);
VN_RELE(bvp);
@@ -1696,7 +1700,7 @@ out:
ufs_trans_onerror();
/*
- * if we have a seperate /usr it will never unmount
+ * if we have a separate /usr it will never unmount
* when halting. In order to not re-read all the
* cylinder group summary info on mounting after
* reboot the logging of summary info is re-enabled
@@ -2099,7 +2103,7 @@ ufs_remountroot(struct vfs *vfsp)
new_rootvp = makespecvp(new_rootdev, VBLK);
error = VOP_OPEN(&new_rootvp,
- (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, CRED());
+ (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, CRED(), NULL);
if (error) {
cmn_err(CE_CONT,
"Cannot open mirrored root device, error %d\n", error);
@@ -2245,7 +2249,7 @@ ufs_remountroot(struct vfs *vfsp)
vfs_unlock(vfsp);
- error = VOP_CLOSE(old_rootvp, FREAD, 1, (offset_t)0, CRED());
+ error = VOP_CLOSE(old_rootvp, FREAD, 1, (offset_t)0, CRED(), NULL);
if (error) {
cmn_err(CE_CONT,
"close of root device component failed, error %d\n",
diff --git a/usr/src/uts/common/fs/ufs/ufs_vnops.c b/usr/src/uts/common/fs/ufs/ufs_vnops.c
index 414aa037c4..4c712bbd75 100644
--- a/usr/src/uts/common/fs/ufs/ufs_vnops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_vnops.c
@@ -103,64 +103,80 @@ static struct instats ins;
static int ufs_getpage_ra(struct vnode *, u_offset_t, struct seg *, caddr_t);
static int ufs_getpage_miss(struct vnode *, u_offset_t, size_t, struct seg *,
caddr_t, struct page **, size_t, enum seg_rw, int);
-static int ufs_open(struct vnode **, int, struct cred *);
-static int ufs_close(struct vnode *, int, int, offset_t, struct cred *);
+static int ufs_open(struct vnode **, int, struct cred *, caller_context_t *);
+static int ufs_close(struct vnode *, int, int, offset_t, struct cred *,
+ caller_context_t *);
static int ufs_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ struct caller_context *);
static int ufs_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
-static int ufs_ioctl(struct vnode *, int, intptr_t, int, struct cred *, int *);
-static int ufs_getattr(struct vnode *, struct vattr *, int, struct cred *);
+ struct caller_context *);
+static int ufs_ioctl(struct vnode *, int, intptr_t, int, struct cred *,
+ int *, caller_context_t *);
+static int ufs_getattr(struct vnode *, struct vattr *, int, struct cred *,
+ caller_context_t *);
static int ufs_setattr(struct vnode *, struct vattr *, int, struct cred *,
- caller_context_t *);
-static int ufs_access(struct vnode *, int, int, struct cred *);
+ caller_context_t *);
+static int ufs_access(struct vnode *, int, int, struct cred *,
+ caller_context_t *);
static int ufs_lookup(struct vnode *, char *, struct vnode **,
- struct pathname *, int, struct vnode *, struct cred *);
+ struct pathname *, int, struct vnode *, struct cred *,
+ caller_context_t *, int *, pathname_t *);
static int ufs_create(struct vnode *, char *, struct vattr *, enum vcexcl,
- int, struct vnode **, struct cred *, int);
-static int ufs_remove(struct vnode *, char *, struct cred *);
-static int ufs_link(struct vnode *, struct vnode *, char *, struct cred *);
+ int, struct vnode **, struct cred *, int,
+ caller_context_t *, vsecattr_t *);
+static int ufs_remove(struct vnode *, char *, struct cred *,
+ caller_context_t *, int);
+static int ufs_link(struct vnode *, struct vnode *, char *, struct cred *,
+ caller_context_t *, int);
static int ufs_rename(struct vnode *, char *, struct vnode *, char *,
- struct cred *);
+ struct cred *, caller_context_t *, int);
static int ufs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **,
- struct cred *);
-static int ufs_rmdir(struct vnode *, char *, struct vnode *, struct cred *);
-static int ufs_readdir(struct vnode *, struct uio *, struct cred *, int *);
+ struct cred *, caller_context_t *, int, vsecattr_t *);
+static int ufs_rmdir(struct vnode *, char *, struct vnode *, struct cred *,
+ caller_context_t *, int);
+static int ufs_readdir(struct vnode *, struct uio *, struct cred *, int *,
+ caller_context_t *, int);
static int ufs_symlink(struct vnode *, char *, struct vattr *, char *,
- struct cred *);
-static int ufs_readlink(struct vnode *, struct uio *, struct cred *);
-static int ufs_fsync(struct vnode *, int, struct cred *);
-static void ufs_inactive(struct vnode *, struct cred *);
-static int ufs_fid(struct vnode *, struct fid *);
+ struct cred *, caller_context_t *, int);
+static int ufs_readlink(struct vnode *, struct uio *, struct cred *,
+ caller_context_t *);
+static int ufs_fsync(struct vnode *, int, struct cred *, caller_context_t *);
+static void ufs_inactive(struct vnode *, struct cred *, caller_context_t *);
+static int ufs_fid(struct vnode *, struct fid *, caller_context_t *);
static int ufs_rwlock(struct vnode *, int, caller_context_t *);
static void ufs_rwunlock(struct vnode *, int, caller_context_t *);
-static int ufs_seek(struct vnode *, offset_t, offset_t *);
+static int ufs_seek(struct vnode *, offset_t, offset_t *, caller_context_t *);
static int ufs_frlock(struct vnode *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, struct cred *);
+ struct flk_callback *, struct cred *,
+ caller_context_t *);
static int ufs_space(struct vnode *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
static int ufs_getpage(struct vnode *, offset_t, size_t, uint_t *,
struct page **, size_t, struct seg *, caddr_t,
- enum seg_rw, struct cred *);
-static int ufs_putpage(struct vnode *, offset_t, size_t, int, struct cred *);
+ enum seg_rw, struct cred *, caller_context_t *);
+static int ufs_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
+ caller_context_t *);
static int ufs_putpages(struct vnode *, offset_t, size_t, int, struct cred *);
static int ufs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int ufs_addmap(struct vnode *, offset_t, struct as *, caddr_t, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int ufs_delmap(struct vnode *, offset_t, struct as *, caddr_t, size_t,
- uint_t, uint_t, uint_t, struct cred *);
-static int ufs_poll(vnode_t *, short, int, short *, struct pollhead **);
-static int ufs_dump(vnode_t *, caddr_t, int, int);
-static int ufs_l_pathconf(struct vnode *, int, ulong_t *, struct cred *);
+ uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
+static int ufs_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+static int ufs_dump(vnode_t *, caddr_t, int, int, caller_context_t *);
+static int ufs_l_pathconf(struct vnode *, int, ulong_t *, struct cred *,
+ caller_context_t *);
static int ufs_pageio(struct vnode *, struct page *, u_offset_t, size_t, int,
- struct cred *);
-static int ufs_dump(vnode_t *, caddr_t, int, int);
-static int ufs_dumpctl(vnode_t *, int, int *);
+ struct cred *, caller_context_t *);
+static int ufs_dumpctl(vnode_t *, int, int *, caller_context_t *);
static daddr32_t *save_dblks(struct inode *, struct ufsvfs *, daddr32_t *,
- daddr32_t *, int, int);
-static int ufs_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
-static int ufs_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
+ daddr32_t *, int, int);
+static int ufs_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
+static int ufs_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
extern int as_map_locked(struct as *, caddr_t, size_t, int ((*)()), void *);
@@ -246,7 +262,7 @@ static struct dump *dump_info = NULL;
/* ARGSUSED */
static int
-ufs_open(struct vnode **vpp, int flag, struct cred *cr)
+ufs_open(struct vnode **vpp, int flag, struct cred *cr, caller_context_t *ct)
{
return (0);
}
@@ -254,7 +270,7 @@ ufs_open(struct vnode **vpp, int flag, struct cred *cr)
/*ARGSUSED*/
static int
ufs_close(struct vnode *vp, int flag, int count, offset_t offset,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
cleanshares(vp, ttoproc(curthread)->p_pid);
@@ -966,7 +982,7 @@ wrip(struct inode *ip, struct uio *uio, int ioflag, struct cred *cr)
* 2) uiomove() causes a page fault.
*
* We have to drop the contents lock to prevent the VM
- * system from trying to reaquire it in ufs_getpage()
+ * system from trying to reacquire it in ufs_getpage()
* should the uiomove cause a pagefault.
*
* We have to drop the reader vfs_dqrwlock here as well.
@@ -1521,7 +1537,8 @@ ufs_ioctl(
intptr_t arg,
int flag,
struct cred *cr,
- int *rvalp)
+ int *rvalp,
+ caller_context_t *ct)
{
struct lockfs lockfs, lockfs_out;
struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs;
@@ -1916,7 +1933,7 @@ ufs_ioctl(
/* ARGSUSED */
static int
ufs_getattr(struct vnode *vp, struct vattr *vap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp;
@@ -2042,10 +2059,8 @@ ufs_setattr(
/*
* Cannot set these attributes.
*/
- if (mask & AT_NOSET) {
- error = EINVAL;
- goto out;
- }
+ if ((mask & AT_NOSET) || (mask & AT_XVATTR))
+ return (EINVAL);
/*
* check for forced unmount
@@ -2349,7 +2364,8 @@ out:
/*ARGSUSED*/
static int
-ufs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+ufs_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
int error;
@@ -2379,7 +2395,8 @@ ufs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
/* ARGSUSED */
static int
-ufs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cr)
+ufs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp;
@@ -2505,7 +2522,7 @@ again:
(void) VOP_PUTPAGE(ITOV(ip),
(offset_t)0, PAGESIZE,
(B_DONTNEED | B_FREE | B_FORCE | B_ASYNC),
- cr);
+ cr, ct);
} else {
int i;
/* error, clear garbage left behind */
@@ -2534,7 +2551,8 @@ nolockout:
/* ARGSUSED */
static int
-ufs_fsync(struct vnode *vp, int syncflag, struct cred *cr)
+ufs_fsync(struct vnode *vp, int syncflag, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
@@ -2552,7 +2570,7 @@ ufs_fsync(struct vnode *vp, int syncflag, struct cred *cr)
if (vn_has_cached_data(vp) && !(syncflag & FNODSYNC) &&
(vp->v_type != VCHR) && !(IS_SWAPVP(vp))) {
error = VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
- 0, CRED());
+ 0, CRED(), ct);
if (error)
goto out;
}
@@ -2627,7 +2645,7 @@ out:
/*ARGSUSED*/
static void
-ufs_inactive(struct vnode *vp, struct cred *cr)
+ufs_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
ufs_iinactive(VTOI(vp));
}
@@ -2639,7 +2657,8 @@ int ufs_lookup_idle_count = 2; /* Number of inodes to idle each time */
/* ARGSUSED */
static int
ufs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
- struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cr)
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cr,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
{
struct inode *ip;
struct inode *sip;
@@ -2658,6 +2677,12 @@ ufs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
if (flags & LOOKUP_XATTR) {
/*
+ * If not mounted with XATTR support then return EINVAL
+ */
+
+ if (!(ip->i_ufsvfs->vfs_vfs->vfs_flag & VFS_XATTR))
+ return (EINVAL);
+ /*
* We don't allow recursive attributes...
* Maybe someday we will.
*/
@@ -2796,9 +2821,11 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
ufs_create(struct vnode *dvp, char *name, struct vattr *vap, enum vcexcl excl,
- int mode, struct vnode **vpp, struct cred *cr, int flag)
+ int mode, struct vnode **vpp, struct cred *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
struct inode *ip;
struct inode *xip;
@@ -2988,7 +3015,7 @@ again:
}
if (error == 0) {
- vnevent_create(ITOV(ip));
+ vnevent_create(ITOV(ip), ct);
}
}
}
@@ -3082,7 +3109,8 @@ out:
extern int ufs_idle_max;
/*ARGSUSED*/
static int
-ufs_remove(struct vnode *vp, char *nm, struct cred *cr)
+ufs_remove(struct vnode *vp, char *nm, struct cred *cr,
+ caller_context_t *ct, int flags)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
@@ -3135,7 +3163,7 @@ retry_remove:
if (rmvp != NULL) {
/* Only send the event if there were no errors */
if (error == 0)
- vnevent_remove(rmvp, vp, nm);
+ vnevent_remove(rmvp, vp, nm, ct);
VN_RELE(rmvp);
}
out:
@@ -3146,8 +3174,10 @@ out:
* Link a file or a directory. Only privileged processes are allowed to
* make links to directories.
*/
+/*ARGSUSED*/
static int
-ufs_link(struct vnode *tdvp, struct vnode *svp, char *tnm, struct cred *cr)
+ufs_link(struct vnode *tdvp, struct vnode *svp, char *tnm, struct cred *cr,
+ caller_context_t *ct, int flags)
{
struct inode *sip;
struct inode *tdp = VTOI(tdvp);
@@ -3169,7 +3199,7 @@ retry_link:
TRANS_BEGIN_CSYNC(ufsvfsp, issync, TOP_LINK,
trans_size = (int)TOP_LINK_SIZE(VTOI(tdvp)));
- if (VOP_REALVP(svp, &realvp) == 0)
+ if (VOP_REALVP(svp, &realvp, ct) == 0)
svp = realvp;
/*
@@ -3216,7 +3246,7 @@ unlock:
}
if (!error) {
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
out:
return (error);
@@ -3247,7 +3277,9 @@ ufs_rename(
char *snm, /* old (source) entry name */
struct vnode *tdvp, /* new (target) parent vnode */
char *tnm, /* new (target) entry name */
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
struct inode *sip = NULL; /* source inode */
struct inode *ip = NULL; /* check inode */
@@ -3278,7 +3310,7 @@ retry_rename:
TRANS_BEGIN_CSYNC(ufsvfsp, issync, TOP_RENAME,
trans_size = (int)TOP_RENAME_SIZE(sdp));
- if (VOP_REALVP(tdvp, &realvp) == 0)
+ if (VOP_REALVP(tdvp, &realvp, ct) == 0)
tdvp = realvp;
tdp = VTOI(tdvp);
@@ -3598,14 +3630,14 @@ unlock:
*/
if (error == 0) {
if (tvp != NULL)
- vnevent_rename_dest(tvp, tdvp, tnm);
+ vnevent_rename_dest(tvp, tdvp, tnm, ct);
/*
* Notify the target directory of the rename event
* if source and target directories are not same.
*/
if (sdvp != tdvp)
- vnevent_rename_dest_dir(tdvp);
+ vnevent_rename_dest_dir(tdvp, ct);
/*
* Note that if ufs_direnter_lr() returned ESAME then
@@ -3613,7 +3645,7 @@ unlock:
* to be a problem for anticipated usage by consumers.
*/
if (sip != NULL)
- vnevent_rename_src(ITOV(sip), sdvp, snm);
+ vnevent_rename_src(ITOV(sip), sdvp, snm, ct);
}
if (tvp != NULL)
@@ -3629,7 +3661,8 @@ out:
/*ARGSUSED*/
static int
ufs_mkdir(struct vnode *dvp, char *dirname, struct vattr *vap,
- struct vnode **vpp, struct cred *cr)
+ struct vnode **vpp, struct cred *cr, caller_context_t *ct, int flags,
+ vsecattr_t *vsecp)
{
struct inode *ip;
struct inode *xip;
@@ -3705,7 +3738,8 @@ out:
/*ARGSUSED*/
static int
-ufs_rmdir(struct vnode *vp, char *nm, struct vnode *cdir, struct cred *cr)
+ufs_rmdir(struct vnode *vp, char *nm, struct vnode *cdir, struct cred *cr,
+ caller_context_t *ct, int flags)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
@@ -3759,7 +3793,7 @@ retry_rmdir:
if (rmvp != NULL) {
/* Only send the event if there were no errors */
if (error == 0)
- vnevent_rmdir(rmvp, vp, nm);
+ vnevent_rmdir(rmvp, vp, nm, ct);
VN_RELE(rmvp);
}
out:
@@ -3772,7 +3806,9 @@ ufs_readdir(
struct vnode *vp,
struct uio *uiop,
struct cred *cr,
- int *eofp)
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct iovec *iovp;
struct inode *ip;
@@ -3980,7 +4016,9 @@ ufs_symlink(
char *linkname, /* name of symbolic link */
struct vattr *vap, /* attributes */
char *target, /* target path */
- struct cred *cr) /* user credentials */
+ struct cred *cr, /* user credentials */
+ caller_context_t *ct,
+ int flags)
{
struct inode *ip, *dip = VTOI(dvp);
struct ufsvfs *ufsvfsp = dip->i_ufsvfs;
@@ -4203,10 +4241,9 @@ ufs_rdwri(enum uio_rw rw, int ioflag, struct inode *ip, caddr_t base,
return (error);
}
+/*ARGSUSED*/
static int
-ufs_fid(vp, fidp)
- struct vnode *vp;
- struct fid *fidp;
+ufs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct ufid *ufid;
struct inode *ip = VTOI(vp);
@@ -4297,7 +4334,8 @@ ufs_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
@@ -4305,7 +4343,8 @@ ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
/* ARGSUSED */
static int
ufs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, struct cred *cr)
+ offset_t offset, struct flk_callback *flk_cbp, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
@@ -4321,7 +4360,7 @@ ufs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
*/
if (ip->i_mapcnt > 0 && MANDLOCK(vp, ip->i_mode))
return (EAGAIN);
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
/* ARGSUSED */
@@ -4383,10 +4422,11 @@ ufs_space(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
* the time this thread tests the i_nextrio value and then reads it
* again to use it as the offset for the read ahead.
*/
+/*ARGSUSED*/
static int
ufs_getpage(struct vnode *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, struct cred *cr)
+ enum seg_rw rw, struct cred *cr, caller_context_t *ct)
{
u_offset_t uoff = (u_offset_t)off; /* type conversion */
u_offset_t pgoff;
@@ -4966,7 +5006,7 @@ int ufs_delay = 1;
/*ARGSUSED*/
static int
ufs_putpage(struct vnode *vp, offset_t off, size_t len, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
int err = 0;
@@ -5435,7 +5475,8 @@ ufs_map(struct vnode *vp,
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs;
@@ -5538,7 +5579,8 @@ ufs_addmap(struct vnode *vp,
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
@@ -5556,7 +5598,7 @@ ufs_addmap(struct vnode *vp,
static int
ufs_delmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr,
size_t len, uint_t prot, uint_t maxprot, uint_t flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
@@ -5577,7 +5619,8 @@ struct pollhead ufs_pollhd;
/* ARGSUSED */
int
-ufs_poll(vnode_t *vp, short ev, int any, short *revp, struct pollhead **phpp)
+ufs_poll(vnode_t *vp, short ev, int any, short *revp, struct pollhead **phpp,
+ caller_context_t *ct)
{
struct ufsvfs *ufsvfsp;
@@ -5622,7 +5665,8 @@ out:
/* ARGSUSED */
static int
-ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
+ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr,
+ caller_context_t *ct)
{
struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs;
struct ulockfs *ulp = NULL;
@@ -5694,7 +5738,7 @@ ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
error = 0;
}
} else {
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
break;
@@ -5706,8 +5750,14 @@ ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
*valp = (ulong_t)ip->i_fs->fs_bsize;
break;
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ *valp = vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) &&
+ (vp->v_type == VREG || vp->v_type == VDIR);
+ break;
+
default:
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
if (ulp != NULL) {
@@ -5721,7 +5771,7 @@ int ufs_pageio_writes, ufs_pageio_reads;
/*ARGSUSED*/
static int
ufs_pageio(struct vnode *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, struct cred *cr)
+ int flags, struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp;
@@ -5940,8 +5990,9 @@ ufs_pageio(struct vnode *vp, page_t *pp, u_offset_t io_off, size_t io_len,
* directly to the device. It uses a private dump data structure,
* set up by dump_ctl, to locate the correct disk block to which to dump.
*/
+/*ARGSUSED*/
static int
-ufs_dump(vnode_t *vp, caddr_t addr, int ldbn, int dblks)
+ufs_dump(vnode_t *vp, caddr_t addr, int ldbn, int dblks, caller_context_t *ct)
{
u_offset_t file_size;
struct inode *ip = VTOI(vp);
@@ -6019,8 +6070,9 @@ ufs_dump(vnode_t *vp, caddr_t addr, int ldbn, int dblks)
* if found, the starting file-relative DEV_BSIZE lbn is written
* to *bklp; that lbn is intended for use with VOP_DUMP()
*/
+/*ARGSUSED*/
static int
-ufs_dumpctl(vnode_t *vp, int action, int *blkp)
+ufs_dumpctl(vnode_t *vp, int action, int *blkp, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
ufsvfs_t *ufsvfsp = ip->i_ufsvfs;
@@ -6199,7 +6251,7 @@ save_dblks(struct inode *ip, struct ufsvfs *ufsvfsp, daddr32_t *storeblk,
/* ARGSUSED */
static int
ufs_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ulockfs *ulp;
@@ -6230,7 +6282,8 @@ ufs_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag,
/* ARGSUSED */
static int
-ufs_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
+ufs_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ulockfs *ulp = NULL;
diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c
index a1b7059e9b..3b0f7afec0 100644
--- a/usr/src/uts/common/fs/vfs.c
+++ b/usr/src/uts/common/fs/vfs.c
@@ -83,6 +83,7 @@
#include <sys/objfs.h>
#include <sys/console.h>
#include <sys/reboot.h>
+#include <sys/attr.h>
#include <vm/page.h>
@@ -120,6 +121,8 @@ static kmutex_t vfs_miplist_mutex;
static struct ipmnt *vfs_miplist = NULL;
static struct ipmnt *vfs_miplist_end = NULL;
+static kmem_cache_t *vfs_cache; /* Pointer to VFS kmem cache */
+
/*
* VFS global data.
*/
@@ -257,6 +260,21 @@ fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
int
fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
{
+ /*
+ * In order to handle system attribute fids in a manner
+ * transparent to the underlying fs, we embed the fid for
+ * the sysattr parent object in the sysattr fid and tack on
+ * some extra bytes that only the sysattr layer knows about.
+ *
+ * This guarantees that sysattr fids are larger than other fids
+ * for this vfs. If the vfs supports sysattrs (implied
+ * by VFSFT_XVATTR support), we cannot have a size collision
+ * with XATTR_FIDSZ.
+ */
+ if (vfs_has_feature(vfsp, VFSFT_XVATTR) &&
+ fidp->fid_len == XATTR_FIDSZ)
+ return (xattr_dir_vget(vfsp, vpp, fidp));
+
return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
}
@@ -442,7 +460,7 @@ vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
op = vfsp->vfs_op;
membar_consumer();
- if ((vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) &&
+ if (vfsp->vfs_femhead == NULL &&
casptr(&vfsp->vfs_op, op, vfsops) == op) {
return;
}
@@ -459,8 +477,7 @@ vfs_getops(vfs_t *vfsp)
op = vfsp->vfs_op;
membar_consumer();
- if ((vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) &&
- op == vfsp->vfs_op) {
+ if (vfsp->vfs_femhead == NULL && op == vfsp->vfs_op) {
return (op);
} else {
return (fsem_getvfsops(vfsp));
@@ -494,25 +511,16 @@ vfs_can_sync(vfs_t *vfsp)
void
vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
{
+ /* Other initialization has been moved to vfs_alloc() */
vfsp->vfs_count = 0;
vfsp->vfs_next = vfsp;
vfsp->vfs_prev = vfsp;
vfsp->vfs_zone_next = vfsp;
vfsp->vfs_zone_prev = vfsp;
- vfsp->vfs_flag = 0;
+ sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
+ vfsimpl_setup(vfsp);
vfsp->vfs_data = (data);
- vfsp->vfs_resource = NULL;
- vfsp->vfs_mntpt = NULL;
- vfsp->vfs_mntopts.mo_count = 0;
- vfsp->vfs_mntopts.mo_list = NULL;
- vfsp->vfs_implp = NULL;
- vfsp->vfs_zone = NULL;
- /*
- * Note: Don't initialize any member of the vfs_impl_t structure
- * here as it could be a problem for unbundled file systems.
- */
vfs_setops((vfsp), (op));
- sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
}
/*
@@ -522,11 +530,22 @@ vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
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 this are #define'd in vfs.h */
- vfsp->vfs_femhead = NULL;
+ /* 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;
+ }
}
/*
@@ -542,13 +561,6 @@ vfsimpl_teardown(vfs_t *vfsp)
if (vip == NULL)
return;
- if (vip->vi_femhead) {
- ASSERT(vip->vi_femhead->femh_list == NULL);
- mutex_destroy(&vip->vi_femhead->femh_lock);
- kmem_free(vip->vi_femhead, sizeof (*(vip->vi_femhead)));
- vip->vi_femhead = NULL;
- }
-
kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
vfsp->vfs_implp = NULL;
}
@@ -1308,22 +1320,21 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
goto errout;
}
/*
- * Changing the NBMAND setting on remounts is permitted
- * but logged since it can lead to unexpected behavior.
- * We also counsel against using it for / and /usr.
+ * Disallow changing the NBMAND disposition of the file
+ * system on remounts.
*/
if ((nbmand && ((vp->v_vfsp->vfs_flag & VFS_NBMAND) == 0)) ||
(!nbmand && (vp->v_vfsp->vfs_flag & VFS_NBMAND))) {
- cmn_err(CE_WARN, "domount: nbmand turned %s via "
- "remounting %s", nbmand ? "on" : "off",
- refstr_value(vp->v_vfsp->vfs_mntpt));
+ vn_vfsunlock(vp);
+ error = EINVAL;
+ goto errout;
}
vfsp = vp->v_vfsp;
ovflags = vfsp->vfs_flag;
vfsp->vfs_flag |= VFS_REMOUNT;
vfsp->vfs_flag &= ~VFS_RDONLY;
} else {
- vfsp = kmem_alloc(sizeof (vfs_t), KM_SLEEP);
+ vfsp = vfs_alloc(KM_SLEEP);
VFS_INIT(vfsp, vfsops, NULL);
}
@@ -1350,9 +1361,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
vfsp->vfs_flag = ovflags;
if (splice)
vn_vfsunlock(vp);
- if (vfsp->vfs_implp)
- vfsimpl_teardown(vfsp);
- kmem_free(vfsp, sizeof (struct vfs));
+ vfs_free(vfsp);
goto errout;
}
} else {
@@ -1444,7 +1453,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
/*
* going to mount on this vnode, so notify.
*/
- vnevent_mountedover(vp);
+ vnevent_mountedover(vp, NULL);
error = VFS_MOUNT(vfsp, vp, uap, credp);
if (uap->flags & MS_RDONLY)
@@ -1472,9 +1481,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
} else {
vfs_unlock(vfsp);
vfs_freemnttab(vfsp);
- if (vfsp->vfs_implp)
- vfsimpl_teardown(vfsp);
- kmem_free(vfsp, sizeof (struct vfs));
+ vfs_free(vfsp);
}
} else {
/*
@@ -2597,7 +2604,8 @@ vfs_mntdummywrite(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred,
*/
/* ARGSUSED */
static int
-vfs_mntdummygetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+vfs_mntdummygetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
bzero(vap, sizeof (vattr_t));
vap->va_type = VREG;
@@ -3996,12 +4004,14 @@ vfsinit(void)
NULL, NULL
};
- /* Initialize the vnode cache (file systems may use it during init). */
+ /* Create vfs cache */
+ vfs_cache = kmem_cache_create("vfs_cache", sizeof (struct vfs),
+ sizeof (uintptr_t), NULL, NULL, NULL, NULL, NULL, 0);
+ /* Initialize the vnode cache (file systems may use it during init). */
vn_create_cache();
/* Setup event monitor framework */
-
fem_init();
/* Initialize the dummy stray file system type. */
@@ -4044,6 +4054,52 @@ vfsinit(void)
EIO_vfs.vfs_vskap = NULL;
EIO_vfs.vfs_flag |= VFS_STATS;
}
+
+ xattr_init();
+}
+
+vfs_t *
+vfs_alloc(int kmflag)
+{
+ vfs_t *vfsp;
+
+ vfsp = kmem_cache_alloc(vfs_cache, 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".
+ * The problem is that this gets called out of domount() with
+ * a partially initialized vfs and a vfs_count of 1. This is
+ * also called from vfs_rele() with a vfs_count of 0. We can't
+ * call VFS_RELE() from domount() if VFS_MOUNT() hasn't successfully
+ * returned. This is because VFS_MOUNT() fully initializes the
+ * vfs structure and its associated data. VFS_RELE() will call
+ * VFS_FREEVFS() which may panic the system if the data structures
+ * aren't fully initialized from a successful VFS_MOUNT()).
+ */
+
+ /* If FEM was in use, make sure everything gets cleaned up */
+ if (vfsp->vfs_femhead) {
+ ASSERT(vfsp->vfs_femhead->femh_list == NULL);
+ mutex_destroy(&vfsp->vfs_femhead->femh_lock);
+ kmem_free(vfsp->vfs_femhead, sizeof (*(vfsp->vfs_femhead)));
+ vfsp->vfs_femhead = NULL;
+ }
+
+ if (vfsp->vfs_implp)
+ vfsimpl_teardown(vfsp);
+ sema_destroy(&vfsp->vfs_reflock);
+ kmem_cache_free(vfs_cache, vfsp);
}
/*
@@ -4070,10 +4126,7 @@ vfs_rele(vfs_t *vfsp)
if (vfsp->vfs_zone)
zone_rele(vfsp->vfs_zone);
vfs_freemnttab(vfsp);
- if (vfsp->vfs_implp)
- vfsimpl_teardown(vfsp);
- sema_destroy(&vfsp->vfs_reflock);
- kmem_free(vfsp, sizeof (*vfsp));
+ vfs_free(vfsp);
}
}
@@ -4346,3 +4399,40 @@ getrootfs(char **fstypp, char **fsmodp)
*fsmodp = "nfs";
}
#endif
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+}
diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c
index 2e0364a2d4..5431d1ed09 100644
--- a/usr/src/uts/common/fs/vnode.c
+++ b/usr/src/uts/common/fs/vnode.c
@@ -361,6 +361,36 @@ static const fs_operation_trans_def_t vn_ops_table[] = {
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);
+}
+
/*
* Used by the AVL routines to compare two vsk_anchor_t structures in the tree.
* We use the f_fsid reported by VFS_STATVFS() since we use that for the
@@ -740,7 +770,7 @@ vn_rdwr(
if (error != 0)
goto done;
if (nbl_conflict(vp, rw == UIO_WRITE ? NBL_WRITE : NBL_READ,
- uio.uio_offset, uio.uio_resid, svmand)) {
+ uio.uio_offset, uio.uio_resid, svmand, NULL)) {
error = EACCES;
goto done;
}
@@ -757,8 +787,8 @@ vn_rdwr(
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);
+ VOP_RWUNLOCK(vp,
+ rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
if (residp)
*residp = uio.uio_resid;
else if (uio.uio_resid)
@@ -789,7 +819,7 @@ vn_rele(vnode_t *vp)
mutex_enter(&vp->v_lock);
if (vp->v_count == 1) {
mutex_exit(&vp->v_lock);
- VOP_INACTIVE(vp, CRED());
+ VOP_INACTIVE(vp, CRED(), NULL);
} else {
vp->v_count--;
mutex_exit(&vp->v_lock);
@@ -812,7 +842,7 @@ vn_rele_stream(vnode_t *vp)
vp->v_stream = NULL;
if (vp->v_count == 1) {
mutex_exit(&vp->v_lock);
- VOP_INACTIVE(vp, CRED());
+ VOP_INACTIVE(vp, CRED(), NULL);
} else {
vp->v_count--;
mutex_exit(&vp->v_lock);
@@ -829,8 +859,8 @@ vn_open(
enum create crwhy,
mode_t umask)
{
- return (vn_openat(pnamep, seg, filemode,
- createmode, vpp, crwhy, umask, NULL));
+ return (vn_openat(pnamep, seg, filemode, createmode, vpp, crwhy,
+ umask, NULL, -1));
}
@@ -849,21 +879,30 @@ vn_openat(
struct vnode **vpp,
enum create crwhy,
mode_t umask,
- struct vnode *startvp)
+ struct vnode *startvp,
+ int fd)
{
struct vnode *vp;
int mode;
+ int accessflags;
int error;
int in_crit = 0;
+ int open_done = 0;
+ int shrlock_done = 0;
struct vattr vattr;
enum symfollow follow;
int estale_retry = 0;
+ struct shrlock shr;
+ struct shr_locowner shr_own;
mode = 0;
+ accessflags = 0;
if (filemode & FREAD)
mode |= VREAD;
if (filemode & (FWRITE|FTRUNC))
mode |= VWRITE;
+ if (filemode & FXATTRDIROPEN)
+ mode |= VEXEC;
/* symlink interpretation */
if (filemode & FNOFOLLOW)
@@ -871,6 +910,9 @@ vn_openat(
else
follow = FOLLOW;
+ if (filemode & FAPPEND)
+ accessflags |= V_APPEND;
+
top:
if (filemode & FCREAT) {
enum vcexcl excl;
@@ -914,7 +956,8 @@ top:
if (!(filemode & FOFFMAX) && (vp->v_type == VREG)) {
vattr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
+ if ((error = VOP_GETATTR(vp, &vattr, 0,
+ CRED(), NULL))) {
goto out;
}
if (vattr.va_size > (u_offset_t)MAXOFF32_T) {
@@ -944,36 +987,19 @@ top:
goto out;
}
/*
- * Can't truncate files on which mandatory locking
- * or non-blocking mandatory locking is in effect.
+ * Can't truncate files on which
+ * sysv mandatory locking is in effect.
*/
if (filemode & FTRUNC) {
vnode_t *rvp;
- if (VOP_REALVP(vp, &rvp) != 0)
+ if (VOP_REALVP(vp, &rvp, NULL) != 0)
rvp = vp;
- if (nbl_need_check(vp)) {
- nbl_start_crit(vp, RW_READER);
- in_crit = 1;
- vattr.va_mask = AT_MODE|AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0,
- CRED())) == 0) {
- if (rvp->v_filocks != NULL)
- if (MANDLOCK(vp,
- vattr.va_mode))
- error = EAGAIN;
- if (!error) {
- if (nbl_conflict(vp,
- NBL_WRITE, 0,
- vattr.va_size, 0))
- error = EACCES;
- }
- }
- } else if (rvp->v_filocks != NULL) {
+ if (rvp->v_filocks != NULL) {
vattr.va_mask = AT_MODE;
- if ((error = VOP_GETATTR(vp, &vattr,
- 0, CRED())) == 0 && MANDLOCK(vp,
- vattr.va_mode))
+ if ((error = VOP_GETATTR(vp,
+ &vattr, 0, CRED(), NULL)) == 0 &&
+ MANDLOCK(vp, vattr.va_mode))
error = EAGAIN;
}
}
@@ -983,7 +1009,7 @@ top:
/*
* Check permissions.
*/
- if (error = VOP_ACCESS(vp, mode, 0, CRED()))
+ if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
goto out;
}
@@ -996,7 +1022,7 @@ top:
}
if (filemode & FNOLINKS) {
vattr.va_mask = AT_NLINK;
- if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
+ if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
goto out;
}
if (vattr.va_nlink != 1) {
@@ -1020,25 +1046,66 @@ top:
if (vp->v_type == VSOCK) {
struct vnode *nvp;
- error = VOP_REALVP(vp, &nvp);
+ error = VOP_REALVP(vp, &nvp, NULL);
if (error != 0 || nvp == NULL || nvp == vp ||
nvp->v_type != VSOCK) {
error = EOPNOTSUPP;
goto out;
}
}
+
+ if ((vp->v_type == VREG) && nbl_need_check(vp)) {
+ /* get share reservation */
+ shr.s_access = 0;
+ if (filemode & FWRITE)
+ shr.s_access |= F_WRACC;
+ if (filemode & FREAD)
+ shr.s_access |= F_RDACC;
+ shr.s_deny = 0;
+ shr.s_sysid = 0;
+ shr.s_pid = ttoproc(curthread)->p_pid;
+ shr_own.sl_pid = shr.s_pid;
+ shr_own.sl_id = fd;
+ shr.s_own_len = sizeof (shr_own);
+ shr.s_owner = (caddr_t)&shr_own;
+ error = VOP_SHRLOCK(vp, F_SHARE_NBMAND, &shr, filemode, CRED(),
+ NULL);
+ if (error)
+ goto out;
+ shrlock_done = 1;
+
+ /* nbmand conflict check if truncating file */
+ if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
+ nbl_start_crit(vp, RW_READER);
+ in_crit = 1;
+
+ vattr.va_mask = AT_SIZE;
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
+ goto out;
+ if (nbl_conflict(vp, NBL_WRITE, 0, vattr.va_size, 0,
+ NULL)) {
+ error = EACCES;
+ goto out;
+ }
+ }
+ }
+
/*
* Do opening protocol.
*/
- error = VOP_OPEN(&vp, filemode, CRED());
+ error = VOP_OPEN(&vp, filemode, CRED(), NULL);
+ if (error)
+ goto out;
+ open_done = 1;
+
/*
* Truncate if required.
*/
- if (error == 0 && (filemode & FTRUNC) && !(filemode & FCREAT)) {
+ if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
vattr.va_size = 0;
vattr.va_mask = AT_SIZE;
if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
- (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED());
+ goto out;
}
out:
ASSERT(vp->v_count > 0);
@@ -1048,6 +1115,18 @@ out:
in_crit = 0;
}
if (error) {
+ if (open_done) {
+ (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
+ NULL);
+ open_done = 0;
+ shrlock_done = 0;
+ }
+ if (shrlock_done) {
+ (void) VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, CRED(),
+ NULL);
+ shrlock_done = 0;
+ }
+
/*
* The following clause was added to handle a problem
* with NFS consistency. It is possible that a lookup
@@ -1068,6 +1147,49 @@ out:
return (error);
}
+/*
+ * The following two accessor functions are for the NFSv4 server. Since there
+ * is no VOP_OPEN_UP/DOWNGRADE we need a way for the NFS server to keep the
+ * vnode open counts correct when a client "upgrades" an open or does an
+ * open_downgrade. In NFS, an upgrade or downgrade can not only change the
+ * open mode (add or subtract read or write), but also change the share/deny
+ * modes. However, share reservations are not integrated with OPEN, yet, so
+ * we need to handle each separately. These functions are cleaner than having
+ * the NFS server manipulate the counts directly, however, nobody else should
+ * use these functions.
+ */
+void
+vn_open_upgrade(
+ vnode_t *vp,
+ int filemode)
+{
+ ASSERT(vp->v_type == VREG);
+
+ if (filemode & FREAD)
+ atomic_add_32(&(vp->v_rdcnt), 1);
+ if (filemode & FWRITE)
+ atomic_add_32(&(vp->v_wrcnt), 1);
+
+}
+
+void
+vn_open_downgrade(
+ vnode_t *vp,
+ int filemode)
+{
+ ASSERT(vp->v_type == VREG);
+
+ if (filemode & FREAD) {
+ ASSERT(vp->v_rdcnt > 0);
+ atomic_add_32(&(vp->v_rdcnt), -1);
+ }
+ if (filemode & FWRITE) {
+ ASSERT(vp->v_wrcnt > 0);
+ atomic_add_32(&(vp->v_wrcnt), -1);
+ }
+
+}
+
int
vn_create(
char *pnamep,
@@ -1080,8 +1202,8 @@ vn_create(
int flag,
mode_t umask)
{
- return (vn_createat(pnamep, seg, vap, excl, mode, vpp,
- why, flag, umask, NULL));
+ return (vn_createat(pnamep, seg, vap, excl, mode, vpp, why, flag,
+ umask, NULL));
}
/*
@@ -1171,7 +1293,7 @@ top:
vsec.vsa_dfaclcnt = 0;
vsec.vsa_dfaclentp = NULL;
vsec.vsa_mask = VSA_DFACLCNT;
- error = VOP_GETSECATTR(dvp, &vsec, 0, CRED());
+ error = VOP_GETSECATTR(dvp, &vsec, 0, CRED(), NULL);
/*
* If error is ENOSYS then treat it as no error
* Don't want to force all file systems to support
@@ -1230,7 +1352,7 @@ top:
* applied, return error.
*/
vp = *vpp;
- if (VOP_REALVP(vp, &rvp) != 0)
+ if (VOP_REALVP(vp, &rvp, NULL) != 0)
rvp = vp;
if ((vap->va_mask & AT_SIZE) && nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
@@ -1238,7 +1360,7 @@ top:
}
if (rvp->v_filocks != NULL || rvp->v_shrlocks != NULL) {
vattr.va_mask = AT_MODE|AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED())) {
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) {
goto out;
}
if (MANDLOCK(vp, vattr.va_mode)) {
@@ -1259,7 +1381,7 @@ top:
vap->va_size - vattr.va_size :
vattr.va_size - vap->va_size;
if (nbl_conflict(vp, NBL_WRITE, offset,
- length, 0)) {
+ length, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1281,9 +1403,8 @@ top:
*/
if (vp->v_flag & VROOT) {
ASSERT(why != CRMKDIR);
- error =
- VOP_CREATE(vp, "", vap, excl, mode, vpp, CRED(),
- flag);
+ error = VOP_CREATE(vp, "", vap, excl, mode, vpp,
+ CRED(), flag, NULL, NULL);
/*
* If the create succeeded, it will have created
* a new reference to the vnode. Give up the
@@ -1307,7 +1428,8 @@ top:
!(flag & FOFFMAX) &&
(vp->v_type == VREG)) {
vattr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
+ if ((error = VOP_GETATTR(vp, &vattr, 0,
+ CRED(), NULL))) {
goto out;
}
if ((vattr.va_size > (u_offset_t)MAXOFF32_T)) {
@@ -1324,10 +1446,17 @@ top:
int must_be_dir = pn_fixslash(&pn); /* trailing '/'? */
if (why == CRMKDIR)
- error = VOP_MKDIR(dvp, pn.pn_path, vap, vpp, CRED());
+ /*
+ * 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, pn.pn_path, vap, vpp, CRED(),
+ NULL, 0, NULL);
else if (!must_be_dir)
error = VOP_CREATE(dvp, pn.pn_path, vap,
- excl, mode, vpp, CRED(), flag);
+ excl, mode, vpp, CRED(), flag, NULL, NULL);
else
error = ENOTDIR;
}
@@ -1389,11 +1518,11 @@ top:
* in the same vfs and that it is writeable.
*/
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(fvp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(fvp, &vattr, 0, CRED(), NULL))
goto out;
fsid = vattr.va_fsid;
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(tdvp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(tdvp, &vattr, 0, CRED(), NULL))
goto out;
if (fsid != vattr.va_fsid) {
error = EXDEV;
@@ -1407,7 +1536,7 @@ top:
* Do the link.
*/
(void) pn_fixslash(&pn);
- error = VOP_LINK(tdvp, fvp, pn.pn_path, CRED());
+ error = VOP_LINK(tdvp, fvp, pn.pn_path, CRED(), NULL, 0);
out:
pn_free(&pn);
if (fvp)
@@ -1434,13 +1563,14 @@ vn_renameat(vnode_t *fdvp, char *fname, vnode_t *tdvp,
struct pathname fpn; /* from pathname */
struct pathname tpn; /* to pathname */
dev_t fsid;
- int in_crit = 0;
+ int in_crit_src, in_crit_targ;
vnode_t *fromvp, *fvp;
- vnode_t *tovp;
+ vnode_t *tovp, *targvp;
int estale_retry = 0;
top:
- fvp = fromvp = tovp = NULL;
+ fvp = fromvp = tovp = targvp = NULL;
+ in_crit_src = in_crit_targ = 0;
/*
* Get to and from pathnames.
*/
@@ -1483,7 +1613,7 @@ top:
if (audit_active)
audit_setfsat_path(3);
#endif /* C2_AUDIT */
- if (error = lookuppnat(&tpn, NULL, NO_FOLLOW, &tovp, NULLVPP, tdvp)) {
+ if (error = lookuppnat(&tpn, NULL, NO_FOLLOW, &tovp, &targvp, tdvp)) {
goto out;
}
@@ -1494,11 +1624,11 @@ top:
*/
if (fromvp != tovp) {
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(fromvp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(fromvp, &vattr, 0, CRED(), NULL))
goto out;
fsid = vattr.va_fsid;
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(tovp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(tovp, &vattr, 0, CRED(), NULL))
goto out;
if (fsid != vattr.va_fsid) {
error = EXDEV;
@@ -1511,10 +1641,19 @@ top:
goto out;
}
+ if (targvp && (fvp != targvp)) {
+ nbl_start_crit(targvp, RW_READER);
+ in_crit_targ = 1;
+ if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
+ error = EACCES;
+ goto out;
+ }
+ }
+
if (nbl_need_check(fvp)) {
nbl_start_crit(fvp, RW_READER);
- in_crit = 1;
- if (nbl_conflict(fvp, NBL_RENAME, 0, 0, 0)) {
+ in_crit_src = 1;
+ if (nbl_conflict(fvp, NBL_RENAME, 0, 0, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1524,19 +1663,22 @@ top:
* Do the rename.
*/
(void) pn_fixslash(&tpn);
- error = VOP_RENAME(fromvp, fpn.pn_path, tovp, tpn.pn_path, CRED());
+ error = VOP_RENAME(fromvp, fpn.pn_path, tovp, tpn.pn_path, CRED(),
+ NULL, 0);
out:
pn_free(&fpn);
pn_free(&tpn);
- if (in_crit) {
+ if (in_crit_src)
nbl_end_crit(fvp);
- in_crit = 0;
- }
+ if (in_crit_targ)
+ nbl_end_crit(targvp);
if (fromvp)
VN_RELE(fromvp);
if (tovp)
VN_RELE(tovp);
+ if (targvp)
+ VN_RELE(targvp);
if (fvp)
VN_RELE(fvp);
if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
@@ -1691,7 +1833,7 @@ top:
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1715,14 +1857,15 @@ top:
cwd = PTOU(pp)->u_cdir;
VN_HOLD(cwd);
mutex_exit(&pp->p_lock);
- error = VOP_RMDIR(dvp, pn.pn_path, cwd, CRED());
+ error = VOP_RMDIR(dvp, pn.pn_path, cwd, CRED(),
+ NULL, 0);
VN_RELE(cwd);
}
} else {
/*
* Unlink(2) can be applied to anything.
*/
- error = VOP_REMOVE(dvp, pn.pn_path, CRED());
+ error = VOP_REMOVE(dvp, pn.pn_path, CRED(), NULL, 0);
}
out:
@@ -1750,9 +1893,9 @@ vn_compare(vnode_t *vp1, vnode_t *vp2)
{
vnode_t *realvp;
- if (vp1 != NULL && VOP_REALVP(vp1, &realvp) == 0)
+ if (vp1 != NULL && VOP_REALVP(vp1, &realvp, NULL) == 0)
vp1 = realvp;
- if (vp2 != NULL && VOP_REALVP(vp2, &realvp) == 0)
+ if (vp2 != NULL && VOP_REALVP(vp2, &realvp, NULL) == 0)
vp2 = realvp;
return (VN_CMP(vp1, vp2));
}
@@ -2170,6 +2313,7 @@ vn_reinit(vnode_t *vp)
vp->v_msflags = 0;
vp->v_msnext = NULL;
vp->v_msprev = NULL;
+ vp->v_xattrdir = NULL;
/* Handles v_femhead, v_path, and the r/w/map counts */
vn_recycle(vp);
@@ -2194,6 +2338,9 @@ vn_alloc(int kmflag)
void
vn_free(vnode_t *vp)
{
+ ASSERT(vp->v_shrlocks == NULL);
+ ASSERT(vp->v_filocks == NULL);
+
/*
* Some file systems call vn_free() with v_count of zero,
* some with v_count of 1. In any case, the value should
@@ -2275,84 +2422,85 @@ vn_invalid(vnode_t *vp)
/* Vnode event notification */
int
-vnevent_support(vnode_t *vp)
+vnevent_support(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL)
return (EINVAL);
- return (VOP_VNEVENT(vp, VE_SUPPORT, NULL, NULL));
+ return (VOP_VNEVENT(vp, VE_SUPPORT, NULL, NULL, ct));
}
void
-vnevent_rename_src(vnode_t *vp, vnode_t *dvp, char *name)
+vnevent_rename_src(vnode_t *vp, vnode_t *dvp, char *name, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_RENAME_SRC, dvp, name);
+ (void) VOP_VNEVENT(vp, VE_RENAME_SRC, dvp, name, ct);
}
void
-vnevent_rename_dest(vnode_t *vp, vnode_t *dvp, char *name)
+vnevent_rename_dest(vnode_t *vp, vnode_t *dvp, char *name,
+ caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_RENAME_DEST, dvp, name);
+ (void) VOP_VNEVENT(vp, VE_RENAME_DEST, dvp, name, ct);
}
void
-vnevent_rename_dest_dir(vnode_t *vp)
+vnevent_rename_dest_dir(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_RENAME_DEST_DIR, NULL, NULL);
+ (void) VOP_VNEVENT(vp, VE_RENAME_DEST_DIR, NULL, NULL, ct);
}
void
-vnevent_remove(vnode_t *vp, vnode_t *dvp, char *name)
+vnevent_remove(vnode_t *vp, vnode_t *dvp, char *name, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_REMOVE, dvp, name);
+ (void) VOP_VNEVENT(vp, VE_REMOVE, dvp, name, ct);
}
void
-vnevent_rmdir(vnode_t *vp, vnode_t *dvp, char *name)
+vnevent_rmdir(vnode_t *vp, vnode_t *dvp, char *name, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_RMDIR, dvp, name);
+ (void) VOP_VNEVENT(vp, VE_RMDIR, dvp, name, ct);
}
void
-vnevent_create(vnode_t *vp)
+vnevent_create(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_CREATE, NULL, NULL);
+ (void) VOP_VNEVENT(vp, VE_CREATE, NULL, NULL, ct);
}
void
-vnevent_link(vnode_t *vp)
+vnevent_link(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_LINK, NULL, NULL);
+ (void) VOP_VNEVENT(vp, VE_LINK, NULL, NULL, ct);
}
void
-vnevent_mountedover(vnode_t *vp)
+vnevent_mountedover(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_MOUNTEDOVER, NULL, NULL);
+ (void) VOP_VNEVENT(vp, VE_MOUNTEDOVER, NULL, NULL, ct);
}
/*
@@ -2400,7 +2548,7 @@ vn_can_change_zones(vnode_t *vp)
/*
* We always want to look at the underlying vnode if there is one.
*/
- if (VOP_REALVP(vp, &rvp) != 0)
+ if (VOP_REALVP(vp, &rvp, NULL) != 0)
rvp = vp;
/*
* Some pseudo filesystems (including doorfs) don't actually register
@@ -2433,6 +2581,45 @@ vn_mountedvfs(vnode_t *vp)
}
/*
+ * 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.
*
@@ -2821,7 +3008,8 @@ int
fop_open(
vnode_t **vpp,
int mode,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int ret;
vnode_t *vp = *vpp;
@@ -2848,7 +3036,7 @@ fop_open(
VOPXID_MAP_CR(vp, cr);
- ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr);
+ ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr, ct);
if (ret) {
/*
@@ -2892,13 +3080,14 @@ fop_close(
int flag,
int count,
offset_t offset,
- cred_t *cr)
+ 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);
+ 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
@@ -2923,7 +3112,7 @@ fop_read(
uio_t *uiop,
int ioflag,
cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int err;
ssize_t resid_start = uiop->uio_resid;
@@ -2942,7 +3131,7 @@ fop_write(
uio_t *uiop,
int ioflag,
cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int err;
ssize_t resid_start = uiop->uio_resid;
@@ -2962,13 +3151,14 @@ fop_ioctl(
intptr_t arg,
int flag,
cred_t *cr,
- int *rvalp)
+ 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);
+ err = (*(vp)->v_op->vop_ioctl)(vp, cmd, arg, flag, cr, rvalp, ct);
VOPSTATS_UPDATE(vp, ioctl);
return (err);
}
@@ -2978,13 +3168,14 @@ fop_setfl(
vnode_t *vp,
int oflags,
int nflags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr);
+ err = (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr, ct);
VOPSTATS_UPDATE(vp, setfl);
return (err);
}
@@ -2994,13 +3185,30 @@ fop_getattr(
vnode_t *vp,
vattr_t *vap,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_getattr)(vp, vap, flags, 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);
}
@@ -3017,6 +3225,22 @@ fop_setattr(
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);
@@ -3027,13 +3251,19 @@ fop_access(
vnode_t *vp,
int mode,
int flags,
- cred_t *cr)
+ 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);
+ err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct);
VOPSTATS_UPDATE(vp, access);
return (err);
}
@@ -3046,13 +3276,32 @@ fop_lookup(
pathname_t *pnp,
int flags,
vnode_t *rdir,
- cred_t *cr)
+ 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);
- ret = (*(dvp)->v_op->vop_lookup)(dvp, nm, vpp, pnp, flags, rdir, cr);
+ if ((flags & LOOKUP_XATTR) && (flags & LOOKUP_HAVE_SYSATTR_DIR) == 0) {
+ ret = xattr_dir_lookup(dvp, vpp, flags, cr);
+ } else {
+ ret = (*(dvp)->v_op->vop_lookup)
+ (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp);
+ }
if (ret == 0 && *vpp) {
VOPSTATS_UPDATE(*vpp, lookup);
if ((*vpp)->v_path == NULL) {
@@ -3072,14 +3321,29 @@ fop_create(
int mode,
vnode_t **vpp,
cred_t *cr,
- int flag)
+ 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, flag);
+ (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp);
if (ret == 0 && *vpp) {
VOPSTATS_UPDATE(*vpp, create);
if ((*vpp)->v_path == NULL) {
@@ -3094,13 +3358,24 @@ int
fop_remove(
vnode_t *dvp,
char *nm,
- cred_t *cr)
+ 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);
+ err = (*(dvp)->v_op->vop_remove)(dvp, nm, cr, ct, flags);
VOPSTATS_UPDATE(dvp, remove);
return (err);
}
@@ -3110,13 +3385,24 @@ fop_link(
vnode_t *tdvp,
vnode_t *svp,
char *tnm,
- cred_t *cr)
+ 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);
+ err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags);
VOPSTATS_UPDATE(tdvp, link);
return (err);
}
@@ -3127,13 +3413,25 @@ fop_rename(
char *snm,
vnode_t *tdvp,
char *tnm,
- cred_t *cr)
+ 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);
+ err = (*(sdvp)->v_op->vop_rename)(sdvp, snm, tdvp, tnm, cr, ct, flags);
VOPSTATS_UPDATE(sdvp, rename);
return (err);
}
@@ -3144,13 +3442,30 @@ fop_mkdir(
char *dirname,
vattr_t *vap,
vnode_t **vpp,
- cred_t *cr)
+ 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);
+ ret = (*(dvp)->v_op->vop_mkdir)
+ (dvp, dirname, vap, vpp, cr, ct, flags, vsecp);
if (ret == 0 && *vpp) {
VOPSTATS_UPDATE(*vpp, mkdir);
if ((*vpp)->v_path == NULL) {
@@ -3167,13 +3482,24 @@ fop_rmdir(
vnode_t *dvp,
char *nm,
vnode_t *cdir,
- cred_t *cr)
+ 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);
+ err = (*(dvp)->v_op->vop_rmdir)(dvp, nm, cdir, cr, ct, flags);
VOPSTATS_UPDATE(dvp, rmdir);
return (err);
}
@@ -3183,14 +3509,24 @@ fop_readdir(
vnode_t *vp,
uio_t *uiop,
cred_t *cr,
- int *eofp)
+ 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);
+ 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);
@@ -3202,13 +3538,25 @@ fop_symlink(
char *linkname,
vattr_t *vap,
char *target,
- cred_t *cr)
+ 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_symlink) (dvp, linkname, vap, target, cr);
+ err = (*(dvp)->v_op->vop_symlink)
+ (dvp, linkname, vap, target, cr, ct, flags);
VOPSTATS_UPDATE(dvp, symlink);
return (err);
}
@@ -3217,13 +3565,14 @@ int
fop_readlink(
vnode_t *vp,
uio_t *uiop,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_readlink)(vp, uiop, cr);
+ err = (*(vp)->v_op->vop_readlink)(vp, uiop, cr, ct);
VOPSTATS_UPDATE(vp, readlink);
return (err);
}
@@ -3232,13 +3581,14 @@ int
fop_fsync(
vnode_t *vp,
int syncflag,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_fsync)(vp, syncflag, cr);
+ err = (*(vp)->v_op->vop_fsync)(vp, syncflag, cr, ct);
VOPSTATS_UPDATE(vp, fsync);
return (err);
}
@@ -3246,24 +3596,26 @@ fop_fsync(
void
fop_inactive(
vnode_t *vp,
- cred_t *cr)
+ 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);
+ (*(vp)->v_op->vop_inactive)(vp, cr, ct);
}
int
fop_fid(
vnode_t *vp,
- fid_t *fidp)
+ fid_t *fidp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_fid)(vp, fidp);
+ err = (*(vp)->v_op->vop_fid)(vp, fidp, ct);
VOPSTATS_UPDATE(vp, fid);
return (err);
}
@@ -3295,11 +3647,12 @@ int
fop_seek(
vnode_t *vp,
offset_t ooff,
- offset_t *noffp)
+ offset_t *noffp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_seek)(vp, ooff, noffp);
+ err = (*(vp)->v_op->vop_seek)(vp, ooff, noffp, ct);
VOPSTATS_UPDATE(vp, seek);
return (err);
}
@@ -3307,11 +3660,12 @@ fop_seek(
int
fop_cmp(
vnode_t *vp1,
- vnode_t *vp2)
+ vnode_t *vp2,
+ caller_context_t *ct)
{
int err;
- err = (*(vp1)->v_op->vop_cmp)(vp1, vp2);
+ err = (*(vp1)->v_op->vop_cmp)(vp1, vp2, ct);
VOPSTATS_UPDATE(vp1, cmp);
return (err);
}
@@ -3324,14 +3678,15 @@ fop_frlock(
int flag,
offset_t offset,
struct flk_callback *flk_cbp,
- cred_t *cr)
+ 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);
+ (vp, cmd, bfp, flag, offset, flk_cbp, cr, ct);
VOPSTATS_UPDATE(vp, frlock);
return (err);
}
@@ -3358,11 +3713,12 @@ fop_space(
int
fop_realvp(
vnode_t *vp,
- vnode_t **vpp)
+ vnode_t **vpp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_realvp)(vp, vpp);
+ err = (*(vp)->v_op->vop_realvp)(vp, vpp, ct);
VOPSTATS_UPDATE(vp, realvp);
return (err);
}
@@ -3378,14 +3734,15 @@ fop_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- cred_t *cr)
+ 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);
+ (vp, off, len, protp, plarr, plsz, seg, addr, rw, cr, ct);
VOPSTATS_UPDATE(vp, getpage);
return (err);
}
@@ -3396,13 +3753,14 @@ fop_putpage(
offset_t off,
size_t len,
int flags,
- cred_t *cr)
+ 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);
+ err = (*(vp)->v_op->vop_putpage)(vp, off, len, flags, cr, ct);
VOPSTATS_UPDATE(vp, putpage);
return (err);
}
@@ -3417,14 +3775,15 @@ fop_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- cred_t *cr)
+ 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);
+ (vp, off, as, addrp, len, prot, maxprot, flags, cr, ct);
VOPSTATS_UPDATE(vp, map);
return (err);
}
@@ -3439,7 +3798,8 @@ fop_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int error;
u_longlong_t delta;
@@ -3447,7 +3807,7 @@ fop_addmap(
VOPXID_MAP_CR(vp, cr);
error = (*(vp)->v_op->vop_addmap)
- (vp, off, as, addr, len, prot, maxprot, flags, cr);
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
if ((!error) && (vp->v_type == VREG)) {
delta = (u_longlong_t)btopr(len);
@@ -3488,7 +3848,8 @@ fop_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int error;
u_longlong_t delta;
@@ -3496,7 +3857,7 @@ fop_delmap(
VOPXID_MAP_CR(vp, cr);
error = (*(vp)->v_op->vop_delmap)
- (vp, off, as, addr, len, prot, maxprot, flags, cr);
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
/*
* NFS calls into delmap twice, the first time
@@ -3539,11 +3900,12 @@ fop_poll(
short events,
int anyyet,
short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp);
+ err = (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp, ct);
VOPSTATS_UPDATE(vp, poll);
return (err);
}
@@ -3553,11 +3915,12 @@ fop_dump(
vnode_t *vp,
caddr_t addr,
int lbdn,
- int dblks)
+ int dblks,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks);
+ err = (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks, ct);
VOPSTATS_UPDATE(vp, dump);
return (err);
}
@@ -3567,13 +3930,14 @@ fop_pathconf(
vnode_t *vp,
int cmd,
ulong_t *valp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr);
+ err = (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr, ct);
VOPSTATS_UPDATE(vp, pathconf);
return (err);
}
@@ -3585,13 +3949,14 @@ fop_pageio(
u_offset_t io_off,
size_t io_len,
int flags,
- cred_t *cr)
+ 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);
+ err = (*(vp)->v_op->vop_pageio)(vp, pp, io_off, io_len, flags, cr, ct);
VOPSTATS_UPDATE(vp, pageio);
return (err);
}
@@ -3600,10 +3965,11 @@ int
fop_dumpctl(
vnode_t *vp,
int action,
- int *blkp)
+ int *blkp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_dumpctl)(vp, action, blkp);
+ err = (*(vp)->v_op->vop_dumpctl)(vp, action, blkp, ct);
VOPSTATS_UPDATE(vp, dumpctl);
return (err);
}
@@ -3614,14 +3980,15 @@ fop_dispose(
page_t *pp,
int flag,
int dn,
- cred_t *cr)
+ 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);
+ (*(vp)->v_op->vop_dispose)(vp, pp, flag, dn, cr, ct);
}
int
@@ -3629,13 +3996,22 @@ fop_setsecattr(
vnode_t *vp,
vsecattr_t *vsap,
int flag,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, 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);
}
@@ -3645,13 +4021,23 @@ fop_getsecattr(
vnode_t *vp,
vsecattr_t *vsap,
int flag,
- cred_t *cr)
+ 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);
+ err = (*(vp)->v_op->vop_getsecattr) (vp, vsap, flag, cr, ct);
VOPSTATS_UPDATE(vp, getsecattr);
return (err);
}
@@ -3662,23 +4048,25 @@ fop_shrlock(
int cmd,
struct shrlock *shr,
int flag,
- cred_t *cr)
+ 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);
+ 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)
+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);
+ err = (*(vp)->v_op->vop_vnevent)(vp, vnevent, dvp, fnm, ct);
VOPSTATS_UPDATE(vp, vnevent);
return (err);
}
diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c
new file mode 100644
index 0000000000..65e0cd80d0
--- /dev/null
+++ b/usr/src/uts/common/fs/xattr.c
@@ -0,0 +1,1428 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#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/acl.h>
+#include <sys/file.h>
+#include <sys/sunddi.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/vnode.h>
+#include <sys/mode.h>
+#include <sys/nvpair.h>
+#include <sys/attr.h>
+#include <sys/gfs.h>
+#include <sys/mutex.h>
+#include <fs/fs_subr.h>
+#include <sys/kidmap.h>
+
+typedef struct {
+ gfs_file_t gfs_private;
+ xattr_view_t xattr_view;
+} xattr_file_t;
+
+/* ARGSUSED */
+static int
+xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
+{
+ xattr_file_t *np = (*vpp)->v_data;
+
+ if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE))
+ return (EACCES);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ xattr_file_t *np = vp->v_data;
+
+ if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE))
+ return (EACCES);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_close(vnode_t *vp, int flags, int count, offset_t off,
+ cred_t *cr, caller_context_t *ct)
+{
+ cleanlocks(vp, ddi_get_pid(), 0);
+ cleanshares(vp, ddi_get_pid());
+ return (0);
+}
+
+static int
+xattr_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
+{
+ xattr_fid_t *xfidp;
+ vnode_t *pvp, *savevp;
+ int error;
+ uint16_t orig_len;
+
+ if (fidp->fid_len < XATTR_FIDSZ) {
+ fidp->fid_len = XATTR_FIDSZ;
+ return (ENOSPC);
+ }
+
+ savevp = pvp = gfs_file_parent(vp);
+ mutex_enter(&savevp->v_lock);
+ if (pvp->v_flag & V_XATTRDIR) {
+ pvp = gfs_file_parent(pvp);
+ }
+ mutex_exit(&savevp->v_lock);
+
+ xfidp = (xattr_fid_t *)fidp;
+ orig_len = fidp->fid_len;
+ fidp->fid_len = sizeof (xfidp->parent_fid);
+
+ error = VOP_FID(pvp, fidp, ct);
+ if (error) {
+ fidp->fid_len = orig_len;
+ return (error);
+ }
+
+ xfidp->parent_len = fidp->fid_len;
+ fidp->fid_len = XATTR_FIDSZ;
+ xfidp->dir_offset = gfs_file_inode(vp);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
+ cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ f_attr_t attr;
+ uint64_t fsid;
+ dev_t mdev;
+ xvattr_t xvattr;
+ xoptattr_t *xoap; /* Pointer to optional attributes */
+ vnode_t *ppvp;
+ const char *domain;
+ uint32_t rid;
+
+ xva_init(&xvattr);
+
+ if ((xoap = xva_getxoptattr(&xvattr)) == NULL)
+ return (EINVAL);
+
+ /*
+ * For detecting ephemeral uid/gid
+ */
+ xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID);
+
+ /*
+ * We need to access the real fs object.
+ * vp points to a GFS file; ppvp points to the real object.
+ */
+ ppvp = gfs_file_parent(gfs_file_parent(vp));
+
+ /*
+ * Iterate through the attrs associated with this view
+ */
+
+ for (attr = 0; attr < F_ATTR_ALL; attr++) {
+ if (xattr_view != attr_to_xattr_view(attr)) {
+ continue;
+ }
+
+ switch (attr) {
+ case F_SYSTEM:
+ XVA_SET_REQ(&xvattr, XAT_SYSTEM);
+ break;
+ case F_READONLY:
+ XVA_SET_REQ(&xvattr, XAT_READONLY);
+ break;
+ case F_HIDDEN:
+ XVA_SET_REQ(&xvattr, XAT_HIDDEN);
+ break;
+ case F_ARCHIVE:
+ XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
+ break;
+ case F_IMMUTABLE:
+ XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
+ break;
+ case F_APPENDONLY:
+ XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
+ break;
+ case F_NOUNLINK:
+ XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
+ break;
+ case F_OPAQUE:
+ XVA_SET_REQ(&xvattr, XAT_OPAQUE);
+ break;
+ case F_NODUMP:
+ XVA_SET_REQ(&xvattr, XAT_NODUMP);
+ break;
+ case F_AV_QUARANTINED:
+ XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
+ break;
+ case F_AV_MODIFIED:
+ XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
+ break;
+ case F_AV_SCANSTAMP:
+ if (ppvp->v_type == VREG)
+ XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
+ break;
+ case F_CRTIME:
+ XVA_SET_REQ(&xvattr, XAT_CREATETIME);
+ break;
+ case F_FSID:
+ fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) |
+ (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] &
+ 0xffffffff));
+ VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr),
+ fsid) == 0);
+ break;
+ case F_MDEV:
+ mdev = ((int16_t)vp->v_vfsp->vfs_dev);
+ VERIFY(nvlist_add_uint16(nvlp, attr_to_name(attr),
+ mdev) == 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
+ if (error)
+ return (error);
+
+ /*
+ * Process all the optional attributes together here. Notice that
+ * xoap was set when the optional attribute bits were set above.
+ */
+ if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) {
+ if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_READONLY),
+ xoap->xoa_readonly) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_HIDDEN),
+ xoap->xoa_hidden) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_SYSTEM),
+ xoap->xoa_system) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_ARCHIVE),
+ xoap->xoa_archive) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_IMMUTABLE),
+ xoap->xoa_immutable) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_NOUNLINK),
+ xoap->xoa_nounlink) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_APPENDONLY),
+ xoap->xoa_appendonly) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_NODUMP),
+ xoap->xoa_nodump) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_OPAQUE),
+ xoap->xoa_opaque) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_AV_QUARANTINED),
+ xoap->xoa_av_quarantined) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_AV_MODIFIED),
+ xoap->xoa_av_modified) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) {
+ VERIFY(nvlist_add_uint8_array(nvlp,
+ attr_to_name(F_AV_SCANSTAMP),
+ xoap->xoa_av_scanstamp,
+ sizeof (xoap->xoa_av_scanstamp)) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) {
+ VERIFY(nvlist_add_uint64_array(nvlp,
+ attr_to_name(F_CRTIME),
+ (uint64_t *)&(xoap->xoa_createtime),
+ sizeof (xoap->xoa_createtime) /
+ sizeof (uint64_t)) == 0);
+ }
+ }
+ /*
+ * Check for optional ownersid/groupsid
+ */
+
+ if (xvattr.xva_vattr.va_uid > MAXUID) {
+ nvlist_t *nvl_sid;
+
+ if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
+ return (ENOMEM);
+
+ if (kidmap_getsidbyuid(xvattr.xva_vattr.va_uid,
+ &domain, &rid) == 0) {
+ VERIFY(nvlist_add_string(nvl_sid,
+ SID_DOMAIN, domain) == 0);
+ VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
+ VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID),
+ nvl_sid) == 0);
+ }
+ nvlist_free(nvl_sid);
+ }
+ if (xvattr.xva_vattr.va_gid > MAXUID) {
+ nvlist_t *nvl_sid;
+
+ if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
+ return (ENOMEM);
+
+ if (kidmap_getsidbygid(xvattr.xva_vattr.va_gid,
+ &domain, &rid) == 0) {
+ VERIFY(nvlist_add_string(nvl_sid,
+ SID_DOMAIN, domain) == 0);
+ VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
+ VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID),
+ nvl_sid) == 0);
+ }
+ nvlist_free(nvl_sid);
+ }
+
+ return (0);
+}
+
+/*
+ * The size of a sysattr file is the size of the nvlist that will be
+ * returned by xattr_file_read(). A call to xattr_file_write() could
+ * change the size of that nvlist. That size is not stored persistently
+ * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated.
+ */
+static int
+xattr_file_size(vnode_t *vp, xattr_view_t xattr_view, size_t *size,
+ cred_t *cr, caller_context_t *ct)
+{
+ nvlist_t *nvl;
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) {
+ return (ENOMEM);
+ }
+
+ if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) {
+ nvlist_free(nvl);
+ return (EFAULT);
+ }
+
+ VERIFY(nvlist_size(nvl, size, NV_ENCODE_XDR) == 0);
+ nvlist_free(nvl);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ xattr_file_t *np = vp->v_data;
+ timestruc_t now;
+ size_t size;
+ int error;
+ vnode_t *pvp;
+ vattr_t pvattr;
+
+ vap->va_type = VREG;
+ vap->va_mode = MAKEIMODE(vap->va_type,
+ (np->xattr_view == XATTR_VIEW_READONLY ? 0444 : 0644));
+ vap->va_nodeid = gfs_file_inode(vp);
+ vap->va_nlink = 1;
+ pvp = gfs_file_parent(vp);
+ (void) memset(&pvattr, 0, sizeof (pvattr));
+ pvattr.va_mask = AT_CTIME|AT_MTIME;
+ error = VOP_GETATTR(pvp, &pvattr, flags, cr, ct);
+ if (error) {
+ return (error);
+ }
+ vap->va_ctime = pvattr.va_ctime;
+ vap->va_mtime = pvattr.va_mtime;
+ gethrestime(&now);
+ vap->va_atime = now;
+ vap->va_uid = 0;
+ vap->va_gid = 0;
+ vap->va_rdev = 0;
+ vap->va_blksize = DEV_BSIZE;
+ vap->va_seq = 0;
+ vap->va_fsid = vp->v_vfsp->vfs_dev;
+ error = xattr_file_size(vp, np->xattr_view, &size, cr, ct);
+ vap->va_size = size;
+ vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
+ caller_context_t *ct)
+{
+ xattr_file_t *np = vp->v_data;
+ xattr_view_t xattr_view = np->xattr_view;
+ char *buf;
+ size_t filesize;
+ nvlist_t *nvl;
+ int error;
+
+ /*
+ * Validate file offset and fasttrack empty reads
+ */
+ if (uiop->uio_loffset < (offset_t)0)
+ return (EINVAL);
+
+ if (uiop->uio_resid == 0)
+ return (0);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP))
+ return (ENOMEM);
+
+ if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) {
+ nvlist_free(nvl);
+ return (EFAULT);
+ }
+
+ VERIFY(nvlist_size(nvl, &filesize, NV_ENCODE_XDR) == 0);
+
+ if (uiop->uio_loffset >= filesize) {
+ nvlist_free(nvl);
+ return (0);
+ }
+
+ buf = kmem_alloc(filesize, KM_SLEEP);
+ VERIFY(nvlist_pack(nvl, &buf, &filesize, NV_ENCODE_XDR,
+ KM_SLEEP) == 0);
+
+ error = uiomove((caddr_t)buf, filesize, UIO_READ, uiop);
+ kmem_free(buf, filesize);
+ nvlist_free(nvl);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error = 0;
+ char *buf;
+ char *domain;
+ uint32_t rid;
+ ssize_t size = uiop->uio_resid;
+ nvlist_t *nvp;
+ nvpair_t *pair = NULL;
+ vnode_t *ppvp;
+ xvattr_t xvattr;
+ xoptattr_t *xoap = NULL; /* Pointer to optional attributes */
+
+ /*
+ * Validate file offset and size.
+ */
+ if (uiop->uio_loffset < (offset_t)0)
+ return (EINVAL);
+
+ if (size == 0)
+ return (EINVAL);
+
+ xva_init(&xvattr);
+
+ if ((xoap = xva_getxoptattr(&xvattr)) == NULL) {
+ return (EINVAL);
+ }
+
+ /*
+ * Copy and unpack the nvlist
+ */
+ buf = kmem_alloc(size, KM_SLEEP);
+ if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) {
+ return (EFAULT);
+ }
+
+ if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) {
+ kmem_free(buf, size);
+ uiop->uio_resid = size;
+ return (EINVAL);
+ }
+ kmem_free(buf, size);
+
+ /*
+ * Fasttrack empty writes (nvlist with no nvpairs)
+ */
+ if (nvlist_next_nvpair(nvp, NULL) == 0)
+ return (0);
+
+ ppvp = gfs_file_parent(gfs_file_parent(vp));
+
+ while (pair = nvlist_next_nvpair(nvp, pair)) {
+ data_type_t type;
+ f_attr_t attr;
+ boolean_t value;
+ uint64_t *time, *times;
+ uint_t elem, nelems;
+ nvlist_t *nvp_sid;
+ uint8_t *scanstamp;
+
+ /*
+ * Validate the name and type of each attribute.
+ * Log any unknown names and continue. This will
+ * help if additional attributes are added later.
+ */
+ type = nvpair_type(pair);
+ if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) {
+ cmn_err(CE_WARN, "Unknown attribute %s",
+ nvpair_name(pair));
+ continue;
+ }
+
+ /*
+ * Verify nvlist type matches required type and view is OK
+ */
+
+ if (type != attr_to_data_type(attr) ||
+ (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+
+ /*
+ * For OWNERSID/GROUPSID make sure the target
+ * file system support ephemeral ID's
+ */
+ if ((attr == F_OWNERSID || attr == F_GROUPSID) &&
+ (!(vp->v_vfsp->vfs_flag & VFS_XID))) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+
+ /*
+ * Retrieve data from nvpair
+ */
+ switch (type) {
+ case DATA_TYPE_BOOLEAN_VALUE:
+ if (nvpair_value_boolean_value(pair, &value)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ case DATA_TYPE_UINT64_ARRAY:
+ if (nvpair_value_uint64_array(pair, &times, &nelems)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ case DATA_TYPE_NVLIST:
+ if (nvpair_value_nvlist(pair, &nvp_sid)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ case DATA_TYPE_UINT8_ARRAY:
+ if (nvpair_value_uint8_array(pair,
+ &scanstamp, &nelems)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ default:
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+
+ switch (attr) {
+ /*
+ * If we have several similar optional attributes to
+ * process then we should do it all together here so that
+ * xoap and the requested bitmap can be set in one place.
+ */
+ case F_READONLY:
+ XVA_SET_REQ(&xvattr, XAT_READONLY);
+ xoap->xoa_readonly = value;
+ break;
+ case F_HIDDEN:
+ XVA_SET_REQ(&xvattr, XAT_HIDDEN);
+ xoap->xoa_hidden = value;
+ break;
+ case F_SYSTEM:
+ XVA_SET_REQ(&xvattr, XAT_SYSTEM);
+ xoap->xoa_system = value;
+ break;
+ case F_ARCHIVE:
+ XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
+ xoap->xoa_archive = value;
+ break;
+ case F_IMMUTABLE:
+ XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
+ xoap->xoa_immutable = value;
+ break;
+ case F_NOUNLINK:
+ XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
+ xoap->xoa_nounlink = value;
+ break;
+ case F_APPENDONLY:
+ XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
+ xoap->xoa_appendonly = value;
+ break;
+ case F_NODUMP:
+ XVA_SET_REQ(&xvattr, XAT_NODUMP);
+ xoap->xoa_nodump = value;
+ break;
+ case F_AV_QUARANTINED:
+ XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
+ xoap->xoa_av_quarantined = value;
+ break;
+ case F_AV_MODIFIED:
+ XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
+ xoap->xoa_av_modified = value;
+ break;
+ case F_CRTIME:
+ XVA_SET_REQ(&xvattr, XAT_CREATETIME);
+ time = (uint64_t *)&(xoap->xoa_createtime);
+ for (elem = 0; elem < nelems; elem++)
+ *time++ = times[elem];
+ break;
+ case F_OWNERSID:
+ case F_GROUPSID:
+ if (nvlist_lookup_string(nvp_sid, SID_DOMAIN,
+ &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID,
+ &rid)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+
+ /*
+ * Now map domain+rid to ephemeral id's
+ *
+ * If mapping fails, then the uid/gid will
+ * be set to UID_NOBODY by Winchester.
+ */
+
+ if (attr == F_OWNERSID) {
+ (void) kidmap_getuidbysid(domain, rid,
+ &xvattr.xva_vattr.va_uid);
+ xvattr.xva_vattr.va_mask |= AT_UID;
+ } else {
+ (void) kidmap_getgidbysid(domain, rid,
+ &xvattr.xva_vattr.va_gid);
+ xvattr.xva_vattr.va_mask |= AT_GID;
+ }
+ break;
+ case F_AV_SCANSTAMP:
+ if (ppvp->v_type == VREG) {
+ XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
+ (void) memcpy(xoap->xoa_av_scanstamp,
+ scanstamp, nelems);
+ } else {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ppvp = gfs_file_parent(gfs_file_parent(vp));
+ error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
+ if (error)
+ uiop->uio_resid = size;
+
+ nvlist_free(nvp);
+ return (error);
+}
+
+static int
+xattr_file_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
+{
+ switch (cmd) {
+ case _PC_XATTR_EXISTS:
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ *valp = 0;
+ return (0);
+ default:
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
+ }
+}
+
+vnodeops_t *xattr_file_ops;
+
+static const fs_operation_def_t xattr_file_tops[] = {
+ { VOPNAME_OPEN, { .vop_open = xattr_file_open } },
+ { VOPNAME_CLOSE, { .vop_close = xattr_file_close } },
+ { VOPNAME_READ, { .vop_read = xattr_file_read } },
+ { VOPNAME_WRITE, { .vop_write = xattr_file_write } },
+ { VOPNAME_IOCTL, { .error = fs_ioctl } },
+ { VOPNAME_GETATTR, { .vop_getattr = xattr_file_getattr } },
+ { VOPNAME_ACCESS, { .vop_access = xattr_file_access } },
+ { VOPNAME_READDIR, { .error = fs_notdir } },
+ { VOPNAME_SEEK, { .vop_seek = fs_seek } },
+ { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } },
+ { VOPNAME_FID, { .vop_fid = xattr_common_fid } },
+ { VOPNAME_PATHCONF, { .vop_pathconf = xattr_file_pathconf } },
+ { VOPNAME_PUTPAGE, { .error = fs_putpage } },
+ { VOPNAME_FSYNC, { .error = fs_fsync } },
+ { NULL }
+};
+
+vnode_t *
+xattr_mkfile(vnode_t *pvp, xattr_view_t xattr_view)
+{
+ vnode_t *vp;
+ xattr_file_t *np;
+
+ vp = gfs_file_create(sizeof (xattr_file_t), pvp, xattr_file_ops);
+ np = vp->v_data;
+ np->xattr_view = xattr_view;
+ vp->v_flag |= V_SYSATTR;
+ return (vp);
+}
+
+vnode_t *
+xattr_mkfile_ro(vnode_t *pvp)
+{
+ return (xattr_mkfile(pvp, XATTR_VIEW_READONLY));
+}
+
+vnode_t *
+xattr_mkfile_rw(vnode_t *pvp)
+{
+ return (xattr_mkfile(pvp, XATTR_VIEW_READWRITE));
+}
+
+vnodeops_t *xattr_dir_ops;
+
+static gfs_dirent_t xattr_dirents[] = {
+ { VIEW_READONLY, xattr_mkfile_ro, GFS_CACHE_VNODE, },
+ { VIEW_READWRITE, xattr_mkfile_rw, GFS_CACHE_VNODE, },
+ { NULL },
+};
+
+#define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1)
+
+static int
+is_sattr_name(char *s)
+{
+ int i;
+
+ for (i = 0; i < XATTRDIR_NENTS; ++i) {
+ if (strcmp(s, xattr_dirents[i].gfse_name) == 0) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int
+xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
+ cred_t *cr, caller_context_t *ct)
+{
+ xvattr_t xvattr;
+ vnode_t *pdvp;
+ int error;
+
+ /*
+ * Only copy system attrs if the views are the same
+ */
+ if (strcmp(snm, tnm) != 0)
+ return (EINVAL);
+
+ xva_init(&xvattr);
+
+ XVA_SET_REQ(&xvattr, XAT_SYSTEM);
+ XVA_SET_REQ(&xvattr, XAT_READONLY);
+ XVA_SET_REQ(&xvattr, XAT_HIDDEN);
+ XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
+ XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
+ XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
+ XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
+ XVA_SET_REQ(&xvattr, XAT_NODUMP);
+ XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
+ XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
+ XVA_SET_REQ(&xvattr, XAT_CREATETIME);
+
+ pdvp = gfs_file_parent(sdvp);
+ error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
+ if (error)
+ return (error);
+
+ pdvp = gfs_file_parent(tdvp);
+ error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
+ return (error);
+}
+
+static int
+xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags,
+ cred_t *cr, caller_context_t *ct)
+{
+ vnode_t *pvp;
+ int error;
+ struct pathname pn;
+ char *startnm = "";
+
+ *realdvp = NULL;
+
+ pvp = gfs_file_parent(dvp);
+
+ error = pn_get(startnm, UIO_SYSSPACE, &pn);
+ if (error) {
+ VN_RELE(pvp);
+ return (error);
+ }
+
+ /*
+ * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an
+ * infinite loop with fop_lookup calling back to xattr_dir_lookup.
+ */
+ lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR;
+ error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags,
+ rootvp, cr, ct, NULL, NULL);
+ pn_free(&pn);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
+{
+ if (flags & FWRITE) {
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr,
+ caller_context_t *ct)
+{
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ timestruc_t now;
+ vnode_t *pvp;
+ int error;
+ vattr_t pvattr;
+
+ error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_GETATTR(pvp, vap, 0, cr, ct);
+ VN_RELE(pvp);
+ if (error) {
+ return (error);
+ }
+ vap->va_nlink += XATTRDIR_NENTS;
+ vap->va_size += XATTRDIR_NENTS;
+ return (0);
+ }
+
+ /*
+ * There is no real xattr directory. Cobble together
+ * an entry using info from the parent object.
+ */
+ pvp = gfs_file_parent(vp);
+ (void) memset(&pvattr, 0, sizeof (pvattr));
+ pvattr.va_mask = AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME;
+ error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct);
+ if (error) {
+ return (error);
+ }
+ *vap = pvattr;
+ vap->va_type = VDIR;
+ vap->va_mode = MAKEIMODE(vap->va_type, S_ISVTX | 0777);
+ vap->va_fsid = vp->v_vfsp->vfs_dev;
+ vap->va_nodeid = gfs_file_inode(vp);
+ vap->va_nlink = XATTRDIR_NENTS+2;
+ vap->va_size = vap->va_nlink;
+ gethrestime(&now);
+ vap->va_atime = now;
+ vap->va_blksize = 0;
+ vap->va_nblocks = 0;
+ vap->va_seq = 0;
+ return (0);
+}
+
+static int
+xattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ vnode_t *realvp;
+ int error;
+
+ /*
+ * If there is a real xattr directory, do the setattr there.
+ * Otherwise, just return success. The GFS directory is transient,
+ * and any setattr changes can disappear anyway.
+ */
+ error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_SETATTR(realvp, vap, flags, cr, ct);
+ VN_RELE(realvp);
+ }
+ if (error == ENOENT) {
+ error = 0;
+ }
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+xattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+ vnode_t *realvp = NULL;
+
+ if (mode & VWRITE) {
+ return (EACCES);
+ }
+
+ error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
+
+ if (realvp)
+ VN_RELE(realvp);
+
+ /*
+ * No real xattr dir isn't an error
+ * an error of EINVAL indicates attributes on attributes
+ * are not supported. In that case just allow access to the
+ * transient directory.
+ */
+ return ((error == ENOENT || error == EINVAL) ? 0 : error);
+}
+
+static int
+xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
+{
+ vnode_t *pvp;
+ int error;
+
+ *vpp = NULL;
+
+ /*
+ * Don't allow creation of extended attributes with sysattr names.
+ */
+ if (is_sattr_name(name)) {
+ return (gfs_dir_lookup(dvp, name, vpp, cr));
+ }
+
+ error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
+ cr, ct);
+ if (error == 0) {
+ error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag,
+ ct, vsecp);
+ VN_RELE(pvp);
+ }
+ return (error);
+}
+
+static int
+xattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct,
+ int flags)
+{
+ vnode_t *pvp;
+ int error;
+
+ if (is_sattr_name(name)) {
+ return (EACCES);
+ }
+
+ error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_REMOVE(pvp, name, cr, ct, flags);
+ VN_RELE(pvp);
+ }
+ return (error);
+}
+
+static int
+xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
+ caller_context_t *ct, int flags)
+{
+ vnode_t *pvp;
+ int error;
+
+ if (svp->v_flag & V_SYSATTR) {
+ return (EINVAL);
+ }
+
+ error = xattr_dir_realdir(tdvp, &pvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_LINK(pvp, svp, name, cr, ct, flags);
+ VN_RELE(pvp);
+ }
+ return (error);
+}
+
+static int
+xattr_dir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
+ cred_t *cr, caller_context_t *ct, int flags)
+{
+ vnode_t *spvp, *tpvp;
+ int error;
+ int held_tgt;
+
+ if (is_sattr_name(snm) || is_sattr_name(tnm))
+ return (xattr_copy(sdvp, snm, tdvp, tnm, cr, ct));
+ /*
+ * We know that sdvp is a GFS dir, or we wouldn't be here.
+ * Get the real unnamed directory.
+ */
+ error = xattr_dir_realdir(sdvp, &spvp, LOOKUP_XATTR, cr, ct);
+ if (error) {
+ return (error);
+ }
+
+ if (sdvp == tdvp) {
+ /*
+ * If the source and target are the same GFS directory, the
+ * underlying unnamed source and target dir will be the same.
+ */
+ tpvp = spvp;
+ VN_HOLD(tpvp);
+ held_tgt = 1;
+ } else if (tdvp->v_flag & V_SYSATTR) {
+ /*
+ * If the target dir is a different GFS directory,
+ * find its underlying unnamed dir.
+ */
+ error = xattr_dir_realdir(tdvp, &tpvp, LOOKUP_XATTR, cr, ct);
+ if (error) {
+ VN_RELE(spvp);
+ return (error);
+ }
+ held_tgt = 1;
+ } else {
+ /*
+ * Target dir is outside of GFS, pass it on through.
+ */
+ tpvp = tdvp;
+ held_tgt = 0;
+ }
+
+ error = VOP_RENAME(spvp, snm, tpvp, tnm, cr, ct, flags);
+
+ if (held_tgt) {
+ VN_RELE(tpvp);
+ }
+ VN_RELE(spvp);
+
+ return (error);
+}
+
+static int
+xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
+{
+ vnode_t *pvp;
+ int error;
+ int local_eof = 0;
+ int reset_off = 0;
+ int has_xattrs = 0;
+
+ if (eofp == NULL) {
+ eofp = &local_eof;
+ }
+
+ /*
+ * See if there is a real extended attribute directory.
+ */
+ error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ has_xattrs = 1;
+ }
+
+ /*
+ * Start by reading up the static entries.
+ */
+ if (uiop->uio_loffset == 0) {
+ if (has_xattrs) {
+ /*
+ * If there is a real xattr dir, skip . and ..
+ * in the GFS dir. We'll pick them up below
+ * when we call into the underlying fs.
+ */
+ uiop->uio_loffset = GFS_STATIC_ENTRY_OFFSET;
+ }
+ error = gfs_dir_readdir(dvp, uiop, eofp, NULL, cr, ct);
+ if (error) {
+ if (has_xattrs) {
+ VN_RELE(pvp);
+ }
+ return (error);
+ }
+ /*
+ * We must read all of the static entries in the first
+ * call. Otherwise we won't know if uio_loffset in a
+ * subsequent call refers to the static entries or to those
+ * in an underlying fs.
+ */
+ ASSERT(*eofp);
+ reset_off = 1;
+ }
+
+ if (!has_xattrs) {
+ *eofp = 1;
+ return (0);
+ }
+
+ *eofp = 0;
+ if (reset_off) {
+ uiop->uio_loffset = 0;
+ }
+ (void) VOP_RWLOCK(pvp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READDIR(pvp, uiop, cr, eofp, ct, flags);
+ VOP_RWUNLOCK(pvp, V_WRITELOCK_FALSE, NULL);
+ VN_RELE(pvp);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static void
+xattr_dir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+ gfs_file_t *fp;
+
+ fp = gfs_dir_inactive(vp);
+ if (fp != NULL) {
+ kmem_free(fp, fp->gfs_size);
+ }
+}
+
+static int
+xattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
+{
+ switch (cmd) {
+ case _PC_XATTR_EXISTS:
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ *valp = 0;
+ return (0);
+ default:
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
+ }
+}
+
+static const fs_operation_def_t xattr_dir_tops[] = {
+ { VOPNAME_OPEN, { .vop_open = xattr_dir_open } },
+ { VOPNAME_CLOSE, { .vop_close = xattr_dir_close } },
+ { VOPNAME_IOCTL, { .error = fs_inval } },
+ { VOPNAME_GETATTR, { .vop_getattr = xattr_dir_getattr } },
+ { VOPNAME_SETATTR, { .vop_setattr = xattr_dir_setattr } },
+ { VOPNAME_ACCESS, { .vop_access = xattr_dir_access } },
+ { VOPNAME_READDIR, { .vop_readdir = xattr_dir_readdir } },
+ { VOPNAME_LOOKUP, { .vop_lookup = gfs_vop_lookup } },
+ { VOPNAME_CREATE, { .vop_create = xattr_dir_create } },
+ { VOPNAME_REMOVE, { .vop_remove = xattr_dir_remove } },
+ { VOPNAME_LINK, { .vop_link = xattr_dir_link } },
+ { VOPNAME_RENAME, { .vop_rename = xattr_dir_rename } },
+ { VOPNAME_MKDIR, { .error = fs_inval } },
+ { VOPNAME_SEEK, { .vop_seek = fs_seek } },
+ { VOPNAME_INACTIVE, { .vop_inactive = xattr_dir_inactive } },
+ { VOPNAME_FID, { .vop_fid = xattr_common_fid } },
+ { VOPNAME_PATHCONF, { .vop_pathconf = xattr_dir_pathconf } },
+ { NULL, NULL }
+};
+
+static gfs_opsvec_t xattr_opsvec[] = {
+ { "xattr dir", xattr_dir_tops, &xattr_dir_ops },
+ { "system attributes", xattr_file_tops, &xattr_file_ops },
+ { NULL, NULL, NULL }
+};
+
+static int
+xattr_lookup_cb(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
+ cred_t *cr)
+{
+ vnode_t *pvp;
+ struct pathname pn;
+ int error;
+
+ *vpp = NULL;
+ *inop = 0;
+
+ error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
+ cr, NULL);
+
+ /*
+ * Return ENOENT for EACCES requests during lookup. Once an
+ * attribute create is attempted EACCES will be returned.
+ */
+ if (error) {
+ if (error == EACCES)
+ return (ENOENT);
+ return (error);
+ }
+
+ error = pn_get((char *)nm, UIO_SYSSPACE, &pn);
+ if (error == 0) {
+ error = VOP_LOOKUP(pvp, (char *)nm, vpp, &pn, 0, rootvp,
+ cr, NULL, NULL, NULL);
+ pn_free(&pn);
+ }
+ VN_RELE(pvp);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static ino64_t
+xattrdir_do_ino(vnode_t *vp, int index)
+{
+ /*
+ * We use index 0 for the directory fid. Start
+ * the file numbering at 1.
+ */
+ return ((ino64_t)index+1);
+}
+
+void
+xattr_init(void)
+{
+ VERIFY(gfs_make_opsvec(xattr_opsvec) == 0);
+}
+
+int
+xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr)
+{
+ int error = 0;
+
+ *vpp = NULL;
+
+ if (dvp->v_type != VDIR && dvp->v_type != VREG)
+ return (EINVAL);
+
+ mutex_enter(&dvp->v_lock);
+
+ /*
+ * If we're already in sysattr space, don't allow creation
+ * of another level of sysattrs.
+ */
+ if (dvp->v_flag & V_SYSATTR) {
+ mutex_exit(&dvp->v_lock);
+ return (EINVAL);
+ }
+
+ if (dvp->v_xattrdir != NULL) {
+ *vpp = dvp->v_xattrdir;
+ VN_HOLD(*vpp);
+ } else {
+ ulong_t val;
+ int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR;
+ int sysattrs_allowed = 1;
+
+ /*
+ * We have to drop the lock on dvp. gfs_dir_create will
+ * grab it for a VN_HOLD.
+ */
+ mutex_exit(&dvp->v_lock);
+
+ /*
+ * If dvp allows xattr creation, but not sysattr
+ * creation, return the real xattr dir vp. We can't
+ * use the vfs feature mask here because _PC_SATTR_ENABLED
+ * has vnode-level granularity (e.g. .zfs).
+ */
+ error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL);
+ if (error != 0 || val == 0)
+ sysattrs_allowed = 0;
+
+ if (!xattrs_allowed && !sysattrs_allowed)
+ return (EINVAL);
+
+ if (!sysattrs_allowed) {
+ struct pathname pn;
+ char *nm = "";
+
+ error = pn_get(nm, UIO_SYSSPACE, &pn);
+ if (error)
+ return (error);
+ error = VOP_LOOKUP(dvp, nm, vpp, &pn,
+ flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
+ NULL, NULL);
+ pn_free(&pn);
+ return (error);
+ }
+
+ /*
+ * Note that we act as if we were given CREATE_XATTR_DIR,
+ * but only for creation of the GFS directory.
+ */
+ *vpp = gfs_dir_create(
+ sizeof (gfs_dir_t), dvp, xattr_dir_ops, xattr_dirents,
+ xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb);
+ mutex_enter(&dvp->v_lock);
+ if (dvp->v_xattrdir != NULL) {
+ /*
+ * We lost the race to create the xattr dir.
+ * Destroy this one, use the winner. We can't
+ * just call VN_RELE(*vpp), because the vnode
+ * is only partially initialized.
+ */
+ gfs_dir_t *dp = (*vpp)->v_data;
+
+ ASSERT((*vpp)->v_count == 1);
+ vn_free(*vpp);
+
+ mutex_destroy(&dp->gfsd_lock);
+ kmem_free(dp->gfsd_static,
+ dp->gfsd_nstatic * sizeof (gfs_dirent_t));
+ kmem_free(dp, dp->gfsd_file.gfs_size);
+
+ /*
+ * There is an implied VN_HOLD(dvp) here. We should
+ * be doing a VN_RELE(dvp) to clean up the reference
+ * from *vpp, and then a VN_HOLD(dvp) for the new
+ * reference. Instead, we just leave the count alone.
+ */
+
+ *vpp = dvp->v_xattrdir;
+ VN_HOLD(*vpp);
+ } else {
+ (*vpp)->v_flag |= (V_XATTRDIR|V_SYSATTR);
+ dvp->v_xattrdir = *vpp;
+ }
+ }
+ mutex_exit(&dvp->v_lock);
+
+ return (error);
+}
+
+int
+xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
+{
+ int error;
+ vnode_t *pvp, *dvp;
+ xattr_fid_t *xfidp;
+ struct pathname pn;
+ char *nm;
+ uint16_t orig_len;
+
+ *vpp = NULL;
+
+ if (fidp->fid_len < XATTR_FIDSZ)
+ return (EINVAL);
+
+ xfidp = (xattr_fid_t *)fidp;
+ orig_len = fidp->fid_len;
+ fidp->fid_len = xfidp->parent_len;
+
+ error = VFS_VGET(vfsp, &pvp, fidp);
+ fidp->fid_len = orig_len;
+ if (error)
+ return (error);
+
+ /*
+ * Start by getting the GFS sysattr directory. We might need
+ * to recreate it during the VOP_LOOKUP.
+ */
+ nm = "";
+ error = pn_get(nm, UIO_SYSSPACE, &pn);
+ if (error) {
+ VN_RELE(pvp);
+ return (EINVAL);
+ }
+
+ error = VOP_LOOKUP(pvp, nm, &dvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR,
+ rootvp, CRED(), NULL, NULL, NULL);
+ pn_free(&pn);
+ VN_RELE(pvp);
+ if (error)
+ return (error);
+
+ if (xfidp->dir_offset == 0) {
+ /*
+ * If we were looking for the directory, we're done.
+ */
+ *vpp = dvp;
+ return (0);
+ }
+
+ if (xfidp->dir_offset > XATTRDIR_NENTS) {
+ VN_RELE(dvp);
+ return (EINVAL);
+ }
+
+ nm = xattr_dirents[xfidp->dir_offset - 1].gfse_name;
+
+ error = pn_get(nm, UIO_SYSSPACE, &pn);
+ if (error) {
+ VN_RELE(dvp);
+ return (EINVAL);
+ }
+
+ error = VOP_LOOKUP(dvp, nm, vpp, &pn, 0, rootvp, CRED(), NULL,
+ NULL, NULL);
+
+ pn_free(&pn);
+ VN_RELE(dvp);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c
index b41458bd15..170f5cc320 100644
--- a/usr/src/uts/common/fs/zfs/dmu.c
+++ b/usr/src/uts/common/fs/zfs/dmu.c
@@ -65,7 +65,7 @@ const dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES] = {
{ zap_byteswap, TRUE, "DSL props" },
{ byteswap_uint64_array, TRUE, "DSL dataset" },
{ zfs_znode_byteswap, TRUE, "ZFS znode" },
- { zfs_acl_byteswap, TRUE, "ZFS ACL" },
+ { zfs_oldacl_byteswap, TRUE, "ZFS V0 ACL" },
{ byteswap_uint8_array, FALSE, "ZFS plain file" },
{ zap_byteswap, TRUE, "ZFS directory" },
{ zap_byteswap, TRUE, "ZFS master node" },
@@ -79,7 +79,11 @@ const dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES] = {
{ byteswap_uint8_array, TRUE, "SPA history" },
{ byteswap_uint64_array, TRUE, "SPA history offsets" },
{ zap_byteswap, TRUE, "Pool properties" },
- { zap_byteswap, TRUE, "DSL permissions" }
+ { zap_byteswap, TRUE, "DSL permissions" },
+ { zfs_acl_byteswap, TRUE, "ZFS ACL" },
+ { byteswap_uint8_array, TRUE, "ZFS SYSACL" },
+ { byteswap_uint8_array, TRUE, "FUID table" },
+ { byteswap_uint8_array, TRUE, "FUID table size" },
};
int
diff --git a/usr/src/uts/common/fs/zfs/dsl_deleg.c b/usr/src/uts/common/fs/zfs/dsl_deleg.c
index 6f071afab8..3a9ffa430d 100644
--- a/usr/src/uts/common/fs/zfs/dsl_deleg.c
+++ b/usr/src/uts/common/fs/zfs/dsl_deleg.c
@@ -31,7 +31,7 @@
* it is a local or descendent permission. The first letter
* identifies the type of entry.
*
- * ul$<id> identifies permssions granted locally for this userid.
+ * ul$<id> identifies permissions granted locally for this userid.
* ud$<id> identifies permissions granted on descendent datasets for
* this userid.
* Ul$<id> identifies permission sets granted locally for this userid.
@@ -55,7 +55,7 @@
* s-$@<name> permissions defined in specified set @<name>
* S-$@<name> Sets defined in named set @<name>
*
- * Each of the above entiies points to another zap attribute that contains one
+ * Each of the above entities points to another zap attribute that contains one
* attribute for each allowed permission, such as create, destroy,...
* All of the "upper" case class types will specify permission set names
* rather than permissions.
diff --git a/usr/src/uts/common/fs/zfs/dsl_prop.c b/usr/src/uts/common/fs/zfs/dsl_prop.c
index fcf756b267..ef248f26e3 100644
--- a/usr/src/uts/common/fs/zfs/dsl_prop.c
+++ b/usr/src/uts/common/fs/zfs/dsl_prop.c
@@ -44,8 +44,13 @@ dodefault(const char *propname, int intsz, int numint, void *buf)
{
zfs_prop_t prop;
+ /*
+ * The setonce properties are read-only, BUT they still
+ * have a default value that can be used as the initial
+ * value.
+ */
if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL ||
- zfs_prop_readonly(prop))
+ (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
return (ENOENT);
if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
@@ -93,8 +98,7 @@ dsl_prop_get_impl(dsl_dir_t *dd, const char *propname,
/*
* Break out of this loop for non-inheritable properties.
*/
- if (prop != ZPROP_INVAL &&
- !zfs_prop_inheritable(prop))
+ if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop))
break;
}
if (err == ENOENT)
@@ -418,14 +422,12 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
{
dsl_dataset_t *ds = os->os->os_dsl_dataset;
dsl_dir_t *dd = ds->ds_dir;
+ boolean_t snapshot;
int err = 0;
dsl_pool_t *dp;
objset_t *mos;
- if (dsl_dataset_is_snapshot(ds)) {
- VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
- return (0);
- }
+ snapshot = dsl_dataset_is_snapshot(ds);
VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
@@ -453,6 +455,10 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
dd != ds->ds_dir)
continue;
+ if (snapshot &&
+ !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
+ continue;
+
if (nvlist_lookup_nvlist(*nvp, za.za_name,
&propval) == 0)
continue;
diff --git a/usr/src/uts/common/fs/zfs/spa_config.c b/usr/src/uts/common/fs/zfs/spa_config.c
index 599f960cb7..6ce83e0d14 100644
--- a/usr/src/uts/common/fs/zfs/spa_config.c
+++ b/usr/src/uts/common/fs/zfs/spa_config.c
@@ -197,13 +197,13 @@ spa_config_sync(void)
if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
0, RLIM64_INFINITY, kcred, NULL) == 0 &&
- VOP_FSYNC(vp, FSYNC, kcred) == 0) {
+ VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
(void) snprintf(pathname2, sizeof (pathname2), "%s/%s",
spa_config_dir, ZPOOL_CACHE_FILE);
(void) vn_rename(pathname, pathname2, UIO_SYSSPACE);
}
- (void) VOP_CLOSE(vp, oflags, 1, 0, kcred);
+ (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
VN_RELE(vp);
out:
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu.h b/usr/src/uts/common/fs/zfs/sys/dmu.h
index 6e6495e2ec..3300e901a1 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h
@@ -92,7 +92,7 @@ typedef enum dmu_object_type {
DMU_OT_DSL_DATASET, /* UINT64 */
/* zpl: */
DMU_OT_ZNODE, /* ZNODE */
- DMU_OT_ACL, /* ACL */
+ DMU_OT_OLDACL, /* Old ACL */
DMU_OT_PLAIN_FILE_CONTENTS, /* UINT8 */
DMU_OT_DIRECTORY_CONTENTS, /* ZAP */
DMU_OT_MASTER_NODE, /* ZAP */
@@ -110,6 +110,10 @@ typedef enum dmu_object_type {
DMU_OT_SPA_HISTORY_OFFSETS, /* spa_his_phys_t */
DMU_OT_POOL_PROPS, /* ZAP */
DMU_OT_DSL_PERMS, /* ZAP */
+ DMU_OT_ACL, /* ACL */
+ DMU_OT_SYSACL, /* SYSACL */
+ DMU_OT_FUID, /* FUID table (Packed NVLIST UINT8) */
+ DMU_OT_FUID_SIZE, /* FUID table size UINT64 */
DMU_OT_NUMTYPES
} dmu_object_type_t;
@@ -128,6 +132,7 @@ void byteswap_uint32_array(void *buf, size_t size);
void byteswap_uint16_array(void *buf, size_t size);
void byteswap_uint8_array(void *buf, size_t size);
void zap_byteswap(void *buf, size_t size);
+void zfs_oldacl_byteswap(void *buf, size_t size);
void zfs_acl_byteswap(void *buf, size_t size);
void zfs_znode_byteswap(void *buf, size_t size);
@@ -545,7 +550,7 @@ uint64_t dmu_tx_get_txg(dmu_tx_t *tx);
* Synchronous write.
* If a parent zio is provided this function initiates a write on the
* provided buffer as a child of the parent zio.
- * In the absense of a parent zio, the write is completed synchronously.
+ * In the absence of a parent zio, the write is completed synchronously.
* At write completion, blk is filled with the bp of the written block.
* Note that while the data covered by this function will be on stable
* storage when the write completes this new data does not become a
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
index 1d01123c77..a29e44e67d 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
@@ -50,6 +50,7 @@ extern "C" {
#define ZFS_DELEG_PERM_RECEIVE "receive"
#define ZFS_DELEG_PERM_ALLOW "allow"
#define ZFS_DELEG_PERM_USERPROP "userprop"
+#define ZFS_DELEG_PERM_VSCAN "vscan"
/*
* Note: the names of properties that are marked delegatable are also
diff --git a/usr/src/uts/common/fs/zfs/sys/zap.h b/usr/src/uts/common/fs/zfs/sys/zap.h
index d194705987..b762a93da5 100644
--- a/usr/src/uts/common/fs/zfs/sys/zap.h
+++ b/usr/src/uts/common/fs/zfs/sys/zap.h
@@ -31,7 +31,7 @@
/*
* ZAP - ZFS Attribute Processor
*
- * The ZAP is a module which sits on top of the DMU (Data Managemnt
+ * The ZAP is a module which sits on top of the DMU (Data Management
* Unit) and implements a higher-level storage primitive using DMU
* objects. Its primary consumer is the ZPL (ZFS Posix Layer).
*
@@ -91,10 +91,38 @@ extern "C" {
#define ZAP_MAXVALUELEN 1024
/*
+ * The matchtype specifies which entry will be accessed.
+ * MT_EXACT: only find an exact match (non-normalized)
+ * MT_FIRST: find the "first" normalized (case and Unicode
+ * form) match; the designated "first" match will not change as long
+ * as the set of entries with this normalization doesn't change
+ * MT_BEST: if there is an exact match, find that, otherwise find the
+ * first normalized match
+ */
+typedef enum matchtype
+{
+ MT_EXACT,
+ MT_BEST,
+ MT_FIRST
+} matchtype_t;
+
+/*
* Create a new zapobj with no attributes and return its object number.
+ * MT_EXACT will cause the zap object to only support MT_EXACT lookups,
+ * otherwise any matchtype can be used for lookups.
+ *
+ * normflags specifies what normalization will be done. values are:
+ * 0: no normalization (legacy on-disk format, supports MT_EXACT matching
+ * only)
+ * U8_TEXTPREP_TOLOWER: case normalization will be performed.
+ * MT_FIRST/MT_BEST matching will find entries that match without
+ * regard to case (eg. looking for "foo" can find an entry "Foo").
+ * Eventually, other flags will permit unicode normalization as well.
*/
uint64_t zap_create(objset_t *ds, dmu_object_type_t ot,
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+uint64_t zap_create_norm(objset_t *ds, int normflags, dmu_object_type_t ot,
+ dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
/*
* Create a new zapobj with no attributes from the given (unallocated)
@@ -102,6 +130,9 @@ uint64_t zap_create(objset_t *ds, dmu_object_type_t ot,
*/
int zap_create_claim(objset_t *ds, uint64_t obj, dmu_object_type_t ot,
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+int zap_create_claim_norm(objset_t *ds, uint64_t obj,
+ int normflags, dmu_object_type_t ot,
+ dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
/*
* The zapobj passed in must be a valid ZAP object for all of the
@@ -140,9 +171,20 @@ int zap_destroy(objset_t *ds, uint64_t zapobj, dmu_tx_t *tx);
* If the attribute is longer than the buffer, as many integers as will
* fit will be transferred to 'buf'. If the entire attribute was not
* transferred, the call will return EOVERFLOW.
+ *
+ * If rn_len is nonzero, realname will be set to the name of the found
+ * entry (which may be different from the requested name if matchtype is
+ * not MT_EXACT).
+ *
+ * If normalization_conflictp is not NULL, it will be set if there is
+ * another name with the same case/unicode normalized form.
*/
int zap_lookup(objset_t *ds, uint64_t zapobj, const char *name,
uint64_t integer_size, uint64_t num_integers, void *buf);
+int zap_lookup_norm(objset_t *ds, uint64_t zapobj, const char *name,
+ uint64_t integer_size, uint64_t num_integers, void *buf,
+ matchtype_t mt, char *realname, int rn_len,
+ boolean_t *normalization_conflictp);
/*
* Create an attribute with the given name and value.
@@ -182,6 +224,8 @@ int zap_length(objset_t *ds, uint64_t zapobj, const char *name,
* return ENOENT.
*/
int zap_remove(objset_t *ds, uint64_t zapobj, const char *name, dmu_tx_t *tx);
+int zap_remove_norm(objset_t *ds, uint64_t zapobj, const char *name,
+ matchtype_t mt, dmu_tx_t *tx);
/*
* Returns (in *count) the number of attributes in the specified zap
@@ -213,6 +257,11 @@ typedef struct zap_cursor {
typedef struct {
int za_integer_length;
+ /*
+ * za_normalization_conflict will be set if there are additional
+ * entries with this normalized form (eg, "foo" and "Foo").
+ */
+ boolean_t za_normalization_conflict;
uint64_t za_num_integers;
uint64_t za_first_integer; /* no sign extension for <8byte ints */
char za_name[MAXNAMELEN];
diff --git a/usr/src/uts/common/fs/zfs/sys/zap_impl.h b/usr/src/uts/common/fs/zfs/sys/zap_impl.h
index 4e43f4ae49..8cc1108846 100644
--- a/usr/src/uts/common/fs/zfs/sys/zap_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zap_impl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,7 +59,8 @@ typedef struct mzap_ent_phys {
typedef struct mzap_phys {
uint64_t mz_block_type; /* ZBT_MICRO */
uint64_t mz_salt;
- uint64_t mz_pad[6];
+ uint64_t mz_normflags;
+ uint64_t mz_pad[5];
mzap_ent_phys_t mz_chunk[1];
/* actually variable size depending on block size */
} mzap_phys_t;
@@ -127,6 +128,7 @@ typedef struct zap_phys {
uint64_t zap_num_leafs; /* number of leafs */
uint64_t zap_num_entries; /* number of entries */
uint64_t zap_salt; /* salt to stir into hash function */
+ uint64_t zap_normflags; /* flags for u8_textprep_str() */
/*
* This structure is followed by padding, and then the embedded
* pointer table. The embedded pointer table takes up second
@@ -142,7 +144,8 @@ typedef struct zap {
uint64_t zap_object;
struct dmu_buf *zap_dbuf;
krwlock_t zap_rwlock;
- int zap_ismicro;
+ boolean_t zap_ismicro;
+ int zap_normflags;
uint64_t zap_salt;
union {
struct {
@@ -165,34 +168,45 @@ typedef struct zap {
} zap_u;
} zap_t;
+typedef struct zap_name {
+ zap_t *zn_zap;
+ const char *zn_name_orij;
+ uint64_t zn_hash;
+ matchtype_t zn_matchtype;
+ const char *zn_name_norm;
+ char zn_normbuf[ZAP_MAXNAMELEN];
+} zap_name_t;
+
#define zap_f zap_u.zap_fat
#define zap_m zap_u.zap_micro
-uint64_t zap_hash(zap_t *zap, const char *name);
+boolean_t zap_match(zap_name_t *zn, const char *matchname);
int zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
krw_t lti, int fatreader, zap_t **zapp);
void zap_unlockdir(zap_t *zap);
void zap_evict(dmu_buf_t *db, void *vmzap);
+zap_name_t *zap_name_alloc(zap_t *zap, const char *name, matchtype_t mt);
+void zap_name_free(zap_name_t *zn);
#define ZAP_HASH_IDX(hash, n) (((n) == 0) ? 0 : ((hash) >> (64 - (n))))
void fzap_byteswap(void *buf, size_t size);
int fzap_count(zap_t *zap, uint64_t *count);
-int fzap_lookup(zap_t *zap, const char *name,
- uint64_t integer_size, uint64_t num_integers, void *buf);
-int fzap_add(zap_t *zap, const char *name,
- uint64_t integer_size, uint64_t num_integers,
+int fzap_lookup(zap_name_t *zn,
+ uint64_t integer_size, uint64_t num_integers, void *buf,
+ char *realname, int rn_len, boolean_t *normalization_conflictp);
+int fzap_add(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers,
const void *val, dmu_tx_t *tx);
-int fzap_update(zap_t *zap, const char *name,
+int fzap_update(zap_name_t *zn,
int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx);
-int fzap_length(zap_t *zap, const char *name,
+int fzap_length(zap_name_t *zn,
uint64_t *integer_size, uint64_t *num_integers);
-int fzap_remove(zap_t *zap, const char *name, dmu_tx_t *tx);
+int fzap_remove(zap_name_t *zn, dmu_tx_t *tx);
int fzap_cursor_retrieve(zap_t *zap, zap_cursor_t *zc, zap_attribute_t *za);
void fzap_get_stats(zap_t *zap, zap_stats_t *zs);
void zap_put_leaf(struct zap_leaf *l);
-int fzap_add_cd(zap_t *zap, const char *name,
+int fzap_add_cd(zap_name_t *zn,
uint64_t integer_size, uint64_t num_integers,
const void *val, uint32_t cd, dmu_tx_t *tx);
void fzap_upgrade(zap_t *zap, dmu_tx_t *tx);
diff --git a/usr/src/uts/common/fs/zfs/sys/zap_leaf.h b/usr/src/uts/common/fs/zfs/sys/zap_leaf.h
index 147fb72124..6cee851f1f 100644
--- a/usr/src/uts/common/fs/zfs/sys/zap_leaf.h
+++ b/usr/src/uts/common/fs/zfs/sys/zap_leaf.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -92,6 +92,8 @@ typedef enum zap_chunk_type {
ZAP_CHUNK_TYPE_MAX = 250
} zap_chunk_type_t;
+#define ZLF_ENTRIES_CDSORTED (1<<0)
+
/*
* TAKE NOTE:
* If zap_leaf_phys_t is modified, zap_leaf_byteswap() must be modified.
@@ -109,7 +111,8 @@ typedef struct zap_leaf_phys {
/* above is accessable to zap, below is zap_leaf private */
uint16_t lh_freelist; /* chunk head of free list */
- uint8_t lh_pad2[12];
+ uint8_t lh_flags; /* ZLF_* flags */
+ uint8_t lh_pad2[11];
} l_hdr; /* 2 24-byte chunks */
/*
@@ -174,7 +177,7 @@ typedef struct zap_entry_handle {
* value must equal zap_hash(name).
*/
extern int zap_leaf_lookup(zap_leaf_t *l,
- const char *name, uint64_t h, zap_entry_handle_t *zeh);
+ zap_name_t *zn, zap_entry_handle_t *zeh);
/*
* Return a handle to the entry with this hash+cd, or the entry with the
@@ -219,12 +222,19 @@ extern int zap_entry_create(zap_leaf_t *l,
zap_entry_handle_t *zeh);
/*
+ * Return true if there are additional entries with the same normalized
+ * form.
+ */
+extern boolean_t zap_entry_normalization_conflict(zap_entry_handle_t *zeh,
+ zap_name_t *zn, const char *name, zap_t *zap);
+
+/*
* Other stuff.
*/
-extern void zap_leaf_init(zap_leaf_t *l);
+extern void zap_leaf_init(zap_leaf_t *l, int version);
extern void zap_leaf_byteswap(zap_leaf_phys_t *buf, int len);
-extern void zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl);
+extern void zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl, int version);
extern void zap_leaf_stats(zap_t *zap, zap_leaf_t *l, zap_stats_t *zs);
#ifdef __cplusplus
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
index e3a653c5fa..6a7724cee4 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,6 +34,7 @@
#endif
#include <sys/acl.h>
#include <sys/dmu.h>
+#include <sys/zfs_fuid.h>
#ifdef __cplusplus
extern "C" {
@@ -44,30 +45,129 @@ struct znode_phys;
#define ACCESS_UNDETERMINED -1
#define ACE_SLOT_CNT 6
+#define ZFS_ACL_VERSION_INITIAL 0ULL
+#define ZFS_ACL_VERSION_FUID 1ULL
+#define ZFS_ACL_VERSION ZFS_ACL_VERSION_FUID
-typedef struct zfs_znode_acl {
+/*
+ * ZFS ACLs are store in various forms.
+ * Files created with ACL version ZFS_ACL_VERSION_INITIAL
+ * will all be created with fixed length ACEs of type
+ * zfs_oldace_t.
+ *
+ * Files with ACL version ZFS_ACL_VERSION_FUID will be created
+ * with various sized ACEs. The abstraction entries will utilize
+ * zfs_ace_hdr_t, normal user/group entries will use zfs_ace_t
+ * and some specialized CIFS ACEs will use zfs_object_ace_t.
+ */
+
+/*
+ * All ACEs have a common hdr. For
+ * owner@, group@, and everyone@ this is all
+ * thats needed.
+ */
+typedef struct zfs_ace_hdr {
+ uint16_t z_type;
+ uint16_t z_flags;
+ uint32_t z_access_mask;
+} zfs_ace_hdr_t;
+
+typedef zfs_ace_hdr_t zfs_ace_abstract_t;
+
+/*
+ * Standard ACE
+ */
+typedef struct zfs_ace {
+ zfs_ace_hdr_t z_hdr;
+ uint64_t z_fuid;
+} zfs_ace_t;
+
+/*
+ * The following type only applies to ACE_ACCESS_ALLOWED|DENIED_OBJECT_ACE_TYPE
+ * and will only be set/retrieved in a CIFS context.
+ */
+
+typedef struct zfs_object_ace {
+ zfs_ace_t z_ace;
+ uint8_t z_object_type[16]; /* object type */
+ uint8_t z_inherit_type[16]; /* inherited object type */
+} zfs_object_ace_t;
+
+typedef struct zfs_oldace {
+ uint32_t z_fuid; /* "who" */
+ uint32_t z_access_mask; /* access mask */
+ uint16_t z_flags; /* flags, i.e inheritance */
+ uint16_t z_type; /* type of entry allow/deny */
+} zfs_oldace_t;
+
+typedef struct zfs_acl_phys_v0 {
+ uint64_t z_acl_extern_obj; /* ext acl pieces */
+ uint32_t z_acl_count; /* Number of ACEs */
+ uint16_t z_acl_version; /* acl version */
+ uint16_t z_acl_pad; /* pad */
+ zfs_oldace_t z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */
+} zfs_acl_phys_v0_t;
+
+#define ZFS_ACE_SPACE (sizeof (zfs_oldace_t) * ACE_SLOT_CNT)
+
+typedef struct zfs_acl_phys {
uint64_t z_acl_extern_obj; /* ext acl pieces */
- uint32_t z_acl_count; /* Number of ACEs */
+ uint32_t z_acl_size; /* Number of bytes in ACL */
uint16_t z_acl_version; /* acl version */
- uint16_t z_acl_pad; /* pad */
- ace_t z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */
-} zfs_znode_acl_t;
-
-#define ACL_DATA_ALLOCED 0x1
+ uint16_t z_acl_count; /* ace count */
+ uint8_t z_ace_data[ZFS_ACE_SPACE]; /* space for embedded ACEs */
+} zfs_acl_phys_t;
+
+
+
+typedef struct acl_ops {
+ uint32_t (*ace_mask_get) (void *acep); /* get access mask */
+ void (*ace_mask_set) (void *acep,
+ uint32_t mask); /* set access mask */
+ uint16_t (*ace_flags_get) (void *acep); /* get flags */
+ void (*ace_flags_set) (void *acep,
+ uint16_t flags); /* set flags */
+ uint16_t (*ace_type_get)(void *acep); /* get type */
+ void (*ace_type_set)(void *acep,
+ uint16_t type); /* set type */
+ uint64_t (*ace_who_get)(void *acep); /* get who/fuid */
+ void (*ace_who_set)(void *acep,
+ uint64_t who); /* set who/fuid */
+ size_t (*ace_size)(void *acep); /* how big is this ace */
+ size_t (*ace_abstract_size)(void); /* sizeof abstract entry */
+ int (*ace_mask_off)(void); /* off of access mask in ace */
+ int (*ace_data)(void *acep, void **datap);
+ /* ptr to data if any */
+} acl_ops_t;
/*
- * Max ACL size is prepended deny for all entries + the
- * canonical six tacked on * the end.
+ * A zfs_acl_t structure is composed of a list of zfs_acl_node_t's.
+ * Each node will have one or more ACEs associated with it. You will
+ * only have multiple nodes during a chmod operation. Normally only
+ * one node is required.
*/
-#define MAX_ACL_SIZE (MAX_ACL_ENTRIES * 2 + 6)
+typedef struct zfs_acl_node {
+ list_node_t z_next; /* Next chunk of ACEs */
+ void *z_acldata; /* pointer into actual ACE(s) */
+ void *z_allocdata; /* pointer to kmem allocated memory */
+ size_t z_allocsize; /* Size of blob in bytes */
+ size_t z_size; /* length of ACL data */
+ int z_ace_count; /* number of ACEs in this acl node */
+ int z_ace_idx; /* ace iterator positioned on */
+} zfs_acl_node_t;
typedef struct zfs_acl {
- int z_slots; /* number of allocated slots for ACEs */
- int z_acl_count;
- uint_t z_state;
- ace_t *z_acl;
+ int z_acl_count; /* Number of ACEs */
+ size_t z_acl_bytes; /* Number of bytes in ACL */
+ uint_t z_version; /* version of ACL */
+ void *z_next_ace; /* pointer to next ACE */
+ int z_hints; /* ACL hints (ZFS_INHERIT_ACE ...) */
+ zfs_acl_node_t *z_curr_node; /* current node iterator is handling */
+ list_t z_acl; /* chunks of ACE data */
+ acl_ops_t z_ops; /* ACL operations */
} zfs_acl_t;
+#define ACL_DATA_ALLOCED 0x1
#define ZFS_ACL_SIZE(aclcnt) (sizeof (ace_t) * (aclcnt))
/*
@@ -84,24 +184,26 @@ typedef struct zfs_acl {
#define ZFS_ACL_SECURE 4
struct znode;
+struct zfsvfs;
#ifdef _KERNEL
void zfs_perm_init(struct znode *, struct znode *, int, vattr_t *,
- dmu_tx_t *, cred_t *);
-int zfs_getacl(struct znode *, vsecattr_t *, cred_t *);
-int zfs_mode_update(struct znode *, uint64_t, dmu_tx_t *);
-int zfs_setacl(struct znode *, vsecattr_t *, cred_t *);
+ dmu_tx_t *, cred_t *, zfs_acl_t *, zfs_fuid_info_t **);
+int zfs_getacl(struct znode *, vsecattr_t *, boolean_t, cred_t *);
+int zfs_setacl(struct znode *, vsecattr_t *, boolean_t, cred_t *);
void zfs_acl_rele(void *);
-void zfs_ace_byteswap(ace_t *, int);
-extern int zfs_zaccess(struct znode *, int, cred_t *);
-extern int zfs_zaccess_rwx(struct znode *, mode_t, cred_t *);
+void zfs_oldace_byteswap(ace_t *, int);
+void zfs_ace_byteswap(void *, size_t, boolean_t);
+extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *);
+extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *);
+extern int zfs_zaccess_unix(struct znode *, mode_t, cred_t *);
extern int zfs_acl_access(struct znode *, int, cred_t *);
int zfs_acl_chmod_setattr(struct znode *, uint64_t, dmu_tx_t *);
int zfs_zaccess_delete(struct znode *, struct znode *, cred_t *);
int zfs_zaccess_rename(struct znode *, struct znode *,
struct znode *, struct znode *, cred_t *cr);
-int zfs_zaccess_v4_perm(struct znode *, int, cred_t *);
void zfs_acl_free(zfs_acl_t *);
+int zfs_vsec_2_aclp(struct zfsvfs *, vtype_t, vsecattr_t *, zfs_acl_t **);
#endif
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h b/usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h
index 8f1cb74d94..78f52bf22c 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h
@@ -58,7 +58,8 @@ int zfsctl_umount_snapshots(vfs_t *, int, cred_t *);
int zfsctl_unmount_snap(vnode_t *dvp, const char *name, int force, cred_t *cr);
int zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr);
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp);
int zfsctl_make_fid(zfsvfs_t *zfsvfsp, uint64_t object, uint32_t gen,
fid_t *fidp);
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_dir.h b/usr/src/uts/common/fs/zfs/sys/zfs_dir.h
index f60d614953..0ad129092c 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_dir.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_dir.h
@@ -28,6 +28,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
+#include <sys/pathname.h>
#include <sys/dmu.h>
#include <sys/zfs_znode.h>
@@ -41,6 +42,8 @@ extern "C" {
#define ZSHARED 0x0004 /* shared access (zfs_dirlook()) */
#define ZXATTR 0x0008 /* we want the xattr dir */
#define ZRENAMING 0x0010 /* znode is being renamed */
+#define ZCILOOK 0x0020 /* case-insensitive lookup requested */
+#define ZCIEXACT 0x0040 /* c-i requires c-s match (rename) */
/* mknode flags */
#define IS_ROOT_NODE 0x01 /* create a root node */
@@ -48,15 +51,18 @@ extern "C" {
#define IS_REPLAY 0x04 /* we are replaying intent log */
extern int zfs_dirent_lock(zfs_dirlock_t **, znode_t *, char *, znode_t **,
- int);
+ int, int *, pathname_t *);
extern void zfs_dirent_unlock(zfs_dirlock_t *);
extern int zfs_link_create(zfs_dirlock_t *, znode_t *, dmu_tx_t *, int);
extern int zfs_link_destroy(zfs_dirlock_t *, znode_t *, dmu_tx_t *, int,
boolean_t *);
-extern int zfs_dirlook(znode_t *, char *, vnode_t **);
+extern int zfs_dirlook(znode_t *, char *, vnode_t **, int, int *,
+ pathname_t *);
extern void zfs_mknode(znode_t *, vattr_t *, uint64_t *,
- dmu_tx_t *, cred_t *, uint_t, znode_t **, int);
+ dmu_tx_t *, cred_t *, uint_t, znode_t **, int,
+ zfs_acl_t *, zfs_fuid_info_t **);
extern void zfs_rmnode(znode_t *);
+extern void zfs_dl_name_switch(zfs_dirlock_t *dl, char *new, char **old);
extern boolean_t zfs_dirempty(znode_t *);
extern void zfs_unlinked_add(znode_t *, dmu_tx_t *);
extern void zfs_unlinked_drain(zfsvfs_t *zfsvfs);
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h b/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h
new file mode 100644
index 0000000000..3f46ff7e3e
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_FS_ZFS_FUID_H
+#define _SYS_FS_ZFS_FUID_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+#include <sys/types32.h>
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#include <sys/sid.h>
+#include <sys/dmu.h>
+#include <sys/zfs_vfsops.h>
+#endif
+
+#ifdef _KERNEL
+typedef struct zfs_fuid_hdl {
+ idmap_get_handle_t *z_hdl;
+ boolean_t z_map_needed; /* is mapping required */
+ idmap_stat z_status; /* needed for kidmap interface */
+} zfs_fuid_hdl_t;
+
+typedef enum {
+ ZFS_OWNER,
+ ZFS_GROUP,
+ ZFS_ACE_USER,
+ ZFS_ACE_GROUP
+} zfs_fuid_type_t;
+
+#endif
+
+
+#define FUID_INDEX(x) (x >> 32)
+#define FUID_RID(x) (x & 0xffffffff)
+#define FUID_ENCODE(idx, rid) ((idx << 32) | rid)
+/*
+ * FUIDs cause problems for the intent log
+ * we need to replay the creation of the FUID,
+ * but we can't count on the idmapper to be around
+ * and during replay the FUID index may be different than
+ * before. Also, if an ACL has 100 ACEs and 12 different
+ * domains we don't want to log 100 domain strings, but rather
+ * just the unique 12.
+ */
+
+/*
+ * The FUIDs in the log will index into
+ * domain string table and the bottom half will be the rid.
+ * Used for mapping ephemeral uid/gid during ACL setting to FUIDs
+ */
+typedef struct zfs_fuid {
+ list_node_t z_next;
+ uint64_t z_id; /* uid/gid being converted to fuid */
+ uint64_t z_domidx; /* index in AVL domain table */
+ uint64_t z_logfuid; /* index for domain in log */
+} zfs_fuid_t;
+
+/* list of unique domains */
+typedef struct zfs_fuid_domain {
+ list_node_t z_next;
+ uint64_t z_domidx; /* AVL tree idx */
+ const char *z_domain; /* domain string */
+} zfs_fuid_domain_t;
+
+/*
+ * FUID information necessary for logging create, setattr, and setacl.
+ */
+typedef struct zfs_fuid_info {
+ list_t z_fuids;
+ list_t z_domains;
+ uint64_t z_fuid_owner;
+ uint64_t z_fuid_group;
+ char **z_domain_table; /* Used during replay */
+ uint32_t z_fuid_cnt; /* How many fuids in z_fuids */
+ uint32_t z_domain_cnt; /* How many domains */
+ size_t z_domain_str_sz; /* len of domain strings z_domain list */
+} zfs_fuid_info_t;
+
+#ifdef _KERNEL
+struct znode;
+extern void zfs_fuid_map_id(zfsvfs_t *, uint64_t, zfs_fuid_type_t, uid_t *);
+extern void zfs_fuid_destroy(zfsvfs_t *);
+extern uint64_t zfs_fuid_create_cred(zfsvfs_t *, uint64_t, zfs_fuid_type_t,
+ dmu_tx_t *, cred_t *, zfs_fuid_info_t **);
+extern uint64_t zfs_fuid_create(zfsvfs_t *, uint64_t, zfs_fuid_type_t,
+ dmu_tx_t *, zfs_fuid_info_t **);
+extern void zfs_fuid_queue_map_id(zfsvfs_t *zfsvfs, zfs_fuid_hdl_t *,
+ uint64_t, zfs_fuid_type_t, uid_t *);
+extern void zfs_fuid_map_ids(struct znode *zp, uid_t *uid, uid_t *gid);
+extern void zfs_fuid_get_mappings(zfs_fuid_hdl_t *);
+extern char *zfs_fuid_find_by_idx(zfsvfs_t *, uint64_t);
+int zfs_fuid_find_by_domain(zfsvfs_t *, const char *, char **, dmu_tx_t *);
+extern zfs_fuid_info_t *zfs_fuid_info_alloc(void);
+extern void zfs_fuid_info_free();
+extern boolean_t zfs_groupmember(zfsvfs_t *, uint64_t, cred_t *);
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_FUID_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_i18n.h b/usr/src/uts/common/fs/zfs/sys/zfs_i18n.h
new file mode 100644
index 0000000000..96fe54a230
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_i18n.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_ZFS_I18N_H
+#define _SYS_ZFS_I18N_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sunddi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * z_case behaviors
+ * The first two describe the extent of case insensitivity.
+ * The third describes matching behavior when mixed sensitivity
+ * is allowed.
+ */
+#define ZFS_CI_ONLY 0x01 /* all lookups case-insensitive */
+#define ZFS_CI_MIXD 0x02 /* some lookups case-insensitive */
+
+/*
+ * ZFS_UTF8_ONLY
+ * If set, the file system should reject non-utf8 characters in names.
+ */
+#define ZFS_UTF8_ONLY 0x04
+
+enum zfs_case {
+ ZFS_CASE_SENSITIVE,
+ ZFS_CASE_INSENSITIVE,
+ ZFS_CASE_MIXED
+};
+
+enum zfs_normal {
+ ZFS_NORMALIZE_NONE,
+ ZFS_NORMALIZE_D,
+ ZFS_NORMALIZE_KC,
+ ZFS_NORMALIZE_C,
+ ZFS_NORMALIZE_KD
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFS_I18N_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
index e1bb9f0514..93c8d76bc0 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
@@ -33,6 +33,10 @@
#include <sys/zio.h>
#include <sys/dsl_deleg.h>
+#ifdef _KERNEL
+#include <sys/nvpair.h>
+#endif /* _KERNEL */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -152,6 +156,11 @@ typedef struct zfs_cmd {
#ifdef _KERNEL
+typedef struct zfs_creat {
+ int zct_norm;
+ nvlist_t *zct_props;
+} zfs_creat_t;
+
extern dev_info_t *zfs_dip;
extern int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr);
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
index ea55a86b9e..b21dadaa15 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
@@ -49,9 +49,17 @@ struct zfsvfs {
uint64_t z_unlinkedobj; /* id of unlinked zapobj */
uint64_t z_max_blksz; /* maximum block size for files */
uint64_t z_assign; /* TXG_NOWAIT or set by zil_replay() */
+ uint64_t z_fuid_obj; /* fuid table object number */
+ avl_tree_t z_fuid_idx; /* fuid tree keyed by index */
+ avl_tree_t z_fuid_domain; /* fuid tree keyed by domain */
+ krwlock_t z_fuid_lock; /* fuid lock */
+ boolean_t z_fuid_loaded; /* fuid tables are loaded */
+ struct zfs_fuid_info *z_fuid_replay; /* fuid info for replay */
zilog_t *z_log; /* intent log pointer */
uint_t z_acl_mode; /* acl chmod/mode behavior */
uint_t z_acl_inherit; /* acl inheritance behavior */
+ uint_t z_case; /* case-insensitive behavior */
+ int z_norm; /* normalization flags */
boolean_t z_atime; /* enable atimes mount option */
boolean_t z_unmounted; /* unmounted */
rrwlock_t z_teardown_lock;
@@ -61,6 +69,8 @@ struct zfsvfs {
vnode_t *z_ctldir; /* .zfs directory pointer */
boolean_t z_show_ctldir; /* expose .zfs in the root dir */
boolean_t z_issnap; /* true if this is a snapshot */
+ boolean_t z_vscan; /* virus scan on/off */
+ boolean_t z_use_fuids; /* version allows fuids */
uint64_t z_version;
#define ZFS_OBJ_MTX_SZ 64
kmutex_t z_hold_mtx[ZFS_OBJ_MTX_SZ]; /* znode hold locks */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
index 8b4ee46218..b9e0c95290 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
@@ -31,6 +31,7 @@
#ifdef _KERNEL
#include <sys/isa_defs.h>
#include <sys/types32.h>
+#include <sys/attr.h>
#include <sys/list.h>
#include <sys/dmu.h>
#include <sys/zfs_vfsops.h>
@@ -44,21 +45,62 @@ extern "C" {
#endif
/*
+ * Additional file level attributes, that are stored
+ * in the upper half of zp_flags
+ */
+#define ZFS_READONLY 0x0000000100000000
+#define ZFS_HIDDEN 0x0000000200000000
+#define ZFS_SYSTEM 0x0000000400000000
+#define ZFS_ARCHIVE 0x0000000800000000
+#define ZFS_IMMUTABLE 0x0000001000000000
+#define ZFS_NOUNLINK 0x0000002000000000
+#define ZFS_APPENDONLY 0x0000004000000000
+#define ZFS_NODUMP 0x0000008000000000
+#define ZFS_OPAQUE 0x0000010000000000
+#define ZFS_AV_QUARANTINED 0x0000020000000000
+#define ZFS_AV_MODIFIED 0x0000040000000000
+
+#define ZFS_ATTR_SET(zp, attr, value) \
+{ \
+ if (value) \
+ zp->z_phys->zp_flags |= attr; \
+ else \
+ zp->z_phys->zp_flags &= ~attr; \
+}
+
+/*
* Define special zfs pflags
*/
-#define ZFS_XATTR 0x1 /* is an extended attribute */
-#define ZFS_INHERIT_ACE 0x2 /* ace has inheritable ACEs */
-#define ZFS_ACL_TRIVIAL 0x4 /* files ACL is trivial */
+#define ZFS_XATTR 0x1 /* is an extended attribute */
+#define ZFS_INHERIT_ACE 0x2 /* ace has inheritable ACEs */
+#define ZFS_ACL_TRIVIAL 0x4 /* files ACL is trivial */
+#define ZFS_ACL_OBJ_ACE 0x8 /* ACL has CMPLX Object ACE */
+#define ZFS_ACL_PROTECTED 0x10 /* ACL protected */
+#define ZFS_ACL_DEFAULTED 0x20 /* ACL should be defaulted */
+#define ZFS_ACL_AUTO_INHERIT 0x40 /* ACL should be inherited */
+#define ZFS_BONUS_SCANSTAMP 0x80 /* Scanstamp in bonus area */
+
+/*
+ * Is ID ephemeral?
+ */
+#define IS_EPHEMERAL(x) (x > MAXUID)
+
+/*
+ * Should we use FUIDs?
+ */
+#define USE_FUIDS(version, os) (version >= ZPL_VERSION_FUID &&\
+ spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
#define MASTER_NODE_OBJ 1
/*
- * special attributes for master node.
+ * Special attributes for master node.
*/
#define ZFS_FSID "FSID"
#define ZFS_UNLINKED_SET "DELETE_QUEUE"
#define ZFS_ROOT_OBJ "ROOT"
#define ZPL_VERSION_STR "VERSION"
+#define ZFS_FUID_TABLES "FUID"
#define ZFS_MAX_BLOCKSIZE (SPA_MAXBLOCKSIZE)
@@ -107,8 +149,9 @@ typedef struct znode_phys {
uint64_t zp_flags; /* 120 - persistent flags */
uint64_t zp_uid; /* 128 - file owner */
uint64_t zp_gid; /* 136 - owning group */
- uint64_t zp_pad[4]; /* 144 - future */
- zfs_znode_acl_t zp_acl; /* 176 - 263 ACL */
+ uint64_t zp_zap; /* 144 - extra attributes */
+ uint64_t zp_pad[3]; /* 152 - future */
+ zfs_acl_phys_t zp_acl; /* 176 - 263 ACL */
/*
* Data may pad out any remaining bytes in the znode buffer, eg:
*
@@ -116,7 +159,9 @@ typedef struct znode_phys {
* |<-- dnode (192) --->|<----------- "bonus" buffer (320) ---------->|
* |<---- znode (264) ---->|<---- data (56) ---->|
*
- * At present, we only use this space to store symbolic links.
+ * At present, we use this space for the following:
+ * - symbolic links
+ * - 32-byte anti-virus scanstamp (regular files only)
*/
} znode_phys_t;
@@ -253,7 +298,8 @@ typedef struct znode {
extern int zfs_init_fs(zfsvfs_t *, znode_t **, cred_t *);
extern void zfs_set_dataprop(objset_t *);
-extern void zfs_create_fs(objset_t *os, cred_t *cr, uint64_t, dmu_tx_t *tx);
+extern void zfs_create_fs(objset_t *os, cred_t *cr, uint64_t, int,
+ dmu_tx_t *tx);
extern void zfs_time_stamper(znode_t *, uint_t, dmu_tx_t *);
extern void zfs_time_stamper_locked(znode_t *, uint_t, dmu_tx_t *);
extern void zfs_grow_blocksize(znode_t *, uint64_t, dmu_tx_t *);
@@ -271,25 +317,31 @@ extern int zfs_sync(vfs_t *vfsp, short flag, cred_t *cr);
extern dev_t zfs_cmpldev(uint64_t);
extern int zfs_get_version(objset_t *os, uint64_t *version);
extern int zfs_set_version(const char *name, uint64_t newvers);
-
-extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *dzp, znode_t *zp, char *name);
-extern void zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+extern int zfs_get_stats(objset_t *os, nvlist_t *nv);
+
+extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+ znode_t *dzp, znode_t *zp, char *name, vsecattr_t *, zfs_fuid_info_t *,
+ vattr_t *vap);
+extern int zfs_log_create_txtype(zil_create_t, vsecattr_t *vsecp,
+ vattr_t *vap);
+extern void zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, char *name);
-extern void zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+extern void zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, znode_t *zp, char *name);
-extern void zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+extern void zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, znode_t *zp, char *name, char *link);
-extern void zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+extern void zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *sdzp, char *sname, znode_t *tdzp, char *dname, znode_t *szp);
extern void zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
znode_t *zp, offset_t off, ssize_t len, int ioflag);
extern void zfs_log_truncate(zilog_t *zilog, dmu_tx_t *tx, int txtype,
znode_t *zp, uint64_t off, uint64_t len);
extern void zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *zp, vattr_t *vap, uint_t mask_applied);
-extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *zp, int aclcnt, ace_t *z_ace);
+ znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp);
+extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp,
+ vsecattr_t *vsecp, zfs_fuid_info_t *fuidp);
+extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap);
+extern void zfs_upgrade(zfsvfs_t *zfsvfs, dmu_tx_t *tx);
extern zil_get_data_t zfs_get_data;
extern zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE];
diff --git a/usr/src/uts/common/fs/zfs/sys/zil.h b/usr/src/uts/common/fs/zfs/sys/zil.h
index 55de6b6f27..b5b665c26c 100644
--- a/usr/src/uts/common/fs/zfs/sys/zil.h
+++ b/usr/src/uts/common/fs/zfs/sys/zil.h
@@ -88,22 +88,53 @@ typedef struct zil_trailer {
#define ZIL_ZC_OBJSET 2
#define ZIL_ZC_SEQ 3
+typedef enum zil_create {
+ Z_FILE,
+ Z_DIR,
+ Z_XATTRDIR,
+} zil_create_t;
+
+/*
+ * size of xvattr log section.
+ * its composed of lr_attr_t + xvattr bitmap + 2 64 bit timestamps
+ * for create time and a single 64 bit integer for all of the attributes,
+ * and 4 64 bit integers (32 bytes) for the scanstamp.
+ *
+ */
+
+#define ZIL_XVAT_SIZE(mapsize) \
+ sizeof (lr_attr_t) + (sizeof (uint32_t) * (mapsize - 1)) + \
+ (sizeof (uint64_t) * 7)
/*
* Intent log transaction types and record structures
*/
-#define TX_CREATE 1 /* Create file */
-#define TX_MKDIR 2 /* Make directory */
-#define TX_MKXATTR 3 /* Make XATTR directory */
-#define TX_SYMLINK 4 /* Create symbolic link to a file */
-#define TX_REMOVE 5 /* Remove file */
-#define TX_RMDIR 6 /* Remove directory */
-#define TX_LINK 7 /* Create hard link to a file */
-#define TX_RENAME 8 /* Rename a file */
-#define TX_WRITE 9 /* File write */
-#define TX_TRUNCATE 10 /* Truncate a file */
-#define TX_SETATTR 11 /* Set file attributes */
-#define TX_ACL 12 /* Set acl */
-#define TX_MAX_TYPE 13 /* Max transaction type */
+#define TX_CREATE 1 /* Create file */
+#define TX_MKDIR 2 /* Make directory */
+#define TX_MKXATTR 3 /* Make XATTR directory */
+#define TX_SYMLINK 4 /* Create symbolic link to a file */
+#define TX_REMOVE 5 /* Remove file */
+#define TX_RMDIR 6 /* Remove directory */
+#define TX_LINK 7 /* Create hard link to a file */
+#define TX_RENAME 8 /* Rename a file */
+#define TX_WRITE 9 /* File write */
+#define TX_TRUNCATE 10 /* Truncate a file */
+#define TX_SETATTR 11 /* Set file attributes */
+#define TX_ACL_V0 12 /* Set old formatted ACL */
+#define TX_ACL 13 /* Set ACL */
+#define TX_CREATE_ACL 14 /* create with ACL */
+#define TX_CREATE_ATTR 15 /* create + attrs */
+#define TX_CREATE_ACL_ATTR 16 /* create with ACL + attrs */
+#define TX_MKDIR_ACL 17 /* mkdir with ACL */
+#define TX_MKDIR_ATTR 18 /* mkdir with attr */
+#define TX_MKDIR_ACL_ATTR 19 /* mkdir with ACL + attrs */
+#define TX_MAX_TYPE 20 /* Max transaction type */
+
+/*
+ * The transactions for mkdir, symlink, remove, rmdir, link, and rename
+ * may have the following bit set, indicating the original request
+ * specified case-insensitive handling of names.
+ */
+#define TX_CI ((uint64_t)0x1 << 63) /* case-insensitive behavior requested */
/*
* Format of log records.
@@ -124,6 +155,23 @@ typedef struct { /* common log record header */
uint64_t lrc_seq; /* see comment above */
} lr_t;
+/*
+ * Handle option extended vattr attributes.
+ *
+ * Whenever new attributes are added the version number
+ * will need to be updated as will code in
+ * zfs_log.c and zfs_replay.c
+ */
+typedef struct {
+ uint32_t lr_attr_masksize; /* number of elements in array */
+ uint32_t lr_attr_bitmap; /* First entry of array */
+ /* remainder of array and any additional fields */
+} lr_attr_t;
+
+/*
+ * log record for creates without optional ACL.
+ * This log record does support optional xvattr_t attributes.
+ */
typedef struct {
lr_t lr_common; /* common portion of log record */
uint64_t lr_doid; /* object id of directory */
@@ -136,8 +184,42 @@ typedef struct {
uint64_t lr_rdev; /* rdev of object to create */
/* name of object to create follows this */
/* for symlinks, link content follows name */
+ /* for creates with xvattr data, the name follows the xvattr info */
} lr_create_t;
+/*
+ * FUID ACL record will be an array of ACEs from the original ACL.
+ * If this array includes ephemeral IDs, the record will also include
+ * an array of log-specific FUIDs to replace the ephemeral IDs.
+ * Only one copy of each unique domain will be present, so the log-specific
+ * FUIDs will use an index into a compressed domain table. On replay this
+ * information will be used to construct real FUIDs (and bypass idmap,
+ * since it may not be available).
+ */
+
+/*
+ * Log record for creates with optional ACL
+ * This log record is also used for recording any FUID
+ * information needed for replaying the create. If the
+ * file doesn't have any actual ACEs then the lr_aclcnt
+ * would be zero.
+ */
+typedef struct {
+ lr_create_t lr_create; /* common create portion */
+ uint64_t lr_aclcnt; /* number of ACEs in ACL */
+ uint64_t lr_domcnt; /* number of unique domains */
+ uint64_t lr_fuidcnt; /* number of real fuids */
+ uint64_t lr_acl_bytes; /* number of bytes in ACL */
+ uint64_t lr_acl_flags; /* ACL flags */
+ /* lr_acl_bytes number of variable sized ace's follows */
+ /* if create is also setting xvattr's, then acl data follows xvattr */
+ /* if ACE FUIDs are needed then they will follow the xvattr_t */
+ /* Following the FUIDs will be the domain table information. */
+ /* The FUIDs for the owner and group will be in the lr_create */
+ /* portion of the record. */
+ /* name follows ACL data */
+} lr_acl_create_t;
+
typedef struct {
lr_t lr_common; /* common portion of log record */
uint64_t lr_doid; /* obj id of directory */
@@ -185,6 +267,7 @@ typedef struct {
uint64_t lr_size; /* size to set */
uint64_t lr_atime[2]; /* access time */
uint64_t lr_mtime[2]; /* modification time */
+ /* optional attribute lr_attr_t may be here */
} lr_setattr_t;
typedef struct {
@@ -192,6 +275,17 @@ typedef struct {
uint64_t lr_foid; /* obj id of file */
uint64_t lr_aclcnt; /* number of acl entries */
/* lr_aclcnt number of ace_t entries follow this */
+} lr_acl_v0_t;
+
+typedef struct {
+ lr_t lr_common; /* common portion of log record */
+ uint64_t lr_foid; /* obj id of file */
+ uint64_t lr_aclcnt; /* number of ACEs in ACL */
+ uint64_t lr_domcnt; /* number of unique domains */
+ uint64_t lr_fuidcnt; /* number of real fuids */
+ uint64_t lr_acl_bytes; /* number of bytes in ACL */
+ uint64_t lr_acl_flags; /* ACL flags */
+ /* lr_acl_bytes number of variable sized ace's follows */
} lr_acl_t;
/*
@@ -253,7 +347,7 @@ extern void zil_replay(objset_t *os, void *arg, uint64_t *txgp,
extern void zil_destroy(zilog_t *zilog, boolean_t keep_first);
extern void zil_rollback_destroy(zilog_t *zilog, dmu_tx_t *tx);
-extern itx_t *zil_itx_create(int txtype, size_t lrsize);
+extern itx_t *zil_itx_create(uint64_t txtype, size_t lrsize);
extern uint64_t zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx);
extern void zil_commit(zilog_t *zilog, uint64_t seq, uint64_t oid);
diff --git a/usr/src/uts/common/fs/zfs/vdev_file.c b/usr/src/uts/common/fs/zfs/vdev_file.c
index 6f099b6629..b212161c64 100644
--- a/usr/src/uts/common/fs/zfs/vdev_file.c
+++ b/usr/src/uts/common/fs/zfs/vdev_file.c
@@ -61,7 +61,7 @@ vdev_file_open_common(vdev_t *vd)
*/
ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/');
error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE,
- spa_mode | FOFFMAX, 0, &vp, 0, 0, rootdir);
+ spa_mode | FOFFMAX, 0, &vp, 0, 0, rootdir, -1);
if (error) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
@@ -99,7 +99,7 @@ vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
* Determine the physical size of the file.
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred);
+ error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL);
if (error) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
return (error);
@@ -120,8 +120,8 @@ vdev_file_close(vdev_t *vd)
return;
if (vf->vf_vnode != NULL) {
- (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred);
- (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred);
+ (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL);
+ (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred, NULL);
VN_RELE(vf->vf_vnode);
}
@@ -233,7 +233,7 @@ vdev_file_io_start(zio_t *zio)
switch (zio->io_cmd) {
case DKIOCFLUSHWRITECACHE:
zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC,
- kcred);
+ kcred, NULL);
dprintf("fsync(%s) = %d\n", vdev_description(vd),
zio->io_error);
break;
diff --git a/usr/src/uts/common/fs/zfs/zap.c b/usr/src/uts/common/fs/zfs/zap.c
index 7dfe44baba..db0162b0ee 100644
--- a/usr/src/uts/common/fs/zfs/zap.c
+++ b/usr/src/uts/common/fs/zfs/zap.c
@@ -102,6 +102,7 @@ fzap_upgrade(zap_t *zap, dmu_tx_t *tx)
zp->zap_num_leafs = 1;
zp->zap_num_entries = 0;
zp->zap_salt = zap->zap_salt;
+ zp->zap_normflags = zap->zap_normflags;
/* block 1 will be the first leaf */
for (i = 0; i < (1<<zp->zap_ptrtbl.zt_shift); i++)
@@ -118,7 +119,7 @@ fzap_upgrade(zap_t *zap, dmu_tx_t *tx)
l->l_dbuf = db;
l->l_phys = db->db_data;
- zap_leaf_init(l);
+ zap_leaf_init(l, spa_version(dmu_objset_spa(zap->zap_objset)));
kmem_free(l, sizeof (zap_leaf_t));
dmu_buf_rele(db, FTAG);
@@ -398,7 +399,7 @@ zap_create_leaf(zap_t *zap, dmu_tx_t *tx)
ASSERT(winner == NULL);
dmu_buf_will_dirty(l->l_dbuf, tx);
- zap_leaf_init(l);
+ zap_leaf_init(l, spa_version(dmu_objset_spa(zap->zap_objset)));
zap->zap_f.zap_phys->zap_num_leafs++;
@@ -642,7 +643,7 @@ zap_expand_leaf(zap_t *zap, zap_leaf_t *l, uint64_t hash, dmu_tx_t *tx,
}
nl = zap_create_leaf(zap, tx);
- zap_leaf_split(l, nl);
+ zap_leaf_split(l, nl, spa_version(dmu_objset_spa(zap->zap_objset)));
/* set sibling pointers */
for (i = 0; i < (1ULL<<prefix_diff); i++) {
@@ -720,53 +721,58 @@ fzap_checksize(const char *name, uint64_t integer_size, uint64_t num_integers)
}
/*
- * Routines for maniplulating attributes.
+ * Routines for manipulating attributes.
*/
int
-fzap_lookup(zap_t *zap, const char *name,
- uint64_t integer_size, uint64_t num_integers, void *buf)
+fzap_lookup(zap_name_t *zn,
+ uint64_t integer_size, uint64_t num_integers, void *buf,
+ char *realname, int rn_len, boolean_t *ncp)
{
zap_leaf_t *l;
int err;
- uint64_t hash;
zap_entry_handle_t zeh;
- err = fzap_checksize(name, integer_size, num_integers);
+ err = fzap_checksize(zn->zn_name_orij, integer_size, num_integers);
if (err != 0)
return (err);
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, NULL, RW_READER, &l);
+ err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, NULL, RW_READER, &l);
if (err != 0)
return (err);
- err = zap_leaf_lookup(l, name, hash, &zeh);
- if (err == 0)
+ err = zap_leaf_lookup(l, zn, &zeh);
+ if (err == 0) {
err = zap_entry_read(&zeh, integer_size, num_integers, buf);
+ (void) zap_entry_read_name(&zeh, rn_len, realname);
+ if (ncp) {
+ *ncp = zap_entry_normalization_conflict(&zeh,
+ zn, NULL, zn->zn_zap);
+ }
+ }
zap_put_leaf(l);
return (err);
}
int
-fzap_add_cd(zap_t *zap, const char *name,
+fzap_add_cd(zap_name_t *zn,
uint64_t integer_size, uint64_t num_integers,
const void *val, uint32_t cd, dmu_tx_t *tx)
{
zap_leaf_t *l;
- uint64_t hash;
int err;
zap_entry_handle_t zeh;
+ zap_t *zap = zn->zn_zap;
ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
ASSERT(!zap->zap_ismicro);
- ASSERT(fzap_checksize(name, integer_size, num_integers) == 0);
+ ASSERT(fzap_checksize(zn->zn_name_orij,
+ integer_size, num_integers) == 0);
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, tx, RW_WRITER, &l);
+ err = zap_deref_leaf(zap, zn->zn_hash, tx, RW_WRITER, &l);
if (err != 0)
return (err);
retry:
- err = zap_leaf_lookup(l, name, hash, &zeh);
+ err = zap_leaf_lookup(l, zn, &zeh);
if (err == 0) {
err = EEXIST;
goto out;
@@ -774,13 +780,13 @@ retry:
if (err != ENOENT)
goto out;
- err = zap_entry_create(l, name, hash, cd,
+ err = zap_entry_create(l, zn->zn_name_orij, zn->zn_hash, cd,
integer_size, num_integers, val, &zeh);
if (err == 0) {
zap_increment_num_entries(zap, 1, tx);
} else if (err == EAGAIN) {
- err = zap_expand_leaf(zap, l, hash, tx, &l);
+ err = zap_expand_leaf(zap, l, zn->zn_hash, tx, &l);
if (err == 0)
goto retry;
}
@@ -791,46 +797,43 @@ out:
}
int
-fzap_add(zap_t *zap, const char *name,
+fzap_add(zap_name_t *zn,
uint64_t integer_size, uint64_t num_integers,
const void *val, dmu_tx_t *tx)
{
- int err = fzap_checksize(name, integer_size, num_integers);
+ int err = fzap_checksize(zn->zn_name_orij, integer_size, num_integers);
if (err != 0)
return (err);
- return (fzap_add_cd(zap, name, integer_size, num_integers,
+ return (fzap_add_cd(zn, integer_size, num_integers,
val, ZAP_MAXCD, tx));
}
int
-fzap_update(zap_t *zap, const char *name,
+fzap_update(zap_name_t *zn,
int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx)
{
zap_leaf_t *l;
- uint64_t hash;
int err, create;
zap_entry_handle_t zeh;
+ zap_t *zap = zn->zn_zap;
ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
- err = fzap_checksize(name, integer_size, num_integers);
+ err = fzap_checksize(zn->zn_name_orij, integer_size, num_integers);
if (err != 0)
return (err);
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, tx, RW_WRITER, &l);
+ err = zap_deref_leaf(zap, zn->zn_hash, tx, RW_WRITER, &l);
if (err != 0)
return (err);
retry:
- err = zap_leaf_lookup(l, name, hash, &zeh);
+ err = zap_leaf_lookup(l, zn, &zeh);
create = (err == ENOENT);
ASSERT(err == 0 || err == ENOENT);
- /* XXX If this leaf is chained, split it if we can. */
-
if (create) {
- err = zap_entry_create(l, name, hash, ZAP_MAXCD,
- integer_size, num_integers, val, &zeh);
+ err = zap_entry_create(l, zn->zn_name_orij, zn->zn_hash,
+ ZAP_MAXCD, integer_size, num_integers, val, &zeh);
if (err == 0)
zap_increment_num_entries(zap, 1, tx);
} else {
@@ -838,7 +841,7 @@ retry:
}
if (err == EAGAIN) {
- err = zap_expand_leaf(zap, l, hash, tx, &l);
+ err = zap_expand_leaf(zap, l, zn->zn_hash, tx, &l);
if (err == 0)
goto retry;
}
@@ -848,19 +851,17 @@ retry:
}
int
-fzap_length(zap_t *zap, const char *name,
+fzap_length(zap_name_t *zn,
uint64_t *integer_size, uint64_t *num_integers)
{
zap_leaf_t *l;
int err;
- uint64_t hash;
zap_entry_handle_t zeh;
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, NULL, RW_READER, &l);
+ err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, NULL, RW_READER, &l);
if (err != 0)
return (err);
- err = zap_leaf_lookup(l, name, hash, &zeh);
+ err = zap_leaf_lookup(l, zn, &zeh);
if (err != 0)
goto out;
@@ -874,25 +875,21 @@ out:
}
int
-fzap_remove(zap_t *zap, const char *name, dmu_tx_t *tx)
+fzap_remove(zap_name_t *zn, dmu_tx_t *tx)
{
zap_leaf_t *l;
- uint64_t hash;
int err;
zap_entry_handle_t zeh;
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, tx, RW_WRITER, &l);
+ err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, tx, RW_WRITER, &l);
if (err != 0)
return (err);
- err = zap_leaf_lookup(l, name, hash, &zeh);
+ err = zap_leaf_lookup(l, zn, &zeh);
if (err == 0) {
zap_entry_remove(&zeh);
- zap_increment_num_entries(zap, -1, tx);
+ zap_increment_num_entries(zn->zn_zap, -1, tx);
}
zap_put_leaf(l);
- dprintf("fzap_remove: ds=%p obj=%llu name=%s err=%d\n",
- zap->zap_objset, zap->zap_object, name, err);
return (err);
}
@@ -986,6 +983,10 @@ again:
err = zap_entry_read_name(&zeh,
sizeof (za->za_name), za->za_name);
ASSERT(err == 0);
+
+ za->za_normalization_conflict =
+ zap_entry_normalization_conflict(&zeh,
+ NULL, za->za_name, zap);
}
rw_exit(&zc->zc_leaf->l_rwlock);
return (err);
diff --git a/usr/src/uts/common/fs/zfs/zap_leaf.c b/usr/src/uts/common/fs/zfs/zap_leaf.c
index 5dff514530..d048bbc77c 100644
--- a/usr/src/uts/common/fs/zfs/zap_leaf.c
+++ b/usr/src/uts/common/fs/zfs/zap_leaf.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -38,6 +38,8 @@
#include <sys/spa.h>
#include <sys/dmu.h>
+static uint16_t *zap_leaf_rehash_entry(zap_leaf_t *l, uint16_t entry);
+
#define CHAIN_END 0xffff /* end of the chunk chain */
/* half the (current) minimum block size */
@@ -150,7 +152,7 @@ zap_leaf_byteswap(zap_leaf_phys_t *buf, int size)
}
void
-zap_leaf_init(zap_leaf_t *l)
+zap_leaf_init(zap_leaf_t *l, int version)
{
int i;
@@ -165,6 +167,8 @@ zap_leaf_init(zap_leaf_t *l)
l->l_phys->l_hdr.lh_block_type = ZBT_LEAF;
l->l_phys->l_hdr.lh_magic = ZAP_LEAF_MAGIC;
l->l_phys->l_hdr.lh_nfree = ZAP_LEAF_NUMCHUNKS(l);
+ if (version >= SPA_VERSION_NORMALIZATION)
+ l->l_phys->l_hdr.lh_flags |= ZLF_ENTRIES_CDSORTED;
}
/*
@@ -327,19 +331,30 @@ zap_leaf_array_read(zap_leaf_t *l, uint16_t chunk,
/*
* Only to be used on 8-bit arrays.
* array_len is actual len in bytes (not encoded le_value_length).
- * buf is null-terminated.
+ * namenorm is null-terminated.
*/
-static int
-zap_leaf_array_equal(zap_leaf_t *l, int chunk,
- int array_len, const char *buf)
+static boolean_t
+zap_leaf_array_match(zap_leaf_t *l, zap_name_t *zn, int chunk, int array_len)
{
int bseen = 0;
+ if (zn->zn_matchtype == MT_FIRST) {
+ char *thisname = kmem_alloc(array_len, KM_SLEEP);
+ boolean_t match;
+
+ zap_leaf_array_read(l, chunk, 1, array_len, 1,
+ array_len, thisname);
+ match = zap_match(zn, thisname);
+ kmem_free(thisname, array_len);
+ return (match);
+ }
+
+ /* Fast path for exact matching */
while (bseen < array_len) {
struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, chunk).l_array;
int toread = MIN(array_len - bseen, ZAP_LEAF_ARRAY_BYTES);
ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
- if (bcmp(la->la_array, buf + bseen, toread))
+ if (bcmp(la->la_array, zn->zn_name_orij + bseen, toread))
break;
chunk = la->la_next;
bseen += toread;
@@ -352,15 +367,15 @@ zap_leaf_array_equal(zap_leaf_t *l, int chunk,
*/
int
-zap_leaf_lookup(zap_leaf_t *l,
- const char *name, uint64_t h, zap_entry_handle_t *zeh)
+zap_leaf_lookup(zap_leaf_t *l, zap_name_t *zn, zap_entry_handle_t *zeh)
{
uint16_t *chunkp;
struct zap_leaf_entry *le;
ASSERT3U(l->l_phys->l_hdr.lh_magic, ==, ZAP_LEAF_MAGIC);
- for (chunkp = LEAF_HASH_ENTPTR(l, h);
+again:
+ for (chunkp = LEAF_HASH_ENTPTR(l, zn->zn_hash);
*chunkp != CHAIN_END; chunkp = &le->le_next) {
uint16_t chunk = *chunkp;
le = ZAP_LEAF_ENTRY(l, chunk);
@@ -368,11 +383,18 @@ zap_leaf_lookup(zap_leaf_t *l,
ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
- if (le->le_hash != h)
+ if (le->le_hash != zn->zn_hash)
continue;
- if (zap_leaf_array_equal(l, le->le_name_chunk,
- le->le_name_length, name)) {
+ /*
+ * NB: the entry chain is always sorted by cd on
+ * normalized zap objects, so this will find the
+ * lowest-cd match for MT_FIRST.
+ */
+ ASSERT(zn->zn_matchtype == MT_EXACT ||
+ (l->l_phys->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED));
+ if (zap_leaf_array_match(l, zn, le->le_name_chunk,
+ le->le_name_length)) {
zeh->zeh_num_integers = le->le_value_length;
zeh->zeh_integer_size = le->le_int_size;
zeh->zeh_cd = le->le_cd;
@@ -383,6 +405,15 @@ zap_leaf_lookup(zap_leaf_t *l,
}
}
+ /*
+ * NB: we could of course do this in one pass, but that would be
+ * a pain. We'll see if MT_BEST is even used much.
+ */
+ if (zn->zn_matchtype == MT_BEST) {
+ zn->zn_matchtype = MT_FIRST;
+ goto again;
+ }
+
return (ENOENT);
}
@@ -539,22 +570,41 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
return (E2BIG);
if (cd == ZAP_MAXCD) {
- for (cd = 0; cd < ZAP_MAXCD; cd++) {
+ /* find the lowest unused cd */
+ if (l->l_phys->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED) {
+ cd = 0;
+
for (chunk = *LEAF_HASH_ENTPTR(l, h);
chunk != CHAIN_END; chunk = le->le_next) {
le = ZAP_LEAF_ENTRY(l, chunk);
- if (le->le_hash == h &&
- le->le_cd == cd) {
+ if (le->le_cd > cd)
break;
+ if (le->le_hash == h) {
+ ASSERT3U(cd, ==, le->le_cd);
+ cd++;
}
}
- /* If this cd is not in use, we are good. */
- if (chunk == CHAIN_END)
- break;
+ } else {
+ /* old unsorted format; do it the O(n^2) way */
+ for (cd = 0; cd < ZAP_MAXCD; cd++) {
+ for (chunk = *LEAF_HASH_ENTPTR(l, h);
+ chunk != CHAIN_END; chunk = le->le_next) {
+ le = ZAP_LEAF_ENTRY(l, chunk);
+ if (le->le_hash == h &&
+ le->le_cd == cd) {
+ break;
+ }
+ }
+ /* If this cd is not in use, we are good. */
+ if (chunk == CHAIN_END)
+ break;
+ }
}
- /* If we tried all the cd's, we lose. */
- if (cd == ZAP_MAXCD)
- return (ENOSPC);
+ /*
+ * we would run out of space in a block before we could
+ * have ZAP_MAXCD entries
+ */
+ ASSERT3U(cd, <, ZAP_MAXCD);
}
if (l->l_phys->l_hdr.lh_nfree < numchunks)
@@ -574,9 +624,8 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
le->le_cd = cd;
/* link it into the hash chain */
- chunkp = LEAF_HASH_ENTPTR(l, h);
- le->le_next = *chunkp;
- *chunkp = chunk;
+ /* XXX if we did the search above, we could just use that */
+ chunkp = zap_leaf_rehash_entry(l, chunk);
l->l_phys->l_hdr.lh_nentries++;
@@ -591,16 +640,76 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
}
/*
+ * Determine if there is another entry with the same normalized form.
+ * For performance purposes, either zn or name must be provided (the
+ * other can be NULL). Note, there usually won't be any hash
+ * conflicts, in which case we don't need the concatenated/normalized
+ * form of the name. But all callers have one of these on hand anyway,
+ * so might as well take advantage. A cleaner but slower interface
+ * would accept neither argument, and compute the normalized name as
+ * needed (using zap_name_alloc(zap_entry_read_name(zeh))).
+ */
+boolean_t
+zap_entry_normalization_conflict(zap_entry_handle_t *zeh, zap_name_t *zn,
+ const char *name, zap_t *zap)
+{
+ uint64_t chunk;
+ struct zap_leaf_entry *le;
+ boolean_t allocdzn = B_FALSE;
+
+ if (zap->zap_normflags == 0)
+ return (B_FALSE);
+
+ for (chunk = *LEAF_HASH_ENTPTR(zeh->zeh_leaf, zeh->zeh_hash);
+ chunk != CHAIN_END; chunk = le->le_next) {
+ le = ZAP_LEAF_ENTRY(zeh->zeh_leaf, chunk);
+ if (le->le_hash != zeh->zeh_hash)
+ continue;
+ if (le->le_cd == zeh->zeh_cd)
+ continue;
+
+ if (zn == NULL) {
+ zn = zap_name_alloc(zap, name, MT_FIRST);
+ allocdzn = B_TRUE;
+ }
+ if (zap_leaf_array_match(zeh->zeh_leaf, zn,
+ le->le_name_chunk, le->le_name_length)) {
+ if (allocdzn)
+ zap_name_free(zn);
+ return (B_TRUE);
+ }
+ }
+ if (allocdzn)
+ zap_name_free(zn);
+ return (B_FALSE);
+}
+
+/*
* Routines for transferring entries between leafs.
*/
-static void
+static uint16_t *
zap_leaf_rehash_entry(zap_leaf_t *l, uint16_t entry)
{
struct zap_leaf_entry *le = ZAP_LEAF_ENTRY(l, entry);
- uint16_t *ptr = LEAF_HASH_ENTPTR(l, le->le_hash);
- le->le_next = *ptr;
- *ptr = entry;
+ struct zap_leaf_entry *le2;
+ uint16_t *chunkp;
+
+ /*
+ * keep the entry chain sorted by cd
+ * NB: this will not cause problems for unsorted leafs, though
+ * it is unnecessary there.
+ */
+ for (chunkp = LEAF_HASH_ENTPTR(l, le->le_hash);
+ *chunkp != CHAIN_END; chunkp = &le2->le_next) {
+ le2 = ZAP_LEAF_ENTRY(l, *chunkp);
+ if (le2->le_cd > le->le_cd)
+ break;
+ }
+
+ le->le_next = *chunkp;
+ *chunkp = entry;
+ return (chunkp);
}
static uint16_t
@@ -644,7 +753,7 @@ zap_leaf_transfer_entry(zap_leaf_t *l, int entry, zap_leaf_t *nl)
nle = ZAP_LEAF_ENTRY(nl, chunk);
*nle = *le; /* structure assignment */
- zap_leaf_rehash_entry(nl, chunk);
+ (void) zap_leaf_rehash_entry(nl, chunk);
nle->le_name_chunk = zap_leaf_transfer_array(l, le->le_name_chunk, nl);
nle->le_value_chunk =
@@ -660,7 +769,7 @@ zap_leaf_transfer_entry(zap_leaf_t *l, int entry, zap_leaf_t *nl)
* Transfer the entries whose hash prefix ends in 1 to the new leaf.
*/
void
-zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl)
+zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl, int version)
{
int i;
int bit = 64 - 1 - l->l_phys->l_hdr.lh_prefix_len;
@@ -674,6 +783,9 @@ zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl)
/* break existing hash chains */
zap_memset(l->l_phys->l_hash, CHAIN_END, 2*ZAP_LEAF_HASH_NUMENTRIES(l));
+ if (version >= SPA_VERSION_NORMALIZATION)
+ l->l_phys->l_hdr.lh_flags |= ZLF_ENTRIES_CDSORTED;
+
/*
* Transfer entries whose hash bit 'bit' is set to nl; rehash
* the remaining entries
@@ -691,7 +803,7 @@ zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl)
if (le->le_hash & (1ULL << bit))
zap_leaf_transfer_entry(l, i, nl);
else
- zap_leaf_rehash_entry(l, i);
+ (void) zap_leaf_rehash_entry(l, i);
}
}
diff --git a/usr/src/uts/common/fs/zfs/zap_micro.c b/usr/src/uts/common/fs/zfs/zap_micro.c
index 8fce0ba400..f185a7754f 100644
--- a/usr/src/uts/common/fs/zfs/zap_micro.c
+++ b/usr/src/uts/common/fs/zfs/zap_micro.c
@@ -33,11 +33,103 @@
#include <sys/zap_impl.h>
#include <sys/zap_leaf.h>
#include <sys/avl.h>
-
+#include <sys/zfs_i18n.h>
static void mzap_upgrade(zap_t *zap, dmu_tx_t *tx);
+static uint64_t
+zap_hash(zap_t *zap, const char *normname)
+{
+ const uint8_t *cp;
+ uint8_t c;
+ uint64_t crc = zap->zap_salt;
+
+ /* NB: name must already be normalized, if necessary */
+
+ ASSERT(crc != 0);
+ ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
+ for (cp = (const uint8_t *)normname; (c = *cp) != '\0'; cp++) {
+ crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ c) & 0xFF];
+ }
+
+ /*
+ * Only use 28 bits, since we need 4 bits in the cookie for the
+ * collision differentiator. We MUST use the high bits, since
+ * those are the ones that we first pay attention to when
+ * chosing the bucket.
+ */
+ crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1);
+
+ return (crc);
+}
+
+static int
+zap_normalize(zap_t *zap, const char *name, char *namenorm)
+{
+ size_t inlen, outlen;
+ int err;
+
+ inlen = strlen(name) + 1;
+ outlen = ZAP_MAXNAMELEN;
+
+ err = 0;
+ (void) u8_textprep_str((char *)name, &inlen, namenorm, &outlen,
+ zap->zap_normflags | U8_TEXTPREP_IGNORE_NULL, U8_UNICODE_LATEST,
+ &err);
+
+ return (err);
+}
+
+boolean_t
+zap_match(zap_name_t *zn, const char *matchname)
+{
+ if (zn->zn_matchtype == MT_FIRST) {
+ char norm[ZAP_MAXNAMELEN];
+
+ if (zap_normalize(zn->zn_zap, matchname, norm) != 0)
+ return (B_FALSE);
+
+ return (strcmp(zn->zn_name_norm, norm) == 0);
+ } else {
+ /* MT_BEST or MT_EXACT */
+ return (strcmp(zn->zn_name_orij, matchname) == 0);
+ }
+}
+
+void
+zap_name_free(zap_name_t *zn)
+{
+ kmem_free(zn, sizeof (zap_name_t));
+}
+
+/* XXX combine this with zap_lockdir()? */
+zap_name_t *
+zap_name_alloc(zap_t *zap, const char *name, matchtype_t mt)
+{
+ zap_name_t *zn = kmem_alloc(sizeof (zap_name_t), KM_SLEEP);
+
+ zn->zn_zap = zap;
+ zn->zn_name_orij = name;
+ zn->zn_matchtype = mt;
+ if (zap->zap_normflags) {
+ if (zap_normalize(zap, name, zn->zn_normbuf) != 0) {
+ zap_name_free(zn);
+ return (NULL);
+ }
+ zn->zn_name_norm = zn->zn_normbuf;
+ } else {
+ if (mt != MT_EXACT) {
+ zap_name_free(zn);
+ return (NULL);
+ }
+ zn->zn_name_norm = zn->zn_name_orij;
+ }
+
+ zn->zn_hash = zap_hash(zap, zn->zn_name_norm);
+ return (zn);
+}
+
static void
mzap_byteswap(mzap_phys_t *buf, size_t size)
{
@@ -93,7 +185,6 @@ mze_insert(zap_t *zap, int chunkid, uint64_t hash, mzap_ent_phys_t *mzep)
ASSERT(zap->zap_ismicro);
ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
ASSERT(mzep->mze_cd < ZAP_MAXCD);
- ASSERT3U(zap_hash(zap, mzep->mze_name), ==, hash);
mze = kmem_alloc(sizeof (mzap_ent_t), KM_SLEEP);
mze->mze_chunkid = chunkid;
@@ -103,30 +194,34 @@ mze_insert(zap_t *zap, int chunkid, uint64_t hash, mzap_ent_phys_t *mzep)
}
static mzap_ent_t *
-mze_find(zap_t *zap, const char *name, uint64_t hash)
+mze_find(zap_name_t *zn)
{
mzap_ent_t mze_tofind;
mzap_ent_t *mze;
avl_index_t idx;
- avl_tree_t *avl = &zap->zap_m.zap_avl;
+ avl_tree_t *avl = &zn->zn_zap->zap_m.zap_avl;
- ASSERT(zap->zap_ismicro);
- ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
- ASSERT3U(zap_hash(zap, name), ==, hash);
+ ASSERT(zn->zn_zap->zap_ismicro);
+ ASSERT(RW_LOCK_HELD(&zn->zn_zap->zap_rwlock));
- if (strlen(name) >= sizeof (mze_tofind.mze_phys.mze_name))
+ if (strlen(zn->zn_name_norm) >= sizeof (mze_tofind.mze_phys.mze_name))
return (NULL);
- mze_tofind.mze_hash = hash;
+ mze_tofind.mze_hash = zn->zn_hash;
mze_tofind.mze_phys.mze_cd = 0;
+again:
mze = avl_find(avl, &mze_tofind, &idx);
if (mze == NULL)
mze = avl_nearest(avl, idx, AVL_AFTER);
- for (; mze && mze->mze_hash == hash; mze = AVL_NEXT(avl, mze)) {
- if (strcmp(name, mze->mze_phys.mze_name) == 0)
+ for (; mze && mze->mze_hash == zn->zn_hash; mze = AVL_NEXT(avl, mze)) {
+ if (zap_match(zn, mze->mze_phys.mze_name))
return (mze);
}
+ if (zn->zn_matchtype == MT_BEST) {
+ zn->zn_matchtype = MT_FIRST;
+ goto again;
+ }
return (NULL);
}
@@ -193,7 +288,7 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
zap->zap_object = obj;
zap->zap_dbuf = db;
- if (((uint64_t *)db->db_data)[0] != ZBT_MICRO) {
+ if (*(uint64_t *)db->db_data != ZBT_MICRO) {
mutex_init(&zap->zap_f.zap_num_entries_mtx, 0, 0, 0);
zap->zap_f.zap_block_shift = highbit(db->db_size) - 1;
} else {
@@ -218,6 +313,7 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
if (zap->zap_ismicro) {
zap->zap_salt = zap->zap_m.zap_phys->mz_salt;
+ zap->zap_normflags = zap->zap_m.zap_phys->mz_normflags;
zap->zap_m.zap_num_chunks = db->db_size / MZAP_ENT_LEN - 1;
avl_create(&zap->zap_m.zap_avl, mze_compare,
sizeof (mzap_ent_t), offsetof(mzap_ent_t, mze_node));
@@ -226,13 +322,18 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
mzap_ent_phys_t *mze =
&zap->zap_m.zap_phys->mz_chunk[i];
if (mze->mze_name[0]) {
+ zap_name_t *zn;
+
zap->zap_m.zap_num_entries++;
- mze_insert(zap, i,
- zap_hash(zap, mze->mze_name), mze);
+ zn = zap_name_alloc(zap, mze->mze_name,
+ MT_EXACT);
+ mze_insert(zap, i, zn->zn_hash, mze);
+ zap_name_free(zn);
}
}
} else {
zap->zap_salt = zap->zap_f.zap_phys->zap_salt;
+ zap->zap_normflags = zap->zap_f.zap_phys->zap_normflags;
ASSERT3U(sizeof (struct zap_leaf_header), ==,
2*ZAP_LEAF_CHUNKSIZE);
@@ -357,6 +458,7 @@ mzap_upgrade(zap_t *zap, dmu_tx_t *tx)
dprintf("upgrading obj=%llu with %u chunks\n",
zap->zap_object, nchunks);
+ /* XXX destroy the avl later, so we can use the stored hash value */
mze_destroy(zap);
fzap_upgrade(zap, tx);
@@ -364,48 +466,28 @@ mzap_upgrade(zap_t *zap, dmu_tx_t *tx)
for (i = 0; i < nchunks; i++) {
int err;
mzap_ent_phys_t *mze = &mzp->mz_chunk[i];
+ zap_name_t *zn;
if (mze->mze_name[0] == 0)
continue;
dprintf("adding %s=%llu\n",
mze->mze_name, mze->mze_value);
- err = fzap_add_cd(zap,
- mze->mze_name, 8, 1, &mze->mze_value,
+ zn = zap_name_alloc(zap, mze->mze_name, MT_EXACT);
+ err = fzap_add_cd(zn, 8, 1, &mze->mze_value,
mze->mze_cd, tx);
+ zap_name_free(zn);
ASSERT3U(err, ==, 0);
}
kmem_free(mzp, sz);
}
-uint64_t
-zap_hash(zap_t *zap, const char *name)
-{
- const uint8_t *cp;
- uint8_t c;
- uint64_t crc = zap->zap_salt;
-
- ASSERT(crc != 0);
- ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
- for (cp = (const uint8_t *)name; (c = *cp) != '\0'; cp++)
- crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ c) & 0xFF];
-
- /*
- * Only use 28 bits, since we need 4 bits in the cookie for the
- * collision differentiator. We MUST use the high bits, since
- * those are the onces that we first pay attention to when
- * chosing the bucket.
- */
- crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1);
-
- return (crc);
-}
-
-
static void
-mzap_create_impl(objset_t *os, uint64_t obj, dmu_tx_t *tx)
+mzap_create_impl(objset_t *os, uint64_t obj, int normflags, dmu_tx_t *tx)
{
dmu_buf_t *db;
mzap_phys_t *zp;
+ ASSERT(normflags == 0 ||
+ spa_version(dmu_objset_spa(os)) >= SPA_VERSION_NORMALIZATION);
VERIFY(0 == dmu_buf_hold(os, obj, 0, FTAG, &db));
#ifdef ZFS_DEBUG
@@ -420,7 +502,7 @@ mzap_create_impl(objset_t *os, uint64_t obj, dmu_tx_t *tx)
zp = db->db_data;
zp->mz_block_type = ZBT_MICRO;
zp->mz_salt = ((uintptr_t)db ^ (uintptr_t)tx ^ (obj << 1)) | 1ULL;
- ASSERT(zp->mz_salt != 0);
+ zp->mz_normflags = normflags;
dmu_buf_rele(db, FTAG);
}
@@ -428,12 +510,21 @@ int
zap_create_claim(objset_t *os, uint64_t obj, dmu_object_type_t ot,
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
{
+ return (zap_create_claim_norm(os, obj,
+ 0, ot, bonustype, bonuslen, tx));
+}
+
+int
+zap_create_claim_norm(objset_t *os, uint64_t obj, int normflags,
+ dmu_object_type_t ot,
+ dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
int err;
err = dmu_object_claim(os, obj, ot, 0, bonustype, bonuslen, tx);
if (err != 0)
return (err);
- mzap_create_impl(os, obj, tx);
+ mzap_create_impl(os, obj, normflags, tx);
return (0);
}
@@ -441,9 +532,16 @@ uint64_t
zap_create(objset_t *os, dmu_object_type_t ot,
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
{
+ return (zap_create_norm(os, 0, ot, bonustype, bonuslen, tx));
+}
+
+uint64_t
+zap_create_norm(objset_t *os, int normflags, dmu_object_type_t ot,
+ dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
uint64_t obj = dmu_object_alloc(os, ot, 0, bonustype, bonuslen, tx);
- mzap_create_impl(os, obj, tx);
+ mzap_create_impl(os, obj, normflags, tx);
return (obj);
}
@@ -494,36 +592,102 @@ zap_count(objset_t *os, uint64_t zapobj, uint64_t *count)
}
/*
- * Routines for maniplulating attributes.
+ * zn may be NULL; if not specified, it will be computed if needed.
+ * See also the comment above zap_entry_normalization_conflict().
+ */
+static boolean_t
+mzap_normalization_conflict(zap_t *zap, zap_name_t *zn, mzap_ent_t *mze)
+{
+ mzap_ent_t *other;
+ int direction = AVL_BEFORE;
+ boolean_t allocdzn = B_FALSE;
+
+ if (zap->zap_normflags == 0)
+ return (B_FALSE);
+
+again:
+ for (other = avl_walk(&zap->zap_m.zap_avl, mze, direction);
+ other && other->mze_hash == mze->mze_hash;
+ other = avl_walk(&zap->zap_m.zap_avl, other, direction)) {
+
+ if (zn == NULL) {
+ zn = zap_name_alloc(zap, mze->mze_phys.mze_name,
+ MT_FIRST);
+ allocdzn = B_TRUE;
+ }
+ if (zap_match(zn, other->mze_phys.mze_name)) {
+ if (allocdzn)
+ zap_name_free(zn);
+ return (B_TRUE);
+ }
+ }
+
+ if (direction == AVL_BEFORE) {
+ direction = AVL_AFTER;
+ goto again;
+ }
+
+ if (allocdzn)
+ zap_name_free(zn);
+ return (B_FALSE);
+}
+
+/*
+ * Routines for manipulating attributes.
*/
int
zap_lookup(objset_t *os, uint64_t zapobj, const char *name,
uint64_t integer_size, uint64_t num_integers, void *buf)
{
+ return (zap_lookup_norm(os, zapobj, name, integer_size,
+ num_integers, buf, MT_EXACT, NULL, 0, NULL));
+}
+
+int
+zap_lookup_norm(objset_t *os, uint64_t zapobj, const char *name,
+ uint64_t integer_size, uint64_t num_integers, void *buf,
+ matchtype_t mt, char *realname, int rn_len,
+ boolean_t *ncp)
+{
zap_t *zap;
int err;
mzap_ent_t *mze;
+ zap_name_t *zn;
err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, &zap);
if (err)
return (err);
+ zn = zap_name_alloc(zap, name, mt);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
+
if (!zap->zap_ismicro) {
- err = fzap_lookup(zap, name,
- integer_size, num_integers, buf);
+ err = fzap_lookup(zn, integer_size, num_integers, buf,
+ realname, rn_len, ncp);
} else {
- mze = mze_find(zap, name, zap_hash(zap, name));
+ mze = mze_find(zn);
if (mze == NULL) {
err = ENOENT;
} else {
- if (num_integers < 1)
+ if (num_integers < 1) {
err = EOVERFLOW;
- else if (integer_size != 8)
+ } else if (integer_size != 8) {
err = EINVAL;
- else
+ } else {
*(uint64_t *)buf = mze->mze_phys.mze_value;
+ (void) strlcpy(realname,
+ mze->mze_phys.mze_name, rn_len);
+ if (ncp) {
+ *ncp = mzap_normalization_conflict(zap,
+ zn, mze);
+ }
+ }
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
@@ -535,14 +699,20 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name,
zap_t *zap;
int err;
mzap_ent_t *mze;
+ zap_name_t *zn;
err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, &zap);
if (err)
return (err);
+ zn = zap_name_alloc(zap, name, MT_EXACT);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
if (!zap->zap_ismicro) {
- err = fzap_length(zap, name, integer_size, num_integers);
+ err = fzap_length(zn, integer_size, num_integers);
} else {
- mze = mze_find(zap, name, zap_hash(zap, name));
+ mze = mze_find(zn);
if (mze == NULL) {
err = ENOENT;
} else {
@@ -552,28 +722,31 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name,
*num_integers = 1;
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
static void
-mzap_addent(zap_t *zap, const char *name, uint64_t hash, uint64_t value)
+mzap_addent(zap_name_t *zn, uint64_t value)
{
int i;
+ zap_t *zap = zn->zn_zap;
int start = zap->zap_m.zap_alloc_next;
uint32_t cd;
- dprintf("obj=%llu %s=%llu\n", zap->zap_object, name, value);
+ dprintf("obj=%llu %s=%llu\n", zap->zap_object,
+ zn->zn_name_orij, value);
ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
#ifdef ZFS_DEBUG
for (i = 0; i < zap->zap_m.zap_num_chunks; i++) {
mzap_ent_phys_t *mze = &zap->zap_m.zap_phys->mz_chunk[i];
- ASSERT(strcmp(name, mze->mze_name) != 0);
+ ASSERT(strcmp(zn->zn_name_orij, mze->mze_name) != 0);
}
#endif
- cd = mze_find_unused_cd(zap, hash);
+ cd = mze_find_unused_cd(zap, zn->zn_hash);
/* given the limited size of the microzap, this can't happen */
ASSERT(cd != ZAP_MAXCD);
@@ -583,13 +756,13 @@ again:
if (mze->mze_name[0] == 0) {
mze->mze_value = value;
mze->mze_cd = cd;
- (void) strcpy(mze->mze_name, name);
+ (void) strcpy(mze->mze_name, zn->zn_name_orij);
zap->zap_m.zap_num_entries++;
zap->zap_m.zap_alloc_next = i+1;
if (zap->zap_m.zap_alloc_next ==
zap->zap_m.zap_num_chunks)
zap->zap_m.zap_alloc_next = 0;
- mze_insert(zap, i, hash, mze);
+ mze_insert(zap, i, zn->zn_hash, mze);
return;
}
}
@@ -609,28 +782,33 @@ zap_add(objset_t *os, uint64_t zapobj, const char *name,
int err;
mzap_ent_t *mze;
const uint64_t *intval = val;
- uint64_t hash;
+ zap_name_t *zn;
err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, &zap);
if (err)
return (err);
+ zn = zap_name_alloc(zap, name, MT_EXACT);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
if (!zap->zap_ismicro) {
- err = fzap_add(zap, name, integer_size, num_integers, val, tx);
+ err = fzap_add(zn, integer_size, num_integers, val, tx);
} else if (integer_size != 8 || num_integers != 1 ||
strlen(name) >= MZAP_NAME_LEN) {
dprintf("upgrading obj %llu: intsz=%u numint=%llu name=%s\n",
zapobj, integer_size, num_integers, name);
mzap_upgrade(zap, tx);
- err = fzap_add(zap, name, integer_size, num_integers, val, tx);
+ err = fzap_add(zn, integer_size, num_integers, val, tx);
} else {
- hash = zap_hash(zap, name);
- mze = mze_find(zap, name, hash);
+ mze = mze_find(zn);
if (mze != NULL) {
err = EEXIST;
} else {
- mzap_addent(zap, name, hash, *intval);
+ mzap_addent(zn, *intval);
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
@@ -642,34 +820,36 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name,
zap_t *zap;
mzap_ent_t *mze;
const uint64_t *intval = val;
- uint64_t hash;
+ zap_name_t *zn;
int err;
err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, &zap);
if (err)
return (err);
- ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+ zn = zap_name_alloc(zap, name, MT_EXACT);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
if (!zap->zap_ismicro) {
- err = fzap_update(zap, name,
- integer_size, num_integers, val, tx);
+ err = fzap_update(zn, integer_size, num_integers, val, tx);
} else if (integer_size != 8 || num_integers != 1 ||
strlen(name) >= MZAP_NAME_LEN) {
dprintf("upgrading obj %llu: intsz=%u numint=%llu name=%s\n",
zapobj, integer_size, num_integers, name);
mzap_upgrade(zap, tx);
- err = fzap_update(zap, name,
- integer_size, num_integers, val, tx);
+ err = fzap_update(zn, integer_size, num_integers, val, tx);
} else {
- hash = zap_hash(zap, name);
- mze = mze_find(zap, name, hash);
+ mze = mze_find(zn);
if (mze != NULL) {
mze->mze_phys.mze_value = *intval;
zap->zap_m.zap_phys->mz_chunk
[mze->mze_chunkid].mze_value = *intval;
} else {
- mzap_addent(zap, name, hash, *intval);
+ mzap_addent(zn, *intval);
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
@@ -677,28 +857,40 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name,
int
zap_remove(objset_t *os, uint64_t zapobj, const char *name, dmu_tx_t *tx)
{
+ return (zap_remove_norm(os, zapobj, name, MT_EXACT, tx));
+}
+
+int
+zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name,
+ matchtype_t mt, dmu_tx_t *tx)
+{
zap_t *zap;
int err;
mzap_ent_t *mze;
+ zap_name_t *zn;
err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, &zap);
if (err)
return (err);
+ zn = zap_name_alloc(zap, name, mt);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
if (!zap->zap_ismicro) {
- err = fzap_remove(zap, name, tx);
+ err = fzap_remove(zn, tx);
} else {
- mze = mze_find(zap, name, zap_hash(zap, name));
+ mze = mze_find(zn);
if (mze == NULL) {
- dprintf("fail: %s\n", name);
err = ENOENT;
} else {
- dprintf("success: %s\n", name);
zap->zap_m.zap_num_entries--;
bzero(&zap->zap_m.zap_phys->mz_chunk[mze->mze_chunkid],
sizeof (mzap_ent_phys_t));
mze_remove(zap, mze);
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
@@ -795,14 +987,17 @@ zap_cursor_retrieve(zap_cursor_t *zc, zap_attribute_t *za)
mze_tofind.mze_phys.mze_cd = zc->zc_cd;
mze = avl_find(&zc->zc_zap->zap_m.zap_avl, &mze_tofind, &idx);
- ASSERT(mze == NULL || 0 == bcmp(&mze->mze_phys,
- &zc->zc_zap->zap_m.zap_phys->mz_chunk[mze->mze_chunkid],
- sizeof (mze->mze_phys)));
if (mze == NULL) {
mze = avl_nearest(&zc->zc_zap->zap_m.zap_avl,
idx, AVL_AFTER);
}
if (mze) {
+ ASSERT(0 == bcmp(&mze->mze_phys,
+ &zc->zc_zap->zap_m.zap_phys->mz_chunk
+ [mze->mze_chunkid], sizeof (mze->mze_phys)));
+
+ za->za_normalization_conflict =
+ mzap_normalization_conflict(zc->zc_zap, NULL, mze);
za->za_integer_length = 8;
za->za_num_integers = 1;
za->za_first_integer = mze->mze_phys.mze_value;
diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c
index f78a9cd000..34057b6d72 100644
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c
@@ -33,6 +33,7 @@
#include <sys/resource.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
+#include <sys/sid.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/kmem.h>
@@ -44,17 +45,19 @@
#include <sys/mode.h>
#include <sys/policy.h>
#include <sys/zfs_znode.h>
+#include <sys/zfs_fuid.h>
#include <sys/zfs_acl.h>
#include <sys/zfs_dir.h>
#include <sys/zfs_vfsops.h>
#include <sys/dmu.h>
+#include <sys/dnode.h>
#include <sys/zap.h>
-#include <util/qsort.h>
#include "fs/fs_subr.h"
#include <acl/acl_common.h>
#define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE
#define DENY ACE_ACCESS_DENIED_ACE_TYPE
+#define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
#define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP)
#define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
@@ -63,8 +66,15 @@
ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
#define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
-#define WRITE_MASK (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS| \
- ACE_WRITE_ATTRIBUTES|ACE_WRITE_ACL|ACE_WRITE_OWNER)
+#define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
+
+#define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \
+ ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \
+ ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \
+ ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE)
+
+#define WRITE_MASK (WRITE_MASK_DATA|ACE_WRITE_ATTRIBUTES|ACE_WRITE_ACL|\
+ ACE_WRITE_OWNER)
#define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
@@ -73,59 +83,634 @@
ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
#define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
- ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
+ ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE)
#define SECURE_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER)
-#define OGE_PAD 6 /* traditional owner/group/everyone ACES */
+#define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\
+ ZFS_ACL_PROTECTED)
+
+#define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\
+ ZFS_ACL_OBJ_ACE)
+
+static uint16_t
+zfs_ace_v0_get_type(void *acep)
+{
+ return (((zfs_oldace_t *)acep)->z_type);
+}
+
+static uint16_t
+zfs_ace_v0_get_flags(void *acep)
+{
+ return (((zfs_oldace_t *)acep)->z_flags);
+}
+
+static uint32_t
+zfs_ace_v0_get_mask(void *acep)
+{
+ return (((zfs_oldace_t *)acep)->z_access_mask);
+}
+
+static uint64_t
+zfs_ace_v0_get_who(void *acep)
+{
+ return (((zfs_oldace_t *)acep)->z_fuid);
+}
-static int zfs_ace_can_use(znode_t *zp, ace_t *);
+static void
+zfs_ace_v0_set_type(void *acep, uint16_t type)
+{
+ ((zfs_oldace_t *)acep)->z_type = type;
+}
+
+static void
+zfs_ace_v0_set_flags(void *acep, uint16_t flags)
+{
+ ((zfs_oldace_t *)acep)->z_flags = flags;
+}
+
+static void
+zfs_ace_v0_set_mask(void *acep, uint32_t mask)
+{
+ ((zfs_oldace_t *)acep)->z_access_mask = mask;
+}
+
+static void
+zfs_ace_v0_set_who(void *acep, uint64_t who)
+{
+ ((zfs_oldace_t *)acep)->z_fuid = who;
+}
+
+/*ARGSUSED*/
+static size_t
+zfs_ace_v0_size(void *acep)
+{
+ return (sizeof (zfs_oldace_t));
+}
+
+static size_t
+zfs_ace_v0_abstract_size(void)
+{
+ return (sizeof (zfs_oldace_t));
+}
+
+static int
+zfs_ace_v0_mask_off(void)
+{
+ return (offsetof(zfs_oldace_t, z_access_mask));
+}
+
+/*ARGSUSED*/
+static int
+zfs_ace_v0_data(void *acep, void **datap)
+{
+ *datap = NULL;
+ return (0);
+}
+
+static acl_ops_t zfs_acl_v0_ops = {
+ zfs_ace_v0_get_mask,
+ zfs_ace_v0_set_mask,
+ zfs_ace_v0_get_flags,
+ zfs_ace_v0_set_flags,
+ zfs_ace_v0_get_type,
+ zfs_ace_v0_set_type,
+ zfs_ace_v0_get_who,
+ zfs_ace_v0_set_who,
+ zfs_ace_v0_size,
+ zfs_ace_v0_abstract_size,
+ zfs_ace_v0_mask_off,
+ zfs_ace_v0_data
+};
+
+static uint16_t
+zfs_ace_fuid_get_type(void *acep)
+{
+ return (((zfs_ace_hdr_t *)acep)->z_type);
+}
+
+static uint16_t
+zfs_ace_fuid_get_flags(void *acep)
+{
+ return (((zfs_ace_hdr_t *)acep)->z_flags);
+}
+
+static uint32_t
+zfs_ace_fuid_get_mask(void *acep)
+{
+ return (((zfs_ace_hdr_t *)acep)->z_access_mask);
+}
+
+static uint64_t
+zfs_ace_fuid_get_who(void *args)
+{
+ uint16_t entry_type;
+ zfs_ace_t *acep = args;
+
+ entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+
+ if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
+ entry_type == ACE_EVERYONE)
+ return (-1);
+ return (((zfs_ace_t *)acep)->z_fuid);
+}
+
+static void
+zfs_ace_fuid_set_type(void *acep, uint16_t type)
+{
+ ((zfs_ace_hdr_t *)acep)->z_type = type;
+}
+
+static void
+zfs_ace_fuid_set_flags(void *acep, uint16_t flags)
+{
+ ((zfs_ace_hdr_t *)acep)->z_flags = flags;
+}
+
+static void
+zfs_ace_fuid_set_mask(void *acep, uint32_t mask)
+{
+ ((zfs_ace_hdr_t *)acep)->z_access_mask = mask;
+}
+
+static void
+zfs_ace_fuid_set_who(void *arg, uint64_t who)
+{
+ zfs_ace_t *acep = arg;
+
+ uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+
+ if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
+ entry_type == ACE_EVERYONE)
+ return;
+ acep->z_fuid = who;
+}
+
+static size_t
+zfs_ace_fuid_size(void *acep)
+{
+ zfs_ace_hdr_t *zacep = acep;
+ uint16_t entry_type;
+
+ switch (zacep->z_type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ return (sizeof (zfs_object_ace_t));
+ case ALLOW:
+ case DENY:
+ entry_type =
+ (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS);
+ if (entry_type == ACE_OWNER ||
+ entry_type == (ACE_GROUP | ACE_IDENTIFIER_GROUP) ||
+ entry_type == ACE_EVERYONE)
+ return (sizeof (zfs_ace_hdr_t));
+ /*FALLTHROUGH*/
+ default:
+ return (sizeof (zfs_ace_t));
+ }
+}
+
+static size_t
+zfs_ace_fuid_abstract_size(void)
+{
+ return (sizeof (zfs_ace_hdr_t));
+}
+
+static int
+zfs_ace_fuid_mask_off(void)
+{
+ return (offsetof(zfs_ace_hdr_t, z_access_mask));
+}
+
+static int
+zfs_ace_fuid_data(void *acep, void **datap)
+{
+ zfs_ace_t *zacep = acep;
+ zfs_object_ace_t *zobjp;
+
+ switch (zacep->z_hdr.z_type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ zobjp = acep;
+ *datap = (caddr_t)zobjp + sizeof (zfs_ace_t);
+ return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
+ default:
+ *datap = NULL;
+ return (0);
+ }
+}
+
+static acl_ops_t zfs_acl_fuid_ops = {
+ zfs_ace_fuid_get_mask,
+ zfs_ace_fuid_set_mask,
+ zfs_ace_fuid_get_flags,
+ zfs_ace_fuid_set_flags,
+ zfs_ace_fuid_get_type,
+ zfs_ace_fuid_set_type,
+ zfs_ace_fuid_get_who,
+ zfs_ace_fuid_set_who,
+ zfs_ace_fuid_size,
+ zfs_ace_fuid_abstract_size,
+ zfs_ace_fuid_mask_off,
+ zfs_ace_fuid_data
+};
+
+static int
+zfs_acl_version(int version)
+{
+ if (version < ZPL_VERSION_FUID)
+ return (ZFS_ACL_VERSION_INITIAL);
+ else
+ return (ZFS_ACL_VERSION_FUID);
+}
+
+static int
+zfs_acl_version_zp(znode_t *zp)
+{
+ return (zfs_acl_version(zp->z_zfsvfs->z_version));
+}
static zfs_acl_t *
-zfs_acl_alloc(int slots)
+zfs_acl_alloc(int vers)
{
zfs_acl_t *aclp;
aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
- if (slots != 0) {
- aclp->z_acl = kmem_alloc(ZFS_ACL_SIZE(slots), KM_SLEEP);
- aclp->z_acl_count = 0;
- aclp->z_state = ACL_DATA_ALLOCED;
- } else {
- aclp->z_state = 0;
- }
- aclp->z_slots = slots;
+ list_create(&aclp->z_acl, sizeof (zfs_acl_node_t),
+ offsetof(zfs_acl_node_t, z_next));
+ aclp->z_version = vers;
+ if (vers == ZFS_ACL_VERSION_FUID)
+ aclp->z_ops = zfs_acl_fuid_ops;
+ else
+ aclp->z_ops = zfs_acl_v0_ops;
return (aclp);
}
+static zfs_acl_node_t *
+zfs_acl_node_alloc(size_t bytes)
+{
+ zfs_acl_node_t *aclnode;
+
+ aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
+ if (bytes) {
+ aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP);
+ aclnode->z_allocdata = aclnode->z_acldata;
+ aclnode->z_allocsize = bytes;
+ aclnode->z_size = bytes;
+ }
+
+ return (aclnode);
+}
+
+static void
+zfs_acl_node_free(zfs_acl_node_t *aclnode)
+{
+ if (aclnode->z_allocsize)
+ kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
+ kmem_free(aclnode, sizeof (zfs_acl_node_t));
+}
+
void
zfs_acl_free(zfs_acl_t *aclp)
{
- if (aclp->z_state == ACL_DATA_ALLOCED) {
- kmem_free(aclp->z_acl, ZFS_ACL_SIZE(aclp->z_slots));
+ zfs_acl_node_t *aclnode;
+
+ while (aclnode = list_head(&aclp->z_acl)) {
+ list_remove(&aclp->z_acl, aclnode);
+ zfs_acl_node_free(aclnode);
}
+
+ list_destroy(&aclp->z_acl);
kmem_free(aclp, sizeof (zfs_acl_t));
}
-static uint32_t
-zfs_v4_to_unix(uint32_t access_mask)
+static boolean_t
+zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
{
- uint32_t new_mask = 0;
+ /*
+ * first check type of entry
+ */
+
+ switch (iflags & ACE_TYPE_FLAGS) {
+ case ACE_OWNER:
+ case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
+ case ACE_IDENTIFIER_GROUP:
+ case ACE_EVERYONE:
+ case 0: /* User entry */
+ break;
+ default:
+ return (B_FALSE);
+
+ }
/*
- * This is used for mapping v4 permissions into permissions
- * that can be passed to secpolicy_vnode_access()
+ * next check inheritance level flags
*/
- if (access_mask & (ACE_READ_DATA | ACE_LIST_DIRECTORY |
- ACE_READ_ATTRIBUTES | ACE_READ_ACL))
- new_mask |= S_IROTH;
- if (access_mask & (ACE_WRITE_DATA | ACE_APPEND_DATA |
- ACE_WRITE_ATTRIBUTES | ACE_ADD_FILE | ACE_WRITE_NAMED_ATTRS))
- new_mask |= S_IWOTH;
- if (access_mask & (ACE_EXECUTE | ACE_READ_NAMED_ATTRS))
- new_mask |= S_IXOTH;
- return (new_mask);
+ if (type != ALLOW && type > MAX_ACE_TYPE) {
+ return (B_FALSE);
+ }
+
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ if (aclp->z_version < ZFS_ACL_VERSION_FUID)
+ return (B_FALSE);
+ aclp->z_hints |= ZFS_ACL_OBJ_ACE;
+ }
+
+ /*
+ * Only directories should have inheritance flags.
+ */
+ if (obj_type != VDIR && (iflags &
+ (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE|
+ ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE))) {
+ return (B_FALSE);
+ }
+
+ if (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))
+ aclp->z_hints |= ZFS_INHERIT_ACE;
+
+ if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
+ if ((iflags & (ACE_FILE_INHERIT_ACE|
+ ACE_DIRECTORY_INHERIT_ACE)) == 0) {
+ return (B_FALSE);
+ }
+ }
+
+ return (B_TRUE);
+}
+
+static void *
+zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
+ uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
+{
+ zfs_acl_node_t *aclnode;
+
+ if (start == NULL) {
+ aclnode = list_head(&aclp->z_acl);
+ if (aclnode == NULL)
+ return (NULL);
+
+ aclp->z_next_ace = aclnode->z_acldata;
+ aclp->z_curr_node = aclnode;
+ aclnode->z_ace_idx = 0;
+ }
+
+ aclnode = aclp->z_curr_node;
+
+ if (aclnode == NULL)
+ return (NULL);
+
+ if (aclnode->z_ace_idx >= aclnode->z_ace_count) {
+ aclnode = list_next(&aclp->z_acl, aclnode);
+ if (aclnode == NULL)
+ return (NULL);
+ else {
+ aclp->z_curr_node = aclnode;
+ aclnode->z_ace_idx = 0;
+ aclp->z_next_ace = aclnode->z_acldata;
+ }
+ }
+
+ if (aclnode->z_ace_idx < aclnode->z_ace_count) {
+ void *acep = aclp->z_next_ace;
+ *iflags = aclp->z_ops.ace_flags_get(acep);
+ *type = aclp->z_ops.ace_type_get(acep);
+ *access_mask = aclp->z_ops.ace_mask_get(acep);
+ *who = aclp->z_ops.ace_who_get(acep);
+ aclp->z_next_ace = (caddr_t)aclp->z_next_ace +
+ aclp->z_ops.ace_size(acep);
+ aclnode->z_ace_idx++;
+ return ((void *)acep);
+ }
+ return (NULL);
+}
+
+/*ARGSUSED*/
+static uint64_t
+zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
+ uint16_t *flags, uint16_t *type, uint32_t *mask)
+{
+ zfs_acl_t *aclp = datap;
+ zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
+ uint64_t who;
+
+ acep = zfs_acl_next_ace(aclp, acep, &who, mask,
+ flags, type);
+ return ((uint64_t)(uintptr_t)acep);
+}
+
+static zfs_acl_node_t *
+zfs_acl_curr_node(zfs_acl_t *aclp)
+{
+ ASSERT(aclp->z_curr_node);
+ return (aclp->z_curr_node);
+}
+
+/*
+ * Copy ACE to internal ZFS format.
+ * While processing the ACL each ACE will be validated for correctness.
+ * ACE FUIDs will be created later.
+ */
+int
+zfs_copy_ace_2_fuid(vtype_t obj_type, zfs_acl_t *aclp, void *datap,
+ zfs_ace_t *z_acl, int aclcnt, size_t *size)
+{
+ int i;
+ uint16_t entry_type;
+ zfs_ace_t *aceptr = z_acl;
+ ace_t *acep = datap;
+ zfs_object_ace_t *zobjacep;
+ ace_object_t *aceobjp;
+
+ for (i = 0; i != aclcnt; i++) {
+ aceptr->z_hdr.z_access_mask = acep->a_access_mask;
+ aceptr->z_hdr.z_flags = acep->a_flags;
+ aceptr->z_hdr.z_type = acep->a_type;
+ entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS;
+ if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
+ entry_type != ACE_EVERYONE)
+ aceptr->z_fuid = (uint64_t)acep->a_who;
+ /*
+ * Make sure ACE is valid
+ */
+ if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type,
+ aceptr->z_hdr.z_flags) != B_TRUE)
+ return (EINVAL);
+
+ switch (acep->a_type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ zobjacep = (zfs_object_ace_t *)aceptr;
+ aceobjp = (ace_object_t *)acep;
+
+ bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
+ sizeof (aceobjp->a_obj_type));
+ bcopy(aceobjp->a_inherit_obj_type,
+ zobjacep->z_inherit_type,
+ sizeof (aceobjp->a_inherit_obj_type));
+ acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
+ break;
+ default:
+ acep = (ace_t *)((caddr_t)acep + sizeof (ace_t));
+ }
+
+ aceptr = (zfs_ace_t *)((caddr_t)aceptr +
+ aclp->z_ops.ace_size(aceptr));
+ }
+
+ *size = (caddr_t)aceptr - (caddr_t)z_acl;
+
+ return (0);
+}
+
+/*
+ * Copy ZFS ACEs to fixed size ace_t layout
+ */
+static void
+zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *datap, int filter)
+{
+ uint64_t who;
+ uint32_t access_mask;
+ uint16_t iflags, type;
+ zfs_ace_hdr_t *zacep = NULL;
+ ace_t *acep = datap;
+ ace_object_t *objacep;
+ zfs_object_ace_t *zobjacep;
+ zfs_fuid_hdl_t hdl = { 0 };
+ size_t ace_size;
+ uint16_t entry_type;
+
+ while (zacep = zfs_acl_next_ace(aclp, zacep,
+ &who, &access_mask, &iflags, &type)) {
+
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ if (filter) {
+ continue;
+ }
+ zobjacep = (zfs_object_ace_t *)zacep;
+ objacep = (ace_object_t *)acep;
+ bcopy(zobjacep->z_object_type,
+ objacep->a_obj_type,
+ sizeof (zobjacep->z_object_type));
+ bcopy(zobjacep->z_inherit_type,
+ objacep->a_inherit_obj_type,
+ sizeof (zobjacep->z_inherit_type));
+ ace_size = sizeof (ace_object_t);
+ break;
+ default:
+ ace_size = sizeof (ace_t);
+ break;
+ }
+
+ entry_type = (iflags & ACE_TYPE_FLAGS);
+ if ((entry_type != ACE_OWNER &&
+ entry_type != (ACE_GROUP | ACE_IDENTIFIER_GROUP) &&
+ entry_type != ACE_EVERYONE))
+ zfs_fuid_queue_map_id(zfsvfs, &hdl, who,
+ (entry_type & ACE_IDENTIFIER_GROUP) ?
+ ZFS_ACE_GROUP : ZFS_ACE_USER, &acep->a_who);
+ else
+ acep->a_who = (uid_t)(int64_t)who;
+ acep->a_access_mask = access_mask;
+ acep->a_flags = iflags;
+ acep->a_type = type;
+ acep = (ace_t *)((caddr_t)acep + ace_size);
+ }
+ zfs_fuid_get_mappings(&hdl);
+}
+
+static int
+zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep,
+ zfs_oldace_t *z_acl, int aclcnt, size_t *size)
+{
+ int i;
+ zfs_oldace_t *aceptr = z_acl;
+
+ for (i = 0; i != aclcnt; i++, aceptr++) {
+ aceptr->z_access_mask = acep[i].a_access_mask;
+ aceptr->z_type = acep[i].a_type;
+ aceptr->z_flags = acep[i].a_flags;
+ aceptr->z_fuid = acep[i].a_who;
+ /*
+ * Make sure ACE is valid
+ */
+ if (zfs_ace_valid(obj_type, aclp, aceptr->z_type,
+ aceptr->z_flags) != B_TRUE)
+ return (EINVAL);
+ }
+ *size = (caddr_t)aceptr - (caddr_t)z_acl;
+ return (0);
+}
+
+/*
+ * convert old ACL format to new
+ */
+void
+zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp)
+{
+ zfs_oldace_t *oldaclp;
+ int i;
+ uint16_t type, iflags;
+ uint32_t access_mask;
+ uint64_t who;
+ void *cookie = NULL;
+ zfs_acl_node_t *aclnode, *newaclnode;
+
+ ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL);
+ /*
+ * First create the ACE in a contiguous piece of memory
+ * for zfs_copy_ace_2_fuid().
+ *
+ * We only convert an ACL once, so this won't happen
+ * everytime.
+ */
+ oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
+ KM_SLEEP);
+ i = 0;
+ while (cookie = zfs_acl_next_ace(aclp, cookie, &who,
+ &access_mask, &iflags, &type)) {
+ oldaclp[i].z_flags = iflags;
+ oldaclp[i].z_type = type;
+ oldaclp[i].z_fuid = who;
+ oldaclp[i++].z_access_mask = access_mask;
+ }
+
+ newaclnode = zfs_acl_node_alloc(aclp->z_acl_count *
+ sizeof (zfs_object_ace_t));
+ aclp->z_ops = zfs_acl_fuid_ops;
+ VERIFY(zfs_copy_ace_2_fuid(ZTOV(zp)->v_type, aclp, oldaclp,
+ newaclnode->z_acldata, aclp->z_acl_count,
+ &newaclnode->z_size) == 0);
+ aclp->z_acl_bytes = newaclnode->z_size;
+ newaclnode->z_ace_count = aclp->z_acl_count;
+ aclp->z_version = ZFS_ACL_VERSION;
+ kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
+
+ /*
+ * Release all previous ACL nodes
+ */
+
+ while (aclnode = list_head(&aclp->z_acl)) {
+ list_remove(&aclp->z_acl, aclnode);
+ if (aclnode->z_allocsize)
+ kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
+ kmem_free(aclnode, sizeof (zfs_acl_node_t));
+ }
+ list_insert_head(&aclp->z_acl, newaclnode);
}
/*
@@ -136,164 +721,207 @@ zfs_unix_to_v4(uint32_t access_mask)
{
uint32_t new_mask = 0;
- if (access_mask & 01)
- new_mask |= (ACE_EXECUTE);
- if (access_mask & 02) {
- new_mask |= (ACE_WRITE_DATA);
- } if (access_mask & 04) {
+ if (access_mask & S_IXOTH)
+ new_mask |= ACE_EXECUTE;
+ if (access_mask & S_IWOTH)
+ new_mask |= ACE_WRITE_DATA;
+ if (access_mask & S_IROTH)
new_mask |= ACE_READ_DATA;
- }
return (new_mask);
}
static void
-zfs_set_ace(ace_t *zacep, uint32_t access_mask, int access_type,
- uid_t uid, int entry_type)
+zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
+ uint16_t access_type, uint64_t fuid, uint16_t entry_type)
{
- zacep->a_access_mask = access_mask;
- zacep->a_type = access_type;
- zacep->a_who = uid;
- zacep->a_flags = entry_type;
+ uint16_t type = entry_type & ACE_TYPE_FLAGS;
+
+ aclp->z_ops.ace_mask_set(acep, access_mask);
+ aclp->z_ops.ace_type_set(acep, access_type);
+ aclp->z_ops.ace_flags_set(acep, entry_type);
+ if ((type != ACE_OWNER && type != (ACE_GROUP | ACE_IDENTIFIER_GROUP) &&
+ type != ACE_EVERYONE))
+ aclp->z_ops.ace_who_set(acep, fuid);
}
+/*
+ * Determine mode of file based on ACL.
+ * Also, create FUIDs for any User/Group ACEs
+ */
static uint64_t
-zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp)
+zfs_mode_fuid_compute(znode_t *zp, zfs_acl_t *aclp, zfs_fuid_info_t **fuidp,
+ dmu_tx_t *tx)
{
- int i;
- int entry_type;
- mode_t mode = (zp->z_phys->zp_mode &
- (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
- mode_t seen = 0;
- ace_t *acep;
+ int entry_type;
+ mode_t mode;
+ mode_t seen = 0;
+ zfs_ace_hdr_t *acep = NULL;
+ uint64_t who;
+ uint16_t iflags, type;
+ uint32_t access_mask;
- for (i = 0, acep = aclp->z_acl;
- i != aclp->z_acl_count; i++, acep++) {
+ mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
+
+ while (acep = zfs_acl_next_ace(aclp, acep, &who,
+ &access_mask, &iflags, &type)) {
+ entry_type = (iflags & ACE_TYPE_FLAGS);
/*
* Skip over inherit only ACEs
*/
- if (acep->a_flags & ACE_INHERIT_ONLY_ACE)
+ if (entry_type == ACE_INHERIT_ONLY_ACE)
continue;
- entry_type = (acep->a_flags & ACE_TYPE_FLAGS);
if (entry_type == ACE_OWNER) {
- if ((acep->a_access_mask & ACE_READ_DATA) &&
+ if ((access_mask & ACE_READ_DATA) &&
(!(seen & S_IRUSR))) {
seen |= S_IRUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IRUSR;
}
}
- if ((acep->a_access_mask & ACE_WRITE_DATA) &&
+ if ((access_mask & ACE_WRITE_DATA) &&
(!(seen & S_IWUSR))) {
seen |= S_IWUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWUSR;
}
}
- if ((acep->a_access_mask & ACE_EXECUTE) &&
+ if ((access_mask & ACE_EXECUTE) &&
(!(seen & S_IXUSR))) {
seen |= S_IXUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXUSR;
}
}
} else if (entry_type == OWNING_GROUP) {
- if ((acep->a_access_mask & ACE_READ_DATA) &&
+ if ((access_mask & ACE_READ_DATA) &&
(!(seen & S_IRGRP))) {
seen |= S_IRGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IRGRP;
}
}
- if ((acep->a_access_mask & ACE_WRITE_DATA) &&
+ if ((access_mask & ACE_WRITE_DATA) &&
(!(seen & S_IWGRP))) {
seen |= S_IWGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWGRP;
}
}
- if ((acep->a_access_mask & ACE_EXECUTE) &&
+ if ((access_mask & ACE_EXECUTE) &&
(!(seen & S_IXGRP))) {
seen |= S_IXGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXGRP;
}
}
} else if (entry_type == ACE_EVERYONE) {
- if ((acep->a_access_mask & ACE_READ_DATA)) {
+ if ((access_mask & ACE_READ_DATA)) {
if (!(seen & S_IRUSR)) {
seen |= S_IRUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IRUSR;
}
}
if (!(seen & S_IRGRP)) {
seen |= S_IRGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IRGRP;
}
}
if (!(seen & S_IROTH)) {
seen |= S_IROTH;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IROTH;
}
}
}
- if ((acep->a_access_mask & ACE_WRITE_DATA)) {
+ if ((access_mask & ACE_WRITE_DATA)) {
if (!(seen & S_IWUSR)) {
seen |= S_IWUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWUSR;
}
}
if (!(seen & S_IWGRP)) {
seen |= S_IWGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWGRP;
}
}
if (!(seen & S_IWOTH)) {
seen |= S_IWOTH;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWOTH;
}
}
}
- if ((acep->a_access_mask & ACE_EXECUTE)) {
+ if ((access_mask & ACE_EXECUTE)) {
if (!(seen & S_IXUSR)) {
seen |= S_IXUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXUSR;
}
}
if (!(seen & S_IXGRP)) {
seen |= S_IXGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXGRP;
}
}
if (!(seen & S_IXOTH)) {
seen |= S_IXOTH;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXOTH;
}
}
}
}
+ /*
+ * Now handle FUID create for user/group ACEs
+ */
+ if (entry_type == 0 || entry_type == ACE_IDENTIFIER_GROUP) {
+ aclp->z_ops.ace_who_set(acep,
+ zfs_fuid_create(zp->z_zfsvfs, who,
+ entry_type == 0 ? ZFS_ACE_USER : ZFS_ACE_GROUP, tx,
+ fuidp));
+ }
}
return (mode);
}
static zfs_acl_t *
-zfs_acl_node_read_internal(znode_t *zp)
+zfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify)
{
zfs_acl_t *aclp;
+ zfs_acl_node_t *aclnode;
- aclp = zfs_acl_alloc(0);
- aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
- aclp->z_acl = &zp->z_phys->zp_acl.z_ace_data[0];
+ aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version);
+
+ /*
+ * Version 0 to 1 znode_acl_phys has the size/count fields swapped.
+ * Version 0 didn't have a size field, only a count.
+ */
+ if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
+ aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_size;
+ aclp->z_acl_bytes = ZFS_ACL_SIZE(aclp->z_acl_count);
+ } else {
+ aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
+ aclp->z_acl_bytes = zp->z_phys->zp_acl.z_acl_size;
+ }
+
+ aclnode = zfs_acl_node_alloc(will_modify ? aclp->z_acl_bytes : 0);
+ aclnode->z_ace_count = aclp->z_acl_count;
+ if (will_modify) {
+ bcopy(zp->z_phys->zp_acl.z_ace_data, aclnode->z_acldata,
+ aclp->z_acl_bytes);
+ } else {
+ aclnode->z_size = aclp->z_acl_bytes;
+ aclnode->z_acldata = &zp->z_phys->zp_acl.z_ace_data[0];
+ }
+
+ list_insert_head(&aclp->z_acl, aclnode);
return (aclp);
}
@@ -302,144 +930,127 @@ zfs_acl_node_read_internal(znode_t *zp)
* Read an external acl object.
*/
static int
-zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp)
+zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
{
uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj;
zfs_acl_t *aclp;
+ size_t aclsize;
+ size_t acl_count;
+ zfs_acl_node_t *aclnode;
int error;
ASSERT(MUTEX_HELD(&zp->z_acl_lock));
if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) {
- *aclpp = zfs_acl_node_read_internal(zp);
+ *aclpp = zfs_acl_node_read_internal(zp, will_modify);
return (0);
}
- aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_count);
+ aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version);
+ if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
+ zfs_acl_phys_v0_t *zacl0 =
+ (zfs_acl_phys_v0_t *)&zp->z_phys->zp_acl;
+ aclsize = ZFS_ACL_SIZE(zacl0->z_acl_count);
+ acl_count = zacl0->z_acl_count;
+ } else {
+ aclsize = zp->z_phys->zp_acl.z_acl_size;
+ acl_count = zp->z_phys->zp_acl.z_acl_count;
+ if (aclsize == 0)
+ aclsize = acl_count * sizeof (zfs_ace_t);
+ }
+ aclnode = zfs_acl_node_alloc(aclsize);
+ list_insert_head(&aclp->z_acl, aclnode);
error = dmu_read(zp->z_zfsvfs->z_os, extacl, 0,
- ZFS_ACL_SIZE(zp->z_phys->zp_acl.z_acl_count), aclp->z_acl);
+ aclsize, aclnode->z_acldata);
+ aclnode->z_ace_count = acl_count;
+ aclp->z_acl_count = acl_count;
+ aclp->z_acl_bytes = aclsize;
+
if (error != 0) {
zfs_acl_free(aclp);
return (error);
}
- aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
-
*aclpp = aclp;
return (0);
}
-static boolean_t
-zfs_acl_valid(znode_t *zp, ace_t *uace, int aclcnt, int *inherit)
-{
- ace_t *acep;
- int i;
-
- *inherit = 0;
-
- if (aclcnt > MAX_ACL_ENTRIES || aclcnt <= 0) {
- return (B_FALSE);
- }
-
- for (i = 0, acep = uace; i != aclcnt; i++, acep++) {
-
- /*
- * first check type of entry
- */
-
- switch (acep->a_flags & ACE_TYPE_FLAGS) {
- case ACE_OWNER:
- acep->a_who = (uid_t)-1;
- break;
- case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
- case ACE_IDENTIFIER_GROUP:
- if (acep->a_flags & ACE_GROUP) {
- acep->a_who = (uid_t)-1;
- }
- break;
- case ACE_EVERYONE:
- acep->a_who = (uid_t)-1;
- break;
- }
-
- /*
- * next check inheritance level flags
- */
-
- if (acep->a_type != ALLOW && acep->a_type != DENY)
- return (B_FALSE);
-
- /*
- * Only directories should have inheritance flags.
- */
- if (ZTOV(zp)->v_type != VDIR && (acep->a_flags &
- (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE|
- ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE))) {
- return (B_FALSE);
- }
-
- if (acep->a_flags &
- (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))
- *inherit = 1;
-
- if (acep->a_flags &
- (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
- if ((acep->a_flags & (ACE_FILE_INHERIT_ACE|
- ACE_DIRECTORY_INHERIT_ACE)) == 0) {
- return (B_FALSE);
- }
- }
- }
-
- return (B_TRUE);
-}
/*
- * common code for setting acl's.
+ * common code for setting ACLs.
*
* This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
* zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
* already checked the acl and knows whether to inherit.
*/
int
-zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, dmu_tx_t *tx, int *ihp)
+zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, zfs_fuid_info_t **fuidp,
+ dmu_tx_t *tx)
{
- int inherit = 0;
int error;
znode_phys_t *zphys = zp->z_phys;
- zfs_znode_acl_t *zacl = &zphys->zp_acl;
- uint32_t acl_phys_size = ZFS_ACL_SIZE(aclp->z_acl_count);
+ zfs_acl_phys_t *zacl = &zphys->zp_acl;
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
uint64_t aoid = zphys->zp_acl.z_acl_extern_obj;
+ uint64_t off = 0;
+ dmu_object_type_t otype;
+ zfs_acl_node_t *aclnode;
ASSERT(MUTEX_HELD(&zp->z_lock));
ASSERT(MUTEX_HELD(&zp->z_acl_lock));
- if (ihp)
- inherit = *ihp; /* already determined by caller */
- else if (!zfs_acl_valid(zp, aclp->z_acl,
- aclp->z_acl_count, &inherit)) {
- return (EINVAL);
- }
-
dmu_buf_will_dirty(zp->z_dbuf, tx);
+ zphys->zp_mode = zfs_mode_fuid_compute(zp, aclp, fuidp, tx);
+
/*
- * Will ACL fit internally?
+ * Decide which opbject type to use. If we are forced to
+ * use old ACL format than transform ACL into zfs_oldace_t
+ * layout.
*/
- if (aclp->z_acl_count > ACE_SLOT_CNT) {
+ if (!zfsvfs->z_use_fuids) {
+ otype = DMU_OT_OLDACL;
+ } else {
+ if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) &&
+ (zfsvfs->z_version >= ZPL_VERSION_FUID))
+ zfs_acl_xform(zp, aclp);
+ ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID);
+ otype = DMU_OT_ACL;
+ }
+
+ if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+ /*
+ * If ACL was previously external and we are now
+ * converting to new ACL format then release old
+ * ACL object and create a new one.
+ */
+ if (aoid && aclp->z_version != zacl->z_acl_version) {
+ error = dmu_object_free(zfsvfs->z_os,
+ zp->z_phys->zp_acl.z_acl_extern_obj, tx);
+ if (error)
+ return (error);
+ aoid = 0;
+ }
if (aoid == 0) {
aoid = dmu_object_alloc(zfsvfs->z_os,
- DMU_OT_ACL, acl_phys_size, DMU_OT_NONE, 0, tx);
+ otype, aclp->z_acl_bytes,
+ otype == DMU_OT_ACL ? DMU_OT_SYSACL : DMU_OT_NONE,
+ otype == DMU_OT_ACL ? DN_MAX_BONUSLEN : 0, tx);
} else {
(void) dmu_object_set_blocksize(zfsvfs->z_os, aoid,
- acl_phys_size, 0, tx);
+ aclp->z_acl_bytes, 0, tx);
}
zphys->zp_acl.z_acl_extern_obj = aoid;
- zphys->zp_acl.z_acl_count = aclp->z_acl_count;
- dmu_write(zfsvfs->z_os, aoid, 0,
- acl_phys_size, aclp->z_acl, tx);
+ for (aclnode = list_head(&aclp->z_acl); aclnode;
+ aclnode = list_next(&aclp->z_acl, aclnode)) {
+ if (aclnode->z_ace_count == 0)
+ continue;
+ dmu_write(zfsvfs->z_os, aoid, off,
+ aclnode->z_size, aclnode->z_acldata, tx);
+ off += aclnode->z_size;
+ }
} else {
+ void *start = zacl->z_ace_data;
/*
* Migrating back embedded?
*/
@@ -450,64 +1061,75 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, dmu_tx_t *tx, int *ihp)
return (error);
zphys->zp_acl.z_acl_extern_obj = 0;
}
- bcopy(aclp->z_acl, zacl->z_ace_data,
- aclp->z_acl_count * sizeof (ace_t));
- zacl->z_acl_count = aclp->z_acl_count;
+
+ for (aclnode = list_head(&aclp->z_acl); aclnode;
+ aclnode = list_next(&aclp->z_acl, aclnode)) {
+ if (aclnode->z_ace_count == 0)
+ continue;
+ bcopy(aclnode->z_acldata, start, aclnode->z_size);
+ start = (caddr_t)start + aclnode->z_size;
+ }
}
- zp->z_phys->zp_flags &= ~(ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE);
- if (inherit) {
- zp->z_phys->zp_flags |= ZFS_INHERIT_ACE;
- } else if (ace_trivial(zacl->z_ace_data, zacl->z_acl_count) == 0) {
- zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL;
+ /*
+ * If Old version then swap count/bytes to match old
+ * layout of znode_acl_phys_t.
+ */
+ if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
+ zphys->zp_acl.z_acl_size = aclp->z_acl_count;
+ zphys->zp_acl.z_acl_count = aclp->z_acl_bytes;
+ } else {
+ zphys->zp_acl.z_acl_size = aclp->z_acl_bytes;
+ zphys->zp_acl.z_acl_count = aclp->z_acl_count;
}
- zphys->zp_mode = zfs_mode_compute(zp, aclp);
- zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
+ zphys->zp_acl.z_acl_version = aclp->z_version;
+
+ /*
+ * Replace ACL wide bits, but first clear them.
+ */
+ zp->z_phys->zp_flags &= ~ZFS_ACL_WIDE_FLAGS;
+
+ zp->z_phys->zp_flags |= aclp->z_hints;
+ if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0)
+ zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL;
+
+ zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
return (0);
}
/*
- * Create space for slots_needed ACEs to be append
- * to aclp.
+ * Remove ACE from aclp
*/
static void
-zfs_acl_append(zfs_acl_t *aclp, int slots_needed)
+zfs_ace_remove(zfs_acl_t *aclp, void *acep)
{
- ace_t *newacep;
- ace_t *oldaclp;
- int slot_cnt;
- int slots_left = aclp->z_slots - aclp->z_acl_count;
+ zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp);
+ size_t length;
- if (aclp->z_state == ACL_DATA_ALLOCED)
- ASSERT(aclp->z_slots >= aclp->z_acl_count);
- if (slots_left < slots_needed || aclp->z_state != ACL_DATA_ALLOCED) {
- slot_cnt = aclp->z_slots + 1 + (slots_needed - slots_left);
- newacep = kmem_alloc(ZFS_ACL_SIZE(slot_cnt), KM_SLEEP);
- bcopy(aclp->z_acl, newacep,
- ZFS_ACL_SIZE(aclp->z_acl_count));
- oldaclp = aclp->z_acl;
- if (aclp->z_state == ACL_DATA_ALLOCED)
- kmem_free(oldaclp, ZFS_ACL_SIZE(aclp->z_slots));
- aclp->z_acl = newacep;
- aclp->z_slots = slot_cnt;
- aclp->z_state = ACL_DATA_ALLOCED;
+ /*
+ * If first entry then just alter acldata ptr
+ *
+ * Otherwise split node in two
+ */
+ if (currnode->z_ace_count > 1) {
+ length = currnode->z_size - ((caddr_t)aclp->z_next_ace -
+ (caddr_t)currnode->z_acldata);
+ (void) memmove(acep, aclp->z_next_ace, length);
+ currnode->z_size = currnode->z_size -
+ aclp->z_ops.ace_size(acep);
+ aclp->z_next_ace = acep;
+ aclp->z_acl_bytes -= ((caddr_t)aclp->z_next_ace -
+ (caddr_t)currnode->z_acldata);
+ } else {
+ list_remove(&aclp->z_acl, currnode);
+ aclp->z_next_ace = NULL;
+ aclp->z_acl_bytes = 0;
}
-}
-
-/*
- * Remove "slot" ACE from aclp
- */
-static void
-zfs_ace_remove(zfs_acl_t *aclp, int slot)
-{
- if (aclp->z_acl_count > 1) {
- (void) memmove(&aclp->z_acl[slot],
- &aclp->z_acl[slot +1], sizeof (ace_t) *
- (--aclp->z_acl_count - slot));
- } else
- aclp->z_acl_count--;
+ currnode->z_ace_count--;
+ currnode->z_ace_idx--;
+ aclp->z_acl_count--;
}
/*
@@ -516,16 +1138,24 @@ zfs_ace_remove(zfs_acl_t *aclp, int slot)
* This applies the "groupmask" value for aclmode property.
*/
static void
-zfs_acl_prepend_fixup(ace_t *acep, ace_t *origacep, mode_t mode, uid_t owner)
+zfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep,
+ mode_t mode, uint64_t owner)
{
-
int rmask, wmask, xmask;
int user_ace;
+ uint16_t aceflags;
+ uint32_t origmask, acepmask;
+ uint64_t fuid;
+
+ aceflags = aclp->z_ops.ace_flags_get(acep);
+ fuid = aclp->z_ops.ace_who_get(acep);
+ origmask = aclp->z_ops.ace_mask_get(origacep);
+ acepmask = aclp->z_ops.ace_mask_get(acep);
- user_ace = (!(acep->a_flags &
+ user_ace = (!(aceflags &
(ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
- if (user_ace && (acep->a_who == owner)) {
+ if (user_ace && (fuid == owner)) {
rmask = S_IRUSR;
wmask = S_IWUSR;
xmask = S_IXUSR;
@@ -535,33 +1165,38 @@ zfs_acl_prepend_fixup(ace_t *acep, ace_t *origacep, mode_t mode, uid_t owner)
xmask = S_IXGRP;
}
- if (origacep->a_access_mask & ACE_READ_DATA) {
- if (mode & rmask)
- acep->a_access_mask &= ~ACE_READ_DATA;
- else
- acep->a_access_mask |= ACE_READ_DATA;
+ if (origmask & ACE_READ_DATA) {
+ if (mode & rmask) {
+ acepmask &= ~ACE_READ_DATA;
+ } else {
+ acepmask |= ACE_READ_DATA;
+ }
}
- if (origacep->a_access_mask & ACE_WRITE_DATA) {
- if (mode & wmask)
- acep->a_access_mask &= ~ACE_WRITE_DATA;
- else
- acep->a_access_mask |= ACE_WRITE_DATA;
+ if (origmask & ACE_WRITE_DATA) {
+ if (mode & wmask) {
+ acepmask &= ~ACE_WRITE_DATA;
+ } else {
+ acepmask |= ACE_WRITE_DATA;
+ }
}
- if (origacep->a_access_mask & ACE_APPEND_DATA) {
- if (mode & wmask)
- acep->a_access_mask &= ~ACE_APPEND_DATA;
- else
- acep->a_access_mask |= ACE_APPEND_DATA;
+ if (origmask & ACE_APPEND_DATA) {
+ if (mode & wmask) {
+ acepmask &= ~ACE_APPEND_DATA;
+ } else {
+ acepmask |= ACE_APPEND_DATA;
+ }
}
- if (origacep->a_access_mask & ACE_EXECUTE) {
- if (mode & xmask)
- acep->a_access_mask &= ~ACE_EXECUTE;
- else
- acep->a_access_mask |= ACE_EXECUTE;
+ if (origmask & ACE_EXECUTE) {
+ if (mode & xmask) {
+ acepmask &= ~ACE_EXECUTE;
+ } else {
+ acepmask |= ACE_EXECUTE;
+ }
}
+ aclp->z_ops.ace_mask_set(acep, acepmask);
}
/*
@@ -570,116 +1205,156 @@ zfs_acl_prepend_fixup(ace_t *acep, ace_t *origacep, mode_t mode, uid_t owner)
static void
zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode)
{
- int cnt;
- ace_t *acep;
+ zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl);
+ void *acep;
+ int maskoff = aclp->z_ops.ace_mask_off();
+ size_t abstract_size = aclp->z_ops.ace_abstract_size();
- cnt = aclp->z_acl_count -1;
- acep = aclp->z_acl;
+ ASSERT(aclnode != NULL);
+
+ acep = (void *)((caddr_t)aclnode->z_acldata +
+ aclnode->z_size - (abstract_size * 6));
/*
* Fixup final ACEs to match the mode
*/
- ASSERT(cnt >= 5);
- adjust_ace_pair(&acep[cnt - 1], mode); /* everyone@ */
- adjust_ace_pair(&acep[cnt - 3], (mode & 0070) >> 3); /* group@ */
- adjust_ace_pair(&acep[cnt - 5], (mode & 0700) >> 6); /* owner@ */
+ adjust_ace_pair_common(acep, maskoff, abstract_size,
+ (mode & 0700) >> 6); /* owner@ */
+
+ acep = (caddr_t)acep + (abstract_size * 2);
+
+ adjust_ace_pair_common(acep, maskoff, abstract_size,
+ (mode & 0070) >> 3); /* group@ */
+
+ acep = (caddr_t)acep + (abstract_size * 2);
+ adjust_ace_pair_common(acep, maskoff,
+ abstract_size, mode); /* everyone@ */
}
static int
-zfs_acl_ace_match(ace_t *acep, int allow_deny, int type, int mask)
+zfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny,
+ int entry_type, int accessmask)
{
- return (acep->a_access_mask == mask && acep->a_type == allow_deny &&
- ((acep->a_flags & ACE_TYPE_FLAGS) == type));
+ uint32_t mask = aclp->z_ops.ace_mask_get(acep);
+ uint16_t type = aclp->z_ops.ace_type_get(acep);
+ uint16_t flags = aclp->z_ops.ace_flags_get(acep);
+
+ return (mask == accessmask && type == allow_deny &&
+ ((flags & ACE_TYPE_FLAGS) == entry_type));
}
/*
* Can prepended ACE be reused?
*/
static int
-zfs_reuse_deny(ace_t *acep, int i)
+zfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep)
{
int okay_masks;
+ uint16_t prevtype;
+ uint16_t prevflags;
+ uint16_t flags;
+ uint32_t mask, prevmask;
- if (i < 1)
+ if (prevacep == NULL)
return (B_FALSE);
- if (acep[i-1].a_type != DENY)
+ prevtype = aclp->z_ops.ace_type_get(prevacep);
+ prevflags = aclp->z_ops.ace_flags_get(prevacep);
+ flags = aclp->z_ops.ace_flags_get(acep);
+ mask = aclp->z_ops.ace_mask_get(acep);
+ prevmask = aclp->z_ops.ace_mask_get(prevacep);
+
+ if (prevtype != DENY)
return (B_FALSE);
- if (acep[i-1].a_flags != (acep[i].a_flags & ACE_IDENTIFIER_GROUP))
+ if (prevflags != (flags & ACE_IDENTIFIER_GROUP))
return (B_FALSE);
- okay_masks = (acep[i].a_access_mask & OKAY_MASK_BITS);
+ okay_masks = (mask & OKAY_MASK_BITS);
- if (acep[i-1].a_access_mask & ~okay_masks)
+ if (prevmask & ~okay_masks)
return (B_FALSE);
return (B_TRUE);
}
+
/*
- * Create space to prepend an ACE
+ * Insert new ACL node into chain of zfs_acl_node_t's
+ *
+ * This will result in two possible results.
+ * 1. If the ACL is currently just a single zfs_acl_node and
+ * we are prepending the entry then current acl node will have
+ * a new node inserted above it.
+ *
+ * 2. If we are inserting in the middle of current acl node then
+ * the current node will be split in two and new node will be inserted
+ * in between the two split nodes.
*/
-static void
-zfs_acl_prepend(zfs_acl_t *aclp, int i)
-{
- ace_t *oldaclp = NULL;
- ace_t *to, *from;
- int slots_left = aclp->z_slots - aclp->z_acl_count;
- int oldslots;
- int need_free = 0;
-
- if (aclp->z_state == ACL_DATA_ALLOCED)
- ASSERT(aclp->z_slots >= aclp->z_acl_count);
-
- if (slots_left == 0 || aclp->z_state != ACL_DATA_ALLOCED) {
-
- to = kmem_alloc(ZFS_ACL_SIZE(aclp->z_acl_count +
- OGE_PAD), KM_SLEEP);
- if (aclp->z_state == ACL_DATA_ALLOCED)
- need_free++;
- from = aclp->z_acl;
- oldaclp = aclp->z_acl;
- (void) memmove(to, from,
- sizeof (ace_t) * aclp->z_acl_count);
- aclp->z_state = ACL_DATA_ALLOCED;
- } else {
- from = aclp->z_acl;
- to = aclp->z_acl;
+static zfs_acl_node_t *
+zfs_acl_ace_insert(zfs_acl_t *aclp, void *acep)
+{
+ zfs_acl_node_t *newnode;
+ zfs_acl_node_t *trailernode = NULL;
+ zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp);
+ int curr_idx = aclp->z_curr_node->z_ace_idx;
+ int trailer_count;
+ size_t oldsize;
+
+ newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep));
+ newnode->z_ace_count = 1;
+
+ oldsize = currnode->z_size;
+
+ if (curr_idx != 1) {
+ trailernode = zfs_acl_node_alloc(0);
+ trailernode->z_acldata = acep;
+
+ trailer_count = currnode->z_ace_count - curr_idx + 1;
+ currnode->z_ace_count = curr_idx - 1;
+ currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata;
+ trailernode->z_size = oldsize - currnode->z_size;
+ trailernode->z_ace_count = trailer_count;
}
-
- (void) memmove(&to[i + 1], &from[i],
- sizeof (ace_t) * (aclp->z_acl_count - i));
-
- if (oldaclp) {
- aclp->z_acl = to;
- oldslots = aclp->z_slots;
- aclp->z_slots = aclp->z_acl_count + OGE_PAD;
- if (need_free)
- kmem_free(oldaclp, ZFS_ACL_SIZE(oldslots));
+ aclp->z_acl_count += 1;
+ aclp->z_acl_bytes += aclp->z_ops.ace_size(acep);
+
+ if (curr_idx == 1)
+ list_insert_before(&aclp->z_acl, currnode, newnode);
+ else
+ list_insert_after(&aclp->z_acl, currnode, newnode);
+ if (trailernode) {
+ list_insert_after(&aclp->z_acl, newnode, trailernode);
+ aclp->z_curr_node = trailernode;
+ trailernode->z_ace_idx = 1;
}
+ return (newnode);
}
/*
* Prepend deny ACE
*/
-static void
-zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, int i,
+static void *
+zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, void *acep,
mode_t mode)
{
- ace_t *acep;
-
- zfs_acl_prepend(aclp, i);
-
- acep = aclp->z_acl;
- zfs_set_ace(&acep[i], 0, DENY, acep[i + 1].a_who,
- (acep[i + 1].a_flags & ACE_TYPE_FLAGS));
- zfs_acl_prepend_fixup(&acep[i], &acep[i+1], mode, zp->z_phys->zp_uid);
- aclp->z_acl_count++;
+ zfs_acl_node_t *aclnode;
+ void *newacep;
+ uint64_t fuid;
+ uint16_t flags;
+
+ aclnode = zfs_acl_ace_insert(aclp, acep);
+ newacep = aclnode->z_acldata;
+ fuid = aclp->z_ops.ace_who_get(acep);
+ flags = aclp->z_ops.ace_flags_get(acep);
+ zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS));
+ zfs_acl_prepend_fixup(aclp, newacep, acep, mode, zp->z_phys->zp_uid);
+
+ return (newacep);
}
/*
@@ -687,41 +1362,72 @@ zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, int i,
* and original ACE with inheritance flags stripped off.
*/
static void
-zfs_acl_split_ace(zfs_acl_t *aclp, int i)
+zfs_acl_split_ace(zfs_acl_t *aclp, zfs_ace_hdr_t *acep)
{
- ace_t *acep = aclp->z_acl;
-
- zfs_acl_prepend(aclp, i);
- acep = aclp->z_acl;
- acep[i] = acep[i + 1];
- acep[i].a_flags |= ACE_INHERIT_ONLY_ACE;
- acep[i + 1].a_flags &= ~ALL_INHERIT;
- aclp->z_acl_count++;
+ zfs_acl_node_t *aclnode;
+ zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp);
+ void *newacep;
+ uint16_t type, flags;
+ uint32_t mask;
+ uint64_t fuid;
+
+ type = aclp->z_ops.ace_type_get(acep);
+ flags = aclp->z_ops.ace_flags_get(acep);
+ mask = aclp->z_ops.ace_mask_get(acep);
+ fuid = aclp->z_ops.ace_who_get(acep);
+
+ aclnode = zfs_acl_ace_insert(aclp, acep);
+ newacep = aclnode->z_acldata;
+
+ aclp->z_ops.ace_type_set(newacep, type);
+ aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE);
+ aclp->z_ops.ace_mask_set(newacep, mask);
+ aclp->z_ops.ace_type_set(newacep, type);
+ aclp->z_ops.ace_who_set(newacep, fuid);
+ aclp->z_next_ace = acep;
+ flags &= ~ALL_INHERIT;
+ aclp->z_ops.ace_flags_set(acep, flags);
+ currnode->z_ace_idx -= 1;
}
/*
* Are ACES started at index i, the canonical six ACES?
*/
static int
-zfs_have_canonical_six(zfs_acl_t *aclp, int i)
+zfs_have_canonical_six(zfs_acl_t *aclp)
{
- ace_t *acep = aclp->z_acl;
+ void *acep;
+ zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl);
+ int i = 0;
+ size_t abstract_size = aclp->z_ops.ace_abstract_size();
+
+ ASSERT(aclnode != NULL);
- if ((zfs_acl_ace_match(&acep[i],
+ if (aclnode->z_ace_count < 6)
+ return (0);
+
+ acep = (void *)((caddr_t)aclnode->z_acldata +
+ aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6));
+
+ if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
DENY, ACE_OWNER, 0) &&
- zfs_acl_ace_match(&acep[i + 1], ALLOW, ACE_OWNER,
- OWNER_ALLOW_MASK) && zfs_acl_ace_match(&acep[i + 2],
- DENY, OWNING_GROUP, 0) && zfs_acl_ace_match(&acep[i + 3],
- ALLOW, OWNING_GROUP, 0) && zfs_acl_ace_match(&acep[i + 4],
+ zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
+ ALLOW, ACE_OWNER, OWNER_ALLOW_MASK) &&
+ zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY,
+ OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep +
+ (abstract_size * i++),
+ ALLOW, OWNING_GROUP, 0) &&
+ zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) &&
- zfs_acl_ace_match(&acep[i + 5], ALLOW, ACE_EVERYONE,
- EVERYONE_ALLOW_MASK))) {
+ zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
+ ALLOW, ACE_EVERYONE, EVERYONE_ALLOW_MASK))) {
return (1);
} else {
return (0);
}
}
+
/*
* Apply step 1g, to group entries
*
@@ -731,32 +1437,36 @@ zfs_have_canonical_six(zfs_acl_t *aclp, int i)
* group has.
*/
static void
-zfs_fixup_group_entries(ace_t *acep, mode_t mode)
+zfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep,
+ mode_t mode)
{
+ uint32_t prevmask = aclp->z_ops.ace_mask_get(prevacep);
+ uint32_t mask = aclp->z_ops.ace_mask_get(acep);
+ uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep);
mode_t extramode = (mode >> 3) & 07;
mode_t ownermode = (mode >> 6);
- if (acep[0].a_flags & ACE_IDENTIFIER_GROUP) {
+ if (prevflags & ACE_IDENTIFIER_GROUP) {
extramode &= ~ownermode;
if (extramode) {
- if (extramode & 04) {
- acep[0].a_access_mask &= ~ACE_READ_DATA;
- acep[1].a_access_mask &= ~ACE_READ_DATA;
+ if (extramode & S_IROTH) {
+ prevmask &= ~ACE_READ_DATA;
+ mask &= ~ACE_READ_DATA;
}
- if (extramode & 02) {
- acep[0].a_access_mask &=
- ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
- acep[1].a_access_mask &=
- ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
+ if (extramode & S_IWOTH) {
+ prevmask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
+ mask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
}
- if (extramode & 01) {
- acep[0].a_access_mask &= ~ACE_EXECUTE;
- acep[1].a_access_mask &= ~ACE_EXECUTE;
+ if (extramode & S_IXOTH) {
+ prevmask &= ~ACE_EXECUTE;
+ mask &= ~ACE_EXECUTE;
}
}
}
+ aclp->z_ops.ace_mask_set(acep, mask);
+ aclp->z_ops.ace_mask_set(prevacep, prevmask);
}
/*
@@ -768,58 +1478,64 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
dmu_tx_t *tx)
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
- ace_t *acep;
+ void *acep = NULL, *prevacep = NULL;
+ uint64_t who;
int i;
int error;
int entry_type;
int reuse_deny;
int need_canonical_six = 1;
- int inherit = 0;
- int iflags;
+ uint16_t iflags, type;
+ uint32_t access_mask;
ASSERT(MUTEX_HELD(&zp->z_acl_lock));
ASSERT(MUTEX_HELD(&zp->z_lock));
- i = 0;
- while (i < aclp->z_acl_count) {
- acep = aclp->z_acl;
- entry_type = (acep[i].a_flags & ACE_TYPE_FLAGS);
- iflags = (acep[i].a_flags & ALL_INHERIT);
+ aclp->z_hints = (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
+ while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+ &iflags, &type)) {
+
+ entry_type = (iflags & ACE_TYPE_FLAGS);
+ iflags = (iflags & ALL_INHERIT);
- if ((acep[i].a_type != ALLOW && acep[i].a_type != DENY) ||
+ if ((type != ALLOW && type != DENY) ||
(iflags & ACE_INHERIT_ONLY_ACE)) {
- i++;
if (iflags)
- inherit = 1;
- continue;
+ aclp->z_hints |= ZFS_INHERIT_ACE;
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ aclp->z_hints |= ZFS_ACL_OBJ_ACE;
+ break;
+ }
+ goto nextace;
}
-
if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) {
- zfs_ace_remove(aclp, i);
- continue;
+ zfs_ace_remove(aclp, acep);
+ goto nextace;
}
-
/*
* Need to split ace into two?
*/
if ((iflags & (ACE_FILE_INHERIT_ACE|
ACE_DIRECTORY_INHERIT_ACE)) &&
(!(iflags & ACE_INHERIT_ONLY_ACE))) {
- zfs_acl_split_ace(aclp, i);
- i++;
- inherit = 1;
- continue;
+ zfs_acl_split_ace(aclp, acep);
+ aclp->z_hints |= ZFS_INHERIT_ACE;
+ goto nextace;
}
if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
(entry_type == OWNING_GROUP)) {
- acep[i].a_access_mask &= ~OGE_CLEAR;
- i++;
- continue;
-
+ access_mask &= ~OGE_CLEAR;
+ aclp->z_ops.ace_mask_set(acep, access_mask);
+ goto nextace;
} else {
- if (acep[i].a_type == ALLOW) {
+ reuse_deny = B_TRUE;
+ if (type == ALLOW) {
/*
* Check preceding ACE if any, to see
@@ -829,25 +1545,27 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
*/
if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) {
- reuse_deny = zfs_reuse_deny(acep, i);
+ reuse_deny = zfs_reuse_deny(aclp, acep,
+ prevacep);
if (reuse_deny == B_FALSE) {
- zfs_acl_prepend_deny(zp, aclp,
- i, mode);
- i++;
- acep = aclp->z_acl;
+ prevacep =
+ zfs_acl_prepend_deny(zp,
+ aclp, acep, mode);
} else {
zfs_acl_prepend_fixup(
- &acep[i - 1],
- &acep[i], mode,
+ aclp, prevacep,
+ acep, mode,
zp->z_phys->zp_uid);
}
- zfs_fixup_group_entries(&acep[i - 1],
- mode);
+ zfs_fixup_group_entries(aclp, acep,
+ prevacep, mode);
+
}
}
- i++;
}
+nextace:
+ prevacep = acep;
}
/*
@@ -855,37 +1573,46 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
*/
if (aclp->z_acl_count >= 6) {
- i = aclp->z_acl_count - 6;
-
- if (zfs_have_canonical_six(aclp, i)) {
+ if (zfs_have_canonical_six(aclp)) {
need_canonical_six = 0;
}
}
if (need_canonical_six) {
-
- zfs_acl_append(aclp, 6);
- i = aclp->z_acl_count;
- acep = aclp->z_acl;
- zfs_set_ace(&acep[i++], 0, DENY, -1, ACE_OWNER);
- zfs_set_ace(&acep[i++], OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER);
- zfs_set_ace(&acep[i++], 0, DENY, -1, OWNING_GROUP);
- zfs_set_ace(&acep[i++], 0, ALLOW, -1, OWNING_GROUP);
- zfs_set_ace(&acep[i++], EVERYONE_DENY_MASK,
- DENY, -1, ACE_EVERYONE);
- zfs_set_ace(&acep[i++], EVERYONE_ALLOW_MASK,
- ALLOW, -1, ACE_EVERYONE);
+ size_t abstract_size = aclp->z_ops.ace_abstract_size();
+ void *zacep;
+ zfs_acl_node_t *aclnode =
+ zfs_acl_node_alloc(abstract_size * 6);
+
+ aclnode->z_size = abstract_size * 6;
+ aclnode->z_ace_count = 6;
+ aclp->z_acl_bytes += aclnode->z_size;
+ list_insert_tail(&aclp->z_acl, aclnode);
+
+ zacep = aclnode->z_acldata;
+
+ i = 0;
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
+ 0, DENY, -1, ACE_OWNER);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
+ OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
+ DENY, -1, OWNING_GROUP);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
+ ALLOW, -1, OWNING_GROUP);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
+ EVERYONE_DENY_MASK, DENY, -1, ACE_EVERYONE);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
+ EVERYONE_ALLOW_MASK, ALLOW, -1, ACE_EVERYONE);
aclp->z_acl_count += 6;
}
zfs_acl_fixup_canonical_six(aclp, mode);
-
zp->z_phys->zp_mode = mode;
- error = zfs_aclset_common(zp, aclp, tx, &inherit);
+ error = zfs_aclset_common(zp, aclp, NULL, tx);
return (error);
}
-
int
zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
{
@@ -894,7 +1621,7 @@ zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
ASSERT(MUTEX_HELD(&zp->z_lock));
mutex_enter(&zp->z_acl_lock);
- error = zfs_acl_node_read(zp, &aclp);
+ error = zfs_acl_node_read(zp, &aclp, B_TRUE);
if (error == 0)
error = zfs_acl_chmod(zp, mode, aclp, tx);
mutex_exit(&zp->z_acl_lock);
@@ -907,11 +1634,32 @@ zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
* strip off write_owner and write_acl
*/
static void
-zfs_securemode_update(zfsvfs_t *zfsvfs, ace_t *acep)
+zfs_securemode_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep)
{
+ uint32_t mask = aclp->z_ops.ace_mask_get(acep);
+
if ((zfsvfs->z_acl_inherit == ZFS_ACL_SECURE) &&
- (acep->a_type == ALLOW))
- acep->a_access_mask &= ~SECURE_CLEAR;
+ (aclp->z_ops.ace_type_get(acep) == ALLOW)) {
+ mask &= ~SECURE_CLEAR;
+ aclp->z_ops.ace_mask_set(acep, mask);
+ }
+}
+
+/*
+ * Should ACE be inherited?
+ */
+static int
+zfs_ace_can_use(znode_t *zp, uint16_t acep_flags)
+{
+ int vtype = ZTOV(zp)->v_type;
+ int iflags = (acep_flags & 0xf);
+
+ if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
+ return (1);
+ else if (iflags & ACE_FILE_INHERIT_ACE)
+ return (!((vtype == VDIR) &&
+ (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
+ return (0);
}
/*
@@ -921,90 +1669,108 @@ static zfs_acl_t *
zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp)
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
- ace_t *pacep;
- ace_t *acep;
- int ace_cnt = 0;
- int pace_cnt;
- int i, j;
+ void *pacep;
+ void *acep, *acep2;
+ zfs_acl_node_t *aclnode, *aclnode2;
zfs_acl_t *aclp = NULL;
-
- i = j = 0;
- pace_cnt = paclp->z_acl_count;
- pacep = paclp->z_acl;
+ uint64_t who;
+ uint32_t access_mask;
+ uint16_t iflags, newflags, type;
+ size_t ace_size;
+ void *data1, *data2;
+ size_t data1sz, data2sz;
+
+ pacep = NULL;
+ aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
if (zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) {
- for (i = 0; i != pace_cnt; i++) {
+ while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
+ &access_mask, &iflags, &type)) {
if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW &&
- pacep[i].a_type == ALLOW)
+ type == ALLOW)
continue;
- if (zfs_ace_can_use(zp, &pacep[i])) {
- ace_cnt++;
- if (!(pacep[i].a_flags &
- ACE_NO_PROPAGATE_INHERIT_ACE))
- ace_cnt++;
- }
- }
- }
+ ace_size = aclp->z_ops.ace_size(pacep);
- aclp = zfs_acl_alloc(ace_cnt + OGE_PAD);
- if (ace_cnt && zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) {
- acep = aclp->z_acl;
- pacep = paclp->z_acl;
- for (i = 0; i != pace_cnt; i++) {
+ if (zfs_ace_can_use(zp, iflags)) {
+ aclnode =
+ zfs_acl_node_alloc(ace_size);
- if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW &&
- pacep[i].a_type == ALLOW)
- continue;
-
- if (zfs_ace_can_use(zp, &pacep[i])) {
+ list_insert_tail(&aclp->z_acl, aclnode);
+ acep = aclnode->z_acldata;
+ zfs_set_ace(aclp, acep, access_mask, type,
+ who, iflags|ACE_INHERITED_ACE);
/*
- * Now create entry for inherited ace
+ * Copy special opaque data if any
*/
-
- acep[j] = pacep[i];
-
- /*
- * When AUDIT/ALARM a_types are supported
- * they should be inherited here.
- */
-
- if ((pacep[i].a_flags &
+ if ((data1sz = paclp->z_ops.ace_data(pacep,
+ &data1)) != 0) {
+ VERIFY((data2sz =
+ aclp->z_ops.ace_data(acep,
+ &data2)) == data1sz);
+ bcopy(data1, data2, data2sz);
+ }
+ aclp->z_acl_count++;
+ aclnode->z_ace_count++;
+ aclp->z_acl_bytes += aclnode->z_size;
+ newflags = aclp->z_ops.ace_flags_get(acep);
+ if ((iflags &
ACE_NO_PROPAGATE_INHERIT_ACE) ||
(ZTOV(zp)->v_type != VDIR)) {
- acep[j].a_flags &= ~ALL_INHERIT;
- zfs_securemode_update(zfsvfs, &acep[j]);
- j++;
+ newflags &= ~ALL_INHERIT;
+ aclp->z_ops.ace_flags_set(acep,
+ newflags|ACE_INHERITED_ACE);
+ zfs_securemode_update(zfsvfs,
+ aclp, acep);
continue;
}
ASSERT(ZTOV(zp)->v_type == VDIR);
- /*
- * If we are inheriting an ACE targeted for
- * only files, then make sure inherit_only
- * is on for future propagation.
- */
- if ((pacep[i].a_flags & (ACE_FILE_INHERIT_ACE |
+ newflags = aclp->z_ops.ace_flags_get(acep);
+ if ((iflags & (ACE_FILE_INHERIT_ACE |
ACE_DIRECTORY_INHERIT_ACE)) !=
ACE_FILE_INHERIT_ACE) {
- j++;
- acep[j] = acep[j-1];
- acep[j-1].a_flags |=
- ACE_INHERIT_ONLY_ACE;
- acep[j].a_flags &= ~ALL_INHERIT;
+ aclnode2 = zfs_acl_node_alloc(ace_size);
+ list_insert_tail(&aclp->z_acl,
+ aclnode2);
+ acep2 = aclnode2->z_acldata;
+ zfs_set_ace(aclp, acep2,
+ access_mask, type, who,
+ iflags|ACE_INHERITED_ACE);
+ newflags |= ACE_INHERIT_ONLY_ACE;
+ aclp->z_ops.ace_flags_set(acep,
+ newflags);
+ newflags &= ~ALL_INHERIT;
+ aclp->z_ops.ace_flags_set(acep2,
+ newflags|ACE_INHERITED_ACE);
+
+ /*
+ * Copy special opaque data if any
+ */
+ if ((data1sz =
+ aclp->z_ops.ace_data(acep,
+ &data1)) != 0) {
+ VERIFY((data2sz =
+ aclp->z_ops.ace_data(acep2,
+ &data2)) == data1sz);
+ bcopy(data1, data2, data1sz);
+ }
+ aclp->z_acl_count++;
+ aclnode2->z_ace_count++;
+ aclp->z_acl_bytes += aclnode->z_size;
+ zfs_securemode_update(zfsvfs,
+ aclp, acep2);
} else {
- acep[j].a_flags |= ACE_INHERIT_ONLY_ACE;
+ newflags |= ACE_INHERIT_ONLY_ACE;
+ aclp->z_ops.ace_flags_set(acep,
+ newflags|ACE_INHERITED_ACE);
}
- zfs_securemode_update(zfsvfs, &acep[j]);
- j++;
+
}
}
}
- aclp->z_acl_count = j;
- ASSERT(aclp->z_slots >= aclp->z_acl_count);
-
return (aclp);
}
@@ -1014,14 +1780,21 @@ zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp)
*/
void
zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
- vattr_t *vap, dmu_tx_t *tx, cred_t *cr)
+ vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
+ zfs_acl_t *setaclp, zfs_fuid_info_t **fuidp)
{
uint64_t mode;
- uid_t uid;
- gid_t gid;
+ uint64_t uid;
+ uint64_t gid;
int error;
int pull_down;
- zfs_acl_t *aclp, *paclp;
+ zfsvfs_t *zfsvfs = zp->z_zfsvfs;
+ zfs_acl_t *aclp = NULL;
+ zfs_acl_t *paclp;
+ xvattr_t *xvap = (xvattr_t *)vap;
+
+ if (setaclp)
+ aclp = setaclp;
mode = MAKEIMODE(vap->va_type, vap->va_mode);
@@ -1030,18 +1803,25 @@ zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
*/
if ((flag & (IS_ROOT_NODE | IS_REPLAY)) ||
((flag & IS_XATTR) && (vap->va_type == VDIR))) {
- uid = vap->va_uid;
- gid = vap->va_gid;
+ uid = zfs_fuid_create(zfsvfs, vap->va_uid,
+ ZFS_OWNER, tx, fuidp);
+ gid = zfs_fuid_create(zfsvfs, vap->va_gid,
+ ZFS_GROUP, tx, fuidp);
} else {
- uid = crgetuid(cr);
+ uid = zfs_fuid_create_cred(zfsvfs, crgetuid(cr),
+ ZFS_OWNER, tx, cr, fuidp);
if ((vap->va_mask & AT_GID) &&
((vap->va_gid == parent->z_phys->zp_gid) ||
groupmember(vap->va_gid, cr) ||
- secpolicy_vnode_create_gid(cr) == 0))
- gid = vap->va_gid;
- else
+ secpolicy_vnode_create_gid(cr) == 0)) {
+ gid = zfs_fuid_create_cred(zfsvfs, vap->va_gid,
+ ZFS_GROUP, tx, cr, fuidp);
+ } else {
gid = (parent->z_phys->zp_mode & S_ISGID) ?
parent->z_phys->zp_gid : crgetgid(cr);
+ gid = zfs_fuid_create_cred(zfsvfs, gid,
+ ZFS_GROUP, tx, cr, fuidp);
+ }
}
/*
@@ -1063,85 +1843,133 @@ zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
zp->z_phys->zp_gid = gid;
zp->z_phys->zp_mode = mode;
- mutex_enter(&parent->z_lock);
- pull_down = (parent->z_phys->zp_flags & ZFS_INHERIT_ACE);
- if (pull_down) {
- mutex_enter(&parent->z_acl_lock);
- VERIFY(0 == zfs_acl_node_read(parent, &paclp));
- mutex_exit(&parent->z_acl_lock);
- aclp = zfs_acl_inherit(zp, paclp);
- zfs_acl_free(paclp);
+ if (aclp == NULL) {
+ mutex_enter(&parent->z_lock);
+ pull_down = (parent->z_phys->zp_flags & ZFS_INHERIT_ACE);
+ if (pull_down) {
+ mutex_enter(&parent->z_acl_lock);
+ VERIFY(0 == zfs_acl_node_read(parent, &paclp, B_FALSE));
+ mutex_exit(&parent->z_acl_lock);
+ aclp = zfs_acl_inherit(zp, paclp);
+ zfs_acl_free(paclp);
+ } else {
+ aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
+ }
+ mutex_exit(&parent->z_lock);
+ mutex_enter(&zp->z_lock);
+ mutex_enter(&zp->z_acl_lock);
+ error = zfs_acl_chmod(zp, mode, aclp, tx);
} else {
- aclp = zfs_acl_alloc(6);
+ mutex_enter(&zp->z_lock);
+ mutex_enter(&zp->z_acl_lock);
}
- mutex_exit(&parent->z_lock);
- mutex_enter(&zp->z_lock);
- mutex_enter(&zp->z_acl_lock);
- error = zfs_acl_chmod(zp, mode, aclp, tx);
+
+ /* Force auto_inherit on all new directory objects */
+ if (vap->va_type == VDIR)
+ aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
+
+ error = zfs_aclset_common(zp, aclp, fuidp, tx);
+
+ /* Set optional attributes if any */
+ if (vap->va_mask & AT_XVATTR)
+ zfs_xvattr_set(zp, xvap);
+
mutex_exit(&zp->z_lock);
mutex_exit(&zp->z_acl_lock);
ASSERT3U(error, ==, 0);
- zfs_acl_free(aclp);
-}
-
-/*
- * Should ACE be inherited?
- */
-static int
-zfs_ace_can_use(znode_t *zp, ace_t *acep)
-{
- int vtype = ZTOV(zp)->v_type;
-
- int iflags = (acep->a_flags & 0xf);
- if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
- return (1);
- else if (iflags & ACE_FILE_INHERIT_ACE)
- return (!((vtype == VDIR) &&
- (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
- return (0);
+ if (aclp != setaclp) {
+ zfs_acl_free(aclp);
+ }
}
/*
* Retrieve a files ACL
*/
int
-zfs_getacl(znode_t *zp, vsecattr_t *vsecp, cred_t *cr)
+zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
{
zfs_acl_t *aclp;
- ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
+ ulong_t mask;
int error;
+ int count = 0;
+ int largeace = 0;
- if (error = zfs_zaccess(zp, ACE_READ_ACL, cr)) {
- /*
- * If owner of file then allow reading of the
- * ACL.
- */
- if (crgetuid(cr) != zp->z_phys->zp_uid)
- return (error);
- }
+ mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT |
+ VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
+
+ if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
+ return (error);
if (mask == 0)
return (ENOSYS);
mutex_enter(&zp->z_acl_lock);
- error = zfs_acl_node_read(zp, &aclp);
+ error = zfs_acl_node_read(zp, &aclp, B_FALSE);
if (error != 0) {
mutex_exit(&zp->z_acl_lock);
return (error);
}
+ /*
+ * Scan ACL to determine number of ACEs
+ */
+ if ((zp->z_phys->zp_flags & ZFS_ACL_OBJ_ACE) &&
+ !(mask & VSA_ACE_ALLTYPES)) {
+ void *zacep = NULL;
+ uint64_t who;
+ uint32_t access_mask;
+ uint16_t type, iflags;
+
+ while (zacep = zfs_acl_next_ace(aclp, zacep,
+ &who, &access_mask, &iflags, &type)) {
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ largeace++;
+ continue;
+ default:
+ count++;
+ }
+ }
+ vsecp->vsa_aclcnt = count;
+ } else
+ count = aclp->z_acl_count;
if (mask & VSA_ACECNT) {
- vsecp->vsa_aclcnt = aclp->z_acl_count;
+ vsecp->vsa_aclcnt = count;
}
if (mask & VSA_ACE) {
- vsecp->vsa_aclentp = kmem_alloc(aclp->z_acl_count *
- sizeof (ace_t), KM_SLEEP);
- bcopy(aclp->z_acl, vsecp->vsa_aclentp,
- aclp->z_acl_count * sizeof (ace_t));
+ size_t aclsz;
+
+ zfs_acl_node_t *aclnode = list_head(&aclp->z_acl);
+
+ aclsz = count * sizeof (ace_t) +
+ sizeof (ace_object_t) * largeace;
+
+ vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP);
+ vsecp->vsa_aclentsz = aclsz;
+
+ if (aclp->z_version == ZFS_ACL_VERSION_FUID)
+ zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp,
+ vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES));
+ else {
+ bcopy(aclnode->z_acldata, vsecp->vsa_aclentp,
+ count * sizeof (ace_t));
+ }
+ }
+ if (mask & VSA_ACE_ACLFLAGS) {
+ vsecp->vsa_aclflags = 0;
+ if (zp->z_phys->zp_flags & ZFS_ACL_DEFAULTED)
+ vsecp->vsa_aclflags |= ACL_DEFAULTED;
+ if (zp->z_phys->zp_flags & ZFS_ACL_PROTECTED)
+ vsecp->vsa_aclflags |= ACL_PROTECTED;
+ if (zp->z_phys->zp_flags & ZFS_ACL_AUTO_INHERIT)
+ vsecp->vsa_aclflags |= ACL_AUTO_INHERIT;
}
mutex_exit(&zp->z_acl_lock);
@@ -1151,36 +1979,99 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, cred_t *cr)
return (0);
}
+int
+zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type,
+ vsecattr_t *vsecp, zfs_acl_t **zaclp)
+{
+ zfs_acl_t *aclp;
+ zfs_acl_node_t *aclnode;
+ int aclcnt = vsecp->vsa_aclcnt;
+ int error;
+
+ if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
+ return (EINVAL);
+
+ aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version));
+
+ aclp->z_hints = 0;
+ aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
+ if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
+ if ((error = zfs_copy_ace_2_oldace(obj_type, aclp,
+ (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata,
+ aclcnt, &aclnode->z_size)) != 0) {
+ zfs_acl_free(aclp);
+ zfs_acl_node_free(aclnode);
+ return (error);
+ }
+ } else {
+ if ((error = zfs_copy_ace_2_fuid(obj_type, aclp,
+ vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt,
+ &aclnode->z_size)) != 0) {
+ zfs_acl_free(aclp);
+ zfs_acl_node_free(aclnode);
+ return (error);
+ }
+ }
+ aclp->z_acl_bytes = aclnode->z_size;
+ aclnode->z_ace_count = aclcnt;
+ aclp->z_acl_count = aclcnt;
+ list_insert_head(&aclp->z_acl, aclnode);
+
+ /*
+ * If flags are being set then add them to z_hints
+ */
+ if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) {
+ if (vsecp->vsa_aclflags & ACL_PROTECTED)
+ aclp->z_hints |= ZFS_ACL_PROTECTED;
+ if (vsecp->vsa_aclflags & ACL_DEFAULTED)
+ aclp->z_hints |= ZFS_ACL_DEFAULTED;
+ if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT)
+ aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
+ }
+
+ *zaclp = aclp;
+
+ return (0);
+}
+
/*
* Set a files ACL
*/
int
-zfs_setacl(znode_t *zp, vsecattr_t *vsecp, cred_t *cr)
+zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
zilog_t *zilog = zfsvfs->z_log;
- ace_t *acep = vsecp->vsa_aclentp;
- int aclcnt = vsecp->vsa_aclcnt;
ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
dmu_tx_t *tx;
int error;
- int inherit;
zfs_acl_t *aclp;
+ zfs_fuid_info_t *fuidp = NULL;
if (mask == 0)
return (ENOSYS);
- if (!zfs_acl_valid(zp, acep, aclcnt, &inherit))
- return (EINVAL);
+ if (zp->z_phys->zp_flags & ZFS_IMMUTABLE)
+ return (EPERM);
+
+ if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
+ return (error);
+
+ error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, &aclp);
+ if (error)
+ return (error);
+
+ /*
+ * If ACL wide flags aren't being set then preserve any
+ * existing flags.
+ */
+ if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
+ aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
+ }
top:
- error = zfs_zaccess_v4_perm(zp, ACE_WRITE_ACL, cr);
- if (error == EACCES || error == ACCESS_UNDETERMINED) {
- if ((error = secpolicy_vnode_setdac(cr,
- zp->z_phys->zp_uid)) != 0) {
- return (error);
- }
- } else if (error) {
- return (error == EROFS ? error : EPERM);
+ if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) {
+ zfs_acl_free(aclp);
+ return (error);
}
mutex_enter(&zp->z_lock);
@@ -1190,10 +2081,32 @@ top:
dmu_tx_hold_bonus(tx, zp->z_id);
if (zp->z_phys->zp_acl.z_acl_extern_obj) {
- dmu_tx_hold_write(tx, zp->z_phys->zp_acl.z_acl_extern_obj,
- 0, ZFS_ACL_SIZE(aclcnt));
- } else if (aclcnt > ACE_SLOT_CNT) {
- dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, ZFS_ACL_SIZE(aclcnt));
+ /* Are we upgrading ACL? */
+ if (zfsvfs->z_version <= ZPL_VERSION_FUID &&
+ zp->z_phys->zp_acl.z_acl_version ==
+ ZFS_ACL_VERSION_INITIAL) {
+ dmu_tx_hold_free(tx,
+ zp->z_phys->zp_acl.z_acl_extern_obj,
+ 0, DMU_OBJECT_END);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
+ 0, sizeof (zfs_object_ace_t) * 2048 + 6);
+ } else {
+ dmu_tx_hold_write(tx,
+ zp->z_phys->zp_acl.z_acl_extern_obj,
+ 0, aclp->z_acl_bytes);
+ }
+ } else if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
+ }
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
}
error = dmu_tx_assign(tx, zfsvfs->z_assign);
@@ -1207,17 +2120,18 @@ top:
goto top;
}
dmu_tx_abort(tx);
+ zfs_acl_free(aclp);
return (error);
}
- aclp = zfs_acl_alloc(aclcnt);
- bcopy(acep, aclp->z_acl, sizeof (ace_t) * aclcnt);
- aclp->z_acl_count = aclcnt;
- error = zfs_aclset_common(zp, aclp, tx, &inherit);
+ error = zfs_aclset_common(zp, aclp, &fuidp, tx);
ASSERT(error == 0);
+ zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
+
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
zfs_acl_free(aclp);
- zfs_log_acl(zilog, tx, TX_ACL, zp, aclcnt, acep);
dmu_tx_commit(tx);
done:
mutex_exit(&zp->z_acl_lock);
@@ -1226,46 +2140,34 @@ done:
return (error);
}
+/*
+ * working_mode returns the permissions that were not granted
+ */
static int
-zfs_ace_access(ace_t *zacep, int *working_mode)
-{
- if (*working_mode == 0) {
- return (0);
- }
-
- if (zacep->a_access_mask & *working_mode) {
- if (zacep->a_type == ALLOW) {
- *working_mode &=
- ~(*working_mode & zacep->a_access_mask);
- if (*working_mode == 0)
- return (0);
- } else if (zacep->a_type == DENY) {
- return (EACCES);
- }
- }
-
- /*
- * haven't been specifcally denied at this point
- * so return UNDETERMINED.
- */
-
- return (ACCESS_UNDETERMINED);
-}
-
-
-static int
-zfs_zaccess_common(znode_t *zp, int v4_mode, int *working_mode, cred_t *cr)
+zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
+ boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
{
zfs_acl_t *aclp;
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
- ace_t *zacep;
- gid_t gid;
- int cnt;
- int i;
int error;
int access_deny = ACCESS_UNDETERMINED;
- uint_t entry_type;
uid_t uid = crgetuid(cr);
+ uint64_t who;
+ uint16_t type, iflags;
+ uint16_t entry_type;
+ uint32_t access_mask;
+ zfs_ace_hdr_t *acep = NULL;
+ boolean_t checkit;
+ uid_t fowner;
+ uid_t gowner;
+
+ /*
+ * Short circuit empty requests
+ */
+ if (v4_mode == 0)
+ return (0);
+
+ *check_privs = B_TRUE;
if (zfsvfs->z_assign >= TXG_INITIAL) { /* ZIL replay */
*working_mode = 0;
@@ -1277,68 +2179,109 @@ zfs_zaccess_common(znode_t *zp, int v4_mode, int *working_mode, cred_t *cr)
if ((v4_mode & WRITE_MASK) &&
(zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
(!IS_DEVVP(ZTOV(zp)))) {
+ *check_privs = B_FALSE;
return (EROFS);
}
+ /*
+ * Only check for READONLY on non-directories.
+ */
+ if ((v4_mode & WRITE_MASK_DATA) &&
+ (((ZTOV(zp)->v_type != VDIR) &&
+ (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
+ (ZTOV(zp)->v_type == VDIR &&
+ (zp->z_phys->zp_flags & ZFS_IMMUTABLE)))) {
+ *check_privs = B_FALSE;
+ return (EPERM);
+ }
+
+ if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) &&
+ (zp->z_phys->zp_flags & ZFS_NOUNLINK)) {
+ *check_privs = B_FALSE;
+ return (EPERM);
+ }
+
+ if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) &&
+ (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED))) {
+ *check_privs = B_FALSE;
+ return (EACCES);
+ }
+
+ /*
+ * The caller requested that the ACL check be skipped. This
+ * would only happen if the caller checked VOP_ACCESS() with a
+ * 32 bit ACE mask and already had the appropriate permissions.
+ */
+ if (skipaclchk) {
+ *working_mode = 0;
+ return (0);
+ }
+
+ zfs_fuid_map_ids(zp, &fowner, &gowner);
+
mutex_enter(&zp->z_acl_lock);
- error = zfs_acl_node_read(zp, &aclp);
+ error = zfs_acl_node_read(zp, &aclp, B_FALSE);
if (error != 0) {
mutex_exit(&zp->z_acl_lock);
return (error);
}
+ while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+ &iflags, &type)) {
- zacep = aclp->z_acl;
- cnt = aclp->z_acl_count;
-
- for (i = 0; i != cnt; i++) {
+ if (iflags & ACE_INHERIT_ONLY_ACE)
+ continue;
- DTRACE_PROBE2(zfs__access__common,
- ace_t *, &zacep[i], int, *working_mode);
+ entry_type = (iflags & ACE_TYPE_FLAGS);
- if (zacep[i].a_flags & ACE_INHERIT_ONLY_ACE)
- continue;
+ checkit = B_FALSE;
- entry_type = (zacep[i].a_flags & ACE_TYPE_FLAGS);
switch (entry_type) {
case ACE_OWNER:
- if (uid == zp->z_phys->zp_uid) {
- access_deny = zfs_ace_access(&zacep[i],
- working_mode);
- }
+ if (uid == fowner)
+ checkit = B_TRUE;
break;
- case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
+ case OWNING_GROUP:
+ who = gowner;
+ /*FALLTHROUGH*/
case ACE_IDENTIFIER_GROUP:
- /*
- * Owning group gid is in znode not ACL
- */
- if (entry_type == (ACE_IDENTIFIER_GROUP | ACE_GROUP))
- gid = zp->z_phys->zp_gid;
- else
- gid = zacep[i].a_who;
-
- if (groupmember(gid, cr)) {
- access_deny = zfs_ace_access(&zacep[i],
- working_mode);
- }
+ checkit = zfs_groupmember(zfsvfs, who, cr);
break;
case ACE_EVERYONE:
- access_deny = zfs_ace_access(&zacep[i], working_mode);
+ checkit = B_TRUE;
break;
/* USER Entry */
default:
if (entry_type == 0) {
- if (uid == zacep[i].a_who) {
- access_deny = zfs_ace_access(&zacep[i],
- working_mode);
- }
+ uid_t newid;
+
+ zfs_fuid_map_id(zfsvfs, who,
+ ZFS_ACE_USER, &newid);
+ if (newid != IDMAP_WK_CREATOR_OWNER_UID &&
+ uid == newid)
+ checkit = B_TRUE;
break;
+ } else {
+ zfs_acl_free(aclp);
+ mutex_exit(&zp->z_acl_lock);
+ return (EIO);
+ }
+ }
+
+ if (checkit) {
+ if (access_mask & *working_mode) {
+ if (type == ALLOW) {
+ *working_mode &=
+ ~(*working_mode & access_mask);
+ if (*working_mode == 0) {
+ access_deny = 0;
+ }
+ } else if (type == DENY) {
+ access_deny = EACCES;
+ }
}
- zfs_acl_free(aclp);
- mutex_exit(&zp->z_acl_lock);
- return (EIO);
}
if (access_deny != ACCESS_UNDETERMINED)
@@ -1347,23 +2290,35 @@ zfs_zaccess_common(znode_t *zp, int v4_mode, int *working_mode, cred_t *cr)
mutex_exit(&zp->z_acl_lock);
zfs_acl_free(aclp);
-
+out:
return (access_deny);
}
+static int
+zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
+ cred_t *cr)
+{
+ if (*working_mode != ACE_WRITE_DATA)
+ return (EACCES);
+
+ return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
+ check_privs, B_FALSE, cr));
+}
/*
* Determine whether Access should be granted/denied, invoking least
* priv subsytem when a deny is determined.
*/
int
-zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
+zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
{
- int working_mode;
- int error;
- int is_attr;
- znode_t *xzp;
- znode_t *check_zp = zp;
+ uint32_t working_mode;
+ int error;
+ int is_attr;
+ zfsvfs_t *zfsvfs = zp->z_zfsvfs;
+ boolean_t check_privs;
+ znode_t *xzp;
+ znode_t *check_zp = zp;
is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) &&
(ZTOV(zp)->v_type == VDIR));
@@ -1376,7 +2331,9 @@ zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
zp->z_phys->zp_parent, &xzp)) != 0) {
return (error);
}
+
check_zp = xzp;
+
/*
* fixup mode to map to xattr perms
*/
@@ -1392,18 +2349,76 @@ zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
}
}
- error = zfs_zaccess_common(check_zp, mode, &working_mode, cr);
+ if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
+ &check_privs, skipaclchk, cr)) == 0) {
+ if (is_attr)
+ VN_RELE(ZTOV(xzp));
+ return (0);
+ }
- if (error == EROFS) {
+ if (error && check_privs == B_FALSE) {
if (is_attr)
VN_RELE(ZTOV(xzp));
return (error);
}
- if (error || working_mode) {
- working_mode = (zfs_v4_to_unix(working_mode) << 6);
- error = secpolicy_vnode_access(cr, ZTOV(check_zp),
- check_zp->z_phys->zp_uid, working_mode);
+ if (error && (flags & V_APPEND)) {
+ error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
+ }
+
+ if (error && check_privs) {
+ uid_t owner;
+ mode_t checkmode = 0;
+
+ zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid,
+ ZFS_OWNER, &owner);
+
+ /*
+ * First check for implicit owner permission on
+ * read_acl/read_attributes
+ */
+
+ error = 0;
+ ASSERT(working_mode != 0);
+
+ if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
+ owner == crgetuid(cr)))
+ working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
+
+ if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
+ ACE_READ_ACL|ACE_READ_ATTRIBUTES))
+ checkmode |= VREAD;
+ if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
+ ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES))
+ checkmode |= VWRITE;
+ if (working_mode & ACE_EXECUTE)
+ checkmode |= VEXEC;
+
+ if (checkmode)
+ error = secpolicy_vnode_access(cr, ZTOV(check_zp),
+ owner, checkmode);
+
+ if (error == 0 && (working_mode & ACE_WRITE_OWNER))
+ error = secpolicy_vnode_create_gid(cr);
+ if (error == 0 && (working_mode & ACE_WRITE_ACL))
+ error = secpolicy_vnode_setdac(cr, owner);
+
+ if (error == 0 && (working_mode &
+ (ACE_DELETE|ACE_DELETE_CHILD)))
+ error = secpolicy_vnode_remove(cr);
+
+ if (error == 0 && (working_mode & ACE_SYNCHRONIZE))
+ error = secpolicy_vnode_owner(cr, owner);
+
+ if (error == 0) {
+ /*
+ * See if any bits other than those already checked
+ * for are still present. If so then return EACCES
+ */
+ if (working_mode & ~(ZFS_CHECKED_MASKS)) {
+ error = EACCES;
+ }
+ }
}
if (is_attr)
@@ -1413,38 +2428,36 @@ zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
}
/*
- * Special zaccess function to check for special nfsv4 perm.
- * doesn't call secpolicy_vnode_access() for failure, since that
- * would probably be the wrong policy function to call.
- * instead its up to the caller to handle that situation.
+ * Translate traditional unix VREAD/VWRITE/VEXEC mode into
+ * native ACL format and call zfs_zaccess()
*/
-
int
-zfs_zaccess_v4_perm(znode_t *zp, int mode, cred_t *cr)
+zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
{
- int working_mode = 0;
- return (zfs_zaccess_common(zp, mode, &working_mode, cr));
+ return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
}
/*
- * Translate tradition unix VREAD/VWRITE/VEXEC mode into
- * native ACL format and call zfs_zaccess()
+ * Access function for secpolicy_vnode_setattr
*/
int
-zfs_zaccess_rwx(znode_t *zp, mode_t mode, cred_t *cr)
+zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
{
int v4_mode = zfs_unix_to_v4(mode >> 6);
- return (zfs_zaccess(zp, v4_mode, cr));
+ return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
}
static int
zfs_delete_final_check(znode_t *zp, znode_t *dzp, cred_t *cr)
{
int error;
+ uid_t downer;
+ zfsvfs_t *zfsvfs = zp->z_zfsvfs;
+
+ zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, ZFS_OWNER, &downer);
- error = secpolicy_vnode_access(cr, ZTOV(zp),
- dzp->z_phys->zp_uid, S_IWRITE|S_IEXEC);
+ error = secpolicy_vnode_access(cr, ZTOV(zp), downer, S_IWRITE|S_IEXEC);
if (error == 0)
error = zfs_sticky_remove_access(dzp, zp, cr);
@@ -1490,9 +2503,11 @@ zfs_delete_final_check(znode_t *zp, znode_t *dzp, cred_t *cr)
int
zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
{
- int dzp_working_mode = 0;
- int zp_working_mode = 0;
+ uint32_t dzp_working_mode = 0;
+ uint32_t zp_working_mode = 0;
int dzp_error, zp_error;
+ boolean_t dzpcheck_privs = B_TRUE;
+ boolean_t zpcheck_privs = B_TRUE;
/*
* Arghh, this check is going to require a couple of questions
@@ -1505,11 +2520,16 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
* by secpolicy_vnode_access().
*/
+ if (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
+ return (EPERM);
+
dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
- &dzp_working_mode, cr);
- zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, cr);
+ &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
+ zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
+ &zpcheck_privs, B_FALSE, cr);
- if (dzp_error == EROFS || zp_error == EROFS)
+ if ((dzp_error && dzpcheck_privs == B_FALSE) ||
+ (zp_error && zpcheck_privs == B_FALSE))
return (dzp_error);
/*
@@ -1550,9 +2570,9 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
*/
dzp_error = zfs_zaccess_common(dzp, ACE_WRITE_DATA|ACE_EXECUTE,
- &dzp_working_mode, cr);
+ &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
- if (dzp_error == EROFS)
+ if (dzp_error && dzpcheck_privs == B_FALSE)
return (dzp_error);
if ((dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE)) == 0)
@@ -1576,6 +2596,9 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
int add_perm;
int error;
+ if (szp->z_phys->zp_flags & ZFS_AV_QUARANTINED)
+ return (EACCES);
+
add_perm = (ZTOV(szp)->v_type == VDIR) ?
ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
@@ -1604,7 +2627,7 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
/*
* Now check for add permissions
*/
- error = zfs_zaccess(tdzp, add_perm, cr);
+ error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
return (error);
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_byteswap.c b/usr/src/uts/common/fs/zfs/zfs_byteswap.c
index c8450d488b..ab97f83eb0 100644
--- a/usr/src/uts/common/fs/zfs/zfs_byteswap.c
+++ b/usr/src/uts/common/fs/zfs/zfs_byteswap.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,7 +32,7 @@
#include <sys/zfs_acl.h>
void
-zfs_ace_byteswap(ace_t *ace, int ace_cnt)
+zfs_oldace_byteswap(ace_t *ace, int ace_cnt)
{
int i;
@@ -45,9 +44,74 @@ zfs_ace_byteswap(ace_t *ace, int ace_cnt)
}
}
+/*
+ * swap ace_t and ace_oject_t
+ */
+void
+zfs_ace_byteswap(void *buf, size_t size, boolean_t zfs_layout)
+{
+ caddr_t end;
+ caddr_t ptr;
+ zfs_ace_t *zacep;
+ ace_t *acep;
+ uint16_t entry_type;
+ size_t entry_size;
+ int ace_type;
+
+ end = (caddr_t)buf + size;
+ ptr = buf;
+
+ while (ptr < end) {
+ if (zfs_layout) {
+ zacep = (zfs_ace_t *)ptr;
+ zacep->z_hdr.z_access_mask =
+ BSWAP_32(zacep->z_hdr.z_access_mask);
+ zacep->z_hdr.z_flags = BSWAP_16(zacep->z_hdr.z_flags);
+ ace_type = zacep->z_hdr.z_type =
+ BSWAP_16(zacep->z_hdr.z_type);
+ entry_type = zacep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+ } else {
+ acep = (ace_t *)ptr;
+ acep->a_access_mask = BSWAP_32(acep->a_access_mask);
+ acep->a_flags = BSWAP_16(acep->a_flags);
+ ace_type = acep->a_type = BSWAP_16(acep->a_type);
+ acep->a_who = BSWAP_32(acep->a_who);
+ entry_type = acep->a_flags & ACE_TYPE_FLAGS;
+ }
+ switch (entry_type) {
+ case ACE_OWNER:
+ case ACE_EVERYONE:
+ case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
+ entry_size = zfs_layout ?
+ sizeof (zfs_ace_hdr_t) : sizeof (ace_t);
+ break;
+ case ACE_IDENTIFIER_GROUP:
+ default:
+ if (zfs_layout) {
+ zacep->z_fuid = BSWAP_64(zacep->z_fuid);
+ }
+ switch (ace_type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ entry_size = zfs_layout ?
+ sizeof (zfs_object_ace_t) :
+ sizeof (ace_object_t);
+ break;
+ default:
+ entry_size = zfs_layout ? sizeof (zfs_ace_t) :
+ sizeof (ace_t);
+ break;
+ }
+ }
+ ptr = ptr + entry_size;
+ }
+}
+
/* ARGSUSED */
void
-zfs_acl_byteswap(void *buf, size_t size)
+zfs_oldacl_byteswap(void *buf, size_t size)
{
int cnt;
@@ -58,7 +122,14 @@ zfs_acl_byteswap(void *buf, size_t size)
cnt = size / sizeof (ace_t);
- zfs_ace_byteswap((ace_t *)buf, cnt);
+ zfs_oldace_byteswap((ace_t *)buf, cnt);
+}
+
+/* ARGSUSED */
+void
+zfs_acl_byteswap(void *buf, size_t size)
+{
+ zfs_ace_byteswap(buf, size, B_TRUE);
}
void
@@ -86,14 +157,19 @@ zfs_znode_byteswap(void *buf, size_t size)
zp->zp_flags = BSWAP_64(zp->zp_flags);
zp->zp_uid = BSWAP_64(zp->zp_uid);
zp->zp_gid = BSWAP_64(zp->zp_gid);
+ zp->zp_zap = BSWAP_64(zp->zp_zap);
zp->zp_pad[0] = BSWAP_64(zp->zp_pad[0]);
zp->zp_pad[1] = BSWAP_64(zp->zp_pad[1]);
zp->zp_pad[2] = BSWAP_64(zp->zp_pad[2]);
- zp->zp_pad[3] = BSWAP_64(zp->zp_pad[3]);
zp->zp_acl.z_acl_extern_obj = BSWAP_64(zp->zp_acl.z_acl_extern_obj);
- zp->zp_acl.z_acl_count = BSWAP_32(zp->zp_acl.z_acl_count);
+ zp->zp_acl.z_acl_size = BSWAP_32(zp->zp_acl.z_acl_size);
zp->zp_acl.z_acl_version = BSWAP_16(zp->zp_acl.z_acl_version);
- zp->zp_acl.z_acl_pad = BSWAP_16(zp->zp_acl.z_acl_pad);
- zfs_ace_byteswap(&zp->zp_acl.z_ace_data[0], ACE_SLOT_CNT);
+ zp->zp_acl.z_acl_count = BSWAP_16(zp->zp_acl.z_acl_count);
+ if (zp->zp_acl.z_acl_version == ZFS_ACL_VERSION) {
+ zfs_acl_byteswap((void *)&zp->zp_acl.z_ace_data[0],
+ ZFS_ACE_SPACE);
+ } else
+ zfs_oldace_byteswap((ace_t *)&zp->zp_acl.z_ace_data[0],
+ ACE_SLOT_CNT);
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_ctldir.c b/usr/src/uts/common/fs/zfs/zfs_ctldir.c
index 3b2cc409e0..b272d16ddb 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ctldir.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ctldir.c
@@ -243,7 +243,7 @@ zfsctl_root(znode_t *zp)
*/
/* ARGSUSED */
static int
-zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr)
+zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
{
if (flags & FWRITE)
return (EACCES);
@@ -257,7 +257,7 @@ zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr)
/* ARGSUSED */
static int
zfsctl_common_close(vnode_t *vpp, int flags, int count, offset_t off,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
return (0);
}
@@ -267,7 +267,8 @@ zfsctl_common_close(vnode_t *vpp, int flags, int count, offset_t off,
*/
/* ARGSUSED */
static int
-zfsctl_common_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+zfsctl_common_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
if (mode & VWRITE)
return (EACCES);
@@ -306,8 +307,9 @@ zfsctl_common_getattr(vnode_t *vp, vattr_t *vap)
vap->va_mtime = vap->va_ctime = zcp->zc_cmtime;
}
+/*ARGSUSED*/
static int
-zfsctl_common_fid(vnode_t *vp, fid_t *fidp)
+zfsctl_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
zfsctl_node_t *zcp = vp->v_data;
@@ -357,7 +359,8 @@ zfsctl_common_fid(vnode_t *vp, fid_t *fidp)
*/
/* ARGSUSED */
static int
-zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
@@ -377,17 +380,24 @@ zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
int
zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
int err;
+ /*
+ * No extended attributes allowed under .zfs
+ */
+ if (flags & LOOKUP_XATTR)
+ return (EINVAL);
+
ZFS_ENTER(zfsvfs);
if (strcmp(nm, "..") == 0) {
err = VFS_ROOT(dvp->v_vfsp, vpp);
} else {
- err = gfs_dir_lookup(dvp, nm, vpp);
+ err = gfs_dir_lookup(dvp, nm, vpp, cr);
}
ZFS_EXIT(zfsvfs);
@@ -449,7 +459,7 @@ zfsctl_unmount_snap(vnode_t *dvp, const char *name, int force, cred_t *cr)
return (err);
}
ASSERT(sep->se_root->v_count == 1);
- gfs_vop_inactive(sep->se_root, cr);
+ gfs_vop_inactive(sep->se_root, cr, NULL);
avl_remove(&sdp->sd_snaps, sep);
kmem_free(sep->se_name, strlen(sep->se_name) + 1);
@@ -512,9 +522,10 @@ zfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm)
vfs_unlock(vfsp);
}
+/*ARGSUSED*/
static int
zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
zfsctl_snapdir_t *sdp = sdvp->v_data;
zfs_snapentry_t search, *sep;
@@ -560,7 +571,8 @@ zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
/* ARGSUSED */
static int
-zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
+zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr,
+ caller_context_t *ct, int flags)
{
zfsctl_snapdir_t *sdp = dvp->v_data;
char snapname[MAXNAMELEN];
@@ -594,7 +606,7 @@ zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
/* ARGSUSED */
static int
zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp)
{
zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
char name[MAXNAMELEN];
@@ -628,7 +640,8 @@ zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
/* ARGSUSED */
static int
zfsctl_snapdir_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
zfsctl_snapdir_t *sdp = dvp->v_data;
objset_t *snap;
@@ -642,6 +655,12 @@ zfsctl_snapdir_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
int err;
+ /*
+ * No extended attributes allowed under .zfs
+ */
+ if (flags & LOOKUP_XATTR)
+ return (EINVAL);
+
ASSERT(dvp->v_type == VDIR);
if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0)
@@ -814,7 +833,8 @@ zfsctl_mknode_snapdir(vnode_t *pvp)
/* ARGSUSED */
static int
-zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
zfsctl_snapdir_t *sdp = vp->v_data;
@@ -830,7 +850,7 @@ zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
static void
-zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr)
+zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
zfsctl_snapdir_t *sdp = vp->v_data;
void *private;
@@ -883,13 +903,13 @@ zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset)
}
static void
-zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr)
+zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
zfsctl_snapdir_t *sdp;
zfs_snapentry_t *sep, *next;
vnode_t *dvp;
- VERIFY(gfs_dir_lookup(vp, "..", &dvp) == 0);
+ VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr) == 0);
sdp = dvp->v_data;
mutex_enter(&sdp->sd_lock);
@@ -924,7 +944,7 @@ zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr)
* "active". If we lookup the same name again we will end up
* creating a new vnode.
*/
- gfs_vop_inactive(vp, cr);
+ gfs_vop_inactive(vp, cr, ct);
}
@@ -949,7 +969,7 @@ zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp)
ASSERT(zfsvfs->z_ctldir != NULL);
error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error != 0)
return (error);
sdp = dvp->v_data;
@@ -1008,7 +1028,7 @@ zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
ASSERT(zfsvfs->z_ctldir != NULL);
error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
- NULL, 0, NULL, cr);
+ NULL, 0, NULL, cr, NULL, NULL, NULL);
if (error != 0)
return (error);
sdp = dvp->v_data;
@@ -1046,7 +1066,7 @@ zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
* would lead to an attempt to re-grab the sd_lock.
*/
ASSERT3U(svp->v_count, ==, 1);
- gfs_vop_inactive(svp, cr);
+ gfs_vop_inactive(svp, cr, NULL);
}
sep = next;
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_dir.c b/usr/src/uts/common/fs/zfs/zfs_dir.c
index bcaa6fd4b5..8ae6a95e41 100644
--- a/usr/src/uts/common/fs/zfs/zfs_dir.c
+++ b/usr/src/uts/common/fs/zfs/zfs_dir.c
@@ -52,7 +52,51 @@
#include <sys/dmu.h>
#include <sys/atomic.h>
#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
#include <sys/dnlc.h>
+#include <sys/extdirent.h>
+#include <sys/zfs_i18n.h>
+
+/*
+ * zfs_match_find() is used by zfs_dirent_lock() to peform zap lookups
+ * of names after deciding which is the appropriate lookup interface.
+ */
+static int
+zfs_match_find(zfsvfs_t *zfsvfs, znode_t *dzp, char *name, boolean_t exact,
+ boolean_t update, int *deflags, pathname_t *rpnp, uint64_t *zoid)
+{
+ int error;
+
+ if (zfsvfs->z_norm) {
+ matchtype_t mt = MT_FIRST;
+ boolean_t conflict = B_FALSE;
+ size_t bufsz = 0;
+ char *buf = NULL;
+
+ if (rpnp) {
+ buf = rpnp->pn_path;
+ bufsz = rpnp->pn_bufsize;
+ }
+ if (exact)
+ mt = MT_EXACT;
+ /*
+ * In the non-mixed case we only expect there would ever
+ * be one match, but we need to use the normalizing lookup.
+ */
+ error = zap_lookup_norm(zfsvfs->z_os, dzp->z_id, name, 8, 1,
+ zoid, mt, buf, bufsz, &conflict);
+ if (deflags)
+ *deflags = conflict ? ED_CASE_CONFLICT : 0;
+ } else {
+ error = zap_lookup(zfsvfs->z_os, dzp->z_id, name, 8, 1, zoid);
+ }
+ *zoid = ZFS_DIRENT_OBJ(*zoid);
+
+ if (error == ENOENT && update)
+ dnlc_update(ZTOV(dzp), name, DNLC_NO_VNODE);
+
+ return (error);
+}
/*
* Lock a directory entry. A dirlock on <dzp, name> protects that name
@@ -67,24 +111,38 @@
* ZEXISTS: if the entry does not exist, fail with ENOENT.
* ZSHARED: allow concurrent access with other ZSHARED callers.
* ZXATTR: we want dzp's xattr directory
+ * ZCILOOK: On a mixed sensitivity file system,
+ * this lookup should be case-insensitive.
+ * ZCIEXACT: On a purely case-insensitive file system,
+ * this lookup should be case-sensitive.
+ * ZRENAMING: we are locking for renaming, force narrow locks
*
* Output arguments:
* zpp - pointer to the znode for the entry (NULL if there isn't one)
* dlpp - pointer to the dirlock for this entry (NULL on error)
+ * direntflags - (case-insensitive lookup only)
+ * flags if multiple case-sensitive matches exist in directory
+ * realpnp - (case-insensitive lookup only)
+ * actual name matched within the directory
*
* Return value: 0 on success or errno on failure.
*
* NOTE: Always checks for, and rejects, '.' and '..'.
+ * NOTE: For case-insensitive file systems we take wide locks (see below),
+ * but return znode pointers to a single match.
*/
int
zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
- int flag)
+ int flag, int *direntflags, pathname_t *realpnp)
{
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
zfs_dirlock_t *dl;
+ boolean_t update;
+ boolean_t exact;
uint64_t zoid;
- int error;
- vnode_t *vp;
+ vnode_t *vp = NULL;
+ int error = 0;
+ int cmpflags;
*zpp = NULL;
*dlpp = NULL;
@@ -98,6 +156,58 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
return (EEXIST);
/*
+ * Case sensitivity and normalization preferences are set when
+ * the file system is created. These are stored in the
+ * zfsvfs->z_case and zfsvfs->z_norm fields. These choices
+ * affect what vnodes can be cached in the DNLC, how we
+ * perform zap lookups, and the "width" of our dirlocks.
+ *
+ * A normal dirlock locks a single name. Note that with
+ * normalization a name can be composed multiple ways, but
+ * when normalized, these names all compare equal. A wide
+ * dirlock locks multiple names. We need these when the file
+ * system is supporting mixed-mode access. It is sometimes
+ * necessary to lock all case permutations of file name at
+ * once so that simultaneous case-insensitive/case-sensitive
+ * behaves as rationally as possible.
+ */
+
+ /*
+ * Decide if exact matches should be requested when performing
+ * a zap lookup on file systems supporting case-insensitive
+ * access.
+ */
+ exact = ((zfsvfs->z_case & ZFS_CI_ONLY) && (flag & ZCIEXACT)) ||
+ ((zfsvfs->z_case & ZFS_CI_MIXD) && !(flag & ZCILOOK));
+
+ /*
+ * Only look in or update the DNLC if we are looking for the
+ * name on a file system that does not require normalization
+ * or case folding. We can also look there if we happen to be
+ * on a non-normalizing, mixed sensitivity file system IF we
+ * are looking for the exact name.
+ *
+ * Maybe can add TO-UPPERed version of name to dnlc in ci-only
+ * case for performance improvement?
+ */
+ update = !zfsvfs->z_norm ||
+ ((zfsvfs->z_case & ZFS_CI_MIXD) &&
+ !(zfsvfs->z_norm & ~U8_TEXTPREP_TOUPPER) && !(flag & ZCILOOK));
+
+ /*
+ * ZRENAMING indicates we are in a situation where we should
+ * take narrow locks regardless of the file system's
+ * preferences for normalizing and case folding. This will
+ * prevent us deadlocking trying to grab the same wide lock
+ * twice if the two names happen to be case-insensitive
+ * matches.
+ */
+ if (flag & ZRENAMING)
+ cmpflags = 0;
+ else
+ cmpflags = zfsvfs->z_norm;
+
+ /*
* Wait until there are no locks on this name.
*/
rw_enter(&dzp->z_name_lock, RW_READER);
@@ -108,9 +218,16 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
rw_exit(&dzp->z_name_lock);
return (ENOENT);
}
- for (dl = dzp->z_dirlocks; dl != NULL; dl = dl->dl_next)
- if (strcmp(name, dl->dl_name) == 0)
+ for (dl = dzp->z_dirlocks; dl != NULL; dl = dl->dl_next) {
+ if ((u8_strcmp(name, dl->dl_name, 0, cmpflags,
+ U8_UNICODE_LATEST, &error) == 0) || error != 0)
break;
+ }
+ if (error != 0) {
+ mutex_exit(&dzp->z_lock);
+ rw_exit(&dzp->z_name_lock);
+ return (ENOENT);
+ }
if (dl == NULL) {
/*
* Allocate a new dirlock and add it to the list.
@@ -156,7 +273,8 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
zoid = dzp->z_phys->zp_xattr;
error = (zoid == 0 ? ENOENT : 0);
} else {
- vp = dnlc_lookup(ZTOV(dzp), name);
+ if (update)
+ vp = dnlc_lookup(ZTOV(dzp), name);
if (vp == DNLC_NO_VNODE) {
VN_RELE(vp);
error = ENOENT;
@@ -170,11 +288,8 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
*zpp = VTOZ(vp);
return (0);
} else {
- error = zap_lookup(zfsvfs->z_os, dzp->z_id, name,
- 8, 1, &zoid);
- zoid = ZFS_DIRENT_OBJ(zoid);
- if (error == ENOENT)
- dnlc_update(ZTOV(dzp), name, DNLC_NO_VNODE);
+ error = zfs_match_find(zfsvfs, dzp, name, exact,
+ update, direntflags, realpnp, &zoid);
}
}
if (error) {
@@ -192,7 +307,7 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
zfs_dirent_unlock(dl);
return (error);
}
- if (!(flag & ZXATTR))
+ if (!(flag & ZXATTR) && update)
dnlc_update(ZTOV(dzp), name, ZTOV(*zpp));
}
@@ -239,7 +354,8 @@ zfs_dirent_unlock(zfs_dirlock_t *dl)
* special pseudo-directory.
*/
int
-zfs_dirlook(znode_t *dzp, char *name, vnode_t **vpp)
+zfs_dirlook(znode_t *dzp, char *name, vnode_t **vpp, int flags,
+ int *deflg, pathname_t *rpnp)
{
zfs_dirlock_t *dl;
znode_t *zp;
@@ -257,7 +373,8 @@ zfs_dirlook(znode_t *dzp, char *name, vnode_t **vpp)
if (dzp->z_phys->zp_parent == dzp->z_id &&
zfsvfs->z_parent != zfsvfs) {
error = zfsctl_root_lookup(zfsvfs->z_parent->z_ctldir,
- "snapshot", vpp, NULL, 0, NULL, kcred);
+ "snapshot", vpp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL);
return (error);
}
rw_enter(&dzp->z_parent_lock, RW_READER);
@@ -268,14 +385,24 @@ zfs_dirlook(znode_t *dzp, char *name, vnode_t **vpp)
} else if (zfs_has_ctldir(dzp) && strcmp(name, ZFS_CTLDIR_NAME) == 0) {
*vpp = zfsctl_root(dzp);
} else {
- error = zfs_dirent_lock(&dl, dzp, name, &zp, ZEXISTS | ZSHARED);
+ int zf;
+
+ zf = ZEXISTS | ZSHARED;
+ if (flags & FIGNORECASE)
+ zf |= ZCILOOK;
+
+ error = zfs_dirent_lock(&dl, dzp, name, &zp, zf, deflg, rpnp);
if (error == 0) {
*vpp = ZTOV(zp);
zfs_dirent_unlock(dl);
dzp->z_zn_prefetch = B_TRUE; /* enable prefetching */
}
+ rpnp = NULL;
}
+ if ((flags & FIGNORECASE) && rpnp)
+ (void) strlcpy(rpnp->pn_path, name, rpnp->pn_bufsize);
+
return (error);
}
@@ -633,7 +760,20 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
zfs_time_stamper_locked(dzp, CONTENT_MODIFIED, tx);
mutex_exit(&dzp->z_lock);
- error = zap_remove(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, tx);
+ if (zp->z_zfsvfs->z_norm) {
+ if (((zp->z_zfsvfs->z_case & ZFS_CI_ONLY) &&
+ (flag & ZCIEXACT)) ||
+ ((zp->z_zfsvfs->z_case & ZFS_CI_MIXD) &&
+ !(flag & ZCILOOK)))
+ error = zap_remove_norm(zp->z_zfsvfs->z_os,
+ dzp->z_id, dl->dl_name, MT_EXACT, tx);
+ else
+ error = zap_remove_norm(zp->z_zfsvfs->z_os,
+ dzp->z_id, dl->dl_name, MT_FIRST, tx);
+ } else {
+ error = zap_remove(zp->z_zfsvfs->z_os,
+ dzp->z_id, dl->dl_name, tx);
+ }
ASSERT(error == 0);
if (unlinkedp != NULL)
@@ -663,15 +803,24 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr)
dmu_tx_t *tx;
uint64_t xoid;
int error;
+ zfs_fuid_info_t *fuidp = NULL;
*xvpp = NULL;
- if (error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, cr))
+ if (error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr))
return (error);
tx = dmu_tx_create(zfsvfs->z_os);
dmu_tx_hold_bonus(tx, zp->z_id);
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0, SPA_MAXBLOCKSIZE);
+ }
error = dmu_tx_assign(tx, zfsvfs->z_assign);
if (error) {
if (error == ERESTART && zfsvfs->z_assign == TXG_NOWAIT)
@@ -679,13 +828,16 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr)
dmu_tx_abort(tx);
return (error);
}
- zfs_mknode(zp, vap, &xoid, tx, cr, IS_XATTR, &xzp, 0);
+ zfs_mknode(zp, vap, &xoid, tx, cr, IS_XATTR, &xzp, 0, NULL, &fuidp);
ASSERT(xzp->z_id == xoid);
ASSERT(xzp->z_phys->zp_parent == zp->z_id);
dmu_buf_will_dirty(zp->z_dbuf, tx);
zp->z_phys->zp_xattr = xoid;
- (void) zfs_log_create(zfsvfs->z_log, tx, TX_MKXATTR, zp, xzp, "");
+ (void) zfs_log_create(zfsvfs->z_log, tx, TX_MKXATTR, zp,
+ xzp, "", NULL, fuidp, vap);
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
dmu_tx_commit(tx);
*xvpp = ZTOV(xzp);
@@ -715,7 +867,7 @@ zfs_get_xattrdir(znode_t *zp, vnode_t **xvpp, cred_t *cr, int flags)
vattr_t va;
int error;
top:
- error = zfs_dirent_lock(&dl, zp, "", &xzp, ZXATTR);
+ error = zfs_dirent_lock(&dl, zp, "", &xzp, ZXATTR, NULL, NULL);
if (error)
return (error);
@@ -750,8 +902,7 @@ top:
va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
va.va_type = VDIR;
va.va_mode = S_IFDIR | S_ISVTX | 0777;
- va.va_uid = (uid_t)zp->z_phys->zp_uid;
- va.va_gid = (gid_t)zp->z_phys->zp_gid;
+ zfs_fuid_map_ids(zp, &va.va_uid, &va.va_gid);
error = zfs_make_xattrdir(zp, &va, xvpp, cr);
zfs_dirent_unlock(dl);
@@ -781,15 +932,22 @@ int
zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr)
{
uid_t uid;
+ uid_t downer;
+ uid_t fowner;
+ zfsvfs_t *zfsvfs = zdp->z_zfsvfs;
if (zdp->z_zfsvfs->z_assign >= TXG_INITIAL) /* ZIL replay */
return (0);
- if ((zdp->z_phys->zp_mode & S_ISVTX) == 0 ||
- (uid = crgetuid(cr)) == zdp->z_phys->zp_uid ||
- uid == zp->z_phys->zp_uid ||
+ if ((zdp->z_phys->zp_mode & S_ISVTX) == 0)
+ return (0);
+
+ zfs_fuid_map_id(zfsvfs, zdp->z_phys->zp_uid, ZFS_OWNER, &downer);
+ zfs_fuid_map_id(zfsvfs, zp->z_phys->zp_uid, ZFS_OWNER, &fowner);
+
+ if ((uid = crgetuid(cr)) == downer || uid == fowner ||
(ZTOV(zp)->v_type == VREG &&
- zfs_zaccess(zp, ACE_WRITE_DATA, cr) == 0))
+ zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0))
return (0);
else
return (secpolicy_vnode_remove(cr));
diff --git a/usr/src/uts/common/fs/zfs/zfs_fuid.c b/usr/src/uts/common/fs/zfs/zfs_fuid.c
new file mode 100644
index 0000000000..3eb7d56611
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/zfs_fuid.c
@@ -0,0 +1,724 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/unistd.h>
+#include <sys/sysmacros.h>
+#include <sys/sunddi.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_fuid.h>
+#include <sys/dmu.h>
+#include <sys/refcount.h>
+#include <sys/avl.h>
+#include <sys/zap.h>
+#include <sys/nvpair.h>
+#include <sys/kidmap.h>
+#include <sys/sid.h>
+
+/*
+ * FUID Domain table(s).
+ *
+ * The FUID table is stored as a packed nvlist of an array
+ * of nvlists which contain an index, domain string and offset
+ *
+ * During file system initialization the nvlist(s) are read and
+ * two AVL trees are created. One tree is keyed by the index number
+ * and the other by the domain string. Nodes are never removed from
+ * trees, but new entries may be added. If a new entry is added then the
+ * on-disk packed nvlist will also be updated.
+ */
+
+#define FUID_IDX "fuid_idx"
+#define FUID_DOMAIN "fuid_domain"
+#define FUID_OFFSET "fuid_offset"
+#define FUID_NVP_ARRAY "fuid_nvlist"
+
+typedef struct fuid_domain {
+ avl_node_t f_node;
+ ksiddomain_t *f_ksid;
+ int f_idx;
+ uint32_t f_offset;
+} fuid_domain_t;
+
+typedef struct fuid_idx {
+ avl_node_t f_node;
+ int f_idx;
+ fuid_domain_t *f_domain;
+} fuid_idx_t;
+
+/*
+ * Compare two indexes.
+ */
+static int
+idx_compare(const void *arg1, const void *arg2)
+{
+ const fuid_idx_t *node1 = arg1;
+ const fuid_idx_t *node2 = arg2;
+
+ if (node1->f_idx < node2->f_idx)
+ return (-1);
+ else if (node1->f_idx > node2->f_idx)
+ return (1);
+ return (0);
+}
+
+/*
+ * Compare two domain strings.
+ */
+static int
+domain_compare(const void *arg1, const void *arg2)
+{
+ const fuid_domain_t *node1 = arg1;
+ const fuid_domain_t *node2 = arg2;
+ int val;
+
+ val = strcmp(node1->f_ksid->kd_name, node2->f_ksid->kd_name);
+ if (val == 0)
+ return (0);
+ return (val > 0 ? 1 : -1);
+}
+
+/*
+ * Load the fuid table(s) into memory.
+ */
+static void
+zfs_fuid_init(zfsvfs_t *zfsvfs, dmu_tx_t *tx)
+{
+ dmu_buf_t *db;
+ char *packed;
+ size_t nvsize = 0;
+ int error = 0;
+ int i;
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
+
+ if (zfsvfs->z_fuid_loaded) {
+ rw_exit(&zfsvfs->z_fuid_lock);
+ return;
+ }
+
+ if (zfsvfs->z_fuid_obj == 0) {
+
+ /* first make sure we need to allocate object */
+
+ error = zap_lookup(zfsvfs->z_os, MASTER_NODE_OBJ,
+ ZFS_FUID_TABLES, 8, 1, &zfsvfs->z_fuid_obj);
+ if (error == ENOENT && tx != NULL) {
+ zfsvfs->z_fuid_obj = dmu_object_alloc(zfsvfs->z_os,
+ DMU_OT_FUID, 1 << 14, DMU_OT_FUID_SIZE,
+ sizeof (uint64_t), tx);
+ VERIFY(zap_add(zfsvfs->z_os, MASTER_NODE_OBJ,
+ ZFS_FUID_TABLES, sizeof (uint64_t), 1,
+ &zfsvfs->z_fuid_obj, tx) == 0);
+ }
+ }
+
+ avl_create(&zfsvfs->z_fuid_idx, idx_compare,
+ sizeof (fuid_idx_t), offsetof(fuid_idx_t, f_node));
+ avl_create(&zfsvfs->z_fuid_domain, domain_compare,
+ sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_node));
+
+ if (zfsvfs->z_fuid_obj) {
+ VERIFY(0 == dmu_bonus_hold(zfsvfs->z_os, zfsvfs->z_fuid_obj,
+ FTAG, &db));
+ nvsize = *(uint64_t *)db->db_data;
+ dmu_buf_rele(db, FTAG);
+ }
+
+ if (nvsize == 0)
+ goto initialized;
+
+ packed = kmem_alloc(nvsize, KM_SLEEP);
+ error = dmu_read(zfsvfs->z_os, zfsvfs->z_fuid_obj, 0, nvsize, packed);
+ if (error == 0) {
+ nvlist_t **fuidnvp;
+ nvlist_t *nvp = NULL;
+ uint_t count;
+
+ VERIFY(nvlist_unpack(packed, nvsize, &nvp, 0) == 0);
+ VERIFY((error = nvlist_lookup_nvlist_array(nvp, FUID_NVP_ARRAY,
+ &fuidnvp, &count)) == 0);
+
+ for (i = 0; i != count; i++) {
+ fuid_idx_t *idxnode;
+ fuid_domain_t *domnode;
+ char *domain;
+ avl_index_t loc;
+ uint64_t idx, offset;
+
+ VERIFY(nvlist_lookup_string(fuidnvp[i], FUID_DOMAIN,
+ &domain) == 0);
+ VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_IDX,
+ &idx) == 0);
+ VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_OFFSET,
+ &offset) == 0);
+
+ idxnode = kmem_alloc(sizeof (fuid_idx_t), KM_SLEEP);
+ domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
+
+ domnode->f_idx = idxnode->f_idx = idx;
+ domnode->f_ksid = ksid_lookupdomain(domain);
+ idxnode->f_domain = domnode;
+ domnode->f_offset = offset;
+ if (avl_find(&zfsvfs->z_fuid_idx,
+ idxnode, &loc) == NULL) {
+ avl_insert(&zfsvfs->z_fuid_idx, idxnode, loc);
+ }
+ if (avl_find(&zfsvfs->z_fuid_domain,
+ domnode, &loc) == NULL) {
+ avl_insert(&zfsvfs->z_fuid_domain,
+ domnode, loc);
+ }
+ }
+ nvlist_free(nvp);
+ }
+ kmem_free(packed, nvsize);
+
+initialized:
+ zfsvfs->z_fuid_loaded = B_TRUE;
+ rw_exit(&zfsvfs->z_fuid_lock);
+}
+
+/*
+ * Query domain table for a given domain.
+ *
+ * If domain isn't found it is added to AVL trees and
+ * the results are pushed out to disk.
+ */
+int
+zfs_fuid_find_by_domain(zfsvfs_t *zfsvfs, const char *domain, char **retdomain,
+ dmu_tx_t *tx)
+{
+ fuid_domain_t searchnode, *findnode;
+ avl_index_t loc;
+
+ searchnode.f_ksid = ksid_lookupdomain(domain);
+ if (retdomain) {
+ *retdomain = searchnode.f_ksid->kd_name;
+ }
+ if (zfsvfs->z_fuid_loaded == B_FALSE)
+ zfs_fuid_init(zfsvfs, tx);
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_READER);
+ findnode = avl_find(&zfsvfs->z_fuid_domain, &searchnode, &loc);
+ rw_exit(&zfsvfs->z_fuid_lock);
+
+ if (findnode) {
+ ksiddomain_rele(searchnode.f_ksid);
+ return (findnode->f_idx);
+ } else {
+ fuid_domain_t *domnode;
+ fuid_idx_t *newidxnode;
+ nvlist_t *nvp;
+ nvlist_t **fuids;
+ uint64_t retidx;
+ size_t nvsize = 0;
+ char *packed;
+ dmu_buf_t *db;
+ int i = 0;
+
+ domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
+ domnode->f_ksid = searchnode.f_ksid;
+ domnode->f_offset = 0;
+
+ newidxnode = kmem_alloc(sizeof (fuid_idx_t), KM_SLEEP);
+ newidxnode->f_domain = domnode;
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
+ retidx = domnode->f_idx = newidxnode->f_idx =
+ avl_numnodes(&zfsvfs->z_fuid_idx) + 1;
+
+ avl_add(&zfsvfs->z_fuid_domain, domnode);
+ avl_add(&zfsvfs->z_fuid_idx, newidxnode);
+ /*
+ * Now resync the on-disk nvlist.
+ */
+ VERIFY(nvlist_alloc(&nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ domnode = avl_first(&zfsvfs->z_fuid_domain);
+ fuids = kmem_alloc(retidx * sizeof (void *), KM_SLEEP);
+ while (domnode) {
+ VERIFY(nvlist_alloc(&fuids[i],
+ NV_UNIQUE_NAME, KM_SLEEP) == 0);
+ VERIFY(nvlist_add_uint64(fuids[i], FUID_IDX,
+ domnode->f_idx) == 0);
+ VERIFY(nvlist_add_uint64(fuids[i], FUID_OFFSET,
+ domnode->f_offset) == 0);
+ VERIFY(nvlist_add_string(fuids[i++], FUID_DOMAIN,
+ domnode->f_ksid->kd_name) == 0);
+ domnode = AVL_NEXT(&zfsvfs->z_fuid_domain, domnode);
+ }
+ VERIFY(nvlist_add_nvlist_array(nvp, FUID_NVP_ARRAY,
+ fuids, retidx) == 0);
+ for (i = 0; i != retidx; i++)
+ nvlist_free(fuids[i]);
+ kmem_free(fuids, retidx * sizeof (void *));
+ VERIFY(nvlist_size(nvp, &nvsize, NV_ENCODE_XDR) == 0);
+ packed = kmem_alloc(nvsize, KM_SLEEP);
+ VERIFY(nvlist_pack(nvp, &packed, &nvsize,
+ NV_ENCODE_XDR, KM_SLEEP) == 0);
+ nvlist_free(nvp);
+ dmu_write(zfsvfs->z_os, zfsvfs->z_fuid_obj, 0, nvsize,
+ packed, tx);
+ kmem_free(packed, nvsize);
+ VERIFY(0 == dmu_bonus_hold(zfsvfs->z_os, zfsvfs->z_fuid_obj,
+ FTAG, &db));
+ dmu_buf_will_dirty(db, tx);
+ *(uint64_t *)db->db_data = nvsize;
+ dmu_buf_rele(db, FTAG);
+
+ rw_exit(&zfsvfs->z_fuid_lock);
+ return (retidx);
+ }
+}
+
+/*
+ * Query domain table by index, returning domain string
+ *
+ * Returns a pointer from an avl node of the domain string.
+ *
+ */
+char *
+zfs_fuid_find_by_idx(zfsvfs_t *zfsvfs, uint64_t idx)
+{
+ fuid_idx_t searchnode, *findnode;
+ avl_index_t loc;
+
+ if (idx == 0 || zfsvfs->z_use_fuids == B_FALSE)
+ return (NULL);
+
+ if (zfsvfs->z_fuid_loaded == B_FALSE)
+ zfs_fuid_init(zfsvfs, NULL);
+
+ searchnode.f_idx = idx;
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_READER);
+ findnode = avl_find(&zfsvfs->z_fuid_idx, &searchnode, &loc);
+ rw_exit(&zfsvfs->z_fuid_lock);
+
+ ASSERT(findnode);
+ return (findnode->f_domain->f_ksid->kd_name);
+}
+
+void
+zfs_fuid_get_mappings(zfs_fuid_hdl_t *hdl)
+{
+ VERIFY(hdl != NULL);
+ if (hdl->z_map_needed == B_FALSE)
+ return;
+
+ (void) kidmap_get_mappings(hdl->z_hdl);
+
+ kidmap_get_destroy(hdl->z_hdl);
+ hdl->z_hdl = NULL;
+ hdl->z_map_needed = B_FALSE;
+}
+
+void
+zfs_fuid_queue_map_id(zfsvfs_t *zfsvfs, zfs_fuid_hdl_t *hdl,
+ uint64_t fuid, zfs_fuid_type_t type, uid_t *id)
+{
+ uint32_t index = FUID_INDEX(fuid);
+ char *domain;
+ int status;
+
+ VERIFY(hdl);
+
+ if (index == 0 || zfsvfs->z_use_fuids == B_FALSE) {
+ *id = (uid_t)fuid;
+ return;
+ }
+
+ if (hdl->z_hdl == NULL) {
+ hdl->z_hdl = kidmap_get_create();
+ hdl->z_map_needed = B_TRUE;
+ }
+
+ domain = zfs_fuid_find_by_idx(zfsvfs, index);
+ ASSERT(domain != NULL);
+
+ if (type == ZFS_OWNER || type == ZFS_ACE_USER)
+ status = kidmap_batch_getuidbysid(hdl->z_hdl, domain,
+ FUID_RID(fuid), id, &hdl->z_status);
+ else
+ status = kidmap_batch_getgidbysid(hdl->z_hdl, domain,
+ FUID_RID(fuid), id, &hdl->z_status);
+ ASSERT(status == 0);
+}
+
+void
+zfs_fuid_map_ids(znode_t *zp, uid_t *uid, uid_t *gid)
+{
+ uint32_t uid_index = FUID_INDEX(zp->z_phys->zp_uid);
+ uint32_t gid_index = FUID_INDEX(zp->z_phys->zp_gid);
+
+ /* Favor the common case, neither will be ephemeral */
+ if (uid_index == 0 && gid_index == 0) {
+ *uid = zp->z_phys->zp_uid;
+ *gid = zp->z_phys->zp_gid;
+ return;
+ } else {
+ zfs_fuid_hdl_t hdl = { 0 };
+
+ zfs_fuid_queue_map_id(zp->z_zfsvfs, &hdl,
+ zp->z_phys->zp_uid, ZFS_OWNER, uid);
+
+ zfs_fuid_queue_map_id(zp->z_zfsvfs, &hdl,
+ zp->z_phys->zp_gid, ZFS_GROUP, gid);
+
+ zfs_fuid_get_mappings(&hdl);
+ }
+}
+
+void
+zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid,
+ zfs_fuid_type_t type, uid_t *id)
+{
+ uint32_t index = FUID_INDEX(fuid);
+ char *domain;
+
+ if (index == 0) {
+ *id = (uid_t)fuid;
+ return;
+ }
+
+ domain = zfs_fuid_find_by_idx(zfsvfs, index);
+ ASSERT(domain != NULL);
+
+ if (type == ZFS_OWNER || type == ZFS_ACE_USER)
+ (void) kidmap_getuidbysid(domain, FUID_RID(fuid), id);
+ else
+ (void) kidmap_getgidbysid(domain, FUID_RID(fuid), id);
+}
+
+/*
+ * Add a FUID node to the list of fuid's being created for this
+ * ACL
+ *
+ * If ACL has multiple domains, then keep only one copy of each unique
+ * domain.
+ */
+static void
+zfs_fuid_node_add(zfs_fuid_info_t **fuidpp, const char *domain, uint32_t rid,
+ uint64_t idx, uint64_t id, zfs_fuid_type_t type)
+{
+ zfs_fuid_t *fuid;
+ zfs_fuid_domain_t *fuid_domain;
+ zfs_fuid_info_t *fuidp;
+ uint64_t fuididx;
+ boolean_t found = B_FALSE;
+
+ if (*fuidpp == NULL)
+ *fuidpp = zfs_fuid_info_alloc();
+
+ fuidp = *fuidpp;
+ /*
+ * First find fuid domain index in linked list
+ *
+ * If one isn't found then create an entry.
+ */
+
+ for (fuididx = 1, fuid_domain = list_head(&fuidp->z_domains);
+ fuid_domain; fuid_domain = list_next(&fuidp->z_domains,
+ fuid_domain), fuididx++) {
+ if (idx == fuid_domain->z_domidx) {
+ found = B_TRUE;
+ break;
+ }
+ }
+
+ if (found == B_FALSE) {
+ fuid_domain = kmem_alloc(sizeof (zfs_fuid_domain_t), KM_SLEEP);
+ fuid_domain->z_domain = domain;
+ fuid_domain->z_domidx = idx;
+ list_insert_tail(&fuidp->z_domains, fuid_domain);
+ fuidp->z_domain_str_sz += strlen(domain) + 1;
+ fuidp->z_domain_cnt++;
+ }
+
+ if (type == ZFS_ACE_USER || type == ZFS_ACE_GROUP) {
+ /*
+ * Now allocate fuid entry and add it on the end of the list
+ */
+
+ fuid = kmem_alloc(sizeof (zfs_fuid_t), KM_SLEEP);
+ fuid->z_id = id;
+ fuid->z_domidx = idx;
+ fuid->z_logfuid = FUID_ENCODE(fuididx, rid);
+
+ list_insert_tail(&fuidp->z_fuids, fuid);
+ fuidp->z_fuid_cnt++;
+ } else {
+ if (type == ZFS_OWNER)
+ fuidp->z_fuid_owner = FUID_ENCODE(fuididx, rid);
+ else
+ fuidp->z_fuid_group = FUID_ENCODE(fuididx, rid);
+ }
+}
+
+/*
+ * Create a file system FUID
+ *
+ * During a replay operation the id will be incorrect and
+ * will be ignored. In this case replay must be true and the
+ * cred will have a ksid_t attached to it.
+ *
+ * A mapped uid/gid would have a ksid_t attached to the cred.
+ */
+uint64_t
+zfs_fuid_create_cred(zfsvfs_t *zfsvfs, uint64_t id,
+ zfs_fuid_type_t type, dmu_tx_t *tx, cred_t *cr, zfs_fuid_info_t **fuidp)
+{
+ uint64_t idx;
+ ksid_t *ksid;
+ uint32_t rid;
+ char *kdomain;
+ const char *domain;
+
+ VERIFY(type == ZFS_OWNER || type == ZFS_GROUP);
+
+ if (zfsvfs->z_use_fuids == B_FALSE || !IS_EPHEMERAL(id))
+ return ((uint64_t)id);
+
+ ksid = crgetsid(cr, (type == ZFS_OWNER) ? KSID_OWNER : KSID_GROUP);
+
+ VERIFY(ksid != NULL);
+ rid = ksid_getrid(ksid);
+ domain = ksid_getdomain(ksid);
+
+ idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, tx);
+
+ zfs_fuid_node_add(fuidp, kdomain, rid, idx, id, type);
+
+ return (FUID_ENCODE(idx, rid));
+}
+
+/*
+ * Create a file system FUID for an ACL ace
+ * or a chown/chgrp of the file.
+ * This is similar to zfs_fuid_create_cred, except that
+ * we can't find the domain + rid information in the
+ * cred. Instead we have to query Winchester for the
+ * domain and rid.
+ */
+uint64_t
+zfs_fuid_create(zfsvfs_t *zfsvfs, uint64_t id,
+ zfs_fuid_type_t type, dmu_tx_t *tx, zfs_fuid_info_t **fuidpp)
+{
+ const char *domain;
+ char *kdomain;
+ uint32_t fuid_idx = FUID_INDEX(id);
+ uint32_t rid;
+ idmap_stat status;
+ uint64_t idx;
+ boolean_t is_replay = (zfsvfs->z_assign >= TXG_INITIAL);
+ zfs_fuid_t *zfuid = NULL;
+ zfs_fuid_info_t *fuidp;
+
+ /*
+ * If POSIX ID, or entry is already a FUID then
+ * just return the id
+ */
+ if (!IS_EPHEMERAL(id) || fuid_idx != 0)
+ return (id);
+
+ if (is_replay) {
+ fuidp = zfsvfs->z_fuid_replay;
+
+ /*
+ * If we are passed an ephemeral id, but no
+ * fuid_info was logged then return NOBODY.
+ * This is most likely a result of idmap service
+ * not being available.
+ */
+ if (fuidp == NULL)
+ return (UID_NOBODY);
+
+ switch (type) {
+ case ZFS_ACE_USER:
+ case ZFS_ACE_GROUP:
+ zfuid = list_head(&fuidp->z_fuids);
+ rid = FUID_RID(zfuid->z_logfuid);
+ idx = FUID_INDEX(zfuid->z_logfuid);
+ break;
+ case ZFS_OWNER:
+ rid = FUID_RID(fuidp->z_fuid_owner);
+ idx = FUID_INDEX(fuidp->z_fuid_owner);
+ break;
+ case ZFS_GROUP:
+ rid = FUID_RID(fuidp->z_fuid_group);
+ idx = FUID_INDEX(fuidp->z_fuid_group);
+ break;
+ };
+ domain = fuidp->z_domain_table[idx -1];
+ } else {
+ if (type == ZFS_OWNER || type == ZFS_ACE_USER)
+ status = kidmap_getsidbyuid(id, &domain, &rid);
+ else
+ status = kidmap_getsidbygid(id, &domain, &rid);
+
+ if (status != 0)
+ return (UID_NOBODY);
+
+ }
+
+ idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, tx);
+
+ if (is_replay == B_FALSE)
+ zfs_fuid_node_add(fuidpp, kdomain, rid, idx, id, type);
+ else if (zfuid != NULL) {
+ list_remove(&fuidp->z_fuids, zfuid);
+ kmem_free(zfuid, sizeof (zfs_fuid_t));
+ }
+ return (FUID_ENCODE(idx, rid));
+}
+
+void
+zfs_fuid_destroy(zfsvfs_t *zfsvfs)
+{
+ fuid_domain_t *domnode;
+ fuid_idx_t *idxnode;
+ void *cookie;
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
+ if (zfsvfs->z_fuid_loaded == B_FALSE) {
+ rw_exit(&zfsvfs->z_fuid_lock);
+ return;
+ }
+ cookie = NULL;
+ while (domnode = avl_destroy_nodes(&zfsvfs->z_fuid_domain, &cookie)) {
+ ksiddomain_rele(domnode->f_ksid);
+ kmem_free(domnode, sizeof (fuid_domain_t));
+ }
+ avl_destroy(&zfsvfs->z_fuid_domain);
+ cookie = NULL;
+ while (idxnode = avl_destroy_nodes(&zfsvfs->z_fuid_idx, &cookie))
+ kmem_free(idxnode, sizeof (fuid_idx_t));
+ avl_destroy(&zfsvfs->z_fuid_idx);
+ rw_exit(&zfsvfs->z_fuid_lock);
+}
+
+/*
+ * Allocate zfs_fuid_info for tracking FUIDs created during
+ * zfs_mknode, VOP_SETATTR() or VOP_SETSECATTR()
+ */
+zfs_fuid_info_t *
+zfs_fuid_info_alloc(void)
+{
+ zfs_fuid_info_t *fuidp;
+
+ fuidp = kmem_zalloc(sizeof (zfs_fuid_info_t), KM_SLEEP);
+ list_create(&fuidp->z_domains, sizeof (zfs_fuid_domain_t),
+ offsetof(zfs_fuid_domain_t, z_next));
+ list_create(&fuidp->z_fuids, sizeof (zfs_fuid_t),
+ offsetof(zfs_fuid_t, z_next));
+ return (fuidp);
+}
+
+/*
+ * Release all memory associated with zfs_fuid_info_t
+ */
+void
+zfs_fuid_info_free(zfs_fuid_info_t *fuidp)
+{
+ zfs_fuid_t *zfuid;
+ zfs_fuid_domain_t *zdomain;
+
+ while ((zfuid = list_head(&fuidp->z_fuids)) != NULL) {
+ list_remove(&fuidp->z_fuids, zfuid);
+ kmem_free(zfuid, sizeof (zfs_fuid_t));
+ }
+
+ if (fuidp->z_domain_table != NULL)
+ kmem_free(fuidp->z_domain_table,
+ (sizeof (char **)) * fuidp->z_domain_cnt);
+
+ while ((zdomain = list_head(&fuidp->z_domains)) != NULL) {
+ list_remove(&fuidp->z_domains, zdomain);
+ kmem_free(zdomain, sizeof (zfs_fuid_domain_t));
+ }
+
+ kmem_free(fuidp, sizeof (zfs_fuid_info_t));
+}
+
+/*
+ * Check to see if id is a groupmember. If cred
+ * has ksid info then sidlist is checked first
+ * and if still not found then POSIX groups are checked
+ *
+ * Will use a straight FUID compare when possible.
+ */
+boolean_t
+zfs_groupmember(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr)
+{
+ ksid_t *ksid = crgetsid(cr, KSID_GROUP);
+ uid_t gid;
+
+ if (ksid) {
+ int i;
+ ksid_t *ksid_groups;
+ ksidlist_t *ksidlist = crgetsidlist(cr);
+ uint32_t idx = FUID_INDEX(id);
+ uint32_t rid = FUID_RID(id);
+
+ ASSERT(ksidlist);
+ ksid_groups = ksidlist->ksl_sids;
+
+ for (i = 0; i != ksidlist->ksl_nsid; i++) {
+ if (idx == 0) {
+ if (id != IDMAP_WK_CREATOR_GROUP_GID &&
+ id == ksid_groups[i].ks_id) {
+ return (B_TRUE);
+ }
+ } else {
+ char *domain;
+
+ domain = zfs_fuid_find_by_idx(zfsvfs, idx);
+ ASSERT(domain != NULL);
+
+ if (strcmp(domain,
+ IDMAP_WK_CREATOR_SID_AUTHORITY) == 0) {
+ return (B_FALSE);
+ }
+
+ if ((strcmp(domain,
+ ksid_groups[i].ks_domain->kd_name) == 0) &&
+ rid == ksid_groups[i].ks_rid) {
+ return (B_TRUE);
+ }
+ }
+ }
+ }
+
+ /*
+ * Not found in ksidlist, check posix groups
+ */
+ zfs_fuid_map_id(zfsvfs, id, ZFS_GROUP, &gid);
+
+ return (groupmember(gid, cr));
+}
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 54158d03f2..72e2524646 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -38,6 +38,8 @@
#include <sys/cmn_err.h>
#include <sys/stat.h>
#include <sys/zfs_ioctl.h>
+#include <sys/zfs_i18n.h>
+#include <sys/zfs_znode.h>
#include <sys/zap.h>
#include <sys/spa.h>
#include <sys/spa_impl.h>
@@ -60,6 +62,7 @@
#include <sys/sdt.h>
#include <sys/fs/zfs.h>
#include <sys/zfs_ctldir.h>
+#include <sys/zfs_dir.h>
#include <sys/zvol.h>
#include <sharefs/share.h>
#include <sys/zfs_znode.h>
@@ -154,6 +157,22 @@ history_str_get(zfs_cmd_t *zc)
return (buf);
}
+static int
+zfs_check_version(const char *name, int version)
+{
+
+ spa_t *spa;
+
+ if (spa_open(name, &spa, FTAG) == 0) {
+ if (spa_version(spa) < version) {
+ spa_close(spa, FTAG);
+ return (1);
+ }
+ spa_close(spa, FTAG);
+ }
+ return (0);
+}
+
static void
zfs_log_history(zfs_cmd_t *zc)
{
@@ -1280,9 +1299,8 @@ zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
nvpair_type(elem) != DATA_TYPE_STRING)
return (EINVAL);
- error = zfs_secpolicy_write_perms(name,
- ZFS_DELEG_PERM_USERPROP, CRED());
- if (error)
+ if (error = zfs_secpolicy_write_perms(name,
+ ZFS_DELEG_PERM_USERPROP, CRED()))
return (error);
continue;
}
@@ -1304,35 +1322,25 @@ zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
nvpair_value_uint64(elem, &intval) == 0 &&
intval >= ZIO_COMPRESS_GZIP_1 &&
intval <= ZIO_COMPRESS_GZIP_9) {
- spa_t *spa;
-
- if (spa_open(name, &spa, FTAG) == 0) {
- if (spa_version(spa) <
- SPA_VERSION_GZIP_COMPRESSION) {
- spa_close(spa, FTAG);
- return (ENOTSUP);
- }
-
- spa_close(spa, FTAG);
- }
+ if (zfs_check_version(name,
+ SPA_VERSION_GZIP_COMPRESSION))
+ return (ENOTSUP);
}
break;
case ZFS_PROP_COPIES:
- {
- spa_t *spa;
-
- if (spa_open(name, &spa, FTAG) == 0) {
- if (spa_version(spa) <
- SPA_VERSION_DITTO_BLOCKS) {
- spa_close(spa, FTAG);
- return (ENOTSUP);
- }
- spa_close(spa, FTAG);
- }
+ if (zfs_check_version(name, SPA_VERSION_DITTO_BLOCKS))
+ return (ENOTSUP);
break;
+ case ZFS_PROP_NORMALIZE:
+ case ZFS_PROP_UTF8ONLY:
+ case ZFS_PROP_CASE:
+ if (zfs_check_version(name, SPA_VERSION_NORMALIZATION))
+ return (ENOTSUP);
+
}
- }
+ if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
+ return (error);
}
elem = NULL;
@@ -1642,13 +1650,163 @@ zfs_get_vfs(const char *resource)
static void
zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
{
- nvlist_t *nvprops = arg;
- uint64_t version = ZPL_VERSION;
+ zfs_creat_t *zct = arg;
+ uint64_t version;
+
+ if (spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
+ version = ZPL_VERSION;
+ else
+ version = ZPL_VERSION_FUID - 1;
- (void) nvlist_lookup_uint64(nvprops,
+ (void) nvlist_lookup_uint64(zct->zct_props,
zfs_prop_to_name(ZFS_PROP_VERSION), &version);
- zfs_create_fs(os, cr, version, tx);
+ zfs_create_fs(os, cr, version, zct->zct_norm, tx);
+}
+
+/*
+ * zfs_prop_lookup()
+ *
+ * Look for the property first in the existing property nvlist. If
+ * it's already present, you're done. If it's not there, attempt to
+ * find the property value from a parent dataset. If that fails, fall
+ * back to the property's default value. In either of these two
+ * cases, if update is TRUE, add a value for the property to the
+ * property nvlist.
+ *
+ * If the rval pointer is non-NULL, copy the discovered value to rval.
+ *
+ * If we get any unexpected errors, bail and return the error number
+ * to the caller.
+ *
+ * If we succeed, return 0.
+ */
+static int
+zfs_prop_lookup(const char *parentname, zfs_prop_t propnum,
+ nvlist_t *proplist, uint64_t *rval, boolean_t update)
+{
+ const char *propname;
+ uint64_t value;
+ int error = ENOENT;
+
+ propname = zfs_prop_to_name(propnum);
+ if (proplist != NULL)
+ error = nvlist_lookup_uint64(proplist, propname, &value);
+ if (error == ENOENT) {
+ error = dsl_prop_get_integer(parentname, propname,
+ &value, NULL);
+ if (error == ENOENT)
+ value = zfs_prop_default_numeric(propnum);
+ else if (error != 0)
+ return (error);
+ if (update) {
+ ASSERT(proplist != NULL);
+ error = nvlist_add_uint64(proplist, propname, value);
+ }
+ }
+ if (error == 0 && rval)
+ *rval = value;
+ return (error);
+}
+
+/*
+ * zfs_normalization_get
+ *
+ * Get the normalization flag value. If the properties have
+ * non-default values, make sure the pool version is recent enough to
+ * support these choices.
+ */
+static int
+zfs_normalization_get(const char *dataset, nvlist_t *proplist, int *norm,
+ boolean_t update)
+{
+ char parentname[MAXNAMELEN];
+ char poolname[MAXNAMELEN];
+ char *cp;
+ uint64_t value;
+ int check = 0;
+ int error;
+
+ ASSERT(norm != NULL);
+ *norm = 0;
+
+ (void) strncpy(parentname, dataset, sizeof (parentname));
+ cp = strrchr(parentname, '@');
+ if (cp != NULL) {
+ cp[0] = '\0';
+ } else {
+ cp = strrchr(parentname, '/');
+ if (cp == NULL)
+ return (ENOENT);
+ cp[0] = '\0';
+ }
+
+ (void) strncpy(poolname, dataset, sizeof (poolname));
+ cp = strchr(poolname, '/');
+ if (cp != NULL)
+ cp[0] = '\0';
+
+ error = zfs_prop_lookup(parentname, ZFS_PROP_UTF8ONLY,
+ proplist, &value, update);
+ if (error != 0)
+ return (error);
+ if (value != zfs_prop_default_numeric(ZFS_PROP_UTF8ONLY))
+ check = 1;
+
+ error = zfs_prop_lookup(parentname, ZFS_PROP_NORMALIZE,
+ proplist, &value, update);
+ if (error != 0)
+ return (error);
+ if (value != zfs_prop_default_numeric(ZFS_PROP_NORMALIZE)) {
+ check = 1;
+ switch ((int)value) {
+ case ZFS_NORMALIZE_NONE:
+ break;
+ case ZFS_NORMALIZE_C:
+ *norm |= U8_TEXTPREP_NFC;
+ break;
+ case ZFS_NORMALIZE_D:
+ *norm |= U8_TEXTPREP_NFD;
+ break;
+ case ZFS_NORMALIZE_KC:
+ *norm |= U8_TEXTPREP_NFKC;
+ break;
+ case ZFS_NORMALIZE_KD:
+ *norm |= U8_TEXTPREP_NFKD;
+ break;
+ default:
+ ASSERT((int)value >= ZFS_NORMALIZE_NONE);
+ ASSERT((int)value <= ZFS_NORMALIZE_KD);
+ break;
+ }
+ }
+
+ error = zfs_prop_lookup(parentname, ZFS_PROP_CASE,
+ proplist, &value, update);
+ if (error != 0)
+ return (error);
+ if (value != zfs_prop_default_numeric(ZFS_PROP_CASE)) {
+ check = 1;
+ switch ((int)value) {
+ case ZFS_CASE_SENSITIVE:
+ break;
+ case ZFS_CASE_INSENSITIVE:
+ *norm |= U8_TEXTPREP_TOUPPER;
+ break;
+ case ZFS_CASE_MIXED:
+ *norm |= U8_TEXTPREP_TOUPPER;
+ break;
+ default:
+ ASSERT((int)value >= ZFS_CASE_SENSITIVE);
+ ASSERT((int)value <= ZFS_CASE_MIXED);
+ break;
+ }
+ }
+
+ if (check == 1)
+ if (zfs_check_version(poolname, SPA_VERSION_NORMALIZATION))
+ return (ENOTSUP);
+ return (0);
}
static int
@@ -1656,6 +1814,7 @@ zfs_ioc_create(zfs_cmd_t *zc)
{
objset_t *clone;
int error = 0;
+ zfs_creat_t zct;
nvlist_t *nvprops = NULL;
void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
dmu_objset_type_t type = zc->zc_objset_type;
@@ -1682,6 +1841,9 @@ zfs_ioc_create(zfs_cmd_t *zc)
&nvprops)) != 0)
return (error);
+ zct.zct_norm = 0;
+ zct.zct_props = nvprops;
+
if (zc->zc_value[0] != '\0') {
/*
* We're creating a clone of an existing snapshot.
@@ -1699,6 +1861,34 @@ zfs_ioc_create(zfs_cmd_t *zc)
return (error);
}
error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
+ if (error) {
+ dmu_objset_close(clone);
+ nvlist_free(nvprops);
+ return (error);
+ }
+ /*
+ * If caller did not provide any properties, allocate
+ * an nvlist for properties, as we will be adding our set-once
+ * properties to it. This carries the choices made on the
+ * original file system into the clone.
+ */
+ if (nvprops == NULL)
+ VERIFY(nvlist_alloc(&nvprops,
+ NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ /*
+ * We have to have normalization and case-folding
+ * flags correct when we do the file system creation,
+ * so go figure them out now. All we really care about
+ * here is getting these values into the property list.
+ */
+ error = zfs_normalization_get(zc->zc_value, nvprops,
+ &zct.zct_norm, B_TRUE);
+ if (error != 0) {
+ dmu_objset_close(clone);
+ nvlist_free(nvprops);
+ return (error);
+ }
dmu_objset_close(clone);
} else {
if (cbfunc == NULL) {
@@ -1737,18 +1927,38 @@ zfs_ioc_create(zfs_cmd_t *zc)
}
} else if (type == DMU_OST_ZFS) {
uint64_t version;
+ int error;
+
+ error = nvlist_lookup_uint64(nvprops,
+ zfs_prop_to_name(ZFS_PROP_VERSION), &version);
- if (0 == nvlist_lookup_uint64(nvprops,
- zfs_prop_to_name(ZFS_PROP_VERSION), &version) &&
- (version < ZPL_VERSION_INITIAL ||
+ if (error == 0 && (version < ZPL_VERSION_INITIAL ||
version > ZPL_VERSION)) {
nvlist_free(nvprops);
- return (EINVAL);
+ return (ENOTSUP);
+ } else if (error == 0 && version >= ZPL_VERSION_FUID &&
+ zfs_check_version(zc->zc_name, SPA_VERSION_FUID)) {
+ nvlist_free(nvprops);
+ return (ENOTSUP);
}
- }
+ /*
+ * We have to have normalization and
+ * case-folding flags correct when we do the
+ * file system creation, so go figure them out
+ * now. The final argument to zfs_normalization_get()
+ * tells that routine not to update the nvprops
+ * list.
+ */
+ error = zfs_normalization_get(zc->zc_name, nvprops,
+ &zct.zct_norm, B_FALSE);
+ if (error != 0) {
+ nvlist_free(nvprops);
+ return (error);
+ }
+ }
error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
- nvprops);
+ &zct);
}
/*
@@ -1952,7 +2162,7 @@ zfs_ioc_recvbackup(zfs_cmd_t *zc)
if (zfsvfs != NULL)
VFS_RELE(zfsvfs->z_vfs);
new_off = fp->f_offset + zc->zc_cookie;
- if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0)
+ if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off, NULL) == 0)
fp->f_offset = new_off;
releasef(fd);
@@ -2123,55 +2333,129 @@ zfs_ioc_promote(zfs_cmd_t *zc)
/*
* We don't want to have a hard dependency
* against some special symbols in sharefs
- * and nfs. Determine them if needed when
+ * nfs, and smbsrv. Determine them if needed when
* the first file system is shared.
- * Neither sharefs or nfs are unloadable modules.
+ * Neither sharefs, nfs or smbsrv are unloadable modules.
*/
-int (*zexport_fs)(void *arg);
+int (*znfsexport_fs)(void *arg);
int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t);
+int (*zsmbexport_fs)(void *arg, boolean_t add_share);
+
+int zfs_nfsshare_inited;
+int zfs_smbshare_inited;
-int zfs_share_inited;
ddi_modhandle_t nfs_mod;
ddi_modhandle_t sharefs_mod;
+ddi_modhandle_t smbsrv_mod;
kmutex_t zfs_share_lock;
static int
+zfs_init_sharefs()
+{
+ int error;
+
+ ASSERT(MUTEX_HELD(&zfs_share_lock));
+ /* Both NFS and SMB shares also require sharetab support. */
+ if (sharefs_mod == NULL && ((sharefs_mod =
+ ddi_modopen("fs/sharefs",
+ KRTLD_MODE_FIRST, &error)) == NULL)) {
+ return (ENOSYS);
+ }
+ if (zshare_fs == NULL && ((zshare_fs =
+ (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
+ ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
+ return (ENOSYS);
+ }
+ return (0);
+}
+
+static int
zfs_ioc_share(zfs_cmd_t *zc)
{
int error;
int opcode;
- if (zfs_share_inited == 0) {
- mutex_enter(&zfs_share_lock);
- nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error);
- sharefs_mod = ddi_modopen("fs/sharefs",
- KRTLD_MODE_FIRST, &error);
- if (nfs_mod == NULL || sharefs_mod == NULL) {
+ switch (zc->zc_share.z_sharetype) {
+ case ZFS_SHARE_NFS:
+ case ZFS_UNSHARE_NFS:
+ if (zfs_nfsshare_inited == 0) {
+ mutex_enter(&zfs_share_lock);
+ if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs",
+ KRTLD_MODE_FIRST, &error)) == NULL)) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ if (znfsexport_fs == NULL &&
+ ((znfsexport_fs = (int (*)(void *))
+ ddi_modsym(nfs_mod,
+ "nfs_export", &error)) == NULL)) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ error = zfs_init_sharefs();
+ if (error) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ zfs_nfsshare_inited = 1;
mutex_exit(&zfs_share_lock);
- return (ENOSYS);
}
- if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *))
- ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) {
+ break;
+ case ZFS_SHARE_SMB:
+ case ZFS_UNSHARE_SMB:
+ if (zfs_smbshare_inited == 0) {
+ mutex_enter(&zfs_share_lock);
+ if (smbsrv_mod == NULL && ((smbsrv_mod =
+ ddi_modopen("drv/smbsrv",
+ KRTLD_MODE_FIRST, &error)) == NULL)) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ if (zsmbexport_fs == NULL && ((zsmbexport_fs =
+ (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod,
+ "lmshrd_share_upcall", &error)) == NULL)) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ error = zfs_init_sharefs();
+ if (error) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ zfs_smbshare_inited = 1;
mutex_exit(&zfs_share_lock);
- return (ENOSYS);
}
+ break;
+ default:
+ return (EINVAL);
+ }
- if (zshare_fs == NULL && ((zshare_fs =
- (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
- ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
- mutex_exit(&zfs_share_lock);
- return (ENOSYS);
+ switch (zc->zc_share.z_sharetype) {
+ case ZFS_SHARE_NFS:
+ case ZFS_UNSHARE_NFS:
+ if (error =
+ znfsexport_fs((void *)
+ (uintptr_t)zc->zc_share.z_exportdata))
+ return (error);
+ break;
+ case ZFS_SHARE_SMB:
+ case ZFS_UNSHARE_SMB:
+ if (error = zsmbexport_fs((void *)
+ (uintptr_t)zc->zc_share.z_exportdata,
+ zc->zc_share.z_sharetype == ZFS_SHARE_SMB ?
+ B_TRUE : B_FALSE)) {
+ return (error);
}
- zfs_share_inited = 1;
- mutex_exit(&zfs_share_lock);
+ break;
}
- if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata))
- return (error);
-
- opcode = (zc->zc_share.z_sharetype == B_TRUE) ?
+ opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS ||
+ zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ?
SHAREFS_ADD : SHAREFS_REMOVE;
+ /*
+ * Add or remove share from sharetab
+ */
error = zshare_fs(opcode,
(void *)(uintptr_t)zc->zc_share.z_sharedata,
zc->zc_share.z_sharemax);
@@ -2447,10 +2731,12 @@ _fini(void)
zvol_fini();
zfs_fini();
spa_fini();
- if (zfs_share_inited) {
+ if (zfs_nfsshare_inited)
(void) ddi_modclose(nfs_mod);
+ if (zfs_smbshare_inited)
+ (void) ddi_modclose(smbsrv_mod);
+ if (zfs_nfsshare_inited || zfs_smbshare_inited)
(void) ddi_modclose(sharefs_mod);
- }
tsd_destroy(&zfs_fsyncer_key);
ldi_ident_release(zfs_li);
diff --git a/usr/src/uts/common/fs/zfs/zfs_log.c b/usr/src/uts/common/fs/zfs/zfs_log.c
index e5e26d3a05..04075f47bf 100644
--- a/usr/src/uts/common/fs/zfs/zfs_log.c
+++ b/usr/src/uts/common/fs/zfs/zfs_log.c
@@ -45,44 +45,277 @@
#include <sys/acl.h>
#include <sys/dmu.h>
#include <sys/spa.h>
+#include <sys/zfs_fuid.h>
#include <sys/ddi.h>
/*
* All the functions in this file are used to construct the log entries
- * to record transactions. They allocate * a intent log transaction
+ * to record transactions. They allocate * an intent log transaction
* structure (itx_t) and save within it all the information necessary to
* possibly replay the transaction. The itx is then assigned a sequence
* number and inserted in the in-memory list anchored in the zilog.
*/
+int
+zfs_log_create_txtype(zil_create_t type, vsecattr_t *vsecp, vattr_t *vap)
+{
+ int isxvattr = (vap->va_mask & AT_XVATTR);
+ switch (type) {
+ case Z_FILE:
+ if (vsecp == NULL && !isxvattr)
+ return (TX_CREATE);
+ if (vsecp && isxvattr)
+ return (TX_CREATE_ACL_ATTR);
+ if (vsecp)
+ return (TX_CREATE_ACL);
+ else
+ return (TX_CREATE_ATTR);
+ /*NOTREACHED*/
+ case Z_DIR:
+ if (vsecp == NULL && !isxvattr)
+ return (TX_MKDIR);
+ if (vsecp && isxvattr)
+ return (TX_MKDIR_ACL_ATTR);
+ if (vsecp)
+ return (TX_MKDIR_ACL);
+ else
+ return (TX_MKDIR_ATTR);
+ case Z_XATTRDIR:
+ return (TX_MKXATTR);
+ }
+ ASSERT(0);
+ return (TX_MAX_TYPE);
+}
+
+/*
+ * build up the log data necessary for logging xvattr_t
+ * First lr_attr_t is initialized. following the lr_attr_t
+ * is the mapsize and attribute bitmap copied from the xvattr_t.
+ * Following the bitmap and bitmapsize two 64 bit words are reserved
+ * for the create time which may be set. Following the create time
+ * records a single 64 bit integer which has the bits to set on
+ * replay for the xvattr.
+ */
+static void
+zfs_log_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
+{
+ uint32_t *bitmap;
+ uint64_t *attrs;
+ uint64_t *crtime;
+ xoptattr_t *xoap;
+ void *scanstamp;
+ int i;
+
+ xoap = xva_getxoptattr(xvap);
+ ASSERT(xoap);
+
+ lrattr->lr_attr_masksize = xvap->xva_mapsize;
+ bitmap = &lrattr->lr_attr_bitmap;
+ for (i = 0; i != xvap->xva_mapsize; i++, bitmap++) {
+ *bitmap = xvap->xva_reqattrmap[i];
+ }
+
+ /* Now pack the attributes up in a single uint64_t */
+ attrs = (uint64_t *)bitmap;
+ crtime = attrs + 1;
+ scanstamp = (caddr_t)(crtime + 2);
+ *attrs = 0;
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY))
+ *attrs |= (xoap->xoa_readonly == 0) ? 0 :
+ XAT0_READONLY;
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN))
+ *attrs |= (xoap->xoa_hidden == 0) ? 0 :
+ XAT0_HIDDEN;
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM))
+ *attrs |= (xoap->xoa_system == 0) ? 0 :
+ XAT0_SYSTEM;
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE))
+ *attrs |= (xoap->xoa_archive == 0) ? 0 :
+ XAT0_ARCHIVE;
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
+ *attrs |= (xoap->xoa_immutable == 0) ? 0 :
+ XAT0_IMMUTABLE;
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
+ *attrs |= (xoap->xoa_nounlink == 0) ? 0 :
+ XAT0_NOUNLINK;
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
+ *attrs |= (xoap->xoa_appendonly == 0) ? 0 :
+ XAT0_APPENDONLY;
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE))
+ *attrs |= (xoap->xoa_opaque == 0) ? 0 :
+ XAT0_APPENDONLY;
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP))
+ *attrs |= (xoap->xoa_nodump == 0) ? 0 :
+ XAT0_NODUMP;
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED))
+ *attrs |= (xoap->xoa_av_quarantined == 0) ? 0 :
+ XAT0_AV_QUARANTINED;
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
+ *attrs |= (xoap->xoa_av_modified == 0) ? 0 :
+ XAT0_AV_MODIFIED;
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME))
+ ZFS_TIME_ENCODE(&xoap->xoa_createtime, crtime);
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+ bcopy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ);
+}
+
+static void *
+zfs_log_fuid_ids(zfs_fuid_info_t *fuidp, void *start)
+{
+ zfs_fuid_t *zfuid;
+ uint64_t *fuidloc = start;
+
+ /* First copy in the ACE FUIDs */
+ for (zfuid = list_head(&fuidp->z_fuids); zfuid;
+ zfuid = list_next(&fuidp->z_fuids, zfuid)) {
+ *fuidloc++ = zfuid->z_logfuid;
+ }
+ return (fuidloc);
+}
+
+
+static void *
+zfs_log_fuid_domains(zfs_fuid_info_t *fuidp, void *start)
+{
+ zfs_fuid_domain_t *zdomain;
+
+ /* now copy in the domain info, if any */
+ if (fuidp->z_domain_str_sz != 0) {
+ for (zdomain = list_head(&fuidp->z_domains); zdomain;
+ zdomain = list_next(&fuidp->z_domains, zdomain)) {
+ bcopy((void *)zdomain->z_domain, start,
+ strlen(zdomain->z_domain) + 1);
+ start = (caddr_t)start +
+ strlen(zdomain->z_domain) + 1;
+ }
+ }
+ return (start);
+}
+
/*
- * zfs_log_create() is used to handle TX_CREATE, TX_MKDIR and TX_MKXATTR
+ * zfs_log_create() is used to handle TX_CREATE, TX_CREATE_ATTR, TX_MKDIR,
+ * TX_MKDIR_ATTR and TX_MKXATTR
* transactions.
+ *
+ * TX_CREATE and TX_MKDIR are standard creates, but they may have FUID
+ * domain information appended prior to the name. In this case the
+ * uid/gid in the log record will be a log centric FUID.
+ *
+ * TX_CREATE_ACL_ATTR and TX_MKDIR_ACL_ATTR handle special creates that
+ * may contain attributes, ACL and optional fuid information.
+ *
+ * TX_CREATE_ACL and TX_MKDIR_ACL handle special creates that specify
+ * and ACL and normal users/groups in the ACEs.
+ *
+ * There may be an optional xvattr attribute information similar
+ * to zfs_log_setattr.
+ *
+ * Also, after the file name "domain" strings may be appended.
*/
void
-zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *dzp, znode_t *zp, char *name)
+zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+ znode_t *dzp, znode_t *zp, char *name, vsecattr_t *vsecp,
+ zfs_fuid_info_t *fuidp, vattr_t *vap)
{
itx_t *itx;
uint64_t seq;
lr_create_t *lr;
+ lr_acl_create_t *lracl;
+ size_t aclsize;
+ size_t xvatsize = 0;
+ size_t txsize;
+ xvattr_t *xvap = (xvattr_t *)vap;
+ void *end;
+ size_t lrsize;
+
size_t namesize = strlen(name) + 1;
+ size_t fuidsz = 0;
if (zilog == NULL)
return;
- itx = zil_itx_create(txtype, sizeof (*lr) + namesize);
+ /*
+ * If we have FUIDs present then add in space for
+ * domains and ACE fuid's if any.
+ */
+ if (fuidp) {
+ fuidsz += fuidp->z_domain_str_sz;
+ fuidsz += fuidp->z_fuid_cnt * sizeof (uint64_t);
+ }
+
+ if (vap->va_mask & AT_XVATTR)
+ xvatsize = ZIL_XVAT_SIZE(xvap->xva_mapsize);
+
+ if ((int)txtype == TX_CREATE_ATTR || (int)txtype == TX_MKDIR_ATTR ||
+ (int)txtype == TX_CREATE || (int)txtype == TX_MKDIR ||
+ (int)txtype == TX_MKXATTR) {
+ txsize = sizeof (*lr) + namesize + fuidsz + xvatsize;
+ lrsize = sizeof (*lr);
+ } else {
+ aclsize = (vsecp) ? vsecp->vsa_aclentsz : 0;
+ txsize =
+ sizeof (lr_acl_create_t) + namesize + fuidsz +
+ aclsize + xvatsize;
+ lrsize = sizeof (lr_acl_create_t);
+ }
+
+ itx = zil_itx_create(txtype, txsize);
+
lr = (lr_create_t *)&itx->itx_lr;
lr->lr_doid = dzp->z_id;
lr->lr_foid = zp->z_id;
lr->lr_mode = zp->z_phys->zp_mode;
- lr->lr_uid = zp->z_phys->zp_uid;
- lr->lr_gid = zp->z_phys->zp_gid;
+ if (!IS_EPHEMERAL(zp->z_phys->zp_uid)) {
+ lr->lr_uid = (uint64_t)zp->z_phys->zp_uid;
+ } else {
+ lr->lr_uid = fuidp->z_fuid_owner;
+ }
+ if (!IS_EPHEMERAL(zp->z_phys->zp_gid)) {
+ lr->lr_gid = (uint64_t)zp->z_phys->zp_gid;
+ } else {
+ lr->lr_gid = fuidp->z_fuid_group;
+ }
lr->lr_gen = zp->z_phys->zp_gen;
lr->lr_crtime[0] = zp->z_phys->zp_crtime[0];
lr->lr_crtime[1] = zp->z_phys->zp_crtime[1];
lr->lr_rdev = zp->z_phys->zp_rdev;
- bcopy(name, (char *)(lr + 1), namesize);
+
+ /*
+ * Fill in xvattr info if any
+ */
+ if (vap->va_mask & AT_XVATTR) {
+ zfs_log_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), xvap);
+ end = (caddr_t)lr + lrsize + xvatsize;
+ } else {
+ end = (caddr_t)lr + lrsize;
+ }
+
+ /* Now fill in any ACL info */
+
+ if (vsecp) {
+ lracl = (lr_acl_create_t *)&itx->itx_lr;
+ lracl->lr_aclcnt = vsecp->vsa_aclcnt;
+ lracl->lr_acl_bytes = aclsize;
+ lracl->lr_domcnt = fuidp ? fuidp->z_domain_cnt : 0;
+ lracl->lr_fuidcnt = fuidp ? fuidp->z_fuid_cnt : 0;
+ if (vsecp->vsa_aclflags & VSA_ACE_ACLFLAGS)
+ lracl->lr_acl_flags = (uint64_t)vsecp->vsa_aclflags;
+ else
+ lracl->lr_acl_flags = 0;
+
+ bcopy(vsecp->vsa_aclentp, end, aclsize);
+ end = (caddr_t)end + aclsize;
+ }
+
+ /* drop in FUID info */
+ if (fuidp) {
+ end = zfs_log_fuid_ids(fuidp, end);
+ end = zfs_log_fuid_domains(fuidp, end);
+ }
+ /*
+ * Now place file name in log record
+ */
+ bcopy(name, end, namesize);
seq = zil_itx_assign(zilog, itx, tx);
dzp->z_last_itx = seq;
@@ -93,7 +326,7 @@ zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_remove() handles both TX_REMOVE and TX_RMDIR transactions.
*/
void
-zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, char *name)
{
itx_t *itx;
@@ -117,7 +350,7 @@ zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_link() handles TX_LINK transactions.
*/
void
-zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, znode_t *zp, char *name)
{
itx_t *itx;
@@ -143,8 +376,8 @@ zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_symlink() handles TX_SYMLINK transactions.
*/
void
-zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *dzp, znode_t *zp, char *name, char *link)
+zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+ znode_t *dzp, znode_t *zp, char *name, char *link)
{
itx_t *itx;
uint64_t seq;
@@ -177,7 +410,7 @@ zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_rename() handles TX_RENAME transactions.
*/
void
-zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *sdzp, char *sname, znode_t *tdzp, char *dname, znode_t *szp)
{
itx_t *itx;
@@ -328,25 +561,60 @@ zfs_log_truncate(zilog_t *zilog, dmu_tx_t *tx, int txtype,
*/
void
zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *zp, vattr_t *vap, uint_t mask_applied)
+ znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp)
{
- itx_t *itx;
- uint64_t seq;
- lr_setattr_t *lr;
+ itx_t *itx;
+ uint64_t seq;
+ lr_setattr_t *lr;
+ xvattr_t *xvap = (xvattr_t *)vap;
+ size_t recsize = sizeof (lr_setattr_t);
+ void *start;
+
if (zilog == NULL || zp->z_unlinked)
return;
- itx = zil_itx_create(txtype, sizeof (*lr));
+ /*
+ * If XVATTR set, then log record size needs to allow
+ * for lr_attr_t + xvattr mask, mapsize and create time
+ * plus actual attribute values
+ */
+ if (vap->va_mask & AT_XVATTR)
+ recsize = sizeof (*lr) + ZIL_XVAT_SIZE(xvap->xva_mapsize);
+
+ if (fuidp)
+ recsize += fuidp->z_domain_str_sz;
+
+ itx = zil_itx_create(txtype, recsize);
lr = (lr_setattr_t *)&itx->itx_lr;
lr->lr_foid = zp->z_id;
lr->lr_mask = (uint64_t)mask_applied;
lr->lr_mode = (uint64_t)vap->va_mode;
- lr->lr_uid = (uint64_t)vap->va_uid;
- lr->lr_gid = (uint64_t)vap->va_gid;
+ if ((mask_applied & AT_UID) && IS_EPHEMERAL(vap->va_uid))
+ lr->lr_uid = fuidp->z_fuid_owner;
+ else
+ lr->lr_uid = (uint64_t)vap->va_uid;
+
+ if ((mask_applied & AT_GID) && IS_EPHEMERAL(vap->va_gid))
+ lr->lr_gid = fuidp->z_fuid_group;
+ else
+ lr->lr_gid = (uint64_t)vap->va_gid;
+
lr->lr_size = (uint64_t)vap->va_size;
ZFS_TIME_ENCODE(&vap->va_atime, lr->lr_atime);
ZFS_TIME_ENCODE(&vap->va_mtime, lr->lr_mtime);
+ start = (lr_setattr_t *)(lr + 1);
+ if (vap->va_mask & AT_XVATTR) {
+ zfs_log_xvattr((lr_attr_t *)start, xvap);
+ start = (caddr_t)start + ZIL_XVAT_SIZE(xvap->xva_mapsize);
+ }
+
+ /*
+ * Now stick on domain information if any on end
+ */
+
+ if (fuidp)
+ (void) zfs_log_fuid_domains(fuidp, start);
itx->itx_sync = (zp->z_sync_cnt != 0);
seq = zil_itx_assign(zilog, itx, tx);
@@ -357,21 +625,62 @@ zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_acl() handles TX_ACL transactions.
*/
void
-zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *zp, int aclcnt, ace_t *z_ace)
+zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp,
+ vsecattr_t *vsecp, zfs_fuid_info_t *fuidp)
{
itx_t *itx;
uint64_t seq;
+ lr_acl_v0_t *lrv0;
lr_acl_t *lr;
+ int txtype;
+ int lrsize;
+ size_t txsize;
+ size_t aclbytes = vsecp->vsa_aclentsz;
+
+ txtype = (zp->z_zfsvfs->z_version == ZPL_VERSION_INITIAL) ?
+ TX_ACL_V0 : TX_ACL;
+
+ if (txtype == TX_ACL)
+ lrsize = sizeof (*lr);
+ else
+ lrsize = sizeof (*lrv0);
if (zilog == NULL || zp->z_unlinked)
return;
- itx = zil_itx_create(txtype, sizeof (*lr) + aclcnt * sizeof (ace_t));
+ txsize = lrsize + aclbytes + (fuidp ? fuidp->z_domain_str_sz : 0) +
+ sizeof (uint64) * (fuidp ? fuidp->z_fuid_cnt : 0);
+
+ itx = zil_itx_create(txtype, txsize);
+
lr = (lr_acl_t *)&itx->itx_lr;
lr->lr_foid = zp->z_id;
- lr->lr_aclcnt = (uint64_t)aclcnt;
- bcopy(z_ace, (ace_t *)(lr + 1), aclcnt * sizeof (ace_t));
+ if (txtype == TX_ACL) {
+ lr->lr_acl_bytes = aclbytes;
+ lr->lr_domcnt = fuidp ? fuidp->z_domain_cnt : 0;
+ lr->lr_fuidcnt = fuidp ? fuidp->z_fuid_cnt : 0;
+ if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS)
+ lr->lr_acl_flags = (uint64_t)vsecp->vsa_aclflags;
+ else
+ lr->lr_acl_flags = 0;
+ }
+ lr->lr_aclcnt = (uint64_t)vsecp->vsa_aclcnt;
+
+ if (txtype == TX_ACL_V0) {
+ lrv0 = (lr_acl_v0_t *)lr;
+ bcopy(vsecp->vsa_aclentp, (ace_t *)(lrv0 + 1), aclbytes);
+ } else {
+ void *start = (ace_t *)(lr + 1);
+
+ bcopy(vsecp->vsa_aclentp, start, aclbytes);
+
+ start = (caddr_t)start + aclbytes;
+
+ if (fuidp) {
+ start = zfs_log_fuid_ids(fuidp, start);
+ (void) zfs_log_fuid_domains(fuidp, start);
+ }
+ }
itx->itx_sync = (zp->z_sync_cnt != 0);
seq = zil_itx_assign(zilog, itx, tx);
diff --git a/usr/src/uts/common/fs/zfs/zfs_replay.c b/usr/src/uts/common/fs/zfs/zfs_replay.c
index 4b028510b5..6b2937490f 100644
--- a/usr/src/uts/common/fs/zfs/zfs_replay.c
+++ b/usr/src/uts/common/fs/zfs/zfs_replay.c
@@ -39,6 +39,7 @@
#include <sys/zfs_znode.h>
#include <sys/zfs_dir.h>
#include <sys/zfs_acl.h>
+#include <sys/zfs_fuid.h>
#include <sys/spa.h>
#include <sys/zil.h>
#include <sys/byteorder.h>
@@ -62,8 +63,8 @@ zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
vap->va_mask = (uint_t)mask;
vap->va_type = IFTOVT(mode);
vap->va_mode = mode & MODEMASK;
- vap->va_uid = (uid_t)uid;
- vap->va_gid = (gid_t)gid;
+ vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid;
+ vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid;
vap->va_rdev = zfs_cmpldev(rdev);
vap->va_nodeid = nodeid;
}
@@ -75,23 +76,345 @@ zfs_replay_error(zfsvfs_t *zfsvfs, lr_t *lr, boolean_t byteswap)
return (ENOTSUP);
}
+static void
+zfs_replay_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
+{
+ xoptattr_t *xoap = NULL;
+ uint64_t *attrs;
+ uint64_t *crtime;
+ void *scanstamp;
+
+ xvap->xva_vattr.va_mask |= AT_XVATTR;
+ if ((xoap = xva_getxoptattr(xvap)) == NULL) {
+ xvap->xva_vattr.va_mask &= ~AT_XVATTR; /* shouldn't happen */
+ return;
+ }
+
+ ASSERT(lrattr->lr_attr_masksize == xvap->xva_mapsize);
+ bcopy(&lrattr->lr_attr_bitmap, xvap->xva_reqattrmap,
+ xvap->xva_mapsize);
+ attrs = (uint64_t *)(lrattr + lrattr->lr_attr_masksize - 1);
+ crtime = attrs + 1;
+ scanstamp = (caddr_t)(crtime + 2);
+
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN))
+ xoap->xoa_hidden = ((*attrs & XAT0_HIDDEN) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM))
+ xoap->xoa_system = ((*attrs & XAT0_SYSTEM) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE))
+ xoap->xoa_archive = ((*attrs & XAT0_ARCHIVE) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY))
+ xoap->xoa_readonly = ((*attrs & XAT0_READONLY) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
+ xoap->xoa_immutable = ((*attrs & XAT0_IMMUTABLE) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
+ xoap->xoa_nounlink = ((*attrs & XAT0_NOUNLINK) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
+ xoap->xoa_appendonly = ((*attrs & XAT0_APPENDONLY) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP))
+ xoap->xoa_nodump = ((*attrs & XAT0_NODUMP) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE))
+ xoap->xoa_opaque = ((*attrs & XAT0_OPAQUE) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
+ xoap->xoa_av_modified = ((*attrs & XAT0_AV_MODIFIED) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED))
+ xoap->xoa_av_quarantined =
+ ((*attrs & XAT0_AV_QUARANTINED) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME))
+ ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime);
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+ bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
+}
+
+static int
+zfs_replay_domain_cnt(uint64_t uid, uint64_t gid)
+{
+ uint64_t uid_idx;
+ uint64_t gid_idx;
+ int domcnt = 0;
+
+ uid_idx = FUID_INDEX(uid);
+ gid_idx = FUID_INDEX(gid);
+ if (uid_idx)
+ domcnt++;
+ if (gid_idx > 0 && gid_idx != uid_idx)
+ domcnt++;
+
+ return (domcnt);
+}
+
+static void *
+zfs_replay_fuid_domain_common(zfs_fuid_info_t *fuid_infop, void *start,
+ int domcnt)
+{
+ int i;
+
+ for (i = 0; i != domcnt; i++) {
+ fuid_infop->z_domain_table[i] = start;
+ start = (caddr_t)start + strlen(start) + 1;
+ }
+
+ return (start);
+}
+
+/*
+ * Set the uid/gid in the fuid_info structure.
+ */
+static void
+zfs_replay_fuid_ugid(zfs_fuid_info_t *fuid_infop, uint64_t uid, uint64_t gid)
+{
+ /*
+ * If owner or group are log specific FUIDs then slurp up
+ * domain information and build zfs_fuid_info_t
+ */
+ if (IS_EPHEMERAL(uid))
+ fuid_infop->z_fuid_owner = uid;
+
+ if (IS_EPHEMERAL(gid))
+ fuid_infop->z_fuid_group = gid;
+}
+
+/*
+ * Load fuid domains into fuid_info_t
+ */
+static zfs_fuid_info_t *
+zfs_replay_fuid_domain(void *buf, void **end, uint64_t uid, uint64_t gid)
+{
+ int domcnt;
+
+ zfs_fuid_info_t *fuid_infop;
+
+ fuid_infop = zfs_fuid_info_alloc();
+
+ domcnt = zfs_replay_domain_cnt(uid, gid);
+
+ if (domcnt == 0)
+ return (fuid_infop);
+
+ fuid_infop->z_domain_table =
+ kmem_zalloc(domcnt * sizeof (char **), KM_SLEEP);
+
+ zfs_replay_fuid_ugid(fuid_infop, uid, gid);
+
+ fuid_infop->z_domain_cnt = domcnt;
+ *end = zfs_replay_fuid_domain_common(fuid_infop, buf, domcnt);
+ return (fuid_infop);
+}
+
+/*
+ * load zfs_fuid_t's and fuid_domains into fuid_info_t
+ */
+static zfs_fuid_info_t *
+zfs_replay_fuids(void *start, void **end, int idcnt, int domcnt, uint64_t uid,
+ uint64_t gid)
+{
+ uint64_t *log_fuid = (uint64_t *)start;
+ zfs_fuid_info_t *fuid_infop;
+ int i;
+
+ fuid_infop = zfs_fuid_info_alloc();
+ fuid_infop->z_domain_cnt = domcnt;
+
+ fuid_infop->z_domain_table =
+ kmem_zalloc(domcnt * sizeof (char **), KM_SLEEP);
+
+ for (i = 0; i != idcnt; i++) {
+ zfs_fuid_t *zfuid;
+
+ zfuid = kmem_alloc(sizeof (zfs_fuid_t), KM_SLEEP);
+ zfuid->z_logfuid = *log_fuid;
+ zfuid->z_id = -1;
+ zfuid->z_domidx = 0;
+ list_insert_tail(&fuid_infop->z_fuids, zfuid);
+ log_fuid++;
+ }
+
+ zfs_replay_fuid_ugid(fuid_infop, uid, gid);
+
+ *end = zfs_replay_fuid_domain_common(fuid_infop, log_fuid, domcnt);
+ return (fuid_infop);
+}
+
+static void
+zfs_replay_swap_attrs(lr_attr_t *lrattr)
+{
+ /* swap the lr_attr structure */
+ byteswap_uint32_array(lrattr, sizeof (*lrattr));
+ /* swap the bitmap */
+ byteswap_uint32_array(lrattr + 1, lrattr->lr_attr_masksize - 1);
+ /* swap the attributes, create time + 64 bit word for attributes */
+ byteswap_uint64_array(lrattr + (sizeof (uint32_t) *
+ (lrattr->lr_attr_masksize - 1)), 3 * sizeof (uint64_t));
+}
+
+/*
+ * Replay file create with optional ACL, xvattr information as well
+ * as option FUID information.
+ */
+static int
+zfs_replay_create_acl(zfsvfs_t *zfsvfs,
+ lr_acl_create_t *lracl, boolean_t byteswap)
+{
+ char *name = NULL; /* location determined later */
+ lr_create_t *lr = (lr_create_t *)lracl;
+ znode_t *dzp;
+ vnode_t *vp = NULL;
+ xvattr_t xva;
+ int vflg = 0;
+ vsecattr_t vsec = { 0 };
+ lr_attr_t *lrattr;
+ void *aclstart;
+ void *fuidstart;
+ size_t xvatlen = 0;
+ uint64_t txtype;
+ int error;
+
+ if (byteswap) {
+ byteswap_uint64_array(lracl, sizeof (*lracl));
+ txtype = (int)lr->lr_common.lrc_txtype;
+ if (txtype == TX_CREATE_ACL_ATTR ||
+ txtype == TX_MKDIR_ACL_ATTR) {
+ lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
+ zfs_replay_swap_attrs(lrattr);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ }
+
+ aclstart = (caddr_t)(lracl + 1) + xvatlen;
+ zfs_ace_byteswap(aclstart, lracl->lr_acl_bytes, B_FALSE);
+ /* swap fuids */
+ if (lracl->lr_fuidcnt) {
+ byteswap_uint64_array((caddr_t)aclstart +
+ lracl->lr_acl_bytes, sizeof (uint64_t));
+ }
+ }
+
+ if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
+ return (error);
+
+ xva_init(&xva);
+ zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID,
+ lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);
+
+ /*
+ * All forms of zfs create (create, mkdir, mkxattrdir, symlink)
+ * eventually end up in zfs_mknode(), which assigns the object's
+ * creation time and generation number. The generic VOP_CREATE()
+ * doesn't have either concept, so we smuggle the values inside
+ * the vattr's otherwise unused va_ctime and va_nblocks fields.
+ */
+ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
+ xva.xva_vattr.va_nblocks = lr->lr_gen;
+
+ error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL);
+ if (error != ENOENT)
+ goto bail;
+
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+ switch ((int)lr->lr_common.lrc_txtype) {
+ case TX_CREATE_ACL:
+ aclstart = (caddr_t)(lracl + 1);
+ fuidstart = (caddr_t)aclstart + lracl->lr_acl_bytes;
+ zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
+ (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+ lr->lr_uid, lr->lr_gid);
+ /*FALLTHROUGH*/
+ case TX_CREATE_ACL_ATTR:
+ if (name == NULL) {
+ lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ xva.xva_vattr.va_mask |= AT_XVATTR;
+ zfs_replay_xvattr(lrattr, &xva);
+ }
+ vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+ vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen;
+ vsec.vsa_aclcnt = lracl->lr_aclcnt;
+ vsec.vsa_aclentsz = lracl->lr_acl_bytes;
+ vsec.vsa_aclflags = lracl->lr_acl_flags;
+ if (zfsvfs->z_fuid_replay == NULL)
+ fuidstart = (caddr_t)(lracl + 1) + xvatlen +
+ lracl->lr_acl_bytes;
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuids(fuidstart,
+ (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+ lr->lr_uid, lr->lr_gid);
+
+ error = VOP_CREATE(ZTOV(dzp), name, &xva.xva_vattr,
+ 0, 0, &vp, kcred, vflg, NULL, &vsec);
+ break;
+ case TX_MKDIR_ACL:
+ aclstart = (caddr_t)(lracl + 1);
+ fuidstart = (caddr_t)aclstart + lracl->lr_acl_bytes;
+ zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
+ (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+ lr->lr_uid, lr->lr_gid);
+ /*FALLTHROUGH*/
+ case TX_MKDIR_ACL_ATTR:
+ if (name == NULL) {
+ lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ zfs_replay_xvattr(lrattr, &xva);
+ }
+ vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+ vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen;
+ vsec.vsa_aclcnt = lracl->lr_aclcnt;
+ vsec.vsa_aclentsz = lracl->lr_acl_bytes;
+ vsec.vsa_aclflags = lracl->lr_acl_flags;
+ if (zfsvfs->z_fuid_replay == NULL)
+ fuidstart = (caddr_t)(lracl + 1) + xvatlen +
+ lracl->lr_acl_bytes;
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuids(fuidstart,
+ (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+ lr->lr_uid, lr->lr_gid);
+ error = VOP_MKDIR(ZTOV(dzp), name, &xva.xva_vattr,
+ &vp, kcred, NULL, vflg, &vsec);
+ break;
+ default:
+ error = ENOTSUP;
+ }
+
+bail:
+ if (error == 0 && vp != NULL)
+ VN_RELE(vp);
+
+ VN_RELE(ZTOV(dzp));
+
+ zfs_fuid_info_free(zfsvfs->z_fuid_replay);
+ zfsvfs->z_fuid_replay = NULL;
+
+ return (error);
+}
+
static int
zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap)
{
- char *name = (char *)(lr + 1); /* name follows lr_create_t */
+ char *name = NULL; /* location determined later */
char *link; /* symlink content follows name */
znode_t *dzp;
vnode_t *vp = NULL;
- vattr_t va;
+ xvattr_t xva;
+ int vflg = 0;
+ size_t lrsize = sizeof (lr_create_t);
+ lr_attr_t *lrattr;
+ void *start;
+ size_t xvatlen;
+ uint64_t txtype;
int error;
- if (byteswap)
+ if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
+ txtype = (int)lr->lr_common.lrc_txtype;
+ if (txtype == TX_CREATE_ATTR || txtype == TX_MKDIR_ATTR)
+ zfs_replay_swap_attrs((lr_attr_t *)(lr + 1));
+ }
+
if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
return (error);
- zfs_init_vattr(&va, AT_TYPE | AT_MODE | AT_UID | AT_GID,
+ xva_init(&xva);
+ zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID,
lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);
/*
@@ -101,26 +424,77 @@ zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap)
* doesn't have either concept, so we smuggle the values inside
* the vattr's otherwise unused va_ctime and va_nblocks fields.
*/
- ZFS_TIME_DECODE(&va.va_ctime, lr->lr_crtime);
- va.va_nblocks = lr->lr_gen;
+ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
+ xva.xva_vattr.va_nblocks = lr->lr_gen;
error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL);
if (error != ENOENT)
goto out;
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+
+ /*
+ * Symlinks don't have fuid info, and CIFS never creates
+ * symlinks.
+ *
+ * The _ATTR versions will grab the fuid info in their subcases.
+ */
+ if ((int)lr->lr_common.lrc_txtype != TX_SYMLINK &&
+ (int)lr->lr_common.lrc_txtype != TX_MKDIR_ATTR &&
+ (int)lr->lr_common.lrc_txtype != TX_CREATE_ATTR) {
+ start = (lr + 1);
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuid_domain(start, &start,
+ lr->lr_uid, lr->lr_gid);
+ }
+
switch ((int)lr->lr_common.lrc_txtype) {
+ case TX_CREATE_ATTR:
+ lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva);
+ start = (caddr_t)(lr + 1) + xvatlen;
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuid_domain(start, &start,
+ lr->lr_uid, lr->lr_gid);
+ name = (char *)start;
+
+ /*FALLTHROUGH*/
case TX_CREATE:
- error = VOP_CREATE(ZTOV(dzp), name, &va, 0, 0, &vp, kcred, 0);
+ if (name == NULL)
+ name = (char *)start;
+
+ error = VOP_CREATE(ZTOV(dzp), name, &xva.xva_vattr,
+ 0, 0, &vp, kcred, vflg, NULL, NULL);
break;
+ case TX_MKDIR_ATTR:
+ lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva);
+ start = (caddr_t)(lr + 1) + xvatlen;
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuid_domain(start, &start,
+ lr->lr_uid, lr->lr_gid);
+ name = (char *)start;
+
+ /*FALLTHROUGH*/
case TX_MKDIR:
- error = VOP_MKDIR(ZTOV(dzp), name, &va, &vp, kcred);
+ if (name == NULL)
+ name = (char *)(lr + 1);
+
+ error = VOP_MKDIR(ZTOV(dzp), name, &xva.xva_vattr,
+ &vp, kcred, NULL, vflg, NULL);
break;
case TX_MKXATTR:
- error = zfs_make_xattrdir(dzp, &va, &vp, kcred);
+ name = (char *)(lr + 1);
+ error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &vp, kcred);
break;
case TX_SYMLINK:
+ name = (char *)(lr + 1);
link = name + strlen(name) + 1;
- error = VOP_SYMLINK(ZTOV(dzp), name, &va, link, kcred);
+ error = VOP_SYMLINK(ZTOV(dzp), name, &xva.xva_vattr,
+ link, kcred, NULL, vflg);
break;
default:
error = ENOTSUP;
@@ -132,6 +506,9 @@ out:
VN_RELE(ZTOV(dzp));
+ if (zfsvfs->z_fuid_replay)
+ zfs_fuid_info_free(zfsvfs->z_fuid_replay);
+ zfsvfs->z_fuid_replay = NULL;
return (error);
}
@@ -141,6 +518,7 @@ zfs_replay_remove(zfsvfs_t *zfsvfs, lr_remove_t *lr, boolean_t byteswap)
char *name = (char *)(lr + 1); /* name follows lr_remove_t */
znode_t *dzp;
int error;
+ int vflg = 0;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
@@ -148,12 +526,15 @@ zfs_replay_remove(zfsvfs_t *zfsvfs, lr_remove_t *lr, boolean_t byteswap)
if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
return (error);
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+
switch ((int)lr->lr_common.lrc_txtype) {
case TX_REMOVE:
- error = VOP_REMOVE(ZTOV(dzp), name, kcred);
+ error = VOP_REMOVE(ZTOV(dzp), name, kcred, NULL, vflg);
break;
case TX_RMDIR:
- error = VOP_RMDIR(ZTOV(dzp), name, NULL, kcred);
+ error = VOP_RMDIR(ZTOV(dzp), name, NULL, kcred, NULL, vflg);
break;
default:
error = ENOTSUP;
@@ -170,6 +551,7 @@ zfs_replay_link(zfsvfs_t *zfsvfs, lr_link_t *lr, boolean_t byteswap)
char *name = (char *)(lr + 1); /* name follows lr_link_t */
znode_t *dzp, *zp;
int error;
+ int vflg = 0;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
@@ -182,7 +564,10 @@ zfs_replay_link(zfsvfs_t *zfsvfs, lr_link_t *lr, boolean_t byteswap)
return (error);
}
- error = VOP_LINK(ZTOV(dzp), ZTOV(zp), name, kcred);
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+
+ error = VOP_LINK(ZTOV(dzp), ZTOV(zp), name, kcred, NULL, vflg);
VN_RELE(ZTOV(zp));
VN_RELE(ZTOV(dzp));
@@ -197,6 +582,7 @@ zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, boolean_t byteswap)
char *tname = sname + strlen(sname) + 1;
znode_t *sdzp, *tdzp;
int error;
+ int vflg = 0;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
@@ -209,7 +595,11 @@ zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, boolean_t byteswap)
return (error);
}
- error = VOP_RENAME(ZTOV(sdzp), sname, ZTOV(tdzp), tname, kcred);
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+
+ error = VOP_RENAME(ZTOV(sdzp), sname, ZTOV(tdzp), tname, kcred,
+ NULL, vflg);
VN_RELE(ZTOV(tdzp));
VN_RELE(ZTOV(sdzp));
@@ -286,12 +676,20 @@ static int
zfs_replay_setattr(zfsvfs_t *zfsvfs, lr_setattr_t *lr, boolean_t byteswap)
{
znode_t *zp;
- vattr_t va;
+ xvattr_t xva;
+ vattr_t *vap = &xva.xva_vattr;
int error;
+ void *start;
- if (byteswap)
+ xva_init(&xva);
+ if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
+ if ((lr->lr_mask & AT_XVATTR) &&
+ zfsvfs->z_version >= ZPL_VERSION_INITIAL)
+ zfs_replay_swap_attrs((lr_attr_t *)(lr + 1));
+ }
+
if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
/*
* As we can log setattrs out of order, it's possible the
@@ -303,33 +701,95 @@ zfs_replay_setattr(zfsvfs_t *zfsvfs, lr_setattr_t *lr, boolean_t byteswap)
return (error);
}
- zfs_init_vattr(&va, lr->lr_mask, lr->lr_mode,
+ zfs_init_vattr(vap, lr->lr_mask, lr->lr_mode,
lr->lr_uid, lr->lr_gid, 0, lr->lr_foid);
- va.va_size = lr->lr_size;
- ZFS_TIME_DECODE(&va.va_atime, lr->lr_atime);
- ZFS_TIME_DECODE(&va.va_mtime, lr->lr_mtime);
+ vap->va_size = lr->lr_size;
+ ZFS_TIME_DECODE(&vap->va_atime, lr->lr_atime);
+ ZFS_TIME_DECODE(&vap->va_mtime, lr->lr_mtime);
+
+ /*
+ * Fill in xvattr_t portions if necessary.
+ */
+
+ start = (lr_setattr_t *)(lr + 1);
+ if (vap->va_mask & AT_XVATTR) {
+ zfs_replay_xvattr((lr_attr_t *)start, &xva);
+ start = (caddr_t)start +
+ ZIL_XVAT_SIZE(((lr_attr_t *)start)->lr_attr_masksize);
+ } else
+ xva.xva_vattr.va_mask &= ~AT_XVATTR;
+
+ zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start,
+ lr->lr_uid, lr->lr_gid);
- error = VOP_SETATTR(ZTOV(zp), &va, 0, kcred, NULL);
+ error = VOP_SETATTR(ZTOV(zp), vap, 0, kcred, NULL);
+ zfs_fuid_info_free(zfsvfs->z_fuid_replay);
+ zfsvfs->z_fuid_replay = NULL;
VN_RELE(ZTOV(zp));
return (error);
}
static int
-zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
+zfs_replay_acl_v0(zfsvfs_t *zfsvfs, lr_acl_v0_t *lr, boolean_t byteswap)
{
ace_t *ace = (ace_t *)(lr + 1); /* ace array follows lr_acl_t */
vsecattr_t vsa;
znode_t *zp;
int error;
+ if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
+ /*
+ * As we can log acls out of order, it's possible the
+ * file has been removed. In this case just drop the acl
+ * and return success.
+ */
+ if (error == ENOENT)
+ error = 0;
+ return (error);
+ }
+
if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
- zfs_ace_byteswap(ace, lr->lr_aclcnt);
+ zfs_oldace_byteswap(ace, lr->lr_aclcnt);
}
+ bzero(&vsa, sizeof (vsa));
+ vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
+ vsa.vsa_aclcnt = lr->lr_aclcnt;
+ vsa.vsa_aclentp = ace;
+
+ error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred, NULL);
+
+ VN_RELE(ZTOV(zp));
+
+ return (error);
+}
+
+/*
+ * Replaying ACLs is complicated by FUID support.
+ * The log record may contain some optional data
+ * to be used for replaying FUID's. These pieces
+ * are the actual FUIDs that were created initially.
+ * The FUID table index may no longer be valid and
+ * during zfs_create() a new index may be assigned.
+ * Because of this the log will contain the original
+ * doman+rid in order to create a new FUID.
+ *
+ * The individual ACEs may contain an ephemeral uid/gid which is no
+ * longer valid and will need to be replaced with an actual FUID.
+ *
+ */
+static int
+zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
+{
+ ace_t *ace = (ace_t *)(lr + 1);
+ vsecattr_t vsa;
+ znode_t *zp;
+ int error;
+
if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
/*
* As we can log acls out of order, it's possible the
@@ -341,13 +801,36 @@ zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
return (error);
}
+ if (byteswap) {
+ byteswap_uint64_array(lr, sizeof (*lr));
+ zfs_ace_byteswap(ace, lr->lr_acl_bytes, B_FALSE);
+ if (lr->lr_fuidcnt) {
+ byteswap_uint64_array((caddr_t)ace + lr->lr_acl_bytes,
+ lr->lr_fuidcnt * sizeof (uint64_t));
+ }
+ }
+
bzero(&vsa, sizeof (vsa));
- vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
+ vsa.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
vsa.vsa_aclcnt = lr->lr_aclcnt;
vsa.vsa_aclentp = ace;
+ vsa.vsa_aclentsz = lr->lr_acl_bytes;
+ vsa.vsa_aclflags = lr->lr_acl_flags;
+
+ if (lr->lr_fuidcnt) {
+ void *fuidstart = (caddr_t)ace + lr->lr_acl_bytes;
+
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuids(fuidstart, &fuidstart,
+ lr->lr_fuidcnt, lr->lr_domcnt, 0, 0);
+ }
+
+ error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred, NULL);
- error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred);
+ if (zfsvfs->z_fuid_replay)
+ zfs_fuid_info_free(zfsvfs->z_fuid_replay);
+ zfsvfs->z_fuid_replay = NULL;
VN_RELE(ZTOV(zp));
return (error);
@@ -369,5 +852,12 @@ zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE] = {
zfs_replay_write, /* TX_WRITE */
zfs_replay_truncate, /* TX_TRUNCATE */
zfs_replay_setattr, /* TX_SETATTR */
+ zfs_replay_acl_v0, /* TX_ACL_V0 */
zfs_replay_acl, /* TX_ACL */
+ zfs_replay_create_acl, /* TX_CREATE_ACL */
+ zfs_replay_create, /* TX_CREATE_ATTR */
+ zfs_replay_create_acl, /* TX_CREATE_ACL_ATTR */
+ zfs_replay_create_acl, /* TX_MKDIR_ACL */
+ zfs_replay_create, /* TX_MKDIR_ATTR */
+ zfs_replay_create_acl, /* TX_MKDIR_ACL_ATTR */
};
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index 0736cb3224..4106ca8f2f 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -40,6 +40,7 @@
#include "fs/fs_subr.h"
#include <sys/zfs_znode.h>
#include <sys/zfs_dir.h>
+#include <sys/zfs_i18n.h>
#include <sys/zil.h>
#include <sys/fs/zfs.h>
#include <sys/dmu.h>
@@ -56,6 +57,7 @@
#include <sys/refstr.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
#include <sys/bootconf.h>
#include <sys/sunddi.h>
#include <sys/dnlc.h>
@@ -329,6 +331,27 @@ exec_changed_cb(void *arg, uint64_t newval)
}
}
+/*
+ * The nbmand mount option can be changed at mount time.
+ * We can't allow it to be toggled on live file systems or incorrect
+ * behavior may be seen from cifs clients
+ *
+ * This property isn't registered via dsl_prop_register(), but this callback
+ * will be called when a file system is first mounted
+ */
+static void
+nbmand_changed_cb(void *arg, uint64_t newval)
+{
+ zfsvfs_t *zfsvfs = arg;
+ if (newval == FALSE) {
+ vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NBMAND);
+ vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NONBMAND, NULL, 0);
+ } else {
+ vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NONBMAND);
+ vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NBMAND, NULL, 0);
+ }
+}
+
static void
snapdir_changed_cb(void *arg, uint64_t newval)
{
@@ -338,6 +361,14 @@ snapdir_changed_cb(void *arg, uint64_t newval)
}
static void
+vscan_changed_cb(void *arg, uint64_t newval)
+{
+ zfsvfs_t *zfsvfs = arg;
+
+ zfsvfs->z_vscan = newval;
+}
+
+static void
acl_mode_changed_cb(void *arg, uint64_t newval)
{
zfsvfs_t *zfsvfs = arg;
@@ -354,17 +385,85 @@ acl_inherit_changed_cb(void *arg, uint64_t newval)
}
static int
+zfs_normalization_set(char *osname, zfsvfs_t *zfsvfs)
+{
+ uint64_t pval;
+ int error;
+
+ if (zfsvfs->z_version < ZPL_VERSION_FUID)
+ return (0);
+
+ error = dsl_prop_get_integer(osname, "normalization", &pval, NULL);
+ if (error)
+ goto normquit;
+ switch ((int)pval) {
+ case ZFS_NORMALIZE_NONE:
+ break;
+ case ZFS_NORMALIZE_C:
+ zfsvfs->z_norm |= U8_TEXTPREP_NFC;
+ break;
+ case ZFS_NORMALIZE_KC:
+ zfsvfs->z_norm |= U8_TEXTPREP_NFKC;
+ break;
+ case ZFS_NORMALIZE_D:
+ zfsvfs->z_norm |= U8_TEXTPREP_NFD;
+ break;
+ case ZFS_NORMALIZE_KD:
+ zfsvfs->z_norm |= U8_TEXTPREP_NFKD;
+ break;
+ default:
+ ASSERT(pval <= ZFS_NORMALIZE_KD);
+ break;
+ }
+
+ error = dsl_prop_get_integer(osname, "utf8only", &pval, NULL);
+ if (error)
+ goto normquit;
+ if (pval)
+ zfsvfs->z_case |= ZFS_UTF8_ONLY;
+ else
+ zfsvfs->z_case &= ~ZFS_UTF8_ONLY;
+
+ error = dsl_prop_get_integer(osname, "casesensitivity", &pval, NULL);
+ if (error)
+ goto normquit;
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_DIRENTFLAGS);
+ switch ((int)pval) {
+ case ZFS_CASE_SENSITIVE:
+ break;
+ case ZFS_CASE_INSENSITIVE:
+ zfsvfs->z_norm |= U8_TEXTPREP_TOUPPER;
+ zfsvfs->z_case |= ZFS_CI_ONLY;
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_CASEINSENSITIVE);
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_NOCASESENSITIVE);
+ break;
+ case ZFS_CASE_MIXED:
+ zfsvfs->z_norm |= U8_TEXTPREP_TOUPPER;
+ zfsvfs->z_case |= ZFS_CI_MIXD;
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_CASEINSENSITIVE);
+ break;
+ default:
+ ASSERT(pval <= ZFS_CASE_MIXED);
+ break;
+ }
+
+normquit:
+ return (error);
+}
+
+static int
zfs_register_callbacks(vfs_t *vfsp)
{
struct dsl_dataset *ds = NULL;
objset_t *os = NULL;
zfsvfs_t *zfsvfs = NULL;
- int readonly, do_readonly = FALSE;
- int setuid, do_setuid = FALSE;
- int exec, do_exec = FALSE;
- int devices, do_devices = FALSE;
- int xattr, do_xattr = FALSE;
- int atime, do_atime = FALSE;
+ uint64_t nbmand;
+ int readonly, do_readonly = B_FALSE;
+ int setuid, do_setuid = B_FALSE;
+ int exec, do_exec = B_FALSE;
+ int devices, do_devices = B_FALSE;
+ int xattr, do_xattr = B_FALSE;
+ int atime, do_atime = B_FALSE;
int error = 0;
ASSERT(vfsp);
@@ -430,6 +529,26 @@ zfs_register_callbacks(vfs_t *vfsp)
}
/*
+ * nbmand is a special property. It can only be changed at
+ * mount time.
+ *
+ * This is weird, but it is documented to only be changeable
+ * at mount time.
+ */
+ if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) {
+ nbmand = B_FALSE;
+ } else if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) {
+ nbmand = B_TRUE;
+ } else {
+ char osname[MAXNAMELEN];
+
+ dmu_objset_name(os, osname);
+ if (error = dsl_prop_get_integer(osname, "nbmand", &nbmand,
+ NULL))
+ return (error);
+ }
+
+ /*
* Register property callbacks.
*
* It would probably be fine to just check for i/o error from
@@ -456,6 +575,8 @@ zfs_register_callbacks(vfs_t *vfsp)
"aclmode", acl_mode_changed_cb, zfsvfs);
error = error ? error : dsl_prop_register(ds,
"aclinherit", acl_inherit_changed_cb, zfsvfs);
+ error = error ? error : dsl_prop_register(ds,
+ "vscan", vscan_changed_cb, zfsvfs);
if (error)
goto unregister;
@@ -475,6 +596,8 @@ zfs_register_callbacks(vfs_t *vfsp)
if (do_atime)
atime_changed_cb(zfsvfs, atime);
+ nbmand_changed_cb(zfsvfs, nbmand);
+
return (0);
unregister:
@@ -494,6 +617,7 @@ unregister:
(void) dsl_prop_unregister(ds, "aclmode", acl_mode_changed_cb, zfsvfs);
(void) dsl_prop_unregister(ds, "aclinherit", acl_inherit_changed_cb,
zfsvfs);
+ (void) dsl_prop_unregister(ds, "vscan", vscan_changed_cb, zfsvfs);
return (error);
}
@@ -643,15 +767,34 @@ zfs_domount(vfs_t *vfsp, char *osname, cred_t *cr)
/* The call to zfs_init_fs leaves the vnode held, release it here. */
VN_RELE(ZTOV(zp));
+ /*
+ * Set features for file system.
+ */
+ zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os);
+ if (zfsvfs->z_use_fuids) {
+ vfs_set_feature(vfsp, VFSFT_XVATTR);
+ vfs_set_feature(vfsp, VFSFT_ACEMASKONACCESS);
+ vfs_set_feature(vfsp, VFSFT_ACLONCREATE);
+ }
+
+ /*
+ * Set normalization regardless of whether or not the object
+ * set is a snapshot. Snapshots and clones need to have
+ * identical normalization as did the file system they
+ * originated from.
+ */
+ if ((error = zfs_normalization_set(osname, zfsvfs)) != 0)
+ goto out;
+
if (dmu_objset_is_snapshot(zfsvfs->z_os)) {
- uint64_t xattr;
+ uint64_t pval;
ASSERT(mode & DS_MODE_READONLY);
atime_changed_cb(zfsvfs, B_FALSE);
readonly_changed_cb(zfsvfs, B_TRUE);
- if (error = dsl_prop_get_integer(osname, "xattr", &xattr, NULL))
+ if (error = dsl_prop_get_integer(osname, "xattr", &pval, NULL))
goto out;
- xattr_changed_cb(zfsvfs, xattr);
+ xattr_changed_cb(zfsvfs, pval);
zfsvfs->z_issnap = B_TRUE;
} else {
error = zfsvfs_setup(zfsvfs, B_TRUE);
@@ -715,6 +858,9 @@ zfs_unregister_callbacks(zfsvfs_t *zfsvfs)
VERIFY(dsl_prop_unregister(ds, "aclinherit",
acl_inherit_changed_cb, zfsvfs) == 0);
+
+ VERIFY(dsl_prop_unregister(ds, "vscan",
+ vscan_changed_cb, zfsvfs) == 0);
}
}
@@ -916,7 +1062,7 @@ zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
vattr.va_mask = AT_UID;
- if (error = VOP_GETATTR(mvp, &vattr, 0, cr)) {
+ if (error = VOP_GETATTR(mvp, &vattr, 0, cr, NULL)) {
goto out;
}
@@ -924,7 +1070,7 @@ zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
goto out;
}
- if (error = VOP_ACCESS(mvp, VWRITE, 0, cr)) {
+ if (error = VOP_ACCESS(mvp, VWRITE, 0, cr, NULL)) {
goto out;
}
@@ -1301,7 +1447,7 @@ zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
ASSERT(*vpp != NULL);
if (object == ZFSCTL_INO_SNAPDIR) {
VERIFY(zfsctl_root_lookup(*vpp, "snapshot", vpp, NULL,
- 0, NULL, NULL) == 0);
+ 0, NULL, NULL, NULL, NULL, NULL) == 0);
} else {
VN_HOLD(*vpp);
}
@@ -1415,6 +1561,7 @@ zfs_freevfs(vfs_t *vfsp)
list_destroy(&zfsvfs->z_all_znodes);
rrw_destroy(&zfsvfs->z_teardown_lock);
rw_destroy(&zfsvfs->z_teardown_inactive_lock);
+ zfs_fuid_destroy(zfsvfs);
kmem_free(zfsvfs, sizeof (zfsvfs_t));
atomic_add_32(&zfs_active_fs_count, -1);
@@ -1553,7 +1700,8 @@ static vfsdef_t vfw = {
VFSDEF_VERSION,
MNTTYPE_ZFS,
zfs_vfsinit,
- VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_VOLATILEDEV|VSW_STATS,
+ VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_VOLATILEDEV|VSW_STATS|
+ VSW_XID,
&zfs_mntopts
};
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 2e6405be7a..573f746e72 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -56,6 +56,7 @@
#include <sys/zfs_dir.h>
#include <sys/zfs_acl.h>
#include <sys/zfs_ioctl.h>
+#include <sys/zfs_i18n.h>
#include <sys/fs/zfs.h>
#include <sys/dmu.h>
#include <sys/spa.h>
@@ -68,8 +69,12 @@
#include <sys/filio.h>
#include "fs/fs_subr.h"
#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
#include <sys/dnlc.h>
#include <sys/zfs_rlock.h>
+#include <sys/extdirent.h>
+#include <sys/kidmap.h>
+#include <sys/cred_impl.h>
/*
* Programming rules.
@@ -77,8 +82,8 @@
* Each vnode op performs some logical unit of work. To do this, the ZPL must
* properly lock its in-core state, create a DMU transaction, do the work,
* record this work in the intent log (ZIL), commit the DMU transaction,
- * and wait the the intent log to commit if it's is a synchronous operation.
- * Morover, the vnode ops must work in both normal and log replay context.
+ * and wait for the intent log to commit if it is a synchronous operation.
+ * Moreover, the vnode ops must work in both normal and log replay context.
* The ordering of events is important to avoid deadlocks and references
* to freed memory. The example below illustrates the following Big Rules:
*
@@ -160,19 +165,33 @@
*/
/* ARGSUSED */
static int
-zfs_open(vnode_t **vpp, int flag, cred_t *cr)
+zfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(*vpp);
+ if ((flag & FWRITE) && (zp->z_phys->zp_flags & ZFS_APPENDONLY) &&
+ ((flag & FAPPEND) == 0)) {
+ return (EPERM);
+ }
+
+ if (!zfs_has_ctldir(zp) && zp->z_zfsvfs->z_vscan &&
+ ZTOV(zp)->v_type == VREG &&
+ !(zp->z_phys->zp_flags & ZFS_AV_QUARANTINED) &&
+ zp->z_phys->zp_size > 0)
+ if (fs_vscan(*vpp, cr, 0) != 0)
+ return (EACCES);
+
/* Keep a count of the synchronous opens in the znode */
if (flag & (FSYNC | FDSYNC))
atomic_inc_32(&zp->z_sync_cnt);
+
return (0);
}
/* ARGSUSED */
static int
-zfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+zfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
@@ -186,6 +205,12 @@ zfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
cleanlocks(vp, ddi_get_pid(), 0);
cleanshares(vp, ddi_get_pid());
+ if (!zfs_has_ctldir(zp) && zp->z_zfsvfs->z_vscan &&
+ ZTOV(zp)->v_type == VREG &&
+ !(zp->z_phys->zp_flags & ZFS_AV_QUARANTINED) &&
+ zp->z_phys->zp_size > 0)
+ VERIFY(fs_vscan(vp, cr, 1) == 0);
+
return (0);
}
@@ -235,7 +260,7 @@ zfs_holey(vnode_t *vp, int cmd, offset_t *off)
/* ARGSUSED */
static int
zfs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
offset_t off;
int error;
@@ -386,6 +411,7 @@ offset_t zfs_read_chunk_size = 1024 * 1024; /* Tunable */
* and return buffer.
* ioflag - SYNC flags; used to provide FRSYNC semantics.
* cr - credentials of caller.
+ * ct - caller context
*
* OUT: uio - updated offset and range, buffer filled.
*
@@ -552,6 +578,7 @@ zfs_prefault_write(ssize_t n, struct uio *uio)
* and data buffer.
* ioflag - FAPPEND flag set if in append mode.
* cr - credentials of caller.
+ * ct - caller context (NFS/CIFS fem monitor only)
*
* OUT: uio - updated offset and range.
*
@@ -577,9 +604,18 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
ssize_t n, nbytes;
rl_t *rl;
int max_blksz = zfsvfs->z_max_blksz;
+ uint64_t pflags = zp->z_phys->zp_flags;
int error;
/*
+ * If immutable or not appending then return EPERM
+ */
+ if ((pflags & (ZFS_IMMUTABLE | ZFS_READONLY)) ||
+ ((pflags & ZFS_APPENDONLY) && !(ioflag & FAPPEND) &&
+ (uio->uio_loffset < zp->z_phys->zp_size)))
+ return (EPERM);
+
+ /*
* Fasttrack empty write
*/
n = start_resid;
@@ -734,6 +770,9 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
* It would be nice to to this after all writes have
* been done, but that would still expose the ISUID/ISGID
* to another app after the partial write is committed.
+ *
+ * Note: we don't call zfs_fuid_map_id() here because
+ * user 0 is not an ephemeral uid.
*/
mutex_enter(&zp->z_acl_lock);
if ((zp->z_phys->zp_mode & (S_IXUSR | (S_IXUSR >> 3) |
@@ -905,14 +944,20 @@ out:
/*ARGSUSED*/
static int
-zfs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+zfs_access(vnode_t *vp, int mode, int flag, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
- error = zfs_zaccess_rwx(zp, mode, cr);
+
+ if (flag & V_ACE_MASK)
+ error = zfs_zaccess(zp, mode, flag, B_FALSE, cr);
+ else
+ error = zfs_zaccess_rwx(zp, mode, flag, cr);
+
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -927,6 +972,9 @@ zfs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
* flags - LOOKUP_XATTR set if looking for an attribute.
* rdir - root directory vnode [UNUSED].
* cr - credentials of caller.
+ * ct - caller context
+ * direntflags - directory lookup flags
+ * realpnp - returned pathname.
*
* OUT: vpp - vnode of located entry, NULL if not found.
*
@@ -939,9 +987,9 @@ zfs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
/* ARGSUSED */
static int
zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
-
znode_t *zdp = VTOZ(dvp);
zfsvfs_t *zfsvfs = zdp->z_zfsvfs;
int error;
@@ -977,8 +1025,10 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* Do we have permission to get into attribute directory?
*/
- if (error = zfs_zaccess(VTOZ(*vpp), ACE_EXECUTE, cr)) {
+ if (error = zfs_zaccess(VTOZ(*vpp), ACE_EXECUTE, 0,
+ B_FALSE, cr)) {
VN_RELE(*vpp);
+ *vpp = NULL;
}
ZFS_EXIT(zfsvfs);
@@ -994,13 +1044,19 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* Check accessibility of directory.
*/
- if (error = zfs_zaccess(zdp, ACE_EXECUTE, cr)) {
+ if (error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr)) {
ZFS_EXIT(zfsvfs);
return (error);
}
- if ((error = zfs_dirlook(zdp, nm, vpp)) == 0) {
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(nm, strlen(nm),
+ NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+ error = zfs_dirlook(zdp, nm, vpp, flags, direntflags, realpnp);
+ if (error == 0) {
/*
* Convert device special files
*/
@@ -1032,6 +1088,8 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* mode - mode to open file with.
* cr - credentials of caller.
* flag - large file flag [UNUSED].
+ * ct - caller context
+ * vsecp - ACL to be set
*
* OUT: vpp - vnode of created or trunc'd entry.
*
@@ -1042,10 +1100,12 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* dvp - ctime|mtime updated if new entry created
* vp - ctime|mtime always, atime if new
*/
+
/* ARGSUSED */
static int
zfs_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
znode_t *zp, *dzp = VTOZ(dvp);
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
@@ -1055,11 +1115,36 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
dmu_tx_t *tx;
int error;
uint64_t zoid;
+ zfs_acl_t *aclp = NULL;
+ zfs_fuid_info_t *fuidp = NULL;
+
+ /*
+ * If we have an ephemeral id, ACL, or XVATTR then
+ * make sure file system is at proper version
+ */
+
+ if (zfsvfs->z_use_fuids == B_FALSE &&
+ (vsecp || (vap->va_mask & AT_XVATTR) ||
+ IS_EPHEMERAL(crgetuid(cr)) || IS_EPHEMERAL(crgetgid(cr))))
+ return (EINVAL);
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
os = zfsvfs->z_os;
zilog = zfsvfs->z_log;
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(name, strlen(name),
+ NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+
+ if (vap->va_mask & AT_XVATTR) {
+ if ((error = secpolicy_xvattr((xvattr_t *)vap,
+ crgetuid(cr), cr, vap->va_type)) != 0) {
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
+ }
top:
*vpp = NULL;
@@ -1076,22 +1161,41 @@ top:
error = 0;
} else {
/* possible VN_HOLD(zp) */
- if (error = zfs_dirent_lock(&dl, dzp, name, &zp, 0)) {
+ int zflg = 0;
+
+ if (flag & FIGNORECASE)
+ zflg |= ZCILOOK;
+
+ error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
+ NULL, NULL);
+ if (error) {
if (strcmp(name, "..") == 0)
error = EISDIR;
ZFS_EXIT(zfsvfs);
+ if (aclp)
+ zfs_acl_free(aclp);
+ return (error);
+ }
+ }
+ if (vsecp && aclp == NULL) {
+ error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, &aclp);
+ if (error) {
+ ZFS_EXIT(zfsvfs);
+ if (dl)
+ zfs_dirent_unlock(dl);
return (error);
}
}
-
zoid = zp ? zp->z_id : -1ULL;
if (zp == NULL) {
+ uint64_t txtype;
+
/*
* Create a new file object and update the directory
* to reference it.
*/
- if (error = zfs_zaccess(dzp, ACE_ADD_FILE, cr)) {
+ if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) {
goto out;
}
@@ -1107,11 +1211,22 @@ top:
tx = dmu_tx_create(os);
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
dmu_tx_hold_bonus(tx, dzp->z_id);
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
- if (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)
+ if ((dzp->z_phys->zp_flags & ZFS_INHERIT_ACE) || aclp) {
dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
0, SPA_MAXBLOCKSIZE);
+ }
error = dmu_tx_assign(tx, zfsvfs->z_assign);
if (error) {
zfs_dirent_unlock(dl);
@@ -1123,14 +1238,24 @@ top:
}
dmu_tx_abort(tx);
ZFS_EXIT(zfsvfs);
+ if (aclp)
+ zfs_acl_free(aclp);
return (error);
}
- zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0);
+ zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0, aclp, &fuidp);
ASSERT(zp->z_id == zoid);
(void) zfs_link_create(dl, zp, tx, ZNEW);
- zfs_log_create(zilog, tx, TX_CREATE, dzp, zp, name);
+ txtype = zfs_log_create_txtype(Z_FILE, vsecp, vap);
+ if (flag & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_create(zilog, tx, txtype, dzp, zp, name,
+ vsecp, fuidp, vap);
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
dmu_tx_commit(tx);
} else {
+ int aflags = (flag & FAPPEND) ? V_APPEND : 0;
+
/*
* A directory entry already exists for this name.
*/
@@ -1151,7 +1276,7 @@ top:
/*
* Verify requested access to file.
*/
- if (mode && (error = zfs_zaccess_rwx(zp, mode, cr))) {
+ if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr))) {
goto out;
}
@@ -1174,7 +1299,7 @@ top:
}
if (error == 0) {
- vnevent_create(ZTOV(zp));
+ vnevent_create(ZTOV(zp), ct);
}
}
}
@@ -1202,6 +1327,8 @@ out:
*vpp = svp;
}
}
+ if (aclp)
+ zfs_acl_free(aclp);
ZFS_EXIT(zfsvfs);
return (error);
@@ -1213,6 +1340,8 @@ out:
* IN: dvp - vnode of directory to remove entry from.
* name - name of entry to remove.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* RETURN: 0 if success
* error code if failure
@@ -1221,8 +1350,10 @@ out:
* dvp - ctime|mtime
* vp - ctime (if nlink > 0)
*/
+/*ARGSUSED*/
static int
-zfs_remove(vnode_t *dvp, char *name, cred_t *cr)
+zfs_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct,
+ int flags)
{
znode_t *zp, *dzp = VTOZ(dvp);
znode_t *xzp = NULL;
@@ -1234,16 +1365,29 @@ zfs_remove(vnode_t *dvp, char *name, cred_t *cr)
dmu_tx_t *tx;
boolean_t may_delete_now, delete_now = FALSE;
boolean_t unlinked;
+ uint64_t txtype;
+ pathname_t *realnmp = NULL;
+ pathname_t realnm;
int error;
+ int zflg = ZEXISTS;
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
+ if (flags & FIGNORECASE) {
+ zflg |= ZCILOOK;
+ pn_alloc(&realnm);
+ realnmp = &realnm;
+ }
+
top:
/*
* Attempt to lock directory; fail if entry doesn't exist.
*/
- if (error = zfs_dirent_lock(&dl, dzp, name, &zp, ZEXISTS)) {
+ if (error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
+ NULL, realnmp)) {
+ if (realnmp)
+ pn_free(realnmp);
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -1262,9 +1406,12 @@ top:
goto out;
}
- vnevent_remove(vp, dvp, name);
+ vnevent_remove(vp, dvp, name, ct);
- dnlc_remove(dvp, name);
+ if (realnmp)
+ dnlc_remove(dvp, realnmp->pn_path);
+ else
+ dnlc_remove(dvp, name);
mutex_enter(&vp->v_lock);
may_delete_now = vp->v_count == 1 && !vn_has_cached_data(vp);
@@ -1305,6 +1452,8 @@ top:
dmu_tx_abort(tx);
goto top;
}
+ if (realnmp)
+ pn_free(realnmp);
dmu_tx_abort(tx);
ZFS_EXIT(zfsvfs);
return (error);
@@ -1313,7 +1462,7 @@ top:
/*
* Remove the directory entry.
*/
- error = zfs_link_destroy(dl, zp, tx, 0, &unlinked);
+ error = zfs_link_destroy(dl, zp, tx, zflg, &unlinked);
if (error) {
dmu_tx_commit(tx);
@@ -1354,10 +1503,16 @@ top:
zfs_unlinked_add(zp, tx);
}
- zfs_log_remove(zilog, tx, TX_REMOVE, dzp, name);
+ txtype = TX_REMOVE;
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_remove(zilog, tx, txtype, dzp, name);
dmu_tx_commit(tx);
out:
+ if (realnmp)
+ pn_free(realnmp);
+
zfs_dirent_unlock(dl);
if (!delete_now) {
@@ -1379,6 +1534,8 @@ out:
* dirname - name of new directory.
* vap - attributes of new directory.
* cr - credentials of caller.
+ * ct - caller context
+ * vsecp - ACL to be set
*
* OUT: vpp - vnode of created directory.
*
@@ -1389,19 +1546,35 @@ out:
* dvp - ctime|mtime updated
* vp - ctime|mtime|atime updated
*/
+/*ARGSUSED*/
static int
-zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr)
+zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr,
+ caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
znode_t *zp, *dzp = VTOZ(dvp);
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
zilog_t *zilog;
zfs_dirlock_t *dl;
uint64_t zoid = 0;
+ uint64_t txtype;
dmu_tx_t *tx;
int error;
+ zfs_acl_t *aclp = NULL;
+ zfs_fuid_info_t *fuidp = NULL;
+ int zf = ZNEW;
ASSERT(vap->va_type == VDIR);
+ /*
+ * If we have an ephemeral id, ACL, or XVATTR then
+ * make sure file system is at proper version
+ */
+
+ if (zfsvfs->z_use_fuids == B_FALSE &&
+ (vsecp || (vap->va_mask & AT_XVATTR) || IS_EPHEMERAL(crgetuid(cr))||
+ IS_EPHEMERAL(crgetgid(cr))))
+ return (EINVAL);
+
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
@@ -1409,30 +1582,65 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr)
ZFS_EXIT(zfsvfs);
return (EINVAL);
}
-top:
- *vpp = NULL;
+
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(dirname,
+ strlen(dirname), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+ if (flags & FIGNORECASE)
+ zf |= ZCILOOK;
+
+ if (vap->va_mask & AT_XVATTR)
+ if ((error = secpolicy_xvattr((xvattr_t *)vap,
+ crgetuid(cr), cr, vap->va_type)) != 0) {
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
/*
* First make sure the new directory doesn't exist.
*/
- if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, ZNEW)) {
+top:
+ *vpp = NULL;
+
+ if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf,
+ NULL, NULL)) {
ZFS_EXIT(zfsvfs);
return (error);
}
- if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, cr)) {
+ if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) {
zfs_dirent_unlock(dl);
ZFS_EXIT(zfsvfs);
return (error);
}
+ if (vsecp && aclp == NULL) {
+ error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, &aclp);
+ if (error) {
+ zfs_dirent_unlock(dl);
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
+ }
/*
* Add a new entry to the directory.
*/
tx = dmu_tx_create(zfsvfs->z_os);
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, dirname);
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
- if (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
+ if ((dzp->z_phys->zp_flags & ZFS_INHERIT_ACE) || aclp)
dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
0, SPA_MAXBLOCKSIZE);
error = dmu_tx_assign(tx, zfsvfs->z_assign);
@@ -1445,13 +1653,18 @@ top:
}
dmu_tx_abort(tx);
ZFS_EXIT(zfsvfs);
+ if (aclp)
+ zfs_acl_free(aclp);
return (error);
}
/*
* Create new node.
*/
- zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0);
+ zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0, aclp, &fuidp);
+
+ if (aclp)
+ zfs_acl_free(aclp);
/*
* Now put new name in parent dir.
@@ -1460,7 +1673,13 @@ top:
*vpp = ZTOV(zp);
- zfs_log_create(zilog, tx, TX_MKDIR, dzp, zp, dirname);
+ txtype = zfs_log_create_txtype(Z_DIR, vsecp, vap);
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_create(zilog, tx, txtype, dzp, zp, dirname, vsecp, fuidp, vap);
+
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
dmu_tx_commit(tx);
zfs_dirent_unlock(dl);
@@ -1478,6 +1697,8 @@ top:
* name - name of directory to be removed.
* cwd - vnode of current working directory.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* RETURN: 0 if success
* error code if failure
@@ -1485,8 +1706,10 @@ top:
* Timestamps:
* dvp - ctime|mtime updated
*/
+/*ARGSUSED*/
static int
-zfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
+zfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr,
+ caller_context_t *ct, int flags)
{
znode_t *dzp = VTOZ(dvp);
znode_t *zp;
@@ -1496,17 +1719,21 @@ zfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
zfs_dirlock_t *dl;
dmu_tx_t *tx;
int error;
+ int zflg = ZEXISTS;
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
+ if (flags & FIGNORECASE)
+ zflg |= ZCILOOK;
top:
zp = NULL;
/*
* Attempt to lock directory; fail if entry doesn't exist.
*/
- if (error = zfs_dirent_lock(&dl, dzp, name, &zp, ZEXISTS)) {
+ if (error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
+ NULL, NULL)) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -1527,7 +1754,7 @@ top:
goto out;
}
- vnevent_rmdir(vp, dvp, name);
+ vnevent_rmdir(vp, dvp, name, ct);
/*
* Grab a lock on the directory to make sure that noone is
@@ -1561,10 +1788,14 @@ top:
return (error);
}
- error = zfs_link_destroy(dl, zp, tx, 0, NULL);
+ error = zfs_link_destroy(dl, zp, tx, zflg, NULL);
- if (error == 0)
- zfs_log_remove(zilog, tx, TX_RMDIR, dzp, name);
+ if (error == 0) {
+ uint64_t txtype = TX_RMDIR;
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_remove(zilog, tx, txtype, dzp, name);
+ }
dmu_tx_commit(tx);
@@ -1588,6 +1819,8 @@ out:
* uio - structure supplying read location, range info,
* and return buffer.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* OUT: uio - updated offset and range, buffer filled.
* eofp - set to true if end-of-file detected.
@@ -1605,10 +1838,12 @@ out:
*/
/* ARGSUSED */
static int
-zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
+zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
znode_t *zp = VTOZ(vp);
iovec_t *iovp;
+ edirent_t *eodp;
dirent64_t *odp;
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
objset_t *os;
@@ -1681,6 +1916,7 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
bufsize = bytes_wanted;
odp = (struct dirent64 *)iovp->iov_base;
}
+ eodp = (struct edirent *)odp;
/*
* Transform to file-system independent format
@@ -1696,12 +1932,15 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
*/
if (offset == 0) {
(void) strcpy(zap.za_name, ".");
+ zap.za_normalization_conflict = 0;
objnum = zp->z_id;
} else if (offset == 1) {
(void) strcpy(zap.za_name, "..");
+ zap.za_normalization_conflict = 0;
objnum = zp->z_phys->zp_parent;
} else if (offset == 2 && zfs_show_ctldir(zp)) {
(void) strcpy(zap.za_name, ZFS_CTLDIR_NAME);
+ zap.za_normalization_conflict = 0;
objnum = ZFSCTL_INO_ROOT;
} else {
/*
@@ -1730,7 +1969,11 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
* uint8_t type = ZFS_DIRENT_TYPE(zap.za_first_integer);
*/
}
- reclen = DIRENT64_RECLEN(strlen(zap.za_name));
+
+ if (flags & V_RDDIR_ENTFLAGS)
+ reclen = EDIRENT_RECLEN(strlen(zap.za_name));
+ else
+ reclen = DIRENT64_RECLEN(strlen(zap.za_name));
/*
* Will this entry fit in the buffer?
@@ -1745,17 +1988,32 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
}
break;
}
- /*
- * Add this entry:
- */
- odp->d_ino = objnum;
- odp->d_reclen = reclen;
- /* NOTE: d_off is the offset for the *next* entry */
- next = &(odp->d_off);
- (void) strncpy(odp->d_name, zap.za_name,
- DIRENT64_NAMELEN(reclen));
+ if (flags & V_RDDIR_ENTFLAGS) {
+ /*
+ * Add extended flag entry:
+ */
+ eodp->ed_ino = objnum;
+ eodp->ed_reclen = reclen;
+ /* NOTE: ed_off is the offset for the *next* entry */
+ next = &(eodp->ed_off);
+ eodp->ed_eflags = zap.za_normalization_conflict ?
+ ED_CASE_CONFLICT : 0;
+ (void) strncpy(eodp->ed_name, zap.za_name,
+ EDIRENT_NAMELEN(reclen));
+ eodp = (edirent_t *)((intptr_t)eodp + reclen);
+ } else {
+ /*
+ * Add normal entry:
+ */
+ odp->d_ino = objnum;
+ odp->d_reclen = reclen;
+ /* NOTE: d_off is the offset for the *next* entry */
+ next = &(odp->d_off);
+ (void) strncpy(odp->d_name, zap.za_name,
+ DIRENT64_NAMELEN(reclen));
+ odp = (dirent64_t *)((intptr_t)odp + reclen);
+ }
outcount += reclen;
- odp = (dirent64_t *)((intptr_t)odp + reclen);
ASSERT(outcount <= bufsize);
@@ -1805,7 +2063,7 @@ update:
ulong_t zfs_fsync_sync_cnt = 4;
static int
-zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -1818,7 +2076,7 @@ zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
*/
if (vn_has_cached_data(vp) && !(syncflag & FNODSYNC) &&
(vp->v_type == VREG) && !(IS_SWAPVP(vp)))
- (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_ASYNC, cr, ct);
(void) tsd_set(zfs_fsyncer_key, (void *)zfs_fsync_sync_cnt);
@@ -1828,14 +2086,17 @@ zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
return (0);
}
+
/*
* Get the requested file attributes and place them in the provided
* vattr structure.
*
* IN: vp - vnode of file.
* vap - va_mask identifies requested attributes.
- * flags - [UNUSED]
+ * If AT_XVATTR set, then optional attrs are requested
+ * flags - ATTR_NOACLCHECK (CIFS server context)
* cr - credentials of caller.
+ * ct - caller context
*
* OUT: vap - attribute values.
*
@@ -1843,27 +2104,46 @@ zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
znode_phys_t *pzp;
- int error;
+ int error = 0;
uint64_t links;
+ xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */
+ xoptattr_t *xoap = NULL;
+ boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
pzp = zp->z_phys;
+ mutex_enter(&zp->z_lock);
+
+ /*
+ * If ACL is trivial don't bother looking for ACE_READ_ATTRIBUTES.
+ * Also, if we are the owner don't bother, since owner should
+ * always be allowed to read basic attributes of file.
+ */
+ if (!(pzp->zp_flags & ZFS_ACL_TRIVIAL) &&
+ (pzp->zp_uid != crgetuid(cr))) {
+ if (error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0,
+ skipaclchk, cr)) {
+ mutex_exit(&zp->z_lock);
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
+ }
+
/*
* Return all attributes. It's cheaper to provide the answer
* than to determine whether we were asked the question.
*/
- mutex_enter(&zp->z_lock);
vap->va_type = vp->v_type;
vap->va_mode = pzp->zp_mode & MODEMASK;
- vap->va_uid = zp->z_phys->zp_uid;
- vap->va_gid = zp->z_phys->zp_gid;
+ zfs_fuid_map_ids(zp, &vap->va_uid, &vap->va_gid);
vap->va_fsid = zp->z_zfsvfs->z_vfs->vfs_dev;
vap->va_nodeid = zp->z_id;
if ((vp->v_flag & VROOT) && zfs_show_ctldir(zp))
@@ -1875,24 +2155,113 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
vap->va_rdev = vp->v_rdev;
vap->va_seq = zp->z_seq;
- ZFS_TIME_DECODE(&vap->va_atime, pzp->zp_atime);
- ZFS_TIME_DECODE(&vap->va_mtime, pzp->zp_mtime);
- ZFS_TIME_DECODE(&vap->va_ctime, pzp->zp_ctime);
-
/*
- * If ACL is trivial don't bother looking for ACE_READ_ATTRIBUTES.
- * Also, if we are the owner don't bother, since owner should
- * always be allowed to read basic attributes of file.
+ * Add in any requested optional attributes and the create time.
+ * Also set the corresponding bits in the returned attribute bitmap.
*/
- if (!(zp->z_phys->zp_flags & ZFS_ACL_TRIVIAL) &&
- (zp->z_phys->zp_uid != crgetuid(cr))) {
- if (error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, cr)) {
- mutex_exit(&zp->z_lock);
- ZFS_EXIT(zfsvfs);
- return (error);
+ if ((xoap = xva_getxoptattr(xvap)) != NULL && zfsvfs->z_use_fuids) {
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
+ xoap->xoa_archive =
+ ((pzp->zp_flags & ZFS_ARCHIVE) != 0);
+ XVA_SET_RTN(xvap, XAT_ARCHIVE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
+ xoap->xoa_readonly =
+ ((pzp->zp_flags & ZFS_READONLY) != 0);
+ XVA_SET_RTN(xvap, XAT_READONLY);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
+ xoap->xoa_system =
+ ((pzp->zp_flags & ZFS_SYSTEM) != 0);
+ XVA_SET_RTN(xvap, XAT_SYSTEM);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
+ xoap->xoa_hidden =
+ ((pzp->zp_flags & ZFS_HIDDEN) != 0);
+ XVA_SET_RTN(xvap, XAT_HIDDEN);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+ xoap->xoa_nounlink =
+ ((pzp->zp_flags & ZFS_NOUNLINK) != 0);
+ XVA_SET_RTN(xvap, XAT_NOUNLINK);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+ xoap->xoa_immutable =
+ ((pzp->zp_flags & ZFS_IMMUTABLE) != 0);
+ XVA_SET_RTN(xvap, XAT_IMMUTABLE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+ xoap->xoa_appendonly =
+ ((pzp->zp_flags & ZFS_APPENDONLY) != 0);
+ XVA_SET_RTN(xvap, XAT_APPENDONLY);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+ xoap->xoa_nodump =
+ ((pzp->zp_flags & ZFS_NODUMP) != 0);
+ XVA_SET_RTN(xvap, XAT_NODUMP);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) {
+ xoap->xoa_opaque =
+ ((pzp->zp_flags & ZFS_OPAQUE) != 0);
+ XVA_SET_RTN(xvap, XAT_OPAQUE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+ xoap->xoa_av_quarantined =
+ ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0);
+ XVA_SET_RTN(xvap, XAT_AV_QUARANTINED);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+ xoap->xoa_av_modified =
+ ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0);
+ XVA_SET_RTN(xvap, XAT_AV_MODIFIED);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) &&
+ vp->v_type == VREG &&
+ (pzp->zp_flags & ZFS_BONUS_SCANSTAMP)) {
+ size_t len;
+ dmu_object_info_t doi;
+
+ /*
+ * Only VREG files have anti-virus scanstamps, so we
+ * won't conflict with symlinks in the bonus buffer.
+ */
+ dmu_object_info_from_db(zp->z_dbuf, &doi);
+ len = sizeof (xoap->xoa_av_scanstamp) +
+ sizeof (znode_phys_t);
+ if (len <= doi.doi_bonus_size) {
+ /*
+ * pzp points to the start of the
+ * znode_phys_t. pzp + 1 points to the
+ * first byte after the znode_phys_t.
+ */
+ (void) memcpy(xoap->xoa_av_scanstamp,
+ pzp + 1,
+ sizeof (xoap->xoa_av_scanstamp));
+ XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
+ }
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+ ZFS_TIME_DECODE(&xoap->xoa_createtime, pzp->zp_crtime);
+ XVA_SET_RTN(xvap, XAT_CREATETIME);
}
}
+ ZFS_TIME_DECODE(&vap->va_atime, pzp->zp_atime);
+ ZFS_TIME_DECODE(&vap->va_mtime, pzp->zp_mtime);
+ ZFS_TIME_DECODE(&vap->va_ctime, pzp->zp_ctime);
+
mutex_exit(&zp->z_lock);
dmu_object_size_from_db(zp->z_dbuf, &vap->va_blksize, &vap->va_nblocks);
@@ -1914,8 +2283,11 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*
* IN: vp - vnode of file to be modified.
* vap - new attribute values.
+ * If AT_XVATTR set, then optional attrs are being set
* flags - ATTR_UTIME set if non-default time values provided.
+ * - ATTR_NOACLCHECK (CIFS context only).
* cr - credentials of caller.
+ * ct - caller context
*
* RETURN: 0 if success
* error code if failure
@@ -1941,6 +2313,10 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
znode_t *attrzp;
int need_policy = FALSE;
int err;
+ zfs_fuid_info_t *fuidp = NULL;
+ xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */
+ xoptattr_t *xoap;
+ boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
if (mask == 0)
return (0);
@@ -1948,15 +2324,44 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
if (mask & AT_NOSET)
return (EINVAL);
+ ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
+
+ pzp = zp->z_phys;
+ zilog = zfsvfs->z_log;
+
+ /*
+ * Make sure that if we have ephemeral uid/gid or xvattr specified
+ * that file system is at proper version level
+ */
+
+ if (zfsvfs->z_use_fuids == B_FALSE &&
+ (((mask & AT_UID) && IS_EPHEMERAL(vap->va_uid)) ||
+ ((mask & AT_GID) && IS_EPHEMERAL(vap->va_gid)) ||
+ (mask & AT_XVATTR)))
+ return (EINVAL);
+
if (mask & AT_SIZE && vp->v_type == VDIR)
return (EISDIR);
if (mask & AT_SIZE && vp->v_type != VREG && vp->v_type != VFIFO)
return (EINVAL);
- ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
- pzp = zp->z_phys;
- zilog = zfsvfs->z_log;
+ /*
+ * If this is an xvattr_t, then get a pointer to the structure of
+ * optional attributes. If this is NULL, then we have a vattr_t.
+ */
+ xoap = xva_getxoptattr(xvap);
+
+ /*
+ * Immutable files can only alter immutable bit and atime
+ */
+ if ((pzp->zp_flags & ZFS_IMMUTABLE) &&
+ ((mask & (AT_SIZE|AT_UID|AT_GID|AT_MTIME|AT_MODE)) ||
+ ((mask & AT_XVATTR) && XVA_ISSET_REQ(xvap, XAT_CREATETIME))))
+ return (EPERM);
+
+ if ((mask & AT_SIZE) && (pzp->zp_flags & ZFS_READONLY))
+ return (EPERM);
top:
attrzp = NULL;
@@ -1971,7 +2376,7 @@ top:
*/
if (mask & AT_SIZE) {
- err = zfs_zaccess(zp, ACE_WRITE_DATA, cr);
+ err = zfs_zaccess(zp, ACE_WRITE_DATA, 0, skipaclchk, cr);
if (err) {
ZFS_EXIT(zfsvfs);
return (err);
@@ -1992,8 +2397,14 @@ top:
}
}
- if (mask & (AT_ATIME|AT_MTIME))
- need_policy = zfs_zaccess_v4_perm(zp, ACE_WRITE_ATTRIBUTES, cr);
+ if (mask & (AT_ATIME|AT_MTIME) ||
+ ((mask & AT_XVATTR) && (XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
+ XVA_ISSET_REQ(xvap, XAT_READONLY) ||
+ XVA_ISSET_REQ(xvap, XAT_ARCHIVE) ||
+ XVA_ISSET_REQ(xvap, XAT_CREATETIME) ||
+ XVA_ISSET_REQ(xvap, XAT_SYSTEM))))
+ need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0,
+ skipaclchk, cr);
if (mask & (AT_UID|AT_GID)) {
int idmask = (mask & (AT_UID|AT_GID));
@@ -2013,7 +2424,8 @@ top:
*/
take_owner = (mask & AT_UID) && (vap->va_uid == crgetuid(cr));
- take_group = (mask & AT_GID) && groupmember(vap->va_gid, cr);
+ take_group = (mask & AT_GID) &&
+ zfs_groupmember(zfsvfs, vap->va_gid, cr);
/*
* If both AT_UID and AT_GID are set then take_owner and
@@ -2027,7 +2439,8 @@ top:
if (((idmask == (AT_UID|AT_GID)) && take_owner && take_group) ||
((idmask == AT_UID) && take_owner) ||
((idmask == AT_GID) && take_group)) {
- if (zfs_zaccess_v4_perm(zp, ACE_WRITE_OWNER, cr) == 0) {
+ if (zfs_zaccess(zp, ACE_WRITE_OWNER, 0,
+ skipaclchk, cr) == 0) {
/*
* Remove setuid/setgid for non-privileged users
*/
@@ -2043,12 +2456,37 @@ top:
mutex_enter(&zp->z_lock);
oldva.va_mode = pzp->zp_mode;
- oldva.va_uid = zp->z_phys->zp_uid;
- oldva.va_gid = zp->z_phys->zp_gid;
+ zfs_fuid_map_ids(zp, &oldva.va_uid, &oldva.va_gid);
+ if (mask & AT_XVATTR) {
+ if ((need_policy == FALSE) &&
+ (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) &&
+ xoap->xoa_appendonly !=
+ ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) &&
+ xoap->xoa_nounlink !=
+ ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) &&
+ xoap->xoa_immutable !=
+ ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_NODUMP) &&
+ xoap->xoa_nodump !=
+ ((pzp->zp_flags & ZFS_NODUMP) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) &&
+ xoap->xoa_av_modified !=
+ ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) &&
+ xoap->xoa_av_quarantined !=
+ ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) ||
+ (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) {
+ need_policy = TRUE;
+ }
+ }
+
mutex_exit(&zp->z_lock);
if (mask & AT_MODE) {
- if (zfs_zaccess_v4_perm(zp, ACE_WRITE_ACL, cr) == 0) {
+ if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr) == 0) {
err = secpolicy_setid_setsticky_clear(vp, vap,
&oldva, cr);
if (err) {
@@ -2073,10 +2511,9 @@ top:
if (trim_mask) {
saved_mask = vap->va_mask;
vap->va_mask &= ~trim_mask;
-
}
err = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
- (int (*)(void *, int, cred_t *))zfs_zaccess_rwx, zp);
+ (int (*)(void *, int, cred_t *))zfs_zaccess_unix, zp);
if (err) {
ZFS_EXIT(zfsvfs);
return (err);
@@ -2094,22 +2531,45 @@ top:
tx = dmu_tx_create(zfsvfs->z_os);
dmu_tx_hold_bonus(tx, zp->z_id);
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
if (mask & AT_MODE) {
uint64_t pmode = pzp->zp_mode;
new_mode = (pmode & S_IFMT) | (vap->va_mode & ~S_IFMT);
- if (zp->z_phys->zp_acl.z_acl_extern_obj)
- dmu_tx_hold_write(tx,
- pzp->zp_acl.z_acl_extern_obj, 0, SPA_MAXBLOCKSIZE);
- else
+ if (pzp->zp_acl.z_acl_extern_obj) {
+ /* Are we upgrading ACL from old V0 format to new V1 */
+ if (zfsvfs->z_version <= ZPL_VERSION_FUID &&
+ pzp->zp_acl.z_acl_version ==
+ ZFS_ACL_VERSION_INITIAL) {
+ dmu_tx_hold_free(tx,
+ pzp->zp_acl.z_acl_extern_obj, 0,
+ DMU_OBJECT_END);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
+ 0, sizeof (zfs_object_ace_t) * 2048 + 6);
+ } else {
+ dmu_tx_hold_write(tx,
+ pzp->zp_acl.z_acl_extern_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
+ } else {
dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
- 0, ZFS_ACL_SIZE(MAX_ACL_SIZE));
+ 0, sizeof (zfs_object_ace_t) * 2048 + 6);
+ }
}
- if ((mask & (AT_UID | AT_GID)) && zp->z_phys->zp_xattr != 0) {
- err = zfs_zget(zp->z_zfsvfs, zp->z_phys->zp_xattr, &attrzp);
+ if ((mask & (AT_UID | AT_GID)) && pzp->zp_xattr != 0) {
+ err = zfs_zget(zp->z_zfsvfs, pzp->zp_xattr, &attrzp);
if (err) {
dmu_tx_abort(tx);
ZFS_EXIT(zfsvfs);
@@ -2153,16 +2613,20 @@ top:
mutex_enter(&attrzp->z_lock);
if (mask & AT_UID) {
- zp->z_phys->zp_uid = (uint64_t)vap->va_uid;
+ pzp->zp_uid = zfs_fuid_create(zfsvfs,
+ vap->va_uid, ZFS_OWNER, tx, &fuidp);
if (attrzp) {
- attrzp->z_phys->zp_uid = (uint64_t)vap->va_uid;
+ attrzp->z_phys->zp_uid = zfs_fuid_create(zfsvfs,
+ vap->va_uid, ZFS_OWNER, tx, &fuidp);
}
}
if (mask & AT_GID) {
- zp->z_phys->zp_gid = (uint64_t)vap->va_gid;
+ pzp->zp_gid = zfs_fuid_create(zfsvfs, vap->va_gid,
+ ZFS_GROUP, tx, &fuidp);
if (attrzp)
- attrzp->z_phys->zp_gid = (uint64_t)vap->va_gid;
+ attrzp->z_phys->zp_gid = zfs_fuid_create(zfsvfs,
+ vap->va_gid, ZFS_GROUP, tx, &fuidp);
}
if (attrzp)
@@ -2178,10 +2642,33 @@ top:
zfs_time_stamper_locked(zp, CONTENT_MODIFIED, tx);
else if (mask != 0)
zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
+ /*
+ * Do this after setting timestamps to prevent timestamp
+ * update from toggling bit
+ */
+
+ if (xoap && (mask & AT_XVATTR)) {
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
+ size_t len;
+ dmu_object_info_t doi;
+
+ ASSERT(vp->v_type == VREG);
+
+ /* Grow the bonus buffer if necessary. */
+ dmu_object_info_from_db(zp->z_dbuf, &doi);
+ len = sizeof (xoap->xoa_av_scanstamp) +
+ sizeof (znode_phys_t);
+ if (len > doi.doi_bonus_size)
+ VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0);
+ }
+ zfs_xvattr_set(zp, xvap);
+ }
if (mask != 0)
- zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask);
+ zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp);
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
mutex_exit(&zp->z_lock);
if (attrzp)
@@ -2298,6 +2785,8 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp)
* tdvp - Target directory to contain the "new entry".
* tnm - New entry name.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* RETURN: 0 if success
* error code if failure
@@ -2305,8 +2794,10 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp)
* Timestamps:
* sdvp,tdvp - ctime|mtime updated
*/
+/*ARGSUSED*/
static int
-zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
+zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
znode_t *tdzp, *szp, *tzp;
znode_t *sdzp = VTOZ(sdvp);
@@ -2316,7 +2807,9 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
zfs_dirlock_t *sdl, *tdl;
dmu_tx_t *tx;
zfs_zlock_t *zl;
- int cmp, serr, terr, error;
+ int cmp, serr, terr;
+ int error = 0;
+ int zflg = 0;
ZFS_ENTER_VERIFY_ZP(zfsvfs, sdzp);
zilog = zfsvfs->z_log;
@@ -2324,7 +2817,7 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
/*
* Make sure we have the real vp for the target directory.
*/
- if (VOP_REALVP(tdvp, &realvp) == 0)
+ if (VOP_REALVP(tdvp, &realvp, ct) == 0)
tdvp = realvp;
if (tdvp->v_vfsp != sdvp->v_vfsp) {
@@ -2337,6 +2830,15 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
ZFS_EXIT(zfsvfs);
return (EIO);
}
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(tnm,
+ strlen(tnm), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+
+ if (flags & FIGNORECASE)
+ zflg |= ZCILOOK;
+
top:
szp = NULL;
tzp = NULL;
@@ -2364,7 +2866,14 @@ top:
} else if (sdzp->z_id > tdzp->z_id) {
cmp = 1;
} else {
- cmp = strcmp(snm, tnm);
+ /*
+ * First compare the two name arguments without
+ * considering any case folding.
+ */
+ int nofold = (zfsvfs->z_norm & ~U8_TEXTPREP_TOUPPER);
+
+ cmp = u8_strcmp(snm, tnm, 0, nofold, U8_UNICODE_LATEST, &error);
+ ASSERT(error == 0 || !(zfsvfs->z_case & ZFS_UTF8_ONLY));
if (cmp == 0) {
/*
* POSIX: "If the old argument and the new argument
@@ -2375,13 +2884,48 @@ top:
ZFS_EXIT(zfsvfs);
return (0);
}
+ /*
+ * If the file system is case-folding, then we may
+ * have some more checking to do. A case-folding file
+ * system is either supporting mixed case sensitivity
+ * access or is completely case-insensitive. Note
+ * that the file system is always case preserving.
+ *
+ * In mixed sensitivity mode case sensitive behavior
+ * is the default. FIGNORECASE must be used to
+ * explicitly request case insensitive behavior.
+ *
+ * If the source and target names provided differ only
+ * by case (e.g., a request to rename 'tim' to 'Tim'),
+ * we will treat this as a special case in the
+ * case-insensitive mode: as long as the source name
+ * is an exact match, we will allow this to proceed as
+ * a name-change request.
+ */
+ if ((zfsvfs->z_case & ZFS_CI_ONLY ||
+ (zfsvfs->z_case & ZFS_CI_MIXD && flags & FIGNORECASE)) &&
+ u8_strcmp(snm, tnm, 0, zfsvfs->z_norm, U8_UNICODE_LATEST,
+ &error) == 0) {
+ /*
+ * case preserving rename request, require exact
+ * name matches
+ */
+ zflg |= ZCIEXACT;
+ zflg &= ~ZCILOOK;
+ }
}
+
if (cmp < 0) {
- serr = zfs_dirent_lock(&sdl, sdzp, snm, &szp, ZEXISTS);
- terr = zfs_dirent_lock(&tdl, tdzp, tnm, &tzp, 0);
+ serr = zfs_dirent_lock(&sdl, sdzp, snm, &szp,
+ ZEXISTS | zflg, NULL, NULL);
+ terr = zfs_dirent_lock(&tdl,
+ tdzp, tnm, &tzp, ZRENAMING | zflg, NULL, NULL);
} else {
- terr = zfs_dirent_lock(&tdl, tdzp, tnm, &tzp, 0);
- serr = zfs_dirent_lock(&sdl, sdzp, snm, &szp, ZEXISTS);
+ terr = zfs_dirent_lock(&tdl,
+ tdzp, tnm, &tzp, zflg, NULL, NULL);
+ serr = zfs_dirent_lock(&sdl,
+ sdzp, snm, &szp, ZEXISTS | ZRENAMING | zflg,
+ NULL, NULL);
}
if (serr) {
@@ -2455,16 +2999,16 @@ top:
}
}
- vnevent_rename_src(ZTOV(szp), sdvp, snm);
+ vnevent_rename_src(ZTOV(szp), sdvp, snm, ct);
if (tzp)
- vnevent_rename_dest(ZTOV(tzp), tdvp, tnm);
+ vnevent_rename_dest(ZTOV(tzp), tdvp, tnm, ct);
/*
* notify the target directory if it is not the same
* as source directory.
*/
if (tdvp != sdvp) {
- vnevent_rename_dest_dir(tdvp);
+ vnevent_rename_dest_dir(tdvp, ct);
}
tx = dmu_tx_create(zfsvfs->z_os);
@@ -2497,15 +3041,19 @@ top:
}
if (tzp) /* Attempt to remove the existing target */
- error = zfs_link_destroy(tdl, tzp, tx, 0, NULL);
+ error = zfs_link_destroy(tdl, tzp, tx, zflg, NULL);
if (error == 0) {
error = zfs_link_create(tdl, szp, tx, ZRENAMING);
if (error == 0) {
+ szp->z_phys->zp_flags |= ZFS_AV_MODIFIED;
+
error = zfs_link_destroy(sdl, szp, tx, ZRENAMING, NULL);
ASSERT(error == 0);
- zfs_log_rename(zilog, tx, TX_RENAME, sdzp,
- sdl->dl_name, tdzp, tdl->dl_name, szp);
+
+ zfs_log_rename(zilog, tx,
+ TX_RENAME | (flags & FIGNORECASE ? TX_CI : 0),
+ sdzp, sdl->dl_name, tdzp, tdl->dl_name, szp);
}
}
@@ -2533,6 +3081,8 @@ out:
* vap - Attributes of new entry.
* target - Target path of new symlink.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* RETURN: 0 if success
* error code if failure
@@ -2540,8 +3090,10 @@ out:
* Timestamps:
* dvp - ctime|mtime updated
*/
+/*ARGSUSED*/
static int
-zfs_symlink(vnode_t *dvp, char *name, vattr_t *vap, char *link, cred_t *cr)
+zfs_symlink(vnode_t *dvp, char *name, vattr_t *vap, char *link, cred_t *cr,
+ caller_context_t *ct, int flags)
{
znode_t *zp, *dzp = VTOZ(dvp);
zfs_dirlock_t *dl;
@@ -2551,13 +3103,23 @@ zfs_symlink(vnode_t *dvp, char *name, vattr_t *vap, char *link, cred_t *cr)
uint64_t zoid;
int len = strlen(link);
int error;
+ int zflg = ZNEW;
+ zfs_fuid_info_t *fuidp = NULL;
ASSERT(vap->va_type == VLNK);
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
+
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(name, strlen(name),
+ NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+ if (flags & FIGNORECASE)
+ zflg |= ZCILOOK;
top:
- if (error = zfs_zaccess(dzp, ACE_ADD_FILE, cr)) {
+ if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -2570,7 +3132,8 @@ top:
/*
* Attempt to lock directory; fail if entry already exists.
*/
- if (error = zfs_dirent_lock(&dl, dzp, name, &zp, ZNEW)) {
+ error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, NULL);
+ if (error) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -2581,6 +3144,16 @@ top:
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
if (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)
dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, SPA_MAXBLOCKSIZE);
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
error = dmu_tx_assign(tx, zfsvfs->z_assign);
if (error) {
zfs_dirent_unlock(dl);
@@ -2603,14 +3176,13 @@ top:
*/
zoid = 0;
if (sizeof (znode_phys_t) + len <= dmu_bonus_max()) {
- zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, len);
+ zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, len, NULL, &fuidp);
if (len != 0)
bcopy(link, zp->z_phys + 1, len);
} else {
dmu_buf_t *dbp;
- zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0);
-
+ zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0, NULL, &fuidp);
/*
* Nothing can access the znode yet so no locking needed
* for growing the znode's blocksize.
@@ -2631,8 +3203,14 @@ top:
*/
(void) zfs_link_create(dl, zp, tx, ZNEW);
out:
- if (error == 0)
- zfs_log_symlink(zilog, tx, TX_SYMLINK, dzp, zp, name, link);
+ if (error == 0) {
+ uint64_t txtype = TX_SYMLINK;
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_symlink(zilog, tx, txtype, dzp, zp, name, link);
+ }
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
dmu_tx_commit(tx);
@@ -2651,6 +3229,7 @@ out:
* IN: vp - vnode of symbolic link.
* uoip - structure to contain the link path.
* cr - credentials of caller.
+ * ct - caller context
*
* OUT: uio - structure to contain the link path.
*
@@ -2662,7 +3241,7 @@ out:
*/
/* ARGSUSED */
static int
-zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr)
+zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -2699,6 +3278,7 @@ zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr)
* svp - vnode of new entry.
* name - name of new entry.
* cr - credentials of caller.
+ * ct - caller context
*
* RETURN: 0 if success
* error code if failure
@@ -2709,7 +3289,8 @@ zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr)
+zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
+ caller_context_t *ct, int flags)
{
znode_t *dzp = VTOZ(tdvp);
znode_t *tzp, *szp;
@@ -2719,13 +3300,15 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr)
dmu_tx_t *tx;
vnode_t *realvp;
int error;
+ int zf = ZNEW;
+ uid_t owner;
ASSERT(tdvp->v_type == VDIR);
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
- if (VOP_REALVP(svp, &realvp) == 0)
+ if (VOP_REALVP(svp, &realvp, ct) == 0)
svp = realvp;
if (svp->v_vfsp != tdvp->v_vfsp) {
@@ -2733,6 +3316,14 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr)
return (EXDEV);
}
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(name,
+ strlen(name), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+ if (flags & FIGNORECASE)
+ zf |= ZCILOOK;
+
szp = VTOZ(svp);
if (!szp->z_dbuf_held) {
ZFS_EXIT(zfsvfs);
@@ -2760,13 +3351,14 @@ top:
return (EPERM);
}
- if ((uid_t)szp->z_phys->zp_uid != crgetuid(cr) &&
+ zfs_fuid_map_id(zfsvfs, szp->z_phys->zp_uid, ZFS_OWNER, &owner);
+ if (owner != crgetuid(cr) &&
secpolicy_basic_link(cr) != 0) {
ZFS_EXIT(zfsvfs);
return (EPERM);
}
- if (error = zfs_zaccess(dzp, ACE_ADD_FILE, cr)) {
+ if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -2774,7 +3366,8 @@ top:
/*
* Attempt to lock directory; fail if entry already exists.
*/
- if (error = zfs_dirent_lock(&dl, dzp, name, &tzp, ZNEW)) {
+ error = zfs_dirent_lock(&dl, dzp, name, &tzp, zf, NULL, NULL);
+ if (error) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -2797,15 +3390,19 @@ top:
error = zfs_link_create(dl, szp, tx, 0);
- if (error == 0)
- zfs_log_link(zilog, tx, TX_LINK, dzp, szp, name);
+ if (error == 0) {
+ uint64_t txtype = TX_LINK;
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_link(zilog, tx, txtype, dzp, szp, name);
+ }
dmu_tx_commit(tx);
zfs_dirent_unlock(dl);
if (error == 0) {
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
ZFS_EXIT(zfsvfs);
@@ -2953,6 +3550,7 @@ out:
* len - amount of data to write.
* flags - flags to control the operation.
* cr - credentials of caller.
+ * ct - caller context.
*
* RETURN: 0 if success
* error code if failure
@@ -2960,8 +3558,10 @@ out:
* Timestamps:
* vp - ctime|mtime updated
*/
+/*ARGSUSED*/
static int
-zfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+zfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3022,8 +3622,9 @@ out:
return (error);
}
+/*ARGSUSED*/
void
-zfs_inactive(vnode_t *vp, cred_t *cr)
+zfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3084,13 +3685,15 @@ zfs_inactive(vnode_t *vp, cred_t *cr)
* IN: vp - vnode seeking within
* ooff - old file offset
* noffp - pointer to new file offset
+ * ct - caller context
*
* RETURN: 0 if success
* EINVAL if new offset invalid
*/
/* ARGSUSED */
static int
-zfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+zfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
if (vp->v_type == VDIR)
return (0);
@@ -3103,7 +3706,7 @@ zfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
*/
static int
zfs_frlock(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset,
- flk_callback_t *flk_cbp, cred_t *cr)
+ flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3121,7 +3724,7 @@ zfs_frlock(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset,
ZFS_EXIT(zfsvfs);
return (EAGAIN);
}
- error = fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr);
+ error = fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct);
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -3239,6 +3842,7 @@ out:
* addr - virtual address of fault.
* rw - mode of created pages.
* cr - credentials of caller.
+ * ct - caller context.
*
* OUT: protp - protection mode of created pages.
* pl - list of pages created.
@@ -3253,7 +3857,7 @@ out:
static int
zfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3384,15 +3988,22 @@ out:
*
* zfs_addmap() updates z_mapcnt
*/
+/*ARGSUSED*/
static int
zfs_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)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
segvn_crargs_t vn_a;
int error;
+ if ((prot & PROT_WRITE) &&
+ (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_READONLY |
+ ZFS_APPENDONLY)))
+ return (EPERM);
+
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
if (vp->v_flag & VNOMAP) {
@@ -3454,7 +4065,8 @@ zfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
/* ARGSUSED */
static int
zfs_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)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
uint64_t pages = btopr(len);
@@ -3486,7 +4098,8 @@ zfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
/* ARGSUSED */
static int
zfs_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)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
uint64_t pages = btopr(len);
@@ -3495,7 +4108,7 @@ zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
if ((flags & MAP_SHARED) && (prot & PROT_WRITE) &&
vn_has_cached_data(vp))
- (void) VOP_PUTPAGE(vp, off, len, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, off, len, B_ASYNC, cr, ct);
return (0);
}
@@ -3512,6 +4125,7 @@ zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
* flag - current file open mode flags.
* offset - current file offset.
* cr - credentials of caller [UNUSED].
+ * ct - caller context.
*
* RETURN: 0 if success
* error code if failure
@@ -3559,8 +4173,9 @@ top:
return (error);
}
+/*ARGSUSED*/
static int
-zfs_fid(vnode_t *vp, fid_t *fidp)
+zfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3611,7 +4226,8 @@ zfs_fid(vnode_t *vp, fid_t *fidp)
}
static int
-zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp, *xzp;
zfsvfs_t *zfsvfs;
@@ -3633,7 +4249,7 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
*valp = 0;
error = zfs_dirent_lock(&dl, zp, "", &xzp,
- ZXATTR | ZEXISTS | ZSHARED);
+ ZXATTR | ZEXISTS | ZSHARED, NULL, NULL);
if (error == 0) {
zfs_dirent_unlock(dl);
if (!zfs_dirempty(xzp))
@@ -3649,6 +4265,13 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
ZFS_EXIT(zfsvfs);
return (error);
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ zp = VTOZ(vp);
+ *valp = vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) &&
+ (vp->v_type == VREG || vp->v_type == VDIR);
+ return (0);
+
case _PC_ACL_ENABLED:
*valp = _ACL_ACE_ENABLED;
return (0);
@@ -3658,20 +4281,22 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
return (0);
default:
- return (fs_pathconf(vp, cmd, valp, cr));
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
}
}
/*ARGSUSED*/
static int
-zfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr)
+zfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
+ boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
- error = zfs_getacl(zp, vsecp, cr);
+ error = zfs_getacl(zp, vsecp, skipaclchk, cr);
ZFS_EXIT(zfsvfs);
return (error);
@@ -3679,14 +4304,16 @@ zfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr)
/*ARGSUSED*/
static int
-zfs_setsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr)
+zfs_setsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
+ boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
- error = zfs_setacl(zp, vsecp, cr);
+ error = zfs_setacl(zp, vsecp, skipaclchk, cr);
ZFS_EXIT(zfsvfs);
return (error);
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c
index 7415a15e74..c9c3e720ba 100644
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c
@@ -51,7 +51,10 @@
#include <sys/zfs_acl.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_rlock.h>
+#include <sys/zfs_fuid.h>
+#include <sys/zfs_i18n.h>
#include <sys/fs/zfs.h>
+#include <sys/kidmap.h>
#endif /* _KERNEL */
#include <sys/dmu.h>
@@ -262,13 +265,18 @@ zfs_init_fs(zfsvfs_t *zfsvfs, znode_t **zpp, cred_t *cr)
*/
if (dmu_object_info(os, MASTER_NODE_OBJ, &doi) == ENOENT) {
dmu_tx_t *tx = dmu_tx_create(os);
+ uint64_t zpl_version;
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, TRUE, NULL); /* master */
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, TRUE, NULL); /* del queue */
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); /* root node */
error = dmu_tx_assign(tx, TXG_WAIT);
ASSERT3U(error, ==, 0);
- zfs_create_fs(os, cr, ZPL_VERSION, tx);
+ if (spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
+ zpl_version = ZPL_VERSION;
+ else
+ zpl_version = ZPL_VERSION_FUID - 1;
+ zfs_create_fs(os, cr, zpl_version, 0, tx);
dmu_tx_commit(tx);
}
@@ -327,6 +335,11 @@ zfs_init_fs(zfsvfs_t *zfsvfs, znode_t **zpp, cred_t *cr)
return (error);
}
ASSERT3U((*zpp)->z_id, ==, zfsvfs->z_root);
+ error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1,
+ &zfsvfs->z_fuid_obj);
+ if (error == ENOENT)
+ error = 0;
+
return (0);
}
@@ -503,13 +516,18 @@ zfs_znode_dmu_init(znode_t *zp)
* IS_ROOT_NODE - new object will be root
* IS_XATTR - new object is an attribute
* IS_REPLAY - intent log replay
+ * bonuslen - length of bonus buffer
+ * setaclp - File/Dir initial ACL
+ * fuidp - Tracks fuid allocation.
*
* OUT: oid - ID of created object
+ * zpp - allocated znode
*
*/
void
zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
- uint_t flag, znode_t **zpp, int bonuslen)
+ uint_t flag, znode_t **zpp, int bonuslen, zfs_acl_t *setaclp,
+ zfs_fuid_info_t **fuidp)
{
dmu_buf_t *dbp;
znode_phys_t *pzp;
@@ -543,13 +561,13 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
*/
if (vap->va_type == VDIR) {
if (flag & IS_REPLAY) {
- err = zap_create_claim(zfsvfs->z_os, *oid,
- DMU_OT_DIRECTORY_CONTENTS,
+ err = zap_create_claim_norm(zfsvfs->z_os, *oid,
+ zfsvfs->z_norm, DMU_OT_DIRECTORY_CONTENTS,
DMU_OT_ZNODE, sizeof (znode_phys_t) + bonuslen, tx);
ASSERT3U(err, ==, 0);
} else {
- *oid = zap_create(zfsvfs->z_os,
- DMU_OT_DIRECTORY_CONTENTS,
+ *oid = zap_create_norm(zfsvfs->z_os,
+ zfsvfs->z_norm, DMU_OT_DIRECTORY_CONTENTS,
DMU_OT_ZNODE, sizeof (znode_phys_t) + bonuslen, tx);
}
} else {
@@ -593,6 +611,9 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
pzp->zp_rdev = zfs_expldev(vap->va_rdev);
}
+ if (zfsvfs->z_use_fuids)
+ pzp->zp_flags = ZFS_ARCHIVE | ZFS_AV_MODIFIED;
+
if (vap->va_type == VDIR) {
pzp->zp_size = 2; /* contents ("." and "..") */
pzp->zp_links = (flag & (IS_ROOT_NODE | IS_XATTR)) ? 2 : 1;
@@ -622,7 +643,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
pzp->zp_mode = MAKEIMODE(vap->va_type, vap->va_mode);
zp = zfs_znode_alloc(zfsvfs, dbp, *oid, 0);
- zfs_perm_init(zp, dzp, flag, vap, tx, cr);
+ zfs_perm_init(zp, dzp, flag, vap, tx, cr, setaclp, fuidp);
if (zpp) {
kmutex_t *hash_mtx = ZFS_OBJ_MUTEX(zp);
@@ -639,6 +660,71 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
}
}
+void
+zfs_xvattr_set(znode_t *zp, xvattr_t *xvap)
+{
+ xoptattr_t *xoap;
+
+ xoap = xva_getxoptattr(xvap);
+ ASSERT(xoap);
+
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+ ZFS_TIME_ENCODE(&xoap->xoa_createtime, zp->z_phys->zp_crtime);
+ XVA_SET_RTN(xvap, XAT_CREATETIME);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
+ ZFS_ATTR_SET(zp, ZFS_READONLY, xoap->xoa_readonly);
+ XVA_SET_RTN(xvap, XAT_READONLY);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
+ ZFS_ATTR_SET(zp, ZFS_HIDDEN, xoap->xoa_hidden);
+ XVA_SET_RTN(xvap, XAT_HIDDEN);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
+ ZFS_ATTR_SET(zp, ZFS_SYSTEM, xoap->xoa_system);
+ XVA_SET_RTN(xvap, XAT_SYSTEM);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
+ ZFS_ATTR_SET(zp, ZFS_ARCHIVE, xoap->xoa_archive);
+ XVA_SET_RTN(xvap, XAT_ARCHIVE);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+ ZFS_ATTR_SET(zp, ZFS_IMMUTABLE, xoap->xoa_immutable);
+ XVA_SET_RTN(xvap, XAT_IMMUTABLE);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+ ZFS_ATTR_SET(zp, ZFS_NOUNLINK, xoap->xoa_nounlink);
+ XVA_SET_RTN(xvap, XAT_NOUNLINK);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+ ZFS_ATTR_SET(zp, ZFS_APPENDONLY, xoap->xoa_appendonly);
+ XVA_SET_RTN(xvap, XAT_APPENDONLY);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+ ZFS_ATTR_SET(zp, ZFS_NODUMP, xoap->xoa_nodump);
+ XVA_SET_RTN(xvap, XAT_NODUMP);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) {
+ ZFS_ATTR_SET(zp, ZFS_OPAQUE, xoap->xoa_opaque);
+ XVA_SET_RTN(xvap, XAT_OPAQUE);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+ ZFS_ATTR_SET(zp, ZFS_AV_QUARANTINED,
+ xoap->xoa_av_quarantined);
+ XVA_SET_RTN(xvap, XAT_AV_QUARANTINED);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+ ZFS_ATTR_SET(zp, ZFS_AV_MODIFIED, xoap->xoa_av_modified);
+ XVA_SET_RTN(xvap, XAT_AV_MODIFIED);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
+ (void) memcpy(zp->z_phys + 1, xoap->xoa_av_scanstamp,
+ sizeof (xoap->xoa_av_scanstamp));
+ zp->z_phys->zp_flags |= ZFS_BONUS_SCANSTAMP;
+ XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
+ }
+}
+
int
zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
{
@@ -861,11 +947,17 @@ zfs_time_stamper_locked(znode_t *zp, uint_t flag, dmu_tx_t *tx)
if (flag & AT_ATIME)
ZFS_TIME_ENCODE(&now, zp->z_phys->zp_atime);
- if (flag & AT_MTIME)
+ if (flag & AT_MTIME) {
ZFS_TIME_ENCODE(&now, zp->z_phys->zp_mtime);
+ if (zp->z_zfsvfs->z_use_fuids)
+ zp->z_phys->zp_flags |= (ZFS_ARCHIVE | ZFS_AV_MODIFIED);
+ }
- if (flag & AT_CTIME)
+ if (flag & AT_CTIME) {
ZFS_TIME_ENCODE(&now, zp->z_phys->zp_ctime);
+ if (zp->z_zfsvfs->z_use_fuids)
+ zp->z_phys->zp_flags |= ZFS_ARCHIVE;
+ }
}
/*
@@ -958,8 +1050,13 @@ zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
rl_t *rl;
uint64_t end = off + len;
uint64_t size, new_blksz;
+ uint64_t pflags = zp->z_phys->zp_flags;
int error;
+ if ((pflags & (ZFS_IMMUTABLE|ZFS_READONLY)) ||
+ off < zp->z_phys->zp_size && (pflags & ZFS_APPENDONLY))
+ return (EPERM);
+
if (ZTOV(zp)->v_type == VFIFO)
return (0);
@@ -1094,7 +1191,8 @@ zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
}
void
-zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version, dmu_tx_t *tx)
+zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version,
+ int norm, dmu_tx_t *tx)
{
zfsvfs_t zfsvfs;
uint64_t moid, doid, roid = 0;
@@ -1155,12 +1253,16 @@ zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version, dmu_tx_t *tx)
zfsvfs.z_os = os;
zfsvfs.z_assign = TXG_NOWAIT;
zfsvfs.z_parent = &zfsvfs;
+ zfsvfs.z_version = version;
+ zfsvfs.z_use_fuids = USE_FUIDS(version, os);
+ zfsvfs.z_norm = norm;
mutex_init(&zfsvfs.z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
list_create(&zfsvfs.z_all_znodes, sizeof (znode_t),
offsetof(znode_t, z_link_node));
- zfs_mknode(rootzp, &vattr, &roid, tx, cr, IS_ROOT_NODE, NULL, 0);
+ zfs_mknode(rootzp, &vattr, &roid, tx, cr, IS_ROOT_NODE,
+ NULL, 0, NULL, NULL);
ASSERT3U(rootzp->z_id, ==, roid);
error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &roid, tx);
ASSERT(error == 0);
@@ -1168,8 +1270,8 @@ zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version, dmu_tx_t *tx)
ZTOV(rootzp)->v_count = 0;
kmem_cache_free(znode_cache, rootzp);
}
-#endif /* _KERNEL */
+#endif /* _KERNEL */
/*
* Given an object number, return its parent object number and whether
* or not the object is an extended attribute directory.
diff --git a/usr/src/uts/common/fs/zfs/zil.c b/usr/src/uts/common/fs/zfs/zil.c
index fb0393f02a..98e494926d 100644
--- a/usr/src/uts/common/fs/zfs/zil.c
+++ b/usr/src/uts/common/fs/zfs/zil.c
@@ -857,7 +857,7 @@ zil_lwb_commit(zilog_t *zilog, itx_t *itx, lwb_t *lwb)
}
itx_t *
-zil_itx_create(int txtype, size_t lrsize)
+zil_itx_create(uint64_t txtype, size_t lrsize)
{
itx_t *itx;
@@ -1396,6 +1396,9 @@ zil_replay_log_record(zilog_t *zilog, lr_t *lr, void *zra, uint64_t claim_txg)
if (lr->lrc_seq <= zh->zh_replay_seq) /* already replayed */
return;
+ /* Strip case-insensitive bit, still present in log record */
+ txtype &= ~TX_CI;
+
/*
* Make a copy of the data so we can revise and extend it.
*/
@@ -1515,8 +1518,9 @@ zil_replay_log_record(zilog_t *zilog, lr_t *lr, void *zra, uint64_t claim_txg)
name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
dmu_objset_name(zr->zr_os, name);
cmn_err(CE_WARN, "ZFS replay transaction error %d, "
- "dataset %s, seq 0x%llx, txtype %llu\n",
- error, name, (u_longlong_t)lr->lrc_seq, (u_longlong_t)txtype);
+ "dataset %s, seq 0x%llx, txtype %llu %s\n",
+ error, name, (u_longlong_t)lr->lrc_seq, (u_longlong_t)txtype,
+ (lr->lrc_txtype & TX_CI) ? "CI" : "");
zilog->zl_stop_replay = 1;
kmem_free(name, MAXNAMELEN);
}
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index 7f7c401831..dd83cb7b01 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -223,7 +223,8 @@ zvol_minor_lookup(const char *name)
void
zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
{
- nvlist_t *nvprops = arg;
+ zfs_creat_t *zct = arg;
+ nvlist_t *nvprops = zct->zct_props;
int error;
uint64_t volblocksize, volsize;
diff --git a/usr/src/uts/common/idmap/idmap_cache.c b/usr/src/uts/common/idmap/idmap_cache.c
index d5c5f4f374..3b4c4963cd 100644
--- a/usr/src/uts/common/idmap/idmap_cache.c
+++ b/usr/src/uts/common/idmap/idmap_cache.c
@@ -368,8 +368,8 @@ kidmap_cache_purge_avl(idmap_avl_cache_t *cache)
if (rw_tryupgrade(&cache->lock) == 0) {
/*
* Could not upgrade lock so release lock
- * and aquire the write lock. It is valid to
- * release abd re-aquire the lock as there
+ * and acquire the write lock. It is valid to
+ * release abd re-acquire the lock as there
* can only be one purge routine running on an
* avl tree and no other routine removes
* entries.
@@ -451,7 +451,7 @@ kidmap_find_sid_prefix(const char *sid_prefix) {
if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) {
/*
* Could not upgrade lock so release lock
- * and aquire the write lock
+ * and acquire the write lock
*/
rw_exit(&kidmap_sid_prefix_store->lock);
rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER);
diff --git a/usr/src/uts/common/io/cons.c b/usr/src/uts/common/io/cons.c
index 2baf58af37..ae55f2ab61 100644
--- a/usr/src/uts/common/io/cons.c
+++ b/usr/src/uts/common/io/cons.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -121,7 +121,7 @@ static struct dev_ops cn_ops = {
* Global variables associated with the console device:
*
* XXX: There are too many of these!
- * moved to space.c to becone resident in the kernel so that cons
+ * moved to space.c to become resident in the kernel so that cons
* can be loadable.
*/
@@ -310,7 +310,7 @@ cnopen(dev_t *dev, int flag, int state, struct cred *cred)
LOG_HIWAT / LOG_MSGSIZE, TASKQ_PREPOPULATE);
}
- if ((err = VOP_OPEN(&vp, flag, cred)) != 0)
+ if ((err = VOP_OPEN(&vp, flag, cred, NULL)) != 0)
return (err);
/*
@@ -323,7 +323,7 @@ cnopen(dev_t *dev, int flag, int state, struct cred *cred)
* whilst we were in the middle of the open.
*/
if (rconsvp == NULL) {
- (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred);
+ (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
return (0);
}
cmn_err(CE_PANIC, "cnopen: cloned open");
@@ -354,7 +354,7 @@ cnclose(dev_t dev, int flag, int state, struct cred *cred)
return (0);
while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) {
- err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred);
+ err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
if (!err) {
vp->v_stream = NULL;
rconsopen--;
diff --git a/usr/src/uts/common/io/devinfo.c b/usr/src/uts/common/io/devinfo.c
index bc441e93a3..79279b4e31 100644
--- a/usr/src/uts/common/io/devinfo.c
+++ b/usr/src/uts/common/io/devinfo.c
@@ -3630,11 +3630,11 @@ di_cache_write(struct di_cache *cache)
/*
* Now sync the file and close it
*/
- if (error = VOP_FSYNC(vp, FSYNC, kcred)) {
+ if (error = VOP_FSYNC(vp, FSYNC, kcred, NULL)) {
CACHE_DEBUG((DI_ERR, "FSYNC failed: %d", error));
}
- if (error = VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred)) {
+ if (error = VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred, NULL)) {
CACHE_DEBUG((DI_ERR, "close() failed: %d", error));
VN_RELE(vp);
return;
@@ -3655,7 +3655,7 @@ di_cache_write(struct di_cache *cache)
return;
fail:
- (void) VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred, NULL);
VN_RELE(vp);
}
diff --git a/usr/src/uts/common/io/devpoll.c b/usr/src/uts/common/io/devpoll.c
index 965df2a9a1..1e71013d17 100644
--- a/usr/src/uts/common/io/devpoll.c
+++ b/usr/src/uts/common/io/devpoll.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -128,12 +128,12 @@ static struct modlinkage modlinkage = {
* This assumption is not true for /dev/poll; hence the need for extra
* locking.
*
- * To allow more paralellism, each /dev/poll file descriptor (indexed by
+ * To allow more parallelism, each /dev/poll file descriptor (indexed by
* minor number) has its own lock. Since read (dpioctl) is a much more
* frequent operation than write, we want to allow multiple reads on same
* /dev/poll fd. However, we prevent writes from being starved by giving
* priority to write operation. Theoretically writes can starve reads as
- * well. But in pratical sense this is not important because (1) writes
+ * well. But in practical sense this is not important because (1) writes
* happens less often than reads, and (2) write operation defines the
* content of poll fd a cache set. If writes happens so often that they
* can starve reads, that means the cached set is very unstable. It may
@@ -348,7 +348,7 @@ retry:
*/
curthread->t_pollcache = pcp;
error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0,
- &revent, &php);
+ &revent, &php, NULL);
curthread->t_pollcache = NULL;
releasef(fd);
if (error != 0) {
@@ -623,7 +623,7 @@ dpwrite(dev_t dev, struct uio *uiop, cred_t *credp)
*/
curthread->t_pollcache = pcp;
error = VOP_POLL(fp->f_vnode, pfdp->events, 0,
- &pfdp->revents, &php);
+ &pfdp->revents, &php, NULL);
curthread->t_pollcache = NULL;
/*
* We always set the bit when this fd is cached.
@@ -809,7 +809,7 @@ dpioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
continue;
/*
- * Sleep until we are notified, signalled, or timed out.
+ * Sleep until we are notified, signaled, or timed out.
* Do not check for signals if we have a zero timeout.
*/
if (time_out == 0) /* immediate timeout */
diff --git a/usr/src/uts/common/io/fssnap.c b/usr/src/uts/common/io/fssnap.c
index 4e047f03a2..54d3470fda 100644
--- a/usr/src/uts/common/io/fssnap.c
+++ b/usr/src/uts/common/io/fssnap.c
@@ -347,7 +347,7 @@ _fini(void)
* together the frozen file system. The data may either be on the master
* device (no translation exists), in memory (a translation exists but has
* not been flushed to the backing store), or in the backing store file.
- * The read request may require the snapshot driver to retreive data from
+ * The read request may require the snapshot driver to retrieve data from
* several different places and piece it together to look like a single
* contiguous read.
*
@@ -1032,7 +1032,7 @@ int *rvalp)
releasef(fc.rootfiledesc);
/* pass ioctl request to file system */
- error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp);
+ error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp, NULL);
VN_RELE(vp);
break;
}
@@ -1055,7 +1055,7 @@ int *rvalp)
releasef(fc.rootfiledesc);
/* pass ioctl request to file system */
- error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp);
+ error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp, NULL);
VN_RELE(vp);
break;
}
@@ -1130,7 +1130,7 @@ int *rvalp)
* to use as a locking semaphore across the IOCTL
* for mount in progress cases...
*/
- vfsp = kmem_alloc(sizeof (vfs_t), KM_SLEEP);
+ vfsp = vfs_alloc(KM_SLEEP);
VFS_INIT(vfsp, vfsops, NULL);
VFS_HOLD(vfsp);
vfs_addmip(dev, vfsp);
@@ -1146,7 +1146,7 @@ int *rvalp)
* until IOCTL complete to prohibit a mount sneaking
* in
*/
- error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp);
+ error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp, NULL);
vfs_delmip(vfsp);
VFS_RELE(vfsp);
VN_RELE(vp);
diff --git a/usr/src/uts/common/io/gentty.c b/usr/src/uts/common/io/gentty.c
index 431e80245d..086624fc26 100644
--- a/usr/src/uts/common/io/gentty.c
+++ b/usr/src/uts/common/io/gentty.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc.
+ * Copyright 2007 Sun Microsystems, Inc.
* All rights reserved.
* Use is subject to license terms.
*/
@@ -217,7 +217,7 @@ syopen(dev_t *devp, int flag, int otyp, struct cred *cr)
* The multi-open, single-clone means that no cloning
* can happen via this open, hence the assertion.
*/
- error = VOP_OPEN(&ttyvp, FNOCTTY | flag, cr);
+ error = VOP_OPEN(&ttyvp, FNOCTTY | flag, cr, NULL);
if (error == 0) {
struct snode *csp;
@@ -326,7 +326,7 @@ syioctl(dev_t dev, int cmd, intptr_t arg, int mode, struct cred *cr,
return (ENXIO);
}
- error = VOP_IOCTL(sp->s_vp, cmd, arg, mode, cr, rvalp);
+ error = VOP_IOCTL(sp->s_vp, cmd, arg, mode, cr, rvalp, NULL);
tty_rele(sp);
return (error);
@@ -350,7 +350,7 @@ sypoll(dev_t dev, short events, int anyyet, short *reventsp,
return (ENXIO);
}
- error = VOP_POLL(sp->s_vp, events, anyyet, reventsp, phpp);
+ error = VOP_POLL(sp->s_vp, events, anyyet, reventsp, phpp, NULL);
tty_rele(sp);
return (error);
diff --git a/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c b/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c
index a69ecc8fea..71a20fa918 100644
--- a/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c
+++ b/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c
@@ -290,7 +290,7 @@ ibcm_arp_unlink_driver(queue_t **q, vnode_t **dev_vp)
setq(rq, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_TRUE);
- if ((rc = VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED())) != 0) {
+ if ((rc = VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL)) != 0) {
IBTF_DPRINTF_L2(cmlog, "ibcm_arp_unlink_driver: VOP_CLOSE "
"failed %d\n", rc);
}
diff --git a/usr/src/uts/common/io/iwscons.c b/usr/src/uts/common/io/iwscons.c
index e254a42916..54e4bd7762 100644
--- a/usr/src/uts/common/io/iwscons.c
+++ b/usr/src/uts/common/io/iwscons.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -105,7 +105,7 @@ static iwscn_list_t *iwscn_list;
* the redirection streams module (redirmod) pushed on them.
*
* If both iwscn_redirect_lock and iwscn_list_lock must be held then
- * iwscn_redirect_lock must be aquired first.
+ * iwscn_redirect_lock must be acquired first.
*/
static kcondvar_t iwscn_list_cv;
static kmutex_t iwscn_list_lock;
@@ -320,7 +320,7 @@ iwscnpoll(dev_t dev, short events, int anyyet, short *reventsp,
ASSERT(getminor(dev) == 0);
lp = srhold();
- error = VOP_POLL(lp->wl_vp, events, anyyet, reventsp, phpp);
+ error = VOP_POLL(lp->wl_vp, events, anyyet, reventsp, phpp, NULL);
srrele(lp);
return (error);
@@ -448,7 +448,7 @@ iwscnioctl(dev_t dev, int cmd, intptr_t arg, int flag,
}
/* Process the ioctl normally */
- error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp);
+ error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp, NULL);
srrele(lp);
mutex_exit(&iwscn_redirect_lock);
@@ -457,7 +457,7 @@ iwscnioctl(dev_t dev, int cmd, intptr_t arg, int flag,
/* Process the ioctl normally */
lp = srhold();
- error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp);
+ error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp, NULL);
srrele(lp);
return (error);
}
@@ -498,11 +498,11 @@ iwscnopen(dev_t *devp, int flag, int state, cred_t *cred)
* There is currently no redirection going on.
* pass this open request onto the console driver
*/
- error = VOP_OPEN(&vp, flag, cred);
+ error = VOP_OPEN(&vp, flag, cred, NULL);
if (error != 0)
return (error);
- /* Re-aquire the list lock */
+ /* Re-acquire the list lock */
mutex_enter(&iwscn_list_lock);
if (iwscn_list == NULL) {
@@ -513,7 +513,7 @@ iwscnopen(dev_t *devp, int flag, int state, cred_t *cred)
* In this case there must already be a copy of
* this vnode on the list, so we can free up this one.
*/
- (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred);
+ (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
}
}
@@ -588,7 +588,8 @@ iwscnclose(dev_t dev, int flag, int state, cred_t *cred)
if (lp->wl_is_console == B_TRUE)
/* Close the underlying console device. */
- (void) VOP_CLOSE(lp->wl_vp, 0, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(lp->wl_vp, 0, 1, (offset_t)0, kcred,
+ NULL);
kmem_free(lp, sizeof (*lp));
}
diff --git a/usr/src/uts/common/io/l_strplumb.c b/usr/src/uts/common/io/l_strplumb.c
index 7c6f1b55d3..a8ff99b126 100644
--- a/usr/src/uts/common/io/l_strplumb.c
+++ b/usr/src/uts/common/io/l_strplumb.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -70,7 +70,7 @@ kstr_open(major_t maj, minor_t min, vnode_t **vpp, int *fd)
if (fd != NULL)
error = fassign(&vp, FREAD|FWRITE, fd);
else
- error = VOP_OPEN(&vp, FREAD|FWRITE, CRED());
+ error = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL);
/*
* Must set vpp after calling fassign()/VOP_OPEN()
@@ -135,7 +135,7 @@ kstr_close(vnode_t *vp, int fd)
return (EINVAL);
}
} else {
- ret = VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED());
+ ret = VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (ret);
}
diff --git a/usr/src/uts/common/io/lofi.c b/usr/src/uts/common/io/lofi.c
index 2f1107e189..14e06740c8 100644
--- a/usr/src/uts/common/io/lofi.c
+++ b/usr/src/uts/common/io/lofi.c
@@ -223,7 +223,8 @@ lofi_free_handle(dev_t dev, minor_t minor, struct lofi_state *lsp,
char namebuf[50];
if (lsp->ls_vp) {
- (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0, credp);
+ (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag,
+ 1, 0, credp, NULL);
VN_RELE(lsp->ls_vp);
lsp->ls_vp = NULL;
}
@@ -864,7 +865,7 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor,
}
}
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, credp);
+ error = VOP_GETATTR(vp, &vattr, 0, credp, NULL);
if (error) {
goto closeout;
}
@@ -936,7 +937,7 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor,
* Try to handle stacked lofs vnodes.
*/
if (vp->v_type == VREG) {
- if (VOP_REALVP(vp, &lsp->ls_vp) != 0) {
+ if (VOP_REALVP(vp, &lsp->ls_vp, NULL) != 0) {
lsp->ls_vp = vp;
} else {
/*
@@ -971,7 +972,7 @@ propout:
(void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME);
(void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME);
closeout:
- (void) VOP_CLOSE(vp, flag, 1, 0, credp);
+ (void) VOP_CLOSE(vp, flag, 1, 0, credp, NULL);
VN_RELE(vp);
out:
if (zalloced)
@@ -1035,7 +1036,7 @@ lofi_unmap_file(dev_t dev, struct lofi_ioctl *ulip, int byfilename,
while (lsp->ls_vp_iocount > 0)
cv_wait(&lsp->ls_vp_cv, &lsp->ls_vp_lock);
(void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0,
- credp);
+ credp, NULL);
VN_RELE(lsp->ls_vp);
lsp->ls_vp = NULL;
cv_broadcast(&lsp->ls_vp_cv);
diff --git a/usr/src/uts/common/io/lvm/trans/trans_ioctl.c b/usr/src/uts/common/io/lvm/trans/trans_ioctl.c
index 156ed4548a..4fd02c4ff2 100644
--- a/usr/src/uts/common/io/lvm/trans/trans_ioctl.c
+++ b/usr/src/uts/common/io/lvm/trans/trans_ioctl.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -296,7 +295,7 @@ trans_test_trypage(void *d, int mode, IOLOCK *lock)
/*
* get rid of the devices pages
*/
- (void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED());
+ (void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED(), NULL);
/*
* test 1 -- don't find nonexistant page
@@ -335,7 +334,7 @@ errout:
/*
* get rid of the file's pages
*/
- (void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED());
+ (void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED(), NULL);
VN_RELE(devvp);
migp->size = test;
@@ -1301,7 +1300,7 @@ trans_detach_ioctl(void *d, int mode, IOLOCK *lock)
mdclrerror(&migp->mde);
- /* aquire both md_unit_array_rw, and unit_reader lock */
+ /* acquire both md_unit_array_rw, and unit_reader lock */
un = trans_getun(migp->id, &migp->mde,
READERS, lock);
if (un == NULL)
@@ -2239,7 +2238,7 @@ trans_renexch_update_kids(
}
/*
- * MDRNM_SELF_UPDATE_FROM (exhange down) [self->child]
+ * MDRNM_SELF_UPDATE_FROM (exchange down) [self->child]
*/
void
trans_exchange_self_update_from_down(
@@ -2366,7 +2365,7 @@ trans_exchange_self_update_from_down(
}
/*
- * MDRNM_PARENT_UPDATE_TO (exhange down) [parent->self]
+ * MDRNM_PARENT_UPDATE_TO (exchange down) [parent->self]
*/
void
trans_exchange_parent_update_to(
diff --git a/usr/src/uts/common/io/physmem.c b/usr/src/uts/common/io/physmem.c
index 8a4cab75d1..8a9ca67db8 100644
--- a/usr/src/uts/common/io/physmem.c
+++ b/usr/src/uts/common/io/physmem.c
@@ -96,17 +96,17 @@ kmutex_t physmem_mutex; /* protects phsymem_vnodecnt */
static int physmem_getpage(struct vnode *vp, offset_t off, size_t len,
uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, struct cred *cr);
+ enum seg_rw rw, struct cred *cr, caller_context_t *ct);
static int physmem_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 *cred);
+ struct cred *cred, caller_context_t *ct);
static int physmem_delmap(struct vnode *vp, offset_t off, struct as *as,
caddr_t addr, size_t len, uint_t prot, uint_t maxprot, uint_t flags,
- struct cred *cred);
+ struct cred *cred, caller_context_t *ct);
-static void physmem_inactive(vnode_t *vp, cred_t *crp);
+static void physmem_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct);
const fs_operation_def_t physmem_vnodeops_template[] = {
VOPNAME_GETPAGE, { .vop_getpage = physmem_getpage },
@@ -334,7 +334,7 @@ physmem_setup_vnops()
* The guts of the PHYSMEM_SETUP ioctl.
* Create a segment in the address space with the specified parameters.
* If pspp->user_va is NULL, as_gap will be used to find an appropriate VA.
- * We do not do bounds checking on the requested phsycial addresses, if they
+ * We do not do bounds checking on the requested physical addresses, if they
* do not exist in the system, they will not be mappable.
* Returns 0 on success with the following error codes on failure:
* ENOMEM - The VA range requested was already mapped if pspp->user_va is
@@ -643,7 +643,7 @@ physmem_destroy_addrs(uint64_t p_cookie)
static int
physmem_getpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
page_t *pp;
@@ -674,7 +674,7 @@ physmem_getpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp,
static int
physmem_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 *cred)
+ struct cred *cred, caller_context_t *ct)
{
if (curproc->p_as != as) {
return (EINVAL);
@@ -687,7 +687,7 @@ physmem_addmap(struct vnode *vp, offset_t off, struct as *as,
static int
physmem_delmap(struct vnode *vp, offset_t off, struct as *as,
caddr_t addr, size_t len, uint_t prot, uint_t maxprot, uint_t flags,
- struct cred *cred)
+ struct cred *cred, caller_context_t *ct)
{
/*
* Release our hold on the vnode so that the final VN_RELE will
@@ -703,7 +703,7 @@ physmem_delmap(struct vnode *vp, offset_t off, struct as *as,
*/
/*ARGSUSED*/
static void
-physmem_inactive(vnode_t *vp, cred_t *crp)
+physmem_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
{
page_t *pp;
diff --git a/usr/src/uts/common/io/rsm/rsmops.c b/usr/src/uts/common/io/rsm/rsmops.c
index e69af1ad80..67319d2027 100644
--- a/usr/src/uts/common/io/rsm/rsmops.c
+++ b/usr/src/uts/common/io/rsm/rsmops.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -322,7 +321,7 @@ rsm_get_controller(const char *name, uint_t number,
mutex_enter(&rsmops_lock);
if (vp != NULL) {
(void) VOP_CLOSE(vp, FREAD|FWRITE, 0, 0,
- CRED());
+ CRED(), NULL);
VN_RELE(vp);
}
p_ctrl = find_rsmpi_controller(name, number);
@@ -534,7 +533,7 @@ rsmops_device_open(const char *major_name, const minor_t minor_num)
vp = makespecvp(makedevice(maj, minor_num), VCHR);
- ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED());
+ ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL);
if (ret == 0) {
return (vp);
} else {
diff --git a/usr/src/uts/common/io/sysmsg.c b/usr/src/uts/common/io/sysmsg.c
index e91648b722..0e7061c42f 100644
--- a/usr/src/uts/common/io/sysmsg.c
+++ b/usr/src/uts/common/io/sysmsg.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -339,7 +338,7 @@ bind_consadm_conf(char *path)
if (vn_open(path, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0) != 0)
return;
vattr.va_mask = AT_SIZE;
- if ((err = VOP_GETATTR(vp, &vattr, 0, kcred)) != 0) {
+ if ((err = VOP_GETATTR(vp, &vattr, 0, kcred, NULL)) != 0) {
cmn_err(CE_WARN, "sysmsg: getattr: '%s': error %d",
path, err);
goto closevp;
@@ -358,7 +357,7 @@ bind_consadm_conf(char *path)
kmem_free(buf, size);
closevp:
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, kcred, NULL);
VN_RELE(vp);
}
@@ -446,7 +445,7 @@ sysmclose(dev_t dev, int flag, int state, cred_t *cred)
return (0);
}
- (void) VOP_CLOSE(dcvp, FWRITE, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(dcvp, FWRITE, 1, (offset_t)0, kcred, NULL);
VN_RELE(dcvp);
dcvp = NULL;
mutex_exit(&dcvp_mutex);
@@ -459,7 +458,7 @@ sysmclose(dev_t dev, int flag, int state, cred_t *cred)
rw_enter(&sysmcache[i].dca_lock, RW_WRITER);
if (sysmcache[i].dca_vp != NULL) {
(void) VOP_CLOSE(sysmcache[i].dca_vp, flag,
- 1, (offset_t)0, cred);
+ 1, (offset_t)0, cred, NULL);
VN_RELE(sysmcache[i].dca_vp);
sysmcache[i].dca_vp = NULL;
}
@@ -565,7 +564,7 @@ sysmioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred, int *rvalp)
}
default:
/* everything else is sent to the console device */
- return (VOP_IOCTL(dcvp, cmd, arg, flag, cred, rvalp));
+ return (VOP_IOCTL(dcvp, cmd, arg, flag, cred, rvalp, NULL));
}
if ((rval = secpolicy_console(cred)) != 0)
@@ -694,7 +693,7 @@ static int
sysmpoll(dev_t dev, short events, int anyyet, short *reventsp,
struct pollhead **phpp)
{
- return (VOP_POLL(dcvp, events, anyyet, reventsp, phpp));
+ return (VOP_POLL(dcvp, events, anyyet, reventsp, phpp, NULL));
}
/* Sanity check that the device is good */
diff --git a/usr/src/uts/common/ipp/ipgpc/classifier.c b/usr/src/uts/common/ipp/ipgpc/classifier.c
index 4f329c9d1b..bb09a3ca89 100644
--- a/usr/src/uts/common/ipp/ipgpc/classifier.c
+++ b/usr/src/uts/common/ipp/ipgpc/classifier.c
@@ -71,7 +71,7 @@ static void get_port_info(ipgpc_packet_t *, void *, int, mblk_t *);
* common_classify(packet, fid_table, slctrs_srchd)
*
* searches each of the common selectors
- * - will return NORMAL_MATCH on sucess. NO_MATCHES on error
+ * - will return NORMAL_MATCH on success. NO_MATCHES on error
*/
static int
common_classify(ipgpc_packet_t *packet, ht_match_t *fid_table,
diff --git a/usr/src/uts/common/ipp/ipgpc/filters.c b/usr/src/uts/common/ipp/ipgpc/filters.c
index 2add8eba6a..7dd4dce48e 100644
--- a/usr/src/uts/common/ipp/ipgpc/filters.c
+++ b/usr/src/uts/common/ipp/ipgpc/filters.c
@@ -1300,7 +1300,7 @@ ipgpc_addclass(ipgpc_class_t *in_class, ipp_flags_t flags) {
* - number of bytes that matched this class
* - number of packets that matched this class
* - time in hrtime of last match for this class
- * any failures are returned, zero on sucess
+ * any failures are returned, zero on success
*/
static int
class_statinit(ipgpc_class_t *in_class, int in_class_id)
@@ -1742,7 +1742,7 @@ ipgpc_modifyfilter(nvlist_t **nvlpp, ipp_flags_t flags)
if (ret == 0) { /* no error, add filter */
ret = ipgpc_addfilter(filter, name, flags);
if (ret != 0) {
- /* error occured, free filter fields */
+ /* error occurred, free filter fields */
ipgpc0dbg(("ipgpc_modifyfilter: invalid " \
"filter given, unable to modify " \
"existing filter %s",
@@ -1756,7 +1756,7 @@ ipgpc_modifyfilter(nvlist_t **nvlpp, ipp_flags_t flags)
}
ipgpc_filter_destructor(&old_filter);
} else {
- ipgpc0dbg(("ipgpc_modifyfilter: error %d occured " \
+ ipgpc0dbg(("ipgpc_modifyfilter: error %d occurred " \
"when modifying filter", ret));
ipgpc_filter_destructor(&old_filter);
ipgpc_filter_destructor(filter);
@@ -1863,7 +1863,7 @@ ipgpc_modifyclass(nvlist_t **nvlpp, ipp_flags_t flags)
if ((rc = ipp_action_ref(ipgpc_aid,
in_class.next_action, 0)) != 0) {
ipgpc0dbg(("ipgpc_modifyclass: error " \
- "occured while adding a reference to " \
+ "occurred while adding a reference to " \
"the new next_action %d",
in_class.next_action));
mutex_exit(&ipgpc_cid_list_lock);
diff --git a/usr/src/uts/common/krtld/kobj.c b/usr/src/uts/common/krtld/kobj.c
index 7a0427265e..deffd012bd 100644
--- a/usr/src/uts/common/krtld/kobj.c
+++ b/usr/src/uts/common/krtld/kobj.c
@@ -217,7 +217,7 @@ static kmutex_t kobj_lock; /* protects mach memory list */
* The following functions have been implemented by the kernel.
* However, many 3rd party drivers provide their own implementations
* of these functions. When such drivers are loaded, messages
- * indicateing that these symbols have been mulply defined will be
+ * indicating that these symbols have been multiply defined will be
* emitted to the console. To avoid alarming customers for no good
* reason, we simply suppress such warnings for the following set of
* functions.
@@ -804,7 +804,7 @@ load_exec(val_t *bootaux, char *filename)
allocsize += MAXPATHLEN;
}
bcopy(libname, mp->depends_on + osize, lsize);
- *(mp->depends_on + nsize) = ' '; /* seperate */
+ *(mp->depends_on + nsize) = ' '; /* separate */
nsize++;
osize = nsize;
}
@@ -1760,7 +1760,7 @@ process_dynamic(struct module *mp, char *dyndata, char *strdata)
* finish up the depends string (if any)
*/
if (depstr != NULL) {
- *(depstr + nsize - 1) = '\0'; /* overwrite seperator w/term */
+ *(depstr + nsize - 1) = '\0'; /* overwrite separator w/term */
if (path != NULL)
kobj_free(path, MAXPATHLEN);
@@ -3577,7 +3577,7 @@ kobj_open(char *filename)
cred_t *saved_cred = curthread->t_cred;
curthread->t_cred = kcred;
Errno = vn_openat(filename, UIO_SYSSPACE, FREAD, 0, &vp,
- 0, 0, rootdir);
+ 0, 0, rootdir, -1);
curthread->t_cred = saved_cred;
}
kobjopen_free(ltp);
@@ -3704,7 +3704,7 @@ kobj_close(intptr_t descr)
if (_modrootloaded) {
struct vnode *vp = (struct vnode *)descr;
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
} else
(void) kobj_boot_close((int)descr);
@@ -3719,7 +3719,7 @@ kobj_fstat(intptr_t descr, struct bootstat *buf)
if (_modrootloaded) {
vattr_t vattr;
struct vnode *vp = (struct vnode *)descr;
- if (VOP_GETATTR(vp, &vattr, 0, kcred) != 0)
+ if (VOP_GETATTR(vp, &vattr, 0, kcred, NULL) != 0)
return (-1);
/*
diff --git a/usr/src/uts/common/ktli/t_kopen.c b/usr/src/uts/common/ktli/t_kopen.c
index c49b03b610..c373d4a7f9 100644
--- a/usr/src/uts/common/ktli/t_kopen.c
+++ b/usr/src/uts/common/ktli/t_kopen.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -124,7 +123,8 @@ t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
* might fail due to temporarely out of memory.
*/
do {
- if ((error = VOP_OPEN(&vp, flags, cr)) == EAGAIN) {
+ if ((error = VOP_OPEN(&vp, flags, cr, NULL))
+ == EAGAIN) {
(void) delay(hz);
}
} while (error == EAGAIN && ++rtries < 5);
diff --git a/usr/src/uts/common/nfs/nfs.h b/usr/src/uts/common/nfs/nfs.h
index 03c32254b7..265b02d315 100644
--- a/usr/src/uts/common/nfs/nfs.h
+++ b/usr/src/uts/common/nfs/nfs.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -254,7 +254,7 @@ extern bool_t nfs_allow_preepoch_time;
* If no negative otw values are allowed, may use the full 32-bits of the
* time to represent time later than 2038, by presenting the value as an
* unsigned (but this can only be used by 64-bit apps due to cstat32
- * retrictions). If negative values are allowed, cannot represent times
+ * restrictions). If negative values are allowed, cannot represent times
* after 2038. Either way, all 32 bits have a valid representation.
*/
@@ -496,7 +496,7 @@ struct nfsfattr {
uint32_t na_uid; /* owner user id */
uint32_t na_gid; /* owner group id */
uint32_t na_size; /* file size in bytes */
- uint32_t na_blocksize; /* prefered block size */
+ uint32_t na_blocksize; /* preferred block size */
uint32_t na_rdev; /* special device # */
uint32_t na_blocks; /* Kb of disk used by file */
uint32_t na_fsid; /* device # */
@@ -907,7 +907,7 @@ extern int nfsinit(int, char *);
extern void nfsfini(void);
extern int nfs_vfsinit(void);
extern void nfs_vfsfini(void);
-extern int nfs_dump(vnode_t *, caddr_t, int, int);
+extern int nfs_dump(vnode_t *, caddr_t, int, int, caller_context_t *);
extern void nfs_perror(int error, char *fmt, ...);
extern void nfs_cmn_err(int error, int level, char *fmt, ...);
extern int nfs_addcllock(vnode_t *vp, struct flock64 *bfp);
diff --git a/usr/src/uts/common/nfs/nfs4.h b/usr/src/uts/common/nfs/nfs4.h
index 2000cac44f..b9a76a2d43 100644
--- a/usr/src/uts/common/nfs/nfs4.h
+++ b/usr/src/uts/common/nfs/nfs4.h
@@ -858,7 +858,8 @@ extern nfsstat4 rfs4_get_deleg_state(stateid4 *,
extern nfsstat4 rfs4_get_lo_state(stateid4 *, rfs4_lo_state_t **,
bool_t);
extern nfsstat4 rfs4_check_stateid(int, vnode_t *, stateid4 *,
- bool_t, bool_t *, bool_t);
+ bool_t, bool_t *, bool_t,
+ caller_context_t *);
extern int rfs4_check_stateid_seqid(rfs4_state_t *, stateid4 *);
extern int rfs4_check_lo_stateid_seqid(rfs4_lo_state_t *,
stateid4 *);
@@ -908,8 +909,8 @@ extern void rfs4_clear_dont_grant(rfs4_file_t *);
/*
* nfs4 monitored operations.
*/
-extern int deleg_rdopen(femarg_t *, int, cred_t *);
-extern int deleg_wropen(femarg_t *, int, cred_t *);
+extern int deleg_rdopen(femarg_t *, int, cred_t *, caller_context_t *);
+extern int deleg_wropen(femarg_t *, int, cred_t *, caller_context_t *);
extern int deleg_rd_rwlock(femarg_t *, int, caller_context_t *);
extern int deleg_wr_rwlock(femarg_t *, int, caller_context_t *);
extern int deleg_read(femarg_t *, uio_t *, int, cred_t *, caller_context_t *);
@@ -918,8 +919,10 @@ extern int deleg_setattr(femarg_t *, vattr_t *, int, cred_t *,
caller_context_t *);
extern int deleg_space(femarg_t *, int, flock64_t *, int, offset_t, cred_t *,
caller_context_t *);
-extern int deleg_setsecattr(femarg_t *, vsecattr_t *, int, cred_t *);
-extern int deleg_vnevent(femarg_t *, vnevent_t, vnode_t *, char *);
+extern int deleg_setsecattr(femarg_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int deleg_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
+ caller_context_t *);
extern void rfs4_mon_hold(void *);
extern void rfs4_mon_rele(void *);
diff --git a/usr/src/uts/common/nfs/rnode.h b/usr/src/uts/common/nfs/rnode.h
index e4eb0cee5c..63d38ba6ee 100644
--- a/usr/src/uts/common/nfs/rnode.h
+++ b/usr/src/uts/common/nfs/rnode.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -334,7 +334,7 @@ extern void nfs_async_commit(vnode_t *, page_t *, offset3, count3,
cred_t *, void (*)(vnode_t *, page_t *,
offset3, count3, cred_t *));
extern void nfs_async_inactive(vnode_t *, cred_t *, void (*)(vnode_t *,
- cred_t *));
+ cred_t *, caller_context_t *));
extern int writerp(rnode_t *, caddr_t, int, struct uio *, int);
extern int nfs_putpages(vnode_t *, u_offset_t, size_t, int, cred_t *);
extern void nfs_invalidate_pages(vnode_t *, u_offset_t, cred_t *);
diff --git a/usr/src/uts/common/os/acct.c b/usr/src/uts/common/os/acct.c
index c596ce45f3..a8da2f8fb0 100644
--- a/usr/src/uts/common/os/acct.c
+++ b/usr/src/uts/common/os/acct.c
@@ -130,7 +130,8 @@ acct_shutdown(zoneid_t zoneid, void *arg)
* held vnode may cause filesystems to be busy, and the zone
* shutdown operation to fail.
*/
- (void) VOP_CLOSE(ag->acctvp, FWRITE, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(ag->acctvp, FWRITE, 1, (offset_t)0, kcred,
+ NULL);
VN_RELE(ag->acctvp);
}
ag->acctvp = NULL;
@@ -211,7 +212,7 @@ acct_find(vnode_t *vp, boolean_t compare_vfs)
ASSERT(MUTEX_HELD(&acct_list_lock));
ASSERT(vp != NULL);
- if (VOP_REALVP(vp, &realvp))
+ if (VOP_REALVP(vp, &realvp, NULL))
realvp = vp;
for (ag = list_head(&acct_list); ag != NULL;
ag = list_next(&acct_list, ag)) {
@@ -223,7 +224,7 @@ acct_find(vnode_t *vp, boolean_t compare_vfs)
mutex_exit(&ag->aclock);
continue;
}
- if (VOP_REALVP(ag->acctvp, &racctvp))
+ if (VOP_REALVP(ag->acctvp, &racctvp, NULL))
racctvp = ag->acctvp;
if (compare_vfs) {
if (racctvp->v_vfsp == realvp->v_vfsp)
@@ -281,7 +282,8 @@ sysacct(char *fname)
ag->acctvp = NULL;
mutex_exit(&ag->aclock);
if (vp) {
- error = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ error = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(),
+ NULL);
VN_RELE(vp);
}
return (error == 0 ? 0 : set_errno(error));
@@ -333,7 +335,7 @@ sysacct(char *fname)
}
if (vp) {
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
return (error == 0 ? 0 : set_errno(error));
@@ -425,7 +427,7 @@ acct(char st)
* currently large file aware.
*/
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vp, &va, 0, kcred) == 0) {
+ if (VOP_GETATTR(vp, &va, 0, kcred, NULL) == 0) {
error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&ag->acctbuf,
sizeof (ag->acctbuf), 0LL, UIO_SYSSPACE, FAPPEND,
(rlim64_t)MAXOFF32_T, kcred, &resid);
diff --git a/usr/src/uts/common/os/core.c b/usr/src/uts/common/os/core.c
index 4adac80e93..71af0012d4 100644
--- a/usr/src/uts/common/os/core.c
+++ b/usr/src/uts/common/os/core.c
@@ -159,16 +159,16 @@ remove_core_file(char *fp, enum core_types core_type)
else if ((dvfsp = dvp->v_vfsp) != NULL &&
(dvfsp->vfs_flag & VFS_RDONLY))
error = EROFS;
- else if ((error = VOP_ACCESS(vp, VWRITE, 0, CRED())) == 0) {
+ else if ((error = VOP_ACCESS(vp, VWRITE, 0, CRED(), NULL)) == 0) {
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_share_conflict(vp, NBL_REMOVE)) {
+ if (nbl_share_conflict(vp, NBL_REMOVE, NULL)) {
error = EACCES;
}
}
if (!error) {
- error = VOP_REMOVE(dvp, pn.pn_path, CRED());
+ error = VOP_REMOVE(dvp, pn.pn_path, CRED(), NULL, 0);
}
}
@@ -254,8 +254,9 @@ create_core_file(char *fp, enum core_types core_type, vnode_t **vpp)
pn_setlast(&pn);
file = pn.pn_path;
}
- error = vn_openat(file, UIO_SYSSPACE, FWRITE | FTRUNC | FEXCL |
- FCREAT | FOFFMAX, perms, &vp, CRCREAT, PTOU(curproc)->u_cmask, dvp);
+ error = vn_openat(file, UIO_SYSSPACE,
+ FWRITE | FTRUNC | FEXCL | FCREAT | FOFFMAX,
+ perms, &vp, CRCREAT, PTOU(curproc)->u_cmask, dvp, -1);
if (core_type != CORE_PROC) {
VN_RELE(dvp);
pn_free(&pn);
@@ -265,10 +266,10 @@ create_core_file(char *fp, enum core_types core_type, vnode_t **vpp)
*/
vattr.va_mask = AT_UID;
if (error == 0 &&
- (VOP_GETATTR(vp, &vattr, 0, credp) != 0 ||
+ (VOP_GETATTR(vp, &vattr, 0, credp, NULL) != 0 ||
vattr.va_uid != crgetuid(credp))) {
(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0,
- credp);
+ credp, NULL);
VN_RELE(vp);
(void) remove_core_file(fp, core_type);
error = EACCES;
@@ -448,7 +449,7 @@ do_core(char *fp, int sig, enum core_types core_type, struct core_globals *cg)
rw_exit(eswp->exec_lock);
}
- closerr = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, credp);
+ closerr = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, credp, NULL);
VN_RELE(vp);
if (error == 0)
error = closerr;
diff --git a/usr/src/uts/common/os/cred.c b/usr/src/uts/common/os/cred.c
index 349c4f3c12..c6a1f1fabb 100644
--- a/usr/src/uts/common/os/cred.c
+++ b/usr/src/uts/common/os/cred.c
@@ -56,11 +56,13 @@
#include <sys/prsystm.h>
#include <sys/modctl.h>
#include <sys/avl.h>
+#include <sys/door.h>
#include <c2/audit.h>
#include <sys/zone.h>
#include <sys/tsol/label.h>
#include <sys/sid.h>
#include <sys/idmap.h>
+#include <sys/varargs.h>
typedef struct ephidmap_data {
uid_t min_uid, last_uid;
@@ -1028,8 +1030,8 @@ eph_gid_alloc(int flags, gid_t *start, int count)
}
/*
- * If the credential contains any ephemeral IDs, map the credential
- * to nobody.
+ * If the credential user SID or group SID is mapped to an ephemeral
+ * ID, map the credential to nobody.
*/
cred_t *
crgetmapped(const cred_t *cr)
@@ -1042,15 +1044,11 @@ crgetmapped(const cred_t *cr)
return (NULL);
if (cr->cr_ksid != NULL) {
- int i;
-
- for (i = 0; i < KSID_COUNT; i++)
- if (cr->cr_ksid->kr_sidx[i].ks_id > MAXUID)
- return (ephemeral_data.nobody);
- if (cr->cr_ksid->kr_sidlist != NULL &&
- cr->cr_ksid->kr_sidlist->ksl_neid > 0) {
- return (ephemeral_data.nobody);
- }
+ if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID)
+ return (ephemeral_data.nobody);
+
+ if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID)
+ return (ephemeral_data.nobody);
}
return ((cred_t *)cr);
@@ -1088,7 +1086,38 @@ crgetsid(const cred_t *cr, int i)
ksidlist_t *
crgetsidlist(const cred_t *cr)
{
- if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidlist != NULL)
+ if (cr->cr_ksid != NULL)
return (cr->cr_ksid->kr_sidlist);
return (NULL);
}
+
+/*
+ * Interface to set the effective and permitted privileges for
+ * a credential; this interface does no security checks and is
+ * intended for kernel (file)servers creating credentials with
+ * specific privileges.
+ */
+int
+crsetpriv(cred_t *cr, ...)
+{
+ va_list ap;
+ const char *privnm;
+
+ ASSERT(cr->cr_ref <= 2);
+
+ priv_set_PA(cr);
+
+ va_start(ap, cr);
+
+ while ((privnm = va_arg(ap, const char *)) != NULL) {
+ int priv = priv_getbyname(privnm, 0);
+ if (priv < 0)
+ return (-1);
+
+ priv_addset(&CR_PPRIV(cr), priv);
+ priv_addset(&CR_EPRIV(cr), priv);
+ }
+ priv_adjust_PA(cr);
+ va_end(ap);
+ return (0);
+}
diff --git a/usr/src/uts/common/os/devcache.c b/usr/src/uts/common/os/devcache.c
index 8e1313d487..75ed982940 100644
--- a/usr/src/uts/common/os/devcache.c
+++ b/usr/src/uts/common/os/devcache.c
@@ -75,7 +75,7 @@
* The data per client is entirely within the control of
* the client. When reading, data unpacked from the backing
* store should be inserted in the list. The pointer to
- * the list can be retreived via nvf_list(). When writing,
+ * the list can be retrieved via nvf_list(). When writing,
* the data on the list is to be packed and returned to the
* nvpdaemon as an nvlist.
*
@@ -618,7 +618,7 @@ kfclose(kfile_t *fp)
KFDEBUG((CE_CONT, "close: %s\n", fp->kf_fname));
if ((fp->kf_vnflags & FWRITE) && fp->kf_state == 0) {
- rval = VOP_FSYNC(fp->kf_vp, FSYNC, kcred);
+ rval = VOP_FSYNC(fp->kf_vp, FSYNC, kcred, NULL);
if (rval != 0) {
nvf_error("%s: sync error %d\n",
fp->kf_fname, rval);
@@ -626,7 +626,8 @@ kfclose(kfile_t *fp)
KFDEBUG((CE_CONT, "%s: sync ok\n", fp->kf_fname));
}
- rval = VOP_CLOSE(fp->kf_vp, fp->kf_vnflags, 1, (offset_t)0, kcred);
+ rval = VOP_CLOSE(fp->kf_vp, fp->kf_vnflags, 1, (offset_t)0, kcred,
+ NULL);
if (rval != 0) {
if (fp->kf_state == 0) {
nvf_error("%s: close error %d\n",
diff --git a/usr/src/uts/common/os/driver.c b/usr/src/uts/common/os/driver.c
index 6526113828..3de2712c4c 100644
--- a/usr/src/uts/common/os/driver.c
+++ b/usr/src/uts/common/os/driver.c
@@ -297,7 +297,7 @@ dev_lopen(dev_t *devp, int flag, int otype, struct cred *cred)
struct vnode *cvp;
vp = makespecvp(*devp, (otype == OTYP_BLK) ? VBLK : VCHR);
- error = VOP_OPEN(&vp, flag | FKLYR, cred);
+ error = VOP_OPEN(&vp, flag | FKLYR, cred, NULL);
if (error == 0) {
/* Pick up the (possibly) new dev_t value. */
*devp = vp->v_rdev;
@@ -332,13 +332,13 @@ dev_lclose(dev_t dev, int flag, int otype, struct cred *cred)
ulong_t offset;
vp = makespecvp(dev, (otype == OTYP_BLK) ? VBLK : VCHR);
- error = VOP_CLOSE(vp, flag | FKLYR, 1, (offset_t)0, cred);
+ error = VOP_CLOSE(vp, flag | FKLYR, 1, (offset_t)0, cred, NULL);
/*
* Release the extra dev_lopen hold on the common vnode. We inline a
* VN_RELE(cvp) call so that we can detect more dev_lclose calls than
* dev_lopen calls without panic. See vn_rele. If our inline of
- * vn_rele called VOP_INACTIVE(cvp, CRED()) we would panic on the
+ * vn_rele called VOP_INACTIVE(cvp, CRED(), ...) we would panic on the
* "release the makespecvp vnode" VN_RELE(vp) that follows - so
* instead we diagnose this situation. Note that the driver has
* still seen a double close(9E), but that would have occurred with
diff --git a/usr/src/uts/common/os/driver_lyr.c b/usr/src/uts/common/os/driver_lyr.c
index 266e3cbb79..66e9f58e35 100644
--- a/usr/src/uts/common/os/driver_lyr.c
+++ b/usr/src/uts/common/os/driver_lyr.c
@@ -757,7 +757,7 @@ ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
return (ENXIO);
/* open the device */
- if ((err = VOP_OPEN(&vp, flag | FKLYR, cr)) != 0)
+ if ((err = VOP_OPEN(&vp, flag | FKLYR, cr, NULL)) != 0)
return (err);
/* possible clone open, make sure that we still have a spec node */
@@ -783,7 +783,7 @@ ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
vnode_t *cvp = common_specvp(nlhp->lh_vp);
dev_t dev = cvp->v_rdev;
- (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred);
+ (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred, NULL);
bflush(dev);
}
@@ -945,7 +945,7 @@ i_check_string(char *str, int prop_len)
/*
* i_pack_string_array takes a a string array property that is represented
- * as a concatination of strings (with the NULL character included for
+ * as a concatenation of strings (with the NULL character included for
* each string) and converts it into a format that can be returned by
* ldi_prop_lookup_string_array.
*/
@@ -1258,7 +1258,7 @@ ldi_mlink_lh(vnode_t *vp, int cmd, intptr_t arg, cred_t *crp, int *rvalp)
}
/*
- * ldi_mlink_fp() is invoked for all successfull streams linkages created
+ * ldi_mlink_fp() is invoked for all successful streams linkages created
* via I_LINK and I_PLINK. ldi_mlink_fp() records the linkage information
* in its internal state so that the devinfo snapshot code has some
* observability into streams device linkage information.
@@ -1693,7 +1693,7 @@ ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
vnode_t *cvp = common_specvp(handlep->lh_vp);
dev_t dev = cvp->v_rdev;
- (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred);
+ (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred, NULL);
bflush(dev);
}
@@ -1727,7 +1727,7 @@ ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
#endif
/* do a layered close on the device */
- err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr);
+ err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr, NULL);
LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", "ldi close", (void *)lh));
@@ -2903,7 +2903,7 @@ ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id)
*
* NDI events: These are events which are serviced by the NDI event subsystem.
* LDI subsystem just provides a thin wrapper around the NDI event interfaces
- * These events are thereefore *not* native events.
+ * These events are therefore *not* native events.
*/
static int
diff --git a/usr/src/uts/common/os/dumpsubr.c b/usr/src/uts/common/os/dumpsubr.c
index 8dd63a298b..b8dba61893 100644
--- a/usr/src/uts/common/os/dumpsubr.c
+++ b/usr/src/uts/common/os/dumpsubr.c
@@ -206,11 +206,11 @@ dumpinit(vnode_t *vp, char *name, int justchecking)
* (1) a real device that's not mounted and has a cb_dump routine, or
* (2) a swapfile on some filesystem that has a vop_dump routine.
*/
- if ((error = VOP_OPEN(&cvp, FREAD | FWRITE, kcred)) != 0)
+ if ((error = VOP_OPEN(&cvp, FREAD | FWRITE, kcred, NULL)) != 0)
return (error);
vattr.va_mask = AT_SIZE | AT_TYPE | AT_RDEV;
- if ((error = VOP_GETATTR(cvp, &vattr, 0, kcred)) == 0) {
+ if ((error = VOP_GETATTR(cvp, &vattr, 0, kcred, NULL)) == 0) {
if (vattr.va_type == VBLK || vattr.va_type == VCHR) {
if (devopsp[getmajor(vattr.va_rdev)]->
devo_cb_ops->cb_dump == nodev)
@@ -228,7 +228,8 @@ dumpinit(vnode_t *vp, char *name, int justchecking)
error = ENOSPC;
if (error || justchecking) {
- (void) VOP_CLOSE(cvp, FREAD | FWRITE, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(cvp, FREAD | FWRITE, 1, (offset_t)0,
+ kcred, NULL);
return (error);
}
@@ -251,24 +252,26 @@ dumpinit(vnode_t *vp, char *name, int justchecking)
*/
if (cvp->v_type == VBLK &&
(cdev_vp = makespecvp(VTOS(cvp)->s_dev, VCHR)) != NULL) {
- if (VOP_OPEN(&cdev_vp, FREAD | FWRITE, kcred) == 0) {
+ if (VOP_OPEN(&cdev_vp, FREAD | FWRITE, kcred, NULL) == 0) {
size_t blk_size;
struct dk_cinfo dki;
struct vtoc vtoc;
if (VOP_IOCTL(cdev_vp, DKIOCGVTOC, (intptr_t)&vtoc,
- FKIOCTL, kcred, NULL) == 0 && vtoc.v_sectorsz != 0)
+ FKIOCTL, kcred, NULL, NULL) == 0 &&
+ vtoc.v_sectorsz != 0)
blk_size = vtoc.v_sectorsz;
else
blk_size = DEV_BSIZE;
if (VOP_IOCTL(cdev_vp, DKIOCINFO, (intptr_t)&dki,
- FKIOCTL, kcred, NULL) == 0) {
+ FKIOCTL, kcred, NULL, NULL) == 0) {
dump_iosize = dki.dki_maxtransfer * blk_size;
dumpbuf_resize();
}
- (void) VOP_CLOSE(cdev_vp, FREAD | FWRITE, 1, 0, kcred);
+ (void) VOP_CLOSE(cdev_vp, FREAD | FWRITE, 1, 0,
+ kcred, NULL);
}
VN_RELE(cdev_vp);
@@ -286,7 +289,7 @@ dumpfini(void)
kmem_free(dumppath, strlen(dumppath) + 1);
- (void) VOP_CLOSE(dumpvp, FREAD | FWRITE, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(dumpvp, FREAD | FWRITE, 1, (offset_t)0, kcred, NULL);
VN_RELE(dumpvp);
@@ -334,7 +337,7 @@ dumpvp_flush(void)
} else if (size != 0) {
if (panicstr)
err = VOP_DUMP(dumpvp, dumpbuf_start,
- lbtodb(dumpvp_off), btod(size));
+ lbtodb(dumpvp_off), btod(size), NULL);
else
err = vn_rdwr(UIO_WRITE, dumpvp, dumpbuf_start, size,
dumpvp_off, UIO_SYSSPACE, 0, dumpvp_limit,
@@ -478,7 +481,7 @@ dump_ereports(void)
if (!panicstr) {
(void) VOP_PUTPAGE(dumpvp, dumpvp_start,
(size_t)(dumpvp_off - dumpvp_start),
- B_INVAL | B_FORCE, kcred);
+ B_INVAL | B_FORCE, kcred, NULL);
}
}
@@ -521,7 +524,7 @@ dump_messages(void)
if (!panicstr) {
(void) VOP_PUTPAGE(dumpvp, dumpvp_start,
(size_t)(dumpvp_off - dumpvp_start),
- B_INVAL | B_FORCE, kcred);
+ B_INVAL | B_FORCE, kcred, NULL);
}
}
@@ -600,8 +603,8 @@ dumpsys(void)
if (panicstr) {
dumphdr->dump_flags &= ~DF_LIVE;
- (void) VOP_DUMPCTL(dumpvp, DUMP_FREE, NULL);
- (void) VOP_DUMPCTL(dumpvp, DUMP_ALLOC, NULL);
+ (void) VOP_DUMPCTL(dumpvp, DUMP_FREE, NULL, NULL);
+ (void) VOP_DUMPCTL(dumpvp, DUMP_ALLOC, NULL, NULL);
(void) vsnprintf(dumphdr->dump_panicstring, DUMP_PANICSIZE,
panicstr, panicargs);
}
diff --git a/usr/src/uts/common/os/exacct.c b/usr/src/uts/common/os/exacct.c
index 88e532d691..6e27952402 100644
--- a/usr/src/uts/common/os/exacct.c
+++ b/usr/src/uts/common/os/exacct.c
@@ -181,7 +181,7 @@ exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize)
* the present accounting file.
*/
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred);
+ error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL);
if (error == 0) {
error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf,
bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T,
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c
index 652a01c34c..8823e44e27 100644
--- a/usr/src/uts/common/os/exec.c
+++ b/usr/src/uts/common/os/exec.c
@@ -538,7 +538,7 @@ gexec(
goto bad;
/* need to open vnode for stateful file systems like rfs */
- if ((error = VOP_OPEN(vpp, FREAD, CRED())) != 0)
+ if ((error = VOP_OPEN(vpp, FREAD, CRED(), NULL)) != 0)
goto bad;
vp = *vpp;
@@ -934,13 +934,13 @@ execpermissions(struct vnode *vp, struct vattr *vattrp, struct uarg *args)
proc_t *p = ttoproc(curthread);
vattrp->va_mask = AT_MODE | AT_UID | AT_GID | AT_SIZE;
- if (error = VOP_GETATTR(vp, vattrp, ATTR_EXEC, p->p_cred))
+ if (error = VOP_GETATTR(vp, vattrp, ATTR_EXEC, p->p_cred, NULL))
return (error);
/*
* Check the access mode.
* If VPROC, ask /proc if the file is an object file.
*/
- if ((error = VOP_ACCESS(vp, VEXEC, 0, p->p_cred)) != 0 ||
+ if ((error = VOP_ACCESS(vp, VEXEC, 0, p->p_cred, NULL)) != 0 ||
!(vp->v_type == VREG || (vp->v_type == VPROC && pr_isobject(vp))) ||
(vp->v_vfsp->vfs_flag & VFS_NOEXEC) != 0 ||
(vattrp->va_mode & (VEXEC|(VEXEC>>3)|(VEXEC>>6))) == 0) {
@@ -950,7 +950,7 @@ execpermissions(struct vnode *vp, struct vattr *vattrp, struct uarg *args)
}
if ((p->p_plist || (p->p_proc_flag & (P_PR_PTRACE|P_PR_TRACE))) &&
- (error = VOP_ACCESS(vp, VREAD, 0, p->p_cred))) {
+ (error = VOP_ACCESS(vp, VREAD, 0, p->p_cred, NULL))) {
/*
* If process is under ptrace(2) compatibility,
* fail the exec(2).
@@ -1011,7 +1011,7 @@ execmap(struct vnode *vp, caddr_t addr, size_t len, size_t zfodlen,
}
if (error = VOP_MAP(vp, (offset_t)offset,
p->p_as, &addr, len, prot, PROT_ALL,
- mflag, CRED()))
+ mflag, CRED(), NULL))
goto bad;
/*
@@ -1188,7 +1188,7 @@ execopen(struct vnode **vpp, int *fdp)
*fdp = -1; /* just in case falloc changed value */
return (error);
}
- if (error = VOP_OPEN(&vp, filemode, CRED())) {
+ if (error = VOP_OPEN(&vp, filemode, CRED(), NULL)) {
VN_RELE(vp);
setf(*fdp, NULL);
unfalloc(fp);
diff --git a/usr/src/uts/common/os/fio.c b/usr/src/uts/common/os/fio.c
index b31c9c7c2e..c5dc56e150 100644
--- a/usr/src/uts/common/os/fio.c
+++ b/usr/src/uts/common/os/fio.c
@@ -23,7 +23,7 @@
/* All Rights Reserved */
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -918,7 +918,7 @@ closef(file_t *fp)
vp = fp->f_vnode;
- error = VOP_CLOSE(vp, flag, count, offset, fp->f_cred);
+ error = VOP_CLOSE(vp, flag, count, offset, fp->f_cred, NULL);
if (count > 1) {
mutex_exit(&fp->f_tlock);
@@ -1348,7 +1348,7 @@ fassign(vnode_t **vpp, int mode, int *fdp)
if (error = falloc((vnode_t *)NULL, mode, &fp, &fd))
return (error);
- if (error = VOP_OPEN(vpp, mode, fp->f_cred)) {
+ if (error = VOP_OPEN(vpp, mode, fp->f_cred, NULL)) {
setf(fd, NULL);
unfalloc(fp);
return (error);
@@ -1506,14 +1506,15 @@ vpsetattr(vnode_t *vp, vattr_t *vap, int flags)
nbl_start_crit(vp, RW_READER);
in_crit = 1;
vattr.va_mask = AT_SIZE;
- if (!(error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
+ if (!(error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
begin = vap->va_size > vattr.va_size ?
vattr.va_size : vap->va_size;
length = vattr.va_size > vap->va_size ?
vattr.va_size - vap->va_size :
vap->va_size - vattr.va_size;
- if (nbl_conflict(vp, NBL_WRITE, begin, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, begin, length, 0,
+ NULL)) {
error = EACCES;
}
}
diff --git a/usr/src/uts/common/os/flock.c b/usr/src/uts/common/os/flock.c
index a3028b75dc..da81003d1c 100644
--- a/usr/src/uts/common/os/flock.c
+++ b/usr/src/uts/common/os/flock.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -22,7 +21,7 @@
/* ONC_PLUS EXTRACT START */
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -201,7 +200,7 @@ static int level_one_path(lock_descriptor_t *, lock_descriptor_t *);
static int level_two_path(lock_descriptor_t *, lock_descriptor_t *, int);
#endif
-/* proc_graph function definitons */
+/* proc_graph function definitions */
static int flk_check_deadlock(lock_descriptor_t *);
static void flk_proc_graph_uncolor(void);
static proc_vertex_t *flk_get_proc_vertex(lock_descriptor_t *);
@@ -684,7 +683,7 @@ flk_zone_fini(zoneid_t zoneid, void *data)
}
/*
- * Get a lock_descriptor structure with initialisation of edge lists.
+ * Get a lock_descriptor structure with initialization of edge lists.
*/
static lock_descriptor_t *
@@ -727,14 +726,14 @@ flk_set_state(lock_descriptor_t *lock, int new_state)
{
/*
* Locks in the sleeping list may be woken up in a number of ways,
- * and more than once. If a sleeping lock is signalled awake more
+ * and more than once. If a sleeping lock is signaled awake more
* than once, then it may or may not change state depending on its
* current state.
* Also note that NLM locks that are sleeping could be moved to an
* interrupted state more than once if the unlock request is
* retransmitted by the NLM client - the second time around, this is
* just a nop.
- * The ordering of being signalled awake is:
+ * The ordering of being signaled awake is:
* INTERRUPTED_STATE > CANCELLED_STATE > GRANTED_STATE.
* The checks below implement this ordering.
*/
@@ -2671,7 +2670,7 @@ convoff(vp, lckdat, whence, offset)
if ((lckdat->l_whence == 2) || (whence == 2)) {
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
return (error);
}
@@ -3271,7 +3270,7 @@ flk_set_lockmgr_status(flk_lockmgr_status_t status)
*
* A list containing the vnode pointer and an flock structure
* describing the lock is returned. Each element in the list is
- * dynammically allocated and must be freed by the caller. The
+ * dynamically allocated and must be freed by the caller. The
* last item in the list is denoted by a NULL value in the ll_next
* field.
*
@@ -3721,7 +3720,7 @@ wait_for_lock(lock_descriptor_t *request)
* Create an flock structure from the existing lock information
*
* This routine is used to create flock structures for the lock manager
- * to use in a reclaim request. Since the lock was orginated on this
+ * to use in a reclaim request. Since the lock was originated on this
* host, it must be conforming to UNIX semantics, so no checking is
* done to make sure it falls within the lower half of the 32-bit range.
*/
@@ -3768,7 +3767,7 @@ flk_convert_lock_data(vnode_t *vp, flock64_t *flp,
break;
case 2: /* SEEK_END */
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
return (error);
*start = (u_offset_t)(flp->l_start + vattr.va_size);
break;
@@ -3914,11 +3913,21 @@ cl_flk_change_nlm_state_to_unknown(int nlmid)
int
nbl_lock_conflict(vnode_t *vp, nbl_op_t op, u_offset_t offset,
- ssize_t length, int svmand)
+ ssize_t length, int svmand, caller_context_t *ct)
{
int conflict = 0;
graph_t *gp;
lock_descriptor_t *lock;
+ pid_t pid;
+ int sysid;
+
+ if (ct == NULL) {
+ pid = curproc->p_pid;
+ sysid = 0;
+ } else {
+ pid = ct->cc_pid;
+ sysid = ct->cc_sysid;
+ }
mutex_enter(&flock_lock);
gp = lock_graph[HASH_INDEX(vp)];
@@ -3931,8 +3940,8 @@ nbl_lock_conflict(vnode_t *vp, nbl_op_t op, u_offset_t offset,
for (; lock && lock->l_vnode == vp; lock = lock->l_next) {
if ((svmand || (lock->l_state & NBMAND_LOCK)) &&
- lock->l_flock.l_sysid == 0 &&
- lock->l_flock.l_pid != curproc->p_pid &&
+ (lock->l_flock.l_sysid != sysid ||
+ lock->l_flock.l_pid != pid) &&
lock_blocks_io(op, offset, length,
lock->l_type, lock->l_start, lock->l_end)) {
conflict = 1;
diff --git a/usr/src/uts/common/os/grow.c b/usr/src/uts/common/os/grow.c
index e463b97004..0033b11ff4 100644
--- a/usr/src/uts/common/os/grow.c
+++ b/usr/src/uts/common/os/grow.c
@@ -51,6 +51,7 @@
#include <sys/vmparam.h>
#include <sys/fcntl.h>
#include <sys/lwpchan_impl.h>
+#include <sys/nbmlock.h>
#include <vm/hat.h>
#include <vm/as.h>
@@ -560,6 +561,7 @@ smmap_common(caddr_t *addrp, size_t len,
struct as *as = curproc->p_as;
uint_t uprot, maxprot, type;
int error;
+ int in_crit = 0;
if ((flags & ~(MAP_SHARED | MAP_PRIVATE | MAP_FIXED | _MAP_NEW |
_MAP_LOW32 | MAP_NORESERVE | MAP_ANON | MAP_ALIGN |
@@ -694,12 +696,36 @@ smmap_common(caddr_t *addrp, size_t len,
}
}
+ if ((prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) &&
+ nbl_need_check(vp)) {
+ int svmand;
+ nbl_op_t nop;
+
+ nbl_start_crit(vp, RW_READER);
+ in_crit = 1;
+ error = nbl_svmand(vp, fp->f_cred, &svmand);
+ if (error != 0)
+ goto done;
+ if ((prot & PROT_WRITE) && (type == MAP_SHARED)) {
+ if (prot & (PROT_READ | PROT_EXEC)) {
+ nop = NBL_READWRITE;
+ } else {
+ nop = NBL_WRITE;
+ }
+ } else {
+ nop = NBL_READ;
+ }
+ if (nbl_conflict(vp, nop, 0, LONG_MAX, svmand, NULL)) {
+ error = EACCES;
+ goto done;
+ }
+ }
/*
* Ok, now let the vnode map routine do its thing to set things up.
*/
error = VOP_MAP(vp, pos, as,
- addrp, len, uprot, maxprot, flags, fp->f_cred);
+ addrp, len, uprot, maxprot, flags, fp->f_cred, NULL);
if (error == 0) {
if (vp->v_type == VREG &&
@@ -713,6 +739,9 @@ smmap_common(caddr_t *addrp, size_t len,
}
}
+done:
+ if (in_crit)
+ nbl_end_crit(vp);
return (error);
}
diff --git a/usr/src/uts/common/os/inst_sync.c b/usr/src/uts/common/os/inst_sync.c
index 1100f1d729..a30f83bee6 100644
--- a/usr/src/uts/common/os/inst_sync.c
+++ b/usr/src/uts/common/os/inst_sync.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -221,7 +220,7 @@ in_fclose(File *fp)
{
int error;
- error = VOP_CLOSE(fp->vp, FCREAT, 1, (offset_t)0, CRED());
+ error = VOP_CLOSE(fp->vp, FCREAT, 1, (offset_t)0, CRED(), NULL);
VN_RELE(fp->vp);
kmem_free(fp, sizeof (File));
return (error);
@@ -235,7 +234,7 @@ in_fflush(File *fp)
if (fp->count)
error = in_write(fp->vp, &fp->voffset, fp->buf, fp->count);
if (error == 0)
- error = VOP_FSYNC(fp->vp, FSYNC, CRED());
+ error = VOP_FSYNC(fp->vp, FSYNC, CRED(), NULL);
return (error);
}
diff --git a/usr/src/uts/common/os/mem_config.c b/usr/src/uts/common/os/mem_config.c
index 64bbc4b5ad..49f7709c41 100644
--- a/usr/src/uts/common/os/mem_config.c
+++ b/usr/src/uts/common/os/mem_config.c
@@ -296,7 +296,7 @@ kphysm_add_memory_dynamic(pfn_t base, pgcnt_t npgs)
mem_node_add_slice(base, pnum);
/*
- * Allocate or resize page counters as necessary to accomodate
+ * Allocate or resize page counters as necessary to accommodate
* the increase in memory pages.
*/
mnode = PFN_2_MEM_NODE(pnum);
@@ -508,7 +508,7 @@ kphysm_addmem_error_undospan(pfn_t pt_base, pgcnt_t tpgs)
* Only return an available memseg of exactly the right size.
* When the meta data area has it's own virtual address space
* we will need to manage this more carefully and do best fit
- * allocations, possibly splitting an availble area.
+ * allocations, possibly splitting an available area.
*/
static struct memseg *
memseg_reuse(pgcnt_t metapgs)
@@ -2013,7 +2013,7 @@ delete_memory_thread(caddr_t amhp)
VN_HOLD(vp);
page_unlock(pp);
(void) VOP_PUTPAGE(vp, offset, PAGESIZE,
- B_INVAL|B_FORCE, kcred);
+ B_INVAL|B_FORCE, kcred, NULL);
VN_RELE(vp);
#ifdef MEM_DEL_STATS
ntick_pgrp = (uint64_t)ddi_get_lbolt() -
diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c
index ac38b40775..b4b0751d23 100644
--- a/usr/src/uts/common/os/modctl.c
+++ b/usr/src/uts/common/os/modctl.c
@@ -3129,7 +3129,7 @@ static char load_msg[] = "load '%s' id %d loaded @ 0x%p/0x%p size %d/%d\n";
/*
* Common code for loading a module (but not installing it).
- * Handoff the task of module loading to a seperate thread
+ * Handoff the task of module loading to a separate thread
* with a large stack if possible, since this code may recurse a few times.
* Return zero if there are no errors or an errno value.
*/
@@ -3513,7 +3513,7 @@ moduninstall(struct modctl *mp)
/*
* Even though we only set mod_installed to zero here, a zero
- * return value means we are commited to a code path were
+ * return value means we are committed to a code path were
* mod_loaded will also end up as zero - we have no other
* way to get the module data and bss back to the pre _init
* state except a reload. To ensure this, after return,
diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c
index e2d466227d..bc6ed66429 100644
--- a/usr/src/uts/common/os/policy.c
+++ b/usr/src/uts/common/os/policy.c
@@ -71,7 +71,7 @@ int priv_debug = 0;
* by privilege, there is quite a bit of duplication of
* functions.
*
- * The secpolicy functions must not make asssumptions about
+ * The secpolicy functions must not make assumptions about
* locks held or not held as any lock can be held while they're
* being called.
*
@@ -485,16 +485,40 @@ secpolicy_setpriority(const cred_t *cr)
int
secpolicy_net_privaddr(const cred_t *cr, in_port_t port)
{
- /*
- * NFS ports, these are extra privileged ports, allow bind
- * only if the SYS_NFS privilege is present.
- */
- if (port == 2049 || port == 4045)
- return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EACCES,
- "NFS port"));
- else
- return (PRIV_POLICY(cr, PRIV_NET_PRIVADDR, B_FALSE, EACCES,
- NULL));
+ char *reason;
+ int priv;
+
+ switch (port) {
+ case 137:
+ case 138:
+ case 139:
+ case 445:
+ /*
+ * NBT and SMB ports, these are extra privileged ports,
+ * allow bind only if the SYS_SMB privilege is present.
+ */
+ priv = PRIV_SYS_SMB;
+ reason = "NBT or SMB port";
+ break;
+
+ case 2049:
+ case 4045:
+ /*
+ * NFS ports, these are extra privileged ports, allow bind
+ * only if the SYS_NFS privilege is present.
+ */
+ priv = PRIV_SYS_NFS;
+ reason = "NFS port";
+ break;
+
+ default:
+ priv = PRIV_NET_PRIVADDR;
+ reason = NULL;
+ break;
+
+ }
+
+ return (PRIV_POLICY(cr, priv, B_FALSE, EACCES, reason));
}
/*
@@ -583,7 +607,7 @@ secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp,
int err;
va.va_mask = AT_UID|AT_MODE;
- err = VOP_GETATTR(mvp, &va, 0, cr);
+ err = VOP_GETATTR(mvp, &va, 0, cr, NULL);
if (err != 0)
return (err);
@@ -965,6 +989,70 @@ secpolicy_setid_setsticky_clear(vnode_t *vp, vattr_t *vap, const vattr_t *ovap,
return (0);
}
+#define ATTR_FLAG_PRIV(attr, value, cr) \
+ PRIV_POLICY(cr, value ? PRIV_FILE_FLAG_SET : PRIV_ALL, \
+ B_FALSE, EPERM, NULL)
+
+/*
+ * Check privileges for setting xvattr attributes
+ */
+int
+secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype)
+{
+ xoptattr_t *xoap;
+ int error = 0;
+
+ if ((xoap = xva_getxoptattr(xvap)) == NULL)
+ return (EINVAL);
+
+ /*
+ * First process the DOS bits
+ */
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE) ||
+ XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
+ XVA_ISSET_REQ(xvap, XAT_READONLY) ||
+ XVA_ISSET_REQ(xvap, XAT_SYSTEM) ||
+ XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+ if ((error = secpolicy_vnode_owner(cr, owner)) != 0)
+ return (error);
+ }
+
+ /*
+ * Now handle special attributes
+ */
+
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
+ error = ATTR_FLAG_PRIV(XAT_IMMUTABLE,
+ xoap->xoa_immutable, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
+ error = ATTR_FLAG_PRIV(XAT_NOUNLINK,
+ xoap->xoa_nounlink, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
+ error = ATTR_FLAG_PRIV(XAT_APPENDONLY,
+ xoap->xoa_appendonly, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NODUMP))
+ error = ATTR_FLAG_PRIV(XAT_NODUMP,
+ xoap->xoa_nodump, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_OPAQUE))
+ error = EPERM;
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+ error = ATTR_FLAG_PRIV(XAT_AV_QUARANTINED,
+ xoap->xoa_av_quarantined, cr);
+ if (error == 0 && vtype != VREG)
+ error = EINVAL;
+ }
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
+ error = ATTR_FLAG_PRIV(XAT_AV_MODIFIED,
+ xoap->xoa_av_modified, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
+ error = ATTR_FLAG_PRIV(XAT_AV_SCANSTAMP,
+ xoap->xoa_av_scanstamp, cr);
+ if (error == 0 && vtype != VREG)
+ error = EINVAL;
+ }
+ return (error);
+}
+
/*
* This function checks the policy decisions surrounding the
* vop setattr call.
@@ -1004,15 +1092,24 @@ secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
{
int mask = vap->va_mask;
int error = 0;
+ boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
if (mask & AT_SIZE) {
if (vp->v_type == VDIR) {
error = EISDIR;
goto out;
}
- error = unlocked_access(node, VWRITE, cr);
- if (error)
- goto out;
+
+ /*
+ * If ATTR_NOACLCHECK is set in the flags, then we don't
+ * perform the secondary unlocked_access() call since the
+ * ACL (if any) is being checked there.
+ */
+ if (skipaclchk == B_FALSE) {
+ error = unlocked_access(node, VWRITE, cr);
+ if (error)
+ goto out;
+ }
}
if (mask & AT_MODE) {
/*
@@ -1092,7 +1189,7 @@ secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
if (cr->cr_uid != ovap->va_uid) {
if (flags & ATTR_UTIME)
error = secpolicy_vnode_utime_modify(cr);
- else {
+ else if (skipaclchk == B_FALSE) {
error = unlocked_access(node, VWRITE, cr);
if (error == EACCES &&
secpolicy_vnode_utime_modify(cr) == 0)
@@ -1102,6 +1199,13 @@ secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
goto out;
}
}
+
+ /*
+ * Check for optional attributes here by checking the following:
+ */
+ if (mask & AT_XVATTR)
+ error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr,
+ vp->v_type);
out:
return (error);
}
@@ -1957,3 +2061,20 @@ secpolicy_sadopen(const cred_t *credp)
return (secpolicy_require_set(credp, &pset, "devpolicy"));
}
+
+/*
+ * secpolicy_smb
+ *
+ * Determine if the cred_t has PRIV_SYS_SMB privilege, indicating
+ * that it has permission to access the smbsrv kernel driver.
+ * PRIV_POLICY checks the privilege and audits the check.
+ *
+ * Returns:
+ * 0 Driver access is allowed.
+ * EPERM Driver access is NOT permitted.
+ */
+int
+secpolicy_smb(const cred_t *cr)
+{
+ return (PRIV_POLICY(cr, PRIV_SYS_SMB, B_FALSE, EPERM, NULL));
+}
diff --git a/usr/src/uts/common/os/priv_defs b/usr/src/uts/common/os/priv_defs
index a39896e73a..b654450428 100644
--- a/usr/src/uts/common/os/priv_defs
+++ b/usr/src/uts/common/os/priv_defs
@@ -149,6 +149,11 @@ privilege PRIV_FILE_UPGRADE_SL
This privilege is interpreted only if the system is configured
with Trusted Extensions.
+privilege PRIV_FILE_FLAG_SET
+
+ Allows a process to set immutable, nounlink or appendonly
+ file attributes.
+
privilege PRIV_GRAPHICS_ACCESS
Allows a process to make privileged ioctls to graphics devices.
@@ -402,6 +407,13 @@ unsafe privilege PRIV_SYS_RESOURCE
Allows a process to extend or create files on a filesystem that
has less than minfree space in reserve.
+privilege PRIV_SYS_SMB
+
+ Allows a process to access the Sun private SMB kernel module.
+ Allows a process to bind to ports reserved by NetBIOS and SMB:
+ ports 137 (NBNS), 138 (NetBIOS Datagram Service), 139 (NetBIOS
+ Session Service and SMB-over-NBT) and 445 (SMB-over-TCP).
+
privilege PRIV_SYS_SUSER_COMPAT
Allows a process to successfully call a third party loadable module
diff --git a/usr/src/uts/common/os/session.c b/usr/src/uts/common/os/session.c
index 7790a09094..ea93f9f6b3 100644
--- a/usr/src/uts/common/os/session.c
+++ b/usr/src/uts/common/os/session.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -166,7 +166,7 @@ tty_hold(void)
/*
* Now we need to drop our hold on the session structure,
* but we can't hold any locks when we do this because
- * sess_rele() may need to aquire pidlock.
+ * sess_rele() may need to acquire pidlock.
*/
mutex_exit(&sp->s_lock);
sess_rele(sp, B_FALSE);
@@ -306,9 +306,9 @@ strctty(stdata_t *stp)
* We are going to try to make stp the default ctty for the session
* associated with curproc. Not only does this require holding a
* bunch of locks but it also requires waiting for any outstanding
- * holds on the session structure (aquired via tty_hold()) to be
+ * holds on the session structure (acquired via tty_hold()) to be
* released. Hence, we have the following for(;;) loop that will
- * aquire our locks, do some sanity checks, and wait for the hold
+ * acquire our locks, do some sanity checks, and wait for the hold
* count on the session structure to hit zero. If we get a signal
* while waiting for outstanding holds to be released then we abort
* the operation and return.
@@ -370,12 +370,12 @@ strctty(stdata_t *stp)
}
/*
- * freectty_lock() attempts to aquire the army of locks required to free
+ * freectty_lock() attempts to acquire the army of locks required to free
* the ctty associated with a given session leader process. If it returns
* successfully the following locks will be held:
* sd_lock, pidlock, p_splock, s_lock
*
- * as a secondary bit of convience, freectty_lock() will also return
+ * as a secondary bit of convenience, freectty_lock() will also return
* pointers to the session, ctty, and ctty stream associated with the
* specified session leader process.
*/
@@ -543,10 +543,10 @@ freectty(boolean_t at_exit)
/*
* If the current process is a session leader we are going to
* try to release the ctty associated our current session. To
- * do this we need to aquire a bunch of locks, signal any
+ * do this we need to acquire a bunch of locks, signal any
* processes in the forground that are associated with the ctty,
* and make sure no one has any outstanding holds on the current
- * session * structure (aquired via tty_hold()). Hence, we have
+ * session * structure (acquired via tty_hold()). Hence, we have
* the following for(;;) loop that will do all this work for
* us and break out when the hold count on the session structure
* hits zero.
@@ -556,7 +556,7 @@ freectty(boolean_t at_exit)
return (EIO);
if (freectty_signal(p, sp, stp, at_exit)) {
- /* loop around to re-aquire locks */
+ /* loop around to re-acquire locks */
continue;
}
@@ -643,7 +643,7 @@ freectty(boolean_t at_exit)
mutex_exit(&stp->sd_lock);
/* This is the only remaining thread with access to this vnode */
- (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred);
+ (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred, NULL);
VN_RELE(vp);
crfree(cred);
diff --git a/usr/src/uts/common/os/share.c b/usr/src/uts/common/os/share.c
index 9714e4b01f..5d3bbb1418 100644
--- a/usr/src/uts/common/os/share.c
+++ b/usr/src/uts/common/os/share.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1996-1998,2001,2003 Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -74,11 +72,11 @@ add_share(struct vnode *vp, struct shrlock *shr)
* Sanity check to make sure we have valid options.
* There is known overlap but it doesn't hurt to be careful.
*/
- if (shr->s_access & ~(F_RDACC|F_WRACC|F_RWACC)) {
+ if (shr->s_access & ~(F_RDACC|F_WRACC|F_RWACC|F_RMACC|F_MDACC)) {
return (EINVAL);
}
if (shr->s_deny & ~(F_NODNY|F_RDDNY|F_WRDNY|F_RWDNY|F_COMPAT|
- F_MANDDNY)) {
+ F_MANDDNY|F_RMDNY)) {
return (EINVAL);
}
@@ -115,7 +113,7 @@ add_share(struct vnode *vp, struct shrlock *shr)
if ((shrl->shr->s_deny & F_COMPAT) &&
(shr->s_deny & F_COMPAT) &&
((shrl->next == NULL) ||
- (shrl->shr->s_access & F_WRACC)))
+ (shrl->shr->s_access & F_WRACC)))
break;
}
@@ -280,13 +278,13 @@ is_match_for_del(struct shrlock *shr, struct shrlock *element)
* and pids.
*/
result = (nlmid1 == nlmid2 &&
- shr->s_pid == element->s_pid);
+ shr->s_pid == element->s_pid);
}
} else { /* not in a cluster */
result = ((shr->s_sysid == 0 &&
- shr->s_pid == element->s_pid) ||
- (shr->s_sysid != 0 &&
- shr->s_sysid == element->s_sysid));
+ shr->s_pid == element->s_pid) ||
+ (shr->s_sysid != 0 &&
+ shr->s_sysid == element->s_sysid));
}
return (result);
}
@@ -315,11 +313,11 @@ del_share(struct vnode *vp, struct shrlock *shr)
shrlp = &vp->v_shrlocks;
while (*shrlp) {
if ((shr->s_own_len == (*shrlp)->shr->s_own_len &&
- (bcmp(shr->s_owner, (*shrlp)->shr->s_owner,
- shr->s_own_len) == 0)) ||
+ (bcmp(shr->s_owner, (*shrlp)->shr->s_owner,
+ shr->s_own_len) == 0)) ||
- (shr->s_own_len == 0 &&
- is_match_for_del(shr, (*shrlp)->shr))) {
+ (shr->s_own_len == 0 &&
+ is_match_for_del(shr, (*shrlp)->shr))) {
shrl = *shrlp;
*shrlp = shrl->next;
@@ -427,7 +425,7 @@ static int
isreadonly(struct vnode *vp)
{
return (vp->v_type != VCHR && vp->v_type != VBLK &&
- vp->v_type != VFIFO && vn_is_readonly(vp));
+ vp->v_type != VFIFO && vn_is_readonly(vp));
}
#ifdef DEBUG
@@ -489,46 +487,117 @@ print_share(struct shrlock *shr)
/*
* Return non-zero if the given I/O request conflicts with a registered
* share reservation.
+ *
+ * A process is identified by the tuple (sysid, pid). When the caller
+ * context is passed to nbl_share_conflict, the sysid and pid in the
+ * caller context are used. Otherwise the sysid is zero, and the pid is
+ * taken from the current process.
+ *
+ * Conflict Algorithm:
+ * 1. An op request of NBL_READ will fail if a different
+ * process has a mandatory share reservation with deny read.
+ *
+ * 2. An op request of NBL_WRITE will fail if a different
+ * process has a mandatory share reservation with deny write.
+ *
+ * 3. An op request of NBL_READWRITE will fail if a different
+ * process has a mandatory share reservation with deny read
+ * or deny write.
+ *
+ * 4. An op request of NBL_REMOVE will fail if there is
+ * a mandatory share reservation with an access of read,
+ * write, or remove. (Anything other than meta data access).
+ *
+ * 5. An op request of NBL_RENAME will fail if there is
+ * a mandatory share reservation with:
+ * a) access write or access remove
+ * or
+ * b) access read and deny remove
+ *
+ * Otherwise there is no conflict and the op request succeeds.
+ *
+ * This behavior is required for interoperability between
+ * the nfs server, cifs server, and local access.
+ * This behavior can result in non-posix semantics.
+ *
+ * When mandatory share reservations are enabled, a process
+ * should call nbl_share_conflict to determine if the
+ * desired operation would conflict with an existing share
+ * reservation.
+ *
+ * The call to nbl_share_conflict may be skipped if the
+ * process has an existing share reservation and the operation
+ * is being performed in the context of that existing share
+ * reservation.
*/
-
int
-nbl_share_conflict(vnode_t *vp, nbl_op_t op)
+nbl_share_conflict(vnode_t *vp, nbl_op_t op, caller_context_t *ct)
{
struct shrlocklist *shrl;
int conflict = 0;
+ pid_t pid;
+ int sysid;
ASSERT(nbl_in_crit(vp));
+ if (ct == NULL) {
+ pid = curproc->p_pid;
+ sysid = 0;
+ } else {
+ pid = ct->cc_pid;
+ sysid = ct->cc_sysid;
+ }
+
mutex_enter(&vp->v_lock);
for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
- if (shrl->shr->s_sysid == 0 &&
- (shrl->shr->s_deny & F_MANDDNY) &&
- shrl->shr->s_pid != curproc->p_pid) {
- switch (op) {
- case NBL_READ:
- if (shrl->shr->s_deny & F_RDDNY)
- conflict = 1;
- break;
- case NBL_WRITE:
- if (shrl->shr->s_deny & F_WRDNY)
- conflict = 1;
- break;
- case NBL_READWRITE:
- if (shrl->shr->s_deny & F_RWDNY)
- conflict = 1;
- break;
- case NBL_RENAME:
- case NBL_REMOVE:
+ if (!(shrl->shr->s_deny & F_MANDDNY))
+ continue;
+ /*
+ * NBL_READ, NBL_WRITE, and NBL_READWRITE need to
+ * check if the share reservation being examined
+ * belongs to the current process.
+ * NBL_REMOVE and NBL_RENAME do not.
+ * This behavior is required by the conflict
+ * algorithm described above.
+ */
+ switch (op) {
+ case NBL_READ:
+ if ((shrl->shr->s_deny & F_RDDNY) &&
+ (shrl->shr->s_sysid != sysid ||
+ shrl->shr->s_pid != pid))
conflict = 1;
- break;
+ break;
+ case NBL_WRITE:
+ if ((shrl->shr->s_deny & F_WRDNY) &&
+ (shrl->shr->s_sysid != sysid ||
+ shrl->shr->s_pid != pid))
+ conflict = 1;
+ break;
+ case NBL_READWRITE:
+ if ((shrl->shr->s_deny & F_RWDNY) &&
+ (shrl->shr->s_sysid != sysid ||
+ shrl->shr->s_pid != pid))
+ conflict = 1;
+ break;
+ case NBL_REMOVE:
+ if (shrl->shr->s_access & (F_RWACC|F_RMACC))
+ conflict = 1;
+ break;
+ case NBL_RENAME:
+ if (shrl->shr->s_access & (F_WRACC|F_RMACC))
+ conflict = 1;
+
+ else if ((shrl->shr->s_access & F_RDACC) &&
+ (shrl->shr->s_deny & F_RMDNY))
+ conflict = 1;
+ break;
#ifdef DEBUG
- default:
- cmn_err(CE_PANIC,
- "nbl_share_conflict: bogus op (%d)",
- op);
- break;
+ default:
+ cmn_err(CE_PANIC,
+ "nbl_share_conflict: bogus op (%d)",
+ op);
+ break;
#endif
- }
}
if (conflict)
break;
@@ -546,10 +615,16 @@ nbl_share_conflict(vnode_t *vp, nbl_op_t op)
int
share_blocks_lock(vnode_t *vp, flock64_t *flkp)
{
+ caller_context_t ct;
+
ASSERT(nbl_in_crit(vp));
+ ct.cc_pid = flkp->l_pid;
+ ct.cc_sysid = flkp->l_sysid;
+ ct.cc_caller_id = 0;
+
if ((flkp->l_type == F_RDLCK || flkp->l_type == F_WRLCK) &&
- nbl_share_conflict(vp, nbl_lock_to_op(flkp->l_type)))
+ nbl_share_conflict(vp, nbl_lock_to_op(flkp->l_type), &ct))
return (1);
else
return (0);
@@ -602,35 +677,34 @@ lock_blocks_share(vnode_t *vp, struct shrlock *shr)
{
struct flock64 lck;
int error;
-
- /*
- * We don't currently have a good way to match lock
- * ownership with share ownership for remote requests.
- * Fortunately, we know that only local processes (in particular,
- * local CIFS servers) care about conflicts between locks and
- * share reservations, and we can distinguish local processes from
- * each other and from remote processes.
- */
- ASSERT(shr->s_sysid == 0);
+ v_mode_t mode = 0;
if ((shr->s_deny & (F_RWDNY|F_COMPAT)) == 0) {
/* if no deny mode, then there's no conflict */
return (0);
}
- lck.l_type = ((shr->s_deny & F_RDDNY) ? F_WRLCK : F_RDLCK);
+ /* check for conflict with mapped region */
+ if ((shr->s_deny & F_RWDNY) == F_WRDNY) {
+ mode = V_WRITE;
+ } else if ((shr->s_deny & F_RWDNY) == F_RDDNY) {
+ mode = V_READ;
+ } else {
+ mode = V_RDORWR;
+ }
+ if (vn_is_mapped(vp, mode))
+ return (1);
+ lck.l_type = ((shr->s_deny & F_RDDNY) ? F_WRLCK : F_RDLCK);
lck.l_whence = 0;
lck.l_start = 0;
lck.l_len = 0; /* to EOF */
- /* would check here for conflict with mapped region */
-
/* XXX should use non-NULL cred? */
- error = VOP_FRLOCK(vp, F_GETLK, &lck, 0, 0, NULL, NULL);
+ error = VOP_FRLOCK(vp, F_GETLK, &lck, 0, 0, NULL, NULL, NULL);
if (error != 0) {
cmn_err(CE_WARN, "lock_blocks_share: unexpected error (%d)",
- error);
+ error);
return (1);
}
diff --git a/usr/src/uts/common/os/sid.c b/usr/src/uts/common/os/sid.c
index 0da71f3cdf..2ed5ad2989 100644
--- a/usr/src/uts/common/os/sid.c
+++ b/usr/src/uts/common/os/sid.c
@@ -41,8 +41,6 @@
#include <sys/kidmap.h>
#include <sys/idmap.h>
-#define KSIDLIST_MEM(n) (sizeof (ksidlist_t) + ((n) - 1) * sizeof (ksid_t))
-
static kmutex_t sid_lock;
static avl_tree_t sid_tree;
static boolean_t sid_inited = B_FALSE;
diff --git a/usr/src/uts/common/os/tlabel.c b/usr/src/uts/common/os/tlabel.c
index 30569bb963..3a46745483 100644
--- a/usr/src/uts/common/os/tlabel.c
+++ b/usr/src/uts/common/os/tlabel.c
@@ -287,7 +287,7 @@ getflabel(vnode_t *vp)
/*
* Traverse lofs mounts and fattach'es to get the real vnode
*/
- if (VOP_REALVP(rvp, &rvp2) == 0)
+ if (VOP_REALVP(rvp, &rvp2, NULL) == 0)
rvp = rvp2;
rvfsp = rvp->v_vfsp;
diff --git a/usr/src/uts/common/os/urw.c b/usr/src/uts/common/os/urw.c
index a0195a6db3..ef70ccac45 100644
--- a/usr/src/uts/common/os/urw.c
+++ b/usr/src/uts/common/os/urw.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -75,7 +74,7 @@ page_valid(struct seg *seg, caddr_t addr)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, addr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
u_offset_t size = roundup(vattr.va_size, (u_offset_t)PAGESIZE);
u_offset_t offset = SEGOP_GETOFFSET(seg, addr);
@@ -177,7 +176,7 @@ mapout(struct as *as, caddr_t addr, caddr_t vaddr, int writing)
}
/*
- * Perform I/O to a given process. This will return EIO if we dectect
+ * Perform I/O to a given process. This will return EIO if we detect
* corrupt memory and ENXIO if there is no such mapped address in the
* user process's address space.
*/
diff --git a/usr/src/uts/common/os/vm_pageout.c b/usr/src/uts/common/os/vm_pageout.c
index e5c80e9bfd..afbca60785 100644
--- a/usr/src/uts/common/os/vm_pageout.c
+++ b/usr/src/uts/common/os/vm_pageout.c
@@ -634,7 +634,7 @@ int dopageout = 1; /* must be non-zero to turn page stealing on */
* Some filesystems may require resources for the VOP_PUTPAGE
* operations (like memory) and hence can block the pageout
* thread, but the scanner thread can still operate. There is still
- * no gaurentee that memory deadlocks cannot occur.
+ * no guarantee that memory deadlocks cannot occur.
*
* For now, this thing is in very rough form.
*/
@@ -709,7 +709,7 @@ pageout()
if (VOP_PUTPAGE(arg->a_vp, (offset_t)arg->a_off,
arg->a_len, arg->a_flags,
- arg->a_cred) == 0) {
+ arg->a_cred, NULL) == 0) {
pushes++;
}
diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c
index c89945e756..ff2812b781 100644
--- a/usr/src/uts/common/os/zone.c
+++ b/usr/src/uts/common/os/zone.c
@@ -2417,7 +2417,8 @@ zone_set_root(zone_t *zone, const char *upath)
* filesystem, if 'vp' is an autoFS vnode.
* Get the new 'vp' if so.
*/
- if ((error = VOP_ACCESS(vp, VEXEC, 0, CRED())) == 0 &&
+ if ((error =
+ VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL)) == 0 &&
(!vn_ismntpt(vp) ||
(error = traverse(&vp)) == 0)) {
pathlen = pn.pn_pathlen + 2;
@@ -4381,7 +4382,7 @@ done:
*
* Also return zero if the process has any shared mappings which reserve
* swap. This is because the counting for zone.max-swap does not allow swap
- * revervation to be shared between zones. zone swap reservation is counted
+ * reservation to be shared between zones. zone swap reservation is counted
* on zone->zone_max_swap.
*/
static int
@@ -5645,7 +5646,7 @@ zone_check_datalink(zoneid_t *zoneidp, char *dlname)
/*
* Get the names of the datalinks assigned to a zone.
* Here *nump is the number of datalinks, and the assumption
- * is that the caller will gurantee that the the supplied buffer is
+ * is that the caller will guarantee that the the supplied buffer is
* big enough to hold at least #*nump datalink names, that is,
* LIFNAMSIZ X *nump
* On return, *nump will be the "new" number of datalinks, if it
diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile
new file mode 100644
index 0000000000..233f5d2141
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/Makefile
@@ -0,0 +1,131 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+include ../../../Makefile.master
+
+HDRS= alloc.h \
+ cifs.h \
+ codepage.h \
+ cp_cyrillic.h \
+ cp_latin1.h \
+ cp_latin2.h \
+ cp_latin3.h \
+ cp_latin4.h \
+ cp_latin5.h \
+ cp_latin6.h \
+ cp_unicode.h \
+ cp_usascii.h \
+ crypt.h \
+ ctype.h \
+ doserror.h \
+ hash_table.h \
+ lm.h \
+ lmdfs.h \
+ lmerr.h \
+ lmshare.h \
+ lmshare_door.h \
+ lsalib.h \
+ mac_cifs.h \
+ mailslot.h \
+ mbuf.h \
+ mlrpc.h \
+ mlsvc.h \
+ mlsvc_util.h \
+ msgbuf.h \
+ ndr.h \
+ netbios.h \
+ netrauth.h \
+ nmpipes.h \
+ ntaccess.h \
+ nterror.h \
+ ntifs.h \
+ ntlocale.h \
+ ntsid.h \
+ ntstatus.h \
+ oem.h \
+ samlib.h \
+ smb.h \
+ smb_common_door.h \
+ smb_door_svc.h \
+ smb_fsd.h \
+ smb_fsops.h \
+ smb_i18n.h \
+ smb_idmap.h \
+ smb_incl.h \
+ smb_ioctl.h \
+ smb_kproto.h \
+ smb_privilege.h \
+ smb_secdesc.h \
+ smb_svc_sm.h \
+ smb_token.h \
+ smb_vops.h \
+ smb_winpipe.h \
+ smb_xdr.h \
+ smbfmt.h \
+ smbinfo.h \
+ smbtrans.h \
+ smbvar.h \
+ string.h \
+ svrapi.h \
+ winioctl.h \
+ winsvc.h \
+ wintypes.h
+
+NDLHDRS= dssetup.ndl \
+ eventlog.ndl \
+ llsrpc.ndl \
+ lsarpc.ndl \
+ ndrtypes.ndl \
+ netdfs.ndl \
+ netlogon.ndl \
+ rpcpdu.ndl \
+ samrpc.ndl \
+ spoolss.ndl \
+ srvsvc.ndl \
+ svcctl.ndl \
+ winreg.ndl \
+
+ROOTDIR= $(ROOT)/usr/include/smbsrv
+NDLDIR= $(ROOTDIR)/ndl
+ROOTHDRS= $(HDRS:%=$(ROOTDIR)/%) $(NDLHDRS:%=$(ROOTDIR)/ndl/%)
+CHECKHDRS= $(HDRS:%.h=%.check)
+
+$(ROOTDIR)/%: %
+ $(INS.file)
+
+$(NDLDIR)/%: ndl/%
+ $(INS.file)
+
+$(ROOTDIR) $(NDLDIR):
+ $(INS.dir)
+
+.KEEP_STATE:
+
+.PARALLEL: $(CHECKHDRS)
+
+install_h: $(ROOTDIR) $(NDLDIR) $(ROOTHDRS)
+
+check: $(CHECKHDRS)
diff --git a/usr/src/uts/common/smbsrv/alloc.h b/usr/src/uts/common/smbsrv/alloc.h
new file mode 100644
index 0000000000..8d49256863
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/alloc.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_ALLOC_H
+#define _SMBSRV_ALLOC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Memory management macros to aid in developing code that can
+ * be compiled for both user and kernel.
+ *
+ * Set the AREA parameter to a short text string that is a hint
+ * about the subsystem calling the function. example: "smbrdr"
+ *
+ * Do not mix usage of these macros with malloc/free functions.
+ * It will not work.
+ *
+ * All library code shared between user and kernel must use
+ * these functions instead of malloc/free/kmem_*.
+ *
+ * Quick Summary
+ * MEM_MALLOC - allocate memory
+ * MEM_ZALLOC - allocate and zero memory
+ * MEM_STRDUP - string copy
+ * MEM_REALLOC - reallocate memory
+ * MEM_FREE - free memory
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <string.h>
+
+#define MEM_MALLOC(AREA, SIZE) malloc(SIZE)
+#define MEM_ZALLOC(AREA, SIZE) calloc((SIZE), 1)
+#define MEM_STRDUP(AREA, PTR) strdup(PTR)
+#define MEM_REALLOC(AREA, PTR, SIZE) realloc((PTR), (SIZE))
+#define MEM_FREE(AREA, PTR) free(PTR)
+
+#else /* _KERNEL */
+
+void *mem_malloc(uint32_t size);
+void *mem_zalloc(uint32_t size);
+char *mem_strdup(const char *ptr);
+void *mem_realloc(void *ptr, uint32_t size);
+void smb_mem_free(void *ptr);
+
+#define MEM_MALLOC(AREA, SIZE) mem_malloc(SIZE)
+#define MEM_ZALLOC(AREA, SIZE) mem_zalloc(SIZE)
+#define MEM_STRDUP(AREA, PTR) mem_strdup(PTR)
+#define MEM_REALLOC(AREA, PTR, SIZE) mem_realloc((PTR), (SIZE))
+#define MEM_FREE(AREA, PTR) smb_mem_free(PTR)
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_ALLOC_H */
diff --git a/usr/src/uts/common/smbsrv/cifs.h b/usr/src/uts/common/smbsrv/cifs.h
new file mode 100644
index 0000000000..4533a21bb6
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cifs.h
@@ -0,0 +1,1161 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CIFS_H
+#define _SMBSRV_CIFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides definitions for the CIFS interface. The Macintosh
+ * Extensions for CIFS are defined in mac_cifs.h.
+ */
+
+/*
+ * Macintosh Extensions for CIFS
+ */
+#include <smbsrv/mac_cifs.h>
+
+/*
+ * NT Installable File System (IFS) interface.
+ */
+#include <smbsrv/ntifs.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/*
+ * SMB-over-TCP (NETBIOS-less SMB) TCP port
+ */
+#define SMB_SRVC_TCP_PORT 445
+
+
+/* Share types */
+#ifndef _SHARE_TYPES_DEFINED_
+#define _SHARE_TYPES_DEFINED_
+#define STYPE_DISKTREE 0x00000000
+#define STYPE_PRINTQ 0x00000001
+#define STYPE_DEVICE 0x00000002
+#define STYPE_IPC 0x00000003
+#define STYPE_MASK 0x0000000F
+#define STYPE_DFS 0x00000064
+#define STYPE_HIDDEN 0x80000000
+#define STYPE_SPECIAL 0x80000000
+#endif /* _SHARE_TYPES_DEFINED_ */
+
+#define STYPE_ISDSK(S) (((S) & STYPE_MASK) == STYPE_DISKTREE)
+#define STYPE_ISPRN(S) (((S) & STYPE_MASK) == STYPE_PRINTQ)
+#define STYPE_ISDEV(S) (((S) & STYPE_MASK) == STYPE_DEVICE)
+#define STYPE_ISIPC(S) (((S) & STYPE_MASK) == STYPE_IPC)
+
+/*
+ * NtCreateAndX and NtTransactCreate creation flags: defined in CIFS
+ * section 4.2.2
+ *
+ * Creation Flag Name Value Description
+ * ========================== ====== ==================================
+ * NT_CREATE_REQUEST_OPLOCK 0x02 Level I oplock requested
+ * NT_CREATE_REQUEST_OPBATCH 0x04 Batch oplock requested
+ * NT_CREATE_OPEN_TARGET_DIR 0x08 Target for open is a directory
+ */
+#define NT_CREATE_FLAG_REQUEST_OPLOCK 0x02
+#define NT_CREATE_FLAG_REQUEST_OPBATCH 0x04
+#define NT_CREATE_FLAG_OPEN_TARGET_DIR 0x08
+
+
+/*
+ * Define the filter flags for NtNotifyChangeDirectoryFile
+ */
+#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
+#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
+#define FILE_NOTIFY_CHANGE_NAME 0x00000003
+#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
+#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
+#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
+#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
+#define FILE_NOTIFY_CHANGE_CREATION 0x00000040
+#define FILE_NOTIFY_CHANGE_EA 0x00000080
+#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100
+#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
+#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
+#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
+#define FILE_NOTIFY_VALID_MASK 0x00000fff
+
+
+/*
+ * Define the file action type codes for NtNotifyChangeDirectoryFile
+ */
+#define FILE_ACTION_ADDED 0x00000001
+#define FILE_ACTION_REMOVED 0x00000002
+#define FILE_ACTION_MODIFIED 0x00000003
+#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
+#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005
+#define FILE_ACTION_ADDED_STREAM 0x00000006
+#define FILE_ACTION_REMOVED_STREAM 0x00000007
+#define FILE_ACTION_MODIFIED_STREAM 0x00000008
+
+
+/* Lock type flags */
+#define LOCKING_ANDX_NORMAL_LOCK 0x00
+#define LOCKING_ANDX_SHARED_LOCK 0x01
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
+#define LOCKING_ANDX_CHANGE_LOCK_TYPE 0x04
+#define LOCKING_ANDX_CANCEL_LOCK 0x08
+#define LOCKING_ANDX_LARGE_FILES 0x10
+
+#define SMB_COM_CREATE_DIRECTORY 0x00
+#define SMB_COM_DELETE_DIRECTORY 0x01
+#define SMB_COM_OPEN 0x02
+#define SMB_COM_CREATE 0x03
+#define SMB_COM_CLOSE 0x04
+#define SMB_COM_FLUSH 0x05
+#define SMB_COM_DELETE 0x06
+#define SMB_COM_RENAME 0x07
+#define SMB_COM_QUERY_INFORMATION 0x08
+#define SMB_COM_SET_INFORMATION 0x09
+#define SMB_COM_READ 0x0A
+#define SMB_COM_WRITE 0x0B
+#define SMB_COM_LOCK_BYTE_RANGE 0x0C
+#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D
+#define SMB_COM_CREATE_TEMPORARY 0x0E
+#define SMB_COM_CREATE_NEW 0x0F
+#define SMB_COM_CHECK_DIRECTORY 0x10
+#define SMB_COM_PROCESS_EXIT 0x11
+#define SMB_COM_SEEK 0x12
+#define SMB_COM_LOCK_AND_READ 0x13
+#define SMB_COM_WRITE_AND_UNLOCK 0x14
+
+#define SMB_COM_READ_RAW 0x1A
+#define SMB_COM_READ_MPX 0x1B
+#define SMB_COM_READ_MPX_SECONDARY 0x1C
+#define SMB_COM_WRITE_RAW 0x1D
+#define SMB_COM_WRITE_MPX 0x1E
+#define SMB_COM_WRITE_MPX_SECONDARY 0x1F
+#define SMB_COM_WRITE_COMPLETE 0x20
+
+#define SMB_COM_SET_INFORMATION2 0x22
+#define SMB_COM_QUERY_INFORMATION2 0x23
+#define SMB_COM_LOCKING_ANDX 0x24
+#define SMB_COM_TRANSACTION 0x25
+#define SMB_COM_TRANSACTION_SECONDARY 0x26
+#define SMB_COM_IOCTL 0x27
+#define SMB_COM_IOCTL_SECONDARY 0x28
+#define SMB_COM_COPY 0x29
+#define SMB_COM_MOVE 0x2A
+#define SMB_COM_ECHO 0x2B
+#define SMB_COM_WRITE_AND_CLOSE 0x2C
+#define SMB_COM_OPEN_ANDX 0x2D
+#define SMB_COM_READ_ANDX 0x2E
+#define SMB_COM_WRITE_ANDX 0x2F
+
+#define SMB_COM_CLOSE_AND_TREE_DISC 0x31
+#define SMB_COM_TRANSACTION2 0x32
+#define SMB_COM_TRANSACTION2_SECONDARY 0x33
+#define SMB_COM_FIND_CLOSE2 0x34
+#define SMB_COM_FIND_NOTIFY_CLOSE 0x35
+
+#define SMB_COM_TREE_CONNECT 0x70
+#define SMB_COM_TREE_DISCONNECT 0x71
+#define SMB_COM_NEGOTIATE 0x72
+#define SMB_COM_SESSION_SETUP_ANDX 0x73
+#define SMB_COM_LOGOFF_ANDX 0x74
+#define SMB_COM_TREE_CONNECT_ANDX 0x75
+
+#define SMB_COM_QUERY_INFORMATION_DISK 0x80
+#define SMB_COM_SEARCH 0x81
+#define SMB_COM_FIND 0x82
+#define SMB_COM_FIND_UNIQUE 0x83
+#define SMB_COM_FIND_CLOSE 0x84
+
+#define SMB_COM_NT_TRANSACT 0xA0
+#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
+#define SMB_COM_NT_CREATE_ANDX 0xA2
+#define SMB_COM_NT_CANCEL 0xA4
+
+#define SMB_COM_OPEN_PRINT_FILE 0xC0
+#define SMB_COM_WRITE_PRINT_FILE 0xC1
+#define SMB_COM_CLOSE_PRINT_FILE 0xC2
+#define SMB_COM_GET_PRINT_QUEUE 0xC3
+
+
+/*
+ * Flags field of the SMB header. The names in parenthesis represent
+ * alternative names for the flags.
+ *
+ * SMB_FLAGS_LOCK_AND_READ_OK If the server supports LockAndRead and
+ * (SMB_FLAGS_LOCKS_SUBDIALECT) WriteAndUnlock, it sets this bit in the
+ * Negotiate response.
+ *
+ * SMB_FLAGS_SEND_NO_ACK When on, the client guarantees that there
+ * (SMB_FLAGS_RCV_BUF_POSTED) is a receive buffer posted such that a
+ * "Send-No-Ack" can be used by the server
+ * to respond to the client's request.
+ *
+ * SMB_FLAGS_CASE_INSENSITIVE This is part of the Flags field of every
+ * SMB header. If this bit is set, then all
+ * pathnames in the SMB should be treated as
+ * case-insensitive. Otherwise pathnames are
+ * case-sensitive.
+ *
+ * SMB_FLAGS_CANONICALIZED_PATHS When on in SessionSetupX, this indicates
+ * that all paths sent to the server are
+ * already in OS/2 canonicalized format.
+ *
+ * OS/2 canonical format means that file/directory names are in upper case,
+ * are valid characters, . and .. have been removed and single backslashes
+ * are used as separators.
+ *
+ * SMB_FLAGS_OPLOCK When set in an open file request SMBs
+ * (Open, Create, OpenX, etc.) this bit
+ * indicates a request for an oplock on the
+ * file. When set in the response, this bit
+ * indicates that the oplock was granted.
+ *
+ * SMB_FLAGS_OPLOCK_NOTIFY_ANY When on, this bit indicates that the server
+ * should notify the client on any request
+ * that could cause the file to be changed.
+ * If not set, the server only notifies the
+ * client on other open requests on the file.
+ * This bit is only relevant when
+ * SMB_FLAGS_OPLOCK is set.
+ *
+ * SMB_FLAGS_SERVER_TO_REDIR This bit indicates that the SMB is being
+ * (SMB_FLAGS_REPLY) sent from server to (client) redirector.
+ */
+#define SMB_FLAGS_LOCK_AND_READ_OK 0x01
+#define SMB_FLAGS_SEND_NO_ACK 0x02
+#define SMB_FLAGS_RESERVED 0x04
+#define SMB_FLAGS_CASE_INSENSITIVE 0x08
+#define SMB_FLAGS_CANONICALIZED_PATHS 0x10
+#define SMB_FLAGS_OPLOCK 0x20
+#define SMB_FLAGS_OPLOCK_NOTIFY_ANY 0x40
+#define SMB_FLAGS_REPLY 0x80
+
+
+/*
+ * Flags2 field of the SMB header.
+ */
+#define SMB_FLAGS2_KNOWS_LONG_NAMES 0x0001
+#define SMB_FLAGS2_KNOWS_EAS 0x0002
+#define SMB_FLAGS2_SMB_SECURITY_SIGNATURE 0x0004
+#define SMB_FLAGS2_IS_LONG_NAME 0x0040
+#define SMB_FLAGS2_EXT_SEC 0x0800
+#define SMB_FLAGS2_DFS 0x1000
+#define SMB_FLAGS2_PAGING_IO 0x2000
+#define SMB_FLAGS2_NT_STATUS 0x4000
+#define SMB_FLAGS2_UNICODE 0x8000
+
+#define DIALECT_UNKNOWN 0
+#define PC_NETWORK_PROGRAM_1_0 1 /* The original MSNET SMB protocol */
+#define PCLAN1_0 2 /* Some versions of the original MSNET */
+#define MICROSOFT_NETWORKS_1_03 3 /* This is used for the MS-NET 1.03 */
+#define MICROSOFT_NETWORKS_3_0 4 /* This is the DOS LANMAN 1.0 specific */
+#define LANMAN1_0 5 /* This is the first version of the full */
+#define LM1_2X002 6 /* This is the first version of the full */
+#define DOS_LM1_2X002 7 /* This is the dos equivalent of the */
+#define DOS_LANMAN2_1 8 /* DOS LANMAN2.1 */
+#define LANMAN2_1 9 /* OS/2 LANMAN2.1 */
+#define Windows_for_Workgroups_3_1a 10 /* Windows for Workgroups Version 1.0 */
+#define NT_LM_0_12 11 /* The SMB protocol designed for NT */
+
+/* SMB_TREE_CONNECT_ANDX flags */
+#define SMB_TREE_SUPPORT_SEARCH_BITS 0x01
+#define SMB_TREE_SHARE_IS_IN_DFS 0x02
+
+#define SMB_FA_READONLY 0x01 /* Read only file */
+#define SMB_FA_HIDDEN 0x02 /* Hidden file */
+#define SMB_FA_SYSTEM 0x04 /* System file */
+#define SMB_FA_VOLUME 0x08 /* Volume */
+#define SMB_FA_DIRECTORY 0x10 /* Directory */
+#define SMB_FA_ARCHIVE 0x20 /* Archive file */
+#define SMB_FA_NORMAL 0x80 /* Normal pipe */
+#define SMB_FA_TEMPORARY 0x100 /* Is a temporary file */
+#define SMB_FA_ATOMIC_WRITE 0x200 /* Do atomic writes */
+#define SMB_FA_XACTION_WRITE 0x400 /* XACTION write */
+
+/*
+ * Mask to match the definitions in section 3.7 File Attribute Encoding.
+ * The other bits are reserved.
+ */
+#define SMB_FA_MASK 0x3F
+
+
+/*
+ * The subcommand codes, placed in SETUP[0], for named pipe operations are:
+ * SubCommand Code Value Description
+ * =================== ===== =========================================
+ */
+
+#define CallNamedPipe 0x54 /* open/write/read/close pipe */
+#define WaitNamedPipe 0x53 /* wait for pipe to be nonbusy */
+#define PeekNmPipe 0x23 /* read but don't remove data */
+#define QNmPHandState 0x21 /* query pipe handle modes */
+#define SetNmPHandState 0x01 /* set pipe handle modes */
+#define QNmPipeInfo 0x22 /* query pipe attributes */
+#define TransactNmPipe 0x26 /* write/read operation on pipe */
+#define RawReadNmPipe 0x11 /* read pipe in "raw" (non message mode) */
+#define RawWriteNmPipe 0x31 /* write pipe "raw" (non message mode) */
+
+
+
+/*
+ * Setup[0] Transaction2 Value Description
+ * Subcommand Code
+ * ========================== ===== =============================
+ */
+
+#define TRANS2_OPEN2 0x00 /* Create file, extended attributes */
+#define TRANS2_FIND_FIRST2 0x01 /* Begin search for files */
+#define TRANS2_FIND_NEXT2 0x02 /* Resume search for files */
+#define TRANS2_QUERY_FS_INFORMATION 0x03 /* Get file system information */
+#define _TRANS2_RESV_0x04 0x04 /* Reserved */
+#define TRANS2_QUERY_PATH_INFORMATION 0x05 /* Get info, named file or dir */
+#define TRANS2_SET_PATH_INFORMATION 0x06 /* Set info, named file or dir */
+#define TRANS2_QUERY_FILE_INFORMATION 0x07 /* Get info, handle */
+#define TRANS2_SET_FILE_INFORMATION 0x08 /* Set info, handle */
+#define TRANS2_FSCTL 0x09 /* Not implemented by NT server */
+#define TRANS2_IOCTL2 0x0A /* Not implemented by NT server */
+#define TRANS2_FIND_NOTIFY_FIRST 0x0B /* Not implemented by NT server */
+#define TRANS2_FIND_NOTIFY_NEXT 0x0C /* Not implemented by NT server */
+#define TRANS2_CREATE_DIRECTORY 0x0D /* Create dir, extended attributes */
+#define TRANS2_SESSION_SETUP 0x0E /* Session setup, extended security */
+#define TRANS2_GET_DFS_REFERRAL 0x10 /* Get a Dfs referral */
+#define TRANS2_REPORT_DFS_INCONSISTENCY 0x11 /* Report a Dfs inconsistency */
+
+/*
+ * Access Mode Encoding (CIFS/1.0 1996 Section 3.8).
+ *
+ * The desired access mode passed in SmbOpen and SmbOpenAndX has the following
+ * mapping:
+ *
+ * 1111 11
+ * 5432 1098 7654 3210
+ * rWrC rLLL rSSS rAAA
+ *
+ * where:
+ *
+ * W - Write through mode. No read ahead or write behind allowed on
+ * this file or device. When protocol is returned, data is expected
+ * to be on the disk or device.
+ *
+ * S - Sharing mode:
+ * 0 - Compatibility mode (as in core open)
+ * 1 - Deny read/write/execute (exclusive)
+ * 2 - Deny write
+ * 3 - Deny read/execute
+ * 4 - Deny none
+ *
+ * A - Access mode
+ * 0 - Open for reading
+ * 1 - Open for writing
+ * 2 - Open for reading and writing
+ * 3 - Open for execute
+ *
+ * rSSSrAAA = 11111111 (hex FF) indicates FCB open (as in core protocol)
+ *
+ * C - Cache mode
+ * 0 - Normal file
+ * 1 - Do not cache this file
+ *
+ * L - Locality of reference
+ * 0 - Locality of reference is unknown
+ * 1 - Mainly sequential access
+ * 2 - Mainly random access
+ * 3 - Random access with some locality
+ * 4 to 7 - Currently undefined
+ */
+
+
+#define SMB_DA_SHARE_MASK 0x70
+#define SMB_DA_ACCESS_MASK 0x07
+#define SMB_DA_FCB_MASK (UCHAR)0xFF
+
+#define SMB_DA_ACCESS_READ 0x00
+#define SMB_DA_ACCESS_WRITE 0x01
+#define SMB_DA_ACCESS_READ_WRITE 0x02
+#define SMB_DA_ACCESS_EXECUTE 0x03
+
+#define SMB_DA_SHARE_COMPATIBILITY 0x00
+#define SMB_DA_SHARE_EXCLUSIVE 0x10
+#define SMB_DA_SHARE_DENY_WRITE 0x20
+#define SMB_DA_SHARE_DENY_READ 0x30
+#define SMB_DA_SHARE_DENY_NONE 0x40
+
+#define SMB_DA_FCB (UCHAR)0xFF
+
+#define SMB_CACHE_NORMAL 0x0000
+#define SMB_DO_NOT_CACHE 0x1000
+
+#define SMB_LR_UNKNOWN 0x0000
+#define SMB_LR_SEQUENTIAL 0x0100
+#define SMB_LR_RANDOM 0x0200
+#define SMB_LR_RANDOM_WITH_LOCALITY 0x0300
+#define SMB_LR_MASK 0x0F00
+
+#define SMB_DA_WRITE_THROUGH 0x4000
+
+/*
+ * The SMB open function determines what action should be taken depending
+ * on the existence or lack thereof of files used in the operation. It
+ * has the following mapping:
+ *
+ * 1111 1
+ * 5432 1098 7654 3210
+ * rrrr rrrr rrrC rrOO
+ *
+ * where:
+ *
+ * O - Open (action to be taken if the target file exists)
+ * 0 - Fail
+ * 1 - Open or Append file
+ * 2 - Truncate file
+ *
+ * C - Create (action to be taken if the target file does not exist)
+ * 0 - Fail
+ * 1 - Create file
+ */
+
+#define SMB_OFUN_OPEN_MASK 0x3
+#define SMB_OFUN_CREATE_MASK 0x10
+
+#define SMB_OFUN_OPEN_FAIL 0
+#define SMB_OFUN_OPEN_APPEND 1
+#define SMB_OFUN_OPEN_OPEN 1
+#define SMB_OFUN_OPEN_TRUNCATE 2
+
+#define SMB_OFUN_CREATE_FAIL 0x00
+#define SMB_OFUN_CREATE_CREATE 0x10
+
+/*
+ * The Action field of OpenAndX has the following format:
+ *
+ * 1111 11
+ * 5432 1098 7654 3210
+ * Lrrr rrrr rrrr rrOO
+ *
+ * where:
+ *
+ * L - Opportunistic lock. 1 if lock granted, else 0.
+ *
+ * O - Open action:
+ * 1 - The file existed and was opened
+ * 2 - The file did not exist but was created
+ * 3 - The file existed and was truncated
+ */
+
+#define SMB_OACT_LOCK 0x8000
+#define SMB_OACT_OPENED 0x01
+#define SMB_OACT_CREATED 0x02
+#define SMB_OACT_TRUNCATED 0x03
+
+#define SMB_OACT_OPLOCK 0x8000
+
+#define SMB_FTYPE_DISK 0
+#define SMB_FTYPE_BYTE_PIPE 1
+#define SMB_FTYPE_MESG_PIPE 2
+#define SMB_FTYPE_PRINTER 3
+#define SMB_FTYPE_UNKNOWN 0xFFFF
+
+#define SMB_DEVST_BLOCKING 0x8000
+#define SMB_DEVST_ENDPOINT 0x4000
+#define SMB_DEVST_TYPE_MASK 0x0C00
+#define SMB_DEVST_TYPE_BYTE_PIPE 0x0000
+#define SMB_DEVST_TYPE_MESG_PIPE 0x0400
+#define SMB_DEVST_RMODE_MASK 0x0300
+#define SMB_DEVST_RMODE_BYTES 0x0000
+#define SMB_DEVST_RMODE_MESGS 0x0100
+#define SMB_DEVST_ICOUNT_MASK 0x00FF /* not used */
+
+#define SMB_FTYPE_IS_DISK(F) ((F) == SMB_FTYPE_DISK)
+#define SMB_FTYPE_IS_PIPE(F) \
+ (((F) == SMB_FTYPE_BYTE_PIPE) || ((F) == SMB_FTYPE_MESG_PIPE))
+#define SMB_FTYPE_IS_PRINTER(F) ((F) == SMB_FTYPE_PRINTER)
+
+/*
+ * TRANS2_FIND
+ */
+#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
+#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
+#define SMB_FIND_FILE_NAMES_INFO 0x103
+#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
+#define SMB_MAC_FIND_BOTH_HFS_INFO MAC_FIND_BOTH_HFS_INFO
+
+
+/*
+ * Flags for TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
+ * (NTDDK cifs.h and smbtrans.h).
+ *
+ * If SMB_FIND_RETURN_RESUME_KEYS was set in the request parameters,
+ * each entry is preceded by a four-byte resume key.
+ */
+#define SMB_FIND_CLOSE_AFTER_REQUEST 0x01
+#define SMB_FIND_CLOSE_AT_EOS 0x02
+#define SMB_FIND_RETURN_RESUME_KEYS 0x04
+#define SMB_FIND_CONTINUE_FROM_LAST 0x08
+#define SMB_FIND_WITH_BACKUP_INTENT 0x10
+
+
+/*
+ * TRANS2_QUERY_FS_INFORMATION
+ */
+#define SMB_INFO_ALLOCATION 1
+#define SMB_INFO_VOLUME 2
+#define SMB_QUERY_FS_LABEL_INFO 0x101
+#define SMB_QUERY_FS_VOLUME_INFO 0x102
+#define SMB_QUERY_FS_SIZE_INFO 0x103
+#define SMB_QUERY_FS_DEVICE_INFO 0x104
+#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
+#define SMB_QUERY_FS_QUOTA_INFO 0x106 /* unused? */
+#define SMB_QUERY_FS_CONTROL_INFO 0x107
+#define SMB_MAC_QUERY_FS_INFO MAC_QUERY_FS_INFO
+
+
+/* TRANS2_QUERY_{PATH,FILE}_INFORMATION */
+
+#define SMB_INFO_STANDARD 1
+#define SMB_INFO_QUERY_EA_SIZE 2
+#define SMB_INFO_SET_EAS 2
+#define SMB_INFO_QUERY_EAS_FROM_LIST 3
+#define SMB_INFO_QUERY_ALL_EAS 4
+#define SMB_INFO_QUERY_FULL_NAME 5
+#define SMB_INFO_IS_NAME_VALID 6
+#define SMB_INFO_PASSTHROUGH 1000
+
+#define SMB_QUERY_FILE_BASIC_INFO 0x101
+#define SMB_QUERY_FILE_STANDARD_INFO 0x102
+#define SMB_QUERY_FILE_EA_INFO 0x103
+#define SMB_QUERY_FILE_NAME_INFO 0x104
+#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
+#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
+#define SMB_QUERY_FILE_ALL_INFO 0x107
+#define SMB_QUERY_FILE_ALT_NAME_INFO 0x108
+#define SMB_QUERY_FILE_STREAM_INFO 0x109
+#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
+#define SMB_MAC_SET_FINDER_INFO MAC_SET_FINDER_INFO
+#define SMB_MAC_DT_ADD_APPL MAC_DT_ADD_APPL
+#define SMB_MAC_DT_REMOVE_APPL MAC_DT_REMOVE_APPL
+#define SMB_MAC_DT_GET_APPL MAC_DT_GET_APPL
+#define SMB_MAC_DT_GET_ICON MAC_DT_GET_ICON
+#define SMB_MAC_DT_GET_ICON_INFO MAC_DT_GET_ICON_INFO
+#define SMB_MAC_DT_ADD_ICON MAC_DT_ADD_ICON
+
+#define SMB_SET_FILE_BASIC_INFO 0x101
+#define SMB_SET_FILE_DISPOSITION_INFO 0x102
+#define SMB_SET_FILE_ALLOCATION_INFO 0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
+
+
+/*
+ * The following bits may be set in the SecurityMode field of the
+ * SMB_COM_NEGOTIATE response.
+ *
+ * Notes:
+ * NEGOTIATE_SECURITY_SHARE_LEVEL is a montana2 invention.
+ *
+ * The NTDDK cifs.h definitions are:
+ * #define NEGOTIATE_USER_SECURITY 0x01
+ * #define NEGOTIATE_ENCRYPT_PASSWORDS 0x02
+ * #define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
+ * #define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+ */
+#define NEGOTIATE_SECURITY_SHARE_LEVEL 0x00
+#define NEGOTIATE_SECURITY_USER_LEVEL 0x01
+#define NEGOTIATE_SECURITY_CHALLENGE_RESPONSE 0x02
+#define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
+#define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+
+
+/*
+ * Negotiated Capabilities (CIFS/1.0 section 4.1.1)
+ *
+ * Capabilities allow the server to tell the client what it supports.
+ * Undefined bits MUST be set to zero by servers, and MUST be ignored
+ * by clients. The bit definitions are:
+ *
+ * Capability Name Encoding Meaning
+ * ==================== ======== ==================================
+ * CAP_RAW_MODE 0x0001 The server supports SMB_COM_READ_RAW and
+ * SMB_COM_WRITE_RAW (obsolescent)
+ * CAP_MPX_MODE 0x0002 The server supports SMB_COM_READ_MPX and
+ * SMB_COM_WRITE_MPX (obsolescent)
+ * CAP_UNICODE 0x0004 The server supports Unicode strings
+ * CAP_LARGE_FILES 0x0008 The server supports large files with 64
+ * bit offsets
+ * CAP_NT_SMBS 0x0010 The server supports the SMBs particular
+ * to the NT LM 0.12 dialect.
+ * Implies CAP_NT_FIND.
+ * CAP_RPC_REMOTE_APIS 0x0020 The server supports remote admin API
+ * requests via DCE RPC
+ * CAP_STATUS32 0x0040 The server can respond with 32 bit
+ * status codes in Status.Status
+ * CAP_LEVEL_II_OPLOCKS 0x0080 The server supports level 2 oplocks
+ * CAP_LOCK_AND_READ 0x0100 The server supports the
+ * SMB_COM_LOCK_AND_READ SMB
+ * CAP_NT_FIND 0x0200
+ * CAP_BULK_TRANSFER 0x0400
+ * CAP_COMPRESSED_BULK 0x0800
+ * CAP_DFS 0x1000 The server is DFS aware
+ * CAP_LARGE_READX 0x4000 The server supports large
+ * SMB_COM_READ_ANDX
+ * CAP_LARGE_WRITEX 0x8000 The server supports large
+ * SMB_COM_WRITE_ANDX
+ * CAP_RESERVED 0x02000000 Reserved for future use.
+ * CAP_EXTENDED_SECURITY 0x80000000 The server supports extended security
+ * exchanges.
+ *
+ * Extended security exchanges provides a means of supporting arbitrary
+ * authentication protocols within CIFS. Security blobs are opaque to the
+ * CIFS protocol; they are messages in some authentication protocol that
+ * has been agreed upon by client and server by some out of band mechanism,
+ * for which CIFS merely functions as a transport. When
+ * CAP_EXTENDED_SECURITY is negotiated, the server includes a first
+ * security blob in its response; subsequent security blobs are exchanged
+ * in SMB_COM_SESSION_SETUP_ANDX requests and responses until the
+ * authentication protocol terminates.
+ */
+#define CAP_RAW_MODE 0x0001
+#define CAP_MPX_MODE 0x0002
+#define CAP_UNICODE 0x0004
+#define CAP_LARGE_FILES 0x0008
+#define CAP_NT_SMBS 0x0010
+#define CAP_RPC_REMOTE_APIS 0x0020
+#define CAP_STATUS32 0x0040
+#define CAP_LEVEL_II_OPLOCKS 0x0080
+#define CAP_LOCK_AND_READ 0x0100
+#define CAP_NT_FIND 0x0200
+#define CAP_BULK_TRANSFER 0x0400
+#define CAP_COMPRESSED_BULK 0x0800
+#define CAP_DFS 0x1000
+#define CAP_LARGE_READX 0x4000
+#define CAP_LARGE_WRITEX 0x8000
+#define CAP_RESERVED 0x02000000
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+
+/*
+ * Different device types according to NT
+ */
+#define FILE_DEVICE_BEEP 0x00000001
+#define FILE_DEVICE_CD_ROM 0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
+#define FILE_DEVICE_CONTROLLER 0x00000004
+#define FILE_DEVICE_DATALINK 0x00000005
+#define FILE_DEVICE_DFS 0x00000006
+#define FILE_DEVICE_DISK 0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define FILE_DEVICE_INPORT_PORT 0x0000000a
+#define FILE_DEVICE_KEYBOARD 0x0000000b
+#define FILE_DEVICE_MAILSLOT 0x0000000c
+#define FILE_DEVICE_MIDI_IN 0x0000000d
+#define FILE_DEVICE_MIDI_OUT 0x0000000e
+#define FILE_DEVICE_MOUSE 0x0000000f
+#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010
+#define FILE_DEVICE_NAMED_PIPE 0x00000011
+#define FILE_DEVICE_NETWORK 0x00000012
+#define FILE_DEVICE_NETWORK_BROWSER 0x00000013
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL 0x00000015
+#define FILE_DEVICE_PARALLEL_PORT 0x00000016
+#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
+#define FILE_DEVICE_PRINTER 0x00000018
+#define FILE_DEVICE_SCANNER 0x00000019
+#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a
+#define FILE_DEVICE_SERIAL_PORT 0x0000001b
+#define FILE_DEVICE_SCREEN 0x0000001c
+#define FILE_DEVICE_SOUND 0x0000001d
+#define FILE_DEVICE_STREAMS 0x0000001e
+#define FILE_DEVICE_TAPE 0x0000001f
+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+#define FILE_DEVICE_TRANSPORT 0x00000021
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#define FILE_DEVICE_VIDEO 0x00000023
+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
+#define FILE_DEVICE_WAVE_IN 0x00000025
+#define FILE_DEVICE_WAVE_OUT 0x00000026
+#define FILE_DEVICE_8042_PORT 0x00000027
+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
+#define FILE_DEVICE_BATTERY 0x00000029
+#define FILE_DEVICE_BUS_EXTENDER 0x0000002a
+#define FILE_DEVICE_MODEM 0x0000002b
+#define FILE_DEVICE_VDM 0x0000002c
+
+/*
+ * Some of these device types are not currently accessible over the network
+ * and may never be accessible over the network. Some may change to be
+ *
+ * accessible over the network. The values for device types that may never
+ * be accessible over the network may be redefined to be just reserved at
+ * some date in the future.
+ *
+ * Characteristics is the sum of any of the following:
+ */
+
+#define FILE_REMOVABLE_MEDIA 0x00000001
+#define FILE_READ_ONLY_DEVICE 0x00000002
+#define FILE_FLOPPY_DISKETTE 0x00000004
+#define FILE_WRITE_ONE_MEDIA 0x00000008
+#define FILE_REMOTE_DEVICE 0x00000010
+#define FILE_DEVICE_IS_MOUNTED 0x00000020
+#define FILE_VIRTUAL_VOLUME 0x00000040
+
+/*
+ * CREATE_ANDX ShareAccess Flags
+ */
+
+#define FILE_SHARE_NONE 0x00000000
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+#define FILE_SHARE_DELETE 0x00000004
+#define FILE_SHARE_ALL 0x00000007
+#define FILE_SHARE_VALID_FLAGS 0x00000007
+
+
+/*
+ * CREATE_ANDX CreateDisposition flags
+ *
+ * FILE_SUPERSEDE If the file already exists it should be superseded
+ * by the specified file. If the file does not already
+ * exist then it should be created.
+ *
+ * FILE_CREATE If the file already exists the operation should fail.
+ * If the file does not already exist then it should be
+ * created. (aka CREATE_NEW)
+ *
+ * FILE_OPEN If the file already exists then it should be opened.
+ * If the file does not already exist then the operation
+ * should fail. (aka OPEN_EXISTING)
+ *
+ * FILE_OPEN_IF If the file already exists then it should be opened.
+ * If the file does not already exist then it should be
+ * created. (aka OPEN_ALWAYS)
+ *
+ * FILE_OVERWRITE If the file already exists, it should be opened and
+ * overwritten. If the file does not already exist then
+ * the operation should fail. (aka TRUNCATE_EXISTING)
+ *
+ * FILE_OVERWRITE_IF If the file already exists, it should be opened and
+ * overwritten. If the file does not already exist then
+ * it should be created. (aka CREATE_ALWAYS)
+ */
+#define FILE_SUPERSEDE 0x00000000
+#define FILE_OPEN 0x00000001
+#define FILE_CREATE 0x00000002
+#define FILE_OPEN_IF 0x00000003
+#define FILE_OVERWRITE 0x00000004
+#define FILE_OVERWRITE_IF 0x00000005
+#define FILE_MAXIMUM_DISPOSITION 0x00000005
+
+/*
+ * CREATE_ANDX Impersonation levels
+ */
+
+#define SECURITY_ANONYMOUS 0x00000001
+#define SECURITY_IDENTIFICATION 0x00000002
+#define SECURITY_IMPERSONATION 0x00000003
+#define SECURITY_DELEGATION 0x00000004
+
+/*
+ * CREATE_ANDX SecurityFlags
+ */
+
+#define SECURITY_CONTEXT_TRACKING 0x00000001
+#define SECURITY_EFFECTIVE_ONLY 0x00000002
+
+/*
+ * Server types
+ */
+#define SV_WORKSTATION 0x00000001 /* All workstations */
+#define SV_SERVER 0x00000002 /* All servers */
+#define SV_SQLSERVER 0x00000004 /* running with SQL server */
+#define SV_DOMAIN_CTRL 0x00000008 /* Primary domain controller */
+#define SV_DOMAIN_BAKCTRL 0x00000010 /* Backup domain controller */
+#define SV_TIME_SOURCE 0x00000020 /* running timesource service */
+#define SV_AFP 0x00000040 /* Apple File Protocol */
+#define SV_NOVELL 0x00000080 /* Novell servers */
+#define SV_DOMAIN_MEMBER 0x00000100 /* Domain Member */
+#define SV_PRINTQ_SERVER 0x00000200 /* Server sharing print queue */
+#define SV_DIALIN_SERVER 0x00000400 /* Server running dialin */
+#define SV_XENIX_SERVER 0x00000800 /* Xenix server */
+#define SV_NT 0x00001000 /* NT server */
+#define SV_WFW 0x00002000 /* Server running Windows for */
+#define SV_SERVER_NT 0x00008000 /* Windows NT non DC server */
+#define SV_POTENTIAL_BROWSER 0x00010000 /* can run browser service */
+#define SV_BACKUP_BROWSER 0x00020000 /* Backup browser server */
+#define SV_MASTER_BROWSER 0x00040000 /* Master browser server */
+#define SV_DOMAIN_MASTER 0x00080000 /* Domain Master Browser */
+#define SV_OSF 0x00100000 /* OSF operating system */
+#define SV_VMS 0x00200000 /* VMS operating system */
+#define SV_WINDOWS_95_PLUS 0x00400000 /* Windows 95 or better */
+
+#define SV_LOCAL_LIST_ONLY 0x40000000 /* Enumerate only "local" */
+#define SV_TYPE_DOMAIN_ENUM 0x80000000 /* Enumerate Domains */
+
+#define MY_SERVER_TYPE (SV_SERVER | SV_NT | SV_SERVER_NT | SV_DOMAIN_MEMBER)
+
+
+#define PRQ_ACTIVE 0 /* Active */
+#define PRQ_PAUSE 1 /* Paused */
+#define PRQ_ERROR 2 /* Error Occurred */
+#define PRQ_PENDING 3 /* Deletion pending */
+
+#define PRJ_QS_QUEUED 0 /* Active */
+#define PRJ_QS_PAUSED 1 /* Paused */
+#define PRJ_QS_SPOOLING 2 /* Paused */
+#define PRJ_QS_PRINTING 3 /* Paused */
+
+
+#define SHARE_ACCESS_READ 0x01 /* read & execute from resource */
+#define SHARE_ACCESS_WRITE 0x02 /* write data to resource */
+#define SHARE_ACCESS_CREATE 0x04 /* create an instance of */
+#define SHARE_ACCESS_EXEC 0x08 /* execute from resource */
+#define SHARE_ACCESS_DELETE 0x10 /* Permission to delete the resource */
+#define SHARE_ACCESS_ATTRIB 0x20 /* Permission to modify the resource */
+#define SHARE_ACCESS_PERM 0x40 /* Permission to change permissions */
+#define SHARE_ACCESS_ALL 0x7F /* All of the above permissions */
+
+
+/*
+ * SMB_COM_NT_TRANSACTION sub-command codes (CIFS/1.0 section 5.3)
+ *
+ * SubCommand Code Value Description
+ * =============================== ===== =================================
+ * NT_TRANSACT_CREATE 1 File open/create
+ * NT_TRANSACT_IOCTL 2 Device IOCTL
+ * NT_TRANSACT_SET_SECURITY_DESC 3 Set security descriptor
+ * NT_TRANSACT_NOTIFY_CHANGE 4 Start directory watch
+ * NT_TRANSACT_RENAME 5 Reserved (handle-based rename)
+ * NT_TRANSACT_QUERY_SECURITY_DESC 6 Retrieve security descriptor
+ * NT_TRANSACT_QUERY_QUOTA 7 Retrieve quota information
+ * NT_TRANSACT_SET_QUOTA 8 Set quota information
+ */
+#define NT_TRANSACT_MIN_FUNCTION 1
+
+#define NT_TRANSACT_CREATE 1
+#define NT_TRANSACT_IOCTL 2
+#define NT_TRANSACT_SET_SECURITY_DESC 3
+#define NT_TRANSACT_NOTIFY_CHANGE 4
+#define NT_TRANSACT_RENAME 5
+#define NT_TRANSACT_QUERY_SECURITY_DESC 6
+#define NT_TRANSACT_QUERY_QUOTA 7
+#define NT_TRANSACT_SET_QUOTA 8
+
+#define NT_TRANSACT_MAX_FUNCTION 8
+
+
+/*
+ * Pipe states
+ */
+#define SMB_PIPE_READMODE_BYTE 0x0000
+#define SMB_PIPE_READMODE_MESSAGE 0x0100
+#define SMB_PIPE_TYPE_BYTE 0x0000
+#define SMB_PIPE_TYPE_MESSAGE 0x0400
+#define SMB_PIPE_END_CLIENT 0x0000
+#define SMB_PIPE_END_SERVER 0x4000
+#define SMB_PIPE_WAIT 0x0000
+#define SMB_PIPE_NOWAIT 0x8000
+#define SMB_PIPE_UNLIMITED_INSTANCES 0x00FF
+
+/*
+ * smb_com_seek request
+ */
+#define SMB_SEEK_SET 0 /* set file offset to specified offset */
+#define SMB_SEEK_CUR 1 /* set file offset to current plus specified offset */
+#define SMB_SEEK_END 2 /* set file offset to EOF plus specified offset */
+
+/*
+ * API Numbers for Transact based RAP (Remote Administration Protocol) calls
+ */
+#define API_WshareEnum 0
+#define API_WshareGetInfo 1
+#define API_WshareSetInfo 2
+#define API_WshareAdd 3
+#define API_WshareDel 4
+#define API_NetShareCheck 5
+#define API_WsessionEnum 6
+#define API_WsessionGetInfo 7
+#define API_WsessionDel 8
+#define API_WconnectionEnum 9
+#define API_WfileEnum 10
+#define API_WfileGetInfo 11
+#define API_WfileClose 12
+#define API_WserverGetInfo 13
+#define API_WserverSetInfo 14
+#define API_WserverDiskEnum 15
+#define API_WserverAdminCommand 16
+#define API_NetAuditOpen 17
+#define API_WauditClear 18
+#define API_NetErrorLogOpen 19
+#define API_WerrorLogClear 20
+#define API_NetCharDevEnum 21
+#define API_NetCharDevGetInfo 22
+#define API_WCharDevControl 23
+#define API_NetCharDevQEnum 24
+#define API_NetCharDevQGetInfo 25
+#define API_WCharDevQSetInfo 26
+#define API_WCharDevQPurge 27
+#define API_WCharDevQPurgeSelf 28
+#define API_WMessageNameEnum 29
+#define API_WMessageNameGetInfo 30
+#define API_WMessageNameAdd 31
+#define API_WMessageNameDel 32
+#define API_WMessageNameFwd 33
+#define API_WMessageNameUnFwd 34
+#define API_WMessageBufferSend 35
+#define API_WMessageFileSend 36
+#define API_WMessageLogFileSet 37
+#define API_WMessageLogFileGet 38
+#define API_WServiceEnum 39
+#define API_WServiceInstall 40
+#define API_WServiceControl 41
+#define API_WAccessEnum 42
+#define API_WAccessGetInfo 43
+#define API_WAccessSetInfo 44
+#define API_WAccessAdd 45
+#define API_WAccessDel 46
+#define API_WGroupEnum 47
+#define API_WGroupAdd 48
+#define API_WGroupDel 49
+#define API_WGroupAddUser 50
+#define API_WGroupDelUser 51
+#define API_WGroupGetUsers 52
+#define API_WUserEnum 53
+#define API_WUserAdd 54
+#define API_WUserDel 55
+#define API_WUserGetInfo 56
+#define API_WUserSetInfo 57
+#define API_WUserPasswordSet 58
+#define API_WUserGetGroups 59
+#define API_DeadTableEntry 60
+#define API_WWkstaSetUID 62
+#define API_WWkstaGetInfo 63
+#define API_WWkstaSetInfo 64
+#define API_WUseEnum 65
+#define API_WUseAdd 66
+#define API_WUseDel 67
+#define API_WUseGetInfo 68
+#define API_WPrintQEnum 69
+#define API_WPrintQGetInfo 70
+#define API_WPrintQSetInfo 71
+#define API_WPrintQAdd 72
+#define API_WPrintQDel 73
+#define API_WPrintQPause 74
+#define API_WPrintQContinue 75
+#define API_WPrintJobEnum 76
+#define API_WPrintJobGetInfo 77
+#define API_WPrintJobSetInfo_OLD 78
+#define API_WPrintJobDel 81
+#define API_WPrintJobPause 82
+#define API_WPrintJobContinue 83
+#define API_WPrintDestEnum 84
+#define API_WPrintDestGetInfo 85
+#define API_WPrintDestControl 86
+#define API_WProfileSave 87
+#define API_WProfileLoad 88
+#define API_WStatisticsGet 89
+#define API_WStatisticsClear 90
+#define API_NetRemoteTOD 91
+#define API_WNetBiosEnum 92
+#define API_WNetBiosGetInfo 93
+#define API_NetServerEnum 94
+#define API_I_NetServerEnum 95
+#define API_WServiceGetInfo 96
+#define API_WPrintQPurge 103
+#define API_NetServerEnum2 104
+#define API_WAccessGetUserPerms 105
+#define API_WGroupGetInfo 106
+#define API_WGroupSetInfo 107
+#define API_WGroupSetUsers 108
+#define API_WUserSetGroups 109
+#define API_WUserModalsGet 110
+#define API_WUserModalsSet 111
+#define API_WFileEnum2 112
+#define API_WUserAdd2 113
+#define API_WUserSetInfo2 114
+#define API_WUserPasswordSet2 115
+#define API_I_NetServerEnum2 116
+#define API_WConfigGet2 117
+#define API_WConfigGetAll2 118
+#define API_WGetDCName 119
+#define API_NetHandleGetInfo 120
+#define API_NetHandleSetInfo 121
+#define API_WStatisticsGet2 122
+#define API_WBuildGetInfo 123
+#define API_WFileGetInfo2 124
+#define API_WFileClose2 125
+#define API_WNetServerReqChallenge 126
+#define API_WNetServerAuthenticate 127
+#define API_WNetServerPasswordSet 128
+#define API_WNetAccountDeltas 129
+#define API_WNetAccountSync 130
+#define API_WUserEnum2 131
+#define API_WWkstaUserLogon 132
+#define API_WWkstaUserLogoff 133
+#define API_WLogonEnum 134
+#define API_WErrorLogRead 135
+#define API_WI_NetPathType 136
+#define API_WI_NetPathCanonicalize 137
+#define API_WI_NetPathCompare 138
+#define API_WI_NetNameValidate 139
+#define API_WI_NetNameCanonicalize 140
+#define API_WI_NetNameCompare 141
+#define API_WAuditRead 142
+#define API_WPrintDestAdd 143
+#define API_WPrintDestSetInfo 144
+#define API_WPrintDestDel 145
+#define API_WUserValidate2 146
+#define API_WPrintJobSetInfo 147
+#define API_TI_NetServerDiskEnum 148
+#define API_TI_NetServerDiskGetInfo 149
+#define API_TI_FTVerifyMirror 150
+#define API_TI_FTAbortVerify 151
+#define API_TI_FTGetInfo 152
+#define API_TI_FTSetInfo 153
+#define API_TI_FTLockDisk 154
+#define API_TI_FTFixError 155
+#define API_TI_FTAbortFix 156
+#define API_TI_FTDiagnoseError 157
+#define API_TI_FTGetDriveStats 158
+#define API_TI_FTErrorGetInfo 160
+#define API_NetAccessCheck 163
+#define API_NetAlertRaise 164
+#define API_NetAlertStart 165
+#define API_NetAlertStop 166
+#define API_NetAuditWrite 167
+#define API_NetIRemoteAPI 168
+#define API_NetServiceStatus 169
+#define API_I_NetServerRegister 170
+#define API_I_NetServerDeregister 171
+#define API_I_NetSessionEntryMake 172
+#define API_I_NetSessionEntryClear 173
+#define API_I_NetSessionEntryGetInfo 174
+#define API_I_NetSessionEntrySetInfo 175
+#define API_I_NetConnectionEntryMake 176
+#define API_I_NetConnectionEntryClear 177
+#define API_I_NetConnectionEntrySetInfo 178
+#define API_I_NetConnectionEntryGetInfo 179
+#define API_I_NetFileEntryMake 180
+#define API_I_NetFileEntryClear 181
+#define API_I_NetFileEntrySetInfo 182
+#define API_I_NetFileEntryGetInfo 183
+#define API_AltSrvMessageBufferSend 184
+#define API_AltSrvMessageFileSend 185
+#define API_wI_NetRplWkstaEnum 186
+#define API_wI_NetRplWkstaGetInfo 187
+#define API_wI_NetRplWkstaSetInfo 188
+#define API_wI_NetRplWkstaAdd 189
+#define API_wI_NetRplWkstaDel 190
+#define API_wI_NetRplProfileEnum 191
+#define API_wI_NetRplProfileGetInfo 192
+#define API_wI_NetRplProfileSetInfo 193
+#define API_wI_NetRplProfileAdd 194
+#define API_wI_NetRplProfileDel 195
+#define API_wI_NetRplProfileClone 196
+#define API_wI_NetRplBaseProfileEnum 197
+#define API_WIServerSetInfo 201
+#define API_WPrintDriverEnum 205
+#define API_WPrintQProcessorEnum 206
+#define API_WPrintPortEnum 207
+#define API_WNetWriteUpdateLog 208
+#define API_WNetAccountUpdate 209
+#define API_WNetAccountConfirmUpdate 210
+#define API_WConfigSet 211
+#define API_WAccountsReplicate 212
+#define API_SamOEMChgPasswordUser2_P 214
+#define API_NetServerEnum3 215
+#define API_WprintDriverGetInfo 250
+#define API_WprintDriverSetInfo 251
+#define API_WaliasAdd 252
+#define API_WaliasDel 253
+#define API_WaliasGetInfo 254
+#define API_WaliasSetInfo 255
+#define API_WaliasEnum 256
+#define API_WuserGetLogonAsn 257
+#define API_WuserSetLogonAsn 258
+#define API_WuserGetAppSel 259
+#define API_WuserSetAppSel 260
+#define API_WappAdd 261
+#define API_WappDel 262
+#define API_WappGetInfo 263
+#define API_WappSetInfo 264
+#define API_WappEnum 265
+#define API_WUserDCDBInit 266
+#define API_WDASDAdd 267
+#define API_WDASDDel 268
+#define API_WDASDGetInfo 269
+#define API_WDASDSetInfo 270
+#define API_WDASDEnum 271
+#define API_WDASDCheck 272
+#define API_WDASDCtl 273
+#define API_WuserRemoteLogonCheck 274
+#define API_WUserPasswordSet3 275
+#define API_WCreateRIPLMachine 276
+#define API_WDeleteRIPLMachine 277
+#define API_WGetRIPLMachineInfo 278
+#define API_WSetRIPLMachineInfo 279
+#define API_WEnumRIPLMachine 280
+#define API_WI_ShareAdd 281
+#define API_WI_AliasEnum 282
+#define API_WaccessApply 283
+#define API_WPrt16Query 284
+#define API_WPrt16Set 285
+#define API_WUserDel100 286
+#define API_WUserRemoteLogonCheck2 287
+#define API_WRemoteTODSet 294
+#define API_WprintJobMoveAll 295
+#define API_W16AppParmAdd 296
+#define API_W16AppParmDel 297
+#define API_W16AppParmGet 298
+#define API_W16AppParmSet 299
+#define API_W16RIPLMachineCreate 300
+#define API_W16RIPLMachineGetInfo 301
+#define API_W16RIPLMachineSetInfo 302
+#define API_W16RIPLMachineEnum 303
+#define API_W16RIPLMachineListParmEnum 304
+#define API_W16RIPLMachClassGetInfo 305
+#define API_W16RIPLMachClassEnum 306
+#define API_W16RIPLMachClassCreate 307
+#define API_W16RIPLMachClassSetInfo 308
+#define API_W16RIPLMachClassDelete 309
+#define API_W16RIPLMachClassLPEnum 310
+#define API_W16RIPLMachineDelete 311
+#define API_W16WSLevelGetInfo 312
+#define API_WserverNameAdd 313
+#define API_WserverNameDel 314
+#define API_WserverNameEnum 315
+#define API_I_WDASDEnum 316
+#define API_I_WDASDEnumTerminate 317
+#define API_I_WDASDSetInfo2 318
+#define MAX_RAP_API 318
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CIFS_H */
diff --git a/usr/src/uts/common/smbsrv/codepage.h b/usr/src/uts/common/smbsrv/codepage.h
new file mode 100644
index 0000000000..baefb9de22
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/codepage.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CODEPAGE_H
+#define _SMBSRV_CODEPAGE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/string.h>
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Labels to define whether a code page table entry is an uppercase
+ * character, a lowercase character or neither. One of these values
+ * should appear in the ctype field of the code page tables.
+ */
+#define CODEPAGE_ISNONE 0x00
+#define CODEPAGE_ISUPPER 0x01
+#define CODEPAGE_ISLOWER 0x02
+
+/*
+ * The structure of a code page entry. Each code page table will
+ * consist of an array of 256 codepage entries.
+ *
+ * ctype indicates case of the value.
+ * upper indicates the uppercase equivalent value.
+ * lower indicates the lowercase equivalent value.
+ */
+typedef struct codepage {
+ unsigned char ctype;
+ mts_wchar_t upper;
+ mts_wchar_t lower;
+} codepage_t;
+
+/*
+ * Global pointer to the current code page. This is
+ * defaulted to a standard ASCII table.
+ */
+extern codepage_t usascii_codepage[];
+
+/*
+ * This buffer is used to store the language string for display.
+ */
+#define CODEPAGE_BUFSIZ 48
+
+extern int oem_language_set(char *language);
+extern unsigned int oem_get_smb_cpid(void);
+extern unsigned int oem_get_telnet_cpid(void);
+
+extern int codepage_isupper(int c);
+extern int codepage_islower(int c);
+extern int codepage_toupper(int c);
+extern int codepage_tolower(int c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CODEPAGE_H */
diff --git a/usr/src/uts/common/smbsrv/cp_cyrillic.h b/usr/src/uts/common/smbsrv/cp_cyrillic.h
new file mode 100644
index 0000000000..d3b2a27596
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_cyrillic.h
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CP_CYRILLIC_H
+#define _SMBSRV_CP_CYRILLIC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for Cyrillic Character Set
+ * This codepage defines values for the special
+ * characters needed for the written alphabets of the
+ * following languages: Bulgarian, Byelorussian,
+ * Macedonian, Russian, Serbian, and pre-1990 Ukrainian
+ * The cyrillic character set is also known as iso-8859-5
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t cyrillic_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00f1 }, /* 0x00a1 */
+ { CODEPAGE_ISUPPER, 0x00a2, 0x00f2 }, /* 0x00a2 */
+ { CODEPAGE_ISUPPER, 0x00a3, 0x00f3 }, /* 0x00a3 */
+ { CODEPAGE_ISUPPER, 0x00a4, 0x00f4 }, /* 0x00a4 */
+ { CODEPAGE_ISUPPER, 0x00a5, 0x00f5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00f6 }, /* 0x00a6 */
+ { CODEPAGE_ISUPPER, 0x00a7, 0x00f7 }, /* 0x00a7 */
+ { CODEPAGE_ISUPPER, 0x00a8, 0x00f8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00f9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00fa }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00fb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00fc }, /* 0x00ac */
+ { CODEPAGE_ISUPPER, 0x00ad, 0x00fd }, /* 0x00ad */
+ { CODEPAGE_ISUPPER, 0x00ae, 0x00fe }, /* 0x00ae */
+ { CODEPAGE_ISUPPER, 0x00af, 0x00ff }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISNONE, 0x00b1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISNONE, 0x00b6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISNONE, 0x00b9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISNONE, 0x00ba, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISNONE, 0x00bb, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISNONE, 0x00bc, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISNONE, 0x00d0, 0x00d0 }, /* 0x00d0 */
+ { CODEPAGE_ISNONE, 0x00d1, 0x00d1 }, /* 0x00d1 */
+ { CODEPAGE_ISNONE, 0x00d2, 0x00d2 }, /* 0x00d2 */
+ { CODEPAGE_ISNONE, 0x00d3, 0x00d3 }, /* 0x00d3 */
+ { CODEPAGE_ISNONE, 0x00d4, 0x00d4 }, /* 0x00d4 */
+ { CODEPAGE_ISNONE, 0x00d5, 0x00d5 }, /* 0x00d5 */
+ { CODEPAGE_ISNONE, 0x00d6, 0x00d6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISNONE, 0x00d8, 0x00d8 }, /* 0x00d8 */
+ { CODEPAGE_ISNONE, 0x00d9, 0x00d9 }, /* 0x00d9 */
+ { CODEPAGE_ISNONE, 0x00da, 0x00da }, /* 0x00da */
+ { CODEPAGE_ISNONE, 0x00db, 0x00db }, /* 0x00db */
+ { CODEPAGE_ISNONE, 0x00dc, 0x00dc }, /* 0x00dc */
+ { CODEPAGE_ISNONE, 0x00dd, 0x00dd }, /* 0x00dd */
+ { CODEPAGE_ISNONE, 0x00de, 0x00de }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISNONE, 0x00f0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00a2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00a3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00a4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00a5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISLOWER, 0x00a7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00a8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00ad, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00ae, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISLOWER, 0x00af, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_CYRILLIC_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin1.h b/usr/src/uts/common/smbsrv/cp_latin1.h
new file mode 100644
index 0000000000..728b28e05b
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin1.h
@@ -0,0 +1,317 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CP_LATIN1_H
+#define _SMBSRV_CP_LATIN1_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for the Latin-1 Character Set
+ * (Western Europe). This codepage defines values for
+ * the special characters needed for the written alphabets
+ * of the following Languages: French, Spanish, Catalan,
+ * Basque, Portuguese, Italian, Albanian, Rhaeto-Romanic,
+ * Dutch, German, Danish, Swedish, Norwegian, Finnish,
+ * Faroese, Icelandic, Irish, Scottish, English, Afrikaans
+ * and Swahili.
+ * This codepage is also used in North & South America,
+ * Canada, Australia, and much of Africa
+ * The Latin-1 character set is also Known as iso-8859-1.
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin1_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISNONE, 0x00a1, 0x00a1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISNONE, 0x00a3, 0x00a3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISNONE, 0x00a5, 0x00a5 }, /* 0x00a5 */
+ { CODEPAGE_ISNONE, 0x00a6, 0x00a6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISNONE, 0x00a9, 0x00a9 }, /* 0x00a9 */
+ { CODEPAGE_ISNONE, 0x00aa, 0x00aa }, /* 0x00aa */
+ { CODEPAGE_ISNONE, 0x00ab, 0x00ab }, /* 0x00ab */
+ { CODEPAGE_ISNONE, 0x00ac, 0x00ac }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISNONE, 0x00ae, 0x00ae }, /* 0x00ae */
+ { CODEPAGE_ISNONE, 0x00af, 0x00af }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISNONE, 0x00b1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISNONE, 0x00b6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISNONE, 0x00b9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISNONE, 0x00ba, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISNONE, 0x00bb, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISNONE, 0x00bc, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISUPPER, 0x00d0, 0x00f0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISLOWER, 0x00d0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN1_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin2.h b/usr/src/uts/common/smbsrv/cp_latin2.h
new file mode 100644
index 0000000000..77f2e5a2a4
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin2.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 (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.
+ */
+
+#ifndef _SMBSRV_CP_LATIN2_H
+#define _SMBSRV_CP_LATIN2_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for the Latin-2 Character Set
+ * (Central & Eastern Europe). This codepage defines
+ * values for the special characters needed
+ * for the written alphabets of the following languages: Czech,
+ * Hungarian, Polish, Romanian, Croatian, Slovak,
+ * Slovenian, and Sorbian
+ * The Latin-2 character set is also known as iso-8859-2
+ *
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin2_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00b1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISUPPER, 0x00a3, 0x00b3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISUPPER, 0x00a5, 0x00b5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00b6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00b9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00ba }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00bb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00bc }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISUPPER, 0x00ae, 0x00be }, /* 0x00ae */
+ { CODEPAGE_ISUPPER, 0x00af, 0x00bf }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISLOWER, 0x00a3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISLOWER, 0x00a5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISLOWER, 0x00ae, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISLOWER, 0x00af, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISUPPER, 0x00d0, 0x00f0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISLOWER, 0x00d0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN2_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin3.h b/usr/src/uts/common/smbsrv/cp_latin3.h
new file mode 100644
index 0000000000..afc7ae4355
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin3.h
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CP_LATIN3_H
+#define _SMBSRV_CP_LATIN3_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for Latin-3 Character Set
+ * This codepage defines values for the special characters
+ * needed for the written alphabets of the following
+ * languages: Esperanto and Maltese.
+ * The Latin-3 character set is also known as iso-8859-3
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin3_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00b1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISNONE, 0x00a3, 0x00a3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISNONE, 0x00a5, 0x00a5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00b6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00b9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00ba }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00bb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00bc }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISNONE, 0x00ae, 0x00ae }, /* 0x00ae */
+ { CODEPAGE_ISUPPER, 0x00af, 0x00bf }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISLOWER, 0x00af, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISNONE, 0x00c3, 0x00c3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISNONE, 0x00d0, 0x00d0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISNONE, 0x00e3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISNONE, 0x00f0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN3_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin4.h b/usr/src/uts/common/smbsrv/cp_latin4.h
new file mode 100644
index 0000000000..87e8282510
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin4.h
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CP_LATIN4_H
+#define _SMBSRV_CP_LATIN4_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for Latin-4 Character Set.
+ * This codepage defines values for the special
+ * characters needed for the written alphabets of the
+ * following languages: Estonian, Baltic [Latvian &
+ * Lithuanian], Greenlandic, and Lappish
+ * The Latin-4 character set is also known as iso-8859-4
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin4_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00b1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISUPPER, 0x00a3, 0x00b3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISUPPER, 0x00a5, 0x00b5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00b6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00b9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00ba }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00bb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00bc }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISUPPER, 0x00ae, 0x00be }, /* 0x00ae */
+ { CODEPAGE_ISNONE, 0x00af, 0x00af }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISLOWER, 0x00a3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISLOWER, 0x00a5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISLOWER, 0x00ae, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISUPPER, 0x00d0, 0x00f0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISLOWER, 0x00d0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN4_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin5.h b/usr/src/uts/common/smbsrv/cp_latin5.h
new file mode 100644
index 0000000000..87ad426348
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin5.h
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CP_LATIN5_H
+#define _SMBSRV_CP_LATIN5_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for the Latin-5 Character Set
+ * This codepage defines values for the special characters
+ * needed for the written alphabet of the following
+ * language: Turkish * The Latin-5 character set is also known as iso-8859-9.
+ *
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin5_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISNONE, 0x00a1, 0x00a1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISNONE, 0x00a3, 0x00a3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISNONE, 0x00a5, 0x00a5 }, /* 0x00a5 */
+ { CODEPAGE_ISNONE, 0x00a6, 0x00a6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISNONE, 0x00a9, 0x00a9 }, /* 0x00a9 */
+ { CODEPAGE_ISNONE, 0x00aa, 0x00aa }, /* 0x00aa */
+ { CODEPAGE_ISNONE, 0x00ab, 0x00ab }, /* 0x00ab */
+ { CODEPAGE_ISNONE, 0x00ac, 0x00ac }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISNONE, 0x00ae, 0x00ae }, /* 0x00ae */
+ { CODEPAGE_ISNONE, 0x00af, 0x00af }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISNONE, 0x00b1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISNONE, 0x00b6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISNONE, 0x00b9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISNONE, 0x00ba, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISNONE, 0x00bb, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISNONE, 0x00bc, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISUPPER, 0x00d0, 0x00f0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISLOWER, 0x00d0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN5_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin6.h b/usr/src/uts/common/smbsrv/cp_latin6.h
new file mode 100644
index 0000000000..fd86d276c4
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin6.h
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CP_LATIN6_H
+#define _SMBSRV_CP_LATIN6_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is the codepage for the Latin-6 Character Set.
+ * This codepage defines values for the special characters
+ * needed for the written alphabets of the following
+ * Nordic Languages: Greenlandic, Eskimo, Lappish,
+ * and Icelandic
+ * The Latin-6 character set is also known as iso-8859-10
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin6_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00b1 }, /* 0x00a1 */
+ { CODEPAGE_ISUPPER, 0x00a2, 0x00b2 }, /* 0x00a2 */
+ { CODEPAGE_ISUPPER, 0x00a3, 0x00b3 }, /* 0x00a3 */
+ { CODEPAGE_ISUPPER, 0x00a4, 0x00b4 }, /* 0x00a4 */
+ { CODEPAGE_ISUPPER, 0x00a5, 0x00b5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00b6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISUPPER, 0x00a8, 0x00b8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00b9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00ba }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00bb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00bc }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISUPPER, 0x00ae, 0x00be }, /* 0x00ae */
+ { CODEPAGE_ISUPPER, 0x00af, 0x00bf }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISLOWER, 0x00a2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISLOWER, 0x00a3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISLOWER, 0x00a4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISLOWER, 0x00a5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISLOWER, 0x00a8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISLOWER, 0x00ae, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISLOWER, 0x00af, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISNONE, 0x00d0, 0x00d0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISUPPER, 0x00d7, 0x00f7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISNONE, 0x00f0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISLOWER, 0x00d7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN6_H */
diff --git a/usr/src/uts/common/smbsrv/cp_unicode.h b/usr/src/uts/common/smbsrv/cp_unicode.h
new file mode 100644
index 0000000000..e2f1eb83f9
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_unicode.h
@@ -0,0 +1,6639 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CP_UNICODE_H
+#define _SMBSRV_CP_UNICODE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct unicode_cp {
+ mts_wchar_t val;
+ mts_wchar_t ctype;
+ mts_wchar_t lower;
+ mts_wchar_t upper;
+};
+
+struct unicode_cp a_unicode[] = {
+ { 0x0000, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0001, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0002, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0003, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0004, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0005, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0006, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0007, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0008, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0009, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0010, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0011, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0012, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0013, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0014, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0015, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0016, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0017, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0018, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0019, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0020, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0021, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0022, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0023, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0024, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0025, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0026, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0027, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0028, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0029, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0030, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0031, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0032, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0033, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0034, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0035, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0036, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0037, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0038, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0039, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0040, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0041, CODEPAGE_ISUPPER, 0x0061, 0xFFFF },
+ { 0x0042, CODEPAGE_ISUPPER, 0x0062, 0xFFFF },
+ { 0x0043, CODEPAGE_ISUPPER, 0x0063, 0xFFFF },
+ { 0x0044, CODEPAGE_ISUPPER, 0x0064, 0xFFFF },
+ { 0x0045, CODEPAGE_ISUPPER, 0x0065, 0xFFFF },
+ { 0x0046, CODEPAGE_ISUPPER, 0x0066, 0xFFFF },
+ { 0x0047, CODEPAGE_ISUPPER, 0x0067, 0xFFFF },
+ { 0x0048, CODEPAGE_ISUPPER, 0x0068, 0xFFFF },
+ { 0x0049, CODEPAGE_ISUPPER, 0x0069, 0xFFFF },
+ { 0x004A, CODEPAGE_ISUPPER, 0x006A, 0xFFFF },
+ { 0x004B, CODEPAGE_ISUPPER, 0x006B, 0xFFFF },
+ { 0x004C, CODEPAGE_ISUPPER, 0x006C, 0xFFFF },
+ { 0x004D, CODEPAGE_ISUPPER, 0x006D, 0xFFFF },
+ { 0x004E, CODEPAGE_ISUPPER, 0x006E, 0xFFFF },
+ { 0x004F, CODEPAGE_ISUPPER, 0x006F, 0xFFFF },
+ { 0x0050, CODEPAGE_ISUPPER, 0x0070, 0xFFFF },
+ { 0x0051, CODEPAGE_ISUPPER, 0x0071, 0xFFFF },
+ { 0x0052, CODEPAGE_ISUPPER, 0x0072, 0xFFFF },
+ { 0x0053, CODEPAGE_ISUPPER, 0x0073, 0xFFFF },
+ { 0x0054, CODEPAGE_ISUPPER, 0x0074, 0xFFFF },
+ { 0x0055, CODEPAGE_ISUPPER, 0x0075, 0xFFFF },
+ { 0x0056, CODEPAGE_ISUPPER, 0x0076, 0xFFFF },
+ { 0x0057, CODEPAGE_ISUPPER, 0x0077, 0xFFFF },
+ { 0x0058, CODEPAGE_ISUPPER, 0x0078, 0xFFFF },
+ { 0x0059, CODEPAGE_ISUPPER, 0x0079, 0xFFFF },
+ { 0x005A, CODEPAGE_ISUPPER, 0x007A, 0xFFFF },
+ { 0x005B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x005C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x005D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x005E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x005F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0060, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0061, CODEPAGE_ISLOWER, 0xFFFF, 0x0041 },
+ { 0x0062, CODEPAGE_ISLOWER, 0xFFFF, 0x0042 },
+ { 0x0063, CODEPAGE_ISLOWER, 0xFFFF, 0x0043 },
+ { 0x0064, CODEPAGE_ISLOWER, 0xFFFF, 0x0044 },
+ { 0x0065, CODEPAGE_ISLOWER, 0xFFFF, 0x0045 },
+ { 0x0066, CODEPAGE_ISLOWER, 0xFFFF, 0x0046 },
+ { 0x0067, CODEPAGE_ISLOWER, 0xFFFF, 0x0047 },
+ { 0x0068, CODEPAGE_ISLOWER, 0xFFFF, 0x0048 },
+ { 0x0069, CODEPAGE_ISLOWER, 0xFFFF, 0x0049 },
+ { 0x006A, CODEPAGE_ISLOWER, 0xFFFF, 0x004A },
+ { 0x006B, CODEPAGE_ISLOWER, 0xFFFF, 0x004B },
+ { 0x006C, CODEPAGE_ISLOWER, 0xFFFF, 0x004C },
+ { 0x006D, CODEPAGE_ISLOWER, 0xFFFF, 0x004D },
+ { 0x006E, CODEPAGE_ISLOWER, 0xFFFF, 0x004E },
+ { 0x006F, CODEPAGE_ISLOWER, 0xFFFF, 0x004F },
+ { 0x0070, CODEPAGE_ISLOWER, 0xFFFF, 0x0050 },
+ { 0x0071, CODEPAGE_ISLOWER, 0xFFFF, 0x0051 },
+ { 0x0072, CODEPAGE_ISLOWER, 0xFFFF, 0x0052 },
+ { 0x0073, CODEPAGE_ISLOWER, 0xFFFF, 0x0053 },
+ { 0x0074, CODEPAGE_ISLOWER, 0xFFFF, 0x0054 },
+ { 0x0075, CODEPAGE_ISLOWER, 0xFFFF, 0x0055 },
+ { 0x0076, CODEPAGE_ISLOWER, 0xFFFF, 0x0056 },
+ { 0x0077, CODEPAGE_ISLOWER, 0xFFFF, 0x0057 },
+ { 0x0078, CODEPAGE_ISLOWER, 0xFFFF, 0x0058 },
+ { 0x0079, CODEPAGE_ISLOWER, 0xFFFF, 0x0059 },
+ { 0x007A, CODEPAGE_ISLOWER, 0xFFFF, 0x005A },
+ { 0x007B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x007C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x007D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x007E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x007F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0080, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0081, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0082, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0083, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0084, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0085, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0086, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0087, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0088, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0089, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0090, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0091, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0092, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0093, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0094, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0095, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0096, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0097, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0098, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0099, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x00AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x00B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x00BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00C0, CODEPAGE_ISUPPER, 0x00E0, 0xFFFF },
+ { 0x00C1, CODEPAGE_ISUPPER, 0x00E1, 0xFFFF },
+ { 0x00C2, CODEPAGE_ISUPPER, 0x00E2, 0xFFFF },
+ { 0x00C3, CODEPAGE_ISUPPER, 0x00E3, 0xFFFF },
+ { 0x00C4, CODEPAGE_ISUPPER, 0x00E4, 0xFFFF },
+ { 0x00C5, CODEPAGE_ISUPPER, 0x00E5, 0xFFFF },
+ { 0x00C6, CODEPAGE_ISUPPER, 0x00E6, 0xFFFF },
+ { 0x00C7, CODEPAGE_ISUPPER, 0x00E7, 0xFFFF },
+ { 0x00C8, CODEPAGE_ISUPPER, 0x00E8, 0xFFFF },
+ { 0x00C9, CODEPAGE_ISUPPER, 0x00E9, 0xFFFF },
+ { 0x00CA, CODEPAGE_ISUPPER, 0x00EA, 0xFFFF },
+ { 0x00CB, CODEPAGE_ISUPPER, 0x00EB, 0xFFFF },
+ { 0x00CC, CODEPAGE_ISUPPER, 0x00EC, 0xFFFF },
+ { 0x00CD, CODEPAGE_ISUPPER, 0x00ED, 0xFFFF },
+ { 0x00CE, CODEPAGE_ISUPPER, 0x00EE, 0xFFFF },
+ { 0x00CF, CODEPAGE_ISUPPER, 0x00EF, 0xFFFF },
+ { 0x00D0, CODEPAGE_ISUPPER, 0x00F0, 0xFFFF },
+ { 0x00D1, CODEPAGE_ISUPPER, 0x00F1, 0xFFFF },
+ { 0x00D2, CODEPAGE_ISUPPER, 0x00F2, 0xFFFF },
+ { 0x00D3, CODEPAGE_ISUPPER, 0x00F3, 0xFFFF },
+ { 0x00D4, CODEPAGE_ISUPPER, 0x00F4, 0xFFFF },
+ { 0x00D5, CODEPAGE_ISUPPER, 0x00F5, 0xFFFF },
+ { 0x00D6, CODEPAGE_ISUPPER, 0x00F6, 0xFFFF },
+ { 0x00D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00D8, CODEPAGE_ISUPPER, 0x00F8, 0xFFFF },
+ { 0x00D9, CODEPAGE_ISUPPER, 0x00F9, 0xFFFF },
+ { 0x00DA, CODEPAGE_ISUPPER, 0x00FA, 0xFFFF },
+ { 0x00DB, CODEPAGE_ISUPPER, 0x00FB, 0xFFFF },
+ { 0x00DC, CODEPAGE_ISUPPER, 0x00FC, 0xFFFF },
+ { 0x00DD, CODEPAGE_ISUPPER, 0x00FD, 0xFFFF },
+ { 0x00DE, CODEPAGE_ISUPPER, 0x00FE, 0xFFFF },
+ { 0x00DF, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x00E0, CODEPAGE_ISLOWER, 0xFFFF, 0x00C0 },
+ { 0x00E1, CODEPAGE_ISLOWER, 0xFFFF, 0x00C1 },
+ { 0x00E2, CODEPAGE_ISLOWER, 0xFFFF, 0x00C2 },
+ { 0x00E3, CODEPAGE_ISLOWER, 0xFFFF, 0x00C3 },
+ { 0x00E4, CODEPAGE_ISLOWER, 0xFFFF, 0x00C4 },
+ { 0x00E5, CODEPAGE_ISLOWER, 0xFFFF, 0x00C5 },
+ { 0x00E6, CODEPAGE_ISLOWER, 0xFFFF, 0x00C6 },
+ { 0x00E7, CODEPAGE_ISLOWER, 0xFFFF, 0x00C7 },
+ { 0x00E8, CODEPAGE_ISLOWER, 0xFFFF, 0x00C8 },
+ { 0x00E9, CODEPAGE_ISLOWER, 0xFFFF, 0x00C9 },
+ { 0x00EA, CODEPAGE_ISLOWER, 0xFFFF, 0x00CA },
+ { 0x00EB, CODEPAGE_ISLOWER, 0xFFFF, 0x00CB },
+ { 0x00EC, CODEPAGE_ISLOWER, 0xFFFF, 0x00CC },
+ { 0x00ED, CODEPAGE_ISLOWER, 0xFFFF, 0x00CD },
+ { 0x00EE, CODEPAGE_ISLOWER, 0xFFFF, 0x00CE },
+ { 0x00EF, CODEPAGE_ISLOWER, 0xFFFF, 0x00CF },
+ { 0x00F0, CODEPAGE_ISLOWER, 0xFFFF, 0x00D0 },
+ { 0x00F1, CODEPAGE_ISLOWER, 0xFFFF, 0x00D1 },
+ { 0x00F2, CODEPAGE_ISLOWER, 0xFFFF, 0x00D2 },
+ { 0x00F3, CODEPAGE_ISLOWER, 0xFFFF, 0x00D3 },
+ { 0x00F4, CODEPAGE_ISLOWER, 0xFFFF, 0x00D4 },
+ { 0x00F5, CODEPAGE_ISLOWER, 0xFFFF, 0x00D5 },
+ { 0x00F6, CODEPAGE_ISLOWER, 0xFFFF, 0x00D6 },
+ { 0x00F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00F8, CODEPAGE_ISLOWER, 0xFFFF, 0x00D8 },
+ { 0x00F9, CODEPAGE_ISLOWER, 0xFFFF, 0x00D9 },
+ { 0x00FA, CODEPAGE_ISLOWER, 0xFFFF, 0x00DA },
+ { 0x00FB, CODEPAGE_ISLOWER, 0xFFFF, 0x00DB },
+ { 0x00FC, CODEPAGE_ISLOWER, 0xFFFF, 0x00DC },
+ { 0x00FD, CODEPAGE_ISLOWER, 0xFFFF, 0x00DD },
+ { 0x00FE, CODEPAGE_ISLOWER, 0xFFFF, 0x00DE },
+ { 0x00FF, CODEPAGE_ISLOWER, 0xFFFF, 0x0178 },
+ { 0x0100, CODEPAGE_ISUPPER, 0x0101, 0xFFFF },
+ { 0x0101, CODEPAGE_ISLOWER, 0xFFFF, 0x0100 },
+ { 0x0102, CODEPAGE_ISUPPER, 0x0103, 0xFFFF },
+ { 0x0103, CODEPAGE_ISLOWER, 0xFFFF, 0x0102 },
+ { 0x0104, CODEPAGE_ISUPPER, 0x0105, 0xFFFF },
+ { 0x0105, CODEPAGE_ISLOWER, 0xFFFF, 0x0104 },
+ { 0x0106, CODEPAGE_ISUPPER, 0x0107, 0xFFFF },
+ { 0x0107, CODEPAGE_ISLOWER, 0xFFFF, 0x0106 },
+ { 0x0108, CODEPAGE_ISUPPER, 0x0109, 0xFFFF },
+ { 0x0109, CODEPAGE_ISLOWER, 0xFFFF, 0x0108 },
+ { 0x010A, CODEPAGE_ISUPPER, 0x010B, 0xFFFF },
+ { 0x010B, CODEPAGE_ISLOWER, 0xFFFF, 0x010A },
+ { 0x010C, CODEPAGE_ISUPPER, 0x010D, 0xFFFF },
+ { 0x010D, CODEPAGE_ISLOWER, 0xFFFF, 0x010C },
+ { 0x010E, CODEPAGE_ISUPPER, 0x010F, 0xFFFF },
+ { 0x010F, CODEPAGE_ISLOWER, 0xFFFF, 0x010E },
+ { 0x0110, CODEPAGE_ISUPPER, 0x0111, 0xFFFF },
+ { 0x0111, CODEPAGE_ISLOWER, 0xFFFF, 0x0110 },
+ { 0x0112, CODEPAGE_ISUPPER, 0x0113, 0xFFFF },
+ { 0x0113, CODEPAGE_ISLOWER, 0xFFFF, 0x0112 },
+ { 0x0114, CODEPAGE_ISUPPER, 0x0115, 0xFFFF },
+ { 0x0115, CODEPAGE_ISLOWER, 0xFFFF, 0x0114 },
+ { 0x0116, CODEPAGE_ISUPPER, 0x0117, 0xFFFF },
+ { 0x0117, CODEPAGE_ISLOWER, 0xFFFF, 0x0116 },
+ { 0x0118, CODEPAGE_ISUPPER, 0x0119, 0xFFFF },
+ { 0x0119, CODEPAGE_ISLOWER, 0xFFFF, 0x0118 },
+ { 0x011A, CODEPAGE_ISUPPER, 0x011B, 0xFFFF },
+ { 0x011B, CODEPAGE_ISLOWER, 0xFFFF, 0x011A },
+ { 0x011C, CODEPAGE_ISUPPER, 0x011D, 0xFFFF },
+ { 0x011D, CODEPAGE_ISLOWER, 0xFFFF, 0x011C },
+ { 0x011E, CODEPAGE_ISUPPER, 0x011F, 0xFFFF },
+ { 0x011F, CODEPAGE_ISLOWER, 0xFFFF, 0x011E },
+ { 0x0120, CODEPAGE_ISUPPER, 0x0121, 0xFFFF },
+ { 0x0121, CODEPAGE_ISLOWER, 0xFFFF, 0x0120 },
+ { 0x0122, CODEPAGE_ISUPPER, 0x0123, 0xFFFF },
+ { 0x0123, CODEPAGE_ISLOWER, 0xFFFF, 0x0122 },
+ { 0x0124, CODEPAGE_ISUPPER, 0x0125, 0xFFFF },
+ { 0x0125, CODEPAGE_ISLOWER, 0xFFFF, 0x0124 },
+ { 0x0126, CODEPAGE_ISUPPER, 0x0127, 0xFFFF },
+ { 0x0127, CODEPAGE_ISLOWER, 0xFFFF, 0x0126 },
+ { 0x0128, CODEPAGE_ISUPPER, 0x0129, 0xFFFF },
+ { 0x0129, CODEPAGE_ISLOWER, 0xFFFF, 0x0128 },
+ { 0x012A, CODEPAGE_ISUPPER, 0x012B, 0xFFFF },
+ { 0x012B, CODEPAGE_ISLOWER, 0xFFFF, 0x012A },
+ { 0x012C, CODEPAGE_ISUPPER, 0x012D, 0xFFFF },
+ { 0x012D, CODEPAGE_ISLOWER, 0xFFFF, 0x012C },
+ { 0x012E, CODEPAGE_ISUPPER, 0x012F, 0xFFFF },
+ { 0x012F, CODEPAGE_ISLOWER, 0xFFFF, 0x012E },
+ { 0x0130, CODEPAGE_ISUPPER, 0x0069, 0xFFFF },
+ { 0x0131, CODEPAGE_ISLOWER, 0xFFFF, 0x0049 },
+ { 0x0132, CODEPAGE_ISUPPER, 0x0133, 0xFFFF },
+ { 0x0133, CODEPAGE_ISLOWER, 0xFFFF, 0x0132 },
+ { 0x0134, CODEPAGE_ISUPPER, 0x0135, 0xFFFF },
+ { 0x0135, CODEPAGE_ISLOWER, 0xFFFF, 0x0134 },
+ { 0x0136, CODEPAGE_ISUPPER, 0x0137, 0xFFFF },
+ { 0x0137, CODEPAGE_ISLOWER, 0xFFFF, 0x0136 },
+ { 0x0138, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0139, CODEPAGE_ISUPPER, 0x013A, 0xFFFF },
+ { 0x013A, CODEPAGE_ISLOWER, 0xFFFF, 0x0139 },
+ { 0x013B, CODEPAGE_ISUPPER, 0x013C, 0xFFFF },
+ { 0x013C, CODEPAGE_ISLOWER, 0xFFFF, 0x013B },
+ { 0x013D, CODEPAGE_ISUPPER, 0x013E, 0xFFFF },
+ { 0x013E, CODEPAGE_ISLOWER, 0xFFFF, 0x013D },
+ { 0x013F, CODEPAGE_ISUPPER, 0x0140, 0xFFFF },
+ { 0x0140, CODEPAGE_ISLOWER, 0xFFFF, 0x013F },
+ { 0x0141, CODEPAGE_ISUPPER, 0x0142, 0xFFFF },
+ { 0x0142, CODEPAGE_ISLOWER, 0xFFFF, 0x0141 },
+ { 0x0143, CODEPAGE_ISUPPER, 0x0144, 0xFFFF },
+ { 0x0144, CODEPAGE_ISLOWER, 0xFFFF, 0x0143 },
+ { 0x0145, CODEPAGE_ISUPPER, 0x0146, 0xFFFF },
+ { 0x0146, CODEPAGE_ISLOWER, 0xFFFF, 0x0145 },
+ { 0x0147, CODEPAGE_ISUPPER, 0x0148, 0xFFFF },
+ { 0x0148, CODEPAGE_ISLOWER, 0xFFFF, 0x0147 },
+ { 0x0149, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x014A, CODEPAGE_ISUPPER, 0x014B, 0xFFFF },
+ { 0x014B, CODEPAGE_ISLOWER, 0xFFFF, 0x014A },
+ { 0x014C, CODEPAGE_ISUPPER, 0x014D, 0xFFFF },
+ { 0x014D, CODEPAGE_ISLOWER, 0xFFFF, 0x014C },
+ { 0x014E, CODEPAGE_ISUPPER, 0x014F, 0xFFFF },
+ { 0x014F, CODEPAGE_ISLOWER, 0xFFFF, 0x014E },
+ { 0x0150, CODEPAGE_ISUPPER, 0x0151, 0xFFFF },
+ { 0x0151, CODEPAGE_ISLOWER, 0xFFFF, 0x0150 },
+ { 0x0152, CODEPAGE_ISUPPER, 0x0153, 0xFFFF },
+ { 0x0153, CODEPAGE_ISLOWER, 0xFFFF, 0x0152 },
+ { 0x0154, CODEPAGE_ISUPPER, 0x0155, 0xFFFF },
+ { 0x0155, CODEPAGE_ISLOWER, 0xFFFF, 0x0154 },
+ { 0x0156, CODEPAGE_ISUPPER, 0x0157, 0xFFFF },
+ { 0x0157, CODEPAGE_ISLOWER, 0xFFFF, 0x0156 },
+ { 0x0158, CODEPAGE_ISUPPER, 0x0159, 0xFFFF },
+ { 0x0159, CODEPAGE_ISLOWER, 0xFFFF, 0x0158 },
+ { 0x015A, CODEPAGE_ISUPPER, 0x015B, 0xFFFF },
+ { 0x015B, CODEPAGE_ISLOWER, 0xFFFF, 0x015A },
+ { 0x015C, CODEPAGE_ISUPPER, 0x015D, 0xFFFF },
+ { 0x015D, CODEPAGE_ISLOWER, 0xFFFF, 0x015C },
+ { 0x015E, CODEPAGE_ISUPPER, 0x015F, 0xFFFF },
+ { 0x015F, CODEPAGE_ISLOWER, 0xFFFF, 0x015E },
+ { 0x0160, CODEPAGE_ISUPPER, 0x0161, 0xFFFF },
+ { 0x0161, CODEPAGE_ISLOWER, 0xFFFF, 0x0160 },
+ { 0x0162, CODEPAGE_ISUPPER, 0x0163, 0xFFFF },
+ { 0x0163, CODEPAGE_ISLOWER, 0xFFFF, 0x0162 },
+ { 0x0164, CODEPAGE_ISUPPER, 0x0165, 0xFFFF },
+ { 0x0165, CODEPAGE_ISLOWER, 0xFFFF, 0x0164 },
+ { 0x0166, CODEPAGE_ISUPPER, 0x0167, 0xFFFF },
+ { 0x0167, CODEPAGE_ISLOWER, 0xFFFF, 0x0166 },
+ { 0x0168, CODEPAGE_ISUPPER, 0x0169, 0xFFFF },
+ { 0x0169, CODEPAGE_ISLOWER, 0xFFFF, 0x0168 },
+ { 0x016A, CODEPAGE_ISUPPER, 0x016B, 0xFFFF },
+ { 0x016B, CODEPAGE_ISLOWER, 0xFFFF, 0x016A },
+ { 0x016C, CODEPAGE_ISUPPER, 0x016D, 0xFFFF },
+ { 0x016D, CODEPAGE_ISLOWER, 0xFFFF, 0x016C },
+ { 0x016E, CODEPAGE_ISUPPER, 0x016F, 0xFFFF },
+ { 0x016F, CODEPAGE_ISLOWER, 0xFFFF, 0x016E },
+ { 0x0170, CODEPAGE_ISUPPER, 0x0171, 0xFFFF },
+ { 0x0171, CODEPAGE_ISLOWER, 0xFFFF, 0x0170 },
+ { 0x0172, CODEPAGE_ISUPPER, 0x0173, 0xFFFF },
+ { 0x0173, CODEPAGE_ISLOWER, 0xFFFF, 0x0172 },
+ { 0x0174, CODEPAGE_ISUPPER, 0x0175, 0xFFFF },
+ { 0x0175, CODEPAGE_ISLOWER, 0xFFFF, 0x0174 },
+ { 0x0176, CODEPAGE_ISUPPER, 0x0177, 0xFFFF },
+ { 0x0177, CODEPAGE_ISLOWER, 0xFFFF, 0x0176 },
+ { 0x0178, CODEPAGE_ISUPPER, 0x00FF, 0xFFFF },
+ { 0x0179, CODEPAGE_ISUPPER, 0x017A, 0xFFFF },
+ { 0x017A, CODEPAGE_ISLOWER, 0xFFFF, 0x0179 },
+ { 0x017B, CODEPAGE_ISUPPER, 0x017C, 0xFFFF },
+ { 0x017C, CODEPAGE_ISLOWER, 0xFFFF, 0x017B },
+ { 0x017D, CODEPAGE_ISUPPER, 0x017E, 0xFFFF },
+ { 0x017E, CODEPAGE_ISLOWER, 0xFFFF, 0x017D },
+ { 0x017F, CODEPAGE_ISLOWER, 0xFFFF, 0x0053 },
+ { 0x0180, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0181, CODEPAGE_ISUPPER, 0x0253, 0xFFFF },
+ { 0x0182, CODEPAGE_ISUPPER, 0x0183, 0xFFFF },
+ { 0x0183, CODEPAGE_ISLOWER, 0xFFFF, 0x0182 },
+ { 0x0184, CODEPAGE_ISUPPER, 0x0185, 0xFFFF },
+ { 0x0185, CODEPAGE_ISLOWER, 0xFFFF, 0x0184 },
+ { 0x0186, CODEPAGE_ISUPPER, 0x0254, 0xFFFF },
+ { 0x0187, CODEPAGE_ISUPPER, 0x0188, 0xFFFF },
+ { 0x0188, CODEPAGE_ISLOWER, 0xFFFF, 0x0187 },
+ { 0x0189, CODEPAGE_ISUPPER, 0x0256, 0xFFFF },
+ { 0x018A, CODEPAGE_ISUPPER, 0x0257, 0xFFFF },
+ { 0x018B, CODEPAGE_ISUPPER, 0x018C, 0xFFFF },
+ { 0x018C, CODEPAGE_ISLOWER, 0xFFFF, 0x018B },
+ { 0x018D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x018E, CODEPAGE_ISUPPER, 0x0258, 0xFFFF },
+ { 0x018F, CODEPAGE_ISUPPER, 0x0259, 0xFFFF },
+ { 0x0190, CODEPAGE_ISUPPER, 0x025B, 0xFFFF },
+ { 0x0191, CODEPAGE_ISUPPER, 0x0192, 0xFFFF },
+ { 0x0192, CODEPAGE_ISLOWER, 0xFFFF, 0x0191 },
+ { 0x0193, CODEPAGE_ISUPPER, 0x0260, 0xFFFF },
+ { 0x0194, CODEPAGE_ISUPPER, 0x0263, 0xFFFF },
+ { 0x0195, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0196, CODEPAGE_ISUPPER, 0x0269, 0xFFFF },
+ { 0x0197, CODEPAGE_ISUPPER, 0x0268, 0xFFFF },
+ { 0x0198, CODEPAGE_ISUPPER, 0x0199, 0xFFFF },
+ { 0x0199, CODEPAGE_ISLOWER, 0xFFFF, 0x0198 },
+ { 0x019A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x019B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x019C, CODEPAGE_ISUPPER, 0x026F, 0xFFFF },
+ { 0x019D, CODEPAGE_ISUPPER, 0x0272, 0xFFFF },
+ { 0x019E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x019F, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x01A0, CODEPAGE_ISUPPER, 0x01A1, 0xFFFF },
+ { 0x01A1, CODEPAGE_ISLOWER, 0xFFFF, 0x01A0 },
+ { 0x01A2, CODEPAGE_ISUPPER, 0x01A3, 0xFFFF },
+ { 0x01A3, CODEPAGE_ISLOWER, 0xFFFF, 0x01A2 },
+ { 0x01A4, CODEPAGE_ISUPPER, 0x01A5, 0xFFFF },
+ { 0x01A5, CODEPAGE_ISLOWER, 0xFFFF, 0x01A4 },
+ { 0x01A6, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x01A7, CODEPAGE_ISUPPER, 0x01A8, 0xFFFF },
+ { 0x01A8, CODEPAGE_ISLOWER, 0xFFFF, 0x01A7 },
+ { 0x01A9, CODEPAGE_ISUPPER, 0x0283, 0xFFFF },
+ { 0x01AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01AB, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x01AC, CODEPAGE_ISUPPER, 0x01AD, 0xFFFF },
+ { 0x01AD, CODEPAGE_ISLOWER, 0xFFFF, 0x01AC },
+ { 0x01AE, CODEPAGE_ISUPPER, 0x0288, 0xFFFF },
+ { 0x01AF, CODEPAGE_ISUPPER, 0x01B0, 0xFFFF },
+ { 0x01B0, CODEPAGE_ISLOWER, 0xFFFF, 0x01AF },
+ { 0x01B1, CODEPAGE_ISUPPER, 0x028A, 0xFFFF },
+ { 0x01B2, CODEPAGE_ISUPPER, 0x028B, 0xFFFF },
+ { 0x01B3, CODEPAGE_ISUPPER, 0x01B4, 0xFFFF },
+ { 0x01B4, CODEPAGE_ISLOWER, 0xFFFF, 0x01B3 },
+ { 0x01B5, CODEPAGE_ISUPPER, 0x01B6, 0xFFFF },
+ { 0x01B6, CODEPAGE_ISLOWER, 0xFFFF, 0x01B5 },
+ { 0x01B7, CODEPAGE_ISUPPER, 0x0292, 0xFFFF },
+ { 0x01B8, CODEPAGE_ISUPPER, 0x01B9, 0xFFFF },
+ { 0x01B9, CODEPAGE_ISLOWER, 0xFFFF, 0x01B8 },
+ { 0x01BA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x01BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01BC, CODEPAGE_ISUPPER, 0x01BD, 0xFFFF },
+ { 0x01BD, CODEPAGE_ISLOWER, 0xFFFF, 0x01BC },
+ { 0x01BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C4, CODEPAGE_ISUPPER, 0x01C6, 0x01C5 },
+ { 0x01C5, CODEPAGE_ISNONE, 0x01C6, 0xFFFF },
+ { 0x01C6, CODEPAGE_ISLOWER, 0xFFFF, 0x01C5 },
+ { 0x01C7, CODEPAGE_ISUPPER, 0x01C9, 0x01C8 },
+ { 0x01C8, CODEPAGE_ISNONE, 0x01C9, 0xFFFF },
+ { 0x01C9, CODEPAGE_ISLOWER, 0xFFFF, 0x01C8 },
+ { 0x01CA, CODEPAGE_ISUPPER, 0x01CC, 0x01CB },
+ { 0x01CB, CODEPAGE_ISNONE, 0x01CC, 0xFFFF },
+ { 0x01CC, CODEPAGE_ISLOWER, 0xFFFF, 0x01CB },
+ { 0x01CD, CODEPAGE_ISUPPER, 0x01CE, 0xFFFF },
+ { 0x01CE, CODEPAGE_ISLOWER, 0xFFFF, 0x01CD },
+ { 0x01CF, CODEPAGE_ISUPPER, 0x01D0, 0xFFFF },
+ { 0x01D0, CODEPAGE_ISLOWER, 0xFFFF, 0x01CF },
+ { 0x01D1, CODEPAGE_ISUPPER, 0x01D2, 0xFFFF },
+ { 0x01D2, CODEPAGE_ISLOWER, 0xFFFF, 0x01D1 },
+ { 0x01D3, CODEPAGE_ISUPPER, 0x01D4, 0xFFFF },
+ { 0x01D4, CODEPAGE_ISLOWER, 0xFFFF, 0x01D3 },
+ { 0x01D5, CODEPAGE_ISUPPER, 0x01D6, 0xFFFF },
+ { 0x01D6, CODEPAGE_ISLOWER, 0xFFFF, 0x01D5 },
+ { 0x01D7, CODEPAGE_ISUPPER, 0x01D8, 0xFFFF },
+ { 0x01D8, CODEPAGE_ISLOWER, 0xFFFF, 0x01D7 },
+ { 0x01D9, CODEPAGE_ISUPPER, 0x01DA, 0xFFFF },
+ { 0x01DA, CODEPAGE_ISLOWER, 0xFFFF, 0x01D9 },
+ { 0x01DB, CODEPAGE_ISUPPER, 0x01DC, 0xFFFF },
+ { 0x01DC, CODEPAGE_ISLOWER, 0xFFFF, 0x01DB },
+ { 0x01DD, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x01DE, CODEPAGE_ISUPPER, 0x01DF, 0xFFFF },
+ { 0x01DF, CODEPAGE_ISLOWER, 0xFFFF, 0x01DE },
+ { 0x01E0, CODEPAGE_ISUPPER, 0x01E1, 0xFFFF },
+ { 0x01E1, CODEPAGE_ISLOWER, 0xFFFF, 0x01E0 },
+ { 0x01E2, CODEPAGE_ISUPPER, 0x01E3, 0xFFFF },
+ { 0x01E3, CODEPAGE_ISLOWER, 0xFFFF, 0x01E2 },
+ { 0x01E4, CODEPAGE_ISUPPER, 0x01E5, 0xFFFF },
+ { 0x01E5, CODEPAGE_ISLOWER, 0xFFFF, 0x01E4 },
+ { 0x01E6, CODEPAGE_ISUPPER, 0x01E7, 0xFFFF },
+ { 0x01E7, CODEPAGE_ISLOWER, 0xFFFF, 0x01E6 },
+ { 0x01E8, CODEPAGE_ISUPPER, 0x01E9, 0xFFFF },
+ { 0x01E9, CODEPAGE_ISLOWER, 0xFFFF, 0x01E8 },
+ { 0x01EA, CODEPAGE_ISUPPER, 0x01EB, 0xFFFF },
+ { 0x01EB, CODEPAGE_ISLOWER, 0xFFFF, 0x01EA },
+ { 0x01EC, CODEPAGE_ISUPPER, 0x01ED, 0xFFFF },
+ { 0x01ED, CODEPAGE_ISLOWER, 0xFFFF, 0x01EC },
+ { 0x01EE, CODEPAGE_ISUPPER, 0x01EF, 0xFFFF },
+ { 0x01EF, CODEPAGE_ISLOWER, 0xFFFF, 0x01EE },
+ { 0x01F0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x01F1, CODEPAGE_ISUPPER, 0x01F3, 0x01F2 },
+ { 0x01F2, CODEPAGE_ISNONE, 0x01F3, 0xFFFF },
+ { 0x01F3, CODEPAGE_ISLOWER, 0xFFFF, 0x01F2 },
+ { 0x01F4, CODEPAGE_ISUPPER, 0x01F5, 0xFFFF },
+ { 0x01F5, CODEPAGE_ISLOWER, 0xFFFF, 0x01F4 },
+ { 0x01FA, CODEPAGE_ISUPPER, 0x01FB, 0xFFFF },
+ { 0x01FB, CODEPAGE_ISLOWER, 0xFFFF, 0x01FA },
+ { 0x01FC, CODEPAGE_ISUPPER, 0x01FD, 0xFFFF },
+ { 0x01FD, CODEPAGE_ISLOWER, 0xFFFF, 0x01FC },
+ { 0x01FE, CODEPAGE_ISUPPER, 0x01FF, 0xFFFF },
+ { 0x01FF, CODEPAGE_ISLOWER, 0xFFFF, 0x01FE },
+ { 0x0200, CODEPAGE_ISUPPER, 0x0201, 0xFFFF },
+ { 0x0201, CODEPAGE_ISLOWER, 0xFFFF, 0x0200 },
+ { 0x0202, CODEPAGE_ISUPPER, 0x0203, 0xFFFF },
+ { 0x0203, CODEPAGE_ISLOWER, 0xFFFF, 0x0202 },
+ { 0x0204, CODEPAGE_ISUPPER, 0x0205, 0xFFFF },
+ { 0x0205, CODEPAGE_ISLOWER, 0xFFFF, 0x0204 },
+ { 0x0206, CODEPAGE_ISUPPER, 0x0207, 0xFFFF },
+ { 0x0207, CODEPAGE_ISLOWER, 0xFFFF, 0x0206 },
+ { 0x0208, CODEPAGE_ISUPPER, 0x0209, 0xFFFF },
+ { 0x0209, CODEPAGE_ISLOWER, 0xFFFF, 0x0208 },
+ { 0x020A, CODEPAGE_ISUPPER, 0x020B, 0xFFFF },
+ { 0x020B, CODEPAGE_ISLOWER, 0xFFFF, 0x020A },
+ { 0x020C, CODEPAGE_ISUPPER, 0x020D, 0xFFFF },
+ { 0x020D, CODEPAGE_ISLOWER, 0xFFFF, 0x020C },
+ { 0x020E, CODEPAGE_ISUPPER, 0x020F, 0xFFFF },
+ { 0x020F, CODEPAGE_ISLOWER, 0xFFFF, 0x020E },
+ { 0x0210, CODEPAGE_ISUPPER, 0x0211, 0xFFFF },
+ { 0x0211, CODEPAGE_ISLOWER, 0xFFFF, 0x0210 },
+ { 0x0212, CODEPAGE_ISUPPER, 0x0213, 0xFFFF },
+ { 0x0213, CODEPAGE_ISLOWER, 0xFFFF, 0x0212 },
+ { 0x0214, CODEPAGE_ISUPPER, 0x0215, 0xFFFF },
+ { 0x0215, CODEPAGE_ISLOWER, 0xFFFF, 0x0214 },
+ { 0x0216, CODEPAGE_ISUPPER, 0x0217, 0xFFFF },
+ { 0x0217, CODEPAGE_ISLOWER, 0xFFFF, 0x0216 },
+ { 0x0250, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0251, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0252, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0253, CODEPAGE_ISLOWER, 0xFFFF, 0x0181 },
+ { 0x0254, CODEPAGE_ISLOWER, 0xFFFF, 0x0186 },
+ { 0x0255, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0256, CODEPAGE_ISLOWER, 0xFFFF, 0x0189 },
+ { 0x0257, CODEPAGE_ISLOWER, 0xFFFF, 0x018A },
+ { 0x0258, CODEPAGE_ISLOWER, 0xFFFF, 0x018E },
+ { 0x0259, CODEPAGE_ISLOWER, 0xFFFF, 0x018F },
+ { 0x025A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x025B, CODEPAGE_ISLOWER, 0xFFFF, 0x0190 },
+ { 0x025C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x025D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x025E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x025F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0260, CODEPAGE_ISLOWER, 0xFFFF, 0x0193 },
+ { 0x0261, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0262, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0263, CODEPAGE_ISLOWER, 0xFFFF, 0x0194 },
+ { 0x0264, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0265, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0266, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0267, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0268, CODEPAGE_ISLOWER, 0xFFFF, 0x0197 },
+ { 0x0269, CODEPAGE_ISLOWER, 0xFFFF, 0x0196 },
+ { 0x026A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026F, CODEPAGE_ISLOWER, 0xFFFF, 0x019C },
+ { 0x0270, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0271, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0272, CODEPAGE_ISLOWER, 0xFFFF, 0x019D },
+ { 0x0273, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0274, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0275, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0276, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0277, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0278, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0279, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0280, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0281, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0282, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0283, CODEPAGE_ISLOWER, 0xFFFF, 0x01A9 },
+ { 0x0284, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0285, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0286, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0287, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0288, CODEPAGE_ISLOWER, 0xFFFF, 0x01AE },
+ { 0x0289, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x028A, CODEPAGE_ISLOWER, 0xFFFF, 0x01B1 },
+ { 0x028B, CODEPAGE_ISLOWER, 0xFFFF, 0x01B2 },
+ { 0x028C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x028D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x028E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x028F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0290, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0291, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0292, CODEPAGE_ISLOWER, 0xFFFF, 0x01B7 },
+ { 0x0293, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0294, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0295, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0296, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0297, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0298, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0299, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A8, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0300, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0301, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0302, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0303, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0304, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0305, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0306, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0307, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0308, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0309, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0310, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0311, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0312, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0313, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0314, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0315, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0316, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0317, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0318, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0319, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0320, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0321, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0322, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0323, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0324, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0325, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0326, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0327, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0328, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0329, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0330, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0331, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0332, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0333, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0334, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0335, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0336, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0337, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0338, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0339, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0340, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0341, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0342, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0343, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0344, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0345, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0360, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0361, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0374, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0375, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x037A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x037E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0384, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0385, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0386, CODEPAGE_ISUPPER, 0x03AC, 0xFFFF },
+ { 0x0387, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0388, CODEPAGE_ISUPPER, 0x03AD, 0xFFFF },
+ { 0x0389, CODEPAGE_ISUPPER, 0x03AE, 0xFFFF },
+ { 0x038A, CODEPAGE_ISUPPER, 0x03AF, 0xFFFF },
+ { 0x038C, CODEPAGE_ISUPPER, 0x03CC, 0xFFFF },
+ { 0x038E, CODEPAGE_ISUPPER, 0x03CD, 0xFFFF },
+ { 0x038F, CODEPAGE_ISUPPER, 0x03CE, 0xFFFF },
+ { 0x0390, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0391, CODEPAGE_ISUPPER, 0x03B1, 0xFFFF },
+ { 0x0392, CODEPAGE_ISUPPER, 0x03B2, 0xFFFF },
+ { 0x0393, CODEPAGE_ISUPPER, 0x03B3, 0xFFFF },
+ { 0x0394, CODEPAGE_ISUPPER, 0x03B4, 0xFFFF },
+ { 0x0395, CODEPAGE_ISUPPER, 0x03B5, 0xFFFF },
+ { 0x0396, CODEPAGE_ISUPPER, 0x03B6, 0xFFFF },
+ { 0x0397, CODEPAGE_ISUPPER, 0x03B7, 0xFFFF },
+ { 0x0398, CODEPAGE_ISUPPER, 0x03B8, 0xFFFF },
+ { 0x0399, CODEPAGE_ISUPPER, 0x03B9, 0xFFFF },
+ { 0x039A, CODEPAGE_ISUPPER, 0x03BA, 0xFFFF },
+ { 0x039B, CODEPAGE_ISUPPER, 0x03BB, 0xFFFF },
+ { 0x039C, CODEPAGE_ISUPPER, 0x03BC, 0xFFFF },
+ { 0x039D, CODEPAGE_ISUPPER, 0x03BD, 0xFFFF },
+ { 0x039E, CODEPAGE_ISUPPER, 0x03BE, 0xFFFF },
+ { 0x039F, CODEPAGE_ISUPPER, 0x03BF, 0xFFFF },
+ { 0x03A0, CODEPAGE_ISUPPER, 0x03C0, 0xFFFF },
+ { 0x03A1, CODEPAGE_ISUPPER, 0x03C1, 0xFFFF },
+ { 0x03A3, CODEPAGE_ISUPPER, 0x03C3, 0xFFFF },
+ { 0x03A4, CODEPAGE_ISUPPER, 0x03C4, 0xFFFF },
+ { 0x03A5, CODEPAGE_ISUPPER, 0x03C5, 0xFFFF },
+ { 0x03A6, CODEPAGE_ISUPPER, 0x03C6, 0xFFFF },
+ { 0x03A7, CODEPAGE_ISUPPER, 0x03C7, 0xFFFF },
+ { 0x03A8, CODEPAGE_ISUPPER, 0x03C8, 0xFFFF },
+ { 0x03A9, CODEPAGE_ISUPPER, 0x03C9, 0xFFFF },
+ { 0x03AA, CODEPAGE_ISUPPER, 0x03CA, 0xFFFF },
+ { 0x03AB, CODEPAGE_ISUPPER, 0x03CB, 0xFFFF },
+ { 0x03AC, CODEPAGE_ISLOWER, 0xFFFF, 0x0386 },
+ { 0x03AD, CODEPAGE_ISLOWER, 0xFFFF, 0x0388 },
+ { 0x03AE, CODEPAGE_ISLOWER, 0xFFFF, 0x0389 },
+ { 0x03AF, CODEPAGE_ISLOWER, 0xFFFF, 0x038A },
+ { 0x03B0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03B1, CODEPAGE_ISLOWER, 0xFFFF, 0x0391 },
+ { 0x03B2, CODEPAGE_ISLOWER, 0xFFFF, 0x0392 },
+ { 0x03B3, CODEPAGE_ISLOWER, 0xFFFF, 0x0393 },
+ { 0x03B4, CODEPAGE_ISLOWER, 0xFFFF, 0x0394 },
+ { 0x03B5, CODEPAGE_ISLOWER, 0xFFFF, 0x0395 },
+ { 0x03B6, CODEPAGE_ISLOWER, 0xFFFF, 0x0396 },
+ { 0x03B7, CODEPAGE_ISLOWER, 0xFFFF, 0x0397 },
+ { 0x03B8, CODEPAGE_ISLOWER, 0xFFFF, 0x0398 },
+ { 0x03B9, CODEPAGE_ISLOWER, 0xFFFF, 0x0399 },
+ { 0x03BA, CODEPAGE_ISLOWER, 0xFFFF, 0x039A },
+ { 0x03BB, CODEPAGE_ISLOWER, 0xFFFF, 0x039B },
+ { 0x03BC, CODEPAGE_ISLOWER, 0xFFFF, 0x039C },
+ { 0x03BD, CODEPAGE_ISLOWER, 0xFFFF, 0x039D },
+ { 0x03BE, CODEPAGE_ISLOWER, 0xFFFF, 0x039E },
+ { 0x03BF, CODEPAGE_ISLOWER, 0xFFFF, 0x039F },
+ { 0x03C0, CODEPAGE_ISLOWER, 0xFFFF, 0x03A0 },
+ { 0x03C1, CODEPAGE_ISLOWER, 0xFFFF, 0x03A1 },
+ { 0x03C2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03C3, CODEPAGE_ISLOWER, 0xFFFF, 0x03A3 },
+ { 0x03C4, CODEPAGE_ISLOWER, 0xFFFF, 0x03A4 },
+ { 0x03C5, CODEPAGE_ISLOWER, 0xFFFF, 0x03A5 },
+ { 0x03C6, CODEPAGE_ISLOWER, 0xFFFF, 0x03A6 },
+ { 0x03C7, CODEPAGE_ISLOWER, 0xFFFF, 0x03A7 },
+ { 0x03C8, CODEPAGE_ISLOWER, 0xFFFF, 0x03A8 },
+ { 0x03C9, CODEPAGE_ISLOWER, 0xFFFF, 0x03A9 },
+ { 0x03CA, CODEPAGE_ISLOWER, 0xFFFF, 0x03AA },
+ { 0x03CB, CODEPAGE_ISLOWER, 0xFFFF, 0x03AB },
+ { 0x03CC, CODEPAGE_ISLOWER, 0xFFFF, 0x038C },
+ { 0x03CD, CODEPAGE_ISLOWER, 0xFFFF, 0x038E },
+ { 0x03CE, CODEPAGE_ISLOWER, 0xFFFF, 0x038F },
+ { 0x03D0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03D1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03D2, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03D3, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03D4, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03D5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03D6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03DA, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03DC, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03DE, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03E0, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03E2, CODEPAGE_ISUPPER, 0x03E3, 0xFFFF },
+ { 0x03E3, CODEPAGE_ISLOWER, 0xFFFF, 0x03E2 },
+ { 0x03E4, CODEPAGE_ISUPPER, 0x03E5, 0xFFFF },
+ { 0x03E5, CODEPAGE_ISLOWER, 0xFFFF, 0x03E4 },
+ { 0x03E6, CODEPAGE_ISUPPER, 0x03E7, 0xFFFF },
+ { 0x03E7, CODEPAGE_ISLOWER, 0xFFFF, 0x03E6 },
+ { 0x03E8, CODEPAGE_ISUPPER, 0x03E9, 0xFFFF },
+ { 0x03E9, CODEPAGE_ISLOWER, 0xFFFF, 0x03E8 },
+ { 0x03EA, CODEPAGE_ISUPPER, 0x03EB, 0xFFFF },
+ { 0x03EB, CODEPAGE_ISLOWER, 0xFFFF, 0x03EA },
+ { 0x03EC, CODEPAGE_ISUPPER, 0x03ED, 0xFFFF },
+ { 0x03ED, CODEPAGE_ISLOWER, 0xFFFF, 0x03EC },
+ { 0x03EE, CODEPAGE_ISUPPER, 0x03EF, 0xFFFF },
+ { 0x03EF, CODEPAGE_ISLOWER, 0xFFFF, 0x03EE },
+ { 0x03F0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03F1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03F2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0401, CODEPAGE_ISUPPER, 0x0451, 0xFFFF },
+ { 0x0402, CODEPAGE_ISUPPER, 0x0452, 0xFFFF },
+ { 0x0403, CODEPAGE_ISUPPER, 0x0453, 0xFFFF },
+ { 0x0404, CODEPAGE_ISUPPER, 0x0454, 0xFFFF },
+ { 0x0405, CODEPAGE_ISUPPER, 0x0455, 0xFFFF },
+ { 0x0406, CODEPAGE_ISUPPER, 0x0456, 0xFFFF },
+ { 0x0407, CODEPAGE_ISUPPER, 0x0457, 0xFFFF },
+ { 0x0408, CODEPAGE_ISUPPER, 0x0458, 0xFFFF },
+ { 0x0409, CODEPAGE_ISUPPER, 0x0459, 0xFFFF },
+ { 0x040A, CODEPAGE_ISUPPER, 0x045A, 0xFFFF },
+ { 0x040B, CODEPAGE_ISUPPER, 0x045B, 0xFFFF },
+ { 0x040C, CODEPAGE_ISUPPER, 0x045C, 0xFFFF },
+ { 0x040E, CODEPAGE_ISUPPER, 0x045E, 0xFFFF },
+ { 0x040F, CODEPAGE_ISUPPER, 0x045F, 0xFFFF },
+ { 0x0410, CODEPAGE_ISUPPER, 0x0430, 0xFFFF },
+ { 0x0411, CODEPAGE_ISUPPER, 0x0431, 0xFFFF },
+ { 0x0412, CODEPAGE_ISUPPER, 0x0432, 0xFFFF },
+ { 0x0413, CODEPAGE_ISUPPER, 0x0433, 0xFFFF },
+ { 0x0414, CODEPAGE_ISUPPER, 0x0434, 0xFFFF },
+ { 0x0415, CODEPAGE_ISUPPER, 0x0435, 0xFFFF },
+ { 0x0416, CODEPAGE_ISUPPER, 0x0436, 0xFFFF },
+ { 0x0417, CODEPAGE_ISUPPER, 0x0437, 0xFFFF },
+ { 0x0418, CODEPAGE_ISUPPER, 0x0438, 0xFFFF },
+ { 0x0419, CODEPAGE_ISUPPER, 0x0439, 0xFFFF },
+ { 0x041A, CODEPAGE_ISUPPER, 0x043A, 0xFFFF },
+ { 0x041B, CODEPAGE_ISUPPER, 0x043B, 0xFFFF },
+ { 0x041C, CODEPAGE_ISUPPER, 0x043C, 0xFFFF },
+ { 0x041D, CODEPAGE_ISUPPER, 0x043D, 0xFFFF },
+ { 0x041E, CODEPAGE_ISUPPER, 0x043E, 0xFFFF },
+ { 0x041F, CODEPAGE_ISUPPER, 0x043F, 0xFFFF },
+ { 0x0420, CODEPAGE_ISUPPER, 0x0440, 0xFFFF },
+ { 0x0421, CODEPAGE_ISUPPER, 0x0441, 0xFFFF },
+ { 0x0422, CODEPAGE_ISUPPER, 0x0442, 0xFFFF },
+ { 0x0423, CODEPAGE_ISUPPER, 0x0443, 0xFFFF },
+ { 0x0424, CODEPAGE_ISUPPER, 0x0444, 0xFFFF },
+ { 0x0425, CODEPAGE_ISUPPER, 0x0445, 0xFFFF },
+ { 0x0426, CODEPAGE_ISUPPER, 0x0446, 0xFFFF },
+ { 0x0427, CODEPAGE_ISUPPER, 0x0447, 0xFFFF },
+ { 0x0428, CODEPAGE_ISUPPER, 0x0448, 0xFFFF },
+ { 0x0429, CODEPAGE_ISUPPER, 0x0449, 0xFFFF },
+ { 0x042A, CODEPAGE_ISUPPER, 0x044A, 0xFFFF },
+ { 0x042B, CODEPAGE_ISUPPER, 0x044B, 0xFFFF },
+ { 0x042C, CODEPAGE_ISUPPER, 0x044C, 0xFFFF },
+ { 0x042D, CODEPAGE_ISUPPER, 0x044D, 0xFFFF },
+ { 0x042E, CODEPAGE_ISUPPER, 0x044E, 0xFFFF },
+ { 0x042F, CODEPAGE_ISUPPER, 0x044F, 0xFFFF },
+ { 0x0430, CODEPAGE_ISLOWER, 0xFFFF, 0x0410 },
+ { 0x0431, CODEPAGE_ISLOWER, 0xFFFF, 0x0411 },
+ { 0x0432, CODEPAGE_ISLOWER, 0xFFFF, 0x0412 },
+ { 0x0433, CODEPAGE_ISLOWER, 0xFFFF, 0x0413 },
+ { 0x0434, CODEPAGE_ISLOWER, 0xFFFF, 0x0414 },
+ { 0x0435, CODEPAGE_ISLOWER, 0xFFFF, 0x0415 },
+ { 0x0436, CODEPAGE_ISLOWER, 0xFFFF, 0x0416 },
+ { 0x0437, CODEPAGE_ISLOWER, 0xFFFF, 0x0417 },
+ { 0x0438, CODEPAGE_ISLOWER, 0xFFFF, 0x0418 },
+ { 0x0439, CODEPAGE_ISLOWER, 0xFFFF, 0x0419 },
+ { 0x043A, CODEPAGE_ISLOWER, 0xFFFF, 0x041A },
+ { 0x043B, CODEPAGE_ISLOWER, 0xFFFF, 0x041B },
+ { 0x043C, CODEPAGE_ISLOWER, 0xFFFF, 0x041C },
+ { 0x043D, CODEPAGE_ISLOWER, 0xFFFF, 0x041D },
+ { 0x043E, CODEPAGE_ISLOWER, 0xFFFF, 0x041E },
+ { 0x043F, CODEPAGE_ISLOWER, 0xFFFF, 0x041F },
+ { 0x0440, CODEPAGE_ISLOWER, 0xFFFF, 0x0420 },
+ { 0x0441, CODEPAGE_ISLOWER, 0xFFFF, 0x0421 },
+ { 0x0442, CODEPAGE_ISLOWER, 0xFFFF, 0x0422 },
+ { 0x0443, CODEPAGE_ISLOWER, 0xFFFF, 0x0423 },
+ { 0x0444, CODEPAGE_ISLOWER, 0xFFFF, 0x0424 },
+ { 0x0445, CODEPAGE_ISLOWER, 0xFFFF, 0x0425 },
+ { 0x0446, CODEPAGE_ISLOWER, 0xFFFF, 0x0426 },
+ { 0x0447, CODEPAGE_ISLOWER, 0xFFFF, 0x0427 },
+ { 0x0448, CODEPAGE_ISLOWER, 0xFFFF, 0x0428 },
+ { 0x0449, CODEPAGE_ISLOWER, 0xFFFF, 0x0429 },
+ { 0x044A, CODEPAGE_ISLOWER, 0xFFFF, 0x042A },
+ { 0x044B, CODEPAGE_ISLOWER, 0xFFFF, 0x042B },
+ { 0x044C, CODEPAGE_ISLOWER, 0xFFFF, 0x042C },
+ { 0x044D, CODEPAGE_ISLOWER, 0xFFFF, 0x042D },
+ { 0x044E, CODEPAGE_ISLOWER, 0xFFFF, 0x042E },
+ { 0x044F, CODEPAGE_ISLOWER, 0xFFFF, 0x042F },
+ { 0x0451, CODEPAGE_ISLOWER, 0xFFFF, 0x0401 },
+ { 0x0452, CODEPAGE_ISLOWER, 0xFFFF, 0x0402 },
+ { 0x0453, CODEPAGE_ISLOWER, 0xFFFF, 0x0403 },
+ { 0x0454, CODEPAGE_ISLOWER, 0xFFFF, 0x0404 },
+ { 0x0455, CODEPAGE_ISLOWER, 0xFFFF, 0x0405 },
+ { 0x0456, CODEPAGE_ISLOWER, 0xFFFF, 0x0406 },
+ { 0x0457, CODEPAGE_ISLOWER, 0xFFFF, 0x0407 },
+ { 0x0458, CODEPAGE_ISLOWER, 0xFFFF, 0x0408 },
+ { 0x0459, CODEPAGE_ISLOWER, 0xFFFF, 0x0409 },
+ { 0x045A, CODEPAGE_ISLOWER, 0xFFFF, 0x040A },
+ { 0x045B, CODEPAGE_ISLOWER, 0xFFFF, 0x040B },
+ { 0x045C, CODEPAGE_ISLOWER, 0xFFFF, 0x040C },
+ { 0x045E, CODEPAGE_ISLOWER, 0xFFFF, 0x040E },
+ { 0x045F, CODEPAGE_ISLOWER, 0xFFFF, 0x040F },
+ { 0x0460, CODEPAGE_ISUPPER, 0x0461, 0xFFFF },
+ { 0x0461, CODEPAGE_ISLOWER, 0xFFFF, 0x0460 },
+ { 0x0462, CODEPAGE_ISUPPER, 0x0463, 0xFFFF },
+ { 0x0463, CODEPAGE_ISLOWER, 0xFFFF, 0x0462 },
+ { 0x0464, CODEPAGE_ISUPPER, 0x0465, 0xFFFF },
+ { 0x0465, CODEPAGE_ISLOWER, 0xFFFF, 0x0464 },
+ { 0x0466, CODEPAGE_ISUPPER, 0x0467, 0xFFFF },
+ { 0x0467, CODEPAGE_ISLOWER, 0xFFFF, 0x0466 },
+ { 0x0468, CODEPAGE_ISUPPER, 0x0469, 0xFFFF },
+ { 0x0469, CODEPAGE_ISLOWER, 0xFFFF, 0x0468 },
+ { 0x046A, CODEPAGE_ISUPPER, 0x046B, 0xFFFF },
+ { 0x046B, CODEPAGE_ISLOWER, 0xFFFF, 0x046A },
+ { 0x046C, CODEPAGE_ISUPPER, 0x046D, 0xFFFF },
+ { 0x046D, CODEPAGE_ISLOWER, 0xFFFF, 0x046C },
+ { 0x046E, CODEPAGE_ISUPPER, 0x046F, 0xFFFF },
+ { 0x046F, CODEPAGE_ISLOWER, 0xFFFF, 0x046E },
+ { 0x0470, CODEPAGE_ISUPPER, 0x0471, 0xFFFF },
+ { 0x0471, CODEPAGE_ISLOWER, 0xFFFF, 0x0470 },
+ { 0x0472, CODEPAGE_ISUPPER, 0x0473, 0xFFFF },
+ { 0x0473, CODEPAGE_ISLOWER, 0xFFFF, 0x0472 },
+ { 0x0474, CODEPAGE_ISUPPER, 0x0475, 0xFFFF },
+ { 0x0475, CODEPAGE_ISLOWER, 0xFFFF, 0x0474 },
+ { 0x0476, CODEPAGE_ISUPPER, 0x0477, 0xFFFF },
+ { 0x0477, CODEPAGE_ISLOWER, 0xFFFF, 0x0476 },
+ { 0x0478, CODEPAGE_ISUPPER, 0x0479, 0xFFFF },
+ { 0x0479, CODEPAGE_ISLOWER, 0xFFFF, 0x0478 },
+ { 0x047A, CODEPAGE_ISUPPER, 0x047B, 0xFFFF },
+ { 0x047B, CODEPAGE_ISLOWER, 0xFFFF, 0x047A },
+ { 0x047C, CODEPAGE_ISUPPER, 0x047D, 0xFFFF },
+ { 0x047D, CODEPAGE_ISLOWER, 0xFFFF, 0x047C },
+ { 0x047E, CODEPAGE_ISUPPER, 0x047F, 0xFFFF },
+ { 0x047F, CODEPAGE_ISLOWER, 0xFFFF, 0x047E },
+ { 0x0480, CODEPAGE_ISUPPER, 0x0481, 0xFFFF },
+ { 0x0481, CODEPAGE_ISLOWER, 0xFFFF, 0x0480 },
+ { 0x0482, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0483, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0484, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0485, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0486, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0490, CODEPAGE_ISUPPER, 0x0491, 0xFFFF },
+ { 0x0491, CODEPAGE_ISLOWER, 0xFFFF, 0x0490 },
+ { 0x0492, CODEPAGE_ISUPPER, 0x0493, 0xFFFF },
+ { 0x0493, CODEPAGE_ISLOWER, 0xFFFF, 0x0492 },
+ { 0x0494, CODEPAGE_ISUPPER, 0x0495, 0xFFFF },
+ { 0x0495, CODEPAGE_ISLOWER, 0xFFFF, 0x0494 },
+ { 0x0496, CODEPAGE_ISUPPER, 0x0497, 0xFFFF },
+ { 0x0497, CODEPAGE_ISLOWER, 0xFFFF, 0x0496 },
+ { 0x0498, CODEPAGE_ISUPPER, 0x0499, 0xFFFF },
+ { 0x0499, CODEPAGE_ISLOWER, 0xFFFF, 0x0498 },
+ { 0x049A, CODEPAGE_ISUPPER, 0x049B, 0xFFFF },
+ { 0x049B, CODEPAGE_ISLOWER, 0xFFFF, 0x049A },
+ { 0x049C, CODEPAGE_ISUPPER, 0x049D, 0xFFFF },
+ { 0x049D, CODEPAGE_ISLOWER, 0xFFFF, 0x049C },
+ { 0x049E, CODEPAGE_ISUPPER, 0x049F, 0xFFFF },
+ { 0x049F, CODEPAGE_ISLOWER, 0xFFFF, 0x049E },
+ { 0x04A0, CODEPAGE_ISUPPER, 0x04A1, 0xFFFF },
+ { 0x04A1, CODEPAGE_ISLOWER, 0xFFFF, 0x04A0 },
+ { 0x04A2, CODEPAGE_ISUPPER, 0x04A3, 0xFFFF },
+ { 0x04A3, CODEPAGE_ISLOWER, 0xFFFF, 0x04A2 },
+ { 0x04A4, CODEPAGE_ISUPPER, 0x04A5, 0xFFFF },
+ { 0x04A5, CODEPAGE_ISLOWER, 0xFFFF, 0x04A4 },
+ { 0x04A6, CODEPAGE_ISUPPER, 0x04A7, 0xFFFF },
+ { 0x04A7, CODEPAGE_ISLOWER, 0xFFFF, 0x04A6 },
+ { 0x04A8, CODEPAGE_ISUPPER, 0x04A9, 0xFFFF },
+ { 0x04A9, CODEPAGE_ISLOWER, 0xFFFF, 0x04A8 },
+ { 0x04AA, CODEPAGE_ISUPPER, 0x04AB, 0xFFFF },
+ { 0x04AB, CODEPAGE_ISLOWER, 0xFFFF, 0x04AA },
+ { 0x04AC, CODEPAGE_ISUPPER, 0x04AD, 0xFFFF },
+ { 0x04AD, CODEPAGE_ISLOWER, 0xFFFF, 0x04AC },
+ { 0x04AE, CODEPAGE_ISUPPER, 0x04AF, 0xFFFF },
+ { 0x04AF, CODEPAGE_ISLOWER, 0xFFFF, 0x04AE },
+ { 0x04B0, CODEPAGE_ISUPPER, 0x04B1, 0xFFFF },
+ { 0x04B1, CODEPAGE_ISLOWER, 0xFFFF, 0x04B0 },
+ { 0x04B2, CODEPAGE_ISUPPER, 0x04B3, 0xFFFF },
+ { 0x04B3, CODEPAGE_ISLOWER, 0xFFFF, 0x04B2 },
+ { 0x04B4, CODEPAGE_ISUPPER, 0x04B5, 0xFFFF },
+ { 0x04B5, CODEPAGE_ISLOWER, 0xFFFF, 0x04B4 },
+ { 0x04B6, CODEPAGE_ISUPPER, 0x04B7, 0xFFFF },
+ { 0x04B7, CODEPAGE_ISLOWER, 0xFFFF, 0x04B6 },
+ { 0x04B8, CODEPAGE_ISUPPER, 0x04B9, 0xFFFF },
+ { 0x04B9, CODEPAGE_ISLOWER, 0xFFFF, 0x04B8 },
+ { 0x04BA, CODEPAGE_ISUPPER, 0x04BB, 0xFFFF },
+ { 0x04BB, CODEPAGE_ISLOWER, 0xFFFF, 0x04BA },
+ { 0x04BC, CODEPAGE_ISUPPER, 0x04BD, 0xFFFF },
+ { 0x04BD, CODEPAGE_ISLOWER, 0xFFFF, 0x04BC },
+ { 0x04BE, CODEPAGE_ISUPPER, 0x04BF, 0xFFFF },
+ { 0x04BF, CODEPAGE_ISLOWER, 0xFFFF, 0x04BE },
+ { 0x04C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x04C1, CODEPAGE_ISUPPER, 0x04C2, 0xFFFF },
+ { 0x04C2, CODEPAGE_ISLOWER, 0xFFFF, 0x04C1 },
+ { 0x04C3, CODEPAGE_ISUPPER, 0x04C4, 0xFFFF },
+ { 0x04C4, CODEPAGE_ISLOWER, 0xFFFF, 0x04C3 },
+ { 0x04C7, CODEPAGE_ISUPPER, 0x04C8, 0xFFFF },
+ { 0x04C8, CODEPAGE_ISLOWER, 0xFFFF, 0x04C7 },
+ { 0x04CB, CODEPAGE_ISUPPER, 0x04CC, 0xFFFF },
+ { 0x04CC, CODEPAGE_ISLOWER, 0xFFFF, 0x04CB },
+ { 0x04D0, CODEPAGE_ISUPPER, 0x04D1, 0xFFFF },
+ { 0x04D1, CODEPAGE_ISLOWER, 0xFFFF, 0x04D0 },
+ { 0x04D2, CODEPAGE_ISUPPER, 0x04D3, 0xFFFF },
+ { 0x04D3, CODEPAGE_ISLOWER, 0xFFFF, 0x04D2 },
+ { 0x04D4, CODEPAGE_ISUPPER, 0x04D5, 0xFFFF },
+ { 0x04D5, CODEPAGE_ISLOWER, 0xFFFF, 0x04D4 },
+ { 0x04D6, CODEPAGE_ISUPPER, 0x04D7, 0xFFFF },
+ { 0x04D7, CODEPAGE_ISLOWER, 0xFFFF, 0x04D6 },
+ { 0x04D8, CODEPAGE_ISUPPER, 0x04D9, 0xFFFF },
+ { 0x04D9, CODEPAGE_ISLOWER, 0xFFFF, 0x04D8 },
+ { 0x04DA, CODEPAGE_ISUPPER, 0x04DB, 0xFFFF },
+ { 0x04DB, CODEPAGE_ISLOWER, 0xFFFF, 0x04DA },
+ { 0x04DC, CODEPAGE_ISUPPER, 0x04DD, 0xFFFF },
+ { 0x04DD, CODEPAGE_ISLOWER, 0xFFFF, 0x04DC },
+ { 0x04DE, CODEPAGE_ISUPPER, 0x04DF, 0xFFFF },
+ { 0x04DF, CODEPAGE_ISLOWER, 0xFFFF, 0x04DE },
+ { 0x04E0, CODEPAGE_ISUPPER, 0x04E1, 0xFFFF },
+ { 0x04E1, CODEPAGE_ISLOWER, 0xFFFF, 0x04E0 },
+ { 0x04E2, CODEPAGE_ISUPPER, 0x04E3, 0xFFFF },
+ { 0x04E3, CODEPAGE_ISLOWER, 0xFFFF, 0x04E2 },
+ { 0x04E4, CODEPAGE_ISUPPER, 0x04E5, 0xFFFF },
+ { 0x04E5, CODEPAGE_ISLOWER, 0xFFFF, 0x04E4 },
+ { 0x04E6, CODEPAGE_ISUPPER, 0x04E7, 0xFFFF },
+ { 0x04E7, CODEPAGE_ISLOWER, 0xFFFF, 0x04E6 },
+ { 0x04E8, CODEPAGE_ISUPPER, 0x04E9, 0xFFFF },
+ { 0x04E9, CODEPAGE_ISLOWER, 0xFFFF, 0x04E8 },
+ { 0x04EA, CODEPAGE_ISUPPER, 0x04EB, 0xFFFF },
+ { 0x04EB, CODEPAGE_ISLOWER, 0xFFFF, 0x04EA },
+ { 0x04EE, CODEPAGE_ISUPPER, 0x04EF, 0xFFFF },
+ { 0x04EF, CODEPAGE_ISLOWER, 0xFFFF, 0x04EE },
+ { 0x04F0, CODEPAGE_ISUPPER, 0x04F1, 0xFFFF },
+ { 0x04F1, CODEPAGE_ISLOWER, 0xFFFF, 0x04F0 },
+ { 0x04F2, CODEPAGE_ISUPPER, 0x04F3, 0xFFFF },
+ { 0x04F3, CODEPAGE_ISLOWER, 0xFFFF, 0x04F2 },
+ { 0x04F4, CODEPAGE_ISUPPER, 0x04F5, 0xFFFF },
+ { 0x04F5, CODEPAGE_ISLOWER, 0xFFFF, 0x04F4 },
+ { 0x04F8, CODEPAGE_ISUPPER, 0x04F9, 0xFFFF },
+ { 0x04F9, CODEPAGE_ISLOWER, 0xFFFF, 0x04F8 },
+ { 0x0531, CODEPAGE_ISUPPER, 0x0561, 0xFFFF },
+ { 0x0532, CODEPAGE_ISUPPER, 0x0562, 0xFFFF },
+ { 0x0533, CODEPAGE_ISUPPER, 0x0563, 0xFFFF },
+ { 0x0534, CODEPAGE_ISUPPER, 0x0564, 0xFFFF },
+ { 0x0535, CODEPAGE_ISUPPER, 0x0565, 0xFFFF },
+ { 0x0536, CODEPAGE_ISUPPER, 0x0566, 0xFFFF },
+ { 0x0537, CODEPAGE_ISUPPER, 0x0567, 0xFFFF },
+ { 0x0538, CODEPAGE_ISUPPER, 0x0568, 0xFFFF },
+ { 0x0539, CODEPAGE_ISUPPER, 0x0569, 0xFFFF },
+ { 0x053A, CODEPAGE_ISUPPER, 0x056A, 0xFFFF },
+ { 0x053B, CODEPAGE_ISUPPER, 0x056B, 0xFFFF },
+ { 0x053C, CODEPAGE_ISUPPER, 0x056C, 0xFFFF },
+ { 0x053D, CODEPAGE_ISUPPER, 0x056D, 0xFFFF },
+ { 0x053E, CODEPAGE_ISUPPER, 0x056E, 0xFFFF },
+ { 0x053F, CODEPAGE_ISUPPER, 0x056F, 0xFFFF },
+ { 0x0540, CODEPAGE_ISUPPER, 0x0570, 0xFFFF },
+ { 0x0541, CODEPAGE_ISUPPER, 0x0571, 0xFFFF },
+ { 0x0542, CODEPAGE_ISUPPER, 0x0572, 0xFFFF },
+ { 0x0543, CODEPAGE_ISUPPER, 0x0573, 0xFFFF },
+ { 0x0544, CODEPAGE_ISUPPER, 0x0574, 0xFFFF },
+ { 0x0545, CODEPAGE_ISUPPER, 0x0575, 0xFFFF },
+ { 0x0546, CODEPAGE_ISUPPER, 0x0576, 0xFFFF },
+ { 0x0547, CODEPAGE_ISUPPER, 0x0577, 0xFFFF },
+ { 0x0548, CODEPAGE_ISUPPER, 0x0578, 0xFFFF },
+ { 0x0549, CODEPAGE_ISUPPER, 0x0579, 0xFFFF },
+ { 0x054A, CODEPAGE_ISUPPER, 0x057A, 0xFFFF },
+ { 0x054B, CODEPAGE_ISUPPER, 0x057B, 0xFFFF },
+ { 0x054C, CODEPAGE_ISUPPER, 0x057C, 0xFFFF },
+ { 0x054D, CODEPAGE_ISUPPER, 0x057D, 0xFFFF },
+ { 0x054E, CODEPAGE_ISUPPER, 0x057E, 0xFFFF },
+ { 0x054F, CODEPAGE_ISUPPER, 0x057F, 0xFFFF },
+ { 0x0550, CODEPAGE_ISUPPER, 0x0580, 0xFFFF },
+ { 0x0551, CODEPAGE_ISUPPER, 0x0581, 0xFFFF },
+ { 0x0552, CODEPAGE_ISUPPER, 0x0582, 0xFFFF },
+ { 0x0553, CODEPAGE_ISUPPER, 0x0583, 0xFFFF },
+ { 0x0554, CODEPAGE_ISUPPER, 0x0584, 0xFFFF },
+ { 0x0555, CODEPAGE_ISUPPER, 0x0585, 0xFFFF },
+ { 0x0556, CODEPAGE_ISUPPER, 0x0586, 0xFFFF },
+ { 0x0559, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0561, CODEPAGE_ISLOWER, 0xFFFF, 0x0531 },
+ { 0x0562, CODEPAGE_ISLOWER, 0xFFFF, 0x0532 },
+ { 0x0563, CODEPAGE_ISLOWER, 0xFFFF, 0x0533 },
+ { 0x0564, CODEPAGE_ISLOWER, 0xFFFF, 0x0534 },
+ { 0x0565, CODEPAGE_ISLOWER, 0xFFFF, 0x0535 },
+ { 0x0566, CODEPAGE_ISLOWER, 0xFFFF, 0x0536 },
+ { 0x0567, CODEPAGE_ISLOWER, 0xFFFF, 0x0537 },
+ { 0x0568, CODEPAGE_ISLOWER, 0xFFFF, 0x0538 },
+ { 0x0569, CODEPAGE_ISLOWER, 0xFFFF, 0x0539 },
+ { 0x056A, CODEPAGE_ISLOWER, 0xFFFF, 0x053A },
+ { 0x056B, CODEPAGE_ISLOWER, 0xFFFF, 0x053B },
+ { 0x056C, CODEPAGE_ISLOWER, 0xFFFF, 0x053C },
+ { 0x056D, CODEPAGE_ISLOWER, 0xFFFF, 0x053D },
+ { 0x056E, CODEPAGE_ISLOWER, 0xFFFF, 0x053E },
+ { 0x056F, CODEPAGE_ISLOWER, 0xFFFF, 0x053F },
+ { 0x0570, CODEPAGE_ISLOWER, 0xFFFF, 0x0540 },
+ { 0x0571, CODEPAGE_ISLOWER, 0xFFFF, 0x0541 },
+ { 0x0572, CODEPAGE_ISLOWER, 0xFFFF, 0x0542 },
+ { 0x0573, CODEPAGE_ISLOWER, 0xFFFF, 0x0543 },
+ { 0x0574, CODEPAGE_ISLOWER, 0xFFFF, 0x0544 },
+ { 0x0575, CODEPAGE_ISLOWER, 0xFFFF, 0x0545 },
+ { 0x0576, CODEPAGE_ISLOWER, 0xFFFF, 0x0546 },
+ { 0x0577, CODEPAGE_ISLOWER, 0xFFFF, 0x0547 },
+ { 0x0578, CODEPAGE_ISLOWER, 0xFFFF, 0x0548 },
+ { 0x0579, CODEPAGE_ISLOWER, 0xFFFF, 0x0549 },
+ { 0x057A, CODEPAGE_ISLOWER, 0xFFFF, 0x054A },
+ { 0x057B, CODEPAGE_ISLOWER, 0xFFFF, 0x054B },
+ { 0x057C, CODEPAGE_ISLOWER, 0xFFFF, 0x054C },
+ { 0x057D, CODEPAGE_ISLOWER, 0xFFFF, 0x054D },
+ { 0x057E, CODEPAGE_ISLOWER, 0xFFFF, 0x054E },
+ { 0x057F, CODEPAGE_ISLOWER, 0xFFFF, 0x054F },
+ { 0x0580, CODEPAGE_ISLOWER, 0xFFFF, 0x0550 },
+ { 0x0581, CODEPAGE_ISLOWER, 0xFFFF, 0x0551 },
+ { 0x0582, CODEPAGE_ISLOWER, 0xFFFF, 0x0552 },
+ { 0x0583, CODEPAGE_ISLOWER, 0xFFFF, 0x0553 },
+ { 0x0584, CODEPAGE_ISLOWER, 0xFFFF, 0x0554 },
+ { 0x0585, CODEPAGE_ISLOWER, 0xFFFF, 0x0555 },
+ { 0x0586, CODEPAGE_ISLOWER, 0xFFFF, 0x0556 },
+ { 0x0587, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0589, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0591, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0592, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0593, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0594, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0595, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0596, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0597, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0598, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0599, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x060C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x061B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x061F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0621, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0622, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0623, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0624, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0625, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0626, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0627, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0628, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0629, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0630, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0631, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0632, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0633, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0634, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0635, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0636, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0637, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0638, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0639, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x063A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0640, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0641, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0642, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0643, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0644, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0645, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0646, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0647, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0648, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0649, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0650, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0651, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0652, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0660, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0661, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0662, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0663, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0664, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0665, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0666, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0667, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0668, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0669, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x066A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x066B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x066C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x066D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0670, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0671, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0672, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0673, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0674, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0675, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0676, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0677, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0678, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0679, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0680, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0681, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0682, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0683, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0684, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0685, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0686, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0687, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0688, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0689, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0690, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0691, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0692, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0693, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0694, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0695, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0696, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0697, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0698, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0699, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0901, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0902, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0903, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0905, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0906, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0907, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0908, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0909, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0910, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0911, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0912, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0913, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0914, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0915, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0916, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0917, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0918, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0919, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0920, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0921, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0922, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0923, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0924, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0925, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0926, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0927, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0928, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0929, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0930, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0931, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0932, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0933, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0934, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0935, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0936, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0937, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0938, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0939, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x093C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x093D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x093E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x093F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0940, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0941, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0942, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0943, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0944, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0945, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0946, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0947, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0948, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0949, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x094A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x094B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x094C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x094D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0950, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0951, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0952, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0953, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0954, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0958, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0959, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0960, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0961, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0962, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0963, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0964, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0965, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0966, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0967, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0968, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0969, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0970, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0981, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0982, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0983, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0985, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0986, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0987, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0988, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0989, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x098A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x098B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x098C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x098F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0990, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0993, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0994, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0995, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0996, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0997, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0998, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0999, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09FA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ABC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ABD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ABE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ABF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ACB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ACC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ACD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AD0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BCA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BCB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BCC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BD7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CCA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CCB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CCC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CD5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CD6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E45, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ECA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ECB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ECC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ECD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F45, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x10A0, CODEPAGE_ISUPPER, 0x10D0, 0xFFFF },
+ { 0x10A1, CODEPAGE_ISUPPER, 0x10D1, 0xFFFF },
+ { 0x10A2, CODEPAGE_ISUPPER, 0x10D2, 0xFFFF },
+ { 0x10A3, CODEPAGE_ISUPPER, 0x10D3, 0xFFFF },
+ { 0x10A4, CODEPAGE_ISUPPER, 0x10D4, 0xFFFF },
+ { 0x10A5, CODEPAGE_ISUPPER, 0x10D5, 0xFFFF },
+ { 0x10A6, CODEPAGE_ISUPPER, 0x10D6, 0xFFFF },
+ { 0x10A7, CODEPAGE_ISUPPER, 0x10D7, 0xFFFF },
+ { 0x10A8, CODEPAGE_ISUPPER, 0x10D8, 0xFFFF },
+ { 0x10A9, CODEPAGE_ISUPPER, 0x10D9, 0xFFFF },
+ { 0x10AA, CODEPAGE_ISUPPER, 0x10DA, 0xFFFF },
+ { 0x10AB, CODEPAGE_ISUPPER, 0x10DB, 0xFFFF },
+ { 0x10AC, CODEPAGE_ISUPPER, 0x10DC, 0xFFFF },
+ { 0x10AD, CODEPAGE_ISUPPER, 0x10DD, 0xFFFF },
+ { 0x10AE, CODEPAGE_ISUPPER, 0x10DE, 0xFFFF },
+ { 0x10AF, CODEPAGE_ISUPPER, 0x10DF, 0xFFFF },
+ { 0x10B0, CODEPAGE_ISUPPER, 0x10E0, 0xFFFF },
+ { 0x10B1, CODEPAGE_ISUPPER, 0x10E1, 0xFFFF },
+ { 0x10B2, CODEPAGE_ISUPPER, 0x10E2, 0xFFFF },
+ { 0x10B3, CODEPAGE_ISUPPER, 0x10E3, 0xFFFF },
+ { 0x10B4, CODEPAGE_ISUPPER, 0x10E4, 0xFFFF },
+ { 0x10B5, CODEPAGE_ISUPPER, 0x10E5, 0xFFFF },
+ { 0x10B6, CODEPAGE_ISUPPER, 0x10E6, 0xFFFF },
+ { 0x10B7, CODEPAGE_ISUPPER, 0x10E7, 0xFFFF },
+ { 0x10B8, CODEPAGE_ISUPPER, 0x10E8, 0xFFFF },
+ { 0x10B9, CODEPAGE_ISUPPER, 0x10E9, 0xFFFF },
+ { 0x10BA, CODEPAGE_ISUPPER, 0x10EA, 0xFFFF },
+ { 0x10BB, CODEPAGE_ISUPPER, 0x10EB, 0xFFFF },
+ { 0x10BC, CODEPAGE_ISUPPER, 0x10EC, 0xFFFF },
+ { 0x10BD, CODEPAGE_ISUPPER, 0x10ED, 0xFFFF },
+ { 0x10BE, CODEPAGE_ISUPPER, 0x10EE, 0xFFFF },
+ { 0x10BF, CODEPAGE_ISUPPER, 0x10EF, 0xFFFF },
+ { 0x10C0, CODEPAGE_ISUPPER, 0x10F0, 0xFFFF },
+ { 0x10C1, CODEPAGE_ISUPPER, 0x10F1, 0xFFFF },
+ { 0x10C2, CODEPAGE_ISUPPER, 0x10F2, 0xFFFF },
+ { 0x10C3, CODEPAGE_ISUPPER, 0x10F3, 0xFFFF },
+ { 0x10C4, CODEPAGE_ISUPPER, 0x10F4, 0xFFFF },
+ { 0x10C5, CODEPAGE_ISUPPER, 0x10F5, 0xFFFF },
+ { 0x10D0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D8, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D9, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DB, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DC, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DD, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DE, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DF, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E8, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E9, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EB, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EC, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10ED, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EE, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EF, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10FB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1100, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1101, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1102, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1103, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1104, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1105, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1106, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1107, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1108, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1109, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1110, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1111, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1112, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1113, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1114, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1115, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1116, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1117, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1118, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1119, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1120, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1121, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1122, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1123, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1124, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1125, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1126, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1127, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1128, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1129, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1130, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1131, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1132, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1133, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1134, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1135, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1136, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1137, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1138, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1139, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1140, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1141, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1142, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1143, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1144, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1145, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1146, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1147, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1148, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1149, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1150, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1151, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1152, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1153, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1154, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1155, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1156, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1157, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1158, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1159, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x115F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1160, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1161, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1162, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1163, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1164, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1165, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1166, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1167, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1168, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1169, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1170, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1171, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1172, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1173, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1174, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1175, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1176, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1177, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1178, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1179, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1180, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1181, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1182, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1183, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1184, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1185, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1186, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1187, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1188, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1189, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1190, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1191, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1192, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1193, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1194, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1195, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1196, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1197, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1198, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1199, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1E00, CODEPAGE_ISUPPER, 0x1E01, 0xFFFF },
+ { 0x1E01, CODEPAGE_ISLOWER, 0xFFFF, 0x1E00 },
+ { 0x1E02, CODEPAGE_ISUPPER, 0x1E03, 0xFFFF },
+ { 0x1E03, CODEPAGE_ISLOWER, 0xFFFF, 0x1E02 },
+ { 0x1E04, CODEPAGE_ISUPPER, 0x1E05, 0xFFFF },
+ { 0x1E05, CODEPAGE_ISLOWER, 0xFFFF, 0x1E04 },
+ { 0x1E06, CODEPAGE_ISUPPER, 0x1E07, 0xFFFF },
+ { 0x1E07, CODEPAGE_ISLOWER, 0xFFFF, 0x1E06 },
+ { 0x1E08, CODEPAGE_ISUPPER, 0x1E09, 0xFFFF },
+ { 0x1E09, CODEPAGE_ISLOWER, 0xFFFF, 0x1E08 },
+ { 0x1E0A, CODEPAGE_ISUPPER, 0x1E0B, 0xFFFF },
+ { 0x1E0B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E0A },
+ { 0x1E0C, CODEPAGE_ISUPPER, 0x1E0D, 0xFFFF },
+ { 0x1E0D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E0C },
+ { 0x1E0E, CODEPAGE_ISUPPER, 0x1E0F, 0xFFFF },
+ { 0x1E0F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E0E },
+ { 0x1E10, CODEPAGE_ISUPPER, 0x1E11, 0xFFFF },
+ { 0x1E11, CODEPAGE_ISLOWER, 0xFFFF, 0x1E10 },
+ { 0x1E12, CODEPAGE_ISUPPER, 0x1E13, 0xFFFF },
+ { 0x1E13, CODEPAGE_ISLOWER, 0xFFFF, 0x1E12 },
+ { 0x1E14, CODEPAGE_ISUPPER, 0x1E15, 0xFFFF },
+ { 0x1E15, CODEPAGE_ISLOWER, 0xFFFF, 0x1E14 },
+ { 0x1E16, CODEPAGE_ISUPPER, 0x1E17, 0xFFFF },
+ { 0x1E17, CODEPAGE_ISLOWER, 0xFFFF, 0x1E16 },
+ { 0x1E18, CODEPAGE_ISUPPER, 0x1E19, 0xFFFF },
+ { 0x1E19, CODEPAGE_ISLOWER, 0xFFFF, 0x1E18 },
+ { 0x1E1A, CODEPAGE_ISUPPER, 0x1E1B, 0xFFFF },
+ { 0x1E1B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E1A },
+ { 0x1E1C, CODEPAGE_ISUPPER, 0x1E1D, 0xFFFF },
+ { 0x1E1D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E1C },
+ { 0x1E1E, CODEPAGE_ISUPPER, 0x1E1F, 0xFFFF },
+ { 0x1E1F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E1E },
+ { 0x1E20, CODEPAGE_ISUPPER, 0x1E21, 0xFFFF },
+ { 0x1E21, CODEPAGE_ISLOWER, 0xFFFF, 0x1E20 },
+ { 0x1E22, CODEPAGE_ISUPPER, 0x1E23, 0xFFFF },
+ { 0x1E23, CODEPAGE_ISLOWER, 0xFFFF, 0x1E22 },
+ { 0x1E24, CODEPAGE_ISUPPER, 0x1E25, 0xFFFF },
+ { 0x1E25, CODEPAGE_ISLOWER, 0xFFFF, 0x1E24 },
+ { 0x1E26, CODEPAGE_ISUPPER, 0x1E27, 0xFFFF },
+ { 0x1E27, CODEPAGE_ISLOWER, 0xFFFF, 0x1E26 },
+ { 0x1E28, CODEPAGE_ISUPPER, 0x1E29, 0xFFFF },
+ { 0x1E29, CODEPAGE_ISLOWER, 0xFFFF, 0x1E28 },
+ { 0x1E2A, CODEPAGE_ISUPPER, 0x1E2B, 0xFFFF },
+ { 0x1E2B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E2A },
+ { 0x1E2C, CODEPAGE_ISUPPER, 0x1E2D, 0xFFFF },
+ { 0x1E2D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E2C },
+ { 0x1E2E, CODEPAGE_ISUPPER, 0x1E2F, 0xFFFF },
+ { 0x1E2F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E2E },
+ { 0x1E30, CODEPAGE_ISUPPER, 0x1E31, 0xFFFF },
+ { 0x1E31, CODEPAGE_ISLOWER, 0xFFFF, 0x1E30 },
+ { 0x1E32, CODEPAGE_ISUPPER, 0x1E33, 0xFFFF },
+ { 0x1E33, CODEPAGE_ISLOWER, 0xFFFF, 0x1E32 },
+ { 0x1E34, CODEPAGE_ISUPPER, 0x1E35, 0xFFFF },
+ { 0x1E35, CODEPAGE_ISLOWER, 0xFFFF, 0x1E34 },
+ { 0x1E36, CODEPAGE_ISUPPER, 0x1E37, 0xFFFF },
+ { 0x1E37, CODEPAGE_ISLOWER, 0xFFFF, 0x1E36 },
+ { 0x1E38, CODEPAGE_ISUPPER, 0x1E39, 0xFFFF },
+ { 0x1E39, CODEPAGE_ISLOWER, 0xFFFF, 0x1E38 },
+ { 0x1E3A, CODEPAGE_ISUPPER, 0x1E3B, 0xFFFF },
+ { 0x1E3B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E3A },
+ { 0x1E3C, CODEPAGE_ISUPPER, 0x1E3D, 0xFFFF },
+ { 0x1E3D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E3C },
+ { 0x1E3E, CODEPAGE_ISUPPER, 0x1E3F, 0xFFFF },
+ { 0x1E3F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E3E },
+ { 0x1E40, CODEPAGE_ISUPPER, 0x1E41, 0xFFFF },
+ { 0x1E41, CODEPAGE_ISLOWER, 0xFFFF, 0x1E40 },
+ { 0x1E42, CODEPAGE_ISUPPER, 0x1E43, 0xFFFF },
+ { 0x1E43, CODEPAGE_ISLOWER, 0xFFFF, 0x1E42 },
+ { 0x1E44, CODEPAGE_ISUPPER, 0x1E45, 0xFFFF },
+ { 0x1E45, CODEPAGE_ISLOWER, 0xFFFF, 0x1E44 },
+ { 0x1E46, CODEPAGE_ISUPPER, 0x1E47, 0xFFFF },
+ { 0x1E47, CODEPAGE_ISLOWER, 0xFFFF, 0x1E46 },
+ { 0x1E48, CODEPAGE_ISUPPER, 0x1E49, 0xFFFF },
+ { 0x1E49, CODEPAGE_ISLOWER, 0xFFFF, 0x1E48 },
+ { 0x1E4A, CODEPAGE_ISUPPER, 0x1E4B, 0xFFFF },
+ { 0x1E4B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E4A },
+ { 0x1E4C, CODEPAGE_ISUPPER, 0x1E4D, 0xFFFF },
+ { 0x1E4D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E4C },
+ { 0x1E4E, CODEPAGE_ISUPPER, 0x1E4F, 0xFFFF },
+ { 0x1E4F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E4E },
+ { 0x1E50, CODEPAGE_ISUPPER, 0x1E51, 0xFFFF },
+ { 0x1E51, CODEPAGE_ISLOWER, 0xFFFF, 0x1E50 },
+ { 0x1E52, CODEPAGE_ISUPPER, 0x1E53, 0xFFFF },
+ { 0x1E53, CODEPAGE_ISLOWER, 0xFFFF, 0x1E52 },
+ { 0x1E54, CODEPAGE_ISUPPER, 0x1E55, 0xFFFF },
+ { 0x1E55, CODEPAGE_ISLOWER, 0xFFFF, 0x1E54 },
+ { 0x1E56, CODEPAGE_ISUPPER, 0x1E57, 0xFFFF },
+ { 0x1E57, CODEPAGE_ISLOWER, 0xFFFF, 0x1E56 },
+ { 0x1E58, CODEPAGE_ISUPPER, 0x1E59, 0xFFFF },
+ { 0x1E59, CODEPAGE_ISLOWER, 0xFFFF, 0x1E58 },
+ { 0x1E5A, CODEPAGE_ISUPPER, 0x1E5B, 0xFFFF },
+ { 0x1E5B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E5A },
+ { 0x1E5C, CODEPAGE_ISUPPER, 0x1E5D, 0xFFFF },
+ { 0x1E5D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E5C },
+ { 0x1E5E, CODEPAGE_ISUPPER, 0x1E5F, 0xFFFF },
+ { 0x1E5F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E5E },
+ { 0x1E60, CODEPAGE_ISUPPER, 0x1E61, 0xFFFF },
+ { 0x1E61, CODEPAGE_ISLOWER, 0xFFFF, 0x1E60 },
+ { 0x1E62, CODEPAGE_ISUPPER, 0x1E63, 0xFFFF },
+ { 0x1E63, CODEPAGE_ISLOWER, 0xFFFF, 0x1E62 },
+ { 0x1E64, CODEPAGE_ISUPPER, 0x1E65, 0xFFFF },
+ { 0x1E65, CODEPAGE_ISLOWER, 0xFFFF, 0x1E64 },
+ { 0x1E66, CODEPAGE_ISUPPER, 0x1E67, 0xFFFF },
+ { 0x1E67, CODEPAGE_ISLOWER, 0xFFFF, 0x1E66 },
+ { 0x1E68, CODEPAGE_ISUPPER, 0x1E69, 0xFFFF },
+ { 0x1E69, CODEPAGE_ISLOWER, 0xFFFF, 0x1E68 },
+ { 0x1E6A, CODEPAGE_ISUPPER, 0x1E6B, 0xFFFF },
+ { 0x1E6B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E6A },
+ { 0x1E6C, CODEPAGE_ISUPPER, 0x1E6D, 0xFFFF },
+ { 0x1E6D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E6C },
+ { 0x1E6E, CODEPAGE_ISUPPER, 0x1E6F, 0xFFFF },
+ { 0x1E6F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E6E },
+ { 0x1E70, CODEPAGE_ISUPPER, 0x1E71, 0xFFFF },
+ { 0x1E71, CODEPAGE_ISLOWER, 0xFFFF, 0x1E70 },
+ { 0x1E72, CODEPAGE_ISUPPER, 0x1E73, 0xFFFF },
+ { 0x1E73, CODEPAGE_ISLOWER, 0xFFFF, 0x1E72 },
+ { 0x1E74, CODEPAGE_ISUPPER, 0x1E75, 0xFFFF },
+ { 0x1E75, CODEPAGE_ISLOWER, 0xFFFF, 0x1E74 },
+ { 0x1E76, CODEPAGE_ISUPPER, 0x1E77, 0xFFFF },
+ { 0x1E77, CODEPAGE_ISLOWER, 0xFFFF, 0x1E76 },
+ { 0x1E78, CODEPAGE_ISUPPER, 0x1E79, 0xFFFF },
+ { 0x1E79, CODEPAGE_ISLOWER, 0xFFFF, 0x1E78 },
+ { 0x1E7A, CODEPAGE_ISUPPER, 0x1E7B, 0xFFFF },
+ { 0x1E7B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E7A },
+ { 0x1E7C, CODEPAGE_ISUPPER, 0x1E7D, 0xFFFF },
+ { 0x1E7D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E7C },
+ { 0x1E7E, CODEPAGE_ISUPPER, 0x1E7F, 0xFFFF },
+ { 0x1E7F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E7E },
+ { 0x1E80, CODEPAGE_ISUPPER, 0x1E81, 0xFFFF },
+ { 0x1E81, CODEPAGE_ISLOWER, 0xFFFF, 0x1E80 },
+ { 0x1E82, CODEPAGE_ISUPPER, 0x1E83, 0xFFFF },
+ { 0x1E83, CODEPAGE_ISLOWER, 0xFFFF, 0x1E82 },
+ { 0x1E84, CODEPAGE_ISUPPER, 0x1E85, 0xFFFF },
+ { 0x1E85, CODEPAGE_ISLOWER, 0xFFFF, 0x1E84 },
+ { 0x1E86, CODEPAGE_ISUPPER, 0x1E87, 0xFFFF },
+ { 0x1E87, CODEPAGE_ISLOWER, 0xFFFF, 0x1E86 },
+ { 0x1E88, CODEPAGE_ISUPPER, 0x1E89, 0xFFFF },
+ { 0x1E89, CODEPAGE_ISLOWER, 0xFFFF, 0x1E88 },
+ { 0x1E8A, CODEPAGE_ISUPPER, 0x1E8B, 0xFFFF },
+ { 0x1E8B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E8A },
+ { 0x1E8C, CODEPAGE_ISUPPER, 0x1E8D, 0xFFFF },
+ { 0x1E8D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E8C },
+ { 0x1E8E, CODEPAGE_ISUPPER, 0x1E8F, 0xFFFF },
+ { 0x1E8F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E8E },
+ { 0x1E90, CODEPAGE_ISUPPER, 0x1E91, 0xFFFF },
+ { 0x1E91, CODEPAGE_ISLOWER, 0xFFFF, 0x1E90 },
+ { 0x1E92, CODEPAGE_ISUPPER, 0x1E93, 0xFFFF },
+ { 0x1E93, CODEPAGE_ISLOWER, 0xFFFF, 0x1E92 },
+ { 0x1E94, CODEPAGE_ISUPPER, 0x1E95, 0xFFFF },
+ { 0x1E95, CODEPAGE_ISLOWER, 0xFFFF, 0x1E94 },
+ { 0x1E96, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E97, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E98, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E99, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E9A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E9B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1EA0, CODEPAGE_ISUPPER, 0x1EA1, 0xFFFF },
+ { 0x1EA1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA0 },
+ { 0x1EA2, CODEPAGE_ISUPPER, 0x1EA3, 0xFFFF },
+ { 0x1EA3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA2 },
+ { 0x1EA4, CODEPAGE_ISUPPER, 0x1EA5, 0xFFFF },
+ { 0x1EA5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA4 },
+ { 0x1EA6, CODEPAGE_ISUPPER, 0x1EA7, 0xFFFF },
+ { 0x1EA7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA6 },
+ { 0x1EA8, CODEPAGE_ISUPPER, 0x1EA9, 0xFFFF },
+ { 0x1EA9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA8 },
+ { 0x1EAA, CODEPAGE_ISUPPER, 0x1EAB, 0xFFFF },
+ { 0x1EAB, CODEPAGE_ISLOWER, 0xFFFF, 0x1EAA },
+ { 0x1EAC, CODEPAGE_ISUPPER, 0x1EAD, 0xFFFF },
+ { 0x1EAD, CODEPAGE_ISLOWER, 0xFFFF, 0x1EAC },
+ { 0x1EAE, CODEPAGE_ISUPPER, 0x1EAF, 0xFFFF },
+ { 0x1EAF, CODEPAGE_ISLOWER, 0xFFFF, 0x1EAE },
+ { 0x1EB0, CODEPAGE_ISUPPER, 0x1EB1, 0xFFFF },
+ { 0x1EB1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB0 },
+ { 0x1EB2, CODEPAGE_ISUPPER, 0x1EB3, 0xFFFF },
+ { 0x1EB3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB2 },
+ { 0x1EB4, CODEPAGE_ISUPPER, 0x1EB5, 0xFFFF },
+ { 0x1EB5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB4 },
+ { 0x1EB6, CODEPAGE_ISUPPER, 0x1EB7, 0xFFFF },
+ { 0x1EB7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB6 },
+ { 0x1EB8, CODEPAGE_ISUPPER, 0x1EB9, 0xFFFF },
+ { 0x1EB9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB8 },
+ { 0x1EBA, CODEPAGE_ISUPPER, 0x1EBB, 0xFFFF },
+ { 0x1EBB, CODEPAGE_ISLOWER, 0xFFFF, 0x1EBA },
+ { 0x1EBC, CODEPAGE_ISUPPER, 0x1EBD, 0xFFFF },
+ { 0x1EBD, CODEPAGE_ISLOWER, 0xFFFF, 0x1EBC },
+ { 0x1EBE, CODEPAGE_ISUPPER, 0x1EBF, 0xFFFF },
+ { 0x1EBF, CODEPAGE_ISLOWER, 0xFFFF, 0x1EBE },
+ { 0x1EC0, CODEPAGE_ISUPPER, 0x1EC1, 0xFFFF },
+ { 0x1EC1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC0 },
+ { 0x1EC2, CODEPAGE_ISUPPER, 0x1EC3, 0xFFFF },
+ { 0x1EC3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC2 },
+ { 0x1EC4, CODEPAGE_ISUPPER, 0x1EC5, 0xFFFF },
+ { 0x1EC5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC4 },
+ { 0x1EC6, CODEPAGE_ISUPPER, 0x1EC7, 0xFFFF },
+ { 0x1EC7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC6 },
+ { 0x1EC8, CODEPAGE_ISUPPER, 0x1EC9, 0xFFFF },
+ { 0x1EC9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC8 },
+ { 0x1ECA, CODEPAGE_ISUPPER, 0x1ECB, 0xFFFF },
+ { 0x1ECB, CODEPAGE_ISLOWER, 0xFFFF, 0x1ECA },
+ { 0x1ECC, CODEPAGE_ISUPPER, 0x1ECD, 0xFFFF },
+ { 0x1ECD, CODEPAGE_ISLOWER, 0xFFFF, 0x1ECC },
+ { 0x1ECE, CODEPAGE_ISUPPER, 0x1ECF, 0xFFFF },
+ { 0x1ECF, CODEPAGE_ISLOWER, 0xFFFF, 0x1ECE },
+ { 0x1ED0, CODEPAGE_ISUPPER, 0x1ED1, 0xFFFF },
+ { 0x1ED1, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED0 },
+ { 0x1ED2, CODEPAGE_ISUPPER, 0x1ED3, 0xFFFF },
+ { 0x1ED3, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED2 },
+ { 0x1ED4, CODEPAGE_ISUPPER, 0x1ED5, 0xFFFF },
+ { 0x1ED5, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED4 },
+ { 0x1ED6, CODEPAGE_ISUPPER, 0x1ED7, 0xFFFF },
+ { 0x1ED7, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED6 },
+ { 0x1ED8, CODEPAGE_ISUPPER, 0x1ED9, 0xFFFF },
+ { 0x1ED9, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED8 },
+ { 0x1EDA, CODEPAGE_ISUPPER, 0x1EDB, 0xFFFF },
+ { 0x1EDB, CODEPAGE_ISLOWER, 0xFFFF, 0x1EDA },
+ { 0x1EDC, CODEPAGE_ISUPPER, 0x1EDD, 0xFFFF },
+ { 0x1EDD, CODEPAGE_ISLOWER, 0xFFFF, 0x1EDC },
+ { 0x1EDE, CODEPAGE_ISUPPER, 0x1EDF, 0xFFFF },
+ { 0x1EDF, CODEPAGE_ISLOWER, 0xFFFF, 0x1EDE },
+ { 0x1EE0, CODEPAGE_ISUPPER, 0x1EE1, 0xFFFF },
+ { 0x1EE1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE0 },
+ { 0x1EE2, CODEPAGE_ISUPPER, 0x1EE3, 0xFFFF },
+ { 0x1EE3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE2 },
+ { 0x1EE4, CODEPAGE_ISUPPER, 0x1EE5, 0xFFFF },
+ { 0x1EE5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE4 },
+ { 0x1EE6, CODEPAGE_ISUPPER, 0x1EE7, 0xFFFF },
+ { 0x1EE7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE6 },
+ { 0x1EE8, CODEPAGE_ISUPPER, 0x1EE9, 0xFFFF },
+ { 0x1EE9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE8 },
+ { 0x1EEA, CODEPAGE_ISUPPER, 0x1EEB, 0xFFFF },
+ { 0x1EEB, CODEPAGE_ISLOWER, 0xFFFF, 0x1EEA },
+ { 0x1EEC, CODEPAGE_ISUPPER, 0x1EED, 0xFFFF },
+ { 0x1EED, CODEPAGE_ISLOWER, 0xFFFF, 0x1EEC },
+ { 0x1EEE, CODEPAGE_ISUPPER, 0x1EEF, 0xFFFF },
+ { 0x1EEF, CODEPAGE_ISLOWER, 0xFFFF, 0x1EEE },
+ { 0x1EF0, CODEPAGE_ISUPPER, 0x1EF1, 0xFFFF },
+ { 0x1EF1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF0 },
+ { 0x1EF2, CODEPAGE_ISUPPER, 0x1EF3, 0xFFFF },
+ { 0x1EF3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF2 },
+ { 0x1EF4, CODEPAGE_ISUPPER, 0x1EF5, 0xFFFF },
+ { 0x1EF5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF4 },
+ { 0x1EF6, CODEPAGE_ISUPPER, 0x1EF7, 0xFFFF },
+ { 0x1EF7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF6 },
+ { 0x1EF8, CODEPAGE_ISUPPER, 0x1EF9, 0xFFFF },
+ { 0x1EF9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF8 },
+ { 0x1F00, CODEPAGE_ISLOWER, 0xFFFF, 0x1F08 },
+ { 0x1F01, CODEPAGE_ISLOWER, 0xFFFF, 0x1F09 },
+ { 0x1F02, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0A },
+ { 0x1F03, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0B },
+ { 0x1F04, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0C },
+ { 0x1F05, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0D },
+ { 0x1F06, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0E },
+ { 0x1F07, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0F },
+ { 0x1F08, CODEPAGE_ISUPPER, 0x1F00, 0xFFFF },
+ { 0x1F09, CODEPAGE_ISUPPER, 0x1F01, 0xFFFF },
+ { 0x1F0A, CODEPAGE_ISUPPER, 0x1F02, 0xFFFF },
+ { 0x1F0B, CODEPAGE_ISUPPER, 0x1F03, 0xFFFF },
+ { 0x1F0C, CODEPAGE_ISUPPER, 0x1F04, 0xFFFF },
+ { 0x1F0D, CODEPAGE_ISUPPER, 0x1F05, 0xFFFF },
+ { 0x1F0E, CODEPAGE_ISUPPER, 0x1F06, 0xFFFF },
+ { 0x1F0F, CODEPAGE_ISUPPER, 0x1F07, 0xFFFF },
+ { 0x1F10, CODEPAGE_ISLOWER, 0xFFFF, 0x1F18 },
+ { 0x1F11, CODEPAGE_ISLOWER, 0xFFFF, 0x1F19 },
+ { 0x1F12, CODEPAGE_ISLOWER, 0xFFFF, 0x1F1A },
+ { 0x1F13, CODEPAGE_ISLOWER, 0xFFFF, 0x1F1B },
+ { 0x1F14, CODEPAGE_ISLOWER, 0xFFFF, 0x1F1C },
+ { 0x1F15, CODEPAGE_ISLOWER, 0xFFFF, 0x1F1D },
+ { 0x1F18, CODEPAGE_ISUPPER, 0x1F10, 0xFFFF },
+ { 0x1F19, CODEPAGE_ISUPPER, 0x1F11, 0xFFFF },
+ { 0x1F1A, CODEPAGE_ISUPPER, 0x1F12, 0xFFFF },
+ { 0x1F1B, CODEPAGE_ISUPPER, 0x1F13, 0xFFFF },
+ { 0x1F1C, CODEPAGE_ISUPPER, 0x1F14, 0xFFFF },
+ { 0x1F1D, CODEPAGE_ISUPPER, 0x1F15, 0xFFFF },
+ { 0x1F20, CODEPAGE_ISLOWER, 0xFFFF, 0x1F28 },
+ { 0x1F21, CODEPAGE_ISLOWER, 0xFFFF, 0x1F29 },
+ { 0x1F22, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2A },
+ { 0x1F23, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2B },
+ { 0x1F24, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2C },
+ { 0x1F25, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2D },
+ { 0x1F26, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2E },
+ { 0x1F27, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2F },
+ { 0x1F28, CODEPAGE_ISUPPER, 0x1F20, 0xFFFF },
+ { 0x1F29, CODEPAGE_ISUPPER, 0x1F21, 0xFFFF },
+ { 0x1F2A, CODEPAGE_ISUPPER, 0x1F22, 0xFFFF },
+ { 0x1F2B, CODEPAGE_ISUPPER, 0x1F23, 0xFFFF },
+ { 0x1F2C, CODEPAGE_ISUPPER, 0x1F24, 0xFFFF },
+ { 0x1F2D, CODEPAGE_ISUPPER, 0x1F25, 0xFFFF },
+ { 0x1F2E, CODEPAGE_ISUPPER, 0x1F26, 0xFFFF },
+ { 0x1F2F, CODEPAGE_ISUPPER, 0x1F27, 0xFFFF },
+ { 0x1F30, CODEPAGE_ISLOWER, 0xFFFF, 0x1F38 },
+ { 0x1F31, CODEPAGE_ISLOWER, 0xFFFF, 0x1F39 },
+ { 0x1F32, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3A },
+ { 0x1F33, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3B },
+ { 0x1F34, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3C },
+ { 0x1F35, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3D },
+ { 0x1F36, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3E },
+ { 0x1F37, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3F },
+ { 0x1F38, CODEPAGE_ISUPPER, 0x1F30, 0xFFFF },
+ { 0x1F39, CODEPAGE_ISUPPER, 0x1F31, 0xFFFF },
+ { 0x1F3A, CODEPAGE_ISUPPER, 0x1F32, 0xFFFF },
+ { 0x1F3B, CODEPAGE_ISUPPER, 0x1F33, 0xFFFF },
+ { 0x1F3C, CODEPAGE_ISUPPER, 0x1F34, 0xFFFF },
+ { 0x1F3D, CODEPAGE_ISUPPER, 0x1F35, 0xFFFF },
+ { 0x1F3E, CODEPAGE_ISUPPER, 0x1F36, 0xFFFF },
+ { 0x1F3F, CODEPAGE_ISUPPER, 0x1F37, 0xFFFF },
+ { 0x1F40, CODEPAGE_ISLOWER, 0xFFFF, 0x1F48 },
+ { 0x1F41, CODEPAGE_ISLOWER, 0xFFFF, 0x1F49 },
+ { 0x1F42, CODEPAGE_ISLOWER, 0xFFFF, 0x1F4A },
+ { 0x1F43, CODEPAGE_ISLOWER, 0xFFFF, 0x1F4B },
+ { 0x1F44, CODEPAGE_ISLOWER, 0xFFFF, 0x1F4C },
+ { 0x1F45, CODEPAGE_ISLOWER, 0xFFFF, 0x1F4D },
+ { 0x1F48, CODEPAGE_ISUPPER, 0x1F40, 0xFFFF },
+ { 0x1F49, CODEPAGE_ISUPPER, 0x1F41, 0xFFFF },
+ { 0x1F4A, CODEPAGE_ISUPPER, 0x1F42, 0xFFFF },
+ { 0x1F4B, CODEPAGE_ISUPPER, 0x1F43, 0xFFFF },
+ { 0x1F4C, CODEPAGE_ISUPPER, 0x1F44, 0xFFFF },
+ { 0x1F4D, CODEPAGE_ISUPPER, 0x1F45, 0xFFFF },
+ { 0x1F50, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1F51, CODEPAGE_ISLOWER, 0xFFFF, 0x1F59 },
+ { 0x1F52, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1F53, CODEPAGE_ISLOWER, 0xFFFF, 0x1F5B },
+ { 0x1F54, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1F55, CODEPAGE_ISLOWER, 0xFFFF, 0x1F5D },
+ { 0x1F56, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1F57, CODEPAGE_ISLOWER, 0xFFFF, 0x1F5F },
+ { 0x1F59, CODEPAGE_ISUPPER, 0x1F51, 0xFFFF },
+ { 0x1F5B, CODEPAGE_ISUPPER, 0x1F53, 0xFFFF },
+ { 0x1F5D, CODEPAGE_ISUPPER, 0x1F55, 0xFFFF },
+ { 0x1F5F, CODEPAGE_ISUPPER, 0x1F57, 0xFFFF },
+ { 0x1F60, CODEPAGE_ISLOWER, 0xFFFF, 0x1F68 },
+ { 0x1F61, CODEPAGE_ISLOWER, 0xFFFF, 0x1F69 },
+ { 0x1F62, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6A },
+ { 0x1F63, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6B },
+ { 0x1F64, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6C },
+ { 0x1F65, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6D },
+ { 0x1F66, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6E },
+ { 0x1F67, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6F },
+ { 0x1F68, CODEPAGE_ISUPPER, 0x1F60, 0xFFFF },
+ { 0x1F69, CODEPAGE_ISUPPER, 0x1F61, 0xFFFF },
+ { 0x1F6A, CODEPAGE_ISUPPER, 0x1F62, 0xFFFF },
+ { 0x1F6B, CODEPAGE_ISUPPER, 0x1F63, 0xFFFF },
+ { 0x1F6C, CODEPAGE_ISUPPER, 0x1F64, 0xFFFF },
+ { 0x1F6D, CODEPAGE_ISUPPER, 0x1F65, 0xFFFF },
+ { 0x1F6E, CODEPAGE_ISUPPER, 0x1F66, 0xFFFF },
+ { 0x1F6F, CODEPAGE_ISUPPER, 0x1F67, 0xFFFF },
+ { 0x1F70, CODEPAGE_ISLOWER, 0xFFFF, 0x1FBA },
+ { 0x1F71, CODEPAGE_ISLOWER, 0xFFFF, 0x1FBB },
+ { 0x1F72, CODEPAGE_ISLOWER, 0xFFFF, 0x1FC8 },
+ { 0x1F73, CODEPAGE_ISLOWER, 0xFFFF, 0x1FC9 },
+ { 0x1F74, CODEPAGE_ISLOWER, 0xFFFF, 0x1FCA },
+ { 0x1F75, CODEPAGE_ISLOWER, 0xFFFF, 0x1FCB },
+ { 0x1F76, CODEPAGE_ISLOWER, 0xFFFF, 0x1FDA },
+ { 0x1F77, CODEPAGE_ISLOWER, 0xFFFF, 0x1FDB },
+ { 0x1F78, CODEPAGE_ISLOWER, 0xFFFF, 0x1FF8 },
+ { 0x1F79, CODEPAGE_ISLOWER, 0xFFFF, 0x1FF9 },
+ { 0x1F7A, CODEPAGE_ISLOWER, 0xFFFF, 0x1FEA },
+ { 0x1F7B, CODEPAGE_ISLOWER, 0xFFFF, 0x1FEB },
+ { 0x1F7C, CODEPAGE_ISLOWER, 0xFFFF, 0x1FFA },
+ { 0x1F7D, CODEPAGE_ISLOWER, 0xFFFF, 0x1FFB },
+ { 0x1F80, CODEPAGE_ISLOWER, 0xFFFF, 0x1F88 },
+ { 0x1F81, CODEPAGE_ISLOWER, 0xFFFF, 0x1F89 },
+ { 0x1F82, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8A },
+ { 0x1F83, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8B },
+ { 0x1F84, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8C },
+ { 0x1F85, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8D },
+ { 0x1F86, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8E },
+ { 0x1F87, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8F },
+ { 0x1F88, CODEPAGE_ISUPPER, 0x1F80, 0xFFFF },
+ { 0x1F89, CODEPAGE_ISUPPER, 0x1F81, 0xFFFF },
+ { 0x1F8A, CODEPAGE_ISUPPER, 0x1F82, 0xFFFF },
+ { 0x1F8B, CODEPAGE_ISUPPER, 0x1F83, 0xFFFF },
+ { 0x1F8C, CODEPAGE_ISUPPER, 0x1F84, 0xFFFF },
+ { 0x1F8D, CODEPAGE_ISUPPER, 0x1F85, 0xFFFF },
+ { 0x1F8E, CODEPAGE_ISUPPER, 0x1F86, 0xFFFF },
+ { 0x1F8F, CODEPAGE_ISUPPER, 0x1F87, 0xFFFF },
+ { 0x1F90, CODEPAGE_ISLOWER, 0xFFFF, 0x1F98 },
+ { 0x1F91, CODEPAGE_ISLOWER, 0xFFFF, 0x1F99 },
+ { 0x1F92, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9A },
+ { 0x1F93, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9B },
+ { 0x1F94, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9C },
+ { 0x1F95, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9D },
+ { 0x1F96, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9E },
+ { 0x1F97, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9F },
+ { 0x1F98, CODEPAGE_ISUPPER, 0x1F90, 0xFFFF },
+ { 0x1F99, CODEPAGE_ISUPPER, 0x1F91, 0xFFFF },
+ { 0x1F9A, CODEPAGE_ISUPPER, 0x1F92, 0xFFFF },
+ { 0x1F9B, CODEPAGE_ISUPPER, 0x1F93, 0xFFFF },
+ { 0x1F9C, CODEPAGE_ISUPPER, 0x1F94, 0xFFFF },
+ { 0x1F9D, CODEPAGE_ISUPPER, 0x1F95, 0xFFFF },
+ { 0x1F9E, CODEPAGE_ISUPPER, 0x1F96, 0xFFFF },
+ { 0x1F9F, CODEPAGE_ISUPPER, 0x1F97, 0xFFFF },
+ { 0x1FA0, CODEPAGE_ISLOWER, 0xFFFF, 0x1FA8 },
+ { 0x1FA1, CODEPAGE_ISLOWER, 0xFFFF, 0x1FA9 },
+ { 0x1FA2, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAA },
+ { 0x1FA3, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAB },
+ { 0x1FA4, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAC },
+ { 0x1FA5, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAD },
+ { 0x1FA6, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAE },
+ { 0x1FA7, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAF },
+ { 0x1FA8, CODEPAGE_ISUPPER, 0x1FA0, 0xFFFF },
+ { 0x1FA9, CODEPAGE_ISUPPER, 0x1FA1, 0xFFFF },
+ { 0x1FAA, CODEPAGE_ISUPPER, 0x1FA2, 0xFFFF },
+ { 0x1FAB, CODEPAGE_ISUPPER, 0x1FA3, 0xFFFF },
+ { 0x1FAC, CODEPAGE_ISUPPER, 0x1FA4, 0xFFFF },
+ { 0x1FAD, CODEPAGE_ISUPPER, 0x1FA5, 0xFFFF },
+ { 0x1FAE, CODEPAGE_ISUPPER, 0x1FA6, 0xFFFF },
+ { 0x1FAF, CODEPAGE_ISUPPER, 0x1FA7, 0xFFFF },
+ { 0x1FB0, CODEPAGE_ISLOWER, 0xFFFF, 0x1FB8 },
+ { 0x1FB1, CODEPAGE_ISLOWER, 0xFFFF, 0x1FB9 },
+ { 0x1FB2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FB3, CODEPAGE_ISLOWER, 0xFFFF, 0x1FBC },
+ { 0x1FB4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FB6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FB7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FB8, CODEPAGE_ISUPPER, 0x1FB0, 0xFFFF },
+ { 0x1FB9, CODEPAGE_ISUPPER, 0x1FB1, 0xFFFF },
+ { 0x1FBA, CODEPAGE_ISUPPER, 0x1F70, 0xFFFF },
+ { 0x1FBB, CODEPAGE_ISUPPER, 0x1F71, 0xFFFF },
+ { 0x1FBC, CODEPAGE_ISUPPER, 0x1FB3, 0xFFFF },
+ { 0x1FBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FBE, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x1FBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FC2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FC3, CODEPAGE_ISLOWER, 0xFFFF, 0x1FCC },
+ { 0x1FC4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FC6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FC7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FC8, CODEPAGE_ISUPPER, 0x1F72, 0xFFFF },
+ { 0x1FC9, CODEPAGE_ISUPPER, 0x1F73, 0xFFFF },
+ { 0x1FCA, CODEPAGE_ISUPPER, 0x1F74, 0xFFFF },
+ { 0x1FCB, CODEPAGE_ISUPPER, 0x1F75, 0xFFFF },
+ { 0x1FCC, CODEPAGE_ISUPPER, 0x1FC3, 0xFFFF },
+ { 0x1FCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FCE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FCF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FD0, CODEPAGE_ISLOWER, 0xFFFF, 0x1FD8 },
+ { 0x1FD1, CODEPAGE_ISLOWER, 0xFFFF, 0x1FD9 },
+ { 0x1FD2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FD3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FD6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FD7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FD8, CODEPAGE_ISUPPER, 0x1FD0, 0xFFFF },
+ { 0x1FD9, CODEPAGE_ISUPPER, 0x1FD1, 0xFFFF },
+ { 0x1FDA, CODEPAGE_ISUPPER, 0x1F76, 0xFFFF },
+ { 0x1FDB, CODEPAGE_ISUPPER, 0x1F77, 0xFFFF },
+ { 0x1FDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FDF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FE0, CODEPAGE_ISLOWER, 0xFFFF, 0x1FE8 },
+ { 0x1FE1, CODEPAGE_ISLOWER, 0xFFFF, 0x1FE9 },
+ { 0x1FE2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE5, CODEPAGE_ISLOWER, 0xFFFF, 0x1FEC },
+ { 0x1FE6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE8, CODEPAGE_ISUPPER, 0x1FE0, 0xFFFF },
+ { 0x1FE9, CODEPAGE_ISUPPER, 0x1FE1, 0xFFFF },
+ { 0x1FEA, CODEPAGE_ISUPPER, 0x1F7A, 0xFFFF },
+ { 0x1FEB, CODEPAGE_ISUPPER, 0x1F7B, 0xFFFF },
+ { 0x1FEC, CODEPAGE_ISUPPER, 0x1FE5, 0xFFFF },
+ { 0x1FED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FF2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FF3, CODEPAGE_ISLOWER, 0xFFFF, 0x1FFC },
+ { 0x1FF4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FF6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FF7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FF8, CODEPAGE_ISUPPER, 0x1F78, 0xFFFF },
+ { 0x1FF9, CODEPAGE_ISUPPER, 0x1F79, 0xFFFF },
+ { 0x1FFA, CODEPAGE_ISUPPER, 0x1F7C, 0xFFFF },
+ { 0x1FFB, CODEPAGE_ISUPPER, 0x1F7D, 0xFFFF },
+ { 0x1FFC, CODEPAGE_ISUPPER, 0x1FF3, 0xFFFF },
+ { 0x1FFD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FFE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2000, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2001, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2002, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2003, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2004, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2005, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2006, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2007, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2008, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2009, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2010, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2011, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2012, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2013, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2014, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2015, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2016, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2017, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2018, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2019, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2020, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2021, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2022, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2023, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2024, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2025, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2026, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2027, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2028, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2029, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2030, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2031, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2032, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2033, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2034, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2035, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2036, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2037, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2038, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2039, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2040, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2041, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2042, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2043, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2044, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2045, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2046, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2070, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2074, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2075, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2076, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2077, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2078, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2079, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2080, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2081, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2082, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2083, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2084, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2085, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2086, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2087, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2088, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2089, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2100, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2101, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2102, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2103, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2104, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2105, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2106, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2107, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2108, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2109, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x210A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x210B, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x210C, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x210D, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x210E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x210F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2110, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2111, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2112, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2113, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2114, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2115, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2116, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2117, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2118, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2119, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211A, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211B, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211C, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211D, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x211F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2120, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2121, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2122, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2123, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2124, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2125, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2126, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2127, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2128, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2129, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x212A, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x212B, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x212C, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x212D, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x212E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x212F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2130, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2131, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2132, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2133, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2134, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2135, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2136, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2137, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2138, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2153, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2154, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2155, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2156, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2157, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2158, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2159, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2160, CODEPAGE_ISNONE, 0x2170, 0xFFFF },
+ { 0x2161, CODEPAGE_ISNONE, 0x2171, 0xFFFF },
+ { 0x2162, CODEPAGE_ISNONE, 0x2172, 0xFFFF },
+ { 0x2163, CODEPAGE_ISNONE, 0x2173, 0xFFFF },
+ { 0x2164, CODEPAGE_ISNONE, 0x2174, 0xFFFF },
+ { 0x2165, CODEPAGE_ISNONE, 0x2175, 0xFFFF },
+ { 0x2166, CODEPAGE_ISNONE, 0x2176, 0xFFFF },
+ { 0x2167, CODEPAGE_ISNONE, 0x2177, 0xFFFF },
+ { 0x2168, CODEPAGE_ISNONE, 0x2178, 0xFFFF },
+ { 0x2169, CODEPAGE_ISNONE, 0x2179, 0xFFFF },
+ { 0x216A, CODEPAGE_ISNONE, 0x217A, 0xFFFF },
+ { 0x216B, CODEPAGE_ISNONE, 0x217B, 0xFFFF },
+ { 0x216C, CODEPAGE_ISNONE, 0x217C, 0xFFFF },
+ { 0x216D, CODEPAGE_ISNONE, 0x217D, 0xFFFF },
+ { 0x216E, CODEPAGE_ISNONE, 0x217E, 0xFFFF },
+ { 0x216F, CODEPAGE_ISNONE, 0x217F, 0xFFFF },
+ { 0x2170, CODEPAGE_ISNONE, 0xFFFF, 0x2160 },
+ { 0x2171, CODEPAGE_ISNONE, 0xFFFF, 0x2161 },
+ { 0x2172, CODEPAGE_ISNONE, 0xFFFF, 0x2162 },
+ { 0x2173, CODEPAGE_ISNONE, 0xFFFF, 0x2163 },
+ { 0x2174, CODEPAGE_ISNONE, 0xFFFF, 0x2164 },
+ { 0x2175, CODEPAGE_ISNONE, 0xFFFF, 0x2165 },
+ { 0x2176, CODEPAGE_ISNONE, 0xFFFF, 0x2166 },
+ { 0x2177, CODEPAGE_ISNONE, 0xFFFF, 0x2167 },
+ { 0x2178, CODEPAGE_ISNONE, 0xFFFF, 0x2168 },
+ { 0x2179, CODEPAGE_ISNONE, 0xFFFF, 0x2169 },
+ { 0x217A, CODEPAGE_ISNONE, 0xFFFF, 0x216A },
+ { 0x217B, CODEPAGE_ISNONE, 0xFFFF, 0x216B },
+ { 0x217C, CODEPAGE_ISNONE, 0xFFFF, 0x216C },
+ { 0x217D, CODEPAGE_ISNONE, 0xFFFF, 0x216D },
+ { 0x217E, CODEPAGE_ISNONE, 0xFFFF, 0x216E },
+ { 0x217F, CODEPAGE_ISNONE, 0xFFFF, 0x216F },
+ { 0x2180, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2181, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2182, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2190, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2191, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2192, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2193, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2194, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2195, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2196, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2197, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2198, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2199, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2200, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2201, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2202, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2203, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2204, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2205, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2206, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2207, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2208, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2209, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2210, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2211, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2212, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2213, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2214, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2215, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2216, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2217, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2218, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2219, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2220, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2221, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2222, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2223, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2224, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2225, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2226, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2227, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2228, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2229, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2230, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2231, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2232, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2233, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2234, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2235, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2236, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2237, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2238, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2239, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2240, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2241, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2242, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2243, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2244, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2245, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2246, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2247, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2248, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2249, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2250, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2251, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2252, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2253, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2254, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2255, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2256, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2257, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2258, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2259, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2260, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2261, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2262, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2263, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2264, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2265, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2266, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2267, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2268, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2269, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2270, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2271, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2272, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2273, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2274, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2275, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2276, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2277, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2278, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2279, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2280, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2281, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2282, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2283, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2284, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2285, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2286, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2287, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2288, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2289, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2290, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2291, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2292, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2293, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2294, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2295, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2296, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2297, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2298, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2299, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2300, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2302, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2303, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2304, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2305, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2306, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2307, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2308, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2309, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2310, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2311, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2312, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2313, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2314, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2315, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2316, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2317, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2318, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2319, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2320, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2321, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2322, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2323, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2324, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2325, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2326, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2327, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2328, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2329, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2330, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2331, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2332, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2333, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2334, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2335, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2336, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2337, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2338, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2339, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2340, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2341, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2342, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2343, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2344, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2345, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2346, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2347, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2348, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2349, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2350, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2351, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2352, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2353, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2354, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2355, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2356, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2357, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2358, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2359, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2360, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2361, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2362, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2363, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2364, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2365, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2366, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2367, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2368, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2369, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2370, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2371, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2372, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2373, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2374, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2375, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2376, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2377, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2378, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2379, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x237A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2400, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2401, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2402, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2403, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2404, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2405, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2406, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2407, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2408, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2409, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2410, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2411, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2412, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2413, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2414, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2415, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2416, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2417, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2418, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2419, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2420, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2421, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2422, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2423, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2424, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2440, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2441, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2442, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2443, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2444, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2445, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2446, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2447, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2448, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2449, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x244A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2460, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2461, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2462, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2463, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2464, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2465, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2466, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2467, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2468, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2469, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2470, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2471, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2472, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2473, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2474, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2475, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2476, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2477, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2478, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2479, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2480, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2481, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2482, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2483, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2484, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2485, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2486, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2487, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2488, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2489, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2490, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2491, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2492, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2493, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2494, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2495, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2496, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2497, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2498, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2499, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B6, CODEPAGE_ISUPPER, 0x24D0, 0xFFFF },
+ { 0x24B7, CODEPAGE_ISUPPER, 0x24D1, 0xFFFF },
+ { 0x24B8, CODEPAGE_ISUPPER, 0x24D2, 0xFFFF },
+ { 0x24B9, CODEPAGE_ISUPPER, 0x24D3, 0xFFFF },
+ { 0x24BA, CODEPAGE_ISUPPER, 0x24D4, 0xFFFF },
+ { 0x24BB, CODEPAGE_ISUPPER, 0x24D5, 0xFFFF },
+ { 0x24BC, CODEPAGE_ISUPPER, 0x24D6, 0xFFFF },
+ { 0x24BD, CODEPAGE_ISUPPER, 0x24D7, 0xFFFF },
+ { 0x24BE, CODEPAGE_ISUPPER, 0x24D8, 0xFFFF },
+ { 0x24BF, CODEPAGE_ISUPPER, 0x24D9, 0xFFFF },
+ { 0x24C0, CODEPAGE_ISUPPER, 0x24DA, 0xFFFF },
+ { 0x24C1, CODEPAGE_ISUPPER, 0x24DB, 0xFFFF },
+ { 0x24C2, CODEPAGE_ISUPPER, 0x24DC, 0xFFFF },
+ { 0x24C3, CODEPAGE_ISUPPER, 0x24DD, 0xFFFF },
+ { 0x24C4, CODEPAGE_ISUPPER, 0x24DE, 0xFFFF },
+ { 0x24C5, CODEPAGE_ISUPPER, 0x24DF, 0xFFFF },
+ { 0x24C6, CODEPAGE_ISUPPER, 0x24E0, 0xFFFF },
+ { 0x24C7, CODEPAGE_ISUPPER, 0x24E1, 0xFFFF },
+ { 0x24C8, CODEPAGE_ISUPPER, 0x24E2, 0xFFFF },
+ { 0x24C9, CODEPAGE_ISUPPER, 0x24E3, 0xFFFF },
+ { 0x24CA, CODEPAGE_ISUPPER, 0x24E4, 0xFFFF },
+ { 0x24CB, CODEPAGE_ISUPPER, 0x24E5, 0xFFFF },
+ { 0x24CC, CODEPAGE_ISUPPER, 0x24E6, 0xFFFF },
+ { 0x24CD, CODEPAGE_ISUPPER, 0x24E7, 0xFFFF },
+ { 0x24CE, CODEPAGE_ISUPPER, 0x24E8, 0xFFFF },
+ { 0x24CF, CODEPAGE_ISUPPER, 0x24E9, 0xFFFF },
+ { 0x24D0, CODEPAGE_ISLOWER, 0xFFFF, 0x24B6 },
+ { 0x24D1, CODEPAGE_ISLOWER, 0xFFFF, 0x24B7 },
+ { 0x24D2, CODEPAGE_ISLOWER, 0xFFFF, 0x24B8 },
+ { 0x24D3, CODEPAGE_ISLOWER, 0xFFFF, 0x24B9 },
+ { 0x24D4, CODEPAGE_ISLOWER, 0xFFFF, 0x24BA },
+ { 0x24D5, CODEPAGE_ISLOWER, 0xFFFF, 0x24BB },
+ { 0x24D6, CODEPAGE_ISLOWER, 0xFFFF, 0x24BC },
+ { 0x24D7, CODEPAGE_ISLOWER, 0xFFFF, 0x24BD },
+ { 0x24D8, CODEPAGE_ISLOWER, 0xFFFF, 0x24BE },
+ { 0x24D9, CODEPAGE_ISLOWER, 0xFFFF, 0x24BF },
+ { 0x24DA, CODEPAGE_ISLOWER, 0xFFFF, 0x24C0 },
+ { 0x24DB, CODEPAGE_ISLOWER, 0xFFFF, 0x24C1 },
+ { 0x24DC, CODEPAGE_ISLOWER, 0xFFFF, 0x24C2 },
+ { 0x24DD, CODEPAGE_ISLOWER, 0xFFFF, 0x24C3 },
+ { 0x24DE, CODEPAGE_ISLOWER, 0xFFFF, 0x24C4 },
+ { 0x24DF, CODEPAGE_ISLOWER, 0xFFFF, 0x24C5 },
+ { 0x24E0, CODEPAGE_ISLOWER, 0xFFFF, 0x24C6 },
+ { 0x24E1, CODEPAGE_ISLOWER, 0xFFFF, 0x24C7 },
+ { 0x24E2, CODEPAGE_ISLOWER, 0xFFFF, 0x24C8 },
+ { 0x24E3, CODEPAGE_ISLOWER, 0xFFFF, 0x24C9 },
+ { 0x24E4, CODEPAGE_ISLOWER, 0xFFFF, 0x24CA },
+ { 0x24E5, CODEPAGE_ISLOWER, 0xFFFF, 0x24CB },
+ { 0x24E6, CODEPAGE_ISLOWER, 0xFFFF, 0x24CC },
+ { 0x24E7, CODEPAGE_ISLOWER, 0xFFFF, 0x24CD },
+ { 0x24E8, CODEPAGE_ISLOWER, 0xFFFF, 0x24CE },
+ { 0x24E9, CODEPAGE_ISLOWER, 0xFFFF, 0x24CF },
+ { 0x24EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2500, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2501, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2502, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2503, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2504, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2505, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2506, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2507, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2508, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2509, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2510, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2511, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2512, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2513, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2514, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2515, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2516, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2517, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2518, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2519, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2520, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2521, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2522, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2523, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2524, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2525, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2526, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2527, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2528, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2529, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2530, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2531, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2532, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2533, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2534, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2535, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2536, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2537, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2538, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2539, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2540, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2541, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2542, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2543, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2544, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2545, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2546, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2547, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2548, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2549, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2550, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2551, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2552, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2553, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2554, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2555, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2556, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2557, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2558, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2559, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2560, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2561, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2562, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2563, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2564, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2565, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2566, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2567, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2568, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2569, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2570, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2571, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2572, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2573, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2574, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2575, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2576, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2577, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2578, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2579, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2580, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2581, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2582, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2583, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2584, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2585, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2586, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2587, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2588, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2589, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2590, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2591, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2592, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2593, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2594, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2595, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2600, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2601, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2602, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2603, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2604, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2605, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2606, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2607, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2608, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2609, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2610, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2611, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2612, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2613, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2620, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2621, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2622, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2623, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2624, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2625, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2626, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2627, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2628, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2629, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2630, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2631, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2632, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2633, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2634, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2635, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2636, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2637, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2638, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2639, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2640, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2641, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2642, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2643, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2644, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2645, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2646, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2647, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2648, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2649, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2650, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2651, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2652, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2653, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2654, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2655, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2656, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2657, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2658, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2659, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2660, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2661, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2662, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2663, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2664, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2665, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2666, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2667, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2668, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2669, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2701, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2702, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2703, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2704, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2706, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2707, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2708, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2709, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x270C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x270D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x270E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x270F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2710, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2711, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2712, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2713, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2714, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2715, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2716, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2717, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2718, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2719, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2720, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2721, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2722, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2723, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2724, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2725, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2726, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2727, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2729, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2730, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2731, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2732, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2733, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2734, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2735, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2736, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2737, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2738, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2739, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2740, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2741, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2742, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2743, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2744, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2745, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2746, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2747, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2748, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2749, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x274A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x274B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x274D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x274F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2750, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2751, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2752, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2756, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2758, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2759, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2761, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2762, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2763, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2764, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2765, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2766, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2767, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2776, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2777, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2778, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2779, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2780, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2781, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2782, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2783, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2784, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2785, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2786, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2787, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2788, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2789, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2790, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2791, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2792, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2793, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2794, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2798, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2799, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3000, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3001, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3002, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3003, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3004, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3005, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3006, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3007, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3008, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3009, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3010, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3011, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3012, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3013, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3014, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3015, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3016, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3017, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3018, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3019, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3020, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3021, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3022, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3023, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3024, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3025, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3026, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3027, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3028, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3029, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3030, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3031, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3032, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3033, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3034, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3035, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3036, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3037, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x303F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3041, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3042, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3043, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3044, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3045, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3046, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3047, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3048, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3049, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3050, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3051, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3052, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3053, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3054, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3055, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3056, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3057, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3058, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3059, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3060, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3061, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3062, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3063, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3064, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3065, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3066, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3067, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3068, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3069, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3070, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3071, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3072, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3073, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3074, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3075, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3076, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3077, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3078, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3079, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3080, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3081, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3082, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3083, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3084, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3085, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3086, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3087, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3088, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3089, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3090, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3091, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3092, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3093, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3094, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3099, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3105, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3106, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3107, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3108, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3109, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3110, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3111, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3112, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3113, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3114, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3115, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3116, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3117, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3118, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3119, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3120, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3121, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3122, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3123, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3124, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3125, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3126, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3127, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3128, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3129, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x312A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x312B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x312C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3131, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3132, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3133, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3134, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3135, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3136, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3137, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3138, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3139, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3140, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3141, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3142, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3143, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3144, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3145, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3146, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3147, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3148, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3149, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3150, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3151, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3152, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3153, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3154, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3155, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3156, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3157, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3158, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3159, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3160, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3161, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3162, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3163, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3164, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3165, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3166, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3167, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3168, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3169, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3170, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3171, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3172, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3173, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3174, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3175, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3176, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3177, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3178, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3179, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3180, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3181, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3182, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3183, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3184, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3185, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3186, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3187, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3188, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3189, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3190, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3191, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3192, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3193, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3194, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3195, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3196, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3197, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3198, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3199, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3200, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3201, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3202, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3203, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3204, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3205, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3206, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3207, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3208, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3209, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3210, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3211, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3212, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3213, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3214, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3215, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3216, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3217, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3218, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3219, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x321A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x321B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x321C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3220, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3221, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3222, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3223, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3224, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3225, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3226, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3227, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3228, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3229, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3230, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3231, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3232, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3233, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3234, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3235, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3236, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3237, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3238, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3239, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3240, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3241, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3242, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3243, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3260, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3261, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3262, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3263, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3264, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3265, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3266, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3267, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3268, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3269, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3270, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3271, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3272, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3273, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3274, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3275, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3276, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3277, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3278, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3279, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x327A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x327B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x327F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3280, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3281, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3282, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3283, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3284, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3285, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3286, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3287, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3288, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3289, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3290, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3291, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3292, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3293, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3294, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3295, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3296, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3297, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3298, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3299, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3300, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3301, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3302, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3303, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3304, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3305, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3306, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3307, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3308, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3309, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3310, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3311, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3312, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3313, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3314, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3315, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3316, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3317, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3318, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3319, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3320, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3321, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3322, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3323, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3324, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3325, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3326, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3327, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3328, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3329, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3330, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3331, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3332, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3333, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3334, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3335, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3336, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3337, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3338, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3339, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3340, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3341, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3342, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3343, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3344, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3345, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3346, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3347, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3348, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3349, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3350, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3351, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3352, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3353, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3354, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3355, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3356, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3357, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3358, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3359, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3360, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3361, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3362, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3363, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3364, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3365, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3366, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3367, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3368, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3369, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3370, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3371, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3372, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x3373, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x3374, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x3375, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3376, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x337B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x337C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x337D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x337E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x337F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3380, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3381, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3382, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3383, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3384, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3385, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x3386, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x3387, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x3388, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x3389, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x338A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x338B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x338C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x338D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x338E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x338F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x3390, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3391, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3392, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3393, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3394, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3395, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3396, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3397, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3398, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3399, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AD, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33B1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33B2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33B3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B9, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BF, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C1, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33C5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33CA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33CB, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33CC, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33CD, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33CE, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33CF, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D7, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33D9, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33DA, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33DB, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x4E00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x9FA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xAC00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xD7A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xD800, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDB7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDB80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDBFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDC00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDFFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xE000, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xF8FF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xF900, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFA2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB00, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB01, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB02, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB03, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB04, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB05, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB06, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB13, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB14, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB15, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB16, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB17, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC45, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDFA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDFB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEFA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEFB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEFC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF21, CODEPAGE_ISUPPER, 0xFF41, 0xFFFF },
+ { 0xFF22, CODEPAGE_ISUPPER, 0xFF42, 0xFFFF },
+ { 0xFF23, CODEPAGE_ISUPPER, 0xFF43, 0xFFFF },
+ { 0xFF24, CODEPAGE_ISUPPER, 0xFF44, 0xFFFF },
+ { 0xFF25, CODEPAGE_ISUPPER, 0xFF45, 0xFFFF },
+ { 0xFF26, CODEPAGE_ISUPPER, 0xFF46, 0xFFFF },
+ { 0xFF27, CODEPAGE_ISUPPER, 0xFF47, 0xFFFF },
+ { 0xFF28, CODEPAGE_ISUPPER, 0xFF48, 0xFFFF },
+ { 0xFF29, CODEPAGE_ISUPPER, 0xFF49, 0xFFFF },
+ { 0xFF2A, CODEPAGE_ISUPPER, 0xFF4A, 0xFFFF },
+ { 0xFF2B, CODEPAGE_ISUPPER, 0xFF4B, 0xFFFF },
+ { 0xFF2C, CODEPAGE_ISUPPER, 0xFF4C, 0xFFFF },
+ { 0xFF2D, CODEPAGE_ISUPPER, 0xFF4D, 0xFFFF },
+ { 0xFF2E, CODEPAGE_ISUPPER, 0xFF4E, 0xFFFF },
+ { 0xFF2F, CODEPAGE_ISUPPER, 0xFF4F, 0xFFFF },
+ { 0xFF30, CODEPAGE_ISUPPER, 0xFF50, 0xFFFF },
+ { 0xFF31, CODEPAGE_ISUPPER, 0xFF51, 0xFFFF },
+ { 0xFF32, CODEPAGE_ISUPPER, 0xFF52, 0xFFFF },
+ { 0xFF33, CODEPAGE_ISUPPER, 0xFF53, 0xFFFF },
+ { 0xFF34, CODEPAGE_ISUPPER, 0xFF54, 0xFFFF },
+ { 0xFF35, CODEPAGE_ISUPPER, 0xFF55, 0xFFFF },
+ { 0xFF36, CODEPAGE_ISUPPER, 0xFF56, 0xFFFF },
+ { 0xFF37, CODEPAGE_ISUPPER, 0xFF57, 0xFFFF },
+ { 0xFF38, CODEPAGE_ISUPPER, 0xFF58, 0xFFFF },
+ { 0xFF39, CODEPAGE_ISUPPER, 0xFF59, 0xFFFF },
+ { 0xFF3A, CODEPAGE_ISUPPER, 0xFF5A, 0xFFFF },
+ { 0xFF3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF41, CODEPAGE_ISLOWER, 0xFFFF, 0xFF21 },
+ { 0xFF42, CODEPAGE_ISLOWER, 0xFFFF, 0xFF22 },
+ { 0xFF43, CODEPAGE_ISLOWER, 0xFFFF, 0xFF23 },
+ { 0xFF44, CODEPAGE_ISLOWER, 0xFFFF, 0xFF24 },
+ { 0xFF45, CODEPAGE_ISLOWER, 0xFFFF, 0xFF25 },
+ { 0xFF46, CODEPAGE_ISLOWER, 0xFFFF, 0xFF26 },
+ { 0xFF47, CODEPAGE_ISLOWER, 0xFFFF, 0xFF27 },
+ { 0xFF48, CODEPAGE_ISLOWER, 0xFFFF, 0xFF28 },
+ { 0xFF49, CODEPAGE_ISLOWER, 0xFFFF, 0xFF29 },
+ { 0xFF4A, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2A },
+ { 0xFF4B, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2B },
+ { 0xFF4C, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2C },
+ { 0xFF4D, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2D },
+ { 0xFF4E, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2E },
+ { 0xFF4F, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2F },
+ { 0xFF50, CODEPAGE_ISLOWER, 0xFFFF, 0xFF30 },
+ { 0xFF51, CODEPAGE_ISLOWER, 0xFFFF, 0xFF31 },
+ { 0xFF52, CODEPAGE_ISLOWER, 0xFFFF, 0xFF32 },
+ { 0xFF53, CODEPAGE_ISLOWER, 0xFFFF, 0xFF33 },
+ { 0xFF54, CODEPAGE_ISLOWER, 0xFFFF, 0xFF34 },
+ { 0xFF55, CODEPAGE_ISLOWER, 0xFFFF, 0xFF35 },
+ { 0xFF56, CODEPAGE_ISLOWER, 0xFFFF, 0xFF36 },
+ { 0xFF57, CODEPAGE_ISLOWER, 0xFFFF, 0xFF37 },
+ { 0xFF58, CODEPAGE_ISLOWER, 0xFFFF, 0xFF38 },
+ { 0xFF59, CODEPAGE_ISLOWER, 0xFFFF, 0xFF39 },
+ { 0xFF5A, CODEPAGE_ISLOWER, 0xFFFF, 0xFF3A },
+ { 0xFF5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFDA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFDB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFFD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_UNICODE_H */
diff --git a/usr/src/uts/common/smbsrv/cp_usascii.h b/usr/src/uts/common/smbsrv/cp_usascii.h
new file mode 100644
index 0000000000..d72c28bb88
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_usascii.h
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_CP_USASCII_H
+#define _SMBSRV_CP_USASCII_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for the US-ASCII Character Set
+ * This codepage defines values for the characters of the
+ * written alphabet of the English language. The US-ASCII
+ * character set is used in the USA. It is a proper
+ * subset of the Latin-1 character set.
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t usascii_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISNONE, 0x00a1, 0x00a1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISNONE, 0x00a3, 0x00a3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISNONE, 0x00a5, 0x00a5 }, /* 0x00a5 */
+ { CODEPAGE_ISNONE, 0x00a6, 0x00a6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISNONE, 0x00a9, 0x00a9 }, /* 0x00a9 */
+ { CODEPAGE_ISNONE, 0x00aa, 0x00aa }, /* 0x00aa */
+ { CODEPAGE_ISNONE, 0x00ab, 0x00ab }, /* 0x00ab */
+ { CODEPAGE_ISNONE, 0x00ac, 0x00ac }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISNONE, 0x00ae, 0x00ae }, /* 0x00ae */
+ { CODEPAGE_ISNONE, 0x00af, 0x00af }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISNONE, 0x00b1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISNONE, 0x00b6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISNONE, 0x00b9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISNONE, 0x00ba, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISNONE, 0x00bb, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISNONE, 0x00bc, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISNONE, 0x00c0, 0x00c0 }, /* 0x00c0 */
+ { CODEPAGE_ISNONE, 0x00c1, 0x00c1 }, /* 0x00c1 */
+ { CODEPAGE_ISNONE, 0x00c2, 0x00c2 }, /* 0x00c2 */
+ { CODEPAGE_ISNONE, 0x00c3, 0x00c3 }, /* 0x00c3 */
+ { CODEPAGE_ISNONE, 0x00c4, 0x00c4 }, /* 0x00c4 */
+ { CODEPAGE_ISNONE, 0x00c5, 0x00c5 }, /* 0x00c5 */
+ { CODEPAGE_ISNONE, 0x00c6, 0x00c6 }, /* 0x00c6 */
+ { CODEPAGE_ISNONE, 0x00c7, 0x00c7 }, /* 0x00c7 */
+ { CODEPAGE_ISNONE, 0x00c8, 0x00c8 }, /* 0x00c8 */
+ { CODEPAGE_ISNONE, 0x00c9, 0x00c9 }, /* 0x00c9 */
+ { CODEPAGE_ISNONE, 0x00ca, 0x00ca }, /* 0x00ca */
+ { CODEPAGE_ISNONE, 0x00cb, 0x00cb }, /* 0x00cb */
+ { CODEPAGE_ISNONE, 0x00cc, 0x00cc }, /* 0x00cc */
+ { CODEPAGE_ISNONE, 0x00cd, 0x00cd }, /* 0x00cd */
+ { CODEPAGE_ISNONE, 0x00ce, 0x00ce }, /* 0x00ce */
+ { CODEPAGE_ISNONE, 0x00cf, 0x00cf }, /* 0x00cf */
+ { CODEPAGE_ISNONE, 0x00d0, 0x00d0 }, /* 0x00d0 */
+ { CODEPAGE_ISNONE, 0x00d1, 0x00d1 }, /* 0x00d1 */
+ { CODEPAGE_ISNONE, 0x00d2, 0x00d2 }, /* 0x00d2 */
+ { CODEPAGE_ISNONE, 0x00d3, 0x00d3 }, /* 0x00d3 */
+ { CODEPAGE_ISNONE, 0x00d4, 0x00d4 }, /* 0x00d4 */
+ { CODEPAGE_ISNONE, 0x00d5, 0x00d5 }, /* 0x00d5 */
+ { CODEPAGE_ISNONE, 0x00d6, 0x00d6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISNONE, 0x00d8, 0x00d8 }, /* 0x00d8 */
+ { CODEPAGE_ISNONE, 0x00d9, 0x00d9 }, /* 0x00d9 */
+ { CODEPAGE_ISNONE, 0x00da, 0x00da }, /* 0x00da */
+ { CODEPAGE_ISNONE, 0x00db, 0x00db }, /* 0x00db */
+ { CODEPAGE_ISNONE, 0x00dc, 0x00dc }, /* 0x00dc */
+ { CODEPAGE_ISNONE, 0x00dd, 0x00dd }, /* 0x00dd */
+ { CODEPAGE_ISNONE, 0x00de, 0x00de }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISNONE, 0x00e0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISNONE, 0x00e1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISNONE, 0x00e2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISNONE, 0x00e3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISNONE, 0x00e4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISNONE, 0x00e5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISNONE, 0x00e6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISNONE, 0x00e7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISNONE, 0x00e8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISNONE, 0x00e9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISNONE, 0x00ea, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISNONE, 0x00eb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISNONE, 0x00ec, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISNONE, 0x00ed, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISNONE, 0x00ee, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISNONE, 0x00ef, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISNONE, 0x00f0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISNONE, 0x00f1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISNONE, 0x00f2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISNONE, 0x00f3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISNONE, 0x00f4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISNONE, 0x00f5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISNONE, 0x00f6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISNONE, 0x00f8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISNONE, 0x00f9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISNONE, 0x00fa, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISNONE, 0x00fb, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISNONE, 0x00fc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISNONE, 0x00fd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISNONE, 0x00fe, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } }; /* 0x00ff */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_USASCII_H */
diff --git a/usr/src/uts/common/smbsrv/crypt.h b/usr/src/uts/common/smbsrv/crypt.h
new file mode 100644
index 0000000000..b2765a2f8e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/crypt.h
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CRYPT_H
+#define _SMBSRV_CRYPT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PASS_LEN 20
+#define BUF_LEN (2 * PASS_LEN)
+
+extern int smb_des_setkey(const char *);
+extern int smb_des_cipher(const char *, char *, long, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CRYPT_H */
diff --git a/usr/src/uts/common/smbsrv/ctype.h b/usr/src/uts/common/smbsrv/ctype.h
new file mode 100644
index 0000000000..284db64419
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ctype.h
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CTYPE_H
+#define _SMBSRV_CTYPE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _mts_between(l, c, u) ((l) <= (c) && (c) <= (u))
+
+/*
+ * These macros take non-ascii characters into account.
+ * Their behavior depends on the codepage that is used.
+ */
+#define mts_islower(c) codepage_islower((c))
+#define mts_isupper(c) codepage_isupper((c))
+#define mts_tolower(c) codepage_tolower((c))
+#define mts_toupper(c) codepage_toupper((c))
+
+#define mts_isalpha(c) (mts_islower(c) || mts_isupper(c))
+#define mts_isdigit(c) _mts_between('0', (c), '9')
+#define mts_isalnum(c) (mts_isalpha(c) || mts_isdigit(c))
+#define mts_isxdigit(c) (mts_isdigit(c) || \
+ _mts_between('a', (c), 'f') || \
+ _mts_between('A', (c), 'F'))
+#define mts_isblank(c) ((c) == ' ' || (c) == '\t')
+#define mts_isspace(c) ((c) == ' ' || \
+ (c) == '\t' || \
+ (c) == '\n' || \
+ (c) == '\r' || \
+ (c) == '\f')
+#define mts_isascii(c) (!((c) &~ 0x7F))
+
+/* These macros only apply to ASCII */
+#define mts_isalpha_ascii(c) \
+ (_mts_between('a', (c), 'z') || _mts_between('A', (c), 'Z'))
+#define mts_isalnum_ascii(c) (mts_isalpha_ascii(c) || mts_isdigit(c))
+
+/* should it include non-ascii characters ? */
+#define mts_isprint(c) _mts_between('!', (c), '~')
+#define mts_iscntrl(c) (((c) >= 0) && ((c) <= 0x1f)) || ((c) == 0x7f))
+#define mts_ispunct(c) (mts_isprint(c) && !mts_isxdigit(c) && !mts_isspace(c))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CTYPE_H */
diff --git a/usr/src/uts/common/smbsrv/doserror.h b/usr/src/uts/common/smbsrv/doserror.h
new file mode 100644
index 0000000000..a5703e1b49
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/doserror.h
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+
+#ifndef _SMBSRV_DOSERROR_H
+#define _SMBSRV_DOSERROR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the list of DOS error codes. I think the error
+ * codes are divided into different classes, which is why there are
+ * duplicate values.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Error source or class
+ */
+#define SUCCESS 0x00 /* The request was successful. */
+#define ERRDOS 0x01 /* Core DOS operating system error. */
+#define ERRSRV 0x02 /* Server network file error */
+#define ERRHRD 0x03 /* Hardware error */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+
+/*
+ * ERRDOS error codes
+ */
+#define ERRbadfunc 1 /* Invalid function. The server did not */
+#define ERRbadfile 2 /* File not found. The last component of a */
+#define ERRbadpath 3 /* Directory invalid. A directory component in */
+#define ERRnofids 4 /* Too many open files. The server has no file */
+#define ERRnoaccess 5 /* Access denied, the client's context does not */
+#define ERRbadfid 6 /* Invalid file handle. The file handle */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Insufficient server memory to perform the */
+#define ERRbadmem 9 /* Invalid memory block address. */
+#define ERRbadenv 10 /* Invalid environment. */
+#define ERRbadformat 11 /* Invalid format. */
+#define ERRbadaccess 12 /* Invalid open mode. */
+#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls */
+#define ERRbaddrive 15 /* Invalid drive specified. */
+#define ERRremcd 16 /* A Delete Directory request attempted to */
+#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename */
+#define ERRnofiles 18 /* A File Search command can find no more files */
+#define ERRbadshare 32 /* The sharing mode specified for an Open */
+#define ERRlock 33 /* A Lock request conflicted with an existing */
+#define ERRfilexists 80 /* The file named in a Create Directory, Make */
+#define ERRnotlocked 158 /* No lock matched the unlock range */
+#define ERRnoatomiclocks 174 /* Change lock type not supported */
+#define ERRbadpipe 230 /* Pipe invalid. */
+#define ERRpipebusy 231 /* All instances of the requested pipe are busy. */
+#define ERRpipeclosing 232 /* Pipe close in progress. */
+#define ERRnotconnected 233 /* No process on other end of pipe. */
+#define ERRmoredata 234 /* There is more data to be returned. */
+#define ERRunknownlevel 124
+
+
+/*
+ * ERRSRV error codes
+ */
+#define ERRerror 1 /* Non-specific error code. It is returned */
+#define ERRbadpw 2 /* Bad password - name/password pair in a Tree */
+#define ERRaccess 4 /* The client does not have the necessary access */
+#define ERRinvnid 5 /* The Tid specified in a command was invalid. */
+#define ERRinvnetname 6 /* Invalid network name in tree connect. */
+#define ERRinvdevice 7 /* Invalid device - printer request made to non- */
+#define ERRqfull 49 /* Print queue full (files) -- returned by open */
+#define ERRqtoobig 50 /* Print queue full -- no space. */
+#define ERRqeof 51 /* EOF on print queue dump. */
+#define ERRinvpfid 52 /* Invalid print file FID. */
+#define ERRsmbcmd 64 /* The server did not recognize the command */
+#define ERRsrverror 65 /* The server encountered an internal error, */
+#define ERRfilespecs 67 /* The Fid and pathname parameters contained an */
+#define ERRbadpermits 69 /* The access permissions specified for a file */
+#define ERRsetattrmode 71 /* The attribute mode in the Set File Attribute */
+#define ERRpaused 81 /* Server is paused. (reserved for messaging) */
+#define ERRmsgoff 82 /* Not receiving messages. (reserved for */
+#define ERRnoroom 83 /* No room to buffer message. (reserved for */
+#define ERRrmuns 87 /* Too many remote user names. (reserved for */
+#define ERRtimeout 88 /* Operation timed out. */
+#define ERRnoresource 89 /* No resources currently available for request. */
+#define ERRtoomanyuids 90 /* Too many Uids active on this session. */
+#define ERRbaduid 91 /* The Uid is not known as a valid user */
+#define ERRusempx 250 /* Temporarily unable to support Raw, use MPX */
+#define ERRusestd 251 /* Temporarily unable to support Raw, use */
+#define ERRcontmpx 252 /* Continue in MPX mode. */
+#define ERRnosupport 65535 /* Function not supported. */
+
+
+/*
+ * ERRHRD error codes
+ */
+#define ERRnowrite 19 /* Attempt to write on write-protected media */
+#define ERRbadunit 20 /* Unknown unit. */
+#define ERRnotready 21 /* Drive not ready. */
+#define ERRbadcmd 22 /* Unknown command. */
+#define ERRdata 23 /* Data error (CRC). */
+#define ERRbadreq 24 /* Bad request structure length. */
+#define ERRseek 25 /* Seek error. */
+#define ERRbadmedia 26 /* Unknown media type. */
+#define ERRbadsector 27 /* Sector not found. */
+#define ERRnopaper 28 /* Printer out of paper. */
+#define ERRwrite 29 /* Write fault. */
+#define ERRread 30 /* Read fault. */
+#define ERRgeneral 31 /* General failure. */
+#define ERRbadshare 32 /* A open conflicts with an existing open. */
+#define ERRlock 33 /* A Lock request conflicted with an existing */
+#define ERRwrongdisk 34 /* The wrong disk was found in a drive. */
+#define ERRFCBUnavail 35 /* No FCBs are available to process request. */
+#define ERRsharebufexc 36 /* A sharing buffer has been exceeded. */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_DOSERROR_H */
diff --git a/usr/src/uts/common/smbsrv/hash_table.h b/usr/src/uts/common/smbsrv/hash_table.h
new file mode 100755
index 0000000000..0e4586097c
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/hash_table.h
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_HASH_TABLE_H
+#define _SMBSRV_HASH_TABLE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * Interface definition for the hash table library. The hash table is a
+ * user-specified array of pointers to items. Hash collisions are handled
+ * using linked lists from the table entries. A handle is associated with
+ * each table, which is used to maintain the hash table.
+ *
+ * +------+ +-------+ +----+ +----+
+ * |handle|---> |index 0|--->|item|--->|item|--->
+ * | ... | +-------+ +----+ +----+
+ * | ... | |index 1|--->
+ * +------+ +-------+ +----+ +----+ +----+
+ * |index 2|--->|item|--->|item|--->|item|--->
+ * +-------+ +----+ +----+ +----+
+ * | ... |--->
+ * +-------+
+ * | ... |--->
+ * +-------+
+ * |index n|--->
+ * +-------+
+ *
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This is the hash multiplier value.
+ */
+#define HASH_MESH_VALUE 77
+
+/*
+ * Each entry (item) in the hash table has a linked-list pointer, a key,
+ * a pointer to some user defined data (which may be null) and some flags.
+ * The key is a user provided key and is used to position the item within
+ * the table. The linked-list is used to store items whose hash values
+ * collide. The data pointer is never dereferenced in the hash code so
+ * it may be a null pointer.
+ *
+ * The item bit flags are:
+ *
+ * HTIF_DELETE: Specifies that an item is marked for deletion (see
+ * ht_mark_delete and ht_clean_table).
+ */
+#define HTIF_MARKED_DELETED 0x01
+#define HT_DELETE HTIF_MARKED_DELETED
+
+typedef struct ht_item {
+ struct ht_item *hi_next;
+ char *hi_key;
+ void *hi_data;
+ size_t hi_flags;
+} HT_ITEM;
+
+/*
+ * HT_TABLE_ENTRY is an opaque structure (to the public) used to maintain
+ * a pointer to the hash table and the number of items in the table entry.
+ * This number shows number of both available items and those are marked
+ * as deleted.
+ */
+typedef struct ht_table_entry {
+ HT_ITEM *he_head;
+ size_t he_count;
+} HT_TABLE_ENTRY;
+
+/*
+ * The HT_HANDLE is an opaque handle that associates each request with
+ * a hash table. A handle is generated when a hash table is created and
+ * it is used to maintain all global data associated with the table.
+ *
+ * The handle bit flags are:
+ *
+ * HTHF_FIXED_KEY: Specifies that keys are fixed length and should
+ * not be assumed to be null terminated.
+ */
+#define HTHF_FIXED_KEY 0x01
+
+typedef struct ht_handle {
+ HT_TABLE_ENTRY *ht_table;
+ size_t ht_sequence;
+ size_t ht_table_size;
+ size_t ht_table_mask;
+ size_t ht_key_size;
+ size_t ht_total_items; /* show total number of available items */
+ size_t ht_flags;
+ size_t (*ht_hash)(struct ht_handle *handle, const char *key);
+ void (*ht_callback)(HT_ITEM *item);
+ int (*ht_cmp)(const char *key1, const char *key2, size_t n);
+} HT_HANDLE;
+
+/*
+ * Typedefs for the optional user-installable functions.
+ */
+typedef void (*HT_CALLBACK)(HT_ITEM *item);
+
+/*
+ * Compare function cast to make all compare
+ * functions look like strncmp.
+ */
+typedef int (*HT_CMP)(const char *, const char *, size_t);
+
+/*
+ * Iterator used with ht_findfirst and ht_findnext to walk through
+ * all the items in a hash table. The iterator should be treated as
+ * an opaque handle. The sequence number in the iterator is used
+ * to maintain consistency with the table on which the iteration
+ * is being performed. If the table sequence number changes, the
+ * iterator becomes invalid.
+ */
+typedef struct ht_iterator {
+ HT_HANDLE *hti_handle;
+ HT_ITEM *hti_item;
+ size_t hti_index;
+ size_t hti_sequence;
+} HT_ITERATOR;
+
+/*
+ * Public API to create and destroy hash tables, to change the hash
+ * function and to find out how many items are in a hash table.
+ */
+extern HT_HANDLE *ht_create_table(size_t table_size, size_t key_size,
+ size_t flags);
+extern void ht_destroy_table(HT_HANDLE *handle);
+extern void ht_set_cmpfn(HT_HANDLE *handle, HT_CMP cmpfn);
+extern size_t ht_get_total_items(HT_HANDLE *handle);
+
+/*
+ * Public API to add, remove, replace or find specific items
+ * in a hash table.
+ */
+extern HT_ITEM *ht_add_item(HT_HANDLE *handle, const char *key,
+ const void *data);
+extern HT_ITEM *ht_replace_item(HT_HANDLE *handle, const char *key,
+ const void *data);
+extern void *ht_remove_item(HT_HANDLE *handle, const char *key);
+extern HT_ITEM *ht_find_item(HT_HANDLE *handle, const char *key);
+
+/*
+ * Public API to iterate over a hash table. A mechanism is provided to
+ * mark items for deletion while searching the table so that the table
+ * is not modified during the search. When the search is complete, all
+ * of the marked items can be deleted by calling ht_clean_table. If
+ * the item data has been dynamically allocated, a callback can be
+ * registered to free the memory. The callback will be invoked with a
+ * pointer to each item as it is removed from the hash table.
+ */
+extern HT_ITEM *ht_findfirst(HT_HANDLE *handle, HT_ITERATOR *iterator);
+extern HT_ITEM *ht_findnext(HT_ITERATOR *iterator);
+extern void ht_mark_delete(HT_HANDLE *handle, HT_ITEM *item);
+extern void ht_clear_delete(HT_HANDLE *handle, HT_ITEM *item);
+extern size_t ht_clean_table(HT_HANDLE *handle);
+extern HT_CALLBACK ht_register_callback(HT_HANDLE *handle,
+ HT_CALLBACK callback);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_HASH_TABLE_H */
diff --git a/usr/src/uts/common/smbsrv/lm.h b/usr/src/uts/common/smbsrv/lm.h
new file mode 100644
index 0000000000..e1cc28c220
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lm.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+
+#ifndef _SMBSRV_LM_H
+#define _SMBSRV_LM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides global Lan Manager definitions.
+ */
+
+#include <smbsrv/wintypes.h>
+#include <syslog.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LM_H */
diff --git a/usr/src/uts/common/smbsrv/lmdfs.h b/usr/src/uts/common/smbsrv/lmdfs.h
new file mode 100644
index 0000000000..418c4a9ad2
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lmdfs.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.
+ */
+
+#ifndef _SMBSRV_LMDFS_H
+#define _SMBSRV_LMDFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * LAN Manager DFS interface definition.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * DFS Volume state
+ */
+#define DFS_VOLUME_STATE_OK 1
+#define DFS_VOLUME_STATE_INCONSISTENT 2
+#define DFS_VOLUME_STATE_OFFLINE 3
+#define DFS_VOLUME_STATE_ONLINE 4
+
+/*
+ * DFS Storage state
+ */
+#define DFS_STORAGE_STATE_OFFLINE 1
+#define DFS_STORAGE_STATE_ONLINE 2
+
+/*
+ * Flags:
+ * DFS_ADD_VOLUME: Add a new volume to the DFS if not already there.
+ * DFS_RESTORE_VOLUME: Volume/Replica is being restored - do not verify
+ * share etc.
+ */
+#define DFS_ADD_VOLUME 1
+#define DFS_RESTORE_VOLUME 2
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LMDFS_H */
diff --git a/usr/src/uts/common/smbsrv/lmerr.h b/usr/src/uts/common/smbsrv/lmerr.h
new file mode 100644
index 0000000000..13e8843bbc
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lmerr.h
@@ -0,0 +1,536 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_LMERR_H
+#define _SMBSRV_LMERR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains the LAN Manager network error definitions. All
+ * network error codes are relative to NERR_BASE (2100), assigned by
+ * Microsoft, to avoid conflicts with system and redirector error
+ * codes. It should be safe to mix NERR error codes with the Win32
+ * error codes defined in nterror.h.
+ *
+ * This file defines error codes in the range 2100 - 2999. NERR values
+ * must not exceed MAX_NERR (2999); values above this are used by other
+ * services.
+ *
+ * The range 2750-2799 has been allocated to the IBM LAN Server.
+ * The range 2900-2999 has been reserved for Microsoft OEMs.
+ *
+ * See lmcons.h for information on the full LANMAN error code range.
+ *
+ * See msdn.microsoft.com for additional information on the meaning
+ * of each error code.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NERR_Success 0
+
+#define NERR_BASE 2100
+
+/* UNUSED BASE+0 */
+/* UNUSED BASE+1 */
+#define NERR_NetNotStarted (NERR_BASE+2)
+#define NERR_UnknownServer (NERR_BASE+3)
+#define NERR_ShareMem (NERR_BASE+4)
+
+#define NERR_NoNetworkResource (NERR_BASE+5)
+#define NERR_RemoteOnly (NERR_BASE+6)
+#define NERR_DevNotRedirected (NERR_BASE+7)
+/* NERR_BASE+8 is used for ERROR_CONNECTED_OTHER_PASSWORD */
+/* UNUSED BASE+9 */
+/* UNUSED BASE+10 */
+/* UNUSED BASE+11 */
+/* UNUSED BASE+12 */
+/* UNUSED BASE+13 */
+#define NERR_ServerNotStarted (NERR_BASE+14)
+#define NERR_ItemNotFound (NERR_BASE+15)
+#define NERR_UnknownDevDir (NERR_BASE+16)
+#define NERR_RedirectedPath (NERR_BASE+17)
+#define NERR_DuplicateShare (NERR_BASE+18)
+#define NERR_NoRoom (NERR_BASE+19)
+/* UNUSED BASE+20 */
+#define NERR_TooManyItems (NERR_BASE+21)
+#define NERR_InvalidMaxUsers (NERR_BASE+22)
+#define NERR_BufTooSmall (NERR_BASE+23)
+/* UNUSED BASE+24 */
+/* UNUSED BASE+25 */
+/* UNUSED BASE+26 */
+#define NERR_RemoteErr (NERR_BASE+27)
+/* UNUSED BASE+28 */
+/* UNUSED BASE+29 */
+/* UNUSED BASE+30 */
+#define NERR_LanmanIniError (NERR_BASE+31)
+/* UNUSED BASE+32 */
+/* UNUSED BASE+33 */
+/* UNUSED BASE+34 */
+/* UNUSED BASE+35 */
+#define NERR_NetworkError (NERR_BASE+36)
+#define NERR_WkstaInconsistentState (NERR_BASE+37)
+#define NERR_WkstaNotStarted (NERR_BASE+38)
+#define NERR_BrowserNotStarted (NERR_BASE+39)
+#define NERR_InternalError (NERR_BASE+40)
+#define NERR_BadTransactConfig (NERR_BASE+41)
+#define NERR_InvalidAPI (NERR_BASE+42)
+#define NERR_BadEventName (NERR_BASE+43)
+#define NERR_DupNameReboot (NERR_BASE+44)
+
+/*
+ * Config API related
+ * Error codes from BASE+45 to BASE+49
+ */
+/* UNUSED BASE+45 */
+#define NERR_CfgCompNotFound (NERR_BASE+46)
+#define NERR_CfgParamNotFound (NERR_BASE+47)
+#define NERR_LineTooLong (NERR_BASE+49)
+
+/*
+ * Spooler API related
+ * Error codes from BASE+50 to BASE+79
+ */
+#define NERR_QNotFound (NERR_BASE+50)
+#define NERR_JobNotFound (NERR_BASE+51)
+#define NERR_DestNotFound (NERR_BASE+52)
+#define NERR_DestExists (NERR_BASE+53)
+#define NERR_QExists (NERR_BASE+54)
+#define NERR_QNoRoom (NERR_BASE+55)
+#define NERR_JobNoRoom (NERR_BASE+56)
+#define NERR_DestNoRoom (NERR_BASE+57)
+#define NERR_DestIdle (NERR_BASE+58)
+#define NERR_DestInvalidOp (NERR_BASE+59)
+#define NERR_ProcNoRespond (NERR_BASE+60)
+#define NERR_SpoolerNotLoaded (NERR_BASE+61)
+#define NERR_DestInvalidState (NERR_BASE+62)
+#define NERR_QInvalidState (NERR_BASE+63)
+#define NERR_JobInvalidState (NERR_BASE+64)
+#define NERR_SpoolNoMemory (NERR_BASE+65)
+#define NERR_DriverNotFound (NERR_BASE+66)
+#define NERR_DataTypeInvalid (NERR_BASE+67)
+#define NERR_ProcNotFound (NERR_BASE+68)
+
+/*
+ * Service API related
+ * Error codes from BASE+80 to BASE+99
+ */
+#define NERR_ServiceTableLocked (NERR_BASE+80)
+#define NERR_ServiceTableFull (NERR_BASE+81)
+#define NERR_ServiceInstalled (NERR_BASE+82)
+#define NERR_ServiceEntryLocked (NERR_BASE+83)
+#define NERR_ServiceNotInstalled (NERR_BASE+84)
+#define NERR_BadServiceName (NERR_BASE+85)
+#define NERR_ServiceCtlTimeout (NERR_BASE+86)
+#define NERR_ServiceCtlBusy (NERR_BASE+87)
+#define NERR_BadServiceProgName (NERR_BASE+88)
+#define NERR_ServiceNotCtrl (NERR_BASE+89)
+#define NERR_ServiceKillProc (NERR_BASE+90)
+#define NERR_ServiceCtlNotValid (NERR_BASE+91)
+#define NERR_NotInDispatchTbl (NERR_BASE+92)
+#define NERR_BadControlRecv (NERR_BASE+93)
+#define NERR_ServiceNotStarting (NERR_BASE+94)
+
+/*
+ * Wksta and Logon API related
+ * Error codes from BASE+100 to BASE+118
+ */
+#define NERR_AlreadyLoggedOn (NERR_BASE+100)
+#define NERR_NotLoggedOn (NERR_BASE+101)
+#define NERR_BadUsername (NERR_BASE+102)
+#define NERR_BadPassword (NERR_BASE+103)
+#define NERR_UnableToAddName_W (NERR_BASE+104)
+#define NERR_UnableToAddName_F (NERR_BASE+105)
+#define NERR_UnableToDelName_W (NERR_BASE+106)
+#define NERR_UnableToDelName_F (NERR_BASE+107)
+/* UNUSED BASE+108 */
+#define NERR_LogonsPaused (NERR_BASE+109)
+#define NERR_LogonServerConflict (NERR_BASE+110)
+#define NERR_LogonNoUserPath (NERR_BASE+111)
+#define NERR_LogonScriptError (NERR_BASE+112)
+/* UNUSED BASE+113 */
+#define NERR_StandaloneLogon (NERR_BASE+114)
+#define NERR_LogonServerNotFound (NERR_BASE+115)
+#define NERR_LogonDomainExists (NERR_BASE+116)
+#define NERR_NonValidatedLogon (NERR_BASE+117)
+
+/*
+ * ACF API related (access, user, group)
+ * Error codes from BASE+119 to BASE+149
+ */
+#define NERR_ACFNotFound (NERR_BASE+119)
+#define NERR_GroupNotFound (NERR_BASE+120)
+#define NERR_UserNotFound (NERR_BASE+121)
+#define NERR_ResourceNotFound (NERR_BASE+122)
+#define NERR_GroupExists (NERR_BASE+123)
+#define NERR_UserExists (NERR_BASE+124)
+#define NERR_ResourceExists (NERR_BASE+125)
+#define NERR_NotPrimary (NERR_BASE+126)
+#define NERR_ACFNotLoaded (NERR_BASE+127)
+#define NERR_ACFNoRoom (NERR_BASE+128)
+#define NERR_ACFFileIOFail (NERR_BASE+129)
+#define NERR_ACFTooManyLists (NERR_BASE+130)
+#define NERR_UserLogon (NERR_BASE+131)
+#define NERR_ACFNoParent (NERR_BASE+132)
+#define NERR_CanNotGrowSegment (NERR_BASE+133)
+#define NERR_SpeGroupOp (NERR_BASE+134)
+#define NERR_NotInCache (NERR_BASE+135)
+#define NERR_UserInGroup (NERR_BASE+136)
+#define NERR_UserNotInGroup (NERR_BASE+137)
+#define NERR_AccountUndefined (NERR_BASE+138)
+#define NERR_AccountExpired (NERR_BASE+139)
+#define NERR_InvalidWorkstation (NERR_BASE+140)
+#define NERR_InvalidLogonHours (NERR_BASE+141)
+#define NERR_PasswordExpired (NERR_BASE+142)
+#define NERR_PasswordCantChange (NERR_BASE+143)
+#define NERR_PasswordHistConflict (NERR_BASE+144)
+#define NERR_PasswordTooShort (NERR_BASE+145)
+#define NERR_PasswordTooRecent (NERR_BASE+146)
+#define NERR_InvalidDatabase (NERR_BASE+147)
+#define NERR_DatabaseUpToDate (NERR_BASE+148)
+#define NERR_SyncRequired (NERR_BASE+149)
+
+/*
+ * Use API related
+ * Error codes from BASE+150 to BASE+169
+ */
+#define NERR_UseNotFound (NERR_BASE+150)
+#define NERR_BadAsgType (NERR_BASE+151)
+#define NERR_DeviceIsShared (NERR_BASE+152)
+
+/*
+ * Message Server related
+ * Error codes BASE+170 to BASE+209
+ */
+#define NERR_NoComputerName (NERR_BASE+170)
+#define NERR_MsgAlreadyStarted (NERR_BASE+171)
+#define NERR_MsgInitFailed (NERR_BASE+172)
+#define NERR_NameNotFound (NERR_BASE+173)
+#define NERR_AlreadyForwarded (NERR_BASE+174)
+#define NERR_AddForwarded (NERR_BASE+175)
+#define NERR_AlreadyExists (NERR_BASE+176)
+#define NERR_TooManyNames (NERR_BASE+177)
+#define NERR_DelComputerName (NERR_BASE+178)
+#define NERR_LocalForward (NERR_BASE+179)
+#define NERR_GrpMsgProcessor (NERR_BASE+180)
+#define NERR_PausedRemote (NERR_BASE+181)
+#define NERR_BadReceive (NERR_BASE+182)
+#define NERR_NameInUse (NERR_BASE+183)
+#define NERR_MsgNotStarted (NERR_BASE+184)
+#define NERR_NotLocalName (NERR_BASE+185)
+#define NERR_NoForwardName (NERR_BASE+186)
+#define NERR_RemoteFull (NERR_BASE+187)
+#define NERR_NameNotForwarded (NERR_BASE+188)
+#define NERR_TruncatedBroadcast (NERR_BASE+189)
+#define NERR_InvalidDevice (NERR_BASE+194)
+#define NERR_WriteFault (NERR_BASE+195)
+/* UNUSED BASE+196 */
+#define NERR_DuplicateName (NERR_BASE+197)
+#define NERR_DeleteLater (NERR_BASE+198)
+#define NERR_IncompleteDel (NERR_BASE+199)
+#define NERR_MultipleNets (NERR_BASE+200)
+
+/*
+ * Server API related
+ * Error codes BASE+210 to BASE+229
+ */
+#define NERR_NetNameNotFound (NERR_BASE+210)
+#define NERR_DeviceNotShared (NERR_BASE+211)
+#define NERR_ClientNameNotFound (NERR_BASE+212)
+#define NERR_FileIdNotFound (NERR_BASE+214)
+#define NERR_ExecFailure (NERR_BASE+215)
+#define NERR_TmpFile (NERR_BASE+216)
+#define NERR_TooMuchData (NERR_BASE+217)
+#define NERR_DeviceShareConflict (NERR_BASE+218)
+#define NERR_BrowserTableIncomplete (NERR_BASE+219)
+#define NERR_NotLocalDomain (NERR_BASE+220)
+#define NERR_IsDfsShare (NERR_BASE+221)
+
+/*
+ * CharDev API related
+ * Error codes BASE+230 to BASE+249
+ */
+/* UNUSED BASE+230 */
+#define NERR_DevInvalidOpCode (NERR_BASE+231)
+#define NERR_DevNotFound (NERR_BASE+232)
+#define NERR_DevNotOpen (NERR_BASE+233)
+#define NERR_BadQueueDevString (NERR_BASE+234)
+#define NERR_BadQueuePriority (NERR_BASE+235)
+#define NERR_NoCommDevs (NERR_BASE+237)
+#define NERR_QueueNotFound (NERR_BASE+238)
+#define NERR_BadDevString (NERR_BASE+240)
+#define NERR_BadDev (NERR_BASE+241)
+#define NERR_InUseBySpooler (NERR_BASE+242)
+#define NERR_CommDevInUse (NERR_BASE+243)
+
+/*
+ * NetICanonicalize and NetIType and NetIMakeLMFileName
+ * NetIListCanon and NetINameCheck
+ * Error codes BASE+250 to BASE+269
+ */
+#define NERR_InvalidComputer (NERR_BASE+251)
+/* UNUSED BASE+252 */
+/* UNUSED BASE+253 */
+#define NERR_MaxLenExceeded (NERR_BASE+254)
+/* UNUSED BASE+255 */
+#define NERR_BadComponent (NERR_BASE+256)
+#define NERR_CantType (NERR_BASE+257)
+/* UNUSED BASE+258 */
+/* UNUSED BASE+259 */
+#define NERR_TooManyEntries (NERR_BASE+262)
+
+/*
+ * NetProfile
+ * Error codes BASE+270 to BASE+276
+ */
+#define NERR_ProfileFileTooBig (NERR_BASE+270)
+#define NERR_ProfileOffset (NERR_BASE+271)
+#define NERR_ProfileCleanup (NERR_BASE+272)
+#define NERR_ProfileUnknownCmd (NERR_BASE+273)
+#define NERR_ProfileLoadErr (NERR_BASE+274)
+#define NERR_ProfileSaveErr (NERR_BASE+275)
+
+/*
+ * NetAudit and NetErrorLog
+ * Error codes BASE+277 to BASE+279
+ */
+#define NERR_LogOverflow (NERR_BASE+277)
+#define NERR_LogFileChanged (NERR_BASE+278)
+#define NERR_LogFileCorrupt (NERR_BASE+279)
+
+/*
+ * NetRemote
+ * Error codes BASE+280 to BASE+299
+ */
+#define NERR_SourceIsDir (NERR_BASE+280)
+#define NERR_BadSource (NERR_BASE+281)
+#define NERR_BadDest (NERR_BASE+282)
+#define NERR_DifferentServers (NERR_BASE+283)
+/* UNUSED BASE+284 */
+#define NERR_RunSrvPaused (NERR_BASE+285)
+/* UNUSED BASE+286 */
+/* UNUSED BASE+287 */
+/* UNUSED BASE+288 */
+#define NERR_ErrCommRunSrv (NERR_BASE+289)
+/* UNUSED BASE+290 */
+#define NERR_ErrorExecingGhost (NERR_BASE+291)
+#define NERR_ShareNotFound (NERR_BASE+292)
+/* UNUSED BASE+293 */
+/* UNUSED BASE+294 */
+
+
+/*
+ * NetWksta.sys (redir) returned error codes.
+ * NERR_BASE + (300-329)
+ */
+#define NERR_InvalidLana (NERR_BASE+300)
+#define NERR_OpenFiles (NERR_BASE+301)
+#define NERR_ActiveConns (NERR_BASE+302)
+#define NERR_BadPasswordCore (NERR_BASE+303)
+#define NERR_DevInUse (NERR_BASE+304)
+#define NERR_LocalDrive (NERR_BASE+305)
+
+/*
+ * Alert error codes.
+ * NERR_BASE + (330-339)
+ */
+#define NERR_AlertExists (NERR_BASE+330)
+#define NERR_TooManyAlerts (NERR_BASE+331)
+#define NERR_NoSuchAlert (NERR_BASE+332)
+#define NERR_BadRecipient (NERR_BASE+333)
+#define NERR_AcctLimitExceeded (NERR_BASE+334)
+
+/*
+ * Additional Error and Audit log codes.
+ * NERR_BASE +(340-343)
+ */
+#define NERR_InvalidLogSeek (NERR_BASE+340)
+/* UNUSED BASE+341 */
+/* UNUSED BASE+342 */
+/* UNUSED BASE+343 */
+
+/*
+ * Additional UAS and NETLOGON codes
+ * NERR_BASE +(350-359)
+ */
+#define NERR_BadUasConfig (NERR_BASE+350)
+#define NERR_InvalidUASOp (NERR_BASE+351)
+#define NERR_LastAdmin (NERR_BASE+352)
+#define NERR_DCNotFound (NERR_BASE+353)
+#define NERR_LogonTrackingError (NERR_BASE+354)
+#define NERR_NetlogonNotStarted (NERR_BASE+355)
+#define NERR_CanNotGrowUASFile (NERR_BASE+356)
+#define NERR_TimeDiffAtDC (NERR_BASE+357)
+#define NERR_PasswordMismatch (NERR_BASE+358)
+
+/*
+ * Server Integration error codes.
+ * NERR_BASE +(360-369)
+ */
+#define NERR_NoSuchServer (NERR_BASE+360)
+#define NERR_NoSuchSession (NERR_BASE+361)
+#define NERR_NoSuchConnection (NERR_BASE+362)
+#define NERR_TooManyServers (NERR_BASE+363)
+#define NERR_TooManySessions (NERR_BASE+364)
+#define NERR_TooManyConnections (NERR_BASE+365)
+#define NERR_TooManyFiles (NERR_BASE+366)
+#define NERR_NoAlternateServers (NERR_BASE+367)
+/* UNUSED BASE+368 */
+/* UNUSED BASE+369 */
+#define NERR_TryDownLevel (NERR_BASE+370)
+
+/*
+ * UPS error codes.
+ * NERR_BASE + (380-384)
+ */
+#define NERR_UPSDriverNotStarted (NERR_BASE+380)
+#define NERR_UPSInvalidConfig (NERR_BASE+381)
+#define NERR_UPSInvalidCommPort (NERR_BASE+382)
+#define NERR_UPSSignalAsserted (NERR_BASE+383)
+#define NERR_UPSShutdownFailed (NERR_BASE+384)
+
+/*
+ * Remoteboot error codes.
+ * NERR_BASE + (400-419)
+ * Error codes 400 - 405 are used by RPLBOOT.SYS.
+ * Error codes 403, 407 - 416 are used by RPLLOADR.COM,
+ * Error code 417 is the alerter message of REMOTEBOOT (RPLSERVR.EXE).
+ * Error code 418 is for when REMOTEBOOT can't start
+ * Error code 419 is for a disallowed 2nd rpl connection
+ */
+#define NERR_BadDosRetCode (NERR_BASE+400)
+#define NERR_ProgNeedsExtraMem (NERR_BASE+401)
+#define NERR_BadDosFunction (NERR_BASE+402)
+#define NERR_RemoteBootFailed (NERR_BASE+403)
+#define NERR_BadFileCheckSum (NERR_BASE+404)
+#define NERR_NoRplBootSystem (NERR_BASE+405)
+#define NERR_RplLoadrNetBiosErr (NERR_BASE+406)
+#define NERR_RplLoadrDiskErr (NERR_BASE+407)
+#define NERR_ImageParamErr (NERR_BASE+408)
+#define NERR_TooManyImageParams (NERR_BASE+409)
+#define NERR_NonDosFloppyUsed (NERR_BASE+410)
+#define NERR_RplBootRestart (NERR_BASE+411)
+#define NERR_RplSrvrCallFailed (NERR_BASE+412)
+#define NERR_CantConnectRplSrvr (NERR_BASE+413)
+#define NERR_CantOpenImageFile (NERR_BASE+414)
+#define NERR_CallingRplSrvr (NERR_BASE+415)
+#define NERR_StartingRplBoot (NERR_BASE+416)
+#define NERR_RplBootServiceTerm (NERR_BASE+417)
+#define NERR_RplBootStartFailed (NERR_BASE+418)
+#define NERR_RPL_CONNECTED (NERR_BASE+419)
+
+/*
+ * FTADMIN API error codes
+ * NERR_BASE + (425-434)
+ * (Currently not used in NT)
+ */
+
+/*
+ * Browser service API error codes
+ * NERR_BASE + (450-475)
+ */
+#define NERR_BrowserConfiguredToNotRun (NERR_BASE+450)
+
+/*
+ * Additional Remoteboot error codes.
+ * NERR_BASE + (510-550)
+ */
+#define NERR_RplNoAdaptersStarted (NERR_BASE+510)
+#define NERR_RplBadRegistry (NERR_BASE+511)
+#define NERR_RplBadDatabase (NERR_BASE+512)
+#define NERR_RplRplfilesShare (NERR_BASE+513)
+#define NERR_RplNotRplServer (NERR_BASE+514)
+#define NERR_RplCannotEnum (NERR_BASE+515)
+#define NERR_RplWkstaInfoCorrupted (NERR_BASE+516)
+#define NERR_RplWkstaNotFound (NERR_BASE+517)
+#define NERR_RplWkstaNameUnavailable (NERR_BASE+518)
+#define NERR_RplProfileInfoCorrupted (NERR_BASE+519)
+#define NERR_RplProfileNotFound (NERR_BASE+520)
+#define NERR_RplProfileNameUnavailable (NERR_BASE+521)
+#define NERR_RplProfileNotEmpty (NERR_BASE+522)
+#define NERR_RplConfigInfoCorrupted (NERR_BASE+523)
+#define NERR_RplConfigNotFound (NERR_BASE+524)
+#define NERR_RplAdapterInfoCorrupted (NERR_BASE+525)
+#define NERR_RplInternal (NERR_BASE+526)
+#define NERR_RplVendorInfoCorrupted (NERR_BASE+527)
+#define NERR_RplBootInfoCorrupted (NERR_BASE+528)
+#define NERR_RplWkstaNeedsUserAcct (NERR_BASE+529)
+#define NERR_RplNeedsRPLUSERAcct (NERR_BASE+530)
+#define NERR_RplBootNotFound (NERR_BASE+531)
+#define NERR_RplIncompatibleProfile (NERR_BASE+532)
+#define NERR_RplAdapterNameUnavailable (NERR_BASE+533)
+#define NERR_RplConfigNotEmpty (NERR_BASE+534)
+#define NERR_RplBootInUse (NERR_BASE+535)
+#define NERR_RplBackupDatabase (NERR_BASE+536)
+#define NERR_RplAdapterNotFound (NERR_BASE+537)
+#define NERR_RplVendorNotFound (NERR_BASE+538)
+#define NERR_RplVendorNameUnavailable (NERR_BASE+539)
+#define NERR_RplBootNameUnavailable (NERR_BASE+540)
+#define NERR_RplConfigNameUnavailable (NERR_BASE+541)
+
+/*
+ * Dfs API error codes.
+ * NERR_BASE + (560-590)
+ */
+#define NERR_DfsInternalCorruption (NERR_BASE+560)
+#define NERR_DfsVolumeDataCorrupt (NERR_BASE+561)
+#define NERR_DfsNoSuchVolume (NERR_BASE+562)
+#define NERR_DfsVolumeAlreadyExists (NERR_BASE+563)
+#define NERR_DfsAlreadyShared (NERR_BASE+564)
+#define NERR_DfsNoSuchShare (NERR_BASE+565)
+#define NERR_DfsNotALeafVolume (NERR_BASE+566)
+#define NERR_DfsLeafVolume (NERR_BASE+567)
+#define NERR_DfsVolumeHasMultipleServers (NERR_BASE+568)
+#define NERR_DfsCantCreateJunctionPoint (NERR_BASE+569)
+#define NERR_DfsServerNotDfsAware (NERR_BASE+570)
+#define NERR_DfsBadRenamePath (NERR_BASE+571)
+#define NERR_DfsVolumeIsOffline (NERR_BASE+572)
+#define NERR_DfsNoSuchServer (NERR_BASE+573)
+#define NERR_DfsCyclicalName (NERR_BASE+574)
+#define NERR_DfsNotSupportedInServerDfs (NERR_BASE+575)
+#define NERR_DfsInternalError (NERR_BASE+590)
+
+/*
+ * Net setup error codes.
+ * NERR_BASE + (591-595)
+ */
+#define NERR_SetupAlreadyJoined (NERR_BASE+591)
+#define NERR_SetupNotJoined (NERR_BASE+592)
+#define NERR_SetupDomainController (NERR_BASE+593)
+
+/*
+ * MAX_NERR is the last value in the NERR range.
+ * Do not exceed this value here.
+ */
+#define MAX_NERR (NERR_BASE+899)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LMERR_H */
diff --git a/usr/src/uts/common/smbsrv/lmshare.h b/usr/src/uts/common/smbsrv/lmshare.h
new file mode 100644
index 0000000000..db41a5bdee
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lmshare.h
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_LMSHARE_H
+#define _SMBSRV_LMSHARE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the LanMan (CIFS/SMB) resource share interface.
+ */
+
+#include <sys/param.h>
+#include <smbsrv/string.h>
+#include <smbsrv/hash_table.h>
+#include <smbsrv/smb_fsd.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/lmerr.h>
+
+#ifndef _KERNEL
+#include <libshare.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHOPT_AD_CONTAINER "ad-container"
+#define SHOPT_NAME "name" /* name is a pseudo property */
+
+#define SMB_DEFAULT_SHARE_GROUP "smb"
+#define SMB_PROTOCOL_NAME "smb"
+
+/*
+ * Despite the fact that the MAXNAMELEN is 256, we only
+ * support a maximum share name length of 15 characters.
+ */
+#define LMSHR_VALID_NAME_MAX 15
+#define LMSHR_VALID_NAME_BUFSIZ 16
+#define LMSHR_COMMENT_MAX (64 * MTS_MB_CHAR_MAX)
+
+/*
+ * Mode should be renamed to flags.
+ *
+ * LMSHRM_TRANS Transient share
+ * LMSHRM_PERM Permanent share
+ */
+#define LMSHRM_TRANS 0x0001
+#define LMSHRM_PERM 0x0002
+#define LMSHRM_ALL (LMSHRM_TRANS | LMSHRM_PERM)
+
+#define LMSHR_PUBLISH 0
+#define LMSHR_UNPUBLISH 1
+
+#define LMSHR_ADD 0
+#define LMSHR_DELETE 1
+
+
+/*
+ * refcnt is currently only used for autohome. autohome needs a refcnt
+ * because a user can map his autohome share from more than one client
+ * at the same time and the share should only be removed when the last
+ * one is disconnected
+ */
+typedef struct lmshare_info {
+ char share_name[MAXNAMELEN];
+ char directory[MAXPATHLEN];
+ char comment[LMSHR_COMMENT_MAX];
+ char container[MAXPATHLEN];
+ int mode;
+ int stype;
+ int refcnt;
+} lmshare_info_t;
+
+typedef struct lmshare_iterator {
+ lmshare_info_t si;
+ HT_ITERATOR *iterator;
+ unsigned int iteration;
+ int mode;
+} lmshare_iterator_t;
+
+#define LMSHARES_PER_REQUEST 10
+typedef struct lmshare_list {
+ int no;
+ lmshare_info_t smbshr[LMSHARES_PER_REQUEST];
+} lmshare_list_t;
+
+
+#ifndef _KERNEL
+/*
+ * CIFS share management functions (private to the smb daemon).
+ */
+extern int lmshare_start(void);
+extern void lmshare_stop(void);
+extern lmshare_iterator_t *lmshare_open_iterator(int mode);
+extern void lmshare_close_iterator(lmshare_iterator_t *iterator);
+extern lmshare_info_t *lmshare_iterate(lmshare_iterator_t *iterator);
+
+extern DWORD lmshare_list(int offset, lmshare_list_t *list);
+extern DWORD lmshare_list_transient(int offset, lmshare_list_t *list);
+extern int lmshare_num_transient(void);
+
+extern int lmshare_num_shares(void);
+extern DWORD lmshare_add(lmshare_info_t *si, int);
+extern DWORD lmshare_delete(char *share_name, int);
+extern DWORD lmshare_rename(char *from, char *to, int);
+extern DWORD lmshare_getinfo(char *share_name, lmshare_info_t *si);
+extern DWORD lmshare_setinfo(lmshare_info_t *si, int);
+extern DWORD lmshare_get_realpath(const char *srcbuf, char *dstbuf, int maxlen);
+extern void lmshare_do_publish(lmshare_info_t *, char, int);
+
+extern int lmshare_exists(char *share_name);
+extern int lmshare_is_special(char *share_name);
+extern int lmshare_is_restricted(char *share_name);
+extern int lmshare_is_admin(char *share_name);
+extern int lmshare_is_valid(char *share_name);
+extern int lmshare_is_dir(char *path);
+/* XXX Move these 2 functions in mlsvc_util.h, after the libmlsvc cleanup */
+extern sa_group_t smb_get_smb_share_group(sa_handle_t handle);
+extern void smb_build_lmshare_info(char *share_name, char *path,
+ sa_optionset_t opts, lmshare_info_t *si);
+
+/* The following 3 functions are called by FSD user-space library */
+extern DWORD lmshare_add_adminshare(char *volname, unsigned char drive);
+
+#endif /* _KERNEL */
+
+/*
+ * LanMan share API (for both SMB kernel module and GUI/CLI sub-system)
+ *
+ * NOTE: If any error is encounted by either the door server or client,
+ * NERR_InternalError will be returned by most functions.
+ * lmshrd_num_shares will return -1 while the lmshrd_open_iterator/
+ * lmshrd_close_iterator will return NULL.
+ */
+
+extern uint64_t lmshrd_open_iterator(int mode);
+extern DWORD lmshrd_close_iterator(uint64_t iterator);
+extern DWORD lmshrd_iterate(uint64_t iterator, lmshare_info_t *si);
+#ifndef _KERNEL
+extern DWORD lmshrd_list(int offset, lmshare_list_t *list);
+extern DWORD lmshrd_list_transient(int offset, lmshare_list_t *list);
+extern DWORD lmshrd_num_transient(void);
+extern int lmshrd_dump_hash(char *logfname);
+#endif
+extern int lmshrd_num_shares(void);
+extern DWORD lmshrd_delete(char *share_name);
+extern DWORD lmshrd_rename(char *from, char *to);
+extern DWORD lmshrd_getinfo(char *share_name, lmshare_info_t *si);
+extern DWORD lmshrd_add(lmshare_info_t *si);
+extern DWORD lmshrd_setinfo(lmshare_info_t *si);
+
+extern int lmshrd_exists(char *share_name);
+extern int lmshrd_is_special(char *share_name);
+extern int lmshrd_is_restricted(char *share_name);
+extern int lmshrd_is_admin(char *share_name);
+extern int lmshrd_is_valid(char *share_name);
+extern int lmshrd_is_dir(char *path);
+
+/*
+ * The SMB kernel module must invoke the following functions to start/stop
+ * the LanMan share door client.
+ */
+#ifdef _KERNEL
+extern int lmshrd_kclient_start(void);
+extern void lmshrd_kclient_stop(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LMSHARE_H */
diff --git a/usr/src/uts/common/smbsrv/lmshare_door.h b/usr/src/uts/common/smbsrv/lmshare_door.h
new file mode 100644
index 0000000000..c1c6f2ba0c
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lmshare_door.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.
+ */
+
+#ifndef _SMBSRV_LMSHARE_DOOR_H
+#define _SMBSRV_LMSHARE_DOOR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smbinfo.h>
+
+/*
+ * Door interface for CIFS share management.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LMSHR_DOOR_NAME "/var/run/smb_lmshare_door"
+#define LMSHR_DOOR_VERSION 1
+
+#define LMSHR_DOOR_COOKIE ((void*)(0xdeadbeef^LMSHR_DOOR_VERSION))
+#define LMSHR_DOOR_SIZE (sizeof (lmshare_list_t) + 32)
+
+/*
+ * Door interface
+ *
+ * Define door operations
+ */
+#define LMSHR_DOOR_OPEN_ITERATOR 1
+#define LMSHR_DOOR_CLOSE_ITERATOR 2
+#define LMSHR_DOOR_ITERATE 3
+#define LMSHR_DOOR_NUM_SHARES 4
+#define LMSHR_DOOR_DELETE 5
+#define LMSHR_DOOR_RENAME 6
+#define LMSHR_DOOR_GETINFO 7
+#define LMSHR_DOOR_ADD 8
+#define LMSHR_DOOR_SETINFO 9
+#define LMSHR_DOOR_EXISTS 10
+#define LMSHR_DOOR_IS_SPECIAL 11
+#define LMSHR_DOOR_IS_RESTRICTED 12
+#define LMSHR_DOOR_IS_ADMIN 13
+#define LMSHR_DOOR_IS_VALID 14
+#define LMSHR_DOOR_IS_DIR 15
+#define LMSHR_DOOR_LIST 16
+
+#define SMB_GET_KCONFIG 17
+
+void smb_load_kconfig(smb_kmod_cfg_t *cfg);
+void smb_dr_get_kconfig(smb_dr_ctx_t *ctx, smb_kmod_cfg_t *cfg);
+void smb_dr_put_kconfig(smb_dr_ctx_t *ctx, smb_kmod_cfg_t *cfg);
+
+/*
+ * Door server status
+ *
+ * LMSHR_DOOR_ERROR is returned by the door server if there is problem
+ * with marshalling/unmarshalling. Otherwise, LMSHR_DOOR_SUCCESS is
+ * returned.
+ *
+ */
+#define LMSHR_DOOR_SRV_SUCCESS 0
+#define LMSHR_DOOR_SRV_ERROR -1
+
+/*
+ * struct door_request {
+ * int req_type;
+ * <parameters>
+ * };
+ *
+ * struct door_response {
+ * int door_srv_status;
+ * <response>
+ * };
+ */
+
+void smb_dr_get_lmshare(smb_dr_ctx_t *ctx, lmshare_info_t *si);
+void smb_dr_put_lmshare(smb_dr_ctx_t *ctx, lmshare_info_t *si);
+
+uint64_t smb_dr_get_lmshr_iterator(smb_dr_ctx_t *ctx);
+void smb_dr_put_lmshr_iterator(smb_dr_ctx_t *ctx,
+ uint64_t lmshr_iter);
+void smb_dr_free_lmshr_iterator(smb_dr_ctx_t *ctx);
+void smb_dr_get_lmshr_list(smb_dr_ctx_t *ctx,
+ lmshare_list_t *shrlist);
+void smb_dr_put_lmshr_list(smb_dr_ctx_t *ctx,
+ lmshare_list_t *shrlist);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LMSHARE_DOOR_H */
diff --git a/usr/src/uts/common/smbsrv/lsalib.h b/usr/src/uts/common/smbsrv/lsalib.h
new file mode 100644
index 0000000000..b8566bf342
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lsalib.h
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_LSALIB_H
+#define _SMBSRV_LSALIB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Prototypes for the LSA library and RPC client side library interface.
+ * There are two levels of interface defined here: lsa_xxx and lsar_xxx.
+ * The lsa_xxx functions provide a high level interface which make
+ * multiple RPC calls and do all the work necessary to obtain and return
+ * the requested information. The lsar_xxx functions provide a low level
+ * interface in which each function maps to a single underlying RPC.
+ */
+
+#include <smbsrv/ndl/lsarpc.ndl>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ntsid.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * lsalib.c
+ */
+int lsa_lookup_builtin_name(char *account_name,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_local_sam(char *domain,
+ char *account_name,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_local(char *name,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_name(char *server,
+ char *domain,
+ char *account_name,
+ smb_userinfo_t *user_info);
+
+DWORD lsa_lookup_name2(char *server,
+ char *domain,
+ char *account_name,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_sid(nt_sid_t *sid,
+ smb_userinfo_t *user_info);
+
+DWORD lsa_lookup_sid2(nt_sid_t *sid,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_privs(char *server,
+ char *account_name,
+ char *target_name,
+ smb_userinfo_t *user_info);
+
+int lsa_test(char *server, char *account_name);
+
+
+/*
+ * lsar_open.c
+ */
+int lsar_open(int ipc_mode,
+ char *server,
+ char *domain,
+ char *username,
+ char *password,
+ mlsvc_handle_t *domain_handle);
+
+int lsar_open_policy2(char *server,
+ char *domain,
+ char *username,
+ mlsvc_handle_t *lsa_handle);
+
+int lsar_open_account(mlsvc_handle_t *lsa_handle,
+ struct mslsa_sid *sid,
+ mlsvc_handle_t *lsa_account_handle);
+
+int lsar_close(mlsvc_handle_t *lsa_handle);
+
+
+/*
+ * lsar_lookup.c
+ */
+int lsar_query_security_desc(mlsvc_handle_t *lsa_handle);
+
+DWORD lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass);
+
+int lsar_lookup_names(mlsvc_handle_t *lsa_handle,
+ char *name,
+ smb_userinfo_t *user_info);
+
+int lsar_lookup_sids(mlsvc_handle_t *lsa_handle,
+ struct mslsa_sid *sid,
+ smb_userinfo_t *user_info);
+
+DWORD lsar_get_userid(char *server, char *name);
+
+int lsar_enum_accounts(mlsvc_handle_t *lsa_handle,
+ DWORD *enum_context,
+ struct mslsa_EnumAccountBuf *accounts);
+
+DWORD lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle,
+ DWORD *enum_context);
+
+int lsar_enum_privs_account(mlsvc_handle_t *account_handle,
+ smb_userinfo_t *user_info);
+
+int lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle,
+ char *name,
+ struct ms_luid *luid);
+
+int lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle,
+ struct ms_luid *luid,
+ char *name,
+ int namelen);
+
+DWORD lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle,
+ char *name,
+ char *display_name,
+ int display_len);
+
+DWORD lsar_lookup_sids2(mlsvc_handle_t *lsa_handle,
+ struct mslsa_sid *sid,
+ smb_userinfo_t *user_info);
+
+DWORD lsar_lookup_names2(mlsvc_handle_t *lsa_handle,
+ char *name,
+ smb_userinfo_t *user_info);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_LSALIB_H */
diff --git a/usr/src/uts/common/smbsrv/mac_cifs.h b/usr/src/uts/common/smbsrv/mac_cifs.h
new file mode 100644
index 0000000000..26f0451958
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mac_cifs.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_MAC_CIFS_H
+#define _SMBSRV_MAC_CIFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides definitions for the Macintosh Extensions for CIFS
+ * interface (see http://www.thursby.com/cifs).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Macintosh information level extensions. The entire list is presented
+ * here for convenience but for consistency with the existing CIFS
+ * information levels don't use these values directly. Use the SMB_MAC_
+ * definitions in cifs.h.
+ *
+ * SmbTrans2QueryFsInformation: MAC_QUERY_FS_INFO
+ * SmbTrans2Find{First|Next}2: MAC_FIND_BOTH_HFS_INFO
+ * SmbTrans2SetPathInformation: MAC_SET_FINDER_INFO
+ * SmbTrans2QueryPathInformation: MAC_DT_{ADD|REMOVE|GET}_{APPL|ICON}
+ */
+#define MAC_QUERY_FS_INFO 0x301
+#define MAC_FIND_BOTH_HFS_INFO 0x302
+#define MAC_SET_FINDER_INFO 0x303
+#define MAC_DT_ADD_APPL 0x304
+#define MAC_DT_REMOVE_APPL 0x305
+#define MAC_DT_GET_APPL 0x306
+#define MAC_DT_GET_ICON 0x307
+#define MAC_DT_GET_ICON_INFO 0x308
+#define MAC_DT_ADD_ICON 0x309
+
+
+/*
+ * Macintosh extensions support bits. Returned by the server in response
+ * to a TRANS2_QUERY_FS_INFORMATION request when the information level
+ * is MAC_QUERY_FS_INFO.
+ */
+#define MAC_SUPPORT_ACCESS_CONTROL 0x0010
+#define MAC_SUPPORT_GETSETCOMMENTS 0x0020
+#define MAC_SUPPORT_DESKTOPDB_CALLS 0x0040
+#define MAC_SUPPORT_UNIQUE_IDS 0x0080
+#define MAC_SUPPORT_NO_STREAMS 0x0100
+
+
+/*
+ * The MAC_ACCESS values are returned from the MAC_FIND_BOTH_HFS_INFO
+ * info level of TRANS2_FIND. Set SUPPORT_MAC_ACCESS_CNTRL to enable
+ * support.
+ *
+ * The MAC_OWNER bit indicates that the user is the owner of the file
+ * or directory.
+ */
+#define MAC_ACCESS_OWNER 0x0800
+#define MAC_ACCESS_OWNER_READ 0x0400
+#define MAC_ACCESS_OWNER_WRITE 0x0200
+#define MAC_ACCESS_OWNER_SEARCH 0x0100
+#define MAC_ACCESS_GROUP_READ 0x0040
+#define MAC_ACCESS_GROUP_WRITE 0x0020
+#define MAC_ACCESS_GROUP_SEARCH 0x0010
+#define MAC_ACCESS_OTHER_READ 0x0004
+#define MAC_ACCESS_OTHER_WRITE 0x0002
+#define MAC_ACCESS_OTHER_SEARCH 0x0001
+
+
+/*
+ * The MAC_FINDER values support the SMB_MAC_SET_FINDER_INFO info level
+ * of TRANS2_SET_PATH_INFORMATION.
+ */
+#define MAC_FINDER_SET_CREATE_DATE 0x0001
+#define MAC_FINDER_SET_MODE_DATE 0x0002
+#define MAC_FINDER_SET_FL_ATTRIB 0x0004
+#define MAC_FINDER_SET_INFO1 0x0008
+#define MAC_FINDER_SET_INFO2 0x0010
+#define MAC_FINDER_SET_HIDDEN 0x0020
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_MAC_CIFS_H */
diff --git a/usr/src/uts/common/smbsrv/mailslot.h b/usr/src/uts/common/smbsrv/mailslot.h
new file mode 100644
index 0000000000..35f2e74552
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mailslot.h
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_MAILSLOT_H
+#define _SMBSRV_MAILSLOT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Mailslots are a one-way, unreliable IPC mechanism that allows a
+ * client to send or broadcast messages to a server. The names follow
+ * the same universal naming convention (UNC) used with named pipes:
+ * \\server\mailslot\name, \\.\mailslot\name etc. There is a good
+ * overview of mailslots, including limitations of NT and Windows 2000,
+ * in Network Programming for Microsoft Windows Chapter 3.
+ *
+ * Network Programming for Microsoft Windows
+ * Anthony Jones and Jim Ohlund
+ * Microsoft Press, ISBN 0-7356-0560-2
+ *
+ * This file defines pre-defined and system common mailslots.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Well-known or pre-defined mailslots.
+ */
+#define MAILSLOT_LANMAN "\\MAILSLOT\\LANMAN"
+#define MAILSLOT_MSBROWSE "\\MAILSLOT\\MSBROWSE"
+#define MAILSLOT_BROWSE "\\MAILSLOT\\BROWSE"
+#define MAILSLOT_NETLOGON "\\MAILSLOT\\NET\\NETLOGON"
+#define MAILSLOT_NTLOGON "\\MAILSLOT\\NET\\NTLOGON"
+
+
+/*
+ * System common mailslots. These should be dynamically assigned
+ * at runtime but we don't support a full mailslot implementation
+ * so we use a set of predefined values that appear to work.
+ */
+#define MAILSLOT_NETLOGON_RDC "\\MAILSLOT\\NET\\GETDC354"
+#define MAILSLOT_NETLOGON_MDC "\\MAILSLOT\\NET\\GETDC576"
+#define MAILSLOT_NETLOGON_SAMLOGON_RDC "\\MAILSLOT\\NET\\GETDC873"
+#define MAILSLOT_NETLOGON_SAMLOGON_MDC "\\MAILSLOT\\NET\\GETDC875"
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_MAILSLOT_H */
diff --git a/usr/src/uts/common/smbsrv/mbuf.h b/usr/src/uts/common/smbsrv/mbuf.h
new file mode 100644
index 0000000000..51a6bea6e8
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mbuf.h
@@ -0,0 +1,269 @@
+/*
+ * 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) 1982, 1986, 1988 Regents of the University of California.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ */
+
+#ifndef _SMBSRV_MBUF_H
+#define _SMBSRV_MBUF_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * PBSHORTCUT This file should be removed from the PB port but is required
+ * for now to get it to compile. This file has also been modified.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/alloc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MSIZE 256
+#define MCLBYTES 2048
+#define MCLSHIFT 11
+#define MCLOFSET (MCLBYTES - 1)
+
+#define NBPG 4096
+#define CLBYTES NBPG
+#define PB_PAGESIZE 4096
+
+/*
+ * Mbufs are of a single size, MSIZE (machine/machparam.h), which
+ * includes overhead. An mbuf may add a single "mbuf cluster" of size
+ * MCLBYTES (also in machine/machparam.h), which has no additional overhead
+ * and is used instead of the internal data area; this is done when
+ * at least MINCLSIZE of data must be stored.
+ */
+
+#define MLEN (MSIZE - sizeof (struct m_hdr)) /* normal data len */
+#define MHLEN (MLEN - sizeof (struct pkthdr)) /* data len w/pkthdr */
+
+#define MINCLSIZE (MHLEN + MLEN) /* smallest amount to put in cluster */
+
+/*
+ * Macros for type conversion
+ * mtod(m,t) - convert mbuf pointer to data pointer of correct type
+ */
+#define mtod(m, t) ((t)((m)->m_data))
+
+
+/* header at beginning of each mbuf: */
+struct m_hdr {
+ struct mbuf *mh_next; /* next buffer in chain */
+ struct mbuf *mh_nextpkt; /* next chain in queue/record */
+ int mh_len; /* amount of data in this mbuf */
+ caddr_t mh_data; /* location of data */
+ short mh_type; /* type of data in this mbuf */
+ short mh_flags; /* flags; see below */
+};
+
+/* record/packet header in first mbuf of chain; valid if M_PKTHDR set */
+struct pkthdr {
+ int len; /* total packet length */
+};
+
+
+/* XXX probably do not need m_ext */
+
+/* description of external storage mapped into mbuf, valid if M_EXT set */
+struct m_ext {
+ caddr_t ext_buf; /* start of buffer */
+ int (*ext_ref)(); /* refcount adjust function */
+ uint_t ext_size; /* size of buffer, for ext_free */
+};
+
+struct mbuf {
+ struct m_hdr m_hdr;
+ union {
+ struct {
+ struct pkthdr MH_pkthdr; /* M_PKTHDR set */
+ union {
+ struct m_ext MH_ext; /* M_EXT set */
+ char MH_databuf[MHLEN];
+ } MH_dat;
+ } MH;
+ char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */
+ } M_dat;
+};
+#define m_next m_hdr.mh_next
+#define m_len m_hdr.mh_len
+#define m_data m_hdr.mh_data
+#define m_type m_hdr.mh_type
+#define m_flags m_hdr.mh_flags
+#define m_nextpkt m_hdr.mh_nextpkt
+#define m_act m_nextpkt
+#define m_pkthdr M_dat.MH.MH_pkthdr
+#define m_ext M_dat.MH.MH_dat.MH_ext
+#define m_pktdat M_dat.MH.MH_dat.MH_databuf
+#define m_dat M_dat.M_databuf
+
+/* mbuf flags */
+#define M_EXT 0x0001 /* has associated external storage */
+#define M_PKTHDR 0x0002 /* start of record */
+#define M_EOR 0x0004 /* end of record */
+
+/* mbuf pkthdr flags, also in m_flags */
+#define M_BCAST 0x0100 /* send/received as link-level broadcast */
+#define M_MCAST 0x0200 /* send/received as link-level multicast */
+
+/* flags copied when copying m_pkthdr */
+#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_BCAST|M_MCAST)
+
+/* XXX probably only need MT_DATA */
+
+/* mbuf types */
+#define MT_FREE 0 /* should be on free list */
+#define MT_DATA 1 /* dynamic (data) allocation */
+#define MT_HEADER 2 /* packet header */
+#define MT_SOCKET 3 /* socket structure */
+#define MT_PCB 4 /* protocol control block */
+#define MT_RTABLE 5 /* routing tables */
+#define MT_HTABLE 6 /* IMP host tables */
+#define MT_ATABLE 7 /* address resolution tables */
+#define MT_SONAME 8 /* socket name */
+#define MT_SOOPTS 10 /* socket options */
+#define MT_FTABLE 11 /* fragment reassembly header */
+#define MT_RIGHTS 12 /* access rights */
+#define MT_IFADDR 13 /* interface address */
+#define MT_CONTROL 14 /* extra-data protocol message */
+#define MT_OOBDATA 15 /* expedited data */
+
+/*
+ * flags to malloc: PBSHORTCUT
+ */
+#define M_WAITOK 0x0000
+#define M_NOWAIT 0x0001
+
+/* flags to m_get/MGET */
+#define M_DONTWAIT M_NOWAIT
+#define M_WAIT M_WAITOK
+
+
+/*
+ * mbuf allocation/deallocation macros:
+ *
+ * MGET(struct mbuf *m, int how, int type)
+ * allocates an mbuf and initializes it to contain internal data.
+ *
+ * MGETHDR(struct mbuf *m, int how, int type)
+ * allocates an mbuf and initializes it to contain a packet header
+ * and internal data.
+ */
+
+#define MGET(m, how, type) { \
+ m = MEM_ZALLOC("mbuf", sizeof (struct mbuf)); \
+ (m)->m_next = (struct mbuf *)NULL; \
+ (m)->m_nextpkt = (struct mbuf *)NULL; \
+ (m)->m_data = (m)->m_dat; \
+ (m)->m_flags = 0; \
+ (m)->m_type = (short)(type); \
+}
+
+#define MGETHDR(m, how, type) { \
+ m = MEM_ZALLOC("mbuf", sizeof (struct mbuf)); \
+ (m)->m_type = (MT_HEADER); \
+ (m)->m_next = (struct mbuf *)NULL; \
+ (m)->m_nextpkt = (struct mbuf *)NULL; \
+ (m)->m_data = (m)->m_pktdat; \
+ (m)->m_flags = M_PKTHDR; \
+}
+
+extern int mclref();
+extern int mclrefnoop();
+#define MCLGET(m, how) \
+ { \
+ (m)->m_ext.ext_buf = MEM_ZALLOC("mbuf", MCLBYTES); \
+ (m)->m_data = (m)->m_ext.ext_buf; \
+ (m)->m_flags |= M_EXT; \
+ (m)->m_ext.ext_size = MCLBYTES; \
+ (m)->m_ext.ext_ref = mclref; \
+ }
+
+/*
+ * MFREE(struct mbuf *m, struct mbuf *nn)
+ * Free a single mbuf and associated external storage.
+ * Place the successor, if any, in nn.
+ */
+#define MFREE(m, nn) \
+ { \
+ if ((m)->m_flags & M_EXT) { \
+ (*((m)->m_ext.ext_ref))((m)->m_ext.ext_buf, \
+ (m)->m_ext.ext_size, -1); \
+ (m)->m_ext.ext_buf = 0; \
+ } \
+ (nn) = (m)->m_next; \
+ (m)->m_next = 0; \
+ MEM_FREE("mbuf", m); \
+ }
+
+
+
+/*
+ * As above, for mbufs allocated with m_gethdr/MGETHDR
+ * or initialized by M_COPY_PKTHDR.
+ */
+#define MH_ALIGN(m, len) \
+ { (m)->m_data += (MHLEN - (len)) &~ (sizeof (int32_t) - 1); }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_MBUF_H */
diff --git a/usr/src/uts/common/smbsrv/mlrpc.h b/usr/src/uts/common/smbsrv/mlrpc.h
new file mode 100644
index 0000000000..fe82cf01df
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mlrpc.h
@@ -0,0 +1,414 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_MLRPC_H
+#define _SMBSRV_MLRPC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MSRPC Like RPC (MLRPC) is an MSRPC compatible implementation of OSF
+ * DCE RPC. DCE RPC is derived from the Apollo Network Computing
+ * Architecture (NCA) RPC implementation. This implementation is based
+ * on the X/Open DCE: Remote Procedure Call specification. The main
+ * MSRPC compatibility issue is the use of Unicode strings. This work
+ * was originally based on the X/Open DCE Remote Procedure Call CAE
+ * 1994 Specification. The current DCE RPC specification is detailed
+ * below.
+ *
+ * CAE Specification (1997)
+ * DCE 1.1: Remote Procedure Call
+ * Document Number: C706
+ * The Open Group
+ * ogspecs@opengroup.org
+ */
+
+/*
+ * Layering
+ *
+ * This shows the software layers of the DCE RPC system compared against
+ * ONC SUN RPC.
+ *
+ * MLRPC Layers Sun RPC Layers Remark
+ * +---------------+ +---------------+ +---------------+
+ * +---------------+ +---------------+
+ * | Application | | Application | The application
+ * +---------------+ +---------------+
+ * | Hand coded | | RPCGEN gen'd | Where the real
+ * | client/server | | client/server | work happens
+ * | srvsvc.ndl | | *_svc.c *_clnt|
+ * | srvsvc.c | | |
+ * +---------------+ +---------------+
+ * | RPC Library | | RPC Library | Calls/Return
+ * | mlrpc_*.c | | | Binding/PMAP
+ * +---------------+ +---------------+
+ * | RPC Protocol | | RPC Protocol | Headers, Auth,
+ * | mlrpcpdu.ndl | | |
+ * +---------------+ +---------------+
+ * | IDL gen'd | | RPCGEN gen'd | Aggregate
+ * | NDR stubs | | XDR stubs | Composition
+ * | *__ndr.c | | *_xdr.c |
+ * +---------------+ +---------------+
+ * | NDR Represen | | XDR Represen | Byte order, padding
+ * +---------------+ +---------------+
+ * | Packet Heaps | | Network Conn | BIG DIFF: DCERPC does
+ * | mlndo_*.c | | clnt_{tcp,udp}| not talk directly to
+ * +---------------+ +---------------+ network.
+ *
+ * There are two major differences between the DCE RPC and ONC RPC:
+ *
+ * 1. MLRPC only generates or processes packets from buffers. Other
+ * layers must take care of packet transmission and reception.
+ * The packet heaps are managed through a simple interface provided
+ * by the Network Data Representation (NDR) module, called struct
+ * mlndr_stream. mlndo_*.c modules implement the different flavors
+ * (operations) of packet heaps.
+ *
+ * ONC RPC communicates directly with the network. You have to do
+ * something special for the RPC packet to be placed in a buffer
+ * rather than sent to the wire.
+ *
+ * 2. MLRPC uses application provided heaps to support operations.
+ * A heap is a single, monolithic chunk of memory that MLRPC manages
+ * as it allocates. When the operation and its result are done, the
+ * heap is disposed of as a single item. The mlrpc_xaction, which
+ * is the anchor of most operations, contains the necessary book-
+ * keeping for the heap.
+ *
+ * ONC RPC uses malloc() liberally throughout its run-time system.
+ * To free results, ONC RPC supports an XDR_FREE operation that
+ * traverses data structures freeing memory as it goes, whether
+ * it was malloc'd or not.
+ */
+
+#include <smbsrv/ndl/rpcpdu.ndl>
+#include <sys/uio.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/ndr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Dispatch Return Code (DRC)
+ *
+ * 0x8000 15:01 Set to indicate a fault, clear indicates status
+ * 0x7F00 08:07 Status/Fault specific
+ * 0x00FF 00:08 MLRPC_PTYPE_... of PDU, 0xFF for header
+ */
+#define MLRPC_DRC_MASK_FAULT 0x8000
+#define MLRPC_DRC_MASK_SPECIFIER 0xFF00
+#define MLRPC_DRC_MASK_PTYPE 0x00FF
+
+/* Usual stuff */
+#define MLRPC_DRC_OK 0x0000
+
+/* Fake PTYPEs for MLRPC_DRC */
+#define MLRPC_DRC_PTYPE_RPCHDR 0x00FF
+#define MLRPC_DRC_PTYPE_API 0x00AA
+
+/* DRC Recognizers */
+#define MLRPC_DRC_IS_OK(DRC) (((DRC)&MLRPC_DRC_MASK_SPECIFIER) == 0)
+#define MLRPC_DRC_IS_FAULT(DRC) (((DRC)&MLRPC_DRC_MASK_FAULT) != 0)
+
+/*
+ * (Un)Marshalling category specifiers
+ */
+#define MLRPC_DRC_FAULT_MODE_MISMATCH 0x8100
+#define MLRPC_DRC_RECEIVED 0x0200
+#define MLRPC_DRC_FAULT_RECEIVED_RUNT 0x8300
+#define MLRPC_DRC_FAULT_RECEIVED_MALFORMED 0x8400
+#define MLRPC_DRC_DECODED 0x0500
+#define MLRPC_DRC_FAULT_DECODE_FAILED 0x8600
+#define MLRPC_DRC_ENCODED 0x0700
+#define MLRPC_DRC_FAULT_ENCODE_FAILED 0x8800
+#define MLRPC_DRC_FAULT_ENCODE_TOO_BIG 0x8900
+#define MLRPC_DRC_SENT 0x0A00
+#define MLRPC_DRC_FAULT_SEND_FAILED 0x8B00
+
+/*
+ * Resource category specifier
+ */
+#define MLRPC_DRC_FAULT_RESOURCE_1 0x9100
+#define MLRPC_DRC_FAULT_RESOURCE_2 0x9200
+
+/*
+ * Parameters. Usually #define'd with useful alias
+ */
+#define MLRPC_DRC_FAULT_PARAM_0_INVALID 0xC000
+#define MLRPC_DRC_FAULT_PARAM_0_UNIMPLEMENTED 0xD000
+#define MLRPC_DRC_FAULT_PARAM_1_INVALID 0xC100
+#define MLRPC_DRC_FAULT_PARAM_1_UNIMPLEMENTED 0xD100
+#define MLRPC_DRC_FAULT_PARAM_2_INVALID 0xC200
+#define MLRPC_DRC_FAULT_PARAM_2_UNIMPLEMENTED 0xD200
+#define MLRPC_DRC_FAULT_PARAM_3_INVALID 0xC300
+#define MLRPC_DRC_FAULT_PARAM_3_UNIMPLEMENTED 0xD300
+
+#define MLRPC_DRC_FAULT_OUT_OF_MEMORY 0xF000
+
+/* RPCHDR */
+#define MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID 0xC0FF /* PARAM_0_INVALID */
+#define MLRPC_DRC_FAULT_RPCHDR_PTYPE_UNIMPLEMENTED 0xD0FF /* PARAM_0_UNIMP */
+
+/* Request */
+#define MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID 0xC000 /* PARAM_0_INVALID */
+#define MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID 0xC100 /* PARAM_1_INVALID */
+
+/* Bind */
+#define MLRPC_DRC_FAULT_BIND_PCONT_BUSY 0xC00B /* PARAM_0_INVALID */
+#define MLRPC_DRC_FAULT_BIND_UNKNOWN_SERVICE 0xC10B /* PARAM_1_INVALID */
+#define MLRPC_DRC_FAULT_BIND_NO_SLOTS 0x910B /* RESOURCE_1 */
+#define MLRPC_DRC_BINDING_MADE 0x000B /* OK */
+
+/* API */
+#define MLRPC_DRC_FAULT_API_SERVICE_INVALID 0xC0AA /* PARAM_0_INVALID */
+#define MLRPC_DRC_FAULT_API_BIND_NO_SLOTS 0x91AA /* RESOURCE_1 */
+#define MLRPC_DRC_FAULT_API_OPNUM_INVALID 0xC1AA /* PARAM_1_INVALID */
+
+struct mlrpc_xaction;
+
+typedef struct mlrpc_stub_table {
+ int (*func)(void *param, struct mlrpc_xaction *mreq);
+ unsigned short opnum;
+} mlrpc_stub_table_t;
+
+typedef struct mlrpc_service {
+ char *name;
+ char *desc;
+ char *endpoint;
+ char *sec_addr_port;
+ char *abstract_syntax_uuid;
+ int abstract_syntax_version;
+ char *transfer_syntax_uuid;
+ int transfer_syntax_version;
+ unsigned bind_instance_size;
+ int (*bind_req)();
+ int (*unbind_and_close)();
+ int (*call_stub)(struct mlrpc_xaction *mreq);
+ struct ndr_typeinfo *interface_ti;
+ struct mlrpc_stub_table *stub_table;
+} mlrpc_service_t;
+
+/*
+ * The list of bindings is anchored at a connection. Nothing in the
+ * RPC mechanism allocates them. Binding elements which have service==0
+ * indicate free elements. When a connection is instantiated, at least
+ * one free binding entry should also be established. Something like
+ * this should suffice for most (all) situations:
+ *
+ * struct connection {
+ * ....
+ * struct mlrpc_binding *binding_list_head;
+ * struct mlrpc_binding binding_pool[N_BINDING_POOL];
+ * ....
+ * };
+ *
+ * init_connection(struct connection *conn) {
+ * ....
+ * mlrpc_binding_pool_initialize(&conn->binding_list_head,
+ * conn->binding_pool, N_BINDING_POOL);
+ */
+struct mlrpc_binding {
+ struct mlrpc_binding *next;
+ mlrpc_p_context_id_t p_cont_id;
+ unsigned char which_side;
+ void * context;
+ struct mlrpc_service *service;
+ void *instance_specific;
+};
+
+#define MLRPC_BIND_SIDE_CLIENT 1
+#define MLRPC_BIND_SIDE_SERVER 2
+
+#define MLRPC_BINDING_TO_SPECIFIC(BINDING, TYPE) \
+ ((TYPE *) (BINDING)->instance_specific)
+
+/*
+ * mlrpc_heap.c
+ *
+ * A number of heap areas are used during marshalling and unmarshalling.
+ * Under some circumstances these areas can be discarded by the library
+ * code, i.e. on the server side before returning to the client and on
+ * completion of a client side bind. In the case of a client side RPC
+ * call, these areas must be preserved after an RPC returns to give the
+ * caller time to take a copy of the data. In this case the client must
+ * call mlrpc_c_free_heap to free the memory.
+ *
+ * The heap management data definition looks a bit like this:
+ *
+ * heap -> +---------------+ +------------+
+ * | iovec[0].base | --> | data block |
+ * | iovec[0].len | +------------+
+ * +---------------+
+ * ::
+ * ::
+ * iov -> +---------------+ +------------+
+ * | iovec[n].base | --> | data block |
+ * | iovec[n].len | +------------+
+ * +---------------+ ^ ^
+ * | |
+ * next ----------------------+ |
+ * top -----------------------------------+
+ *
+ */
+
+/*
+ * Setting MAXIOV to 384 will use ((8 * 384) + 16) = 3088 bytes
+ * of the first heap block.
+ */
+#define MLRPC_HEAP_MAXIOV 384
+#define MLRPC_HEAP_BLKSZ 4096
+
+typedef struct mlrpc_heap {
+ struct iovec iovec[MLRPC_HEAP_MAXIOV];
+ struct iovec *iov;
+ int iovcnt;
+ char *top;
+ char *next;
+} mlrpc_heap_t;
+
+/*
+ * To support the client-side heap preserve functionality.
+ */
+#define MLRPC_HRST_PRESERVED 1
+
+typedef struct mlrpc_heapref {
+ mlrpc_heap_t *heap;
+ char *recv_pdu_buf;
+ char *send_pdu_buf;
+ unsigned int state;
+} mlrpc_heapref_t;
+
+/*
+ * Alternate varying/conformant string definition
+ * - for non-null-terminated strings.
+ */
+struct mlrpc_vcb {
+ /*
+ * size_is (actually a copy of length_is) will
+ * be inserted here by the marshalling library.
+ */
+ DWORD vc_first_is;
+ DWORD vc_length_is;
+ WORD buffer[ANY_SIZE_ARRAY];
+};
+
+typedef struct mlrpc_vcbuf {
+ WORD wclen;
+ WORD wcsize;
+ struct mlrpc_vcb *vcb;
+} mlrpc_vcbuf_t;
+
+mlrpc_heap_t *mlrpc_heap_create(void);
+void mlrpc_heap_destroy(mlrpc_heap_t *);
+void *mlrpc_heap_malloc(mlrpc_heap_t *, unsigned);
+void *mlrpc_heap_strsave(mlrpc_heap_t *, char *);
+void mlrpc_heap_mkvcs(mlrpc_heap_t *, char *, mlrpc_vcbuf_t *);
+int mlrpc_heap_used(mlrpc_heap_t *);
+int mlrpc_heap_avail(mlrpc_heap_t *);
+
+#define MLRPC_HEAP_MALLOC(MXA, SIZE) \
+ mlrpc_heap_malloc((MXA)->heap, SIZE)
+
+#define MLRPC_HEAP_NEW(MXA, TYPE) \
+ mlrpc_heap_malloc((MXA)->heap, sizeof (TYPE))
+
+#define MLRPC_HEAP_NEWN(MXA, TYPE, N) \
+ mlrpc_heap_malloc((MXA)->heap, sizeof (TYPE)*(N))
+
+#define MLRPC_HEAP_STRSAVE(MXA, STR) \
+ mlrpc_heap_strsave((MXA)->heap, (STR))
+
+struct mlrpc_xaction {
+ unsigned short ptype; /* just handy, hi bits spcl */
+ unsigned short opnum; /* for requests */
+ struct mlndr_stream recv_mlnds;
+ mlrpcconn_hdr_t recv_hdr;
+ struct mlndr_stream send_mlnds;
+ mlrpcconn_hdr_t send_hdr;
+ struct mlrpc_binding *binding; /* what we're using */
+ struct mlrpc_binding *binding_list; /* from connection */
+ mlrpc_heap_t *heap;
+ struct mlsvc_rpc_context *context;
+};
+
+struct mlrpc_client {
+ int (*xa_init)(struct mlrpc_client *, struct mlrpc_xaction *,
+ mlrpc_heap_t *);
+ int (*xa_exchange)(struct mlrpc_client *, struct mlrpc_xaction *);
+ int (*xa_read)(struct mlrpc_client *, struct mlrpc_xaction *);
+ int (*xa_preserve)(struct mlrpc_client *, struct mlrpc_xaction *,
+ mlrpc_heapref_t *);
+ int (*xa_destruct)(struct mlrpc_client *, struct mlrpc_xaction *);
+ void (*xa_release)(struct mlrpc_client *, mlrpc_heapref_t *);
+
+ void *context;
+ struct mlrpc_binding *binding_list;
+ uint32_t next_call_id;
+ unsigned next_p_cont_id;
+};
+
+/* mlndo.c */
+int mlnds_initialize(struct mlndr_stream *, unsigned, int, mlrpc_heap_t *);
+void mlnds_destruct(struct mlndr_stream *);
+
+/* mlrpc_client.c */
+int mlrpc_c_bind(struct mlrpc_client *, char *, struct mlrpc_binding **);
+int mlrpc_c_call(struct mlrpc_binding *, int, void *, mlrpc_heapref_t *);
+int mlrpc_c_free_heap(struct mlrpc_binding *, mlrpc_heapref_t *);
+
+/* mlrpc_encdec.c */
+int mlrpc_encode_decode_common(struct mlrpc_xaction *, int, unsigned,
+ struct ndr_typeinfo *, void *);
+int mlrpc_decode_call(struct mlrpc_xaction *, void *);
+int mlrpc_encode_return(struct mlrpc_xaction *, void *);
+int mlrpc_encode_call(struct mlrpc_xaction *, void *);
+int mlrpc_decode_return(struct mlrpc_xaction *, void *);
+int mlrpc_decode_pdu_hdr(struct mlrpc_xaction *);
+int mlrpc_encode_pdu_hdr(struct mlrpc_xaction *);
+void mlrpc_decode_frag_hdr(struct mlndr_stream *, mlrpcconn_common_header_t *);
+unsigned mlrpc_bind_ack_hdr_size(struct mlrpcconn_bind_ack_hdr *);
+
+/* mlrpc_svc.c */
+struct mlrpc_stub_table *mlrpc_find_stub_in_svc(struct mlrpc_service *, int);
+struct mlrpc_service *mlrpc_find_service_by_name(const char *);
+struct mlrpc_service *mlrpc_find_service_by_uuids(mlrpc_uuid_t *, int,
+ mlrpc_uuid_t *, int);
+int mlrpc_register_service(struct mlrpc_service *);
+void mlrpc_unregister_service(struct mlrpc_service *);
+void mlrpc_uuid_to_str(mlrpc_uuid_t *, char *);
+int mlrpc_str_to_uuid(char *, mlrpc_uuid_t *);
+void mlrpc_binding_pool_initialize(struct mlrpc_binding **,
+ struct mlrpc_binding pool[], unsigned);
+struct mlrpc_binding *mlrpc_find_binding(struct mlrpc_xaction *,
+ mlrpc_p_context_id_t);
+struct mlrpc_binding *mlrpc_new_binding(struct mlrpc_xaction *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_MLRPC_H */
diff --git a/usr/src/uts/common/smbsrv/mlsvc.h b/usr/src/uts/common/smbsrv/mlsvc.h
new file mode 100644
index 0000000000..cb13cf5733
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mlsvc.h
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_MLSVC_H
+#define _SMBSRV_MLSVC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MLSVC RPC layer public interface definitions.
+ */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/ksynch.h>
+
+#include <smbsrv/wintypes.h>
+#include <smbsrv/ntsid.h>
+
+#include <smbsrv/smb_winpipe.h>
+#include <smbsrv/smb_xdr.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * RPC strings
+ *
+ * DCE RPC strings (CAE section 14.3.4) are represented as varying or
+ * varying and conformant one-dimensional arrays. Characters can be
+ * single-byte or multi-byte as long as all characters conform to a
+ * fixed element size, i.e. UCS-2 is okay but UTF-8 is not a valid
+ * DCE RPC string format. The string is terminated by a null character
+ * of the appropriate element size.
+ *
+ * MSRPC strings are always varying and conformant format and not null
+ * terminated. This format uses the size_is, first_is and length_is
+ * attributes (CAE section 4.2.18).
+ *
+ * typedef struct mlrpc_string {
+ * DWORD size_is;
+ * DWORD first_is;
+ * DWORD length_is;
+ * wchar_t string[ANY_SIZE_ARRAY];
+ * } mlrpc_string_t;
+ *
+ * The size_is attribute is used to specify the number of data elements
+ * in each dimension of an array.
+ *
+ * The first_is attribute is used to define the lower bound for
+ * significant elements in each dimension of an array. For strings
+ * this is always 0.
+ *
+ * The length_is attribute is used to define the number of significant
+ * elements in each dimension of an array. For strings this is typically
+ * the same as size_is. Although it might be (size_is - 1) if the string
+ * is null terminated.
+ *
+ * In MSRPC, Unicode strings are not null terminated. This means
+ * that the recipient has to manually null-terminate the string after
+ * it has been unmarshalled. Note that there is often a wide-char pad
+ * following a string. Although the padding sometimes contains zero,
+ * it's not guaranteed.
+ *
+ * 4 bytes 4 bytes 4 bytes 2bytes 2bytes 2bytes 2bytes
+ * +---------+---------+---------+------+------+------+------+
+ * |size_is |first_is |length_is| char | char | char | char |
+ * +---------+---------+---------+------+------+------+------+
+ *
+ * The problem is that some strings are null terminated. This seems
+ * to conflict with the statement above that Unicode strings are not
+ * null terminated, which may be a historical thing from earlier
+ * implementations or it may be that different services do different
+ * things. So there is an additional string wrapper with two more
+ * fields used in some RPC structures as shown below (LPTSTR is
+ * automatically converted to mlrpc_string by the NDR marshalling).
+ *
+ * typedef struct ms_string {
+ * WORD length;
+ * WORD maxlen;
+ * LPTSTR str;
+ * } ms_string_t;
+ *
+ * Here, length is the array length in bytes excluding any terminating
+ * null bytes and maxlen is the array length in bytes including null
+ * terminator bytes.
+ */
+typedef struct mlsvc_string {
+ WORD length;
+ WORD maxlen;
+ LPTSTR str;
+} mlsvc_string_t;
+
+/*
+ * The maximum number of domains (NT limit).
+ */
+#define MLSVC_DOMAIN_MAX 32
+
+/*
+ * Some buffer size limits. I don't know if these are definitive
+ * limits for NT but these numbers appear in various places.
+ */
+#define MLSVC_DOMAIN_NAME_MAX 32
+#define MLSVC_ACCOUNT_NAME_MAX 32
+#define MLSVC_CLIENT_NAME_MAX 48
+
+/* 32-byte machine account password (null-terminated) */
+#define MLSVC_MACHINE_ACCT_PASSWD_MAX 32 + 1
+
+/*
+ * Status code returned from enumeration RPCs to indicate
+ * that the server has no more data. Normally returned at
+ * severity level ERROR_SEVERITY_WARNING.
+ */
+#define MLSVC_NO_MORE_DATA 0x1A
+
+/*
+ * IPC connection types, used to indicate the type of session
+ * required for a subsequent series of requests.
+ */
+#define MLSVC_IPC_ANON 0x00
+#define MLSVC_IPC_USER 0x01
+#define MLSVC_IPC_ADMIN 0x02
+
+#define MLSVC_ANON_USER "IPC$"
+
+char *mlsvc_ipc_name(int ipc_type, char *username);
+
+/*
+ * Passthrough negotiation and authentication interface.
+ *
+ * NT supports two forms of password: a Lanman (case-insensitive)
+ * password and an NT (case-sensitive) password. If either of the
+ * passwords is not available its pointer and length should be set
+ * to zero. The session key and vc number are required to validate
+ * the encrypted passwords.
+ */
+
+int mlsvc_anonymous_logon(char *domain_controller, char *domain_name,
+ char **username);
+int mlsvc_user_logon(char *domain_controller, char *domain_name,
+ char *username, char *password);
+int mlsvc_admin_logon(char *domain_controller, char *domain_name);
+int mlsvc_echo(char *server);
+int mlsvc_open_pipe(char *hostname, char *domain, char *username,
+ char *pipename);
+int mlsvc_close_pipe(int fid);
+void mlsvc_nt_password_hash(char *result, char *password);
+int mlsvc_encrypt_nt_password(char *password, char *key, int keylen, char *out,
+ int outmax);
+DWORD mlsvc_validate_user(char *server, char *domain, char *username,
+ char *password);
+int mlsvc_locate_domain_controller(char *domain);
+
+/*
+ * RPC request processing interface (mlsvc_server.c).
+ */
+#define MLSVC_MAX_IOVEC 512
+
+typedef struct mlrpc_frag {
+ struct mlrpc_frag *next;
+ struct mbuf *mhead;
+ uint32_t length;
+} mlrpc_frag_t;
+
+typedef struct mlsvc_stream {
+ mlrpc_frag_t *head;
+ mlrpc_frag_t *tail;
+ mlrpc_frag_t *pending;
+ unsigned int nfrag;
+ struct uio uio;
+ struct iovec iovec[MLSVC_MAX_IOVEC];
+} mlsvc_stream_t;
+
+typedef struct mlsvc_pipe {
+ kmutex_t mutex;
+ kcondvar_t cv;
+ uint32_t busy;
+ uint32_t fid;
+ char *pipe_name;
+ mlsvc_stream_t input;
+ uchar_t *output;
+ int32_t outlen;
+} mlsvc_pipe_t;
+
+int mlsvc_rpc_process(
+ smb_pipe_t *inpipe,
+ smb_pipe_t **outpipe,
+ smb_dr_user_ctx_t *user_ctx);
+
+struct mlsvc_rpc_context *mlsvc_lookup_context(int fid);
+
+void mlsvc_rpc_release(int fid);
+int mlsvc_session_native_values(int fid, int *remote_os, int *remote_lm,
+ int *pdc_type);
+void mlsvc_rpc_report_status(int opnum, DWORD status);
+
+/*
+ * This is a temporary location for this NETLOGON stuff.
+ */
+typedef int (*mlsvc_locate_pdc_t)(char *domain);
+void mlsvc_install_pdc_cb(mlsvc_locate_pdc_t locate_pdc_cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_MLSVC_H */
diff --git a/usr/src/uts/common/smbsrv/mlsvc_util.h b/usr/src/uts/common/smbsrv/mlsvc_util.h
new file mode 100644
index 0000000000..e9ababec15
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mlsvc_util.h
@@ -0,0 +1,244 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_MLSVC_UTIL_H
+#define _SMBSRV_MLSVC_UTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MLSVC RPC interface and utility function definitions.
+ */
+
+#include <smbsrv/ndl/ndrtypes.ndl>
+#include <smbsrv/ndr.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/smb_token.h>
+
+#ifndef _KERNEL
+#include <stdio.h>
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Predefined global RIDs.
+ */
+#define MLSVC_DOMAIN_GROUP_RID_ADMINS 0x00000200L
+#define MLSVC_DOMAIN_GROUP_RID_USERS 0x00000201L
+#define MLSVC_DOMAIN_GROUP_RID_GUESTS 0x00000202L
+#define MLSVC_DOMAIN_GROUP_RID_COMPUTERS 0x00000203L
+#define MLSVC_DOMAIN_GROUP_RID_CONTROLLERS 0x00000204L
+#define MLSVC_DOMAIN_GROUP_RID_CERT_ADMINS 0x00000205L
+#define MLSVC_DOMAIN_GROUP_RID_SCHEMA_ADMINS 0x00000206L
+
+/*
+ * Predefined local alias RIDs.
+ */
+#define MLSVC_LOCAL_GROUP_RID_ADMINS 0x00000220L
+#define MLSVC_LOCAL_GROUP_RID_USERS 0x00000221L
+#define MLSVC_LOCAL_GROUP_RID_GUESTS 0x00000222L
+#define MLSVC_LOCAL_GROUP_RID_POWER_USERS 0x00000223L
+#define MLSVC_LOCAL_GROUP_RID_ACCOUNT_OPS 0x00000224L
+#define MLSVC_LOCAL_GROUP_RID_SERVER_OPS 0x00000225L
+#define MLSVC_LOCAL_GROUP_RID_PRINT_OPS 0x00000226L
+#define MLSVC_LOCAL_GROUP_RID_BACKUP_OPS 0x00000227L
+#define MLSVC_LOCAL_GROUP_RID_REPLICATOR 0x00000228L
+
+/*
+ * All predefined local group RIDs belong
+ * to a special domain called BUILTIN.
+ */
+#define MLSVC_BUILTIN_DOMAIN_NAME "BUILTIN"
+#define MLSVC_BUILTIN_DOMAIN_SIDSTRLEN 8
+
+/*
+ * Universal and NT well-known SIDs
+ */
+#define MLSVC_NULL_SIDSTR "S-1-0-0"
+#define MSLVC_WORLD_SIDSTR "S-1-1-0"
+#define MSLVC_LOCAL_SIDSTR "S-1-2-0"
+#define MSLVC_CREATOR_OWNER_ID_SIDSTR "S-1-3-0"
+#define MSLVC_CREATOR_GROUP_ID_SIDSTR "S-1-3-1"
+#define MSLVC_CREATOR_OWNER_SERVER_ID_SIDSTR "S-1-3-2"
+#define MSLVC_CREATOR_GROUP_SERVER_ID_SIDSTR "S-1-3-3"
+#define MSLVC_NON_UNIQUE_IDS_SIDSTR "S-1-4"
+#define MLSVC_NT_AUTHORITY_SIDSTR "S-1-5"
+#define MLSVC_DIALUP_SIDSTR "S-1-5-1"
+#define MLSVC_NETWORK_SIDSTR "S-1-5-2"
+#define MLSVC_BATCH_SIDSTR "S-1-5-3"
+#define MLSVC_INTERACTIVE_SIDSTR "S-1-5-4"
+#define MLSVC_SERVICE_SIDSTR "S-1-5-6"
+#define MLSVC_ANONYMOUS_LOGON_SIDSTR "S-1-5-7"
+#define MLSVC_PROXY_SIDSTR "S-1-5-8"
+#define MLSVC_SERVER_LOGON_SIDSTR "S-1-5-9"
+#define MLSVC_SELF_SIDSTR "S-1-5-10"
+#define MLSVC_AUTHENTICATED_USER_SIDSTR "S-1-5-11"
+#define MLSVC_RESTRICTED_CODE_SIDSTR "S-1-5-12"
+#define MLSVC_NT_LOCAL_SYSTEM_SIDSTR "S-1-5-18"
+#define MLSVC_NT_NON_UNIQUE_SIDSTR "S-1-5-21"
+#define MLSVC_BUILTIN_DOMAIN_SIDSTR "S-1-5-32"
+
+int mlsvc_lookup_name(char *domain, char *name, nt_sid_t **sid);
+int mlsvc_lookup_sid(nt_sid_t *sid, char *buf, int bufsize);
+
+smb_userinfo_t *mlsvc_alloc_user_info(void);
+void mlsvc_free_user_info(smb_userinfo_t *user_info);
+void mlsvc_release_user_info(smb_userinfo_t *user_info);
+void mlsvc_setadmin_user_info(smb_userinfo_t *user_info);
+char *mlsvc_sid_name_use(unsigned int snu_id);
+
+/*
+ * The definition of a local unique id (LUID). This is an opaque id
+ * used by servers to identify local resources, such as privileges.
+ * A client will use lookup functions to translate the LUID to a
+ * more general, machine independent form; like a string.
+ */
+struct ms_luid {
+ DWORD low_part;
+ DWORD high_part;
+};
+
+/*
+ * As with SIDs, this is the generic, interface independent string
+ * definition.
+ */
+struct ms_string_desc {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct ms_string_desc ms_string_t;
+
+int mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa);
+nt_sid_t *mlsvc_sid_save(nt_sid_t *sid, struct mlrpc_xaction *mxa);
+
+/*
+ * This is the generic, interface independent handle definition.
+ */
+typedef struct ms_handle {
+ DWORD handle[5];
+} ms_handle_t;
+
+/*
+ * List of interface specifications: can be used to identify the
+ * sub-system to which a handle is assigned. The handle management
+ * library doesn't check or care about the ifspec value.
+ */
+typedef enum ms_ifspec {
+ MLSVC_IFSPEC_NULL,
+ MLSVC_IFSPEC_LSAR,
+ MLSVC_IFSPEC_SAMR,
+ MLSVC_IFSPEC_WINREG,
+ MLSVC_IFSPEC_SVCCTL,
+ MLSVC_IFSPEC_SPOOLSS,
+ MLSVC_IFSPEC_LOGR,
+ MLSVC_IFSPEC_LLSR,
+ MLSVC_NUM_IFSPECS
+} ms_ifspec_t;
+
+#define MLSVC_HANDLE_KEY_MAX 32
+
+typedef struct ms_handle_desc {
+ struct ms_handle_desc *next;
+ ms_handle_t handle;
+ ms_ifspec_t ifspec;
+ char key[MLSVC_HANDLE_KEY_MAX];
+ DWORD discrim;
+} ms_handle_desc_t;
+
+ms_handle_t *mlsvc_get_handle(ms_ifspec_t ifspec, char *key, DWORD discrim);
+int mlsvc_put_handle(ms_handle_t *handle);
+int mlsvc_validate_handle(ms_handle_t *handle, char *key);
+ms_handle_desc_t *mlsvc_lookup_handle(ms_handle_t *handle);
+
+/*
+ * The mlsvc_rpc_context structure provides the connection binding context
+ * for client RPC calls. This space must be provided by the client library
+ * for use by the underlying RPC library. Note that we need two binding
+ * pools per connection.
+ */
+#define CTXT_N_BINDING_POOL 2
+
+struct mlsvc_rpc_context {
+ struct mlrpc_client cli;
+ int fid;
+ ms_handle_t *handle;
+ smb_dr_user_ctx_t *user_ctx;
+ smb_pipe_t *inpipe; /* used for winpipe */
+ uint32_t inlen; /* inpipes */
+ smb_pipe_t *outpipe; /* used for winpipe */
+ uint32_t outcookie; /* for rpc_read and transact */
+ uint32_t outlen; /* outpipes */
+ int server_os;
+ int server_pdc;
+ WORD max_xmit_frag;
+ WORD max_recv_frag;
+ struct mlrpc_binding *binding;
+ struct mlrpc_binding binding_pool[CTXT_N_BINDING_POOL];
+};
+
+/*
+ * Each RPC interface requires a context and each RPC call within that
+ * interface requires a handle. Handles are call specific, however, so
+ * a number of different handles may be used during a sequence of calls
+ * to a specific RPC interface. Contexts are interface specific so
+ * there is one per interface per thread of execution. This structure
+ * provides a handle to context relationship so that we know which
+ * context to use with any particular handle.
+ *
+ * The context contains a pointer to the top level handle for the
+ * interface, which is assigned during the bind. It's used when closing
+ * to detect when to free the context.
+ *
+ * I know this is really tacky but the elements in the descriptor are
+ * arranged so that a handle can be overlaid directly onto a descriptor.
+ * I probably won't do this but now you know - just in case you see it
+ * in the code.
+ */
+typedef struct mlsvc_rpc_desc {
+ ms_handle_t handle;
+ struct mlsvc_rpc_context *context;
+} mlsvc_handle_t;
+
+
+int mlsvc_rpc_bind(mlsvc_handle_t *handle, int fid, char *service);
+int mlsvc_rpc_init(mlrpc_heapref_t *heapref);
+int mlsvc_rpc_call(struct mlsvc_rpc_context *context, int opnum, void *params,
+ mlrpc_heapref_t *heapref);
+void mlsvc_rpc_free(struct mlsvc_rpc_context *context,
+ mlrpc_heapref_t *heapref);
+int mlsvc_is_null_handle(mlsvc_handle_t *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_MLSVC_UTIL_H */
diff --git a/usr/src/uts/common/smbsrv/msgbuf.h b/usr/src/uts/common/smbsrv/msgbuf.h
new file mode 100644
index 0000000000..465ba476de
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/msgbuf.h
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_MSGBUF_H
+#define _SMBSRV_MSGBUF_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Definition and interface for smb_msgbuf buffer management. The
+ * smb_msgbuf interface is typically used to encode or decode SMB
+ * data using sprintf/scanf style operations. It can also be used
+ * for general purpose encoding and decoding.
+ */
+
+#include <sys/types.h>
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * When unicode strings are decoded, the resultant UTF-8 strings are
+ * stored in dynamically allocated areas, which are held on a linked
+ * list anchored at smb_msgbuf.mlist. The list is deallocated by
+ * smb_msgbuf_term.
+ */
+typedef struct smb_msgbuf_mlist {
+ struct smb_msgbuf_mlist *next;
+ size_t size;
+} smb_msgbuf_mlist_t;
+
+/*
+ * smb_smgbuf flags
+ *
+ * SMB_MSGBUF_UNICODE When there is a choice between unicode or ascii
+ * formatting, select unicode processing.
+ * SMB_MSGBUF_NOTERM Do not null terminate strings.
+ */
+#define SMB_MSGBUF_UNICODE 0x00000001
+#define SMB_MSGBUF_NOTERM 0x00000002
+
+/*
+ * base: points to the beginning of the buffer
+ * end: points to the limit of the buffer.
+ * scan: points to the current offset.
+ * max: holds the number of bytes in the buffer.
+ * count: unused.
+ * mlist: anchors the dynamically allocated memory list.
+ * flags: see SMB_SMGBUF flags.
+ */
+typedef struct smb_msgbuf {
+ uint8_t *base;
+ uint8_t *end;
+ uint8_t *scan;
+ size_t count;
+ size_t max;
+ smb_msgbuf_mlist_t mlist;
+ uint32_t flags;
+} smb_msgbuf_t;
+
+/*
+ * List of smb_msgbuf_decode and smb_msgbuf_encode return values.
+ */
+#define SMB_MSGBUF_SUCCESS 0
+#define SMB_MSGBUF_UNDERFLOW -1
+#define SMB_MSGBUF_OVERFLOW SMB_MSGBUF_UNDERFLOW
+#define SMB_MSGBUF_INVALID_FORMAT -2
+#define SMB_MSGBUF_INVALID_HEADER -3
+#define SMB_MSGBUF_DATA_ERROR -4
+
+/*
+ * smb_msgbuf_init must be called to associate the smb_msgbuf_t with
+ * a buffer before any encode or decode operations may be performed.
+ *
+ * smb_msgbuf_term must be called to free any dynamically allocated memory
+ * that was acquired during encode or decode operations. At this time
+ * the only operation that allocates memory is a unicode string decode.
+ *
+ * If there are no errors, smb_msgbuf_decode and smb_msgbuf_encode return
+ * the number of bytes decoded or encoded. If there is a problem they
+ * return -ve error codes.
+ */
+extern void smb_msgbuf_init(smb_msgbuf_t *, uint8_t *, size_t, uint32_t);
+extern void smb_msgbuf_term(smb_msgbuf_t *);
+extern int smb_msgbuf_decode(smb_msgbuf_t *, char *, ...);
+extern int smb_msgbuf_encode(smb_msgbuf_t *, char *, ...);
+extern size_t smb_msgbuf_used(smb_msgbuf_t *);
+extern size_t smb_msgbuf_size(smb_msgbuf_t *);
+extern uint8_t *smb_msgbuf_base(smb_msgbuf_t *);
+extern void smb_msgbuf_word_align(smb_msgbuf_t *);
+extern void smb_msgbuf_dword_align(smb_msgbuf_t *);
+extern int smb_msgbuf_has_space(smb_msgbuf_t *, size_t);
+extern void smb_msgbuf_fset(smb_msgbuf_t *, uint32_t);
+extern void smb_msgbuf_fclear(smb_msgbuf_t *, uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_MSGBUF_H */
diff --git a/usr/src/uts/common/smbsrv/ndl/dssetup.ndl b/usr/src/uts/common/smbsrv/ndl/dssetup.ndl
new file mode 100644
index 0000000000..143d243e5a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/dssetup.ndl
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+#ifndef _DSSETUP_NDL_
+#define _DSSETUP_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Active Directory Service Setup
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define DSSETUP_OPNUM_DsRoleGetPrimaryDomainInfo 0x00
+#define DSSETUP_OPNUM_DsRoleDnsNameToFlatName 0x01
+#define DSSETUP_OPNUM_DsRoleDcAsDc 0x02
+#define DSSETUP_OPNUM_DsRoleDcAsReplica 0x03
+#define DSSETUP_OPNUM_DsRoleDemoteDc 0x04
+#define DSSETUP_OPNUM_DsRoleGetDcOperationProgress 0x05
+#define DSSETUP_OPNUM_DsRoleGetDcOperationResults 0x06
+#define DSSETUP_OPNUM_DsRoleCancel 0x07
+#define DSSETUP_OPNUM_DsRoleServerSaveStateForUpgrade 0x08
+#define DSSETUP_OPNUM_DsRoleUpgradeDownlevelServer 0x09
+#define DSSETUP_OPNUM_DsRoleAbortDownlevelServerUpgrade 0x0a
+
+/*
+ * DS roles
+ */
+#define DS_ROLE_STANDALONE_WORKSTATION 0
+#define DS_ROLE_MEMBER_WORKSTATION 1
+#define DS_ROLE_STANDALONE_SERVER 2
+#define DS_ROLE_MEMBER_SERVER 3
+#define DS_ROLE_BACKUP_DC 4
+#define DS_ROLE_PRIMARY_DC 5
+
+/*
+ * DS role flags
+ */
+#define DS_ROLE_PRIMARY_DS_RUNNING 0x00000001
+#define DS_ROLE_PRIMARY_DS_MIXED_MODE 0x00000002
+#define DS_ROLE_UPGRADE_IN_PROGRESS 0x00000004
+#define DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT 0x01000000
+
+/*
+ * DS role upgrade
+ */
+#define DS_ROLE_NOT_UPGRADING 0
+#define DS_ROLE_UPGRADING 1
+
+/*
+ * DS role previous
+ */
+#define DS_ROLE_PREVIOUS_UNKNOWN 0
+#define DS_ROLE_PREVIOUS_PRIMARY 1
+#define DS_ROLE_PREVIOUS_BACKUP 2
+
+/*
+ * DS role state
+ */
+#define DS_ROLE_OP_IDLE 0
+#define DS_ROLE_OP_ACTIVE 1
+#define DS_ROLE_OP_NEEDS_REBOOT 2
+
+/*
+ * DS role information levels
+ */
+#define DS_ROLE_BASIC_INFORMATION 1
+#define DS_ROLE_UPGRADE_STATUS 2
+#define DS_ROLE_OP_STATUS 3
+
+struct dssetup_uuid {
+ DWORD data1;
+ WORD data2;
+ WORD data3;
+ BYTE data4[8];
+};
+typedef struct dssetup_uuid dssetup_uuid_t;
+
+/*
+ * DS_ROLE_BASIC_INFORMATION
+ */
+struct dssetup_DsRolePrimaryDomInfo1 {
+ DWORD role;
+ DWORD flags;
+ LPTSTR nt_domain;
+ LPTSTR dns_domain;
+ LPTSTR forest;
+ dssetup_uuid_t domain_guid;
+};
+
+/*
+ * DS_ROLE_UPGRADE_STATUS
+ */
+struct dssetup_DsRolePrimaryDomInfo2 {
+ DWORD upgrade_state;
+ DWORD previous_role;
+};
+
+/*
+ * DS_ROLE_OP_STATUS
+ */
+struct dssetup_DsRolePrimaryDomInfo3 {
+ DWORD status;
+};
+
+union dssetup_GetPrimaryDomainInfo_ru {
+ UNION_INFO_ENT(1,dssetup_DsRolePrimaryDomInfo);
+ UNION_INFO_ENT(2,dssetup_DsRolePrimaryDomInfo);
+ UNION_INFO_ENT(3,dssetup_DsRolePrimaryDomInfo);
+ DEFAULT char *nullptr;
+};
+
+struct dssetup_GetPrimaryDomainInfoRes {
+ DWORD address;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union dssetup_GetPrimaryDomainInfo_ru ru;
+};
+
+OPERATION(DSSETUP_OPNUM_DsRoleGetPrimaryDomainInfo)
+struct dssetup_DsRoleGetPrimaryDomainInfo {
+ IN WORD level;
+ OUT DWORD address;
+ OUT WORD switch_value;
+ SWITCH(level)
+ OUT union dssetup_GetPrimaryDomainInfo_ru ru;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * DSSETUP interface definiton.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union dssetup_interface {
+ CASE(DSSETUP_OPNUM_DsRoleGetPrimaryDomainInfo)
+ struct dssetup_DsRoleGetPrimaryDomainInfo GetPrimaryDomainInfo;
+};
+typedef union dssetup_interface dssetup_interface_t;
+EXTERNTYPEINFO(dssetup_interface)
+
+#endif /* _DSSETUP_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/eventlog.ndl b/usr/src/uts/common/smbsrv/ndl/eventlog.ndl
new file mode 100644
index 0000000000..3e412ceb00
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/eventlog.ndl
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_LOGR_NDL_
+#define _MLSVC_LOGR_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ ***********************************************************************
+ *
+ * Event log RPC (EVENTLOG) interface definition.
+ *
+ ***********************************************************************
+ */
+
+#include "ndrtypes.ndl"
+
+#define LOGR_OPNUM_EventLogClose 0x02
+#define LOGR_OPNUM_EventLogQueryCount 0x04
+#define LOGR_OPNUM_EventLogGetOldestRec 0x05
+#define LOGR_OPNUM_EventLogOpen 0x07
+#define LOGR_OPNUM_EventLogRead 0x0A
+
+#define LOGR_INFOLEN 200
+#define LOGR_RECBUFLEN 0x4000
+
+struct logr_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+
+typedef struct logr_handle logr_handle_t;
+
+
+struct logr_string {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct logr_string logr_string_t;
+
+
+struct logr_record {
+ DWORD Length1; // Length of full record
+ DWORD Reserved; // Used by the service
+ DWORD RecordNumber; // Absolute record number
+ DWORD TimeGenerated; // Seconds since 1-1-1970
+ DWORD TimeWritten; // Seconds since 1-1-1970
+ DWORD EventID;
+ WORD EventType;
+ WORD NumStrings;
+ WORD EventCategory;
+ WORD ReservedFlags; // For use with paired events (auditing)
+ DWORD ClosingRecordNumber; // For use with paired events (auditing)
+ DWORD StringOffset; // Offset from beginning of record
+ DWORD UserSidLength;
+ DWORD UserSidOffset;
+ DWORD DataLength;
+ DWORD DataOffset;
+ //
+ // Then follow:
+ //
+ // WCHAR SourceName[] null terminated
+ // WCHAR Computername[] null terminated
+ // SID UserSid
+ // WCHAR Strings[]
+ // BYTE Data[]
+ // CHAR Pad[] to DWORD
+ // DWORD Length; must be appear
+ BYTE info[LOGR_INFOLEN];
+ DWORD Length2;
+};
+typedef struct logr_record logr_record_t;
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogClose
+ ***********************************************************************
+ */
+OPERATION(LOGR_OPNUM_EventLogClose)
+struct logr_EventLogClose {
+ IN logr_handle_t handle;
+ OUT logr_handle_t result_handle;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogQueryCount
+ ***********************************************************************
+ */
+OPERATION(LOGR_OPNUM_EventLogQueryCount)
+struct logr_EventLogQueryCount {
+ IN logr_handle_t handle;
+ OUT DWORD rec_num;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogGetOldestRec
+ ***********************************************************************
+ */
+OPERATION(LOGR_OPNUM_EventLogGetOldestRec)
+struct logr_EventLogGetOldestRec {
+ IN logr_handle_t handle;
+ OUT DWORD oldest_rec;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogOpen
+ ***********************************************************************
+ */
+OPERATION(LOGR_OPNUM_EventLogOpen)
+struct logr_EventLogOpen {
+ IN DWORD *whatever;
+ IN logr_string_t log_name;
+ IN DWORD unknown1;
+ IN DWORD unknown2;
+ IN DWORD unknown3;
+ OUT logr_handle_t handle;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogRead
+ ***********************************************************************
+ */
+union logr_read_u {
+ CASE(1024) BYTE rec[1024];
+ DEFAULT BYTE recs[LOGR_RECBUFLEN];
+};
+
+
+struct logr_read_info {
+ DWORD nbytes_to_read;
+ SWITCH(nbytes_to_read)
+ union logr_read_u ru;
+};
+
+OPERATION(LOGR_OPNUM_EventLogRead)
+struct logr_EventLogRead {
+ IN logr_handle_t handle;
+ IN DWORD read_flags;
+ IN DWORD rec_offset;
+ INOUT DWORD nbytes_to_read;
+SWITCH (nbytes_to_read)
+ OUT union logr_read_u ru;
+ OUT DWORD sent_size;
+ OUT DWORD unknown;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * The EVENTLOG interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union logr_interface {
+ CASE(LOGR_OPNUM_EventLogClose)
+ struct logr_EventLogClose EventLogClose;
+ CASE(LOGR_OPNUM_EventLogQueryCount)
+ struct logr_EventLogQueryCount EventLogQueryCount;
+ CASE(LOGR_OPNUM_EventLogGetOldestRec)
+ struct logr_EventLogGetOldestRec EventLogGetOldestRec;
+ CASE(LOGR_OPNUM_EventLogOpen)
+ struct logr_EventLogOpen EventLogOpen;
+ CASE(LOGR_OPNUM_EventLogRead)
+ struct logr_EventLogRead EventLogRead;
+};
+typedef union logr_interface logr_interface_t;
+EXTERNTYPEINFO(logr_interface)
+
+
+#endif /* _MLSVC_LOGR_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/llsrpc.ndl b/usr/src/uts/common/smbsrv/ndl/llsrpc.ndl
new file mode 100644
index 0000000000..33b3cccd77
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/llsrpc.ndl
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_LLSR_NDL_
+#define _MLSVC_LLSR_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * LLSRPC interface.
+ *
+ * 0x50 takes the 3a handle + DWORD, returns 2 DWORDs
+ * 0x3c
+ * 0x3f list of services?
+ * 0x3d unknown
+ * 0x3e unknown
+ * 0x4f
+ * 0x4d
+ * 0x4e
+ * 0x01 closes the handle obtained via 0x00
+ * 0x3b closes the handle obtained via 0x3a
+ */
+
+#include "ndrtypes.ndl"
+
+#define LLSR_OPNUM_Open 0x00
+#define LLSR_OPNUM_Close 0x01
+#define LLSR_OPNUM_Connect 0x3a
+#define LLSR_OPNUM_Disconnect 0x3b
+#define LLSR_OPNUM_Unknown3c 0x3c
+#define LLSR_OPNUM_Unknown3d 0x3d
+#define LLSR_OPNUM_Unknown3e 0x3e
+#define LLSR_OPNUM_Unknown3f 0x3f
+#define LLSR_OPNUM_Unknown4d 0x4d
+#define LLSR_OPNUM_Unknown4e 0x4e
+#define LLSR_OPNUM_Unknown4f 0x4f
+#define LLSR_OPNUM_Unknown50 0x50
+
+
+struct llsr_handle {
+ DWORD opaque[5];
+};
+typedef struct llsr_handle llsr_handle_t;
+
+
+OPERATION(LLSR_OPNUM_Open)
+struct llsr_Open {
+ IN LPTSTR hostname;
+ OUT llsr_handle_t open_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(LLSR_OPNUM_Close)
+struct llsr_Close {
+ IN llsr_handle_t open_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(LLSR_OPNUM_Connect)
+struct llsr_Connect {
+ IN LPTSTR hostname;
+ OUT llsr_handle_t connect_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(LLSR_OPNUM_Disconnect)
+struct llsr_Disconnect {
+ IN llsr_handle_t connect_handle;
+ OUT llsr_handle_t echoed_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(LLSR_OPNUM_Unknown50)
+struct llsr_Unknown50 {
+ IN llsr_handle_t open_handle;
+ IN DWORD unknown1; /* 0x00000004 */
+ OUT DWORD unknown2; /* 0x00000004 */
+ OUT DWORD unknown3; /* 0x0000003F */
+ OUT DWORD status;
+};
+
+
+#endif /* _MLSVC_LLSR_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl b/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl
new file mode 100644
index 0000000000..102a3cf63d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl
@@ -0,0 +1,801 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_LSA_NDL_
+#define _MLSVC_LSA_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ ***********************************************************************
+ * Local Security Authority RPC (LSARPC) interface definition.
+ ***********************************************************************
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define LSARPC_OPNUM_CloseHandle 0x00
+#define LSARPC_OPNUM_EnumPrivileges 0x02
+#define LSARPC_OPNUM_QuerySecurityObject 0x03
+#define LSARPC_OPNUM_SetSecurityObject 0x04
+#define LSARPC_OPNUM_ChangePassword 0x05
+#define LSARPC_OPNUM_OpenPolicy 0x06
+#define LSARPC_OPNUM_QueryInfoPolicy 0x07
+#define LSARPC_OPNUM_SetInfoPolicy 0x08
+#define LSARPC_OPNUM_Unknown09 0x09 /* Crashed the DC */
+#define LSARPC_OPNUM_CreateAccount 0x0a
+#define LSARPC_OPNUM_EnumerateAccounts 0x0b
+#define LSARPC_OPNUM_CreateTrustedDomain 0x0c
+#define LSARPC_OPNUM_EnumTrustedDomain 0x0d
+#define LSARPC_OPNUM_LookupNames 0x0e
+#define LSARPC_OPNUM_LookupSids 0x0f
+#define LSARPC_OPNUM_CreateSecret 0x10
+#define LSARPC_OPNUM_OpenAccount 0x11
+#define LSARPC_OPNUM_EnumPrivsAccount 0x12
+#define LSARPC_OPNUM_GetSystemAccessAccount 0x17
+#define LSARPC_OPNUM_OpenSecret 0x1c
+#define LSARPC_OPNUM_LookupPrivValue 0x1f
+#define LSARPC_OPNUM_LookupPrivName 0x20
+#define LSARPC_OPNUM_LookupPrivDisplayName 0x21
+#define LSARPC_OPNUM_AddAccountRights 0x25
+#define LSARPC_OPNUM_OpenPolicy2 0x2c
+#define LSARPC_OPNUM_GetConnectedUser 0x2d
+#define LSARPC_OPNUM_Discovery 0x2e
+#define LSARPC_OPNUM_LookupSids2 0x39
+#define LSARPC_OPNUM_LookupNames2 0x3a
+
+
+/*
+ * There are at least two lookup level settings. Level 1 appears to mean
+ * only look on the local host and level 2 means forward the request to
+ * the PDC. On the PDC it probably doesn't matter which level you use but
+ * on a BDC a level 1 lookup will fail if the BDC doesn't have the info
+ * whereas a level 2 lookup will also check with the PDC.
+ */
+#define MSLSA_LOOKUP_LEVEL_1 1
+#define MSLSA_LOOKUP_LEVEL_2 2
+
+
+/*
+ * Definition for a SID. The ndl compiler won't allow a typedef of
+ * a structure containing variable size members.
+ */
+struct mslsa_sid {
+ BYTE Revision;
+ BYTE SubAuthCount;
+ BYTE Authority[6];
+ SIZE_IS(SubAuthCount)
+ DWORD SubAuthority[ANY_SIZE_ARRAY];
+};
+
+struct mslsa_string_desc {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct mslsa_string_desc mslsa_string_t;
+
+
+struct mslsa_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+typedef struct mslsa_handle mslsa_handle_t;
+
+
+struct mslsa_luid {
+ DWORD low_part;
+ DWORD high_part;
+};
+typedef struct mslsa_luid mslsa_luid_t;
+
+
+/*
+ ***********************************************************************
+ * OpenPolicy2 obtains a handle for a remote LSA. This handle is
+ * required for all subsequent LSA requests.
+ *
+ * The server name should be the name of the target PDC or BDC, with
+ * the double backslash prefix.
+ *
+ * As far as I can tell, the mslsa_object_attributes structure can be
+ * all zero except for the length, which should be set to sizeof(struct
+ * mslsa_object_attributes).
+ *
+ * For read access, the desired access mask should contain the
+ * READ_CONTROL standard right and whatever policy rights are required.
+ * I haven't tried any update operations but if you get the access mask
+ * wrong you can crash the domain controller.
+ ***********************************************************************
+ */
+
+
+/*
+ * From netmon:
+ * length = 12
+ * impersonation_level = 2
+ * context_tracking_mode = 1
+ * effective_only = 0
+ */
+struct mslsa_quality_of_service {
+ DWORD length;
+ WORD impersonation_level;
+ BYTE context_tracking_mode;
+ BYTE effective_only;
+};
+
+
+struct mslsa_object_attributes {
+ DWORD length;
+ DWORD rootDirectory;
+ DWORD objectName;
+ DWORD attributes;
+ DWORD securityDescriptor;
+ struct mslsa_quality_of_service *qualityOfService;
+};
+
+
+OPERATION(LSARPC_OPNUM_OpenPolicy)
+struct mslsa_OpenPolicy {
+ IN DWORD *servername;
+ IN struct mslsa_object_attributes attributes;
+ IN DWORD desiredAccess;
+ OUT mslsa_handle_t domain_handle;
+ OUT DWORD status;
+};
+
+OPERATION(LSARPC_OPNUM_OpenPolicy2)
+struct mslsa_OpenPolicy2 {
+ IN LPTSTR servername;
+ IN struct mslsa_object_attributes attributes;
+ IN DWORD desiredAccess;
+ OUT mslsa_handle_t domain_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * CloseHandle closes an association with the LSA. The returned handle
+ * will be all zero.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_CloseHandle)
+struct mslsa_CloseHandle {
+ IN mslsa_handle_t handle;
+ OUT mslsa_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * EnumPrivileges
+ *
+ * Obtain a list of privilege names. This interface is not implemented
+ * yet The definition below has not been tested. This is a guess based
+ * on data available from netmon.
+ ***********************************************************************
+ */
+struct mslsa_PrivDef {
+ mslsa_string_t name;
+ mslsa_luid_t luid;
+};
+
+
+struct mslsa_PrivEnumBuf {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslsa_PrivDef *def;
+};
+
+
+OPERATION(LSARPC_OPNUM_EnumPrivileges)
+struct mslsa_EnumPrivileges {
+ IN mslsa_handle_t handle;
+ INOUT DWORD enum_context;
+ IN DWORD max_length;
+ OUT REFERENCE struct mslsa_PrivEnumBuf *enum_buf;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QuerySecurityObject. I'm not entirely sure how to set this up yet.
+ * I used the discovery RPC to scope it out. The structures are set up
+ * according to netmon and the assumption that a security descriptor
+ * on the wire looks like the regular user level security descriptor.
+ ***********************************************************************
+ */
+struct mslsa_SecurityDescriptor {
+ BYTE revision;
+ BYTE sbz1;
+ WORD control;
+ DWORD owner;
+ DWORD group;
+ DWORD sacl;
+ DWORD dacl;
+};
+
+
+struct mslsa_SecurityDescInfo {
+ DWORD length;
+ SIZE_IS(length)
+ BYTE *desc; /* temporary */
+ /* struct mslsa_SecurityDescriptor *desc; */
+};
+
+
+OPERATION(LSARPC_OPNUM_QuerySecurityObject)
+struct mslsa_QuerySecurityObject {
+ IN mslsa_handle_t handle;
+ IN DWORD security_info;
+ OUT struct mslsa_SecurityDescInfo *desc_info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * EnumerateAccounts and EnumerateTrustedDomain.
+ ***********************************************************************
+ */
+struct mslsa_AccountInfo {
+ struct mslsa_sid *sid;
+};
+
+
+struct mslsa_EnumAccountBuf {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslsa_AccountInfo *info;
+};
+
+
+OPERATION(LSARPC_OPNUM_EnumerateAccounts)
+struct mslsa_EnumerateAccounts {
+ IN mslsa_handle_t handle;
+ INOUT DWORD enum_context;
+ IN DWORD max_length;
+ OUT REFERENCE struct mslsa_EnumAccountBuf *enum_buf;
+ OUT DWORD status;
+};
+
+
+struct mslsa_TrustedDomainInfo {
+ mslsa_string_t name;
+ struct mslsa_sid *sid;
+};
+
+
+struct mslsa_EnumTrustedDomainBuf {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslsa_TrustedDomainInfo *info;
+};
+
+
+OPERATION(LSARPC_OPNUM_EnumTrustedDomain)
+struct mslsa_EnumTrustedDomain {
+ IN mslsa_handle_t handle;
+ INOUT DWORD enum_context;
+ IN DWORD max_length;
+ OUT REFERENCE struct mslsa_EnumTrustedDomainBuf *enum_buf;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Definitions common to both LookupSids and LookupNames. Both return
+ * an mslsa_domain_table[]. Each interface also returns a specific
+ * table with entries which index the mslsa_domain_table[].
+ ***********************************************************************
+ */
+struct mslsa_domain_entry {
+ mslsa_string_t domain_name;
+ struct mslsa_sid *domain_sid;
+};
+typedef struct mslsa_domain_entry mslsa_domain_entry_t;
+
+
+struct mslsa_domain_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ mslsa_domain_entry_t *entries;
+ DWORD max_n_entry;
+};
+
+
+/*
+ ***********************************************************************
+ * Definitions for LookupSids.
+ *
+ * The input parameters are:
+ *
+ * A valid LSA handle obtained from an LsarOpenPolicy.
+ * The table of SIDs to be looked up.
+ * A table of names (probably empty).
+ * The lookup level (local=1 or PDC=2).
+ * An enumeration counter (used for continuation operations).
+ *
+ * The output results are:
+ *
+ * A table of referenced domains.
+ * A table of usernames.
+ * The updated value of the enumeration counter.
+ * The result status.
+ ***********************************************************************
+ */
+
+struct mslsa_lup_sid_entry {
+ struct mslsa_sid *psid;
+};
+
+struct mslsa_lup_sid_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct mslsa_lup_sid_entry *entries;
+};
+
+struct mslsa_name_entry {
+ WORD sid_name_use;
+ WORD unknown_flags;
+ mslsa_string_t name;
+ DWORD domain_ix; /* -1 means none */
+};
+
+struct mslsa_name_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct mslsa_name_entry *entries;
+};
+
+OPERATION(LSARPC_OPNUM_LookupSids)
+struct mslsa_LookupSids {
+ IN mslsa_handle_t handle;
+ IN struct mslsa_lup_sid_table lup_sid_table;
+
+ OUT struct mslsa_domain_table *domain_table;
+ INOUT struct mslsa_name_table name_table;
+
+ IN DWORD lookup_level;
+ INOUT DWORD mapped_count;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Definitions for LookupNames.
+ *
+ * LookupNames requires the following input parameters.
+ *
+ * A valid LSA handle obtained from an LsarOpenPolicy.
+ * The table of names to be looked up.
+ * A table of translated sids (probably empty).
+ * The lookup level (local=1 or PDC=2).
+ * An enumeration counter (used for continuation operations).
+ *
+ * The outputs are as follows.
+ *
+ * A table of referenced domains.
+ * A table of translated sids (actually rids).
+ * The updated value of the enumeration counter.
+ * The result status.
+ ***********************************************************************
+ */
+struct mslsa_lup_name_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ mslsa_string_t names[ANY_SIZE_ARRAY];
+};
+
+
+struct mslsa_rid_entry {
+ WORD sid_name_use;
+ WORD pad; /* alignment - probably not required */
+ DWORD rid;
+ DWORD domain_index;
+};
+
+
+struct mslsa_rid_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct mslsa_rid_entry *rids;
+};
+
+
+OPERATION(LSARPC_OPNUM_LookupNames)
+struct mslsa_LookupNames {
+ IN mslsa_handle_t handle;
+ IN REFERENCE struct mslsa_lup_name_table *name_table;
+
+ OUT struct mslsa_domain_table *domain_table;
+ INOUT struct mslsa_rid_table translated_sids;
+
+ IN DWORD lookup_level;
+ INOUT DWORD mapped_count;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryInfoPolicy returns various pieces of policy information. The
+ * desired information is specified using a class value, as defined
+ * below.
+ ***********************************************************************
+ */
+#define MSLSA_POLICY_UNKNOWN_1_INFO 1
+#define MSLSA_POLICY_UNKNOWN_2_INFO 2
+#define MSLSA_POLICY_PRIMARY_DOMAIN_INFO 3
+#define MSLSA_POLICY_UNKNOWN_4_INFO 4
+#define MSLSA_POLICY_ACCOUNT_DOMAIN_INFO 5
+#define MSLSA_POLICY_SERVER_ROLE_INFO 6
+#define MSLSA_POLICY_REPLICA_SOURCE_INFO 7
+#define MSLSA_POLICY_DEFAULT_QUOTA_INFO 8
+
+
+struct mslsa_PrimaryDomainInfo {
+ struct mslsa_string_desc name;
+ struct mslsa_sid *sid;
+};
+
+
+struct mslsa_AccountDomainInfo {
+ struct mslsa_string_desc name;
+ struct mslsa_sid *sid;
+};
+
+/*
+struct mslsa_ServerRoleInfo {
+ WORD unknown_0x0003;
+ WORD unknown_0x000e;
+};
+*/
+
+union mslsa_PolicyInfoResUnion {
+ CASE(3) struct mslsa_PrimaryDomainInfo pd_info;
+ CASE(5) struct mslsa_AccountDomainInfo ad_info;
+ DEFAULT char *nullptr;
+};
+
+
+struct mslsa_PolicyInfo {
+ WORD switch_value;
+ SWITCH(switch_value)
+ union mslsa_PolicyInfoResUnion ru;
+};
+
+
+OPERATION(LSARPC_OPNUM_QueryInfoPolicy)
+struct mslsa_QueryInfoPolicy {
+ IN mslsa_handle_t handle;
+ IN WORD info_class;
+ OUT struct mslsa_PolicyInfo *info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenAccount.
+ *
+ * Returns a handle that can be used to access the account specified
+ * by a SID. This handle can be used to enumerate account privileges.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_OpenAccount)
+struct mslsa_OpenAccount {
+ IN mslsa_handle_t handle;
+ IN REFERENCE struct mslsa_sid *sid;
+ IN DWORD access_mask;
+ OUT mslsa_handle_t account_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * EnumPrivilegesAccount.
+ *
+ * Enumerate the list of privileges held by the specified account. The
+ * handle must be a valid account handle obtained via OpenAccount. The
+ * luid values returned will be probably only be relevant on the domain
+ * controller so we'll need to find a way to convert them to the
+ * actual privilege names.
+ ***********************************************************************
+ */
+struct mslsa_LuidAndAttributes {
+ struct mslsa_luid luid;
+ DWORD attributes;
+};
+
+
+struct mslsa_PrivilegeSet {
+ DWORD privilege_count;
+ DWORD control;
+ SIZE_IS(privilege_count)
+ struct mslsa_LuidAndAttributes privilege[ANY_SIZE_ARRAY];
+};
+
+
+OPERATION(LSARPC_OPNUM_EnumPrivsAccount)
+ struct mslsa_EnumPrivsAccount {
+ IN mslsa_handle_t account_handle;
+ OUT struct mslsa_PrivilegeSet *privileges;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupPrivValue
+ *
+ * Map a privilege name to a local unique id (LUID). Privilege names
+ * are consistent across the network. LUIDs are machine specific.
+ * The privilege list is provided as a set of LUIDs so the privilege
+ * lookup functions must be used to identify which the privilege to
+ * which each LUID refers. The handle here is a policy handle.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_LookupPrivValue)
+struct mslsa_LookupPrivValue {
+ IN mslsa_handle_t handle;
+ IN mslsa_string_t name;
+ OUT struct mslsa_luid luid;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupPrivName
+ *
+ * Map a privilege value (LUID) to a privilege name. Privilege names
+ * are consistent across the network. LUIDs are machine specific.
+ * The privilege list is provided as a set of LUIDs so the privilege
+ * lookup functions must be used to identify which the privilege to
+ * which each LUID refers. The handle here is a policy handle.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_LookupPrivName)
+struct mslsa_LookupPrivName {
+ IN mslsa_handle_t handle;
+ IN struct mslsa_luid luid;
+ OUT mslsa_string_t *name;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupPrivDisplayName
+ *
+ * Map a privilege name to a local unique id (LUID). Privilege names
+ * are consistent across the network. LUIDs are machine specific.
+ * The privilege list is provided as a set of LUIDs so the privilege
+ * lookup functions must be used to identify which the privilege to
+ * which each LUID refers. The handle here is a policy handle.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_LookupPrivDisplayName)
+struct mslsa_LookupPrivDisplayName {
+ IN mslsa_handle_t handle;
+ IN mslsa_string_t name;
+ IN WORD client_language;
+ IN WORD default_language;
+ OUT mslsa_string_t *display_name;
+ OUT WORD language_ret;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * GetConnectedUser
+ *
+ * This is still guesswork. Netmon doesn't know about this
+ * call and I'm not really sure what it is intended to achieve.
+ * Another packet capture application, Ethereal, calls this RPC as
+ * GetConnectedUser.
+ * We will receive our own hostname in the request and it appears
+ * we should respond with an account name and the domain name of connected
+ * user from the client that makes this call.
+ ***********************************************************************
+ */
+
+struct mslsa_DomainName {
+ struct mslsa_string_desc *name;
+};
+
+
+OPERATION(LSARPC_OPNUM_GetConnectedUser)
+struct mslsa_GetConnectedUser {
+ IN LPTSTR hostname;
+ IN BYTE *unknown1;
+ IN BYTE *unknown2;
+ OUT struct mslsa_string_desc *owner;
+ OUT struct mslsa_DomainName *domain;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LSARPC_OPNUM_LookupSids2
+ *
+ * SID lookup function that appeared in Windows 2000. It appears to be
+ * very similar to the original SID lookup RPC. There are two extra IN
+ * parameters, which we don't care about. The OUT name structure has
+ * an extra field, in which zero seems to be okay.
+ ***********************************************************************
+ */
+struct lsar_name_entry2 {
+ WORD sid_name_use;
+ WORD unknown_flags; /* maybe alignment */
+ mslsa_string_t name;
+ DWORD domain_ix; /* -1 means none */
+ DWORD unknown; /* added */
+};
+
+
+struct lsar_name_table2 {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct lsar_name_entry2 *entries;
+};
+
+
+OPERATION(LSARPC_OPNUM_LookupSids2)
+struct lsar_lookup_sids2 {
+ IN mslsa_handle_t policy_handle;
+ IN struct mslsa_lup_sid_table lup_sid_table;
+ OUT struct mslsa_domain_table *domain_table;
+ INOUT struct lsar_name_table2 name_table;
+ IN DWORD lookup_level;
+ INOUT DWORD mapped_count;
+ IN DWORD zero;
+ IN DWORD requested_count;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LSARPC_OPNUM_LookupNames2
+ *
+ * Name lookup function that appeared in Windows 2000. It appears to be
+ * very similar to the original name lookup RPC. There are two extra IN
+ * parameters, which we don't care about. The lsar_rid_entry2 structure
+ * has an extra field, in which zero seems to be okay.
+ ***********************************************************************
+ */
+struct lsar_rid_entry2 {
+ WORD sid_name_use;
+ WORD pad; /* alignment - probably not required */
+ DWORD rid;
+ DWORD domain_index; /* -1 means none */
+ DWORD unknown; /* new */
+};
+
+
+struct lsar_rid_table2 {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct lsar_rid_entry2 *rids;
+};
+
+
+OPERATION(LSARPC_OPNUM_LookupNames2)
+struct lsar_LookupNames2 {
+ IN mslsa_handle_t policy_handle;
+ IN REFERENCE struct mslsa_lup_name_table *name_table;
+ OUT struct mslsa_domain_table *domain_table;
+ INOUT struct lsar_rid_table2 translated_sids;
+ IN DWORD lookup_level;
+ INOUT DWORD mapped_count;
+ IN DWORD unknown_sbz;
+ IN DWORD unknown_sb2;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * This is a generic discovery entry. As long as the handle is valid
+ * this is useful for scoping the network to discover new worlds. To
+ * seek out new life, new civilizations. To boldly spilt infinitives
+ * where no man has gone before. So basically we send and receive a
+ * big buffer and let netmon tell us to which RPC the opnum refers.
+ ***********************************************************************
+ */
+
+#define LSA_DISCOVERY_SIZE 16
+
+
+OPERATION(LSARPC_OPNUM_Discovery)
+struct mslsa_Discovery {
+ IN mslsa_handle_t handle;
+ IN DWORD in_stuff[LSA_DISCOVERY_SIZE];
+ OUT DWORD out_stuff[LSA_DISCOVERY_SIZE];
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The LSARPC interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union lsarpc_interface {
+ CASE(LSARPC_OPNUM_CloseHandle)
+ struct mslsa_CloseHandle CloseHandle;
+ CASE(LSARPC_OPNUM_QuerySecurityObject)
+ struct mslsa_QuerySecurityObject QuerySecurityObj;
+ CASE(LSARPC_OPNUM_EnumerateAccounts)
+ struct mslsa_EnumerateAccounts EnumAccounts;
+ CASE(LSARPC_OPNUM_EnumTrustedDomain)
+ struct mslsa_EnumTrustedDomain EnumTrustedDomain;
+ CASE(LSARPC_OPNUM_OpenAccount)
+ struct mslsa_OpenAccount OpenAccount;
+ CASE(LSARPC_OPNUM_EnumPrivsAccount)
+ struct mslsa_EnumPrivsAccount EnumPrivsAccount;
+ CASE(LSARPC_OPNUM_LookupPrivValue)
+ struct mslsa_LookupPrivValue LookupPrivValue;
+ CASE(LSARPC_OPNUM_LookupPrivName)
+ struct mslsa_LookupPrivName LookupPrivName;
+ CASE(LSARPC_OPNUM_LookupPrivDisplayName)
+ struct mslsa_LookupPrivDisplayName LookupPrivDisplayName;
+ CASE(LSARPC_OPNUM_Discovery)
+ struct mslsa_Discovery Discovery;
+ CASE(LSARPC_OPNUM_QueryInfoPolicy)
+ struct mslsa_QueryInfoPolicy QueryInfoPolicy;
+ CASE(LSARPC_OPNUM_OpenPolicy)
+ struct mslsa_OpenPolicy OpenPolicy;
+ CASE(LSARPC_OPNUM_OpenPolicy2)
+ struct mslsa_OpenPolicy2 OpenPolicy2;
+ CASE(LSARPC_OPNUM_LookupSids)
+ struct mslsa_LookupSids LookupSids;
+ CASE(LSARPC_OPNUM_LookupNames)
+ struct mslsa_LookupNames LookupNames;
+ CASE(LSARPC_OPNUM_GetConnectedUser)
+ struct mslsa_GetConnectedUser GetConnectedUser;
+ CASE(LSARPC_OPNUM_LookupSids2)
+ struct lsar_lookup_sids2 LookupSids2;
+ CASE(LSARPC_OPNUM_LookupNames2)
+ struct lsar_LookupNames2 LookupNames2;
+};
+typedef union lsarpc_interface lsarpc_interface_t;
+EXTERNTYPEINFO(lsarpc_interface)
+
+#endif /* _MLSVC_LSA_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/ndrtypes.ndl b/usr/src/uts/common/smbsrv/ndl/ndrtypes.ndl
new file mode 100644
index 0000000000..ec3b76c978
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/ndrtypes.ndl
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#ifndef _NDR_TYPES_NDL_
+#define _NDR_TYPES_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define TYPEINFO(TYPE) ndt__##TYPE
+
+#ifdef NDRGEN
+
+#define ALIGN(X) [align(X)]
+#define OPERATION(X) [operation(X)]
+#define IN [in]
+#define OUT [out]
+#define INOUT [in out]
+
+#define STRING [string]
+#define SIZE_IS(X) [size_is(X)]
+
+#define SWITCH(X) [switch_is(X)]
+#define CASE(X) [case(X)]
+#define DEFAULT [default]
+
+#define INTERFACE(X) [interface(X)]
+#define UUID(X) [uuid(X)]
+
+#define ARG_IS(X) [arg_is(X)]
+
+#define REFERENCE [reference]
+
+#define ANY_SIZE_ARRAY *
+
+#define IMPORT_EXTERN [extern]
+
+#define BYTE uchar
+#define WORD ushort
+#define DWORD ulong
+
+#define LPTSTR STRING wchar *
+
+#define LPBYTE uchar *
+#define LPWORD ushort *
+#define LPDWORD ulong *
+
+#define EXTERNTYPEINFO(TYPE)
+
+#else /* NDRGEN */
+
+#define ALIGN(X)
+#define OPERATION(X)
+#define IN
+#define OUT
+#define INOUT
+
+#define STRING
+#define SIZE_IS(X)
+
+#define SWITCH(X)
+#define CASE(X)
+#define DEFAULT
+
+#define INTERFACE(X)
+#define UUID(X)
+
+#define ARG_IS(X)
+
+#define REFERENCE
+
+
+#ifndef ANY_SIZE_ARRAY
+#define ANY_SIZE_ARRAY 1
+#endif /* ANY_SIZE_ARRAY */
+
+
+#define IMPORT_EXTERN
+
+
+#ifndef UNSIGNED_TYPES_DEFINED
+#define UNSIGNED_TYPES_DEFINED
+
+#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned long
+#define LPTSTR unsigned char *
+#define LPBYTE unsigned char *
+#define LPWORD unsigned short *
+#define LPDWORD unsigned long *
+
+#endif /* UNSIGNED_TYPES_DEFINED */
+
+
+#define EXTERNTYPEINFO(TYPE) extern struct ndr_typeinfo TYPEINFO(TYPE);
+
+
+/*
+ ***********************************************************************
+ * There is a bug in the way that midl and the marshalling code handles
+ * unions so we need to fix some of the data offsets at runtime. The
+ * following macros and the fixup function handle the correction.
+ ***********************************************************************
+ */
+
+/*
+ * DECL_FIXUP_STRUCT allows us to declare external references to data
+ * structures generated by ndrgen in the _ndr.c file.
+ */
+#define DECL_FIXUP_STRUCT(NAME) \
+ extern struct ndr_typeinfo ndt__##NAME
+
+/*
+ * CASE_INFO_ENT is intended to simplify the declaration of the case
+ * statement in the fixup function. Assuming you have followed the
+ * convention for naming the individual structures all you have to do
+ * is add a single line to the fixup function for each new case.
+ */
+#define CASE_INFO_ENT(NAME,N) \
+ case N: size1 = sizeof (struct NAME##N); \
+ break
+
+/*
+ * FIXUP_PDU_SIZE is used to patch the appropriate structures (identified
+ * by DECL_FIXUP_STRUCT) at runtime. The values are based on the
+ * switch_index.
+ */
+#define FIXUP_PDU_SIZE(NAME,SIZE) { \
+ ndt__##NAME.pdu_size_fixed_part = SIZE; \
+ ndt__##NAME.c_size_fixed_part = SIZE; \
+}
+
+
+#endif /* NDRGEN */
+
+/*
+ * UNION_INFO_ENT is intended to simplify adding new entries to a union.
+ * If the entry structures are named using the form FunctionNameX,
+ * where X is the sitch_value, you can just add a single line. Note
+ * that you must also update the fixup function in mlsvc_xxx.c.
+ */
+#define UNION_INFO_ENT(N,NAME) CASE(N) struct NAME##N info##N
+#define UNION_INFO_PTR(N,NAME) CASE(N) struct NAME##N *info##N
+
+#endif /* _NDR_TYPES_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/netdfs.ndl b/usr/src/uts/common/smbsrv/ndl/netdfs.ndl
new file mode 100644
index 0000000000..a2f86b452d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/netdfs.ndl
@@ -0,0 +1,493 @@
+/*
+ * 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.
+ */
+
+#ifndef _NETDFS_NDL_
+#define _NETDFS_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Distributed File Service (NETDFS) RPC interface definition.
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define NETDFS_ABSTRACT_UUID "4fc742e0-4a10-11cf-827300aa004ae673"
+#define NETDFS_ABSTRACT_VERS 3
+
+#define NETDFS_TRANSFER_UUID "8a885d04-1ceb-11c9-9fe808002b104860"
+#define NETDFS_TRANSFER_VERS 2
+
+#define NETDFS_OPNUM_GETVER 0x00
+#define NETDFS_OPNUM_ADD 0x01
+#define NETDFS_OPNUM_REMOVE 0x02
+#define NETDFS_OPNUM_SETINFO 0x03
+#define NETDFS_OPNUM_GETINFO 0x04
+#define NETDFS_OPNUM_ENUM 0x05
+#define NETDFS_OPNUM_RENAME 0x06
+#define NETDFS_OPNUM_MOVE 0x07
+#define NETDFS_OPNUM_ADDSTDROOT 0x0c
+#define NETDFS_OPNUM_REMSTDROOT 0x0d
+#define NETDFS_OPNUM_ENUMEX 0x15
+
+#define DFS_MANAGER_VERSION_NT4 0x01
+#define DFS_MANAGER_VERSION_W2K 0x02
+#define DFS_MANAGER_VERSION_W2K3 0x04
+
+
+#define DFS_PROP_FLAG_INSITE_REFERRALS 0x01
+#define DFS_PROP_FLAG_ROOT_SCALABILITY 0x02
+#define DFS_PROP_FLAG_SITE_COSTING 0x04
+#define DFS_PROP_FLAG_TARGET_FAILBACK 0x08
+#define DFS_PROP_FLAG_CLUSTER_ENABLED 0x10
+
+
+#define DFS_STORAGE_PRI_INVALID -1
+#define DFS_STORAGE_PRI_SITE_COST_NORM 0
+#define DFS_STORAGE_PRI_GLOBAL_HIGH 1
+#define DFS_STORAGE_PRI_SITE_COST_HIGH 2
+#define DFS_STORAGE_PRI_SITE_COST_LOW 3
+#define DFS_STORAGE_PRI_GLOBAL_LOW 4
+
+
+struct netdfs_storage_info {
+ DWORD state;
+ LPTSTR server;
+ LPTSTR share;
+};
+
+
+struct netdfs_storage_info2 {
+ DWORD state;
+ LPTSTR server;
+ LPTSTR share;
+ DWORD priority;
+ DWORD rank;
+};
+
+struct netdfs_info1 {
+ LPTSTR entry_path;
+};
+
+
+struct netdfs_info2 {
+ LPTSTR entry_path;
+ LPTSTR comment;
+ DWORD state;
+ DWORD n_store;
+};
+
+
+struct netdfs_info3 {
+ LPTSTR entry_path;
+ LPTSTR comment;
+ DWORD state;
+ DWORD n_store;
+ SIZE_IS(n_store)
+ struct netdfs_storage_info *si;
+};
+
+
+struct netdfs_info4 {
+ LPTSTR entry_path;
+ LPTSTR comment;
+ DWORD state;
+ DWORD timeout;
+ DWORD guuid[4];
+ DWORD n_store;
+ SIZE_IS(n_store)
+ struct netdfs_storage_info *si;
+};
+
+
+struct netdfs_info6 {
+ LPTSTR entry_path;
+ LPTSTR comment;
+ DWORD state;
+ DWORD timeout;
+ DWORD guuid[4];
+ DWORD flags;
+ DWORD pktsize;
+ DWORD n_store;
+ SIZE_IS(n_store)
+ struct netdfs_storage_info2 *si;
+};
+
+
+struct netdfs_info100 {
+ LPTSTR comment;
+};
+
+
+struct netdfs_info101 {
+ DWORD state;
+};
+
+
+struct netdfs_info102 {
+ DWORD timeout;
+};
+
+
+struct netdfs_info103 {
+ DWORD property_flags;
+};
+
+
+struct netdfs_info104 {
+ DWORD priority_class;
+ DWORD priority_rank;
+};
+
+
+struct netdfs_info105 {
+ LPTSTR comment;
+ DWORD volume_state;
+ DWORD timeout;
+ DWORD property_flag_mask;
+ DWORD property_flags;
+};
+
+
+struct netdfs_info106 {
+ DWORD storage_state;
+ DWORD priority_class;
+ DWORD priority_rank;
+};
+
+
+struct netdfs_info200 {
+ LPTSTR entry_path;
+};
+
+
+struct netdfs_info300 {
+ DWORD flavor;
+ LPTSTR entry_path;
+};
+
+
+union netdfs_info_u {
+ CASE(1) struct netdfs_info1 *info1;
+ CASE(2) struct netdfs_info2 *info2;
+ CASE(3) struct netdfs_info3 *info3;
+ CASE(4) struct netdfs_info4 *info4;
+ CASE(6) struct netdfs_info6 *info6;
+ CASE(100) struct netdfs_info100 *info100;
+ CASE(101) struct netdfs_info101 *info101;
+ CASE(102) struct netdfs_info102 *info102;
+ CASE(103) struct netdfs_info103 *info103;
+ CASE(104) struct netdfs_info104 *info104;
+ CASE(105) struct netdfs_info105 *info105;
+ CASE(106) struct netdfs_info106 *info106;
+ DEFAULT char *nullptr;
+};
+
+
+struct netdfs_info {
+ DWORD level;
+ SWITCH(level)
+ union netdfs_info_u iu;
+};
+
+
+struct netdfs_array1 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info1 *info1;
+};
+
+struct netdfs_array2 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info2 *info2;
+};
+
+struct netdfs_array3 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info3 *info3;
+};
+
+struct netdfs_array4 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info4 *info4;
+};
+
+struct netdfs_array6 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info6 *info6;
+};
+
+struct netdfs_array200 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info200 *info200;
+};
+
+struct netdfs_array300 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info300 *info300;
+};
+
+union netdfs_enum_info_u {
+ CASE(1) struct netdfs_array1 *info1;
+ CASE(2) struct netdfs_array2 *info2;
+ CASE(3) struct netdfs_array3 *info3;
+ CASE(4) struct netdfs_array4 *info4;
+ CASE(6) struct netdfs_array6 *info6;
+ CASE(200) struct netdfs_array200 *info200;
+ CASE(300) struct netdfs_array300 *info300;
+ DEFAULT char *nullptr;
+};
+
+
+struct netdfs_enum_info {
+ DWORD address;
+ DWORD level;
+ SWITCH(level)
+ union netdfs_enum_info_u iu;
+};
+
+
+/*
+ ***********************************************************************
+ * Return server version id
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_GETVER)
+struct netdfs_getver {
+ OUT DWORD version;
+};
+
+
+/*
+ ***********************************************************************
+ * Add a new volume or additional storage for an existing volume at
+ * dfs_path.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_ADD)
+struct netdfs_add {
+ IN REFERENCE LPTSTR dfs_path;
+ IN REFERENCE LPTSTR server;
+ IN LPTSTR share;
+ IN LPTSTR comment;
+ IN DWORD flags;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Remove a volume or additional storage for volume from the DFS at
+ * dfs_path. When applied to the last storage in a volume, removes
+ * the volume from the DFS.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_REMOVE)
+struct netdfs_remove {
+ IN REFERENCE LPTSTR dfs_path;
+ IN LPTSTR server;
+ IN LPTSTR share;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Set information about the volume or storage. If the server and share
+ * are specified, the information set is specific to that server and
+ * share. Otherwise the information is specific to the volume as a whole.
+ *
+ * Valid levels are 100-102.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_SETINFO)
+struct netdfs_setinfo {
+ IN REFERENCE LPTSTR dfs_path;
+ IN LPTSTR server;
+ IN LPTSTR share;
+ IN DWORD level;
+ IN struct netdfs_info info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Get information about the volume or storage. If the server and share
+ * are specified, the information returned is specific to that server
+ * and share. Otherwise the information is specific to the volume as a
+ * whole.
+ *
+ * Valid levels are 1-4, 100-102.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_GETINFO)
+struct netdfs_getinfo {
+ IN REFERENCE LPTSTR dfs_path;
+ IN LPTSTR server;
+ IN LPTSTR share;
+ IN DWORD level;
+ OUT struct netdfs_info info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Get information about all of the volumes in the DFS. dfs_path is
+ * the "server" part of the UNC name used to refer to this particular
+ * DFS.
+ *
+ * Valid levels are 1-3.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_ENUM)
+struct netdfs_enum {
+ IN DWORD level;
+ IN DWORD pref_max_len;
+ INOUT struct netdfs_enum_info *info;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Rename the current Win32 path in a DFS to a new Win32 path in the
+ * same DFS.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_RENAME)
+struct netdfs_rename {
+ IN REFERENCE LPTSTR dfs_path;
+ IN REFERENCE LPTSTR new_path;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Move a DFS volume and all subordinate volumes from one place in the
+ * DFS to another place in the DFS.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_MOVE)
+struct netdfs_move {
+ IN REFERENCE LPTSTR dfs_path;
+ IN REFERENCE LPTSTR new_path;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Add a DFS root share.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_ADDSTDROOT)
+struct netdfs_addstdroot {
+ IN REFERENCE LPTSTR server;
+ IN REFERENCE LPTSTR share;
+ IN REFERENCE LPTSTR comment;
+ IN DWORD flags;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * Remove a DFS root share.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_REMSTDROOT)
+struct netdfs_remstdroot {
+ IN REFERENCE LPTSTR server;
+ IN REFERENCE LPTSTR share;
+ IN DWORD flags;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Get information about all of the volumes in the DFS. dfs_path is
+ * the "server" part of the UNC name used to refer to this particular
+ * DFS.
+ *
+ * Valid levels are 1-3.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_ENUMEX)
+struct netdfs_enumex {
+ IN REFERENCE LPTSTR dfs_path;
+ IN DWORD level;
+ IN DWORD pref_max_len;
+ INOUT struct netdfs_enum_info *info;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The NETDFS interface definiton.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union netdfs_interface {
+ CASE(NETDFS_OPNUM_GETVER)
+ struct netdfs_getver netdfs_getver;
+ CASE(NETDFS_OPNUM_ADD)
+ struct netdfs_add netdfs_add;
+ CASE(NETDFS_OPNUM_REMOVE)
+ struct netdfs_remove netdfs_remove;
+ CASE(NETDFS_OPNUM_SETINFO)
+ struct netdfs_setinfo netdfs_setinfo;
+ CASE(NETDFS_OPNUM_GETINFO)
+ struct netdfs_getinfo netdfs_getinfo;
+ CASE(NETDFS_OPNUM_ENUM)
+ struct netdfs_enum netdfs_enum;
+ CASE(NETDFS_OPNUM_MOVE)
+ struct netdfs_move netdfs_move;
+ CASE(NETDFS_OPNUM_RENAME)
+ struct netdfs_rename netdfs_rename;
+ CASE(NETDFS_OPNUM_ADDSTDROOT)
+ struct netdfs_addstdroot netdfs_addstdroot;
+ CASE(NETDFS_OPNUM_REMSTDROOT)
+ struct netdfs_remstdroot netdfs_remstdroot;
+ CASE(NETDFS_OPNUM_ENUMEX)
+ struct netdfs_enumex netdfs_enumex;
+};
+typedef union netdfs_interface netdfs_interface_t;
+EXTERNTYPEINFO(netdfs_interface)
+
+
+#endif /* _NETDFS_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/netlogon.ndl b/usr/src/uts/common/smbsrv/ndl/netlogon.ndl
new file mode 100644
index 0000000000..e37ee4ca8c
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/netlogon.ndl
@@ -0,0 +1,395 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_NETR_NDL_
+#define _MLSVC_NETR_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ ***********************************************************************
+ *
+ * NetLogon RPC (NETR) interface definition.
+ *
+ ***********************************************************************
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define NETR_OPNUM_SamLogon 0x02
+#define NETR_OPNUM_SamLogoff 0x03
+#define NETR_OPNUM_ServerReqChallenge 0x04
+#define NETR_OPNUM_ServerPasswordSet 0x06
+#define NETR_OPNUM_LogonControl2 0x0E
+#define NETR_OPNUM_ServerAuthenticate2 0x0F
+#define NETR_OPNUM_TrustDomainList 0x13
+
+
+struct netr_sid {
+ BYTE Revision;
+ BYTE SubAuthCount;
+ BYTE Authority[6];
+ SIZE_IS(SubAuthCount)
+ DWORD SubAuthority[ANY_SIZE_ARRAY];
+};
+
+
+struct netr_string {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct netr_string netr_string_t;
+
+
+/*
+ * Alternative varying/conformant string definition - for
+ * non-null terminated strings. This definition must match
+ * mlrpc_vcbuf_t.
+ */
+struct netr_vcb {
+ /*
+ * size_is (actually a copy of length_is) will
+ * be inserted here by the marshalling library.
+ */
+ DWORD vc_first_is;
+ DWORD vc_length_is;
+ SIZE_IS(vc_length_is)
+ WORD buffer[ANY_SIZE_ARRAY];
+};
+
+struct netr_vcbuf {
+ WORD wclen;
+ WORD wcsize;
+ struct netr_vcb *vcb;
+};
+typedef struct netr_vcbuf netr_vcbuf_t;
+
+
+struct netr_credential {
+ BYTE data[8];
+};
+
+
+struct netr_authenticator {
+ struct netr_credential credential;
+ DWORD timestamp;
+};
+typedef struct netr_authenticator netr_auth_t;
+
+
+struct OLD_LARGE_INTEGER {
+ DWORD LowPart;
+ DWORD HighPart;
+};
+typedef struct OLD_LARGE_INTEGER netr_int64_t;
+
+
+struct OWF_PASSWORD {
+ BYTE data[16];
+};
+typedef struct OWF_PASSWORD netr_owf_password_t;
+
+
+struct CYPHER_BLOCK {
+ BYTE data[8];
+};
+
+
+struct USER_SESSION_KEY {
+ struct CYPHER_BLOCK data[2];
+};
+
+
+
+
+/*
+ ***********************************************************************
+ * ServerReqChallenge
+ ***********************************************************************
+ */
+ALIGN(2)
+OPERATION(NETR_OPNUM_ServerReqChallenge)
+struct netr_ServerReqChallenge {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR hostname;
+ IN struct netr_credential client_challenge;
+ OUT struct netr_credential server_challenge;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * ServerAuthenticate2
+ ***********************************************************************
+ */
+ALIGN(2)
+OPERATION(NETR_OPNUM_ServerAuthenticate2)
+struct netr_ServerAuthenticate2 {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR account_name;
+ IN WORD account_type;
+ IN REFERENCE LPTSTR hostname;
+ IN struct netr_credential client_credential;
+ OUT struct netr_credential server_credential;
+ INOUT DWORD negotiate_flags;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * ServerPasswordSet
+ ***********************************************************************
+ */
+ALIGN(2)
+OPERATION(NETR_OPNUM_ServerPasswordSet)
+struct netr_PasswordSet {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR account_name;
+ IN WORD account_type;
+ IN REFERENCE LPTSTR hostname;
+ INOUT struct netr_authenticator auth;
+ IN netr_owf_password_t uas_new_password;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SamLogon
+ ***********************************************************************
+ */
+
+/*
+ * The challenge-response data should always be 24 bytes.
+ */
+#define NETR_CR_PASSWORD_SIZE 24
+
+
+struct lm_challenge {
+ BYTE data[8];
+};
+typedef struct lm_challenge lm_challenge_t;
+
+
+struct netr_response {
+ DWORD length;
+ DWORD start;
+ DWORD max_length;
+ BYTE data[NETR_CR_PASSWORD_SIZE];
+};
+typedef struct netr_response netr_response_t;
+
+
+struct netr_response_desc {
+ WORD length;
+ WORD max_length;
+ netr_response_t *data;
+};
+typedef struct netr_response_desc netr_response_desc_t;
+
+/*
+ * Input data
+ */
+struct netr_logon_identity_info {
+ netr_vcbuf_t domain_name;
+ DWORD parameter_control;
+ struct OLD_LARGE_INTEGER logon_id;
+ netr_vcbuf_t username;
+ netr_vcbuf_t workstation;
+};
+typedef struct netr_logon_identity_info netr_logon_id_t;
+
+
+/*
+ * Level 1: interactive logon
+ */
+struct netr_logon_info1 {
+ netr_logon_id_t identity;
+ netr_owf_password_t lm_owf_password;
+ netr_owf_password_t nt_owf_password;
+};
+
+
+/*
+ * Level 2: network logon.
+ */
+struct netr_logon_info2 {
+ netr_logon_id_t identity;
+ lm_challenge_t lm_challenge;
+ netr_response_desc_t nt_response;
+ netr_response_desc_t lm_response;
+};
+
+
+union netr_logon_info_u {
+ UNION_INFO_PTR(1,netr_logon_info);
+ UNION_INFO_PTR(2,netr_logon_info);
+ DEFAULT DWORD nothing;
+};
+
+
+struct netr_login_info {
+ WORD logon_level;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union netr_logon_info_u ru;
+};
+
+
+/*
+ * Output data
+ */
+struct netr_group_membership {
+ DWORD rid;
+ DWORD attributes;
+};
+
+
+struct netr_sid_and_attributes {
+ struct netr_sid *sid;
+ DWORD attributes;
+};
+
+
+struct netr_validation_info3 {
+ struct OLD_LARGE_INTEGER LogonTime;
+ struct OLD_LARGE_INTEGER LogoffTime;
+ struct OLD_LARGE_INTEGER KickOffTime;
+ struct OLD_LARGE_INTEGER PasswordLastSet;
+ struct OLD_LARGE_INTEGER PasswordCanChange;
+ struct OLD_LARGE_INTEGER PasswordMustChange;
+ netr_string_t EffectiveName;
+ netr_string_t FullName;
+ netr_string_t LogonScript;
+ netr_string_t ProfilePath;
+ netr_string_t HomeDirectory;
+ netr_string_t HomeDirectoryDrive;
+ WORD LogonCount;
+ WORD BadPasswordCount;
+ DWORD UserId;
+ DWORD PrimaryGroupId;
+ DWORD GroupCount;
+ SIZE_IS(GroupCount)
+ struct netr_group_membership *GroupIds;
+ DWORD UserFlags;
+ struct USER_SESSION_KEY UserSessionKey;
+ netr_string_t LogonServer;
+ netr_string_t LogonDomainName;
+ struct netr_sid *LogonDomainId;
+ DWORD ExpansionRoom[10];
+ DWORD SidCount;
+ SIZE_IS(SidCount)
+ struct netr_sid_and_attributes *ExtraSids;
+};
+
+
+union netr_validation_u {
+ CASE(3) struct netr_validation_info3 *info3;
+ DEFAULT DWORD nothing;
+};
+
+
+/*
+ * This structure needs to be declared, even though it can't be used
+ * in netr_SamLogon, in order to get the appropriate size to calculate
+ * the correct fixup offsets. If ndrgen did the right thing,
+ * netr_validation_info would be one of the out parameters. However,
+ * if we do it that way, the switch_value isn't known early enough to
+ * do the fixup calculation. So it all has to go in netr_SamLogon.
+ */
+struct netr_validation_info {
+ WORD validation_level;
+ SWITCH(validation_level)
+ union netr_validation_u ru;
+};
+
+
+/*
+ * WARNING
+ *
+ * Validation_level is really a WORD and authoritative is really a
+ * BYTE. They are declared as DWORD here due to the way things are
+ * unmarshalled. NT does not clear out the unused bytes in the
+ * DWORD so they must be cast to get the correct value.
+ */
+OPERATION(NETR_OPNUM_SamLogon)
+struct netr_SamLogon {
+ IN LPTSTR servername;
+ IN LPTSTR hostname;
+ IN struct netr_authenticator *auth;
+ INOUT struct netr_authenticator *ret_auth;
+ IN struct netr_login_info logon_info;
+ INOUT WORD validation_level;
+ SWITCH(validation_level)
+ OUT union netr_validation_u ru;
+ OUT DWORD authoritative;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SamLogoff
+ ***********************************************************************
+ */
+OPERATION(NETR_OPNUM_SamLogoff)
+struct netr_SamLogoff {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR hostname;
+ IN struct netr_authenticator auth;
+ INOUT struct netr_authenticator ret_auth;
+ IN DWORD logon_level;
+ SWITCH(logon_level)
+ IN union netr_logon_info_u ru;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The NETR interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union netr_interface {
+ CASE(NETR_OPNUM_ServerReqChallenge)
+ struct netr_ServerReqChallenge ServerReqChallenge;
+ CASE(NETR_OPNUM_ServerAuthenticate2)
+ struct netr_ServerAuthenticate2 ServerAuthenticate2;
+ CASE(NETR_OPNUM_SamLogon)
+ struct netr_SamLogon SamLogon;
+ CASE(NETR_OPNUM_SamLogoff)
+ struct netr_SamLogoff SamLogoff;
+ CASE(NETR_OPNUM_ServerPasswordSet)
+ struct netr_PasswordSet PasswordSet;
+};
+typedef union netr_interface netr_interface_t;
+EXTERNTYPEINFO(netr_interface)
+
+#endif /* _MLSVC_NETR_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/rpcpdu.ndl b/usr/src/uts/common/smbsrv/ndl/rpcpdu.ndl
new file mode 100644
index 0000000000..fd42fcac1c
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/rpcpdu.ndl
@@ -0,0 +1,552 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLRPCPDU_NDL_
+#define _MLRPCPDU_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "ndrtypes.ndl"
+
+/*
+ * Normally, constructs are (un)marshalled atoms first, then
+ * constructs, then pointers. This can be confusing sometimes
+ * when debugging. We know that everything in here can be
+ * safely (un)marshalled in member order, so we say so.
+ */
+#ifdef NDRGEN
+#define _NO_REORDER_ [_no_reorder]
+#else
+#define _NO_REORDER_
+#endif
+
+/*
+ * UUID (Universal Unique IDentifier)
+ */
+/* (X/Open CAE Spec Appendix A) */
+struct mlrpc_uuid_dce {
+ DWORD time_low;
+ WORD time_mid;
+ WORD time_hi_and_version;
+ BYTE clock_seq_hi_and_reserved;
+ BYTE clock_seq_low;
+ BYTE node[6];
+};
+
+struct mlrpc_uuid {
+ DWORD data1;
+ WORD data2;
+ WORD data3;
+ BYTE data4[8];
+};
+typedef struct mlrpc_uuid mlrpc_uuid_t;
+
+/*
+ * Representation label -- needed for RPC header
+ * (X/Open CAE Spec Chapter 14.1)
+ *
+ * Bits Data Type Description
+ * ---- --------- -----------
+ * 0-3 charset 0=ASCII
+ * 1=EBCDIC
+ * 4-7 byte-order 0=big-endian
+ * 1=little-endian
+ * 8-15 float 0=IEEE
+ * 1=VAX
+ * 2=Cray
+ * 3=IBM
+ * 16-31 reserved
+ */
+#define MLRPC_REPLAB_CHAR_MASK 0x0F /* low nibble of intg_char */
+#define MLRPC_REPLAB_CHAR_ASCII 0x00 /* ASCII */
+#define MLRPC_REPLAB_CHAR_EBCDIC 0x01 /* EBCDIC (never happen) */
+#define MLRPC_REPLAB_INTG_MASK 0xF0 /* hi nibble of intg_char */
+#define MLRPC_REPLAB_INTG_BIG_ENDIAN 0x00 /* big endian */
+#define MLRPC_REPLAB_INTG_LITTLE_ENDIAN 0x10 /* little endian (x86) */
+#define MLRPC_REPLAB_FLOAT_IEEE 0x00
+#define MLRPC_REPLAB_FLOAT_VAX 0x01
+#define MLRPC_REPLAB_FLOAT_CRAY 0x02
+#define MLRPC_REPLAB_FLOAT_IBM 0x03
+
+struct mlrpc_representation_label {
+ BYTE intg_char_rep; /* integer and charset */
+ BYTE float_rep;
+ BYTE _spare[2];
+};
+
+
+
+/*
+ * RPC PDU (Protocol Data Unit) types
+ ****************************************************************
+ * (X/Open CAE Spec 12.1)
+ */
+
+#define MLRPC_PTYPE_REQUEST 0x00 /* CO/CL */
+#define MLRPC_PTYPE_PING 0x01 /* CL */
+#define MLRPC_PTYPE_RESPONSE 0x02 /* CO/CL */
+#define MLRPC_PTYPE_FAULT 0x03 /* CL/CL */
+#define MLRPC_PTYPE_WORKING 0x04 /* CL */
+#define MLRPC_PTYPE_NOCALL 0x05 /* CL */
+#define MLRPC_PTYPE_REJECT 0x06 /* CL */
+#define MLRPC_PTYPE_ACK 0x07 /* CL */
+#define MLRPC_PTYPE_CL_CANCEL 0x08 /* CL */
+#define MLRPC_PTYPE_FACK 0x09 /* CL */
+#define MLRPC_PTYPE_CANCEL_ACK 0x0A /* CL */
+#define MLRPC_PTYPE_BIND 0x0B /* CO */
+#define MLRPC_PTYPE_BIND_ACK 0x0C /* CO */
+#define MLRPC_PTYPE_BIND_NAK 0x0D /* CO */
+#define MLRPC_PTYPE_ALTER_CONTEXT 0x0E /* CO */
+#define MLRPC_PTYPE_ALTER_CONTEXT_RESP 0x0F /* CO */
+ /* 0x10 missing from DCE/RPC */
+#define MLRPC_PTYPE_SHUTDOWN 0x11 /* CO */
+#define MLRPC_PTYPE_CO_CANCEL 0x12 /* CO */
+#define MLRPC_PTYPE_ORPHANED 0x13 /* CO */
+
+/*
+ * Flags in the RPC header for Connection-oriented PDU data types
+ * (X/Open CAE Spec 12.6.3.1)
+ */
+#define MLRPC_PFC_FIRST_FRAG 0x01 /* First fragment */
+#define MLRPC_PFC_LAST_FRAG 0x02 /* Last framgent */
+#define MLRPC_PFC_PENDING_CANCEL 0x04 /* Cancel was pending@sender*/
+#define MLRPC_PFC_RESERVED_1 0x08 /* */
+#define MLRPC_PFC_CONC_MPX 0x10 /* supports concurrent muxing
+ * of single connection */
+#define MLRPC_PFC_DID_NOT_EXECUTE 0x20 /* for PTYPE_FAULT, guarantee
+ * call did not execute */
+#define MLRPC_PFC_MAYBE 0x40 /* "maybe" semantics req'ed*/
+#define MLRPC_PFC_OBJECT_UUID 0x80 /* */
+
+
+/*
+ * Header common to all Connection-oriented RPC PDUs
+ ****************************************************************
+ * (X/Open CAE Spec 12.6.3.1)
+ */
+_NO_REORDER_
+struct mlrpcconn_common_header {
+ BYTE rpc_vers; /* 00:01 5 */
+ BYTE rpc_vers_minor; /* 01:01 0 */
+ BYTE ptype; /* 02:01 MLRPC_PTYPE_... */
+ BYTE pfc_flags; /* 03:01 MLRPC_PFC_... */
+ struct mlrpc_representation_label
+ packed_drep; /* 04:04 NDR representation label */
+ WORD frag_length; /* 08:02 total length of frag */
+ WORD auth_length; /* 10:02 length of auth_value */
+ DWORD call_id; /* 12:04 call identifier */
+ /* 16: */
+};
+typedef struct mlrpcconn_common_header mlrpcconn_common_header_t;
+EXTERNTYPEINFO(mlrpcconn_common_header)
+
+
+/*
+ * A plethora of supporting types, only defined the ones we need
+ * (X/Open CAE Spec 12.6.3.1)
+ */
+typedef WORD mlrpc_p_context_id_t;
+
+_NO_REORDER_
+struct mlrpc_p_syntax_id {
+ mlrpc_uuid_t if_uuid;
+ DWORD if_version;
+};
+typedef struct mlrpc_p_syntax_id mlrpc_p_syntax_id_t;
+
+_NO_REORDER_
+struct mlrpc_p_cont_elem {
+ mlrpc_p_context_id_t p_cont_id;
+ BYTE n_transfer_syn;
+ BYTE _reserved;
+ mlrpc_p_syntax_id_t abstract_syntax;
+ /*SIZE_IS(n_transfer_syn)*/
+ mlrpc_p_syntax_id_t transfer_syntaxes[1];
+};
+typedef struct mlrpc_p_cont_elem mlrpc_p_cont_elem_t;
+EXTERNTYPEINFO(mlrpc_p_cont_elem)
+
+_NO_REORDER_
+struct mlrpc_p_cont_list {
+ BYTE n_context_elem;
+ BYTE _reserved;
+ WORD _reserved2;
+ /*SIZE_IS(n_context_elem)*/
+ mlrpc_p_cont_elem_t p_cont_elem[1];
+};
+typedef struct mlrpc_p_cont_list mlrpc_p_cont_list_t;
+EXTERNTYPEINFO(mlrpc_p_cont_list)
+
+typedef WORD mlrpc_p_cont_def_result_t;
+#define MLRPC_PCDR_ACCEPTANCE 0
+#define MLRPC_PCDR_USER_REJECTION 1
+#define MLRPC_PCDR_PROVIDER_REJECTION 2
+
+typedef WORD mlrpc_p_provider_reason_t;
+#define MLRPC_PPR_REASON_NOT_SPECIFIED 0
+#define MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED 1
+#define MLRPC_PPR_PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED 2
+#define MLRPC_PPR_LOCAL_LIMIT_EXCEEDED 3
+
+
+_NO_REORDER_
+struct mlrpc_p_result {
+ mlrpc_p_cont_def_result_t result; /* MLRPC_PCDR_... */
+ mlrpc_p_provider_reason_t reason; /* MLRPC_PPR_... */
+ mlrpc_p_syntax_id_t transfer_syntax; /* 0-fill if
+ * result!=ACCEPT*/
+};
+typedef struct mlrpc_p_result mlrpc_p_result_t;
+EXTERNTYPEINFO(mlrpc_p_result)
+
+_NO_REORDER_
+struct mlrpc_p_result_list {
+ BYTE n_results;
+ BYTE reserved;
+ WORD reserved2;
+ /*SIZE_IS(n_results)*/
+ mlrpc_p_result_t p_results[1];
+};
+typedef struct mlrpc_p_result_list mlrpc_p_result_list_t;
+EXTERNTYPEINFO(mlrpc_p_result_list)
+
+#define MLRPC_PORT_ANY_MAX_PORT_SPEC 30
+_NO_REORDER_
+struct mlrpc_port_any {
+ WORD length; /* always 18 */
+ /*SIZE_IS(length)*/
+ BYTE port_spec[MLRPC_PORT_ANY_MAX_PORT_SPEC];
+ /* \PIPE\ntsvcs */
+ /* We cheat by using 18, and pad on the right with zeroes */
+};
+typedef struct mlrpc_port_any mlrpc_port_any_t;
+EXTERNTYPEINFO(mlrpc_port_any)
+
+
+/*
+ * Alter Context PDU (0x0E)
+ * (X/Open CAE Spec 12.6.4.1)
+ */
+_NO_REORDER_
+struct mlrpcconn_alter_context_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ WORD max_xmit_frag; /* 16:02 ignored */
+ WORD max_recv_frag; /* 18:02 ignored */
+ DWORD assoc_group_id; /* 20:04 ignored */
+
+ /*
+ * Presentation context list (see bind hdr comments).
+ */
+ mlrpc_p_cont_list_t p_context_elem; /* 24: */
+
+ /* optional authentication verifier if auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_alter_context_hdr mlrpcconn_alter_context_hdr_t;
+
+
+/*
+ * Alter Context Response PDU (0x0F)
+ * (X/Open CAE Spec 12.6.4.2)
+ */
+_NO_REORDER_
+struct mlrpcconn_alter_context_rsp_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ WORD max_xmit_frag; /* 16:02 ignored */
+ WORD max_recv_frag; /* 18:02 ignored */
+ DWORD assoc_group_id; /* 20:04 ignored */
+ mlrpc_port_any_t sec_addr; /* 24:20 ignored */
+
+ /*
+ * Presentation context list (see bind hdr comments).
+ */
+ mlrpc_p_result_list_t p_result_list; /* 44:nn */
+
+ /* optional authentication verifier if auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_alter_context_rsp_hdr mlrpcconn_alter_context_rsp_hdr_t;
+
+
+/*
+ * Bind PDU (0x0B)
+ ****************************************************************
+ * (X/Open CAE Spec 12.6.4.3)
+ */
+
+_NO_REORDER_
+struct mlrpcconn_bind_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ WORD max_xmit_frag; /* 16:02 max xmit frag size, bytes */
+ WORD max_recv_frag; /* 18:02 max recv frag size, bytes */
+ DWORD assoc_group_id; /* 20:04 incarnation of client-server
+ * association group (???) */
+ /* 24: */
+
+ /* presentation, a variable**2 list, of presentation contexts */
+ mlrpc_p_cont_list_t p_context_elem;
+ /*
+ * This could be follow by more transfer_syntaxes[] for
+ * the p_cont_elem[0], and subsequently followed by
+ * more p_cont_elem[] each with one ore more
+ * transfer_syntaxes[]. The single p_cont_elem[]
+ * with a single transfer_syntaxes[] is so common,
+ * though, we embed such right in the bind_hdr.
+ * The mlrpc_s_bind() processor must walk through
+ * this tail if there is one.
+ */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_bind_hdr mlrpcconn_bind_hdr_t;
+
+
+
+
+/*
+ * Bind_Ack PDU (0x0C)
+ ****************************************************************
+ * (X/Open CAE Spec 12.6.4.4)
+ */
+
+/*
+ * hand coded in mlrpc_encdec.c because sec_addr is an
+ * interior conformant (variable length) array.
+ */
+
+IMPORT_EXTERN /* don't generate function */
+_NO_REORDER_
+struct mlrpcconn_bind_ack_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ WORD max_xmit_frag; /* 16:02 max xmit frag size, bytes */
+ WORD max_recv_frag; /* 18:02 max recv frag size, bytes */
+ DWORD assoc_group_id; /* 20:04 incarnation of client-server
+ * association group (???) */
+ /* 24: */
+
+ mlrpc_port_any_t sec_addr; /* 24:20 */
+
+ mlrpc_p_result_list_t p_result_list; /* 44:nn */
+ /* This could be followed by more. See bind_hdr above */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_bind_ack_hdr mlrpcconn_bind_ack_hdr_t;
+
+
+
+
+/*
+ * Request PDU (0x00)
+ ****************************************************************
+ * Two flavors, selected based on MLRPC_PFC_OBJECT_UUID in hdr.pfc_flags
+ * one without the "object" (flag clear)
+ * one with the "object" (flag set)
+ * (X/Open CAE Spec 12.6.4.9)
+ */
+
+_NO_REORDER_
+struct mlrpcconn_request_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ /* needed for request, response, or fault */
+ DWORD alloc_hint; /* 16:04 allocation hint */
+ mlrpc_p_context_id_t
+ p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ WORD opnum; /* 22:02 op number w/i interface */
+
+ /* optional field if PFC_OBJECT_UUID, not present */
+ /* mlrpc_uuid_t object; */
+
+ /* stub-data, 8-octet aligned */ /* 24:nn */
+ /* nn = frag_len - sizeof(common_header) - auth_len */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_request_hdr mlrpcconn_request_hdr_t;
+
+_NO_REORDER_
+struct mlrpcconn_request_hdr_with_object {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ /* needed for request, response, or fault */
+ DWORD alloc_hint; /* 16:04 allocation hint */
+ mlrpc_p_context_id_t
+ p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ WORD opnum; /* 22:02 op number w/i interface */
+
+ /* optional field if PFC_OBJECT_UUID, is present */
+ mlrpc_uuid_t object; /* 24:16 object UUID, unknown purpose*/
+
+ /* stub-data, 8-octet aligned */ /* 28:nn */
+ /* nn = frag_len - sizeof(common_header) - auth_len */
+ /* nn -= sizeof(mlrpc_uuid_t); */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+
+
+
+/*
+ * Hack for response header sizing and multi-fragment responses.
+ * We know the header is going to be 24 bytes.
+ */
+#define MLRPC_RSP_HDR_SIZE 24
+
+
+/*
+ * Response PDU (0x02)
+ * (X/Open CAE Spec 12.6.4.10)
+ */
+
+_NO_REORDER_
+struct mlrpcconn_response_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ /* needed for request, response, or fault */
+ DWORD alloc_hint; /* 16:04 allocation hint */
+ mlrpc_p_context_id_t
+ p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ /* needed for response or fault */
+ BYTE cancel_count; /* 22:01 cancel count */
+ BYTE reserved; /* 23:01 mbz */
+
+ /* stub-data, 8-octet aligned */ /* 24:nn */
+ /* nn = frag_len - sizeof(common_header) - auth_len */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_response_hdr mlrpcconn_response_hdr_t;
+
+
+
+/*
+ * Fault PDU (0x03)
+ * (X/Open CAE Spec 12.6.4.7)
+ */
+
+_NO_REORDER_
+struct mlrpcconn_fault_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ DWORD alloc_hint; /* 16:04 allocation hint */
+ mlrpc_p_context_id_t
+ p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ /* needed for response or fault */
+ BYTE cancel_count; /* 22:01 cancel count */
+ BYTE reserved; /* 23:01 mbz */
+
+ /* fault code */
+ DWORD status; /* 24:04 run-time fault code or 0 */
+
+ /* pad to 8-byte alignment */
+ BYTE reserved2[4]; /* 28:04 must-be-zero */
+
+ /* stub-data here if status==0. We do not use this mode. */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_fault_hdr mlrpcconn_fault_hdr_t;
+
+
+/* Fault status code (X/Open CAE Spec Appendix E) */
+#define MLRPC_FAULT_NCA_RPC_VERSION_MISMATCH 0x1c000008 /* CO/CL */
+#define MLRPC_FAULT_NCA_UNSPEC_REJECT 0x1c000009 /* CO/CL */
+#define MLRPC_FAULT_NCA_S_BAD_ACTID 0x1c00000A /* CL */
+#define MLRPC_FAULT_NCA_WHO_ARE_YOU_FAILED 0x1c00000B /* CL */
+#define MLRPC_FAULT_NCA_MANAGER_NOT_ENTERED 0x1c00000C /* CO/CL */
+#define MLRPC_FAULT_NCA_OP_RNG_ERROR 0x1c010002 /* CO/CL */
+#define MLRPC_FAULT_NCA_UNK_IF 0x1c010003 /* CO/CL */
+#define MLRPC_FAULT_NCA_WRONG_BOOT_TIME 0x1c010006 /* CL */
+#define MLRPC_FAULT_NCA_S_YOU_CRASHED 0x1c010009 /* CL */
+#define MLRPC_FAULT_NCA_PROTO_ERROR 0x1c01000B /* CO/CL */
+#define MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG 0x1c010013 /* CO/CL */
+#define MLRPC_FAULT_NCA_SERVER_TOO_BUSY 0x1c010014 /* CO/CL */
+#define MLRPC_FAULT_NCA_UNSUPPORTED_TYPE 0x1c010017 /* CO/CL */
+#define MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID 0x1c00001c /* CO */
+#define MLRPC_FAULT_NCA_UNSUPPORTED_AUTHN_LEVEL 0x1c00001d /* CO/CL */
+#define MLRPC_FAULT_NCA_INVALID_CHECKSUM 0x1c00001f /* CO/CL */
+#define MLRPC_FAULT_NCA_INVALID_CRC 0x1c000020 /* CO/CL */
+
+
+
+
+/*
+ * The Header Union/Switch
+ ****************************************************************
+ */
+
+#define MLRPC_PTYPE_COMMON 999
+#define MLRPC_PTYPE_REQUEST_WITH 998
+
+
+INTERFACE(0)
+union mlrpcconn_hdr {
+ CASE(MLRPC_PTYPE_COMMON) /* exceeds BYTE range, obtains common hdr */
+ struct mlrpcconn_common_header common_hdr;
+
+ CASE(MLRPC_PTYPE_BIND)
+ struct mlrpcconn_bind_hdr bind_hdr;
+
+ CASE(MLRPC_PTYPE_BIND_ACK)
+ struct mlrpcconn_bind_ack_hdr bind_ack_hdr;
+
+ CASE(MLRPC_PTYPE_REQUEST)
+ struct mlrpcconn_request_hdr request_hdr;
+
+ CASE(MLRPC_PTYPE_REQUEST_WITH) /* exceeds BYTE range, ... */
+ struct mlrpcconn_request_hdr_with_object request_hdr_with;
+
+ CASE(MLRPC_PTYPE_RESPONSE)
+ struct mlrpcconn_response_hdr response_hdr;
+
+ CASE(MLRPC_PTYPE_ALTER_CONTEXT)
+ struct mlrpcconn_alter_context_hdr alter_context_hdr;
+
+ CASE(MLRPC_PTYPE_ALTER_CONTEXT_RESP)
+ struct mlrpcconn_alter_context_rsp_hdr alter_context_rsp_hdr;
+
+ CASE(MLRPC_PTYPE_FAULT)
+ struct mlrpcconn_fault_hdr fault_hdr;
+};
+typedef union mlrpcconn_hdr mlrpcconn_hdr_t;
+EXTERNTYPEINFO(mlrpcconn_hdr)
+
+#endif /* _MLRPCPDU_NDL_ */
+
diff --git a/usr/src/uts/common/smbsrv/ndl/samrpc.ndl b/usr/src/uts/common/smbsrv/ndl/samrpc.ndl
new file mode 100644
index 0000000000..0dfda51186
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/samrpc.ndl
@@ -0,0 +1,1314 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_SAM_NDL_
+#define _MLSVC_SAM_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Security Accounts Manager RPC (SAMR) interface definition.
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define SAMR_OPNUM_ConnectAnon 0x00
+#define SAMR_OPNUM_CloseHandle 0x01
+#define SAMR_OPNUM_QuerySecObject 0x03
+#define SAMR_OPNUM_LookupDomain 0x05
+#define SAMR_OPNUM_EnumLocalDomains 0x06
+#define SAMR_OPNUM_OpenDomain 0x07
+#define SAMR_OPNUM_QueryDomainInfo 0x08
+#define SAMR_OPNUM_CreateDomainGroup 0x0a
+#define SAMR_OPNUM_QueryDomainGroups 0x0b
+#define SAMR_OPNUM_EnumDomainUsers 0x0d
+#define SAMR_OPNUM_CreateDomainAlias 0x0e
+#define SAMR_OPNUM_EnumDomainAliases 0x0f
+#define SAMR_OPNUM_LookupIds 0x10
+#define SAMR_OPNUM_LookupNames 0x11
+#define SAMR_OPNUM_LookupDomainIds 0x12
+#define SAMR_OPNUM_OpenGroup 0x13
+#define SAMR_OPNUM_QueryGroupInfo 0x14
+#define SAMR_OPNUM_StoreGroupInfo 0x15
+#define SAMR_OPNUM_AddGroupMember 0x16
+#define SAMR_OPNUM_DeleteDomainGroup 0x17
+#define SAMR_OPNUM_DeleteGroupMember 0x18
+#define SAMR_OPNUM_ListGroupMembers 0x19
+#define SAMR_OPNUM_OpenAlias 0x1b
+#define SAMR_OPNUM_QueryAliasInfo 0x1c
+#define SAMR_OPNUM_SetAliasInfo 0x1d
+#define SAMR_OPNUM_DeleteDomainAlias 0x1e
+#define SAMR_OPNUM_AddAliasMember 0x1f
+#define SAMR_OPNUM_DeleteAliasMember 0x20
+#define SAMR_OPNUM_QueryAliasMember 0x21
+#define SAMR_OPNUM_OpenUser 0x22
+#define SAMR_OPNUM_DeleteUser 0x23
+#define SAMR_OPNUM_QueryUserInfo 0x24
+#define SAMR_OPNUM_QueryUserGroups 0x27
+#define SAMR_OPNUM_QueryDispInfo 0x28 /* QueryDispInfo1 */
+#define SAMR_OPNUM_GetUserPwInfo 0x2c
+#define SAMR_OPNUM_EnumDomainGroups 0x30 /* QueryDispInfo3 */
+#define SAMR_OPNUM_CreateUser 0x32
+#define SAMR_OPNUM_QueryDispInfo4 0x33
+#define SAMR_OPNUM_AddMultiAliasMember 0x34
+#define SAMR_OPNUM_ChangeUserPasswd 0x37
+#define SAMR_OPNUM_GetDomainPwInfo 0x38
+#define SAMR_OPNUM_Connect 0x39
+#define SAMR_OPNUM_SetUserInfo 0x3a
+#define SAMR_OPNUM_Connect3 0x3e
+#define SAMR_OPNUM_Connect4 0x40
+
+
+/*
+ * UNION_INFO_ENT is intended to simplify adding new entries to a union.
+ * If the entry structures are named using the form samr_QueryUserInfoX,
+ * where X is the sitch_value, you can just add a single line. Note
+ * that you must also update the fixup function in mlsvc_sam.c.
+ */
+#define UNION_INFO_ENT(N,NAME) CASE(N) struct NAME##N info##N
+
+
+/*
+ * Sam account flags used when creating an account. These flags seem
+ * to be very similar to the USER_INFO_X flags (UF_XXX) in lmaccess.h
+ * but the values are different.
+ */
+#define SAMR_AF_ACCOUNTDISABLE 0x0001
+#define SAMR_AF_HOMEDIR_REQUIRED 0x0002
+#define SAMR_AF_PASSWD_NOTREQD 0x0004
+#define SAMR_AF_TEMP_DUPLICATE_ACCOUNT 0x0008
+#define SAMR_AF_NORMAL_ACCOUNT 0x0010
+#define SAMR_AF_MNS_LOGON_ACCOUNT 0x0020
+#define SAMR_AF_INTERDOMAIN_TRUST_ACCOUNT 0x0040
+#define SAMR_AF_WORKSTATION_TRUST_ACCOUNT 0x0080
+#define SAMR_AF_SERVER_TRUST_ACCOUNT 0x0100
+#define SAMR_AF_DONT_EXPIRE_PASSWD 0x0200
+#define SAMR_AF_ACCOUNT_AUTOLOCK 0x0400
+
+
+#define SAMR_AF_MACHINE_ACCOUNT_MASK ( \
+ SAMR_AF_INTERDOMAIN_TRUST_ACCOUNT \
+ | SAMR_AF_WORKSTATION_TRUST_ACCOUNT \
+ | SAMR_AF_SERVER_TRUST_ACCOUNT)
+
+#define SAMR_AF_ACCOUNT_TYPE_MASK ( \
+ SAMR_AF_TEMP_DUPLICATE_ACCOUNT \
+ | SAMR_AF_NORMAL_ACCOUNT \
+ | SAMR_AF_INTERDOMAIN_TRUST_ACCOUNT \
+ | SAMR_AF_WORKSTATION_TRUST_ACCOUNT \
+ | SAMR_AF_SERVER_TRUST_ACCOUNT)
+
+
+/*
+ * specific access rights which can be used in OpenAlias.
+ * extracted from Ethereal network analyzer
+ */
+#define SAMR_ALIAS_ACCESS_SET_INFO 0x00000010
+#define SAMR_ALIAS_ACCESS_GET_INFO 0x00000008
+#define SAMR_ALIAS_ACCESS_GET_MEMBERS 0x00000004
+#define SAMR_ALIAS_ACCESS_DEL_MEMBER 0x00000002
+#define SAMR_ALIAS_ACCESS_ADD_MEMBER 0x00000001
+
+/*
+ * Definition for a SID. The ndl compiler does not allow a typedef of
+ * a structure containing variable size members.
+ */
+struct samr_sid {
+ BYTE Revision;
+ BYTE SubAuthCount;
+ BYTE Authority[6];
+ SIZE_IS(SubAuthCount)
+ DWORD SubAuthority[ANY_SIZE_ARRAY];
+};
+
+
+/*
+ * SAMR definition of a security_descriptor.
+ */
+struct samr_sec_desc {
+ BYTE Revision;
+ BYTE Sbz1;
+ WORD Control;
+ struct samr_sid *owner;
+ struct samr_sid *group;
+ struct samr_sid *sacl;
+ struct samr_sid *dacl;
+};
+
+
+/*
+ * Definition for a string. The length and allosize should be set to
+ * twice the string length (i.e. strlen(str) * 2). The runtime code
+ * will perform the appropriate string to a wide-char conversions,
+ * so str should point to a regular char * string.
+ */
+struct samr_string {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct samr_string samr_string_t;
+
+
+/*
+ * Alternative varying/conformant string definition - for
+ * non-null terminated strings. This definition must match
+ * mlrpc_vcbuf_t.
+ */
+struct samr_vcb {
+ /*
+ * size_is (actually a copy of length_is) will
+ * be inserted here by the marshalling library.
+ */
+ DWORD vc_first_is;
+ DWORD vc_length_is;
+ SIZE_IS(vc_length_is)
+ WORD buffer[ANY_SIZE_ARRAY];
+};
+
+struct samr_vcbuf {
+ WORD wclen;
+ WORD wcsize;
+ struct samr_vcb *vcb;
+};
+typedef struct samr_vcbuf samr_vcbuf_t;
+
+
+/*
+ * Handles appear to be a 20 byte object with the top 4 bytes all zero.
+ * Handles may have some internal structure but this should work since
+ * we always treat it as an opaque handle. They do appear to contain a
+ * sequence number which is incremented when new handle is issued.
+*/
+
+struct samr_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+typedef struct samr_handle samr_handle_t;
+
+/*
+ * A long long, i.e. 64-bit, value.
+ */
+struct samr_quad {
+ DWORD low;
+ DWORD high;
+};
+typedef struct samr_quad samr_quad_t;
+
+
+/*
+ ***********************************************************************
+ * ConnectAnon. It looks like the SAM handle is identical to an LSA
+ * handle. See Connect.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_ConnectAnon)
+struct samr_ConnectAnon {
+ IN DWORD *servername;
+ IN DWORD access_mask;
+ OUT samr_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Connect. I'm not sure what the difference is between Connect and
+ * ConnectAnon but this call seems to work better than ConnectAnon.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_Connect)
+struct samr_Connect {
+ IN LPTSTR servername;
+ IN DWORD access_mask;
+ OUT samr_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SamrConnect3. A new form of connect first seen with Windows 2000.
+ * A new field has been added to the input request. Value: 0x00000002.
+ * I haven't looked at the Win2K response yet to see if it differs
+ * from SAMR_OPNUM_Connect.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_Connect3)
+struct samr_Connect3 {
+ IN LPTSTR servername;
+ IN DWORD unknown_02;
+ IN DWORD access_mask;
+ OUT samr_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SamrConnect4. A new form of connect first seen with Windows XP.
+ * The server name is the fully qualified domain name, i.e.
+ * \\server.procom.com.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_Connect4)
+struct samr_Connect4 {
+ IN LPTSTR servername;
+ IN DWORD access_mask;
+ INOUT DWORD unknown2_00000001;
+ INOUT DWORD unknown3_00000001;
+ INOUT DWORD unknown4_00000003;
+ INOUT DWORD unknown5_00000000;
+ OUT samr_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * CloseHandle closes an association with the SAM. Using the same
+ * structure as the LSA seems to work.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_CloseHandle)
+struct samr_CloseHandle {
+ IN samr_handle_t handle;
+ OUT samr_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupDomain: lookup up the domain SID.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_LookupDomain)
+struct samr_LookupDomain {
+ IN samr_handle_t handle;
+ IN samr_string_t domain_name;
+ OUT struct samr_sid *sid;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * EnumLocalDomain
+ *
+ * This looks like a request to get the local domains supported by a
+ * remote server. NT always seems to return 2 domains: the local
+ * domain (hostname) and the Builtin domain.
+ *
+ * The max_length field is set to 0x2000.
+ * Enum_context is set to 0 in the request and set to entries_read in
+ * the reply. Like most of these enums, total_entries is the same as
+ * entries_read.
+ ***********************************************************************
+ */
+struct samr_LocalDomainEntry {
+ DWORD unknown;
+ samr_string_t name;
+};
+
+struct samr_LocalDomainInfo {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct samr_LocalDomainEntry *entry;
+};
+
+
+OPERATION(SAMR_OPNUM_EnumLocalDomains)
+struct samr_EnumLocalDomain {
+ IN samr_handle_t handle;
+ INOUT DWORD enum_context;
+ IN DWORD max_length;
+ OUT struct samr_LocalDomainInfo *info;
+ OUT DWORD total_entries;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenDomain
+ *
+ * Open a specific domain within the SAM. From this I assume that each
+ * SAM can handle multiple domains so you need to identify the one with
+ * which you want to work. Working with a domain handle does appear to
+ * offer the benefit that you can then use RIDs instead of full SIDs,
+ * which simplifies things a bit. The domain handle can be used to get
+ * user and group handles.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_OpenDomain)
+struct samr_OpenDomain {
+ IN samr_handle_t handle;
+ IN DWORD access_mask;
+ IN REFERENCE struct samr_sid *sid;
+ OUT samr_handle_t domain_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryDomainInfo
+ *
+ * Windows 95 Server Manager sends requests for levels 6 and 7 when
+ * the services menu item is selected.
+ ***********************************************************************
+ */
+#define SAMR_QUERY_DOMAIN_INFO_2 2
+#define SAMR_QUERY_DOMAIN_INFO_6 6
+#define SAMR_QUERY_DOMAIN_INFO_7 7
+
+
+struct samr_QueryDomainInfo2 {
+ DWORD unknown1; /* 00 00 00 00 */
+ DWORD unknown2; /* 00 00 00 80 */
+ samr_string_t s1;
+ samr_string_t domain;
+ samr_string_t s2;
+ DWORD sequence_num; /* 2B 00 00 00 */
+ DWORD unknown3; /* 00 00 00 00 */
+ DWORD unknown4; /* 01 00 00 00 */
+ DWORD unknown5; /* 03 00 00 00 */
+ DWORD unknown6; /* 01 */
+ DWORD num_users;
+ DWORD num_groups;
+ DWORD num_aliases;
+};
+
+
+struct samr_QueryDomainInfo6 {
+ DWORD unknown1; /* 00 00 00 00 */
+ DWORD unknown2; /* B0 7F 14 00 */
+ DWORD unknown3; /* 00 00 00 00 */
+ DWORD unknown4; /* 00 00 00 00 */
+ DWORD unknown5; /* 00 00 00 00 */
+};
+
+
+struct samr_QueryDomainInfo7 {
+ DWORD unknown1; /* 03 00 00 00 */
+};
+
+
+union samr_QueryDomainInfo_ru {
+ UNION_INFO_ENT(2,samr_QueryDomainInfo);
+ UNION_INFO_ENT(6,samr_QueryDomainInfo);
+ UNION_INFO_ENT(7,samr_QueryDomainInfo);
+ DEFAULT char *nullptr;
+};
+
+
+/*
+ * This structure needs to be declared, even though it can't be used in
+ * samr_QueryDomainInfo, in order to calculate the correct fixup offsets.
+ * If ndrgen did the right thing, samr_QueryDomainInfoRes would be one of
+ * the out parameters. However, if we do it that way, the switch_value
+ * isn't known early enough to do the fixup calculation. So it all has
+ * to go in samr_QueryDomainInfo.
+ */
+struct samr_QueryDomainInfoRes {
+ DWORD address;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union samr_QueryDomainInfo_ru ru;
+};
+
+
+OPERATION(SAMR_OPNUM_QueryDomainInfo)
+struct samr_QueryDomainInfo {
+ IN samr_handle_t domain_handle;
+ IN WORD info_level;
+ /*
+ * Can't use the standard "OUT result" form because
+ * we need to include members explicitly.
+ * OUT struct samr_QueryDomainInfoRes result;
+ */
+ OUT DWORD address;
+ OUT WORD switch_value;
+ SWITCH(info_level)
+ OUT union samr_QueryDomainInfo_ru ru;
+ OUT DWORD status;
+};
+
+#define SAMR_QUERY_ALIAS_INFO_1 1
+#define SAMR_QUERY_ALIAS_INFO_3 3
+
+
+struct samr_QueryAliasInfo1 {
+ WORD level;
+ samr_string_t name;
+ DWORD unknown;
+ samr_string_t desc;
+};
+
+struct samr_QueryAliasInfo3 {
+ WORD level;
+ samr_string_t desc;
+};
+
+union samr_QueryAliasInfo_ru {
+ UNION_INFO_ENT(1,samr_QueryAliasInfo);
+ UNION_INFO_ENT(3,samr_QueryAliasInfo);
+ DEFAULT char *nullptr;
+};
+
+struct samr_QueryAliasInfoRes {
+ DWORD address;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union samr_QueryAliasInfo_ru ru;
+};
+
+OPERATION(SAMR_OPNUM_QueryAliasInfo)
+struct samr_QueryAliasInfo {
+ IN samr_handle_t alias_handle;
+ IN WORD level;
+ OUT DWORD address;
+ SWITCH (level)
+ OUT union samr_QueryAliasInfo_ru ru;
+ OUT DWORD status;
+};
+
+OPERATION(SAMR_OPNUM_CreateDomainAlias)
+struct samr_CreateDomainAlias {
+ IN samr_handle_t domain_handle;
+ IN samr_string_t alias_name;
+ IN DWORD access_mask;
+ OUT samr_handle_t alias_handle;
+ OUT DWORD rid;
+ OUT DWORD status;
+};
+
+OPERATION(SAMR_OPNUM_SetAliasInfo)
+struct samr_SetAliasInfo {
+ IN samr_handle_t alias_handle;
+ IN WORD level;
+ /* TBD */
+ OUT DWORD status;
+};
+
+OPERATION(SAMR_OPNUM_DeleteDomainAlias)
+struct samr_DeleteDomainAlias {
+ IN samr_handle_t alias_handle;
+ OUT DWORD status;
+};
+
+OPERATION(SAMR_OPNUM_OpenAlias)
+struct samr_OpenAlias {
+ IN samr_handle_t domain_handle;
+ IN DWORD access_mask;
+ IN DWORD rid;
+ OUT samr_handle_t alias_handle;
+ OUT DWORD status;
+};
+
+struct name_rid {
+ DWORD rid;
+ samr_string_t name;
+};
+
+struct aliases_info {
+ DWORD count;
+ DWORD address;
+ SIZE_IS(count)
+ struct name_rid info[ANY_SIZE_ARRAY];
+};
+
+OPERATION(SAMR_OPNUM_EnumDomainAliases)
+struct samr_EnumDomainAliases {
+ IN samr_handle_t domain_handle;
+ IN DWORD resume_handle;
+ IN DWORD mask;
+ OUT DWORD out_resume;
+ OUT struct aliases_info *aliases;
+ OUT DWORD entries;
+ OUT DWORD status;
+};
+
+struct user_acct_info {
+ DWORD index;
+ DWORD rid;
+ DWORD ctrl;
+ samr_string_t name;
+ samr_string_t fullname;
+ samr_string_t desc;
+};
+
+struct user_disp_info {
+ DWORD count;
+ /* right now we just need two entries */
+ struct user_acct_info acct[2];
+};
+
+OPERATION(SAMR_OPNUM_QueryDispInfo)
+struct samr_QueryDispInfo {
+ IN samr_handle_t domain_handle;
+ IN WORD level;
+ IN DWORD start_idx;
+ IN DWORD max_entries;
+ IN DWORD pref_maxsize;
+ OUT DWORD total_size;
+ OUT DWORD returned_size;
+ OUT WORD switch_value;
+ OUT DWORD count;
+ OUT struct user_disp_info *users;
+ OUT DWORD status;
+};
+
+struct group_acct_info {
+ DWORD index;
+ DWORD rid;
+ DWORD ctrl;
+ samr_string_t name;
+ samr_string_t desc;
+};
+
+struct group_disp_info {
+ DWORD count;
+ /* right now we just need one entry */
+ struct group_acct_info acct[1];
+};
+
+OPERATION(SAMR_OPNUM_EnumDomainGroups)
+struct samr_EnumDomainGroups {
+ IN samr_handle_t domain_handle;
+ IN WORD level;
+ IN DWORD start_idx;
+ IN DWORD max_entries;
+ IN DWORD pref_maxsize;
+ OUT DWORD total_size;
+ OUT DWORD returned_size;
+ OUT WORD switch_value;
+ OUT DWORD count;
+ OUT struct group_disp_info *groups;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * OpenUser
+ *
+ * Input must be a domain handle obtained via SAMR_OPNUM_OpenDomain,
+ * an access mask and the appropriate user rid. The output will be a
+ * handle for use with the specified user.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_OpenUser)
+struct samr_OpenUser {
+ IN samr_handle_t handle;
+ IN DWORD access_mask;
+ IN DWORD rid;
+ OUT samr_handle_t user_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * DeleteUser
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_DeleteUser)
+struct samr_DeleteUser {
+ INOUT samr_handle_t user_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryUserInfo
+ *
+ * Provides various pieces of information on a specific user (see
+ * SAM_Q_QUERY_USERINFO and SAM_R_QUERY_USERINFO). The handle must
+ * be a valid SAM user handle.
+ *
+ * QueryUserInfo (
+ * IN samr_handle_t user_handle,
+ * IN WORD switch_value,
+ * OUT union switch(switch_value) {
+ * case 1: struct QueryUserInfo1 *info1;
+ * } bufptr,
+ * OUT DWORD status
+ * )
+ *
+ * The cases identified so far are:
+ *
+ * 1 = username, fullname, description and some other stuff.
+ * 2 = unknown
+ * 3 = large structure containing user rid, group rid, username
+ * and fullname.
+ * 4 = unknown
+ * 5 = large structure (like 3) containing user rid, group rid,
+ * username, fullname and description.
+ * 6 = username and fullname
+ * 7 = username
+ * 8 = fullname
+ * 9 = group rid
+ * 16 = used after creating a new account
+ *
+ * Due to an ndrgen bug, a function must be provided to to patch the
+ * offsets used by the unmarshalling code at runtime. In order to
+ * simplify things it is useful to use a naming convention that
+ * indicates the switch value for each structure.
+ *
+ ***********************************************************************
+ */
+
+
+#define SAMR_QUERY_USER_INFO_1 1
+#define SAMR_QUERY_USER_UNAME_AND_FNAME 6
+#define SAMR_QUERY_USER_USERNAME 7
+#define SAMR_QUERY_USER_FULLNAME 8
+#define SAMR_QUERY_USER_GROUPRID 9
+#define SAMR_QUERY_USER_UNKNOWN16 16
+
+
+struct samr_QueryUserInfo1 {
+ samr_string_t username;
+ samr_string_t fullname;
+ DWORD group_rid;
+ samr_string_t description;
+ samr_string_t unknown;
+};
+
+
+struct samr_QueryUserInfo6 {
+ samr_string_t username;
+ samr_string_t fullname;
+};
+
+struct samr_QueryUserInfo7 {
+ samr_string_t username;
+};
+
+
+struct samr_QueryUserInfo8 {
+ samr_string_t fullname;
+};
+
+
+struct samr_QueryUserInfo9 {
+ DWORD group_rid;
+};
+
+
+struct samr_QueryUserInfo16 {
+ DWORD unknown;
+};
+
+
+union QueryUserInfo_result_u {
+ UNION_INFO_ENT(1,samr_QueryUserInfo);
+ UNION_INFO_ENT(6,samr_QueryUserInfo);
+ UNION_INFO_ENT(7,samr_QueryUserInfo);
+ UNION_INFO_ENT(8,samr_QueryUserInfo);
+ UNION_INFO_ENT(9,samr_QueryUserInfo);
+ UNION_INFO_ENT(16,samr_QueryUserInfo);
+ DEFAULT char *nullptr;
+};
+
+
+/*
+ * This structure needs to be declared, even though it can't be used in
+ * samr_QueryUserInfo, in order to get the appropriate size to calculate
+ * the correct fixup offsets. If ndrgen did the right thing,
+ * QueryUserInfo_result would be one of the out parameters. However, if
+ * we do it that way, the switch_value isn't known early enough to do
+ * the fixup calculation. So it all has to go in samr_QueryUserInfo.
+ */
+struct QueryUserInfo_result {
+ DWORD address;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union QueryUserInfo_result_u ru;
+};
+
+
+OPERATION(SAMR_OPNUM_QueryUserInfo)
+struct samr_QueryUserInfo {
+ IN samr_handle_t user_handle;
+ IN WORD switch_value;
+ /*
+ * Can't use this form because we need to include members explicitly.
+ * OUT struct QueryUserInfo_result result;
+ */
+ OUT DWORD address;
+ OUT WORD switch_index;
+ SWITCH(switch_value)
+ OUT union QueryUserInfo_result_u ru;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryUserGroups
+ ***********************************************************************
+ */
+struct samr_UserGroups {
+ DWORD rid;
+ DWORD attr;
+};
+
+
+struct samr_UserGroupInfo {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct samr_UserGroups *groups;
+};
+
+
+OPERATION(SAMR_OPNUM_QueryUserGroups)
+struct samr_QueryUserGroups {
+ IN samr_handle_t user_handle;
+ OUT struct samr_UserGroupInfo *info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupName
+ ***********************************************************************
+ */
+struct samr_LookupNameTable {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ samr_string_t names[ANY_SIZE_ARRAY];
+};
+
+
+struct samr_LookupRidTable {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ DWORD *rid;
+};
+
+struct samr_RidType {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ DWORD *rid_type;
+};
+
+
+OPERATION(SAMR_OPNUM_LookupNames)
+struct samr_LookupNames {
+ IN samr_handle_t handle;
+ IN DWORD n_entry;
+ IN DWORD max_n_entry;
+ IN DWORD index;
+ IN DWORD total;
+ IN samr_string_t name;
+ OUT struct samr_LookupRidTable rids;
+ OUT struct samr_RidType rid_types;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenGroup
+ *
+ * Input must be a domain handle obtained via SAMR_OPNUM_OpenDomain,
+ * an access mask and the appropriate group rid. The output will be a
+ * handle for use with the specified group.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_OpenGroup)
+struct samr_OpenGroup {
+ IN samr_handle_t handle;
+ IN DWORD access_mask;
+ IN DWORD rid;
+ OUT samr_handle_t group_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryGroupInfo
+ *
+ * Input must be a group handle obtained via SAMR_OPNUM_OpenGroup,
+ * an access mask and the appropriate group rid. The output will
+ * be a handle for use with the specified group.
+ ***********************************************************************
+ */
+struct samr_QueryGroupInfo1 {
+ samr_string_t groupname;
+};
+
+
+union samr_QueryGroupInfo_result_u {
+ UNION_INFO_ENT(1,samr_QueryGroupInfo);
+ DEFAULT char *nullptr;
+};
+
+
+struct samr_QueryGroupInfo_result {
+ DWORD address;
+ WORD switch_index;
+ SWITCH(switch_index)
+ union samr_QueryGroupInfo_result_u ru;
+};
+
+
+OPERATION(SAMR_OPNUM_QueryGroupInfo)
+struct samr_QueryGroupInfo {
+ IN samr_handle_t group_handle;
+ IN DWORD switch_value;
+ OUT DWORD address;
+ OUT WORD switch_index;
+ SWITCH(switch_index)
+ OUT union samr_QueryGroupInfo_result_u ru;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * StoreGroupInfo
+ *
+ * This definition is mostly just a place holder in case this is useful
+ * in the future. Note that it may not be correct. The information is
+ * from a netmon trace captured when I added a group description. I
+ * haven't implemented it because we don't have to update anything on
+ * the PDC. The description should almost certainly be in a separate
+ * structure.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_StoreGroupInfo)
+struct samr_StoreGroupInfo {
+ IN samr_handle_t group_handle;
+ IN DWORD switch_value;
+ IN samr_string_t group_description;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Request 0x2c is a user request. The only parameter is a user handle.
+ * The response is 12 bytes of the form:
+ * unknown: 00 00 BB 01 (443)
+ * unknown: 00 00 00 00
+ * status: 00 00 00 00
+ * RPC book lists this as GetUsrDomPwInfo.
+ ***********************************************************************
+ */
+struct samr_UserPwInfo {
+ WORD unknown1;
+ WORD unknown2;
+ DWORD unknown3;
+};
+
+
+OPERATION(SAMR_OPNUM_GetUserPwInfo)
+struct samr_GetUserPwInfo {
+ IN samr_handle_t user_handle;
+ OUT struct samr_UserPwInfo pw_info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * CreateUser
+ *
+ * Create a user in the domain specified by the domain handle. The
+ * domain handle is obtained obtained via SAMR_OPNUM_OpenDomain. There
+ * is an unknown value at the end of the request: 0xe00500b0.
+ * The output will be a handle for use with the specified user and the
+ * user's RID. I think the RID may be a pointer but the value came back
+ * as zero once so I've padded it out so that the marshalling doesn't
+ * get confused.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_CreateUser)
+struct samr_CreateUser {
+ IN samr_handle_t handle;
+ IN samr_vcbuf_t username;
+ IN DWORD account_flags;
+ IN DWORD unknown_e00500b0;
+ OUT samr_handle_t user_handle;
+ OUT DWORD maybe_ptr;
+ OUT DWORD rid;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * ChangeUserPasswd
+ ***********************************************************************
+ */
+struct samr_newpasswd {
+ BYTE data[516];
+};
+
+
+struct samr_oldpasswd {
+ BYTE data[16];
+};
+
+
+OPERATION(SAMR_OPNUM_ChangeUserPasswd)
+struct samr_ChangeUserPasswd {
+ IN LPTSTR servername;
+ IN LPTSTR username;
+ IN struct samr_newpasswd *nt_newpasswd;
+ IN struct samr_oldpasswd *nt_oldpasswd;
+ IN struct samr_newpasswd *lm_newpasswd;
+ IN struct samr_oldpasswd *lm_oldpasswd;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * GetDomainPwInfo
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_GetDomainPwInfo)
+struct samr_GetDomainPwInfo {
+ IN LPTSTR servername;
+ OUT WORD unknown0;
+ OUT WORD unknown1;
+ OUT WORD unknown2;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SetUserInfo
+ *
+ * +++ 20 byte user handle and the union switch_value +++
+ * 00 00 00 00 77 F2 DD D5 66 48 D4 11 AD 5F D1 CD
+ * 18 43 7A DF 17 00 17 00
+ *
+ * +++ 14 dwords (56 bytes) of zeros +++
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ *
+ * +++ 9 sets of something - 72 bytes +++
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ *
+ * +++ 9 DWORD zeros +++
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00
+ *
+ * +++ miscellaneous +++
+ * 01 02 00 00
+ * 80 00 00 00
+ * FA 27 F8 09
+ * A8 00 00 00 70 F1 14 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00
+ *
+ * +++ encrypted password buffer - 512 bytes +++
+ * 76 68 E8 AA 23 4F 62 C4 81 4E 30 B8 92 29 66 B9
+ * 12 FF 3A 84 82 3A 55 0F C7 18 EA 56 86 50 D7 C5
+ * 43 BA 9C F8 32 D4 E0 15 74 A1 6F E1 59 C2 F2 95
+ * 53 A9 F2 68 9F 7F 29 B9 88 4C 65 A5 C1 DC 0B 44
+ * B8 3C ED 74 D1 6A F7 09 66 97 94 6B 2C 3A A5 88
+ * 39 34 C6 FE 24 59 30 2D CF 6D 7F D5 EC B1 9A 84
+ * E6 57 96 29 40 32 FB 62 9D 93 E2 BE D8 A3 74 88
+ * 8B 85 BC A0 76 D6 C9 DB 8C AF 81 BD 8A F0 08 8D
+ * 23 B0 52 FD 69 DE EF A1 36 E5 30 19 BD DA 67 A3
+ * 81 BD 3F D0 2A A2 8F 60 62 B0 8D 34 9E A4 4F 20
+ * 4E 79 93 82 58 A8 E5 6F 7A DC 12 13 33 E6 74 02
+ * 4C 32 F9 FC 1A E1 C5 0D E2 CC 36 8D FC 72 87 DD
+ * 6C 44 E3 6F 4B FD 46 10 08 89 E5 64 B8 27 14 83
+ * E7 08 DE CF 69 C7 E1 40 63 DF CB 67 95 73 03 1B
+ * CA 99 E1 1B 53 2A 89 6B 30 39 CD 5C DF A0 8A 1C
+ * 4E 50 74 7C 6D 3D E7 EA E9 B2 97 DD 38 7B DA EC
+ * 1A AD DA CE C4 58 9B 29 F3 6D 30 70 4E 63 6D 84
+ * DB DC 5B CD 9A 4E 57 9C E4 65 5D 4F 76 E3 C7 52
+ * 8B 3B 20 0A 3B 4C 4B B1 2E 5B 4D AB BA 2F 45 6A
+ * CA 17 AD 9F C0 B2 07 FB 56 7F E4 3F 9F D4 C6 8C
+ * A1 05 BF 53 42 1E 67 F4 57 54 E3 2C 38 CF E1 94
+ * 75 69 F7 4E 5C 74 CC B3 FD EF 73 3F D5 28 22 EC
+ * 9B 40 E1 1D 65 44 7C BB 69 88 57 10 05 3A C5 48
+ * 8E 4F 77 DB 1A 5C 49 9C D5 06 00 AC 79 BC 7E 89
+ * B0 01 66 70 88 A2 E5 DF 96 DC 75 98 10 12 45 02
+ * 33 35 6C DF 74 8B 14 2F 26 C6 FD 7A B4 D0 A6 7D
+ * DE 2B 13 44 EF 34 46 4D 9D 3E C3 75 BC 11 B4 41
+ * 27 58 25 1E AF AA F0 BB DA 27 7A 1E AE 81 1A 78
+ * 44 19 DE FC C4 7C 4E 32 44 F7 57 2A 41 A2 85 DC
+ * C0 AD 5D 6B 58 FD 2E 75 25 B9 F2 B6 19 82 E5 0E
+ * B6 69 0D C1 27 A9 B6 40 A6 50 49 E5 CB 17 98 65
+ * 88 18 CA E4 1D 2E 20 F7 DE 8E 7D F2 9D A5 6B CD
+ *
+ * D6 79 45 71
+ *
+ * +++ table of 9 things +++
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ *
+ * +++ miscellaneous +++
+ * EC 04 00 00 00 00 00 00 15 00 00 00
+ * FF FF FF FF FF FF FF FF FF FF FF FF
+ * FF FF FF FF FF FF FF FF FF
+ *
+ ***********************************************************************
+ */
+
+#define SAMR_SET_USER_INFO_23 23
+#define SAMR_SET_USER_DATA_SZ 516
+
+#define SAMR_MINS_PER_WEEK 10080
+#define SAMR_HOURS_PER_WEEK 168
+
+#define SAMR_HOURS_MAX_SIZE (SAMR_MINS_PER_WEEK / 8)
+#define SAMR_HOURS_SET_LEN(LEN) ((LEN) / 8)
+#define SAMR_SET_USER_HOURS_SZ 21
+
+
+struct samr_sd {
+ DWORD length;
+ SIZE_IS(length)
+ BYTE *data;
+};
+
+
+/*
+ * There is some sort of logon bitmap structure in here, which I
+ * think is a varying and conformant array, i.e.
+ *
+ * struct samr_logon_hours {
+ * DWORD size_is; (0x04ec)
+ * DWORD first_is; (zero)
+ * DWORD length_is; (0xa8)
+ * BYTE bitmap[21];
+ * };
+ *
+ * struct samr_logon_info {
+ * DWORD length;
+ * SIZE_IS(length / 8)
+ * struct samr_logon_hours *hours;
+ * };
+ *
+ * There are 10080 minutes/week => 10080/8 = 1260 (0x04EC).
+ * So size_is is set as some sort of maximum.
+ *
+ * There are 168 hours/week => 168/8 = 21 (0xA8). Since there are 21
+ * bytes (all set to 0xFF), this is is probably the default setting.
+ *
+ * ndrgen has a problem with complex [size_is] statements. For now,
+ * we can try to fake it using two separate components.
+ */
+struct samr_logon_hours {
+ DWORD size;
+ DWORD first;
+ DWORD length;
+ BYTE bitmap[SAMR_SET_USER_HOURS_SZ];
+};
+
+
+struct samr_logon_info {
+ DWORD units;
+ DWORD hours;
+};
+
+
+struct samr_oem_password {
+ BYTE password[512];
+ DWORD length;
+};
+
+
+struct samr_SetUserInfo23 {
+ samr_quad_t logon_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t logoff_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t kickoff_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t passwd_last_set_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t passwd_can_change_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t passwd_must_change_time; /* 00 00 00 00 00 00 00 00 */
+
+ samr_vcbuf_t user_name; /* 00 00 00 00 00 00 00 00 */
+ samr_vcbuf_t full_name; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t home_dir; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t home_drive; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t logon_script; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t profile_path; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t acct_desc; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t workstations; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t unknown1; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t unknown2; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t lm_password; /* 00 00 00 00 00 00 00 00 */
+ samr_vcbuf_t nt_password; /* 00 00 00 00 00 00 00 00 */
+ samr_vcbuf_t unknown3; /* 00 00 00 00 00 00 00 00 */
+
+ struct samr_sd sd; /* 00 00 00 00 00 00 00 00 */
+ DWORD user_rid; /* 00 00 00 00 */
+ DWORD group_rid; /* 01 02 00 00 */
+ DWORD acct_info; /* 80 00 00 00 */
+ DWORD flags; /* FA 27 F8 09 */
+ struct samr_logon_info logon_info; /* A8 00 00 00 70 F1 14 00->0xFF */
+ /*
+ * The following 12 bytes are encoded in Ethereal as:
+ *
+ * WORD bad_pwd_count;
+ * WORD logon_count;
+ *
+ * WORD country; (default 0)
+ * WORD codepage;
+ *
+ * BYTE nt_pwd_set;
+ * BYTE lm_pwd_set;
+ * BYTE expired_flag;
+ * BYTE unknown_char;
+ */
+ DWORD unknown4_zero; /* 00 00 00 00 */
+ DWORD unknown5_zero; /* 00 00 00 00 */
+ DWORD unknown6_zero; /* 00 00 00 00 */
+ BYTE password[SAMR_SET_USER_DATA_SZ];
+};
+
+
+union samr_SetUserInfo_u {
+ UNION_INFO_ENT(23,samr_SetUserInfo);
+ DEFAULT char *nullptr;
+};
+
+
+struct samr_SetUserInfo_s {
+ WORD index;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union samr_SetUserInfo_u ru;
+};
+
+
+/*
+ IN DWORD unknown_04EC;
+ IN DWORD unknown_zero;
+ IN DWORD logon_bitmap_size;
+ IN BYTE logon_bitmap[SAMR_SET_USER_HOURS_SZ];
+*/
+OPERATION(SAMR_OPNUM_SetUserInfo)
+struct samr_SetUserInfo {
+ IN samr_handle_t user_handle;
+ IN struct samr_SetUserInfo_s info;
+ IN struct samr_logon_hours logon_hours;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The SAMR interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union samr_interface {
+ CASE(SAMR_OPNUM_ConnectAnon)
+ struct samr_ConnectAnon ConnectAnon;
+ CASE(SAMR_OPNUM_CloseHandle)
+ struct samr_CloseHandle CloseHandle;
+ CASE(SAMR_OPNUM_LookupDomain)
+ struct samr_LookupDomain LookupDomain;
+ CASE(SAMR_OPNUM_EnumLocalDomains)
+ struct samr_EnumLocalDomain EnumLocalDomain;
+ CASE(SAMR_OPNUM_OpenDomain)
+ struct samr_OpenDomain OpenDomain;
+ CASE(SAMR_OPNUM_QueryDomainInfo)
+ struct samr_QueryDomainInfo QueryDomainInfo;
+ CASE(SAMR_OPNUM_LookupNames)
+ struct samr_LookupNames LookupNames;
+ CASE(SAMR_OPNUM_OpenUser)
+ struct samr_OpenUser OpenUser;
+ CASE(SAMR_OPNUM_DeleteUser)
+ struct samr_DeleteUser DeleteUser;
+ CASE(SAMR_OPNUM_QueryUserInfo)
+ struct samr_QueryUserInfo QueryUserInfo;
+ CASE(SAMR_OPNUM_QueryUserGroups)
+ struct samr_QueryUserGroups QueryUserGroups;
+ CASE(SAMR_OPNUM_OpenGroup)
+ struct samr_OpenGroup OpenGroup;
+ CASE(SAMR_OPNUM_GetUserPwInfo)
+ struct samr_GetUserPwInfo GetUserPwInfo;
+ CASE(SAMR_OPNUM_CreateUser)
+ struct samr_CreateUser CreateUser;
+ CASE(SAMR_OPNUM_ChangeUserPasswd)
+ struct samr_ChangeUserPasswd ChangeUserPasswd;
+ CASE(SAMR_OPNUM_GetDomainPwInfo)
+ struct samr_GetDomainPwInfo GetDomainPwInfo;
+ CASE(SAMR_OPNUM_Connect)
+ struct samr_Connect Connect;
+ CASE(SAMR_OPNUM_SetUserInfo)
+ struct samr_SetUserInfo SetUserInfo;
+ CASE(SAMR_OPNUM_Connect3)
+ struct samr_Connect3 Connect3;
+ CASE(SAMR_OPNUM_Connect4)
+ struct samr_Connect4 Connect4;
+ CASE(SAMR_OPNUM_QueryDispInfo)
+ struct samr_QueryDispInfo QueryDispInfo;
+ CASE(SAMR_OPNUM_OpenAlias)
+ struct samr_OpenAlias OpenAlias;
+ CASE(SAMR_OPNUM_CreateDomainAlias)
+ struct samr_CreateDomainAlias CreateDomainAlias;
+ CASE(SAMR_OPNUM_SetAliasInfo)
+ struct samr_SetAliasInfo SetAliasInfo;
+ CASE(SAMR_OPNUM_QueryAliasInfo)
+ struct samr_QueryAliasInfo QueryAliasInfo;
+ CASE(SAMR_OPNUM_DeleteDomainAlias)
+ struct samr_DeleteDomainAlias DeleteDomainAlias;
+ CASE(SAMR_OPNUM_EnumDomainAliases)
+ struct samr_EnumDomainAliases EnumDomainAliases;
+ CASE(SAMR_OPNUM_EnumDomainGroups)
+ struct samr_EnumDomainGroups EnumDomainGroups;
+};
+typedef union samr_interface samr_interface_t;
+EXTERNTYPEINFO(samr_interface)
+
+#endif /* _MLSVC_SAM_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/spoolss.ndl b/usr/src/uts/common/smbsrv/ndl/spoolss.ndl
new file mode 100644
index 0000000000..1598e09d50
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/spoolss.ndl
@@ -0,0 +1,489 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_SPOOLSS_NDL_
+#define _MLSVC_SPOOLSS_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Printing and Spooling RPC interface definition.
+ */
+
+#include "ndrtypes.ndl"
+
+
+/*
+ * The spoolss opcodes.
+ */
+#define SPOOLSS_OPNUM_OpenPrinter 0x01
+#define SPOOLSS_OPNUM_GetJob 0x03
+#define SPOOLSS_OPNUM_DeletePrinter 0x06
+#define SPOOLSS_OPNUM_GetPrinterDriver 0x0b
+#define SPOOLSS_OPNUM_DeletePrinterDriver 0x0d
+#define SPOOLSS_OPNUM_AddPrintProcessor 0x0e
+#define SPOOLSS_OPNUM_GetPrintProcessorDirectory 0x10
+#define SPOOLSS_OPNUM_AbortPrinter 0x15
+#define SPOOLSS_OPNUM_ReadPrinter 0x16
+#define SPOOLSS_OPNUM_WaitForPrinterChange 0x1c
+#define SPOOLSS_OPNUM_AddForm 0x1e
+#define SPOOLSS_OPNUM_DeleteForm 0x1f
+#define SPOOLSS_OPNUM_GetForm 0x20
+#define SPOOLSS_OPNUM_SetForm 0x21
+#define SPOOLSS_OPNUM_EnumMonitors 0x24
+#define SPOOLSS_OPNUM_AddPort 0x25
+#define SPOOLSS_OPNUM_ConfigurePort 0x26
+#define SPOOLSS_OPNUM_DeletePort 0x27
+#define SPOOLSS_OPNUM_CreatePrinterIc 0x28
+#define SPOOLSS_OPNUM_PlayDescriptionPrinterIc 0x29
+#define SPOOLSS_OPNUM_DeletePrinterIc 0x2a
+#define SPOOLSS_OPNUM_AddPrinterConnection 0x2b
+#define SPOOLSS_OPNUM_DeletePrinterConnection 0x2c
+#define SPOOLSS_OPNUM_PrinterMessageBox 0x2d
+#define SPOOLSS_OPNUM_AddMonitor 0x2e
+#define SPOOLSS_OPNUM_DeleteMonitor 0x2f
+#define SPOOLSS_OPNUM_DeletePrintProcessor 0x30
+#define SPOOLSS_OPNUM_AddPrintProvider 0x31
+#define SPOOLSS_OPNUM_DeletePrintProvider 0x32
+#define SPOOLSS_OPNUM_ResetPrinter 0x34
+#define SPOOLSS_OPNUM_FindFirstChangeNotify 0x36
+#define SPOOLSS_OPNUM_FindNextChangeNotify 0x37
+#define SPOOLSS_OPNUM_RouterFindFirstNotify 0x39
+#define SPOOLSS_OPNUM_ReplyOpenPrinter 0x3a
+#define SPOOLSS_OPNUM_RouterReplyPrinter 0x3b
+#define SPOOLSS_OPNUM_ReplyClosePrinter 0x3c
+#define SPOOLSS_OPNUM_AddPortEx 0x3d
+#define SPOOLSS_OPNUM_RemoteFindFirstChangeNotify 0x3e
+#define SPOOLSS_OPNUM_SpoolerInitialize 0x3f
+#define SPOOLSS_OPNUM_ResetPrinterEx 0x40
+#define SPOOLSS_OPNUM_RouterRefreshChangeNotify 0x42
+#define SPOOLSS_OPNUM_OpenPrinter2 0x45
+
+
+/*
+ * The private handle definition for this interface.
+ */
+struct spoolss_handle {
+ DWORD data[5];
+};
+typedef struct spoolss_handle spoolss_handle_t;
+
+
+OPERATION(SPOOLSS_OPNUM_OpenPrinter)
+struct spoolss_OpenPrinter {
+ IN DWORD dontcare;
+ OUT spoolss_handle_t handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_GetJob)
+struct spoolss_GetJob {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrinter)
+struct spoolss_DeletePrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_GetPrinterDriver)
+struct spoolss_GetPrinterDriver {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrinterDriver)
+struct spoolss_DeletePrinterDriver {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPrintProcessor)
+struct spoolss_AddPrintProcessor {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_GetPrintProcessorDirectory)
+struct spoolss_GetPrintProcessorDirectory {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AbortPrinter)
+struct spoolss_AbortPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ReadPrinter)
+struct spoolss_ReadPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_WaitForPrinterChange)
+struct spoolss_WaitForPrinterChange {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddForm)
+struct spoolss_AddForm {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeleteForm)
+struct spoolss_DeleteForm {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_GetForm)
+struct spoolss_GetForm {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_SetForm)
+struct spoolss_SetForm {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_EnumMonitors)
+struct spoolss_EnumMonitors {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPort)
+struct spoolss_AddPort {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ConfigurePort)
+struct spoolss_ConfigurePort {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePort)
+struct spoolss_DeletePort {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_CreatePrinterIc)
+struct spoolss_CreatePrinterIc {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_PlayDescriptionPrinterIc)
+struct spoolss_PlayDescriptionPrinterIc {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrinterIc)
+struct spoolss_DeletePrinterIc {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPrinterConnection)
+struct spoolss_AddPrinterConnection {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrinterConnection)
+struct spoolss_DeletePrinterConnection {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_PrinterMessageBox)
+struct spoolss_PrinterMessageBox {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddMonitor)
+struct spoolss_AddMonitor {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeleteMonitor)
+struct spoolss_DeleteMonitor {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrintProcessor)
+struct spoolss_DeletePrintProcessor {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPrintProvider)
+struct spoolss_AddPrintProvider {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrintProvider)
+struct spoolss_DeletePrintProvider {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ResetPrinter)
+struct spoolss_ResetPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_FindFirstChangeNotify)
+struct spoolss_FindFirstChangeNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_FindNextChangeNotify)
+struct spoolss_FindNextChangeNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_RouterFindFirstNotify)
+struct spoolss_RouterFindFirstNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ReplyOpenPrinter)
+struct spoolss_ReplyOpenPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_RouterReplyPrinter)
+struct spoolss_RouterReplyPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ReplyClosePrinter)
+struct spoolss_ReplyClosePrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPortEx)
+struct spoolss_AddPortEx {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_RemoteFindFirstChangeNotify)
+struct spoolss_RemoteFindFirstChangeNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_SpoolerInitialize)
+struct spoolss_SpoolerInitialize {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ResetPrinterEx)
+struct spoolss_ResetPrinterEx {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_RouterRefreshChangeNotify)
+struct spoolss_RouterRefreshChangeNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_OpenPrinter2)
+struct spoolss_OpenPrinter2 {
+ IN DWORD dontcare;
+ OUT spoolss_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The spoolss interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union spoolss_interface {
+ CASE(SPOOLSS_OPNUM_OpenPrinter)
+ struct spoolss_OpenPrinter OpenPrinter;
+ CASE(SPOOLSS_OPNUM_GetJob)
+ struct spoolss_GetJob GetJob;
+ CASE(SPOOLSS_OPNUM_DeletePrinter)
+ struct spoolss_DeletePrinter DeletePrinter;
+ CASE(SPOOLSS_OPNUM_GetPrinterDriver)
+ struct spoolss_GetPrinterDriver GetPrinterDriver;
+ CASE(SPOOLSS_OPNUM_DeletePrinterDriver)
+ struct spoolss_DeletePrinterDriver DeletePrinterDriver;
+ CASE(SPOOLSS_OPNUM_AddPrintProcessor)
+ struct spoolss_AddPrintProcessor AddPrintProcessor;
+ CASE(SPOOLSS_OPNUM_GetPrintProcessorDirectory)
+ struct spoolss_GetPrintProcessorDirectory
+ GetPrintProcessorDirectory;
+ CASE(SPOOLSS_OPNUM_AbortPrinter)
+ struct spoolss_AbortPrinter AbortPrinter;
+ CASE(SPOOLSS_OPNUM_ReadPrinter)
+ struct spoolss_ReadPrinter ReadPrinter;
+ CASE(SPOOLSS_OPNUM_WaitForPrinterChange)
+ struct spoolss_WaitForPrinterChange WaitForPrinterChange;
+ CASE(SPOOLSS_OPNUM_AddForm)
+ struct spoolss_AddForm AddForm;
+ CASE(SPOOLSS_OPNUM_DeleteForm)
+ struct spoolss_DeleteForm DeleteForm;
+ CASE(SPOOLSS_OPNUM_GetForm)
+ struct spoolss_GetForm GetForm;
+ CASE(SPOOLSS_OPNUM_SetForm)
+ struct spoolss_SetForm SetForm;
+ CASE(SPOOLSS_OPNUM_EnumMonitors)
+ struct spoolss_EnumMonitors EnumMonitors;
+ CASE(SPOOLSS_OPNUM_AddPort)
+ struct spoolss_AddPort AddPort;
+ CASE(SPOOLSS_OPNUM_ConfigurePort)
+ struct spoolss_ConfigurePort ConfigurePort;
+ CASE(SPOOLSS_OPNUM_DeletePort)
+ struct spoolss_DeletePort DeletePort;
+ CASE(SPOOLSS_OPNUM_CreatePrinterIc)
+ struct spoolss_CreatePrinterIc CreatePrinterIc;
+ CASE(SPOOLSS_OPNUM_PlayDescriptionPrinterIc)
+ struct spoolss_PlayDescriptionPrinterIc
+ PlayDescriptionPrinterIc;
+ CASE(SPOOLSS_OPNUM_DeletePrinterIc)
+ struct spoolss_DeletePrinterIc DeletePrinterIc;
+ CASE(SPOOLSS_OPNUM_AddPrinterConnection)
+ struct spoolss_AddPrinterConnection AddPrinterConnection;
+ CASE(SPOOLSS_OPNUM_DeletePrinterConnection)
+ struct spoolss_DeletePrinterConnection DeletePrinterConnection;
+ CASE(SPOOLSS_OPNUM_PrinterMessageBox)
+ struct spoolss_PrinterMessageBox PrinterMessageBox;
+ CASE(SPOOLSS_OPNUM_AddMonitor)
+ struct spoolss_AddMonitor AddMonitor;
+ CASE(SPOOLSS_OPNUM_DeleteMonitor)
+ struct spoolss_DeleteMonitor DeleteMonitor;
+ CASE(SPOOLSS_OPNUM_DeletePrintProcessor)
+ struct spoolss_DeletePrintProcessor DeletePrintProcessor;
+ CASE(SPOOLSS_OPNUM_AddPrintProvider)
+ struct spoolss_AddPrintProvider AddPrintProvider;
+ CASE(SPOOLSS_OPNUM_DeletePrintProvider)
+ struct spoolss_DeletePrintProvider DeletePrintProvider;
+ CASE(SPOOLSS_OPNUM_ResetPrinter)
+ struct spoolss_ResetPrinter ResetPrinter;
+ CASE(SPOOLSS_OPNUM_FindFirstChangeNotify)
+ struct spoolss_FindFirstChangeNotify FindFirstChangeNotify;
+ CASE(SPOOLSS_OPNUM_FindNextChangeNotify)
+ struct spoolss_FindNextChangeNotify FindNextChangeNotify;
+ CASE(SPOOLSS_OPNUM_RouterFindFirstNotify)
+ struct spoolss_RouterFindFirstNotify RouterFindFirstNotify;
+ CASE(SPOOLSS_OPNUM_ReplyOpenPrinter)
+ struct spoolss_ReplyOpenPrinter ReplyOpenPrinter;
+ CASE(SPOOLSS_OPNUM_RouterReplyPrinter)
+ struct spoolss_RouterReplyPrinter RouterReplyPrinter;
+ CASE(SPOOLSS_OPNUM_ReplyClosePrinter)
+ struct spoolss_ReplyClosePrinter ReplyClosePrinter;
+ CASE(SPOOLSS_OPNUM_AddPortEx)
+ struct spoolss_AddPortEx AddPortEx;
+ CASE(SPOOLSS_OPNUM_RemoteFindFirstChangeNotify)
+ struct spoolss_RemoteFindFirstChangeNotify
+ RemoteFindFirstChangeNotify;
+ CASE(SPOOLSS_OPNUM_SpoolerInitialize)
+ struct spoolss_SpoolerInitialize SpoolerInitialize;
+ CASE(SPOOLSS_OPNUM_ResetPrinterEx)
+ struct spoolss_ResetPrinterEx ResetPrinterEx;
+ CASE(SPOOLSS_OPNUM_RouterRefreshChangeNotify)
+ struct spoolss_RouterRefreshChangeNotify
+ RouterRefreshChangeNotify;
+ CASE(SPOOLSS_OPNUM_OpenPrinter2)
+ struct spoolss_OpenPrinter2 OpenPrinter2;
+};
+typedef union spoolss_interface spoolss_interface_t;
+EXTERNTYPEINFO(spoolss_interface)
+
+#endif /* _MLSVC_SPOOLSS_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl
new file mode 100644
index 0000000000..b952feacb7
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl
@@ -0,0 +1,1331 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_LANMAN_NDL_
+#define _MLSVC_LANMAN_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * LanMan RPC (WKSSVC and SRVSVC) interface definitions.
+ */
+
+#include "ndrtypes.ndl"
+
+/*
+ * WARNING: The cpp(1) macros in this file are not understood by
+ * /usr/bin/cpp. Use /usr/libexec/cpp instead.
+ */
+
+/*
+ * TYPE CONSTRUCTOR MACROS FOR INFORMATION RESULTS
+ ****************************************************************
+ *
+ * This is an explanation of the macros that follow this comment.
+ *
+ * The LANMAN API's look something like this:
+ *
+ * NetXXXGetInfo (
+ * IN char * servername,
+ * IN char * XXX_name,
+ * IN int level,
+ * OUT char ** bufptr);
+ *
+ * The bufptr is a pointer-to-pointer (**). The NetXXXGetInfo() function
+ * malloc()s memory, and sets *bufptr to the memory. The API's
+ * are undiscriminated about what bufptr really points to.
+ *
+ * However, for RPI (Remote Procedure Interface), this just won't fly.
+ * We have to know what the result data looks like in order to
+ * properly (un)marshall it.
+ *
+ * As best we can determine, the MSC developers use an RPI that looks
+ * like this (approximately in IDL):
+ *
+ * RemoteNetXXXGetInfo (
+ * IN char * servername,
+ * IN char * XXX_name,
+ * IN int level,
+ * OUT union switch(level) {
+ * case(1): XXX_INFO_1 * info1;
+ * case(2): XXX_INFO_2 * info2;
+ * } bufptr);
+ *
+ * The level guides the (un)marshalling as it follows the pointer.
+ * DCE(MS) IDL will automatically form a structure for the union
+ * which looks about like this (much as Sun/RPC does):
+ *
+ * struct {
+ * int _keyvalue_;
+ * union {
+ * XXX_INFO_1 *info1;
+ * XXX_INFO_2 *info2;
+ * } _u_;
+ * } bufptr;
+ *
+ * This struct is not made visible to the application. It is purely
+ * an internal (automagic) thing. However, ndrgen does not do this.
+ * The ndrgen input MUST remain a valid C header file, and all
+ * struct and union declarations must be exact, and we (would) have
+ * to tediously code sequences like this (approximately NDL)):
+ *
+ * union XXXGetInfo_result_u {
+ * [case(1)]
+ * XXX_INFO_1 * info1;
+ * [case(2)]
+ * XXX_INFO_2 * info2;
+ * };
+ *
+ * struct XXXGetInfo_result {
+ * int level;
+ *
+ * union XXXGetInfo_result_u bufptr;
+ * };
+ *
+ * struct XXXGetInfo_param { // still have to code this one
+ * [in] char * servername;
+ * [in] ushort level;
+ * [out] struct XXXGetInfo_result result;
+ * };
+ *
+ * This is error prone and difficult to write, and more difficult
+ * and distracting to read. It is hard to pick through the
+ * necessary evils and see what's really going on. To mitigate
+ * the situation, we have a series of macros which generate
+ * the tedious code, and are easily recognized as supporting
+ * fluff rather than important structures:
+ *
+ * INFO1RES_DEFINITION(XXXGetInfo,
+ * INFO1RES_UNION_ENTRY(XXXGetInfo, 1)
+ * INFO1RES_UNION_ENTRY(XXXGetInfo, 2))
+ *
+ * structt XXXGetInfo_param { // still have to code this one
+ * [in] char * servername;
+ * [in] ushort level;
+ * [out] struct XXXGetInfo_result result;
+ * };
+ *
+ * The INFO1RES_DEFINITION macro defines two types:
+ *
+ * union ...__ru {...}
+ * struct ..._result { DWORD level; union ..._ru bufptr; }
+ *
+ * There is a similar macro, INFO1RESBUF_DEFINITION, which defines
+ * actual space rather than just pointers. It defines:
+ *
+ * union ...._rb {...}
+ * typedef union ..._rb ..._rb;
+ *
+ * Which is handy in functions because the initial coding sequence
+ * looks something like:
+ *
+ * XXXGetInfoParam (struct XXXGetInfo_param *param) {
+ * XXXGetInfo_rb rb;
+ *
+ * param->result.level = param->level; // for marshalling
+ * param->result.bufptr.nullptr = &rb; // anything fits
+ *
+ * There are two flavors of Info results. The first is the
+ * single XXX_INFO_x result, which the foregoing example
+ * uses. The second flavor is when there are multiple entries
+ * possible. Again, for the sake of guiding the marshalling,
+ * the RPIs use something accommodating:
+ *
+ * struct XXX_INFO_1_result {
+ * unsigned entriesread;
+ * [size_is(entriesread)]
+ * XXX_INFO_1 * table;
+ * };
+ *
+ * union { XXX_INFO_1_result *info1; ...}
+ *
+ * Notice this is using XXX_INFO_1_result rather than just XXX_INFO_1.
+ * The requirements from this point are much like before. Because of
+ * the variable-length value, there is no realistic way to do something
+ * like INFO1RESBUF_DEFINITION.
+ *
+ * There are two sets of macros here. INFO1RES_xxx are for the
+ * single result case, and INFONRES_xxx for the multiple entry case.
+ */
+
+/*
+ * INFO1RES_...
+ * Type constructors for single-result case
+ */
+
+#define INFO1RES_DEFINITION(INFOPREF, ENTRIES) \
+ INFO1RES_UNION(INFOPREF, ENTRIES) \
+ INFO1RES_STRUCT(INFOPREF)
+
+#define INFO1RES_UNION(INFOPREF, ENTRIES) \
+ union INFOPREF##__ru { \
+ INFO1RES_UNION_NULLPTR \
+ ENTRIES \
+ };
+
+#define INFO1RES_UNION_NULLPTR \
+ DEFAULT char * nullptr;
+
+#define INFO1RES_UNION_ENTRY(INFOPREF,NUM) \
+ CASE(NUM) struct INFOPREF##_##NUM * bufptr##NUM;
+
+#define INFO1RES_STRUCT(INFOPREF) \
+ struct INFOPREF##_result { \
+ DWORD level; \
+ SWITCH(level) \
+ union INFOPREF##__ru bufptr; \
+ };
+
+/*
+ * INFO1RESBUF_...
+ * Type constructors for single-result buffering.
+ */
+
+
+#ifndef NDRGEN
+#define INFO1RESBUF_DEFINITION(INFOPREF, ENTRIES) \
+ typedef union INFOPREF##_rb { \
+ ENTRIES \
+ } INFOPREF##_rb;
+#define INFO1RESBUF_UNION_ENTRY(INFOPREF,NUM) \
+ CASE(NUM) struct INFOPREF##_##NUM buf##NUM;
+#else
+#define INFO1RESBUF_DEFINITION(INFOPREF, ENTRIES)
+#define INFO1RESBUF_UNION_ENTRY(INFOPREF,NUM)
+#endif
+
+
+
+
+/*
+ * INFONRES_...
+ * Type constructors for multiple-result case
+ */
+
+#define INFONRES_RESULT(INFOPREF,NUM) \
+ struct INFOPREF##_##NUM##_result { \
+ DWORD entriesread; \
+ SIZE_IS(entriesread) \
+ struct INFOPREF##_##NUM *entries; \
+ };
+
+#define INFONRES_DEFINITION(INFOPREF, ENTRIES) \
+ INFONRES_UNION(INFOPREF, ENTRIES) \
+ INFONRES_STRUCT(INFOPREF)
+
+#define INFONRES_UNION(INFOPREF, ENTRIES) \
+ union INFOPREF##__ru { \
+ INFONRES_UNION_NULLPTR \
+ INFONRES_UNION_INFONRES \
+ ENTRIES \
+ };
+
+#define INFONRES_UNION_NULLPTR \
+ DEFAULT char * nullptr;
+
+#ifndef NDRGEN
+#define INFONRES_UNION_INFONRES \
+ struct mslm_infonres * p;
+#else
+#define INFONRES_UNION_INFONRES
+#endif
+
+#define INFONRES_UNION_ENTRY(INFOPREF,NUM) \
+ CASE(NUM) struct INFOPREF##_##NUM##_result * bufptr##NUM;
+
+#define INFONRES_STRUCT(INFOPREF) \
+ struct INFOPREF##_result { \
+ DWORD level; \
+ SWITCH(level) \
+ union INFOPREF##__ru bufptr; \
+ };
+
+#ifndef NDRGEN
+/*
+ * This just makes things a little easier on the stub modules:
+ *
+ * XXXGetInfoParam (struct XXXGetInfo_param *param) {
+ * struct mslm_infonres infonres;
+ *
+ * infonres.entriesread = 0;
+ * infonres.entries = 0;
+ * param->result.level = param->level; // for marshalling
+ * param->result.bufptr.p = &infonres;
+ */
+struct mslm_infonres {
+ DWORD entriesread;
+ void * entries;
+};
+#endif
+
+
+/*
+ * SERVER SERVICE (SRVSVC)
+ ****************************************************************
+ */
+
+
+#define SRVSVC_OPNUM_NetConnectEnum 0x08
+#define SRVSVC_OPNUM_NetFileEnum 0x09
+#define SRVSVC_OPNUM_NetFileClose 0x0b
+#define SRVSVC_OPNUM_NetSessionEnum 0x0c
+#define SRVSVC_OPNUM_NetSessionDel 0x0d
+#define SRVSVC_OPNUM_NetShareAdd 0x0e
+#define SRVSVC_OPNUM_NetShareEnum 0x0f
+#define SRVSVC_OPNUM_NetShareGetInfo 0x10
+#define SRVSVC_OPNUM_NetShareSetInfo 0x11
+#define SRVSVC_OPNUM_NetShareDel 0x12
+#define SRVSVC_OPNUM_NetServerGetInfo 0x15
+#define SRVSVC_OPNUM_NetServerSetInfo 0x16
+#define SRVSVC_OPNUM_NetRemoteTOD 0x1c
+#define SRVSVC_OPNUM_NetNameValidate 0x21
+#define SRVSVC_OPNUM_NetShareEnumSticky 0x24
+#define SRVSVC_OPNUM_NetGetFileSecurity 0x27
+#define SRVSVC_OPNUM_NetSetFileSecurity 0x28
+
+/*
+ ***********************************************************************
+ * NetConnectEnum:
+ *
+ * Description:
+ *
+ * Request for mslm_NetConnectEnum returns
+ * info of resources in MLRPC server connected
+ * to network. Correctly level 0 and level 1 information
+ * are supported.
+ *
+ ***********************************************************************
+ */
+
+/*
+ * Level 0 connect information.
+ */
+struct mslm_NetConnectInfoBuf0 {
+ DWORD coni0_id;
+};
+
+struct mslm_NetConnectInfo0 {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslm_NetConnectInfoBuf0 *ci0;
+};
+
+/*
+ * Level 1 connect information.
+ */
+struct mslm_NetConnectInfoBuf1 {
+ DWORD coni1_id;
+ DWORD coni1_type;
+ DWORD coni1_num_opens;
+ DWORD coni1_num_users;
+ DWORD coni1_time;
+ LPTSTR coni1_username;
+ LPTSTR coni1_netname; /* share name */
+};
+
+struct mslm_NetConnectInfo1 {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslm_NetConnectInfoBuf1 *ci1;
+};
+
+union mslm_NetConnectInfoResUnion {
+ CASE(0) struct mslm_NetConnectInfo0 *info0;
+ CASE(1) struct mslm_NetConnectInfo1 *info1;
+ DEFAULT char *nullptr;
+};
+
+struct mslm_NetConnectInfo {
+ DWORD level;
+ DWORD switch_value;
+ SWITCH(switch_value)
+ union mslm_NetConnectInfoResUnion ru;
+};
+
+OPERATION(SRVSVC_OPNUM_NetConnectEnum)
+struct mslm_NetConnectEnum {
+ IN LPTSTR servername;
+ IN LPTSTR qualifier; /* share name */
+ INOUT struct mslm_NetConnectInfo info;
+ IN DWORD pref_max_len;
+ OUT DWORD total_entries;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetFileEnum: under construction.
+ ***********************************************************************
+ */
+struct mslm_NetFileInfoBuf3 {
+ DWORD fi3_id;
+ DWORD fi3_permissions;
+ DWORD fi3_num_locks;
+ LPTSTR fi3_pathname;
+ LPTSTR fi3_username;
+};
+
+
+struct mslm_NetFileInfo3 {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslm_NetFileInfoBuf3 *fi3;
+};
+
+
+union mslm_NetFileInfoResUnion {
+ CASE(3) struct mslm_NetFileInfo3 *info3;
+ DEFAULT char *nullptr;
+};
+
+
+struct mslm_NetFileInfo {
+ DWORD level;
+ DWORD switch_value;
+ SWITCH(switch_value)
+ union mslm_NetFileInfoResUnion ru;
+};
+
+
+OPERATION(SRVSVC_OPNUM_NetFileEnum)
+struct mslm_NetFileEnum {
+ IN LPTSTR servername;
+ IN DWORD unknown1;
+ IN DWORD unknown2;
+ INOUT struct mslm_NetFileInfo info;
+ IN DWORD pref_max_len;
+ OUT DWORD total_entries;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetFileClose
+ *
+ * I think this definition is complete but as it doesn't do anything
+ * it probably isn't a big issue. It is used to close files reported
+ * via NetFileEnum (i.e. the file id).
+ ***********************************************************************
+ */
+OPERATION(SRVSVC_OPNUM_NetFileClose)
+struct mslm_NetFileClose {
+ IN LPTSTR servername;
+ IN DWORD file_id;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetShareGetInfo: netname is the name of a share.
+ ***********************************************************************
+ */
+struct mslm_NetShareGetInfo0 {
+ LPTSTR shi0_netname;
+};
+
+
+struct mslm_NetShareGetInfo1 {
+ LPTSTR shi1_netname;
+ DWORD shi1_type; /* type of resource such as IPC$ */
+ LPTSTR shi1_comment;
+};
+
+
+struct mslm_NetShareGetInfo2 {
+ LPTSTR shi2_netname;
+ DWORD shi2_type;
+ LPTSTR shi2_comment;
+ DWORD shi2_permissions;
+ DWORD shi2_max_uses;
+ DWORD shi2_current_uses;
+ LPTSTR shi2_path;
+ LPTSTR shi2_passwd;
+};
+
+struct mslm_NetShareGetInfo502 {
+ LPTSTR shi502_netname;
+ DWORD shi502_type;
+ LPTSTR shi502_comment;
+ DWORD shi502_permissions;
+ DWORD shi502_max_uses;
+ DWORD shi502_current_uses;
+ LPTSTR shi502_path;
+ LPTSTR shi502_passwd;
+ DWORD shi502_reserved;
+ DWORD shi502_security_descriptor;
+};
+
+struct mslm_NetShareGetInfo1005 {
+ DWORD shi1005_flags;
+};
+
+union mlsm_NetShareGetInfoResUnion {
+ CASE(0) struct mslm_NetShareGetInfo0 *info0;
+ CASE(1) struct mslm_NetShareGetInfo1 *info1;
+ CASE(2) struct mslm_NetShareGetInfo2 *info2;
+ CASE(502) struct mslm_NetShareGetInfo502 *info502;
+ CASE(1005) struct mslm_NetShareGetInfo1005 *info1005;
+ DEFAULT char *nullptr;
+};
+
+
+struct mlsm_NetShareGetInfoRes {
+ DWORD switch_value;
+ SWITCH(switch_value)
+ union mlsm_NetShareGetInfoResUnion ru;
+};
+
+
+OPERATION(SRVSVC_OPNUM_NetShareGetInfo)
+struct mlsm_NetShareGetInfo {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR netname;
+ IN DWORD level;
+ OUT struct mlsm_NetShareGetInfoRes result;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetShareSetInfo: netname is the name of a share.
+ ***********************************************************************
+ */
+OPERATION(SRVSVC_OPNUM_NetShareSetInfo)
+struct mlsm_NetShareSetInfo {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR netname;
+ IN DWORD level;
+/*
+ * This should accept all the same levels as NetShareGetInfo
+ * but we always return ACCESS_DENIED for now. So there's no
+ * point in unmarshalling the share information.
+ *
+ * IN struct mlsm_NetShareGetInfoRes result;
+ */
+ OUT DWORD parm_err_ptr;
+ OUT DWORD parm_err;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetSessionEnum
+ *
+ * The NetSessionEnum function provides information about sessions
+ * established on a server.
+ *
+ * Only members of the Administrators or Account Operators local groups
+ * can successfully execute the NetSessionEnum function at level 1 or
+ * level 2. No special group membership is required for level 0 or level
+ * 10 calls.
+ *
+ * Windows NT/2000/XP: The parameter order is as follows.
+ *
+ * NET_API_STATUS NetSessionEnum(LPWSTR servername,
+ * LPWSTR UncClientName,
+ * LPWSTR username,
+ * DWORD level,
+ * LPBYTE *bufptr,
+ * DWORD prefmaxlen,
+ * LPDWORD entriesread,
+ * LPDWORD totalentries,
+ * LPDWORD resume_handle);
+ *
+ * Windows 95/98/Me: The calling application must use the cbBuffer parameter
+ * to specify the size, in bytes, of the information buffer pointed to by the
+ * pbBuffer parameter. (The cbBuffer parameter replaces the prefmaxlen
+ * parameter.) Neither a user name parameter nor a resume handle parameter is
+ * available on this platform. Therefore, the parameter list is as follows.
+ *
+ * API_FUNCTION NetSessionEnum(const char FAR *pszServer,
+ * short sLevel,
+ * char FAR *pbBuffer,
+ * unsigned short cbBuffer,
+ * unsigned short FAR *pcEntriesRead,
+ * unsigned short FAR *pcTotalAvail);
+ *
+ * Parameters
+ *
+ * servername
+ * [in] Pointer to a string that specifies the DNS or NetBIOS name of the
+ * remote server on which the function is to execute. If this parameter is
+ * NULL, the local computer is used.
+ * Windows NT 4.0 and earlier: This string must begin with \\.
+ *
+ * UncClientName
+ * [in] Pointer to a string that specifies the name of the computer session
+ * for which information is to be returned. If this parameter is NULL,
+ * NetSessionEnum returns information for all computer sessions on the server.
+ *
+ * username
+ * [in] Pointer to a string that specifies the name of the user for which
+ * information is to be returned. If this parameter is NULL, NetSessionEnum
+ * returns information for all users.
+ *
+ * level
+ * [in] Specifies the information level of the data. This parameter can be
+ * one of the following values.
+ * Windows NT/2000/XP: The following levels are valid.
+ * Value Meaning
+ * 0 Return the name of the computer that established the session.
+ * The bufptr parameter points to an array of SESSION_INFO_0
+ * structures.
+ * 1 Return the name of the computer, name of the user, and open files,
+ * pipes, and devices on the computer. The bufptr parameter points to
+ * an array of SESSION_INFO_1 structures.
+ * 2 In addition to the information indicated for level 1, return the
+ * type of client and how the user established the session. The bufptr
+ * parameter points to an array of SESSION_INFO_2 structures.
+ * 10 Return the name of the computer, name of the user, and active and
+ * idle times for the session. The bufptr parameter points to an array
+ * of SESSION_INFO_10 structures.
+ * 502 Return the name of the computer; name of the user; open files,
+ * pipes, and devices on the computer; and the name of the transport
+ * the client is using. The bufptr parameter points to an array of
+ * SESSION_INFO_502 structures.
+ *
+ * Windows 95/98/Me: The following level is valid.
+ * Value Meaning
+ * 50 Return the name of the computer, name of the user, open files on
+ * the computer, and the name of the transport protocol the client is
+ * using. The pbBuffer parameter points to an array of session_info_50
+ * structures.
+ *
+ * bufptr
+ * [out] Pointer to the buffer that receives the data. The format of this
+ * data depends on the value of the level parameter.
+ * Windows NT/2000/XP: This buffer is allocated by the system and must be
+ * freed using the NetApiBufferFree function. Note that you must free the
+ * buffer even if the function fails with ERROR_MORE_DATA.
+ * Windows 95/98/Me: The caller must allocate and deallocate this buffer.
+ *
+ * prefmaxlen
+ * [in] Specifies the preferred maximum length of returned data, in bytes.
+ * If you specify MAX_PREFERRED_LENGTH, the function allocates the amount
+ * of memory required for the data. If you specify another value in this
+ * parameter, it can restrict the number of bytes that the function returns.
+ * If the buffer size is insufficient to hold all entries, the function
+ * returns ERROR_MORE_DATA. For more information, see Network Management
+ * Function Buffers and Network Management Function Buffer Lengths.
+ *
+ * entriesread
+ * [out] Pointer to a value that receives the count of elements actually
+ * enumerated.
+ *
+ * totalentries
+ * [out] Pointer to a value that receives the total number of entries that
+ * could have been enumerated from the current resume position.
+ *
+ * resume_handle
+ * [in/out] Pointer to a value that contains a resume handle which is used
+ * to continue an existing session search. The handle should be zero on the
+ * first call and left unchanged for subsequent calls. If resume_handle is
+ * NULL, no resume handle is stored.
+ *
+ *
+ * SESSION_INFO_1
+ * ==============
+ * The SESSION_INFO_1 structure contains information about the session,
+ * including name of the computer; name of the user; and open files, pipes,
+ * and devices on the computer.
+ *
+ * Members
+ *
+ * sesi1_cname
+ * Pointer to a Unicode string specifying the name of the computer that
+ * established the session.
+ *
+ * sesi1_username
+ * Pointer to a Unicode string specifying the name of the user who established
+ * the session.
+ *
+ * sesi1_num_opens
+ * Specifies a DWORD value that contains the number of files, devices,
+ * and pipes opened during the session.
+ *
+ * sesi1_time
+ * Specifies a DWORD value that contains the number of seconds the session
+ * has been active.
+ *
+ * sesi1_idle_time
+ * Specifies a DWORD value that contains the number of seconds the session
+ * has been idle.
+ *
+ * sesi1_user_flags
+ * Specifies a DWORD value that describes how the user established the
+ * session. This member can be one of the following values:
+ * SESS_GUEST The user specified by the sesi1_username member
+ * established the session using a guest account.
+ * SESS_NOENCRYPTION The user specified by the sesi1_username member
+ * established the session without using password
+ * encryption.
+ ***********************************************************************
+ */
+
+#define SESS_GUEST 0x00000001
+#define SESS_NOENCRYPTION 0x00000002
+
+struct mslm_SESSION_INFO_0 {
+ LPTSTR sesi0_cname;
+};
+INFONRES_RESULT(mslm_SESSION_INFO, 0)
+
+struct mslm_SESSION_INFO_1 {
+ LPTSTR sesi1_cname;
+ LPTSTR sesi1_uname;
+ DWORD sesi1_nopens;
+ DWORD sesi1_time;
+ DWORD sesi1_itime;
+ DWORD sesi1_uflags;
+};
+INFONRES_RESULT(mslm_SESSION_INFO, 1)
+
+INFONRES_DEFINITION(mslm_NetSessionEnum,
+ INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 0)
+ INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 1))
+
+OPERATION(SRVSVC_OPNUM_NetSessionEnum)
+struct mslm_NetSessionEnum {
+ IN LPTSTR servername;
+ IN DWORD unc_clientname;
+ IN DWORD username;
+ INOUT DWORD level;
+ INOUT struct mslm_NetSessionEnum_result result;
+ IN DWORD pref_max_len;
+ OUT DWORD total_entries;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetSessionDel (Platform SDK: Network Management)
+ *
+ * The NetSessionDel function ends a network session between a server
+ * and a workstation.
+ *
+ * Security Requirements
+ * Only members of the Administrators or Account Operators local group
+ * can successfully execute the NetSessionDel function.
+ *
+ * Windows NT/2000/XP: The parameter order is as follows.
+ *
+ * NET_API_STATUS NetSessionDel(LPWSTR servername,
+ * LPWSTR UncClientName,
+ * LPWSTR username);
+ *
+ * Windows 95/98/Me: The sReserved parameter replaces the username
+ * parameter. For more information, see the following Remarks section.
+ * The parameter list is as follows.
+ *
+ * API_FUNCTION NetSessionDel(const char FAR *pszServer,
+ * const char FAR *pszClientName,
+ * short sReserved);
+ *
+ * Parameters
+ *
+ * servername
+ * [in] Pointer to a string that specifies the DNS or NetBIOS name
+ * of the remote server on which the function is to execute. If this
+ * parameter is NULL, the local computer is used.
+ * Windows NT 4.0 and earlier: This string must begin with \\.
+ *
+ * UncClientName
+ * [in] Pointer to a string that specifies the computer name of the
+ * client to disconnect. If UncClientName is NULL, then all the sessions
+ * of the user identified by the username parameter will be deleted on
+ * the server specified by servername. For more information, see
+ * NetSessionEnum.
+ *
+ * username
+ * [in] Pointer to a string that specifies the name of the user whose
+ * session is to be terminated. If this parameter is NULL, all users'
+ * sessions from the client specified by the UncClientName parameter
+ * are to be terminated.
+ *
+ * Remarks
+ * Windows 95/98/Me: You must specify the session key in the sReserved
+ * parameter when you call NetSessionDel. The session key is returned by
+ * the NetSessionEnum function or the NetSessionGetInfo function in the
+ * sesi50_key member of the session_info_50 structure.
+ ***********************************************************************
+ */
+
+OPERATION(SRVSVC_OPNUM_NetSessionDel)
+struct mslm_NetSessionDel {
+ IN LPTSTR servername;
+ IN LPTSTR unc_clientname;
+ IN LPTSTR username;
+ OUT DWORD status;
+};
+
+
+/*
+ * SRVSVC NetServerGetInfo (
+ * IN LPTSTR servername,
+ * IN DWORD level,
+ * OUT union switch(level) {
+ * case 100: _SERVER_INFO_100 * p100;
+ * case 101: _SERVER_INFO_101 * p101;
+ * case 102: _SERVER_INFO_102 * p102;
+ * } bufptr,
+ * OUT DWORD status
+ * )
+ */
+
+/* for svX_platform */
+#define SV_PLATFORM_ID_OS2 400
+#define SV_PLATFORM_ID_NT 500
+
+/* Bit-mapped values for svX_type fields */
+#define SV_TYPE_WORKSTATION 0x00000001
+#define SV_TYPE_SERVER 0x00000002
+#define SV_TYPE_SQLSERVER 0x00000004
+#define SV_TYPE_DOMAIN_CTRL 0x00000008
+#define SV_TYPE_DOMAIN_BAKCTRL 0x00000010
+#define SV_TYPE_TIME_SOURCE 0x00000020
+#define SV_TYPE_AFP 0x00000040
+#define SV_TYPE_NOVELL 0x00000080
+#define SV_TYPE_DOMAIN_MEMBER 0x00000100
+#define SV_TYPE_PRINTQ_SERVER 0x00000200
+#define SV_TYPE_DIALIN_SERVER 0x00000400
+#define SV_TYPE_XENIX_SERVER 0x00000800
+#define SV_TYPE_SERVER_UNIX SV_TYPE_XENIX_SERVER
+#define SV_TYPE_NT 0x00001000
+#define SV_TYPE_WFW 0x00002000
+
+#define SV_TYPE_SERVER_MFPN 0x00004000
+#define SV_TYPE_SERVER_NT 0x00008000
+#define SV_TYPE_POTENTIAL_BROWSER 0x00010000
+#define SV_TYPE_BACKUP_BROWSER 0x00020000
+#define SV_TYPE_MASTER_BROWSER 0x00040000
+#define SV_TYPE_DOMAIN_MASTER 0x00080000
+#define SV_TYPE_SERVER_OSF 0x00100000
+#define SV_TYPE_SERVER_VMS 0x00200000
+#define SV_TYPE_WINDOWS 0x00400000 /* Windows95 and above */
+#define SV_TYPE_ALTERNATE_XPORT 0x20000000 /* return list for
+ * alternate transport */
+#define SV_TYPE_LOCAL_LIST_ONLY 0x40000000 /* Return local list only */
+#define SV_TYPE_DOMAIN_ENUM 0x80000000
+#define SV_TYPE_ALL 0xFFFFFFFF /* handy for NetServerEnum2 */
+
+/* NT-Server 4.0 sends 0x0006_120B */
+#define SV_TYPE_SENT_BY_NT_4_0_SERVER \
+ ( SV_TYPE_WORKSTATION \
+ | SV_TYPE_SERVER \
+ | SV_TYPE_DOMAIN_CTRL \
+ | SV_TYPE_NT \
+ | SV_TYPE_BACKUP_BROWSER \
+ | SV_TYPE_MASTER_BROWSER)
+/* NT-workstation 4.0 send 0x0004_1013 */
+#define SV_TYPE_SENT_BY_NT_4_0_WORKSTATION \
+ ( SV_TYPE_WORKSTATION \
+ | SV_TYPE_SERVER \
+ | SV_TYPE_DOMAIN_BAKCTRL \
+ | SV_TYPE_NT \
+ | SV_TYPE_MASTER_BROWSER)
+
+/* Special value for sv102_disc that specifies infinite disconnect time */
+#define SV_NODISC (-1L) /* No autodisconnect timeout enforced */
+
+/* Values of svX_security field */
+#define SV_USERSECURITY 1
+#define SV_SHARESECURITY 0
+
+/* Values of svX_hidden field */
+#define SV_HIDDEN 1
+#define SV_VISIBLE 0
+
+
+/* Let's get some info already */
+struct mslm_SERVER_INFO_100 {
+ DWORD sv100_platform_id;
+ LPTSTR sv100_name;
+};
+
+struct mslm_SERVER_INFO_101 {
+ DWORD sv101_platform_id;
+ LPTSTR sv101_name;
+ DWORD sv101_version_major;
+ DWORD sv101_version_minor;
+ DWORD sv101_type;
+ LPTSTR sv101_comment;
+};
+
+struct mslm_SERVER_INFO_102 {
+ DWORD sv102_platform_id;
+ LPTSTR sv102_name;
+ DWORD sv102_version_major;
+ DWORD sv102_version_minor;
+ DWORD sv102_type;
+ LPTSTR sv102_comment;
+ DWORD sv102_users;
+ DWORD sv102_disc;
+ DWORD sv102_hidden; /* BOOL */
+ DWORD sv102_announce;
+ DWORD sv102_anndelta;
+ DWORD sv102_licenses;
+ LPTSTR sv102_userpath;
+};
+
+union mslm_NetServerGetInfo_ru {
+ CASE(100) struct mslm_SERVER_INFO_100 *bufptr100;
+ CASE(101) struct mslm_SERVER_INFO_101 *bufptr101;
+ CASE(102) struct mslm_SERVER_INFO_102 *bufptr102;
+ DEFAULT char *nullptr;
+};
+
+struct mslm_NetServerGetInfo_result {
+ DWORD level;
+ SWITCH(level)
+ union mslm_NetServerGetInfo_ru bufptr;
+};
+
+
+OPERATION(SRVSVC_OPNUM_NetServerGetInfo)
+struct mslm_NetServerGetInfo {
+ IN LPTSTR servername;
+ IN DWORD level;
+ OUT struct mslm_NetServerGetInfo_result result;
+ OUT DWORD status;
+};
+
+/*
+ * SRVSVC NetRemoteTOD (
+ * IN LPTSTR servername,
+ * OUT _TIME_OF_DAY_INFO *bufptr,
+ * OUT long status
+ * )
+ */
+
+struct mslm_TIME_OF_DAY_INFO {
+ DWORD tod_elapsedt;
+ DWORD tod_msecs;
+ DWORD tod_hours;
+ DWORD tod_mins;
+ DWORD tod_secs;
+ DWORD tod_hunds;
+ DWORD tod_timezone;
+ DWORD tod_tinterval;
+ DWORD tod_day;
+ DWORD tod_month;
+ DWORD tod_year;
+ DWORD tod_weekday;
+};
+
+OPERATION(SRVSVC_OPNUM_NetRemoteTOD)
+struct mslm_NetRemoteTOD {
+ IN LPTSTR servername;
+ OUT struct mslm_TIME_OF_DAY_INFO *bufptr;
+ OUT DWORD status;
+};
+
+/*
+ * SRVSVC_NetNameValidate (
+ * IN LPTSTR servername;
+ * IN REFERENCE LPTSTR pathname;
+ * IN DWORD type;
+ * IN DWORD flags;
+ * OUT DWORD status;
+ * )
+ */
+OPERATION(SRVSVC_OPNUM_NetNameValidate)
+struct mslm_NetNameValidate {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR pathname;
+ IN DWORD type;
+ IN DWORD flags;
+ OUT DWORD status;
+};
+
+/*
+ * SRVSVC NetShareEnum (
+ * IN LPTSTR servername,
+ * IN DWORD level;
+ * OUT union switch(level) {
+ * case 0: struct {
+ * DWORD entriesread;
+ * [size_is(entriesread)]
+ * _SHARE_INFO_0 *entries;
+ * } *bufptr0;
+ * case 1: struct {
+ * DWORD entriesread;
+ * [size_is(entriesread)]
+ * _SHARE_INFO_1 *entries;
+ * } *bufptr1;
+ * ...
+ * } bufptr,
+ * IN DWORD prefmaxlen,
+ * OUT DWORD totalentries,
+ * IN OUT DWORD ?* resume_handle,
+ * OUT DWORD status
+ * )
+ */
+
+/*
+ * Share types for shiX_type fields - duplicated from cifs.h
+ */
+#ifndef _SHARE_TYPES_DEFINED_
+#define _SHARE_TYPES_DEFINED_
+#define STYPE_DISKTREE 0x00000000
+#define STYPE_PRINTQ 0x00000001
+#define STYPE_DEVICE 0x00000002
+#define STYPE_IPC 0x00000003
+#define STYPE_MASK 0x0000000F
+#define STYPE_DFS 0x00000064
+#define STYPE_HIDDEN 0x80000000
+#define STYPE_SPECIAL 0x80000000
+#endif /* _SHARE_TYPES_DEFINED_ */
+
+/* Maximum uses for shiX_max_uses fields */
+#define SHI_USES_UNLIMITED (DWORD)-1
+
+
+
+struct mslm_SHARE_INFO_0 {
+ LPTSTR shi0_netname;
+};
+INFONRES_RESULT(mslm_SHARE_INFO,0)
+
+struct mslm_SHARE_INFO_1 {
+ LPTSTR shi1_netname;
+ DWORD shi1_type;
+ LPTSTR shi1_remark;
+};
+INFONRES_RESULT(mslm_SHARE_INFO,1)
+
+struct mslm_SHARE_INFO_2 {
+ LPTSTR shi2_netname;
+ DWORD shi2_type;
+ LPTSTR shi2_remark;
+ DWORD shi2_permissions;
+ DWORD shi2_max_uses;
+ DWORD shi2_current_uses;
+ LPTSTR shi2_path;
+ LPTSTR shi2_passwd;
+};
+INFONRES_RESULT(mslm_SHARE_INFO,2)
+
+/*
+ * Note: shi502_security_descriptor should be a pointer to a
+ * security descriptor (W32SEC_SECURITY_DESCRIPTOR):
+ * PSECURITY_DESCRIPTOR shi502_security_descriptor;
+ *
+ * For now we can just use a DWORD and set it to zero.
+ */
+struct mslm_SHARE_INFO_502 {
+ LPTSTR shi502_netname;
+ DWORD shi502_type;
+ LPTSTR shi502_remark;
+ DWORD shi502_permissions;
+ DWORD shi502_max_uses;
+ DWORD shi502_current_uses;
+ LPTSTR shi502_path;
+ LPTSTR shi502_passwd;
+ DWORD shi502_reserved;
+ DWORD shi502_security_descriptor;
+};
+INFONRES_RESULT(mslm_SHARE_INFO,502)
+
+union mslm_NetShareAddInfo_u {
+ CASE(2) struct mslm_SHARE_INFO_2 *info2;
+ CASE(502) struct mslm_SHARE_INFO_502 *info502;
+};
+
+struct mslm_NetShareAddInfo {
+ DWORD switch_value;
+ SWITCH(switch_value)
+ union mslm_NetShareAddInfo_u un;
+};
+
+
+OPERATION(SRVSVC_OPNUM_NetShareAdd)
+struct mslm_NetShareAdd {
+ IN LPTSTR servername;
+ IN DWORD level;
+ IN struct mslm_NetShareAddInfo info;
+ INOUT DWORD *parm_err;
+ OUT DWORD status;
+};
+
+
+INFONRES_DEFINITION(mslm_NetShareEnum,
+ INFONRES_UNION_ENTRY(mslm_SHARE_INFO,0)
+ INFONRES_UNION_ENTRY(mslm_SHARE_INFO,1)
+ INFONRES_UNION_ENTRY(mslm_SHARE_INFO,2)
+ INFONRES_UNION_ENTRY(mslm_SHARE_INFO,502))
+
+
+OPERATION(SRVSVC_OPNUM_NetShareEnum)
+struct mslm_NetShareEnum {
+ IN LPTSTR servername;
+ INOUT DWORD level;
+ OUT struct mslm_NetShareEnum_result result;
+ IN DWORD prefmaxlen;
+ OUT DWORD totalentries;
+ INOUT DWORD * resume_handle; /* not sure about ptr */
+ OUT DWORD status;
+};
+
+
+/*
+ * Delete a share. The reserved field appears in netmon
+ * but I've left it out in case it's not always present.
+ * This won't affect RPC processing.
+ */
+OPERATION(SRVSVC_OPNUM_NetShareDel)
+struct mslm_NetShareDel {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR netname;
+ /* IN DWORD reserved; */
+ OUT DWORD status;
+};
+
+
+/*
+ * NetShareEnumSticky is the same as NetShareEnum except that hidden
+ * shares are not returned. This call was apparently added due to a
+ * bug in the NT implementation of NetShareEnum - it didn't process
+ * the resume handle correctly so that attempts to enumerate large
+ * share lists resulted in an infinite loop.
+ */
+OPERATION(SRVSVC_OPNUM_NetShareEnumSticky)
+struct mslm_NetShareEnumSticky {
+ IN LPTSTR servername;
+ INOUT DWORD level;
+ OUT struct mslm_NetShareEnum_result result;
+ IN DWORD prefmaxlen;
+ OUT DWORD totalentries;
+ INOUT DWORD * resume_handle; /* not sure about ptr */
+ OUT DWORD status;
+};
+
+/*
+ * When you install Windows NT Server Tools on a Win95 client,
+ * a security tab will be added to properties dialog box of files/folders.
+ * Within this security tab, when you try to get/set permissions on a
+ * file/folder the next two RPC calls are used.
+ */
+OPERATION(SRVSVC_OPNUM_NetGetFileSecurity)
+struct mslm_NetGetFileSecurity {
+ IN LPTSTR servername;
+ IN LPTSTR sharename;
+ IN REFERENCE LPTSTR filename;
+ IN DWORD securityinfo;
+
+ /*
+ * Right now, we can't send back SD of the requested object
+ * in MLRPC code, so we just reply with access denied error
+ * code. Thus, this output declaration is only valid in this
+ * case i.e., it's not complete.
+ * It looks like:
+ *
+ * A Pointer
+ * A Length
+ *
+ * A Pointer
+ * A Length (equal to the prev length)
+ * A buffer
+ *
+ * return value
+ */
+ OUT DWORD length;
+ OUT DWORD status;
+};
+
+/*
+ * This is the request:
+ *
+ * R_SRVSVC: RPC Client call srvsvc:NetrpSetFileSecurity(..)
+ * R_SRVSVC: SRVSVC_HANDLE ServerName = \\WK76-177
+ * R_SRVSVC: LPWSTR ShareName = AFSHIN
+ * R_SRVSVC: LPWSTR lpFileName = \salek.txt
+ * R_SRVSVC: SECURITY_INFORMATION SecurityInformation = 4 (0x4)
+ * -R_SRVSVC: PADT_SECURITY_DESCRIPTOR SecurityDescriptor {..}
+ * R_SRVSVC: DWORD Length = 64 (0x40)
+ * R_SRVSVC: LPBYTE Buffer = 4496048 (0x449AB0)
+ * R_SRVSVC: LPBYTE Buffer [..] = 01 00 04 80 00 00 00 00 00 00 00 00 00 00 00
+ * ...
+ *
+ * 000000A0 00 83 46 00 0B 00 00 00 00 00 00 00 0B 00 ..F...........
+ * 000000B0 00 00 5C 00 5C 00 57 00 4B 00 37 00 36 00 2D 00 ..\.\.W.K.7.6.-.
+ * 000000C0 31 00 37 00 37 00 00 00 08 00 16 83 46 00 07 00 1.7.7.......F...
+ * 000000D0 00 00 00 00 00 00 07 00 00 00 41 00 46 00 53 00 ..........A.F.S.
+ * 000000E0 48 00 49 00 4E 00 00 00 00 00 0B 00 00 00 00 00 H.I.N...........
+ * 000000F0 00 00 0B 00 00 00 5C 00 73 00 61 00 6C 00 65 00 ......\.s.a.l.e.
+ * 00000100 6B 00 2E 00 74 00 78 00 74 00 00 00 00 00 04 00 k...t.x.t.......
+ * 00000110 00 00 40 00 00 00 B0 9A 44 00 40 00 00 00 01 00 ..@.....D.@.....
+ * 00000120 04 80 00 00 00 00 00 00 00 00 00 00 00 00 14 00 ................
+ * 00000130 00 00 02 00 2C 00 01 00 00 00 00 00 24 00 00 00 ....,.......$...
+ * 00000140 00 A0 01 05 00 00 00 00 00 05 15 00 00 00 1A 24 ...............$
+ * 00000150 44 38 90 00 0F 02 65 3A BE 4C FF 03 00 00 00 00 D8....e:.L......
+ * 00000160 00 00 00 00 00 00 00 00 00 00 ..........
+ */
+OPERATION(SRVSVC_OPNUM_NetSetFileSecurity)
+struct mslm_NetSetFileSecurity {
+ IN LPTSTR servername;
+ IN LPTSTR sharename;
+ IN REFERENCE LPTSTR filename;
+ IN DWORD securityinfo;
+ /*
+ * IN Security Descriptor (looks like):
+ * Length1
+ * Pointer
+ * Length2 (== Length1)
+ * buffer itself
+ */
+
+ OUT DWORD status;
+};
+
+/*
+ * The SRVSVC already
+ */
+INTERFACE(0)
+union srvsvc_interface {
+ CASE(SRVSVC_OPNUM_NetConnectEnum)
+ struct mslm_NetConnectEnum NetConnectEnum;
+ CASE(SRVSVC_OPNUM_NetFileEnum)
+ struct mslm_NetFileEnum NetFileEnum;
+ CASE(SRVSVC_OPNUM_NetFileClose)
+ struct mslm_NetFileClose NetFileClose;
+ CASE(SRVSVC_OPNUM_NetShareGetInfo)
+ struct mlsm_NetShareGetInfo NetShareGetInfo;
+ CASE(SRVSVC_OPNUM_NetShareSetInfo)
+ struct mlsm_NetShareGetInfo NetShareSetInfo;
+ CASE(SRVSVC_OPNUM_NetSessionDel)
+ struct mslm_NetSessionDel NetSessionDel;
+ CASE(SRVSVC_OPNUM_NetSessionEnum)
+ struct mslm_NetSessionEnum NetSessionEnum;
+ CASE(SRVSVC_OPNUM_NetServerGetInfo)
+ struct mslm_NetServerGetInfo NetServerGetInfo;
+ CASE(SRVSVC_OPNUM_NetRemoteTOD)
+ struct mslm_NetRemoteTOD NetRemoteTOD;
+ CASE(SRVSVC_OPNUM_NetNameValidate)
+ struct mslm_NetNameValidate NetNameValidate;
+ CASE(SRVSVC_OPNUM_NetShareAdd)
+ struct mslm_NetShareAdd NetShareAdd;
+ CASE(SRVSVC_OPNUM_NetShareDel)
+ struct mslm_NetShareDel NetShareDel;
+ CASE(SRVSVC_OPNUM_NetShareEnum)
+ struct mslm_NetShareEnum NetShareEnum;
+ CASE(SRVSVC_OPNUM_NetShareEnumSticky)
+ struct mslm_NetShareEnumSticky NetShareEnumSticky;
+ CASE(SRVSVC_OPNUM_NetGetFileSecurity)
+ struct mslm_NetGetFileSecurity NetGetFileSecurity;
+ CASE(SRVSVC_OPNUM_NetSetFileSecurity)
+ struct mslm_NetSetFileSecurity NetSetFileSecurity;
+};
+typedef union srvsvc_interface srvsvc_interface_t;
+EXTERNTYPEINFO(srvsvc_interface)
+
+
+
+/*
+ * WKSSVC -- Workstation Service
+ ****************************************************************
+ */
+
+#define WKSSVC_OPNUM_NetWkstaGetInfo 0x00
+
+
+/*
+ * NET_API_STATUS NET_API_FUNCTION
+ * NetWkstaGetInfo (
+ * IN LPTSTR servername OPTIONAL,
+ * IN DWORD level,
+ * OUT LPBYTE *bufptr
+ * );
+ */
+
+struct mslm_WKSTA_INFO_100 {
+ DWORD wki100_platform_id;
+ LPTSTR wki100_computername;
+ LPTSTR wki100_langroup;
+ DWORD wki100_ver_major;
+ DWORD wki100_ver_minor;
+};
+
+/* NetWkstaGetInfo only. System information - user access */
+struct mslm_WKSTA_INFO_101 {
+ DWORD wki101_platform_id;
+ LPTSTR wki101_computername;
+ LPTSTR wki101_langroup;
+ DWORD wki101_ver_major;
+ DWORD wki101_ver_minor;
+ LPTSTR wki101_lanroot;
+};
+
+/* NetWkstaGetInfo only. System information - admin or operator access */
+struct mslm_WKSTA_INFO_102 {
+ DWORD wki102_platform_id;
+ LPTSTR wki102_computername;
+ LPTSTR wki102_langroup;
+ DWORD wki102_ver_major;
+ DWORD wki102_ver_minor;
+ LPTSTR wki102_lanroot;
+ DWORD wki102_logged_on_users;
+};
+
+INFO1RES_DEFINITION(mslm_NetWkstaGetInfo,
+ INFO1RES_UNION_ENTRY(mslm_WKSTA_INFO,100)
+ INFO1RES_UNION_ENTRY(mslm_WKSTA_INFO,101)
+ INFO1RES_UNION_ENTRY(mslm_WKSTA_INFO,102))
+
+INFO1RESBUF_DEFINITION(mslm_NetWkstaGetInfo,
+ INFO1RESBUF_UNION_ENTRY(mslm_WKSTA_INFO,100)
+ INFO1RESBUF_UNION_ENTRY(mslm_WKSTA_INFO,101)
+ INFO1RESBUF_UNION_ENTRY(mslm_WKSTA_INFO,102))
+
+
+OPERATION(WKSSVC_OPNUM_NetWkstaGetInfo)
+struct mslm_NetWkstaGetInfo {
+ IN LPTSTR servername;
+ IN DWORD level;
+ OUT struct mslm_NetWkstaGetInfo_result result;
+ OUT DWORD status;
+};
+
+/*
+ * The WKSSVC already
+ */
+INTERFACE(0)
+union wkssvc_interface {
+ CASE(WKSSVC_OPNUM_NetWkstaGetInfo)
+ struct mslm_NetWkstaGetInfo NetWkstaGetInfo;
+};
+typedef union wkssvc_interface wkssvc_interface_t;
+EXTERNTYPEINFO(wkssvc_interface)
+
+
+#endif /* _MLSVC_LANMAN_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/svcctl.ndl b/usr/src/uts/common/smbsrv/ndl/svcctl.ndl
new file mode 100644
index 0000000000..a2fb7f6705
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/svcctl.ndl
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_SVCCTL_NDL_
+#define _MLSVC_SVCCTL_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Service Control Services (SVCCTL) RPC interface definition.
+ * This interface provides remote access to add, remove, start and
+ * stop services.
+ */
+
+#include "ndrtypes.ndl"
+
+#define SVCCTL_OPNUM_Close 0x00
+#define SVCCTL_OPNUM_QueryServiceStatus 0x06
+#define SVCCTL_OPNUM_EnumServicesStatus 0x0E
+#define SVCCTL_OPNUM_OpenManager 0x0F
+#define SVCCTL_OPNUM_OpenService 0x10
+#define SVCCTL_OPNUM_QueryServiceConfig 0x11
+
+/*
+ * Standard opaque 20 byte RPC handle.
+ */
+
+
+struct svcctl_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+
+typedef struct svcctl_handle svcctl_handle_t;
+
+/*
+ * The svc_status (SERVICE_STATUS) structure contains information about a
+ * service. The ControlService, EnumDependentServices, EnumServicesStatus,
+ * and QueryServiceStatus functions use this structure to return information
+ * about a service. A service uses this structure in the SetServiceStatus
+ * function to report its current status to the service control manager.
+ *
+ * service_type
+ * The type of service. This member can be one of the following values.
+ *
+ * SERVICE_FILE_SYSTEM_DRIVER
+ * SERVICE_KERNEL_DRIVER
+ * SERVICE_WIN32_OWN_PROCESS
+ * SERVICE_WIN32_SHARE_PROCESS
+ *
+ * If the service type is either SERVICE_WIN32_OWN_PROCESS or
+ * SERVICE_WIN32_SHARE_PROCESS, and the service is running in
+ * the context of the LocalSystem account, the following type
+ * may also be specified to indicate that the service can
+ * interact with the desktop.
+ *
+ * SERVICE_INTERACTIVE_PROCESS
+ *
+ * cur_state
+ * The current state of the service. This member can be one of the
+ * following values.
+ *
+ * SERVICE_CONTINUE_PENDING
+ * SERVICE_PAUSE_PENDING
+ * SERVICE_PAUSED
+ * SERVICE_RUNNING
+ * SERVICE_START_PENDING
+ * SERVICE_STOP_PENDING
+ * SERVICE_STOPPED
+ *
+ * ctrl_accepted
+ * The control codes that the service will accept and process in its
+ * handler function (see Handler and HandlerEx). A user interface
+ * process can control a service by specifying a control command in
+ * the ControlService function. By default, all services accept the
+ * SERVICE_CONTROL_INTERROGATE value. The following are the control
+ * codes.
+ *
+ * SERVICE_ACCEPT_STOP
+ * SERVICE_ACCEPT_PAUSE_CONTINUE
+ * SERVICE_ACCEPT_SHUTDOWN
+ * SERVICE_ACCEPT_PARAMCHANGE
+ * SERVICE_ACCEPT_NETBINDCHANGE
+ *
+ * w32_exitcode
+ * An error code that the service uses to report an error that occurs when
+ * it is starting or stopping. To return an error code specific to the
+ * service, the service must set this value to ERROR_SERVICE_SPECIFIC_ERROR
+ * to indicate that the dwServiceSpecificExitCode member contains the error
+ * code. The service should set this value to NO_ERROR when it is running
+ * and on normal termination.
+ *
+ * svc_specified_exitcode
+ * A service-specific error code that the service returns when an error
+ * occurs while the service is starting or stopping. This value is ignored
+ * unless the w32_exitcode member is set to ERROR_SERVICE_SPECIFIC_ERROR.
+ *
+ * check_point
+ * A value that the service increments periodically to report its progress
+ * during a lengthy start, stop, pause, or continue operation. For example,
+ * the service should increment this value as it completes each step of its
+ * initialization when it is starting up. The user interface program that
+ * invoked the operation on the service uses this value to track the progress
+ * of the service during a lengthy operation. This value is not valid and
+ * should be zero when the service does not have a start, stop, pause, or
+ * continue operation pending.
+ *
+ * wait_hint
+ * An estimate of the amount of time, in milliseconds, that the service
+ * expects a pending start, stop, pause, or continue operation to take
+ * before the service makes its next call to the SetServiceStatus
+ * function with either an incremented check_point value or a change in
+ * dwCurrentState. If the amount of time specified by wait_hint passes,
+ * and check_point has not been incremented, or cur_state has not changed,
+ * the service control manager or service control program can assume that
+ * an error has occurred and the service should be stopped.
+ */
+struct svc_status {
+ DWORD service_type;
+ DWORD cur_state;
+ DWORD ctrl_accepted;
+ DWORD w32_exitcode;
+ DWORD svc_specified_exitcode;
+ DWORD check_point;
+ DWORD wait_hint;
+};
+typedef struct svc_status svc_status_t;
+
+struct svc_enum_status {
+ DWORD svc_name; /* offset within response buffer */
+ DWORD display_name; /* offset within response buffer */
+ svc_status_t svc_status;
+};
+typedef struct svc_enum_status svc_enum_status_t;
+
+struct svc_config {
+ DWORD service_type;
+ DWORD start_type;
+ DWORD error_control;
+ LPTSTR binary_pathname;
+ LPTSTR loadorder_group;
+ DWORD tag_id;
+ LPTSTR dependencies;
+ LPTSTR service_startname;
+ LPTSTR display_name;
+};
+typedef struct svc_config svc_config_t;
+
+
+/*
+ ***********************************************************************
+ * Close
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_Close)
+struct svcctl_Close {
+ IN svcctl_handle_t handle;
+ OUT svcctl_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenManager
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_OpenManager)
+struct svcctl_OpenManager {
+ IN LPTSTR machine_name;
+ IN LPTSTR database_name;
+ IN DWORD desired_access;
+ OUT svcctl_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenService
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_OpenService)
+struct svcctl_OpenService {
+ IN svcctl_handle_t manager_handle;
+ IN REFERENCE LPTSTR service_name;
+ IN DWORD desired_access;
+ OUT svcctl_handle_t service_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryServiceStatus
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_QueryServiceStatus)
+struct svcctl_QueryServiceStatus {
+ IN svcctl_handle_t service_handle;
+ OUT svc_status_t service_status;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * EnumServicesStatus
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_EnumServicesStatus)
+struct svcctl_EnumServicesStatus {
+ IN svcctl_handle_t manager_handle;
+ IN DWORD svc_type;
+ IN DWORD svc_state;
+ INOUT DWORD buf_size;
+ IN DWORD unknown;
+ OUT BYTE services[1024];
+ OUT DWORD bytes_needed;
+ OUT DWORD svc_num;
+ OUT DWORD resume_handle;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * QueryServiceConfig
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_QueryServiceConfig)
+struct svcctl_QueryServiceConfig {
+ IN svcctl_handle_t service_handle;
+ IN DWORD buf_size;
+ OUT svc_config_t service_cfg;
+ OUT DWORD cfg_bytes;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * The SVCCTL interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union svcctl_interface {
+ CASE(SVCCTL_OPNUM_Close)
+ struct svcctl_Close SvcClose;
+ CASE(SVCCTL_OPNUM_OpenManager)
+ struct svcctl_OpenManager SvcOpenManager;
+ CASE(SVCCTL_OPNUM_OpenService)
+ struct svcctl_OpenService SvcOpenService;
+ CASE(SVCCTL_OPNUM_QueryServiceStatus)
+ struct svcctl_QueryServiceStatus SvcQueryServiceStatus;
+ CASE(SVCCTL_OPNUM_EnumServicesStatus)
+ struct svcctl_EnumServicesStatus SvcEnumServicesStatus;
+ CASE(SVCCTL_OPNUM_QueryServiceConfig)
+ struct svcctl_QueryServiceConfig SvcQueryServiceConfig;
+};
+
+typedef union svcctl_interface svcctl_interface_t;
+EXTERNTYPEINFO(svcctl_interface)
+
+
+#endif /* _MLSVC_SVCCTL_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/winreg.ndl b/usr/src/uts/common/smbsrv/ndl/winreg.ndl
new file mode 100644
index 0000000000..2d3d1de28d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/winreg.ndl
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+
+#ifndef _MLSVC_WINREG_NDL_
+#define _MLSVC_WINREG_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Windows Registry (WINREG) RPC interface definition.
+ */
+
+#include "ndrtypes.ndl"
+
+#define WINREG_OPNUM_OpenHKLM 0x02
+#define WINREG_OPNUM_OpenHKUsers 0x04
+#define WINREG_OPNUM_Close 0x05
+#define WINREG_OPNUM_CreateKey 0x06
+#define WINREG_OPNUM_DeleteKey 0x07
+#define WINREG_OPNUM_DeleteValue 0x08
+#define WINREG_OPNUM_EnumKey 0x09
+#define WINREG_OPNUM_EnumValue 0x0a
+#define WINREG_OPNUM_FlushKey 0x0b
+#define WINREG_OPNUM_GetKeySec 0x0c
+#define WINREG_OPNUM_OpenKey 0x0f
+#define WINREG_OPNUM_QueryKey 0x10
+#define WINREG_OPNUM_QueryValue 0x11
+#define WINREG_OPNUM_SetKeySec 0x15
+#define WINREG_OPNUM_CreateValue 0x16
+#define WINREG_OPNUM_Shutdown 0x18
+#define WINREG_OPNUM_GetVersion 0x1a
+
+
+struct msreg_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+typedef struct msreg_handle msreg_handle_t;
+
+struct msreg_string_desc {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct msreg_string_desc msreg_string_t;
+
+/*
+ * Fake Varying/Conformant with a funny conformant.
+ */
+struct msreg_value {
+ DWORD vc_first_is; /* 0 */
+ DWORD vc_length_is;
+ SIZE_IS(vc_length_is)
+ BYTE value[ANY_SIZE_ARRAY];
+};
+
+struct file_time {
+ DWORD low;
+ DWORD high;
+};
+typedef struct file_time file_time_t;
+
+
+OPERATION(WINREG_OPNUM_OpenHKLM)
+struct msreg_OpenHKLM {
+ IN BYTE whatever[8];
+ IN DWORD access_mask;
+ OUT msreg_handle_t handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_OpenHKUsers)
+struct msreg_OpenHKUsers {
+ IN BYTE whatever[8];
+ IN DWORD access_mask;
+ OUT msreg_handle_t handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_Close)
+struct msreg_Close {
+ IN msreg_handle_t handle;
+ OUT msreg_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_CreateKey)
+struct msreg_CreateKey {
+ IN msreg_handle_t handle;
+ IN msreg_string_t subkey;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_DeleteKey)
+struct msreg_DeleteKey {
+ IN msreg_handle_t handle;
+ IN msreg_string_t subkey;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_DeleteValue)
+struct msreg_DeleteValue {
+ IN msreg_handle_t handle;
+ IN msreg_string_t name;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD status;
+};
+
+
+/*
+ * Some of the OUT parameters are also supplied
+ * as IN parameters but we can ignore them.
+ */
+OPERATION(WINREG_OPNUM_EnumValue)
+struct msreg_EnumValue {
+ IN msreg_handle_t handle;
+ IN DWORD index;
+ /* IN ignore the remaining input data */
+
+ OUT msreg_string_t name;
+ OUT DWORD *type;
+ OUT struct msreg_value *value;
+ OUT DWORD *value_size;
+ OUT DWORD *value_size_total;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_OpenKey)
+struct msreg_OpenKey {
+ IN msreg_handle_t handle;
+ IN msreg_string_t name;
+ IN DWORD unknown;
+ IN DWORD access_mask;
+ OUT msreg_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ * 000000A0 00 00 00 00 C1 F9 C0 86 18 B1 ..........
+ * 000000B0 D5 11 99 C8 00 C0 F0 1F 42 26 00 00 10 04 CC ED ........B&......
+ * 000000C0 12 00 08 02 00 00 00 00 00 00 00 00 00 00 ..............
+ DWORD unknown_0x04100000;
+ DWORD unkown_ptr;
+ DWORD unknown_0x00000208;
+ DWORD unknown2;
+ DWORD unknown3;
+ */
+
+OPERATION(WINREG_OPNUM_QueryKey)
+struct msreg_QueryKey {
+ IN msreg_handle_t handle;
+ /*
+ * Ignore the remaining input data
+ * (2 * DWORD, possibly msreg_string_t).
+ */
+
+ OUT msreg_string_t name;
+ OUT DWORD unknown;
+ OUT DWORD sub_keys;
+ OUT DWORD max_subkey_len;
+ OUT DWORD max_class_len;
+ OUT DWORD values;
+ OUT DWORD max_value_namelen;
+ OUT DWORD max_value_len;
+ OUT DWORD security_desc;
+ OUT file_time_t last_write_time;
+ OUT DWORD status;
+};
+
+
+/*
+ * Some of the OUT parameters are also supplied
+ * as IN parameters but we can ignore them.
+ */
+OPERATION(WINREG_OPNUM_QueryValue)
+struct msreg_QueryValue {
+ IN msreg_handle_t handle;
+ IN msreg_string_t value_name;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD *type;
+ OUT struct msreg_value *value;
+ OUT DWORD *value_size;
+ OUT DWORD *value_size_total;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_CreateValue)
+struct msreg_CreateValue {
+ IN msreg_handle_t handle;
+ IN msreg_string_t name;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD status;
+};
+
+
+/*
+ * The real structure of shutdown passes some strings, a timeout
+ * and reboot/shutdown flags but this allows us to accept the call,
+ * without anything appearing in the log, and return access denied.
+ */
+OPERATION(WINREG_OPNUM_Shutdown)
+struct msreg_Shutdown {
+ IN DWORD ignored;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_GetVersion)
+struct msreg_GetVersion {
+ IN msreg_handle_t handle;
+ OUT DWORD version;
+ OUT DWORD status;
+};
+
+
+/*
+ * The WINREG interface.
+ */
+INTERFACE(0)
+union winreg_interface {
+ CASE(WINREG_OPNUM_OpenHKLM)
+ struct msreg_OpenHKLM OpenHKLM;
+ CASE(WINREG_OPNUM_OpenHKUsers)
+ struct msreg_OpenHKUsers OpenHKUsers;
+ CASE(WINREG_OPNUM_Close)
+ struct msreg_Close Close;
+ CASE(WINREG_OPNUM_CreateKey)
+ struct msreg_CreateKey CreateKey;
+ CASE(WINREG_OPNUM_DeleteKey)
+ struct msreg_DeleteKey DeleteKey;
+ CASE(WINREG_OPNUM_DeleteValue)
+ struct msreg_DeleteValue DeleteValue;
+ CASE(WINREG_OPNUM_OpenKey)
+ struct msreg_OpenKey OpenKey;
+ CASE(WINREG_OPNUM_QueryKey)
+ struct msreg_QueryKey QueryKey;
+ CASE(WINREG_OPNUM_QueryValue)
+ struct msreg_QueryValue QueryValue;
+ CASE(WINREG_OPNUM_CreateValue)
+ struct msreg_CreateValue CreateValue;
+ CASE(WINREG_OPNUM_Shutdown)
+ struct msreg_Shutdown Shutdown;
+ CASE(WINREG_OPNUM_GetVersion)
+ struct msreg_GetVersion GetVersion;
+};
+typedef union winreg_interface winreg_interface_t;
+EXTERNTYPEINFO(winreg_interface)
+
+#endif /* _MLSVC_WINREG_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndr.h b/usr/src/uts/common/smbsrv/ndr.h
new file mode 100644
index 0000000000..36c502d1b9
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndr.h
@@ -0,0 +1,468 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_NDR_H
+#define _SMBSRV_NDR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Network Data Representation (NDR) is a compatible subset of DCE RPC
+ * and MSRPC NDR. NDR is used to move parameters consisting of
+ * complicated trees of data constructs between an RPC client and server.
+ *
+ * CAE Specification (1997)
+ * DCE 1.1: Remote Procedure Call
+ * Document Number: C706
+ * The Open Group
+ * ogspecs@opengroup.org
+ */
+
+#ifndef _KERNEL
+#include <syslog.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Normal sequence:
+ * - Application calls client-side stub w/ TOP-MOST arg structure
+ * - client stub performs NDR_M_OP_MARSHALL+NDR_DIR_IN
+ * - PDU conveyed (request, aka call, aka query)
+ * - server stub performs NDR_M_OP_UNMARSHALL+NDR_DIR_IN
+ * - server function called w/ TOP-MOST arg structure
+ * - server function returns w/ TOP-MOST arg structure modified
+ * - server stub performs NDR_M_OP_MARSHALL+NDR_DIR_OUT
+ * - PDU conveyed (reply, aka result, aka response)
+ * - client stub performs NDR_M_OP_UNMARSHALL+NDR_DIR_OUT
+ * - return to Application w/ TOP-MOST arg structure modified
+ *
+ * An interface is a sequence of top-most constructs. Each top-most
+ * construct corresponds to one parameter, either argument or return
+ * value.
+ *
+ * A top-most construct is a sequence of outer constructs. The first
+ * outer construct is the referent of the argument, and the subsequent
+ * outer constructs are descendents referenced by pointers from prior
+ * constructs.
+ *
+ * An outer construct is a sequence of variable-sized info, fixed-sized
+ * data, and variable-sized data.
+ */
+
+/*
+ * Terminology
+ *
+ * The ALL UPPER CASE terms recur in the DCE/RPC documentation.
+ * The mixed-case names have been introduced as a reading aid.
+ *
+ * Size The size of an array in elements. Think of this
+ * as the amount to malloc().
+ *
+ * Length The number of elements of an array which are significant
+ * Think of this as the amount to bcopy().
+ *
+ * Known Size/length is known at build time.
+ *
+ * Determined Size/length is determined at run time.
+ *
+ * FIXED The Size and Length are Known.
+ * Think of this as a string constant or a DOS 8.3 file name.
+ * char array[] = "A Constant Size/Length";
+ *
+ * CONFORMANT The Size is Determined. Length is the same as Size.
+ * Think of this as strdup().
+ * char *array = strdup("Something");
+ *
+ * VARYING The Size is Known. The Length is determined.
+ * Think of this as a strcpy() of a variable length string
+ * into a fixed length buffer:
+ * char array[100];
+ * strcpy(array, "very short string");
+ *
+ * VARYING/CONFORMANT
+ * The Size is Determined. The Length is separately Determined.
+ * Think of this like:
+ * char *array = malloc(size);
+ * strcpy(array, "short string");
+ *
+ * STRING Strings can be CONFORMANT, VARYING, or CONFORMANT/VARYING.
+ * A string is fundamentally an array with the last
+ * significant element some sort of NULL.
+ */
+
+#define NDR_F_NONE 0x0000 /* no flags */
+#define NDR_F_PARAMS_MASK 0x00FF
+#define NDR_F_SIZE_IS 0x0001 /* [size_is(X)] required/given */
+#define NDR_F_LENGTH_IS 0x0002 /* not implemented */
+#define NDR_F_SWITCH_IS 0x0004 /* [switch_is(X)] req./given */
+#define NDR_F_IS_STRING 0x0008 /* [string] req./given */
+#define NDR_F_IS_POINTER 0x0010 /* TYPE * ... req./given */
+#define NDR_F_IS_REFERENCE 0x0020 /* TYPE & ... req./given */
+#define NDR_F_DIMENSION_IS 0x0040 /* TYPE [N] req./given */
+
+#define NDR_F_WHENCE_MASK 0x00F0
+#define NDR_F_BACKPTR 0x0010 /* ref cause by pointer */
+#define NDR_F_OUTER 0x0020 /* ref caused by outer */
+#define NDR_F_TOPMOST 0x0040 /* ref caused by topmost */
+
+#define NDR_F_TYPEOP_MASK 0x0F00
+#define NDR_F_ARRAY 0x0100 /* type is array of somethings */
+#define NDR_F_POINTER 0x0200 /* type is pointer to something(s) */
+#define NDR_F_STRING 0x0300 /* type is string of somethings */
+#define NDR_F_UNION 0x0400 /* type is a union */
+#define NDR_F_STRUCT 0x0500 /* type is a structure */
+#define NDR_F_OPERATION 0x0600 /* type is a structure, special */
+#define NDR_F_INTERFACE 0x0700 /* type is a union, special */
+#define NDR_F_CONFORMANT 0x1000 /* struct conforming (var-size tail) */
+#define NDR_F_VARYING 0x2000 /* not implemented */
+
+struct mlrpc_heap;
+struct mlndr_stream;
+struct ndr_reference;
+struct ndr_typeinfo;
+
+struct ndr_typeinfo {
+ unsigned char version; /* sanity check */
+ unsigned char alignment; /* mask */
+ unsigned short type_flags; /* NDR_F_... */
+ int (*ndr_func)(struct ndr_reference *encl_ref);
+ unsigned short pdu_size_fixed_part;
+ unsigned short pdu_size_variable_part;
+ unsigned short c_size_fixed_part;
+ unsigned short c_size_variable_part;
+};
+
+struct ndr_reference {
+ struct ndr_reference *next; /* queue list (outer only) */
+ struct ndr_reference *enclosing; /* e.g. struct for this memb */
+ struct mlndr_stream *stream; /* root of NDR */
+ struct ndr_typeinfo *ti; /* type of data referenced */
+ char *name; /* name of this member */
+ unsigned long pdu_offset; /* referent in stub data */
+ char *datum; /* referent in local memory */
+ char **backptr; /* referer to set */
+ unsigned short outer_flags; /* XXX_is() from top level */
+ unsigned short inner_flags; /* XXX_is() in encapsulated */
+ unsigned short type_flags; /* "requires" */
+ unsigned short packed_alignment;
+ unsigned long size_is; /* conforming constructs */
+ unsigned long strlen_is; /* strings */
+ unsigned long switch_is; /* union arg selector */
+ unsigned long dimension_is; /* fixed-len array size */
+ unsigned long pdu_end_offset; /* offset for limit of PDU */
+};
+
+/*
+ * For all operations, the mlndr_stream, which is the root of NDR processing,
+ * is the primary object. When available, the appropriate ndr_reference
+ * is passed, NULL otherwise. Functions that return 'int' should return
+ * TRUE (!0) or FALSE (0). When functions return FALSE, including
+ * mlndo_malloc() returning NULL, they should set the stream->error to an
+ * appropriate indicator of what went wrong.
+ *
+ * Functions mlndo_get_pdu(), mlndo_put_pdu(), and mlndo_pad_pdu() must
+ * never grow the PDU data. A request for out-of-bounds data is an error.
+ * The swap_bytes flag is 1 if NDR knows that the byte-order in the PDU
+ * is different from the local system. mlndo_pad_pdu() advised that the
+ * affected bytes should be zero filled.
+ */
+struct mlndr_stream_ops {
+ char *(*mlndo_malloc)(struct mlndr_stream *, unsigned,
+ struct ndr_reference *);
+
+ int (*mlndo_free)(struct mlndr_stream *, char *,
+ struct ndr_reference *);
+
+ int (*mlndo_grow_pdu)(struct mlndr_stream *, unsigned long,
+ struct ndr_reference *);
+
+ int (*mlndo_pad_pdu)(struct mlndr_stream *, unsigned long,
+ unsigned long, struct ndr_reference *);
+
+ int (*mlndo_get_pdu)(struct mlndr_stream *, unsigned long,
+ unsigned long, char *, int, struct ndr_reference *);
+
+ int (*mlndo_put_pdu)(struct mlndr_stream *, unsigned long,
+ unsigned long, char *, int, struct ndr_reference *);
+
+ void (*mlndo_tattle)(struct mlndr_stream *, char *,
+ struct ndr_reference *);
+
+ void (*mlndo_tattle_error)(struct mlndr_stream *,
+ struct ndr_reference *);
+
+ int (*mlndo_reset)(struct mlndr_stream *);
+ void (*mlndo_destruct)(struct mlndr_stream *);
+};
+
+#define MLNDS_MALLOC(MLNDS, LEN, REF) \
+ (*(MLNDS)->mlndo->mlndo_malloc)(MLNDS, LEN, REF)
+
+#define MLNDS_GROW_PDU(MLNDS, WANT_END_OFF, REF) \
+ (*(MLNDS)->mlndo->mlndo_grow_pdu)(MLNDS, WANT_END_OFF, REF)
+#define MLNDS_PAD_PDU(MLNDS, PDU_OFFSET, N_BYTES, REF) \
+ (*(MLNDS)->mlndo->mlndo_pad_pdu)(MLNDS, PDU_OFFSET, N_BYTES, REF)
+#define MLNDS_GET_PDU(MLNDS, PDU_OFFSET, N_BYTES, BUF, SWAP, REF) \
+ (*(MLNDS)->mlndo->mlndo_get_pdu)(MLNDS, PDU_OFFSET, N_BYTES, BUF, \
+ SWAP, REF)
+#define MLNDS_PUT_PDU(MLNDS, PDU_OFFSET, N_BYTES, BUF, SWAP, REF) \
+ (*(MLNDS)->mlndo->mlndo_put_pdu)(MLNDS, PDU_OFFSET, N_BYTES, BUF, \
+ SWAP, REF)
+
+#define MLNDS_TATTLE(MLNDS, WHAT, REF) \
+ (*(MLNDS)->mlndo->mlndo_tattle)(MLNDS, WHAT, REF)
+#define MLNDS_TATTLE_ERROR(MLNDS, WHAT, REF) \
+ (*(MLNDS)->mlndo->mlndo_tattle_error)(MLNDS, REF)
+#define MLNDS_RESET(MLNDS) \
+ (*(MLNDS)->mlndo->mlndo_reset)(MLNDS)
+#define MLNDS_DESTRUCT(MLNDS) \
+ (*(MLNDS)->mlndo->mlndo_destruct)(MLNDS)
+
+struct mlndr_stream {
+ unsigned long pdu_size;
+ unsigned long pdu_size_with_rpc_hdrs;
+ unsigned long pdu_max_size;
+ unsigned long pdu_base_offset;
+ unsigned long pdu_scan_offset;
+ unsigned char *pdu_base_addr;
+ unsigned char *pdu_base_addr_with_rpc_hdrs;
+
+ struct mlndr_stream_ops *mlndo;
+
+ unsigned char m_op;
+ unsigned char dir;
+ unsigned char swap; /* native/net endian swap */
+ short error;
+ short error_ref;
+
+ struct ndr_reference *outer_queue_head;
+ struct ndr_reference **outer_queue_tailp;
+ struct ndr_reference *outer_current;
+ struct mlrpc_heap *heap;
+};
+
+
+#define NDR_M_OP_NONE 0x00
+#define NDR_M_OP_MARSHALL 0x01 /* data moving from datum to PDU */
+#define NDR_M_OP_UNMARSHALL 0x02 /* data moving from PDU to datum */
+
+#define NDR_DIR_NONE 0x00
+#define NDR_DIR_IN 0x10 /* data moving from caller to callee */
+#define NDR_DIR_OUT 0x20 /* data moving from callee to caller */
+
+#define NDR_MODE_CALL_SEND (NDR_M_OP_MARSHALL + NDR_DIR_IN)
+#define NDR_MODE_CALL_RECV (NDR_M_OP_UNMARSHALL + NDR_DIR_IN)
+#define NDR_MODE_RETURN_SEND (NDR_M_OP_MARSHALL + NDR_DIR_OUT)
+#define NDR_MODE_RETURN_RECV (NDR_M_OP_UNMARSHALL + NDR_DIR_OUT)
+
+#define NDR_MODE_TO_M_OP(MODE) ((MODE)&0x0F)
+#define NDR_MODE_TO_DIR(MODE) ((MODE)&0xF0)
+#define NDR_M_OP_AND_DIR_TO_MODE(M_OP, DIR) ((M_OP)|(DIR))
+
+#define NDR_MODE_MATCH(MLNDS, MODE) \
+ (NDR_M_OP_AND_DIR_TO_MODE((MLNDS)->m_op, (MLNDS)->dir) == (MODE))
+
+
+#define NDR_ERR_MALLOC_FAILED -1
+#define NDR_ERR_M_OP_INVALID -2
+#define NDR_ERR_UNDERFLOW -3
+#define NDR_ERR_GROW_FAILED -4 /* overflow */
+#define NDR_ERR_PAD_FAILED -5 /* couldn't possibly happen */
+#define NDR_ERR_OUTER_HEADER_BAD -6
+#define NDR_ERR_SWITCH_VALUE_ILLEGAL -7
+#define NDR_ERR_SWITCH_VALUE_INVALID -8
+#define NDR_ERR_SWITCH_VALUE_MISSING -9
+#define NDR_ERR_SIZE_IS_MISMATCH_PDU -10
+#define NDR_ERR_SIZE_IS_MISMATCH_AFTER -11
+#define NDR_ERR_SIZE_IS_UNEXPECTED -12
+#define NDR_ERR_SIZE_IS_DUPLICATED -13
+#define NDR_ERR_OUTER_PARAMS_MISMATCH -14
+#define NDR_ERR_ARRAY_VARLEN_ILLEGAL -15
+#define NDR_ERR_ARRAY_UNION_ILLEGAL -16
+#define NDR_ERR_OUTER_PARAMS_BAD -17
+#define NDR_ERR_OUTER_UNION_ILLEGAL -18
+#define NDR_ERR_TOPMOST_UNION_ILLEGAL -19
+#define NDR_ERR_TOPMOST_VARLEN_ILLEGAL -20
+#define NDR_ERR_INNER_PARAMS_BAD -21
+#define NDR_ERR_UNIMPLEMENTED -22
+#define NDR_ERR_NOT_AN_INTERFACE -23
+#define NDR_ERR_STRLEN -24
+#define NDR_ERR_STRING_SIZING -25
+#define NDR_ERR_BOUNDS_CHECK -26
+
+#define NDR_SET_ERROR(REF, ERROR) \
+ ((REF)->stream->error = (ERROR), \
+ (REF)->stream->error_ref = __LINE__, \
+ MLNDS_TATTLE_ERROR((REF)->stream, 0, REF))
+
+#define NDR_TATTLE(REF, WHAT) \
+ (*(REF)->stream->mlndo->mlndo_tattle)((REF)->stream, WHAT, REF)
+
+#define MEMBER_STR(MEMBER) #MEMBER
+
+#define NDR_DIR_IS_IN (encl_ref->stream->dir == NDR_DIR_IN)
+#define NDR_DIR_IS_OUT (encl_ref->stream->dir == NDR_DIR_OUT)
+
+#define NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ ARGFLAGS, ARGMEM, ARGVAL) { \
+ myref.pdu_offset = encl_ref->pdu_offset + (OFFSET); \
+ myref.name = MEMBER_STR(MEMBER); \
+ myref.datum = (char *)&val->MEMBER; \
+ myref.inner_flags = ARGFLAGS; \
+ myref.ti = &ndt_##TYPE; \
+ myref.ARGMEM = ARGVAL; \
+ if (!mlndr_inner(&myref)) \
+ return (0); \
+ }
+
+#define NDR_MEMBER(TYPE, MEMBER, OFFSET) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_NONE, size_is, 0)
+
+#define NDR_MEMBER_ARR_WITH_SIZE_IS(TYPE, MEMBER, OFFSET, SIZE_IS) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_SIZE_IS, size_is, SIZE_IS)
+
+#define NDR_MEMBER_ARR_WITH_DIMENSION(TYPE, MEMBER, OFFSET, SIZE_IS) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_DIMENSION_IS, dimension_is, SIZE_IS)
+
+#define NDR_MEMBER_PTR_WITH_SIZE_IS(TYPE, MEMBER, OFFSET, SIZE_IS) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_SIZE_IS+NDR_F_IS_POINTER, size_is, SIZE_IS)
+
+#define NDR_MEMBER_PTR(TYPE, MEMBER, OFFSET) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_IS_POINTER, size_is, 0)
+
+#define NDR_MEMBER_WITH_SWITCH_IS(TYPE, MEMBER, OFFSET, SWITCH_IS) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_SWITCH_IS, switch_is, SWITCH_IS)
+
+
+#define NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ ARGFLAGS, ARGMEM, ARGVAL) { \
+ myref.pdu_offset = -1; \
+ myref.name = MEMBER_STR(MEMBER); \
+ myref.datum = (char *)&val->MEMBER; \
+ myref.inner_flags = ARGFLAGS; \
+ myref.ti = &ndt_##TYPE; \
+ myref.ARGMEM = ARGVAL; \
+ if (!mlndr_topmost(&myref)) \
+ return (0); \
+ }
+
+#define NDR_TOPMOST_MEMBER(TYPE, MEMBER) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_NONE, size_is, 0)
+
+#define NDR_TOPMOST_MEMBER_ARR_WITH_SIZE_IS(TYPE, MEMBER, SIZE_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_SIZE_IS, size_is, SIZE_IS)
+
+#define NDR_TOPMOST_MEMBER_ARR_WITH_DIMENSION(TYPE, MEMBER, SIZE_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_DIMENSION_IS, dimension_is, SIZE_IS)
+
+#define NDR_TOPMOST_MEMBER_PTR_WITH_SIZE_IS(TYPE, MEMBER, SIZE_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_SIZE_IS+NDR_F_IS_POINTER, size_is, SIZE_IS)
+
+#define NDR_TOPMOST_MEMBER_PTR(TYPE, MEMBER) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_IS_POINTER, size_is, 0)
+
+#define NDR_TOPMOST_MEMBER_REF(TYPE, MEMBER) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_IS_REFERENCE, size_is, 0)
+
+#define NDR_TOPMOST_MEMBER_REF_WITH_SIZE_IS(TYPE, MEMBER, SIZE_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_SIZE_IS+NDR_F_IS_REFERENCE, size_is, SIZE_IS)
+
+#define NDR_TOPMOST_MEMBER_WITH_SWITCH_IS(TYPE, MEMBER, SWITCH_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_SWITCH_IS, switch_is, SWITCH_IS)
+
+/* this is assuming offset+0 */
+#define NDR_PARAMS_MEMBER_WITH_ARG(TYPE, MEMBER, ARGFLAGS, \
+ ARGMEM, ARGVAL) { \
+ myref.pdu_offset = encl_ref->pdu_offset; \
+ myref.name = MEMBER_STR(MEMBER); \
+ myref.datum = (char *)&val->MEMBER; \
+ myref.inner_flags = ARGFLAGS; \
+ myref.ti = &ndt_##TYPE; \
+ myref.ARGMEM = ARGVAL; \
+ if (!mlndr_params(&myref)) \
+ return (0); \
+ }
+
+#define NDR_PARAMS_MEMBER(TYPE, MEMBER) \
+ NDR_PARAMS_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_NONE, size_is, 0)
+
+#define NDR_STRING_DIM 1
+#define NDR_ANYSIZE_DIM 1
+
+int mlndo_process(struct mlndr_stream *, struct ndr_typeinfo *, char *);
+int mlndo_operation(struct mlndr_stream *, struct ndr_typeinfo *,
+ int opnum, char *);
+void mlndo_printf(struct mlndr_stream *, struct ndr_reference *,
+ const char *, ...);
+void mlndo_trace(const char *);
+void mlndo_fmt(struct mlndr_stream *, struct ndr_reference *, char *);
+
+int mlndr_params(struct ndr_reference *);
+int mlndr_topmost(struct ndr_reference *);
+int mlndr_run_outer_queue(struct mlndr_stream *);
+int mlndr_outer(struct ndr_reference *);
+int mlndr_outer_fixed(struct ndr_reference *);
+int mlndr_outer_fixed_array(struct ndr_reference *);
+int mlndr_outer_conformant_array(struct ndr_reference *);
+int mlndr_outer_conformant_construct(struct ndr_reference *);
+int mlndr_size_is(struct ndr_reference *);
+int mlndr_outer_string(struct ndr_reference *);
+int mlndr_outer_peek_sizing(struct ndr_reference *, unsigned,
+ unsigned long *);
+int mlndr_outer_poke_sizing(struct ndr_reference *, unsigned,
+ unsigned long *);
+int mlndr_outer_align(struct ndr_reference *);
+int mlndr_outer_grow(struct ndr_reference *, unsigned);
+int mlndr_inner(struct ndr_reference *);
+int mlndr_inner_pointer(struct ndr_reference *);
+int mlndr_inner_reference(struct ndr_reference *);
+int mlndr_inner_array(struct ndr_reference *);
+void mlnds_bswap(void *src, void *dst, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NDR_H */
diff --git a/usr/src/uts/common/smbsrv/netbios.h b/usr/src/uts/common/smbsrv/netbios.h
new file mode 100644
index 0000000000..3c3d616f4b
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/netbios.h
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_NETBIOS_H
+#define _SMBSRV_NETBIOS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NetBIOS over TCP/IP interface definitions. NetBIOS over TCP/IP is
+ * documented in the following RFC documents:
+ *
+ * RFC 1001: Protocol Standard for a NetBIOS Service on a TCP/UDP
+ * Transport: Concepts and Methods
+ *
+ * RFC 1002: Protocol Standard for a NetBIOS Service on a TCP/UDP
+ * Transport: Detailed Specifications
+ *
+ * These documents reference RCF883.
+ * RFC 883: Domain Names - Implementation and Specification
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * NetBIOS names in NetBIOS packets are valid domain names as defined in
+ * RFC 883. Each label is limited to 63 bytes with an overall length of
+ * 255 bytes as described in RFC 1002 section 4.1. This is known as
+ * second-level encoding. In first-level encoding the label lengths are
+ * represented as dots (.).
+ *
+ * RFC 1001 section 14.1 describes first-level encoding of the NetBIOS
+ * name (hostname) and scope. The ASCII name is padded to 15 bytes using
+ * spaces and a one byte type or suffix is written to the 16th byte.
+ * This is then encoded as a 32 byte string.
+ *
+ * NetBIOS Name: NetBIOS
+ * NetBIOS Scope: PROCOM.COM
+ * First Level: EOGFHEECEJEPFDCACACACACACACACACA.PROCOM.COM
+ * Second Level: <32>EOGFHEECEJEPFDCACACACACACACACACA<6>PROCOM<3>COM<0>
+ */
+#define NETBIOS_NAME_SZ 16
+#define NETBIOS_ENCODED_NAME_SZ 32
+#define NETBIOS_LABEL_MAX 63
+#define NETBIOS_DOMAIN_NAME_MAX 255
+#define NETBIOS_DOMAIN_NAME_BUFLEN (NETBIOS_DOMAIN_NAME_MAX + 1)
+#define NETBIOS_SESSION_REQUEST_DATA_LENGTH \
+ ((NETBIOS_ENCODED_NAME_SZ + 2) * 2)
+
+#define NETBIOS_HDR_SZ 4 /* bytes */
+/*
+ * Session Packet Types (RFC 1002 4.3.1).
+ */
+#define SESSION_MESSAGE 0x00
+#define SESSION_REQUEST 0x81
+#define POSITIVE_SESSION_RESPONSE 0x82
+#define NEGATIVE_SESSION_RESPONSE 0x83
+#define RETARGET_SESSION_RESPONSE 0x84
+#define SESSION_KEEP_ALIVE 0x85
+
+/*
+ * NEGATIVE SESSION RESPONSE packet error code values (RFC 1002 4.3.4).
+ */
+#define SESSION_NOT_LISTENING_ON_CALLED_NAME 0x80
+#define SESSION_NOT_LISTENING_FOR_CALLING_NAME 0x81
+#define SESSION_CALLED_NAME_NOT_PRESENT 0x82
+#define SESSION_INSUFFICIENT_RESOURCES 0x83
+#define SESSION_UNSPECIFIED_ERROR 0x8F
+
+/*
+ * Time conversions
+ */
+#define MILLISECONDS 1
+#define SECONDS (1000 * MILLISECONDS)
+#define MINUTES (60 * SECONDS)
+#define HOURS (60 * MINUTES)
+#define TO_SECONDS(x) ((x) / 1000)
+#define TO_MILLISECONDS(x) ((x) * 1000)
+
+/*
+ * DATAGRAM service definitions
+ */
+#define DATAGRAM_DESTINATION_NAME_NOT_PRESENT 0x82
+#define DATAGRAM_INVALID_SOURCE_NAME_FORMAT 0x83
+#define DATAGRAM_INVALID_DESTINATION_NAME_FORMAT 0x84
+
+#define NAME_SERVICE_TCP_PORT 137
+#define NAME_SERVICE_UDP_PORT 137
+#define DGM_SRVC_UDP_PORT 138
+#define SSN_SRVC_TCP_PORT 139
+#define MAX_DATAGRAM_LENGTH 576
+#define DATAGRAM_HEADER_LENGTH 14
+#define MAX_NAME_LENGTH 256
+#define BCAST_REQ_RETRY_COUNT 2
+#define UCAST_REQ_RETRY_COUNT 2
+#define BCAST_REQ_RETRY_TIMEOUT (500 * MILLISECONDS)
+#define UCAST_REQ_RETRY_TIMEOUT (500 * MILLISECONDS)
+#define CONFLICT_TIMER (1 * SECONDS)
+#define INFINITE_TTL 0
+#define DEFAULT_TTL (600 * SECONDS)
+#define SSN_RETRY_COUNT 4
+#define SSN_CLOSE_TIMEOUT (30 * SECONDS)
+/*
+ * K.L. The keep alive time out use to be default to
+ * 900 seconds. It is not long enough for some applications
+ * i.e. MS Access. Therefore, the timeout is increased to
+ * 5400 seconds.
+ */
+#define SSN_KEEP_ALIVE_TIMEOUT (90 * 60) /* seconds */
+#define FRAGMENT_TIMEOUT (2 * SECONDS)
+
+/* smb_netbios_util.c */
+extern int netbios_first_level_name_decode(char *in, char *name, char *scope);
+extern int netbios_first_level_name_encode(unsigned char *name,
+ unsigned char *scope, unsigned char *out, int max_out);
+extern int netbios_name_isvalid(char *in, char *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NETBIOS_H */
diff --git a/usr/src/uts/common/smbsrv/netrauth.h b/usr/src/uts/common/smbsrv/netrauth.h
new file mode 100644
index 0000000000..075bbba2d2
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/netrauth.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_NETRAUTH_H
+#define _SMBSRV_NETRAUTH_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * Interface definitions for the NETR remote authentication and logon
+ * services.
+ */
+
+#include <sys/types.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/mlsvc.h>
+
+#ifndef _KERNEL
+#include <syslog.h>
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * See also netlogon.ndl.
+ */
+#define NETR_WKSTA_TRUST_ACCOUNT_TYPE 0x02
+#define NETR_DOMAIN_TRUST_ACCOUNT_TYPE 0x04
+
+/*
+ * Negotiation flags for challenge/response authentication.
+ * The extra flag (0x40000000) was added in SP4.
+ */
+#define NETR_NEGOTIATE_FLAGS 0x000001FF
+#define NETR_NEGOTIATE_SP4_FLAG 0x40000000
+
+#define NETR_SESSION_KEY_SZ 8
+#define NETR_CRED_DATA_SZ 8
+#define NETR_OWF_PASSWORD_SZ 16
+
+
+/*
+ * SAM logon levels: interactive and network.
+ */
+#define NETR_INTERACTIVE_LOGON 0x01
+#define NETR_NETWORK_LOGON 0x02
+
+
+/*
+ * SAM logon validation levels.
+ */
+#define NETR_VALIDATION_LEVEL3 0x03
+
+
+/*
+ * This is a duplicate of the netr_credential
+ * from netlogon.ndl.
+ */
+typedef struct netr_cred {
+ BYTE data[NETR_CRED_DATA_SZ];
+} netr_cred_t;
+
+
+
+#define NETR_FLG_NULL 0x00000001
+#define NETR_FLG_VALID 0x00000001
+#define NETR_FLG_INIT 0x00000002
+
+
+typedef struct netr_info {
+ DWORD flags;
+ char server[MLSVC_DOMAIN_NAME_MAX * 2];
+ char hostname[MLSVC_DOMAIN_NAME_MAX * 2];
+ netr_cred_t client_challenge;
+ netr_cred_t server_challenge;
+ netr_cred_t client_credential;
+ netr_cred_t server_credential;
+ BYTE session_key[NETR_SESSION_KEY_SZ];
+ BYTE password[MLSVC_MACHINE_ACCT_PASSWD_MAX];
+ time_t timestamp;
+} netr_info_t;
+
+/*
+ * netr_client_t flags
+ *
+ * NETR_CFLG_ANON Anonymous connection
+ * NETR_CFLG_LOCAL Local user
+ * NETR_CFLG_DOMAIN Domain user
+ */
+#define NETR_CFLG_ANON 0x01
+#define NETR_CFLG_LOCAL 0x02
+#define NETR_CFLG_DOMAIN 0x04
+
+
+typedef struct netr_client {
+ uint16_t logon_level;
+ char *username;
+ char *domain;
+ char *workstation;
+ uint32_t ipaddr;
+ struct {
+ uint32_t challenge_key_len;
+ uint8_t *challenge_key_val;
+ } challenge_key;
+ struct {
+ uint32_t nt_password_len;
+ uint8_t *nt_password_val;
+ } nt_password;
+ struct {
+ uint32_t lm_password_len;
+ uint8_t *lm_password_val;
+ } lm_password;
+ uint32_t logon_id;
+ int native_os;
+ int native_lm;
+ uint32_t local_ipaddr;
+ uint16_t local_port;
+ uint32_t flags;
+} netr_client_t;
+
+
+/*
+ * NETLOGON private interface.
+ */
+int netr_gen_session_key(netr_info_t *netr_info);
+
+int netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
+ DWORD timestamp, netr_cred_t *out_cred);
+
+
+#define NETR_A2H(c) (isdigit(c)) ? ((c) - '0') : ((c) - 'A' + 10)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NETRAUTH_H */
diff --git a/usr/src/uts/common/smbsrv/nmpipes.h b/usr/src/uts/common/smbsrv/nmpipes.h
new file mode 100644
index 0000000000..f0cd81cc3a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/nmpipes.h
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_NMPIPES_H
+#define _SMBSRV_NMPIPES_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines pre-defined and system common named pipes.
+ *
+ * Named pipes are a simple IPC mechanism supported by Windows 9x, NT
+ * and 2000. The Windows named pipe implementation supports reliable
+ * one-way and two-way transport independent network messaging. The
+ * names follow the universal naming convention (UNC) defined for the
+ * Windows redirector: \\[server]\[share]\[path]name. There is a good
+ * overview of named pipes in Network Programming for Microsoft Windows
+ * Chapter 4. The redirector is described in Chapter 2. UNC names are
+ * case-insensitive.
+ *
+ * Network Programming for Microsoft Windows
+ * Anthony Jones and Jim Ohlund
+ * Microsoft Press, ISBN 0-7356-0560-2
+ *
+ * Microsoft RPC, which is derived from DCE RPC, uses SMB named pipes
+ * as its transport mechanism. In addition to the pipe used to open
+ * each connection, a named pipe also appears in the bind response as
+ * a secondary address port. Sometimes the secondary address port is
+ * the same and sometimes it is different. The following associations
+ * have been observed.
+ *
+ * LSARPC lsass
+ * NETLOGON lsass
+ * SAMR lsass
+ * SPOOLSS spoolss
+ * SRVSVC ntsvcs
+ * SVCCTL ntsvcs
+ * WINREG winreg
+ * WKSSVC ntsvcs
+ * EVENTLOG ntsvcs
+ * LLSRPC llsrpc
+ *
+ * Further information on RPC named pipes is available in the following
+ * references.
+ *
+ * RPC for NT
+ * Guy R. Eddon
+ * R&D PUblications, ISBN 0-87930-450-2
+ *
+ * Network Programming in Windows NT
+ * Alok K. Sinha
+ * Addison-Wesley, ISBN 0-201-59056-5
+ *
+ * DCE/RPC over SMB Samba and Windows NT Domain Internals
+ * Luke Kenneth Casson Leighton
+ * Macmillan Technical Publishing, ISBN 1-57870-150-3
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Well-known or pre-defined Windows named pipes. Typically used
+ * with SmbNtCreateAndX and/or SmbTransactNmPipe. When passed to
+ * SmbNtCreateAndX the \PIPE prefix is often missing. These names
+ * are presented as observed on the wire but should be treated in
+ * a case-insensitive manner.
+ */
+#define PIPE_LANMAN "\\PIPE\\LANMAN"
+#define PIPE_NETLOGON "\\PIPE\\NETLOGON"
+#define PIPE_LSARPC "\\PIPE\\lsarpc"
+#define PIPE_SAMR "\\PIPE\\samr"
+#define PIPE_SPOOLSS "\\PIPE\\spoolss"
+#define PIPE_SRVSVC "\\PIPE\\srvsvc"
+#define PIPE_SVCCTL "\\PIPE\\svcctl"
+#define PIPE_WINREG "\\PIPE\\winreg"
+#define PIPE_WKSSVC "\\PIPE\\wkssvc"
+#define PIPE_EVENTLOG "\\PIPE\\EVENTLOG"
+#define PIPE_LSASS "\\PIPE\\lsass"
+#define PIPE_NTSVCS "\\PIPE\\ntsvcs"
+#define PIPE_ATSVC "\\PIPE\\atsvc"
+#define PIPE_BROWSESS "\\PIPE\\browsess"
+#define PIPE_WINSSVC "\\PIPE\\winssvc"
+#define PIPE_WINSMGR "\\PIPE\\winsmgr"
+#define PIPE_LLSRPC "\\PIPE\\llsrpc"
+#define PIPE_REPL "\\PIPE\\repl"
+
+/*
+ * Named pipe function codes (NTDDK cifs.h).
+ */
+#define TRANS_SET_NMPIPE_STATE 0x01
+#define TRANS_RAW_READ_NMPIPE 0x11
+#define TRANS_QUERY_NMPIPE_STATE 0x21
+#define TRANS_QUERY_NMPIPE_INFO 0x22
+#define TRANS_PEEK_NMPIPE 0x23
+#define TRANS_TRANSACT_NMPIPE 0x26
+#define TRANS_RAW_WRITE_NMPIPE 0x31
+#define TRANS_READ_NMPIPE 0x36
+#define TRANS_WRITE_NMPIPE 0x37
+#define TRANS_WAIT_NMPIPE 0x53
+#define TRANS_CALL_NMPIPE 0x54
+
+/*
+ * SMB pipe handle state bits used by Query/SetNamedPipeHandleState.
+ * These numbers are the bit locations of the fields in the handle state.
+ */
+#define PIPE_COMPLETION_MODE_BITS 15
+#define PIPE_PIPE_END_BITS 14
+#define PIPE_PIPE_TYPE_BITS 10
+#define PIPE_READ_MODE_BITS 8
+#define PIPE_MAXIMUM_INSTANCES_BITS 0
+
+/*
+ * DosPeekNmPipe pipe states.
+ */
+#define PIPE_STATE_DISCONNECTED 0x0001
+#define PIPE_STATE_LISTENING 0x0002
+#define PIPE_STATE_CONNECTED 0x0003
+#define PIPE_STATE_CLOSING 0x0004
+
+/*
+ * DosCreateNPipe and DosQueryNPHState state.
+ */
+#define SMB_PIPE_READMODE_BYTE 0x0000
+#define SMB_PIPE_READMODE_MESSAGE 0x0100
+#define SMB_PIPE_TYPE_BYTE 0x0000
+#define SMB_PIPE_TYPE_MESSAGE 0x0400
+#define SMB_PIPE_END_CLIENT 0x0000
+#define SMB_PIPE_END_SERVER 0x4000
+#define SMB_PIPE_WAIT 0x0000
+#define SMB_PIPE_NOWAIT 0x8000
+#define SMB_PIPE_UNLIMITED_INSTANCES 0x00FF
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_NMPIPES_H */
diff --git a/usr/src/uts/common/smbsrv/ntaccess.h b/usr/src/uts/common/smbsrv/ntaccess.h
new file mode 100644
index 0000000000..114150baa9
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntaccess.h
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+#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.
+ *
+ * 31-28 Generic bits, interpreted per object type
+ * 27-26 Reserved, must-be-zero
+ * 25 Maximum allowed
+ * 24 System Security rights (SACL is SD)
+ * 23-16 Standard access rights, generic to all object types
+ * 15-0 Specific access rights, object specific
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------+---------------+-------------------------------+
+ * |G|G|G|G|Res'd|A| StandardRights| SpecificRights |
+ * |R|W|E|A| |S| | |
+ * +-+-------------+---------------+-------------------------------+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Specific rights for files, pipes and directories.
+ */
+#define FILE_READ_DATA (0x0001) /* file & pipe */
+#define FILE_LIST_DIRECTORY (0x0001) /* directory */
+#define FILE_WRITE_DATA (0x0002) /* file & pipe */
+#define FILE_ADD_FILE (0x0002) /* directory */
+#define FILE_APPEND_DATA (0x0004) /* file */
+#define FILE_ADD_SUBDIRECTORY (0x0004) /* directory */
+#define FILE_CREATE_PIPE_INSTANCE (0x0004) /* named pipe */
+#define FILE_READ_EA (0x0008) /* file & directory */
+#define FILE_READ_PROPERTIES (0x0008) /* pipe */
+#define FILE_WRITE_EA (0x0010) /* file & directory */
+#define FILE_WRITE_PROPERTIES (0x0010) /* pipe */
+#define FILE_EXECUTE (0x0020) /* file */
+#define FILE_TRAVERSE (0x0020) /* directory */
+#define FILE_DELETE_CHILD (0x0040) /* directory */
+#define FILE_READ_ATTRIBUTES (0x0080) /* all */
+#define FILE_WRITE_ATTRIBUTES (0x0100) /* all */
+#define FILE_SPECIFIC_ALL (0x000001FFL)
+#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL)
+
+
+/*
+ * Standard rights:
+ *
+ * DELETE The right to delete the object.
+ *
+ * READ_CONTROL The right to read the information in the object's security
+ * descriptor, not including the information in the SACL.
+ *
+ * WRITE_DAC The right to modify the DACL in the object's security
+ * descriptor.
+ *
+ * WRITE_OWNER The right to change the owner in the object's security
+ * descriptor.
+ *
+ * SYNCHRONIZE The right to use the object for synchronization. This enables
+ * a thread to wait until the object is in the signaled state.
+ */
+#define DELETE (0x00010000L)
+#define READ_CONTROL (0x00020000L)
+#define WRITE_DAC (0x00040000L)
+#define WRITE_OWNER (0x00080000L) /* take ownership */
+#define SYNCHRONIZE (0x00100000L)
+#define STANDARD_RIGHTS_REQUIRED (0x000F0000L)
+#define STANDARD_RIGHTS_ALL (0x001F0000L)
+
+
+#define STANDARD_RIGHTS_READ (READ_CONTROL)
+#define STANDARD_RIGHTS_WRITE (READ_CONTROL)
+#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL)
+
+#define FILE_METADATA_ALL (FILE_READ_EA |\
+ FILE_READ_ATTRIBUTES |\
+ READ_CONTROL |\
+ FILE_WRITE_EA |\
+ FILE_WRITE_ATTRIBUTES |\
+ WRITE_DAC |\
+ WRITE_OWNER |\
+ SYNCHRONIZE)
+
+#define FILE_DATA_ALL (FILE_READ_DATA |\
+ FILE_WRITE_DATA |\
+ FILE_APPEND_DATA |\
+ FILE_EXECUTE |\
+ DELETE)
+
+#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
+
+
+/*
+ * Miscellaneous bits: SACL access and maximum allowed access.
+ */
+#define ACCESS_SYSTEM_SECURITY (0x01000000L)
+#define MAXIMUM_ALLOWED (0x02000000L)
+
+
+/*
+ * Generic rights. These are shorthands that are interpreted as
+ * appropriate for the type of secured object being accessed.
+ */
+#define GENERIC_ALL (0x10000000UL)
+#define GENERIC_EXECUTE (0x20000000UL)
+#define GENERIC_WRITE (0x40000000UL)
+#define GENERIC_READ (0x80000000UL)
+
+#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | \
+ FILE_READ_DATA | \
+ FILE_READ_ATTRIBUTES | \
+ FILE_READ_EA | \
+ SYNCHRONIZE)
+
+#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | \
+ FILE_WRITE_DATA | \
+ FILE_WRITE_ATTRIBUTES | \
+ FILE_WRITE_EA | \
+ FILE_APPEND_DATA | \
+ SYNCHRONIZE)
+
+#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | \
+ FILE_READ_ATTRIBUTES | \
+ FILE_EXECUTE | \
+ SYNCHRONIZE)
+
+#define FILE_GENERIC_ALL (FILE_GENERIC_READ | \
+ FILE_GENERIC_WRITE | \
+ FILE_GENERIC_EXECUTE)
+
+
+/*
+ * LSA policy desired access masks.
+ */
+#define POLICY_VIEW_LOCAL_INFORMATION 0x00000001L
+#define POLICY_VIEW_AUDIT_INFORMATION 0x00000002L
+#define POLICY_GET_PRIVATE_INFORMATION 0x00000004L
+#define POLICY_TRUST_ADMIN 0x00000008L
+#define POLICY_CREATE_ACCOUNT 0x00000010L
+#define POLICY_CREATE_SECRET 0x00000020L
+#define POLICY_CREATE_PRIVILEGE 0x00000040L
+#define POLICY_SET_DEFAULT_QUOTA_LIMITS 0x00000080L
+#define POLICY_SET_AUDIT_REQUIREMENTS 0x00000100L
+#define POLICY_AUDIT_LOG_ADMIN 0x00000200L
+#define POLICY_SERVER_ADMIN 0x00000400L
+#define POLICY_LOOKUP_NAMES 0x00000800L
+
+
+/*
+ * SAM specific rights desired access masks. These definitions are listed
+ * mostly as a convenience; they don't seem to be documented. Setting the
+ * desired access mask to GENERIC_EXECUTE and STANDARD_RIGHTS_EXECUTE
+ * seems to work when just looking up information.
+ */
+#define SAM_LOOKUP_INFORMATION (GENERIC_EXECUTE \
+ | STANDARD_RIGHTS_EXECUTE)
+
+#define SAM_ACCESS_USER_READ 0x0000031BL
+#define SAM_ACCESS_USER_UPDATE 0x0000031FL
+#define SAM_ACCESS_USER_SETPWD 0x0000037FL
+#define SAM_CONNECT_CREATE_ACCOUNT 0x00000020L
+#define SAM_ENUM_LOCAL_DOMAIN 0x00000030L
+#define SAM_DOMAIN_CREATE_ACCOUNT 0x00000211L
+
+
+/*
+ * File attributes
+ *
+ * Note: 0x00000008 is reserved for use for the old DOS VOLID (volume ID)
+ * and is therefore not considered valid in NT.
+ *
+ * Note: 0x00000010 is reserved for use for the old DOS SUBDIRECTORY flag
+ * and is therefore not considered valid in NT. This flag has
+ * been disassociated with file attributes since the other flags are
+ * protected with READ_ and WRITE_ATTRIBUTES access to the file.
+ *
+ * Note: Note also that the order of these flags is set to allow both the
+ * FAT and the Pinball File Systems to directly set the attributes
+ * flags in attributes words without having to pick each flag out
+ * individually. The order of these flags should not be changed!
+ *
+ * The file attributes are defined in smbsrv/smb_vops.h
+ */
+
+/* Filesystem Attributes */
+#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
+#define FILE_CASE_PRESERVED_NAMES 0x00000002
+#define FILE_UNICODE_ON_DISK 0x00000004
+#define FILE_PERSISTENT_ACLS 0x00000008
+#define FILE_FILE_COMPRESSION 0x00000010
+#define FILE_VOLUME_QUOTAS 0x00000020
+#define FILE_SUPPORTS_SPARSE_FILES 0x00000040
+#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080
+#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100
+#define FILE_VOLUME_IS_COMPRESSED 0x00008000
+#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
+#define FILE_SUPPORTS_ENCRYPTION 0x00020000
+#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NTACCESS_H */
diff --git a/usr/src/uts/common/smbsrv/nterror.h b/usr/src/uts/common/smbsrv/nterror.h
new file mode 100644
index 0000000000..4695d4f15d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/nterror.h
@@ -0,0 +1,941 @@
+/*
+ * 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.
+ */
+
+
+#ifndef _SMBSRV_NTERROR_H
+#define _SMBSRV_NTERROR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the list of Win32 error codes. If you need an
+ * error code that is defined in the Win32 Error Codes document but
+ * is not listed here, please add it to the file. There is a list
+ * of Win32 error codes on:
+ *
+ * http://msdn.microsoft.com/library/psdk/psdkref/errlist_9usz.htm
+ *
+ * Be careful not to confuse status codes with error codes. The status
+ * codes are listed in ntstatus.h. Some mappings between NT status
+ * codes and Win32 error codes is provided in the Microsoft knowledge
+ * base article Q113996.
+ *
+ * Win32 error codes are 32-bit values with the following format
+ * (winerror.h):
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---+-+-+-----------------------+-------------------------------+
+ * |Sev|C|R| Facility | Code |
+ * +---+-+-+-----------------------+-------------------------------+
+ *
+ * Sev severity code
+ * 00 - Success
+ * 01 - Informational
+ * 10 - Warning
+ * 11 - Error
+ *
+ * C customer/client flag (set to 1 for user defined codes).
+ * R reserved (set to zero)
+ * Facility facility code
+ * Code facility's status code
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Facility codes
+ */
+#define FACILITY_NULL 0
+#define FACILITY_RPC 1
+#define FACILITY_DISPATCH 2
+#define FACILITY_STORAGE 3
+#define FACILITY_ITF 4
+/* 5 */
+/* 6 */
+#define FACILITY_WIN32 7
+#define FACILITY_WINDOWS 8
+#define FACILITY_SSPI 9
+#define FACILITY_CONTROL 10
+#define FACILITY_CERT 11
+#define FACILITY_INTERNET 12
+#define FACILITY_MEDIASERVER 13
+#define FACILITY_MSMQ 14
+#define FACILITY_SETUPAPI 15
+
+
+/*
+ * Complete list of Win32 error codes. For error description
+ * you can look at MS-KB articles 155011 and 155012
+ */
+
+#define ERROR_SUCCESS 0
+#define NO_ERROR 0
+#define ERROR_INVALID_FUNCTION 1
+#define ERROR_FILE_NOT_FOUND 2
+#define ERROR_PATH_NOT_FOUND 3
+#define ERROR_TOO_MANY_OPEN_FILES 4
+#define ERROR_ACCESS_DENIED 5
+#define ERROR_INVALID_HANDLE 6
+#define ERROR_ARENA_TRASHED 7
+#define ERROR_NOT_ENOUGH_MEMORY 8
+#define ERROR_INVALID_BLOCK 9
+#define ERROR_BAD_ENVIRONMENT 10
+#define ERROR_BAD_FORMAT 11
+#define ERROR_INVALID_ACCESS 12
+#define ERROR_INVALID_DATA 13
+#define ERROR_OUTOFMEMORY 14
+#define ERROR_INVALID_DRIVE 15
+#define ERROR_CURRENT_DIRECTORY 16
+#define ERROR_NOT_SAME_DEVICE 17
+#define ERROR_NO_MORE_FILES 18
+#define ERROR_WRITE_PROTECT 19
+#define ERROR_BAD_UNIT 20
+#define ERROR_NOT_READY 21
+#define ERROR_BAD_COMMAND 22
+#define ERROR_CRC 23
+#define ERROR_BAD_LENGTH 24
+#define ERROR_SEEK 25
+#define ERROR_NOT_DOS_DISK 26
+#define ERROR_SECTOR_NOT_FOUND 27
+#define ERROR_OUT_OF_PAPER 28
+#define ERROR_WRITE_FAULT 29
+#define ERROR_READ_FAULT 30
+#define ERROR_GEN_FAILURE 31
+#define ERROR_SHARING_VIOLATION 32
+#define ERROR_LOCK_VIOLATION 33
+#define ERROR_WRONG_DISK 34
+#define ERROR_SHARING_BUFFER_EXCEEDED 36
+#define ERROR_HANDLE_EOF 38
+#define ERROR_HANDLE_DISK_FULL 39
+#define ERROR_NOT_SUPPORTED 50
+#define ERROR_REM_NOT_LIST 51
+#define ERROR_DUP_NAME 52
+#define ERROR_BAD_NETPATH 53
+#define ERROR_NETWORK_BUSY 54
+#define ERROR_DEV_NOT_EXIST 55
+#define ERROR_TOO_MANY_CMDS 56
+#define ERROR_ADAP_HDW_ERR 57
+#define ERROR_BAD_NET_RESP 58
+#define ERROR_UNEXP_NET_ERR 59
+#define ERROR_BAD_REM_ADAP 60
+#define ERROR_PRINTQ_FULL 61
+#define ERROR_NO_SPOOL_SPACE 62
+#define ERROR_PRINT_CANCELLED 63
+#define ERROR_NETNAME_DELETED 64
+#define ERROR_NETWORK_ACCESS_DENIED 65
+#define ERROR_BAD_DEV_TYPE 66
+#define ERROR_BAD_NET_NAME 67
+#define ERROR_TOO_MANY_NAMES 68
+#define ERROR_TOO_MANY_SESS 69
+#define ERROR_SHARING_PAUSED 70
+#define ERROR_REQ_NOT_ACCEP 71
+#define ERROR_REDIR_PAUSED 72
+#define ERROR_FILE_EXISTS 80
+#define ERROR_CANNOT_MAKE 82
+#define ERROR_FAIL_I24 83
+#define ERROR_OUT_OF_STRUCTURES 84
+#define ERROR_ALREADY_ASSIGNED 85
+#define ERROR_INVALID_PASSWORD 86
+#define ERROR_INVALID_PARAMETER 87
+#define ERROR_NET_WRITE_FAULT 88
+#define ERROR_NO_PROC_SLOTS 89
+#define ERROR_TOO_MANY_SEMAPHORES 100
+#define ERROR_EXCL_SEM_ALREADY_OWNED 101
+#define ERROR_SEM_IS_SET 102
+#define ERROR_TOO_MANY_SEM_REQUESTS 103
+#define ERROR_INVALID_AT_INTERRUPT_TIME 104
+#define ERROR_SEM_OWNER_DIED 105
+#define ERROR_SEM_USER_LIMIT 106
+#define ERROR_DISK_CHANGE 107
+#define ERROR_DRIVE_LOCKED 108
+#define ERROR_BROKEN_PIPE 109
+#define ERROR_OPEN_FAILED 110
+#define ERROR_BUFFER_OVERFLOW 111
+#define ERROR_DISK_FULL 112
+#define ERROR_NO_MORE_SEARCH_HANDLES 113
+#define ERROR_INVALID_TARGET_HANDLE 114
+#define ERROR_INVALID_CATEGORY 117
+#define ERROR_INVALID_VERIFY_SWITCH 118
+#define ERROR_BAD_DRIVER_LEVEL 119
+#define ERROR_CALL_NOT_IMPLEMENTED 120
+#define ERROR_SEM_TIMEOUT 121
+#define ERROR_INSUFFICIENT_BUFFER 122
+#define ERROR_INVALID_NAME 123
+#define ERROR_INVALID_LEVEL 124
+#define ERROR_NO_VOLUME_LABEL 125
+#define ERROR_MOD_NOT_FOUND 126
+#define ERROR_PROC_NOT_FOUND 127
+#define ERROR_WAIT_NO_CHILDREN 128
+#define ERROR_CHILD_NOT_COMPLETE 129
+#define ERROR_DIRECT_ACCESS_HANDLE 130
+#define ERROR_NEGATIVE_SEEK 131
+#define ERROR_SEEK_ON_DEVICE 132
+#define ERROR_IS_JOIN_TARGET 133
+#define ERROR_IS_JOINED 134
+#define ERROR_IS_SUBSTED 135
+#define ERROR_NOT_JOINED 136
+#define ERROR_NOT_SUBSTED 137
+#define ERROR_JOIN_TO_JOIN 138
+#define ERROR_SUBST_TO_SUBST 139
+#define ERROR_JOIN_TO_SUBST 140
+#define ERROR_SUBST_TO_JOIN 141
+#define ERROR_BUSY_DRIVE 142
+#define ERROR_SAME_DRIVE 143
+#define ERROR_DIR_NOT_ROOT 144
+#define ERROR_DIR_NOT_EMPTY 145
+#define ERROR_IS_SUBST_PATH 146
+#define ERROR_IS_JOIN_PATH 147
+#define ERROR_PATH_BUSY 148
+#define ERROR_IS_SUBST_TARGET 149
+#define ERROR_SYSTEM_TRACE 150
+#define ERROR_INVALID_EVENT_COUNT 151
+#define ERROR_TOO_MANY_MUXWAITERS 152
+#define ERROR_INVALID_LIST_FORMAT 153
+#define ERROR_LABEL_TOO_LONG 154
+#define ERROR_TOO_MANY_TCBS 155
+#define ERROR_SIGNAL_REFUSED 156
+#define ERROR_DISCARDED 157
+#define ERROR_NOT_LOCKED 158
+#define ERROR_BAD_THREADID_ADDR 159
+#define ERROR_BAD_ARGUMENTS 160
+#define ERROR_BAD_PATHNAME 161
+#define ERROR_SIGNAL_PENDING 162
+#define ERROR_MAX_THRDS_REACHED 164
+#define ERROR_LOCK_FAILED 167
+#define ERROR_BUSY 170
+#define ERROR_CANCEL_VIOLATION 173
+#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174
+#define ERROR_INVALID_SEGMENT_NUMBER 180
+#define ERROR_INVALID_ORDINAL 182
+#define ERROR_ALREADY_EXISTS 183
+#define ERROR_INVALID_FLAG_NUMBER 186
+#define ERROR_SEM_NOT_FOUND 187
+#define ERROR_INVALID_STARTING_CODESEG 188
+#define ERROR_INVALID_STACKSEG 189
+#define ERROR_INVALID_MODULETYPE 190
+#define ERROR_INVALID_EXE_SIGNATURE 191
+#define ERROR_EXE_MARKED_INVALID 192
+#define ERROR_BAD_EXE_FORMAT 193
+#define ERROR_ITERATED_DATA_EXCEEDS_64k 194
+#define ERROR_INVALID_MINALLOCSIZE 195
+#define ERROR_DYNLINK_FROM_INVALID_RING 196
+#define ERROR_IOPL_NOT_ENABLED 197
+#define ERROR_INVALID_SEGDPL 198
+#define ERROR_AUTODATASEG_EXCEEDS_64k 199
+#define ERROR_RING2SEG_MUST_BE_MOVABLE 200
+#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201
+#define ERROR_INFLOOP_IN_RELOC_CHAIN 202
+#define ERROR_ENVVAR_NOT_FOUND 203
+#define ERROR_NO_SIGNAL_SENT 205
+#define ERROR_FILENAME_EXCED_RANGE 206
+#define ERROR_RING2_STACK_IN_USE 207
+#define ERROR_META_EXPANSION_TOO_LONG 208
+#define ERROR_INVALID_SIGNAL_NUMBER 209
+#define ERROR_THREAD_1_INACTIVE 210
+#define ERROR_LOCKED 212
+#define ERROR_TOO_MANY_MODULES 214
+#define ERROR_NESTING_NOT_ALLOWED 215
+#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216
+#define ERROR_BAD_PIPE 230
+#define ERROR_PIPE_BUSY 231
+#define ERROR_NO_DATA 232
+#define ERROR_PIPE_NOT_CONNECTED 233
+#define ERROR_MORE_DATA 234
+#define ERROR_VC_DISCONNECTED 240
+#define ERROR_INVALID_EA_NAME 254
+#define ERROR_EA_LIST_INCONSISTENT 255
+#define ERROR_NO_MORE_ITEMS 259
+#define ERROR_CANNOT_COPY 266
+#define ERROR_DIRECTORY 267
+#define ERROR_EAS_DIDNT_FIT 275
+#define ERROR_EA_FILE_CORRUPT 276
+#define ERROR_EA_TABLE_FULL 277
+#define ERROR_INVALID_EA_HANDLE 278
+#define ERROR_EAS_NOT_SUPPORTED 282
+#define ERROR_NOT_OWNER 288
+#define ERROR_TOO_MANY_POSTS 298
+#define ERROR_PARTIAL_COPY 299
+#define ERROR_OPLOCK_NOT_GRANTED 300
+#define ERROR_INVALID_OPLOCK_PROTOCOL 301
+#define ERROR_MR_MID_NOT_FOUND 317
+#define ERROR_INVALID_ADDRESS 487
+#define ERROR_ARITHMETIC_OVERFLOW 534
+#define ERROR_PIPE_CONNECTED 535
+#define ERROR_PIPE_LISTENING 536
+#define ERROR_EA_ACCESS_DENIED 994
+#define ERROR_OPERATION_ABORTED 995
+#define ERROR_IO_INCOMPLETE 996
+#define ERROR_IO_PENDING 997
+#define ERROR_NOACCESS 998
+#define ERROR_SWAPERROR 999
+#define ERROR_STACK_OVERFLOW 1001
+#define ERROR_INVALID_MESSAGE 1002
+#define ERROR_CAN_NOT_COMPLETE 1003
+#define ERROR_INVALID_FLAGS 1004
+#define ERROR_UNRECOGNIZED_VOLUME 1005
+#define ERROR_FILE_INVALID 1006
+#define ERROR_FULLSCREEN_MODE 1007
+#define ERROR_NO_TOKEN 1008
+#define ERROR_BADDB 1009
+#define ERROR_BADKEY 1010
+#define ERROR_CANTOPEN 1011
+#define ERROR_CANTREAD 1012
+#define ERROR_CANTWRITE 1013
+#define ERROR_REGISTRY_RECOVERED 1014
+#define ERROR_REGISTRY_CORRUPT 1015
+#define ERROR_REGISTRY_IO_FAILED 1016
+#define ERROR_NOT_REGISTRY_FILE 1017
+#define ERROR_KEY_DELETED 1018
+#define ERROR_NO_LOG_SPACE 1019
+#define ERROR_KEY_HAS_CHILDREN 1020
+#define ERROR_CHILD_MUST_BE_VOLATILE 1021
+#define ERROR_NOTIFY_ENUM_DIR 1022
+#define ERROR_DEPENDENT_SERVICES_RUNNING 1051
+#define ERROR_INVALID_SERVICE_CONTROL 1052
+#define ERROR_SERVICE_REQUEST_TIMEOUT 1053
+#define ERROR_SERVICE_NO_THREAD 1054
+#define ERROR_SERVICE_DATABASE_LOCKED 1055
+#define ERROR_SERVICE_ALREADY_RUNNING 1056
+#define ERROR_INVALID_SERVICE_ACCOUNT 1057
+#define ERROR_SERVICE_DISABLED 1058
+#define ERROR_CIRCULAR_DEPENDENCY 1059
+#define ERROR_SERVICE_DOES_NOT_EXIST 1060
+#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061
+#define ERROR_SERVICE_NOT_ACTIVE 1062
+#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063
+#define ERROR_EXCEPTION_IN_SERVICE 1064
+#define ERROR_DATABASE_DOES_NOT_EXIST 1065
+#define ERROR_SERVICE_SPECIFIC_ERROR 1066
+#define ERROR_PROCESS_ABORTED 1067
+#define ERROR_SERVICE_DEPENDENCY_FAIL 1068
+#define ERROR_SERVICE_LOGON_FAILED 1069
+#define ERROR_SERVICE_START_HANG 1070
+#define ERROR_INVALID_SERVICE_LOCK 1071
+#define ERROR_SERVICE_MARKED_FOR_DELETE 1072
+#define ERROR_SERVICE_EXISTS 1073
+#define ERROR_ALREADY_RUNNING_LKG 1074
+#define ERROR_SERVICE_DEPENDENCY_DELETED 1075
+#define ERROR_BOOT_ALREADY_ACCEPTED 1076
+#define ERROR_SERVICE_NEVER_STARTED 1077
+#define ERROR_DUPLICATE_SERVICE_NAME 1078
+#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079
+#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080
+#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081
+#define ERROR_NO_RECOVERY_PROGRAM 1082
+#define ERROR_END_OF_MEDIA 1100
+#define ERROR_FILEMARK_DETECTED 1101
+#define ERROR_BEGINNING_OF_MEDIA 1102
+#define ERROR_SETMARK_DETECTED 1103
+#define ERROR_NO_DATA_DETECTED 1104
+#define ERROR_PARTITION_FAILURE 1105
+#define ERROR_INVALID_BLOCK_LENGTH 1106
+#define ERROR_DEVICE_NOT_PARTITIONED 1107
+#define ERROR_UNABLE_TO_LOCK_MEDIA 1108
+#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109
+#define ERROR_MEDIA_CHANGED 1110
+#define ERROR_BUS_RESET 1111
+#define ERROR_NO_MEDIA_IN_DRIVE 1112
+#define ERROR_NO_UNICODE_TRANSLATION 1113
+#define ERROR_DLL_INIT_FAILED 1114
+#define ERROR_SHUTDOWN_IN_PROGRESS 1115
+#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116
+#define ERROR_IO_DEVICE 1117
+#define ERROR_SERIAL_NO_DEVICE 1118
+#define ERROR_IRQ_BUSY 1119
+#define ERROR_MORE_WRITES 1120
+#define ERROR_COUNTER_TIMEOUT 1121
+#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122
+#define ERROR_FLOPPY_WRONG_CYLINDER 1123
+#define ERROR_FLOPPY_UNKNOWN_ERROR 1124
+#define ERROR_FLOPPY_BAD_REGISTERS 1125
+#define ERROR_DISK_RECALIBRATE_FAILED 1126
+#define ERROR_DISK_OPERATION_FAILED 1127
+#define ERROR_DISK_RESET_FAILED 1128
+#define ERROR_EOM_OVERFLOW 1129
+#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130
+#define ERROR_POSSIBLE_DEADLOCK 1131
+#define ERROR_MAPPED_ALIGNMENT 1132
+#define ERROR_SET_POWER_STATE_VETOED 1140
+#define ERROR_SET_POWER_STATE_FAILED 1141
+#define ERROR_TOO_MANY_LINKS 1142
+#define ERROR_OLD_WIN_VERSION 1150
+#define ERROR_APP_WRONG_OS 1151
+#define ERROR_SINGLE_INSTANCE_APP 1152
+#define ERROR_RMODE_APP 1153
+#define ERROR_INVALID_DLL 1154
+#define ERROR_NO_ASSOCIATION 1155
+#define ERROR_DDE_FAIL 1156
+#define ERROR_DLL_NOT_FOUND 1157
+#define ERROR_NO_MORE_USER_HANDLES 1158
+#define ERROR_MESSAGE_SYNC_ONLY 1159
+#define ERROR_SOURCE_ELEMENT_EMPTY 1160
+#define ERROR_DESTINATION_ELEMENT_FULL 1161
+#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162
+#define ERROR_MAGAZINE_NOT_PRESENT 1163
+#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164
+#define ERROR_DEVICE_REQUIRES_CLEANING 1165
+#define ERROR_DEVICE_DOOR_OPEN 1166
+#define ERROR_DEVICE_NOT_CONNECTED 1167
+#define ERROR_NOT_FOUND 1168
+#define ERROR_NO_MATCH 1169
+#define ERROR_SET_NOT_FOUND 1170
+#define ERROR_POINT_NOT_FOUND 1171
+#define ERROR_NO_TRACKING_SERVICE 1172
+#define ERROR_NO_VOLUME_ID 1173
+#define ERROR_CONNECTED_OTHER_PASSWORD 2108
+#define ERROR_BAD_USERNAME 2202
+#define ERROR_NOT_CONNECTED 2250
+#define ERROR_OPEN_FILES 2401
+#define ERROR_ACTIVE_CONNECTIONS 2402
+#define ERROR_DEVICE_IN_USE 2404
+#define ERROR_BAD_DEVICE 1200
+#define ERROR_CONNECTION_UNAVAIL 1201
+#define ERROR_DEVICE_ALREADY_REMEMBERED 1202
+#define ERROR_NO_NET_OR_BAD_PATH 1203
+#define ERROR_BAD_PROVIDER 1204
+#define ERROR_CANNOT_OPEN_PROFILE 1205
+#define ERROR_BAD_PROFILE 1206
+#define ERROR_NOT_CONTAINER 1207
+#define ERROR_EXTENDED_ERROR 1208
+#define ERROR_INVALID_GROUPNAME 1209
+#define ERROR_INVALID_COMPUTERNAME 1210
+#define ERROR_INVALID_EVENTNAME 1211
+#define ERROR_INVALID_DOMAINNAME 1212
+#define ERROR_INVALID_SERVICENAME 1213
+#define ERROR_INVALID_NETNAME 1214
+#define ERROR_INVALID_SHARENAME 1215
+#define ERROR_INVALID_PASSWORDNAME 1216
+#define ERROR_INVALID_MESSAGENAME 1217
+#define ERROR_INVALID_MESSAGEDEST 1218
+#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219
+#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220
+#define ERROR_DUP_DOMAINNAME 1221
+#define ERROR_NO_NETWORK 1222
+#define ERROR_CANCELLED 1223
+#define ERROR_USER_MAPPED_FILE 1224
+#define ERROR_CONNECTION_REFUSED 1225
+#define ERROR_GRACEFUL_DISCONNECT 1226
+#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227
+#define ERROR_ADDRESS_NOT_ASSOCIATED 1228
+#define ERROR_CONNECTION_INVALID 1229
+#define ERROR_CONNECTION_ACTIVE 1230
+#define ERROR_NETWORK_UNREACHABLE 1231
+#define ERROR_HOST_UNREACHABLE 1232
+#define ERROR_PROTOCOL_UNREACHABLE 1233
+#define ERROR_PORT_UNREACHABLE 1234
+#define ERROR_REQUEST_ABORTED 1235
+#define ERROR_CONNECTION_ABORTED 1236
+#define ERROR_RETRY 1237
+#define ERROR_CONNECTION_COUNT_LIMIT 1238
+#define ERROR_LOGIN_TIME_RESTRICTION 1239
+#define ERROR_LOGIN_WKSTA_RESTRICTION 1240
+#define ERROR_INCORRECT_ADDRESS 1241
+#define ERROR_ALREADY_REGISTERED 1242
+#define ERROR_SERVICE_NOT_FOUND 1243
+#define ERROR_NOT_AUTHENTICATED 1244
+#define ERROR_NOT_LOGGED_ON 1245
+#define ERROR_CONTINUE 1246
+#define ERROR_ALREADY_INITIALIZED 1247
+#define ERROR_NO_MORE_DEVICES 1248
+#define ERROR_NO_SUCH_SITE 1249
+#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250
+#define ERROR_DS_NOT_INSTALLED 1251
+#define ERROR_NOT_ALL_ASSIGNED 1300
+#define ERROR_SOME_NOT_MAPPED 1301
+#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302
+#define ERROR_LOCAL_USER_SESSION_KEY 1303
+#define ERROR_NULL_LM_PASSWORD 1304
+#define ERROR_UNKNOWN_REVISION 1305
+#define ERROR_REVISION_MISMATCH 1306
+#define ERROR_INVALID_OWNER 1307
+#define ERROR_INVALID_PRIMARY_GROUP 1308
+#define ERROR_NO_IMPERSONATION_TOKEN 1309
+#define ERROR_CANT_DISABLE_MANDATORY 1310
+#define ERROR_NO_LOGON_SERVERS 1311
+#define ERROR_NO_SUCH_LOGON_SESSION 1312
+#define ERROR_NO_SUCH_PRIVILEGE 1313
+#define ERROR_PRIVILEGE_NOT_HELD 1314
+#define ERROR_INVALID_ACCOUNT_NAME 1315
+#define ERROR_USER_EXISTS 1316
+#define ERROR_NO_SUCH_USER 1317
+#define ERROR_GROUP_EXISTS 1318
+#define ERROR_NO_SUCH_GROUP 1319
+#define ERROR_MEMBER_IN_GROUP 1320
+#define ERROR_MEMBER_NOT_IN_GROUP 1321
+#define ERROR_LAST_ADMIN 1322
+#define ERROR_WRONG_PASSWORD 1323
+#define ERROR_ILL_FORMED_PASSWORD 1324
+#define ERROR_PASSWORD_RESTRICTION 1325
+#define ERROR_LOGON_FAILURE 1326
+#define ERROR_ACCOUNT_RESTRICTION 1327
+#define ERROR_INVALID_LOGON_HOURS 1328
+#define ERROR_INVALID_WORKSTATION 1329
+#define ERROR_PASSWORD_EXPIRED 1330
+#define ERROR_ACCOUNT_DISABLED 1331
+#define ERROR_NONE_MAPPED 1332
+#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333
+#define ERROR_LUIDS_EXHAUSTED 1334
+#define ERROR_INVALID_SUB_AUTHORITY 1335
+#define ERROR_INVALID_ACL 1336
+#define ERROR_INVALID_SID 1337
+#define ERROR_INVALID_SECURITY_DESCR 1338
+#define ERROR_BAD_INHERITANCE_ACL 1340
+#define ERROR_SERVER_DISABLED 1341
+#define ERROR_SERVER_NOT_DISABLED 1342
+#define ERROR_INVALID_ID_AUTHORITY 1343
+#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344
+#define ERROR_INVALID_GROUP_ATTRIBUTES 1345
+#define ERROR_BAD_IMPERSONATION_LEVEL 1346
+#define ERROR_CANT_OPEN_ANONYMOUS 1347
+#define ERROR_BAD_VALIDATION_CLASS 1348
+#define ERROR_BAD_TOKEN_TYPE 1349
+#define ERROR_NO_SECURITY_ON_OBJECT 1350
+#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351
+#define ERROR_INVALID_SERVER_STATE 1352
+#define ERROR_INVALID_DOMAIN_STATE 1353
+#define ERROR_INVALID_DOMAIN_ROLE 1354
+#define ERROR_NO_SUCH_DOMAIN 1355
+#define ERROR_DOMAIN_EXISTS 1356
+#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357
+#define ERROR_INTERNAL_DB_CORRUPTION 1358
+#define ERROR_INTERNAL_ERROR 1359
+#define ERROR_GENERIC_NOT_MAPPED 1360
+#define ERROR_BAD_DESCRIPTOR_FORMAT 1361
+#define ERROR_NOT_LOGON_PROCESS 1362
+#define ERROR_LOGON_SESSION_EXISTS 1363
+#define ERROR_NO_SUCH_PACKAGE 1364
+#define ERROR_BAD_LOGON_SESSION_STATE 1365
+#define ERROR_LOGON_SESSION_COLLISION 1366
+#define ERROR_INVALID_LOGON_TYPE 1367
+#define ERROR_CANNOT_IMPERSONATE 1368
+#define ERROR_RXACT_INVALID_STATE 1369
+#define ERROR_RXACT_COMMIT_FAILURE 1370
+#define ERROR_SPECIAL_ACCOUNT 1371
+#define ERROR_SPECIAL_GROUP 1372
+#define ERROR_SPECIAL_USER 1373
+#define ERROR_MEMBERS_PRIMARY_GROUP 1374
+#define ERROR_TOKEN_ALREADY_IN_USE 1375
+#define ERROR_NO_SUCH_ALIAS 1376
+#define ERROR_MEMBER_NOT_IN_ALIAS 1377
+#define ERROR_MEMBER_IN_ALIAS 1378
+#define ERROR_ALIAS_EXISTS 1379
+#define ERROR_LOGON_NOT_GRANTED 1380
+#define ERROR_TOO_MANY_SECRETS 1381
+#define ERROR_SECRET_TOO_LONG 1382
+#define ERROR_INTERNAL_DB_ERROR 1383
+#define ERROR_TOO_MANY_CONTEXT_IDS 1384
+#define ERROR_LOGON_TYPE_NOT_GRANTED 1385
+#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386
+#define ERROR_NO_SUCH_MEMBER 1387
+#define ERROR_INVALID_MEMBER 1388
+#define ERROR_TOO_MANY_SIDS 1389
+#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390
+#define ERROR_NO_INHERITANCE 1391
+#define ERROR_FILE_CORRUPT 1392
+#define ERROR_DISK_CORRUPT 1393
+#define ERROR_NO_USER_SESSION_KEY 1394
+#define ERROR_LICENSE_QUOTA_EXCEEDED 1395
+#define ERROR_INVALID_WINDOW_HANDLE 1400
+#define ERROR_INVALID_MENU_HANDLE 1401
+#define ERROR_INVALID_CURSOR_HANDLE 1402
+#define ERROR_INVALID_ACCEL_HANDLE 1403
+#define ERROR_INVALID_HOOK_HANDLE 1404
+#define ERROR_INVALID_DWP_HANDLE 1405
+#define ERROR_TLW_WITH_WSCHILD 1406
+#define ERROR_CANNOT_FIND_WND_CLASS 1407
+#define ERROR_WINDOW_OF_OTHER_THREAD 1408
+#define ERROR_HOTKEY_ALREADY_REGISTERED 1409
+#define ERROR_CLASS_ALREADY_EXISTS 1410
+#define ERROR_CLASS_DOES_NOT_EXIST 1411
+#define ERROR_CLASS_HAS_WINDOWS 1412
+#define ERROR_INVALID_INDEX 1413
+#define ERROR_INVALID_ICON_HANDLE 1414
+#define ERROR_PRIVATE_DIALOG_INDEX 1415
+#define ERROR_LISTBOX_ID_NOT_FOUND 1416
+#define ERROR_NO_WILDCARD_CHARACTERS 1417
+#define ERROR_CLIPBOARD_NOT_OPEN 1418
+#define ERROR_HOTKEY_NOT_REGISTERED 1419
+#define ERROR_WINDOW_NOT_DIALOG 1420
+#define ERROR_CONTROL_ID_NOT_FOUND 1421
+#define ERROR_INVALID_COMBOBOX_MESSAGE 1422
+#define ERROR_WINDOW_NOT_COMBOBOX 1423
+#define ERROR_INVALID_EDIT_HEIGHT 1424
+#define ERROR_DC_NOT_FOUND 1425
+#define ERROR_INVALID_HOOK_FILTER 1426
+#define ERROR_INVALID_FILTER_PROC 1427
+#define ERROR_HOOK_NEEDS_HMOD 1428
+#define ERROR_GLOBAL_ONLY_HOOK 1429
+#define ERROR_JOURNAL_HOOK_SET 1430
+#define ERROR_HOOK_NOT_INSTALLED 1431
+#define ERROR_INVALID_LB_MESSAGE 1432
+#define ERROR_SETCOUNT_ON_BAD_LB 1433
+#define ERROR_LB_WITHOUT_TABSTOPS 1434
+#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435
+#define ERROR_CHILD_WINDOW_MENU 1436
+#define ERROR_NO_SYSTEM_MENU 1437
+#define ERROR_INVALID_MSGBOX_STYLE 1438
+#define ERROR_INVALID_SPI_VALUE 1439
+#define ERROR_SCREEN_ALREADY_LOCKED 1440
+#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441
+#define ERROR_NOT_CHILD_WINDOW 1442
+#define ERROR_INVALID_GW_COMMAND 1443
+#define ERROR_INVALID_THREAD_ID 1444
+#define ERROR_NON_MDICHILD_WINDOW 1445
+#define ERROR_POPUP_ALREADY_ACTIVE 1446
+#define ERROR_NO_SCROLLBARS 1447
+#define ERROR_INVALID_SCROLLBAR_RANGE 1448
+#define ERROR_INVALID_SHOWWIN_COMMAND 1449
+#define ERROR_NO_SYSTEM_RESOURCES 1450
+#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451
+#define ERROR_PAGED_SYSTEM_RESOURCES 1452
+#define ERROR_WORKING_SET_QUOTA 1453
+#define ERROR_PAGEFILE_QUOTA 1454
+#define ERROR_COMMITMENT_LIMIT 1455
+#define ERROR_MENU_ITEM_NOT_FOUND 1456
+#define ERROR_INVALID_KEYBOARD_HANDLE 1457
+#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458
+#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459
+#define ERROR_TIMEOUT 1460
+#define ERROR_INVALID_MONITOR_HANDLE 1461
+#define ERROR_EVENTLOG_FILE_CORRUPT 1500
+#define ERROR_EVENTLOG_CANT_START 1501
+#define ERROR_LOG_FILE_FULL 1502
+#define ERROR_EVENTLOG_FILE_CHANGED 1503
+#define ERROR_INSTALL_SERVICE 1601
+#define ERROR_INSTALL_USEREXIT 1602
+#define ERROR_INSTALL_FAILURE 1603
+#define ERROR_INSTALL_SUSPEND 1604
+#define ERROR_UNKNOWN_PRODUCT 1605
+#define ERROR_UNKNOWN_FEATURE 1606
+#define ERROR_UNKNOWN_COMPONENT 1607
+#define ERROR_UNKNOWN_PROPERTY 1608
+#define ERROR_INVALID_HANDLE_STATE 1609
+#define ERROR_BAD_CONFIGURATION 1610
+#define ERROR_INDEX_ABSENT 1611
+#define ERROR_INSTALL_SOURCE_ABSENT 1612
+#define ERROR_BAD_DATABASE_VERSION 1613
+#define ERROR_PRODUCT_UNINSTALLED 1614
+#define ERROR_BAD_QUERY_SYNTAX 1615
+#define ERROR_INVALID_FIELD 1616
+#define RPC_S_INVALID_STRING_BINDING 1700
+#define RPC_S_WRONG_KIND_OF_BINDING 1701
+#define RPC_S_INVALID_BINDING 1702
+#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703
+#define RPC_S_INVALID_RPC_PROTSEQ 1704
+#define RPC_S_INVALID_STRING_UUID 1705
+#define RPC_S_INVALID_ENDPOINT_FORMAT 1706
+#define RPC_S_INVALID_NET_ADDR 1707
+#define RPC_S_NO_ENDPOINT_FOUND 1708
+#define RPC_S_INVALID_TIMEOUT 1709
+#define RPC_S_OBJECT_NOT_FOUND 1710
+#define RPC_S_ALREADY_REGISTERED 1711
+#define RPC_S_TYPE_ALREADY_REGISTERED 1712
+#define RPC_S_ALREADY_LISTENING 1713
+#define RPC_S_NO_PROTSEQS_REGISTERED 1714
+#define RPC_S_NOT_LISTENING 1715
+#define RPC_S_UNKNOWN_MGR_TYPE 1716
+#define RPC_S_UNKNOWN_IF 1717
+#define RPC_S_NO_BINDINGS 1718
+#define RPC_S_NO_PROTSEQS 1719
+#define RPC_S_CANT_CREATE_ENDPOINT 1720
+#define RPC_S_OUT_OF_RESOURCES 1721
+#define RPC_S_SERVER_UNAVAILABLE 1722
+#define RPC_S_SERVER_TOO_BUSY 1723
+#define RPC_S_INVALID_NETWORK_OPTIONS 1724
+#define RPC_S_NO_CALL_ACTIVE 1725
+#define RPC_S_CALL_FAILED 1726
+#define RPC_S_CALL_FAILED_DNE 1727
+#define RPC_S_PROTOCOL_ERROR 1728
+#define RPC_S_UNSUPPORTED_TRANS_SYN 1730
+#define RPC_S_UNSUPPORTED_TYPE 1732
+#define RPC_S_INVALID_TAG 1733
+#define RPC_S_INVALID_BOUND 1734
+#define RPC_S_NO_ENTRY_NAME 1735
+#define RPC_S_INVALID_NAME_SYNTAX 1736
+#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737
+#define RPC_S_UUID_NO_ADDRESS 1739
+#define RPC_S_DUPLICATE_ENDPOINT 1740
+#define RPC_S_UNKNOWN_AUTHN_TYPE 1741
+#define RPC_S_MAX_CALLS_TOO_SMALL 1742
+#define RPC_S_STRING_TOO_LONG 1743
+#define RPC_S_PROTSEQ_NOT_FOUND 1744
+#define RPC_S_PROCNUM_OUT_OF_RANGE 1745
+#define RPC_S_BINDING_HAS_NO_AUTH 1746
+#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747
+#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748
+#define RPC_S_INVALID_AUTH_IDENTITY 1749
+#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750
+#define EPT_S_INVALID_ENTRY 1751
+#define EPT_S_CANT_PERFORM_OP 1752
+#define EPT_S_NOT_REGISTERED 1753
+#define RPC_S_NOTHING_TO_EXPORT 1754
+#define RPC_S_INCOMPLETE_NAME 1755
+#define RPC_S_INVALID_VERS_OPTION 1756
+#define RPC_S_NO_MORE_MEMBERS 1757
+#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758
+#define RPC_S_INTERFACE_NOT_FOUND 1759
+#define RPC_S_ENTRY_ALREADY_EXISTS 1760
+#define RPC_S_ENTRY_NOT_FOUND 1761
+#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762
+#define RPC_S_INVALID_NAF_ID 1763
+#define RPC_S_CANNOT_SUPPORT 1764
+#define RPC_S_NO_CONTEXT_AVAILABLE 1765
+#define RPC_S_INTERNAL_ERROR 1766
+#define RPC_S_ZERO_DIVIDE 1767
+#define RPC_S_ADDRESS_ERROR 1768
+#define RPC_S_FP_DIV_ZERO 1769
+#define RPC_S_FP_UNDERFLOW 1770
+#define RPC_S_FP_OVERFLOW 1771
+#define RPC_X_NO_MORE_ENTRIES 1772
+#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773
+#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774
+#define RPC_X_SS_IN_NULL_CONTEXT 1775
+#define RPC_X_SS_CONTEXT_DAMAGED 1777
+#define RPC_X_SS_HANDLES_MISMATCH 1778
+#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779
+#define RPC_X_NULL_REF_POINTER 1780
+#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781
+#define RPC_X_BYTE_COUNT_TOO_SMALL 1782
+#define RPC_X_BAD_STUB_DATA 1783
+#define ERROR_INVALID_USER_BUFFER 1784
+#define ERROR_UNRECOGNIZED_MEDIA 1785
+#define ERROR_NO_TRUST_LSA_SECRET 1786
+#define ERROR_NO_TRUST_SAM_ACCOUNT 1787
+#define ERROR_TRUSTED_DOMAIN_FAILURE 1788
+#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789
+#define ERROR_TRUST_FAILURE 1790
+#define RPC_S_CALL_IN_PROGRESS 1791
+#define ERROR_NETLOGON_NOT_STARTED 1792
+#define ERROR_ACCOUNT_EXPIRED 1793
+#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794
+#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795
+#define ERROR_UNKNOWN_PORT 1796
+#define ERROR_UNKNOWN_PRINTER_DRIVER 1797
+#define ERROR_UNKNOWN_PRINTPROCESSOR 1798
+#define ERROR_INVALID_SEPARATOR_FILE 1799
+#define ERROR_INVALID_PRIORITY 1800
+#define ERROR_INVALID_PRINTER_NAME 1801
+#define ERROR_PRINTER_ALREADY_EXISTS 1802
+#define ERROR_INVALID_PRINTER_COMMAND 1803
+#define ERROR_INVALID_DATATYPE 1804
+#define ERROR_INVALID_ENVIRONMENT 1805
+#define RPC_S_NO_MORE_BINDINGS 1806
+#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807
+#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808
+#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809
+#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810
+#define ERROR_SERVER_HAS_OPEN_HANDLES 1811
+#define ERROR_RESOURCE_DATA_NOT_FOUND 1812
+#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813
+#define ERROR_RESOURCE_NAME_NOT_FOUND 1814
+#define ERROR_RESOURCE_LANG_NOT_FOUND 1815
+#define ERROR_NOT_ENOUGH_QUOTA 1816
+#define RPC_S_NO_INTERFACES 1817
+#define RPC_S_CALL_CANCELLED 1818
+#define RPC_S_BINDING_INCOMPLETE 1819
+#define RPC_S_COMM_FAILURE 1820
+#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821
+#define RPC_S_NO_PRINC_NAME 1822
+#define RPC_S_NOT_RPC_ERROR 1823
+#define RPC_S_UUID_LOCAL_ONLY 1824
+#define RPC_S_SEC_PKG_ERROR 1825
+#define RPC_S_NOT_CANCELLED 1826
+#define RPC_X_INVALID_ES_ACTION 1827
+#define RPC_X_WRONG_ES_VERSION 1828
+#define RPC_X_WRONG_STUB_VERSION 1829
+#define RPC_X_INVALID_PIPE_OBJECT 1830
+#define RPC_X_WRONG_PIPE_ORDER 1831
+#define RPC_X_WRONG_PIPE_VERSION 1832
+#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898
+#define EPT_S_CANT_CREATE 1899
+#define RPC_S_INVALID_OBJECT 1900
+#define ERROR_INVALID_TIME 1901
+#define ERROR_INVALID_FORM_NAME 1902
+#define ERROR_INVALID_FORM_SIZE 1903
+#define ERROR_ALREADY_WAITING 1904
+#define ERROR_PRINTER_DELETED 1905
+#define ERROR_INVALID_PRINTER_STATE 1906
+#define ERROR_PASSWORD_MUST_CHANGE 1907
+#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908
+#define ERROR_ACCOUNT_LOCKED_OUT 1909
+#define OR_INVALID_OXID 1910
+#define OR_INVALID_OID 1911
+#define OR_INVALID_SET 1912
+#define RPC_S_SEND_INCOMPLETE 1913
+#define RPC_S_INVALID_ASYNC_HANDLE 1914
+#define RPC_S_INVALID_ASYNC_CALL 1915
+#define RPC_X_PIPE_CLOSED 1916
+#define RPC_X_PIPE_DISCIPLINE_ERROR 1917
+#define RPC_X_PIPE_EMPTY 1918
+#define ERROR_NO_SITENAME 1919
+#define ERROR_CANT_ACCESS_FILE 1920
+#define ERROR_CANT_RESOLVE_FILENAME 1921
+#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 1922
+#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 1923
+#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 1924
+#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 1925
+#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 1926
+#define ERROR_DS_BUSY 1927
+#define ERROR_DS_UNAVAILABLE 1928
+#define ERROR_DS_NO_RIDS_ALLOCATED 1929
+#define ERROR_DS_NO_MORE_RIDS 1930
+#define ERROR_DS_INCORRECT_ROLE_OWNER 1931
+#define ERROR_DS_RIDMGR_INIT_ERROR 1932
+#define ERROR_DS_OBJ_CLASS_VIOLATION 1933
+#define ERROR_DS_CANT_ON_NON_LEAF 1934
+#define ERROR_DS_CANT_ON_RDN 1935
+#define ERROR_DS_CANT_MOD_OBJ_CLASS 1936
+#define ERROR_DS_CROSS_DOM_MOVE_ERROR 1937
+#define ERROR_DS_GC_NOT_AVAILABLE 1938
+#define ERROR_NO_BROWSER_SERVERS_FOUND 6118
+#define ERROR_INVALID_PIXEL_FORMAT 2000
+#define ERROR_BAD_DRIVER 2001
+#define ERROR_INVALID_WINDOW_STYLE 2002
+#define ERROR_METAFILE_NOT_SUPPORTED 2003
+#define ERROR_TRANSFORM_NOT_SUPPORTED 2004
+#define ERROR_CLIPPING_NOT_SUPPORTED 2005
+#define ERROR_INVALID_CMM 2300
+#define ERROR_INVALID_PROFILE 2301
+#define ERROR_TAG_NOT_FOUND 2302
+#define ERROR_TAG_NOT_PRESENT 2303
+#define ERROR_DUPLICATE_TAG 2304
+#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2305
+#define ERROR_PROFILE_NOT_FOUND 2306
+#define ERROR_INVALID_COLORSPACE 2307
+#define ERROR_ICM_NOT_ENABLED 2308
+#define ERROR_DELETING_ICM_XFORM 2309
+#define ERROR_INVALID_TRANSFORM 2310
+#define ERROR_UNKNOWN_PRINT_MONITOR 3000
+#define ERROR_PRINTER_DRIVER_IN_USE 3001
+#define ERROR_SPOOL_FILE_NOT_FOUND 3002
+#define ERROR_SPL_NO_STARTDOC 3003
+#define ERROR_SPL_NO_ADDJOB 3004
+#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005
+#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006
+#define ERROR_INVALID_PRINT_MONITOR 3007
+#define ERROR_PRINT_MONITOR_IN_USE 3008
+#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009
+#define ERROR_SUCCESS_REBOOT_REQUIRED 3010
+#define ERROR_SUCCESS_RESTART_REQUIRED 3011
+#define ERROR_WINS_INTERNAL 4000
+#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001
+#define ERROR_STATIC_INIT 4002
+#define ERROR_INC_BACKUP 4003
+#define ERROR_FULL_BACKUP 4004
+#define ERROR_REC_NON_EXISTENT 4005
+#define ERROR_RPL_NOT_ALLOWED 4006
+#define ERROR_DHCP_ADDRESS_CONFLICT 4100
+#define ERROR_WMI_GUID_NOT_FOUND 4200
+#define ERROR_WMI_INSTANCE_NOT_FOUND 4201
+#define ERROR_WMI_ITEMID_NOT_FOUND 4202
+#define ERROR_WMI_TRY_AGAIN 4203
+#define ERROR_WMI_DP_NOT_FOUND 4204
+#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205
+#define ERROR_WMI_ALREADY_ENABLED 4206
+#define ERROR_WMI_GUID_DISCONNECTED 4207
+#define ERROR_WMI_SERVER_UNAVAILABLE 4208
+#define ERROR_WMI_DP_FAILED 4209
+#define ERROR_WMI_INVALID_MOF 4210
+#define ERROR_WMI_INVALID_REGINFO 4211
+#define ERROR_INVALID_MEDIA 4300
+#define ERROR_INVALID_LIBRARY 4301
+#define ERROR_INVALID_MEDIA_POOL 4302
+#define ERROR_DRIVE_MEDIA_MISMATCH 4303
+#define ERROR_MEDIA_OFFLINE 4304
+#define ERROR_LIBRARY_OFFLINE 4305
+#define ERROR_EMPTY 4306
+#define ERROR_NOT_EMPTY 4307
+#define ERROR_MEDIA_UNAVAILABLE 4308
+#define ERROR_RESOURCE_DISABLED 4309
+#define ERROR_INVALID_CLEANER 4310
+#define ERROR_UNABLE_TO_CLEAN 4311
+#define ERROR_OBJECT_NOT_FOUND 4312
+#define ERROR_DATABASE_FAILURE 4313
+#define ERROR_DATABASE_FULL 4314
+#define ERROR_MEDIA_INCOMPATIBLE 4315
+#define ERROR_RESOURCE_NOT_PRESENT 4316
+#define ERROR_INVALID_OPERATION 4317
+#define ERROR_MEDIA_NOT_AVAILABLE 4318
+#define ERROR_DEVICE_NOT_AVAILABLE 4319
+#define ERROR_REQUEST_REFUSED 4320
+#define ERROR_FILE_OFFLINE 4350
+#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351
+#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352
+#define ERROR_NOT_A_REPARSE_POINT 4390
+#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391
+#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001
+#define ERROR_DEPENDENCY_NOT_FOUND 5002
+#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003
+#define ERROR_RESOURCE_NOT_ONLINE 5004
+#define ERROR_HOST_NODE_NOT_AVAILABLE 5005
+#define ERROR_RESOURCE_NOT_AVAILABLE 5006
+#define ERROR_RESOURCE_NOT_FOUND 5007
+#define ERROR_SHUTDOWN_CLUSTER 5008
+#define ERROR_CANT_EVICT_ACTIVE_NODE 5009
+#define ERROR_OBJECT_ALREADY_EXISTS 5010
+#define ERROR_OBJECT_IN_LIST 5011
+#define ERROR_GROUP_NOT_AVAILABLE 5012
+#define ERROR_GROUP_NOT_FOUND 5013
+#define ERROR_GROUP_NOT_ONLINE 5014
+#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015
+#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016
+#define ERROR_RESMON_CREATE_FAILED 5017
+#define ERROR_RESMON_ONLINE_FAILED 5018
+#define ERROR_RESOURCE_ONLINE 5019
+#define ERROR_QUORUM_RESOURCE 5020
+#define ERROR_NOT_QUORUM_CAPABLE 5021
+#define ERROR_CLUSTER_SHUTTING_DOWN 5022
+#define ERROR_INVALID_STATE 5023
+#define ERROR_RESOURCE_PROPERTIES_STORED 5024
+#define ERROR_NOT_QUORUM_CLASS 5025
+#define ERROR_CORE_RESOURCE 5026
+#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027
+#define ERROR_QUORUMLOG_OPEN_FAILED 5028
+#define ERROR_CLUSTERLOG_CORRUPT 5029
+#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030
+#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031
+#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032
+#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033
+#define ERROR_ENCRYPTION_FAILED 6000
+#define ERROR_DECRYPTION_FAILED 6001
+#define ERROR_FILE_ENCRYPTED 6002
+#define ERROR_NO_RECOVERY_POLICY 6003
+#define ERROR_NO_EFS 6004
+#define ERROR_WRONG_EFS 6005
+#define ERROR_NO_USER_KEYS 6006
+#define ERROR_FILE_NOT_ENCRYPTED 6007
+#define ERROR_NOT_EXPORT_FORMAT 6008
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_NTERROR_H */
diff --git a/usr/src/uts/common/smbsrv/ntifs.h b/usr/src/uts/common/smbsrv/ntifs.h
new file mode 100644
index 0000000000..c538e4139e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntifs.h
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_NTIFS_H
+#define _SMBSRV_NTIFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides definitions compatible with the NT Installable
+ * File System (IFS) interface.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * File creation flags must start at the high end since they
+ * are combined with the attributes
+ */
+
+#define FILE_FLAG_WRITE_THROUGH 0x80000000
+#define FILE_FLAG_OVERLAPPED 0x40000000
+#define FILE_FLAG_NO_BUFFERING 0x20000000
+#define FILE_FLAG_RANDOM_ACCESS 0x10000000
+#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
+#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
+#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
+#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
+#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
+#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
+
+/*
+ * The create/open option flags: used in NtCreateAndx and NtTransactCreate
+ * SMB requests.
+ *
+ * The CreateOptions specify the options to be applied when creating or
+ * opening the file, as a compatible combination of the following flags:
+ *
+ * FILE_DIRECTORY_FILE
+ * The file being created or opened is a directory file. With this
+ * flag, the Disposition parameter must be set to one of FILE_CREATE,
+ * FILE_OPEN, or FILE_OPEN_IF. With this flag, other compatible
+ * CreateOptions flags include only the following:
+ * FILE_SYNCHRONOUS_IO_ALERT
+ * FILE_SYNCHRONOUS_IO_NONALERT
+ * FILE_WRITE_THROUGH
+ * FILE_OPEN_FOR_BACKUP_INTENT
+ * FILE_OPEN_BY_FILE_ID
+ *
+ * FILE_NON_DIRECTORY_FILE
+ * The file being opened must not be a directory file or this call
+ * will fail. The file object being opened can represent a data file,
+ * a logical, virtual, or physical device, or a volume.
+ *
+ * FILE_WRITE_THROUGH
+ * System services, FSDs, and drivers that write data to the file must
+ * actually transfer the data into the file before any requested write
+ * operation is considered complete. This flag is automatically set if
+ * the CreateOptions flag FILE_NO_INTERMEDIATE _BUFFERING is set.
+ *
+ * FILE_SEQUENTIAL_ONLY
+ * All accesses to the file will be sequential.
+ *
+ * FILE_RANDOM_ACCESS
+ * Accesses to the file can be random, so no sequential read-ahead
+ * operations should be performed on the file by FSDs or the system.
+ * FILE_NO_INTERMEDIATE _BUFFERING The file cannot be cached or
+ * buffered in a driver's internal buffers. This flag is incompatible
+ * with the DesiredAccess FILE_APPEND_DATA flag.
+ *
+ * FILE_SYNCHRONOUS_IO_ALERT
+ * All operations on the file are performed synchronously. Any wait
+ * on behalf of the caller is subject to premature termination from
+ * alerts. This flag also causes the I/O system to maintain the file
+ * position context. If this flag is set, the DesiredAccess
+ * SYNCHRONIZE flag also must be set.
+ *
+ * FILE_SYNCHRONOUS_IO _NONALERT
+ * All operations on the file are performed synchronously. Waits in
+ * the system to synchronize I/O queuing and completion are not subject
+ * to alerts. This flag also causes the I/O system to maintain the file
+ * position context. If this flag is set, the DesiredAccess SYNCHRONIZE
+ * flag also must be set.
+ *
+ * FILE_CREATE_TREE _CONNECTION
+ * Create a tree connection for this file in order to open it over the
+ * network. This flag is irrelevant to device and intermediate drivers.
+ *
+ * FILE_COMPLETE_IF_OPLOCKED
+ * Complete this operation immediately with an alternate success code
+ * if the target file is oplocked, rather than blocking the caller's
+ * thread. If the file is oplocked, another caller already has access
+ * to the file over the network. This flag is irrelevant to device and
+ * intermediate drivers.
+ *
+ * FILE_NO_EA_KNOWLEDGE
+ * If the extended attributes on an existing file being opened indicate
+ * that the caller must understand EAs to properly interpret the file,
+ * fail this request because the caller does not understand how to deal
+ * with EAs. Device and intermediate drivers can ignore this flag.
+ *
+ * FILE_DELETE_ON_CLOSE
+ * Delete the file when the last reference to it is passed to close.
+ *
+ * FILE_OPEN_BY_FILE_ID
+ * The file name contains the name of a device and a 64-bit ID to
+ * be used to open the file. This flag is irrelevant to device and
+ * intermediate drivers.
+ *
+ * FILE_OPEN_FOR_BACKUP _INTENT
+ * The file is being opened for backup intent, hence, the system should
+ * check for certain access rights and grant the caller the appropriate
+ * accesses to the file before checking the input DesiredAccess against
+ * the file's security descriptor. This flag is irrelevant to device
+ * and intermediate drivers.
+ */
+#define FILE_DIRECTORY_FILE 0x00000001
+#define FILE_WRITE_THROUGH 0x00000002
+#define FILE_SEQUENTIAL_ONLY 0x00000004
+#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008
+
+#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+#define FILE_NON_DIRECTORY_FILE 0x00000040
+#define FILE_CREATE_TREE_CONNECTION 0x00000080
+
+#define FILE_COMPLETE_IF_OPLOCKED 0x00000100
+#define FILE_NO_EA_KNOWLEDGE 0x00000200
+/* UNUSED 0x00000400 */
+#define FILE_RANDOM_ACCESS 0x00000800
+
+#define FILE_DELETE_ON_CLOSE 0x00001000
+#define FILE_OPEN_BY_FILE_ID 0x00002000
+#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
+#define FILE_NO_COMPRESSION 0x00008000
+
+#define FILE_RESERVE_OPFILTER 0x00100000
+#define FILE_RESERVED0 0x00200000
+#define FILE_RESERVED1 0x00400000
+#define FILE_RESERVED2 0x00800000
+
+#define FILE_VALID_OPTION_FLAGS 0x007fffff
+#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032
+#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032
+#define FILE_VALID_SET_FLAGS 0x00000036
+
+/*
+ * Define the file information class values used by the NT DDK and HAL.
+ */
+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 */
+ FileCompletionInformation, /* 30 */
+ FileMoveClusterInformation, /* 31 */
+ FileInformationReserved32, /* 32 */
+ FileInformationReserved33, /* 33 */
+ FileNetworkOpenInformation, /* 34 */
+ FileMaximumInformation
+} FILE_INFORMATION_CLASS;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NTIFS_H */
diff --git a/usr/src/uts/common/smbsrv/ntlocale.h b/usr/src/uts/common/smbsrv/ntlocale.h
new file mode 100644
index 0000000000..778d6fe68e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntlocale.h
@@ -0,0 +1,330 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_NTLOCALE_H
+#define _SMBSRV_NTLOCALE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT language and locale identifiers.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Language IDs.
+ *
+ * A language ID is a 16 bit value which is the combination of a
+ * primary language ID and a secondary language ID. The bits are
+ * allocated as follows:
+ *
+ * +-----------------------+-------------------------+
+ * | Sublanguage ID | Primary Language ID |
+ * +-----------------------+-------------------------+
+ * 15 10 9 0 bit
+ *
+ * The following two combinations of primary language ID and sub-
+ * language ID have special semantics:
+ *
+ * Primary Language ID Sublanguage ID Result
+ * ------------------- --------------- ------------------------
+ * LANG_NEUTRAL SUBLANG_NEUTRAL Language neutral
+ * LANG_NEUTRAL SUBLANG_DEFAULT User default language
+ * LANG_NEUTRAL SUBLANG_SYS_DEFAULT System default language
+ *
+ * Language ID creation/extraction macros:
+ * MAKELANGID - construct language id from a primary language
+ * id and a sublanguage id.
+ * PRIMARYLANGID - extract primary language id from a language id.
+ * SUBLANGID - extract sublanguage id from a language id.
+ */
+#define MAKELANGID(p, s) ((((WORD)(s)) << 10) | (WORD)(p))
+#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff)
+#define SUBLANGID(lgid) ((WORD)(lgid) >> 10)
+
+
+/*
+ * Primary language IDs.
+ */
+#define LANG_NEUTRAL 0x00
+
+#define LANG_AFRIKAANS 0x36
+#define LANG_ALBANIAN 0x1c
+#define LANG_ARABIC 0x01
+#define LANG_ARMENIAN 0x2b
+#define LANG_ASSAMESE 0x4d
+#define LANG_AZERI 0x2c
+#define LANG_BASQUE 0x2d
+#define LANG_BELARUSIAN 0x23
+#define LANG_BENGALI 0x45
+#define LANG_BULGARIAN 0x02
+#define LANG_CATALAN 0x03
+#define LANG_CHINESE 0x04
+#define LANG_CROATIAN 0x1a
+#define LANG_CZECH 0x05
+#define LANG_DANISH 0x06
+#define LANG_DUTCH 0x13
+#define LANG_ENGLISH 0x09
+#define LANG_ESTONIAN 0x25
+#define LANG_FAEROESE 0x38
+#define LANG_FARSI 0x29
+#define LANG_FINNISH 0x0b
+#define LANG_FRENCH 0x0c
+#define LANG_GEORGIAN 0x37
+#define LANG_GERMAN 0x07
+#define LANG_GREEK 0x08
+#define LANG_GUJARATI 0x47
+#define LANG_HEBREW 0x0d
+#define LANG_HINDI 0x39
+#define LANG_HUNGARIAN 0x0e
+#define LANG_ICELANDIC 0x0f
+#define LANG_INDONESIAN 0x21
+#define LANG_ITALIAN 0x10
+#define LANG_JAPANESE 0x11
+#define LANG_KANNADA 0x4b
+#define LANG_KASHMIRI 0x60
+#define LANG_KAZAK 0x3f
+#define LANG_KONKANI 0x57
+#define LANG_KOREAN 0x12
+#define LANG_LATVIAN 0x26
+#define LANG_LITHUANIAN 0x27
+#define LANG_MACEDONIAN 0x2f
+#define LANG_MALAY 0x3e
+#define LANG_MALAYALAM 0x4c
+#define LANG_MANIPURI 0x58
+#define LANG_MARATHI 0x4e
+#define LANG_NEPALI 0x61
+#define LANG_NORWEGIAN 0x14
+#define LANG_ORIYA 0x48
+#define LANG_POLISH 0x15
+#define LANG_PORTUGUESE 0x16
+#define LANG_PUNJABI 0x46
+#define LANG_ROMANIAN 0x18
+#define LANG_RUSSIAN 0x19
+#define LANG_SANSKRIT 0x4f
+#define LANG_SERBIAN 0x1a
+#define LANG_SINDHI 0x59
+#define LANG_SLOVAK 0x1b
+#define LANG_SLOVENIAN 0x24
+#define LANG_SPANISH 0x0a
+#define LANG_SWAHILI 0x41
+#define LANG_SWEDISH 0x1d
+#define LANG_TAMIL 0x49
+#define LANG_TATAR 0x44
+#define LANG_TELUGU 0x4a
+#define LANG_THAI 0x1e
+#define LANG_TURKISH 0x1f
+#define LANG_UKRAINIAN 0x22
+#define LANG_URDU 0x20
+#define LANG_UZBEK 0x43
+#define LANG_VIETNAMESE 0x2a
+
+
+/*
+ * Sublanguage IDs.
+ *
+ * The name immediately following SUBLANG_ dictates which primary
+ * language ID can be combined with the sub-language ID to form a
+ * valid language ID.
+ */
+#define SUBLANG_NEUTRAL 0x00 /* language neutral */
+#define SUBLANG_DEFAULT 0x01 /* user default */
+#define SUBLANG_SYS_DEFAULT 0x02 /* system default */
+
+#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 /* Arabic (Saudi Arabia) */
+#define SUBLANG_ARABIC_IRAQ 0x02 /* Arabic (Iraq) */
+#define SUBLANG_ARABIC_EGYPT 0x03 /* Arabic (Egypt) */
+#define SUBLANG_ARABIC_LIBYA 0x04 /* Arabic (Libya) */
+#define SUBLANG_ARABIC_ALGERIA 0x05 /* Arabic (Algeria) */
+#define SUBLANG_ARABIC_MOROCCO 0x06 /* Arabic (Morocco) */
+#define SUBLANG_ARABIC_TUNISIA 0x07 /* Arabic (Tunisia) */
+#define SUBLANG_ARABIC_OMAN 0x08 /* Arabic (Oman) */
+#define SUBLANG_ARABIC_YEMEN 0x09 /* Arabic (Yemen) */
+#define SUBLANG_ARABIC_SYRIA 0x0a /* Arabic (Syria) */
+#define SUBLANG_ARABIC_JORDAN 0x0b /* Arabic (Jordan) */
+#define SUBLANG_ARABIC_LEBANON 0x0c /* Arabic (Lebanon) */
+#define SUBLANG_ARABIC_KUWAIT 0x0d /* Arabic (Kuwait) */
+#define SUBLANG_ARABIC_UAE 0x0e /* Arabic (U.A.E) */
+#define SUBLANG_ARABIC_BAHRAIN 0x0f /* Arabic (Bahrain) */
+#define SUBLANG_ARABIC_QATAR 0x10 /* Arabic (Qatar) */
+#define SUBLANG_AZERI_LATIN 0x01 /* Azeri (Latin) */
+#define SUBLANG_AZERI_CYRILLIC 0x02 /* Azeri (Cyrillic) */
+#define SUBLANG_CHINESE_TRADITIONAL 0x01 /* Chinese (Taiwan Region) */
+#define SUBLANG_CHINESE_SIMPLIFIED 0x02 /* Chinese (PR China) */
+#define SUBLANG_CHINESE_HONGKONG 0x03 /* Chinese (Hong Kong) */
+#define SUBLANG_CHINESE_SINGAPORE 0x04 /* Chinese (Singapore) */
+#define SUBLANG_CHINESE_MACAU 0x05 /* Chinese (Macau) */
+#define SUBLANG_DUTCH 0x01 /* Dutch */
+#define SUBLANG_DUTCH_BELGIAN 0x02 /* Dutch (Belgian) */
+#define SUBLANG_ENGLISH_US 0x01 /* English (USA) */
+#define SUBLANG_ENGLISH_UK 0x02 /* English (UK) */
+#define SUBLANG_ENGLISH_AUS 0x03 /* English (Australian) */
+#define SUBLANG_ENGLISH_CAN 0x04 /* English (Canadian) */
+#define SUBLANG_ENGLISH_NZ 0x05 /* English (New Zealand) */
+#define SUBLANG_ENGLISH_EIRE 0x06 /* English (Irish) */
+#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 /* English (South Africa) */
+#define SUBLANG_ENGLISH_JAMAICA 0x08 /* English (Jamaica) */
+#define SUBLANG_ENGLISH_CARIBBEAN 0x09 /* English (Caribbean) */
+#define SUBLANG_ENGLISH_BELIZE 0x0a /* English (Belize) */
+#define SUBLANG_ENGLISH_TRINIDAD 0x0b /* English (Trinidad) */
+#define SUBLANG_ENGLISH_ZIMBABWE 0x0c /* English (Zimbabwe) */
+#define SUBLANG_ENGLISH_PHILIPPINES 0x0d /* English (Philippines) */
+#define SUBLANG_FRENCH 0x01 /* French */
+#define SUBLANG_FRENCH_BELGIAN 0x02 /* French (Belgian) */
+#define SUBLANG_FRENCH_CANADIAN 0x03 /* French (Canadian) */
+#define SUBLANG_FRENCH_SWISS 0x04 /* French (Swiss) */
+#define SUBLANG_FRENCH_LUXEMBOURG 0x05 /* French (Luxembourg) */
+#define SUBLANG_FRENCH_MONACO 0x06 /* French (Monaco) */
+#define SUBLANG_GERMAN 0x01 /* German */
+#define SUBLANG_GERMAN_SWISS 0x02 /* German (Swiss) */
+#define SUBLANG_GERMAN_AUSTRIAN 0x03 /* German (Austrian) */
+#define SUBLANG_GERMAN_LUXEMBOURG 0x04 /* German (Luxembourg) */
+#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 /* German (Liechtenstein) */
+#define SUBLANG_ITALIAN 0x01 /* Italian */
+#define SUBLANG_ITALIAN_SWISS 0x02 /* Italian (Swiss) */
+#define SUBLANG_KASHMIRI_INDIA 0x02 /* Kashmiri (India) */
+#define SUBLANG_KOREAN 0x01 /* Korean (Extended Wansung) */
+#define SUBLANG_LITHUANIAN 0x01 /* Lithuanian */
+#define SUBLANG_LITHUANIAN_CLASSIC 0x02 /* Lithuanian (Classic) */
+#define SUBLANG_MALAY_MALAYSIA 0x01 /* Malay (Malaysia) */
+#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 /* Malay (Brunei Darussalam) */
+#define SUBLANG_NEPALI_INDIA 0x02 /* Nepali (India) */
+#define SUBLANG_NORWEGIAN_BOKMAL 0x01 /* Norwegian (Bokmal) */
+#define SUBLANG_NORWEGIAN_NYNORSK 0x02 /* Norwegian (Nynorsk) */
+#define SUBLANG_PORTUGUESE 0x02 /* Portuguese */
+#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 /* Portuguese (Brazilian) */
+#define SUBLANG_SERBIAN_LATIN 0x02 /* Serbian (Latin) */
+#define SUBLANG_SERBIAN_CYRILLIC 0x03 /* Serbian (Cyrillic) */
+#define SUBLANG_SPANISH 0x01 /* Spanish (Castilian) */
+#define SUBLANG_SPANISH_MEXICAN 0x02 /* Spanish (Mexican) */
+#define SUBLANG_SPANISH_MODERN 0x03 /* Spanish (Modern) */
+#define SUBLANG_SPANISH_GUATEMALA 0x04 /* Spanish (Guatemala) */
+#define SUBLANG_SPANISH_COSTA_RICA 0x05 /* Spanish (Costa Rica) */
+#define SUBLANG_SPANISH_PANAMA 0x06 /* Spanish (Panama) */
+#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 /* Spanish (Dom. Republic) */
+#define SUBLANG_SPANISH_VENEZUELA 0x08 /* Spanish (Venezuela) */
+#define SUBLANG_SPANISH_COLOMBIA 0x09 /* Spanish (Colombia) */
+#define SUBLANG_SPANISH_PERU 0x0a /* Spanish (Peru) */
+#define SUBLANG_SPANISH_ARGENTINA 0x0b /* Spanish (Argentina) */
+#define SUBLANG_SPANISH_ECUADOR 0x0c /* Spanish (Ecuador) */
+#define SUBLANG_SPANISH_CHILE 0x0d /* Spanish (Chile) */
+#define SUBLANG_SPANISH_URUGUAY 0x0e /* Spanish (Uruguay) */
+#define SUBLANG_SPANISH_PARAGUAY 0x0f /* Spanish (Paraguay) */
+#define SUBLANG_SPANISH_BOLIVIA 0x10 /* Spanish (Bolivia) */
+#define SUBLANG_SPANISH_EL_SALVADOR 0x11 /* Spanish (El Salvador) */
+#define SUBLANG_SPANISH_HONDURAS 0x12 /* Spanish (Honduras) */
+#define SUBLANG_SPANISH_NICARAGUA 0x13 /* Spanish (Nicaragua) */
+#define SUBLANG_SPANISH_PUERTO_RICO 0x14 /* Spanish (Puerto Rico) */
+#define SUBLANG_SWEDISH 0x01 /* Swedish */
+#define SUBLANG_SWEDISH_FINLAND 0x02 /* Swedish (Finland) */
+#define SUBLANG_URDU_PAKISTAN 0x01 /* Urdu (Pakistan) */
+#define SUBLANG_URDU_INDIA 0x02 /* Urdu (India) */
+#define SUBLANG_UZBEK_LATIN 0x01 /* Uzbek (Latin) */
+#define SUBLANG_UZBEK_CYRILLIC 0x02 /* Uzbek (Cyrillic) */
+
+/*
+ * Sorting IDs.
+ */
+#define SORT_DEFAULT 0x0 /* sorting default */
+
+#define SORT_JAPANESE_XJIS 0x0 /* Japanese XJIS order */
+#define SORT_JAPANESE_UNICODE 0x1 /* Japanese Unicode order */
+
+#define SORT_CHINESE_BIG5 0x0 /* Chinese BIG5 order */
+#define SORT_CHINESE_PRCP 0x0 /* PRC Chinese Phonetic order */
+#define SORT_CHINESE_UNICODE 0x1 /* Chinese Unicode order */
+#define SORT_CHINESE_PRC 0x2 /* PRC Chinese Stroke Count */
+ /* order */
+#define SORT_CHINESE_BOPOMOFO 0x3 /* Traditional Chinese */
+ /* Bopomofo order */
+
+#define SORT_KOREAN_KSC 0x0 /* Korean KSC order */
+#define SORT_KOREAN_UNICODE 0x1 /* Korean Unicode order */
+
+#define SORT_GERMAN_PHONE_BOOK 0x1 /* German Phone Book order */
+
+#define SORT_HUNGARIAN_DEFAULT 0x0 /* Hungarian Default order */
+#define SORT_HUNGARIAN_TECHNICAL 0x1 /* Hungarian Technical order */
+
+#define SORT_GEORGIAN_TRADITIONAL 0x0 /* Georgian Traditional order */
+#define SORT_GEORGIAN_MODERN 0x1 /* Georgian Modern order */
+
+
+/*
+ * A locale ID is a 32 bit value which is the combination of a
+ * language ID, a sort ID, and a reserved area. The bits are
+ * allocated as follows:
+ *
+ * +-------------+---------+-------------------------+
+ * | Reserved | Sort ID | Language ID |
+ * +-------------+---------+-------------------------+
+ * 31 20 19 16 15 0 bit
+ *
+ * Locale ID creation/extraction macros:
+ *
+ * MAKELCID - construct the locale id from a language id
+ * and a sort id.
+ * MAKESORTLCID - construct the locale id from a language id,
+ * sort id, and sort version.
+ * LANGIDFROMLCID - extract the language id from a locale id.
+ * SORTIDFROMLCID - extract the sort id from a locale id.
+ * SORTVERSIONFROMLCID - extract the sort version from a locale id.
+ */
+
+#define NLS_VALID_LOCALE_MASK 0x000fffff
+
+#define MAKELCID(lgid, srtid) \
+ ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid)))))
+
+#define MAKESORTLCID(lgid, srtid, ver) \
+ ((DWORD)((MAKELCID(lgid, srtid)) | (((DWORD)((WORD)(ver))) << 20)))
+
+#define LANGIDFROMLCID(lcid) ((WORD)(lcid))
+#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf))
+#define SORTVERSIONFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 20) & 0xf))
+
+
+/*
+ * Default System and User IDs for language and locale.
+ */
+#define LANG_SYSTEM_DEFAULT MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT))
+#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT))
+
+#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT, SORT_DEFAULT))
+#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT))
+
+#define LOCALE_NEUTRAL \
+ (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NTLOCALE_H */
diff --git a/usr/src/uts/common/smbsrv/ntsid.h b/usr/src/uts/common/smbsrv/ntsid.h
new file mode 100644
index 0000000000..36974ba8fd
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntsid.h
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_NTSID_H
+#define _SMBSRV_NTSID_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Security Identifier (SID) interface definition.
+ */
+
+/*
+ * some kernel include file /usr/include/... is
+ * overriding DWORD and causing conflicts
+ * will investigate further - to be removed
+ */
+
+#ifdef DWORD
+#undef DWORD
+#define DWORD uint32_t
+#endif
+
+#include <smbsrv/wintypes.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Predefined global user RIDs.
+ */
+#define DOMAIN_USER_RID_ADMIN (0x000001F4L) /* 500 */
+#define DOMAIN_USER_RID_GUEST (0x000001F5L) /* 501 */
+#define DOMAIN_USER_RID_KRBTGT (0x000001F6L) /* 502 */
+
+/*
+ * Predefined global group RIDs.
+ */
+#define DOMAIN_GROUP_RID_ADMINS (0x00000200L) /* 512 */
+#define DOMAIN_GROUP_RID_USERS (0x00000201L)
+#define DOMAIN_GROUP_RID_GUESTS (0x00000202L)
+#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L)
+#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L)
+#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L)
+#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L)
+
+
+/*
+ * Predefined local alias RIDs.
+ */
+#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L) /* 544 */
+#define DOMAIN_ALIAS_RID_USERS (0x00000221L)
+#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L)
+#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L)
+#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L)
+#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L)
+#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L)
+#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L)
+#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L)
+
+
+/*
+ * Universal and NT well-known SIDs
+ */
+#define NT_NULL_SIDSTR "S-1-0-0"
+#define NT_WORLD_SIDSTR "S-1-1-0"
+#define NT_LOCAL_SIDSTR "S-1-2-0"
+#define NT_CREATOR_OWNER_ID_SIDSTR "S-1-3-0"
+#define NT_CREATOR_GROUP_ID_SIDSTR "S-1-3-1"
+#define NT_CREATOR_OWNER_SERVER_ID_SIDSTR "S-1-3-2"
+#define NT_CREATOR_GROUP_SERVER_ID_SIDSTR "S-1-3-3"
+#define NT_NON_UNIQUE_IDS_SIDSTR "S-1-4"
+#define NT_AUTHORITY_SIDSTR "S-1-5"
+#define NT_DIALUP_SIDSTR "S-1-5-1"
+#define NT_NETWORK_SIDSTR "S-1-5-2"
+#define NT_BATCH_SIDSTR "S-1-5-3"
+#define NT_INTERACTIVE_SIDSTR "S-1-5-4"
+#define NT_SERVICE_SIDSTR "S-1-5-6"
+#define NT_ANONYMOUS_LOGON_SIDSTR "S-1-5-7"
+#define NT_PROXY_SIDSTR "S-1-5-8"
+#define NT_SERVER_LOGON_SIDSTR "S-1-5-9"
+#define NT_SELF_SIDSTR "S-1-5-10"
+#define NT_AUTHENTICATED_USER_SIDSTR "S-1-5-11"
+#define NT_RESTRICTED_CODE_SIDSTR "S-1-5-12"
+#define NT_LOCAL_SYSTEM_SIDSTR "S-1-5-18"
+#define NT_NON_UNIQUE_SIDSTR "S-1-5-21"
+#define NT_BUILTIN_DOMAIN_SIDSTR "S-1-5-32"
+
+
+/*
+ * SID type indicators (SID_NAME_USE).
+ */
+#define SidTypeNull 0
+#define SidTypeUser 1
+#define SidTypeGroup 2
+#define SidTypeDomain 3
+#define SidTypeAlias 4
+#define SidTypeWellKnownGroup 5
+#define SidTypeDeletedAccount 6
+#define SidTypeInvalid 7
+#define SidTypeUnknown 8
+#define SidTypeComputer 9
+
+
+/*
+ * Identifier authorities for various domains.
+ */
+#define NT_SID_NULL_AUTH 0
+#define NT_SID_WORLD_AUTH 1
+#define NT_SID_LOCAL_AUTH 2
+#define NT_SID_CREATOR_AUTH 3
+#define NT_SID_NON_UNIQUE_AUTH 4
+#define NT_SID_NT_AUTH 5
+
+
+#define NT_SECURITY_NULL_AUTH {0, 0, 0, 0, 0, 0}
+#define NT_SECURITY_WORLD_AUTH {0, 0, 0, 0, 0, 1}
+#define NT_SECURITY_LOCAL_AUTH {0, 0, 0, 0, 0, 2}
+#define NT_SECURITY_CREATOR_AUTH {0, 0, 0, 0, 0, 3}
+#define NT_SECURITY_NON_UNIQUE_AUTH {0, 0, 0, 0, 0, 4}
+#define NT_SECURITY_NT_AUTH {0, 0, 0, 0, 0, 5}
+#define NT_SECURITY_UNIX_AUTH {0, 0, 0, 0, 0, 99}
+
+
+#define SECURITY_NULL_RID (0x00000000L)
+#define SECURITY_WORLD_RID (0x00000000L)
+#define SECURITY_LOCAL_RID (0X00000000L)
+
+#define SECURITY_CREATOR_OWNER_RID (0x00000000L)
+#define SECURITY_CREATOR_GROUP_RID (0x00000001L)
+#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L)
+#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L)
+
+#define SECURITY_DIALUP_RID (0x00000001L)
+#define SECURITY_NETWORK_RID (0x00000002L)
+#define SECURITY_BATCH_RID (0x00000003L)
+#define SECURITY_INTERACTIVE_RID (0x00000004L)
+#define SECURITY_LOGON_IDS_RID (0x00000005L)
+#define SECURITY_LOGON_IDS_RID_COUNT (3L)
+#define SECURITY_SERVICE_RID (0x00000006L)
+#define SECURITY_ANONYMOUS_LOGON_RID (0x00000007L)
+#define SECURITY_PROXY_RID (0x00000008L)
+#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L)
+#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID
+#define SECURITY_PRINCIPAL_SELF_RID (0x0000000AL)
+#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL)
+#define SECURITY_RESTRICTED_CODE_RID (0x0000000CL)
+
+#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L)
+#define SECURITY_NT_NON_UNIQUE (0x00000015L)
+#define SECURITY_BUILTIN_DOMAIN_RID (0x00000020L)
+
+
+#define NT_SID_NON_UNIQUE_SUBAUTH 21
+
+
+/*
+ * Common definition for a SID.
+ */
+#define NT_SID_REVISION 1
+#define NT_SID_AUTH_MAX 6
+#define NT_SID_SUBAUTH_MAX 15
+
+
+/*
+ * Security Identifier (SID)
+ *
+ * The security identifier (SID) uniquely identifies a user, group or
+ * a domain. It consists of a revision number, the identifier authority,
+ * and a list of sub-authorities. The revision number is currently 1.
+ * The identifier authority identifies which system issued the SID. The
+ * sub-authorities of a domain SID uniquely identify a domain. A user
+ * or group SID consists of a domain SID with the user or group id
+ * appended. The user or group id (also known as a relative id (RID)
+ * uniquely identifies a user within a domain. A user or group SID
+ * uniquely identifies a user or group across all domains. The SidType
+ * values identify the various types of SID.
+ *
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------------------------------------------------------+
+ * | SubAuthorityCount |Reserved1 (SBZ)| Revision |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[0] |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[1] |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[2] |
+ * +---------------------------------------------------------------+
+ * | |
+ * +- - - - - - - - SubAuthority[] - - - - - - - - -+
+ * | |
+ * +---------------------------------------------------------------+
+ *
+ */
+/*
+ * Note: NT defines the Identifier Authority as a separate
+ * structure (SID_IDENTIFIER_AUTHORITY) containing a literal
+ * definition of a 6 byte vector but the effect is the same
+ * as defining it as a member value.
+ */
+typedef struct nt_sid {
+ BYTE Revision;
+ BYTE SubAuthCount;
+ BYTE Authority[NT_SID_AUTH_MAX];
+ DWORD SubAuthority[ANY_SIZE_ARRAY];
+} nt_sid_t;
+
+/*
+ * The structure for entries in a static table of well known
+ * SIDs. The table definition is in os/libnt/ntbuitin.c
+ * The domain_ix field is an index into a predefined domain
+ * list in os/libnt/ntbuitin.c
+ */
+typedef struct well_known_account {
+ WORD sid_name_use;
+ WORD domain_ix; /* index to a predefine domain list */
+ char *sid;
+ char *name;
+ WORD flags;
+ char *desc;
+ nt_sid_t *binsid;
+} well_known_account_t;
+
+/*
+ * flags for local group table entry
+ *
+ * LGF_HIDDEN this entry won't be represented to users
+ * via builtin group management interface
+ */
+#define LGF_HIDDEN 0x1
+
+
+/*
+ * The maximum size of the SID format buffer.
+ */
+#define NT_SID_FMTBUF_SIZE 256
+
+
+int nt_sid_is_valid(nt_sid_t *sid);
+int nt_sid_length(nt_sid_t *sid);
+nt_sid_t *nt_sid_dup(nt_sid_t *sid);
+nt_sid_t *nt_sid_splice(nt_sid_t *domain_sid, DWORD rid);
+int nt_sid_get_rid(nt_sid_t *sid, DWORD *rid);
+int nt_sid_split(nt_sid_t *sid, DWORD *rid);
+nt_sid_t *nt_sid_gen_null_sid(void);
+int nt_sid_domain_equal(nt_sid_t *domain_sid, nt_sid_t *sid);
+int nt_sid_is_equal(nt_sid_t *sid1, nt_sid_t *sid2);
+int nt_sid_is_local(nt_sid_t *sid);
+int nt_sid_is_builtin(nt_sid_t *sid);
+int nt_sid_is_domain_equal(nt_sid_t *sid1, nt_sid_t *sid2);
+int nt_sid_is_indomain(nt_sid_t *domain_sid, nt_sid_t *sid);
+void nt_sid_logf(nt_sid_t *sid);
+char *nt_sid_format(nt_sid_t *sid);
+void nt_sid_format2(nt_sid_t *sid, char *fmtbuf);
+nt_sid_t *nt_sid_strtosid(char *sidstr);
+char *nt_sid_name_use(unsigned int snu_id);
+int nt_sid_copy(nt_sid_t *dessid, nt_sid_t *srcsid, unsigned buflen);
+
+
+/*
+ * SID/name translation service for NT BUILTIN SIDs.
+ */
+int nt_builtin_init(void);
+void nt_builtin_fini(void);
+well_known_account_t *nt_builtin_lookup(char *name);
+char *nt_builtin_lookup_sid(nt_sid_t *sid, WORD *sid_name_use);
+nt_sid_t *nt_builtin_lookup_name(char *name, WORD *sid_name_use);
+char *nt_builtin_lookup_domain(char *name);
+int nt_builtin_is_wellknown(char *name);
+well_known_account_t *nt_builtin_findfirst(DWORD *iterator);
+well_known_account_t *nt_builtin_findnext(DWORD *iterator);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_NTSID_H */
diff --git a/usr/src/uts/common/smbsrv/ntstatus.h b/usr/src/uts/common/smbsrv/ntstatus.h
new file mode 100644
index 0000000000..1388dcfcc2
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntstatus.h
@@ -0,0 +1,595 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_NTSTATUS_H
+#define _SMBSRV_NTSTATUS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the list of NT status codes.
+ *
+ * Be careful not to confuse status codes with error
+ * codes. The error codes are listed in nterror.h.
+ */
+
+#include <smbsrv/wintypes.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Status codes are 32-bit values in which the top 2 bits represent
+ * the severity and the lower 16-bits contain a Win32 status code.
+ * The severity levels are:
+ *
+ * 00 success
+ * 01 information
+ * 10 warning
+ * 11 error
+ *
+ * NT also defines an application mask, which is included here
+ * for completeness.
+ */
+#define APPLICATION_ERROR_MASK 0x20000000
+#define ERROR_SEVERITY_SUCCESS 0x00000000
+#define ERROR_SEVERITY_INFORMATIONAL 0x40000000
+#define ERROR_SEVERITY_WARNING 0x80000000
+#define ERROR_SEVERITY_ERROR 0xC0000000
+
+/*
+ * Severity code helper macros.
+ */
+#define NT_SC_SUCCESS(STATUS) (ERROR_SEVERITY_SUCCESS+(STATUS))
+#define NT_SC_INFO(STATUS) (ERROR_SEVERITY_INFORMATIONAL+(STATUS))
+#define NT_SC_WARNING(STATUS) (ERROR_SEVERITY_WARNING+(STATUS))
+#define NT_SC_ERROR(STATUS) (ERROR_SEVERITY_ERROR+(STATUS))
+
+#define NT_SC_IS_SUCCESS(S) (((S) & 0xC0000000) == ERROR_SEVERITY_SUCCESS)
+#define NT_SC_IS_INFO(S) (((S) & 0xC0000000) == ERROR_SEVERITY_INFORMATIONAL)
+#define NT_SC_IS_WARNING(S) (((S) & 0xC0000000) == ERROR_SEVERITY_WARNING)
+#define NT_SC_IS_ERROR(S) (((S) & 0xC0000000) == ERROR_SEVERITY_ERROR)
+
+#define NT_SC_VALUE(S) ((S) & 0x0FFFFFFF)
+
+/*
+ * Win32 status codes
+ */
+#define NT_STATUS_SUCCESS 0
+#define NT_STATUS_UNSUCCESSFUL 1
+#define NT_STATUS_NOT_IMPLEMENTED 2
+#define NT_STATUS_INVALID_INFO_CLASS 3
+#define NT_STATUS_INFO_LENGTH_MISMATCH 4
+#define NT_STATUS_BUFFER_OVERFLOW 5
+/* NT_STATUS_IN_PAGE_ERROR */
+#define NT_STATUS_NO_MORE_FILES 6
+#define NT_STATUS_PAGEFILE_QUOTA 7
+#define NT_STATUS_INVALID_HANDLE 8
+#define NT_STATUS_BAD_INITIAL_STACK 9
+#define NT_STATUS_BAD_INITIAL_PC 10
+#define NT_STATUS_INVALID_CID 11
+#define NT_STATUS_TIMER_NOT_CANCELED 12
+#define NT_STATUS_INVALID_PARAMETER 13
+#define NT_STATUS_NO_SUCH_DEVICE 14
+#define NT_STATUS_NO_SUCH_FILE 15
+#define NT_STATUS_INVALID_DEVICE_REQUEST 16
+#define NT_STATUS_END_OF_FILE 17
+#define NT_STATUS_WRONG_VOLUME 18
+#define NT_STATUS_NO_MEDIA_IN_DEVICE 19
+#define NT_STATUS_UNRECOGNIZED_MEDIA 20
+#define NT_STATUS_NONEXISTENT_SECTOR 21
+#define NT_STATUS_MORE_PROCESSING_REQUIRED 22
+#define NT_STATUS_NO_MEMORY 23
+#define NT_STATUS_CONFLICTING_ADDRESSES 24
+#define NT_STATUS_NOT_MAPPED_VIEW 25
+#define NT_STATUS_UNABLE_TO_FREE_VM 26
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION 27
+#define NT_STATUS_INVALID_SYSTEM_SERVICE 28
+#define NT_STATUS_ILLEGAL_INSTRUCTION 29
+#define NT_STATUS_INVALID_LOCK_SEQUENCE 30
+#define NT_STATUS_INVALID_VIEW_SIZE 31
+#define NT_STATUS_INVALID_FILE_FOR_SECTION 32
+#define NT_STATUS_ALREADY_COMMITTED 33
+#define NT_STATUS_ACCESS_DENIED 34
+#define NT_STATUS_BUFFER_TOO_SMALL 35
+#define NT_STATUS_OBJECT_TYPE_MISMATCH 36
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION 37
+#define NT_STATUS_INVALID_DISPOSITION 38
+#define NT_STATUS_UNWIND 39
+#define NT_STATUS_BAD_STACK 40
+#define NT_STATUS_INVALID_UNWIND_TARGET 41
+#define NT_STATUS_NOT_LOCKED 42
+#define NT_STATUS_PARITY_ERROR 43
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 44
+#define NT_STATUS_NOT_COMMITTED 45
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES 46
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG 47
+#define NT_STATUS_INVALID_PARAMETER_MIX 48
+#define NT_STATUS_INVALID_QUOTA_LOWER 49
+#define NT_STATUS_DISK_CORRUPT_ERROR 50
+#define NT_STATUS_OBJECT_NAME_INVALID 51
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND 52
+#define NT_STATUS_OBJECT_NAME_COLLISION 53
+#define NT_STATUS_HANDLE_NOT_WAITABLE 54
+#define NT_STATUS_PORT_DISCONNECTED 55
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED 56
+#define NT_STATUS_OBJECT_PATH_INVALID 57
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND 58
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 59
+#define NT_STATUS_DATA_OVERRUN 60
+#define NT_STATUS_DATA_LATE_ERROR 61
+#define NT_STATUS_DATA_ERROR 62
+#define NT_STATUS_CRC_ERROR 63
+#define NT_STATUS_SECTION_TOO_BIG 64
+#define NT_STATUS_PORT_CONNECTION_REFUSED 65
+#define NT_STATUS_INVALID_PORT_HANDLE 66
+#define NT_STATUS_SHARING_VIOLATION 67
+#define NT_STATUS_QUOTA_EXCEEDED 68
+#define NT_STATUS_INVALID_PAGE_PROTECTION 69
+#define NT_STATUS_MUTANT_NOT_OWNED 70
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 71
+#define NT_STATUS_PORT_ALREADY_SET 72
+#define NT_STATUS_SECTION_NOT_IMAGE 73
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 74
+#define NT_STATUS_THREAD_IS_TERMINATING 75
+#define NT_STATUS_BAD_WORKING_SET_LIMIT 76
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP 77
+#define NT_STATUS_SECTION_PROTECTION 78
+#define NT_STATUS_EAS_NOT_SUPPORTED 79
+#define NT_STATUS_EA_TOO_LARGE 80
+#define NT_STATUS_NONEXISTENT_EA_ENTRY 81
+#define NT_STATUS_NO_EAS_ON_FILE 82
+#define NT_STATUS_EA_CORRUPT_ERROR 83
+#define NT_STATUS_FILE_LOCK_CONFLICT 84
+#define NT_STATUS_LOCK_NOT_GRANTED 85
+#define NT_STATUS_DELETE_PENDING 86
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 87
+#define NT_STATUS_UNKNOWN_REVISION 88
+#define NT_STATUS_REVISION_MISMATCH 89
+#define NT_STATUS_INVALID_OWNER 90
+#define NT_STATUS_INVALID_PRIMARY_GROUP 91
+#define NT_STATUS_NO_IMPERSONATION_TOKEN 92
+#define NT_STATUS_CANT_DISABLE_MANDATORY 93
+#define NT_STATUS_NO_LOGON_SERVERS 94
+#define NT_STATUS_NO_SUCH_LOGON_SESSION 95
+#define NT_STATUS_NO_SUCH_PRIVILEGE 96
+#define NT_STATUS_PRIVILEGE_NOT_HELD 97
+#define NT_STATUS_INVALID_ACCOUNT_NAME 98
+#define NT_STATUS_USER_EXISTS 99
+#define NT_STATUS_NO_SUCH_USER 100
+#define NT_STATUS_GROUP_EXISTS 101
+#define NT_STATUS_NO_SUCH_GROUP 102
+#define NT_STATUS_MEMBER_IN_GROUP 103
+#define NT_STATUS_MEMBER_NOT_IN_GROUP 104
+#define NT_STATUS_LAST_ADMIN 105
+#define NT_STATUS_WRONG_PASSWORD 106
+#define NT_STATUS_ILL_FORMED_PASSWORD 107
+#define NT_STATUS_PASSWORD_RESTRICTION 108
+#define NT_STATUS_LOGON_FAILURE 109
+#define NT_STATUS_ACCOUNT_RESTRICTION 110
+#define NT_STATUS_INVALID_LOGON_HOURS 111
+#define NT_STATUS_INVALID_WORKSTATION 112
+#define NT_STATUS_PASSWORD_EXPIRED 113
+#define NT_STATUS_ACCOUNT_DISABLED 114
+#define NT_STATUS_NONE_MAPPED 115
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 116
+#define NT_STATUS_LUIDS_EXHAUSTED 117
+#define NT_STATUS_INVALID_SUB_AUTHORITY 118
+#define NT_STATUS_INVALID_ACL 119
+#define NT_STATUS_INVALID_SID 120
+#define NT_STATUS_INVALID_SECURITY_DESCR 121
+#define NT_STATUS_PROCEDURE_NOT_FOUND 122
+#define NT_STATUS_INVALID_IMAGE_FORMAT 123
+#define NT_STATUS_NO_TOKEN 124
+#define NT_STATUS_BAD_INHERITANCE_ACL 125
+#define NT_STATUS_RANGE_NOT_LOCKED 126
+#define NT_STATUS_DISK_FULL 127
+#define NT_STATUS_SERVER_DISABLED 128
+#define NT_STATUS_SERVER_NOT_DISABLED 129
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 130
+#define NT_STATUS_GUIDS_EXHAUSTED 131
+#define NT_STATUS_INVALID_ID_AUTHORITY 132
+#define NT_STATUS_AGENTS_EXHAUSTED 133
+#define NT_STATUS_INVALID_VOLUME_LABEL 134
+#define NT_STATUS_SECTION_NOT_EXTENDED 135
+#define NT_STATUS_NOT_MAPPED_DATA 136
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 137
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 138
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 139
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 140
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND 141
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 142
+#define NT_STATUS_FLOAT_INEXACT_RESULT 143
+#define NT_STATUS_FLOAT_INVALID_OPERATION 144
+#define NT_STATUS_FLOAT_OVERFLOW 145
+#define NT_STATUS_FLOAT_STACK_CHECK 146
+#define NT_STATUS_FLOAT_UNDERFLOW 147
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 148
+#define NT_STATUS_INTEGER_OVERFLOW 149
+#define NT_STATUS_PRIVILEGED_INSTRUCTION 150
+#define NT_STATUS_TOO_MANY_PAGING_FILES 151
+#define NT_STATUS_FILE_INVALID 152
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 153
+#define NT_STATUS_INSUFFICIENT_RESOURCES 154
+#define NT_STATUS_DFS_EXIT_PATH_FOUND 155
+#define NT_STATUS_DEVICE_DATA_ERROR 156
+#define NT_STATUS_DEVICE_NOT_CONNECTED 157
+#define NT_STATUS_DEVICE_POWER_FAILURE 158
+#define NT_STATUS_FREE_VM_NOT_AT_BASE 159
+#define NT_STATUS_MEMORY_NOT_ALLOCATED 160
+#define NT_STATUS_WORKING_SET_QUOTA 161
+#define NT_STATUS_MEDIA_WRITE_PROTECTED 162
+#define NT_STATUS_DEVICE_NOT_READY 163
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 164
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL 165
+#define NT_STATUS_CANT_OPEN_ANONYMOUS 166
+#define NT_STATUS_BAD_VALIDATION_CLASS 167
+#define NT_STATUS_BAD_TOKEN_TYPE 168
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD 169
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT 170
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE 171
+#define NT_STATUS_PIPE_NOT_AVAILABLE 172
+#define NT_STATUS_INVALID_PIPE_STATE 173
+#define NT_STATUS_PIPE_BUSY 174
+#define NT_STATUS_ILLEGAL_FUNCTION 175
+#define NT_STATUS_PIPE_DISCONNECTED 176
+#define NT_STATUS_PIPE_CLOSING 177
+#define NT_STATUS_PIPE_CONNECTED 178
+#define NT_STATUS_PIPE_LISTENING 179
+#define NT_STATUS_INVALID_READ_MODE 180
+#define NT_STATUS_IO_TIMEOUT 181
+#define NT_STATUS_FILE_FORCED_CLOSED 182
+#define NT_STATUS_PROFILING_NOT_STARTED 183
+#define NT_STATUS_PROFILING_NOT_STOPPED 184
+#define NT_STATUS_COULD_NOT_INTERPRET 185
+#define NT_STATUS_FILE_IS_A_DIRECTORY 186
+#define NT_STATUS_NOT_SUPPORTED 187
+#define NT_STATUS_REMOTE_NOT_LISTENING 188
+#define NT_STATUS_DUPLICATE_NAME 189
+#define NT_STATUS_BAD_NETWORK_PATH 190
+#define NT_STATUS_NETWORK_BUSY 191
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST 192
+#define NT_STATUS_TOO_MANY_COMMANDS 193
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR 194
+#define NT_STATUS_INVALID_NETWORK_RESPONSE 195
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 196
+#define NT_STATUS_BAD_REMOTE_ADAPTER 197
+#define NT_STATUS_PRINT_QUEUE_FULL 198
+#define NT_STATUS_NO_SPOOL_SPACE 199
+#define NT_STATUS_PRINT_CANCELLED 200
+#define NT_STATUS_NETWORK_NAME_DELETED 201
+#define NT_STATUS_NETWORK_ACCESS_DENIED 202
+#define NT_STATUS_BAD_DEVICE_TYPE 203
+#define NT_STATUS_BAD_NETWORK_NAME 204
+#define NT_STATUS_TOO_MANY_NAMES 205
+#define NT_STATUS_TOO_MANY_SESSIONS 206
+#define NT_STATUS_SHARING_PAUSED 207
+#define NT_STATUS_REQUEST_NOT_ACCEPTED 208
+#define NT_STATUS_REDIRECTOR_PAUSED 209
+#define NT_STATUS_NET_WRITE_FAULT 210
+#define NT_STATUS_PROFILING_AT_LIMIT 211
+#define NT_STATUS_NOT_SAME_DEVICE 212
+#define NT_STATUS_FILE_RENAMED 213
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 214
+#define NT_STATUS_NO_SECURITY_ON_OBJECT 215
+#define NT_STATUS_CANT_WAIT 216
+#define NT_STATUS_PIPE_EMPTY 217
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 218
+#define NT_STATUS_CANT_TERMINATE_SELF 219
+#define NT_STATUS_INVALID_SERVER_STATE 220
+#define NT_STATUS_INVALID_DOMAIN_STATE 221
+#define NT_STATUS_INVALID_DOMAIN_ROLE 222
+#define NT_STATUS_NO_SUCH_DOMAIN 223
+#define NT_STATUS_DOMAIN_EXISTS 224
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 225
+#define NT_STATUS_OPLOCK_NOT_GRANTED 226
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 227
+#define NT_STATUS_INTERNAL_DB_CORRUPTION 228
+#define NT_STATUS_INTERNAL_ERROR 229
+#define NT_STATUS_GENERIC_NOT_MAPPED 230
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 231
+#define NT_STATUS_INVALID_USER_BUFFER 232
+#define NT_STATUS_UNEXPECTED_IO_ERROR 233
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 234
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 235
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 236
+#define NT_STATUS_NOT_LOGON_PROCESS 237
+#define NT_STATUS_LOGON_SESSION_EXISTS 238
+#define NT_STATUS_INVALID_PARAMETER_1 239
+#define NT_STATUS_INVALID_PARAMETER_2 240
+#define NT_STATUS_INVALID_PARAMETER_3 241
+#define NT_STATUS_INVALID_PARAMETER_4 242
+#define NT_STATUS_INVALID_PARAMETER_5 243
+#define NT_STATUS_INVALID_PARAMETER_6 244
+#define NT_STATUS_INVALID_PARAMETER_7 245
+#define NT_STATUS_INVALID_PARAMETER_8 246
+#define NT_STATUS_INVALID_PARAMETER_9 247
+#define NT_STATUS_INVALID_PARAMETER_10 248
+#define NT_STATUS_INVALID_PARAMETER_11 249
+#define NT_STATUS_INVALID_PARAMETER_12 250
+#define NT_STATUS_REDIRECTOR_NOT_STARTED 251
+#define NT_STATUS_REDIRECTOR_STARTED 252
+#define NT_STATUS_STACK_OVERFLOW 253
+#define NT_STATUS_NO_SUCH_PACKAGE 254
+#define NT_STATUS_BAD_FUNCTION_TABLE 255
+#define NT_STATUS_DIRECTORY_NOT_EMPTY 257
+#define NT_STATUS_FILE_CORRUPT_ERROR 258
+#define NT_STATUS_NOT_A_DIRECTORY 259
+#define NT_STATUS_BAD_LOGON_SESSION_STATE 260
+#define NT_STATUS_LOGON_SESSION_COLLISION 261
+#define NT_STATUS_NAME_TOO_LONG 262
+#define NT_STATUS_FILES_OPEN 263
+#define NT_STATUS_CONNECTION_IN_USE 264
+#define NT_STATUS_MESSAGE_NOT_FOUND 265
+#define NT_STATUS_PROCESS_IS_TERMINATING 266
+#define NT_STATUS_INVALID_LOGON_TYPE 267
+#define NT_STATUS_NO_GUID_TRANSLATION 268
+#define NT_STATUS_CANNOT_IMPERSONATE 269
+#define NT_STATUS_IMAGE_ALREADY_LOADED 270
+#define NT_STATUS_ABIOS_NOT_PRESENT 271
+#define NT_STATUS_ABIOS_LID_NOT_EXIST 272
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 273
+#define NT_STATUS_ABIOS_NOT_LID_OWNER 274
+#define NT_STATUS_ABIOS_INVALID_COMMAND 275
+#define NT_STATUS_ABIOS_INVALID_LID 276
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 277
+#define NT_STATUS_ABIOS_INVALID_SELECTOR 278
+#define NT_STATUS_NO_LDT 279
+#define NT_STATUS_INVALID_LDT_SIZE 280
+#define NT_STATUS_INVALID_LDT_OFFSET 281
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR 282
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 283
+#define NT_STATUS_RXACT_INVALID_STATE 284
+#define NT_STATUS_RXACT_COMMIT_FAILURE 285
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 286
+#define NT_STATUS_TOO_MANY_OPENED_FILES 287
+#define NT_STATUS_CANCELLED 288
+#define NT_STATUS_CANNOT_DELETE 289
+#define NT_STATUS_INVALID_COMPUTER_NAME 290
+#define NT_STATUS_FILE_DELETED 291
+#define NT_STATUS_SPECIAL_ACCOUNT 292
+#define NT_STATUS_SPECIAL_GROUP 293
+#define NT_STATUS_SPECIAL_USER 294
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP 295
+#define NT_STATUS_FILE_CLOSED 296
+#define NT_STATUS_TOO_MANY_THREADS 297
+#define NT_STATUS_THREAD_NOT_IN_PROCESS 298
+#define NT_STATUS_TOKEN_ALREADY_IN_USE 299
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 300
+#define NT_STATUS_COMMITMENT_LIMIT 301
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 302
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ 303
+#define NT_STATUS_INVALID_IMAGE_PROTECT 304
+#define NT_STATUS_INVALID_IMAGE_WIN_16 305
+#define NT_STATUS_LOGON_SERVER_CONFLICT 306
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC 307
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED 308
+#define NT_STATUS_DLL_NOT_FOUND 309
+#define NT_STATUS_OPEN_FAILED 310
+#define NT_STATUS_IO_PRIVILEGE_FAILED 311
+#define NT_STATUS_ORDINAL_NOT_FOUND 312
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND 313
+#define NT_STATUS_CONTROL_C_EXIT 314
+#define NT_STATUS_LOCAL_DISCONNECT 315
+#define NT_STATUS_REMOTE_DISCONNECT 316
+#define NT_STATUS_REMOTE_RESOURCES 317
+#define NT_STATUS_LINK_FAILED 318
+#define NT_STATUS_LINK_TIMEOUT 319
+#define NT_STATUS_INVALID_CONNECTION 320
+#define NT_STATUS_INVALID_ADDRESS 321
+#define NT_STATUS_DLL_INIT_FAILED 322
+#define NT_STATUS_MISSING_SYSTEMFILE 323
+#define NT_STATUS_UNHANDLED_EXCEPTION 324
+#define NT_STATUS_APP_INIT_FAILURE 325
+#define NT_STATUS_PAGEFILE_CREATE_FAILED 326
+#define NT_STATUS_NO_PAGEFILE 327
+#define NT_STATUS_INVALID_LEVEL 328
+#define NT_STATUS_WRONG_PASSWORD_CORE 329
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 330
+#define NT_STATUS_PIPE_BROKEN 331
+#define NT_STATUS_REGISTRY_CORRUPT 332
+#define NT_STATUS_REGISTRY_IO_FAILED 333
+#define NT_STATUS_NO_EVENT_PAIR 334
+#define NT_STATUS_UNRECOGNIZED_VOLUME 335
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED 336
+#define NT_STATUS_NO_SUCH_ALIAS 337
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS 338
+#define NT_STATUS_MEMBER_IN_ALIAS 339
+#define NT_STATUS_ALIAS_EXISTS 340
+#define NT_STATUS_LOGON_NOT_GRANTED 341
+#define NT_STATUS_TOO_MANY_SECRETS 342
+#define NT_STATUS_SECRET_TOO_LONG 343
+#define NT_STATUS_INTERNAL_DB_ERROR 344
+#define NT_STATUS_FULLSCREEN_MODE 345
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS 346
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 347
+#define NT_STATUS_NOT_REGISTRY_FILE 348
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 349
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 350
+#define NT_STATUS_FT_MISSING_MEMBER 351
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 352
+#define NT_STATUS_ILLEGAL_CHARACTER 353
+#define NT_STATUS_UNMAPPABLE_CHARACTER 354
+#define NT_STATUS_UNDEFINED_CHARACTER 355
+#define NT_STATUS_FLOPPY_VOLUME 356
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 357
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER 358
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 359
+#define NT_STATUS_FLOPPY_BAD_REGISTERS 360
+#define NT_STATUS_DISK_RECALIBRATE_FAILED 361
+#define NT_STATUS_DISK_OPERATION_FAILED 362
+#define NT_STATUS_DISK_RESET_FAILED 363
+#define NT_STATUS_SHARED_IRQ_BUSY 364
+#define NT_STATUS_FT_ORPHANING 365
+#define NT_STATUS_PARTITION_FAILURE 370
+#define NT_STATUS_INVALID_BLOCK_LENGTH 371
+#define NT_STATUS_DEVICE_NOT_PARTITIONED 372
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 373
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 374
+#define NT_STATUS_EOM_OVERFLOW 375
+#define NT_STATUS_NO_MEDIA 376
+#define NT_STATUS_NO_SUCH_MEMBER 378
+#define NT_STATUS_INVALID_MEMBER 379
+#define NT_STATUS_KEY_DELETED 380
+#define NT_STATUS_NO_LOG_SPACE 381
+#define NT_STATUS_TOO_MANY_SIDS 382
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 383
+#define NT_STATUS_KEY_HAS_CHILDREN 384
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE 385
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 386
+#define NT_STATUS_DRIVER_INTERNAL_ERROR 387
+#define NT_STATUS_INVALID_DEVICE_STATE 388
+#define NT_STATUS_IO_DEVICE_ERROR 389
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR 390
+#define NT_STATUS_BACKUP_CONTROLLER 391
+#define NT_STATUS_LOG_FILE_FULL 392
+#define NT_STATUS_TOO_LATE 393
+#define NT_STATUS_NO_TRUST_LSA_SECRET 394
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 395
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 396
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 397
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT 398
+#define NT_STATUS_EVENTLOG_CANT_START 399
+#define NT_STATUS_TRUST_FAILURE 400
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 401
+#define NT_STATUS_NETLOGON_NOT_STARTED 402
+#define NT_STATUS_ACCOUNT_EXPIRED 403
+#define NT_STATUS_POSSIBLE_DEADLOCK 404
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 405
+#define NT_STATUS_REMOTE_SESSION_LIMIT 406
+#define NT_STATUS_EVENTLOG_FILE_CHANGED 407
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 408
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 409
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 410
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 411
+#define NT_STATUS_FS_DRIVER_REQUIRED 412
+#define NT_STATUS_NO_USER_SESSION_KEY 514
+#define NT_STATUS_USER_SESSION_DELETED 515
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 516
+#define NT_STATUS_INSUFF_SERVER_RESOURCES 517
+#define NT_STATUS_INVALID_BUFFER_SIZE 518
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT 519
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD 520
+#define NT_STATUS_TOO_MANY_ADDRESSES 521
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS 522
+#define NT_STATUS_ADDRESS_CLOSED 523
+#define NT_STATUS_CONNECTION_DISCONNECTED 524
+#define NT_STATUS_CONNECTION_RESET 525
+#define NT_STATUS_TOO_MANY_NODES 526
+#define NT_STATUS_TRANSACTION_ABORTED 527
+#define NT_STATUS_TRANSACTION_TIMED_OUT 528
+#define NT_STATUS_TRANSACTION_NO_RELEASE 529
+#define NT_STATUS_TRANSACTION_NO_MATCH 530
+#define NT_STATUS_TRANSACTION_RESPONDED 531
+#define NT_STATUS_TRANSACTION_INVALID_ID 532
+#define NT_STATUS_TRANSACTION_INVALID_TYPE 533
+#define NT_STATUS_NOT_SERVER_SESSION 534
+#define NT_STATUS_NOT_CLIENT_SESSION 535
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 536
+#define NT_STATUS_DEBUG_ATTACH_FAILED 537
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 538
+#define NT_STATUS_DATA_NOT_ACCEPTED 539
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 540
+#define NT_STATUS_VDM_HARD_ERROR 541
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 542
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH 543
+#define NT_STATUS_MAPPED_ALIGNMENT 544
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 545
+#define NT_STATUS_LOST_WRITEBEHIND_DATA 546
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 547
+#define NT_STATUS_PASSWORD_MUST_CHANGE 548
+#define NT_STATUS_NOT_FOUND 549
+#define NT_STATUS_NOT_TINY_STREAM 550
+#define NT_STATUS_RECOVERY_FAILURE 551
+#define NT_STATUS_STACK_OVERFLOW_READ 552
+#define NT_STATUS_FAIL_CHECK 553
+#define NT_STATUS_DUPLICATE_OBJECTID 554
+#define NT_STATUS_OBJECTID_EXISTS 555
+#define NT_STATUS_CONVERT_TO_LARGE 556
+#define NT_STATUS_RETRY 557
+#define NT_STATUS_FOUND_OUT_OF_SCOPE 558
+#define NT_STATUS_ALLOCATE_BUCKET 559
+#define NT_STATUS_PROPSET_NOT_FOUND 560
+#define NT_STATUS_MARSHALL_OVERFLOW 561
+#define NT_STATUS_INVALID_VARIANT 562
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 563
+#define NT_STATUS_ACCOUNT_LOCKED_OUT 564
+#define NT_STATUS_HANDLE_NOT_CLOSABLE 565
+#define NT_STATUS_CONNECTION_REFUSED 566
+#define NT_STATUS_GRACEFUL_DISCONNECT 567
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 568
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 569
+#define NT_STATUS_CONNECTION_INVALID 570
+#define NT_STATUS_CONNECTION_ACTIVE 571
+#define NT_STATUS_NETWORK_UNREACHABLE 572
+#define NT_STATUS_HOST_UNREACHABLE 573
+#define NT_STATUS_PROTOCOL_UNREACHABLE 574
+#define NT_STATUS_PORT_UNREACHABLE 575
+#define NT_STATUS_REQUEST_ABORTED 576
+#define NT_STATUS_CONNECTION_ABORTED 577
+#define NT_STATUS_BAD_COMPRESSION_BUFFER 578
+#define NT_STATUS_USER_MAPPED_FILE 579
+#define NT_STATUS_AUDIT_FAILED 580
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 581
+#define NT_STATUS_CONNECTION_COUNT_LIMIT 582
+#define NT_STATUS_LOGIN_TIME_RESTRICTION 583
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 584
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH 585
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO 592
+#define NT_STATUS_BAD_DLL_ENTRYPOINT 593
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 594
+#define NT_STATUS_LPC_REPLY_LOST 595
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 596
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 597
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT 598
+#define NT_STATUS_PATH_NOT_COVERED 599
+#define NT_STATUS_NO_CALLBACK_ACTIVE 600
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 601
+#define NT_STATUS_PWD_TOO_SHORT 602
+#define NT_STATUS_PWD_TOO_RECENT 603
+#define NT_STATUS_PWD_HISTORY_CONFLICT 604
+#define NT_STATUS_PLUGPLAY_NO_DEVICE 606
+#define NT_STATUS_UNSUPPORTED_COMPRESSION 607
+#define NT_STATUS_INVALID_HW_PROFILE 608
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 609
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 610
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 611
+#define NT_STATUS_RESOURCE_NOT_OWNED 612
+#define NT_STATUS_TOO_MANY_LINKS 613
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT 614
+#define NT_STATUS_FILE_IS_OFFLINE 615
+
+char *xlate_nt_status(DWORD ntstatus);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_NTSTATUS_H */
diff --git a/usr/src/uts/common/smbsrv/oem.h b/usr/src/uts/common/smbsrv/oem.h
new file mode 100644
index 0000000000..af30711dac
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/oem.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+/*
+ * Support for oem <-> unicode translations.
+ */
+
+#ifndef _SMBSRV_OEM_H
+#define _SMBSRV_OEM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define oem_default_smb_cpid OEM_CP_IND_850
+#define oem_default_telnet_cpid OEM_CP_IND_1252
+#define oem_default_language "english"
+
+/*
+ * The id should corresponds to oemcp_table in os/library/oem.c.
+ */
+typedef enum codepage_id {
+ OEM_CP_IND_850 = 0,
+ OEM_CP_IND_950,
+ OEM_CP_IND_1252,
+ OEM_CP_IND_949,
+ OEM_CP_IND_936,
+ OEM_CP_IND_932,
+ OEM_CP_IND_852,
+ OEM_CP_IND_1250,
+ OEM_CP_IND_1253,
+ OEM_CP_IND_737,
+ OEM_CP_IND_1254,
+ OEM_CP_IND_857,
+ OEM_CP_IND_1251,
+ OEM_CP_IND_866,
+ OEM_CP_IND_1255,
+ OEM_CP_IND_862,
+ OEM_CP_IND_1256,
+ OEM_CP_IND_720,
+ NO_OF_OEM_CP_INDS
+} codepage_id_t;
+
+
+typedef struct language {
+ char *language;
+ unsigned int smbIndex;
+ unsigned int telnetIndex;
+} language;
+
+
+/*
+ * cpid = the cpid of the oemcp_table that oempage_t belong to.
+ * value = the conversion values
+ */
+typedef struct oempage_t {
+ unsigned int cpid;
+ mts_wchar_t *value;
+} oempage_t;
+
+/*
+ * Private functions for opmlang.c
+ */
+extern int oem_codepage_init(unsigned int);
+extern void oem_codepage_free(unsigned int);
+extern language *oem_get_lang_table(void);
+extern int oem_no_of_languages(void);
+#define NO_OF_LANGUAGES oem_no_of_languages()
+
+/*
+ * Public functions
+ */
+extern size_t unicodestooems(char *, const mts_wchar_t *, size_t, unsigned int);
+extern size_t oemstounicodes(mts_wchar_t *, const char *, size_t, unsigned int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_OEM_H */
diff --git a/usr/src/uts/common/smbsrv/samlib.h b/usr/src/uts/common/smbsrv/samlib.h
new file mode 100644
index 0000000000..19186ad8ba
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/samlib.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SAMLIB_H
+#define _SMBSRV_SAMLIB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Prototypes for the SAM library and RPC client side library interface.
+ * There are two levels of interface defined here: sam_xxx and samr_xxx.
+ * The sam_xxx functions provide a high level interface which make
+ * multiple RPC calls and do all the work necessary to obtain and return
+ * the requested information. The samr_xxx functions provide a low level
+ * interface in which each function maps to a single underlying RPC.
+ */
+
+#include <smbsrv/ndl/samrpc.ndl>
+#include <smbsrv/mlsvc_util.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * samlib.c
+ */
+int sam_lookup_user_info(char *server, char *domain_name, char *username,
+ char *password, smb_userinfo_t *user_info);
+
+DWORD sam_create_trust_account(char *server, char *domain,
+ smb_auth_info_t *auth);
+
+DWORD sam_create_account(char *server, char *domain_name, char *account_name,
+ smb_auth_info_t *auth, DWORD account_flags, smb_userinfo_t *user_info);
+
+DWORD sam_remove_trust_account(char *server, char *domain);
+
+DWORD sam_delete_account(char *server, char *domain_name, char *account_name);
+
+DWORD sam_lookup_name(char *server, char *domain_name, char *account_name,
+ DWORD *rid_ret);
+
+DWORD sam_get_local_domains(char *server, char *domain_name);
+
+/*
+ * samr_open.c
+ */
+int samr_open(int ipc_mode, char *server, char *domain, char *username,
+ char *password, DWORD access_mask, mlsvc_handle_t *samr_handle);
+
+int samr_connect(char *server, char *domain, char *username,
+ DWORD access_mask, mlsvc_handle_t *samr_handle);
+
+int samr_close_handle(mlsvc_handle_t *handle);
+
+DWORD samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask,
+ struct samr_sid *sid, mlsvc_handle_t *domain_handle);
+
+int samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask,
+ DWORD rid, mlsvc_handle_t *user_handle);
+
+DWORD samr_delete_user(mlsvc_handle_t *user_handle);
+
+int samr_open_group(mlsvc_handle_t *domain_handle, DWORD rid,
+ mlsvc_handle_t *group_handle);
+
+DWORD samr_create_user(mlsvc_handle_t *domain_handle, char *username,
+ DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle);
+
+/*
+ * samr_lookup.c
+ */
+union samr_user_info {
+ struct info1 {
+ char *username;
+ char *fullname;
+ DWORD group_rid;
+ char *description;
+ char *unknown;
+ } info1;
+
+ struct info6 {
+ char *username;
+ char *fullname;
+ } info6;
+
+ struct info7 {
+ char *username;
+ } info7;
+
+ struct info8 {
+ char *fullname;
+ } info8;
+
+ struct info9 {
+ DWORD group_rid;
+ } info9;
+
+ struct info16 {
+ DWORD unknown;
+ } info16;
+};
+
+
+int samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name,
+ smb_userinfo_t *user_info);
+
+DWORD samr_enum_local_domains(mlsvc_handle_t *samr_handle);
+
+DWORD samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
+ smb_userinfo_t *user_info);
+
+int samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value,
+ union samr_user_info *user_info);
+
+int samr_query_user_groups(mlsvc_handle_t *user_handle,
+ smb_userinfo_t *user_info);
+
+DWORD samr_get_user_pwinfo(mlsvc_handle_t *user_handle);
+
+typedef struct oem_password {
+ BYTE data[512];
+ DWORD length;
+} oem_password_t;
+
+
+int sam_oem_password(oem_password_t *oem_password, unsigned char *new_password,
+ unsigned char *old_password);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_SAMLIB_H */
diff --git a/usr/src/uts/common/smbsrv/smb.h b/usr/src/uts/common/smbsrv/smb.h
new file mode 100644
index 0000000000..1214f041d7
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb.h
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMB_H
+#define _SMBSRV_SMB_H
+
+/*
+ * SMB definitions and interfaces, mostly defined in the CIFS spec.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB definitions and interfaces, mostly defined in the CIFS spec.
+ */
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#endif
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/msgbuf.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Typedefs from CIFS section 3.2
+ */
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef uint32_t ULONG;
+typedef int32_t LONG;
+
+
+/*
+ * The msgbuf format and length of an SMB header.
+ */
+#define SMB_HEADER_DOS_FMT "Mbbbwbww10.wwww"
+#define SMB_HEADER_NT_FMT "Mblbww#c2.wwww"
+#define SMB_HEADER_LEN 32
+#define SMB_SIG_SIZE 8 /* SMB signature size */
+
+/*
+ * CIFS definition for the SMB header (CIFS Section 3.2). Note that the
+ * pid_high field is not documented in the 1997 CIFS specificaction. This
+ * is a decoded or memory-based definition, which may be padded to align
+ * its elements on word boundaries. See smb_hdrbuf_t for the network
+ * ready structure.
+ */
+typedef struct smb_hdr {
+ UCHAR protocol[4];
+ UCHAR command;
+
+ union {
+ struct {
+ UCHAR error_class;
+ UCHAR reserved;
+ USHORT error;
+ } dos_error;
+ ULONG ntstatus;
+ }status;
+
+ UCHAR flags;
+ USHORT flags2;
+ USHORT pid_high;
+
+ union {
+ USHORT pad[5];
+ struct {
+ USHORT reserved;
+ UCHAR security_sig[SMB_SIG_SIZE];
+ } extra;
+ } extra;
+
+ USHORT tid;
+ USHORT pid;
+ USHORT uid;
+ USHORT mid;
+} smb_hdr_t;
+
+
+/*
+ * Encoded or packed SMB header in network ready format.
+ */
+typedef struct smb_hdrbuf {
+ unsigned char hdr[SMB_HEADER_LEN];
+} smb_hdrbuf_t;
+
+typedef struct smb_nethdr {
+ uint8_t sh_protocol[4];
+ uint8_t sh_command;
+
+ union {
+ struct {
+ uint8_t sh_error_class;
+ uint8_t sh_reserved;
+ uint8_t sh_error[2];
+ } dos_error;
+ uint8_t sh_ntstatus[4];
+ } status;
+
+ uint8_t sh_flags;
+ uint8_t sh_flags2[2];
+ uint8_t sh_pid_high[2];
+
+ union {
+ uint8_t sh_pad[10];
+ struct {
+ uint8_t sh_reserved[2];
+ uint8_t sh_security_sig[SMB_SIG_SIZE];
+ } extra;
+ } extra;
+
+ uint8_t sh_tid[2];
+ uint8_t sh_pid[2];
+ uint8_t sh_uid[2];
+ uint8_t sh_mid[2];
+} smb_nethdr_t;
+
+/*
+ * Protocol magic value as a 32-bit. This will be 0xff 0x53 0x4d 0x42 on
+ * the wire.
+ */
+
+#define SMB_PROTOCOL_MAGIC 0x424d53ff
+
+/*
+ * Time and date encoding (CIFS Section 3.6). The date is encoded such
+ * that the year has a range of 0-119, which represents 1980-2099. The
+ * month range is 1-12, and the day range is 1-31.
+ */
+typedef struct smb_date {
+ USHORT day : 5;
+ USHORT month : 4;
+ USHORT year : 7;
+} smb_date_t;
+
+
+/*
+ * The hours range is 0-23, the minutes range is 0-59 and the two_sec
+ * range is 0-29.
+ */
+typedef struct smb_time {
+ USHORT two_sec : 5;
+ USHORT minutes : 6;
+ USHORT hours : 5;
+} smb_time_t;
+
+
+/*
+ * This is a 64-bit signed absolute time representing 100ns increments.
+ * A positive value represents the absolute time since 1601AD. A
+ * negative value represents a context specific relative time.
+ */
+typedef struct smb_time2 {
+ ULONG low_time;
+ LONG high_time;
+} smb_time2_t;
+
+
+/*
+ * The number of seconds since Jan 1, 1970, 00:00:00.0.
+ */
+typedef uint32_t smb_utime_t;
+
+
+#define SMB_LM_NEGOTIATE_WORDCNT 13
+#define SMB_NT_NEGOTIATE_WORDCNT 17
+
+
+typedef struct smb_nt_negotiate_rsp {
+ UCHAR word_count;
+ USHORT dialect_index;
+ UCHAR security_mode;
+ USHORT max_mpx;
+ USHORT max_vc;
+ ULONG max_buffer_size;
+ ULONG max_raw_size;
+ ULONG session_key;
+ ULONG capabilities;
+ ULONG time_low;
+ ULONG time_high;
+ USHORT server_tz;
+ UCHAR security_len;
+ USHORT byte_count;
+ UCHAR *guid;
+ UCHAR *challenge;
+ UCHAR *oem_domain;
+} smb_nt_negotiate_rsp_t;
+
+/*
+ * SMB_COM_TRANSACTION
+ */
+typedef struct smb_transact_rsp {
+ UCHAR WordCount; /* Count of data bytes */
+ /* value = 10 + SetupCount */
+ USHORT TotalParamCount; /* Total parameter bytes being sent */
+ USHORT TotalDataCount; /* Total data bytes being sent */
+ USHORT Reserved;
+ USHORT ParamCount; /* Parameter bytes sent this buffer */
+ USHORT ParamOffset; /* Offset (from hdr start) to params */
+ USHORT ParamDisplacement; /* Displacement of these param bytes */
+ USHORT DataCount; /* Data bytes sent this buffer */
+ USHORT DataOffset; /* Offset (from hdr start) to data */
+ USHORT DataDisplacement; /* Displacement of these data bytes */
+ UCHAR SetupCount; /* Count of setup words */
+ USHORT BCC;
+#if 0
+ UCHAR Reserved2; /* Reserved (pad above to word) */
+ UCHAR Buffer[1]; /* Buffer containing: */
+ USHORT Setup[]; /* Setup words (# = SetupWordCount) */
+ USHORT ByteCount; /* Count of data bytes */
+ UCHAR Pad[]; /* Pad to SHORT or LONG */
+ UCHAR Params[]; /* Param. bytes (# = ParamCount) */
+ UCHAR Pad1[]; /* Pad to SHORT or LONG */
+ UCHAR Data[]; /* Data bytes (# = DataCount) */
+#endif
+} smb_transact_rsp_t;
+
+/*
+ * SMBreadX
+ */
+typedef struct smb_read_andx_rsp {
+ UCHAR WordCount;
+ UCHAR AndXCmd;
+ UCHAR AndXReserved;
+ USHORT AndXOffset;
+ USHORT Remaining;
+ USHORT DataCompactionMode;
+ USHORT Reserved;
+ USHORT DataLength;
+ USHORT DataOffset;
+ ULONG DataLengthHigh;
+ USHORT Reserved2[3];
+ USHORT ByteCount;
+#if 0
+ UCHAR Pad[];
+ UCHAR Data[];
+#endif
+} smb_read_andx_rsp_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_SMB_H */
diff --git a/usr/src/uts/common/smbsrv/smb_common_door.h b/usr/src/uts/common/smbsrv/smb_common_door.h
new file mode 100644
index 0000000000..07ff2f1dd4
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_common_door.h
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMB_COMMON_DOOR_H
+#define _SMBSRV_SMB_COMMON_DOOR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/wintypes.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_token.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int smb_dr_get_opcode(char *argp, size_t arg_size);
+extern int smb_dr_get_res_stat(char *rbufp, size_t rbuf_size);
+extern char *smb_dr_set_opcode(uint32_t opcode, size_t *len);
+extern char *smb_dr_set_res_stat(uint32_t stat, size_t *len);
+extern char *smb_dr_encode_string(uint32_t reserved, char *buf, size_t *len);
+
+#ifdef _KERNEL
+extern int smb_kdr_decode_common(char *buf, size_t len, xdrproc_t proc,
+ void *data);
+extern char *smb_kdr_encode_common(uint_t reserved, void *data,
+ xdrproc_t proc, size_t *len);
+
+/* kernel encode functions */
+extern char *smb_dr_encode_arg_get_token(netr_client_t *clnt_info,
+ size_t *len);
+/* kernel decode functions */
+extern smb_token_t *smb_dr_decode_res_token(char *buf, size_t len);
+extern smb_dr_kshare_t *smb_dr_decode_kshare(char *buf, size_t len);
+
+/* kernel free functions */
+void smb_dr_kshare_free(smb_dr_kshare_t *kshare);
+#else /* _KERNEL */
+extern int smb_dr_decode_common(char *buf, size_t len, xdrproc_t proc,
+ void *data);
+extern char *smb_dr_encode_common(uint_t reserved, void *data, xdrproc_t proc,
+ size_t *len);
+
+/* user-space encode functions */
+extern char *smb_dr_encode_res_token(smb_token_t *token, size_t *len);
+extern char *smb_dr_encode_kshare(smb_dr_kshare_t *, size_t *);
+
+/* user-space decode functions */
+extern netr_client_t *smb_dr_decode_arg_get_token(char *buf, size_t len);
+extern char *smb_dr_decode_string(char *buf, size_t len);
+
+/* user-space free functions */
+extern void smb_dr_ulist_free(smb_dr_ulist_t *ulist);
+#endif /* _KERNEL */
+
+/*
+ * PBSHORTCUT - should be removed once XDR is used for
+ * serializing/deserializing data across door.
+ */
+
+/*
+ * Common encode/decode functions used by door clients/servers.
+ */
+
+typedef struct smb_dr_ctx {
+ char *ptr;
+ char *start_ptr;
+ char *end_ptr;
+ int status;
+} smb_dr_ctx_t;
+
+
+extern smb_dr_ctx_t *smb_dr_decode_start(char *ptr, int size);
+extern int smb_dr_decode_finish(smb_dr_ctx_t *ctx);
+
+extern smb_dr_ctx_t *smb_dr_encode_start(char *ptr, int size);
+extern int smb_dr_encode_finish(smb_dr_ctx_t *ctx, unsigned int *used);
+
+extern int32_t smb_dr_get_int32(smb_dr_ctx_t *ctx);
+extern DWORD smb_dr_get_dword(smb_dr_ctx_t *ctx);
+extern uint32_t smb_dr_get_uint32(smb_dr_ctx_t *ctx);
+extern int64_t smb_dr_get_int64(smb_dr_ctx_t *ctx);
+extern uint64_t smb_dr_get_uint64(smb_dr_ctx_t *ctx);
+
+extern void smb_dr_put_int32(smb_dr_ctx_t *ctx, int32_t num);
+extern void smb_dr_put_dword(smb_dr_ctx_t *ctx, DWORD num);
+extern void smb_dr_put_uint32(smb_dr_ctx_t *ctx, uint32_t num);
+extern void smb_dr_put_int64(smb_dr_ctx_t *ctx, int64_t num);
+extern void smb_dr_put_uint64(smb_dr_ctx_t *ctx, uint64_t num);
+
+extern char *smb_dr_get_string(smb_dr_ctx_t *ctx);
+extern void smb_dr_put_string(smb_dr_ctx_t *ctx, char *buf);
+extern void smb_dr_free_string(char *buf);
+
+extern void smb_dr_put_word(smb_dr_ctx_t *ctx, WORD num);
+extern WORD smb_dr_get_word(smb_dr_ctx_t *ctx);
+
+extern void smb_dr_put_BYTE(smb_dr_ctx_t *ctx, BYTE byte);
+extern BYTE smb_dr_get_BYTE(smb_dr_ctx_t *ctx);
+
+extern void smb_dr_put_buf(smb_dr_ctx_t *ctx, unsigned char *start, int len);
+extern int smb_dr_get_buf(smb_dr_ctx_t *ctx, unsigned char *buf, int bufsize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_COMMON_DOOR_H */
diff --git a/usr/src/uts/common/smbsrv/smb_door_svc.h b/usr/src/uts/common/smbsrv/smb_door_svc.h
new file mode 100644
index 0000000000..be8898f42a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_door_svc.h
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMB_DOOR_SVC_H
+#define _SMBSRV_SMB_DOOR_SVC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_token.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SMB door service (user-space and kernel-space)
+ */
+#define SMB_DR_SVC_NAME "/var/run/smbd_door"
+#define SMB_DR_SVC_VERSION 1
+#define SMB_DR_SVC_COOKIE ((void*)(0xdeadbeef^SMB_DR_SVC_VERSION))
+
+/*
+ * Door argument buffer starts off by the four-byte opcode.
+ * Door result buffer starts off by the four-byte status.
+ * The real data starts at offset 4 of the door buffer.
+ */
+#define SMB_DR_DATA_OFFSET 4
+
+/*
+ * A smb_dr_op_t exists for each user-space door operation.
+ * A smb_kdr_op_t exists for each kernel-space door operation.
+ *
+ * The first argument to smb_dr_op_t/smb_kdr_op_t is a pointer to the
+ * door argument buffer. The second argument indicates the size of
+ * the door argument buffer.
+ *
+ * The user-space door server accepts file descriptors from clients.
+ * Thus, door_desc_t and n_desc can be passed to any smb_dr_op_t operation.
+ *
+ * Returns door result buffer and its size 'rbufsize' upon success.
+ * Otherwise, NULL pointer will be returned and appropriate error code
+ * will be set.
+ */
+typedef char *(*smb_dr_op_t)(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t n_desc, size_t *rbufsize, int *err);
+typedef char *(*smb_kdr_op_t)(char *argp, size_t arg_size, size_t *rbufsize,
+ int *errno);
+
+extern smb_dr_op_t smb_doorsrv_optab[];
+
+/*
+ * Door Opcode
+ * -------------
+ * smb_dr_opcode_t - opcodes for user-space door operations.
+ * smb_kdr_opcode_t - opcodes for kernel-space door operations.
+ */
+enum smb_dr_opcode_t {
+ SMB_DR_USER_AUTH_LOGON,
+ SMB_DR_SET_DWNCALL_DESC,
+ SMB_DR_USER_NONAUTH_LOGON,
+ SMB_DR_USER_AUTH_LOGOFF,
+ SMB_DR_USER_LIST,
+ SMB_DR_GROUP_ADD,
+ SMB_DR_GROUP_DELETE,
+ SMB_DR_GROUP_MEMBER_ADD,
+ SMB_DR_GROUP_MEMBER_REMOVE,
+ SMB_DR_GROUP_COUNT,
+ SMB_DR_GROUP_CACHE_SIZE,
+ SMB_DR_GROUP_MODIFY,
+ SMB_DR_GROUP_PRIV_NUM,
+ SMB_DR_GROUP_PRIV_LIST,
+ SMB_DR_GROUP_PRIV_GET,
+ SMB_DR_GROUP_PRIV_SET,
+ SMB_DR_GROUP_LIST,
+ SMB_DR_GROUP_MEMBER_LIST,
+ SMB_DR_GROUP_MEMBER_COUNT
+};
+
+enum smb_kdr_opcode_t {
+ SMB_KDR_USER_NUM,
+ SMB_KDR_USER_LIST,
+ SMB_KDR_SHARE
+};
+
+/*
+ * Door result status
+ * SMB door servers will pass the following result status along with the
+ * requested data back to the clients.
+ */
+#define SMB_DR_OP_SUCCESS 0
+#define SMB_DR_OP_ERR 1
+#define SMB_DR_OP_ERR_DECODE 2
+#define SMB_DR_OP_ERR_ENCODE 3
+#define SMB_DR_OP_ERR_EMPTYBUF 4
+#define SMB_DR_OP_ERR_INVALID_OPCODE 5
+
+#ifdef _KERNEL
+/*
+ * The 2nd argument of the smb_kdoor_srv_callback will be of the
+ * following data structure type.
+ *
+ * rbuf - The pointer to a dynamically allocated door result buffer that
+ * is required to be freed after the kernel completes the copyout
+ * operation.
+ */
+typedef struct smb_kdoor_cb_arg {
+ char *rbuf;
+ size_t rbuf_size;
+} smb_kdoor_cb_arg_t;
+
+/*
+ * SMB kernel door server
+ * ------------------------
+ * NOTE: smb_kdoor_srv_init()/smb_kdoor_srv_fini() are noops.
+ */
+extern int smb_kdoor_srv_start();
+extern void smb_kdoor_srv_stop();
+extern int smb_kdr_is_valid_opcode(int opcode);
+
+extern char *smb_kdr_op_user_num(char *argp, size_t arg_size,
+ size_t *rbufsize, int *errno);
+extern char *smb_kdr_op_users(char *argp, size_t arg_size,
+ size_t *rbufsize, int *errno);
+extern char *smb_kdr_op_share(char *argp, size_t arg_size,
+ size_t *rbufsize, int *errno);
+
+/*
+ * SMB kernel door client
+ * ------------------------
+ * NOTE: smb_kdoor_clnt_init()/smb_kdoor_clnt_fini() are noops.
+ */
+extern int smb_kdoor_clnt_start();
+extern void smb_kdoor_clnt_stop();
+extern void smb_kdoor_clnt_free();
+extern char *smb_kdoor_clnt_upcall(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t desc_num, size_t *rbufsize);
+
+/*
+ * SMB upcalls
+ */
+extern smb_token_t *smb_upcall_get_token(netr_client_t *clnt_info);
+extern int smb_upcall_set_dwncall_desc(uint32_t opcode, door_desc_t *dp,
+ uint_t n_desc);
+extern void smb_user_nonauth_logon(uint32_t);
+extern void smb_user_auth_logoff(uint32_t);
+#else /* _KERNEL */
+
+/*
+ * SMB user-space door server
+ */
+extern int smb_door_srv_start();
+extern void smb_door_srv_stop(void);
+
+/* downcall descriptor */
+typedef int (*smb_dwncall_get_desc_t)();
+extern int smb_dwncall_install_callback(smb_dwncall_get_desc_t get_desc_cb);
+
+extern int smb_dr_is_valid_opcode(int opcode);
+
+/*
+ * SMB user-space door client
+ */
+extern int smb_dr_clnt_open(int *fd, char *path, char *op_desc);
+extern char *smb_dr_clnt_call(int fd, char *argp, size_t arg_size,
+ size_t *rbufsize, char *op_desc);
+extern void smb_dr_clnt_free(char *argp, size_t arg_size, char *rbufp,
+ size_t rbuf_size);
+/*
+ * SMB downcalls
+ */
+extern int smb_dwncall_get_users(int offset, smb_dr_ulist_t *users);
+extern int smb_dwncall_share(int op, char *path, char *sharename);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_DOOR_SVC_H */
diff --git a/usr/src/uts/common/smbsrv/smb_fsd.h b/usr/src/uts/common/smbsrv/smb_fsd.h
new file mode 100644
index 0000000000..e2fe7787b8
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_fsd.h
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_FSD_H
+#define _SMBSRV_SMB_FSD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/vfs.h>
+#include <sys/refstr_impl.h>
+#include <sys/stat.h>
+
+#ifndef _KERNEL
+#include <stdio.h>
+#include <sys/mnttab.h>
+#endif
+
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * VOL_NAME_MAX is derived from Montana's FSOL_NAME_MAX (32).
+ * This is consistent with MAX_FS_NAME from PB fsadm (QFS).
+ */
+
+#define VOL_NAME_MAX 32
+
+typedef struct fsvol_attr {
+ char name[VOL_NAME_MAX];
+ char fs_typename[_ST_FSTYPSZ];
+ unsigned flags;
+ uint32_t fs_sequence;
+} fsvol_attr_t;
+
+/*
+ * Note: fsid_t consists of two 32-bit values.
+ * The first corresponds to the dev and the second to the file system type.
+ * The fsid_t uniquely (and persistently) denotes a file system in a running
+ * system.
+ *
+ * For the CIFS volume serial number, fsid.val[0] is used (a 32-bit value
+ * is expected by TRANS2_QUERY_FS_INFORMATION).
+ */
+
+#define fs_desc_t fsid_t
+
+extern fs_desc_t null_fsd;
+
+#ifdef _KERNEL
+
+void *fsd_lookup(char *, unsigned, fs_desc_t *);
+int fsd_cmp(fs_desc_t *, fs_desc_t *);
+int fsd_getattr(fs_desc_t *, fsvol_attr_t *);
+int fsd_chkcap(fs_desc_t *, unsigned);
+
+void *fsd_hold(fs_desc_t *fsd);
+void fsd_rele(void *vfsp);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_FSD_H */
diff --git a/usr/src/uts/common/smbsrv/smb_fsops.h b/usr/src/uts/common/smbsrv/smb_fsops.h
new file mode 100644
index 0000000000..56a15aa2d0
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_fsops.h
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMB_FSOPS_H
+#define _SMBSRV_SMB_FSOPS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This header file contains all the functions for the interface between
+ * the smb layer and the fs layer.
+ */
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_vops.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int smb_fsop_open(smb_ofile_t *of);
+
+int smb_fsop_close(smb_ofile_t *of);
+
+int smb_fsop_create(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ char *name, smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr);
+
+int smb_fsop_mkdir(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ char *name, smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr);
+
+int smb_fsop_remove(struct smb_request *sr, cred_t *cr, smb_node_t *dir_snode,
+ char *name, int od);
+
+int smb_fsop_rmdir(struct smb_request *sr, cred_t *cr, smb_node_t *dir_snode,
+ char *name, int od);
+
+int smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ smb_attr_t *attr);
+
+int smb_fsop_readdir(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t *cookie, char *name, int *namelen, ino64_t *fileid,
+ struct fs_stream_info *stream_info, smb_node_t **ret_snode,
+ smb_attr_t *ret_attr);
+
+int smb_fsop_getdents(struct smb_request *sr, cred_t *cr,
+ struct smb_node *dir_snode, uint32_t *cookie, uint64_t *verifierp,
+ int32_t *maxcnt, char *args, char *pattern);
+
+int smb_maybe_mangled_name(char *name);
+
+int smb_fsop_rename(struct smb_request *sr, cred_t *cr,
+ smb_node_t *from_snode, char *from_name, smb_node_t *to_snode,
+ char *to_name);
+
+int smb_fsop_setattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ smb_attr_t *set_attr, smb_attr_t *ret_attr);
+
+int smb_fsop_read(struct smb_request *sr, cred_t *cr,
+ smb_node_t *snode, uio_t *uio, smb_attr_t *ret_attr);
+
+int smb_fsop_write(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ uio_t *uio, uint32_t *lcount, smb_attr_t *ret_attr,
+ uint32_t *stability);
+
+int smb_fsop_statfs(cred_t *cr, struct smb_node *snode,
+ struct statvfs64 *statp);
+
+int smb_fsop_remove_streams(struct smb_request *sr, cred_t *cr,
+ smb_node_t *fnode);
+
+int smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t faccess);
+
+void smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t *faccess);
+
+int smb_fsop_lookup_name(struct smb_request *sr, cred_t *cr, int flags,
+ smb_node_t *root_node, smb_node_t *dir_snode, char *name,
+ smb_node_t **ret_snode, smb_attr_t *ret_attr);
+
+int smb_fsop_lookup(struct smb_request *sr, cred_t *cr, int flags,
+ smb_node_t *root_node, smb_node_t *dir_snode, char *name,
+ smb_node_t **ret_snode, smb_attr_t *ret_attr, char *ret_shortname,
+ char *ret_name83);
+
+int smb_fsop_commit(smb_request_t *sr, cred_t *cr, struct smb_node *snode);
+
+int smb_fsop_stream_readdir(struct smb_request *sr, cred_t *cr,
+ smb_node_t *fnode, uint32_t *cookiep, struct fs_stream_info *stream_info,
+ smb_node_t **ret_snode, smb_attr_t *ret_attr);
+
+void smb_fsop_aclfree(acl_t *acl);
+acl_t *smb_fsop_aclalloc(int acenum, int flags);
+int smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fssd);
+int smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd);
+acl_type_t smb_fsop_acltype(smb_node_t *snode);
+
+void smb_fsop_sdinit(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t sd_flags);
+void smb_fsop_sdterm(smb_fssd_t *fssd);
+int smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fssd);
+int smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd, int overwrite);
+
+
+void smb_get_caller_context(smb_request_t *sr, caller_context_t *ct);
+
+/*
+ * Lookup-related flags
+ *
+ * SMB_FOLLOW_LINKS Follow symbolic links.
+ * SMB_IGNORE_CASE Perform case-insensitive lookup.
+ *
+ * Misc flags
+ *
+ * SMB_STREAM_RDDIR use eflags=0 for streams readdirs this
+ * is currently a workaround because the
+ * vfs isn't filling in this flag
+ */
+
+#define SMB_FOLLOW_LINKS 0x00000001
+#define SMB_IGNORE_CASE 0x00000002
+#define SMB_STREAM_RDDIR 0x00000004
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_FSOPS_H */
diff --git a/usr/src/uts/common/smbsrv/smb_i18n.h b/usr/src/uts/common/smbsrv/smb_i18n.h
new file mode 100644
index 0000000000..74804d0056
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_i18n.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMB_I18N_H
+#define _SMB_I18N_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned short mts_wchar_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_I18N_H */
diff --git a/usr/src/uts/common/smbsrv/smb_idmap.h b/usr/src/uts/common/smbsrv/smb_idmap.h
new file mode 100644
index 0000000000..0f6380f1bf
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_idmap.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMB_IDMAP_H
+#define _SMB_IDMAP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#else
+#include <idmap.h>
+#endif
+
+#include <smbsrv/ntsid.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SMB ID mapping
+ *
+ * Solaris ID mapping service (aka Winchester) works with domain SIDs
+ * and RIDs where domain SIDs are in string format. CIFS service works
+ * with binary SIDs understanable by CIFS clients. A layer of SMB ID
+ * mapping functions are implemeted to hide the SID conversion details
+ * and also hide the handling of array of batch mapping requests.
+ */
+
+#define SMB_IDMAP_UNKNOWN -1
+#define SMB_IDMAP_GROUP 0
+#define SMB_IDMAP_USER 1
+#define SMB_IDMAP_EVERYONE 2
+
+#define SMB_IDMAP_SID2ID 0x0001
+#define SMB_IDMAP_ID2SID 0x0002
+
+/*
+ * smb_idmap_t
+ *
+ * sim_idtype: ID type (output in sid->uid mapping)
+ * sim_id: UID/GID (output in sid->uid mapping)
+ */
+typedef struct smb_idmap {
+ int sim_idtype;
+ uid_t *sim_id;
+ char *sim_domsid;
+ uint32_t sim_rid;
+ nt_sid_t *sim_sid;
+ idmap_stat sim_stat;
+} smb_idmap_t;
+
+typedef struct smb_idmap_batch {
+ uint16_t sib_nmap;
+ uint32_t sib_flags;
+ uint32_t sib_size;
+ smb_idmap_t *sib_maps;
+ idmap_get_handle_t *sib_idmaph;
+} smb_idmap_batch_t;
+
+idmap_stat smb_idmap_getsid(uid_t, int, nt_sid_t **);
+idmap_stat smb_idmap_getid(nt_sid_t *, uid_t *, int *);
+
+void smb_idmap_batch_destroy(smb_idmap_batch_t *);
+idmap_stat smb_idmap_batch_create(smb_idmap_batch_t *, uint16_t, int);
+idmap_stat smb_idmap_batch_getmappings(smb_idmap_batch_t *);
+idmap_stat smb_idmap_batch_getid(idmap_get_handle_t *, smb_idmap_t *,
+ nt_sid_t *, int);
+idmap_stat smb_idmap_batch_getsid(idmap_get_handle_t *, smb_idmap_t *,
+ uid_t, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMB_IDMAP_H */
diff --git a/usr/src/uts/common/smbsrv/smb_incl.h b/usr/src/uts/common/smbsrv/smb_incl.h
new file mode 100644
index 0000000000..b9cdaa3f13
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_incl.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMB_INCL_H
+#define _SMBSRV_SMB_INCL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/cmn_err.h>
+#include <sys/cpuvar.h>
+#include <sys/list.h>
+#include <sys/sunddi.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+
+#include <smbsrv/alloc.h>
+#include <smbsrv/ctype.h>
+#include <smbsrv/string.h>
+
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/doserror.h>
+#include <smbsrv/cifs.h>
+#include <smbsrv/ntaccess.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb.h>
+
+#include <smbsrv/smbvar.h>
+#include <smbsrv/smbfmt.h>
+#include <smbsrv/smb_kproto.h>
+
+#define QUEUE_INSERT_HEAD(q, e) \
+ { \
+ ((e)->forw) = (void *)((q)->forw); \
+ ((e)->back) = (void *)(q); \
+ ((q)->forw->back) = (void *)(e); \
+ ((q)->forw) = (void *)(e); \
+ }
+
+
+#define QUEUE_INSERT_TAIL(q, e) \
+ { \
+ ((e)->back) = (void *)((q)->back); \
+ ((e)->forw) = (void *)(q); \
+ ((q)->back->forw) = (void *)(e); \
+ ((q)->back) = (void *)(e); \
+ }
+
+#define QUEUE_INSERT_SORT(q, e, k, t) \
+ { \
+ (void *)(t) = (void *)((q)->forw); \
+ while (((t)->k) < ((e)->k)) { \
+ (void *)(t) = (void *)((t)->forw); \
+ } \
+ QUEUE_INSERT_TAIL(t, e); \
+ }
+
+#define QUEUE_CLIP(e) \
+ { \
+ (e)->forw->back = (e)->back; \
+ (e)->back->forw = (e)->forw; \
+ (e)->forw = 0; \
+ (e)->back = 0; \
+ }
+
+/* These should be defined in system header files */
+
+extern int atoi(const char *);
+extern int getchar(void);
+
+/*
+ * PBSHORTCUT - remove this when we replace BYTE/WORD/DWORD to
+ * uint8_t/uint16_t/uint32_t and <inet/ip.h> gets included by
+ * files that invoke the following functions.
+ */
+extern char *inet_ntop(int, const void *, char *, int);
+extern int inet_pton(int, char *, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_INCL_H */
diff --git a/usr/src/uts/common/smbsrv/smb_ioctl.h b/usr/src/uts/common/smbsrv/smb_ioctl.h
new file mode 100755
index 0000000000..6b6ad051fb
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_ioctl.h
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_IOCTL_H_
+#define _SMB_IOCTL_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define SMB_IOC_BASE (('S' << 16) | ('B' << 8))
+#define SMB_IOC_GMTOFF _IOW(SMB_IOC_BASE, 1, int)
+#define SMB_IOC_CONFIG_REFRESH _IOW(SMB_IOC_BASE, 2, int)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_IOCTL_H_ */
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
new file mode 100644
index 0000000000..26ac73055e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -0,0 +1,602 @@
+/*
+ * 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.
+ */
+
+/*
+ * Function prototypes for the SMB module.
+ */
+
+#ifndef _SMB_KPROTO_H_
+#define _SMB_KPROTO_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/strsubr.h>
+#include <sys/socketvar.h>
+#include <sys/cred.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_token.h>
+
+/*
+ * Definitions that should be elsewhere...
+ */
+struct mbuf *m_free(struct mbuf *);
+void m_freem(struct mbuf *);
+
+int fd_dealloc(int);
+
+off_t lseek(int fildes, off_t offset, int whence);
+
+int arpioctl(int cmd, void *data);
+/* Why? uint32_t inet_addr(char *str); */
+int microtime(timestruc_t *tvp);
+int clock_get_uptime(void);
+
+/*
+ * SMB Service init/shutdown functions
+ */
+int smb_service_init(void);
+void smb_service_fini(void);
+int smb_service_open(struct smb_info *si);
+void smb_service_close(struct smb_info *si);
+int smb_service_connect(struct smb_info *si);
+void smb_service_disconnect(struct smb_info *si);
+int smb_service_start_threads(struct smb_info *si);
+void smb_service_stop_threads(struct smb_info *si);
+
+/*
+ * Logging functions
+ */
+void smb_log_flush(void);
+void smb_correct_keep_alive_values(uint32_t new_keep_alive);
+void smb_close_all_connections(void);
+int smb_set_file_size(struct smb_request *sr);
+int smb_session_send(smb_session_t *, uint8_t type, struct mbuf_chain *);
+int smb_session_xprt_gethdr(smb_session_t *, smb_xprt_t *);
+
+int smb_net_id(uint32_t);
+uint32_t smb_gmt_to_local_time(uint32_t);
+uint32_t smb_local_time_to_gmt(uint32_t);
+
+void smb_process_file_notify_change_queue(struct smb_ofile *of);
+
+void smb_oplock_init(void);
+
+DWORD smb_acquire_oplock(struct smb_request *sr,
+ struct smb_ofile *file,
+ unsigned int level_requested,
+ unsigned int *level_granted);
+
+DWORD smb_break_oplock(struct smb_request *sr, struct smb_node *node);
+void smb_release_oplock(struct smb_ofile *file, int reason);
+
+uint32_t smb_unlock_range(struct smb_request *, struct smb_node *,
+ uint64_t, uint64_t);
+void smb_unlock_range_raise_error(smb_request_t *sr, uint32_t ntstatus);
+uint32_t smb_lock_range(struct smb_request *, struct smb_ofile *,
+ uint64_t, uint64_t, uint32_t, uint32_t);
+void smb_lock_range_raise_error(smb_request_t *sr, uint32_t ntstatus);
+
+int smb_mangle_name(ino64_t fileid, char *name, char *shortname,
+ char *name83, int force);
+int smb_unmangle_name(struct smb_request *sr, cred_t *cred,
+ smb_node_t *dir_node, char *name, char *real_name, int realname_size,
+ char *shortname, char *name83, int od);
+int smb_maybe_mangled_name(char *name);
+int smb_maybe_mangled_path(const char *path, size_t pathlen);
+int smb_needs_mangle(char *name, char **dot_pos);
+
+void smb_set_stability(int mode);
+void smb_commit_required(int state);
+
+
+void smbsr_cleanup(struct smb_request *sr);
+
+int smbsr_connect_tree(struct smb_request *);
+
+int smb_convert_unicode_wildcards(char *);
+int smb_ascii_or_unicode_strlen(struct smb_request *, char *);
+int smb_ascii_or_unicode_strlen_null(struct smb_request *, char *);
+int smb_ascii_or_unicode_null_len(struct smb_request *);
+
+int smb_search(struct smb_request *);
+void smb_rdir_close(struct smb_request *);
+int smb_rdir_open(struct smb_request *, char *, unsigned short);
+int smb_rdir_next(smb_request_t *sr, smb_node_t **rnode,
+ smb_odir_context_t *pc);
+
+DWORD smb_open_subr(struct smb_request *);
+DWORD smb_validate_object_name(char *path, unsigned int ftype);
+
+uint32_t smb_omode_to_amask(uint32_t desired_access);
+
+void sshow_distribution_info(char *);
+
+int smb_dispatch_request(struct smb_request *);
+void smbsr_disconnect_file(smb_request_t *sr);
+void smbsr_disconnect_dir(smb_request_t *sr);
+void smbsr_check_result(struct smb_request *, int, int);
+void smbsr_decode_error(struct smb_request *);
+void smbsr_encode_error(struct smb_request *);
+void smbsr_encode_empty_result(struct smb_request *sr);
+
+#pragma does_not_return(smbsr_decode_error)
+#pragma does_not_return(smbsr_encode_error)
+
+int smbsr_decode_vwv(struct smb_request *sr, char *fmt, ...);
+int smbsr_decode_data(struct smb_request *sr, char *fmt, ...);
+void smbsr_encode_result(struct smb_request *, int, int, char *, ...);
+smb_xa_t *smbsr_lookup_xa(smb_request_t *sr);
+void smbsr_send_reply(struct smb_request *);
+
+void smbsr_raise_cifs_error(struct smb_request *sr, DWORD status,
+ int error_class, int error_code);
+
+int smbsr_set_errno(struct smb_request *, int);
+void smbsr_raise_errno(struct smb_request *, int);
+void smbsr_raise_error(struct smb_request *, int, int);
+void smbsr_raise_nt_error(struct smb_request *sr, uint32_t);
+
+#pragma does_not_return(smbsr_raise_cifs_error)
+#pragma does_not_return(smbsr_raise_error)
+#pragma does_not_return(smbsr_raise_nt_error)
+#pragma does_not_return(smbsr_raise_errno)
+
+void smbsr_setup_nt_status(struct smb_request *sr,
+ uint32_t severity,
+ uint32_t nt_status);
+
+int smb_mbc_encode(struct mbuf_chain *mbc, char *fmt, va_list ap);
+int smb_mbc_decode(struct mbuf_chain *mbc, char *fmt, va_list ap);
+
+int clock_get_milli_uptime(void);
+int dosfs_dos_to_ux_time(int, int);
+int dosfs_ux_to_dos_time(int, short int *, short int *);
+
+int smb_decode_mbc(struct mbuf_chain *mbc, char *fmt, ...);
+int smb_decode_buf(unsigned char *buf, int n_buf, char *fmt, ...);
+int smb_encode_mbc(struct mbuf_chain *mbc, char *fmt, ...);
+int smb_encode_buf(unsigned char *buf, int n_buf, char *fmt, ...);
+int smb_peek_mbc(struct mbuf_chain *buf, int offset, char *fmt, ...);
+int smb_poke_mbc(struct mbuf_chain *buf, int offset, char *fmt, ...);
+
+void smbsr_encode_header(struct smb_request *sr, int wct,
+ int bcc, char *fmt, ...);
+
+int smb_xlate_dialect_str_to_cd(char *);
+char *smb_xlate_com_cd_to_str(int);
+char *smb_xlate_dialect_cd_to_str(int);
+
+void smb_od_destruct(struct smb_session *, struct smb_odir *);
+int smbd_fs_query(struct smb_request *, struct smb_fqi *, int);
+int smb_component_match(struct smb_request *sr, ino64_t fileid,
+ struct smb_odir *od, smb_odir_context_t *pc);
+
+int smb_lock_range_access(struct smb_request *, struct smb_node *,
+ uint64_t, uint64_t, uint32_t desired_access);
+
+/*
+ * Socket functions
+ */
+struct sonode *smb_socreate(int domain, int type, int protocol);
+void smb_soshutdown(struct sonode *so);
+void smb_sodestroy(struct sonode *so);
+int smb_sosend(struct sonode *so, void *msg, size_t len);
+int smb_sorecv(struct sonode *so, void *msg, size_t len);
+int smb_iov_sosend(struct sonode *so, iovec_t *iop, int iovlen,
+ size_t total_len);
+int smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen,
+ size_t total_len);
+
+/*
+ * SMB RPC interface
+ */
+int smb_rpc_open(struct smb_request *sr);
+void smb_rpc_close(struct smb_ofile *of);
+int smb_rpc_transact(struct smb_request *sr, struct uio *uio);
+int smb_rpc_read(struct smb_request *sr, struct uio *uio);
+int smb_rpc_write(struct smb_request *sr, struct uio *uio);
+
+/*
+ * SMB node functions (file smb_node.c)
+ */
+struct smb_node *smb_node_lookup(struct smb_request *sr, struct open_param *op,
+ cred_t *cr, vnode_t *vp, char *od_name, smb_node_t *dir_snode,
+ smb_node_t *unnamed_node, smb_attr_t *attr);
+struct smb_node *smb_stream_node_lookup(struct smb_request *sr, cred_t *cr,
+ smb_node_t *fnode, vnode_t *xattrdirvp, vnode_t *vp, char *stream_name,
+ smb_attr_t *ret_attr);
+void smb_node_ref(smb_node_t *node);
+void smb_node_release(smb_node_t *node);
+int smb_node_assert(smb_node_t *node, const char *file, int line);
+int smb_node_rename(smb_node_t *from_dir_snode, smb_node_t *ret_snode,
+ smb_node_t *to_dir_snode, char *to_name);
+int smb_node_root_init();
+void smb_node_root_fini();
+void smb_node_add_lock(smb_node_t *node, smb_lock_t *lock);
+void smb_node_destroy_lock(smb_node_t *node, smb_lock_t *lock);
+void smb_node_destroy_lock_by_ofile(smb_node_t *node, smb_ofile_t *file);
+uint64_t smb_node_get_size(smb_node_t *node, smb_attr_t *attr);
+void smb_node_set_time(struct smb_node *node, timestruc_t *crtime,
+ timestruc_t *mtime, timestruc_t *atime,
+ timestruc_t *ctime, unsigned int what);
+timestruc_t *smb_node_get_crtime(struct smb_node *node);
+timestruc_t *smb_node_get_atime(struct smb_node *node);
+timestruc_t *smb_node_get_ctime(struct smb_node *node);
+timestruc_t *smb_node_get_mtime(struct smb_node *node);
+void smb_node_set_dosattr(struct smb_node *, uint32_t);
+uint32_t smb_node_get_dosattr(struct smb_node *node);
+int smb_node_set_delete_on_close(smb_node_t *, cred_t *);
+void smb_node_reset_delete_on_close(smb_node_t *);
+
+
+
+/*
+ * Pathname functions
+ */
+
+int smb_pathname_reduce(struct smb_request *, cred_t *,
+ const char *, smb_node_t *, smb_node_t *, smb_node_t **, char *);
+
+int smb_pathname(struct smb_request *, char *, int, smb_node_t *,
+ smb_node_t *, smb_node_t **, smb_node_t **, cred_t *);
+
+/*
+ * Share functions
+ */
+
+int smb_share_export(char *);
+int smb_share_unexport(char *, char *);
+
+/*
+ * smb_vfs functions
+ */
+
+boolean_t smb_vfs_hold(vfs_t *);
+void smb_vfs_rele(vfs_t *);
+void smb_vfs_rele_all(void);
+
+/*
+ * String manipulation function
+ */
+char *smb_kstrdup(const char *s, size_t n);
+
+int smb_sync_fsattr(struct smb_request *sr, cred_t *cr,
+ struct smb_node *node);
+
+int smb_com_create_directory(struct smb_request *sr);
+DWORD smb_validate_dirname(char *path);
+
+int smb_com_trans2_create_directory(struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_find_first2(struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_find_next2(struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_query_fs_information(struct smb_request *sr,
+ struct smb_xa *xa);
+int smb_com_trans2_query_path_information(
+ struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_query_file_information(
+ struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_set_path_information(
+ struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_set_file_information(
+ struct smb_request *sr, struct smb_xa *xa);
+
+void smb_encode_stream_info(struct smb_request *sr, struct smb_xa *xa,
+ smb_node_t *snode, smb_attr_t *attr);
+
+int smb_nt_transact_create(struct smb_request *sr, struct smb_xa *xa);
+int smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa);
+int smb_nt_transact_query_security_info(struct smb_request *sr,
+ struct smb_xa *xa);
+int smb_nt_transact_set_security_info(struct smb_request *sr,
+ struct smb_xa *xa);
+int smb_nt_transact_ioctl(struct smb_request *sr, struct smb_xa *xa);
+
+/* NOTIFY CHANGE */
+int smb_reply_notify_change_request(smb_request_t *sr);
+void smb_process_session_notify_change_queue(struct smb_session *session);
+void smb_process_node_notify_change_queue(struct smb_node *node);
+void smb_reply_specific_cancel_request(struct smb_request *sr);
+
+void smb_fem_fcn_install(smb_node_t *node);
+void smb_fem_fcn_uninstall(smb_node_t *node);
+
+/* FEM */
+
+int smb_fem_init();
+void smb_fem_shutdown();
+
+int smb_try_grow(struct smb_request *sr, int64_t new_size);
+
+/* functions from smb_memory_manager.c */
+
+void *smbsr_malloc(smb_malloc_list *, size_t);
+void *smbsr_realloc(void *, size_t);
+void smbsr_free_malloc_list(smb_malloc_list *);
+
+void smbsr_rq_notify(smb_request_t *sr,
+ smb_session_t *session, smb_tree_t *tree);
+
+unsigned short smb_worker_getnum();
+int smb_common_close(struct smb_request *sr, uint32_t last_wtime);
+void smb_preset_delete_on_close(struct smb_ofile *file);
+void smb_commit_delete_on_close(struct smb_ofile *file);
+
+int smb_stream_parse_name(char *name, char *u_stream_name,
+ char *stream_name);
+
+uint32_t smb_get_gmtoff(void);
+void smb_set_gmtoff(uint32_t);
+
+void smb_errmap_unix2smb(int en, smb_error_t *smberr);
+DWORD smb_trans2_set_information(struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr);
+
+/* SMB signing routines smb_signing.c */
+void smb_sign_init(struct smb_request *req,
+ smb_session_key_t *session_key, char *resp, int resp_len);
+
+int smb_sign_check_request(struct smb_request *req);
+
+int smb_sign_check_secondary(struct smb_request *req, unsigned int seqnum);
+
+void smb_sign_reply(struct smb_request *req, struct mbuf_chain *reply);
+
+uint32_t smb_mode_to_dos_attributes(smb_attr_t *ap);
+int smb_sattr_check(smb_attr_t *ap, char *name, unsigned short sattr);
+
+smb_request_t *smb_request_alloc(struct smb_session *session,
+ int request_length);
+void smb_request_cancel(smb_request_t *sr);
+void smb_request_free(smb_request_t *sr);
+
+smb_session_t *smb_session_create(struct sonode *new_so, uint16_t port);
+void smb_session_delete(smb_session_t *session);
+void smb_session_cancel(smb_session_t *session);
+void smb_session_cancel_requests(smb_session_t *session);
+void smb_session_config(smb_session_t *session);
+void smb_session_reject(smb_session_t *session, char *reason);
+void smb_session_disconnect_share(char *);
+void smb_session_disconnect_volume(fs_desc_t *);
+
+
+/*
+ * ofile functions (file smb_ofile.c)
+ */
+smb_ofile_t *smb_ofile_lookup_by_fid(smb_tree_t *tree, uint16_t fid);
+smb_ofile_t *smb_ofile_open(smb_tree_t *tree, smb_node_t *node, uint16_t pid,
+ uint32_t access_granted, uint32_t create_options, uint32_t share_access,
+ uint16_t ftype, char *pipe_name, uint32_t rpc_fid, smb_error_t *err);
+int smb_ofile_close(smb_ofile_t *ofile, uint32_t last_wtime);
+uint32_t smb_ofile_access(smb_ofile_t *ofile, cred_t *cr, uint32_t access);
+int smb_ofile_seek(smb_ofile_t *of, ushort_t mode, int32_t off,
+ uint32_t *retoff);
+void smb_ofile_release(smb_ofile_t *ofile);
+void smb_ofile_close_all(smb_tree_t *tree);
+void smb_ofile_close_all_by_pid(smb_tree_t *tree, uint16_t pid);
+void smb_ofile_set_flags(smb_ofile_t *of, uint32_t flags);
+void smb_ofile_close_timestamp_update(smb_ofile_t *of, uint32_t last_wtime);
+boolean_t smb_ofile_is_open(smb_ofile_t *of);
+#define smb_ofile_granted_access(_of_) ((_of_)->f_granted_access)
+
+/*
+ * odir functions (file smb_odir.c)
+ */
+smb_odir_t *smb_odir_open(smb_tree_t *tree, smb_node_t *node, char *pattern,
+ uint16_t pid, unsigned short sattr);
+void smb_odir_close(smb_odir_t *od);
+void smb_odir_close_all(smb_tree_t *tree);
+void smb_odir_close_all_by_pid(smb_tree_t *tree, uint16_t pid);
+void smb_odir_release(smb_odir_t *od);
+smb_odir_t *smb_odir_lookup_by_sid(smb_tree_t *tree, uint16_t sid);
+
+/*
+ * SMB user functions (file smb_user.c)
+ */
+smb_user_t *smb_user_login(smb_session_t *, cred_t *,
+ char *, char *, uint32_t, uint32_t, uint32_t);
+smb_user_t *smb_user_dup(smb_user_t *);
+void smb_user_logoff(smb_user_t *user);
+void smb_user_logoff_all(smb_session_t *session);
+smb_user_t *smb_user_lookup_by_uid(smb_session_t *, cred_t **, uint16_t);
+smb_user_t *smb_user_lookup_by_name(smb_session_t *, char *, char *);
+smb_user_t *smb_user_lookup_by_state(smb_session_t *, smb_user_t *user);
+void smb_user_disconnect_share(smb_user_t *user, char *sharename);
+void smb_user_disconnect_volume(smb_user_t *user, fs_desc_t *fsd);
+void smb_user_release(smb_user_t *user);
+
+/*
+ * SMB tree functions (file smb_tree.c)
+ */
+smb_tree_t *smb_tree_connect(smb_user_t *user, uint16_t access_flags,
+ char *sharename, char *resource, int32_t rt_share,
+ smb_node_t *snode, fsvol_attr_t *vol_attr);
+void smb_tree_disconnect(smb_tree_t *tree);
+void smb_tree_disconnect_all(smb_user_t *user);
+void smb_tree_close_all_by_pid(smb_user_t *user, uint16_t pid);
+smb_tree_t *smb_tree_lookup_by_tid(smb_user_t *user, uint16_t tid);
+smb_tree_t *smb_tree_lookup_by_name(smb_user_t *, char *, smb_tree_t *);
+smb_tree_t *smb_tree_lookup_by_fsd(smb_user_t *, fs_desc_t *, smb_tree_t *);
+void smb_tree_release(smb_tree_t *tree);
+
+uint32_t smb_user_get_num(void);
+void smb_dr_user_free(smb_dr_user_ctx_t *uinfo);
+void smb_dr_ulist_free(smb_dr_ulist_t *ulist);
+int smb_dr_ulist_get(int offset, smb_dr_ulist_t *dr_ulist);
+
+/*
+ * SMB user's credential functions
+ */
+cred_t *smb_cred_create(smb_token_t *, uint32_t *);
+void smb_cred_rele(cred_t *cr);
+int smb_cred_is_member(cred_t *cr, nt_sid_t *sid);
+
+smb_xa_t *smb_xa_create(smb_session_t *session, smb_request_t *sr,
+ uint32_t total_parameter_count, uint32_t total_data_count,
+ uint32_t max_parameter_count, uint32_t max_data_count,
+ uint32_t max_setup_count, uint32_t setup_word_count);
+void smb_xa_delete(smb_xa_t *xa);
+smb_xa_t *smb_xa_hold(smb_xa_t *xa);
+void smb_xa_rele(smb_session_t *session, smb_xa_t *xa);
+int smb_xa_open(smb_xa_t *xa);
+void smb_xa_close(smb_xa_t *xa);
+int smb_xa_complete(smb_xa_t *xa);
+smb_xa_t *smb_xa_find(smb_session_t *session, uint16_t pid, uint16_t mid);
+
+struct mbuf *smb_mbuf_get(uchar_t *buf, int nbytes);
+struct mbuf *smb_mbuf_allocate(struct uio *uio);
+void smb_mbuf_trim(struct mbuf *mhead, int nbytes);
+
+void smb_check_status(void);
+int smb_handle_write_raw(smb_session_t *session, smb_request_t *sr);
+
+void smb_winpipe_init(void);
+void smb_winpipe_fini(void);
+int smb_winpipe_open(void);
+void smb_winpipe_close(void);
+int smb_winpipe_call(smb_request_t *, mlsvc_pipe_t *, mlsvc_stream_t *,
+ uint16_t, uint32_t *);
+
+void smb_reconnection_check(struct smb_session *session);
+
+uint32_t nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time);
+uint64_t unix_to_nt_time(timestruc_t *);
+
+int netbios_name_isvalid(char *in, char *out);
+
+size_t
+unicodestooems(char *oemstring, const mts_wchar_t *unicodestring,
+ size_t nbytes, unsigned int cpid);
+
+size_t oemstounicodes(mts_wchar_t *unicodestring, const char *oemstring,
+ size_t nwchars, unsigned int cpid);
+
+int uioxfer(struct uio *src_uio, struct uio *dst_uio, int n);
+
+int smb_match_name(ino64_t fileid, char *name, char *shortname,
+ char *name83, char *pattern, int ignore_case);
+int is_dot_or_dotdot(char *name);
+int token2buf(smb_token_t *token, char *buf);
+
+/*
+ * Pool ID function prototypes
+ */
+int smb_idpool_constructor(smb_idpool_t *pool);
+void smb_idpool_destructor(smb_idpool_t *pool);
+int smb_idpool_alloc(smb_idpool_t *pool, uint16_t *id);
+void smb_idpool_free(smb_idpool_t *pool, uint16_t id);
+
+/*
+ * SMB thread function prototypes
+ */
+void smb_session_worker(void *arg);
+
+/*
+ * SMB locked list function prototypes
+ */
+void smb_llist_constructor(smb_llist_t *, size_t, size_t);
+void smb_llist_destructor(smb_llist_t *);
+void smb_llist_insert_head(smb_llist_t *ll, void *obj);
+void smb_llist_insert_tail(smb_llist_t *ll, void *obj);
+void smb_llist_remove(smb_llist_t *ll, void *obj);
+int smb_llist_upgrade(smb_llist_t *ll);
+uint32_t smb_llist_get_count(smb_llist_t *ll);
+#define smb_llist_enter(ll, mode) rw_enter(&(ll)->ll_lock, mode)
+#define smb_llist_exit(ll) rw_exit(&(ll)->ll_lock)
+#define smb_llist_head(ll) list_head(&(ll)->ll_list)
+#define smb_llist_next(ll, obj) list_next(&(ll)->ll_list, obj)
+int smb_account_connected(smb_user_t *user);
+
+/*
+ * SMB Synchronized list function prototypes
+ */
+void smb_slist_constructor(smb_slist_t *, size_t, size_t);
+void smb_slist_destructor(smb_slist_t *);
+void smb_slist_insert_head(smb_slist_t *sl, void *obj);
+void smb_slist_insert_tail(smb_slist_t *sl, void *obj);
+void smb_slist_remove(smb_slist_t *sl, void *obj);
+void smb_slist_wait_for_empty(smb_slist_t *sl);
+void smb_slist_exit(smb_slist_t *sl);
+uint32_t smb_slist_move_tail(list_t *lst, smb_slist_t *sl);
+void smb_slist_obj_move(smb_slist_t *dst, smb_slist_t *src, void *obj);
+#define smb_slist_enter(sl) mutex_enter(&(sl)->sl_mutex)
+#define smb_slist_head(sl) list_head(&(sl)->sl_list)
+#define smb_slist_next(sl, obj) list_next(&(sl)->sl_list, obj)
+
+void smb_rwx_init(smb_rwx_t *rwx);
+void smb_rwx_destroy(smb_rwx_t *rwx);
+#define smb_rwx_rwenter(rwx, mode) rw_enter(&(rwx)->rwx_lock, mode)
+void smb_rwx_rwexit(smb_rwx_t *rwx);
+int smb_rwx_rwwait(smb_rwx_t *rwx, clock_t timeout);
+#define smb_rwx_xenter(rwx) mutex_enter(&(rwx)->rwx_mutex)
+#define smb_rwx_xexit(rwx) mutex_exit(&(rwx)->rwx_mutex)
+krw_t smb_rwx_rwupgrade(smb_rwx_t *rwx);
+void smb_rwx_rwdowngrade(smb_rwx_t *rwx, krw_t mode);
+
+void smb_thread_init(smb_thread_t *, char *, smb_thread_ep_t, void *,
+ smb_thread_aw_t, void *);
+void smb_thread_destroy(smb_thread_t *);
+int smb_thread_start(smb_thread_t *);
+void smb_thread_stop(smb_thread_t *);
+void smb_thread_signal(smb_thread_t *);
+boolean_t smb_thread_continue(smb_thread_t *);
+boolean_t smb_thread_continue_nowait(smb_thread_t *);
+boolean_t smb_thread_continue_timedwait(smb_thread_t *, int /* seconds */);
+void smb_thread_set_awaken(smb_thread_t *, smb_thread_aw_t, void *);
+
+uint32_t smb_denymode_to_sharemode(uint32_t desired_access, char *fname);
+uint32_t smb_ofun_to_crdisposition(uint16_t ofun);
+
+void smb_audit_buf_node_create(smb_node_t *node);
+void smb_audit_buf_node_destroy(smb_node_t *node);
+#define smb_audit_node(_n_) \
+ if ((_n_)->n_audit_buf) { \
+ smb_audit_record_node_t *anr; \
+ \
+ anr = (_n_)->n_audit_buf->anb_records; \
+ anr += (_n_)->n_audit_buf->anb_index; \
+ (_n_)->n_audit_buf->anb_index++; \
+ (_n_)->n_audit_buf->anb_index &= \
+ (_n_)->n_audit_buf->anb_max_index; \
+ anr->anr_refcnt = node->n_refcnt; \
+ anr->anr_depth = getpcstack(anr->anr_stack, \
+ SMB_AUDIT_STACK_DEPTH); \
+ }
+
+/* 100's of ns between 1/1/1970 and 1/1/1601 */
+#define NT_TIME_BIAS (134774LL * 24LL * 60LL * 60LL * 10000000LL)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_KPROTO_H_ */
diff --git a/usr/src/uts/common/smbsrv/smb_privilege.h b/usr/src/uts/common/smbsrv/smb_privilege.h
new file mode 100644
index 0000000000..c03455d469
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_privilege.h
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMB_PRIVILEGE_H
+#define _SMB_PRIVILEGE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_xdr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Privileges
+ *
+ * Privileges apply to all objects and over-ride the access controls
+ * in an object's security descriptor in a manner specific to each
+ * privilege. Privileges are still not full defined. Privileges are
+ * defined in a set structure (LUID = Locally Unique Identifier).
+ *
+ * The default LUID, name and display names defined on NT 4.0 are:
+ * LUID Privilege Name Display Name
+ * ---- -------------- ------------
+ * 0:2 SeCreateTokenPrivilege Create a token object
+ * 0:3 SeAssignPrimaryTokenPrivilege Replace a process level token
+ * 0:4 SeLockMemoryPrivilege Lock pages in memory
+ * 0:5 SeIncreaseQuotaPrivilege Increase quotas
+ * 0:6 SeMachineAccountPrivilege Add workstations to domain
+ * 0:7 SeTcbPrivilege Act as part of the operating system
+ * 0:8 SeSecurityPrivilege Manage auditing and security log
+ * 0:9 SeTakeOwnershipPrivilege Take ownership of files or other objects
+ * 0:10 SeLoadDriverPrivilege Load and unload device drivers
+ * 0:11 SeSystemProfilePrivilege Profile system performance
+ * 0:12 SeSystemtimePrivilege Change the system time
+ * 0:13 SeProfileSingleProcessPrivilege Profile single process
+ * 0:14 SeIncreaseBasePriorityPrivilege Increase scheduling priority
+ * 0:15 SeCreatePagefilePrivilege Create a pagefile
+ * 0:16 SeCreatePermanentPrivilege Create permanent shared objects
+ * 0:17 SeBackupPrivilege Back up files and directories
+ * 0:18 SeRestorePrivilege Restore files and directories
+ * 0:19 SeShutdownPrivilege Shut down the system
+ * 0:20 SeDebugPrivilege Debug programs
+ * 0:21 SeAuditPrivilege Generate security audits
+ * 0:22 SeSystemEnvironmentPrivilege Modify firmware environment values
+ * 0:23 SeChangeNotifyPrivilege Bypass traverse checking
+ * 0:24 SeRemoteShutdownPrivilege Force shutdown from a remote system
+ */
+
+/*
+ * Privilege names
+ */
+#define SE_CREATE_TOKEN_NAME "SeCreateTokenPrivilege"
+#define SE_ASSIGNPRIMARYTOKEN_NAME "SeAssignPrimaryTokenPrivilege"
+#define SE_LOCK_MEMORY_NAME "SeLockMemoryPrivilege"
+#define SE_INCREASE_QUOTA_NAME "SeIncreaseQuotaPrivilege"
+#define SE_UNSOLICITED_INPUT_NAME "SeUnsolicitedInputPrivilege"
+#define SE_MACHINE_ACCOUNT_NAME "SeMachineAccountPrivilege"
+#define SE_TCB_NAME "SeTcbPrivilege"
+#define SE_SECURITY_NAME "SeSecurityPrivilege"
+#define SE_TAKE_OWNERSHIP_NAME "SeTakeOwnershipPrivilege"
+#define SE_LOAD_DRIVER_NAME "SeLoadDriverPrivilege"
+#define SE_SYSTEM_PROFILE_NAME "SeSystemProfilePrivilege"
+#define SE_SYSTEMTIME_NAME "SeSystemtimePrivilege"
+#define SE_PROF_SINGLE_PROCESS_NAME "SeProfileSingleProcessPrivilege"
+#define SE_INC_BASE_PRIORITY_NAME "SeIncreaseBasePriorityPrivilege"
+#define SE_CREATE_PAGEFILE_NAME "SeCreatePagefilePrivilege"
+#define SE_CREATE_PERMANENT_NAME "SeCreatePermanentPrivilege"
+#define SE_BACKUP_NAME "SeBackupPrivilege"
+#define SE_RESTORE_NAME "SeRestorePrivilege"
+#define SE_SHUTDOWN_NAME "SeShutdownPrivilege"
+#define SE_DEBUG_NAME "SeDebugPrivilege"
+#define SE_AUDIT_NAME "SeAuditPrivilege"
+#define SE_SYSTEM_ENVIRONMENT_NAME "SeSystemEnvironmentPrivilege"
+#define SE_CHANGE_NOTIFY_NAME "SeChangeNotifyPrivilege"
+#define SE_REMOTE_SHUTDOWN_NAME "SeRemoteShutdownPrivilege"
+
+#define SE_CREATE_TOKEN_LUID 2
+#define SE_ASSIGNPRIMARYTOKEN_LUID 3
+#define SE_LOCK_MEMORY_LUID 4
+#define SE_INCREASE_QUOTA_LUID 5
+#define SE_MACHINE_ACCOUNT_LUID 6
+#define SE_TCB_LUID 7
+#define SE_SECURITY_LUID 8
+#define SE_TAKE_OWNERSHIP_LUID 9
+#define SE_LOAD_DRIVER_LUID 10
+#define SE_SYSTEM_PROFILE_LUID 11
+#define SE_SYSTEMTIME_LUID 12
+#define SE_PROF_SINGLE_PROCESS_LUID 13
+#define SE_INC_BASE_PRIORITY_LUID 14
+#define SE_CREATE_PAGEFILE_LUID 15
+#define SE_CREATE_PERMANENT_LUID 16
+#define SE_BACKUP_LUID 17
+#define SE_RESTORE_LUID 18
+#define SE_SHUTDOWN_LUID 19
+#define SE_DEBUG_LUID 20
+#define SE_AUDIT_LUID 21
+#define SE_SYSTEM_ENVIRONMENT_LUID 22
+#define SE_CHANGE_NOTIFY_LUID 23
+#define SE_REMOTE_SHUTDOWN_LUID 24
+
+/*
+ * Privilege attributes
+ */
+#define SE_PRIVILEGE_DISABLED 0x00000000
+#define SE_PRIVILEGE_ENABLED_BY_DEFAULT 0x00000001
+#define SE_PRIVILEGE_ENABLED 0x00000002
+#define SE_PRIVILEGE_USED_FOR_ACCESS 0x80000000
+
+/*
+ * Privilege Set Control flags
+ */
+#define PRIVILEGE_SET_ALL_NECESSARY 1
+
+typedef struct smb_luid {
+ uint32_t lo_part;
+ uint32_t hi_part;
+} smb_luid_t;
+
+
+typedef struct smb_luid_attrs {
+ smb_luid_t luid;
+ uint32_t attrs;
+} smb_luid_attrs_t;
+
+
+typedef struct smb_privset {
+ uint32_t priv_cnt;
+ uint32_t control;
+ smb_luid_attrs_t priv[ANY_SIZE_ARRAY];
+} smb_privset_t;
+
+/*
+ * These are possible value for smb_privinfo_t.flags
+ *
+ * PF_PRESENTABLE Privilege is user visible
+ */
+#define PF_PRESENTABLE 0x1
+
+/*
+ * Structure for passing privilege name and id information around within
+ * the system. Note that we are only storing the low uint32_t of the LUID;
+ * the high part is always zero here.
+ */
+typedef struct smb_privinfo {
+ uint32_t id;
+ char *name;
+ char *display_name;
+ uint16_t flags;
+} smb_privinfo_t;
+
+smb_privinfo_t *smb_priv_getbyvalue(uint32_t id);
+smb_privinfo_t *smb_priv_getbyname(char *name);
+int smb_priv_presentable_num(void);
+int smb_priv_presentable_ids(uint32_t *ids, int num);
+smb_privset_t *smb_privset_new();
+int smb_privset_size();
+void smb_privset_init(smb_privset_t *privset);
+void smb_privset_free(smb_privset_t *privset);
+void smb_privset_copy(smb_privset_t *dst, smb_privset_t *src);
+void smb_privset_enable(smb_privset_t *privset, uint32_t id);
+int smb_privset_query(smb_privset_t *privset, uint32_t id);
+void smb_privset_log(smb_privset_t *privset);
+
+/* XDR routines */
+extern bool_t xdr_smb_luid_t();
+extern bool_t xdr_smb_luid_attrs_t();
+extern bool_t xdr_smb_privset_t();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_PRIVILEGE_H */
diff --git a/usr/src/uts/common/smbsrv/smb_secdesc.h b/usr/src/uts/common/smbsrv/smb_secdesc.h
new file mode 100644
index 0000000000..68b890a8e4
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_secdesc.h
@@ -0,0 +1,397 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMB_SECDESC_H
+#define _SMB_SECDESC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/acl.h>
+#include <smbsrv/ntsid.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Discretionary Access Control List (DACL)
+ *
+ * A Discretionary Access Control List (DACL), often abbreviated to
+ * ACL, is a list of access controls which either allow or deny access
+ * for users or groups to a resource. There is a list header followed
+ * by a list of access control entries (ACE). Each ACE specifies the
+ * access allowed or denied to a single user or group (identified by
+ * a SID).
+ *
+ * There is another access control list object called a System Access
+ * Control List (SACL), which is used to control auditing, but no
+ * support is provideed for SACLs at this time.
+ *
+ * ACL header format:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-------------------------------+---------------+---------------+
+ * | AclSize | Sbz1 | AclRevision |
+ * +-------------------------------+---------------+---------------+
+ * | Sbz2 | AceCount |
+ * +-------------------------------+-------------------------------+
+ *
+ * AclRevision specifies the revision level of the ACL. This value should
+ * be ACL_REVISION, unless the ACL contains an object-specific ACE, in which
+ * case this value must be ACL_REVISION_DS. All ACEs in an ACL must be at the
+ * same revision level.
+ *
+ * ACE header format:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------+-------+-------+---------------+---------------+
+ * | AceSize | AceFlags | AceType |
+ * +---------------+-------+-------+---------------+---------------+
+ *
+ * Access mask format:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------+---------------+-------------------------------+
+ * |G|G|G|G|Res'd|A| StandardRights| SpecificRights |
+ * |R|W|E|A| |S| | |
+ * +-+-------------+---------------+-------------------------------+
+ *
+ * typedef struct ACCESS_MASK {
+ * WORD SpecificRights;
+ * BYTE StandardRights;
+ * BYTE AccessSystemAcl : 1;
+ * BYTE Reserved : 3;
+ * BYTE GenericAll : 1;
+ * BYTE GenericExecute : 1;
+ * BYTE GenericWrite : 1;
+ * BYTE GenericRead : 1;
+ * } ACCESS_MASK;
+ *
+ */
+
+#define ACL_REVISION1 1
+#define ACL_REVISION2 2
+#define MIN_ACL_REVISION2 ACL_REVISION2
+#define ACL_REVISION3 3
+#define ACL_REVISION4 4
+#define MAX_ACL_REVISION ACL_REVISION4
+
+/*
+ * Current ACE and ACL revision Levels
+ */
+#define ACE_REVISION 1
+#define ACL_REVISION ACL_REVISION2
+#define ACL_REVISION_DS ACL_REVISION4
+
+
+#define ACCESS_ALLOWED_ACE_TYPE 0
+#define ACCESS_DENIED_ACE_TYPE 1
+#define SYSTEM_AUDIT_ACE_TYPE 2
+#define SYSTEM_ALARM_ACE_TYPE 3
+
+/*
+ * se_flags
+ * ----------
+ * Specifies a set of ACE type-specific control flags. This member can be a
+ * combination of the following values.
+ *
+ * CONTAINER_INHERIT_ACE: Child objects that are containers, such as
+ * directories, inherit the ACE as an effective ACE. The inherited
+ * ACE is inheritable unless the NO_PROPAGATE_INHERIT_ACE bit flag
+ * is also set.
+ *
+ * INHERIT_ONLY_ACE: Indicates an inherit-only ACE which does not control
+ * access to the object to which it is attached.
+ * If this flag is not set,
+ * the ACE is an effective ACE which controls access to the object
+ * to which it is attached.
+ * Both effective and inherit-only ACEs can be inherited
+ * depending on the state of the other inheritance flags.
+ *
+ * INHERITED_ACE: Windows 2000/XP: Indicates that the ACE was inherited.
+ * The system sets this bit when it propagates an
+ * inherited ACE to a child object.
+ *
+ * NO_PROPAGATE_INHERIT_ACE: If the ACE is inherited by a child object, the
+ * system clears the OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE
+ * flags in the inherited ACE.
+ * This prevents the ACE from being inherited by
+ * subsequent generations of objects.
+ *
+ * OBJECT_INHERIT_ACE: Noncontainer child objects inherit the ACE as an
+ * effective ACE. For child objects that are containers,
+ * the ACE is inherited as an inherit-only ACE unless the
+ * NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ */
+#define OBJECT_INHERIT_ACE 0x01
+#define CONTAINER_INHERIT_ACE 0x02
+#define NO_PROPOGATE_INHERIT_ACE 0x04
+#define INHERIT_ONLY_ACE 0x08
+#define INHERITED_ACE 0x10
+#define INHERIT_MASK_ACE 0x1F
+
+
+/*
+ * These flags are only used in system audit or alarm ACEs to
+ * indicate when an audit message should be generated, i.e.
+ * on successful access or on unsuccessful access.
+ */
+#define SUCCESSFUL_ACCESS_ACE_FLAG 0x40
+#define FAILED_ACCESS_ACE_FLAG 0x80
+
+
+/*
+ * AclSize is the size, in bytes, allocated for the ACL. This
+ * includes the ACL header, ACEs and remaining free space in
+ * the buffer. sl_acecnt is the number of ACES in the ACL.
+ */
+typedef struct smb_acl {
+ uint8_t sl_revision;
+ uint8_t sl_sbz1;
+ uint16_t sl_size;
+ uint16_t sl_acecnt;
+ uint16_t sl_sbz2;
+ /* immediately followed by ACE[]s */
+} smb_acl_t;
+
+
+/*
+ * se_type denotes the type of the ace, there are some predefined
+ * ACE types. se_size is the size, in bytes, of ACE. se_flags are
+ * the ACE flags for auditing and inheritance.
+ */
+typedef struct smb_ace_hdr {
+ uint8_t se_type;
+ uint8_t se_flags;
+ uint16_t se_size;
+} smb_ace_hdr_t;
+
+
+typedef struct smb_ace {
+ smb_ace_hdr_t se_header;
+ uint32_t se_mask;
+ nt_sid_t se_sid; /* variable length */
+} smb_ace_t;
+
+
+/*
+ * Security Descriptor (SD)
+ *
+ * Security descriptors provide protection for objects, for example
+ * files and directories. It identifies the owner and primary group
+ * (SIDs) and contains an access control list. When a user tries to
+ * access an object his SID is compared to the permissions in the
+ * DACL to determine if access should be allowed or denied. Note that
+ * this is a simplification because there are other factors, such as
+ * default behavior and privileges to be taken into account (see also
+ * access tokens).
+ *
+ * The boolean flags have the following meanings when set:
+ *
+ * SE_OWNER_DEFAULTED indicates that the SID pointed to by the Owner
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the SID with respect to inheritance of
+ * an owner.
+ *
+ * SE_GROUP_DEFAULTED indicates that the SID in the Group field was
+ * provided by a defaulting mechanism rather than explicitly provided
+ * by the original provider of the security descriptor. This may
+ * affect the treatment of the SID with respect to inheritance of a
+ * primary group.
+ *
+ * SE_DACL_PRESENT indicates that the security descriptor contains a
+ * discretionary ACL. If this flag is set and the Dacl field of the
+ * SECURITY_DESCRIPTOR is null, then a null ACL is explicitly being
+ * specified.
+ *
+ * SE_DACL_DEFAULTED indicates that the ACL pointed to by the Dacl
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the ACL with respect to inheritance of
+ * an ACL. This flag is ignored if the DaclPresent flag is not set.
+ *
+ * SE_SACL_PRESENT indicates that the security descriptor contains a
+ * system ACL pointed to by the Sacl field. If this flag is set and
+ * the Sacl field of the SECURITY_DESCRIPTOR is null, then an empty
+ * (but present) ACL is being specified.
+ *
+ * SE_SACL_DEFAULTED indicates that the ACL pointed to by the Sacl
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the ACL with respect to inheritance of
+ * an ACL. This flag is ignored if the SaclPresent flag is not set.
+ *
+ * SE_DACL_PROTECTED Prevents ACEs set on the DACL of the parent container
+ * (and any objects above the parent container in the directory hierarchy)
+ * from being applied to the object's DACL.
+ *
+ * SE_SACL_PROTECTED Prevents ACEs set on the SACL of the parent container
+ * (and any objects above the parent container in the directory hierarchy)
+ * from being applied to the object's SACL.
+ *
+ * Note that the SE_DACL_PRESENT flag needs to be present to set
+ * SE_DACL_PROTECTED and SE_SACL_PRESENT needs to be present to set
+ * SE_SACL_PROTECTED.
+ *
+ * SE_SELF_RELATIVE indicates that the security descriptor is in self-
+ * relative form. In this form, all fields of the security descriptor
+ * are contiguous in memory and all pointer fields are expressed as
+ * offsets from the beginning of the security descriptor.
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------------------------------------------------------+
+ * | Control |Reserved1 (SBZ)| Revision |
+ * +---------------------------------------------------------------+
+ * | Owner |
+ * +---------------------------------------------------------------+
+ * | Group |
+ * +---------------------------------------------------------------+
+ * | Sacl |
+ * +---------------------------------------------------------------+
+ * | Dacl |
+ * +---------------------------------------------------------------+
+ *
+ */
+
+#define SMB_OWNER_SECINFO 0x0001
+#define SMB_GROUP_SECINFO 0x0002
+#define SMB_DACL_SECINFO 0x0004
+#define SMB_SACL_SECINFO 0x0008
+#define SMB_ALL_SECINFO 0x000F
+#define SMB_ACL_SECINFO (SMB_DACL_SECINFO | SMB_SACL_SECINFO)
+
+#define SECURITY_DESCRIPTOR_REVISION 1
+
+
+#define SE_OWNER_DEFAULTED 0x0001
+#define SE_GROUP_DEFAULTED 0x0002
+#define SE_DACL_PRESENT 0x0004
+#define SE_DACL_DEFAULTED 0x0008
+#define SE_SACL_PRESENT 0x0010
+#define SE_SACL_DEFAULTED 0x0020
+#define SE_DACL_AUTO_INHERIT_REQ 0x0100
+#define SE_SACL_AUTO_INHERIT_REQ 0x0200
+#define SE_DACL_AUTO_INHERITED 0x0400
+#define SE_SACL_AUTO_INHERITED 0x0800
+#define SE_DACL_PROTECTED 0x1000
+#define SE_SACL_PROTECTED 0x2000
+#define SE_SELF_RELATIVE 0x8000
+
+#define SE_DACL_INHERITANCE_MASK 0x1500
+#define SE_SACL_INHERITANCE_MASK 0x2A00
+
+/*
+ * Security descriptor structures:
+ *
+ * smb_sd_t SD in SMB pointer form
+ * smb_sdbuf_t SD in SMB self-relative form
+ * smb_fssd_t SD in filesystem form
+ *
+ * We have to use two different structures to represent
+ * pointer form and self-relative form of the security
+ * descriptor because in SR form the offsets are 4-byte
+ * but in pointer form, pointers will be 8-byte in 64-bit
+ * kernel binary.
+ *
+ * Filesystems (e.g. ZFS/UFS) don't have something equivalent
+ * to SD. The items comprising a SMB SD are kept separately in
+ * filesystem. smb_fssd_t is introduced as a helper to provide
+ * the required abstraction for CIFS code.
+ */
+typedef struct smb_sd_hdr {
+ uint8_t sd_revision;
+ uint8_t sd_sbz1;
+ uint16_t sd_control;
+} smb_sd_hdr_t;
+
+typedef struct smb_sd {
+ smb_sd_hdr_t sd_hdr;
+ nt_sid_t *sd_owner; /* SID file owner */
+ nt_sid_t *sd_group; /* SID group (for POSIX) */
+ smb_acl_t *sd_sacl; /* ACL System (audits) */
+ smb_acl_t *sd_dacl; /* ACL Discretionary (perm) */
+} smb_sd_t;
+
+typedef struct smb_sdbuf {
+ smb_sd_hdr_t sd_hdr;
+ uint32_t sd_owner_offs; /* SID file owner */
+ uint32_t sd_group_offs; /* SID group (for POSIX) */
+ uint32_t sd_sacl_offs; /* ACL System (audits) */
+ uint32_t sd_dacl_offs; /* ACL Discretionary (perm) */
+} smb_sdbuf_t;
+
+/*
+ * values for smb_fssd.sd_flags
+ */
+#define SMB_FSSD_FLAGS_DIR 0x01
+
+typedef struct smb_fssd {
+ uint32_t sd_secinfo;
+ uint32_t sd_flags;
+ uid_t sd_uid;
+ gid_t sd_gid;
+ acl_t *sd_zdacl;
+ acl_t *sd_zsacl;
+} smb_fssd_t;
+
+void smb_sd_init(smb_sd_t *sd, uint8_t revision);
+void smb_sd_set_owner(smb_sd_t *sd, nt_sid_t *owner, int defaulted);
+void smb_sd_set_group(smb_sd_t *sd, nt_sid_t *group, int defaulted);
+void smb_sd_set_dacl(smb_sd_t *sd, int present, smb_acl_t *acl, int defaulted);
+void smb_sd_set_sacl(smb_sd_t *sd, int present, smb_acl_t *acl, int defaulted);
+
+nt_sid_t *smb_sd_get_owner(void *sd, int *defaulted);
+nt_sid_t *smb_sd_get_group(void *sd, int *defaulted);
+smb_acl_t *smb_sd_get_dacl(void *sd, int *present, int *defaulted);
+smb_acl_t *smb_sd_get_sacl(void *sd, int *present, int *defaulted);
+uint32_t smb_sd_get_secinfo(void *sd);
+uint32_t smb_sd_len(void *sd, uint32_t secinfo);
+void smb_sd_log(void *sd);
+void smb_sd_term(smb_sd_t *sd);
+
+smb_acl_t *smb_acl_from_zfs(acl_t *, uid_t, gid_t);
+uint32_t smb_acl_to_zfs(smb_acl_t *, uint32_t, int, acl_t **);
+int smb_acl_isvalid(smb_acl_t *, int);
+uint16_t smb_acl_len(smb_acl_t *);
+smb_acl_t *smb_acl_sort(smb_acl_t *);
+int smb_acl_copy(uint16_t, smb_acl_t *, smb_acl_t *);
+acl_t *smb_acl_inherit(acl_t *, int, int, uid_t);
+
+smb_ace_t *smb_ace_get(smb_acl_t *acl, uint16_t idx);
+int smb_ace_is_generic(int type);
+int smb_ace_is_access(int type);
+int smb_ace_is_audit(int type);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_SECDESC_H */
diff --git a/usr/src/uts/common/smbsrv/smb_svc_sm.h b/usr/src/uts/common/smbsrv/smb_svc_sm.h
new file mode 100644
index 0000000000..d843585edc
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_svc_sm.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/*
+ * Structures and type definitions for the SMB module.
+ */
+
+#ifndef _SMBSRV_SMB_SVC_SM_H
+#define _SMBSRV_SMB_SVC_SM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * CIFS Service State Machine Definitions
+ */
+
+/*
+ * Events
+ *
+ * SMB_SVCEVT_UNDEFINED Invalid Event
+ * SMB_SVCEVT_OPEN Pseudo-device opened
+ * SMB_SVCEVT_CLOSE Pseudo-device closed
+ * SMB_SVCEVT_OPEN_SUCCESS Open actions completed successfully
+ * SMB_SVCEVT_OPEN_FAILED Open actions failed
+ * SMB_SVCEVT_CLOSE_SUCCESS Close actions completed successfully
+ * SMB_SVCEVT_CONNECT Connected and listening on SMB session port
+ * SMB_SVCEVT_DISCONNECT SMB connection dropped or failed to connect
+ * SMB_SVCEVT_CONFIG New config from smbd
+ * SMB_SVCEVT_CONFIG_SUCCESS Configuration updated successfully
+ * SMB_SVCEVT_CONFIG_FAILED Configuration update failed
+ * SMB_SVCEVT_SESSION_CREATE SMB port listener accepted a connection
+ * SMB_SVCEVT_SESSION_DELETE Session ended
+ * SMB_SVCEVT_MAX_EVENT Invalid Event
+ */
+
+typedef enum {
+ SMB_SVCEVT_UNDEFINED = 0,
+ SMB_SVCEVT_OPEN,
+ SMB_SVCEVT_CLOSE,
+ SMB_SVCEVT_OPEN_SUCCESS,
+ SMB_SVCEVT_OPEN_FAILED,
+ SMB_SVCEVT_CLOSE_SUCCESS,
+ SMB_SVCEVT_CONNECT,
+ SMB_SVCEVT_DISCONNECT,
+ SMB_SVCEVT_CONFIG,
+ SMB_SVCEVT_CONFIG_SUCCESS,
+ SMB_SVCEVT_CONFIG_FAILED,
+ SMB_SVCEVT_SESSION_CREATE,
+ SMB_SVCEVT_SESSION_DELETE,
+ SMB_SVCEVT_MAX_EVENT
+} smb_svcevt_t;
+
+/*
+ * States
+ *
+ * SMB_SVCSTATE_UNDEFINED Invalid state
+ * SMB_SVCSTATE_INIT Pseudo-driver loaded/idle
+ * SMB_SVCSTATE_OPENING Pseudo-driver opened, starting
+ * SMB_SVCSTATE_CONFIG_WAIT Waiting for configuration
+ * SMB_SVCSTATE_CONNECTING Waiting for socket bind to SMB
+ * SMB_SVCSTATE_ONLINE Online, accepting connections
+ * SMB_SVCSTATE_RECONFIGURING Updating config, no new connections
+ * SMB_SVCSTATE_DISCONNECTING Smbd requested shutdown, closing socket
+ * SMB_SVCSTATE_SESSION_CLOSE Shutting down, closing active sessions
+ * SMB_SVCSTATE_CLOSING Shutting down, releasing resources
+ * SMB_SVCSTATE_ERROR_SESSION_CLOSE Unexpected SMB socket error,
+ * closing active sessions
+ * SMB_SVCSTATE_ERROR_CLOSING Error, releasing resources
+ * SMB_SVCSTATE_MAX_STATE Invalid state
+ */
+typedef enum {
+ SMB_SVCSTATE_UNDEFINED = 0,
+ SMB_SVCSTATE_INIT,
+ SMB_SVCSTATE_OPENING,
+ SMB_SVCSTATE_CONFIG_WAIT,
+ SMB_SVCSTATE_CONNECTING,
+ SMB_SVCSTATE_ONLINE,
+ SMB_SVCSTATE_RECONFIGURING,
+ SMB_SVCSTATE_DISCONNECTING,
+ SMB_SVCSTATE_SESSION_CLOSE,
+ SMB_SVCSTATE_ERROR_SESSION_CLOSE,
+ SMB_SVCSTATE_CLOSING,
+ SMB_SVCSTATE_ERROR_CLOSING,
+ SMB_SVCSTATE_ERROR,
+ SMB_SVCSTATE_MAX_STATE
+} smb_svcstate_t;
+
+#ifdef _KERNEL
+/* Event context */
+typedef struct {
+ smb_svcevt_t sec_event;
+ uintptr_t sec_info;
+} smb_event_ctx_t;
+
+/* Service state machine context */
+typedef struct {
+ taskq_t *ssc_taskq;
+ krwlock_t ssc_state_rwlock;
+ kmutex_t ssc_state_cv_mutex;
+ kcondvar_t ssc_state_cv;
+ int ssc_started;
+ int ssc_start_error;
+ int ssc_disconnect_error;
+ smb_svcstate_t ssc_state;
+ smb_svcstate_t ssc_last_state; /* Debug only */
+ int ssc_session_creates_waiting;
+ int ssc_deferred_session_count;
+ list_t ssc_deferred_sessions;
+ int ssc_active_session_count;
+ list_t ssc_active_sessions;
+ uint32_t ssc_error_no_resources;
+} smb_svc_sm_ctx_t;
+
+/*
+ * SMB service state machine API
+ */
+
+extern int smb_svcstate_sm_init(smb_svc_sm_ctx_t *svc_sm);
+extern void smb_svcstate_sm_fini(smb_svc_sm_ctx_t *svc_sm);
+extern int smb_svcstate_sm_start(smb_svc_sm_ctx_t *svc_sm);
+extern void smb_svcstate_sm_stop(smb_svc_sm_ctx_t *svc_sm);
+extern boolean_t smb_svcstate_sm_busy(void);
+extern void smb_svcstate_event(smb_svcevt_t event, uintptr_t event_info);
+extern void smb_svcstate_lock_read(smb_svc_sm_ctx_t *svc_sm);
+extern void smb_svcstate_unlock(smb_svc_sm_ctx_t *svc_sm);
+extern smb_session_t *smb_svcstate_session_getnext(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *prev);
+extern int smb_svcstate_session_count(smb_svc_sm_ctx_t *svc_sm);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_SVC_SM_H */
diff --git a/usr/src/uts/common/smbsrv/smb_token.h b/usr/src/uts/common/smbsrv/smb_token.h
new file mode 100644
index 0000000000..c2bea1e9a9
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_token.h
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMB_TOKEN_H
+#define _SMB_TOKEN_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/netrauth.h>
+#include <smbsrv/smb_privilege.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * User Session Key
+ *
+ * This is part of the MAC key which is required for signing SMB messages.
+ */
+typedef struct smb_session_key {
+ uint8_t data[16];
+} smb_session_key_t;
+
+/*
+ * Access Token
+ *
+ * An access token identifies a user, the user's privileges and the
+ * list of groups of which the user is a member. This information is
+ * used when access is requested to an object by comparing this
+ * information with the DACL in the object's security descriptor.
+ *
+ * Only group attributes are defined. No user attributes defined.
+ */
+
+#define SE_GROUP_MANDATORY 0x00000001
+#define SE_GROUP_ENABLED_BY_DEFAULT 0x00000002
+#define SE_GROUP_ENABLED 0x00000004
+#define SE_GROUP_OWNER 0x00000008
+#define SE_GROUP_USE_FOR_DENY_ONLY 0x00000010
+#define SE_GROUP_LOGON_ID 0xC0000000
+
+typedef struct smb_sid_attrs {
+ uint32_t attrs;
+ nt_sid_t *sid;
+} smb_sid_attrs_t;
+
+/*
+ * smb_id_t consists of both the Windows security identifier
+ * and its corresponding POSIX/ephemeral ID.
+ */
+typedef struct smb_id {
+ smb_sid_attrs_t i_sidattr;
+ uid_t i_id;
+} smb_id_t;
+
+/*
+ * Windows groups (each group SID is associated with a POSIX/ephemeral
+ * gid.
+ */
+typedef struct smb_win_grps {
+ uint16_t wg_count;
+ smb_id_t wg_groups[ANY_SIZE_ARRAY];
+} smb_win_grps_t;
+
+/*
+ * Access Token Flags
+ *
+ * SMB_ATF_GUEST Token belongs to guest user
+ * SMB_ATF_ANON Token belongs to anonymous user
+ * and it's only good for IPC Connection.
+ * SMB_ATF_POWERUSER Token belongs to a Power User member
+ * SMB_ATF_BACKUPOP Token belongs to a Power User member
+ * SMB_ATF_ADMIN Token belongs to a Domain Admins member
+ */
+#define SMB_ATF_GUEST 0x00000001
+#define SMB_ATF_ANON 0x00000002
+#define SMB_ATF_POWERUSER 0x00000004
+#define SMB_ATF_BACKUPOP 0x00000008
+#define SMB_ATF_ADMIN 0x00000010
+
+#define SMB_POSIX_GRPS_SIZE(n) \
+ (sizeof (smb_posix_grps_t) + (n - 1) * sizeof (gid_t))
+/*
+ * It consists of the primary and supplementary POSIX groups.
+ */
+typedef struct smb_posix_grps {
+ uint32_t pg_ngrps;
+ gid_t pg_grps[ANY_SIZE_ARRAY];
+} smb_posix_grps_t;
+
+/*
+ * Token Structure.
+ *
+ * This structure contains information of a user. There should be one
+ * unique token per user per session per client. The information
+ * provided will either give or deny access to shares, files or folders.
+ */
+typedef struct smb_token {
+ smb_id_t *tkn_user;
+ smb_id_t *tkn_owner;
+ smb_id_t *tkn_primary_grp;
+ smb_win_grps_t *tkn_win_grps;
+ smb_privset_t *tkn_privileges;
+ char *tkn_account_name;
+ char *tkn_domain_name;
+ uint32_t tkn_flags;
+ uint32_t tkn_audit_sid;
+ smb_session_key_t *tkn_session_key;
+ smb_posix_grps_t *tkn_posix_grps;
+} smb_token_t;
+
+/*
+ * This is the max buffer length for holding certain fields of
+ * any access token: domain, account, workstation, and IP with the
+ * format as show below:
+ * [domain name]\[user account] [workstation] (IP)
+ *
+ * This is not meant to be the maximum buffer length for holding
+ * the entire context of a token.
+ */
+#define NTTOKEN_BASIC_INFO_MAXLEN (SMB_PI_MAX_DOMAIN + SMB_PI_MAX_USERNAME \
+ + SMB_PI_MAX_HOST + INET_ADDRSTRLEN + 8)
+
+/*
+ * Information returned by an RPC call is allocated on an internal heap
+ * which is deallocated before returning from the interface call. The
+ * smb_userinfo structure provides a useful common mechanism to get the
+ * information back to the caller. It's like a compact access token but
+ * only parts of it are filled in by each RPC so the content is call
+ * specific.
+ */
+typedef struct smb_rid_attrs {
+ uint32_t rid;
+ uint32_t attributes;
+} smb_rid_attrs_t;
+
+#define SMB_UINFO_FLAG_ANON 0x01
+#define SMB_UINFO_FLAG_LADMIN 0x02 /* Local admin */
+#define SMB_UINFO_FLAG_DADMIN 0x04 /* Domain admin */
+#define SMB_UINFO_FLAG_ADMIN (SMB_UINFO_FLAG_LADMIN | SMB_UINFO_FLAG_DADMIN)
+
+/*
+ * This structure is mainly used where there's some
+ * kind of user related interaction with a domain
+ * controller via different RPC calls.
+ */
+typedef struct smb_userinfo {
+ uint16_t sid_name_use;
+ uint32_t rid;
+ uint32_t primary_group_rid;
+ char *name;
+ char *domain_name;
+ nt_sid_t *domain_sid;
+ uint32_t n_groups;
+ smb_rid_attrs_t *groups;
+ uint32_t n_other_grps;
+ smb_sid_attrs_t *other_grps;
+ smb_session_key_t *session_key;
+
+ nt_sid_t *user_sid;
+ nt_sid_t *pgrp_sid;
+ uint32_t flags;
+} smb_userinfo_t;
+
+/* XDR routines */
+extern bool_t xdr_smb_session_key_t();
+extern bool_t xdr_netr_client_t();
+extern bool_t xdr_nt_sid_t();
+extern bool_t xdr_smb_sid_attrs_t();
+extern bool_t xdr_smb_id_t();
+extern bool_t xdr_smb_win_grps_t();
+extern bool_t xdr_smb_posix_grps_t();
+extern bool_t xdr_smb_token_t();
+
+
+#ifndef _KERNEL
+smb_token_t *smb_logon(netr_client_t *clnt);
+void smb_token_destroy(smb_token_t *token);
+uint8_t *smb_token_mkselfrel(smb_token_t *obj, uint32_t *len);
+netr_client_t *netr_client_mkabsolute(uint8_t *buf, uint32_t len);
+#else /* _KERNEL */
+smb_token_t *smb_token_mkabsolute(uint8_t *buf, uint32_t len);
+void smb_token_free(smb_token_t *token);
+uint8_t *netr_client_mkselfrel(netr_client_t *obj, uint32_t *len);
+#endif /* _KERNEL */
+
+int smb_token_query_privilege(smb_token_t *token, int priv_id);
+/*
+ * Diagnostic routines:
+ * smb_token_print: write the contents of a token to the log.
+ * smb_token_log: log message is prefixed with token basic info.
+ */
+void smb_token_print(smb_token_t *token);
+void smb_token_log(int level, smb_dr_user_ctx_t *user_ctx, char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMB_TOKEN_H */
diff --git a/usr/src/uts/common/smbsrv/smb_vops.h b/usr/src/uts/common/smbsrv/smb_vops.h
new file mode 100644
index 0000000000..8bc18b73ca
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_vops.h
@@ -0,0 +1,386 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMB_VOPS_H
+#define _SMBSRV_SMB_VOPS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Common file system interfaces and definitions.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/mntent.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/refstr.h>
+#include <sys/acl.h>
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/smb_fsd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ROOTVOL ""
+#define CHKPNT ".chkpnt"
+#define XATTR_DIR "xattr_dir"
+
+#define SMB_STREAM_PREFIX "SUNWsmb"
+#define SMB_STREAM_PREFIX_LEN (sizeof (SMB_STREAM_PREFIX) - 1)
+
+#define MANGLE_NAMELEN 14
+#define SMB_EOF 0x7FFFFFFF
+
+/*
+ * SMB_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to
+ * VOP_READDIR. Its value is the size of the maximum possible edirent_t
+ * for solaris. The EDIRENT_RECLEN macro returns the size of edirent_t
+ * required for a given name length. MAXNAMELEN is the maximum
+ * filename length allowed in Solaris. The first two EDIRENT_RECLEN()
+ * macros are to allow for . and .. entries -- just a minor tweak to try
+ * and guarantee that buffer we give to VOP_READDIR will be large enough
+ * to hold ., .., and the largest possible solaris edirent_t.
+ *
+ * This bufsize will also be used when reading dirent64_t entries.
+ */
+
+#define SMB_MINLEN_RDDIR_BUF \
+ (EDIRENT_RECLEN(1) + EDIRENT_RECLEN(2) + EDIRENT_RECLEN(MAXNAMELEN))
+
+/*
+ * DP_TO_EDP
+ *
+ * Fill in an edirent_t structure with information from a dirent64_t.
+ * This allows the use of an edirent_t in code where both edirent_t's
+ * and dirent64_t's are manipulated.
+ */
+
+#define DP_TO_EDP(dp, edp) \
+{ \
+ ASSERT((dp)); \
+ ASSERT((edp)); \
+ (edp)->ed_ino = (dp)->d_ino; \
+ (edp)->ed_off = (dp)->d_off; \
+ (edp)->ed_eflags = 0; \
+ (edp)->ed_reclen = (dp)->d_reclen; \
+ (void) strlcpy((edp)->ed_name, (dp)->d_name, MAXNAMELEN); \
+}
+
+/*
+ * DP_ADVANCE
+ *
+ * In readdir operations, advance to read the next entry in a buffer
+ * returned from VOP_READDIR. The entries are of type dirent64_t.
+ */
+
+#define DP_ADVANCE(dp, dirbuf, numbytes) \
+{ \
+ ASSERT((dp)); \
+ if ((dp)->d_reclen == 0) { \
+ (dp) = NULL; \
+ } else { \
+ (dp) = (dirent64_t *)((char *)(dp) + (dp)->d_reclen); \
+ if ((dp) >= (dirent64_t *)((dirbuf) + (numbytes))) \
+ (dp) = NULL; \
+ } \
+}
+
+/*
+ * EDP_ADVANCE
+ *
+ * In readdir operations, advance to read the next entry in a buffer
+ * returned from VOP_READDIR. The entries are of type edirent_t.
+ */
+
+#define EDP_ADVANCE(edp, dirbuf, numbytes) \
+{ \
+ ASSERT((edp)); \
+ if ((edp)->ed_reclen == 0) { \
+ (edp) = NULL; \
+ } else { \
+ (edp) = (edirent_t *)((char *)(edp) + (edp)->ed_reclen);\
+ if ((edp) >= (edirent_t *)((dirbuf) + (numbytes))) \
+ (edp) = NULL; \
+ } \
+}
+
+struct smb_node;
+struct smb_request;
+
+/*
+ * Note: When specifying the mask for an smb_attr_t,
+ * the sa_mask, and not the sa_vattr.va_mask, should be
+ * filled in. The #define's that should be used are those
+ * prefixed with SMB_AT_*. Only FSIL routines should
+ * manipulate the sa_vattr.va_mask field.
+ */
+typedef struct smb_attr {
+ uint_t sa_mask; /* For both vattr and CIFS attr's */
+ vattr_t sa_vattr; /* Legacy vattr */
+ uint32_t sa_dosattr; /* DOS attributes */
+ timestruc_t sa_crtime; /* Creation time */
+} smb_attr_t;
+
+#define SMB_AT_TYPE 0x00001
+#define SMB_AT_MODE 0x00002
+#define SMB_AT_UID 0x00004
+#define SMB_AT_GID 0x00008
+#define SMB_AT_FSID 0x00010
+#define SMB_AT_NODEID 0x00020
+#define SMB_AT_NLINK 0x00040
+#define SMB_AT_SIZE 0x00080
+#define SMB_AT_ATIME 0x00100
+#define SMB_AT_MTIME 0x00200
+#define SMB_AT_CTIME 0x00400
+#define SMB_AT_RDEV 0x00800
+#define SMB_AT_BLKSIZE 0x01000
+#define SMB_AT_NBLOCKS 0x02000
+#define SMB_AT_SEQ 0x08000
+
+#define SMB_AT_DOSATTR 0x00100000
+#define SMB_AT_CRTIME 0x00200000
+#define SMB_AT_SMB 0x00300000
+
+#define SMB_AT_ALL (SMB_AT_TYPE|SMB_AT_MODE|SMB_AT_UID|SMB_AT_GID|\
+ SMB_AT_FSID|SMB_AT_NODEID|SMB_AT_NLINK|SMB_AT_SIZE|\
+ SMB_AT_ATIME|SMB_AT_MTIME|SMB_AT_CTIME|SMB_AT_RDEV|\
+ SMB_AT_BLKSIZE|SMB_AT_NBLOCKS|SMB_AT_SEQ|SMB_AT_SMB)
+
+/*
+ * DOS Attributes
+ * Previously defined in smbsrv/ntaccess.h
+ */
+
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
+#define FILE_ATTRIBUTE_ENCRYPTED 0x00000040
+#define FILE_ATTRIBUTE_NORMAL 0x00000080
+#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
+#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
+#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
+#define FILE_ATTRIBUTE_OFFLINE 0x00001000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
+#define FILE_ATTRIBUTE_MODIFIED 0x00004000
+#define FILE_ATTRIBUTE_QUARANTINED 0x00008000
+#define FILE_ATTRIBUTE_VALID_FLAGS 0x0000dfb7
+#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x0000dfa7
+#define FILE_ATTRIBUTE_MASK 0x00003FFF
+
+
+#ifndef PBSHORTCUT
+/* remove from libsmbbase */
+#define FHF_SMB 0x02
+#endif
+
+/* DOS specific attribute bits */
+#define FSA_DOSATTR (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM | \
+ FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN)
+
+/*
+ * File types (FSA_FMT) and permissions (FSA_MODMASK).
+ * Restricted to lower 16-bits due to FS inode definitions.
+ */
+#define FSA_MTIME_SEQ 0x10000000
+/* #define FSA_USTREAM_SKIPSEQ 0x10000000 */
+#define FSA_UNDEF 0007000
+#define FSA_SUID 0004000
+#define FSA_SGID 0002000
+#define FSA_STICKY 0001000
+#define FSA_UPERM 0000700
+#define FSA_UREAD 0000400
+#define FSA_UWRITE 0000200
+#define FSA_UEXEC 0000100
+#define FSA_GPERM 0000070
+#define FSA_GREAD 0000040
+#define FSA_GWRITE 0000020
+#define FSA_GEXEC 0000010
+#define FSA_OPERM 0000007
+#define FSA_OREAD 0000004
+#define FSA_OWRITE 0000002
+#define FSA_OEXEC 0000001
+
+
+#define FSA_PERM_MASK (FSA_UPERM | FSA_GPERM | FSA_OPERM)
+#define FSA_MODMASK 0007777 /* mutable by fs_setaddr() */
+#define FSA_DIR_PERM 0777 /* default permission for new */
+ /* directories */
+#define FSA_FILE_PERM 0666 /* default permission for new files */
+
+#define FCM_CREATEVERFSIZE 8
+
+/* stability for write */
+#define FSSTAB_UNSTABLE 0
+#define FSSTAB_DATA_SYNC 1
+#define FSSTAB_FILE_SYNC 2
+
+/*
+ * fs_online flags (meaning when set):
+ *
+ * FSOLF_NOMON Do not monitor this FS.
+ * FSOLF_UTF8_NAME All names in this FS should be in UTF-8 format.
+ * FSOLF_SYNCNOW Flush all dirty blocks for this FS.
+ * FSOLF_NODRIVE Do not assign a drive letter to this FS.
+ * FSOLF_STREAMS This FS supports streams.
+ * FSOLF_DISABLE_OPLOCKS Oplocks are disabled on this FS.
+ * FSOLF_RM_PENDING The volume is being removed (unmounted, deleted,
+ * zapped etc.).
+ * FSOLF_MDCACHE Enable VFS meta-data caching for this FS.
+ * FSOLF_ERROR Inconsistencies detected in the volume.
+ * FSOLF_SYSTEM This is a system volume, no del, ren, dtq, quotas etc
+ * allowed
+ * FSOLF_COMPLIANT This volume is compliant; supports retention on
+ * immutable and unlinkable (no delete, no rename).
+ * FSOLF_LITE_COMPLIANT This volume has a less-stringent compliant capability
+ * FSOLF_SYSAUDIT This volume supports the storing of system audit logs
+ */
+#define FSOLF_NOEXPORT 0x00000001
+#define FSOLF_READONLY 0x00000002
+#define FSOLF_LOCKED 0x00000004
+#define FSOLF_NOMON 0x00000008
+#define FSOLF_NOSHOWMNT 0x00000010
+#define FSOLF_CASE_INSENSITIVE 0x00000020
+#define FSOLF_SUPPORTS_ACLS 0x00000040
+#define FSOLF_UTF8_NAME 0x00000080
+#define FSOLF_MIRRORING 0x00000100
+#define FSOLF_SYNCNOW 0x00000200
+#define FSOLF_NODRIVE 0x00000400
+#define FSOLF_OFFLINE 0x00000800
+#define FSOLF_STREAMS 0x00001000
+#define FSOLF_DISABLE_OPLOCKS 0x00002000
+#define FSOLF_RM_PENDING 0x00004000
+#define FSOLF_MDCACHE 0x00008000
+#define FSOLF_MNT_IN_PROGRESS 0x00010000
+#define FSOLF_NO_ATIME 0x00020000
+#define FSOLF_ERROR 0x00040000
+#define FSOLF_SYSTEM 0x00080000
+#define FSOLF_COMPLIANT 0x00100000
+#define FSOLF_LITE_COMPLIANT 0x00200000
+#define FSOLF_SYSAUDIT 0x00400000
+#define FSOLF_NO_CASE_SENSITIVE 0x00800000
+#define FSOLF_XVATTR 0x02000000
+#define FSOLF_DIRENTFLAGS 0x04000000
+
+/*
+ * The following flags are shared between live and checkpoint volumes.
+ */
+#define FSOLF_SHARED_FLAGS (FSOLF_CASE_INSENSITIVE | FSOLF_UTF8_NAME | \
+ FSOLF_STREAMS)
+
+/*
+ * the following flags are dynamically set and reset so should not be stored
+ * in volume.
+ */
+#define FSOLF_MASK ~(FSOLF_NOEXPORT | FSOLF_READONLY | \
+ FSOLF_LOCKED | FSOLF_NOMON | \
+ FSOLF_SYNCNOW | FSOLF_NOSHOWMNT | \
+ FSOLF_NODRIVE | FSOLF_RM_PENDING)
+
+/*
+ * case_flag: set FHF_IGNORECASE for case-insensitive compare.
+ */
+
+struct fs_stream_info {
+ char name[MAXPATHLEN];
+ uint64_t size;
+};
+
+int fhopen(const struct smb_node *, int);
+
+extern int smb_vop_open(vnode_t **vpp, int mode, cred_t *cred,
+ caller_context_t *ct);
+extern int smb_vop_close(vnode_t *vp, int flag, cred_t *cred,
+ caller_context_t *ct);
+extern int smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_write(vnode_t *vp, uio_t *uiop, unsigned int *flag,
+ uint32_t *lcount, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp,
+ smb_attr_t *ret_attr, int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp,
+ smb_attr_t *set_attr, int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp,
+ cred_t *cr);
+extern void smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp,
+ cred_t *cr);
+extern int smb_vop_lookup(vnode_t *dvp, char *name, vnode_t **vpp,
+ char *od_name, int flags, vnode_t *rootvp, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr,
+ vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct,
+ vsecattr_t *vsap);
+extern int smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp,
+ char *to_name, int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr,
+ vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct,
+ vsecattr_t *vsap);
+extern int smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name,
+ int *namelen, ino64_t *inop, vnode_t **vpp, char *od_name, int flags,
+ cred_t *cr, caller_context_t *ct);
+extern int smb_vop_commit(vnode_t *vp, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_getdents(struct smb_node *dir_snode, uint32_t *cookiep,
+ uint64_t *verifierp, int32_t *dircountp, char *arg, char *pattern,
+ uint32_t flags, struct smb_request *sr, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr);
+extern int smb_vop_stream_lookup(vnode_t *fvp, char *stream_name,
+ vnode_t **vpp, char *name, vnode_t **xattrdirvpp, int flags,
+ vnode_t *rootvp, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_stream_create(vnode_t *fvp, char *stream_name,
+ smb_attr_t *attr, vnode_t **vpp, vnode_t **xattrdirvpp, int flags,
+ cred_t *cr, caller_context_t *ct);
+extern int smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags,
+ cred_t *cr, caller_context_t *ct);
+extern int smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep,
+ struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvp,
+ int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp,
+ int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_traverse_check(vnode_t **vpp);
+
+int smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type,
+ cred_t *cr, caller_context_t *ct);
+int smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr,
+ caller_context_t *ct);
+acl_type_t smb_vop_acl_type(vnode_t *vp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_VOPS_H */
diff --git a/usr/src/uts/common/smbsrv/smb_winpipe.h b/usr/src/uts/common/smbsrv/smb_winpipe.h
new file mode 100755
index 0000000000..93a176c101
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_winpipe.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMB_WINPIPE_H_
+#define _SMB_WINPIPE_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef _KERNEL
+#include <stddef.h>
+#endif /* _KERNEL */
+
+#include <sys/thread.h>
+#include <sys/door.h>
+#include <sys/disp.h>
+#include <sys/systm.h>
+#include <sys/processor.h>
+#include <sys/socket.h>
+#include <inet/common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMB_IO_MAX_SIZE 32
+#define SMB_MAX_PIPENAMELEN 32
+
+#define SMB_WINPIPE_DOOR_DOWN_PATH "/var/run/winpipe_doordown"
+#define SMB_WINPIPE_DOOR_UP_PATH "/var/run/winpipe_doorup"
+
+#define SMB_DOWNCALLINFO_MAGIC 0x19121969
+#define SMB_MLSVC_DOOR_VERSION 1
+
+#define SMB_RPC_FLUSH_MAGIC 0x123456CC
+#define SMB_RPC_TRANSACT 1
+#define SMB_RPC_READ 2
+#define SMB_RPC_WRITE 3
+#define SMB_RPC_FLUSH 4
+
+typedef struct {
+ uint64_t md_tid; /* caller's thread id */
+ uint16_t md_version; /* version number, start with 1 */
+ uint16_t md_call_type; /* transact, read, write, flush */
+ uint32_t md_length; /* max bytes to return */
+ uint64_t md_reserved;
+} mlsvc_door_hdr_t;
+
+typedef struct {
+ uint32_t sp_pipeid;
+ char sp_pipename[SMB_MAX_PIPENAMELEN];
+ int32_t sp_datalen;
+ char sp_data[1]; /* any size buffer */
+} smb_pipe_t;
+
+void smb_downcall_service(void *, door_arg_t *, void (**)(void *, void *),
+ void **, int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_WINPIPE_H_ */
diff --git a/usr/src/uts/common/smbsrv/smb_xdr.h b/usr/src/uts/common/smbsrv/smb_xdr.h
new file mode 100644
index 0000000000..31a7b3e72e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_xdr.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMB_XDR_H
+#define _SMBSRV_SMB_XDR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rpc/xdr.h>
+#include <sys/param.h>
+
+typedef struct smb_dr_kshare {
+ int32_t k_op;
+ char *k_path;
+ char *k_sharename;
+} smb_dr_kshare_t;
+
+#ifdef _KERNEL
+#define xdr_int8_t xdr_char
+#define xdr_uint8_t xdr_u_char
+#define xdr_int16_t xdr_short
+#define xdr_uint16_t xdr_u_short
+
+extern bool_t xdr_u_char(XDR *xdrs, uchar_t *cp);
+extern bool_t xdr_vector(XDR *xdrs, char *basep, uint_t nelem,
+ uint_t elemsize, xdrproc_t xdr_elem);
+
+smb_dr_kshare_t *smb_share_mkabsolute(uint8_t *buf, uint32_t len);
+#else
+uint8_t *smb_kshare_mkselfrel(smb_dr_kshare_t *kshare, uint32_t *len);
+#endif /* _KERNEL */
+
+/* null-terminated string buffer */
+typedef struct smb_dr_string {
+ char *buf;
+} smb_dr_string_t;
+
+/* byte buffer (non-null terminated) */
+typedef struct smb_dr_bytes {
+ uint32_t bytes_len;
+ uint8_t *bytes_val;
+} smb_dr_bytes_t;
+
+/*
+ * smb_dr_user_ctx/smb_dr_ulist data structures are defined to transfer
+ * the necessary information for all connected users via door to
+ * mlsvc. The smb_dr_user_ctx provides user context that will be part
+ * of the MLSVC rpc context.
+ *
+ * Both SMB session ID and SMB UID of smb_dr_user_ctx_t are used to
+ * uniquely identified the corresponding in-kernel SMB user object.
+ */
+#define SMB_DR_MAX_USERS 50
+typedef struct smb_dr_user_ctx {
+ uint64_t du_session_id;
+ uint16_t du_uid;
+ uint16_t du_domain_len;
+ char *du_domain;
+ uint16_t du_account_len;
+ char *du_account;
+ uint16_t du_workstation_len;
+ char *du_workstation;
+ uint32_t du_ipaddr;
+ int32_t du_native_os;
+ int64_t du_logon_time;
+ uint32_t du_flags;
+} smb_dr_user_ctx_t;
+
+typedef struct smb_dr_ulist {
+ uint32_t dul_cnt;
+ smb_dr_user_ctx_t dul_users[SMB_DR_MAX_USERS];
+} smb_dr_ulist_t;
+
+/* xdr routines for common door arguments/results */
+extern bool_t xdr_smb_dr_string_t(XDR *, smb_dr_string_t *);
+extern bool_t xdr_smb_dr_bytes_t(XDR *, smb_dr_bytes_t *);
+extern bool_t xdr_smb_dr_user_ctx_t(XDR *, smb_dr_user_ctx_t *);
+extern bool_t xdr_smb_dr_ulist_t(XDR *, smb_dr_ulist_t *);
+extern bool_t xdr_smb_dr_kshare_t(XDR *, smb_dr_kshare_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_XDR_H */
diff --git a/usr/src/uts/common/smbsrv/smbfmt.h b/usr/src/uts/common/smbsrv/smbfmt.h
new file mode 100644
index 0000000000..4f7e852e14
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smbfmt.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMBFMT_H
+#define _SMBSRV_SMBFMT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB message header formats.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMB_RESUME_KEY_FMT ".11ccl4."
+#define SMB_HEADER_ED_FMT "Mbbbwbww8c2.wwww"
+#define SMB_HEADER_ED_LEN (4+1+1+1+2+1+2+12+2+2+2+2)
+#define SMB_TRANSHDR_ED_FMT "wwwwb.wl2.wwwwb."
+#define SMB_TRANSHDR_ED_LEN (2+2+2+2+1+1+2+4+2+2+2+2+2+1+1)
+#define SMB_TRANSSHDR_ED_FMT "wwwwwwwww"
+#define SMB_TRANSSHDR_ED_LEN (2+2+2+2+2+2+2+2)
+#define SMB_TRANS2SHDR_ED_FMT "wwwwwwwww"
+#define SMB_TRANS2SHDR_ED_LEN (2+2+2+2+2+2+2+2+2)
+/* There is something wrong with this. Should be 38 bytes. It is 37 bytes */
+#define SMB_NT_TRANSHDR_ED_FMT "b2.llllllllbw"
+#define SMB_NT_TRANSHDR_ED_LEN (1+2+4+4+4+4+4+4+4+4+1+2)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMBFMT_H */
diff --git a/usr/src/uts/common/smbsrv/smbinfo.h b/usr/src/uts/common/smbsrv/smbinfo.h
new file mode 100644
index 0000000000..d6a7a03a9a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smbinfo.h
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_SMBINFO_H
+#define _SMBSRV_SMBINFO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Native OS types used in SmbSessionSetupX.
+ */
+#ifndef NATIVE_OS_DEFINED
+#define NATIVE_OS_DEFINED
+
+#define NATIVE_OS_UNKNOWN 0x00000000
+#define NATIVE_OS_NT4_0 0x00000001
+#define NATIVE_OS_WIN95 0x00000002
+#define NATIVE_OS_OTHER 0x00000003
+#define NATIVE_OS_NT5_0 0x00000004
+#define NATIVE_OS_NT5_1 0x00000005
+#define NATIVE_OS_MACOS 0x00000006
+
+/*
+ * Backward compatibility aliases.
+ */
+#define NATIVE_OS_WINNT NATIVE_OS_NT4_0
+#define NATIVE_OS_WIN2000 NATIVE_OS_NT5_0
+#define NATIVE_OS_WINXP NATIVE_OS_NT5_1
+
+#endif /* NATIVE_OS_DEFINED */
+
+
+/*
+ * Native lanman types in SmbSessionSetupX. Note that these values
+ * are not directly related to the negotiated protocol dialect.
+ */
+#ifndef NATIVE_LANMAN_DEFINED
+#define NATIVE_LANMAN_DEFINED
+
+#define NATIVE_LM_NONE 0x00000000
+#define NATIVE_LM_NT 0x00000001
+#define NATIVE_LM_WIN2000 0x00000002
+
+#endif /* NATIVE_LANMAN_DEFINED */
+
+
+/* PDC types to be used in user authentication process */
+
+#define PDC_UNKNOWN 0
+#define PDC_WINNT 1
+#define PDC_WIN2000 2
+#define PDC_WINXP 3
+#define PDC_SAMBA 4
+
+/*
+ * Please replace the use of MAX_NETWORKS with SMB_PI_MAX_NETWORKS if
+ * you find it used in conjunction with smbparm_info and maybe one day
+ * there will be just a single definition (here) throughout the code.
+ */
+#ifndef MAX_NETWORKS
+#define MAX_NETWORKS 36
+#endif /* MAX_NETWORKS */
+
+#define SMB_PI_MAX_NETWORKS 36
+#define SMB_PI_MAX_WINS 2
+
+#define SMB_SECMODE_WORKGRP 1
+#define SMB_SECMODE_DOMAIN 2
+
+#define SMB_PI_MAX_HOST 48
+#define SMB_PI_MAX_DOMAIN 48
+#define SMB_PI_MAX_SCOPE 16
+#define SMB_PI_MAX_COMMENT 58
+#define SMB_PI_MAX_USERNAME 40
+#define SMB_PI_MAX_PASSWD 40
+#define SMB_PI_MAX_NATIVE_OS 32
+#define SMB_PI_MAX_LANMAN 32
+
+
+#define SMB_PI_UNKNOWN_DOMAIN 0
+#define SMB_PI_RESOURCE_DOMAIN 1
+
+/*
+ * K.L. The keep alive time out use to default to 900
+ * seconds. It is not long enough for some applications
+ * i.e. MS Access. We currently use 5400 seconds.
+ */
+#define SMB_PI_KEEP_ALIVE_MIN (90 * 60)
+#define SMB_LM_COMPATIBILITY_DEFAULT_LEV 3
+
+/*
+ * This is max networks multiply by canonical address for IPv4
+ * This needs a fix for IPv4
+ */
+#define MAX_EXCLUDE_LIST_LEN (SMB_PI_MAX_NETWORKS * INET_ADDRSTRLEN)
+
+typedef struct smb_kmod_cfg {
+ uint32_t skc_maxbufsize;
+ uint32_t skc_maxworkers;
+ uint32_t skc_maxconnections;
+ uint32_t skc_keepalive;
+ uint32_t skc_restrict_anon;
+ uint32_t skc_signing_enable;
+ uint32_t skc_signing_required;
+ uint32_t skc_signing_check;
+ uint32_t skc_oplock_enable;
+ uint32_t skc_oplock_timeout;
+ uint32_t skc_flush_required;
+ uint32_t skc_sync_enable;
+ uint32_t skc_dirsymlink_enable;
+ uint32_t skc_announce_quota;
+ uint32_t skc_secmode;
+ uint32_t skc_lmlevel;
+
+ char skc_resource_domain[SMB_PI_MAX_DOMAIN];
+ char skc_hostname[SMB_PI_MAX_HOST];
+ char skc_system_comment[SMB_PI_MAX_COMMENT];
+} smb_kmod_cfg_t;
+
+#define SMB_VERSION_MAJOR 4
+#define SMB_VERSION_MINOR 0
+
+int smbnative_os_value(char *native_os);
+int smbnative_lm_value(char *native_lm);
+int smbnative_pdc_value(char *native_lm);
+
+/*
+ * Support for passthrough authentication.
+ */
+#define AUTH_USER_GRANT 0x00000000
+#define AUTH_GUEST_GRANT 0x00000001
+#define AUTH_IPC_ONLY_GRANT 0x00000002
+#define AUTH_CONEXUS_GRANT 0x00000004
+
+#define SMBD_DOOR_NAME "/var/run/smbd_door_old"
+#define SMBD_DOOR_VERSION 1
+
+#define SMBD_DOOR_COOKIE ((void*)(0xdeadbeef^SMBD_DOOR_VERSION))
+#define SMBD_DOOR_SIZE 256
+
+#define SMBD_DOOR_SRV_SUCCESS 0
+#define SMBD_DOOR_SRV_ERROR -1
+
+#define SMBD_DOOR_JOIN 1
+#define SMBD_DOOR_PARAM_GET 2
+#define SMBD_DOOR_PARAM_SET 3
+#define SMBD_DOOR_NETBIOS_RECONFIG 4
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMBINFO_H */
diff --git a/usr/src/uts/common/smbsrv/smbtrans.h b/usr/src/uts/common/smbsrv/smbtrans.h
new file mode 100644
index 0000000000..9ffd7e3667
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smbtrans.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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMBTRANS_H
+#define _SMBSRV_SMBTRANS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Note that name can be variable length; therefore, it has to
+ * stay last.
+ */
+typedef struct smb_dent_info {
+ uint32_t cookie;
+ smb_attr_t attr;
+ struct smb_node *snode;
+ char name83[14];
+ char shortname[14];
+ char name[1];
+} smb_dent_info_t;
+
+#define SMB_MAX_DENT_INFO_SIZE (sizeof (smb_dent_info_t) + MAXNAMELEN - 1)
+#define SMB_MAX_DENTS_BUF_SIZE (64 * 1024) /* 64k */
+#define SMB_MAX_DENTS_IOVEC (SMB_MAX_DENTS_BUF_SIZE / SMB_MAX_DENT_INFO_SIZE)
+
+typedef struct smb_dent_info_hdr {
+ struct smb_request *sr;
+ char *pattern;
+ unsigned short sattr;
+ struct uio uio;
+ struct iovec iov[SMB_MAX_DENTS_IOVEC];
+} smb_dent_info_hdr_t;
+
+int smb_get_dents(struct smb_request *sr, uint32_t *cookie,
+ struct smb_node *dir_snode, unsigned int wildcards,
+ smb_dent_info_hdr_t *ihdr, int *more);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMBTRANS_H */
diff --git a/usr/src/uts/common/smbsrv/smbvar.h b/usr/src/uts/common/smbsrv/smbvar.h
new file mode 100644
index 0000000000..30e41c714a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smbvar.h
@@ -0,0 +1,1402 @@
+/*
+ * 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.
+ */
+
+/*
+ * Structures and type definitions for the SMB module.
+ */
+
+#ifndef _SMBSRV_SMBVAR_H
+#define _SMBSRV_SMBVAR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/synch.h>
+#include <sys/taskq.h>
+#include <sys/acl.h>
+#include <sys/sdt.h>
+#include <sys/vnode.h>
+#include <sys/cred.h>
+#include <smbsrv/smb.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/smb_secdesc.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_fsd.h>
+#include <smbsrv/mlsvc.h>
+
+typedef struct smb_session smb_session_t;
+typedef struct smb_request smb_request_t;
+
+#include <smbsrv/smb_svc_sm.h>
+
+int smb_noop(void *, size_t, int);
+
+#define SMB_AUDIT_STACK_DEPTH 16
+#define SMB_AUDIT_BUF_MAX_REC 16
+#define SMB_AUDIT_NODE 0x00000001
+
+extern uint32_t smb_audit_flags;
+
+typedef struct {
+ uint32_t anr_refcnt;
+ int anr_depth;
+ pc_t anr_stack[SMB_AUDIT_STACK_DEPTH];
+} smb_audit_record_node_t;
+
+typedef struct {
+ int anb_index;
+ int anb_max_index;
+ smb_audit_record_node_t anb_records[SMB_AUDIT_BUF_MAX_REC];
+} smb_audit_buf_node_t;
+
+#define SMB_WORKER_PRIORITY 99
+/*
+ * Thread State Machine
+ * --------------------
+ *
+ * T5 T0
+ * smb_thread_destroy() <-------+ +------- smb_thread_init()
+ * | |
+ * | v
+ * +-----------------------------+
+ * | SMB_THREAD_STATE_EXITED |<---+
+ * +-----------------------------+ |
+ * | T1 |
+ * v |
+ * +-----------------------------+ |
+ * | SMB_THREAD_STATE_STARTING | |
+ * +-----------------------------+ |
+ * | T2 | T4
+ * v |
+ * +-----------------------------+ |
+ * | SMB_THREAD_STATE_RUNNING | |
+ * +-----------------------------+ |
+ * | T3 |
+ * v |
+ * +-----------------------------+ |
+ * | SMB_THREAD_STATE_EXITING |----+
+ * +-----------------------------+
+ *
+ * Transition T0
+ *
+ * This transition is executed in smb_thread_init().
+ *
+ * Transition T1
+ *
+ * This transition is executed in smb_thread_start().
+ *
+ * Transition T2
+ *
+ * This transition is executed by the thread itself when it starts running.
+ *
+ * Transition T3
+ *
+ * This transition is executed by the thread itself in
+ * smb_thread_entry_point() just before calling thread_exit().
+ *
+ *
+ * Transition T4
+ *
+ * This transition is executed in smb_thread_stop().
+ *
+ * Transition T5
+ *
+ * This transition is executed in smb_thread_destroy().
+ *
+ * Comments
+ * --------
+ *
+ * The field smb_thread_aw_t contains a function pointer that knows how to
+ * awake the thread. It is a temporary solution to work around the fact that
+ * kernel threads (not part of a userspace process) cannot be signaled.
+ */
+typedef enum smb_thread_state {
+ SMB_THREAD_STATE_STARTING = 0,
+ SMB_THREAD_STATE_RUNNING,
+ SMB_THREAD_STATE_EXITING,
+ SMB_THREAD_STATE_EXITED
+} smb_thread_state_t;
+
+struct _smb_thread;
+
+typedef void (*smb_thread_ep_t)(struct _smb_thread *, void *ep_arg);
+typedef void (*smb_thread_aw_t)(struct _smb_thread *, void *aw_arg);
+
+#define SMB_THREAD_MAGIC 0x534D4254 /* SMBT */
+
+typedef struct _smb_thread {
+ uint32_t sth_magic;
+ char sth_name[16];
+ smb_thread_state_t sth_state;
+ kthread_t *sth_th;
+ kt_did_t sth_did;
+ smb_thread_ep_t sth_ep;
+ void *sth_ep_arg;
+ smb_thread_aw_t sth_aw;
+ void *sth_aw_arg;
+ boolean_t sth_kill;
+ kmutex_t sth_mtx;
+ kcondvar_t sth_cv;
+} smb_thread_t;
+
+/*
+ * Pool of IDs
+ * -----------
+ *
+ * A pool of IDs is a pool of 16 bit numbers. It is implemented as a bitmap.
+ * A bit set to '1' indicates that that particular value has been allocated.
+ * The allocation process is done shifting a bit through the whole bitmap.
+ * The current position of that index bit is kept in the smb_idpool_t
+ * structure and represented by a byte index (0 to buffer size minus 1) and
+ * a bit index (0 to 7).
+ *
+ * The pools start with a size of 8 bytes or 64 IDs. Each time the pool runs
+ * out of IDs its current size is doubled until it reaches its maximum size
+ * (8192 bytes or 65536 IDs). The IDs 0 and 65535 are never given out which
+ * means that a pool can have a maximum number of 65534 IDs available.
+ */
+#define SMB_IDPOOL_MAGIC 0x4944504C /* IDPL */
+#define SMB_IDPOOL_MIN_SIZE 64 /* Number of IDs to begin with */
+#define SMB_IDPOOL_MAX_SIZE 64 * 1024
+
+typedef struct smb_idpool {
+ uint32_t id_magic;
+ kmutex_t id_mutex;
+ uint8_t *id_pool;
+ uint32_t id_size;
+ uint8_t id_bit;
+ uint8_t id_bit_idx;
+ uint32_t id_idx;
+ uint32_t id_idx_msk;
+ uint32_t id_free_counter;
+ uint32_t id_max_free_counter;
+} smb_idpool_t;
+
+/*
+ * Maximum size of a Netbios Request.
+ * 0x1FFFF -> Maximum size of the data
+ * 4 -> Size of the Netbios header
+ */
+#define NETBIOS_REQ_MAX_SIZE (0x1FFFF + 0x4)
+
+/*
+ * IR104720 Experiments with Windows 2000 indicate that we achieve better
+ * SmbWriteX performance with a buffer size of 64KB instead of the 37KB
+ * used with Windows NT4.0. Previous experiments with NT4.0 resulted in
+ * directory listing problems so this buffer size is configurable based
+ * on the end-user environment. When in doubt use 37KB.
+ *
+ * smb_maxbufsize (smb_negotiate.c) is setup from SMB_NT_MAXBUF during
+ * initialization.
+ */
+#define NBMAXBUF 8
+#define SMB_NT_MAXBUF(S) (((S) * 1024) - NBMAXBUF)
+extern int smb_maxbufsize;
+
+#define OUTBUFSIZE (65 * 1024)
+#define SMBHEADERSIZE 32
+#define SMBND_HASH_MASK (0xFF)
+#define MAX_IOVEC 512
+#define MAX_READREF (8 * 1024)
+
+#define SMB_WORKER_MIN 4
+#define SMB_WORKER_DEFAULT 64
+#define SMB_WORKER_MAX 1024
+
+/*
+ * Fix align a pointer or offset appropriately so that fields will not
+ * cross word boundaries.
+ */
+#define PTRALIGN(x) \
+ (((uintptr_t)(x) + (uintptr_t)(_POINTER_ALIGNMENT) - 1l) & \
+ ~((uintptr_t)(_POINTER_ALIGNMENT) - 1l))
+
+/*
+ * native os types are defined in win32/smbinfo.h
+ */
+
+/*
+ * All 4 different time / date formats that will bee seen in SMB
+ */
+typedef struct {
+ uint16_t Day : 5;
+ uint16_t Month : 4;
+ uint16_t Year : 7;
+} SMB_DATE;
+
+typedef struct {
+ uint16_t TwoSeconds : 5;
+ uint16_t Minutes : 6;
+ uint16_t Hours : 5;
+} SMB_TIME;
+
+
+typedef uint32_t UTIME; /* seconds since Jan 1 1970 */
+
+typedef struct smb_malloc_list {
+ struct smb_malloc_list *forw;
+ struct smb_malloc_list *back;
+} smb_malloc_list;
+
+typedef struct smb_llist {
+ krwlock_t ll_lock;
+ list_t ll_list;
+ uint32_t ll_count;
+ uint64_t ll_wrop;
+} smb_llist_t;
+
+typedef struct smb_slist {
+ kmutex_t sl_mutex;
+ kcondvar_t sl_cv;
+ list_t sl_list;
+ uint32_t sl_count;
+ boolean_t sl_waiting;
+} smb_slist_t;
+
+typedef struct {
+ kcondvar_t rwx_cv;
+ kmutex_t rwx_mutex;
+ krwlock_t rwx_lock;
+ boolean_t rwx_waiting;
+} smb_rwx_t;
+
+/* NOTIFY CHANGE */
+
+typedef struct smb_notify_change_req {
+ list_node_t nc_lnd;
+ struct smb_node *nc_node;
+ uint32_t nc_reply_type;
+ uint32_t nc_flags;
+} smb_notify_change_req_t;
+
+/*
+ * SMB operates over a NetBIOS-over-TCP transport (NBT) or directly
+ * over TCP, which is also known as direct hosted NetBIOS-less SMB
+ * or SMB-over-TCP.
+ *
+ * NBT messages have a 4-byte header that defines the message type
+ * (8-bits), a 7-bit flags field and a 17-bit length.
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TYPE | FLAGS |E| LENGTH |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 8-bit type Defined in RFC 1002
+ * 7-bit flags Bits 0-6 reserved (must be 0)
+ * Bit 7: Length extension bit (E)
+ * 17-bit length Includes bit 7 of the flags byte
+ *
+ *
+ * SMB-over-TCP is defined to use a modified version of the NBT header
+ * containing an 8-bit message type and 24-bit message length.
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TYPE | LENGTH |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 8-bit type Must be 0
+ * 24-bit length
+ *
+ * The following structure is used to represent a generic, in-memory
+ * SMB transport header; it is not intended to map directly to either
+ * of the over-the-wire formats.
+ */
+typedef struct {
+ uint8_t xh_type;
+ uint32_t xh_length;
+} smb_xprt_t;
+
+struct mbuf_chain {
+ volatile uint32_t flags; /* Various flags */
+ struct mbuf_chain *shadow_of; /* I'm shadowing someone */
+ struct mbuf *chain; /* Start of chain */
+ int32_t max_bytes; /* max # of bytes for chain */
+ int32_t chain_offset; /* Current offset into chain */
+};
+
+int MBC_LENGTH(struct mbuf_chain *MBC);
+void MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes);
+void MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes);
+void MBC_FLUSH(struct mbuf_chain *MBC);
+void MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF);
+void MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF);
+void MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN);
+int MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC,
+ int OFF, int LEN);
+
+#define MBC_ROOM_FOR(b, n) (((b)->chain_offset + (n)) <= (b)->max_bytes)
+
+typedef struct smb_oplock {
+ struct smb_ofile *op_ofile;
+ uint32_t op_flags;
+} smb_oplock_t;
+
+#define OPLOCK_FLAG_BREAKING 1
+
+#define OPLOCK_RELEASE_LOCK_RELEASED 0
+#define OPLOCK_RELEASE_FILE_CLOSED 1
+
+#define DOS_ATTR_VALID 0x80000000
+
+#define SMB_VFS_MAGIC 0x534D4256 /* 'SMBV' */
+
+typedef struct smb_vfs {
+ uint32_t sv_magic;
+ list_node_t sv_lnd;
+ uint32_t sv_refcnt;
+ vfs_t *sv_vfsp;
+ vnode_t *sv_rootvp;
+} smb_vfs_t;
+
+#define SMB_NODE_MAGIC 0x4E4F4445 /* 'NODE' */
+
+typedef enum {
+ SMB_NODE_STATE_AVAILABLE = 0,
+ SMB_NODE_STATE_DESTROYING
+} smb_node_state_t;
+
+typedef struct smb_node {
+ uint32_t n_magic;
+ smb_rwx_t n_lock;
+ list_node_t n_lnd;
+ smb_node_state_t n_state;
+ uint32_t n_refcnt;
+ uint32_t n_hashkey;
+ smb_llist_t *n_hash_bucket;
+ uint64_t n_orig_session_id;
+ uint32_t n_orig_uid;
+ smb_llist_t n_ofile_list;
+ smb_llist_t n_lock_list;
+ volatile int flags; /* FILE_NOTIFY_CHANGE_* */
+ volatile int waiting_event; /* # of clients requesting FCN */
+ smb_attr_t attr;
+ unsigned int what;
+ off_t n_size;
+ smb_oplock_t n_oplock;
+ struct smb_node *dir_snode; /* Directory of node */
+ struct smb_node *unnamed_stream_node; /* set in stream nodes */
+ /* Credentials for delayed delete */
+ cred_t *delete_on_close_cred;
+ char od_name[MAXNAMELEN];
+ timestruc_t set_mtime;
+ fs_desc_t tree_fsd;
+ vnode_t *vp;
+ smb_audit_buf_node_t *n_audit_buf;
+
+} smb_node_t;
+
+#define NODE_FLAGS_NOTIFY_CHANGE 0x10000fff
+#define NODE_OPLOCKS_IN_FORCE 0x0000f000
+#define NODE_OPLOCK_NONE 0x00000000
+#define NODE_EXCLUSIVE_OPLOCK 0x00001000
+#define NODE_BATCH_OPLOCK 0x00002000
+#define NODE_LEVEL_II_OPLOCK 0x00003000
+#define NODE_CAP_LEVEL_II 0x00010000
+#define NODE_PROTOCOL_LOCK 0x00020000
+#define NODE_READ_ONLY 0x00040000
+#define NODE_CREATED_READONLY 0x00080000
+#define NODE_FLAGS_WRITE_THROUGH 0x00100000
+#define NODE_FLAGS_SYNCATIME 0x00200000
+#define NODE_FLAGS_LOCKED 0x00400000
+#define NODE_FLAGS_ATTR_VALID 0x00800000
+#define NODE_FLAGS_CREATED 0x04000000
+#define NODE_FLAGS_CHANGED 0x08000000
+#define NODE_FLAGS_WATCH_TREE 0x10000000
+#define NODE_FLAGS_SET_SIZE 0x20000000
+#define NODE_FLAGS_DELETE_ON_CLOSE 0x40000000
+#define NODE_FLAGS_EXECUTABLE 0x80000000
+
+#define NODE_IS_READONLY(node) \
+ ((node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) || \
+ (node->flags & NODE_READ_ONLY) || \
+ (node->flags & NODE_CREATED_READONLY))
+
+#define OPLOCK_TYPE(n) ((n)->flags & NODE_OPLOCKS_IN_FORCE)
+#define OPLOCKS_IN_FORCE(n) (OPLOCK_TYPE(n) != NODE_OPLOCK_NONE)
+#define EXCLUSIVE_OPLOCK_IN_FORCE(n) \
+ (OPLOCK_TYPE(n) == NODE_EXCLUSIVE_OPLOCK)
+#define BATCH_OPLOCK_IN_FORCE(n) (OPLOCK_TYPE(n) == NODE_BATCH_OPLOCK)
+#define LEVEL_II_OPLOCK_IN_FORCE(n) (OPLOCK_TYPE(n) == NODE_LEVEL_II_OPLOCK)
+
+/*
+ * Based on section 2.6.1.2 (Connection Management) of the June 13,
+ * 1996 CIFS spec, a server may terminate the transport connection
+ * due to inactivity. The client software is expected to be able to
+ * automatically reconnect to the server if this happens. Like much
+ * of the useful background information, this section appears to
+ * have been dropped from later revisions of the document.
+ *
+ * Each session has an activity timestamp that's updated whenever a
+ * request is dispatched. If the session is idle, i.e. receives no
+ * requests, for SMB_SESSION_INACTIVITY_TIMEOUT minutes it will be
+ * closed.
+ *
+ * Each session has an I/O semaphore to serialize communication with
+ * the client. For example, after receiving a raw-read request, the
+ * server is not allowed to send an oplock break to the client until
+ * after it has sent the raw-read data.
+ */
+#define SMB_SESSION_INACTIVITY_TIMEOUT (15 * 60)
+
+#define SMB_SESSION_OFILE_MAX (16 * 1024)
+
+/*
+ * When a connection is set up we need to remember both the client
+ * (peer) IP address and the local IP address used to establish the
+ * connection. When a client connects with a vc number of zero, we
+ * are supposed to abort any existing connections with that client
+ * (see notes in smb_negotiate.c and smb_session_setup_andx.c). For
+ * servers with multiple network interfaces or IP aliases, however,
+ * each interface has to be managed independently since the client
+ * is not aware of the server configuration. We have to allow the
+ * client to establish a connection on each interface with a vc
+ * number of zero without aborting the other connections.
+ *
+ * ipaddr: the client (peer) IP address for the session.
+ * local_ipaddr: the local IP address used to connect to the server.
+ */
+
+#define SMB_MAC_KEYSZ 512
+
+struct smb_sign {
+ unsigned int seqnum;
+ unsigned int mackey_len;
+ unsigned int flags;
+ unsigned char mackey[SMB_MAC_KEYSZ];
+};
+
+#define SMB_SIGNING_ENABLED 1
+#define SMB_SIGNING_CHECK 2
+
+/*
+ * Session State Machine
+ * ---------------------
+ *
+ * +-----------------------------+ +------------------------------+
+ * | SMB_SESSION_STATE_CONNECTED | | SMB_SESSION_STATE_TERMINATED |
+ * +-----------------------------+ +------------------------------+
+ * T0| ^
+ * +--------------------+ |T13
+ * v |T14 |
+ * +-------------------------------+ | +--------------------------------+
+ * | SMB_SESSION_STATE_ESTABLISHED |---+--->| SMB_SESSION_STATE_DISCONNECTED |
+ * +-------------------------------+ +--------------------------------+
+ * T1| ^ ^ ^ ^
+ * +----------+ |T9 | | |
+ * v | | | |
+ * +------------------------------+ | | |
+ * | SMB_SESSION_STATE_NEGOTIATED | | | |
+ * +------------------------------+ | | |
+ * ^| ^| | ^ | | |
+ * +----------------+| || | | | | |
+ * |+----------------+ || T7| |T8 | | |
+ * || || | | | | |
+ * || +----------------+| | | | | |
+ * || |+----------------+ | | | | |
+ * || || v | | | |
+ * || || +-----------------------------------+ T10| | |
+ * || || | SMB_SESSION_STATE_OPLOCK_BREAKING |----+ | |
+ * || || +-----------------------------------+ | |
+ * || ||T5 | |
+ * || |+-->+-----------------------------------+ T11| |
+ * || |T6 | SMB_SESSION_STATE_READ_RAW_ACTIVE |------+ |
+ * || +----+-----------------------------------+ |
+ * ||T3 |
+ * |+------->+------------------------------------+ T12|
+ * |T4 | SMB_SESSION_STATE_WRITE_RAW_ACTIVE |-------+
+ * +---------+------------------------------------+
+ *
+ * Transition T0
+ *
+ *
+ *
+ * Transition T1
+ *
+ *
+ *
+ * Transition T2
+ *
+ *
+ *
+ * Transition T3
+ *
+ *
+ *
+ * Transition T4
+ *
+ *
+ *
+ * Transition T5
+ *
+ *
+ *
+ * Transition T6
+ *
+ *
+ *
+ * Transition T7
+ *
+ *
+ *
+ * Transition T8
+ *
+ *
+ *
+ * Transition T9
+ *
+ *
+ *
+ * Transition T10
+ *
+ *
+ *
+ * Transition T11
+ *
+ *
+ *
+ * Transition T12
+ *
+ *
+ *
+ * Transition T13
+ *
+ *
+ *
+ * Transition T14
+ *
+ *
+ *
+ */
+#define SMB_SESSION_MAGIC 0x53455353 /* 'SESS' */
+
+typedef enum {
+ SMB_SESSION_STATE_DISCONNECTED = 0,
+ SMB_SESSION_STATE_CONNECTED,
+ SMB_SESSION_STATE_ESTABLISHED,
+ SMB_SESSION_STATE_NEGOTIATED,
+ SMB_SESSION_STATE_OPLOCK_BREAKING,
+ SMB_SESSION_STATE_WRITE_RAW_ACTIVE,
+ SMB_SESSION_STATE_TERMINATED
+} smb_session_state_t;
+
+struct smb_session {
+ uint32_t s_magic;
+ smb_rwx_t s_lock;
+ list_node_t s_lnd;
+ uint64_t s_kid;
+ smb_session_state_t s_state;
+ uint32_t s_flags;
+ int s_write_raw_status;
+ smb_thread_t s_thread;
+ uint32_t keep_alive;
+ uint64_t opentime;
+ uint16_t vcnumber;
+ uint16_t s_local_port;
+ uint32_t ipaddr;
+ uint32_t local_ipaddr;
+ char workstation[SMB_PI_MAX_HOST];
+ int dialect;
+ int native_os;
+ uint32_t capabilities;
+ struct smb_sign signing;
+
+ struct sonode *sock;
+
+ smb_slist_t s_req_list;
+ smb_llist_t s_xa_list;
+ smb_llist_t s_user_list;
+ smb_idpool_t s_uid_pool;
+
+ volatile uint32_t s_tree_cnt;
+ volatile uint32_t s_file_cnt;
+ volatile uint32_t s_dir_cnt;
+
+ uint16_t secmode;
+ uint32_t sesskey;
+ uint32_t challenge_len;
+ unsigned char challenge_key[8];
+ unsigned char MAC_key[44];
+ int64_t activity_timestamp;
+ /*
+ * Maximum negotiated buffer size between SMB client and server
+ * in SMB_SESSION_SETUP_ANDX
+ */
+ uint16_t smb_msg_size;
+ uchar_t *outpipe_data;
+ int outpipe_datalen;
+ int outpipe_cookie;
+};
+
+#define SMB_USER_MAGIC 0x55534552 /* 'USER' */
+
+#define SMB_USER_FLAG_GUEST SMB_ATF_GUEST
+#define SMB_USER_FLAG_IPC SMB_ATF_ANON
+#define SMB_USER_FLAG_ADMIN SMB_ATF_ADMIN
+#define SMB_USER_FLAG_POWER_USER SMB_ATF_POWERUSER
+#define SMB_USER_FLAG_BACKUP_OPERATOR SMB_ATF_BACKUPOP
+
+#define SMB_USER_PRIV_TAKE_OWNERSHIP 0x00000001
+#define SMB_USER_PRIV_BACKUP 0x00000002
+#define SMB_USER_PRIV_RESTORE 0x00000004
+#define SMB_USER_PRIV_SECURITY 0x00000008
+
+
+typedef enum {
+ SMB_USER_STATE_LOGGED_IN = 0,
+ SMB_USER_STATE_LOGGING_OFF,
+ SMB_USER_STATE_LOGGED_OFF
+} smb_user_state_t;
+
+typedef struct smb_user {
+ uint32_t u_magic;
+ list_node_t u_lnd;
+ kmutex_t u_mutex;
+ smb_user_state_t u_state;
+
+ smb_session_t *u_session;
+ uint16_t u_name_len;
+ char *u_name;
+ uint16_t u_domain_len;
+ char *u_domain;
+ time_t u_logon_time;
+ cred_t *u_cred;
+
+ smb_llist_t u_tree_list;
+ smb_idpool_t u_tid_pool;
+
+ uint32_t u_refcnt;
+ uint32_t u_flags;
+ uint32_t u_privileges;
+ uint16_t u_uid;
+ uint32_t u_audit_sid;
+} smb_user_t;
+
+#define SMB_TREE_MAGIC 0x54524545 /* 'TREE' */
+#define SMB_TREE_TYPENAME_SZ 8
+
+typedef enum {
+ SMB_TREE_STATE_CONNECTED = 0,
+ SMB_TREE_STATE_DISCONNECTING,
+ SMB_TREE_STATE_DISCONNECTED
+} smb_tree_state_t;
+
+typedef struct smb_tree {
+ uint32_t t_magic;
+ kmutex_t t_mutex;
+ list_node_t t_lnd;
+ smb_tree_state_t t_state;
+
+ smb_session_t *t_session;
+ smb_user_t *t_user;
+ smb_node_t *t_snode;
+
+ smb_llist_t t_ofile_list;
+ smb_idpool_t t_fid_pool;
+
+ smb_llist_t t_odir_list;
+ smb_idpool_t t_sid_pool;
+
+ uint32_t t_refcnt;
+ uint32_t t_flags;
+ int32_t t_res_type;
+ uint16_t t_tid;
+ uint16_t t_access;
+ uint16_t t_umask;
+ char t_sharename[MAXNAMELEN];
+ char t_resource[MAXPATHLEN];
+ char t_typename[SMB_TREE_TYPENAME_SZ];
+ fs_desc_t t_fsd;
+ acl_type_t t_acltype;
+} smb_tree_t;
+
+/* Tree access bits */
+#define SMB_TREE_NO_ACCESS 0x0000
+#define SMB_TREE_READ_ONLY 0x0001
+#define SMB_TREE_READ_WRITE 0x0002
+
+/*
+ * Tree flags
+ *
+ * SMB_TREE_FLAG_ACLONCREATE Underlying FS supports ACL on create.
+ *
+ * SMB_TREE_FLAG_ACEMASKONACCESS Underlying FS understands 32-bit access mask
+ */
+#define SMB_TREE_FLAG_OPEN 0x0001
+#define SMB_TREE_FLAG_CLOSE 0x0002
+#define SMB_TREE_FLAG_ACLONCREATE 0x0004
+#define SMB_TREE_FLAG_ACEMASKONACCESS 0x0008
+#define SMB_TREE_FLAG_IGNORE_CASE 0x0010
+#define SMB_TREE_CLOSED(tree) ((tree)->t_flags & SMB_TREE_FLAG_CLOSE)
+
+/*
+ * SMB_TREE_CASE_INSENSITIVE returns whether operations on a given tree
+ * will be case-insensitive or not. SMB_TREE_FLAG_IGNORE_CASE is set at
+ * share set up time based on file system capability and client preference.
+ */
+
+#define SMB_TREE_CASE_INSENSITIVE(sr) \
+ (((sr) && (sr)->tid_tree) ? \
+ ((sr)->tid_tree->t_flags & SMB_TREE_FLAG_IGNORE_CASE) : 0)
+
+/*
+ * SMB_TREE_ROOT_FS is called by certain smb_fsop_* functions to make sure
+ * that a given vnode is in the same file system as the share root.
+ */
+
+#define SMB_TREE_ROOT_FS(sr, node) \
+ (((sr) && (sr)->tid_tree) ? \
+ ((sr)->tid_tree->t_snode->vp->v_vfsp == (node)->vp->v_vfsp) : 1)
+
+#define SMB_TREE_IS_READ_ONLY(sr) \
+ ((sr) && ((sr)->tid_tree->t_access == SMB_TREE_READ_ONLY))
+
+
+#define PIPE_STATE_AUTH_VERIFY 0x00000001
+
+/*
+ * The of_ftype of an open file should contain the SMB_FTYPE value
+ * (cifs.h) returned when the file/pipe was opened. The following
+ * assumptions are currently made:
+ *
+ * File Type Node PipeInfo
+ * --------- -------- --------
+ * SMB_FTYPE_DISK Valid Null
+ * SMB_FTYPE_BYTE_PIPE Undefined Undefined
+ * SMB_FTYPE_MESG_PIPE Null Valid
+ * SMB_FTYPE_PRINTER Undefined Undefined
+ * SMB_FTYPE_UNKNOWN Undefined Undefined
+ */
+
+/*
+ * Some flags for ofile structure
+ *
+ * SMB_OFLAGS_SET_DELETE_ON_CLOSE
+ * Set this flag when the corresponding open operation whose
+ * DELETE_ON_CLOSE bit of the CreateOptions is set. If any
+ * open file instance has this bit set, the NODE_FLAGS_DELETE_ON_CLOSE
+ * will be set for the file node upon close.
+ */
+
+#define SMB_OFLAGS_SET_DELETE_ON_CLOSE 0x0004
+#define SMB_OFLAGS_LLF_POS_VALID 0x0008
+
+#define SMB_OFILE_MAGIC 0x4F464C45 /* 'OFLE' */
+
+typedef enum {
+ SMB_OFILE_STATE_OPEN = 0,
+ SMB_OFILE_STATE_CLOSING,
+ SMB_OFILE_STATE_CLOSED
+} smb_ofile_state_t;
+
+typedef struct smb_ofile {
+ uint32_t f_magic;
+ kmutex_t f_mutex;
+ list_node_t f_lnd;
+ list_node_t f_nnd;
+ smb_ofile_state_t f_state;
+
+ smb_session_t *f_session;
+ smb_user_t *f_user;
+ smb_tree_t *f_tree;
+ smb_node_t *f_node;
+
+ mlsvc_pipe_t *f_pipe_info;
+
+ uint32_t f_refcnt;
+ uint64_t f_seek_pos;
+ uint32_t f_flags;
+ uint32_t f_granted_access;
+ uint32_t f_share_access;
+ uint32_t f_create_options;
+ uint16_t f_fid;
+ uint16_t f_opened_by_pid;
+ uint16_t f_ftype;
+ uint64_t f_llf_pos;
+ cred_t *f_cr;
+} smb_ofile_t;
+
+/* odir flags bits */
+#define SMB_DIR_FLAG_OPEN 0x0001
+#define SMB_DIR_FLAG_CLOSE 0x0002
+#define SMB_DIR_CLOSED(dir) ((dir)->d_flags & SMB_DIR_FLAG_CLOSE)
+
+#define SMB_ODIR_MAGIC 0x4F444952 /* 'ODIR' */
+
+typedef enum {
+ SMB_ODIR_STATE_OPEN = 0,
+ SMB_ODIR_STATE_CLOSING,
+ SMB_ODIR_STATE_CLOSED
+} smb_odir_state_t;
+
+typedef struct smb_odir {
+ uint32_t d_magic;
+ kmutex_t d_mutex;
+ list_node_t d_lnd;
+ smb_odir_state_t d_state;
+
+ smb_session_t *d_session;
+ smb_user_t *d_user;
+ smb_tree_t *d_tree;
+
+ uint32_t d_refcnt;
+ uint32_t d_cookie;
+ uint16_t d_sid;
+ uint16_t d_opened_by_pid;
+ uint16_t d_sattr;
+ char d_pattern[MAXNAMELEN];
+ struct smb_node *d_dir_snode;
+ unsigned int d_wildcards;
+} smb_odir_t;
+
+typedef struct smb_odir_context {
+ uint32_t dc_cookie;
+ uint16_t dc_dattr;
+ char dc_name[MAXNAMELEN]; /* Real 'Xxxx.yyy.xx' */
+ char dc_name83[14]; /* w/ dot 'XXXX .XX ' */
+ char dc_shortname[14]; /* w/ dot 'XXXX.XX' */
+ smb_attr_t dc_attr;
+} smb_odir_context_t;
+
+#define SMB_LOCK_MAGIC 0x4C4F434B /* 'LOCK' */
+
+typedef struct smb_lock {
+ uint32_t l_magic;
+ kmutex_t l_mutex;
+ list_node_t l_lnd;
+ kcondvar_t l_cv;
+
+ list_node_t l_conflict_lnd;
+ smb_slist_t l_conflict_list;
+
+ smb_session_t *l_session;
+ smb_ofile_t *l_file;
+ smb_request_t *l_sr;
+
+ uint32_t l_flags;
+ uint64_t l_session_kid;
+ struct smb_lock *l_blocked_by; /* Debug info only */
+
+ uint16_t l_pid;
+ uint16_t l_uid;
+ uint32_t l_type;
+ uint64_t l_start;
+ uint64_t l_length;
+ clock_t l_end_time;
+} smb_lock_t;
+
+#define SMB_LOCK_FLAG_INDEFINITE 0x0004
+#define SMB_LOCK_INDEFINITE_WAIT(lock) \
+ ((lock)->l_flags & SMB_LOCK_FLAG_INDEFINITE)
+
+#define SMB_LOCK_TYPE_READWRITE 101
+#define SMB_LOCK_TYPE_READONLY 102
+
+
+struct smb_fqi { /* fs_query_info */
+ char *path;
+ uint16_t srch_attr;
+ struct smb_node *dir_snode;
+ smb_attr_t dir_attr;
+ char last_comp[MAXNAMELEN];
+ int last_comp_was_found;
+ char last_comp_od[MAXNAMELEN];
+ struct smb_node *last_snode;
+ smb_attr_t last_attr;
+};
+
+#define SMB_NULL_FQI_NODES(fqi) \
+ (fqi).last_snode = NULL; \
+ (fqi).dir_snode = NULL;
+
+#define FQM_DIR_MUST_EXIST 1
+#define FQM_PATH_MUST_EXIST 2
+#define FQM_PATH_MUST_NOT_EXIST 3
+
+#define MYF_OPLOCK_MASK 0x000000F0
+#define MYF_OPLOCK_NONE 0x00000000
+#define MYF_EXCLUSIVE_OPLOCK 0x00000010
+#define MYF_BATCH_OPLOCK 0x00000020
+#define MYF_LEVEL_II_OPLOCK 0x00000030
+#define MYF_MUST_BE_DIRECTORY 0x00000100
+
+#define MYF_OPLOCK_TYPE(o) ((o) & MYF_OPLOCK_MASK)
+#define MYF_OPLOCKS_REQUEST(o) (MYF_OPLOCK_TYPE(o) != MYF_OPLOCK_NONE)
+#define MYF_IS_EXCLUSIVE_OPLOCK(o) (MYF_OPLOCK_TYPE(o) == MYF_EXCLUSIVE_OPLOCK)
+#define MYF_IS_BATCH_OPLOCK(o) (MYF_OPLOCK_TYPE(o) == MYF_BATCH_OPLOCK)
+#define MYF_IS_LEVEL_II_OPLOCK(o) (MYF_OPLOCK_TYPE(o) == MYF_LEVEL_II_OPLOCK)
+
+#define OPLOCK_MIN_TIMEOUT (5 * 1000)
+#define OPLOCK_STD_TIMEOUT (15 * 1000)
+
+
+/*
+ * SMB Request State Machine
+ * -------------------------
+ *
+ * T4 +------+ T0
+ * +--------------------------->| FREE |---------------------------+
+ * | +------+ |
+ * +-----------+ |
+ * | COMPLETED | |
+ * +-----------+
+ * ^ |
+ * | T15 +----------+ v
+ * +------------+ T6 | | +--------------+
+ * | CLEANED_UP |<-----------------| CANCELED | | INITIALIZING |
+ * +------------+ | | +--------------+
+ * | ^ +----------+ |
+ * | | ^ ^ ^ ^ |
+ * | | +-------------+ | | | |
+ * | | T3 | | | | T13 | T1
+ * | +-------------------------+ | | +----------------------+ |
+ * +----------------------------+ | | | | |
+ * T16 | | | | +-----------+ | |
+ * | \/ | | T5 | | v
+ * +-----------------+ | T12 +--------+ | T2 +-----------+
+ * | EVENT_OCCURRED |------------->| ACTIVE |<--------------------| SUBMITTED |
+ * +-----------------+ | +--------+ | +-----------+
+ * ^ | | ^ | |
+ * | | T8 | | | T7 |
+ * | T10 T9 | +----------+ | +-------+ | T11
+ * | | | +-------+ | |
+ * | | | T14 | | |
+ * | | v | v |
+ * +----------------------+ +--------------+
+ * | WAITING_EVENT | | WAITING_LOCK |
+ * +----------------------+ +--------------+
+ *
+ *
+ *
+ *
+ *
+ * Transition T0
+ *
+ * This transition occurs when the request is allocated and is still under the
+ * control of the session thread.
+ *
+ * Transition T1
+ *
+ * This transition occurs when the session thread dispatches a task to treat the
+ * request.
+ *
+ * Transition T2
+ *
+ *
+ *
+ * Transition T3
+ *
+ * A request completes and smbsr_cleanup is called to release resources
+ * associated with the request (but not the smb_request_t itself). This
+ * includes references on smb_ofile_t, smb_node_t, and other structures.
+ * CLEANED_UP state exists to detect if we attempt to cleanup a request
+ * multiple times and to allow us to detect that we are accessing a
+ * request that has already been cleaned up.
+ *
+ * Transition T4
+ *
+ *
+ *
+ * Transition T5
+ *
+ *
+ *
+ * Transition T6
+ *
+ *
+ *
+ * Transition T7
+ *
+ *
+ *
+ * Transition T8
+ *
+ *
+ *
+ * Transition T9
+ *
+ *
+ *
+ * Transition T10
+ *
+ *
+ *
+ * Transition T11
+ *
+ *
+ *
+ * Transition T12
+ *
+ *
+ *
+ * Transition T13
+ *
+ *
+ *
+ * Transition T14
+ *
+ *
+ *
+ * Transition T15
+ *
+ * Request processing is completed (control returns from smb_dispatch)
+ *
+ * Transition T16
+ *
+ * Multipart (andx) request was cleaned up with smbsr_cleanup but more "andx"
+ * sections remain to be processed.
+ *
+ */
+
+#define SMB_REQ_MAGIC 0x534D4252 /* 'SMBR' */
+
+typedef enum smb_req_state {
+ SMB_REQ_STATE_FREE = 0,
+ SMB_REQ_STATE_INITIALIZING,
+ SMB_REQ_STATE_SUBMITTED,
+ SMB_REQ_STATE_ACTIVE,
+ SMB_REQ_STATE_WAITING_EVENT,
+ SMB_REQ_STATE_EVENT_OCCURRED,
+ SMB_REQ_STATE_WAITING_LOCK,
+ SMB_REQ_STATE_COMPLETED,
+ SMB_REQ_STATE_CANCELED,
+ SMB_REQ_STATE_CLEANED_UP
+} smb_req_state_t;
+
+struct smb_request {
+ uint32_t sr_magic;
+ kmutex_t sr_mutex;
+ list_node_t sr_session_lnd;
+ smb_req_state_t sr_state;
+ boolean_t sr_keep;
+
+ struct smb_session *session;
+
+ smb_notify_change_req_t sr_ncr;
+
+ /* Info from session service header */
+ uint32_t sr_req_length; /* Excluding NBT header */
+
+ /* Request buffer excluding NBT header */
+ void *sr_request_buf;
+
+ /* Fields for raw writes */
+ uint32_t sr_raw_data_length;
+ void *sr_raw_data_buf;
+
+ smb_lock_t *sr_awaiting;
+ struct mbuf_chain command;
+ struct mbuf_chain reply;
+ struct mbuf_chain raw_data;
+ smb_malloc_list request_storage;
+ struct smb_xa *r_xa;
+ int andx_prev_wct;
+ int cur_reply_offset;
+ int orig_request_hdr;
+ unsigned int reply_seqnum; /* reply sequence number */
+ unsigned char first_smb_com; /* command code */
+ unsigned char smb_com; /* command code */
+ unsigned char smb_rcls; /* error code class */
+ unsigned char smb_reh; /* rsvd (AH DOS INT-24 ERR) */
+ uint16_t smb_err; /* error code */
+ uint8_t smb_flg; /* flags */
+ uint16_t smb_flg2; /* flags */
+ uint16_t smb_pid_high; /* high part of pid */
+ unsigned char smb_sig[8]; /* signiture */
+ uint16_t smb_tid; /* tree id # */
+ uint16_t smb_pid; /* caller's process id # */
+ uint16_t smb_uid; /* user id # */
+ uint16_t smb_mid; /* mutiplex id # */
+ unsigned char smb_wct; /* count of parameter words */
+ uint16_t smb_bcc; /* data byte count */
+
+ /* Parameters */
+ struct mbuf_chain smb_vwv; /* variable width value */
+
+ /* Data */
+ struct mbuf_chain smb_data;
+
+ uint16_t smb_fid; /* not in hdr, but common */
+ uint16_t smb_sid; /* not in hdr, but common */
+
+ unsigned char andx_com;
+ uint16_t andx_off;
+
+ struct smb_tree *tid_tree;
+ struct smb_ofile *fid_ofile;
+ struct smb_odir *sid_odir;
+ smb_user_t *uid_user;
+
+ union {
+ struct {
+ char *path;
+ char *service;
+ int pwdlen;
+ char *password;
+ uint16_t flags;
+ } tcon;
+
+ struct open_param {
+ struct smb_fqi fqi;
+ uint16_t omode;
+ uint16_t oflags;
+ uint16_t ofun;
+ uint32_t my_flags;
+ uint32_t timeo;
+ uint32_t dattr;
+ timestruc_t utime;
+ uint64_t dsize;
+ uint32_t desired_access;
+ uint32_t share_access;
+ uint32_t create_options;
+ uint32_t create_disposition;
+ uint32_t ftype, devstate;
+ uint32_t action_taken;
+ uint64_t fileid;
+ /* This is only set by NTTransactCreate */
+ smb_sdbuf_t *sd_buf;
+ } open;
+
+ struct {
+ struct smb_fqi fqi;
+ struct smb_fqi dst_fqi;
+ } dirop;
+
+ } arg;
+
+ label_t exjb;
+ cred_t *user_cr;
+ caller_context_t ct;
+};
+
+caller_context_t local_ct;
+
+#define SMB_READ_PROTOCOL(smb_nh_ptr) \
+ LE_IN32(((smb_nethdr_t *)(smb_nh_ptr))->sh_protocol)
+
+#define SMB_PROTOCOL_MAGIC_INVALID(rd_sr) \
+ (SMB_READ_PROTOCOL((rd_sr)->sr_request_buf) != SMB_PROTOCOL_MAGIC)
+
+#define SMB_READ_COMMAND(smb_nh_ptr) \
+ (((smb_nethdr_t *)(smb_nh_ptr))->sh_command)
+
+#define SMB_IS_WRITERAW(rd_sr) \
+ (SMB_READ_COMMAND((rd_sr)->sr_request_buf) == SMB_COM_WRITE_RAW)
+
+
+#define SR_FLG_OFFSET 9
+
+#define MAX_TRANS_NAME 64
+
+#define SMB_XA_FLAG_OPEN 0x0001
+#define SMB_XA_FLAG_CLOSE 0x0002
+#define SMB_XA_FLAG_COMPLETE 0x0004
+#define SMB_XA_CLOSED(xa) (!((xa)->xa_flags & SMB_XA_FLAG_OPEN))
+
+#define SMB_XA_MAGIC 0x534D4258 /* 'SMBX' */
+
+typedef struct smb_xa {
+ uint32_t xa_magic;
+ kmutex_t xa_mutex;
+ list_node_t xa_lnd;
+
+ uint32_t xa_refcnt;
+ uint32_t xa_flags;
+
+ struct smb_session *xa_session;
+
+ unsigned char smb_com; /* which TRANS type */
+ unsigned char smb_flg; /* flags */
+ uint16_t smb_flg2; /* flags */
+ uint16_t smb_tid; /* tree id number */
+ uint16_t smb_pid; /* caller's process id number */
+ uint16_t smb_uid; /* user id number */
+ uint32_t smb_func; /* NT_TRANS function */
+
+ uint16_t xa_smb_mid; /* mutiplex id number */
+ uint16_t xa_smb_fid; /* TRANS2 secondary */
+
+ unsigned int reply_seqnum; /* reply sequence number */
+
+ uint32_t smb_tpscnt; /* total parameter bytes being sent */
+ uint32_t smb_tdscnt; /* total data bytes being sent */
+ uint32_t smb_mprcnt; /* max parameter bytes to return */
+ uint32_t smb_mdrcnt; /* max data bytes to return */
+ uint32_t smb_msrcnt; /* max setup words to return */
+ uint32_t smb_flags; /* additional information: */
+ /* bit 0 - if set, disconnect TID in smb_tid */
+ /* bit 1 - if set, transaction is one way */
+ /* (no final response) */
+ int32_t smb_timeout; /* number of milliseconds to await completion */
+ uint32_t smb_suwcnt; /* set up word count */
+
+
+ char *xa_smb_trans_name;
+
+ int req_disp_param;
+ int req_disp_data;
+
+ struct mbuf_chain req_setup_mb;
+ struct mbuf_chain req_param_mb;
+ struct mbuf_chain req_data_mb;
+
+ struct mbuf_chain rep_setup_mb;
+ struct mbuf_chain rep_param_mb;
+ struct mbuf_chain rep_data_mb;
+} smb_xa_t;
+
+
+#define SDDF_NO_FLAGS 0
+#define SDDF_SUPPRESS_TID 0x0001
+#define SDDF_SUPPRESS_UID 0x0002
+#define SDDF_SUPPRESS_UNLEASH 0x0004
+#define SDDF_SUPPRESS_SHOW 0x0080
+
+#define SDRC_NORMAL_REPLY 0
+#define SDRC_DROP_VC 1
+#define SDRC_NO_REPLY 2
+#define SDRC_ERROR_REPLY 3
+#define SDRC_UNIMPLEMENTED 4
+#define SDRC_UNSUPPORTED 5
+
+
+struct vardata_block {
+ unsigned char tag;
+ uint16_t len;
+ struct uio uio;
+ struct iovec iovec[MAX_IOVEC];
+};
+
+#define VAR_BCC ((short)-1)
+
+
+
+
+extern struct smb_info smb_info;
+
+#define SMB_SI_NBT_CONNECTED 0x01
+#define SMB_SI_TCP_CONNECTED 0x02
+
+typedef struct smb_info {
+ smb_svc_sm_ctx_t si_svc_sm_ctx;
+
+ uint32_t si_open_progress;
+ uint32_t si_connect_progress;
+
+ volatile uint64_t si_global_kid;
+ volatile uint32_t si_gmtoff;
+
+ smb_thread_t si_nbt_daemon;
+ smb_thread_t si_tcp_daemon;
+ smb_thread_t si_thread_notify_change;
+ smb_thread_t si_thread_timers;
+
+ taskq_t *thread_pool;
+
+ kmem_cache_t *si_cache_vfs;
+ kmem_cache_t *si_cache_request;
+ kmem_cache_t *si_cache_session;
+ kmem_cache_t *si_cache_user;
+ kmem_cache_t *si_cache_tree;
+ kmem_cache_t *si_cache_ofile;
+ kmem_cache_t *si_cache_odir;
+ kmem_cache_t *si_cache_node;
+
+ smb_slist_t si_ncr_list;
+ smb_slist_t si_nce_list;
+
+ smb_kmod_cfg_t si;
+
+ volatile uint32_t open_trees;
+ volatile uint32_t open_files;
+ volatile uint32_t open_users;
+
+ smb_node_t *si_root_smb_node;
+ smb_llist_t node_hash_table[SMBND_HASH_MASK+1];
+ smb_llist_t si_vfs_list;
+} smb_info_t;
+
+#define SMB_INFO_NETBIOS_SESSION_SVC_RUNNING 0x0001
+#define SMB_INFO_NETBIOS_SESSION_SVC_FAILED 0x0002
+#define SMB_INFO_USER_LEVEL_SECURITY 0x40000000
+#define SMB_INFO_ENCRYPT_PASSWORDS 0x80000000
+
+#define SMB_NEW_KID() atomic_inc_64_nv(&smb_info.si_global_kid)
+
+typedef struct {
+ uint16_t errcls;
+ uint16_t errcode;
+ DWORD status;
+} smb_error_t;
+
+/*
+ * This is to be used by Trans2SetFileInfo
+ * and Trans2SetPathInfo
+ */
+typedef struct smb_trans2_setinfo {
+ uint16_t level;
+ struct smb_xa *ts_xa;
+ struct smb_node *node;
+ char *path;
+ char name[MAXNAMELEN];
+} smb_trans2_setinfo_t;
+
+
+#define SMB_IS_STREAM(node) ((node)->unnamed_stream_node)
+
+#ifdef DEBUG
+extern uint_t smb_tsd_key;
+#endif
+
+typedef struct smb_tsd {
+ void (*proc)();
+ void *arg;
+ char name[100];
+} smb_tsd_t;
+
+#define SMB_INVALID_AMASK -1
+#define SMB_INVALID_SHAREMODE -1
+#define SMB_INVALID_CRDISPOSITION -1
+
+typedef struct smb_dispatch_table {
+ int (*sdt_function)(struct smb_request *);
+ char sdt_dialect;
+ unsigned char sdt_flags;
+ krw_t sdt_slock_mode;
+ kstat_named_t sdt_dispatch_stats; /* invocations */
+} smb_dispatch_table_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMBVAR_H */
diff --git a/usr/src/uts/common/smbsrv/string.h b/usr/src/uts/common/smbsrv/string.h
new file mode 100644
index 0000000000..6696cbc33d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/string.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_STRING_H
+#define _SMBSRV_STRING_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *strsubst(char *, char, char);
+extern char *strsep(char **, const char *);
+extern char *strcanon(char *, const char *);
+
+extern char *utf8_strupr(char *);
+extern char *utf8_strlwr(char *);
+extern int utf8_isstrupr(const char *);
+extern int utf8_isstrlwr(const char *);
+extern int utf8_strcasecmp(const char *, const char *);
+extern int utf8_strncasecmp(const char *, const char *, int);
+extern int utf8_isstrascii(const char *);
+
+extern int smb_match(char *patn, char *str);
+extern int smb_match_ci(char *patn, char *str);
+extern int smb_match83(char *patn, char *str83);
+
+/*
+ * Maximum number of bytes per multi-byte character.
+ */
+#define MTS_MB_CUR_MAX 3
+#define MTS_MB_CHAR_MAX MTS_MB_CUR_MAX
+
+size_t mts_mbstowcs(mts_wchar_t *, const char *, size_t);
+size_t mts_wcstombs(char *, const mts_wchar_t *, size_t);
+int mts_mbtowc(mts_wchar_t *, const char *, size_t);
+int mts_wctomb(char *, mts_wchar_t);
+
+size_t mts_wcequiv_strlen(const char *);
+size_t mts_sbequiv_strlen(const char *);
+
+int mts_stombs(char *, char *, int);
+int mts_mbstos(char *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_STRING_H */
diff --git a/usr/src/uts/common/smbsrv/svrapi.h b/usr/src/uts/common/smbsrv/svrapi.h
new file mode 100644
index 0000000000..4199feb8d7
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/svrapi.h
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SVRAPI_H
+#define _SMBSRV_SVRAPI_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides definitions for the SMB Net interface. On Windows
+ * this would be NetAccess, NetConnection, NetFile, NetServer,
+ * NetSession, NetShare and NetSecurity but here things are a limited.
+ * This stuff should be described in Windows 9x LanMan documentation.
+ *
+ * Notes:
+ * Lengths of ASCIIZ strings are given as the maximum strlen() value.
+ * This does not include space for the terminating 0-byte. When
+ * allocating space for such an item, use the form:
+ *
+ * char username[LM20_UNLEN+1];
+ *
+ * An exception to this is PATHLEN, which does include space for the
+ * terminating 0-byte.
+ *
+ * User names, computer names and share names should be upper-cased
+ * by the caller and drawn from the ANSI character set.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Server Class (NetServerGetInfo, NetServerEnum2)
+ */
+
+struct server_info_0 {
+ char sv0_name[CNLEN + 1]; /* Server name */
+}; /* server_info_0 */
+
+
+struct server_info_1 {
+ char sv1_name[CNLEN + 1]; /* Server name */
+ unsigned char sv1_version_major; /* Major version # of net */
+ unsigned char sv1_version_minor; /* Minor version # of net */
+ uint32_t sv1_type; /* Server type */
+ char *sv1_comment; /* Exported server comment */
+}; /* server_info_1 */
+
+
+/* NOTE struct prefix must equal server_info_1 format */
+
+struct server_info_50 {
+ char sv50_name[CNLEN + 1];
+ unsigned char sv50_version_major; /* Major version # of net */
+ unsigned char sv50_version_minor; /* Minor version # of net */
+ uint32_t sv50_type; /* Server type */
+ char *sv50_comment; /* Exported server comment */
+ unsigned short sv50_security; /* SV_SECURITY_* (see below) */
+ unsigned short sv50_auditing; /* 0 = no auditing; !0 = auditing */
+ char *sv50_container; /* Security server/domain */
+ char *sv50_ab_server; /* Address book server */
+ char *sv50_ab_dll; /* Address book provider DLL */
+}; /* server_info_50 */
+
+
+struct server_info_2 {
+ char sv2_name[CNLEN + 1];
+ unsigned char sv2_version_major;
+ unsigned char sv2_version_minor;
+ uint32_t sv2_type;
+ char *sv2_comment;
+ uint32_t sv2_ulist_mtime; /* User list, last modification time */
+ uint32_t sv2_glist_mtime; /* Group list, last modification time */
+ uint32_t sv2_alist_mtime; /* Access list, last modification time */
+ uint16_t sv2_users; /* max number of users allowed */
+ uint16_t sv2_disc; /* auto-disconnect timeout(in minutes) */
+ char *sv2_alerts; /* alert names (semicolon separated) */
+ uint16_t sv2_security; /* SV_USERSECURITY or SV_SHARESECURITY */
+ uint16_t sv2_auditing; /* 0 = no auditing; nonzero = auditing */
+
+ uint16_t sv2_numadmin; /* max number of administrators allowed */
+ uint16_t sv2_lanmask; /* bit mask representing the srv'd nets */
+ uint16_t sv2_hidden; /* 0 = visible; nonzero = hidden */
+ uint16_t sv2_announce; /* visible server announce rate (sec) */
+ uint16_t sv2_anndelta; /* announce randomize interval (sec) */
+ /* name of guest account */
+ char sv2_guestacct[LM20_UNLEN + 1];
+ unsigned char sv2_pad1; /* Word alignment pad byte */
+ char *sv2_userpath; /* ASCIIZ path to user directories */
+ uint16_t sv2_chdevs; /* max # shared character devices */
+ uint16_t sv2_chdevq; /* max # character device queues */
+ uint16_t sv2_chdevjobs; /* max # character device jobs */
+ uint16_t sv2_connections; /* max # of connections */
+ uint16_t sv2_shares; /* max # of shares */
+ uint16_t sv2_openfiles; /* max # of open files */
+ uint16_t sv2_sessopens; /* max # of open files per session */
+ uint16_t sv2_sessvcs; /* max # of virtual circuits per client */
+ uint16_t sv2_sessreqs; /* max # of simul. reqs. from a client */
+ uint16_t sv2_opensearch; /* max # of open searches */
+ uint16_t sv2_activelocks; /* max # of active file locks */
+ uint16_t sv2_numreqbuf; /* number of server (standard) buffers */
+ uint16_t sv2_sizreqbuf; /* size of svr (standard) bufs (bytes) */
+ uint16_t sv2_numbigbuf; /* number of big (64K) buffers */
+ uint16_t sv2_numfiletasks; /* number of file worker processes */
+ uint16_t sv2_alertsched; /* alert counting interval (minutes) */
+ uint16_t sv2_erroralert; /* error log alerting threshold */
+ uint16_t sv2_logonalert; /* logon violation alerting threshold */
+ uint16_t sv2_accessalert; /* access violation alerting threshold */
+ uint16_t sv2_diskalert; /* low disk space alert threshold (KB) */
+ uint16_t sv2_netioalert; /* net I/O error ratio alert threshold */
+ /* (tenths of a percent) */
+ uint16_t sv2_maxauditsz; /* Maximum audit file size (KB) */
+ char *sv2_srvheuristics; /* performance related server switches */
+}; /* server_info_2 */
+
+
+struct server_info_3 {
+ char sv3_name[CNLEN + 1];
+ unsigned char sv3_version_major;
+ unsigned char sv3_version_minor;
+ uint32_t sv3_type;
+ char *sv3_comment;
+ uint32_t sv3_ulist_mtime; /* User list, last modification time */
+ uint32_t sv3_glist_mtime; /* Group list, last modification time */
+ uint32_t sv3_alist_mtime; /* Access list, last modification time */
+ uint16_t sv3_users; /* max number of users allowed */
+ uint16_t sv3_disc; /* auto-disconnect timeout(in minutes) */
+ char *sv3_alerts; /* alert names (semicolon separated) */
+ uint16_t sv3_security; /* SV_USERSECURITY or SV_SHARESECURITY */
+ uint16_t sv3_auditing; /* 0 = no auditing; nonzero = auditing */
+
+ uint16_t sv3_numadmin; /* max number of administrators allowed */
+ uint16_t sv3_lanmask; /* bit mask representing the srv'd nets */
+ uint16_t sv3_hidden; /* 0 = visible; nonzero = hidden */
+ uint16_t sv3_announce; /* visible server announce rate (sec) */
+ uint16_t sv3_anndelta; /* announce randomize interval (sec) */
+ /* name of guest account */
+ char sv3_guestacct[LM20_UNLEN + 1];
+ unsigned char sv3_pad1; /* Word alignment pad byte */
+ char *sv3_userpath; /* ASCIIZ path to user directories */
+ uint16_t sv3_chdevs; /* max # shared character devices */
+ uint16_t sv3_chdevq; /* max # character device queues */
+ uint16_t sv3_chdevjobs; /* max # character device jobs */
+ uint16_t sv3_connections; /* max # of connections */
+ uint16_t sv3_shares; /* max # of shares */
+ uint16_t sv3_openfiles; /* max # of open files */
+ uint16_t sv3_sessopens; /* max # of open files per session */
+ uint16_t sv3_sessvcs; /* max # of virtual circuits per client */
+ uint16_t sv3_sessreqs; /* max # of simul. reqs. from a client */
+ uint16_t sv3_opensearch; /* max # of open searches */
+ uint16_t sv3_activelocks; /* max # of active file locks */
+ uint16_t sv3_numreqbuf; /* number of server (standard) buffers */
+ uint16_t sv3_sizreqbuf; /* size of svr (standard) bufs (bytes) */
+ uint16_t sv3_numbigbuf; /* number of big (64K) buffers */
+ uint16_t sv3_numfiletasks; /* number of file worker processes */
+ uint16_t sv3_alertsched; /* alert counting interval (minutes) */
+ uint16_t sv3_erroralert; /* error log alerting threshold */
+ uint16_t sv3_logonalert; /* logon violation alerting threshold */
+ uint16_t sv3_accessalert; /* access violation alerting threshold */
+ uint16_t sv3_diskalert; /* low disk space alert threshold (KB) */
+ uint16_t sv3_netioalert; /* net I/O error ratio alert threshold */
+ /* (tenths of a percent) */
+ uint16_t sv3_maxauditsz; /* Maximum audit file size (KB) */
+ char *sv3_srvheuristics; /* performance related server switches */
+ uint32_t sv3_auditedevents; /* Audit event control mask */
+ uint16_t sv3_autoprofile; /* (0,1,2,3) = (NONE,LOAD,SAVE,or BOTH) */
+ char *sv3_autopath; /* file pathname (where to load & save) */
+}; /* server_info_3 */
+
+
+/*
+ * Mask to be applied to svX_version_major in order to obtain
+ * the major version number.
+ */
+#define MAJOR_VERSION_MASK 0x0F
+
+
+/*
+ * Bit-mapped values for svX_type fields. X = 1, 2, 3 etc.
+ *
+ * SV_TYPE_WORKSTATION 0x00000001 All workstations
+ * SV_TYPE_SERVER 0x00000002 All servers
+ * SV_TYPE_SQLSERVER 0x00000004 Any server running with SQL
+ * server
+ * SV_TYPE_DOMAIN_CTRL 0x00000008 Primary domain controller
+ * SV_TYPE_DOMAIN_BAKCTRL 0x00000010 Backup domain controller
+ * SV_TYPE_TIME_SOURCE 0x00000020 Server running the timesource
+ * service
+ * SV_TYPE_AFP 0x00000040 Apple File Protocol servers
+ * SV_TYPE_NOVELL 0x00000080 Novell servers
+ * SV_TYPE_DOMAIN_MEMBER 0x00000100 Domain Member
+ * SV_TYPE_PRINTQ_SERVER 0x00000200 Server sharing print queue
+ * SV_TYPE_DIALIN_SERVER 0x00000400 Server running dialin service.
+ * SV_TYPE_XENIX_SERVER 0x00000800 Xenix server
+ * SV_TYPE_NT 0x00001000 NT server
+ * SV_TYPE_WFW 0x00002000 Server running Windows for
+ * Workgroups
+ * SV_TYPE_SERVER_NT 0x00008000 Windows NT non DC server
+ * SV_TYPE_POTENTIAL_BROWSER 0x00010000 Server that can run the browser
+ * service
+ * SV_TYPE_BACKUP_BROWSER 0x00020000 Backup browser server
+ * SV_TYPE_MASTER_BROWSER 0x00040000 Master browser server
+ * SV_TYPE_DOMAIN_MASTER 0x00080000 Domain Master Browser server
+ * SV_TYPE_LOCAL_LIST_ONLY 0x40000000 Enumerate only entries marked
+ * "local"
+ * SV_TYPE_DOMAIN_ENUM 0x80000000 Enumerate Domains. The pszDomain
+ * parameter must be NULL.
+ */
+#define SV_TYPE_WORKSTATION 0x00000001
+#define SV_TYPE_SERVER 0x00000002
+#define SV_TYPE_SQLSERVER 0x00000004
+#define SV_TYPE_DOMAIN_CTRL 0x00000008
+#define SV_TYPE_DOMAIN_BAKCTRL 0x00000010
+#define SV_TYPE_TIME_SOURCE 0x00000020
+#define SV_TYPE_AFP 0x00000040
+/* Also set by Win95 NWSERVER */
+#define SV_TYPE_NOVELL 0x00000080
+#define SV_TYPE_DOMAIN_MEMBER 0x00000100
+#define SV_TYPE_PRINTQ_SERVER 0x00000200
+#define SV_TYPE_DIALIN_SERVER 0x00000400
+#define SV_TYPE_XENIX_SERVER 0x00000800
+#define SV_TYPE_NT 0x00001000
+#define SV_TYPE_WFW 0x00002000
+#define SV_TYPE_SERVER_NT 0x00008000
+#define SV_TYPE_POTENTIAL_BROWSER 0x00010000
+#define SV_TYPE_BACKUP_BROWSER 0x00020000
+#define SV_TYPE_MASTER_BROWSER 0x00040000
+#define SV_TYPE_DOMAIN_MASTER 0x00080000
+#define SV_TYPE_LOCAL_LIST_ONLY 0x40000000
+#define SV_TYPE_DOMAIN_ENUM 0x80000000
+/* Handy for NetServerEnum2 */
+#define SV_TYPE_ALL 0xFFFFFFFF
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SVRAPI_H */
diff --git a/usr/src/uts/common/smbsrv/winioctl.h b/usr/src/uts/common/smbsrv/winioctl.h
new file mode 100644
index 0000000000..8a9badc544
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/winioctl.h
@@ -0,0 +1,475 @@
+/*
+ * 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.
+ */
+#ifndef _SMBSRV_WINIOCTL_H
+#define _SMBSRV_WINIOCTL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Standard Windows NT IOCTL/FSCTL definitions (derived from the VC++
+ * include file of the same name).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _DEVIOCTL_
+#define _DEVIOCTL_
+
+/*
+ * begin_ntddk begin_wdm begin_nthal begin_ntifs
+ *
+ * Define the various device type values. Note that values used by Microsoft
+ * Corporation are in the range 0-32767, and 32768-65535 are reserved for use
+ * by customers.
+ */
+
+#define DEVICE_TYPE DWORD
+
+#define FILE_DEVICE_BEEP 0x00000001
+#define FILE_DEVICE_CD_ROM 0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
+#define FILE_DEVICE_CONTROLLER 0x00000004
+#define FILE_DEVICE_DATALINK 0x00000005
+#define FILE_DEVICE_DFS 0x00000006
+#define FILE_DEVICE_DISK 0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define FILE_DEVICE_INPORT_PORT 0x0000000a
+#define FILE_DEVICE_KEYBOARD 0x0000000b
+#define FILE_DEVICE_MAILSLOT 0x0000000c
+#define FILE_DEVICE_MIDI_IN 0x0000000d
+#define FILE_DEVICE_MIDI_OUT 0x0000000e
+#define FILE_DEVICE_MOUSE 0x0000000f
+#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010
+#define FILE_DEVICE_NAMED_PIPE 0x00000011
+#define FILE_DEVICE_NETWORK 0x00000012
+#define FILE_DEVICE_NETWORK_BROWSER 0x00000013
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL 0x00000015
+#define FILE_DEVICE_PARALLEL_PORT 0x00000016
+#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
+#define FILE_DEVICE_PRINTER 0x00000018
+#define FILE_DEVICE_SCANNER 0x00000019
+#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a
+#define FILE_DEVICE_SERIAL_PORT 0x0000001b
+#define FILE_DEVICE_SCREEN 0x0000001c
+#define FILE_DEVICE_SOUND 0x0000001d
+#define FILE_DEVICE_STREAMS 0x0000001e
+#define FILE_DEVICE_TAPE 0x0000001f
+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+#define FILE_DEVICE_TRANSPORT 0x00000021
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#define FILE_DEVICE_VIDEO 0x00000023
+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
+#define FILE_DEVICE_WAVE_IN 0x00000025
+#define FILE_DEVICE_WAVE_OUT 0x00000026
+#define FILE_DEVICE_8042_PORT 0x00000027
+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
+#define FILE_DEVICE_BATTERY 0x00000029
+#define FILE_DEVICE_BUS_EXTENDER 0x0000002a
+#define FILE_DEVICE_MODEM 0x0000002b
+#define FILE_DEVICE_VDM 0x0000002c
+#define FILE_DEVICE_MASS_STORAGE 0x0000002d
+#define FILE_DEVICE_SMB 0x0000002e
+#define FILE_DEVICE_KS 0x0000002f
+#define FILE_DEVICE_CHANGER 0x00000030
+#define FILE_DEVICE_SMARTCARD 0x00000031
+#define FILE_DEVICE_ACPI 0x00000032
+#define FILE_DEVICE_DVD 0x00000033
+#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034
+#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035
+#define FILE_DEVICE_DFS_VOLUME 0x00000036
+
+/*
+ * Macro definition for defining IOCTL and FSCTL function control codes. Note
+ * that function codes 0-2047 are reserved for Microsoft Corporation, and
+ * 2048-4095 are reserved for customers.
+ */
+
+#define CTL_CODE(DeviceType, Function, Method, Access) \
+ (((DeviceType) << 16) | ((Access) << 14) | \
+ ((Function) << 2) | (Method))
+
+/*
+ * Define the method codes for how buffers are passed for I/O and FS controls
+ */
+
+#define METHOD_BUFFERED 0
+#define METHOD_IN_DIRECT 1
+#define METHOD_OUT_DIRECT 2
+#define METHOD_NEITHER 3
+
+/*
+ * Define the access check value for any access
+ */
+
+#define FILE_ANY_ACCESS 0
+#define FILE_READ_ACCESS 0x0001 /* file & pipe */
+#define FILE_WRITE_ACCESS 0x0002 /* file & pipe */
+
+/* end_ntddk end_wdm end_nthal end_ntifs */
+
+#endif /* _DEVIOCTL_ */
+
+
+#ifndef _NTDDSTOR_H_
+#define _NTDDSTOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * IoControlCode values for storage devices
+ */
+
+#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
+
+/*
+ * The following device control codes are common for all class drivers. They
+ * should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE
+ * common codes
+ */
+
+#define IOCTL_STORAGE_CHECK_VERIFY \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_MEDIA_REMOVAL \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_EJECT_MEDIA \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_LOAD_MEDIA \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESERVE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RELEASE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_FIND_NEW_DEVICES \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_STORAGE_GET_MEDIA_TYPES \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_STORAGE_RESET_BUS \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESET_DEVICE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_STORAGE_GET_DEVICE_NUMBER \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _NTDDSTOR_H_ */
+
+/*
+ * IoControlCode values for disk devices.
+ */
+
+#define IOCTL_DISK_BASE FILE_DEVICE_DISK
+#define IOCTL_DISK_GET_DRIVE_GEOMETRY \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_GET_PARTITION_INFO \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_SET_PARTITION_INFO \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_GET_DRIVE_LAYOUT \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_SET_DRIVE_LAYOUT \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_VERIFY \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_FORMAT_TRACKS \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_REASSIGN_BLOCKS \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_PERFORMANCE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_IS_WRITABLE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_LOGGING \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_FORMAT_TRACKS_EX \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_HISTOGRAM_STRUCTURE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_HISTOGRAM_DATA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_HISTOGRAM_RESET \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_REQUEST_STRUCTURE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_REQUEST_DATA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_CONTROLLER_NUMBER \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/*
+ * IOCTL support for SMART drive fault prediction.
+ */
+
+#define SMART_GET_VERSION \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define SMART_SEND_DRIVE_COMMAND \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define SMART_RCV_DRIVE_DATA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+
+/*
+ * The following device control codes are common for all class drivers. The
+ * functions codes defined here must match all of the other class drivers.
+ *
+ * Warning: these codes will be replaced in the future by equivalent
+ * IOCTL_STORAGE codes
+ */
+
+#define IOCTL_DISK_CHECK_VERIFY \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_MEDIA_REMOVAL \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_EJECT_MEDIA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_LOAD_MEDIA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_RESERVE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_RELEASE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_FIND_NEW_DEVICES \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_GET_MEDIA_TYPES \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_CHANGER_BASE FILE_DEVICE_CHANGER
+
+#define IOCTL_CHANGER_GET_PARAMETERS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_GET_STATUS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_GET_PRODUCT_DATA \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_SET_ACCESS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0004, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_CHANGER_GET_ELEMENT_STATUS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0005, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_SET_POSITION \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_EXCHANGE_MEDIUM \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_MOVE_MEDIUM \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0009, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_REINITIALIZE_TRANSPORT \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_QUERY_VOLUME_TAGS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x000B, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#ifndef _FILESYSTEMFSCTL_
+#define _FILESYSTEMFSCTL_
+/*
+ * The following is a list of the native file system fsctls followed by
+ * additional network file system fsctls. Some values have been
+ * decommissioned.
+ */
+
+#define FSCTL_REQUEST_OPLOCK_LEVEL_1 \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_REQUEST_OPLOCK_LEVEL_2 \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_REQUEST_BATCH_OPLOCK \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 3, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_OPBATCH_ACK_CLOSE_PENDING \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 4, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_OPLOCK_BREAK_NOTIFY \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 5, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_LOCK_VOLUME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_UNLOCK_VOLUME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_DISMOUNT_VOLUME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* decommissioned fsctl value 9 */
+#define FSCTL_IS_VOLUME_MOUNTED \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* PATHNAME_BUFFER, */
+#define FSCTL_IS_PATHNAME_VALID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_MARK_VOLUME_DIRTY \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* decommissioned fsctl value 13 */
+#define FSCTL_QUERY_RETRIEVAL_POINTERS \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_GET_COMPRESSION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_SET_COMPRESSION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+/* decommissioned fsctl value 17 */
+/* decommissioned fsctl value 18 */
+#define FSCTL_MARK_AS_SYSTEM_HIVE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_OPLOCK_BREAK_ACK_NO_2 \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_INVALIDATE_VOLUMES \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* FSCTL_QUERY_FAT_BPB_BUFFER */
+#define FSCTL_QUERY_FAT_BPB \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_REQUEST_FILTER_OPLOCK \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* FILESYSTEM_STATISTICS */
+#define FSCTL_FILESYSTEM_GET_STATISTICS \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* NTFS_VOLUME_DATA_BUFFER */
+#define FSCTL_GET_NTFS_VOLUME_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* NTFS_FILE_RECORD_INPUT_BUFFER, NTFS_FILE_RECORD_OUTPUT_BUFFER */
+#define FSCTL_GET_NTFS_FILE_RECORD \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 26, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* STARTING_LCN_INPUT_BUFFER, VOLUME_BITMAP_BUFFER */
+#define FSCTL_GET_VOLUME_BITMAP \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 27, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* STARTING_VCN_INPUT_BUFFER, RETRIEVAL_POINTERS_BUFFER */
+#define FSCTL_GET_RETRIEVAL_POINTERS \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* MOVE_FILE_DATA, */
+#define FSCTL_MOVE_FILE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 29, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_IS_VOLUME_DIRTY \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_GET_HFS_INFORMATION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 31, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_ALLOW_EXTENDED_DASD_IO \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 32, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_READ_PROPERTY_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 33, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_WRITE_PROPERTY_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 34, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_FIND_FILES_BY_SID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 35, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* decommissioned fsctl value 36 */
+#define FSCTL_DUMP_PROPERTY_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 37, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* FILE_OBJECTID_BUFFER */
+#define FSCTL_SET_OBJECT_ID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 38, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* FILE_OBJECTID_BUFFER */
+#define FSCTL_GET_OBJECT_ID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 39, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_DELETE_OBJECT_ID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 40, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* REPARSE_DATA_BUFFER, */
+#define FSCTL_SET_REPARSE_POINT \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* REPARSE_DATA_BUFFER */
+#define FSCTL_GET_REPARSE_POINT \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* REPARSE_DATA_BUFFER, */
+#define FSCTL_DELETE_REPARSE_POINT \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* MFT_ENUM_DATA, */
+#define FSCTL_ENUM_USN_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 44, METHOD_NEITHER, FILE_READ_ACCESS)
+/* BULK_SECURITY_TEST_DATA, */
+#define FSCTL_SECURITY_ID_CHECK \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 45, METHOD_NEITHER, FILE_READ_ACCESS)
+/* READ_USN_JOURNAL_DATA, USN */
+#define FSCTL_READ_USN_JOURNAL \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, FILE_READ_ACCESS)
+#define FSCTL_SET_OBJECT_ID_EXTENDED \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 47, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* FILE_OBJECTID_BUFFER */
+#define FSCTL_CREATE_OR_GET_OBJECT_ID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 48, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_SET_SPARSE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* FILE_ZERO_DATA_INFORMATION, */
+#define FSCTL_SET_ZERO_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* FILE_ALLOCATED_RANGE_BUFFER, FILE_ALLOCATED_RANGE_BUFFER */
+#define FSCTL_QUERY_ALLOCATED_RANGES \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_ACCESS)
+#define FSCTL_ENABLE_UPGRADE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 52, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* ENCRYPTION_BUFFER, */
+#define FSCTL_SET_ENCRYPTION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 53, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_ENCRYPTION_FSCTL_IO \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 54, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* ENCRYPTED_DATA_INFO, */
+#define FSCTL_WRITE_RAW_ENCRYPTED \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 55, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* REQUEST_RAW_ENCRYPTED_DATA, ENCRYPTED_DATA_INFO */
+#define FSCTL_READ_RAW_ENCRYPTED \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 56, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* CREATE_USN_JOUNRAL_DATA, */
+#define FSCTL_CREATE_USN_JOURNAL \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 57, METHOD_NEITHER, FILE_READ_ACCESS)
+/* Read the Usn Record for a file */
+#define FSCTL_READ_FILE_USN_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58, METHOD_NEITHER, FILE_READ_ACCESS)
+/* Generate Close Usn Record */
+#define FSCTL_WRITE_USN_CLOSE_RECORD \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 59, METHOD_NEITHER, FILE_READ_ACCESS)
+#define FSCTL_EXTEND_VOLUME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 60, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif /* _FILESYSTEMFSCTL_ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_WINIOCTL_H */
diff --git a/usr/src/uts/common/smbsrv/winsvc.h b/usr/src/uts/common/smbsrv/winsvc.h
new file mode 100644
index 0000000000..9da682c1bb
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/winsvc.h
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_WINSVC_H
+#define _SMBSRV_WINSVC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Service Control interface definition for the Service Control
+ * Manager (SCM).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Service types (Bit Mask).
+ *
+ * SERVICE_WIN32_OWN_PROCESS The service runs in its own process.
+ * SERVICE_WIN32_SHARE_PROCESS The service shares a process with other
+ * services.
+ */
+#define SERVICE_KERNEL_DRIVER 0x00000001
+#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002
+#define SERVICE_ADAPTER 0x00000004
+#define SERVICE_RECOGNIZER_DRIVER 0x00000008
+#define SERVICE_WIN32_OWN_PROCESS 0x00000010
+#define SERVICE_WIN32_SHARE_PROCESS 0x00000020
+#define SERVICE_INTERACTIVE_PROCESS 0x00000100
+
+#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER \
+ | SERVICE_FILE_SYSTEM_DRIVER \
+ | SERVICE_RECOGNIZER_DRIVER)
+
+#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS \
+ | SERVICE_WIN32_SHARE_PROCESS)
+
+#define SERVICE_TYPE_ALL (SERVICE_WIN32 \
+ | SERVICE_ADAPTER \
+ | SERVICE_DRIVER \
+ | SERVICE_INTERACTIVE_PROCESS)
+
+/*
+ * Start type.
+ */
+#define SERVICE_BOOT_START 0x00000000
+#define SERVICE_SYSTEM_START 0x00000001
+#define SERVICE_AUTO_START 0x00000002
+#define SERVICE_DEMAND_START 0x00000003
+#define SERVICE_DISABLED 0x00000004
+
+/*
+ * Error control type.
+ */
+#define SERVICE_ERROR_IGNORE 0x00000000
+#define SERVICE_ERROR_NORMAL 0x00000001
+#define SERVICE_ERROR_SEVERE 0x00000002
+#define SERVICE_ERROR_CRITICAL 0x00000003
+
+/*
+ * Value to indicate no change to an optional parameter.
+ */
+#define SERVICE_NO_CHANGE 0xffffffff
+
+/*
+ * Service State - for Enum Requests (Bit Mask).
+ */
+#define SERVICE_ACTIVE 0x00000001
+#define SERVICE_INACTIVE 0x00000002
+#define SERVICE_STATE_ALL (SERVICE_ACTIVE | SERVICE_INACTIVE)
+
+/*
+ * Controls
+ */
+#define SERVICE_CONTROL_STOP 0x00000001
+#define SERVICE_CONTROL_PAUSE 0x00000002
+#define SERVICE_CONTROL_CONTINUE 0x00000003
+#define SERVICE_CONTROL_INTERROGATE 0x00000004
+#define SERVICE_CONTROL_SHUTDOWN 0x00000005
+#define SERVICE_CONTROL_PARAMCHANGE 0x00000006
+#define SERVICE_CONTROL_NETBINDADD 0x00000007
+#define SERVICE_CONTROL_NETBINDREMOVE 0x00000008
+#define SERVICE_CONTROL_NETBINDENABLE 0x00000009
+#define SERVICE_CONTROL_NETBINDDISABLE 0x0000000A
+
+/*
+ * Service State -- for CurrentState
+ */
+#define SERVICE_STOPPED 0x00000001
+#define SERVICE_START_PENDING 0x00000002
+#define SERVICE_STOP_PENDING 0x00000003
+#define SERVICE_RUNNING 0x00000004
+#define SERVICE_CONTINUE_PENDING 0x00000005
+#define SERVICE_PAUSE_PENDING 0x00000006
+#define SERVICE_PAUSED 0x00000007
+
+/*
+ * Controls Accepted (Bit Mask)
+ *
+ * SERVICE_ACCEPT_NETBINDCHANGE
+ * Windows 2000/XP: The service is a network component that
+ * can accept changes in its binding without being stopped and restarted.
+ * This control code allows the service to receive SERVICE_CONTROL_NETBINDADD,
+ * SERVICE_CONTROL_NETBINDREMOVE, SERVICE_CONTROL_NETBINDENABLE, and
+ * SERVICE_CONTROL_NETBINDDISABLE notifications.
+ *
+ * SERVICE_ACCEPT_PARAMCHANGE
+ * Windows 2000/XP: The service can reread its startup parameters without
+ * being stopped and restarted. This control code allows the service to
+ * receive SERVICE_CONTROL_PARAMCHANGE notifications.
+ *
+ * SERVICE_ACCEPT_PAUSE_CONTINUE
+ * The service can be paused and continued. This control code allows the
+ * service to receive SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE
+ * notifications.
+ *
+ * SERVICE_ACCEPT_SHUTDOWN
+ * The service is notified when system shutdown occurs. This control code
+ * allows the service to receive SERVICE_CONTROL_SHUTDOWN notifications.
+ * Note that ControlService cannot send this notification; only the system
+ * can send it.
+ *
+ * SERVICE_ACCEPT_STOP
+ * The service can be stopped. This control code allows the service to
+ * receive SERVICE_CONTROL_STOP notifications.
+ */
+#define SERVICE_ACCEPT_STOP 0x00000001
+#define SERVICE_ACCEPT_PAUSE_CONTINUE 0x00000002
+#define SERVICE_ACCEPT_SHUTDOWN 0x00000004
+#define SERVICE_ACCEPT_PARAMCHANGE 0x00000008
+#define SERVICE_ACCEPT_NETBINDCHANGE 0x00000010
+
+/*
+ * Service Control Manager object specific access types.
+ */
+#define SC_MANAGER_CONNECT 0x0001
+#define SC_MANAGER_CREATE_SERVICE 0x0002
+#define SC_MANAGER_ENUMERATE_SERVICE 0x0004
+#define SC_MANAGER_LOCK 0x0008
+#define SC_MANAGER_QUERY_LOCK_STATUS 0x0010
+#define SC_MANAGER_MODIFY_BOOT_CONFIG 0x0020
+
+#define SC_MANAGER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED \
+ | SC_MANAGER_CONNECT \
+ | SC_MANAGER_CREATE_SERVICE \
+ | SC_MANAGER_ENUMERATE_SERVICE \
+ | SC_MANAGER_LOCK \
+ | SC_MANAGER_QUERY_LOCK_STATUS \
+ | SC_MANAGER_MODIFY_BOOT_CONFIG)
+
+/*
+ * Service object specific access type.
+ */
+#define SERVICE_QUERY_CONFIG 0x0001
+#define SERVICE_CHANGE_CONFIG 0x0002
+#define SERVICE_QUERY_STATUS 0x0004
+#define SERVICE_ENUMERATE_DEPENDENTS 0x0008
+#define SERVICE_START 0x0010
+#define SERVICE_STOP 0x0020
+#define SERVICE_PAUSE_CONTINUE 0x0040
+#define SERVICE_INTERROGATE 0x0080
+#define SERVICE_USER_DEFINED_CONTROL 0x0100
+
+#define SERVICE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED \
+ | SERVICE_QUERY_CONFIG \
+ | SERVICE_CHANGE_CONFIG \
+ | SERVICE_QUERY_STATUS \
+ | SERVICE_ENUMERATE_DEPENDENTS \
+ | SERVICE_START \
+ | SERVICE_STOP \
+ | SERVICE_PAUSE_CONTINUE \
+ | SERVICE_INTERROGATE \
+ | SERVICE_USER_DEFINED_CONTROL)
+
+/*
+ * Info levels for ChangeServiceConfig2 and QueryServiceConfig2.
+ */
+#define SERVICE_CONFIG_DESCRIPTION 1
+#define SERVICE_CONFIG_FAILURE_ACTIONS 2
+
+/*
+ * Actions to take on service failure (SC_ACTION_TYPE).
+ */
+#define SC_ACTION_NONE 0
+#define SC_ACTION_RESTART 1
+#define SC_ACTION_REBOOT 2
+#define SC_ACTION_RUN_COMMAND 3
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_WINSVC_H */
diff --git a/usr/src/uts/common/smbsrv/wintypes.h b/usr/src/uts/common/smbsrv/wintypes.h
new file mode 100644
index 0000000000..698e5dcdde
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/wintypes.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef _SMBSRV_WINTYPES_H
+#define _SMBSRV_WINTYPES_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Standard win32 types and definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef UNSIGNED_TYPES_DEFINED
+#define UNSIGNED_TYPES_DEFINED
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned int DWORD;
+/* XXX PGD Shouldn't this be "char *"? */
+typedef unsigned char *LPTSTR;
+typedef unsigned char *LPBYTE;
+typedef unsigned short *LPWORD;
+typedef unsigned int *LPDWORD;
+
+#endif /* UNSIGNED_TYPES_DEFINED */
+
+
+#ifndef ANY_SIZE_ARRAY
+#define ANY_SIZE_ARRAY 1
+#endif /* ANY_SIZE_ARRAY */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_WINTYPES_H */
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index 4cd97b5c3a..55b5b18e42 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -76,6 +76,7 @@ CHKHDRS= \
acct.h \
acctctl.h \
acl.h \
+ acl_impl.h \
aggr.h \
aggr_impl.h \
aio.h \
@@ -85,6 +86,7 @@ CHKHDRS= \
ascii.h \
asynch.h \
atomic.h \
+ attr.h \
audio.h \
audiodebug.h \
audioio.h \
@@ -223,6 +225,7 @@ CHKHDRS= \
exacct_impl.h \
exec.h \
exechdr.h \
+ extdirent.h \
fault.h \
fasttrap.h \
fasttrap_impl.h \
@@ -540,6 +543,7 @@ CHKHDRS= \
turnstile.h \
types.h \
types32.h \
+ tzfile.h \
u8_textprep.h \
u8_textprep_data.h \
uadmin.h \
diff --git a/usr/src/uts/common/sys/acl.h b/usr/src/uts/common/sys/acl.h
index b0dc94240d..98f962deba 100644
--- a/usr/src/uts/common/sys/acl.h
+++ b/usr/src/uts/common/sys/acl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,6 +29,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
+#include <sys/acl_impl.h>
#ifdef __cplusplus
extern "C" {
@@ -62,7 +63,7 @@ typedef struct acl_info acl_t;
#define ACL_DEFAULT (0x1000) /* default flag */
/* default object owner */
#define DEF_USER_OBJ (ACL_DEFAULT | USER_OBJ)
-/* defalut additional users */
+/* default additional users */
#define DEF_USER (ACL_DEFAULT | USER)
/* default owning group */
#define DEF_GROUP_OBJ (ACL_DEFAULT | GROUP_OBJ)
@@ -101,6 +102,7 @@ typedef struct acl_info acl_t;
#define ACE_SUCCESSFUL_ACCESS_ACE_FLAG 0x0010
#define ACE_FAILED_ACCESS_ACE_FLAG 0x0020
#define ACE_IDENTIFIER_GROUP 0x0040
+#define ACE_INHERITED_ACE 0x0080
#define ACE_OWNER 0x1000
#define ACE_GROUP 0x2000
#define ACE_EVERYONE 0x4000
@@ -110,6 +112,44 @@ typedef struct acl_info acl_t;
#define ACE_SYSTEM_AUDIT_ACE_TYPE 0x0002
#define ACE_SYSTEM_ALARM_ACE_TYPE 0x0003
+#define ACL_AUTO_INHERIT 0x0001
+#define ACL_PROTECTED 0x0002
+#define ACL_DEFAULTED 0x0004
+#define ACL_FLAGS_ALL (ACL_AUTO_INHERIT|ACL_PROTECTED| \
+ ACL_DEFAULTED)
+
+#ifdef _KERNEL
+
+/*
+ * These are only applicable in a CIFS context.
+ */
+#define ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x04
+#define ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05
+#define ACE_ACCESS_DENIED_OBJECT_ACE_TYPE 0x06
+#define ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07
+#define ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08
+#define ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x09
+#define ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE 0x0A
+#define ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE 0x0B
+#define ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE 0x0C
+#define ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE 0x0D
+#define ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE 0x0E
+#define ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE 0x0F
+#define ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 0x10
+
+#define ACE_ALL_TYPES 0x001F
+
+typedef struct ace_object {
+ uid_t a_who; /* uid or gid */
+ uint32_t a_access_mask; /* read,write,... */
+ uint16_t a_flags; /* see below */
+ uint16_t a_type; /* allow or deny */
+ uint8_t a_obj_type[16]; /* obj type */
+ uint8_t a_inherit_obj_type[16]; /* inherit obj */
+} ace_object_t;
+
+#endif
+
#define ACE_ALL_PERMS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS| \
ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES| \
@@ -125,7 +165,10 @@ typedef struct acl_info acl_t;
ACE_INHERIT_ONLY_ACE | \
ACE_IDENTIFIER_GROUP)
-#define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE|ACE_IDENTIFIER_GROUP)
+#define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE| \
+ ACE_IDENTIFIER_GROUP)
+#define ACE_INHERIT_FLAGS (ACE_FILE_INHERIT_ACE| \
+ ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
/* cmd args to acl(2) for aclent_t */
#define GETACL 1
diff --git a/usr/src/uts/common/sys/acl_impl.h b/usr/src/uts/common/sys/acl_impl.h
new file mode 100644
index 0000000000..b82f259143
--- /dev/null
+++ b/usr/src/uts/common/sys/acl_impl.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_ACL_IMPL_H
+#define _SYS_ACL_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * acl flags
+ *
+ * ACL_AUTO_INHERIT, ACL_PROTECTED and ACL_DEFAULTED
+ * flags can also be stored in this field.
+ */
+#define ACL_IS_TRIVIAL 0x10000
+#define ACL_IS_DIR 0x20000
+
+typedef enum acl_type {
+ ACLENT_T = 0,
+ ACE_T = 1
+} acl_type_t;
+
+struct acl_info {
+ acl_type_t acl_type; /* style of acl */
+ int acl_cnt; /* number of acl entries */
+ int acl_entry_size; /* sizeof acl entry */
+ int acl_flags; /* special flags about acl */
+ void *acl_aclp; /* the acl */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ACL_IMPL_H */
diff --git a/usr/src/uts/common/sys/attr.h b/usr/src/uts/common/sys/attr.h
new file mode 100644
index 0000000000..34e802eed1
--- /dev/null
+++ b/usr/src/uts/common/sys/attr.h
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_ATTR_H
+#define _SYS_ATTR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <nfs/nfs.h>
+#endif
+#include <sys/nvpair.h>
+
+/* Attribute names for nvlist's */
+#define A_CRTIME "crtime"
+#define A_HIDDEN "hidden"
+#define A_SYSTEM "system"
+#define A_READONLY "readonly"
+#define A_ARCHIVE "archive"
+#define A_NOUNLINK "nounlink"
+#define A_IMMUTABLE "immutable"
+#define A_APPENDONLY "appendonly"
+#define A_NODUMP "nodump"
+#define A_OPAQUE "opaque"
+#define A_AV_QUARANTINED "av_quarantined"
+#define A_AV_MODIFIED "av_modified"
+#define A_FSID "fsid"
+#define A_AV_SCANSTAMP "av_scanstamp"
+#define A_MDEV "mdev"
+#define A_OWNERSID "ownersid"
+#define A_GROUPSID "groupsid"
+
+/* Attribute option for utilities */
+#define O_HIDDEN "H"
+#define O_SYSTEM "S"
+#define O_READONLY "R"
+#define O_ARCHIVE "A"
+#define O_NOUNLINK "u"
+#define O_IMMUTABLE "i"
+#define O_APPENDONLY "a"
+#define O_NODUMP "d"
+#define O_AV_QUARANTINED "q"
+#define O_AV_MODIFIED "m"
+#define O_NONE ""
+
+/* ownersid and groupsid are composed of two nvpairs */
+#define SID_DOMAIN "domain"
+#define SID_RID "rid"
+
+typedef enum {
+ F_ATTR_INVAL = -1,
+ F_ARCHIVE,
+ F_HIDDEN,
+ F_READONLY,
+ F_SYSTEM,
+ F_APPENDONLY,
+ F_NODUMP,
+ F_IMMUTABLE,
+ F_AV_MODIFIED,
+ F_OPAQUE,
+ F_AV_SCANSTAMP,
+ F_AV_QUARANTINED,
+ F_NOUNLINK,
+ F_CRTIME,
+ F_OWNERSID,
+ F_GROUPSID,
+ F_FSID,
+ F_MDEV,
+ F_ATTR_ALL
+} f_attr_t;
+
+#define VIEW_READONLY "SUNWattr_ro"
+#define VIEW_READWRITE "SUNWattr_rw"
+
+/*
+ * These are the supported views into the virtual sysattr directory.
+ * Additional views should be added before XATTR_VIEW_LAST.
+ */
+typedef enum {
+ XATTR_VIEW_INVALID = -1,
+ XATTR_VIEW_READONLY,
+ XATTR_VIEW_READWRITE,
+ XATTR_VIEW_LAST
+} xattr_view_t;
+
+typedef struct {
+ char *x_name;
+ char *x_option;
+ xattr_view_t x_xattr_view;
+ data_type_t x_data_type;
+} xattr_entry_t;
+
+#ifdef _KERNEL
+#define XATTR_MAXFIDSZ NFS_FHMAXDATA
+
+typedef struct {
+ uint16_t len;
+ char parent_fid[XATTR_MAXFIDSZ];
+ uint16_t parent_len;
+ uint16_t dir_offset;
+} xattr_fid_t;
+
+#define XATTR_FIDSZ (sizeof (xattr_fid_t) - sizeof (uint16_t))
+
+int xattr_dir_vget(vfs_t *, vnode_t **, fid_t *);
+#endif
+
+int attr_count(void);
+const char *attr_to_name(f_attr_t);
+const char *attr_to_option(f_attr_t);
+f_attr_t name_to_attr(const char *name);
+f_attr_t option_to_attr(const char *option);
+xattr_view_t attr_to_xattr_view(f_attr_t attr);
+data_type_t attr_to_data_type(f_attr_t attr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ATTR_H */
diff --git a/usr/src/uts/common/sys/byteorder.h b/usr/src/uts/common/sys/byteorder.h
index b80a0f02bd..36a82e2bbf 100644
--- a/usr/src/uts/common/sys/byteorder.h
+++ b/usr/src/uts/common/sys/byteorder.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -128,6 +128,68 @@ extern in_port_t ntohs(in_port_t);
#define BE_64(x) BSWAP_64(x)
#endif
+/*
+ * Macros to read unaligned values from a specific byte order to
+ * native byte order
+ */
+
+#define BE_IN8(xa) \
+ *((uint8_t *)(xa))
+
+#define BE_IN16(xa) \
+ (((uint16_t)BE_IN8(xa) << 8) | BE_IN8((uint8_t *)(xa)+1))
+
+#define BE_IN32(xa) \
+ (((uint32_t)BE_IN16(xa) << 16) | BE_IN16((uint8_t *)(xa)+2))
+
+#define BE_IN64(xa) \
+ (((uint64_t)BE_IN32(xa) << 32) | BE_IN32((uint8_t *)(xa)+4))
+
+#define LE_IN8(xa) \
+ *((uint8_t *)(xa))
+
+#define LE_IN16(xa) \
+ (((uint16_t)LE_IN8((uint8_t *)(xa) + 1) << 8) | LE_IN8(xa))
+
+#define LE_IN32(xa) \
+ (((uint32_t)LE_IN16((uint8_t *)(xa) + 2) << 16) | LE_IN16(xa))
+
+#define LE_IN64(xa) \
+ (((uint64_t)LE_IN32((uint8_t *)(xa) + 4) << 32) | LE_IN32(xa))
+
+/*
+ * Macros to write unaligned values from native byte order to a specific byte
+ * order.
+ */
+
+#define BE_OUT8(xa, yv) *((uint8_t *)(xa)) = (uint8_t)(yv);
+
+#define BE_OUT16(xa, yv) \
+ BE_OUT8((uint8_t *)(xa) + 1, yv); \
+ BE_OUT8((uint8_t *)(xa), (yv) >> 8);
+
+#define BE_OUT32(xa, yv) \
+ BE_OUT16((uint8_t *)(xa) + 2, yv); \
+ BE_OUT16((uint8_t *)(xa), (yv) >> 16);
+
+#define BE_OUT64(xa, yv) \
+ BE_OUT32((uint8_t *)(xa) + 4, yv); \
+ BE_OUT32((uint8_t *)(xa), (yv) >> 32);
+
+#define LE_OUT8(xa, yv) *((uint8_t *)(xa)) = (uint8_t)(yv);
+
+#define LE_OUT16(xa, yv) \
+ LE_OUT8((uint8_t *)(xa), yv); \
+ LE_OUT8((uint8_t *)(xa) + 1, (yv) >> 8);
+
+#define LE_OUT32(xa, yv) \
+ LE_OUT16((uint8_t *)(xa), yv); \
+ LE_OUT16((uint8_t *)(xa) + 2, (yv) >> 16);
+
+#define LE_OUT64(xa, yv) \
+ LE_OUT32((uint8_t *)(xa), yv); \
+ LE_OUT32((uint8_t *)(xa) + 4, (yv) >> 32);
+
#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/cred.h b/usr/src/uts/common/sys/cred.h
index 29e9a6ddeb..41f2827f78 100644
--- a/usr/src/uts/common/sys/cred.h
+++ b/usr/src/uts/common/sys/cred.h
@@ -170,6 +170,8 @@ extern void crsetsidlist(cred_t *, struct ksidlist *);
extern struct ksid *crgetsid(const cred_t *, int);
extern struct ksidlist *crgetsidlist(const cred_t *);
+extern int crsetpriv(cred_t *, ...);
+
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/ctfs_impl.h b/usr/src/uts/common/sys/ctfs_impl.h
index 1c835a60f6..77e491a550 100644
--- a/usr/src/uts/common/sys/ctfs_impl.h
+++ b/usr/src/uts/common/sys/ctfs_impl.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -207,11 +206,16 @@ extern vnode_t *ctfs_create_symnode(vnode_t *, contract_t *);
* common ctfs routines
*/
extern void ctfs_common_getattr(vnode_t *, vattr_t *);
-extern int ctfs_close(vnode_t *, int, int, offset_t, cred_t *);
-extern int ctfs_access_dir(vnode_t *, int, int, cred_t *);
-extern int ctfs_access_readonly(vnode_t *, int, int, cred_t *);
-extern int ctfs_access_readwrite(vnode_t *, int, int, cred_t *);
-extern int ctfs_open(vnode_t **, int, cred_t *);
+extern int ctfs_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+extern int ctfs_access_dir(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+extern int ctfs_access_readonly(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+extern int ctfs_access_readwrite(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+extern int ctfs_open(vnode_t **, int, cred_t *,
+ caller_context_t *);
/*
* vnode ops vector templates
diff --git a/usr/src/uts/common/sys/epm.h b/usr/src/uts/common/sys/epm.h
index 35b656409b..d1c67f383f 100644
--- a/usr/src/uts/common/sys/epm.h
+++ b/usr/src/uts/common/sys/epm.h
@@ -33,6 +33,7 @@
#include <sys/devops.h>
#include <sys/ddi_impldefs.h>
#include <sys/taskq.h>
+#include <sys/tzfile.h>
/*
* XXXX
@@ -166,7 +167,7 @@ typedef struct pm_component {
* kidsupcnt counts (the number of components of new-style children at non-zero
* level (unknown counts as non-zero)) + (the number of old-style children with
* component 0 at non-zero level) for parents that have not asked for
- * notifcation. When kidsupcnt is 0 for a nexus node, then pm scans it,
+ * notification. When kidsupcnt is 0 for a nexus node, then pm scans it,
* otherwise it leaves it alone.
* Parents that ask for notification always get get scanned,
* so we keep their kidsupcnt at zero.
@@ -911,7 +912,7 @@ typedef struct pscc { /* pm_state_change_control */
#define PSCCOUNT 128 /* number of state change entries kept per process */
/*
- * Struct used to track the existance of devices exporting the
+ * Struct used to track the existence of devices exporting the
* no-involuntary-power-cycles property, and remember things from their
* devinfo node for later attach.
*/
@@ -985,14 +986,6 @@ typedef struct pm_desc_pwrchk {
* These defines are used by pm_trans_check() to calculate time.
* Mostly copied from "tzfile.h".
*/
-#define EPOCH_YEAR 1970
-#define SECSPERMIN 60
-#define MINSPERHOUR 60
-#define HOURSPERDAY 24
-#define DAYSPERWEEK 7
-#define DAYSPERNYEAR 365
-#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
-#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY)
#define DC_SPY (SECSPERDAY * DAYSPERNYEAR)
#define DC_SPW (SECSPERDAY * DAYSPERWEEK)
#define DC_SPD SECSPERDAY
diff --git a/usr/src/uts/common/sys/extdirent.h b/usr/src/uts/common/sys/extdirent.h
new file mode 100644
index 0000000000..3f9a665f00
--- /dev/null
+++ b/usr/src/uts/common/sys/extdirent.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_EXTDIRENT_H
+#define _SYS_EXTDIRENT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#if defined(_KERNEL)
+
+/*
+ * Extended file-system independent directory entry. This style of
+ * dirent provides additional informational flag bits for each
+ * directory entry. This dirent will be returned instead of the
+ * standard dirent if a VOP_READDIR() requests dirent flags via
+ * V_RDDIR_ENTFLAGS, and if the file system supports the flags.
+ */
+typedef struct edirent {
+ ino64_t ed_ino; /* "inode number" of entry */
+ off64_t ed_off; /* offset of disk directory entry */
+ uint32_t ed_eflags; /* per-entry flags */
+ unsigned short ed_reclen; /* length of this record */
+ char ed_name[1]; /* name of file */
+} edirent_t;
+
+#define EDIRENT_RECLEN(namelen) \
+ ((offsetof(edirent_t, ed_name[0]) + 1 + (namelen) + 7) & ~ 7)
+#define EDIRENT_NAMELEN(reclen) \
+ ((reclen) - (offsetof(edirent_t, ed_name[0])))
+
+/*
+ * Extended entry flags
+ * Extended entries include a bitfield of extra information
+ * regarding that entry.
+ */
+#define ED_CASE_CONFLICT 0x10 /* Disconsidering case, entry is not unique */
+
+/*
+ * Extended flags accessor function
+ */
+#define ED_CASE_CONFLICTS(x) ((x)->ed_eflags & ED_CASE_CONFLICT)
+
+#endif /* defined(_KERNEL) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_EXTDIRENT_H */
diff --git a/usr/src/uts/common/sys/fcntl.h b/usr/src/uts/common/sys/fcntl.h
index 70df5244f6..cb55161060 100644
--- a/usr/src/uts/common/sys/fcntl.h
+++ b/usr/src/uts/common/sys/fcntl.h
@@ -329,6 +329,8 @@ typedef struct fshare {
#define F_RDACC 0x1 /* Read-only share access */
#define F_WRACC 0x2 /* Write-only share access */
#define F_RWACC 0x3 /* Read-Write share access */
+#define F_RMACC 0x4 /* private flag: Delete share access */
+#define F_MDACC 0x20 /* private flag: Metadata share access */
/*
* f_deny values
@@ -337,6 +339,7 @@ typedef struct fshare {
#define F_RDDNY 0x1 /* Deny others read share access */
#define F_WRDNY 0x2 /* Deny others write share access */
#define F_RWDNY 0x3 /* Deny others read or write share access */
+#define F_RMDNY 0x4 /* private flag: Deny delete share access */
#define F_COMPAT 0x8 /* Set share to old DOS compatibility mode */
#define F_MANDDNY 0x10 /* private flag: mandatory enforcement */
#endif /* defined(__EXTENSIONS__) || !defined(__XOPEN_OR_POSIX) */
diff --git a/usr/src/uts/common/sys/fem.h b/usr/src/uts/common/sys/fem.h
index 2816734291..e1f051b4ad 100644
--- a/usr/src/uts/common/sys/fem.h
+++ b/usr/src/uts/common/sys/fem.h
@@ -92,6 +92,8 @@ typedef struct fsem fsem_t;
typedef int femop_t();
+typedef void (*fem_func_t)(void *);
+
/*
* The following enumerations specify the conditions
* under which a monitor (operation/argument combination)
@@ -146,95 +148,119 @@ struct fem_head {
* the fem structure (below) and the fs_func_p union (vfs_opreg.h).
*/
#define FEM_OPS \
- int (*femop_open)(femarg_t *vf, int mode, cred_t *cr); \
+ int (*femop_open)(femarg_t *vf, int mode, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_close)(femarg_t *vf, int flag, int count, \
- offset_t offset, cred_t *cr); \
+ offset_t offset, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_read)(femarg_t *vf, uio_t *uiop, int ioflag, \
- cred_t *cr, struct caller_context *ct); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_write)(femarg_t *vf, uio_t *uiop, int ioflag, \
- cred_t *cr, struct caller_context *ct); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_ioctl)(femarg_t *vf, int cmd, intptr_t arg, \
- int flag, cred_t *cr, int *rvalp); \
+ int flag, cred_t *cr, int *rvalp, \
+ caller_context_t *ct); \
int (*femop_setfl)(femarg_t *vf, int oflags, int nflags, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_getattr)(femarg_t *vf, vattr_t *vap, int flags, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_setattr)(femarg_t *vf, vattr_t *vap, int flags, \
cred_t *cr, caller_context_t *ct); \
int (*femop_access)(femarg_t *vf, int mode, int flags, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_lookup)(femarg_t *vf, char *nm, vnode_t **vpp, \
pathname_t *pnp, int flags, vnode_t *rdir, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct, \
+ int *direntflags, pathname_t *realpnp); \
int (*femop_create)(femarg_t *vf, char *name, vattr_t *vap, \
vcexcl_t excl, int mode, vnode_t **vpp, \
- cred_t *cr, int flag); \
- int (*femop_remove)(femarg_t *vf, char *nm, cred_t *cr); \
+ cred_t *cr, int flag, caller_context_t *ct, \
+ vsecattr_t *vsecp); \
+ int (*femop_remove)(femarg_t *vf, char *nm, cred_t *cr, \
+ caller_context_t *ct, int flags); \
int (*femop_link)(femarg_t *vf, vnode_t *svp, char *tnm, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct, int flags); \
int (*femop_rename)(femarg_t *vf, char *snm, vnode_t *tdvp, \
- char *tnm, cred_t *cr); \
+ char *tnm, cred_t *cr, caller_context_t *ct, \
+ int flags); \
int (*femop_mkdir)(femarg_t *vf, char *dirname, vattr_t *vap, \
- vnode_t **vpp, cred_t *cr); \
+ vnode_t **vpp, cred_t *cr, \
+ caller_context_t *ct, int flags, \
+ vsecattr_t *vsecp); \
int (*femop_rmdir)(femarg_t *vf, char *nm, vnode_t *cdir, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct, int flags); \
int (*femop_readdir)(femarg_t *vf, uio_t *uiop, cred_t *cr, \
- int *eofp); \
+ int *eofp, caller_context_t *ct, int flags); \
int (*femop_symlink)(femarg_t *vf, char *linkname, \
- vattr_t *vap, char *target, cred_t *cr); \
- int (*femop_readlink)(femarg_t *vf, uio_t *uiop, cred_t *cr); \
- int (*femop_fsync)(femarg_t *vf, int syncflag, cred_t *cr); \
- void (*femop_inactive)(femarg_t *vf, cred_t *cr); \
- int (*femop_fid)(femarg_t *vf, fid_t *fidp); \
+ vattr_t *vap, char *target, cred_t *cr, \
+ caller_context_t *ct, int flags); \
+ int (*femop_readlink)(femarg_t *vf, uio_t *uiop, cred_t *cr, \
+ caller_context_t *ct); \
+ int (*femop_fsync)(femarg_t *vf, int syncflag, cred_t *cr, \
+ caller_context_t *ct); \
+ void (*femop_inactive)(femarg_t *vf, cred_t *cr, \
+ caller_context_t *ct); \
+ int (*femop_fid)(femarg_t *vf, fid_t *fidp, \
+ caller_context_t *ct); \
int (*femop_rwlock)(femarg_t *vf, int write_lock, \
caller_context_t *ct); \
void (*femop_rwunlock)(femarg_t *vf, int write_lock, \
caller_context_t *ct); \
int (*femop_seek)(femarg_t *vf, offset_t ooff, \
- offset_t *noffp); \
- int (*femop_cmp)(femarg_t *vf, vnode_t *vp2); \
+ offset_t *noffp, caller_context_t *ct); \
+ int (*femop_cmp)(femarg_t *vf, vnode_t *vp2, \
+ caller_context_t *ct); \
int (*femop_frlock)(femarg_t *vf, int cmd, struct flock64 *bfp, \
int flag, offset_t offset, \
- struct flk_callback *flk_cbp, cred_t *cr); \
+ struct flk_callback *flk_cbp, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_space)(femarg_t *vf, int cmd, struct flock64 *bfp, \
int flag, offset_t offset, cred_t *cr, \
caller_context_t *ct); \
- int (*femop_realvp)(femarg_t *vf, vnode_t **vpp); \
+ int (*femop_realvp)(femarg_t *vf, vnode_t **vpp, \
+ caller_context_t *ct); \
int (*femop_getpage)(femarg_t *vf, offset_t off, size_t len, \
uint_t *protp, struct page **plarr, \
size_t plsz, struct seg *seg, caddr_t addr, \
- enum seg_rw rw, cred_t *cr); \
+ enum seg_rw rw, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_putpage)(femarg_t *vf, offset_t off, size_t len, \
- int flags, cred_t *cr); \
+ int flags, cred_t *cr, caller_context_t *ct); \
int (*femop_map)(femarg_t *vf, offset_t off, struct as *as, \
caddr_t *addrp, size_t len, uchar_t prot, \
- uchar_t maxprot, uint_t flags, cred_t *cr); \
+ uchar_t maxprot, uint_t flags, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_addmap)(femarg_t *vf, offset_t off, struct as *as, \
caddr_t addr, size_t len, uchar_t prot, \
- uchar_t maxprot, uint_t flags, cred_t *cr); \
+ uchar_t maxprot, uint_t flags, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_delmap)(femarg_t *vf, offset_t off, struct as *as, \
caddr_t addr, size_t len, uint_t prot, \
- uint_t maxprot, uint_t flags, cred_t *cr); \
+ uint_t maxprot, uint_t flags, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_poll)(femarg_t *vf, short events, int anyyet, \
- short *reventsp, struct pollhead **phpp); \
+ short *reventsp, struct pollhead **phpp, \
+ caller_context_t *ct); \
int (*femop_dump)(femarg_t *vf, caddr_t addr, int lbdn, \
- int dblks); \
+ int dblks, caller_context_t *ct); \
int (*femop_pathconf)(femarg_t *vf, int cmd, ulong_t *valp, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_pageio)(femarg_t *vf, struct page *pp, \
u_offset_t io_off, size_t io_len, int flags, \
- cred_t *cr); \
- int (*femop_dumpctl)(femarg_t *vf, int action, int *blkp); \
+ cred_t *cr, caller_context_t *ct); \
+ int (*femop_dumpctl)(femarg_t *vf, int action, int *blkp, \
+ caller_context_t *ct); \
void (*femop_dispose)(femarg_t *vf, struct page *pp, int flag, \
- int dn, cred_t *cr); \
+ int dn, cred_t *cr, caller_context_t *ct); \
int (*femop_setsecattr)(femarg_t *vf, vsecattr_t *vsap, \
- int flag, cred_t *cr); \
+ int flag, cred_t *cr, caller_context_t *ct); \
int (*femop_getsecattr)(femarg_t *vf, vsecattr_t *vsap, \
- int flag, cred_t *cr); \
+ int flag, cred_t *cr, caller_context_t *ct); \
int (*femop_shrlock)(femarg_t *vf, int cmd, \
- struct shrlock *shr, int flag, cred_t *cr); \
+ struct shrlock *shr, int flag, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_vnevent)(femarg_t *vf, vnevent_t vnevent, \
- vnode_t *dvp, char *cname)
+ vnode_t *dvp, char *cname, caller_context_t *ct)
/* NB: No ";" */
struct fem {
@@ -267,83 +293,105 @@ struct fsem {
FSEM_OPS; /* Signatures of all FSEM operations (fsemops) */
};
-extern int vnext_open(femarg_t *vf, int mode, cred_t *cr);
+extern int vnext_open(femarg_t *vf, int mode, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_close(femarg_t *vf, int flag, int count, offset_t offset,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct);
+ caller_context_t *ct);
extern int vnext_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct);
+ caller_context_t *ct);
extern int vnext_ioctl(femarg_t *vf, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp);
-extern int vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr);
-extern int vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr);
+ cred_t *cr, int *rvalp, caller_context_t *ct);
+extern int vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct);
+extern int vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
caller_context_t *ct);
-extern int vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr);
+extern int vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_lookup(femarg_t *vf, char *nm, vnode_t **vpp,
pathname_t *pnp, int flags, vnode_t *rdir,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp);
extern int vnext_create(femarg_t *vf, char *name, vattr_t *vap,
vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cr,
- int flag);
-extern int vnext_remove(femarg_t *vf, char *nm, cred_t *cr);
-extern int vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr);
+ int flag, caller_context_t *ct, vsecattr_t *vsecp);
+extern int vnext_remove(femarg_t *vf, char *nm, cred_t *cr,
+ caller_context_t *ct, int flags);
+extern int vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags);
extern int vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct, int flags);
extern int vnext_mkdir(femarg_t *vf, char *dirname, vattr_t *vap,
- vnode_t **vpp, cred_t *cr);
-extern int vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr);
-extern int vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp);
+ vnode_t **vpp, cred_t *cr, caller_context_t *ct,
+ int flags, vsecattr_t *vsecp);
+extern int vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags);
+extern int vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags);
extern int vnext_symlink(femarg_t *vf, char *linkname, vattr_t *vap,
- char *target, cred_t *cr);
-extern int vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr);
-extern int vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr);
-extern void vnext_inactive(femarg_t *vf, cred_t *cr);
-extern int vnext_fid(femarg_t *vf, fid_t *fidp);
+ char *target, cred_t *cr, caller_context_t *ct,
+ int flags);
+extern int vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr,
+ caller_context_t *ct);
+extern int vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr,
+ caller_context_t *ct);
+extern void vnext_inactive(femarg_t *vf, cred_t *cr, caller_context_t *ct);
+extern int vnext_fid(femarg_t *vf, fid_t *fidp, caller_context_t *ct);
extern int vnext_rwlock(femarg_t *vf, int write_lock, caller_context_t *ct);
extern void vnext_rwunlock(femarg_t *vf, int write_lock, caller_context_t *ct);
-extern int vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp);
-extern int vnext_cmp(femarg_t *vf, vnode_t *vp2);
+extern int vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct);
+extern int vnext_cmp(femarg_t *vf, vnode_t *vp2, caller_context_t *ct);
extern int vnext_frlock(femarg_t *vf, int cmd, struct flock64 *bfp,
int flag, offset_t offset,
- struct flk_callback *flk_cbp, cred_t *cr);
+ struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_space(femarg_t *vf, int cmd, struct flock64 *bfp,
int flag, offset_t offset, cred_t *cr,
caller_context_t *ct);
-extern int vnext_realvp(femarg_t *vf, vnode_t **vpp);
+extern int vnext_realvp(femarg_t *vf, vnode_t **vpp, caller_context_t *ct);
extern int vnext_getpage(femarg_t *vf, offset_t off, size_t len,
uint_t *protp, struct page **plarr, size_t plsz,
struct seg *seg, caddr_t addr, enum seg_rw rw,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_putpage(femarg_t *vf, offset_t off, size_t len, int flags,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_map(femarg_t *vf, offset_t off, struct as *as,
caddr_t *addrp, size_t len, uchar_t prot, uchar_t maxprot,
- uint_t flags, cred_t *cr);
+ uint_t flags, cred_t *cr, caller_context_t *ct);
extern int vnext_addmap(femarg_t *vf, offset_t off, struct as *as,
caddr_t addr, size_t len, uchar_t prot,
- uchar_t maxprot, uint_t flags, cred_t *cr);
+ uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_delmap(femarg_t *vf, offset_t off, struct as *as,
caddr_t addr, size_t len, uint_t prot,
- uint_t maxprot, uint_t flags, cred_t *cr);
+ uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_poll(femarg_t *vf, short events, int anyyet,
- short *reventsp, struct pollhead **phpp);
-extern int vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks);
-extern int vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr);
+ short *reventsp, struct pollhead **phpp,
+ caller_context_t *ct);
+extern int vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks,
+ caller_context_t *ct);
+extern int vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_pageio(femarg_t *vf, struct page *pp, u_offset_t io_off,
- size_t io_len, int flags, cred_t *cr);
-extern int vnext_dumpctl(femarg_t *vf, int action, int *blkp);
+ size_t io_len, int flags, cred_t *cr,
+ caller_context_t *ct);
+extern int vnext_dumpctl(femarg_t *vf, int action, int *blkp,
+ caller_context_t *ct);
extern void vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr,
- int flag, cred_t *cr);
+ int flag, cred_t *cr, caller_context_t *ct);
extern int vnext_vnevent(femarg_t *vf, vnevent_t vevent, vnode_t *dvp,
- char *cname);
+ char *cname, caller_context_t *ct);
extern int vfsnext_mount(fsemarg_t *vf, vnode_t *mvp, struct mounta *uap,
cred_t *cr);
diff --git a/usr/src/uts/common/sys/file.h b/usr/src/uts/common/sys/file.h
index e893696564..01af00ddb2 100644
--- a/usr/src/uts/common/sys/file.h
+++ b/usr/src/uts/common/sys/file.h
@@ -89,10 +89,6 @@ typedef struct fpollinfo {
#define FREVOKED 0x20 /* C2 Security - Revoke Subsystem */
#endif
#define FDSYNC 0x40 /* file data only integrity while writing */
-#define FRSYNC 0x8000 /* sync read operations at same level of */
- /* integrity as specified for writes by */
- /* FSYNC and FDSYNC flags */
-#define FOFFMAX 0x2000 /* large file */
#define FNONBLOCK 0x80
#define FMASK 0xa0ff /* all flags that can be changed by F_SETFL */
@@ -102,14 +98,20 @@ typedef struct fpollinfo {
#define FCREAT 0x0100
#define FTRUNC 0x0200
#define FEXCL 0x0400
-#define FNOCTTY 0x0800
+#define FASYNC 0x1000 /* asyncio in progress pseudo flag */
+#define FOFFMAX 0x2000 /* large file */
#define FXATTR 0x4000 /* open as extended attribute */
+#define FNOCTTY 0x0800
+#define FRSYNC 0x8000 /* sync read operations at same level of */
+ /* integrity as specified for writes by */
+ /* FSYNC and FDSYNC flags */
-#define FASYNC 0x1000 /* asyncio in progress pseudo flag */
#define FNODSYNC 0x10000 /* fsync pseudo flag */
#define FNOFOLLOW 0x20000 /* don't follow symlinks */
#define FNOLINKS 0x40000 /* don't allow multiple hard links */
+#define FIGNORECASE 0x80000 /* request case-insensitive lookups */
+#define FXATTRDIROPEN 0x100000 /* only opening hidden attribute directory */
#ifdef _KERNEL
diff --git a/usr/src/uts/common/sys/fs/fifonode.h b/usr/src/uts/common/sys/fs/fifonode.h
index ddd64ab0a3..5ef83b4778 100644
--- a/usr/src/uts/common/sys/fs/fifonode.h
+++ b/usr/src/uts/common/sys/fs/fifonode.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -123,8 +123,8 @@ typedef struct fifodata {
#define FIFOPOLLR 0x1000 /* process waiting on poll read */
#define FIFOISOPEN 0x2000 /* pipe is open */
#define FIFOSYNC 0x4000 /* FIFO is waiting for open sync */
-#define FIFOWOCR 0x8000 /* Write open occured */
-#define FIFOROCR 0x10000 /* Read open occured */
+#define FIFOWOCR 0x8000 /* Write open occurred */
+#define FIFOROCR 0x10000 /* Read open occurred */
/*
* process waiting on poll read on band data
* this can only occur if we go to streams
@@ -165,8 +165,9 @@ struct queue;
extern int fifoinit(int, char *);
extern int fifo_stropen(vnode_t **, int, cred_t *, int, int);
-extern int fifo_open(vnode_t **, int, cred_t *);
-extern int fifo_close(vnode_t *, int, int, offset_t, cred_t *);
+extern int fifo_open(vnode_t **, int, cred_t *, caller_context_t *);
+extern int fifo_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
extern void fifo_cleanup(vnode_t *, int);
extern void fiforemove(fifonode_t *);
extern ino_t fifogetid(void);
diff --git a/usr/src/uts/common/sys/fs/pc_node.h b/usr/src/uts/common/sys/fs/pc_node.h
index 72e96d579b..1e8921c6c1 100644
--- a/usr/src/uts/common/sys/fs/pc_node.h
+++ b/usr/src/uts/common/sys/fs/pc_node.h
@@ -129,8 +129,10 @@ extern void pc_mark_irrecov(struct pcfs *);
extern int pc_dirlook(struct pcnode *, char *, struct pcnode **);
extern int pc_direnter(struct pcnode *, char *, struct vattr *,
struct pcnode **);
-extern int pc_dirremove(struct pcnode *, char *, struct vnode *, enum vtype);
-extern int pc_rename(struct pcnode *, struct pcnode *, char *, char *);
+extern int pc_dirremove(struct pcnode *, char *, struct vnode *, enum vtype,
+ caller_context_t *);
+extern int pc_rename(struct pcnode *, struct pcnode *, char *, char *,
+ caller_context_t *);
extern int pc_blkatoff(struct pcnode *, offset_t, struct buf **,
struct pcdir **);
extern int pc_truncate(struct pcnode *, uint_t);
diff --git a/usr/src/uts/common/sys/fs/snode.h b/usr/src/uts/common/sys/fs/snode.h
index cd572d545c..d0176af293 100644
--- a/usr/src/uts/common/sys/fs/snode.h
+++ b/usr/src/uts/common/sys/fs/snode.h
@@ -162,7 +162,8 @@ void sdelete(struct snode *);
void smark(struct snode *, int);
int specinit(int, char *);
int device_close(struct vnode *, int, struct cred *);
-int spec_putpage(struct vnode *, offset_t, size_t, int, struct cred *);
+int spec_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
+ caller_context_t *);
int spec_segmap(dev_t, off_t, struct as *, caddr_t *, off_t,
uint_t, uint_t, uint_t, cred_t *);
struct vnode *specvp_devfs(struct vnode *, dev_t, vtype_t,
diff --git a/usr/src/uts/common/sys/fs/tmp.h b/usr/src/uts/common/sys/fs/tmp.h
index 583eaab18c..68dd67c61e 100644
--- a/usr/src/uts/common/sys/fs/tmp.h
+++ b/usr/src/uts/common/sys/fs/tmp.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1989-1991, 1996-1999, 2001-2003 Sun Microsystems, Inc.
+ * Copyright 2007 Sun Microsystems, Inc.
* All rights reserved. Use is subject to license terms.
*/
@@ -111,7 +110,7 @@ extern int tmp_sticky_remove_access(struct tmpnode *, struct tmpnode *,
extern int tmp_convnum(char *, pgcnt_t *);
extern int tdirenter(struct tmount *, struct tmpnode *, char *,
enum de_op, struct tmpnode *, struct tmpnode *, struct vattr *,
- struct tmpnode **, struct cred *);
+ struct tmpnode **, struct cred *, caller_context_t *);
#define TMP_MUSTHAVE 0x01
diff --git a/usr/src/uts/common/sys/fs/udf_inode.h b/usr/src/uts/common/sys/fs/udf_inode.h
index 6a2b3e83e1..dd68124bca 100644
--- a/usr/src/uts/common/sys/fs/udf_inode.h
+++ b/usr/src/uts/common/sys/fs/udf_inode.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -709,10 +708,10 @@ int32_t ud_dirlook(struct ud_inode *,
char *, struct ud_inode **, struct cred *, int32_t);
int32_t ud_direnter(struct ud_inode *, char *, enum de_op,
struct ud_inode *, struct ud_inode *, struct vattr *,
- struct ud_inode **, struct cred *);
+ struct ud_inode **, struct cred *, caller_context_t *);
int32_t ud_dirremove(struct ud_inode *,
char *, struct ud_inode *, struct vnode *,
- enum dr_op, struct cred *);
+ enum dr_op, struct cred *, caller_context_t *);
/*
diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h
index 8babbef0d1..1250b18c4e 100644
--- a/usr/src/uts/common/sys/fs/zfs.h
+++ b/usr/src/uts/common/sys/fs/zfs.h
@@ -92,6 +92,12 @@ typedef enum {
ZFS_PROP_NUMCLONES, /* not exposed to the user */
ZFS_PROP_COPIES,
ZFS_PROP_VERSION,
+ ZFS_PROP_UTF8ONLY,
+ ZFS_PROP_NORMALIZE,
+ ZFS_PROP_CASE,
+ ZFS_PROP_VSCAN,
+ ZFS_PROP_NBMAND,
+ ZFS_PROP_SHARESMB,
ZFS_NUM_PROPS
} zfs_prop_t;
@@ -144,11 +150,13 @@ const char *zfs_prop_default_string(zfs_prop_t);
uint64_t zfs_prop_default_numeric(zfs_prop_t);
boolean_t zfs_prop_readonly(zfs_prop_t);
boolean_t zfs_prop_inheritable(zfs_prop_t);
+boolean_t zfs_prop_setonce(zfs_prop_t);
const char *zfs_prop_to_name(zfs_prop_t);
zfs_prop_t zfs_name_to_prop(const char *);
boolean_t zfs_prop_user(const char *);
int zfs_prop_index_to_string(zfs_prop_t, uint64_t, const char **);
int zfs_prop_string_to_index(zfs_prop_t, const char *, uint64_t *);
+int zfs_prop_valid_for_type(int, zfs_type_t);
/*
* Pool property functions shared between libzfs and kernel.
@@ -190,6 +198,13 @@ typedef enum {
#define ZFS_DELEG_PERM_GID "gid"
#define ZFS_DELEG_PERM_GROUPS "groups"
+typedef enum zfs_share_op {
+ ZFS_SHARE_NFS = 0,
+ ZFS_UNSHARE_NFS = 1,
+ ZFS_SHARE_SMB = 2,
+ ZFS_UNSHARE_SMB = 3
+} zfs_share_op_t;
+
/*
* On-disk version number.
*/
@@ -201,13 +216,15 @@ typedef enum {
#define SPA_VERSION_6 6ULL
#define SPA_VERSION_7 7ULL
#define SPA_VERSION_8 8ULL
+#define SPA_VERSION_9 9ULL
+
/*
* When bumping up SPA_VERSION, make sure GRUB ZFS understand the on-disk
* format change. Go to usr/src/grub/grub-0.95/stage2/{zfs-include/, fsys_zfs*},
* and do the appropriate changes.
*/
-#define SPA_VERSION SPA_VERSION_8
-#define SPA_VERSION_STRING "8"
+#define SPA_VERSION SPA_VERSION_9
+#define SPA_VERSION_STRING "9"
/*
* Symbolic names for the changes that caused a SPA_VERSION switch.
@@ -232,6 +249,8 @@ typedef enum {
#define SPA_VERSION_BOOTFS SPA_VERSION_6
#define SPA_VERSION_SLOGS SPA_VERSION_7
#define SPA_VERSION_DELEGATED_PERMS SPA_VERSION_8
+#define SPA_VERSION_FUID SPA_VERSION_9
+#define SPA_VERSION_NORMALIZATION SPA_VERSION_9
/*
* ZPL version - rev'd whenever an incompatible on-disk format change
@@ -243,11 +262,14 @@ typedef enum {
*/
#define ZPL_VERSION_1 1ULL
#define ZPL_VERSION_2 2ULL
-#define ZPL_VERSION ZPL_VERSION_2
-#define ZPL_VERSION_STRING "2"
+#define ZPL_VERSION_3 3ULL
+#define ZPL_VERSION ZPL_VERSION_3
+#define ZPL_VERSION_STRING "3"
#define ZPL_VERSION_INITIAL ZPL_VERSION_1
#define ZPL_VERSION_DIRENT_TYPE ZPL_VERSION_2
+#define ZPL_VERSION_FUID ZPL_VERSION_3
+#define ZPL_VERSION_SYSATTR ZPL_VERSION_3
/*
* The following are configuration names used in the nvlist describing a pool's
diff --git a/usr/src/uts/common/sys/gfs.h b/usr/src/uts/common/sys/gfs.h
index ce21cbe525..b53031086b 100644
--- a/usr/src/uts/common/sys/gfs.h
+++ b/usr/src/uts/common/sys/gfs.h
@@ -76,7 +76,8 @@ typedef struct gfs_file {
typedef int (*gfs_readdir_cb)(vnode_t *, struct dirent64 *, int *, offset_t *,
offset_t *, void *);
-typedef int (*gfs_lookup_cb)(vnode_t *, const char *, vnode_t **, ino64_t *);
+typedef int (*gfs_lookup_cb)(vnode_t *, const char *, vnode_t **, ino64_t *,
+ cred_t *);
typedef ino64_t (*gfs_inode_cb)(vnode_t *, int);
typedef struct gfs_dir {
@@ -103,8 +104,9 @@ extern vnode_t *gfs_root_create_file(size_t, struct vfs *, vnodeops_t *,
extern void *gfs_file_inactive(vnode_t *);
extern void *gfs_dir_inactive(vnode_t *);
-extern int gfs_dir_lookup(vnode_t *, const char *, vnode_t **);
-extern int gfs_dir_readdir(vnode_t *, uio_t *, int *, void *);
+extern int gfs_dir_lookup(vnode_t *, const char *, vnode_t **, cred_t *);
+extern int gfs_dir_readdir(vnode_t *, uio_t *, int *, void *, cred_t *,
+ caller_context_t *);
#define gfs_dir_lock(gd) mutex_enter(&(gd)->gfsd_lock)
#define gfs_dir_unlock(gd) mutex_exit(&(gd)->gfsd_lock)
@@ -137,14 +139,22 @@ extern int gfs_readdir_emitn(gfs_readdir_state_t *, uio_t *, offset_t, ino64_t,
extern int gfs_readdir_pred(gfs_readdir_state_t *, uio_t *, offset_t *);
extern int gfs_readdir_fini(gfs_readdir_state_t *, int, int *, int);
+/*
+ * Objects with real extended attributes will get their . and ..
+ * readdir entries from the real xattr directory. GFS_STATIC_ENTRY_OFFSET
+ * lets us skip right to the static entries in the GFS directory.
+ */
+#define GFS_STATIC_ENTRY_OFFSET ((offset_t)2)
+
extern int gfs_lookup_dot(vnode_t **, vnode_t *, vnode_t *, const char *);
extern int gfs_vop_lookup(vnode_t *, char *, vnode_t **, pathname_t *,
- int, vnode_t *, cred_t *);
-extern int gfs_vop_readdir(vnode_t *, uio_t *, cred_t *, int *);
+ int, vnode_t *, cred_t *, caller_context_t *, int *, pathname_t *);
+extern int gfs_vop_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
extern int gfs_vop_map(vnode_t *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-extern void gfs_vop_inactive(vnode_t *, cred_t *);
+ size_t, uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+extern void gfs_vop_inactive(vnode_t *, cred_t *, caller_context_t *);
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/modctl.h b/usr/src/uts/common/sys/modctl.h
index 3477a11cb6..818572a94d 100644
--- a/usr/src/uts/common/sys/modctl.h
+++ b/usr/src/uts/common/sys/modctl.h
@@ -109,7 +109,7 @@ struct modlsys {
struct modlfs {
struct mod_ops *fs_modops;
char *fs_linkinfo;
- struct vfsdef_v3 *fs_vfsdef; /* version may actually vary */
+ struct vfsdef_v4 *fs_vfsdef; /* version may actually vary */
};
#if defined(__i386) || defined(__amd64)
diff --git a/usr/src/uts/common/sys/nbmlock.h b/usr/src/uts/common/sys/nbmlock.h
index 98211d7b70..e5215cc9ee 100644
--- a/usr/src/uts/common/sys/nbmlock.h
+++ b/usr/src/uts/common/sys/nbmlock.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#ifndef _NBMLOCK_H
@@ -57,9 +56,11 @@ extern int nbl_in_crit(vnode_t *);
/* conflict checking */
extern int nbl_need_check(vnode_t *);
-extern int nbl_conflict(vnode_t *, nbl_op_t, u_offset_t, ssize_t, int);
-extern int nbl_share_conflict(vnode_t *, nbl_op_t);
-extern int nbl_lock_conflict(vnode_t *, nbl_op_t, u_offset_t, ssize_t, int);
+extern int nbl_conflict(vnode_t *, nbl_op_t, u_offset_t, ssize_t, int,
+ caller_context_t *);
+extern int nbl_share_conflict(vnode_t *, nbl_op_t, caller_context_t *);
+extern int nbl_lock_conflict(vnode_t *, nbl_op_t, u_offset_t, ssize_t, int,
+ caller_context_t *);
extern int nbl_svmand(vnode_t *, cred_t *, int *);
extern nbl_op_t nbl_lock_to_op(int);
diff --git a/usr/src/uts/common/sys/objfs_impl.h b/usr/src/uts/common/sys/objfs_impl.h
index df60a8af95..687db9edec 100644
--- a/usr/src/uts/common/sys/objfs_impl.h
+++ b/usr/src/uts/common/sys/objfs_impl.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -49,9 +48,11 @@ typedef struct objfs_vfs {
/*
* Common vop_ entry points
*/
-extern int objfs_dir_open(vnode_t **, int, cred_t *);
-extern int objfs_dir_access(vnode_t *, int, int, cred_t *);
-extern int objfs_common_close(vnode_t *, int, int, offset_t, cred_t *);
+extern int objfs_dir_open(vnode_t **, int, cred_t *, caller_context_t *);
+extern int objfs_dir_access(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+extern int objfs_common_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
/*
* Common vop_ support functions
diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h
index c132402d3b..2949605b9e 100644
--- a/usr/src/uts/common/sys/policy.h
+++ b/usr/src/uts/common/sys/policy.h
@@ -129,6 +129,7 @@ int secpolicy_rpcmod_open(const cred_t *);
int secpolicy_rsm_access(const cred_t *, uid_t, mode_t);
int secpolicy_setpriority(const cred_t *);
int secpolicy_settime(const cred_t *);
+int secpolicy_smb(const cred_t *);
int secpolicy_spec_open(const cred_t *, struct vnode *, int);
int secpolicy_sti(const cred_t *);
int secpolicy_swapctl(const cred_t *);
@@ -154,6 +155,7 @@ void secpolicy_setid_clear(vattr_t *, cred_t *);
void secpolicy_fs_mount_clearopts(cred_t *, struct vfs *);
int secpolicy_setid_setsticky_clear(vnode_t *, vattr_t *,
const vattr_t *, cred_t *);
+int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t);
int secpolicy_basic_exec(const cred_t *);
int secpolicy_basic_fork(const cred_t *);
diff --git a/usr/src/uts/common/sys/sid.h b/usr/src/uts/common/sys/sid.h
index 9d68191eb6..96b9f5a0b8 100644
--- a/usr/src/uts/common/sys/sid.h
+++ b/usr/src/uts/common/sys/sid.h
@@ -52,6 +52,8 @@ extern "C" {
#define SIDSYS_ID2SID 1
#ifdef _KERNEL
+#define KSIDLIST_MEM(n) (sizeof (ksidlist_t) + ((n) - 1) * sizeof (ksid_t))
+
/* Domains are stored in AVL trees so we can share them among SIDs */
typedef struct ksiddomain {
uint_t kd_ref;
diff --git a/usr/src/uts/common/sys/socketvar.h b/usr/src/uts/common/sys/socketvar.h
index 1863d2ea01..0680546ade 100644
--- a/usr/src/uts/common/sys/socketvar.h
+++ b/usr/src/uts/common/sys/socketvar.h
@@ -262,7 +262,7 @@ struct sonode {
* but one of the key reasons for their existence and careful
* tracking in sockfs is to support getsockname and getpeername
* when the transport does not handle the TI_GET*NAME ioctls
- * and caching when it does (signalled by valid bits in so_state).
+ * and caching when it does (signaled by valid bits in so_state).
* When all transports support the new TPI (with T_ADDR_REQ)
* we can revisit this code.
* The other usage of so_faddr is to keep the "connected to"
@@ -704,7 +704,8 @@ extern int sock_putmsg(vnode_t *, struct strbuf *, struct strbuf *,
uchar_t, int, int);
struct sonode *sotpi_create(vnode_t *, int, int, int, int, struct sonode *,
int *);
-extern int socktpi_open(struct vnode **, int, struct cred *);
+extern int socktpi_open(struct vnode **, int, struct cred *,
+ caller_context_t *);
extern int so_sock2stream(struct sonode *);
extern void so_stream2sock(struct sonode *);
extern int sockinit(int, char *);
@@ -783,7 +784,7 @@ extern int sotpi_getsockopt(struct sonode *, int, int, void *,
extern int sotpi_setsockopt(struct sonode *, int, int, const void *,
socklen_t);
extern int socktpi_ioctl(struct vnode *, int, intptr_t, int,
- struct cred *, int *);
+ struct cred *, int *, caller_context_t *);
extern int sodisconnect(struct sonode *, t_scalar_t, int);
extern ssize_t soreadfile(file_t *, uchar_t *, u_offset_t, int *, size_t);
extern int so_set_asyncsigs(vnode_t *, pid_t, int, int, cred_t *);
@@ -795,7 +796,7 @@ extern void sock_kstat_fini(zoneid_t, void *);
extern struct sonode *getsonode(int, int *, file_t **);
/*
- * Function wrappers (mostly arround the sonode switch) for
+ * Function wrappers (mostly around the sonode switch) for
* backward compatibility.
*/
extern int soaccept(struct sonode *, int, struct sonode **);
@@ -820,15 +821,19 @@ extern struct sonode *socreate(vnode_t *, int, int, int, int,
extern int so_copyin(const void *, void *, size_t, int);
extern int so_copyout(const void *, void *, size_t, int);
-extern int socktpi_access(struct vnode *, int, int, struct cred *);
-extern int socktpi_fid(struct vnode *, struct fid *);
-extern int socktpi_fsync(struct vnode *, int, struct cred *);
+extern int socktpi_access(struct vnode *, int, int, struct cred *,
+ caller_context_t *);
+extern int socktpi_fid(struct vnode *, struct fid *, caller_context_t *);
+extern int socktpi_fsync(struct vnode *, int, struct cred *,
+ caller_context_t *);
extern int socktpi_getattr(struct vnode *, struct vattr *, int,
- struct cred *);
-extern int socktpi_seek(struct vnode *, offset_t, offset_t *);
+ struct cred *, caller_context_t *);
+extern int socktpi_seek(struct vnode *, offset_t, offset_t *,
+ caller_context_t *);
extern int socktpi_setattr(struct vnode *, struct vattr *, int,
struct cred *, caller_context_t *);
-extern int socktpi_setfl(vnode_t *, int, int, cred_t *);
+extern int socktpi_setfl(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
/* SCTP sockfs */
extern struct sonode *sosctp_create(vnode_t *, int, int, int, int,
diff --git a/usr/src/uts/common/sys/tzfile.h b/usr/src/uts/common/sys/tzfile.h
new file mode 100644
index 0000000000..8f451f27d9
--- /dev/null
+++ b/usr/src/uts/common/sys/tzfile.h
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+/*
+ * from Arthur Olson's 6.1
+ */
+
+#ifndef _SYS_TZFILE_H
+#define _SYS_TZFILE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Information about time zone files.
+ */
+
+#define TZDIR "/usr/share/lib/zoneinfo" /* Time zone object file directory */
+
+#define TZDEFAULT (getenv("TZ"))
+
+#define TZDEFRULES "posixrules"
+
+/*
+ * Each file begins with. . .
+ */
+
+struct tzhead {
+ char tzh_reserved[24]; /* reserved for future use */
+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ char tzh_leapcnt[4]; /* coded number of leap seconds */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
+};
+
+/*
+ * . . .followed by. . .
+ *
+ * tzh_timecnt (char [4])s coded transition times a la time(2)
+ * tzh_timecnt (unsigned char)s types of local time starting at above
+ * tzh_typecnt repetitions of
+ * one (char [4]) coded GMT offset in seconds
+ * one (unsigned char) used to set tm_isdst
+ * one (unsigned char) that's an abbreviation list index
+ * tzh_charcnt (char)s '\0'-terminated zone abbreviations
+ * tzh_leapcnt repetitions of
+ * one (char [4]) coded leap second transition times
+ * one (char [4]) total correction after above
+ * tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
+ * time is standard time, if FALSE,
+ * transition time is wall clock time
+ * if absent, transition times are
+ * assumed to be wall clock time
+ */
+
+/*
+ * In the current implementation, "tzset()" refuses to deal with files that
+ * exceed any of the limits below.
+ */
+
+/*
+ * The TZ_MAX_TIMES value below is enough to handle a bit more than a
+ * year's worth of solar time (corrected daily to the nearest second) or
+ * 138 years of Pacific Presidential Election time
+ * (where there are three time zone transitions every fourth year).
+ */
+#define TZ_MAX_TIMES 370
+
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long)SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define TM_SUNDAY 0
+#define TM_MONDAY 1
+#define TM_TUESDAY 2
+#define TM_WEDNESDAY 3
+#define TM_THURSDAY 4
+#define TM_FRIDAY 5
+#define TM_SATURDAY 6
+
+#define TM_JANUARY 0
+#define TM_FEBRUARY 1
+#define TM_MARCH 2
+#define TM_APRIL 3
+#define TM_MAY 4
+#define TM_JUNE 5
+#define TM_JULY 6
+#define TM_AUGUST 7
+#define TM_SEPTEMBER 8
+#define TM_OCTOBER 9
+#define TM_NOVEMBER 10
+#define TM_DECEMBER 11
+
+#define TM_YEAR_BASE 1900
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+/*
+ * Accurate only for the past couple of centuries;
+ * that will probably do.
+ */
+
+#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
+
+/*
+ * Use of the underscored variants may cause problems if you move your code to
+ * certain System-V-based systems; for maximum portability, use the
+ * underscore-free variants. The underscored variants are provided for
+ * backward compatibility only; they may disappear from future versions of
+ * this file.
+ */
+
+#define SECS_PER_MIN SECSPERMIN
+#define MINS_PER_HOUR MINSPERHOUR
+#define HOURS_PER_DAY HOURSPERDAY
+#define DAYS_PER_WEEK DAYSPERWEEK
+#define DAYS_PER_NYEAR DAYSPERNYEAR
+#define DAYS_PER_LYEAR DAYSPERLYEAR
+#define SECS_PER_HOUR SECSPERHOUR
+#define SECS_PER_DAY SECSPERDAY
+#define MONS_PER_YEAR MONSPERYEAR
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_TZFILE_H */
diff --git a/usr/src/uts/common/sys/unistd.h b/usr/src/uts/common/sys/unistd.h
index 7cfbb9744f..29e0476abd 100644
--- a/usr/src/uts/common/sys/unistd.h
+++ b/usr/src/uts/common/sys/unistd.h
@@ -310,6 +310,10 @@ extern "C" {
#define _PC_2_SYMLINKS 19
#define _PC_ACL_ENABLED 20
#define _PC_MIN_HOLE_SIZE 21
+#define _PC_CASE_BEHAVIOR 22
+#define _PC_SATTR_ENABLED 23
+#define _PC_SATTR_EXISTS 24
+
/*
* Large File Summit names
*
@@ -326,6 +330,12 @@ extern "C" {
#define _PC_XATTR_EXISTS 101
/*
+ * Case sensitivity values (related to _PC_CASE_BEHAVIOR)
+ */
+#define _CASE_SENSITIVE 0x1
+#define _CASE_INSENSITIVE 0x2
+
+/*
* The value of 0 is returned when
* ACL's are not supported
*/
diff --git a/usr/src/uts/common/sys/vfs.h b/usr/src/uts/common/sys/vfs.h
index 114ce97811..2b627cd344 100644
--- a/usr/src/uts/common/sys/vfs.h
+++ b/usr/src/uts/common/sys/vfs.h
@@ -175,6 +175,24 @@ extern avl_tree_t vskstat_tree;
extern kmutex_t vskstat_tree_lock;
/*
+ * 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 */
+} vfs_impl_t;
+
+
+/*
* Structure per mounted file system. Each mounted file system has
* an array of operations and an instance record.
*
@@ -200,19 +218,6 @@ extern kmutex_t vskstat_tree_lock;
struct zone; /* from zone.h */
struct fem_head; /* from fem.h */
-/*
- * Private vfs data, NOT to be used by a file system implementation.
- */
-typedef struct vfs_impl {
- struct fem_head *vi_femhead; /* fs monitoring */
- /*
- * 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 */
-} vfs_impl_t;
-
typedef struct vfs {
struct vfs *vfs_next; /* next VFS in VFS list */
struct vfs *vfs_prev; /* prev VFS in VFS list */
@@ -246,9 +251,10 @@ typedef struct vfs {
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 */
} vfs_t;
-#define vfs_femhead vfs_implp->vi_femhead
+#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
@@ -275,6 +281,22 @@ typedef struct vfs {
#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 */
+
+/*
* Argument structure for mount(2).
*
* Flags are defined in <sys/mount.h>.
@@ -380,21 +402,22 @@ typedef struct vfssw {
/*
* Filesystem type definition record. All file systems must export a record
- * of this type through their modlfs structure.
+ * of this type through their modlfs structure. N.B., changing the version
+ * number requires a change in sys/modctl.h.
*/
-typedef struct vfsdef_v3 {
+typedef struct vfsdef_v4 {
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_v3;
+} vfsdef_v4;
-typedef struct vfsdef_v3 vfsdef_t;
+typedef struct vfsdef_v4 vfsdef_t;
enum {
- VFSDEF_VERSION = 3
+ VFSDEF_VERSION = 4
};
/*
@@ -424,6 +447,8 @@ 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);
@@ -450,6 +475,10 @@ 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);
+int vfs_has_feature(vfs_t *, vfs_feature_t);
+
/* The following functions are not for general use by filesystems */
void vfs_createopttbl(mntopts_t *, const char *);
@@ -545,7 +574,6 @@ extern const mntopts_t vfs_mntopts; /* globally recognized options */
#define VFS_INIT(vfsp, op, data) { \
vfs_init((vfsp), (op), (data)); \
- vfsimpl_setup((vfsp)); \
}
diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h
index 56f4ac42d8..3195fb4ebd 100644
--- a/usr/src/uts/common/sys/vnode.h
+++ b/usr/src/uts/common/sys/vnode.h
@@ -194,6 +194,7 @@ struct vsd_node {
* v_shrlocks
* v_path
* v_vsd
+ * v_xattrdir
*
* A special lock (implemented by vn_vfswlock in vnode.c) protects:
* v_vfsmountedhere
@@ -262,6 +263,7 @@ typedef struct vnode {
krwlock_t v_mslock; /* protects v_mset */
void *v_fopdata; /* list of file ops event watches */
struct vsd_node *v_vsd; /* vnode specific data */
+ struct vnode *v_xattrdir; /* unnamed extended attr dir (GFS) */
} vnode_t;
#define IS_DEVVP(vp) \
@@ -334,6 +336,8 @@ typedef struct vn_vfslocks_entry {
#define VISSWAPFS 0x20000 /* vnode is being used for swapfs */
#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
@@ -366,6 +370,101 @@ typedef struct vattr {
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];
+} 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.
@@ -407,22 +506,29 @@ typedef vattr_t vattr32_t;
/*
* Attributes of interest to the caller of setattr or getattr.
*/
-#define AT_TYPE 0x0001
-#define AT_MODE 0x0002
-#define AT_UID 0x0004
-#define AT_GID 0x0008
-#define AT_FSID 0x0010
-#define AT_NODEID 0x0020
-#define AT_NLINK 0x0040
-#define AT_SIZE 0x0080
-#define AT_ATIME 0x0100
-#define AT_MTIME 0x0200
-#define AT_CTIME 0x0400
-#define AT_RDEV 0x0800
-#define AT_BLKSIZE 0x1000
-#define AT_NBLOCKS 0x2000
-/* 0x4000 */ /* unused */
-#define AT_SEQ 0x8000
+#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|\
@@ -437,6 +543,116 @@ typedef vattr_t vattr32_t;
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_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)
+
+/* 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)
+
+/*
+ * 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_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 */
@@ -454,6 +670,12 @@ typedef vattr_t vattr32_t;
#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.
*/
@@ -506,15 +728,19 @@ typedef struct vsecattr {
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_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
@@ -552,79 +778,110 @@ struct pollhead;
* the vnodeops structure (below) and the fs_func_p union (vfs_opreg.h).
*/
#define VNODE_OPS \
- int (*vop_open)(vnode_t **, int, cred_t *); \
- int (*vop_close)(vnode_t *, int, int, offset_t, cred_t *); \
+ 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 *); \
- int (*vop_setfl)(vnode_t *, int, int, cred_t *); \
- int (*vop_getattr)(vnode_t *, vattr_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 *); \
+ 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 *); \
+ 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); \
- int (*vop_remove)(vnode_t *, char *, cred_t *); \
- int (*vop_link)(vnode_t *, vnode_t *, char *, cred_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 *); \
+ cred_t *, caller_context_t *, int); \
int (*vop_mkdir)(vnode_t *, char *, vattr_t *, vnode_t **, \
- cred_t *); \
- int (*vop_rmdir)(vnode_t *, char *, vnode_t *, cred_t *); \
- int (*vop_readdir)(vnode_t *, uio_t *, cred_t *, int *); \
+ 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 *); \
- int (*vop_readlink)(vnode_t *, uio_t *, cred_t *); \
- int (*vop_fsync)(vnode_t *, int, cred_t *); \
- void (*vop_inactive)(vnode_t *, cred_t *); \
- int (*vop_fid)(vnode_t *, struct fid *); \
+ 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 *); \
- int (*vop_cmp)(vnode_t *, vnode_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 *); \
+ 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 **); \
+ 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 *); \
+ caddr_t, enum seg_rw, cred_t *, \
+ caller_context_t *); \
int (*vop_putpage)(vnode_t *, offset_t, size_t, \
- int, cred_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 *); \
+ 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 *); \
+ 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 *); \
+ uint_t, uint_t, uint_t, cred_t *, \
+ caller_context_t *); \
int (*vop_poll)(vnode_t *, short, int, short *, \
- struct pollhead **); \
- int (*vop_dump)(vnode_t *, caddr_t, int, int); \
- int (*vop_pathconf)(vnode_t *, int, ulong_t *, cred_t *); \
+ struct pollhead **, \
+ caller_context_t *); \
+ int (*vop_dump)(vnode_t *, caddr_t, int, int, \
+ 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 *); \
- int (*vop_dumpctl)(vnode_t *, int, int *); \
+ u_offset_t, size_t, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_dumpctl)(vnode_t *, int, int *, \
+ caller_context_t *); \
void (*vop_dispose)(vnode_t *, struct page *, \
- int, int, cred_t *); \
+ int, int, cred_t *, \
+ caller_context_t *); \
int (*vop_setsecattr)(vnode_t *, vsecattr_t *, \
- int, cred_t *); \
+ int, cred_t *, caller_context_t *); \
int (*vop_getsecattr)(vnode_t *, vsecattr_t *, \
- int, cred_t *); \
+ int, cred_t *, caller_context_t *); \
int (*vop_shrlock)(vnode_t *, int, struct shrlock *, \
- int, cred_t *); \
- int (*vop_vnevent)(vnode_t *, vnevent_t, vnode_t *, char *) \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_vnevent)(vnode_t *, vnevent_t, vnode_t *, \
+ char *, caller_context_t *)
/* NB: No ";" */
/*
@@ -639,153 +896,178 @@ typedef struct vnodeops {
typedef int (*fs_generic_func_p) (); /* Generic vop/vfsop/femop/fsemop ptr */
-extern int fop_open(vnode_t **, int, cred_t *);
-extern int fop_close(vnode_t *, int, int, offset_t, cred_t *);
+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 *);
-extern int fop_setfl(vnode_t *, int, int, cred_t *);
-extern int fop_getattr(vnode_t *, vattr_t *, int, cred_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 *);
+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 *);
+ 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);
-extern int fop_remove(vnode_t *vp, char *, cred_t *);
-extern int fop_link(vnode_t *, vnode_t *, char *, cred_t *);
-extern int fop_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-extern int fop_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *);
-extern int fop_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
-extern int fop_readdir(vnode_t *, uio_t *, cred_t *, int *);
-extern int fop_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *);
-extern int fop_readlink(vnode_t *, uio_t *, cred_t *);
-extern int fop_fsync(vnode_t *, int, cred_t *);
-extern void fop_inactive(vnode_t *, cred_t *);
-extern int fop_fid(vnode_t *, struct fid *);
+ 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 *);
-extern int fop_cmp(vnode_t *, vnode_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 *);
+ 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 **);
+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 *);
-extern int fop_putpage(vnode_t *, offset_t, size_t, int, cred_t *);
+ 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);
+ 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 *);
+ 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 *);
-extern int fop_poll(vnode_t *, short, int, short *, struct pollhead **);
-extern int fop_dump(vnode_t *, caddr_t, int, int);
-extern int fop_pathconf(vnode_t *, int, ulong_t *, cred_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, int, int, 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 *);
-extern int fop_dumpctl(vnode_t *, int, int *);
-extern void fop_dispose(vnode_t *, struct page *, int, int, cred_t *);
-extern int fop_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-extern int fop_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-extern int fop_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *);
-extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *);
+ cred_t *, caller_context_t *);
+extern int fop_dumpctl(vnode_t *, int, int *, 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 *);
#endif /* _KERNEL */
-#define VOP_OPEN(vpp, mode, cr) \
- fop_open(vpp, mode, cr)
-#define VOP_CLOSE(vp, f, c, o, cr) \
- fop_close(vp, f, c, o, cr)
+#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) \
- fop_ioctl(vp, cmd, a, f, cr, rvp)
-#define VOP_SETFL(vp, f, a, cr) \
- fop_setfl(vp, f, a, cr)
-#define VOP_GETATTR(vp, vap, f, cr) \
- fop_getattr(vp, vap, f, cr)
+#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) \
- fop_access(vp, mode, f, cr)
-#define VOP_LOOKUP(vp, cp, vpp, pnp, f, rdir, cr) \
- fop_lookup(vp, cp, vpp, pnp, f, rdir, cr)
-#define VOP_CREATE(dvp, p, vap, ex, mode, vpp, cr, flag) \
- fop_create(dvp, p, vap, ex, mode, vpp, cr, flag)
-#define VOP_REMOVE(dvp, p, cr) \
- fop_remove(dvp, p, cr)
-#define VOP_LINK(tdvp, fvp, p, cr) \
- fop_link(tdvp, fvp, p, cr)
-#define VOP_RENAME(fvp, fnm, tdvp, tnm, cr) \
- fop_rename(fvp, fnm, tdvp, tnm, cr)
-#define VOP_MKDIR(dp, p, vap, vpp, cr) \
- fop_mkdir(dp, p, vap, vpp, cr)
-#define VOP_RMDIR(dp, p, cdir, cr) \
- fop_rmdir(dp, p, cdir, cr)
-#define VOP_READDIR(vp, uiop, cr, eofp) \
- fop_readdir(vp, uiop, cr, eofp)
-#define VOP_SYMLINK(dvp, lnm, vap, tnm, cr) \
- fop_symlink(dvp, lnm, vap, tnm, cr)
-#define VOP_READLINK(vp, uiop, cr) \
- fop_readlink(vp, uiop, cr)
-#define VOP_FSYNC(vp, syncflag, cr) \
- fop_fsync(vp, syncflag, cr)
-#define VOP_INACTIVE(vp, cr) \
- fop_inactive(vp, cr)
-#define VOP_FID(vp, fidp) \
- fop_fid(vp, fidp)
+#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) \
- fop_seek(vp, ooff, noffp)
-#define VOP_CMP(vp1, vp2) \
- fop_cmp(vp1, vp2)
-#define VOP_FRLOCK(vp, cmd, a, f, o, cb, cr) \
- fop_frlock(vp, cmd, a, f, o, cb, cr)
+#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) \
- fop_realvp(vp1, vp2)
-#define VOP_GETPAGE(vp, of, sz, pr, pl, ps, sg, a, rw, cr) \
- fop_getpage(vp, of, sz, pr, pl, ps, sg, a, rw, cr)
-#define VOP_PUTPAGE(vp, of, sz, fl, cr) \
- fop_putpage(vp, of, sz, fl, cr)
-#define VOP_MAP(vp, of, as, a, sz, p, mp, fl, cr) \
- fop_map(vp, of, as, a, sz, p, mp, fl, cr)
-#define VOP_ADDMAP(vp, of, as, a, sz, p, mp, fl, cr) \
- fop_addmap(vp, of, as, a, sz, p, mp, fl, cr)
-#define VOP_DELMAP(vp, of, as, a, sz, p, mp, fl, cr) \
- fop_delmap(vp, of, as, a, sz, p, mp, fl, cr)
-#define VOP_POLL(vp, events, anyyet, reventsp, phpp) \
- fop_poll(vp, events, anyyet, reventsp, phpp)
-#define VOP_DUMP(vp, addr, bn, count) \
- fop_dump(vp, addr, bn, count)
-#define VOP_PATHCONF(vp, cmd, valp, cr) \
- fop_pathconf(vp, cmd, valp, cr)
-#define VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr) \
- fop_pageio(vp, pp, io_off, io_len, flags, cr)
-#define VOP_DUMPCTL(vp, action, blkp) \
- fop_dumpctl(vp, action, blkp)
-#define VOP_DISPOSE(vp, pp, flag, dn, cr) \
- fop_dispose(vp, pp, flag, dn, cr)
-#define VOP_GETSECATTR(vp, vsap, f, cr) \
- fop_getsecattr(vp, vsap, f, cr)
-#define VOP_SETSECATTR(vp, vsap, f, cr) \
- fop_setsecattr(vp, vsap, f, cr)
-#define VOP_SHRLOCK(vp, cmd, shr, f, cr) \
- fop_shrlock(vp, cmd, shr, f, cr)
-#define VOP_VNEVENT(vp, vnevent, dvp, fnm) \
- fop_vnevent(vp, vnevent, dvp, fnm)
+#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 VOPNAME_OPEN "open"
#define VOPNAME_CLOSE "close"
@@ -834,10 +1116,19 @@ extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *);
/*
* Flags for VOP_LOOKUP
+ *
+ * Defined in file.h, but also possible, FIGNORECASE
+ *
*/
#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 */
/*
* Flags for VOP_RWLOCK/VOP_RWUNLOCK
@@ -866,6 +1157,9 @@ 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);
@@ -890,7 +1184,7 @@ 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);
+ 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);
@@ -927,15 +1221,15 @@ void vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
const char *path, size_t plen);
/* Vnode event notification */
-void vnevent_rename_src(vnode_t *, vnode_t *, char *);
-void vnevent_rename_dest(vnode_t *, vnode_t *, char *);
-void vnevent_remove(vnode_t *, vnode_t *, char *);
-void vnevent_rmdir(vnode_t *, vnode_t *, char *);
-void vnevent_create(vnode_t *);
-void vnevent_link(vnode_t *);
-void vnevent_rename_dest_dir(vnode_t *);
-void vnevent_mountedover(vnode_t *);
-int vnevent_support(vnode_t *);
+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 *);
+int vnevent_support(vnode_t *, caller_context_t *);
/* Vnode specific data */
void vsd_create(uint_t *, void (*)(void *));
@@ -944,6 +1238,19 @@ 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 *);
+
/* Context identification */
u_longlong_t fs_new_caller_id();
@@ -976,7 +1283,7 @@ extern uint_t pvn_vmodsort_supported;
*/
#define VN_CMP(VP1, VP2) ((VP1) == (VP2) ? 1 : \
((VP1) && (VP2) && (vn_getops(VP1) == vn_getops(VP2)) ? \
- VOP_CMP(VP1, VP2) : 0))
+ VOP_CMP(VP1, VP2, NULL) : 0))
extern struct vnode kvp;
extern struct vnode zvp;
@@ -993,8 +1300,8 @@ extern struct vnode zvp;
#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.
*/
@@ -1026,7 +1333,7 @@ struct async_reqs {
#define VN_DISPOSE(pp, flag, dn, cr) { \
extern struct vnode kvp; \
if ((pp)->p_vnode != NULL && !VN_ISKAS((pp)->p_vnode)) \
- VOP_DISPOSE((pp)->p_vnode, (pp), (flag), (dn), (cr)); \
+ VOP_DISPOSE((pp)->p_vnode, (pp), (flag), (dn), (cr), NULL); \
else if ((flag) == B_FREE) \
page_free((pp), (dn)); \
else \
diff --git a/usr/src/uts/common/syscall/access.c b/usr/src/uts/common/syscall/access.c
index 0c19d8898a..467cb4ecb1 100644
--- a/usr/src/uts/common/syscall/access.c
+++ b/usr/src/uts/common/syscall/access.c
@@ -101,7 +101,7 @@ lookup:
}
if (mode) {
- error = VOP_ACCESS(vp, mode, 0, tmpcr);
+ error = VOP_ACCESS(vp, mode, 0, tmpcr, NULL);
if (error) {
if ((error == ESTALE) &&
fs_need_estale_retry(estale_retry++)) {
diff --git a/usr/src/uts/common/syscall/acctctl.c b/usr/src/uts/common/syscall/acctctl.c
index 8c134b0a62..1f614f23fb 100644
--- a/usr/src/uts/common/syscall/acctctl.c
+++ b/usr/src/uts/common/syscall/acctctl.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -161,7 +160,8 @@ ac_file_set(ac_info_t *info, void *ubuf, size_t bufsz)
* Closing accounting file
*/
if (info->ac_vnode != NULL) {
- error = VOP_CLOSE(info->ac_vnode, FWRITE, 1, 0, CRED());
+ error = VOP_CLOSE(info->ac_vnode, FWRITE, 1, 0,
+ CRED(), NULL);
if (error) {
mutex_exit(&info->ac_lock);
return (error);
@@ -265,7 +265,7 @@ ac_file_set(ac_info_t *info, void *ubuf, size_t bufsz)
/*
* We still need to close the old file.
*/
- if ((error = VOP_CLOSE(vp, FWRITE, 1, 0, CRED())) != 0) {
+ if ((error = VOP_CLOSE(vp, FWRITE, 1, 0, CRED(), NULL)) != 0) {
VN_RELE(vp);
mutex_exit(&info->ac_lock);
kmem_free(namebuf, namelen);
@@ -545,7 +545,7 @@ exacct_free_info(ac_info_t *info)
{
mutex_enter(&info->ac_lock);
if (info->ac_vnode) {
- (void) VOP_CLOSE(info->ac_vnode, FWRITE, 1, 0, kcred);
+ (void) VOP_CLOSE(info->ac_vnode, FWRITE, 1, 0, kcred, NULL);
VN_RELE(info->ac_vnode);
kmem_free(info->ac_file, strlen(info->ac_file) + 1);
}
diff --git a/usr/src/uts/common/syscall/acl.c b/usr/src/uts/common/syscall/acl.c
index 1a7321928d..5c2fe3a9bc 100644
--- a/usr/src/uts/common/syscall/acl.c
+++ b/usr/src/uts/common/syscall/acl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -133,6 +133,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
caddr_t uaddrp;
aclent_t *aclp, *aaclp;
vsecattr_t vsecattr;
+ size_t entry_size;
ASSERT(vp);
@@ -142,20 +143,23 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
case ACE_GETACLCNT:
case GETACLCNT:
- if (cmd == GETACLCNT)
+ if (cmd == GETACLCNT) {
+ entry_size = sizeof (aclent_t);
vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT;
- else
+ } else {
+ entry_size = sizeof (ace_t);
vsecattr.vsa_mask = VSA_ACECNT;
- if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED()))
+ }
+ if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL))
return (error);
*rv = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt;
if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp) {
kmem_free(vsecattr.vsa_aclentp,
- vsecattr.vsa_aclcnt * sizeof (aclent_t));
+ vsecattr.vsa_aclcnt * entry_size);
}
if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp) {
kmem_free(vsecattr.vsa_dfaclentp,
- vsecattr.vsa_dfaclcnt * sizeof (aclent_t));
+ vsecattr.vsa_dfaclcnt * entry_size);
}
break;
case GETACL:
@@ -172,7 +176,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
return (EFAULT);
vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
VSA_DFACLCNT;
- if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED()))
+ if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL))
return (error);
/* Check user's buffer is big enough */
numacls = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt;
@@ -222,7 +226,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
return (EFAULT);
vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT;
- if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED()))
+ if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL))
return (error);
aclbsize = vsecattr.vsa_aclcnt * sizeof (ace_t);
@@ -240,8 +244,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
*rv = vsecattr.vsa_aclcnt;
if (vsecattr.vsa_aclcnt) {
- kmem_free(vsecattr.vsa_aclentp,
- vsecattr.vsa_aclcnt * sizeof (ace_t));
+ kmem_free(vsecattr.vsa_aclentp, vsecattr.vsa_aclentsz);
}
break;
@@ -300,7 +303,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
return (ENOTDIR);
}
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
- if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED())) {
+ if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) {
kmem_free(aaclp, aclbsize);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
return (error);
@@ -327,13 +330,14 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
vsecattr.vsa_aclentp = kmem_alloc(aclbsize, KM_SLEEP);
aaclp = vsecattr.vsa_aclentp;
vsecattr.vsa_aclcnt = nentries;
+ vsecattr.vsa_aclentsz = aclbsize;
uaddrp = (caddr_t)aclbufp;
if (copyin(uaddrp, vsecattr.vsa_aclentp, aclbsize)) {
kmem_free(aaclp, aclbsize);
return (EFAULT);
}
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
- if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED())) {
+ if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) {
kmem_free(aaclp, aclbsize);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
return (error);
diff --git a/usr/src/uts/common/syscall/chdir.c b/usr/src/uts/common/syscall/chdir.c
index 28abd43076..02bc93da74 100644
--- a/usr/src/uts/common/syscall/chdir.c
+++ b/usr/src/uts/common/syscall/chdir.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -174,7 +174,7 @@ chdirec(vnode_t *vp, int ischroot, int do_traverse)
error = ENOTDIR;
goto bad;
}
- if (error = VOP_ACCESS(vp, VEXEC, 0, CRED()))
+ if (error = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL))
goto bad;
/*
@@ -199,11 +199,11 @@ chdirec(vnode_t *vp, int ischroot, int do_traverse)
vnode_t *zonevp = curproc->p_zone->zone_rootvp;
tattr.va_mask = AT_FSID|AT_NODEID;
- if (error = VOP_GETATTR(vp, &tattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &tattr, 0, CRED(), NULL))
goto bad;
rattr.va_mask = AT_FSID|AT_NODEID;
- if (error = VOP_GETATTR(zonevp, &rattr, 0, CRED()))
+ if (error = VOP_GETATTR(zonevp, &rattr, 0, CRED(), NULL))
goto bad;
if ((tattr.va_fsid != rattr.va_fsid ||
diff --git a/usr/src/uts/common/syscall/fcntl.c b/usr/src/uts/common/syscall/fcntl.c
index 15245e4c8c..2e0807e697 100644
--- a/usr/src/uts/common/syscall/fcntl.c
+++ b/usr/src/uts/common/syscall/fcntl.c
@@ -20,7 +20,7 @@
*/
/* ONC_PLUS EXTRACT START */
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -205,7 +205,8 @@ fcntl(int fdes, int cmd, intptr_t arg)
flag = fp->f_flag;
if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
iarg &= ~FNDELAY;
- if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred)) == 0) {
+ if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) ==
+ 0) {
iarg &= FMASK;
mutex_enter(&fp->f_tlock);
fp->f_flag &= ~FMASK | (FREAD|FWRITE);
@@ -317,7 +318,7 @@ fcntl(int fdes, int cmd, intptr_t arg)
* there's no need for them to know. Map it to F_GETLK.
*/
if ((error = VOP_FRLOCK(vp, (cmd == F_O_GETLK) ? F_GETLK : cmd,
- &bf, flag, offset, NULL, fp->f_cred)) != 0)
+ &bf, flag, offset, NULL, fp->f_cred, NULL)) != 0)
break;
/*
@@ -527,12 +528,14 @@ fcntl(int fdes, int cmd, intptr_t arg)
nbl_start_crit(vp, RW_READER);
in_crit = 1;
vattr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0, CRED())) != 0)
+ if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
+ != 0)
break;
begin = start > vattr.va_size ? vattr.va_size : start;
length = vattr.va_size > start ? vattr.va_size - start :
start - vattr.va_size;
- if (nbl_conflict(vp, NBL_WRITE, begin, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, begin, length, 0,
+ NULL)) {
error = EACCES;
break;
}
@@ -599,7 +602,7 @@ fcntl(int fdes, int cmd, intptr_t arg)
break;
if ((error = VOP_FRLOCK(vp, cmd, &bf, flag, offset,
- NULL, fp->f_cred)) != 0)
+ NULL, fp->f_cred, NULL)) != 0)
break;
if ((cmd == F_GETLK) && bf.l_type == F_UNLCK) {
@@ -658,7 +661,7 @@ fcntl(int fdes, int cmd, intptr_t arg)
shr_own.sl_id = fsh.f_id;
shr.s_own_len = sizeof (shr_own);
shr.s_owner = (caddr_t)&shr_own;
- error = VOP_SHRLOCK(vp, cmd, &shr, flag, fp->f_cred);
+ error = VOP_SHRLOCK(vp, cmd, &shr, flag, fp->f_cred, NULL);
/* ONC_PLUS EXTRACT END */
break;
@@ -710,7 +713,7 @@ flock_check(vnode_t *vp, flock64_t *flp, offset_t offset, offset_t max)
break;
case 2: /* SEEK_END */
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
return (error);
if (flp->l_start > (max - (offset_t)vattr.va_size))
return (EOVERFLOW);
@@ -774,7 +777,7 @@ flock_get_start(vnode_t *vp, flock64_t *flp, offset_t offset, u_offset_t *start)
break;
case 2: /* SEEK_END */
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
return (error);
*start = (u_offset_t)(flp->l_start + (offset_t)vattr.va_size);
break;
diff --git a/usr/src/uts/common/syscall/fdsync.c b/usr/src/uts/common/syscall/fdsync.c
index 9951eb8727..8d8eaeab14 100644
--- a/usr/src/uts/common/syscall/fdsync.c
+++ b/usr/src/uts/common/syscall/fdsync.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1998 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,7 +31,7 @@
* under license from the Regents of the University of California.
*/
-#ident "%Z%%M% %I% %E% SMI"
+#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/param.h>
#include <sys/isa_defs.h>
@@ -65,7 +64,7 @@ fdsync(int fd, int flag)
*/
syncflag = flag & (FSYNC|FDSYNC);
- if (error = VOP_FSYNC(fp->f_vnode, syncflag, fp->f_cred))
+ if (error = VOP_FSYNC(fp->f_vnode, syncflag, fp->f_cred, NULL))
(void) set_errno(error);
releasef(fd);
} else
diff --git a/usr/src/uts/common/syscall/fsat.c b/usr/src/uts/common/syscall/fsat.c
index a558518d85..0ad6a6446e 100644
--- a/usr/src/uts/common/syscall/fsat.c
+++ b/usr/src/uts/common/syscall/fsat.c
@@ -42,6 +42,7 @@ extern int fchownat(int, char *, uid_t, gid_t, int);
extern int fstatat(int, char *, struct stat *, int);
extern int futimesat(int, char *, struct timeval *);
extern int accessat(int, char *, int);
+extern int openattrdirat(int, char *);
#if defined(_SYSCALL32_IMPL) || defined(_ILP32)
extern int fstatat64_32(int, char *, struct stat64_32 *, int);
extern int fstatat32(int, char *, struct stat32 *, int);
@@ -65,6 +66,7 @@ extern int fstatat64_32(int, char *, struct stat64_32 *, int);
* 6 - futimesat
* 7 - renameat
* 8 - accessat
+ * 9 - openattrdirat
*
* The code for handling the at functionality exists in the file where the
* base syscall is defined. For example openat is in open.c
@@ -81,43 +83,45 @@ fsat32(int code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
case 0: /* openat */
#if defined(_LP64)
return (openat32((int)arg1, (char *)arg2,
- (int)arg3, (int)arg4));
+ (int)arg3, (int)arg4));
#else
return (openat((int)arg1, (char *)arg2,
- (int)arg3, (int)arg4));
+ (int)arg3, (int)arg4));
#endif
case 1: /* openat64 */
return (openat64((int)arg1, (char *)arg2,
- (int)arg3, (int)arg4));
+ (int)arg3, (int)arg4));
case 2: /* fstatat64 */
#if defined(_LP64)
return (fstatat64_32((int)arg1, (char *)arg2,
- (struct stat64_32 *)arg3, (int)arg4));
+ (struct stat64_32 *)arg3, (int)arg4));
#else
return (fstatat64((int)arg1, (char *)arg2,
- (struct stat64 *)arg3, (int)arg4));
+ (struct stat64 *)arg3, (int)arg4));
#endif
case 3: /* fstatat */
#if defined(_LP64)
return (fstatat32((int)arg1, (char *)arg2,
- (struct stat32 *)arg3, (int)arg4));
+ (struct stat32 *)arg3, (int)arg4));
#else
return (fstatat((int)arg1, (char *)arg2,
- (struct stat *)arg3, (int)arg4));
+ (struct stat *)arg3, (int)arg4));
#endif
case 4: /* fchownat */
return (fchownat((int)arg1, (char *)arg2,
- (uid_t)arg3, (gid_t)arg4, (int)arg5));
+ (uid_t)arg3, (gid_t)arg4, (int)arg5));
case 5: /* unlinkat */
return (unlinkat((int)arg1, (char *)arg2, (int)arg3));
case 6: /* futimesat */
return (futimesat((int)arg1,
- (char *)arg2, (struct timeval *)arg3));
+ (char *)arg2, (struct timeval *)arg3));
case 7: /* renameat */
return (renameat((int)arg1, (char *)arg2, (int)arg3,
- (char *)arg4));
+ (char *)arg4));
case 8: /* accessat */
return (accessat((int)arg1, (char *)arg2, (int)arg3));
+ case 9: /* openattrdirat */
+ return (openattrdirat((int)arg1, (char *)arg2));
default:
return (set_errno(EINVAL));
}
@@ -139,27 +143,29 @@ fsat64(int code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
case 0: /* openat */
return (openat((int)arg1, (char *)arg2,
- (int)arg3, (int)arg4));
+ (int)arg3, (int)arg4));
case 1: /* openat64 */
return (set_errno(ENOSYS));
case 2: /* fstatat64 */
return (set_errno(ENOSYS));
case 3: /* fstatat */
return (fstatat((int)arg1, (char *)arg2,
- (struct stat *)arg3, (int)arg4));
+ (struct stat *)arg3, (int)arg4));
case 4: /* fchownat */
return (fchownat((int)arg1, (char *)arg2,
- (uid_t)arg3, (gid_t)arg4, (int)arg5));
+ (uid_t)arg3, (gid_t)arg4, (int)arg5));
case 5: /* unlinkat */
return (unlinkat((int)arg1, (char *)arg2, (int)arg3));
case 6: /* futimesat */
return (futimesat((int)arg1,
- (char *)arg2, (struct timeval *)arg3));
+ (char *)arg2, (struct timeval *)arg3));
case 7: /* renameat */
return (renameat((int)arg1, (char *)arg2, (int)arg3,
- (char *)arg4));
+ (char *)arg4));
case 8: /* accessat */
return (accessat((int)arg1, (char *)arg2, (int)arg3));
+ case 9: /* openattrdirat */
+ return (openattrdirat((int)arg1, (char *)arg2));
default:
return (set_errno(EINVAL));
}
diff --git a/usr/src/uts/common/syscall/getdents.c b/usr/src/uts/common/syscall/getdents.c
index a7d410d2a6..5daa9c39b4 100644
--- a/usr/src/uts/common/syscall/getdents.c
+++ b/usr/src/uts/common/syscall/getdents.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -119,7 +118,7 @@ getdents32(int fd, void *buf, size_t count)
auio.uio_fmode = 0;
auio.uio_extflg = UIO_COPY_CACHED;
(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(vp, &auio, fp->f_cred, &sink);
+ error = VOP_READDIR(vp, &auio, fp->f_cred, &sink, NULL, 0);
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
if (error)
goto out;
@@ -222,7 +221,7 @@ getdents64(int fd, void *buf, size_t count)
auio.uio_fmode = 0;
auio.uio_extflg = UIO_COPY_CACHED;
(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(vp, &auio, fp->f_cred, &sink);
+ error = VOP_READDIR(vp, &auio, fp->f_cred, &sink, NULL, 0);
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
if (error) {
releasef(fd);
diff --git a/usr/src/uts/common/syscall/ioctl.c b/usr/src/uts/common/syscall/ioctl.c
index c4b514d4de..f3c068dc6b 100644
--- a/usr/src/uts/common/syscall/ioctl.c
+++ b/usr/src/uts/common/syscall/ioctl.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -90,7 +89,7 @@ ioctl(int fdes, int cmd, intptr_t arg)
int32_t offset;
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error) {
releasef(fdes);
return (set_errno(error));
@@ -127,7 +126,7 @@ ioctl(int fdes, int cmd, intptr_t arg)
* ioctl() now passes in the model information in some high bits.
*/
flag = fp->f_flag | get_udatamodel();
- error = VOP_IOCTL(fp->f_vnode, cmd, arg, flag, CRED(), &rv);
+ error = VOP_IOCTL(fp->f_vnode, cmd, arg, flag, CRED(), &rv, NULL);
if (error != 0) {
releasef(fdes);
return (set_errno(error));
diff --git a/usr/src/uts/common/syscall/lseek.c b/usr/src/uts/common/syscall/lseek.c
index d03687eb68..b5cc2e5d4e 100644
--- a/usr/src/uts/common/syscall/lseek.c
+++ b/usr/src/uts/common/syscall/lseek.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -113,7 +112,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
case SEEK_END:
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred)) {
+ if (error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL)) {
goto out;
}
if (reg && (off > (max - (offset_t)vattr.va_size))) {
@@ -134,7 +133,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
*/
noff = (u_offset_t)off;
error = VOP_IOCTL(vp, _FIO_SEEK_DATA, (intptr_t)(&noff),
- FKIOCTL, kcred, NULL);
+ FKIOCTL, kcred, NULL, NULL);
if (error) {
if (error != ENOTTY)
return (error);
@@ -143,7 +142,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
* "off" is not past the end of file
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error)
return (error);
if (noff >= (u_offset_t)vattr.va_size)
@@ -163,7 +162,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
*/
noff = (u_offset_t)off;
error = VOP_IOCTL(vp, _FIO_SEEK_HOLE, (intptr_t)(&noff),
- FKIOCTL, kcred, NULL);
+ FKIOCTL, kcred, NULL, NULL);
if (error) {
if (error != ENOTTY)
return (error);
@@ -172,7 +171,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
* the "virtual hole" at the end of the file.
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error)
return (error);
if (off < (offset_t)vattr.va_size)
@@ -194,7 +193,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
ASSERT((reg && noff <= max) || !reg);
newoff = (offset_t)noff;
- if ((error = VOP_SEEK(vp, curoff, &newoff)) == 0) {
+ if ((error = VOP_SEEK(vp, curoff, &newoff, NULL)) == 0) {
fp->f_offset = newoff;
(*retoff) = newoff;
return (0);
@@ -294,7 +293,7 @@ lseek64(int fdes, off_t off, int stype)
case SEEK_END:
vattr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred)) != 0)
+ if ((error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL)) != 0)
goto lseek64error;
new_off += vattr.va_size;
break;
@@ -309,7 +308,7 @@ lseek64(int fdes, off_t off, int stype)
*/
new_off = (offset_t)off;
error = VOP_IOCTL(vp, _FIO_SEEK_DATA, (intptr_t)(&new_off),
- FKIOCTL, kcred, NULL);
+ FKIOCTL, kcred, NULL, NULL);
if (error) {
if (error != ENOTTY) {
goto lseek64error;
@@ -319,7 +318,7 @@ lseek64(int fdes, off_t off, int stype)
* is not past end of file
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error)
goto lseek64error;
if (new_off >= (offset_t)vattr.va_size) {
@@ -338,7 +337,7 @@ lseek64(int fdes, off_t off, int stype)
*/
new_off = off;
error = VOP_IOCTL(vp, _FIO_SEEK_HOLE, (intptr_t)(&new_off),
- FKIOCTL, kcred, NULL);
+ FKIOCTL, kcred, NULL, NULL);
if (error) {
if (error != ENOTTY)
goto lseek64error;
@@ -347,7 +346,7 @@ lseek64(int fdes, off_t off, int stype)
* the "virtual hole" at the end of the file.
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error)
goto lseek64error;
if (off < (offset_t)vattr.va_size) {
@@ -367,7 +366,7 @@ lseek64(int fdes, off_t off, int stype)
}
old_off = fp->f_offset;
- if ((error = VOP_SEEK(vp, old_off, &new_off)) == 0) {
+ if ((error = VOP_SEEK(vp, old_off, &new_off, NULL)) == 0) {
fp->f_offset = new_off;
releasef(fdes);
return (new_off);
diff --git a/usr/src/uts/common/syscall/open.c b/usr/src/uts/common/syscall/open.c
index f5b873bdb7..b45f7bf35b 100644
--- a/usr/src/uts/common/syscall/open.c
+++ b/usr/src/uts/common/syscall/open.c
@@ -49,6 +49,7 @@
#include <sys/uio.h>
#include <sys/debug.h>
#include <c2/audit.h>
+#include <sys/cmn_err.h>
/*
* Common code for open()/openat() and creat(). Check permissions, allocate
@@ -66,6 +67,8 @@ copen(int startfd, char *fname, int filemode, int createmode)
int fd, dupfd;
vnode_t *startvp;
proc_t *p = curproc;
+ uio_seg_t seg = UIO_USERSPACE;
+ char *open_filename = fname;
if (startfd == AT_FDCWD) {
/*
@@ -95,7 +98,31 @@ copen(int startfd, char *fname, int filemode, int createmode)
}
}
- if (filemode & FXATTR) {
+ /*
+ * Handle openattrdirat request
+ */
+ if (filemode & FXATTRDIROPEN) {
+#ifdef C2_AUDIT
+ if (audit_active)
+ audit_setfsat_path(1);
+#endif /* C2_AUDIT */
+
+ if (error = lookupnameat(fname, seg, FOLLOW,
+ NULLVPP, &vp, startvp))
+ return (set_errno(error));
+ if (startvp) {
+ VN_RELE(startvp);
+ startvp = NULL;
+ }
+
+ startvp = vp;
+ }
+
+ /*
+ * Do we need to go into extended attribute space?
+ */
+ if (filemode & (FXATTR|FXATTRDIROPEN)) {
+ vattr_t vattr;
/*
* Make sure we have a valid request.
@@ -111,7 +138,7 @@ copen(int startfd, char *fname, int filemode, int createmode)
goto out;
}
- if (startfd == AT_FDCWD) {
+ if (startfd == AT_FDCWD && !(filemode & FXATTRDIROPEN)) {
mutex_enter(&p->p_lock);
startvp = PTOU(p)->u_cdir;
VN_HOLD(startvp);
@@ -119,23 +146,34 @@ copen(int startfd, char *fname, int filemode, int createmode)
}
/*
- * Verify permission to put attributes on file
+ * In order to access hidden attribute directory the
+ * user must be able to stat() the file
*/
- if ((VOP_ACCESS(startvp, VREAD, 0, CRED()) != 0) &&
- (VOP_ACCESS(startvp, VWRITE, 0, CRED()) != 0) &&
- (VOP_ACCESS(startvp, VEXEC, 0, CRED()) != 0)) {
- error = EACCES;
+ vattr.va_mask = AT_ALL;
+ if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) {
pn_free(&pn);
goto out;
}
- if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0) {
+ if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 ||
+ vfs_has_feature(startvp->v_vfsp, VFSFT_XVATTR)) {
error = VOP_LOOKUP(startvp, "", &sdvp, &pn,
- LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED());
+ LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(),
+ NULL, NULL, NULL);
} else {
error = EINVAL;
}
+
+ /*
+ * For openattrdirat use "." as filename to open
+ * as part of vn_openat()
+ */
+ if (error == 0 && (filemode & FXATTRDIROPEN)) {
+ open_filename = ".";
+ seg = UIO_SYSSPACE;
+ }
+
pn_free(&pn);
if (error != 0)
goto out;
@@ -144,7 +182,7 @@ copen(int startfd, char *fname, int filemode, int createmode)
startvp = sdvp;
}
- if ((filemode & (FREAD|FWRITE)) != 0) {
+ if ((filemode & (FREAD|FWRITE|FXATTRDIROPEN)) != 0) {
if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
filemode &= ~FNDELAY;
error = falloc((vnode_t *)NULL, filemode, &fp, &fd);
@@ -157,9 +195,11 @@ copen(int startfd, char *fname, int filemode, int createmode)
* Last arg is a don't-care term if
* !(filemode & FCREAT).
*/
- error = vn_openat(fname, UIO_USERSPACE, filemode,
- (int)(createmode & MODEMASK), &vp, CRCREAT,
- PTOU(curproc)->u_cmask, startvp);
+
+ error = vn_openat(open_filename, seg, filemode,
+ (int)(createmode & MODEMASK),
+ &vp, CRCREAT, PTOU(curproc)->u_cmask,
+ startvp, fd);
if (startvp != NULL)
VN_RELE(startvp);
@@ -223,6 +263,7 @@ out:
#define OPENMODE32(fmode) ((int)((fmode)-FOPEN))
#define CREATMODE32 (FWRITE|FCREAT|FTRUNC)
#define OPENMODE64(fmode) (OPENMODE32(fmode) | FOFFMAX)
+#define OPENMODEATTRDIR FXATTRDIROPEN
#define CREATMODE64 (CREATMODE32 | FOFFMAX)
#ifdef _LP64
#define OPENMODE(fmode) OPENMODE64(fmode)
@@ -301,4 +342,14 @@ openat32(int fd, char *path, int fmode, int cmode)
{
return (copen(fd, path, OPENMODE32(fmode), cmode));
}
+
#endif /* _SYSCALL32_IMPL */
+
+/*
+ * Special interface to open hidden attribute directory.
+ */
+int
+openattrdirat(int fd, char *fname)
+{
+ return (copen(fd, fname, OPENMODEATTRDIR, 0));
+}
diff --git a/usr/src/uts/common/syscall/pathconf.c b/usr/src/uts/common/syscall/pathconf.c
index f6b38d4d84..5ef8ce1675 100644
--- a/usr/src/uts/common/syscall/pathconf.c
+++ b/usr/src/uts/common/syscall/pathconf.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,7 +59,7 @@ cpathconf(register vnode_t *vp, int cmd, struct cred *cr)
switch (cmd) {
case _PC_2_SYMLINKS:
- if (error = VOP_PATHCONF(vp, _PC_SYMLINK_MAX, &val, cr))
+ if (error = VOP_PATHCONF(vp, _PC_SYMLINK_MAX, &val, cr, NULL))
return ((long)set_errno(error));
return ((long)(val > 0));
@@ -77,7 +77,7 @@ cpathconf(register vnode_t *vp, int cmd, struct cred *cr)
return ((long)set_errno(EINVAL));
case _PC_SYNC_IO:
- if (!(error = VOP_FSYNC(vp, FSYNC, cr)))
+ if (!(error = VOP_FSYNC(vp, FSYNC, cr, NULL)))
return (1l);
return ((long)set_errno(error));
@@ -85,7 +85,7 @@ cpathconf(register vnode_t *vp, int cmd, struct cred *cr)
return ((vp->v_vfsp->vfs_flag & VFS_XATTR) ? 1 : 0);
default:
- if (error = VOP_PATHCONF(vp, cmd, &val, cr))
+ if (error = VOP_PATHCONF(vp, cmd, &val, cr, NULL))
return ((long)set_errno(error));
return (val);
}
diff --git a/usr/src/uts/common/syscall/pipe.c b/usr/src/uts/common/syscall/pipe.c
index c980270a55..7721cd2764 100644
--- a/usr/src/uts/common/syscall/pipe.c
+++ b/usr/src/uts/common/syscall/pipe.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -142,7 +141,7 @@ pipe()
if (error = fifo_stropen(&vp2, FWRITE|FREAD, fp2->f_cred, 0, 0)) {
(void) VOP_CLOSE(vp1, FWRITE|FREAD, 1, (offset_t)0,
- fp1->f_cred);
+ fp1->f_cred, NULL);
goto out;
}
diff --git a/usr/src/uts/common/syscall/poll.c b/usr/src/uts/common/syscall/poll.c
index c5ab2b83e4..2fdac673b3 100644
--- a/usr/src/uts/common/syscall/poll.c
+++ b/usr/src/uts/common/syscall/poll.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1264,7 +1264,7 @@ pcache_insert(pollstate_t *ps, file_t *fp, pollfd_t *pollfdp, int *fdcntp,
*/
ASSERT(curthread->t_pollcache == NULL);
error = VOP_POLL(fp->f_vnode, pollfdp->events, 0, &pollfdp->revents,
- &memphp);
+ &memphp, NULL);
if (error) {
return (error);
}
@@ -1979,7 +1979,7 @@ retry:
*/
ASSERT(curthread->t_pollcache == NULL);
error = VOP_POLL(fp->f_vnode, pollfdp[entry].events, 0,
- &pollfdp[entry].revents, &php);
+ &pollfdp[entry].revents, &php, NULL);
/*
* releasef after completely done with this cached
* poll entry. To prevent close() coming in to clear
@@ -2804,7 +2804,7 @@ plist_chkdupfd(file_t *fp, polldat_t *pdp, pollstate_t *psp, pollfd_t *pollfdp,
ASSERT(curthread->t_pollcache == NULL);
error = VOP_POLL(fp->f_vnode,
pollfdp[i].events, 0,
- &pollfdp[i].revents, &php);
+ &pollfdp[i].revents, &php, NULL);
if (error) {
return (error);
}
diff --git a/usr/src/uts/common/syscall/readlink.c b/usr/src/uts/common/syscall/readlink.c
index aaeff14c0d..4c31e16d3f 100644
--- a/usr/src/uts/common/syscall/readlink.c
+++ b/usr/src/uts/common/syscall/readlink.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -77,7 +77,7 @@ lookup:
* object to look like a symlink at user-level.
*/
vattr.va_mask = AT_TYPE;
- error = VOP_GETATTR(vp, &vattr, 0, CRED());
+ error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL);
if (error || vattr.va_type != VLNK) {
VN_RELE(vp);
if ((error == ESTALE) &&
@@ -94,7 +94,7 @@ lookup:
auio.uio_segflg = UIO_USERSPACE;
auio.uio_extflg = UIO_COPY_CACHED;
auio.uio_resid = cnt;
- error = VOP_READLINK(vp, &auio, CRED());
+ error = VOP_READLINK(vp, &auio, CRED(), NULL);
VN_RELE(vp);
if (error) {
if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
diff --git a/usr/src/uts/common/syscall/rw.c b/usr/src/uts/common/syscall/rw.c
index 3eb98b50ac..f614761e33 100644
--- a/usr/src/uts/common/syscall/rw.c
+++ b/usr/src/uts/common/syscall/rw.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -115,7 +115,8 @@ read(int fdes, void *cbuf, size_t count)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_READ, fp->f_offset, cnt, svmand)) {
+ if (nbl_conflict(vp, NBL_READ, fp->f_offset, cnt, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -138,7 +139,7 @@ read(int fdes, void *cbuf, size_t count)
if (fileoff >= OFFSET_MAX(fp) && (vp->v_type == VREG)) {
struct vattr va;
va.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred))) {
+ if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) {
VOP_RWUNLOCK(vp, rwflag, NULL);
goto out;
}
@@ -250,7 +251,8 @@ write(int fdes, void *cbuf, size_t count)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, cnt, svmand)) {
+ if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, cnt, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -402,7 +404,8 @@ pread(int fdes, void *cbuf, size_t count, off_t offset)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand)) {
+ if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -414,7 +417,7 @@ pread(int fdes, void *cbuf, size_t count, off_t offset)
if (vp->v_type == VREG && fileoff == (u_offset_t)maxoff) {
struct vattr va;
va.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred))) {
+ if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) {
VOP_RWUNLOCK(vp, rwflag, NULL);
goto out;
}
@@ -555,7 +558,8 @@ pwrite(int fdes, void *cbuf, size_t count, off_t offset)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand)) {
+ if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -682,7 +686,8 @@ readv(int fdes, struct iovec *iovp, int iovcnt)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_READ, fp->f_offset, count, svmand)) {
+ if (nbl_conflict(vp, NBL_READ, fp->f_offset, count, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -698,7 +703,7 @@ readv(int fdes, struct iovec *iovp, int iovcnt)
if ((vp->v_type == VREG) && (fileoff >= OFFSET_MAX(fp))) {
struct vattr va;
va.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred))) {
+ if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) {
VOP_RWUNLOCK(vp, rwflag, NULL);
goto out;
}
@@ -839,7 +844,8 @@ writev(int fdes, struct iovec *iovp, int iovcnt)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, count, svmand)) {
+ if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, count, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -980,7 +986,8 @@ pread64(int fdes, void *cbuf, size32_t count, uint32_t offset_1,
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand)) {
+ if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -1112,7 +1119,8 @@ pwrite64(int fdes, void *cbuf, size32_t count, uint32_t offset_1,
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand)) {
+ if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
diff --git a/usr/src/uts/common/syscall/sendfile.c b/usr/src/uts/common/syscall/sendfile.c
index c9c14df59a..72c1e84465 100644
--- a/usr/src/uts/common/syscall/sendfile.c
+++ b/usr/src/uts/common/syscall/sendfile.c
@@ -916,7 +916,7 @@ sendvec_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
}
readvp = ffp->f_vnode;
- if (VOP_REALVP(readvp, &realvp) == 0)
+ if (VOP_REALVP(readvp, &realvp, NULL) == 0)
readvp = realvp;
if (readvp->v_type != VREG) {
releasef(sfv->sfv_fd);
diff --git a/usr/src/uts/common/syscall/stat.c b/usr/src/uts/common/syscall/stat.c
index 33403cf89e..c559747e2f 100644
--- a/usr/src/uts/common/syscall/stat.c
+++ b/usr/src/uts/common/syscall/stat.c
@@ -252,7 +252,7 @@ cstat(vnode_t *vp, struct stat *ubp, int flag, cred_t *cr)
int error;
vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, flag, cr)) != 0)
+ if ((error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) != 0)
return (error);
#ifdef _ILP32
/*
@@ -339,7 +339,6 @@ out:
*/
static int cstatat32(int, char *, int, struct stat32 *, int, int);
static int cstat32(vnode_t *, struct stat32 *, int, cred_t *);
-
int
stat32(char *fname, struct stat32 *sb)
{
@@ -401,7 +400,7 @@ cstat32(vnode_t *vp, struct stat32 *ubp, int flag, struct cred *cr)
dev32_t st_dev, st_rdev;
vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, flag, cr))
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
return (error);
/* devices are a special case, see comments in cstat */
@@ -521,7 +520,7 @@ cstat64(vnode_t *vp, struct stat64 *ubp, int flag, cred_t *cr)
int error;
vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, flag, cr))
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
return (error);
bzero(&lsb, sizeof (lsb));
@@ -627,7 +626,7 @@ cstat64_32(vnode_t *vp, struct stat64_32 *ubp, int flag, cred_t *cr)
dev32_t st_dev, st_rdev;
vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, flag, cr))
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
return (error);
if (!cmpldev(&st_dev, vattr.va_fsid) ||
diff --git a/usr/src/uts/common/syscall/symlink.c b/usr/src/uts/common/syscall/symlink.c
index 915fc9d050..1db42e474e 100644
--- a/usr/src/uts/common/syscall/symlink.c
+++ b/usr/src/uts/common/syscall/symlink.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -83,7 +83,7 @@ top:
vattr.va_mode = 0777;
vattr.va_mask = AT_TYPE|AT_MODE;
error = VOP_SYMLINK(dvp, lpn.pn_path, &vattr,
- tbuf, CRED());
+ tbuf, CRED(), NULL, 0);
#ifdef C2_AUDIT
if (audit_active)
audit_symlink_create(dvp, lpn.pn_path,
diff --git a/usr/src/uts/common/syscall/ucredsys.c b/usr/src/uts/common/syscall/ucredsys.c
index 38d13884c7..0f5c0e6303 100644
--- a/usr/src/uts/common/syscall/ucredsys.c
+++ b/usr/src/uts/common/syscall/ucredsys.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -66,7 +66,7 @@ getpeerucred(int fd, void *buf)
case VFIFO:
case VSOCK:
err = VOP_IOCTL(vp, _I_GETPEERCRED, (intptr_t)&kpc,
- FKIOCTL, CRED(), &rval);
+ FKIOCTL, CRED(), &rval, NULL);
break;
case VCHR: {
struct strioctl strioc;
diff --git a/usr/src/uts/common/vm/seg_dev.c b/usr/src/uts/common/vm/seg_dev.c
index f24a1d46ed..02e2306703 100644
--- a/usr/src/uts/common/vm/seg_dev.c
+++ b/usr/src/uts/common/vm/seg_dev.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -422,7 +422,7 @@ segdev_create(struct seg *seg, void *argsp)
*/
error = VOP_ADDMAP(VTOCVP(sdp->vp), sdp->offset,
seg->s_as, seg->s_base, seg->s_size,
- sdp->prot, sdp->maxprot, sdp->type, CRED());
+ sdp->prot, sdp->maxprot, sdp->type, CRED(), NULL);
if (error != 0) {
sdp->devmap_data = NULL;
@@ -522,7 +522,7 @@ segdev_dup(struct seg *seg, struct seg *newseg)
return (VOP_ADDMAP(VTOCVP(newsdp->vp),
newsdp->offset, newseg->s_as,
newseg->s_base, newseg->s_size, newsdp->prot,
- newsdp->maxprot, sdp->type, CRED()));
+ newsdp->maxprot, sdp->type, CRED(), NULL));
}
/*
@@ -707,7 +707,7 @@ segdev_unmap(struct seg *seg, caddr_t addr, size_t len)
*/
ASSERT(sdp->vp != NULL);
(void) VOP_DELMAP(VTOCVP(sdp->vp), off, seg->s_as, addr, len,
- sdp->prot, sdp->maxprot, sdp->type, CRED());
+ sdp->prot, sdp->maxprot, sdp->type, CRED(), NULL);
/*
* Check for entire segment
@@ -2889,7 +2889,7 @@ devmap_get_large_pgsize(devmap_handle_t *dhp, size_t len, caddr_t addr,
*llen += pgsize;
off = ptob(pfn - dhp->dh_pfn) + pgsize;
}
- /* Large page mapping len/addr cover more range than orginal fault */
+ /* Large page mapping len/addr cover more range than original fault */
ASSERT(*llen >= len && *laddr <= addr);
ASSERT((*laddr + *llen) >= (addr + len));
}
@@ -3799,7 +3799,7 @@ devmap_alloc_pages(vmem_t *vmp, size_t size, int vmflag)
}
/*
- * This is where things are a bit incestrous with seg_kmem: unlike
+ * This is where things are a bit incestuous with seg_kmem: unlike
* seg_kp, seg_kmem does not keep its pages long-term sharelocked, so
* we need to do a bit of a dance around that to prevent duplication of
* code until we decide to bite the bullet and implement a new kernel
@@ -3851,7 +3851,7 @@ devmap_free_pages(vmem_t *vmp, void *inaddr, size_t size)
* default request. For now we allocate our own pages and we keep
* them long-term sharelocked, since: A) the fault routines expect the
* memory to already be locked; B) pageable umem is already long-term
- * locked; C) it's a lot of work to make it otherwise, particuarly
+ * locked; C) it's a lot of work to make it otherwise, particularly
* since the nexus layer expects the pages to never fault. An RFE is to
* not keep the pages long-term locked, but instead to be able to
* take faults on them and simply look them up in kvp in case we
diff --git a/usr/src/uts/common/vm/seg_kp.c b/usr/src/uts/common/vm/seg_kp.c
index d58e873a19..d65b3062bc 100644
--- a/usr/src/uts/common/vm/seg_kp.c
+++ b/usr/src/uts/common/vm/seg_kp.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -536,7 +536,7 @@ segkp_get_internal(
*/
err = VOP_GETPAGE(vp, (offset_t)off, PAGESIZE,
NULL, pl, PAGESIZE, seg, va, S_CREATE,
- kcred);
+ kcred, NULL);
if (err) {
/*
* XXX - This should not fail.
@@ -1129,7 +1129,7 @@ segkp_load(
* which is returned to us already kept.
*/
err = VOP_GETPAGE(vp, (offset_t)off, PAGESIZE, NULL,
- pl, PAGESIZE, seg, va, S_READ, kcred);
+ pl, PAGESIZE, seg, va, S_READ, kcred, NULL);
if (err) {
/*
@@ -1242,7 +1242,7 @@ segkp_unlock(
* use kcred.
*/
(void) VOP_PUTPAGE(vp, (offset_t)off, PAGESIZE,
- B_ASYNC | B_FREE, kcred);
+ B_ASYNC | B_FREE, kcred, NULL);
VN_RELE(vp);
} else {
page_unlock(pp);
diff --git a/usr/src/uts/common/vm/seg_map.c b/usr/src/uts/common/vm/seg_map.c
index de27f6e2ff..ad18a2cb31 100644
--- a/usr/src/uts/common/vm/seg_map.c
+++ b/usr/src/uts/common/vm/seg_map.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -707,7 +707,7 @@ segmap_fault(
TRACE_3(TR_FAC_VM, TR_SEGMAP_GETPAGE,
"segmap_getpage:seg %p addr %p vp %p", seg, addr, vp);
err = VOP_GETPAGE(vp, (offset_t)off, len, &prot, pl, MAXBSIZE,
- seg, addr, rw, CRED());
+ seg, addr, rw, CRED(), NULL);
if (err)
return (FC_MAKE_ERR(err));
@@ -829,7 +829,7 @@ segmap_faulta(struct seg *seg, caddr_t addr)
err = VOP_GETPAGE(vp, (offset_t)(off + ((offset_t)((uintptr_t)addr
& MAXBOFFSET))), PAGESIZE, (uint_t *)NULL, (page_t **)NULL, 0,
- seg, addr, S_READ, CRED());
+ seg, addr, S_READ, CRED(), NULL);
if (err)
return (FC_MAKE_ERR(err));
@@ -1369,7 +1369,7 @@ next_smap:
*/
/*
- * Create pages (without using VOP_GETPAGE) and load up tranlations to them.
+ * Create pages (without using VOP_GETPAGE) and load up translations to them.
* If softlock is TRUE, then set things up so that it looks like a call
* to segmap_fault with F_SOFTLOCK.
*
@@ -1455,7 +1455,7 @@ segmap_pagecreate(struct seg *seg, caddr_t addr, size_t len, int softlock)
* "exclusive" lock will not be dropped to prevent
* other users from accessing the page. We also
* have to lock the translation to prevent a fault
- * from occuring when the virtual address mapped by
+ * from occurring when the virtual address mapped by
* this page is written into. This is necessary to
* avoid a deadlock since we haven't dropped the
* "exclusive" lock.
@@ -1898,7 +1898,7 @@ vrfy_smp:
base = segkpm_create_va(baseoff);
error = VOP_GETPAGE(vp, (offset_t)baseoff, len, &prot, pl, MAXBSIZE,
- seg, base, rw, CRED());
+ seg, base, rw, CRED(), NULL);
pp = pl[0];
if (error || pp == NULL) {
@@ -2010,7 +2010,7 @@ segmap_release(struct seg *seg, caddr_t addr, uint_t flags)
smtx = SMAPMTX(smp);
/*
- * For compatibilty reasons segmap_pagecreate_kpm sets this
+ * For compatibility reasons segmap_pagecreate_kpm sets this
* flag to allow a following segmap_pagecreate to return
* this as "newpage" flag. When segmap_pagecreate is not
* called at all we clear it now.
@@ -2117,7 +2117,7 @@ segmap_release(struct seg *seg, caddr_t addr, uint_t flags)
*/
if ((flags & ~SM_DONTNEED) != 0) {
error = VOP_PUTPAGE(vp, offset, MAXBSIZE,
- bflags, CRED());
+ bflags, CRED(), NULL);
} else {
error = 0;
}
diff --git a/usr/src/uts/common/vm/seg_vn.c b/usr/src/uts/common/vm/seg_vn.c
index b7fe798061..e3f67cf336 100644
--- a/usr/src/uts/common/vm/seg_vn.c
+++ b/usr/src/uts/common/vm/seg_vn.c
@@ -466,7 +466,7 @@ segvn_setvnode_mpss(vnode_t *vp)
if (vp->v_mpssdata == NULL) {
if (vn_vmpss_usepageio(vp)) {
err = VOP_PAGEIO(vp, (page_t *)NULL,
- (u_offset_t)0, 0, 0, CRED());
+ (u_offset_t)0, 0, 0, CRED(), NULL);
} else {
err = ENOSYS;
}
@@ -594,7 +594,7 @@ segvn_create(struct seg *seg, void *argsp)
if (a->vp != NULL) {
error = VOP_ADDMAP(a->vp, a->offset & PAGEMASK,
seg->s_as, seg->s_base, seg->s_size, a->prot,
- a->maxprot, a->type, cred);
+ a->maxprot, a->type, cred, NULL);
if (error) {
if (swresv != 0) {
anon_unresv(swresv);
@@ -1614,7 +1614,7 @@ retry:
if (newsvd->vp != NULL) {
error = VOP_ADDMAP(newsvd->vp, (offset_t)newsvd->offset,
newseg->s_as, newseg->s_base, newseg->s_size, newsvd->prot,
- newsvd->maxprot, newsvd->type, newsvd->cred);
+ newsvd->maxprot, newsvd->type, newsvd->cred, NULL);
}
out:
if (error == 0 && HAT_IS_REGION_COOKIE_VALID(svd->rcookie)) {
@@ -1771,7 +1771,7 @@ retry:
error = VOP_DELMAP(svd->vp,
(offset_t)svd->offset + (uintptr_t)(addr - seg->s_base),
seg->s_as, addr, len, svd->prot, svd->maxprot,
- svd->type, svd->cred);
+ svd->type, svd->cred, NULL);
if (error == EAGAIN)
return (error);
@@ -2265,7 +2265,7 @@ ulong_t segvn_lpglck_limit = 0;
* Support routines used by segvn_pagelock() and softlock faults for anonymous
* pages to implement availrmem accounting in a way that makes sure the
* same memory is accounted just once for all softlock/pagelock purposes.
- * This prevents a bug when availrmem is quickly incorrectly exausted from
+ * This prevents a bug when availrmem is quickly incorrectly exhausted from
* several pagelocks to different parts of the same large page since each
* pagelock has to decrement availrmem by the size of the entire large
* page. Note those pages are not COW shared until softunlock/pageunlock so
@@ -2274,7 +2274,7 @@ ulong_t segvn_lpglck_limit = 0;
* entire large page because large anon pages can't be demoted when any of
* constituent pages is locked. The caller calls this routine for every page_t
* it locks. The very first page in the range may not be the root page of a
- * large page. For all other pages it's guranteed we are going to visit the
+ * large page. For all other pages it's guaranteed we are going to visit the
* root of a particular large page before any other constituent page as we are
* locking sequential pages belonging to the same anon map. So we do all the
* locking when the root is encountered except for the very first page. Since
@@ -3255,9 +3255,9 @@ segvn_full_szcpages(page_t **ppa, uint_t szc, int *upgrdfail, uint_t *pszc)
* page_size(szc)) range and for private segment return them in ppa array.
* Pages are created either via IO or relocations.
*
- * Return 1 on sucess and 0 on failure.
+ * Return 1 on success and 0 on failure.
*
- * If physically contiguos pages already exist for this range return 1 without
+ * If physically contiguous pages already exist for this range return 1 without
* filling ppa array. Caller initializes ppa[0] as NULL to detect that ppa
* array wasn't filled. In this case caller fills ppa array via VOP_GETPAGE().
*/
@@ -3394,7 +3394,7 @@ segvn_fill_vp_pages(struct segvn_data *svd, vnode_t *vp, u_offset_t off,
* XXX fix NFS to remove this check.
*/
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vp, &va, ATTR_HINT, svd->cred) != 0) {
+ if (VOP_GETATTR(vp, &va, ATTR_HINT, svd->cred, NULL)) {
VM_STAT_ADD(segvnvmstats.fill_vp_pages[6]);
page_unlock(targpp);
goto out;
@@ -3407,7 +3407,7 @@ segvn_fill_vp_pages(struct segvn_data *svd, vnode_t *vp, u_offset_t off,
goto out;
}
io_err = VOP_PAGEIO(vp, io_pplist, io_off, io_len,
- B_READ, svd->cred);
+ B_READ, svd->cred, NULL);
if (io_err) {
VM_STAT_ADD(segvnvmstats.fill_vp_pages[8]);
page_unlock(targpp);
@@ -3464,7 +3464,7 @@ segvn_fill_vp_pages(struct segvn_data *svd, vnode_t *vp, u_offset_t off,
VM_STAT_ADD(segvnvmstats.fill_vp_pages[12]);
io_len = eoff - io_off;
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vp, &va, ATTR_HINT, svd->cred) != 0) {
+ if (VOP_GETATTR(vp, &va, ATTR_HINT, svd->cred, NULL) != 0) {
VM_STAT_ADD(segvnvmstats.fill_vp_pages[13]);
goto out;
}
@@ -3475,7 +3475,7 @@ segvn_fill_vp_pages(struct segvn_data *svd, vnode_t *vp, u_offset_t off,
goto out;
}
io_err = VOP_PAGEIO(vp, io_pplist, io_off, io_len,
- B_READ, svd->cred);
+ B_READ, svd->cred, NULL);
if (io_err) {
VM_STAT_ADD(segvnvmstats.fill_vp_pages[15]);
if (io_err == EDEADLK) {
@@ -3966,7 +3966,7 @@ segvn_fault_vnodepages(struct hat *hat, struct seg *seg, caddr_t lpgaddr,
ppa[0] = NULL;
ierr = VOP_GETPAGE(vp, (offset_t)off, pgsz,
&vpprot, ppa, pgsz, seg, a, arw,
- svd->cred);
+ svd->cred, NULL);
#ifdef DEBUG
if (ierr == 0) {
for (i = 0; i < pages; i++) {
@@ -4003,7 +4003,7 @@ segvn_fault_vnodepages(struct hat *hat, struct seg *seg, caddr_t lpgaddr,
goto out;
}
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vp, &va, 0, svd->cred) != 0) {
+ if (VOP_GETATTR(vp, &va, 0, svd->cred, NULL)) {
SEGVN_VMSTAT_FLTVNPAGES(20);
err = FC_MAKE_ERR(EIO);
goto out;
@@ -5313,7 +5313,7 @@ slow:
(void) VOP_PUTPAGE(fvp,
(offset_t)fpgoff, PAGESIZE,
(B_DONTNEED|B_FREE|B_ASYNC),
- svd->cred);
+ svd->cred, NULL);
VN_RELE(fvp);
} else {
/*
@@ -5429,7 +5429,7 @@ slow:
seg, addr, vp);
err = VOP_GETPAGE(vp, (offset_t)vp_off, vp_len,
&vpprot, plp, plsz, seg, addr + (vp_off - off), arw,
- svd->cred);
+ svd->cred, NULL);
if (err) {
SEGVN_LOCK_EXIT(seg->s_as, &svd->lock);
segvn_pagelist_rele(plp);
@@ -5661,7 +5661,7 @@ segvn_faulta(struct seg *seg, caddr_t addr)
err = VOP_GETPAGE(vp,
(offset_t)(svd->offset + (uintptr_t)(addr - seg->s_base)),
PAGESIZE, NULL, NULL, 0, seg, addr,
- S_OTHER, svd->cred);
+ S_OTHER, svd->cred, NULL);
SEGVN_LOCK_EXIT(seg->s_as, &svd->lock);
if (err)
@@ -5745,7 +5745,7 @@ segvn_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
/*
* If we are holding the as lock as a reader then
* we need to return IE_RETRY and let the as
- * layer drop and re-aquire the lock as a writer.
+ * layer drop and re-acquire the lock as a writer.
*/
if (AS_READ_HELD(seg->s_as, &seg->s_as->a_lock))
return (IE_RETRY);
@@ -6207,7 +6207,7 @@ segvn_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
va.va_mask = AT_SIZE;
eoffpage += seg->s_size;
eoffpage = btopr(eoffpage);
- if (VOP_GETATTR(svd->vp, &va, 0, svd->cred) != 0) {
+ if (VOP_GETATTR(svd->vp, &va, 0, svd->cred, NULL) != 0) {
segvn_setpgsz_getattr_err++;
return (EINVAL);
}
@@ -6451,7 +6451,7 @@ segvn_claim_pages(
}
/*
- * Returns right (upper address) segment if split occured.
+ * Returns right (upper address) segment if split occurred.
* If the address is equal to the beginning or end of its segment it returns
* the current segment.
*/
@@ -6920,7 +6920,7 @@ segvn_kluster(struct seg *seg, caddr_t addr, ssize_t delta)
swap_xlate(oap, &vp2, &off2);
- if (!VOP_CMP(vp1, vp2) || off1 - off2 != delta)
+ if (!VOP_CMP(vp1, vp2, NULL) || off1 - off2 != delta)
return (-1);
return (0);
}
@@ -7194,7 +7194,7 @@ segvn_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
* is not on, just use one big request.
*/
err = VOP_PUTPAGE(svd->vp, (offset_t)offset, len,
- bflags, svd->cred);
+ bflags, svd->cred, NULL);
SEGVN_LOCK_EXIT(seg->s_as, &svd->lock);
return (err);
}
@@ -7270,7 +7270,7 @@ segvn_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
}
} else if (svd->type == MAP_SHARED && amp != NULL) {
/*
- * Avoid writting out to disk ISM's large pages
+ * Avoid writing out to disk ISM's large pages
* because segspt_free_pages() relies on NULL an_pvp
* of anon slots of such pages.
*/
@@ -7303,7 +7303,7 @@ segvn_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
*/
VN_HOLD(vp);
err = VOP_PUTPAGE(vp, (offset_t)off, PAGESIZE,
- bflags, svd->cred);
+ bflags, svd->cred, NULL);
VN_RELE(vp);
if (err)
break;
@@ -7734,7 +7734,7 @@ segvn_lockop(struct seg *seg, caddr_t addr, size_t len,
error = VOP_GETPAGE(vp, (offset_t)off, PAGESIZE,
(uint_t *)NULL, pl, PAGESIZE, seg, addr,
- S_OTHER, svd->cred);
+ S_OTHER, svd->cred, NULL);
/*
* If the error is EDEADLK then we must bounce
@@ -7759,7 +7759,7 @@ segvn_lockop(struct seg *seg, caddr_t addr, size_t len,
if (error && svd->vp) {
va.va_mask = AT_SIZE;
if (VOP_GETATTR(svd->vp, &va, 0,
- svd->cred) != 0) {
+ svd->cred, NULL) != 0) {
err = EIO;
goto out;
}
@@ -9007,7 +9007,7 @@ segvn_textrepl(struct seg *seg)
* If VOP_GETATTR() call fails bail out.
*/
va.va_mask = AT_SIZE | AT_MTIME | AT_CTIME;
- if (VOP_GETATTR(vp, &va, 0, svd->cred) != 0) {
+ if (VOP_GETATTR(vp, &va, 0, svd->cred, NULL) != 0) {
svd->tr_state = SEGVN_TR_OFF;
SEGVN_TR_ADDSTAT(gaerr);
return;
@@ -9337,7 +9337,7 @@ done:
}
/*
- * This is called when a MAP_SHARED writabble mapping is created to a vnode
+ * This is called when a MAP_SHARED writable mapping is created to a vnode
* that is currently used for execution (VVMEXEC flag is set). In this case we
* need to prevent further use of existing replicas.
*/
diff --git a/usr/src/uts/common/vm/vm_anon.c b/usr/src/uts/common/vm/vm_anon.c
index 58b505f0a6..10f6ccafa1 100644
--- a/usr/src/uts/common/vm/vm_anon.c
+++ b/usr/src/uts/common/vm/vm_anon.c
@@ -1418,7 +1418,8 @@ anon_fill_cow_holes(
page_t *pp;
err = VOP_GETPAGE(vp, vp_off, PAGESIZE, NULL,
- pl, PAGESIZE, seg, addr, S_READ, cred);
+ pl, PAGESIZE, seg, addr, S_READ, cred,
+ NULL);
if (err) {
break;
}
@@ -1770,7 +1771,7 @@ anon_getpage(
seg, addr, vp);
err = VOP_GETPAGE(vp, (u_offset_t)off, PAGESIZE, protp, pl, plsz,
- seg, addr, rw, cred);
+ seg, addr, rw, cred, NULL);
if (err == 0 && pl != NULL) {
ahm = &anonhash_lock[AH_LOCK(ap->an_vp, ap->an_off)];
@@ -1787,8 +1788,8 @@ anon_getpage(
* page cannot be allocated. returns -2 if some other process has allocated a
* larger page.
*
- * For cowfault it will alocate any size pages to fill the requested area to
- * avoid partially overwritting anon slots (i.e. sharing only some of the anon
+ * For cowfault it will allocate any size pages to fill the requested area to
+ * avoid partially overwriting anon slots (i.e. sharing only some of the anon
* slots within a large page with other processes). This policy greatly
* simplifies large page freeing (which is only freed when all anon slot
* refcnts are 0).
@@ -2271,7 +2272,7 @@ anon_private(
* vnode at the same time.
*/
err = VOP_GETPAGE(vp, (u_offset_t)off, PAGESIZE, NULL,
- anon_pl, PAGESIZE, seg, addr, S_CREATE, cred);
+ anon_pl, PAGESIZE, seg, addr, S_CREATE, cred, NULL);
if (err)
goto out;
@@ -2640,7 +2641,7 @@ anon_zero(struct seg *seg, caddr_t addr, struct anon **app, struct cred *cred)
* the vnode at the same time since it is locked.
*/
err = VOP_GETPAGE(vp, off, PAGESIZE, NULL,
- anon_pl, PAGESIZE, seg, addr, S_CREATE, cred);
+ anon_pl, PAGESIZE, seg, addr, S_CREATE, cred, NULL);
if (err) {
*app = NULL;
anon_decref(ap);
@@ -3109,7 +3110,7 @@ top:
* have at most one reference at this point. This means underlying pages can
* be exclusively locked and demoted or freed. If not freeing the entire
* large pages demote the ends of the region we free to be able to free
- * subpages. Page roots correspend to aligned index positions in anon map.
+ * subpages. Page roots correspond to aligned index positions in anon map.
*/
void
anon_shmap_free_pages(struct anon_map *amp, ulong_t sidx, size_t len)
@@ -3216,7 +3217,7 @@ anonmap_free(struct anon_map *amp)
/*
* Returns true if the app array has some empty slots.
- * The offp and lenp paramters are in/out paramters. On entry
+ * The offp and lenp parameters are in/out parameters. On entry
* these values represent the starting offset and length of the
* mapping. When true is returned, these values may be modified
* to be the largest range which includes empty slots.
@@ -3272,7 +3273,7 @@ anon_pages(struct anon_hdr *ahp, ulong_t anon_index, pgcnt_t nslots)
/*
* Move reserved phys swap into memory swap (unreserve phys swap
* and reserve mem swap by the same amount).
- * Used by segspt when it needs to lock resrved swap npages in memory
+ * Used by segspt when it needs to lock reserved swap npages in memory
*/
int
anon_swap_adjust(pgcnt_t npages)
diff --git a/usr/src/uts/common/vm/vm_as.c b/usr/src/uts/common/vm/vm_as.c
index d7ed7da8ec..86d7bc982f 100644
--- a/usr/src/uts/common/vm/vm_as.c
+++ b/usr/src/uts/common/vm/vm_as.c
@@ -1160,7 +1160,7 @@ setprot_top:
/*
* Normally we only lock the as as a reader. But
* if due to setprot the segment driver needs to split
- * a segment it will return IE_RETRY. Therefore we re-aquire
+ * a segment it will return IE_RETRY. Therefore we re-acquire
* the as lock as a writer so the segment driver can change
* the seg list. Also the segment driver will return IE_RETRY
* after it has changed the segment list so we therefore keep
@@ -1602,7 +1602,7 @@ again:
}
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vn_a->vp, &va, ATTR_HINT, vn_a->cred) != 0) {
+ if (VOP_GETATTR(vn_a->vp, &va, ATTR_HINT, vn_a->cred, NULL) != 0) {
szcvec = 0;
goto again;
}
diff --git a/usr/src/uts/common/vm/vm_page.c b/usr/src/uts/common/vm/vm_page.c
index c725b13f17..bb1adbe42a 100644
--- a/usr/src/uts/common/vm/vm_page.c
+++ b/usr/src/uts/common/vm/vm_page.c
@@ -109,11 +109,11 @@ pgcnt_t availrmem_initial;
* segvn_pages_locked : This keeps track on a global basis how many pages
* are currently locked because of I/O.
*
- * pages_locked : How many pages are locked becuase of user specified
+ * pages_locked : How many pages are locked because of user specified
* locking through mlock or plock.
*
* pages_useclaim,pages_claimed : These two variables track the
- * cliam adjustments because of the protection changes on a segvn segment.
+ * claim adjustments because of the protection changes on a segvn segment.
*
* All these globals are protected by the same lock which protects availrmem.
*/
@@ -503,7 +503,7 @@ page_free_large_ctr(pgcnt_t npages)
}
/*
- * Add a physical chunk of memory to the system freee lists during startup.
+ * Add a physical chunk of memory to the system free lists during startup.
* Platform specific startup() allocates the memory for the page structs.
*
* num - number of page structures
@@ -670,7 +670,7 @@ page_lookup(vnode_t *vp, u_offset_t off, se_t se)
* Find a page representing the specified [vp, offset].
* We either return the one we found or, if passed in,
* create one with identity of [vp, offset] of the
- * pre-allocated page. If we find exsisting page but it is
+ * pre-allocated page. If we find existing page but it is
* intransit coming in, it will have an "exclusive" lock
* and we wait for the i/o to complete. A page found on
* the free list is always reclaimed and then locked.
@@ -1466,7 +1466,7 @@ page_create_throttle(pgcnt_t npages, int flags)
}
/*
- * page_create_wait() is called to either coalecse pages from the
+ * page_create_wait() is called to either coalesce pages from the
* different pcf buckets or to wait because there simply are not
* enough pages to satisfy the caller's request.
*
@@ -2410,7 +2410,7 @@ page_create_va(vnode_t *vp, u_offset_t off, size_t bytes, uint_t flags,
if (!enough) {
/*
* Have to look harder. If npages is greater than
- * one, then we might have to coalecse the counters.
+ * one, then we might have to coalesce the counters.
*
* Go wait. We come back having accounted
* for the memory.
@@ -4394,7 +4394,7 @@ page_busy(int cleanit)
VN_HOLD(vp);
page_unlock(pp);
(void) VOP_PUTPAGE(vp, off, PAGESIZE,
- B_ASYNC | B_FREE, kcred);
+ B_ASYNC | B_FREE, kcred, NULL);
VN_RELE(vp);
}
} while ((pp = page_next(pp)) != page0);
@@ -4527,7 +4527,7 @@ top:
* if this putpage fails.
*/
(void) VOP_PUTPAGE(vp, offset, PAGESIZE, B_INVAL,
- kcred);
+ kcred, NULL);
VN_RELE(vp);
} else {
page_destroy(pp, 0);
@@ -4542,7 +4542,7 @@ top:
/*
* Replace the page "old" with the page "new" on the page hash and vnode lists
*
- * the replacemnt must be done in place, ie the equivalent sequence:
+ * the replacement must be done in place, ie the equivalent sequence:
*
* vp = old->p_vnode;
* off = old->p_offset;
@@ -4690,7 +4690,7 @@ page_relocate_hash(page_t *pp_new, page_t *pp_old)
*
* Returns 1 on success, 0 on failure.
*
- * If success is returned this routine gurantees p_szc for all constituent
+ * If success is returned this routine guarantees p_szc for all constituent
* pages of a large page pp belongs to can't change. To achieve this we
* recheck szc of pp after locking all constituent pages and retry if szc
* changed (it could only decrease). Since hat_page_demote() needs an EXCL
@@ -4698,7 +4698,7 @@ page_relocate_hash(page_t *pp_new, page_t *pp_old)
* pages are locked. hat_page_demote() with a lock on a constituent page
* outside of this large page (i.e. pp belonged to a larger large page) is
* already done with all constituent pages of pp since the root's p_szc is
- * changed last. Thefore no need to synchronize with hat_page_demote() that
+ * changed last. Therefore no need to synchronize with hat_page_demote() that
* locked a constituent page outside of pp's current large page.
*/
#ifdef DEBUG
@@ -5335,7 +5335,7 @@ page_try_demote_pages(page_t *pp)
* cache). However file system pages can be truncated or invalidated at a
* PAGESIZE level from the file system side and end up in page_free() or
* page_destroy() (we also allow only part of the large page to be SOFTLOCKed
- * and therfore pageout should be able to demote a large page by EXCL locking
+ * and therefore pageout should be able to demote a large page by EXCL locking
* any constituent page that is not under SOFTLOCK). In those cases we cannot
* rely on being able to lock EXCL all constituent pages.
*
@@ -5354,9 +5354,9 @@ page_try_demote_pages(page_t *pp)
*
* This routine calls page_szc_lock() before calling hat_page_demote() to
* allow segvn in one special case not to lock all constituent pages SHARED
- * before calling hat_memload_array() that relies on p_szc not changeing even
+ * before calling hat_memload_array() that relies on p_szc not changing even
* before hat level mlist lock is taken. In that case segvn uses
- * page_szc_lock() to prevent hat_page_demote() changeing p_szc values.
+ * page_szc_lock() to prevent hat_page_demote() changing p_szc values.
*
* Anonymous or kernel page demotion still has to lock all pages exclusively
* and do hat_pageunload() on all constituent pages before demoting the page
@@ -5371,7 +5371,7 @@ page_try_demote_pages(page_t *pp)
* pages within szc 1 area to prevent szc changes because hat_page_demote()
* that started on this page when it had szc > 1 is done for this szc 1 area.
*
- * We are guranteed that all constituent pages of pp's large page belong to
+ * We are guaranteed that all constituent pages of pp's large page belong to
* the same vnode with the consecutive offsets increasing in the direction of
* the pfn i.e. the identity of constituent pages can't change until their
* p_szc is decreased. Therefore it's safe for hat_page_demote() to remove
@@ -5443,7 +5443,7 @@ page_mark_migrate(struct seg *seg, caddr_t addr, size_t len,
len = P2ROUNDUP(len, segpgsz);
/*
- * Allocate page array to accomodate largest page size
+ * Allocate page array to accommodate largest page size
*/
pgsz = page_get_pagesize(page_num_pagesizes() - 1);
ppa_nentries = btop(pgsz);
diff --git a/usr/src/uts/common/vm/vm_rm.c b/usr/src/uts/common/vm/vm_rm.c
index 36cd5f0375..eb920214f7 100644
--- a/usr/src/uts/common/vm/vm_rm.c
+++ b/usr/src/uts/common/vm/vm_rm.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -118,7 +117,8 @@ rm_assize(struct as *as)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, addr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, ATTR_HINT, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, ATTR_HINT,
+ CRED(), NULL) == 0) {
u_offset_t filesize = vattr.va_size;
u_offset_t offset = SEGOP_GETOFFSET(seg, addr);
diff --git a/usr/src/uts/common/vm/vm_swap.c b/usr/src/uts/common/vm/vm_swap.c
index d7028b6f29..d39c85f069 100644
--- a/usr/src/uts/common/vm/vm_swap.c
+++ b/usr/src/uts/common/vm/vm_swap.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -653,7 +652,7 @@ lout:
if (vp->v_vfsp && vn_is_readonly(vp))
error = EROFS;
else
- error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED());
+ error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL);
break;
case VDIR:
@@ -858,7 +857,7 @@ lout:
if (vp->v_vfsp && vn_is_readonly(vp))
error = EROFS;
else
- error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED());
+ error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL);
break;
case VDIR:
@@ -918,7 +917,7 @@ swapadd(struct vnode *vp, ulong_t lowblk, ulong_t nblks, char *swapname)
mutex_exit(&cvp->v_lock);
mutex_enter(&swap_lock);
- if (error = VOP_OPEN(&cvp, FREAD|FWRITE, CRED())) {
+ if (error = VOP_OPEN(&cvp, FREAD|FWRITE, CRED(), NULL)) {
mutex_exit(&swap_lock);
/* restore state of v_flag */
if (!wasswap) {
@@ -939,7 +938,7 @@ swapadd(struct vnode *vp, ulong_t lowblk, ulong_t nblks, char *swapname)
* on a machine with a different size swap partition.
*/
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(cvp, &vattr, ATTR_COMM, CRED()))
+ if (error = VOP_GETATTR(cvp, &vattr, ATTR_COMM, CRED(), NULL))
goto out;
/*
@@ -973,7 +972,8 @@ swapadd(struct vnode *vp, ulong_t lowblk, ulong_t nblks, char *swapname)
goto out;
/* Fail if fs does not support VOP_PAGEIO */
- error = VOP_PAGEIO(cvp, (page_t *)NULL, (u_offset_t)0, 0, 0, CRED());
+ error = VOP_PAGEIO(cvp, (page_t *)NULL, (u_offset_t)0, 0, 0, CRED(),
+ NULL);
if (error == ENOSYS)
goto out;
@@ -1165,7 +1165,8 @@ out:
kmem_free(nsip, sizeof (*nsip));
}
mutex_enter(&swap_lock);
- (void) VOP_CLOSE(cvp, FREAD|FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(cvp, FREAD|FWRITE, 1, (offset_t)0, CRED(),
+ NULL);
mutex_exit(&swap_lock);
}
return (error);
@@ -1361,7 +1362,7 @@ top:
/* Release the vnode */
mutex_enter(&swap_lock);
- (void) VOP_CLOSE(cvp, FREAD|FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(cvp, FREAD|FWRITE, 1, (offset_t)0, CRED(), NULL);
mutex_enter(&cvp->v_lock);
cvp->v_flag &= ~VISSWAP;
mutex_exit(&cvp->v_lock);
@@ -1391,7 +1392,7 @@ swapslot_free(
* Users of the physical slot will synchronize on the i/o lock.
*/
if (error = VOP_GETPAGE(vp, (offset_t)off, ptob(1), NULL,
- pl, ptob(1), segkmap, NULL, S_READ, CRED())) {
+ pl, ptob(1), segkmap, NULL, S_READ, CRED(), NULL)) {
/*
* Anon slot went away (EIDRM) or vp was truncated (EFAULT)
* while we got the page. Thus the physical slot must be
diff --git a/usr/src/uts/common/vm/vpm.c b/usr/src/uts/common/vm/vpm.c
index 935680d600..5cb72b628f 100644
--- a/usr/src/uts/common/vm/vpm.c
+++ b/usr/src/uts/common/vm/vpm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -237,7 +237,7 @@ vpm_init()
* Use prefetch as we have to walk thru a large number of
* these data structures. We just use the smap's prefetch
* routine as it does the same. This should work fine
- * for x64(this needs to be modifed when enabled on sparc).
+ * for x64(this needs to be modified when enabled on sparc).
*/
prefetch_smap_w((void *)vpm);
@@ -866,7 +866,7 @@ vpm_map_pages(
base = segkpm_create_va(baseoff);
error = VOP_GETPAGE(vp, baseoff, len, &prot, &pplist[i],
- len, segkmap, base, rw, CRED());
+ len, segkmap, base, rw, CRED(), NULL);
if (error) {
VPM_DEBUG(vpmd_getpagefailed);
pplist[i] = NULL;
@@ -1070,7 +1070,7 @@ vpm_sync_pages(struct vnode *vp,
if (flags & SM_DONTNEED)
bflags |= B_DONTNEED;
- error = VOP_PUTPAGE(vp, off, psize, bflags, CRED());
+ error = VOP_PUTPAGE(vp, off, psize, bflags, CRED(), NULL);
}
return (error);
diff --git a/usr/src/uts/i86xpv/vm/seg_mf.c b/usr/src/uts/i86xpv/vm/seg_mf.c
index 7c042ad137..8364349911 100644
--- a/usr/src/uts/i86xpv/vm/seg_mf.c
+++ b/usr/src/uts/i86xpv/vm/seg_mf.c
@@ -105,7 +105,7 @@ segmf_create(struct seg *seg, void *args)
data->mfns[i] = MFN_INVALID;
error = VOP_ADDMAP(VTOCVP(data->vp), 0, as, seg->s_base, seg->s_size,
- data->prot, data->maxprot, MAP_SHARED, CRED());
+ data->prot, data->maxprot, MAP_SHARED, CRED(), NULL);
if (error != 0)
hat_unload(as->a_hat,
@@ -136,7 +136,7 @@ segmf_dup(struct seg *seg, struct seg *newseg)
return (VOP_ADDMAP(VTOCVP(ndata->vp), 0, newseg->s_as,
newseg->s_base, newseg->s_size, ndata->prot, ndata->maxprot,
- MAP_SHARED, CRED()));
+ MAP_SHARED, CRED(), NULL));
}
/*
@@ -164,7 +164,7 @@ segmf_unmap(struct seg *seg, caddr_t addr, size_t len)
ASSERT(data->vp != NULL);
(void) VOP_DELMAP(VTOCVP(data->vp), off, seg->s_as, addr, len,
- data->prot, data->maxprot, MAP_SHARED, CRED());
+ data->prot, data->maxprot, MAP_SHARED, CRED(), NULL);
seg_free(seg);
return (0);
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index 4602092e15..b6568504fe 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -302,6 +302,7 @@ DRV_KMODS += sgen
DRV_KMODS += si3124
DRV_KMODS += smbios
DRV_KMODS += spdsock
+DRV_KMODS += smbsrv
DRV_KMODS += sppp
DRV_KMODS += sppptun
DRV_KMODS += st
diff --git a/usr/src/uts/intel/os/minor_perm b/usr/src/uts/intel/os/minor_perm
index 1182263005..435e1d6756 100644
--- a/usr/src/uts/intel/os/minor_perm
+++ b/usr/src/uts/intel/os/minor_perm
@@ -114,6 +114,7 @@ bmc:bmc 0666 root sys
dld:* 0666 root sys
aggr:* 0666 root sys
smbios:smbios 0444 root sys
+smbsrv:* 0640 root sys
zfs:* 0600 root sys
zfs:zfs 0666 root sys
scsi_vhci:* 0666 root sys
diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major
index 28810d57b0..aa5a760625 100644
--- a/usr/src/uts/intel/os/name_to_major
+++ b/usr/src/uts/intel/os/name_to_major
@@ -129,6 +129,7 @@ domcaps 200
balloon 201
acpippm 202
srn 203
+smbsrv 210
did 239
lx_ptm 240
lx_systrace 241
diff --git a/usr/src/uts/intel/smbsrv/Makefile b/usr/src/uts/intel/smbsrv/Makefile
new file mode 100644
index 0000000000..f8482ba8ce
--- /dev/null
+++ b/usr/src/uts/intel/smbsrv/Makefile
@@ -0,0 +1,100 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the cifs server file system
+# kernel module.
+#
+# intel implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = smbsrv
+OBJECTS = $(SMBSRV_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(SMBSRV_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/common/fs/smbsrv
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+# Module dependencies
+#
+#
+LDFLAGS += -dy -Nfs/sockfs -Ndrv/ip -Nstrmod/rpcmod -Nsys/doorfs -Nmisc/kcf
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE)
+
+#
+# Overrides.
+#
+MODSTUBS_DIR = $(OBJS_DIR)
+CLEANFILES += $(MODSTUBS_O)
+
+INC_PATH += -I$(SRC)/common
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+$(ROOTLINK): $(ROOT_SYS_DIR) $(ROOTMODULE)
+ -$(RM) $@; ln $(ROOTMODULE) $@
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
diff --git a/usr/src/uts/intel/zfs/Makefile b/usr/src/uts/intel/zfs/Makefile
index 5239b2cbf7..c9596a4eef 100644
--- a/usr/src/uts/intel/zfs/Makefile
+++ b/usr/src/uts/intel/zfs/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -60,7 +60,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE)
# Overrides and depends_on
#
MODSTUBS_DIR = $(OBJS_DIR)
-LDFLAGS += -dy -Nfs/specfs -Ndrv/random
+LDFLAGS += -dy -Nfs/specfs -Ndrv/random -Nmisc/idmap
INC_PATH += -I$(UTSBASE)/common/fs/zfs
INC_PATH += -I$(SRC)/common
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 694538725e..35ced8cc25 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -241,6 +241,7 @@ DRV_KMODS += vni vnic
DRV_KMODS += xge
DRV_KMODS += rds
DRV_KMODS += chxge
+DRV_KMODS += smbsrv
#
# Don't build some of these for OpenSolaris, since they will be
diff --git a/usr/src/uts/sparc/os/minor_perm b/usr/src/uts/sparc/os/minor_perm
index 21b3b4d1ce..1106dea0aa 100644
--- a/usr/src/uts/sparc/os/minor_perm
+++ b/usr/src/uts/sparc/os/minor_perm
@@ -74,6 +74,7 @@ sd:* 0640 root sys
dad:* 0640 root sys
sdt:sdt 0644 root sys
sgen:* 0600 root sys
+smbsrv:* 0640 root sys
ssd:* 0640 root sys
st:* 0666 root sys
su:[a-z] 0666 root sys
diff --git a/usr/src/uts/sparc/os/name_to_major b/usr/src/uts/sparc/os/name_to_major
index 82d40a46e8..eced54e622 100644
--- a/usr/src/uts/sparc/os/name_to_major
+++ b/usr/src/uts/sparc/os/name_to_major
@@ -149,6 +149,7 @@ bscbus 198
bscv 199
i2bsc 200
mc-us3i 201
+smbsrv 202
rmc_comm 203
rmclomv 204
rmcadm 205
diff --git a/usr/src/uts/sparc/smbsrv/Makefile b/usr/src/uts/sparc/smbsrv/Makefile
new file mode 100644
index 0000000000..71c4cc5398
--- /dev/null
+++ b/usr/src/uts/sparc/smbsrv/Makefile
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# This makefile drives the production of the cifs server file system
+# kernel module.
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = smbsrv
+OBJECTS = $(SMBSRV_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(SMBSRV_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/common/fs/smbsrv
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+# Module dependencies
+#
+LDFLAGS += -dy -Nfs/sockfs -Ndrv/ip -Nstrmod/rpcmod -Nsys/doorfs -Nmisc/kcf
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE)
+
+#
+# Overrides.
+#
+MODSTUBS_DIR = $(OBJS_DIR)
+CLEANFILES += $(MODSTUBS_O)
+
+INC_PATH += -I$(SRC)/common
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+$(ROOTLINK): $(ROOT_SYS_DIR) $(ROOTMODULE)
+ -$(RM) $@; ln $(ROOTMODULE) $@
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
diff --git a/usr/src/uts/sparc/zfs/Makefile b/usr/src/uts/sparc/zfs/Makefile
index 5239b2cbf7..c9596a4eef 100644
--- a/usr/src/uts/sparc/zfs/Makefile
+++ b/usr/src/uts/sparc/zfs/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -60,7 +60,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE)
# Overrides and depends_on
#
MODSTUBS_DIR = $(OBJS_DIR)
-LDFLAGS += -dy -Nfs/specfs -Ndrv/random
+LDFLAGS += -dy -Nfs/specfs -Ndrv/random -Nmisc/idmap
INC_PATH += -I$(UTSBASE)/common/fs/zfs
INC_PATH += -I$(SRC)/common
diff --git a/usr/src/uts/sun4u/montecarlo/io/ttymux_dacf/ttymux_dacf.c b/usr/src/uts/sun4u/montecarlo/io/ttymux_dacf/ttymux_dacf.c
index c02a9984e7..4e08be6d8d 100644
--- a/usr/src/uts/sun4u/montecarlo/io/ttymux_dacf/ttymux_dacf.c
+++ b/usr/src/uts/sun4u/montecarlo/io/ttymux_dacf/ttymux_dacf.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -536,7 +535,7 @@ fs_devtype(char *fspath)
return (NODEV);
} else {
dev = vp->v_rdev;
- VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (dev);
}
@@ -568,7 +567,7 @@ open_stream(vnode_t **vp, int *fd, dev_t dev)
/* create a vnode for the device and open it */
*vp = makespecvp(dev, VCHR);
- if ((rv = VOP_OPEN(vp, FREAD+FWRITE+FNOCTTY, CRED())) != 0) {
+ if ((rv = VOP_OPEN(vp, FREAD+FWRITE+FNOCTTY, CRED(), NULL)) != 0) {
goto out2;
}
/* Associate a file pointer with the vnode */
@@ -586,7 +585,7 @@ open_stream(vnode_t **vp, int *fd, dev_t dev)
return (0);
out1:
- VOP_CLOSE(*vp, FREAD+FWRITE+FNOCTTY, 1, (offset_t)0, CRED());
+ VOP_CLOSE(*vp, FREAD+FWRITE+FNOCTTY, 1, (offset_t)0, CRED(), NULL);
out2:
VN_RELE(*vp);
return (rv);
@@ -669,7 +668,7 @@ link_aconsole(vnode_t *mux_avp, sm_console_t *cn)
return (rv);
out:
- VOP_CLOSE(lvp, FREAD+FWRITE+FNOCTTY, 1, (offset_t)0, CRED());
+ VOP_CLOSE(lvp, FREAD+FWRITE+FNOCTTY, 1, (offset_t)0, CRED(), NULL);
VN_RELE(lvp);
return (rv);
}
@@ -905,12 +904,12 @@ ttymux_config(dacf_infohdl_t info_hdl, dacf_arghdl_t arg_hdl, int flags)
muxvp = dacf_makevp(info_hdl);
- if ((rv = VOP_OPEN(&muxvp, OFLAGS, CRED())) == 0) {
+ if ((rv = VOP_OPEN(&muxvp, OFLAGS, CRED(), NULL)) == 0) {
(void) enable_all_consoles(ms, muxvp);
(void) usable_consoles(ms, &icnt, &ocnt);
- VOP_CLOSE(muxvp, OFLAGS, 1, (offset_t)0, CRED());
+ VOP_CLOSE(muxvp, OFLAGS, 1, (offset_t)0, CRED(), NULL);
VN_RELE(muxvp);
} else {
ttymux_dprintf(DPRINT_L3,
diff --git a/usr/src/uts/sun4u/os/cpr_impl.c b/usr/src/uts/sun4u/os/cpr_impl.c
index e0c6a4b2d8..b08f6660e3 100644
--- a/usr/src/uts/sun4u/os/cpr_impl.c
+++ b/usr/src/uts/sun4u/os/cpr_impl.c
@@ -229,7 +229,7 @@ i_cpr_mp_setup(void)
/*
* Do not allow setting page size codes in MMU primary context
* register while using cif wrapper. This is needed to work
- * arround OBP incorrect handling of this MMU register.
+ * around OBP incorrect handling of this MMU register.
*/
kcontextreg = 0;
@@ -1421,7 +1421,7 @@ i_cpr_reusefini(void)
}
}
- (void) VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
kmem_free(cdef, sizeof (*cdef));
@@ -1473,7 +1473,7 @@ i_cpr_check_cprinfo(void)
}
rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini));
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (rc) {
diff --git a/usr/src/uts/sun4v/io/vds.c b/usr/src/uts/sun4v/io/vds.c
index 14afdb7a64..525d8c8529 100644
--- a/usr/src/uts/sun4v/io/vds.c
+++ b/usr/src/uts/sun4v/io/vds.c
@@ -1270,7 +1270,7 @@ vd_reset_if_needed(vd_t *vd)
ddi_taskq_wait(vd->completionq);
if (vd->file) {
- status = VOP_FSYNC(vd->file_vnode, FSYNC, kcred);
+ status = VOP_FSYNC(vd->file_vnode, FSYNC, kcred, NULL);
if (status) {
PR0("VOP_FSYNC returned errno %d", status);
}
@@ -1982,7 +1982,7 @@ vd_do_file_ioctl(vd_t *vd, int cmd, void *ioctl_arg)
return (0);
case DKIOCFLUSHWRITECACHE:
- return (VOP_FSYNC(vd->file_vnode, FSYNC, kcred));
+ return (VOP_FSYNC(vd->file_vnode, FSYNC, kcred, NULL));
default:
return (ENOTSUP);
@@ -2550,7 +2550,7 @@ vd_process_ver_msg(vd_t *vd, vio_msg_t *msg, size_t msglen)
* the negotiated major and minor version values in the "vd" data
* structure to govern further communication; in particular, note that
* the client might have specified a lower minor version for the
- * agreed major version than specifed in the vds_version[] array. The
+ * agreed major version than specified in the vds_version[] array. The
* following assertions should help remind future maintainers to make
* the appropriate changes to support multiple versions.
*/
@@ -3758,7 +3758,8 @@ vd_setup_backend_vnode(vd_t *vd)
vd->file = B_TRUE;
vattr.va_mask = AT_SIZE;
- if ((status = VOP_GETATTR(vd->file_vnode, &vattr, 0, kcred)) != 0) {
+ if ((status = VOP_GETATTR(vd->file_vnode, &vattr, 0, kcred, NULL))
+ != 0) {
PRN("VOP_GETATTR(%s) = errno %d", file_path, status);
return (EIO);
}
@@ -4376,10 +4377,11 @@ vds_destroy_vd(void *arg)
kmem_free(vd->inband_task.msg, vd->max_msglen);
vd->inband_task.msg = NULL;
}
+
if (vd->file) {
/* Close file */
(void) VOP_CLOSE(vd->file_vnode, vd->open_flags, 1,
- 0, kcred);
+ 0, kcred, NULL);
VN_RELE(vd->file_vnode);
if (vd->file_devid != NULL)
ddi_devid_free(vd->file_devid);