diff options
author | jose borrego <Jose.Borrego@Sun.COM> | 2009-02-27 17:10:20 -0700 |
---|---|---|
committer | jose borrego <Jose.Borrego@Sun.COM> | 2009-02-27 17:10:20 -0700 |
commit | 2c2961f8403049d948b9f3e6c35d6488b6b7e1aa (patch) | |
tree | 9a3b5e85cf05528de14661b9c54a18a80ac78325 /usr/src/uts/common/fs/smbsrv | |
parent | 8475e04352e630e4bd0f59a283286ee2475a14ce (diff) | |
download | illumos-gate-2c2961f8403049d948b9f3e6c35d6488b6b7e1aa.tar.gz |
6709704 smbtorture RAW-BENCH-OPLOCK test fails (when oplocks enabled)
6800443 ReadX and WriteX should support CAP_LARGE_READX and CAP_LARGE_WRITEX
--HG--
rename : usr/src/uts/common/fs/smbsrv/smb_create_directory.c => usr/src/uts/common/fs/smbsrv/smb_directory.c
Diffstat (limited to 'usr/src/uts/common/fs/smbsrv')
49 files changed, 2257 insertions, 1711 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb_check_directory.c b/usr/src/uts/common/fs/smbsrv/smb_check_directory.c deleted file mode 100644 index d9164ee988..0000000000 --- a/usr/src/uts/common/fs/smbsrv/smb_check_directory.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 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> - -smb_sdrc_t -smb_pre_check_directory(smb_request_t *sr) -{ - int rc; - - rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path); - - DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr, - struct dirop *, &sr->arg.dirop); - - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); -} - -void -smb_post_check_directory(smb_request_t *sr) -{ - DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr); -} - -smb_sdrc_t -smb_com_check_directory(smb_request_t *sr) -{ - int rc; - struct smb_node *dnode; - - if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { - smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, - ERROR_ACCESS_DENIED); - return (SDRC_ERROR); - } - - sr->arg.dirop.fqi.srch_attr = 0; - - rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST); - if (rc) { - smbsr_errno(sr, rc); - return (SDRC_ERROR); - } - - /* - * 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_errno(sr, ENOTDIR); - return (SDRC_ERROR); - } - - 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_error(sr, NT_STATUS_ACCESS_DENIED, - ERRDOS, ERROR_ACCESS_DENIED); - return (SDRC_ERROR); - } - - rc = smbsr_encode_empty_result(sr); - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); -} diff --git a/usr/src/uts/common/fs/smbsrv/smb_close.c b/usr/src/uts/common/fs/smbsrv/smb_close.c index 2394905d31..9babe9a3b1 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_close.c +++ b/usr/src/uts/common/fs/smbsrv/smb_close.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "@(#)smb_close.c 1.6 08/08/08 SMI" - #include <smbsrv/smb_incl.h> @@ -59,7 +57,7 @@ smb_post_close(smb_request_t *sr) smb_sdrc_t smb_com_close(smb_request_t *sr) { - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -97,7 +95,7 @@ smb_post_close_and_tree_disconnect(smb_request_t *sr) smb_sdrc_t smb_com_close_and_tree_disconnect(smb_request_t *sr) { - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c index 0deddbcaa5..2d8c165f39 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c +++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c @@ -117,10 +117,10 @@ smb_omode_to_amask(uint32_t desired_access) case SMB_DA_ACCESS_EXECUTE: return (FILE_GENERIC_EXECUTE); - } - /* invalid open mode */ - return ((uint32_t)SMB_INVALID_AMASK); + default: + return (FILE_GENERIC_ALL); + } } /* @@ -149,11 +149,9 @@ smb_denymode_to_sharemode(uint32_t desired_access, char *fname) return (FILE_SHARE_WRITE); case SMB_DA_SHARE_DENY_NONE: + default: return (FILE_SHARE_READ | FILE_SHARE_WRITE); } - - /* invalid deny mode */ - return ((uint32_t)SMB_INVALID_SHAREMODE); } /* @@ -176,7 +174,7 @@ smb_ofun_to_crdisposition(uint16_t ofun) int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4; if (row == 3) - return ((uint32_t)SMB_INVALID_CRDISPOSITION); + return (FILE_MAXIMUM_DISPOSITION + 1); return (ofun_cr_map[row][col]); } @@ -206,6 +204,11 @@ smb_common_open(smb_request_t *sr) ERRDOS, ERROR_SHARING_VIOLATION); } + if (status == NT_STATUS_NO_SUCH_FILE) { + smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERROR_FILE_NOT_FOUND); + } + return (status); } @@ -293,28 +296,27 @@ smb_common_open(smb_request_t *sr) * 4. Opening an existing file or directory * The request attributes are ignored. */ - static uint32_t smb_open_subr(smb_request_t *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; - uint32_t status = NT_STATUS_SUCCESS; - int is_dir; - smb_error_t err; - int is_stream = 0; - int lookup_flags = SMB_FOLLOW_LINKS; - uint32_t daccess; - uint32_t uniq_fid; + int created = 0; + smb_node_t *node = NULL; + smb_node_t *dnode = NULL; + smb_node_t *cur_node; + open_param_t *op = &sr->arg.open; + int rc; + smb_ofile_t *of; + smb_attr_t new_attr; + int pathlen; + int max_requested = 0; + uint32_t max_allowed; + uint32_t status = NT_STATUS_SUCCESS; + int is_dir; + smb_error_t err; + boolean_t is_stream = B_FALSE; + int lookup_flags = SMB_FOLLOW_LINKS; + uint32_t daccess; + uint32_t uniq_fid; is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0; @@ -479,7 +481,7 @@ smb_open_subr(smb_request_t *sr) } } else { if ((op->create_options & FILE_DIRECTORY_FILE) || - (op->my_flags & MYF_MUST_BE_DIRECTORY)) { + (op->nt_flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)) { smb_node_release(node); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); @@ -537,9 +539,10 @@ smb_open_subr(smb_request_t *sr) } if (smb_oplock_conflict(node, sr->session, op)) - smb_oplock_break(node); + (void) smb_oplock_break(node, + SMB_SESSION_GET_ID(sr->session), B_FALSE); - rw_enter(&node->n_share_lock, RW_WRITER); + smb_node_wrlock(node); if ((op->create_disposition == FILE_SUPERSEDE) || (op->create_disposition == FILE_OVERWRITE_IF) || @@ -549,8 +552,8 @@ smb_open_subr(smb_request_t *sr) (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) || (!smb_sattr_check(node->attr.sa_dosattr, - op->dattr, NULL))) { - rw_exit(&node->n_share_lock); + op->dattr))) { + smb_node_unlock(node); smb_node_release(node); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); @@ -564,7 +567,7 @@ smb_open_subr(smb_request_t *sr) op->desired_access, op->share_access); if (status == NT_STATUS_SHARING_VIOLATION) { - rw_exit(&node->n_share_lock); + smb_node_unlock(node); smb_node_release(node); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); @@ -577,7 +580,7 @@ smb_open_subr(smb_request_t *sr) if (status != NT_STATUS_SUCCESS) { smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); - rw_exit(&node->n_share_lock); + smb_node_unlock(node); smb_node_release(node); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); @@ -599,7 +602,7 @@ smb_open_subr(smb_request_t *sr) case FILE_OVERWRITE: if (node->attr.sa_vattr.va_type == VDIR) { smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); - rw_exit(&node->n_share_lock); + smb_node_unlock(node); smb_node_release(node); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); @@ -620,7 +623,7 @@ smb_open_subr(smb_request_t *sr) if (rc) { smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); - rw_exit(&node->n_share_lock); + smb_node_unlock(node); smb_node_release(node); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); @@ -659,7 +662,6 @@ smb_open_subr(smb_request_t *sr) break; } } else { - /* Last component was not found. */ dnode = op->fqi.dir_snode; @@ -675,11 +677,20 @@ smb_open_subr(smb_request_t *sr) return (NT_STATUS_OBJECT_NAME_NOT_FOUND); } + if ((is_dir == 0) && (!is_stream) && + smb_is_invalid_filename(op->fqi.last_comp)) { + smb_node_release(dnode); + SMB_NULL_FQI_NODES(op->fqi); + smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, + ERRDOS, ERROR_INVALID_NAME); + return (NT_STATUS_OBJECT_NAME_INVALID); + } + /* * 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); + smb_node_wrlock(dnode); bzero(&new_attr, sizeof (new_attr)); new_attr.sa_dosattr = op->dattr; @@ -722,7 +733,7 @@ smb_open_subr(smb_request_t *sr) &op->fqi.last_snode, &op->fqi.last_attr); if (rc != 0) { - smb_rwx_rwexit(&dnode->n_lock); + smb_node_unlock(dnode); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); smbsr_errno(sr, rc); @@ -733,16 +744,16 @@ smb_open_subr(smb_request_t *sr) op->fqi.last_attr = node->attr; - rw_enter(&node->n_share_lock, RW_WRITER); + smb_node_wrlock(node); status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid, op->desired_access, op->share_access); if (status == NT_STATUS_SHARING_VIOLATION) { - rw_exit(&node->n_share_lock); - smb_rwx_rwexit(&dnode->n_lock); + smb_node_unlock(node); SMB_DEL_NEWOBJ(op->fqi); smb_node_release(node); + smb_node_unlock(dnode); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); return (status); @@ -757,7 +768,7 @@ smb_open_subr(smb_request_t *sr) 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_unlock(dnode); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); smbsr_errno(sr, rc); @@ -765,7 +776,7 @@ smb_open_subr(smb_request_t *sr) } node = op->fqi.last_snode; - rw_enter(&node->n_share_lock, RW_WRITER); + smb_node_wrlock(node); } created = 1; @@ -808,44 +819,16 @@ smb_open_subr(smb_request_t *sr) smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); SMB_DEL_NEWOBJ(op->fqi); - rw_exit(&node->n_share_lock); + smb_node_unlock(node); smb_node_release(node); if (created) - smb_rwx_rwexit(&dnode->n_lock); + smb_node_unlock(dnode); smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); smbsr_error(sr, err.status, err.errcls, err.errcode); return (err.status); } - if (op->fqi.last_attr.sa_vattr.va_type == VREG) { - status = smb_oplock_acquire(sr, of, op); - - if (status != NT_STATUS_SUCCESS) { - rw_exit(&node->n_share_lock); - /* - * smb_fsop_unshrlock() and smb_fsop_close() - * are called from smb_ofile_close() - */ - 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_error(sr, status, - ERRDOS, ERROR_SHARING_VIOLATION); - return (status); - } - - op->dsize = op->fqi.last_attr.sa_vattr.va_size; - } else { /* VDIR or VLNK */ - op->my_flags &= ~MYF_OPLOCK_MASK; - op->dsize = 0; - } - /* * Propagate the write-through mode from the open params * to the node: see the notes in the function header. @@ -863,10 +846,18 @@ smb_open_subr(smb_request_t *sr) sr->smb_fid = of->f_fid; sr->fid_ofile = of; - rw_exit(&node->n_share_lock); + smb_node_unlock(node); if (created) - smb_rwx_rwexit(&dnode->n_lock); + smb_node_unlock(dnode); + + if (op->fqi.last_attr.sa_vattr.va_type == VREG) { + smb_oplock_acquire(node, of, op); + op->dsize = op->fqi.last_attr.sa_vattr.va_size; + } else { /* VDIR or VLNK */ + op->op_oplock_level = SMB_OPLOCK_NONE; + op->dsize = 0; + } smb_node_release(dnode); SMB_NULL_FQI_NODES(op->fqi); diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c index dd40d6acbf..2daa29a306 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c +++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c @@ -19,9 +19,8 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * */ #include <smbsrv/smb_incl.h> @@ -1373,7 +1372,7 @@ smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa) uint16_t devstate; char *req_fmt; char *rep_fmt; - struct vardata_block vdb; + smb_vdb_t vdb; n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200; n_setup++; @@ -1403,8 +1402,7 @@ smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa) break; case TRANS_TRANSACT_NMPIPE: - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, - sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); @@ -1416,7 +1414,7 @@ smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa) if (rc != 0) goto trans_err_not_supported; - rc = smb_opipe_transact(sr, &vdb.uio); + rc = smb_opipe_transact(sr, &vdb.vdb_uio); break; case TRANS_WAIT_NMPIPE: @@ -1586,6 +1584,10 @@ smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa) /* for now, only respond to the */ switch (opcode) { + case TRANS2_OPEN2: + rc = smb_com_trans2_open2(sr, xa); + break; + case TRANS2_CREATE_DIRECTORY: rc = smb_com_trans2_create_directory(sr, xa); break; @@ -1663,6 +1665,7 @@ smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa) rc = smb_com_trans2_set_file_information(sr, xa); break; default: + (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); goto trans_err_not_supported; } diff --git a/usr/src/uts/common/fs/smbsrv/smb_create.c b/usr/src/uts/common/fs/smbsrv/smb_create.c index b2e1090136..bb8ce0e9e1 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_create.c +++ b/usr/src/uts/common/fs/smbsrv/smb_create.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -186,30 +186,23 @@ smb_common_create(smb_request_t *sr) if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) op->mtime.tv_sec = smb_local2gmt(sr, op->mtime.tv_sec); op->mtime.tv_nsec = 0; + op->dsize = 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_error(sr, NT_STATUS_INVALID_PARAMETER, - ERRDOS, ERROR_INVALID_PARAMETER); - return (NT_STATUS_INVALID_PARAMETER); - } - - 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; - } + if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) + op->op_oplock_level = SMB_OPLOCK_BATCH; + else + op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; + } else { + op->op_oplock_level = SMB_OPLOCK_NONE; } status = smb_common_open(sr); - if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) { + if (op->op_oplock_level == SMB_OPLOCK_NONE) { sr->smb_flg &= ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_create_directory.c b/usr/src/uts/common/fs/smbsrv/smb_create_directory.c deleted file mode 100644 index cd2c5c242d..0000000000 --- a/usr/src/uts/common/fs/smbsrv/smb_create_directory.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * 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 { - char *sp_path; /* Original path */ - char *sp_curp; /* Current pointer into the original path */ - smb_request_t *sp_sr; /* Current request pointer */ -} SmbPath; - - -static int smbpath_next(SmbPath *spp); -static SmbPath* smbpath_new(smb_request_t *sr); - -smb_sdrc_t -smb_pre_create_directory(smb_request_t *sr) -{ - int rc; - - rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path); - - DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr, - struct dirop *, &sr->arg.dirop); - - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); -} - -void -smb_post_create_directory(smb_request_t *sr) -{ - DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, 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. - */ -smb_sdrc_t -smb_com_create_directory(smb_request_t *sr) -{ - SmbPath* spp; - DWORD status; - int rc = 0; - - if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { - smbsr_error(sr, NT_STATUS_ACCESS_DENIED, - ERRDOS, ERROR_ACCESS_DENIED); - return (SDRC_ERROR); - } - - if ((status = smb_validate_dirname(sr->arg.dirop.fqi.path)) != 0) { - smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME); - return (SDRC_ERROR); - } - - /* - * 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_errno(sr, rc); - return (SDRC_ERROR); - } - } - - /* We should have created one directory successfully! */ - if (rc != 0) { - smbsr_errno(sr, rc); - return (SDRC_ERROR); - } - - rc = smbsr_encode_empty_result(sr); - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); -} - - -/* - * 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(smb_request_t *sr) -{ - int rc; - smb_attr_t new_attr; - struct smb_node *dnode; - struct smb_node *node; - - 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; - - /* - * Explicitly set sa_dosattr, otherwise the file system may - * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for - * compatibility with windows servers, should not be set. - */ - bzero(&new_attr, sizeof (new_attr)); - new_attr.sa_dosattr = FILE_ATTRIBUTE_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 | SMB_AT_DOSATTR; - - 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(smb_request_t *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 index 213f04650e..2b07ae3f94 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_delete.c +++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c @@ -484,7 +484,7 @@ smb_delete_remove_file(smb_request_t *sr, smb_error_t *err) fqi = &sr->arg.dirop.fqi; node = fqi->last_snode; - smb_oplock_break(node); + (void) smb_oplock_break(node, SMB_SESSION_GET_ID(sr->session), B_FALSE); smb_node_start_crit(node, RW_READER); diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c b/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c deleted file mode 100644 index ecf614ea80..0000000000 --- a/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "@(#)smb_delete_directory.c 1.5 08/08/04 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 - */ -smb_sdrc_t -smb_pre_delete_directory(smb_request_t *sr) -{ - int rc; - - rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path); - - DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr, - struct dirop *, &sr->arg.dirop); - - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); -} - -void -smb_post_delete_directory(smb_request_t *sr) -{ - DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr); -} - -smb_sdrc_t -smb_com_delete_directory(smb_request_t *sr) -{ - smb_node_t *dnode; - int rc; - - if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { - smbsr_error(sr, NT_STATUS_ACCESS_DENIED, - ERRDOS, ERROR_ACCESS_DENIED); - return (SDRC_ERROR); - } - - sr->arg.dirop.fqi.srch_attr = 0; - - rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST); - if (rc) { - smbsr_errno(sr, rc); - return (SDRC_ERROR); - } - - 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_error(sr, NT_STATUS_CANNOT_DELETE, - ERRDOS, ERROR_ACCESS_DENIED); - return (SDRC_ERROR); - } - - 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); - if (rc == EEXIST) - smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY, - ERRDOS, ERROR_DIR_NOT_EMPTY); - else - smbsr_errno(sr, rc); - return (SDRC_ERROR); - } - - smb_node_release(dnode); - SMB_NULL_FQI_NODES(sr->arg.dirop.fqi); - - rc = smbsr_encode_empty_result(sr); - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); -} diff --git a/usr/src/uts/common/fs/smbsrv/smb_directory.c b/usr/src/uts/common/fs/smbsrv/smb_directory.c new file mode 100644 index 0000000000..3960fd5514 --- /dev/null +++ b/usr/src/uts/common/fs/smbsrv/smb_directory.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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <smbsrv/nterror.h> +#include <smbsrv/ntstatus.h> +#include <smbsrv/smbinfo.h> +#include <smbsrv/smb_incl.h> +#include <smbsrv/smb_fsops.h> + +typedef struct smb_dirpath { + char *sp_path; /* Original path */ + char *sp_curp; /* Current pointer into the original path */ + smb_request_t *sp_sr; /* Current request pointer */ +} smb_dirpath_t; + +static smb_dirpath_t *smb_dirpath_new(smb_request_t *); +static int smb_dirpath_next(smb_dirpath_t *); +static boolean_t smb_dirpath_isvalid(const char *); + +/* + * 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 + */ +smb_sdrc_t +smb_pre_create_directory(smb_request_t *sr) +{ + int rc; + + rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path); + + DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr, + struct dirop *, &sr->arg.dirop); + + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); +} + +void +smb_post_create_directory(smb_request_t *sr) +{ + DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, 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. + */ +smb_sdrc_t +smb_com_create_directory(smb_request_t *sr) +{ + smb_dirpath_t *spp; + smb_attr_t *attr; + DWORD status; + int rc = 0; + + if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, + ERRDOS, ERROR_ACCESS_DENIED); + return (SDRC_ERROR); + } + + if (!smb_dirpath_isvalid(sr->arg.dirop.fqi.path)) { + smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, + ERRDOS, ERROR_BAD_PATHNAME); + return (SDRC_ERROR); + } + + if ((status = smb_validate_dirname(sr->arg.dirop.fqi.path)) != 0) { + smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME); + return (SDRC_ERROR); + } + + /* + * Try each component of the path. EEXIST on path + * components is okay except on the last one. + */ + spp = smb_dirpath_new(sr); + + while (smb_dirpath_next(spp)) { + rc = smb_common_create_directory(sr); + + switch (rc) { + case 0: + break; + case EEXIST: + attr = &sr->arg.dirop.fqi.last_attr; + + if (attr->sa_vattr.va_type != VDIR) { + smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION, + ERRDOS, ERROR_PATH_NOT_FOUND); + return (SDRC_ERROR); + } + break; + case ENOENT: + smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERROR_FILE_NOT_FOUND); + return (SDRC_ERROR); + case ENOTDIR: + smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, + ERRDOS, ERROR_PATH_NOT_FOUND); + return (SDRC_ERROR); + default: + smbsr_errno(sr, rc); + return (SDRC_ERROR); + } + } + + if (rc != 0) { + smbsr_errno(sr, rc); + return (SDRC_ERROR); + } + + rc = smbsr_encode_empty_result(sr); + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); +} + +/* + * 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(smb_request_t *sr) +{ + int rc; + smb_attr_t new_attr; + smb_node_t *dnode; + smb_node_t *node; + + 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; + + rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_ADD_SUBDIRECTORY); + if (rc != NT_STATUS_SUCCESS) + return (EACCES); + + /* + * Explicitly set sa_dosattr, otherwise the file system may + * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for + * compatibility with windows servers, should not be set. + */ + bzero(&new_attr, sizeof (new_attr)); + new_attr.sa_dosattr = FILE_ATTRIBUTE_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 | SMB_AT_DOSATTR; + + 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); +} + +static smb_dirpath_t * +smb_dirpath_new(smb_request_t *sr) +{ + int pathLen; + char *xpath; + smb_dirpath_t *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 (smb_dirpath_t)); + 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. + */ +static int +smb_dirpath_next(smb_dirpath_t *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); +} + +/* + * 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 + */ +smb_sdrc_t +smb_pre_delete_directory(smb_request_t *sr) +{ + int rc; + + rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path); + + DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr, + struct dirop *, &sr->arg.dirop); + + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); +} + +void +smb_post_delete_directory(smb_request_t *sr) +{ + DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr); +} + +smb_sdrc_t +smb_com_delete_directory(smb_request_t *sr) +{ + smb_node_t *dnode; + smb_attr_t *attr; + int rc; + + if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, + ERRDOS, ERROR_ACCESS_DENIED); + return (SDRC_ERROR); + } + + sr->arg.dirop.fqi.srch_attr = 0; + + rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST); + if (rc) { + if (rc == ENOENT) + smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERROR_FILE_NOT_FOUND); + else + smbsr_errno(sr, rc); + return (SDRC_ERROR); + } + + attr = &sr->arg.dirop.fqi.last_attr; + if (attr->sa_vattr.va_type != VDIR) { + smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, + ERRDOS, ERROR_PATH_NOT_FOUND); + return (SDRC_ERROR); + } + + dnode = sr->arg.dirop.fqi.last_snode; + rc = smb_fsop_access(sr, sr->user_cr, dnode, DELETE); + + if ((rc != NT_STATUS_SUCCESS) || + (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_error(sr, NT_STATUS_CANNOT_DELETE, + ERRDOS, ERROR_ACCESS_DENIED); + return (SDRC_ERROR); + } + + 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); + if (rc == EEXIST) + smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY, + ERRDOS, ERROR_DIR_NOT_EMPTY); + else + smbsr_errno(sr, rc); + return (SDRC_ERROR); + } + + smb_node_release(dnode); + SMB_NULL_FQI_NODES(sr->arg.dirop.fqi); + + rc = smbsr_encode_empty_result(sr); + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); +} + +/* + * 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 ERRbadpath if the directory is + * not found. + */ +smb_sdrc_t +smb_pre_check_directory(smb_request_t *sr) +{ + int rc; + + rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path); + + DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr, + struct dirop *, &sr->arg.dirop); + + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); +} + +void +smb_post_check_directory(smb_request_t *sr) +{ + DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr); +} + +smb_sdrc_t +smb_com_check_directory(smb_request_t *sr) +{ + smb_node_t *dnode; + int rc; + + if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, + ERROR_ACCESS_DENIED); + return (SDRC_ERROR); + } + + if (sr->arg.dirop.fqi.path[0] == '\0') { + rc = smbsr_encode_empty_result(sr); + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); + } + + if (!smb_dirpath_isvalid(sr->arg.dirop.fqi.path)) { + smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, + ERRDOS, ERROR_PATH_NOT_FOUND); + return (SDRC_ERROR); + } + + sr->arg.dirop.fqi.srch_attr = 0; + + rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST); + if (rc) { + if (rc == ENOENT) + smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERROR_PATH_NOT_FOUND); + else + smbsr_errno(sr, rc); + return (SDRC_ERROR); + } + + 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_error(sr, NT_STATUS_NOT_A_DIRECTORY, + ERRDOS, ERROR_PATH_NOT_FOUND); + return (SDRC_ERROR); + } + + 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_error(sr, NT_STATUS_ACCESS_DENIED, + ERRDOS, ERROR_ACCESS_DENIED); + return (SDRC_ERROR); + } + + rc = smbsr_encode_empty_result(sr); + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); +} + +static boolean_t +smb_dirpath_isvalid(const char *path) +{ + struct { + char *name; + int len; + } *bad, bad_paths[] = { + { ".\0", 2 }, + { ".\\\0", 3 }, + { "..\0", 3 }, + { "..\\", 3 } + }; + + char *cp; + char *p; + int i; + + if (*path == '\0') + return (B_TRUE); + + cp = smb_kstrdup(path, MAXPATHLEN); + p = strcanon(cp, "\\"); + p += strspn(p, "\\"); + + for (i = 0; i < sizeof (bad_paths) / sizeof (bad_paths[0]); ++i) { + bad = &bad_paths[i]; + + if (strncmp(p, bad->name, bad->len) == 0) { + kmem_free(cp, MAXPATHLEN); + return (B_FALSE); + } + } + + kmem_free(cp, MAXPATHLEN); + return (B_TRUE); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c index c5461501c0..18ac05575d 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c +++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c @@ -21,13 +21,10 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * - * - * Dispatching SMB requests. */ /* - * ALMOST EVERYTHING YOU NEED TO KNOW ABOUT A SERVER MESSAGE BLOCK + * SMB requests. * * Request * Header @@ -151,7 +148,7 @@ static kmutex_t smb_dispatch_ksmtx; static int is_andx_com(unsigned char); static int smbsr_check_result(struct smb_request *, int, int); -static smb_dispatch_table_t dispatch[SMB_COM_NUM] = { +static smb_disp_entry_t dispatch[SMB_COM_NUM] = { { SMB_SDT_OPS(create_directory), /* 0x00 000 */ PC_NETWORK_PROGRAM_1_0, 0, RW_READER, { "SmbCreateDirectory", KSTAT_DATA_UINT64 } }, @@ -545,9 +542,6 @@ smbsr_cleanup(smb_request_t *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->r_xa) { if (sr->r_xa->xa_flags & SMB_XA_FLAG_COMPLETE) smb_xa_close(sr->r_xa); @@ -578,11 +572,14 @@ boolean_t smb_dispatch_request(struct smb_request *sr) { smb_sdrc_t sdrc; - smb_dispatch_table_t *sdd; + smb_disp_entry_t *sdd; boolean_t disconnect = B_FALSE; smb_session_t *session; + uint32_t capabilities; + uint32_t byte_count; session = sr->session; + capabilities = session->capabilities; ASSERT(sr->tid_tree == 0); ASSERT(sr->uid_user == 0); @@ -675,10 +672,24 @@ andx_more: goto report_error; } + /* + * Ignore smb_bcc if CAP_LARGE_READX/CAP_LARGE_WRITEX + * and this is SmbReadX/SmbWriteX since this enables + * large reads/write and bcc is only 16-bits. + */ + if (((sr->smb_com == SMB_COM_READ_ANDX) && + (capabilities & CAP_LARGE_READX)) || + ((sr->smb_com == SMB_COM_WRITE_ANDX) && + (capabilities & CAP_LARGE_WRITEX))) { + byte_count = sr->command.max_bytes - sr->command.chain_offset; + } else { + byte_count = (uint32_t)sr->smb_bcc; + } + (void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command, - sr->command.chain_offset, sr->smb_bcc); + sr->command.chain_offset, byte_count); - sr->command.chain_offset += sr->smb_bcc; + sr->command.chain_offset += byte_count; if (sr->command.chain_offset > sr->command.max_bytes) { disconnect = B_TRUE; goto report_error; @@ -1168,6 +1179,14 @@ smbsr_disconnect_file(smb_request_t *sr) (void) smb_ofile_release(of); } +void +smbsr_lookup_file(smb_request_t *sr) +{ + if (sr->fid_ofile == NULL) + sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, + sr->smb_fid); +} + static int is_andx_com(unsigned char com) { @@ -1241,8 +1260,8 @@ smb_com_invalid(smb_request_t *sr) static int smb_dispatch_kstat_update(kstat_t *ksp, int rw) { - smb_dispatch_table_t *sdd; - kstat_named_t *ks_named; + smb_disp_entry_t *sdd; + kstat_named_t *ks_named; int i; if (rw == KSTAT_WRITE) diff --git a/usr/src/uts/common/fs/smbsrv/smb_fem.c b/usr/src/uts/common/fs/smbsrv/smb_fem.c index 514c2f2b09..f88ff345af 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_fem.c +++ b/usr/src/uts/common/fs/smbsrv/smb_fem.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 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/sdt.h> @@ -108,6 +106,8 @@ static const fs_operation_def_t smb_oplock_tmpl[] = { NULL, NULL }; +static int smb_fem_oplock_break(femarg_t *, caller_context_t *); + /* * smb_fem_init * @@ -397,21 +397,19 @@ smb_fem_fcn_symlink( * CIFS higher-level routines will break oplocks as needed prior * to getting to the VFS layer. */ - -#define SMB_FEM_OPLOCK_BREAK(arg) \ - smb_oplock_break((smb_node_t *)((arg)->fa_fnode->fn_available)); - static int smb_fem_oplock_open( - femarg_t *arg, - int mode, - cred_t *cr, - struct caller_context *ct) + femarg_t *arg, + int mode, + cred_t *cr, + caller_context_t *ct) { - if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id) - SMB_FEM_OPLOCK_BREAK(arg); + int rc; - return (vnext_open(arg, mode, cr, ct)); + rc = smb_fem_oplock_break(arg, ct); + if (rc == 0) + rc = vnext_open(arg, mode, cr, ct); + return (rc); } /* @@ -421,16 +419,18 @@ smb_fem_oplock_open( static int smb_fem_oplock_read( - femarg_t *arg, - uio_t *uiop, - int ioflag, - cred_t *cr, - struct caller_context *ct) + femarg_t *arg, + uio_t *uiop, + int ioflag, + cred_t *cr, + caller_context_t *ct) { - if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id) - SMB_FEM_OPLOCK_BREAK(arg); + int rc; - return (vnext_read(arg, uiop, ioflag, cr, ct)); + rc = smb_fem_oplock_break(arg, ct); + if (rc == 0) + rc = vnext_read(arg, uiop, ioflag, cr, ct); + return (rc); } /* @@ -440,74 +440,84 @@ smb_fem_oplock_read( static int smb_fem_oplock_write( - femarg_t *arg, - uio_t *uiop, - int ioflag, - cred_t *cr, - struct caller_context *ct) + femarg_t *arg, + uio_t *uiop, + int ioflag, + cred_t *cr, + caller_context_t *ct) { - if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id) - SMB_FEM_OPLOCK_BREAK(arg); + int rc; - return (vnext_write(arg, uiop, ioflag, cr, ct)); + rc = smb_fem_oplock_break(arg, ct); + if (rc == 0) + rc = vnext_write(arg, uiop, ioflag, cr, ct); + return (rc); } static int smb_fem_oplock_setattr( - femarg_t *arg, - vattr_t *vap, - int flags, - cred_t *cr, - caller_context_t *ct) + femarg_t *arg, + vattr_t *vap, + int flags, + cred_t *cr, + caller_context_t *ct) { - if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id) - SMB_FEM_OPLOCK_BREAK(arg); + int rc; - return (vnext_setattr(arg, vap, flags, cr, ct)); + rc = smb_fem_oplock_break(arg, ct); + if (rc == 0) + rc = vnext_setattr(arg, vap, flags, cr, ct); + return (rc); } static int smb_fem_oplock_rwlock( - femarg_t *arg, - int write_lock, - caller_context_t *ct) + femarg_t *arg, + int write_lock, + caller_context_t *ct) { if (write_lock) { - if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id) - SMB_FEM_OPLOCK_BREAK(arg); - } + int rc; + rc = smb_fem_oplock_break(arg, ct); + if (rc != 0) + return (rc); + } return (vnext_rwlock(arg, write_lock, ct)); } static int smb_fem_oplock_space( - femarg_t *arg, - int cmd, - flock64_t *bfp, - int flag, - offset_t offset, - cred_t *cr, - caller_context_t *ct) + femarg_t *arg, + int cmd, + flock64_t *bfp, + int flag, + offset_t offset, + cred_t *cr, + caller_context_t *ct) { - if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id) - SMB_FEM_OPLOCK_BREAK(arg); + int rc; - return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct)); + rc = smb_fem_oplock_break(arg, ct); + if (rc == 0) + rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct); + return (rc); } static int smb_fem_oplock_setsecattr( - femarg_t *arg, - vsecattr_t *vsap, - int flag, - cred_t *cr, - caller_context_t *ct) + femarg_t *arg, + vsecattr_t *vsap, + int flag, + cred_t *cr, + caller_context_t *ct) { - if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id) - SMB_FEM_OPLOCK_BREAK(arg); + int rc; - return (vnext_setsecattr(arg, vsap, flag, cr, ct)); + rc = smb_fem_oplock_break(arg, ct); + if (rc == 0) + rc = vnext_setsecattr(arg, vsap, flag, cr, ct); + return (rc); } /* @@ -526,18 +536,21 @@ smb_fem_oplock_setsecattr( static int smb_fem_oplock_vnevent( - femarg_t *arg, - vnevent_t vnevent, - vnode_t *dvp, - char *name, - caller_context_t *ct) + femarg_t *arg, + vnevent_t vnevent, + vnode_t *dvp, + char *name, + caller_context_t *ct) { + int rc; + switch (vnevent) { case VE_REMOVE: case VE_RENAME_DEST: case VE_RENAME_SRC: - - SMB_FEM_OPLOCK_BREAK(arg); + rc = smb_fem_oplock_break(arg, ct); + if (rc != 0) + return (rc); break; default: @@ -545,3 +558,32 @@ smb_fem_oplock_vnevent( } return (vnext_vnevent(arg, vnevent, dvp, name, ct)); } + +static int +smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct) +{ + smb_node_t *node; + int rc; + + node = (smb_node_t *)((arg)->fa_fnode->fn_available); + SMB_NODE_VALID(node); + + if (ct == NULL) { + (void) smb_oplock_break(node, 0, B_FALSE); + return (0); + } + + if (ct->cc_caller_id == smb_ct.cc_caller_id) + return (0); + + if (ct->cc_flags & CC_DONTBLOCK) { + if (smb_oplock_break(node, 0, B_TRUE)) + return (0); + ct->cc_flags |= CC_WOULDBLOCK; + rc = EAGAIN; + } else { + (void) smb_oplock_break(node, 0, B_FALSE); + rc = 0; + } + return (rc); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_find.c b/usr/src/uts/common/fs/smbsrv/smb_find.c index fd0aa16d4c..409b3ef734 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_find.c +++ b/usr/src/uts/common/fs/smbsrv/smb_find.c @@ -324,9 +324,6 @@ smb_com_search(smb_request_t *sr) if ((rc != 0 || (eos == B_TRUE))) break; - if (smb_is_dot_or_dotdot(fileinfo.fi_name)) - continue; - (void) memset(name, ' ', sizeof (name)); if (*fileinfo.fi_shortname == '\0') { (void) strlcpy(name, fileinfo.fi_name, @@ -604,18 +601,18 @@ smb_com_find_unique(struct smb_request *sr) smb_odir_t *od; smb_fileinfo_t fileinfo; boolean_t eos; - struct vardata_block *vdb; + smb_vdb_t *vdb; if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) return (SDRC_ERROR); - vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP); + vdb = kmem_alloc(sizeof (smb_vdb_t), KM_SLEEP); if ((smbsr_decode_data(sr, "%AV", sr, &path, vdb) != 0) || - (vdb->len != 0)) { - kmem_free(vdb, sizeof (struct vardata_block)); + (vdb->vdb_len != 0)) { + kmem_free(vdb, sizeof (smb_vdb_t)); return (SDRC_ERROR); } - kmem_free(vdb, sizeof (struct vardata_block)); + kmem_free(vdb, sizeof (smb_vdb_t)); (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); diff --git a/usr/src/uts/common/fs/smbsrv/smb_flush.c b/usr/src/uts/common/fs/smbsrv/smb_flush.c index 0792f592e2..5f86e42dee 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_flush.c +++ b/usr/src/uts/common/fs/smbsrv/smb_flush.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -84,8 +84,7 @@ smb_com_flush(smb_request_t *sr) } if (sr->smb_fid != 0xffff) { - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, - sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c index d27b423832..161b4b8e73 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c +++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c @@ -1075,7 +1075,7 @@ smb_fsop_rename( if (from_snode == NULL) { rc = ENOMEM; } else { - (void) smb_node_rename(from_dir_snode, from_snode, + smb_node_rename(from_dir_snode, from_snode, to_dir_snode, to_name); smb_node_release(from_snode); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_init.c b/usr/src/uts/common/fs/smbsrv/smb_init.c index 94abdbd4f0..2dce286ede 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_init.c +++ b/usr/src/uts/common/fs/smbsrv/smb_init.c @@ -59,11 +59,17 @@ static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); * environment. When in doubt use 37KB. */ int smb_maxbufsize = SMB_NT_MAXBUF; -clock_t smb_oplock_timeout = OPLOCK_STD_TIMEOUT; +int smb_oplock_timeout = OPLOCK_STD_TIMEOUT; int smb_flush_required = 1; int smb_dirsymlink_enable = 1; int smb_announce_quota = 0; int smb_sign_debug = 0; +uint_t smb_audit_flags = +#ifdef DEBUG + SMB_AUDIT_NODE; +#else + 0; +#endif /* * ***************************************************************************** diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock.c b/usr/src/uts/common/fs/smbsrv/smb_lock.c index 034be2c0eb..7c63572aa6 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_lock.c +++ b/usr/src/uts/common/fs/smbsrv/smb_lock.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "@(#)smb_lock.c 1.10 08/08/04 SMI" - /* * This module provides range lock functionality for CIFS/SMB clients. * Lock range service functions process SMB lock and and unlock @@ -279,9 +277,7 @@ smb_node_destroy_lock_by_ofile(smb_node_t *node, smb_ofile_t *file) 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); + SMB_NODE_VALID(node); ASSERT(node->n_refcnt); /* @@ -352,9 +348,7 @@ smb_range_check(smb_request_t *sr, smb_node_t *node, uint64_t start, int nbl_op; int rc; - ASSERT(node); - ASSERT(node->n_magic == SMB_NODE_MAGIC); - ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); + SMB_NODE_VALID(node); ASSERT(smb_node_in_crit(node)); 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 index 35edce4965..bf74578aba 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c +++ b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" - /* * SMB: lock_byte_range * @@ -86,7 +83,7 @@ smb_com_lock_byte_range(struct smb_request *sr) if (smbsr_decode_vwv(sr, "wll", &sr->smb_fid, &count, &off) != 0) return (SDRC_ERROR); - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); diff --git a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c index c4ea950a91..dd765c0979 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c +++ b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" - /* * SMB: locking_andx * @@ -248,7 +245,7 @@ smb_com_locking_andx(smb_request_t *sr) if (rc != 0) return (SDRC_ERROR); - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -262,8 +259,7 @@ smb_com_locking_andx(smb_request_t *sr) pid = sr->smb_pid; /* Save the original pid */ if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) { - smb_oplock_release(sr->fid_ofile->f_node, B_FALSE); - + smb_oplock_release(sr->fid_ofile->f_node, sr->fid_ofile); /* * According to the protocol: * diff --git a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c index a6075186af..e91bcc11b9 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c +++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c @@ -23,9 +23,8 @@ * Use is subject to license terms. */ -#pragma ident "@(#)smb_mangle_name.c 1.3 08/08/07 SMI" - #include <sys/types.h> +#include <sys/param.h> #include <sys/sunddi.h> #include <sys/errno.h> #include <smbsrv/string.h> @@ -35,9 +34,35 @@ #include <smbsrv/smb_incl.h> #include <smbsrv/smb_fsops.h> +#define SMB_NAME83_BASELEN 8 +#define SMB_NAME83_LEN 12 + +/* + * 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)) + 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); +static boolean_t smb_is_reserved_dos_name(const char *name); /* * smb_match_name @@ -156,123 +181,82 @@ smb_match_unknown(char *name, char *pattern) } /* - * smb_match_reserved + * Return true if name contains characters that are invalid in a file + * name or it is a reserved DOS device name. Otherwise, returns false. * - * Checks if the given name matches given - * DOS reserved name prefix. - * - * Returns 1 if match, 0 otherwise + * Control characters (values 0 - 31) and the following characters are + * invalid: + * < > : " / \ | ? * */ -static int -smb_match_reserved(char *name, char *rsrv) +boolean_t +smb_is_invalid_filename(const char *name) { - char ch; + const char *p; - int len = strlen(rsrv); - return (!utf8_strncasecmp(rsrv, name, len) && - ((ch = *(name + len)) == 0 || ch == '.')); + if ((p = strpbrk(name, invalid_dos_chars)) != NULL) { + if (*p != ' ') + return (B_TRUE); + } + + return (smb_is_reserved_dos_name(name)); } /* * 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. + * This function checks if the name is a reserved DOS device name. + * The device name should not be followed immediately by an extension, + * for example, NUL.txt. */ -static int -smb_is_reserved_dos_name(char *name) +static boolean_t +smb_is_reserved_dos_name(const char *name) { + static char *cnames[] = { "CLOCK$", "COM1", "COM2", "COM3", "COM4", + "COM5", "COM6", "COM7", "COM8", "COM9", "CON" }; + static char *lnames[] = { "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", + "LPT6", "LPT7", "LPT8", "LPT9" }; + static char *others[] = { "AUX", "NUL", "PRN" }; + char **reserved; char ch; + int n_reserved; + int len; + int i; - /* - * Eliminate all names reserved by DOS and Windows. - */ ch = mts_toupper(*name); switch (ch) { case 'A': - if (smb_match_reserved(name, "AUX")) - return (1); + case 'N': + case 'P': + reserved = others; + n_reserved = sizeof (others) / sizeof (others[0]); 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); - } - + reserved = cnames; + n_reserved = sizeof (cnames) / sizeof (cnames[0]); 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); + reserved = lnames; + n_reserved = sizeof (lnames) / sizeof (lnames[0]); break; - - case 'P': - if (smb_match_reserved(name, "PRN")) - return (1); + default: + return (B_FALSE); } - /* - * 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++; + for (i = 0; i < n_reserved; ++i) { + len = strlen(reserved[i]); + + if (utf8_strncasecmp(reserved[i], name, len) == 0) { + ch = *(name + len); + if ((ch == '\0') || (ch == '.')) + return (B_TRUE); } } -#endif /* CATIA_SUPPORT */ - return (0); + return (B_FALSE); } /* - * 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. @@ -479,28 +463,38 @@ smb_generate_mangle(ino64_t fileid, unsigned char *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. + * Mangled names should be valid DOS file names: less than 12 characters + * long, contain at least one tilde character and conform to an 8.3 name + * format. * - * 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. + * Returns true if the name looks like a mangled name. */ int smb_maybe_mangled_name(char *name) { - int i, has_tilde = 0; + const char *p; + boolean_t has_tilde = B_FALSE; + int ndots = 0; + int i; + + for (p = name, i = 0; (*p != '\0') && (i < SMB_NAME83_LEN); i++, p++) { + if ((strchr(special_chars, *p) != NULL) || + (strchr(invalid_dos_chars, *p) != NULL)) + return (B_FALSE); + + if (*p == '.') { + if ((++ndots) > 1) + return (B_FALSE); + } - for (i = 0; *name && (i < 12); i++, name++) { - if ((*name == '~') && (i < 8)) - has_tilde = 1; + if ((*p == '~') && (i < SMB_NAME83_BASELEN)) + has_tilde = B_TRUE; - if (*name == '.' && has_tilde == 0) - return (0); + if (*p == '.' && !has_tilde) + return (B_FALSE); } - return ((*name == 0) && has_tilde); + return ((*p == 0) && has_tilde); } /* diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c index 7a361bb0cc..7e0ee57629 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c +++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c @@ -19,11 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - /* * SMB mbuf marshaling encode/decode. */ @@ -147,6 +146,7 @@ smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap) uint8_t cval; uint8_t *cvalp; uint8_t **cvalpp; + uint16_t wval; uint16_t *wvalp; uint32_t *lvalp; uint64_t *llvalp; @@ -240,29 +240,29 @@ smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap) 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) + vdp->vdb_tag = 0; + vdp->vdb_len = repc; + vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; + vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; + vdp->vdb_uio.uio_resid = repc; + if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0) return (-1); break; case 'D': case 'V': vdp = va_arg(ap, struct vardata_block *); - if (mbc_marshal_get_char(mbc, &vdp->tag) != 0) + if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0) return (-1); - if (mbc_marshal_get_short(mbc, &vdp->len) != 0) + if (mbc_marshal_get_short(mbc, &wval) != 0) return (-1); - 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) + vdp->vdb_len = (uint32_t)wval; + vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; + vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; + vdp->vdb_uio.uio_resid = vdp->vdb_len; + if (vdp->vdb_len != 0) { + if (mbc_marshal_get_uio(mbc, + &vdp->vdb_uio) != 0) return (-1); } break; @@ -540,9 +540,9 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap) if (mbc_marshal_put_char(mbc, 1) != 0) return (DECODE_NO_MORE_DATA); - if (mbc_marshal_put_short(mbc, vdp->len) != 0) + if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0) return (DECODE_NO_MORE_DATA); - if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0) + if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0) return (DECODE_NO_MORE_DATA); break; @@ -564,9 +564,9 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap) if (mbc_marshal_put_char(mbc, 5) != 0) return (DECODE_NO_MORE_DATA); - if (mbc_marshal_put_short(mbc, vdp->len) != 0) + if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0) return (DECODE_NO_MORE_DATA); - if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0) + if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0) return (DECODE_NO_MORE_DATA); break; diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c index db2698645f..8dcba3b111 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c +++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -59,6 +59,60 @@ #include <smbsrv/smb_incl.h> #include <smbsrv/mbuf.h> +#include <smbsrv/smb_kstat.h> + +static kmem_cache_t *smb_mbc_cache = NULL; + +int +smb_mbc_init(void) +{ + if (smb_mbc_cache == NULL) { + smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE, + sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0); + } + return (0); +} + +void +smb_mbc_fini(void) +{ + if (smb_mbc_cache != NULL) { + kmem_cache_destroy(smb_mbc_cache); + smb_mbc_cache = NULL; + } +} + +mbuf_chain_t * +smb_mbc_alloc(uint32_t max_bytes) +{ + mbuf_chain_t *mbc; + mbuf_t *m; + + mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP); + bzero(mbc, sizeof (*mbc)); + mbc->mbc_magic = SMB_MBC_MAGIC; + + 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; + return (mbc); +} + +void +smb_mbc_free(mbuf_chain_t *mbc) +{ + SMB_MBC_VALID(mbc); + + m_freem(mbc->chain); + mbc->chain = NULL; + mbc->mbc_magic = 0; + kmem_cache_free(smb_mbc_cache, mbc); +} /* * smb_mbuf_get diff --git a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c index 01fee7371e..fd82d1bfd0 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c +++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c @@ -23,8 +23,6 @@ * Use is subject to license terms. */ -#pragma ident "@(#)smb_negotiate.c 1.6 08/07/21 SMI" - /* * Notes on the virtual circuit (VC) values in the SMB Negotiate * response and SessionSetupAndx request. @@ -358,7 +356,12 @@ smb_com_negotiate(smb_request_t *sr) (void) ksocket_setsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF, (const void *)&smb_nt_tcp_rcvbuf, sizeof (smb_nt_tcp_rcvbuf), CRED()); + /* + * UNICODE support is required for long share names, + * long file names and streams. + */ capabilities = CAP_LARGE_FILES + | CAP_UNICODE | CAP_NT_SMBS | CAP_STATUS32 | CAP_NT_FIND @@ -366,15 +369,8 @@ smb_com_negotiate(smb_request_t *sr) | 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; - + | CAP_LARGE_READX + | CAP_LARGE_WRITEX; /* * Turn off Extended Security Negotiation diff --git a/usr/src/uts/common/fs/smbsrv/smb_node.c b/usr/src/uts/common/fs/smbsrv/smb_node.c index 41808ad392..484bdecfbd 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_node.c +++ b/usr/src/uts/common/fs/smbsrv/smb_node.c @@ -22,9 +22,6 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "@(#)smb_node.c 1.9 08/08/07 SMI" - /* * SMB Node State Machine * ---------------------- @@ -82,18 +79,29 @@ */ #include <smbsrv/smb_incl.h> #include <smbsrv/smb_fsops.h> +#include <smbsrv/smb_kstat.h> #include <sys/pathname.h> #include <sys/sdt.h> #include <sys/nbmlock.h> -uint32_t smb_is_executable(char *path); -static void smb_node_delete_on_close(smb_node_t *node); +uint32_t smb_is_executable(char *); +static void smb_node_delete_on_close(smb_node_t *); +static void smb_node_create_audit_buf(smb_node_t *, int); +static void smb_node_destroy_audit_buf(smb_node_t *); +static void smb_node_audit(smb_node_t *); +static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_attr_t *, + smb_llist_t *bucket, uint32_t hashkey); +static void smb_node_free(smb_node_t *); +static int smb_node_constructor(void *, void *, int); +static void smb_node_destructor(void *, void *); +static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *); #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_)); +static kmem_cache_t *smb_node_cache = NULL; static boolean_t smb_node_initialized = B_FALSE; static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; @@ -112,6 +120,9 @@ smb_node_init(void) if (smb_node_initialized) return (0); + smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE, + sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor, + NULL, NULL, NULL, 0); for (i = 0; i <= SMBND_HASH_MASK; i++) { smb_llist_constructor(&smb_node_hash_table[i], @@ -160,6 +171,8 @@ smb_node_fini(void) for (i = 0; i <= SMBND_HASH_MASK; i++) { smb_llist_destructor(&smb_node_hash_table[i]); } + kmem_cache_destroy(smb_node_cache); + smb_node_cache = NULL; smb_node_initialized = B_FALSE; } @@ -237,9 +250,7 @@ smb_node_lookup( fsid = vp->v_vfsp->vfs_fsid; } - hashkey = fsid.val[0] + attr->sa_vattr.va_nodeid; - hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); - node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; + node_hdr = smb_node_get_hash(&fsid, attr, &hashkey); lock_mode = RW_READER; smb_llist_enter(node_hdr, lock_mode); @@ -249,10 +260,12 @@ smb_node_lookup( 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); + mutex_enter(&node->n_mutex); DTRACE_PROBE1(smb_node_lookup_hit, smb_node_t *, node); switch (node->n_state) { + case SMB_NODE_STATE_OPLOCK_GRANTED: + case SMB_NODE_STATE_OPLOCK_BREAKING: case SMB_NODE_STATE_AVAILABLE: /* The node was found. */ node->n_refcnt++; @@ -268,8 +281,8 @@ smb_node_lookup( node->attr = *attr; node->n_size = attr->sa_vattr.va_size; - smb_audit_node(node); - smb_rwx_xexit(&node->n_lock); + smb_node_audit(node); + mutex_exit(&node->n_mutex); smb_llist_exit(node_hdr); return (node); @@ -279,7 +292,7 @@ smb_node_lookup( * to be destroyed. We act as it hasn't * been found. */ - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); break; default: /* @@ -288,7 +301,7 @@ smb_node_lookup( * been found. */ ASSERT(0); - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); break; } } @@ -300,34 +313,9 @@ smb_node_lookup( } break; } - node = kmem_cache_alloc(sr->sr_server->si_cache_node, KM_SLEEP); - bzero(node, sizeof (smb_node_t)); - - node->n_state = SMB_NODE_STATE_AVAILABLE; - node->n_hash_bucket = node_hdr; - node->n_sr = sr; - node->vp = vp; - VN_HOLD(node->vp); - node->n_hashkey = hashkey; - node->n_refcnt = 1; - node->attr = *attr; - node->flags |= NODE_FLAGS_ATTR_VALID; - node->n_size = node->attr.sa_vattr.va_size; - node->n_orig_session_id = sr->session->s_kid; + node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey); node->n_orig_uid = crgetuid(sr->user_cr); - node->n_cache = sr->sr_server->si_cache_node; - - ASSERT(od_name); - (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); - 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)); - - - if (strcmp(od_name, XATTR_DIR) == 0) - node->flags |= NODE_XATTR_DIR; if (op) node->flags |= smb_is_executable(op->fqi.last_comp); @@ -344,13 +332,9 @@ smb_node_lookup( node->unnamed_stream_node = unnamed_node; } - 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_node_audit(node); smb_llist_insert_head(node_hdr, node); - smb_llist_exit(node_hdr); return (node); } @@ -364,7 +348,7 @@ smb_node_lookup( */ smb_node_t * -smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, +smb_stream_node_lookup(smb_request_t *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; @@ -398,20 +382,25 @@ smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, * 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_VALID(node); + + mutex_enter(&node->n_mutex); + switch (node->n_state) { + case SMB_NODE_STATE_AVAILABLE: + case SMB_NODE_STATE_OPLOCK_GRANTED: + case SMB_NODE_STATE_OPLOCK_BREAKING: + node->n_refcnt++; + ASSERT(node->n_refcnt); + DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); + smb_node_audit(node); + break; + default: + SMB_PANIC(); + } + mutex_exit(&node->n_mutex); } /* @@ -438,10 +427,9 @@ smb_node_ref(smb_node_t *node) void smb_node_release(smb_node_t *node) { - ASSERT(node); - ASSERT(node->n_magic == SMB_NODE_MAGIC); + SMB_NODE_VALID(node); - smb_rwx_xenter(&node->n_lock); + mutex_enter(&node->n_mutex); ASSERT(node->n_refcnt); DTRACE_PROBE1(smb_node_release, smb_node_t *, node); if (--node->n_refcnt == 0) { @@ -449,7 +437,7 @@ smb_node_release(smb_node_t *node) case SMB_NODE_STATE_AVAILABLE: node->n_state = SMB_NODE_STATE_DESTROYING; - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); smb_llist_enter(node->n_hash_bucket, RW_WRITER); smb_llist_remove(node->n_hash_bucket, node); @@ -459,11 +447,6 @@ smb_node_release(smb_node_t *node) * 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 == @@ -477,21 +460,15 @@ smb_node_release(smb_node_t *node) 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(node->n_cache, node); + smb_node_free(node); return; default: - ASSERT(0); - break; + SMB_PANIC(); } } - smb_audit_node(node); - smb_rwx_xexit(&node->n_lock); + smb_node_audit(node); + mutex_exit(&node->n_mutex); } static void @@ -523,39 +500,37 @@ smb_node_delete_on_close(smb_node_t *node) * smb_node_rename() * */ -int +void smb_node_rename( - smb_node_t *from_dir_snode, - smb_node_t *ret_snode, - smb_node_t *to_dir_snode, + smb_node_t *from_dnode, + smb_node_t *ret_node, + smb_node_t *to_dnode, 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); + SMB_NODE_VALID(from_dnode); + SMB_NODE_VALID(to_dnode); + SMB_NODE_VALID(ret_node); + + smb_node_ref(to_dnode); + mutex_enter(&ret_node->n_mutex); + switch (ret_node->n_state) { + case SMB_NODE_STATE_AVAILABLE: + case SMB_NODE_STATE_OPLOCK_GRANTED: + case SMB_NODE_STATE_OPLOCK_BREAKING: + ret_node->dir_snode = to_dnode; + mutex_exit(&ret_node->n_mutex); + ASSERT(to_dnode->dir_snode != ret_node); + ASSERT((to_dnode->vp->v_xattrdir) || + (to_dnode->vp->v_type == VDIR)); + smb_node_release(from_dnode); + (void) strcpy(ret_node->od_name, to_name); + /* + * XXX Need to update attributes? + */ + break; + default: + SMB_PANIC(); + } } int @@ -567,12 +542,6 @@ smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) smb_llist_t *node_hdr; smb_node_t *node; - /* - * Take an explicit hold on rootdir. This goes with the - * corresponding release in smb_node_root_fini()/smb_node_release(). - */ - VN_HOLD(vp); - va.sa_mask = SMB_AT_ALL; error = smb_vop_getattr(vp, NULL, &va, 0, kcred); if (error) { @@ -580,42 +549,16 @@ smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) return (error); } - hashkey = vp->v_vfsp->vfs_fsid.val[0] + va.sa_vattr.va_nodeid; - hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); - node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; - - node = kmem_cache_alloc(sv->si_cache_node, KM_SLEEP); - bzero(node, sizeof (smb_node_t)); - - node->n_state = SMB_NODE_STATE_AVAILABLE; - node->n_hash_bucket = node_hdr; - node->vp = vp; - node->n_hashkey = hashkey; - node->n_refcnt = 1; - node->attr = va; - node->flags |= NODE_FLAGS_ATTR_VALID; - node->n_size = node->attr.sa_vattr.va_size; - node->n_cache = sv->si_cache_node; - (void) strlcpy(node->od_name, ROOTVOL, sizeof (node->od_name)); + node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey); - 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)); - - smb_rwx_init(&node->n_lock); - node->n_magic = SMB_NODE_MAGIC; - smb_audit_buf_node_create(node); + node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey); sv->si_root_smb_node = node; - - smb_audit_node(node); + smb_node_audit(node); smb_llist_enter(node_hdr, RW_WRITER); smb_llist_insert_head(node_hdr, node); smb_llist_exit(node_hdr); - *root = node; - return (0); } @@ -630,12 +573,12 @@ smb_node_get_size(smb_node_t *node, smb_attr_t *attr) if (attr->sa_vattr.va_type == VDIR) return (0); - smb_rwx_xenter(&node->n_lock); + mutex_enter(&node->n_mutex); 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); + mutex_exit(&node->n_mutex); return (size); } @@ -662,9 +605,13 @@ timeval_cmp(timestruc_t *a, timestruc_t *b) * 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_node_set_time( + smb_node_t *node, + timestruc_t *crtime, + timestruc_t *mtime, + timestruc_t *atime, + timestruc_t *ctime, + uint_t what) { if (what == 0) return; @@ -675,7 +622,7 @@ smb_node_set_time(struct smb_node *node, struct timestruc *crtime, (what & SMB_AT_CTIME && ctime == 0)) return; - smb_rwx_xenter(&node->n_lock); + mutex_enter(&node->n_mutex); if ((what & SMB_AT_CRTIME) && timeval_cmp((timestruc_t *)&node->attr.sa_crtime, @@ -731,7 +678,7 @@ smb_node_set_time(struct smb_node *node, struct timestruc *crtime, } else { gethrestime(&node->attr.sa_vattr.va_ctime); } - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); } @@ -773,12 +720,12 @@ smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr) FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); - smb_rwx_xenter(&node->n_lock); + mutex_enter(&node->n_mutex); if (node->attr.sa_dosattr != mode) { node->attr.sa_dosattr = mode; node->what |= SMB_AT_DOSATTR; } - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); } /* @@ -812,7 +759,7 @@ smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr) { int rc = -1; - smb_rwx_xenter(&node->n_lock); + mutex_enter(&node->n_mutex); if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) && !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) { crhold(cr); @@ -820,20 +767,20 @@ smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr) node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; rc = 0; } - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); return (rc); } void smb_node_reset_delete_on_close(smb_node_t *node) { - smb_rwx_xenter(&node->n_lock); + mutex_enter(&node->n_mutex); 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); + mutex_exit(&node->n_mutex); } /* @@ -846,15 +793,16 @@ smb_node_reset_delete_on_close(smb_node_t *node) * sharing conflict, otherwise returns NT_STATUS_SUCCESS. */ uint32_t -smb_node_open_check(struct smb_node *node, cred_t *cr, - uint32_t desired_access, uint32_t share_access) +smb_node_open_check( + smb_node_t *node, + cred_t *cr, + uint32_t desired_access, + uint32_t share_access) { smb_ofile_t *of; uint32_t status; - ASSERT(node); - ASSERT(node->n_magic == SMB_NODE_MAGIC); - ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); + SMB_NODE_VALID(node); smb_llist_enter(&node->n_ofile_list, RW_READER); of = smb_llist_head(&node->n_ofile_list); @@ -879,19 +827,16 @@ smb_node_open_check(struct smb_node *node, cred_t *cr, } uint32_t -smb_node_rename_check(struct smb_node *node) +smb_node_rename_check(smb_node_t *node) { - struct smb_ofile *of; - uint32_t status; + smb_ofile_t *of; + uint32_t status; - ASSERT(node); - ASSERT(node->n_magic == SMB_NODE_MAGIC); - ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); + SMB_NODE_VALID(node); /* * Intra-CIFS check */ - smb_llist_enter(&node->n_ofile_list, RW_READER); of = smb_llist_head(&node->n_ofile_list); while (of) { @@ -913,7 +858,6 @@ smb_node_rename_check(struct smb_node *node) /* * system-wide share check */ - if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) return (NT_STATUS_SHARING_VIOLATION); else @@ -923,12 +867,10 @@ smb_node_rename_check(struct smb_node *node) uint32_t smb_node_delete_check(smb_node_t *node) { - smb_ofile_t *of; - uint32_t status; + smb_ofile_t *of; + uint32_t status; - ASSERT(node); - ASSERT(node->n_magic == SMB_NODE_MAGIC); - ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); + SMB_NODE_VALID(node); if (node->attr.sa_vattr.va_type == VDIR) return (NT_STATUS_SUCCESS); @@ -936,7 +878,6 @@ smb_node_delete_check(smb_node_t *node) /* * intra-CIFS check */ - smb_llist_enter(&node->n_ofile_list, RW_READER); of = smb_llist_head(&node->n_ofile_list); while (of) { @@ -958,7 +899,6 @@ smb_node_delete_check(smb_node_t *node) /* * system-wide share check */ - if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) return (NT_STATUS_SHARING_VIOLATION); else @@ -975,7 +915,7 @@ smb_node_delete_check(smb_node_t *node) void smb_node_start_crit(smb_node_t *node, krw_t mode) { - rw_enter(&node->n_share_lock, mode); + rw_enter(&node->n_lock, mode); nbl_start_crit(node->vp, mode); } @@ -989,11 +929,260 @@ void smb_node_end_crit(smb_node_t *node) { nbl_end_crit(node->vp); - rw_exit(&node->n_share_lock); + rw_exit(&node->n_lock); } int smb_node_in_crit(smb_node_t *node) { - return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock)); + return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock)); +} + +void +smb_node_rdlock(smb_node_t *node) +{ + rw_enter(&node->n_lock, RW_READER); +} + +void +smb_node_wrlock(smb_node_t *node) +{ + rw_enter(&node->n_lock, RW_WRITER); +} + +void +smb_node_unlock(smb_node_t *node) +{ + rw_exit(&node->n_lock); +} + +uint32_t +smb_node_get_ofile_count(smb_node_t *node) +{ + uint32_t cntr; + + SMB_NODE_VALID(node); + + smb_llist_enter(&node->n_ofile_list, RW_READER); + cntr = smb_llist_get_count(&node->n_ofile_list); + smb_llist_exit(&node->n_ofile_list); + return (cntr); +} + +void +smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of) +{ + SMB_NODE_VALID(node); + + 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); +} + +void +smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of) +{ + SMB_NODE_VALID(node); + + smb_llist_enter(&node->n_ofile_list, RW_WRITER); + smb_llist_remove(&node->n_ofile_list, of); + smb_llist_exit(&node->n_ofile_list); +} + +void +smb_node_inc_open_ofiles(smb_node_t *node) +{ + SMB_NODE_VALID(node); + + mutex_enter(&node->n_mutex); + node->n_open_count++; + mutex_exit(&node->n_mutex); +} + +void +smb_node_dec_open_ofiles(smb_node_t *node) +{ + SMB_NODE_VALID(node); + + mutex_enter(&node->n_mutex); + node->n_open_count--; + mutex_exit(&node->n_mutex); +} + +uint32_t +smb_node_get_open_ofiles(smb_node_t *node) +{ + uint32_t cnt; + + SMB_NODE_VALID(node); + + mutex_enter(&node->n_mutex); + cnt = node->n_open_count; + mutex_exit(&node->n_mutex); + return (cnt); +} + +/* + * smb_node_alloc + */ +static smb_node_t * +smb_node_alloc( + char *od_name, + vnode_t *vp, + smb_attr_t *attr, + smb_llist_t *bucket, + uint32_t hashkey) +{ + smb_node_t *node; + + node = kmem_cache_alloc(smb_node_cache, KM_SLEEP); + + if (node->n_audit_buf != NULL) + node->n_audit_buf->anb_index = 0; + + node->attr = *attr; + node->flags = NODE_FLAGS_ATTR_VALID; + node->n_size = node->attr.sa_vattr.va_size; + VN_HOLD(vp); + node->vp = vp; + node->n_refcnt = 1; + node->n_hash_bucket = bucket; + node->n_hashkey = hashkey; + node->n_orig_uid = 0; + node->readonly_creator = NULL; + node->waiting_event = 0; + node->what = 0; + node->n_open_count = 0; + node->dir_snode = NULL; + node->unnamed_stream_node = NULL; + node->delete_on_close_cred = NULL; + + (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); + if (strcmp(od_name, XATTR_DIR) == 0) + node->flags |= NODE_XATTR_DIR; + + node->n_state = SMB_NODE_STATE_AVAILABLE; + node->n_magic = SMB_NODE_MAGIC; + return (node); +} + +/* + * smb_node_free + */ +static void +smb_node_free(smb_node_t *node) +{ + SMB_NODE_VALID(node); + + node->n_magic = 0; + VERIFY(!list_link_active(&node->n_lnd)); + VERIFY(node->n_lock_list.ll_count == 0); + VERIFY(node->n_ofile_list.ll_count == 0); + VERIFY(node->n_oplock.ol_xthread == NULL); + VERIFY(node->n_oplock.ol_waiters_count == 0); + VN_RELE(node->vp); + kmem_cache_free(smb_node_cache, node); +} + +/* + * smb_node_constructor + */ +static int +smb_node_constructor(void *buf, void *un, int kmflags) +{ + _NOTE(ARGUNUSED(kmflags, un)) + + smb_node_t *node = (smb_node_t *)buf; + + bzero(node, sizeof (smb_node_t)); + + 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)); + cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); + rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL); + mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); + smb_node_create_audit_buf(node, kmflags); + return (0); +} + +/* + * smb_node_destructor + */ +static void +smb_node_destructor(void *buf, void *un) +{ + _NOTE(ARGUNUSED(un)) + + smb_node_t *node = (smb_node_t *)buf; + + smb_node_destroy_audit_buf(node); + mutex_destroy(&node->n_mutex); + rw_destroy(&node->n_lock); + cv_destroy(&node->n_oplock.ol_cv); + smb_llist_destructor(&node->n_lock_list); + smb_llist_destructor(&node->n_ofile_list); +} + +/* + * smb_node_create_audit_buf + */ +static void +smb_node_create_audit_buf(smb_node_t *node, int kmflags) +{ + smb_audit_buf_node_t *abn; + + if (smb_audit_flags & SMB_AUDIT_NODE) { + abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags); + abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1; + node->n_audit_buf = abn; + } +} + +/* + * smb_node_destroy_audit_buf + */ +static void +smb_node_destroy_audit_buf(smb_node_t *node) +{ + if (node->n_audit_buf != NULL) { + kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t)); + node->n_audit_buf = NULL; + } +} + +/* + * smb_node_audit + * + * This function saves the calling stack in the audit buffer of the node passed + * in. + */ +static void +smb_node_audit(smb_node_t *node) +{ + smb_audit_buf_node_t *abn; + smb_audit_record_node_t *anr; + + if (node->n_audit_buf) { + abn = node->n_audit_buf; + anr = abn->anb_records; + anr += abn->anb_index; + abn->anb_index++; + abn->anb_index &= abn->anb_max_index; + anr->anr_refcnt = node->n_refcnt; + anr->anr_depth = getpcstack(anr->anr_stack, + SMB_AUDIT_STACK_DEPTH); + } +} + +static smb_llist_t * +smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey) +{ + uint32_t hashkey; + + hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid; + hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); + *phashkey = hashkey; + return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]); } 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 index 6e7f50c404..1506a68905 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -170,7 +170,6 @@ smb_pre_nt_create_andx(smb_request_t *sr) { struct open_param *op = &sr->arg.open; uint8_t SecurityFlags; - uint32_t Flags; uint32_t ImpersonationLevel; uint16_t NameLength; int rc; @@ -179,7 +178,7 @@ smb_pre_nt_create_andx(smb_request_t *sr) rc = smbsr_decode_vwv(sr, "5.wlllqlllllb", &NameLength, - &Flags, + &op->nt_flags, &op->rootdirfid, &op->desired_access, &op->dsize, @@ -203,17 +202,12 @@ smb_pre_nt_create_andx(smb_request_t *sr) } } - 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; + op->op_oplock_level = SMB_OPLOCK_NONE; + if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) { + if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH) + op->op_oplock_level = SMB_OPLOCK_BATCH; + else + op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; } DTRACE_SMB_2(op__NtCreateX__start, smb_request_t *, sr, @@ -240,7 +234,14 @@ smb_com_nt_create_andx(struct smb_request *sr) if ((op->create_options & FILE_DELETE_ON_CLOSE) && !(op->desired_access & DELETE)) { - smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); + smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, + ERRDOS, ERRbadaccess); + return (SDRC_ERROR); + } + + if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) { + smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, + ERRDOS, ERRbadaccess); return (SDRC_ERROR); } @@ -260,8 +261,7 @@ smb_com_nt_create_andx(struct smb_request *sr) op->fqi.dir_snode = sr->tid_tree->t_snode; } else { sr->smb_fid = (ushort_t)op->rootdirfid; - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, - sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); @@ -276,17 +276,17 @@ smb_com_nt_create_andx(struct smb_request *sr) return (SDRC_ERROR); if (STYPE_ISDSK(sr->tid_tree->t_res_type)) { - switch (MYF_OPLOCK_TYPE(op->my_flags)) { - case MYF_EXCLUSIVE_OPLOCK : + switch (op->op_oplock_level) { + case SMB_OPLOCK_EXCLUSIVE: OplockLevel = 1; break; - case MYF_BATCH_OPLOCK : + case SMB_OPLOCK_BATCH: OplockLevel = 2; break; - case MYF_LEVEL_II_OPLOCK : + case SMB_OPLOCK_LEVEL_II: OplockLevel = 3; break; - case MYF_OPLOCK_NONE : + case SMB_OPLOCK_NONE: default: OplockLevel = 0; break; 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 index c0e8100fb1..94c693a1ad 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -60,7 +60,6 @@ smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) struct open_param *op = &sr->arg.open; uint8_t SecurityFlags; uint32_t EaLength; - uint32_t Flags; uint32_t ImpersonationLevel; uint32_t NameLength; uint32_t sd_len; @@ -72,7 +71,7 @@ smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) rc = smb_mbc_decodef(&xa->req_param_mb, "%lllqllllllllb", sr, - &Flags, + &op->nt_flags, &op->rootdirfid, &op->desired_access, &op->dsize, @@ -99,16 +98,12 @@ smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) } } - 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; + op->op_oplock_level = SMB_OPLOCK_NONE; + if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) { + if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH) + op->op_oplock_level = SMB_OPLOCK_BATCH; + else + op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; } if (sd_len) { @@ -155,7 +150,14 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) if ((op->create_options & FILE_DELETE_ON_CLOSE) && !(op->desired_access & DELETE)) { - smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); + smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, + ERRDOS, ERRbadaccess); + return (SDRC_ERROR); + } + + if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) { + smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, + ERRDOS, ERRbadaccess); return (SDRC_ERROR); } @@ -175,8 +177,7 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) op->fqi.dir_snode = sr->tid_tree->t_snode; } else { sr->smb_fid = (ushort_t)op->rootdirfid; - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, - sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); @@ -193,17 +194,17 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) return (SDRC_ERROR); if (STYPE_ISDSK(sr->tid_tree->t_res_type)) { - switch (MYF_OPLOCK_TYPE(op->my_flags)) { - case MYF_EXCLUSIVE_OPLOCK : + switch (op->op_oplock_level) { + case SMB_OPLOCK_EXCLUSIVE: OplockLevel = 1; break; - case MYF_BATCH_OPLOCK : + case SMB_OPLOCK_BATCH: OplockLevel = 2; break; - case MYF_LEVEL_II_OPLOCK : + case SMB_OPLOCK_LEVEL_II: OplockLevel = 3; break; - case MYF_OPLOCK_NONE : + case SMB_OPLOCK_NONE: default: OplockLevel = 0; break; 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 index 447eceedd1..839748bbd3 100644 --- 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 @@ -195,7 +195,7 @@ smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa) &CompletionFilter, &sr->smb_fid, &WatchTree) != 0) return (SDRC_NOT_IMPLEMENTED); - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); 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 index 1ea9dd57aa..4d4abf86f4 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -79,7 +79,7 @@ smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa) return (SDRC_ERROR); } - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -171,7 +171,7 @@ smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa) return (SDRC_ERROR); } - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); diff --git a/usr/src/uts/common/fs/smbsrv/smb_odir.c b/usr/src/uts/common/fs/smbsrv/smb_odir.c index d1adfd614b..571c1efde2 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_odir.c +++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c @@ -973,7 +973,7 @@ smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od, /* check search attributes */ dosattr = smb_node_get_dosattr(fnode); - if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) { + if (!smb_sattr_check(dosattr, od->d_sattr)) { smb_node_release(fnode); return (ENOENT); } @@ -1063,7 +1063,7 @@ smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od, /* check search attributes */ dosattr = smb_node_get_dosattr(fnode); - if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) { + if (!smb_sattr_check(dosattr, od->d_sattr)) { smb_node_release(fnode); return (ENOENT); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c index 7f12c2acbf..de3ec1837b 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c +++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -220,6 +220,10 @@ smb_ofile_open( } else { ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */ ASSERT(node); + + if (of->f_granted_access == FILE_EXECUTE) + of->f_flags |= SMB_OFLAGS_EXECONLY; + if (crgetuid(of->f_cr) == node->attr.sa_vattr.va_uid) { /* * Add this bit for the file's owner even if it's not @@ -251,9 +255,8 @@ smb_ofile_open( if (op->created_readonly) node->readonly_creator = of; - 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_node_add_ofile(node, of); + smb_node_inc_open_ofiles(node); } smb_llist_enter(&tree->t_ofile_list, RW_WRITER); smb_llist_insert_tail(&tree->t_ofile_list, of); @@ -292,7 +295,6 @@ smb_ofile_close( * For files created readonly, propagate the readonly * bit to the ofile now */ - if (of->f_node->readonly_creator == of) { of->f_node->attr.sa_dosattr |= FILE_ATTRIBUTE_READONLY; @@ -303,7 +305,6 @@ smb_ofile_close( smb_ofile_close_timestamp_update(of, last_wtime); (void) smb_sync_fsattr(NULL, of->f_cr, of->f_node); smb_commit_delete_on_close(of); - smb_oplock_release(of->f_node, B_FALSE); smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid); smb_node_destroy_lock_by_ofile(of->f_node, of); @@ -324,6 +325,11 @@ smb_ofile_close( ASSERT(of->f_refcnt); ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); of->f_state = SMB_OFILE_STATE_CLOSED; + if (of->f_oplock_granted) { + smb_node_dec_open_ofiles(of->f_node); + smb_oplock_release(of->f_node, of); + of->f_oplock_granted = B_FALSE; + } mutex_exit(&of->f_mutex); return; } @@ -403,6 +409,9 @@ smb_ofile_release( ASSERT(of->f_magic == SMB_OFILE_MAGIC); mutex_enter(&of->f_mutex); + if (of->f_oplock_exit) + if (smb_oplock_exit(of->f_node)) + of->f_oplock_exit = B_FALSE; ASSERT(of->f_refcnt); of->f_refcnt--; switch (of->f_state) { @@ -599,13 +608,11 @@ smb_ofile_close_timestamp_update( * */ boolean_t -smb_ofile_is_open( - smb_ofile_t *of) +smb_ofile_is_open(smb_ofile_t *of) { boolean_t rc = B_FALSE; - ASSERT(of); - ASSERT(of->f_magic == SMB_OFILE_MAGIC); + SMB_OFILE_VALID(of); mutex_enter(&of->f_mutex); if (of->f_state == SMB_OFILE_STATE_OPEN) { @@ -615,6 +622,17 @@ smb_ofile_is_open( return (rc); } +void +smb_ofile_set_oplock_granted(smb_ofile_t *of) +{ + SMB_OFILE_VALID(of); + mutex_enter(&of->f_mutex); + ASSERT(!of->f_oplock_granted); + of->f_oplock_granted = B_TRUE; + of->f_oplock_exit = B_TRUE; + mutex_exit(&of->f_mutex); +} + /* *************************** Static Functions ***************************** */ /* @@ -697,9 +715,7 @@ smb_ofile_delete( } 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_rem_ofile(of->f_node, of); smb_node_release(of->f_node); } @@ -763,7 +779,7 @@ smb_ofile_open_check( mutex_enter(&of->f_mutex); - if (of->f_state != SMB_OFILE_STATE_OPEN) { + if (of->f_state != SMB_OFILE_STATE_OPEN) { mutex_exit(&of->f_mutex); return (NT_STATUS_INVALID_HANDLE); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c index 74a1d27830..8b8d7802a0 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c +++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c @@ -19,19 +19,16 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include <smbsrv/smb_vops.h> +#include <smbsrv/smb_incl.h> -/* - * This module provides the common open functionality to the various - * open and create SMB interface functions. - */ +int smb_open_dsize_check = 0; /* - * * Client Request Description * ================================== ================================= * @@ -122,11 +119,7 @@ * 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. @@ -255,15 +248,6 @@ smb_com_open(smb_request_t *sr) 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_error(sr, NT_STATUS_INVALID_PARAMETER, - ERRDOS, ERROR_INVALID_PARAMETER); - return (SDRC_ERROR); - } - - op->dsize = 0; /* Don't set spurious size */ op->crtime.tv_sec = op->crtime.tv_nsec = 0; op->create_disposition = FILE_OPEN; op->create_options = FILE_NON_DIRECTORY_FILE; @@ -271,23 +255,24 @@ smb_com_open(smb_request_t *sr) op->create_options |= FILE_WRITE_THROUGH; 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 (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) + op->op_oplock_level = SMB_OPLOCK_BATCH; + else + op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; + } else { + op->op_oplock_level = SMB_OPLOCK_NONE; } if (smb_common_open(sr) != NT_STATUS_SUCCESS) return (SDRC_ERROR); - if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) { + if (op->op_oplock_level == SMB_OPLOCK_NONE) { sr->smb_flg &= ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY); } - if (op->dsize > UINT_MAX) { - smbsr_error(sr, 0, ERRDOS, ERRbadfunc); + if (smb_open_dsize_check && op->dsize > UINT_MAX) { + smbsr_error(sr, 0, ERRDOS, ERRbadaccess); return (SDRC_ERROR); } @@ -300,7 +285,7 @@ smb_com_open(smb_request_t *sr) file_attr, smb_gmt2local(sr, node->attr.sa_vattr.va_mtime.tv_sec), (uint32_t)op->dsize, - op->omode & SMB_DA_ACCESS_MASK, + op->omode, (uint16_t)0); /* bcc */ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); @@ -318,14 +303,13 @@ smb_pre_open_andx(smb_request_t *sr) uint16_t flags; uint32_t creation_time; uint16_t file_attr, sattr; - uint16_t ofun; int rc; bzero(op, sizeof (sr->arg.open)); rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com, &sr->andx_off, &flags, &op->omode, &sattr, - &file_attr, &creation_time, &ofun, &op->dsize, &op->timeo); + &file_attr, &creation_time, &op->ofun, &op->dsize, &op->timeo); if (rc == 0) { rc = smbsr_decode_data(sr, "%u", sr, &op->fqi.path); @@ -333,15 +317,17 @@ smb_pre_open_andx(smb_request_t *sr) op->dattr = file_attr; if (flags & 2) - op->my_flags = MYF_EXCLUSIVE_OPLOCK; + op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; else if (flags & 4) - op->my_flags = MYF_BATCH_OPLOCK; + op->op_oplock_level = SMB_OPLOCK_BATCH; + else + op->op_oplock_level = SMB_OPLOCK_NONE; if ((creation_time != 0) && (creation_time != UINT_MAX)) op->crtime.tv_sec = smb_local2gmt(sr, creation_time); op->crtime.tv_nsec = 0; - op->create_disposition = smb_ofun_to_crdisposition(ofun); + op->create_disposition = smb_ofun_to_crdisposition(op->ofun); } DTRACE_SMB_2(op__OpenX__start, smb_request_t *, sr, @@ -361,21 +347,13 @@ smb_com_open_andx(smb_request_t *sr) { struct open_param *op = &sr->arg.open; uint16_t file_attr; - uint16_t granted_access; int rc; 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_error(sr, NT_STATUS_INVALID_PARAMETER, - ERRDOS, ERROR_INVALID_PARAMETER); - return (SDRC_ERROR); - } - - if (op->create_disposition == ((uint32_t)SMB_INVALID_CRDISPOSITION)) { - smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_PARAMETER); + if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) { + smbsr_error(sr, 0, ERRDOS, ERRbadaccess); return (SDRC_ERROR); } @@ -386,19 +364,15 @@ smb_com_open_andx(smb_request_t *sr) if (smb_common_open(sr) != NT_STATUS_SUCCESS) return (SDRC_ERROR); - if (op->dsize > UINT_MAX) { - smbsr_error(sr, 0, ERRDOS, ERRbadfunc); + if (smb_open_dsize_check && op->dsize > UINT_MAX) { + smbsr_error(sr, 0, ERRDOS, ERRbadaccess); return (SDRC_ERROR); } - if (MYF_OPLOCK_TYPE(op->my_flags) != MYF_OPLOCK_NONE) { + if (op->op_oplock_level != SMB_OPLOCK_NONE) op->action_taken |= SMB_OACT_LOCK; - } else { + else op->action_taken &= ~SMB_OACT_LOCK; - } - - granted_access = (SMB_TREE_IS_READONLY(sr)) - ? 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)) { @@ -411,7 +385,7 @@ smb_com_open_andx(smb_request_t *sr) file_attr, smb_gmt2local(sr, node->attr.sa_vattr.va_mtime.tv_sec), (uint32_t)op->dsize, - granted_access, op->ftype, + op->omode, op->ftype, op->devstate, op->action_taken, op->fileid, 0); @@ -424,7 +398,7 @@ smb_com_open_andx(smb_request_t *sr) file_attr, 0L, 0L, - granted_access, op->ftype, + op->omode, op->ftype, op->devstate, op->action_taken, op->fileid, 0); @@ -432,3 +406,77 @@ smb_com_open_andx(smb_request_t *sr) return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } + +smb_sdrc_t +smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa) +{ + struct open_param *op = &sr->arg.open; + uint32_t creation_time; + uint32_t alloc_size; + uint16_t flags; + uint16_t file_attr; + int rc; + + bzero(op, sizeof (sr->arg.open)); + + rc = smb_mbc_decodef(&xa->req_param_mb, "%wwwwlwl10.u", + sr, &flags, &op->omode, &op->fqi.srch_attr, &file_attr, + &creation_time, &op->ofun, &alloc_size, &op->fqi.path); + if (rc != 0) + return (SDRC_ERROR); + + if ((creation_time != 0) && (creation_time != UINT_MAX)) + op->crtime.tv_sec = smb_local2gmt(sr, creation_time); + op->crtime.tv_nsec = 0; + + op->dattr = file_attr; + op->dsize = alloc_size; + op->create_options = FILE_NON_DIRECTORY_FILE; + + op->desired_access = smb_omode_to_amask(op->omode); + op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path); + + op->create_disposition = smb_ofun_to_crdisposition(op->ofun); + if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) + op->create_disposition = FILE_CREATE; + + if (op->omode & SMB_DA_WRITE_THROUGH) + op->create_options |= FILE_WRITE_THROUGH; + + if (sr->smb_flg & SMB_FLAGS_OPLOCK) { + if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) + op->op_oplock_level = SMB_OPLOCK_BATCH; + else + op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; + } else { + op->op_oplock_level = SMB_OPLOCK_NONE; + } + + if (smb_common_open(sr) != NT_STATUS_SUCCESS) + return (SDRC_ERROR); + + if (op->op_oplock_level != SMB_OPLOCK_NONE) + op->action_taken |= SMB_OACT_LOCK; + else + op->action_taken &= ~SMB_OACT_LOCK; + + file_attr = op->dattr & FILE_ATTRIBUTE_MASK; + + if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) + op->dsize = 0; + + (void) smb_mbc_encodef(&xa->rep_param_mb, "wwllwwwwlwl", + sr->smb_fid, + file_attr, + (uint32_t)0, /* creation time */ + (uint32_t)op->dsize, + op->omode, + op->ftype, + op->devstate, + op->action_taken, + op->fileid, + (uint16_t)0, /* EA error offset */ + (uint32_t)0); /* EA list length */ + + return (SDRC_SUCCESS); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_oplock.c b/usr/src/uts/common/fs/smbsrv/smb_oplock.c index 3d5efdfb43..9044ee880c 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c +++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c @@ -22,9 +22,6 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "@(#)smb_oplock.c 1.5 08/08/07 SMI" - /* * SMB Locking library functions. */ @@ -33,9 +30,7 @@ #include <smbsrv/smb_fsops.h> #include <inet/tcp.h> -/* - * Oplock functionality enable/disable - */ +static void smb_oplock_enter(smb_node_t *); /* * Magic 0xFF 'S' 'M' 'B' @@ -118,7 +113,8 @@ * smb_oplock_acquire * * Attempt to acquire an oplock. Note that the oplock granted may be - * none, i.e. the oplock was not granted. + * none, i.e. the oplock was not granted. The result of the acquisition is + * provided in ol->ol_level. * * Grant an oplock to the requestor if this session is the only one * that has the file open, regardless of the number of instances of @@ -132,100 +128,99 @@ * depending on what action is taken by the other client (unlock or close), * an oplock may or may not be granted. (The breaking of an oplock is * done earlier in the calling path.) - * - * XXX: Node synchronization is not yet implemented. However, racing - * opens are handled thus: - * - * A racing oplock acquire can happen in the open path between - * smb_oplock_break() and smb_fsop_open(), but no later. (Once - * the file is open via smb_fsop_open()/VOP_OPEN, - * smb_fsop_oplock_install() will not be able to install an oplock, - * which requires an open count of 1.) - * - * Hence, we can safely break any oplock that came in after the - * smb_oplock_break() done previously in the open path, knowing that - * no other racing oplock acquisitions should be able to succeed - * because we already have the file open (see above). - * - * The type of oplock being requested is passed in op->my_flags. The result - * is also returned in op->my_flags. - * - * (Note that exclusive and batch oplocks are treated interchangeably.) - * - * The Returns NT status codes: - * NT_STATUS_SUCCESS - * NT_STATUS_CONNECTION_DISCONNECTED */ -DWORD -smb_oplock_acquire( - smb_request_t *sr, - smb_ofile_t *of, - struct open_param *op) +void +smb_oplock_acquire(smb_node_t *node, smb_ofile_t *of, open_param_t *op) { - smb_node_t *node; - unsigned int level; + smb_session_t *session; + smb_oplock_t *ol; + clock_t time; - ASSERT(sr); - ASSERT(of); - ASSERT(op); - ASSERT(op->fqi.last_attr.sa_vattr.va_type == VREG); + SMB_NODE_VALID(node); + SMB_OFILE_VALID(of); - level = op->my_flags & MYF_OPLOCK_MASK; + ASSERT(node == SMB_OFILE_GET_NODE(of)); - op->my_flags &= ~MYF_OPLOCK_MASK; + session = SMB_OFILE_GET_SESSION(of); - if ((sr->sr_cfg->skc_oplock_enable == 0) || - smb_tree_has_feature(of->f_tree, SMB_TREE_NO_OPLOCKS)) - return (NT_STATUS_SUCCESS); + if (!smb_session_oplocks_enable(session) || + smb_tree_has_feature(SMB_OFILE_GET_TREE(of), SMB_TREE_NO_OPLOCKS)) { + /* This implies that trees cannot overlap. */ + op->op_oplock_level = SMB_OPLOCK_NONE; + return; + } - if (!((MYF_IS_EXCLUSIVE_OPLOCK(level)) || - (MYF_IS_BATCH_OPLOCK(level)))) - return (NT_STATUS_SUCCESS); + ol = &node->n_oplock; + time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt(); - node = of->f_node; + mutex_enter(&node->n_mutex); - smb_rwx_rwenter(&node->n_lock, RW_WRITER); + for (;;) { + int rc; - if (EXCLUSIVE_OPLOCK_IN_FORCE(node) || - BATCH_OPLOCK_IN_FORCE(node)) { + smb_oplock_enter(node); - smb_rwx_rwexit(&node->n_lock); + if (node->n_state == SMB_NODE_STATE_AVAILABLE) { + if ((op->op_oplock_level == SMB_OPLOCK_LEVEL_II) || + (op->op_oplock_level == SMB_OPLOCK_NONE) || + (node->n_open_count > 1)) { + mutex_exit(&node->n_mutex); + op->op_oplock_level = SMB_OPLOCK_NONE; + return; + } + ol->ol_ofile = of; + ol->ol_sess_id = SMB_SESSION_GET_ID(session); + ol->ol_level = op->op_oplock_level; + ol->ol_xthread = curthread; + node->n_state = SMB_NODE_STATE_OPLOCK_GRANTED; + mutex_exit(&node->n_mutex); + if (smb_fsop_oplock_install(node, of->f_mode) == 0) { + smb_ofile_set_oplock_granted(of); + return; + } + mutex_enter(&node->n_mutex); + ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED); + node->n_state = SMB_NODE_STATE_AVAILABLE; + ol->ol_xthread = NULL; + op->op_oplock_level = SMB_OPLOCK_NONE; + if (ol->ol_waiters_count != 0) + cv_broadcast(&ol->ol_cv); + break; + } - if (SMB_SAME_SESSION(sr->session, - node->n_oplock.op_ofile->f_session)) { - op->my_flags |= level; - return (NT_STATUS_SUCCESS); - } else if (SMB_ATTR_ONLY_OPEN(op)) { - ASSERT(!(op->my_flags & MYF_OPLOCK_MASK)); - return (NT_STATUS_SUCCESS); + if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) { + if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id) + break; + node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING; + smb_session_oplock_break( + SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile); } - smb_oplock_break(node); + ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING); - smb_rwx_rwenter(&node->n_lock, RW_WRITER); - } + ol->ol_waiters_count++; + rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time); + ol->ol_waiters_count--; - if (smb_fsop_oplock_install(node, of->f_mode) != 0) { - smb_rwx_rwexit(&node->n_lock); - return (NT_STATUS_SUCCESS); + if (rc == -1) { + /* + * Oplock release timed out. + */ + if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) { + node->n_state = SMB_NODE_STATE_AVAILABLE; + ol->ol_xthread = curthread; + mutex_exit(&node->n_mutex); + smb_fsop_oplock_uninstall(node); + smb_session_oplock_break_timedout( + SMB_OFILE_GET_SESSION(ol->ol_ofile)); + mutex_enter(&node->n_mutex); + ol->ol_xthread = NULL; + if (ol->ol_waiters_count != 0) + cv_broadcast(&ol->ol_cv); + } + } } - - node->n_oplock.op_ofile = of; - node->n_oplock.op_ipaddr = sr->session->ipaddr; - node->n_oplock.op_kid = sr->session->s_kid; - node->flags &= ~NODE_OPLOCKS_IN_FORCE; - - if (MYF_IS_EXCLUSIVE_OPLOCK(level)) - node->flags |= NODE_EXCLUSIVE_OPLOCK; - - if (MYF_IS_BATCH_OPLOCK(level)) - node->flags |= NODE_BATCH_OPLOCK; - - op->my_flags |= level; - - smb_rwx_rwexit(&node->n_lock); - - return (NT_STATUS_SUCCESS); + mutex_exit(&node->n_mutex); } /* @@ -233,207 +228,116 @@ smb_oplock_acquire( * * 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 + * Returns: + * + * B_TRUE The oplock is broken. + * B_FALSE The oplock is being broken. This is returned if nowait is set + * to B_TRUE; */ - -void -smb_oplock_break(smb_node_t *node) +boolean_t +smb_oplock_break(smb_node_t *node, uint64_t sess_id, boolean_t nowait) { - smb_session_t *oplock_session; - smb_ofile_t *oplock_ofile; - struct mbuf_chain mbc; - int retries = 0; - clock_t elapsed_time; - clock_t max_time; - boolean_t flag; - - smb_rwx_rwenter(&node->n_lock, RW_WRITER); - - if (!OPLOCKS_IN_FORCE(node)) { - smb_rwx_rwexit(&node->n_lock); - return; - } - - 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. - */ - if (!OPLOCKS_IN_FORCE(node)) { - smb_rwx_rwexit(&node->n_lock); - return; - } else { - /* - * This is an anomalous condition. - * Cancel/release the oplock. - */ - smb_oplock_release(node, B_TRUE); - smb_rwx_rwexit(&node->n_lock); - return; - } - } - - oplock_ofile = node->n_oplock.op_ofile; - ASSERT(oplock_ofile); - - oplock_session = oplock_ofile->f_session; - ASSERT(oplock_session); - - /* - * Start oplock break. - */ - - node->n_oplock.op_flags |= OPLOCK_FLAG_BREAKING; - - smb_rwx_rwexit(&node->n_lock); - - max_time = MSEC_TO_TICK(smb_oplock_timeout); - do { - MBC_INIT(&mbc, MLEN); - (void) smb_mbc_encodef(&mbc, "Mb19.wwwwbb3.ww10.", - SMB_COM_LOCKING_ANDX, oplock_ofile->f_tree->t_tid, - 0xffff, 0, 0xffff, 8, 0xff, oplock_ofile->f_fid, - LOCKING_ANDX_OPLOCK_RELEASE); - - flag = B_TRUE; - smb_rwx_rwenter(&oplock_session->s_lock, RW_WRITER); - while (flag) { - switch (oplock_session->s_state) { - case SMB_SESSION_STATE_DISCONNECTED: - case SMB_SESSION_STATE_TERMINATED: - smb_rwx_rwexit(&oplock_session->s_lock); - smb_rwx_rwenter(&node->n_lock, RW_WRITER); + smb_oplock_t *ol; + clock_t time; - node->flags &= ~NODE_OPLOCKS_IN_FORCE; - node->n_oplock.op_flags &= - ~OPLOCK_FLAG_BREAKING; - node->n_oplock.op_ofile = NULL; - bzero(&node->n_oplock.op_ipaddr, - sizeof (node->n_oplock.op_ipaddr)); - node->n_oplock.op_kid = 0; + SMB_NODE_VALID(node); + ol = &node->n_oplock; + time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt(); - smb_rwx_rwexit(&node->n_lock); + mutex_enter(&node->n_mutex); + if (ol->ol_sess_id == sess_id) { + mutex_exit(&node->n_mutex); + return (B_TRUE); + } - return; + for (;;) { + int rc; - case SMB_SESSION_STATE_OPLOCK_BREAKING: - flag = B_FALSE; - break; + smb_oplock_enter(node); - case SMB_SESSION_STATE_NEGOTIATED: - oplock_session->s_state = - SMB_SESSION_STATE_OPLOCK_BREAKING; - flag = B_FALSE; - break; - - default: - (void) smb_rwx_rwwait(&oplock_session->s_lock, - -1); - break; - } + if (node->n_state == SMB_NODE_STATE_AVAILABLE) { + mutex_exit(&node->n_mutex); + return (B_TRUE); } - smb_rwx_rwexit(&oplock_session->s_lock); - (void) smb_session_send(oplock_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 (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) { + node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING; + smb_session_oplock_break( + SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile); } - if (!OPLOCKS_IN_FORCE(node)) { + ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING); + if (nowait) { + mutex_exit(&node->n_mutex); + return (B_FALSE); + } + ol->ol_waiters_count++; + rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time); + ol->ol_waiters_count--; + if (rc == -1) { /* - * smb_oplock_release() was called + * Oplock release timed out. */ - smb_rwx_rwexit(&node->n_lock); - return; + if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) { + node->n_state = SMB_NODE_STATE_AVAILABLE; + ol->ol_xthread = curthread; + mutex_exit(&node->n_mutex); + smb_fsop_oplock_uninstall(node); + smb_session_oplock_break_timedout( + SMB_OFILE_GET_SESSION(ol->ol_ofile)); + mutex_enter(&node->n_mutex); + ol->ol_xthread = NULL; + if (ol->ol_waiters_count != 0) + cv_broadcast(&ol->ol_cv); + break; + } } - } while (++retries < OPLOCK_RETRIES); - - /* - * Retries exhausted and timed out. - * Cancel the oplock and continue. - */ - - smb_oplock_release(node, B_TRUE); - - smb_rwx_rwexit(&node->n_lock); + } + mutex_exit(&node->n_mutex); + return (B_TRUE); } /* * smb_oplock_release * - * This function uninstalls the FEM oplock monitors and - * clears all flags in relation to an oplock on the - * given node. - * - * The function can be called with the node->n_lock held - * or not held. + * This function releases the oplock on the node passed in. If other threads + * were waiting for the oplock to be released they are signaled. */ - -void /*ARGSUSED*/ -smb_oplock_release(smb_node_t *node, boolean_t have_rwx) +void +smb_oplock_release(smb_node_t *node, smb_ofile_t *of) { - if (!have_rwx) - smb_rwx_rwenter(&node->n_lock, RW_WRITER); + smb_oplock_t *ol; + + SMB_NODE_VALID(node); + ol = &node->n_oplock; + + mutex_enter(&node->n_mutex); + smb_oplock_enter(node); + switch (node->n_state) { + case SMB_NODE_STATE_AVAILABLE: + break; + + case SMB_NODE_STATE_OPLOCK_GRANTED: + case SMB_NODE_STATE_OPLOCK_BREAKING: + if (ol->ol_ofile == of) { + node->n_state = SMB_NODE_STATE_AVAILABLE; + ol->ol_xthread = curthread; + mutex_exit(&node->n_mutex); + smb_fsop_oplock_uninstall(node); + smb_session_oplock_released( + SMB_OFILE_GET_SESSION(ol->ol_ofile)); + mutex_enter(&node->n_mutex); + ol->ol_xthread = NULL; + if (ol->ol_waiters_count != 0) + cv_broadcast(&ol->ol_cv); + } + break; - if (!OPLOCKS_IN_FORCE(node)) { - if (!have_rwx) - smb_rwx_rwexit(&node->n_lock); - return; + default: + SMB_PANIC(); } - - smb_fsop_oplock_uninstall(node); - - node->flags &= ~NODE_OPLOCKS_IN_FORCE; - node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING; - node->n_oplock.op_ofile = NULL; - bzero(&node->n_oplock.op_ipaddr, sizeof (node->n_oplock.op_ipaddr)); - node->n_oplock.op_kid = 0; - - if (!have_rwx) - smb_rwx_rwexit(&node->n_lock); + mutex_exit(&node->n_mutex); } /* @@ -443,37 +347,97 @@ smb_oplock_release(smb_node_t *node, boolean_t have_rwx) * Other CIFS functions may call smb_oplock_conflict() with a session * pointer so as to do the session check. */ - boolean_t -smb_oplock_conflict(smb_node_t *node, smb_session_t *session, - struct open_param *op) +smb_oplock_conflict(smb_node_t *node, smb_session_t *session, open_param_t *op) { - smb_session_t *oplock_session; - smb_ofile_t *oplock_ofile; + boolean_t rb; + + SMB_NODE_VALID(node); + SMB_SESSION_VALID(session); + + mutex_enter(&node->n_mutex); + smb_oplock_enter(node); + switch (node->n_state) { + case SMB_NODE_STATE_AVAILABLE: + rb = B_FALSE; + break; + + case SMB_NODE_STATE_OPLOCK_GRANTED: + case SMB_NODE_STATE_OPLOCK_BREAKING: + if (SMB_SESSION_GET_ID(session) == node->n_oplock.ol_sess_id) { + rb = B_FALSE; + break; + } - smb_rwx_rwenter(&node->n_lock, RW_READER); + if (op != NULL) { + if (((op->desired_access & ~(FILE_READ_ATTRIBUTES | + FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) && + (op->create_disposition != FILE_SUPERSEDE) && + (op->create_disposition != FILE_OVERWRITE)) { + /* Attributs only */ + rb = B_FALSE; + break; + } + } + rb = B_TRUE; + break; - if (!OPLOCKS_IN_FORCE(node)) { - smb_rwx_rwexit(&node->n_lock); - return (B_FALSE); + default: + SMB_PANIC(); } + mutex_exit(&node->n_mutex); + return (rb); +} - oplock_ofile = node->n_oplock.op_ofile; - ASSERT(oplock_ofile); - - oplock_session = oplock_ofile->f_session; - ASSERT(oplock_session); - - if (SMB_SAME_SESSION(session, oplock_session)) { - smb_rwx_rwexit(&node->n_lock); - return (B_FALSE); +/* + * smb_oplock_exit + * + * The the calling thread has the pointer to its context stored in ol_thread + * it resets that field. If any other thread is waiting for that field to + * turn to NULL it is signaled. + * + * Returns: + * B_TRUE Oplock unlocked + * B_FALSE Oplock still locked + */ +boolean_t +smb_oplock_exit(smb_node_t *node) +{ + smb_oplock_t *ol; + boolean_t rb; + + SMB_NODE_VALID(node); + ol = &node->n_oplock; + rb = B_FALSE; + + mutex_enter(&node->n_mutex); + if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) { + ol->ol_xthread = NULL; + if (ol->ol_waiters_count != 0) + cv_broadcast(&ol->ol_cv); + rb = B_TRUE; } + mutex_exit(&node->n_mutex); + return (rb); +} - if (SMB_ATTR_ONLY_OPEN(op)) { - smb_rwx_rwexit(&node->n_lock); - return (B_FALSE); - } +/* + * smb_oplock_wait + * + * The mutex of the node must have benn entered before calling this function. + * If the field ol_xthread is not NULL and doesn't contain the pointer to the + * context of the calling thread, the caller will sleep until that field is + * reset (set to NULL). + */ +static void +smb_oplock_enter(smb_node_t *node) +{ + smb_oplock_t *ol = &node->n_oplock; - smb_rwx_rwexit(&node->n_lock); - return (B_TRUE); + if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) { + ol->ol_waiters_count++; + while (ol->ol_xthread != NULL) + cv_wait(&ol->ol_cv, &node->n_mutex); + ol->ol_waiters_count--; + } } 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 index 0b9eb8cba9..9f65ebc4e4 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c +++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c @@ -443,10 +443,16 @@ smb_pathname( if ((err = pn_getcomponent(&upn, component)) != 0) break; - if (smb_maybe_mangled_name(component)) { + /* + * This mangled name handling is in the wrong place. + * The name must be looked up prior to any mangled + * name checking. + * + * Temporary: check for ~ to keep smbtorture quiet. + */ + if (*component != '~' && smb_maybe_mangled_name(component)) { if ((err = smb_unmangle_name(sr, cred, dnode, - component, real_name, MAXNAMELEN, 0, 0, - 1)) != 0) + component, real_name, MAXNAMELEN, 0, 0, 1)) != 0) break; /* * Do not pass FIGNORECASE to lookuppnvp(). diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c index d8f6d131b5..5a793df1ab 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c +++ b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * SMB: query_information2 * @@ -89,8 +87,7 @@ smb_com_query_information2(smb_request_t *sr) uint16_t dattr; int rc; - - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); diff --git a/usr/src/uts/common/fs/smbsrv/smb_read.c b/usr/src/uts/common/fs/smbsrv/smb_read.c index 374b32d1bf..289d089450 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_read.c +++ b/usr/src/uts/common/fs/smbsrv/smb_read.c @@ -19,17 +19,26 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#include <sys/syslog.h> #include <smbsrv/smb_incl.h> #include <smbsrv/smb_fsops.h> -int smb_common_read(smb_request_t *, smb_rw_param_t *); +/* + * The maximum number of bytes to return from SMB Core + * SmbRead or SmbLockAndRead. + */ +#define SMB_CORE_READ_MAX 4432 + +/* + * The limit in bytes for SmbReadX. + */ +#define SMB_READX_MAX 0x10000 +int smb_common_read(smb_request_t *, smb_rw_param_t *); /* * Read bytes from a file or named pipe (SMB Core). @@ -51,6 +60,7 @@ smb_pre_read(smb_request_t *sr) { smb_rw_param_t *param; uint32_t off_low; + uint16_t count; uint16_t remcnt; int rc; @@ -58,9 +68,10 @@ smb_pre_read(smb_request_t *sr) sr->arg.rw = param; rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, - ¶m->rw_count, &off_low, &remcnt); + &count, &off_low, &remcnt); param->rw_offset = (uint64_t)off_low; + param->rw_count = (uint32_t)count; param->rw_mincnt = 0; DTRACE_SMB_2(op__Read__start, smb_request_t *, sr, @@ -82,9 +93,10 @@ smb_sdrc_t smb_com_read(smb_request_t *sr) { smb_rw_param_t *param = sr->arg.rw; + uint16_t count; int rc; - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -92,13 +104,17 @@ smb_com_read(smb_request_t *sr) sr->user_cr = smb_ofile_getcred(sr->fid_ofile); + if (param->rw_count > SMB_CORE_READ_MAX) + param->rw_count = SMB_CORE_READ_MAX; + if ((rc = smb_common_read(sr, param)) != 0) { smbsr_errno(sr, rc); return (SDRC_ERROR); } + count = (uint16_t)param->rw_count; rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", - 5, param->rw_count, VAR_BCC, 0x01, param->rw_count, &sr->raw_data); + 5, count, VAR_BCC, 0x01, count, &sr->raw_data); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } @@ -129,17 +145,19 @@ smb_sdrc_t smb_pre_lock_and_read(smb_request_t *sr) { smb_rw_param_t *param; - uint16_t remcnt; uint32_t off_low; + uint16_t count; + uint16_t remcnt; int rc; param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); sr->arg.rw = param; rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, - ¶m->rw_count, &off_low, &remcnt); + &count, &off_low, &remcnt); param->rw_offset = (uint64_t)off_low; + param->rw_count = (uint32_t)count; param->rw_mincnt = 0; DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr, @@ -162,6 +180,7 @@ smb_com_lock_and_read(smb_request_t *sr) { smb_rw_param_t *param = sr->arg.rw; DWORD status; + uint16_t count; int rc; if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { @@ -169,7 +188,7 @@ smb_com_lock_and_read(smb_request_t *sr) return (SDRC_ERROR); } - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -178,19 +197,24 @@ smb_com_lock_and_read(smb_request_t *sr) sr->user_cr = smb_ofile_getcred(sr->fid_ofile); status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count, - UINT_MAX, SMB_LOCK_TYPE_READWRITE); + 0, SMB_LOCK_TYPE_READWRITE); + if (status != NT_STATUS_SUCCESS) { smb_lock_range_error(sr, status); return (SDRC_ERROR); } + if (param->rw_count > SMB_CORE_READ_MAX) + param->rw_count = SMB_CORE_READ_MAX; + if ((rc = smb_common_read(sr, param)) != 0) { smbsr_errno(sr, rc); return (SDRC_ERROR); } + count = (uint16_t)param->rw_count; rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", - 5, param->rw_count, VAR_BCC, 0x1, param->rw_count, &sr->raw_data); + 5, count, VAR_BCC, 0x1, count, &sr->raw_data); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } @@ -214,6 +238,7 @@ smb_com_lock_and_read(smb_request_t *sr) * we send a zero length session packet, which will force the client to * retry the read. * + * Do not return errors from SmbReadRaw. * Read errors are handled by sending a zero length response. */ smb_sdrc_t @@ -223,6 +248,7 @@ smb_pre_read_raw(smb_request_t *sr) uint32_t off_low; uint32_t off_high; uint32_t timeout; + uint16_t count; int rc; param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); @@ -230,25 +256,43 @@ smb_pre_read_raw(smb_request_t *sr) if (sr->smb_wct == 8) { rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid, - &off_low, ¶m->rw_count, ¶m->rw_mincnt, - &timeout); - param->rw_offset = (uint64_t)off_low; + &off_low, &count, ¶m->rw_mincnt, &timeout); + if (rc == 0) { + param->rw_offset = (uint64_t)off_low; + param->rw_count = (uint32_t)count; + } } else { rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid, - &off_low, ¶m->rw_count, ¶m->rw_mincnt, - &timeout, &off_high); - param->rw_offset = ((uint64_t)off_high << 32) | off_low; + &off_low, &count, ¶m->rw_mincnt, &timeout, &off_high); + if (rc == 0) { + param->rw_offset = ((uint64_t)off_high << 32) | off_low; + param->rw_count = (uint32_t)count; + } } DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr, smb_rw_param_t *, param); - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); + return (SDRC_SUCCESS); } void smb_post_read_raw(smb_request_t *sr) { + mbuf_chain_t *mbc; + + if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) { + sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; + + while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) != + NULL) { + SMB_MBC_VALID(mbc); + list_remove(&sr->session->s_oplock_brkreqs, mbc); + (void) smb_session_send(sr->session, 0, mbc); + smb_mbc_free(mbc); + } + } + DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr, smb_rw_param_t *, sr->arg.rw); @@ -259,22 +303,24 @@ smb_sdrc_t smb_com_read_raw(smb_request_t *sr) { smb_rw_param_t *param = sr->arg.rw; - smb_node_t *node; - int rc; switch (sr->session->s_state) { case SMB_SESSION_STATE_NEGOTIATED: + sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE; break; 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_TERMINATED: case SMB_SESSION_STATE_DISCONNECTED: return (SDRC_NO_REPLY); + case SMB_SESSION_STATE_READ_RAW_ACTIVE: + sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; + return (SDRC_DROP_VC); + case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: case SMB_SESSION_STATE_CONNECTED: case SMB_SESSION_STATE_ESTABLISHED: @@ -282,27 +328,21 @@ smb_com_read_raw(smb_request_t *sr) return (SDRC_DROP_VC); } - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { - smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); - return (SDRC_ERROR); + (void) smb_session_send(sr->session, 0, NULL); + return (SDRC_NO_REPLY); } sr->user_cr = smb_ofile_getcred(sr->fid_ofile); - rc = smb_common_read(sr, param); - - 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 (param->rw_mincnt > param->rw_count) + param->rw_mincnt = 0; - if (rc != 0) { + if (smb_common_read(sr, param) != 0) { (void) smb_session_send(sr->session, 0, NULL); m_freem(sr->raw_data.chain); - sr->raw_data.chain = 0; + sr->raw_data.chain = NULL; } else { (void) smb_session_send(sr->session, 0, &sr->raw_data); } @@ -314,6 +354,12 @@ smb_com_read_raw(smb_request_t *sr) * 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. + * + * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4: + * If wct is 12 and CAP_LARGE_READX is set, the count may be larger + * than the negotiated buffer size. If maxcnt_high is 0xFF, it must + * be ignored. Otherwise, maxcnt_high represents the upper 16 bits + * of rw_count. */ smb_sdrc_t smb_pre_read_andx(smb_request_t *sr) @@ -321,6 +367,9 @@ smb_pre_read_andx(smb_request_t *sr) smb_rw_param_t *param; uint32_t off_low; uint32_t off_high; + uint32_t maxcnt_high; + uint16_t maxcnt_low; + uint16_t mincnt; uint16_t remcnt; int rc; @@ -328,16 +377,23 @@ smb_pre_read_andx(smb_request_t *sr) sr->arg.rw = param; if (sr->smb_wct == 12) { - rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", ¶m->rw_andx, - &sr->smb_fid, &off_low, ¶m->rw_count, &remcnt, - &off_high); + rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", ¶m->rw_andx, + &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high, + &remcnt, &off_high); + + param->rw_offset = ((uint64_t)off_high << 32) | + (uint64_t)off_low; - param->rw_offset = ((uint64_t)off_high << 32) | off_low; + param->rw_count = (uint32_t)maxcnt_low; + if (maxcnt_high < 0xFF) + param->rw_count |= maxcnt_high << 16; } else { - rc = smbsr_decode_vwv(sr, "b3.wlw6.w", ¶m->rw_andx, - &sr->smb_fid, &off_low, ¶m->rw_count, &remcnt); + rc = smbsr_decode_vwv(sr, "b3.wlwwlw", ¶m->rw_andx, + &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high, + &remcnt); param->rw_offset = (uint64_t)off_low; + param->rw_count = (uint32_t)maxcnt_low; } param->rw_mincnt = 0; @@ -361,10 +417,13 @@ smb_sdrc_t smb_com_read_andx(smb_request_t *sr) { smb_rw_param_t *param = sr->arg.rw; + uint16_t datalen_high; + uint16_t datalen_low; + uint16_t data_offset; uint16_t offset2; int rc; - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -372,41 +431,50 @@ smb_com_read_andx(smb_request_t *sr) sr->user_cr = smb_ofile_getcred(sr->fid_ofile); + if (param->rw_count >= SMB_READX_MAX) + param->rw_count = 0; + if ((rc = smb_common_read(sr, param)) != 0) { smbsr_errno(sr, rc); return (SDRC_ERROR); } - /* - * Ensure that the next response offset is zero - * if there is no secondary command. - */ - offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59; + datalen_low = param->rw_count & 0xFFFF; + datalen_high = (param->rw_count >> 16) & 0xFF; /* - * 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 this is a secondary command, the data offset + * includes the previous wct + sizeof(wct). */ + data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1; + if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { - rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC", + data_offset += 60; + offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60; + + rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC", 12, /* wct */ - param->rw_andx, /* Secondary andx command */ - offset2, /* offset to next */ - 0, /* must be 0 */ - param->rw_count, /* data byte count */ - 60, /* Offset from start to data */ + param->rw_andx, /* secondary andx command */ + offset2, /* offset to next command */ + 0, /* set to 0 for named pipes */ + datalen_low, /* data byte count */ + data_offset, /* offset from start to data */ + datalen_high, /* data byte count */ VAR_BCC, /* BCC marker */ - 0x02, /* unknown */ + 0x00, /* padding */ &sr->raw_data); } else { - rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC", + data_offset += 59; + offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59; + + rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC", 12, /* wct */ - param->rw_andx, /* Secondary andx command */ - offset2, /* offset to next */ - -1, /* must be -1 */ - param->rw_count, /* data byte count */ - 59, /* Offset from start to data */ + param->rw_andx, /* secondary andx command */ + offset2, /* offset to next command */ + -1, /* must be -1 for regular files */ + datalen_low, /* data byte count */ + data_offset, /* offset from start to data */ + datalen_high, /* data byte count */ VAR_BCC, /* BCC marker */ &sr->raw_data); } @@ -431,12 +499,12 @@ smb_common_read(smb_request_t *sr, smb_rw_param_t *param) struct mbuf *top; int rc; - vdb->tag = 0; - vdb->uio.uio_iov = &vdb->iovec[0]; - vdb->uio.uio_iovcnt = MAX_IOVEC; - vdb->uio.uio_resid = param->rw_count; - vdb->uio.uio_loffset = (offset_t)param->rw_offset; - vdb->uio.uio_segflg = UIO_SYSSPACE; + vdb->vdb_tag = 0; + vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0]; + vdb->vdb_uio.uio_iovcnt = MAX_IOVEC; + vdb->vdb_uio.uio_resid = param->rw_count; + vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset; + vdb->vdb_uio.uio_segflg = UIO_SYSSPACE; switch (sr->tid_tree->t_res_type & STYPE_MASK) { case STYPE_DISKTREE: @@ -451,21 +519,33 @@ smb_common_read(smb_request_t *sr, smb_rw_param_t *param) } } + if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) && + !(sr->smb_flg2 & SMB_FLAGS2_PAGING_IO)) { + /* + * SMB_FLAGS2_PAGING_IO: permit execute-only reads. + * + * Reject request if the file has been opened + * execute-only and SMB_FLAGS2_PAGING_IO is not set. + */ + rc = EACCES; + 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); + sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid; + top = smb_mbuf_allocate(&vdb->vdb_uio); - rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio, + rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio, &node->attr); - sr->raw_data.max_bytes -= vdb->uio.uio_resid; + sr->raw_data.max_bytes -= vdb->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_opipe_read(sr, &vdb->uio); + rc = smb_opipe_read(sr, &vdb->vdb_uio); break; default: @@ -473,7 +553,7 @@ smb_common_read(smb_request_t *sr, smb_rw_param_t *param) break; } - param->rw_count -= vdb->uio.uio_resid; + param->rw_count -= vdb->vdb_uio.uio_resid; if (rc != 0) return (rc); diff --git a/usr/src/uts/common/fs/smbsrv/smb_rename.c b/usr/src/uts/common/fs/smbsrv/smb_rename.c index f72ad16e1e..42fe8abac6 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_rename.c +++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "@(#)smb_rename.c 1.6 08/08/04 SMI" - #include <smbsrv/nterror.h> #include <sys/synch.h> #include <smbsrv/smb_incl.h> @@ -182,8 +180,8 @@ smb_do_rename( * has a file open, this will force a flush or close, * which may affect the outcome of any share checking. */ - - smb_oplock_break(src_node); + (void) smb_oplock_break(src_node, SMB_SESSION_GET_ID(sr->session), + B_FALSE); for (count = 0; count <= 3; count++) { if (count) { diff --git a/usr/src/uts/common/fs/smbsrv/smb_seek.c b/usr/src/uts/common/fs/smbsrv/smb_seek.c index 2dcc510ddf..072e9d0014 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_seek.c +++ b/usr/src/uts/common/fs/smbsrv/smb_seek.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -101,7 +101,7 @@ smb_com_seek(smb_request_t *sr) if (smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &mode, &off) != 0) return (SDRC_ERROR); - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c index 5e7b0f50d3..c0deba767a 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_server.c +++ b/usr/src/uts/common/fs/smbsrv/smb_server.c @@ -267,6 +267,8 @@ smb_server_svc_init(void) int rc = 0; while (rc == 0) { + if (rc = smb_mbc_init()) + continue; if (rc = smb_vop_init()) continue; if (rc = smb_node_init()) @@ -291,6 +293,7 @@ smb_server_svc_init(void) smb_fem_fini(); smb_node_fini(); smb_vop_fini(); + smb_mbc_fini(); return (rc); } @@ -313,6 +316,7 @@ smb_server_svc_fini(void) smb_fem_fini(); smb_node_fini(); smb_vop_fini(); + smb_mbc_fini(); smb_llist_destructor(&smb_servers); rc = 0; } @@ -375,8 +379,6 @@ smb_server_create(void) sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0); sv->si_cache_odir = kmem_cache_create("smb_odir_cache", sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0); - sv->si_cache_node = kmem_cache_create("smb_node_cache", - sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0); smb_thread_init(&sv->si_thread_timers, "smb_timers", smb_server_timers, sv, @@ -487,7 +489,6 @@ smb_server_delete(void) kmem_cache_destroy(sv->si_cache_tree); kmem_cache_destroy(sv->si_cache_ofile); kmem_cache_destroy(sv->si_cache_odir); - kmem_cache_destroy(sv->si_cache_node); smb_thread_destroy(&sv->si_thread_timers); smb_thread_destroy(&sv->si_thread_unexport); diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c index 78c396429d..f3c7a4b2b0 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_session.c +++ b/usr/src/uts/common/fs/smbsrv/smb_session.c @@ -38,10 +38,12 @@ static volatile uint64_t smb_kids; uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT; +static void smb_session_cancel(smb_session_t *); static int smb_session_message(smb_session_t *); static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *, uint8_t *, size_t); static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *); +static void smb_session_oplock_broken(smb_session_t *); static void smb_request_init_command_mbuf(smb_request_t *sr); void dump_smb_inaddr(smb_inaddr_t *ipaddr); @@ -438,7 +440,6 @@ smb_request_cancel(smb_request_t *sr) 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: @@ -462,8 +463,7 @@ smb_request_cancel(smb_request_t *sr) * SMB_REQ_STATE_INITIALIZING: */ default: - ASSERT(0); - break; + SMB_PANIC(); } mutex_exit(&sr->sr_mutex); } @@ -669,6 +669,9 @@ smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv, smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t), offsetof(smb_xa_t, xa_lnd)); + list_create(&session->s_oplock_brkreqs, sizeof (mbuf_chain_t), + offsetof(mbuf_chain_t, mbc_lnd)); + smb_net_txl_constructor(&session->s_txlst); smb_rwx_init(&session->s_lock); @@ -708,12 +711,22 @@ smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv, void smb_session_delete(smb_session_t *session) { + mbuf_chain_t *mbc; + ASSERT(session->s_magic == SMB_SESSION_MAGIC); - session->s_magic = (uint32_t)~SMB_SESSION_MAGIC; + session->s_magic = 0; smb_rwx_destroy(&session->s_lock); smb_net_txl_destructor(&session->s_txlst); + + while ((mbc = list_head(&session->s_oplock_brkreqs)) != NULL) { + SMB_MBC_VALID(mbc); + list_remove(&session->s_oplock_brkreqs, mbc); + smb_mbc_free(mbc); + } + list_destroy(&session->s_oplock_brkreqs); + smb_slist_destructor(&session->s_req_list); smb_llist_destructor(&session->s_user_list); smb_llist_destructor(&session->s_xa_list); @@ -726,7 +739,7 @@ smb_session_delete(smb_session_t *session) kmem_cache_free(session->s_cache, session); } -void +static void smb_session_cancel(smb_session_t *session) { smb_xa_t *xa, *nextxa; @@ -751,7 +764,9 @@ smb_session_cancel(smb_session_t *session) smb_xa_close(xa); xa = nextxa; } + smb_rwx_rwenter(&session->s_lock, RW_WRITER); smb_user_logoff_all(session); + smb_rwx_rwexit(&session->s_lock); } /* @@ -785,8 +800,7 @@ smb_session_cancel_requests( } void -smb_session_worker( - void *arg) +smb_session_worker(void *arg) { smb_request_t *sr; @@ -794,7 +808,7 @@ smb_session_worker( ASSERT(sr->sr_magic == SMB_REQ_MAGIC); - + sr->sr_worker = curthread; mutex_enter(&sr->sr_mutex); switch (sr->sr_state) { case SMB_REQ_STATE_SUBMITTED: @@ -1117,13 +1131,15 @@ smb_request_free(smb_request_t *sr) { ASSERT(sr->sr_magic == SMB_REQ_MAGIC); ASSERT(sr->session); - ASSERT(sr->fid_ofile == NULL); ASSERT(sr->r_xa == NULL); - if (sr->tid_tree) + if (sr->fid_ofile != NULL) + smb_ofile_release(sr->fid_ofile); + + if (sr->tid_tree != NULL) smb_tree_release(sr->tid_tree); - if (sr->uid_user) + if (sr->uid_user != NULL) smb_user_release(sr->uid_user); smb_slist_remove(&sr->session->s_req_list, sr); @@ -1157,3 +1173,121 @@ char ipstr[INET6_ADDRSTRLEN]; else cmn_err(CE_WARN, "error converting ip address"); } + +boolean_t +smb_session_oplocks_enable(smb_session_t *session) +{ + SMB_SESSION_VALID(session); + if (session->s_cfg.skc_oplock_enable == 0) + return (B_FALSE); + else + return (B_TRUE); +} + +/* + * smb_session_breaking_oplock + * + * This MUST be a cross-session call, i.e. the caller must be in a different + * context than the one passed. + */ +void +smb_session_oplock_break(smb_session_t *session, smb_ofile_t *of) +{ + mbuf_chain_t *mbc; + + SMB_SESSION_VALID(session); + + mbc = smb_mbc_alloc(MLEN); + + (void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.ww10.", + SMB_COM_LOCKING_ANDX, + SMB_TREE_GET_TID(SMB_OFILE_GET_TREE(of)), + 0xFFFF, 0, 0xFFFF, 8, 0xFF, + SMB_OFILE_GET_FID(of), + LOCKING_ANDX_OPLOCK_RELEASE); + + 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_OPLOCK_BREAKING; + session->s_oplock_brkcntr++; + (void) smb_session_send(session, 0, mbc); + smb_mbc_free(mbc); + break; + + case SMB_SESSION_STATE_READ_RAW_ACTIVE: + list_insert_tail(&session->s_oplock_brkreqs, mbc); + break; + + case SMB_SESSION_STATE_DISCONNECTED: + case SMB_SESSION_STATE_TERMINATED: + smb_mbc_free(mbc); + break; + + default: + SMB_PANIC(); + } + smb_rwx_rwexit(&session->s_lock); +} + +/* + * smb_session_oplock_released + * + * This function MUST be called in the context of the session of the client + * holding the oplock. The lock of the session must have been entered in + * RW_READER or RW_WRITER mode. + */ +void +smb_session_oplock_released(smb_session_t *session) +{ + krw_t mode; + + SMB_SESSION_VALID(session); + + mode = smb_rwx_rwupgrade(&session->s_lock); + smb_session_oplock_broken(session); + smb_rwx_rwdowngrade(&session->s_lock, mode); +} + +/* + * smb_session_oplock_break_timedout + * + * This function MUST be called when the client holding the oplock to file + * failed to release it in the time alloted. It is a cross-session call (The + * caller must be calling in the context of another session). + */ +void +smb_session_oplock_break_timedout(smb_session_t *session) +{ + SMB_SESSION_VALID(session); + + smb_rwx_rwenter(&session->s_lock, RW_WRITER); + smb_session_oplock_broken(session); + smb_rwx_rwexit(&session->s_lock); +} + +/* + * smb_session_oplock_broken + * + * Does the actual work. + */ +static void +smb_session_oplock_broken(smb_session_t *session) +{ + switch (session->s_state) { + case SMB_SESSION_STATE_OPLOCK_BREAKING: + if (--session->s_oplock_brkcntr == 0) + session->s_state = SMB_SESSION_STATE_NEGOTIATED; + break; + + case SMB_SESSION_STATE_NEGOTIATED: + case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: + case SMB_SESSION_STATE_DISCONNECTED: + case SMB_SESSION_STATE_TERMINATED: + break; + + default: + SMB_PANIC(); + } +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_set_information.c index b68cd6ab27..9e5275bbb2 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_set_information.c +++ b/usr/src/uts/common/fs/smbsrv/smb_set_information.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -132,7 +132,8 @@ smb_com_set_information(smb_request_t *sr) /* * for the benefit of attribute setting later on */ - smb_oplock_break(node); + (void) smb_oplock_break(node, SMB_SESSION_GET_ID(sr->session), + B_FALSE); } /* diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c index 3d7f072275..68528f77eb 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c +++ b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -82,7 +82,7 @@ smb_com_set_information2(smb_request_t *sr) if (rc != 0) return (SDRC_ERROR); - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); 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 index ae2012e6fd..e14deb008a 100644 --- 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 @@ -99,7 +99,7 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa) return (SDRC_ERROR); } - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -227,6 +227,7 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa) break; case SMB_QUERY_FILE_BASIC_INFO: + case SMB_FILE_BASIC_INFORMATION: /* * NT includes 6 undocumented bytes at the end of this * response, which are required by NetBench 5.01. @@ -242,8 +243,8 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa) break; case SMB_QUERY_FILE_STANDARD_INFO: - (void) smb_mbc_encodef(&xa->rep_param_mb, "w", - SMB_QUERY_FILE_STANDARD_INFO); + case SMB_FILE_STANDARD_INFORMATION: + (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); /* * Add 2 bytes to pad data to long. It is * necessary because Win2k expects the padded bytes. @@ -371,6 +372,19 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa) datasz, 0, 0, 0, 0); break; + case SMB_FILE_ATTR_TAG_INFORMATION: + /* + * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the + * second dword should be the reparse tag. Otherwise + * the tag value should be set to zero. + * We don't support reparse points, so we set the tag + * to zero. + */ + (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); + (void) smb_mbc_encodef(&xa->rep_data_mb, "ll", + (uint32_t)dattr, 0); + break; + default: kmem_free(filebuf, MAXNAMELEN+1); kmem_free(mangled_name, MAXNAMELEN); 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 index 29f079f4fd..c916daf040 100644 --- 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 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -375,7 +375,11 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa) sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name)) != 0) { kmem_free(name, MAXNAMELEN); - smbsr_errno(sr, rc); + if (rc == ENOENT) + smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERROR_FILE_NOT_FOUND); + else + smbsr_errno(sr, rc); return (SDRC_ERROR); } @@ -389,7 +393,11 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa) kmem_free(short_name, MAXNAMELEN); kmem_free(name83, MAXNAMELEN); - smbsr_errno(sr, rc); + if (rc == ENOENT) + smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERROR_FILE_NOT_FOUND); + else + smbsr_errno(sr, rc); return (SDRC_ERROR); } @@ -457,6 +465,7 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa) break; case SMB_QUERY_FILE_BASIC_INFO: + case SMB_FILE_BASIC_INFORMATION: /* * NT includes 6 undocumented bytes at the end of this * response, which are required by NetBench 5.01. @@ -472,6 +481,7 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa) break; case SMB_QUERY_FILE_STANDARD_INFO: + case SMB_FILE_STANDARD_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); /* * Add 2 bytes to pad data to long. It is @@ -573,6 +583,19 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa) ap->sa_vattr.va_nodeid); break; + case SMB_FILE_ATTR_TAG_INFORMATION: + /* + * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the + * second dword should be the reparse tag. Otherwise + * the tag value should be set to zero. + * We don't support reparse points, so we set the tag + * to zero. + */ + (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); + (void) smb_mbc_encodef(&xa->rep_data_mb, "ll", + (uint32_t)dattr, 0); + break; + default: smb_node_release(node); kmem_free(name, MAXNAMELEN); 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 index 45c964c78a..23444f5984 100644 --- 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 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -125,7 +125,7 @@ smb_com_trans2_set_file_information(struct smb_request *sr, struct smb_xa *xa) return (SDRC_ERROR); } - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { kmem_free(info, sizeof (smb_trans2_setinfo_t)); smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 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 index deab006e45..be82d499e1 100644 --- 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 @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "@(#)smb_trans2_set_path_information.c 1.9 08/08/08 SMI" - /* * SMB: trans2_set_path_information * @@ -164,7 +161,8 @@ smb_com_trans2_set_path_information(struct smb_request *sr, struct smb_xa *xa) /* * for the benefit of attribute setting later on */ - smb_oplock_break(ret_snode); + (void) smb_oplock_break(ret_snode, + SMB_SESSION_GET_ID(sr->session), B_FALSE); } info->node = ret_snode; diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c index b8a6082211..d053031952 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_tree.c +++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c @@ -549,6 +549,7 @@ smb_tree_connect_disk(smb_request_t *sr, const char *sharename) * aclaccess (those from the ACL object for the share). This * is done during the alloc. */ + tree = smb_tree_alloc(user, sharename, si->shr_path, STYPE_DISKTREE, snode, hostaccess & aclaccess); 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 index 0fea514041..aab82acfff 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c +++ b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * SMB: unlock_byte_range * @@ -78,7 +76,7 @@ smb_com_unlock_byte_range(smb_request_t *sr) if (smbsr_decode_vwv(sr, "wll", &sr->smb_fid, &Length, &Offset) != 0) return (SDRC_ERROR); - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); diff --git a/usr/src/uts/common/fs/smbsrv/smb_util.c b/usr/src/uts/common/fs/smbsrv/smb_util.c index b9bf87eae8..2c2aa5f2eb 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_util.c +++ b/usr/src/uts/common/fs/smbsrv/smb_util.c @@ -40,10 +40,6 @@ #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); @@ -143,24 +139,6 @@ smb_convert_unicode_wildcards(char *path) } /* - * smb_is_dot_or_dotdot - * - * Use when checking for the "." and ".." entries in a directory. - * Returns B_TRUE if the name is "." or "..". Otherwise returns B_FALSE. - */ -boolean_t -smb_is_dot_or_dotdot(const char *name) -{ - if (*name != '.') - return (B_FALSE); - - if ((name[1] == 0) || (name[1] == '.' && name[2] == 0)) - return (B_TRUE); - - return (B_FALSE); -} - -/* * smb_sattr_check * * Check file attributes against a search attribute (sattr) mask. @@ -195,14 +173,8 @@ smb_is_dot_or_dotdot(const char *name) * Returns true if the file and sattr match; otherwise, returns false. */ boolean_t -smb_sattr_check(uint16_t dosattr, uint16_t sattr, char *name) +smb_sattr_check(uint16_t dosattr, uint16_t sattr) { - if (name) { - if (smb_is_dot_or_dotdot(name) && - !(sattr & FILE_ATTRIBUTE_HIDDEN)) - return (B_FALSE); - } - if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) && !(sattr & FILE_ATTRIBUTE_DIRECTORY)) return (B_FALSE); @@ -1794,37 +1766,6 @@ smb_timegm(struct tm *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 * @@ -2091,3 +2032,15 @@ smb_cred_create_privs(cred_t *user_cr, uint32_t privileges) return (cr); } + +/* + * smb_panic + * + * Logs the file name, function name and line number passed in and panics the + * system. + */ +void +smb_panic(char *file, const char *func, int line) +{ + cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_write.c b/usr/src/uts/common/fs/smbsrv/smb_write.c index 7af9ed9b72..1fc27b1f9e 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_write.c +++ b/usr/src/uts/common/fs/smbsrv/smb_write.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,6 +33,13 @@ #define SMB_WRMODE_WRITE_THRU 0x0001 #define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU) +/* + * The limit in bytes that the marshalling will grow the buffer + * chain to accomodate incoming data on SmbWriteX requests. + * This sets the upper limit for the data-count per SmbWriteX + * request. + */ +#define SMB_WRITEX_MAX 102400 static int smb_write_common(smb_request_t *, smb_rw_param_t *); static int smb_write_truncate(smb_request_t *, smb_rw_param_t *); @@ -53,16 +60,18 @@ smb_pre_write(smb_request_t *sr) { smb_rw_param_t *param; uint32_t off; + uint16_t count; int rc; param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); sr->arg.rw = param; param->rw_magic = SMB_RW_MAGIC; - rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, ¶m->rw_count, &off); + rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off); + param->rw_count = (uint32_t)count; param->rw_offset = (uint64_t)off; - param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; + param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; DTRACE_SMB_2(op__Write__start, smb_request_t *, sr, smb_rw_param_t *, param); @@ -85,7 +94,7 @@ smb_com_write(smb_request_t *sr) smb_rw_param_t *param = sr->arg.rw; int rc; - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -98,13 +107,13 @@ smb_com_write(smb_request_t *sr) } else { rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); - if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { + if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } - param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; + param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; rc = smb_write_common(sr, param); } @@ -115,7 +124,8 @@ smb_com_write(smb_request_t *sr) return (SDRC_ERROR); } - rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); + rc = smbsr_encode_result(sr, 1, 0, "bww", 1, + (uint16_t)param->rw_count, 0); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } @@ -135,6 +145,7 @@ smb_pre_write_and_close(smb_request_t *sr) { smb_rw_param_t *param; uint32_t off; + uint16_t count; int rc; param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); @@ -143,12 +154,13 @@ smb_pre_write_and_close(smb_request_t *sr) if (sr->smb_wct == 12) { rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, - ¶m->rw_count, &off, ¶m->rw_last_write); + &count, &off, ¶m->rw_last_write); } else { rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, - ¶m->rw_count, &off, ¶m->rw_last_write); + &count, &off, ¶m->rw_last_write); } + param->rw_count = (uint32_t)count; param->rw_offset = (uint64_t)off; DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr, @@ -170,9 +182,10 @@ smb_sdrc_t smb_com_write_and_close(smb_request_t *sr) { smb_rw_param_t *param = sr->arg.rw; + uint16_t count; int rc = 0; - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -189,13 +202,13 @@ smb_com_write_and_close(smb_request_t *sr) rc = smbsr_decode_data(sr, ".#B", param->rw_count, ¶m->rw_vdb); - if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { + if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } - param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; + param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; rc = smb_write_common(sr, param); } @@ -208,7 +221,8 @@ smb_com_write_and_close(smb_request_t *sr) smb_ofile_close(sr->fid_ofile, param->rw_last_write); - rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); + count = (uint16_t)param->rw_count; + rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } @@ -234,6 +248,7 @@ smb_pre_write_and_unlock(smb_request_t *sr) { smb_rw_param_t *param; uint32_t off; + uint16_t count; uint16_t remcnt; int rc; @@ -241,9 +256,9 @@ smb_pre_write_and_unlock(smb_request_t *sr) sr->arg.rw = param; param->rw_magic = SMB_RW_MAGIC; - rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, ¶m->rw_count, &off, - &remcnt); + rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt); + param->rw_count = (uint32_t)count; param->rw_offset = (uint64_t)off; DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, @@ -273,7 +288,7 @@ smb_com_write_and_unlock(smb_request_t *sr) return (SDRC_ERROR); } - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -286,15 +301,16 @@ smb_com_write_and_unlock(smb_request_t *sr) return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } + rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); - if ((rc != 0) || (param->rw_count != param->rw_vdb.len)) { + if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) { smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } - param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; + param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; if ((rc = smb_write_common(sr, param)) != 0) { if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) @@ -310,7 +326,8 @@ smb_com_write_and_unlock(smb_request_t *sr) return (SDRC_ERROR); } - rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); + rc = smbsr_encode_result(sr, 1, 0, "bww", 1, + (uint16_t)param->rw_count, 0); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } @@ -324,6 +341,11 @@ smb_com_write_and_unlock(smb_request_t *sr) * * If bit 0 of WriteMode is set, Fid must refer to a disk file and * the data must be on stable storage before responding. + * + * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5: + * If CAP_LARGE_WRITEX is set, the byte count may be larger than the + * negotiated buffer size and the server is expected to write the + * number of bytes specified. */ smb_sdrc_t smb_pre_write_andx(smb_request_t *sr) @@ -331,6 +353,8 @@ smb_pre_write_andx(smb_request_t *sr) smb_rw_param_t *param; uint32_t off_low; uint32_t off_high; + uint16_t datalen_low; + uint16_t datalen_high; uint16_t remcnt; int rc; @@ -339,21 +363,24 @@ smb_pre_write_andx(smb_request_t *sr) param->rw_magic = SMB_RW_MAGIC; if (sr->smb_wct == 14) { - rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid, - &off_low, ¶m->rw_mode, &remcnt, ¶m->rw_count, - ¶m->rw_dsoff, &off_high); + rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid, + &off_low, ¶m->rw_mode, &remcnt, &datalen_high, + &datalen_low, ¶m->rw_dsoff, &off_high); param->rw_dsoff -= 63; param->rw_offset = ((uint64_t)off_high << 32) | off_low; } else { - rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid, - &off_low, ¶m->rw_mode, &remcnt, ¶m->rw_count, - ¶m->rw_dsoff); + rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid, + &off_low, ¶m->rw_mode, &remcnt, &datalen_high, + &datalen_low, ¶m->rw_dsoff); param->rw_offset = (uint64_t)off_low; param->rw_dsoff -= 59; } + param->rw_count = ((uint32_t)datalen_high << 16) | + (uint32_t)datalen_low; + DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, smb_rw_param_t *, param); @@ -373,12 +400,14 @@ smb_sdrc_t smb_com_write_andx(smb_request_t *sr) { smb_rw_param_t *param = sr->arg.rw; + uint16_t count_high; + uint16_t count_low; int rc; ASSERT(param); ASSERT(param->rw_magic == SMB_RW_MAGIC); - sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); @@ -392,15 +421,17 @@ smb_com_write_andx(smb_request_t *sr) return (SDRC_ERROR); } + sr->smb_data.max_bytes = SMB_WRITEX_MAX; rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, ¶m->rw_vdb); - if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { + + if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } - param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; + param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; if (param->rw_count != 0) { if ((rc = smb_write_common(sr, param)) != 0) { @@ -411,8 +442,11 @@ smb_com_write_andx(smb_request_t *sr) } } - rc = smbsr_encode_result(sr, 6, 0, "bb1.ww6.w", - 6, sr->andx_com, 15, param->rw_count, 0); + count_low = param->rw_count & 0xFFFF; + count_high = (param->rw_count >> 16) & 0xFF; + + rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww", + 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } @@ -451,7 +485,7 @@ smb_write_common(smb_request_t *sr, smb_rw_param_t *param) } rc = smb_fsop_write(sr, sr->user_cr, node, - ¶m->rw_vdb.uio, &lcount, &node->attr, stability); + ¶m->rw_vdb.vdb_uio, &lcount, &node->attr, stability); if (rc) return (rc); @@ -465,13 +499,13 @@ smb_write_common(smb_request_t *sr, smb_rw_param_t *param) } } - param->rw_count = (uint16_t)lcount; + param->rw_count = lcount; break; case STYPE_IPC: - param->rw_count = (uint16_t)param->rw_vdb.uio.uio_resid; + param->rw_count = param->rw_vdb.vdb_uio.uio_resid; - if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.uio)) != 0) + if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0) param->rw_count = 0; break; @@ -517,10 +551,10 @@ smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) append_only = B_TRUE; } - smb_rwx_xenter(&node->n_lock); + mutex_enter(&node->n_mutex); if (append_only && (param->rw_offset < node->n_size)) { - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); return (EACCES); } @@ -528,7 +562,7 @@ smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) status = smb_lock_range_access(sr, node, param->rw_offset, param->rw_count, B_TRUE); if (status != NT_STATUS_SUCCESS) { - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, ERRDOS, ERROR_LOCK_VIOLATION); return (EACCES); @@ -538,7 +572,7 @@ smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) node->flags |= NODE_FLAGS_SET_SIZE; node->n_size = param->rw_offset; - smb_rwx_xexit(&node->n_lock); + mutex_exit(&node->n_mutex); if ((rc = smb_set_file_size(sr, node)) != 0) return (rc); diff --git a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c index 6b8f3e7d69..8abb990749 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c +++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -254,7 +254,7 @@ smb_com_write_raw(struct smb_request *sr) 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); + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); |