diff options
| author | amw <none@none> | 2007-10-25 16:34:29 -0700 |
|---|---|---|
| committer | amw <none@none> | 2007-10-25 16:34:29 -0700 |
| commit | da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch) | |
| tree | 65be91fb78a6a66183197595333f2e8aafb4640a /usr/src/uts/common | |
| parent | e845e33dd0d1aea22db7edaa8c7d43955d24609b (diff) | |
| download | illumos-gate-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
Diffstat (limited to 'usr/src/uts/common')
452 files changed, 89986 insertions, 5361 deletions
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, + ¶m.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, ¶m)) != 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, + ¶m.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, ¶m)) != 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, ¶m.r_count, ¶m.r_mincnt, + &timeout); + param.r_offset = (uint64_t)off_low; + } else { + rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid, + &off_low, ¶m.r_count, ¶m.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, ¶m); + /* + * 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, ¶m.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, ¶m.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, ¶m)) != 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, ¶m->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", ¶m->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, + ¶m->w_count, &off, &last_write); + } else { + rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, + ¶m->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, + ¶m->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, ¶m->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", ¶m->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, ¶m->w_mode, &remcnt, ¶m->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, ¶m->w_mode, &remcnt, ¶m->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, + ¶m->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, + ¶m->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, ¶m->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, ×, &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); |
