/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2020 Tintri by DDN, Inc. All rights reserved. * Copyright 2022-2023 RackTop Systems, Inc. */ /* * Common functions supporting both: * SMB1 Trans2 Set File/Path Info, * SMB2 Set File Info */ #include #include /* * smb_set_basic_info * [MS-FSCC] 2.4.7 * FileBasicInformation * SMB_SET_FILE_BASIC_INFO * SMB_FILE_BASIC_INFORMATION * * Sets basic file/path information. * * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the * target is not a directory. * * For compatibility with windows servers: * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set * clear (0) the file's attributes. * - if the specified attributes are 0 do NOT change the file's attributes. */ uint32_t smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *si) { smb_attr_t *attr = &si->si_attr; smb_node_t *node = si->si_node; uint64_t crtime, atime, mtime, ctime; uint32_t attributes; int rc; if (smb_mbc_decodef(&si->si_data, "qqqql", &crtime, &atime, &mtime, &ctime, &attributes) != 0) return (NT_STATUS_INFO_LENGTH_MISMATCH); /* * MS-FSA 2.1.5.14.2 FileBasicInformation * Return STATUS_INVALID_PARAMETER if: * FILE_ATTRIBUTE_TEMPORARY on a directory, * FILE_ATTRIBUTE_DIRECTORY on a non-directory. */ if (smb_node_is_dir(node)) { if ((attributes & FILE_ATTRIBUTE_TEMPORARY) != 0) return (NT_STATUS_INVALID_PARAMETER); } else { if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) return (NT_STATUS_INVALID_PARAMETER); } bzero(attr, sizeof (*attr)); if (atime != 0) { if ((int64_t)atime < -2) return (NT_STATUS_INVALID_PARAMETER); smb_time_nt_to_unix(atime, &attr->sa_vattr.va_atime); attr->sa_mask |= SMB_AT_ATIME; } if (mtime != 0) { if ((int64_t)mtime < -2) return (NT_STATUS_INVALID_PARAMETER); smb_time_nt_to_unix(mtime, &attr->sa_vattr.va_mtime); attr->sa_mask |= SMB_AT_MTIME; } if (ctime != 0) { if ((int64_t)ctime < -2) return (NT_STATUS_INVALID_PARAMETER); smb_time_nt_to_unix(ctime, &attr->sa_vattr.va_ctime); attr->sa_mask |= SMB_AT_CTIME; } if (crtime != 0) { if ((int64_t)crtime < -2) return (NT_STATUS_INVALID_PARAMETER); smb_time_nt_to_unix(crtime, &attr->sa_crtime); attr->sa_mask |= SMB_AT_CRTIME; } if (attributes != 0) { attr->sa_dosattr = attributes; attr->sa_mask |= SMB_AT_DOSATTR; } rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr); if (rc != 0) return (smb_errno2status(rc)); return (0); } /* * smb_set_eof_info * FileEndOfFileInformation * SMB_SET_FILE_END_OF_FILE_INFO * SMB_FILE_END_OF_FILE_INFORMATION */ uint32_t smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *si) { smb_attr_t *attr = &si->si_attr; smb_node_t *node = si->si_node; uint64_t eof; uint32_t status; int rc; if (smb_mbc_decodef(&si->si_data, "q", &eof) != 0) return (NT_STATUS_INFO_LENGTH_MISMATCH); if (smb_node_is_dir(node)) return (NT_STATUS_INVALID_PARAMETER); status = smb_oplock_break_SETINFO(node, sr->fid_ofile, FileEndOfFileInformation); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); (void) smb_oplock_wait_break(sr, node, 0); status = 0; } if (status != 0) return (status); bzero(attr, sizeof (*attr)); attr->sa_mask = SMB_AT_SIZE; attr->sa_vattr.va_size = (u_offset_t)eof; rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr); if (rc != 0) return (smb_errno2status(rc)); return (0); } /* * smb_set_alloc_info * FileAllocationInformation * SMB_SET_FILE_ALLOCATION_INFO * SMB_FILE_ALLOCATION_INFORMATION */ uint32_t smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *si) { smb_attr_t *attr = &si->si_attr; smb_node_t *node = si->si_node; uint64_t allocsz; uint32_t status; int rc; if (smb_mbc_decodef(&si->si_data, "q", &allocsz) != 0) return (NT_STATUS_INFO_LENGTH_MISMATCH); if (smb_node_is_dir(node)) return (NT_STATUS_INVALID_PARAMETER); status = smb_oplock_break_SETINFO(node, sr->fid_ofile, FileAllocationInformation); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); (void) smb_oplock_wait_break(sr, node, 0); status = 0; } if (status != 0) return (status); bzero(attr, sizeof (*attr)); attr->sa_mask = SMB_AT_ALLOCSZ; attr->sa_allocsz = (u_offset_t)allocsz; rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr); if (rc != 0) return (smb_errno2status(rc)); return (0); } /* * smb_set_disposition_info * See: * FileDispositionInformation * SMB_SET_FILE_DISPOSITION_INFO * SMB_FILE_DISPOSITION_INFORMATION * * Set/Clear DELETE_ON_CLOSE flag for an open file. * File should have been opened with DELETE access otherwise * the operation is not permitted. * * NOTE: The node should be marked delete-on-close upon the receipt * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set. * It is different than both SmbNtCreateAndX and SmbNtTransact, which * set delete-on-close on the ofile and defer setting the flag on the * node until the file is closed. * * Observation of Windows 2000 indicates the following: * * 1) If a file is not opened with delete-on-close create options and * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo) * using that open file handle, any subsequent open requests will fail * with DELETE_PENDING. * * 2) If a file is opened with delete-on-close create options and the * client attempts to unset delete-on-close via Trans2SetFileInfo * (SetDispositionInfo) prior to the file close, any subsequent open * requests will still fail with DELETE_PENDING after the file is closed. * * 3) If a file is opened with delete-on-close create options and that * file handle (not the last open handle and the only file handle * with delete-on-close set) is closed. Any subsequent open requests * will fail with DELETE_PENDING. Unsetting delete-on-close via * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the * node delete-on-close flag, which will result in the file not being * removed even after the last file handle is closed. */ uint32_t smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *si) { smb_attr_t *attr = &si->si_attr; smb_node_t *node = si->si_node; smb_ofile_t *of = sr->fid_ofile; uint8_t mark_delete; uint32_t status; uint32_t flags = 0; if (smb_mbc_decodef(&si->si_data, "b", &mark_delete) != 0) return (NT_STATUS_INFO_LENGTH_MISMATCH); if ((of == NULL) || !(smb_ofile_granted_access(of) & DELETE)) return (NT_STATUS_ACCESS_DENIED); if (mark_delete == 0) { smb_node_reset_delete_on_close(node); return (NT_STATUS_SUCCESS); } /* * MS-FSA 2.1.5.14.3 FileDispositionInformation * If dosattr READONLY, STATUS_CANNOT_DELETE. */ attr->sa_mask = SMB_AT_DOSATTR; status = smb2_ofile_getattr(sr, of, attr); if (status != 0) return (status); if ((attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0) return (NT_STATUS_CANNOT_DELETE); /* * Break any oplock handle caching. */ status = smb_oplock_break_SETINFO(node, of, FileDispositionInformation); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); (void) smb_oplock_wait_break(sr, node, 0); status = 0; } if (status != 0) return (status); if (SMB_TREE_SUPPORTS_CATIA(sr)) flags |= SMB_CATIA; return (smb_node_set_delete_on_close(node, of->f_cr, flags)); }