1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22c5866007SKeyur Desai * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 236d1c73b5SDan Vatca * Copyright 2016 Syneto S.R.L. All rights reserved. 2448bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved. 25*811599a4SMatt Barden * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 26da6c28aaSamw */ 27da6c28aaSamw 28da6c28aaSamw /* 29da6c28aaSamw * General Structures Layout 30da6c28aaSamw * ------------------------- 31da6c28aaSamw * 32da6c28aaSamw * This is a simplified diagram showing the relationship between most of the 33da6c28aaSamw * main structures. 34da6c28aaSamw * 35da6c28aaSamw * +-------------------+ 36da6c28aaSamw * | SMB_INFO | 37da6c28aaSamw * +-------------------+ 38da6c28aaSamw * | 39da6c28aaSamw * | 40da6c28aaSamw * v 41da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 42da6c28aaSamw * | SESSION |<----->| SESSION |......| SESSION | 43da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 443b13a1efSThomas Keiser * | | 453b13a1efSThomas Keiser * | | 463b13a1efSThomas Keiser * | v 473b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+ 483b13a1efSThomas Keiser * | | USER |<--->| USER |...| USER | 493b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+ 50da6c28aaSamw * | 51da6c28aaSamw * | 52da6c28aaSamw * v 53da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 54da6c28aaSamw * | TREE |<----->| TREE |......| TREE | 55da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 56da6c28aaSamw * | | 57da6c28aaSamw * | | 58da6c28aaSamw * | v 59da6c28aaSamw * | +-------+ +-------+ +-------+ 60da6c28aaSamw * | | OFILE |<----->| OFILE |......| OFILE | 61da6c28aaSamw * | +-------+ +-------+ +-------+ 62da6c28aaSamw * | 63da6c28aaSamw * | 64da6c28aaSamw * v 65da6c28aaSamw * +-------+ +------+ +------+ 66da6c28aaSamw * | ODIR |<----->| ODIR |......| ODIR | 67da6c28aaSamw * +-------+ +------+ +------+ 68da6c28aaSamw * 69da6c28aaSamw * 70da6c28aaSamw * Ofile State Machine 71da6c28aaSamw * ------------------ 72da6c28aaSamw * 73da6c28aaSamw * +-------------------------+ T0 74*811599a4SMatt Barden * | SMB_OFILE_STATE_OPEN |<--+-------- Creation/Allocation 75*811599a4SMatt Barden * +-------------------------+ | 76*811599a4SMatt Barden * | | | T5 77*811599a4SMatt Barden * | | +---------------------------+ 78*811599a4SMatt Barden * | | | SMB_OFILE_STATE_RECONNECT | 79*811599a4SMatt Barden * | | +---------------------------+ 80*811599a4SMatt Barden * | | ^ 81*811599a4SMatt Barden * | v | 82*811599a4SMatt Barden * | +---------------+ | 83*811599a4SMatt Barden * | | STATE_SAVE_DH | | 84*811599a4SMatt Barden * | | STATE_SAVING | | 85*811599a4SMatt Barden * | +---------------+ | 86*811599a4SMatt Barden * | | | T4 87*811599a4SMatt Barden * | T1 | T3 +--------------------------+ 88*811599a4SMatt Barden * | +------>| SMB_OFILE_STATE_ORPHANED | 89*811599a4SMatt Barden * v +--------------------------+ 90*811599a4SMatt Barden * +-------------------------+ | | 91*811599a4SMatt Barden * | SMB_OFILE_STATE_CLOSING |<--+ T6 | T7 92*811599a4SMatt Barden * +-------------------------+ | 93*811599a4SMatt Barden * | ^ v 94*811599a4SMatt Barden * | T2 | T8 +-------------------------+ 95*811599a4SMatt Barden * | +-------| SMB_OFILE_STATE_EXPIRED | 96*811599a4SMatt Barden * v +-------------------------+ 97da6c28aaSamw * +-------------------------+ 98da6c28aaSamw * | SMB_OFILE_STATE_CLOSED |----------> Deletion/Free 99*811599a4SMatt Barden * +-------------------------+ T9 100da6c28aaSamw * 101da6c28aaSamw * SMB_OFILE_STATE_OPEN 102da6c28aaSamw * 103da6c28aaSamw * While in this state: 104da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 105da6c28aaSamw * - References will be given out if the ofile is looked up. 106da6c28aaSamw * 107*811599a4SMatt Barden * SMB_OFILE_STATE_SAVE_DH 108*811599a4SMatt Barden * 109*811599a4SMatt Barden * Similar to state _CLOSING, but instead of deleting the ofile, 110*811599a4SMatt Barden * it leaves the ofile in state _ORPHANED (for later reclaim). 111*811599a4SMatt Barden * Will move to _SAVING after last ref, then _ORPHANED. 112*811599a4SMatt Barden * 113*811599a4SMatt Barden * While in this state: 114*811599a4SMatt Barden * - The ofile has been marked for preservation during a 115*811599a4SMatt Barden * walk of the tree ofile list to close multiple files. 116*811599a4SMatt Barden * - References will not be given out if the ofile is looked up, 117*811599a4SMatt Barden * except for oplock break processing. 118*811599a4SMatt Barden * - Still affects Sharing Violation rules 119*811599a4SMatt Barden * 120*811599a4SMatt Barden * SMB_OFILE_STATE_SAVING 121*811599a4SMatt Barden * 122*811599a4SMatt Barden * Transient state used to keep oplock break processing out 123*811599a4SMatt Barden * while the ofile moves to state _ORPHANED. 124*811599a4SMatt Barden * 125*811599a4SMatt Barden * While in this state: 126*811599a4SMatt Barden * - References will not be given out if the ofile is looked up, 127*811599a4SMatt Barden * except for oplock break processing. 128*811599a4SMatt Barden * - Still affects Sharing Violation rules 129*811599a4SMatt Barden * 130da6c28aaSamw * SMB_OFILE_STATE_CLOSING 131da6c28aaSamw * 132*811599a4SMatt Barden * Close has been requested. Stay in this state until the last 133*811599a4SMatt Barden * ref. is gone, then move to state _CLOSED 134*811599a4SMatt Barden * 135da6c28aaSamw * While in this state: 136da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 137da6c28aaSamw * - References will not be given out if the ofile is looked up. 138da6c28aaSamw * - The file is closed and the locks held are being released. 139da6c28aaSamw * - The resources associated with the ofile remain. 140da6c28aaSamw * 141da6c28aaSamw * SMB_OFILE_STATE_CLOSED 142da6c28aaSamw * 143da6c28aaSamw * While in this state: 144da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 145da6c28aaSamw * - References will not be given out if the ofile is looked up. 146da6c28aaSamw * - The resources associated with the ofile remain. 147da6c28aaSamw * 148*811599a4SMatt Barden * SMB_OFILE_STATE_ORPHANED 149*811599a4SMatt Barden * 150*811599a4SMatt Barden * While in this state: 151*811599a4SMatt Barden * - The ofile is queued in the list of ofiles of its tree. 152*811599a4SMatt Barden * - Can be reclaimed by the original owner 153*811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 154*811599a4SMatt Barden * - All the tree, user, and session "up" pointers are NULL! 155*811599a4SMatt Barden * - Will eventually be "expired" if not reclaimed 156*811599a4SMatt Barden * - Can be closed if its oplock is broken 157*811599a4SMatt Barden * - Still affects Sharing Violation rules 158*811599a4SMatt Barden * 159*811599a4SMatt Barden * SMB_OFILE_STATE_EXPIRED 160*811599a4SMatt Barden * 161*811599a4SMatt Barden * While in this state: 162*811599a4SMatt Barden * - The ofile is queued in the list of ofiles of its tree. 163*811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 164*811599a4SMatt Barden * - The ofile has not been reclaimed and will soon be closed, 165*811599a4SMatt Barden * due to, for example, the durable handle timer expiring, or its 166*811599a4SMatt Barden * oplock being broken. 167*811599a4SMatt Barden * - Cannot be reclaimed at this point 168*811599a4SMatt Barden * 169*811599a4SMatt Barden * SMB_OFILE_STATE_RECONNECT 170*811599a4SMatt Barden * 171*811599a4SMatt Barden * Transient state used to keep oplock break processing out 172*811599a4SMatt Barden * while the ofile moves from state _ORPHANED to _OPEN. 173*811599a4SMatt Barden * 174*811599a4SMatt Barden * While in this state: 175*811599a4SMatt Barden * - The ofile is being reclaimed; do not touch it. 176*811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 177*811599a4SMatt Barden * - Still affects Sharing Violation rules 178*811599a4SMatt Barden * - see smb2_dh_reconnect() for which members need to be avoided 179*811599a4SMatt Barden * 180da6c28aaSamw * Transition T0 181da6c28aaSamw * 182da6c28aaSamw * This transition occurs in smb_ofile_open(). A new ofile is created and 183da6c28aaSamw * added to the list of ofiles of a tree. 184da6c28aaSamw * 185da6c28aaSamw * Transition T1 186da6c28aaSamw * 187*811599a4SMatt Barden * This transition occurs in smb_ofile_close(). Note that this only happens 188*811599a4SMatt Barden * when we determine that an ofile should be closed in spite of its durable 189*811599a4SMatt Barden * handle properties. 190da6c28aaSamw * 191da6c28aaSamw * Transition T2 192da6c28aaSamw * 193da6c28aaSamw * This transition occurs in smb_ofile_release(). The resources associated 194da6c28aaSamw * with the ofile are freed as well as the ofile structure. For the 195da6c28aaSamw * transition to occur, the ofile must be in the SMB_OFILE_STATE_CLOSED 196da6c28aaSamw * state and the reference count be zero. 197da6c28aaSamw * 198*811599a4SMatt Barden * Transition T3 199*811599a4SMatt Barden * 200*811599a4SMatt Barden * This transition occurs in smb_ofile_orphan_dh(). It happens during an 201*811599a4SMatt Barden * smb2 logoff, or during a session disconnect when certain conditions are 202*811599a4SMatt Barden * met. The ofile and structures above it will be kept around until the ofile 203*811599a4SMatt Barden * either gets reclaimed, expires after f_timeout_offset nanoseconds, or its 204*811599a4SMatt Barden * oplock is broken. 205*811599a4SMatt Barden * 206*811599a4SMatt Barden * Transition T4 207*811599a4SMatt Barden * 208*811599a4SMatt Barden * This transition occurs in smb2_dh_reconnect(). An smb2 create request 209*811599a4SMatt Barden * with a DURABLE_HANDLE_RECONNECT(_V2) create context has been 210*811599a4SMatt Barden * recieved from the original owner. If leases are supported or it's 211*811599a4SMatt Barden * RECONNECT_V2, reconnect is subject to additional conditions. The ofile 212*811599a4SMatt Barden * will be unwired from the old, disconnected session, tree, and user, 213*811599a4SMatt Barden * and wired up to its new context. 214*811599a4SMatt Barden * 215*811599a4SMatt Barden * Transition T5 216*811599a4SMatt Barden * 217*811599a4SMatt Barden * This transition occurs in smb2_dh_reconnect(). The ofile has been 218*811599a4SMatt Barden * successfully reclaimed. 219*811599a4SMatt Barden * 220*811599a4SMatt Barden * Transition T6 221*811599a4SMatt Barden * 222*811599a4SMatt Barden * This transition occurs in smb_ofile_close(). The ofile has been orphaned 223*811599a4SMatt Barden * while some thread was blocked, and that thread closes the ofile. Can only 224*811599a4SMatt Barden * happen when the ofile is orphaned due to an SMB2 LOGOFF request. 225*811599a4SMatt Barden * 226*811599a4SMatt Barden * Transition T7 227*811599a4SMatt Barden * 228*811599a4SMatt Barden * This transition occurs in smb_session_durable_timers() and 229*811599a4SMatt Barden * smb_oplock_sched_async_break(). The ofile will soon be closed. 230*811599a4SMatt Barden * In the former case, f_timeout_offset nanoseconds have passed since 231*811599a4SMatt Barden * the ofile was orphaned. In the latter, an oplock break occured 232*811599a4SMatt Barden * on the ofile while it was orphaned. 233*811599a4SMatt Barden * 234*811599a4SMatt Barden * Transition T8 235*811599a4SMatt Barden * 236*811599a4SMatt Barden * This transition occurs in smb_ofile_close(). 237*811599a4SMatt Barden * 238*811599a4SMatt Barden * Transition T9 239*811599a4SMatt Barden * 240*811599a4SMatt Barden * This transition occurs in smb_ofile_delete(). 241*811599a4SMatt Barden * 242da6c28aaSamw * Comments 243da6c28aaSamw * -------- 244da6c28aaSamw * 245da6c28aaSamw * The state machine of the ofile structures is controlled by 3 elements: 246da6c28aaSamw * - The list of ofiles of the tree it belongs to. 247da6c28aaSamw * - The mutex embedded in the structure itself. 248da6c28aaSamw * - The reference count. 249da6c28aaSamw * 250da6c28aaSamw * There's a mutex embedded in the ofile structure used to protect its fields 251da6c28aaSamw * and there's a lock embedded in the list of ofiles of a tree. To 252da6c28aaSamw * increment or to decrement the reference count the mutex must be entered. 253da6c28aaSamw * To insert the ofile into the list of ofiles of the tree and to remove 254da6c28aaSamw * the ofile from it, the lock must be entered in RW_WRITER mode. 255da6c28aaSamw * 256da6c28aaSamw * Rules of access to a ofile structure: 257da6c28aaSamw * 258da6c28aaSamw * 1) In order to avoid deadlocks, when both (mutex and lock of the ofile 259*811599a4SMatt Barden * list) have to be entered, the lock must be entered first. Additionally, 260*811599a4SMatt Barden * f_mutex must not be held when removing the ofile from sv_persistid_ht. 261da6c28aaSamw * 262da6c28aaSamw * 2) All actions applied to an ofile require a reference count. 263da6c28aaSamw * 264da6c28aaSamw * 3) There are 2 ways of getting a reference count. One is when the ofile 265da6c28aaSamw * is opened. The other one when the ofile is looked up. This translates 266da6c28aaSamw * into 2 functions: smb_ofile_open() and smb_ofile_lookup_by_fid(). 267da6c28aaSamw * 268da6c28aaSamw * It should be noted that the reference count of an ofile registers the 269da6c28aaSamw * number of references to the ofile in other structures (such as an smb 270da6c28aaSamw * request). The reference count is not incremented in these 2 instances: 271da6c28aaSamw * 27248bbca81SDaniel Hoffman * 1) The ofile is open. An ofile is anchored by its state. If there's 273da6c28aaSamw * no activity involving an ofile currently open, the reference count 274da6c28aaSamw * of that ofile is zero. 275da6c28aaSamw * 276da6c28aaSamw * 2) The ofile is queued in the list of ofiles of its tree. The fact of 277da6c28aaSamw * being queued in that list is NOT registered by incrementing the 278da6c28aaSamw * reference count. 279da6c28aaSamw */ 280*811599a4SMatt Barden #include <smbsrv/smb2_kproto.h> 281da6c28aaSamw #include <smbsrv/smb_fsops.h> 282*811599a4SMatt Barden #include <sys/time.h> 283*811599a4SMatt Barden 284*811599a4SMatt Barden /* Don't leak object addresses */ 285*811599a4SMatt Barden #define SMB_OFILE_PERSISTID(of) \ 286*811599a4SMatt Barden ((uintptr_t)&smb_cache_ofile ^ (uintptr_t)(of)) 287da6c28aaSamw 2881fcced4cSJordan Brown static boolean_t smb_ofile_is_open_locked(smb_ofile_t *); 289*811599a4SMatt Barden static void smb_ofile_delete(void *arg); 290*811599a4SMatt Barden static void smb_ofile_save_dh(void *arg); 291*811599a4SMatt Barden 2921fcced4cSJordan Brown static int smb_ofile_netinfo_encode(smb_ofile_t *, uint8_t *, size_t, 2931fcced4cSJordan Brown uint32_t *); 2941fcced4cSJordan Brown static int smb_ofile_netinfo_init(smb_ofile_t *, smb_netfileinfo_t *); 2951fcced4cSJordan Brown static void smb_ofile_netinfo_fini(smb_netfileinfo_t *); 296da6c28aaSamw 297da6c28aaSamw /* 298da6c28aaSamw * smb_ofile_open 299da6c28aaSamw */ 300da6c28aaSamw smb_ofile_t * 301da6c28aaSamw smb_ofile_open( 3023b13a1efSThomas Keiser smb_request_t *sr, 303da6c28aaSamw smb_node_t *node, 304c8ec8eeaSjose borrego struct open_param *op, 305da6c28aaSamw uint16_t ftype, 306dc20a302Sas200622 uint32_t uniqid, 307da6c28aaSamw smb_error_t *err) 308da6c28aaSamw { 3093b13a1efSThomas Keiser smb_tree_t *tree = sr->tid_tree; 310da6c28aaSamw smb_ofile_t *of; 311da6c28aaSamw uint16_t fid; 312037cac00Sjoyce mcintosh smb_attr_t attr; 3135fd03bc0SGordon Ross int rc; 314da6c28aaSamw 315da6c28aaSamw if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) { 316da6c28aaSamw err->status = NT_STATUS_TOO_MANY_OPENED_FILES; 317da6c28aaSamw err->errcls = ERRDOS; 318da6c28aaSamw err->errcode = ERROR_TOO_MANY_OPEN_FILES; 319da6c28aaSamw return (NULL); 320da6c28aaSamw } 321da6c28aaSamw 3228622ec45SGordon Ross of = kmem_cache_alloc(smb_cache_ofile, KM_SLEEP); 323da6c28aaSamw bzero(of, sizeof (smb_ofile_t)); 324da6c28aaSamw of->f_magic = SMB_OFILE_MAGIC; 325bfe5e737SGordon Ross 326bfe5e737SGordon Ross mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL); 327bfe5e737SGordon Ross list_create(&of->f_notify.nc_waiters, sizeof (smb_request_t), 328bfe5e737SGordon Ross offsetof(smb_request_t, sr_waiters)); 329bfe5e737SGordon Ross 330bfe5e737SGordon Ross of->f_state = SMB_OFILE_STATE_OPEN; 331da6c28aaSamw of->f_refcnt = 1; 332*811599a4SMatt Barden of->f_ftype = ftype; 333da6c28aaSamw of->f_fid = fid; 334*811599a4SMatt Barden /* of->f_persistid see smb2_create */ 335dc20a302Sas200622 of->f_uniqid = uniqid; 33668b2bbf2SGordon Ross of->f_opened_by_pid = sr->smb_pid; 337c8ec8eeaSjose borrego of->f_granted_access = op->desired_access; 338c8ec8eeaSjose borrego of->f_share_access = op->share_access; 339c8ec8eeaSjose borrego of->f_create_options = op->create_options; 340b89a8333Snatalie li - Sun Microsystems - Irvine United States of->f_cr = (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) ? 3413b13a1efSThomas Keiser smb_user_getprivcred(sr->uid_user) : sr->uid_user->u_cred; 342da6c28aaSamw crhold(of->f_cr); 343faa1795aSjb150015 of->f_server = tree->t_server; 3443b13a1efSThomas Keiser of->f_session = tree->t_session; 345bfe5e737SGordon Ross 3463b13a1efSThomas Keiser /* 347*811599a4SMatt Barden * grab a ref for of->f_user and of->f_tree 348*811599a4SMatt Barden * released in smb_ofile_delete() or smb2_dh_reconnect() 3493b13a1efSThomas Keiser */ 3503b13a1efSThomas Keiser smb_user_hold_internal(sr->uid_user); 351*811599a4SMatt Barden smb_tree_hold_internal(tree); 3523b13a1efSThomas Keiser of->f_user = sr->uid_user; 353da6c28aaSamw of->f_tree = tree; 354da6c28aaSamw of->f_node = node; 3555fd03bc0SGordon Ross 356da6c28aaSamw if (ftype == SMB_FTYPE_MESG_PIPE) { 35768b2bbf2SGordon Ross /* See smb_opipe_open. */ 35868b2bbf2SGordon Ross of->f_pipe = op->pipe; 359148c5f43SAlan Wright smb_server_inc_pipes(of->f_server); 360da6c28aaSamw } else { 361da6c28aaSamw ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */ 362da6c28aaSamw ASSERT(node); 3632c2961f8Sjose borrego 364a90cf9f2SGordon Ross /* 365a90cf9f2SGordon Ross * Note that the common open path often adds bits like 366a90cf9f2SGordon Ross * READ_CONTROL, so the logic "is this open exec-only" 367a90cf9f2SGordon Ross * needs to look at only the FILE_DATA_ALL bits. 368a90cf9f2SGordon Ross */ 369a90cf9f2SGordon Ross if ((of->f_granted_access & FILE_DATA_ALL) == FILE_EXECUTE) 3702c2961f8Sjose borrego of->f_flags |= SMB_OFLAGS_EXECONLY; 3712c2961f8Sjose borrego 372bfe5e737SGordon Ross /* 373bfe5e737SGordon Ross * This is an "internal" getattr because we need the 374bfe5e737SGordon Ross * UID and DOS attributes. Don't want to fail here 375bfe5e737SGordon Ross * due to permissions, so use kcred. 376bfe5e737SGordon Ross */ 377037cac00Sjoyce mcintosh bzero(&attr, sizeof (smb_attr_t)); 3785fd03bc0SGordon Ross attr.sa_mask = SMB_AT_UID | SMB_AT_DOSATTR; 379bfe5e737SGordon Ross rc = smb_node_getattr(NULL, node, zone_kcred(), NULL, &attr); 3805fd03bc0SGordon Ross if (rc != 0) { 381037cac00Sjoyce mcintosh err->status = NT_STATUS_INTERNAL_ERROR; 382037cac00Sjoyce mcintosh err->errcls = ERRDOS; 383037cac00Sjoyce mcintosh err->errcode = ERROR_INTERNAL_ERROR; 3843b13a1efSThomas Keiser goto errout; 385037cac00Sjoyce mcintosh } 386037cac00Sjoyce mcintosh if (crgetuid(of->f_cr) == attr.sa_vattr.va_uid) { 387da6c28aaSamw /* 388da6c28aaSamw * Add this bit for the file's owner even if it's not 389da6c28aaSamw * specified in the request (Windows behavior). 390da6c28aaSamw */ 391da6c28aaSamw of->f_granted_access |= FILE_READ_ATTRIBUTES; 392da6c28aaSamw } 393da6c28aaSamw 3949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_node_is_file(node)) { 3958c10a865Sas200622 of->f_mode = 3968c10a865Sas200622 smb_fsop_amask_to_omode(of->f_granted_access); 397c8ec8eeaSjose borrego if (smb_fsop_open(node, of->f_mode, of->f_cr) != 0) { 398da6c28aaSamw err->status = NT_STATUS_ACCESS_DENIED; 399da6c28aaSamw err->errcls = ERRDOS; 400da6c28aaSamw err->errcode = ERROR_ACCESS_DENIED; 4013b13a1efSThomas Keiser goto errout; 402da6c28aaSamw } 4038c10a865Sas200622 } 4048c10a865Sas200622 4052c2961f8Sjose borrego smb_node_inc_open_ofiles(node); 406fc724630SAlan Wright smb_node_add_ofile(node, of); 4078b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_ref(node); 408148c5f43SAlan Wright smb_server_inc_files(of->f_server); 409da6c28aaSamw } 410da6c28aaSamw smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 411da6c28aaSamw smb_llist_insert_tail(&tree->t_ofile_list, of); 412da6c28aaSamw smb_llist_exit(&tree->t_ofile_list); 4131fcced4cSJordan Brown atomic_inc_32(&tree->t_open_files); 414da6c28aaSamw atomic_inc_32(&of->f_session->s_file_cnt); 415da6c28aaSamw return (of); 4163b13a1efSThomas Keiser 4173b13a1efSThomas Keiser errout: 418*811599a4SMatt Barden smb_tree_release(of->f_tree); 4193b13a1efSThomas Keiser smb_user_release(of->f_user); 4203b13a1efSThomas Keiser crfree(of->f_cr); 421bfe5e737SGordon Ross 422bfe5e737SGordon Ross list_destroy(&of->f_notify.nc_waiters); 423bfe5e737SGordon Ross mutex_destroy(&of->f_mutex); 424bfe5e737SGordon Ross 4253b13a1efSThomas Keiser of->f_magic = 0; 4268622ec45SGordon Ross kmem_cache_free(smb_cache_ofile, of); 427bfe5e737SGordon Ross 4283b13a1efSThomas Keiser smb_idpool_free(&tree->t_fid_pool, fid); 429bfe5e737SGordon Ross 4303b13a1efSThomas Keiser return (NULL); 431da6c28aaSamw } 432da6c28aaSamw 433da6c28aaSamw /* 434da6c28aaSamw * smb_ofile_close 435*811599a4SMatt Barden * 436*811599a4SMatt Barden * Incoming states: (where from) 437*811599a4SMatt Barden * SMB_OFILE_STATE_OPEN protocol close, smb_ofile_drop 438*811599a4SMatt Barden * SMB_OFILE_STATE_EXPIRED called via smb2_dh_expire 439*811599a4SMatt Barden * SMB_OFILE_STATE_ORPHANED smb2_dh_shutdown 440da6c28aaSamw */ 441c8ec8eeaSjose borrego void 4425fd03bc0SGordon Ross smb_ofile_close(smb_ofile_t *of, int32_t mtime_sec) 443da6c28aaSamw { 444a90cf9f2SGordon Ross smb_attr_t *pa; 4455fd03bc0SGordon Ross timestruc_t now; 446da6c28aaSamw 4475fd03bc0SGordon Ross SMB_OFILE_VALID(of); 4485fd03bc0SGordon Ross 449da6c28aaSamw mutex_enter(&of->f_mutex); 450da6c28aaSamw ASSERT(of->f_refcnt); 451*811599a4SMatt Barden 452*811599a4SMatt Barden switch (of->f_state) { 453*811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 454*811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 455*811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 456*811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_CLOSING; 457*811599a4SMatt Barden mutex_exit(&of->f_mutex); 458*811599a4SMatt Barden break; 459*811599a4SMatt Barden default: 46068b2bbf2SGordon Ross mutex_exit(&of->f_mutex); 46168b2bbf2SGordon Ross return; 46268b2bbf2SGordon Ross } 463da6c28aaSamw 464a90cf9f2SGordon Ross switch (of->f_ftype) { 465a90cf9f2SGordon Ross case SMB_FTYPE_BYTE_PIPE: 466a90cf9f2SGordon Ross case SMB_FTYPE_MESG_PIPE: 4673db3f65cSamw smb_opipe_close(of); 468148c5f43SAlan Wright smb_server_dec_pipes(of->f_server); 469a90cf9f2SGordon Ross break; 4705fd03bc0SGordon Ross 471a90cf9f2SGordon Ross case SMB_FTYPE_DISK: 472*811599a4SMatt Barden if (of->f_persistid != 0) 473*811599a4SMatt Barden smb_ofile_del_persistid(of); 474*811599a4SMatt Barden /* FALLTHROUGH */ 475*811599a4SMatt Barden case SMB_FTYPE_PRINTER: /* or FTYPE_DISK */ 4765fd03bc0SGordon Ross /* 4775fd03bc0SGordon Ross * In here we make changes to of->f_pending_attr 4785fd03bc0SGordon Ross * while not holding of->f_mutex. This is OK 4795fd03bc0SGordon Ross * because we've changed f_state to CLOSING, 4805fd03bc0SGordon Ross * so no more threads will take this path. 4815fd03bc0SGordon Ross */ 482a90cf9f2SGordon Ross pa = &of->f_pending_attr; 4835fd03bc0SGordon Ross if (mtime_sec != 0) { 4845fd03bc0SGordon Ross pa->sa_vattr.va_mtime.tv_sec = mtime_sec; 4855fd03bc0SGordon Ross pa->sa_mask |= SMB_AT_MTIME; 4865fd03bc0SGordon Ross } 4875fd03bc0SGordon Ross 4885fd03bc0SGordon Ross /* 4895fd03bc0SGordon Ross * If we have ever modified data via this handle 4905fd03bc0SGordon Ross * (write or truncate) and if the mtime was not 4915fd03bc0SGordon Ross * set via this handle, update the mtime again 4925fd03bc0SGordon Ross * during the close. Windows expects this. 4935fd03bc0SGordon Ross * [ MS-FSA 2.1.5.4 "Update Timestamps" ] 4945fd03bc0SGordon Ross */ 4955fd03bc0SGordon Ross if (of->f_written && 4965fd03bc0SGordon Ross (pa->sa_mask & SMB_AT_MTIME) == 0) { 4975fd03bc0SGordon Ross pa->sa_mask |= SMB_AT_MTIME; 4985fd03bc0SGordon Ross gethrestime(&now); 4995fd03bc0SGordon Ross pa->sa_vattr.va_mtime = now; 5005fd03bc0SGordon Ross } 501da6c28aaSamw 5028b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) { 503*811599a4SMatt Barden /* We delete using the on-disk name. */ 504*811599a4SMatt Barden uint32_t flags = SMB_CASE_SENSITIVE; 5058b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_node_set_delete_on_close(of->f_node, 5068b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States of->f_cr, flags); 5078b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 508dc20a302Sas200622 smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid); 5096537f381Sas200622 smb_node_destroy_lock_by_ofile(of->f_node, of); 510dc20a302Sas200622 5115fd03bc0SGordon Ross if (smb_node_is_file(of->f_node)) { 5128c10a865Sas200622 (void) smb_fsop_close(of->f_node, of->f_mode, 5138c10a865Sas200622 of->f_cr); 5145fd03bc0SGordon Ross smb_oplock_release(of->f_node, of); 515a90cf9f2SGordon Ross } else { 516a90cf9f2SGordon Ross /* 517a90cf9f2SGordon Ross * If there was an odir, close it. 518a90cf9f2SGordon Ross */ 519a90cf9f2SGordon Ross if (of->f_odir != NULL) 520a90cf9f2SGordon Ross smb_odir_close(of->f_odir); 521bfe5e737SGordon Ross /* 522bfe5e737SGordon Ross * Cancel any notify change requests that 523bfe5e737SGordon Ross * might be watching this open file (dir), 524bfe5e737SGordon Ross * and unsubscribe it from node events. 525bfe5e737SGordon Ross * 526bfe5e737SGordon Ross * Can't hold f_mutex when calling smb_notify_ofile. 527bfe5e737SGordon Ross * Don't really need it when unsubscribing, but 528bfe5e737SGordon Ross * harmless, and consistent with subscribing. 529bfe5e737SGordon Ross */ 530bfe5e737SGordon Ross if (of->f_notify.nc_subscribed) 531bfe5e737SGordon Ross smb_notify_ofile(of, 532bfe5e737SGordon Ross FILE_ACTION_HANDLE_CLOSED, NULL); 533bfe5e737SGordon Ross mutex_enter(&of->f_mutex); 534bfe5e737SGordon Ross if (of->f_notify.nc_subscribed) { 535bfe5e737SGordon Ross of->f_notify.nc_subscribed = B_FALSE; 536bfe5e737SGordon Ross smb_node_fcn_unsubscribe(of->f_node); 537bfe5e737SGordon Ross of->f_notify.nc_filter = 0; 538bfe5e737SGordon Ross } 539bfe5e737SGordon Ross mutex_exit(&of->f_mutex); 5405fd03bc0SGordon Ross } 5415fd03bc0SGordon Ross if (smb_node_dec_open_ofiles(of->f_node) == 0) { 5425fd03bc0SGordon Ross /* 5435cb2894aSGordon Ross * Last close. If we're not deleting 5445cb2894aSGordon Ross * the file, apply any pending attrs. 5455cb2894aSGordon Ross * Leave allocsz zero when no open files, 5465cb2894aSGordon Ross * just to avoid confusion, because it's 5475cb2894aSGordon Ross * only updated when there are opens. 5485fd03bc0SGordon Ross */ 54949d83597SMatt Barden mutex_enter(&of->f_node->n_mutex); 55049d83597SMatt Barden if (of->f_node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 55149d83597SMatt Barden smb_node_delete_on_close(of->f_node); 55249d83597SMatt Barden pa->sa_mask = 0; 55349d83597SMatt Barden } 5545cb2894aSGordon Ross of->f_node->n_allocsz = 0; 55549d83597SMatt Barden mutex_exit(&of->f_node->n_mutex); 5565fd03bc0SGordon Ross } 5575fd03bc0SGordon Ross if (pa->sa_mask != 0) { 5585fd03bc0SGordon Ross /* 5595fd03bc0SGordon Ross * Commit any pending attributes from 5605fd03bc0SGordon Ross * the ofile we're closing. Note that 5615fd03bc0SGordon Ross * we pass NULL as the ofile to setattr 5625fd03bc0SGordon Ross * so it will write to the file system 5635fd03bc0SGordon Ross * and not keep anything on the ofile. 5645fd03bc0SGordon Ross */ 5655fd03bc0SGordon Ross (void) smb_node_setattr(NULL, of->f_node, 5665fd03bc0SGordon Ross of->f_cr, NULL, pa); 5675fd03bc0SGordon Ross } 568dc20a302Sas200622 569148c5f43SAlan Wright smb_server_dec_files(of->f_server); 570a90cf9f2SGordon Ross break; 571da6c28aaSamw } 572*811599a4SMatt Barden 573*811599a4SMatt Barden /* 574*811599a4SMatt Barden * Keep f_state == SMB_OFILE_STATE_CLOSING 575*811599a4SMatt Barden * until the last ref. is dropped, in 576*811599a4SMatt Barden * smb_ofile_release() 577*811599a4SMatt Barden */ 578*811599a4SMatt Barden } 579*811599a4SMatt Barden 580*811599a4SMatt Barden /* 581*811599a4SMatt Barden * "Destructor" function for smb_ofile_close_all, and 582*811599a4SMatt Barden * smb_ofile_close_all_by_pid, called after the llist lock 583*811599a4SMatt Barden * for tree list has been exited. Our job is to either 584*811599a4SMatt Barden * close this ofile, or (if durable) set state _SAVE_DH. 585*811599a4SMatt Barden * 586*811599a4SMatt Barden * The next interesting thing happens when the last ref. 587*811599a4SMatt Barden * on this ofile calls smb_ofile_release(), where we 588*811599a4SMatt Barden * eihter delete the ofile, or (if durable) leave it 589*811599a4SMatt Barden * in the persistid hash table for possible reclaim. 590*811599a4SMatt Barden * 591*811599a4SMatt Barden * This is run via smb_llist_post (after smb_llist_exit) 592*811599a4SMatt Barden * because smb_ofile_close can block, and we'd rather not 593*811599a4SMatt Barden * block while holding the ofile list as reader. 594*811599a4SMatt Barden */ 595*811599a4SMatt Barden static void 596*811599a4SMatt Barden smb_ofile_drop(void *arg) 597*811599a4SMatt Barden { 598*811599a4SMatt Barden smb_ofile_t *of = arg; 599*811599a4SMatt Barden 600*811599a4SMatt Barden SMB_OFILE_VALID(of); 601da6c28aaSamw 602da6c28aaSamw mutex_enter(&of->f_mutex); 603*811599a4SMatt Barden switch (of->f_state) { 604*811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 605*811599a4SMatt Barden /* DH checks under mutex. */ 606*811599a4SMatt Barden if (of->f_ftype == SMB_FTYPE_DISK && 607*811599a4SMatt Barden of->dh_vers != SMB2_NOT_DURABLE && 608*811599a4SMatt Barden smb_dh_should_save(of)) { 609*811599a4SMatt Barden /* 610*811599a4SMatt Barden * Tell smb_ofile_release() to 611*811599a4SMatt Barden * make this an _ORPHANED DH. 612*811599a4SMatt Barden */ 613*811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_SAVE_DH; 614da6c28aaSamw mutex_exit(&of->f_mutex); 615*811599a4SMatt Barden break; 616*811599a4SMatt Barden } 617*811599a4SMatt Barden /* OK close it. */ 618*811599a4SMatt Barden mutex_exit(&of->f_mutex); 619*811599a4SMatt Barden smb_ofile_close(of, 0); 620*811599a4SMatt Barden break; 621*811599a4SMatt Barden 622*811599a4SMatt Barden default: 623*811599a4SMatt Barden /* Something else closed it already. */ 624*811599a4SMatt Barden mutex_exit(&of->f_mutex); 625*811599a4SMatt Barden break; 626*811599a4SMatt Barden } 627*811599a4SMatt Barden 628*811599a4SMatt Barden /* 629*811599a4SMatt Barden * Release the ref acquired during the traversal loop. 630*811599a4SMatt Barden * Note that on the last ref, this ofile will be 631*811599a4SMatt Barden * removed from the tree list etc. 632*811599a4SMatt Barden * See: smb_llist_post, smb_ofile_delete 633*811599a4SMatt Barden */ 634*811599a4SMatt Barden smb_ofile_release(of); 635da6c28aaSamw } 636da6c28aaSamw 637da6c28aaSamw /* 638da6c28aaSamw * smb_ofile_close_all 639da6c28aaSamw * 640da6c28aaSamw * 641da6c28aaSamw */ 642da6c28aaSamw void 643da6c28aaSamw smb_ofile_close_all( 644*811599a4SMatt Barden smb_tree_t *tree, 645*811599a4SMatt Barden uint32_t pid) 646da6c28aaSamw { 647da6c28aaSamw smb_ofile_t *of; 648*811599a4SMatt Barden smb_llist_t *ll; 649da6c28aaSamw 650da6c28aaSamw ASSERT(tree); 651da6c28aaSamw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 652da6c28aaSamw 653*811599a4SMatt Barden ll = &tree->t_ofile_list; 654*811599a4SMatt Barden 655*811599a4SMatt Barden smb_llist_enter(ll, RW_READER); 656*811599a4SMatt Barden for (of = smb_llist_head(ll); 657*811599a4SMatt Barden of != NULL; 658*811599a4SMatt Barden of = smb_llist_next(ll, of)) { 659da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 660da6c28aaSamw ASSERT(of->f_tree == tree); 661*811599a4SMatt Barden if (pid != 0 && of->f_opened_by_pid != pid) 662*811599a4SMatt Barden continue; 663*811599a4SMatt Barden if (smb_ofile_hold(of)) { 664*811599a4SMatt Barden smb_llist_post(ll, of, smb_ofile_drop); 665da6c28aaSamw } 666da6c28aaSamw } 667da6c28aaSamw 668da6c28aaSamw /* 669*811599a4SMatt Barden * Drop the lock and process the llist dtor queue. 670*811599a4SMatt Barden * Calls smb_ofile_drop on ofiles that were open. 671da6c28aaSamw */ 672*811599a4SMatt Barden smb_llist_exit(ll); 673da6c28aaSamw } 674da6c28aaSamw 675da6c28aaSamw /* 6761fcced4cSJordan Brown * If the enumeration request is for ofile data, handle it here. 6771fcced4cSJordan Brown * Otherwise, return. 6781fcced4cSJordan Brown * 6791fcced4cSJordan Brown * This function should be called with a hold on the ofile. 6801fcced4cSJordan Brown */ 6811fcced4cSJordan Brown int 6821fcced4cSJordan Brown smb_ofile_enum(smb_ofile_t *of, smb_svcenum_t *svcenum) 6831fcced4cSJordan Brown { 6841fcced4cSJordan Brown uint8_t *pb; 6851fcced4cSJordan Brown uint_t nbytes; 6861fcced4cSJordan Brown int rc; 6871fcced4cSJordan Brown 6881fcced4cSJordan Brown ASSERT(of); 6891fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 6901fcced4cSJordan Brown ASSERT(of->f_refcnt); 6911fcced4cSJordan Brown 6921fcced4cSJordan Brown if (svcenum->se_type != SMB_SVCENUM_TYPE_FILE) 6931fcced4cSJordan Brown return (0); 6941fcced4cSJordan Brown 6951fcced4cSJordan Brown if (svcenum->se_nskip > 0) { 6961fcced4cSJordan Brown svcenum->se_nskip--; 6971fcced4cSJordan Brown return (0); 6981fcced4cSJordan Brown } 6991fcced4cSJordan Brown 7001fcced4cSJordan Brown if (svcenum->se_nitems >= svcenum->se_nlimit) { 7011fcced4cSJordan Brown svcenum->se_nitems = svcenum->se_nlimit; 7021fcced4cSJordan Brown return (0); 7031fcced4cSJordan Brown } 7041fcced4cSJordan Brown 7051fcced4cSJordan Brown pb = &svcenum->se_buf[svcenum->se_bused]; 7061fcced4cSJordan Brown 7071fcced4cSJordan Brown rc = smb_ofile_netinfo_encode(of, pb, svcenum->se_bavail, 7081fcced4cSJordan Brown &nbytes); 7091fcced4cSJordan Brown if (rc == 0) { 7101fcced4cSJordan Brown svcenum->se_bavail -= nbytes; 7111fcced4cSJordan Brown svcenum->se_bused += nbytes; 7121fcced4cSJordan Brown svcenum->se_nitems++; 7131fcced4cSJordan Brown } 7141fcced4cSJordan Brown 7151fcced4cSJordan Brown return (rc); 7161fcced4cSJordan Brown } 7171fcced4cSJordan Brown 7181fcced4cSJordan Brown /* 719*811599a4SMatt Barden * Take a reference on an open file, in any of the states: 720*811599a4SMatt Barden * RECONNECT, SAVE_DH, OPEN, ORPHANED. 721*811599a4SMatt Barden * Return TRUE if ref taken. Used for oplock breaks. 722*811599a4SMatt Barden * 723*811599a4SMatt Barden * Note: When the oplock break code calls this, it holds the 724*811599a4SMatt Barden * node ofile list lock and node oplock mutex. When we see 725*811599a4SMatt Barden * an ofile in states RECONNECT or SAVING, we know the ofile 726*811599a4SMatt Barden * is gaining or losing it's tree, and that happens quickly, 727*811599a4SMatt Barden * so we just wait for that work to finish. However, the 728*811599a4SMatt Barden * waiting for state transitions here means we have to be 729*811599a4SMatt Barden * careful not to re-enter the node list lock or otherwise 730*811599a4SMatt Barden * block on things that could cause a deadlock. Waiting 731*811599a4SMatt Barden * just on of->f_mutex here is OK. 732*811599a4SMatt Barden */ 733*811599a4SMatt Barden boolean_t 734*811599a4SMatt Barden smb_ofile_hold_olbrk(smb_ofile_t *of) 735*811599a4SMatt Barden { 736*811599a4SMatt Barden boolean_t ret = B_FALSE; 737*811599a4SMatt Barden 738*811599a4SMatt Barden ASSERT(of); 739*811599a4SMatt Barden ASSERT(of->f_magic == SMB_OFILE_MAGIC); 740*811599a4SMatt Barden 741*811599a4SMatt Barden mutex_enter(&of->f_mutex); 742*811599a4SMatt Barden 743*811599a4SMatt Barden again: 744*811599a4SMatt Barden switch (of->f_state) { 745*811599a4SMatt Barden case SMB_OFILE_STATE_RECONNECT: 746*811599a4SMatt Barden case SMB_OFILE_STATE_SAVING: 747*811599a4SMatt Barden cv_wait(&of->f_cv, &of->f_mutex); 748*811599a4SMatt Barden goto again; 749*811599a4SMatt Barden 750*811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 751*811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 752*811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 753*811599a4SMatt Barden of->f_refcnt++; 754*811599a4SMatt Barden ret = B_TRUE; 755*811599a4SMatt Barden break; 756*811599a4SMatt Barden 757*811599a4SMatt Barden default: 758*811599a4SMatt Barden break; 759*811599a4SMatt Barden } 760*811599a4SMatt Barden mutex_exit(&of->f_mutex); 761*811599a4SMatt Barden 762*811599a4SMatt Barden return (ret); 763*811599a4SMatt Barden } 764*811599a4SMatt Barden 765*811599a4SMatt Barden /* 7661fcced4cSJordan Brown * Take a reference on an open file. 7671fcced4cSJordan Brown */ 7681fcced4cSJordan Brown boolean_t 7691fcced4cSJordan Brown smb_ofile_hold(smb_ofile_t *of) 7701fcced4cSJordan Brown { 7711fcced4cSJordan Brown ASSERT(of); 7721fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 7731fcced4cSJordan Brown 7741fcced4cSJordan Brown mutex_enter(&of->f_mutex); 7751fcced4cSJordan Brown 77668b2bbf2SGordon Ross if (of->f_state != SMB_OFILE_STATE_OPEN) { 7771fcced4cSJordan Brown mutex_exit(&of->f_mutex); 7781fcced4cSJordan Brown return (B_FALSE); 7791fcced4cSJordan Brown } 78068b2bbf2SGordon Ross of->f_refcnt++; 78168b2bbf2SGordon Ross 78268b2bbf2SGordon Ross mutex_exit(&of->f_mutex); 78368b2bbf2SGordon Ross return (B_TRUE); 78468b2bbf2SGordon Ross } 7851fcced4cSJordan Brown 7861fcced4cSJordan Brown /* 7879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Release a reference on a file. If the reference count falls to 7889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * zero and the file has been closed, post the object for deletion. 7899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Object deletion is deferred to avoid modifying a list while an 7909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * iteration may be in progress. 791*811599a4SMatt Barden * 792*811599a4SMatt Barden * We're careful to avoid dropping f_session etc. until the last 793*811599a4SMatt Barden * reference goes away. The oplock break code depends on that 794*811599a4SMatt Barden * not changing while it holds a ref. on an ofile. 795da6c28aaSamw */ 796da6c28aaSamw void 79724d2db37Sjose borrego smb_ofile_release(smb_ofile_t *of) 798da6c28aaSamw { 799*811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 800*811599a4SMatt Barden boolean_t delete = B_FALSE; 801*811599a4SMatt Barden 8029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OFILE_VALID(of); 803da6c28aaSamw 804da6c28aaSamw mutex_enter(&of->f_mutex); 805*811599a4SMatt Barden ASSERT(of->f_refcnt > 0); 806da6c28aaSamw of->f_refcnt--; 807*811599a4SMatt Barden 808da6c28aaSamw switch (of->f_state) { 809da6c28aaSamw case SMB_OFILE_STATE_OPEN: 810*811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 811*811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 812da6c28aaSamw break; 813da6c28aaSamw 814*811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 815*811599a4SMatt Barden ASSERT(tree != NULL); 816*811599a4SMatt Barden if (of->f_refcnt == 0) { 817*811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_SAVING; 818*811599a4SMatt Barden smb_llist_post(&tree->t_ofile_list, of, 819*811599a4SMatt Barden smb_ofile_save_dh); 820*811599a4SMatt Barden } 821*811599a4SMatt Barden break; 822*811599a4SMatt Barden 823*811599a4SMatt Barden case SMB_OFILE_STATE_CLOSING: 824*811599a4SMatt Barden /* Note, tree == NULL on _ORPHANED */ 825*811599a4SMatt Barden if (of->f_refcnt == 0) { 826*811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_CLOSED; 827*811599a4SMatt Barden if (tree == NULL) { 828*811599a4SMatt Barden /* Skip smb_llist_post */ 829*811599a4SMatt Barden delete = B_TRUE; 830*811599a4SMatt Barden break; 831*811599a4SMatt Barden } 832*811599a4SMatt Barden smb_llist_post(&tree->t_ofile_list, of, 833*811599a4SMatt Barden smb_ofile_delete); 834*811599a4SMatt Barden } 835da6c28aaSamw break; 836da6c28aaSamw 837da6c28aaSamw default: 838da6c28aaSamw ASSERT(0); 839da6c28aaSamw break; 840da6c28aaSamw } 841da6c28aaSamw mutex_exit(&of->f_mutex); 842*811599a4SMatt Barden 843*811599a4SMatt Barden /* 844*811599a4SMatt Barden * When we drop the last ref. on an expired DH, it's no longer 845*811599a4SMatt Barden * in any tree, so skip the smb_llist_post and just call 846*811599a4SMatt Barden * smb_ofile_delete directly. 847*811599a4SMatt Barden */ 848*811599a4SMatt Barden if (delete) { 849*811599a4SMatt Barden smb_ofile_delete(of); 850*811599a4SMatt Barden } 851da6c28aaSamw } 852da6c28aaSamw 853da6c28aaSamw /* 854cb174861Sjoyce mcintosh * smb_ofile_request_complete 855cb174861Sjoyce mcintosh * 856cb174861Sjoyce mcintosh * During oplock acquisition, all other oplock requests on the node 857cb174861Sjoyce mcintosh * are blocked until the acquire request completes and the response 858cb174861Sjoyce mcintosh * is on the wire. 859cb174861Sjoyce mcintosh * Call smb_oplock_broadcast to notify the node that the request 860cb174861Sjoyce mcintosh * has completed. 861cb174861Sjoyce mcintosh * 862cb174861Sjoyce mcintosh * THIS MECHANISM RELIES ON THE FACT THAT THE OFILE IS NOT REMOVED 863cb174861Sjoyce mcintosh * FROM THE SR UNTIL REQUEST COMPLETION (when the sr is destroyed) 864cb174861Sjoyce mcintosh */ 865cb174861Sjoyce mcintosh void 866cb174861Sjoyce mcintosh smb_ofile_request_complete(smb_ofile_t *of) 867cb174861Sjoyce mcintosh { 868cb174861Sjoyce mcintosh SMB_OFILE_VALID(of); 869cb174861Sjoyce mcintosh 870cb174861Sjoyce mcintosh switch (of->f_ftype) { 871cb174861Sjoyce mcintosh case SMB_FTYPE_DISK: 872cb174861Sjoyce mcintosh ASSERT(of->f_node); 873cb174861Sjoyce mcintosh smb_oplock_broadcast(of->f_node); 874cb174861Sjoyce mcintosh break; 875cb174861Sjoyce mcintosh case SMB_FTYPE_MESG_PIPE: 876cb174861Sjoyce mcintosh break; 877cb174861Sjoyce mcintosh default: 878cb174861Sjoyce mcintosh break; 879cb174861Sjoyce mcintosh } 880cb174861Sjoyce mcintosh } 881cb174861Sjoyce mcintosh 882cb174861Sjoyce mcintosh /* 883da6c28aaSamw * smb_ofile_lookup_by_fid 884da6c28aaSamw * 885da6c28aaSamw * Find the open file whose fid matches the one specified in the request. 886da6c28aaSamw * If we can't find the fid or the shares (trees) don't match, we have a 887da6c28aaSamw * bad fid. 888da6c28aaSamw */ 889da6c28aaSamw smb_ofile_t * 890da6c28aaSamw smb_ofile_lookup_by_fid( 8913b13a1efSThomas Keiser smb_request_t *sr, 892da6c28aaSamw uint16_t fid) 893da6c28aaSamw { 8943b13a1efSThomas Keiser smb_tree_t *tree = sr->tid_tree; 895da6c28aaSamw smb_llist_t *of_list; 896da6c28aaSamw smb_ofile_t *of; 897da6c28aaSamw 898da6c28aaSamw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 899da6c28aaSamw 900da6c28aaSamw of_list = &tree->t_ofile_list; 901da6c28aaSamw 902da6c28aaSamw smb_llist_enter(of_list, RW_READER); 903da6c28aaSamw of = smb_llist_head(of_list); 904da6c28aaSamw while (of) { 905da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 906da6c28aaSamw ASSERT(of->f_tree == tree); 9073b13a1efSThomas Keiser if (of->f_fid == fid) 9083b13a1efSThomas Keiser break; 9093b13a1efSThomas Keiser of = smb_llist_next(of_list, of); 9103b13a1efSThomas Keiser } 9113b13a1efSThomas Keiser if (of == NULL) 9123b13a1efSThomas Keiser goto out; 9133b13a1efSThomas Keiser 9143b13a1efSThomas Keiser /* 9153b13a1efSThomas Keiser * Only allow use of a given FID with the same UID that 9163b13a1efSThomas Keiser * was used to open it. MS-CIFS 3.3.5.14 9173b13a1efSThomas Keiser */ 9183b13a1efSThomas Keiser if (of->f_user != sr->uid_user) { 9193b13a1efSThomas Keiser of = NULL; 9203b13a1efSThomas Keiser goto out; 9213b13a1efSThomas Keiser } 9223b13a1efSThomas Keiser 923*811599a4SMatt Barden /* inline smb_ofile_hold() */ 924da6c28aaSamw mutex_enter(&of->f_mutex); 925da6c28aaSamw if (of->f_state != SMB_OFILE_STATE_OPEN) { 926da6c28aaSamw mutex_exit(&of->f_mutex); 9273b13a1efSThomas Keiser of = NULL; 9283b13a1efSThomas Keiser goto out; 929da6c28aaSamw } 930da6c28aaSamw of->f_refcnt++; 931da6c28aaSamw mutex_exit(&of->f_mutex); 9323b13a1efSThomas Keiser 9333b13a1efSThomas Keiser out: 934da6c28aaSamw smb_llist_exit(of_list); 935da6c28aaSamw return (of); 936da6c28aaSamw } 937da6c28aaSamw 938da6c28aaSamw /* 9391fcced4cSJordan Brown * smb_ofile_lookup_by_uniqid 9401fcced4cSJordan Brown * 9411fcced4cSJordan Brown * Find the open file whose uniqid matches the one specified in the request. 9421fcced4cSJordan Brown */ 9431fcced4cSJordan Brown smb_ofile_t * 9441fcced4cSJordan Brown smb_ofile_lookup_by_uniqid(smb_tree_t *tree, uint32_t uniqid) 9451fcced4cSJordan Brown { 9461fcced4cSJordan Brown smb_llist_t *of_list; 9471fcced4cSJordan Brown smb_ofile_t *of; 9481fcced4cSJordan Brown 9491fcced4cSJordan Brown ASSERT(tree->t_magic == SMB_TREE_MAGIC); 9501fcced4cSJordan Brown 9511fcced4cSJordan Brown of_list = &tree->t_ofile_list; 9521fcced4cSJordan Brown smb_llist_enter(of_list, RW_READER); 9531fcced4cSJordan Brown of = smb_llist_head(of_list); 9541fcced4cSJordan Brown 9551fcced4cSJordan Brown while (of) { 9561fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 9571fcced4cSJordan Brown ASSERT(of->f_tree == tree); 9581fcced4cSJordan Brown 9591fcced4cSJordan Brown if (of->f_uniqid == uniqid) { 9601fcced4cSJordan Brown if (smb_ofile_hold(of)) { 9611fcced4cSJordan Brown smb_llist_exit(of_list); 9621fcced4cSJordan Brown return (of); 9631fcced4cSJordan Brown } 9641fcced4cSJordan Brown } 9651fcced4cSJordan Brown 9661fcced4cSJordan Brown of = smb_llist_next(of_list, of); 9671fcced4cSJordan Brown } 9681fcced4cSJordan Brown 9691fcced4cSJordan Brown smb_llist_exit(of_list); 9701fcced4cSJordan Brown return (NULL); 9711fcced4cSJordan Brown } 9721fcced4cSJordan Brown 973*811599a4SMatt Barden static smb_ofile_t * 974*811599a4SMatt Barden smb_ofile_hold_cb(smb_ofile_t *of) 975*811599a4SMatt Barden { 976*811599a4SMatt Barden smb_ofile_t *ret = of; 977*811599a4SMatt Barden 978*811599a4SMatt Barden mutex_enter(&of->f_mutex); 979*811599a4SMatt Barden if (of->f_state == SMB_OFILE_STATE_ORPHANED) 980*811599a4SMatt Barden /* inline smb_ofile_hold() */ 981*811599a4SMatt Barden of->f_refcnt++; 982*811599a4SMatt Barden else 983*811599a4SMatt Barden ret = NULL; 984*811599a4SMatt Barden 985*811599a4SMatt Barden mutex_exit(&of->f_mutex); 986*811599a4SMatt Barden return (ret); 987*811599a4SMatt Barden } 988*811599a4SMatt Barden 989*811599a4SMatt Barden /* 990*811599a4SMatt Barden * Lookup an ofile by persistent ID, and return ONLY if in state ORPHANED 991*811599a4SMatt Barden * This is used by SMB2 create "reclaim". 992*811599a4SMatt Barden */ 993*811599a4SMatt Barden smb_ofile_t * 994*811599a4SMatt Barden smb_ofile_lookup_by_persistid(smb_request_t *sr, uint64_t persistid) 995*811599a4SMatt Barden { 996*811599a4SMatt Barden smb_hash_t *hash; 997*811599a4SMatt Barden smb_bucket_t *bucket; 998*811599a4SMatt Barden smb_llist_t *ll; 999*811599a4SMatt Barden smb_ofile_t *of; 1000*811599a4SMatt Barden uint_t idx; 1001*811599a4SMatt Barden 1002*811599a4SMatt Barden hash = sr->sr_server->sv_persistid_ht; 1003*811599a4SMatt Barden idx = smb_hash_uint64(hash, persistid); 1004*811599a4SMatt Barden bucket = &hash->buckets[idx]; 1005*811599a4SMatt Barden ll = &bucket->b_list; 1006*811599a4SMatt Barden 1007*811599a4SMatt Barden smb_llist_enter(ll, RW_READER); 1008*811599a4SMatt Barden of = smb_llist_head(ll); 1009*811599a4SMatt Barden while (of != NULL) { 1010*811599a4SMatt Barden if (of->f_persistid == persistid) 1011*811599a4SMatt Barden break; 1012*811599a4SMatt Barden of = smb_llist_next(ll, of); 1013*811599a4SMatt Barden } 1014*811599a4SMatt Barden if (of != NULL) 1015*811599a4SMatt Barden of = smb_ofile_hold_cb(of); 1016*811599a4SMatt Barden smb_llist_exit(ll); 1017*811599a4SMatt Barden 1018*811599a4SMatt Barden return (of); 1019*811599a4SMatt Barden } 1020*811599a4SMatt Barden 1021*811599a4SMatt Barden /* 1022*811599a4SMatt Barden * Create a (unique) persistent ID for a new ofile, 1023*811599a4SMatt Barden * and add this ofile to the persistid hash table. 1024*811599a4SMatt Barden */ 1025*811599a4SMatt Barden void 1026*811599a4SMatt Barden smb_ofile_set_persistid(smb_ofile_t *of) 1027*811599a4SMatt Barden { 1028*811599a4SMatt Barden smb_hash_t *hash = of->f_server->sv_persistid_ht; 1029*811599a4SMatt Barden smb_bucket_t *bucket; 1030*811599a4SMatt Barden smb_llist_t *ll; 1031*811599a4SMatt Barden uint_t idx; 1032*811599a4SMatt Barden 1033*811599a4SMatt Barden of->f_persistid = SMB_OFILE_PERSISTID(of); 1034*811599a4SMatt Barden 1035*811599a4SMatt Barden idx = smb_hash_uint64(hash, of->f_persistid); 1036*811599a4SMatt Barden bucket = &hash->buckets[idx]; 1037*811599a4SMatt Barden ll = &bucket->b_list; 1038*811599a4SMatt Barden smb_llist_enter(ll, RW_WRITER); 1039*811599a4SMatt Barden smb_llist_insert_tail(ll, of); 1040*811599a4SMatt Barden smb_llist_exit(ll); 1041*811599a4SMatt Barden } 1042*811599a4SMatt Barden 1043*811599a4SMatt Barden void 1044*811599a4SMatt Barden smb_ofile_del_persistid(smb_ofile_t *of) 1045*811599a4SMatt Barden { 1046*811599a4SMatt Barden smb_hash_t *hash = of->f_server->sv_persistid_ht; 1047*811599a4SMatt Barden smb_bucket_t *bucket; 1048*811599a4SMatt Barden smb_llist_t *ll; 1049*811599a4SMatt Barden uint_t idx; 1050*811599a4SMatt Barden 1051*811599a4SMatt Barden idx = smb_hash_uint64(hash, of->f_persistid); 1052*811599a4SMatt Barden bucket = &hash->buckets[idx]; 1053*811599a4SMatt Barden ll = &bucket->b_list; 1054*811599a4SMatt Barden smb_llist_enter(ll, RW_WRITER); 1055*811599a4SMatt Barden smb_llist_remove(ll, of); 1056*811599a4SMatt Barden smb_llist_exit(ll); 1057*811599a4SMatt Barden } 1058*811599a4SMatt Barden 10591fcced4cSJordan Brown /* 10601fcced4cSJordan Brown * Disallow NetFileClose on certain ofiles to avoid side-effects. 10611fcced4cSJordan Brown * Closing a tree root is not allowed: use NetSessionDel or NetShareDel. 10621fcced4cSJordan Brown * Closing SRVSVC connections is not allowed because this NetFileClose 10631fcced4cSJordan Brown * request may depend on this ofile. 10641fcced4cSJordan Brown */ 10651fcced4cSJordan Brown boolean_t 10661fcced4cSJordan Brown smb_ofile_disallow_fclose(smb_ofile_t *of) 10671fcced4cSJordan Brown { 10681fcced4cSJordan Brown ASSERT(of); 10691fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 10701fcced4cSJordan Brown ASSERT(of->f_refcnt); 10711fcced4cSJordan Brown 10721fcced4cSJordan Brown switch (of->f_ftype) { 10731fcced4cSJordan Brown case SMB_FTYPE_DISK: 10741fcced4cSJordan Brown ASSERT(of->f_tree); 10751fcced4cSJordan Brown return (of->f_node == of->f_tree->t_snode); 10761fcced4cSJordan Brown 10771fcced4cSJordan Brown case SMB_FTYPE_MESG_PIPE: 10781fcced4cSJordan Brown ASSERT(of->f_pipe); 1079bbf6f00cSJordan Brown if (smb_strcasecmp(of->f_pipe->p_name, "SRVSVC", 0) == 0) 10801fcced4cSJordan Brown return (B_TRUE); 10811fcced4cSJordan Brown break; 10821fcced4cSJordan Brown default: 10831fcced4cSJordan Brown break; 10841fcced4cSJordan Brown } 10851fcced4cSJordan Brown 10861fcced4cSJordan Brown return (B_FALSE); 10871fcced4cSJordan Brown } 10881fcced4cSJordan Brown 10891fcced4cSJordan Brown /* 1090da6c28aaSamw * smb_ofile_set_flags 1091da6c28aaSamw * 1092da6c28aaSamw * Return value: 1093da6c28aaSamw * 1094da6c28aaSamw * Current flags value 1095da6c28aaSamw * 1096da6c28aaSamw */ 1097da6c28aaSamw void 1098da6c28aaSamw smb_ofile_set_flags( 1099da6c28aaSamw smb_ofile_t *of, 1100da6c28aaSamw uint32_t flags) 1101da6c28aaSamw { 1102da6c28aaSamw ASSERT(of); 1103da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1104da6c28aaSamw ASSERT(of->f_refcnt); 1105da6c28aaSamw 1106da6c28aaSamw mutex_enter(&of->f_mutex); 1107da6c28aaSamw of->f_flags |= flags; 1108da6c28aaSamw mutex_exit(&of->f_mutex); 1109da6c28aaSamw } 1110f96bd5c8SAlan Wright 1111da6c28aaSamw /* 1112da6c28aaSamw * smb_ofile_seek 1113da6c28aaSamw * 1114da6c28aaSamw * Return value: 1115da6c28aaSamw * 1116da6c28aaSamw * 0 Success 1117da6c28aaSamw * EINVAL Unknown mode 1118da6c28aaSamw * EOVERFLOW offset too big 1119da6c28aaSamw * 1120da6c28aaSamw */ 1121da6c28aaSamw int 1122da6c28aaSamw smb_ofile_seek( 1123da6c28aaSamw smb_ofile_t *of, 1124da6c28aaSamw ushort_t mode, 1125da6c28aaSamw int32_t off, 1126da6c28aaSamw uint32_t *retoff) 1127da6c28aaSamw { 112855bf511dSas200622 u_offset_t newoff = 0; 1129da6c28aaSamw int rc = 0; 1130037cac00Sjoyce mcintosh smb_attr_t attr; 1131da6c28aaSamw 1132da6c28aaSamw ASSERT(of); 1133da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1134da6c28aaSamw ASSERT(of->f_refcnt); 1135da6c28aaSamw 1136da6c28aaSamw mutex_enter(&of->f_mutex); 1137da6c28aaSamw switch (mode) { 1138da6c28aaSamw case SMB_SEEK_SET: 1139da6c28aaSamw if (off < 0) 1140da6c28aaSamw newoff = 0; 1141da6c28aaSamw else 114255bf511dSas200622 newoff = (u_offset_t)off; 1143da6c28aaSamw break; 1144da6c28aaSamw 1145da6c28aaSamw case SMB_SEEK_CUR: 1146da6c28aaSamw if (off < 0 && (-off) > of->f_seek_pos) 1147da6c28aaSamw newoff = 0; 1148da6c28aaSamw else 114955bf511dSas200622 newoff = of->f_seek_pos + (u_offset_t)off; 1150da6c28aaSamw break; 1151da6c28aaSamw 1152da6c28aaSamw case SMB_SEEK_END: 1153037cac00Sjoyce mcintosh bzero(&attr, sizeof (smb_attr_t)); 1154037cac00Sjoyce mcintosh attr.sa_mask |= SMB_AT_SIZE; 11558622ec45SGordon Ross rc = smb_fsop_getattr(NULL, zone_kcred(), of->f_node, &attr); 1156037cac00Sjoyce mcintosh if (rc != 0) { 1157037cac00Sjoyce mcintosh mutex_exit(&of->f_mutex); 1158037cac00Sjoyce mcintosh return (rc); 1159037cac00Sjoyce mcintosh } 1160037cac00Sjoyce mcintosh if (off < 0 && (-off) > attr.sa_vattr.va_size) 1161da6c28aaSamw newoff = 0; 1162da6c28aaSamw else 1163037cac00Sjoyce mcintosh newoff = attr.sa_vattr.va_size + (u_offset_t)off; 1164da6c28aaSamw break; 1165da6c28aaSamw 1166da6c28aaSamw default: 1167da6c28aaSamw mutex_exit(&of->f_mutex); 1168da6c28aaSamw return (EINVAL); 1169da6c28aaSamw } 1170da6c28aaSamw 117155bf511dSas200622 /* 117255bf511dSas200622 * See comments at the beginning of smb_seek.c. 117355bf511dSas200622 * If the offset is greater than UINT_MAX, we will return an error. 117455bf511dSas200622 */ 117555bf511dSas200622 117655bf511dSas200622 if (newoff > UINT_MAX) { 1177da6c28aaSamw rc = EOVERFLOW; 1178da6c28aaSamw } else { 1179da6c28aaSamw of->f_seek_pos = newoff; 1180da6c28aaSamw *retoff = (uint32_t)newoff; 1181da6c28aaSamw } 1182da6c28aaSamw mutex_exit(&of->f_mutex); 1183da6c28aaSamw return (rc); 1184da6c28aaSamw } 1185da6c28aaSamw 1186da6c28aaSamw /* 11876d1c73b5SDan Vatca * smb_ofile_flush 11886d1c73b5SDan Vatca * 11896d1c73b5SDan Vatca * If writes on this file are not synchronous, flush it using the NFSv3 11906d1c73b5SDan Vatca * commit interface. 11916d1c73b5SDan Vatca * 11926d1c73b5SDan Vatca * XXX - todo: Flush named pipe should drain writes. 11936d1c73b5SDan Vatca */ 11946d1c73b5SDan Vatca void 11956d1c73b5SDan Vatca smb_ofile_flush(struct smb_request *sr, struct smb_ofile *of) 11966d1c73b5SDan Vatca { 11976d1c73b5SDan Vatca switch (of->f_ftype) { 11986d1c73b5SDan Vatca case SMB_FTYPE_DISK: 11996d1c73b5SDan Vatca if ((of->f_node->flags & NODE_FLAGS_WRITE_THROUGH) == 0) 12006d1c73b5SDan Vatca (void) smb_fsop_commit(sr, of->f_cr, of->f_node); 12016d1c73b5SDan Vatca break; 12026d1c73b5SDan Vatca default: 12036d1c73b5SDan Vatca break; 12046d1c73b5SDan Vatca } 12056d1c73b5SDan Vatca } 12066d1c73b5SDan Vatca 12076d1c73b5SDan Vatca /* 1208da6c28aaSamw * smb_ofile_is_open 1209da6c28aaSamw */ 1210da6c28aaSamw boolean_t 12112c2961f8Sjose borrego smb_ofile_is_open(smb_ofile_t *of) 1212da6c28aaSamw { 12131fcced4cSJordan Brown boolean_t rc; 1214da6c28aaSamw 12152c2961f8Sjose borrego SMB_OFILE_VALID(of); 1216da6c28aaSamw 1217da6c28aaSamw mutex_enter(&of->f_mutex); 12181fcced4cSJordan Brown rc = smb_ofile_is_open_locked(of); 1219da6c28aaSamw mutex_exit(&of->f_mutex); 1220da6c28aaSamw return (rc); 1221da6c28aaSamw } 1222da6c28aaSamw 1223da6c28aaSamw /* *************************** Static Functions ***************************** */ 1224da6c28aaSamw 1225da6c28aaSamw /* 12261fcced4cSJordan Brown * Determine whether or not an ofile is open. 12271fcced4cSJordan Brown * This function must be called with the mutex held. 12281fcced4cSJordan Brown */ 12291fcced4cSJordan Brown static boolean_t 12301fcced4cSJordan Brown smb_ofile_is_open_locked(smb_ofile_t *of) 12311fcced4cSJordan Brown { 1232*811599a4SMatt Barden ASSERT(MUTEX_HELD(&of->f_mutex)); 1233*811599a4SMatt Barden 12341fcced4cSJordan Brown switch (of->f_state) { 12351fcced4cSJordan Brown case SMB_OFILE_STATE_OPEN: 1236*811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 1237*811599a4SMatt Barden case SMB_OFILE_STATE_SAVING: 1238*811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 1239*811599a4SMatt Barden case SMB_OFILE_STATE_RECONNECT: 12401fcced4cSJordan Brown return (B_TRUE); 12411fcced4cSJordan Brown 12421fcced4cSJordan Brown case SMB_OFILE_STATE_CLOSING: 12431fcced4cSJordan Brown case SMB_OFILE_STATE_CLOSED: 1244*811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 12451fcced4cSJordan Brown return (B_FALSE); 12461fcced4cSJordan Brown 12471fcced4cSJordan Brown default: 12481fcced4cSJordan Brown ASSERT(0); 12491fcced4cSJordan Brown return (B_FALSE); 12501fcced4cSJordan Brown } 12511fcced4cSJordan Brown } 12521fcced4cSJordan Brown 12531fcced4cSJordan Brown /* 1254*811599a4SMatt Barden * smb_ofile_save_dh 1255*811599a4SMatt Barden * 1256*811599a4SMatt Barden * Called via smb_llist_post (after smb_llist_exit) when the last ref. 1257*811599a4SMatt Barden * on this ofile has gone, and this ofile is a "durable handle" (DH) 1258*811599a4SMatt Barden * that has state we've decided to save. 1259*811599a4SMatt Barden * 1260*811599a4SMatt Barden * This does parts of what smb_ofile_delete would do, including: 1261*811599a4SMatt Barden * remove the ofile from the tree ofile list and related. 1262*811599a4SMatt Barden * 1263*811599a4SMatt Barden * We leave the ofile in state ORPHANED, ready for reconnect 1264*811599a4SMatt Barden * or expiration via smb2_dh_expire (see smb_ofile_delete). 1265da6c28aaSamw */ 1266*811599a4SMatt Barden static void 1267*811599a4SMatt Barden smb_ofile_save_dh(void *arg) 1268da6c28aaSamw { 1269*811599a4SMatt Barden smb_ofile_t *of = (smb_ofile_t *)arg; 1270*811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 1271da6c28aaSamw 1272*811599a4SMatt Barden SMB_OFILE_VALID(of); 1273*811599a4SMatt Barden ASSERT(of->f_refcnt == 0); 1274*811599a4SMatt Barden ASSERT(of->f_ftype == SMB_FTYPE_DISK); 1275*811599a4SMatt Barden ASSERT(of->f_state == SMB_OFILE_STATE_SAVING); 1276da6c28aaSamw 1277*811599a4SMatt Barden atomic_dec_32(&of->f_session->s_file_cnt); 1278*811599a4SMatt Barden atomic_dec_32(&of->f_tree->t_open_files); 1279*811599a4SMatt Barden smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 1280*811599a4SMatt Barden smb_llist_remove(&tree->t_ofile_list, of); 1281*811599a4SMatt Barden smb_llist_exit(&tree->t_ofile_list); 1282*811599a4SMatt Barden 1283da6c28aaSamw /* 1284*811599a4SMatt Barden * This ofile is no longer on t_ofile_list, however... 1285*811599a4SMatt Barden * 1286*811599a4SMatt Barden * This is called via smb_llist_post, which means it may run 1287*811599a4SMatt Barden * BEFORE smb_ofile_release drops f_mutex (if another thread 1288*811599a4SMatt Barden * flushes the delete queue before we do). Synchronize. 1289da6c28aaSamw */ 1290*811599a4SMatt Barden mutex_enter(&of->f_mutex); 1291*811599a4SMatt Barden DTRACE_PROBE1(ofile__exit, smb_ofile_t, of); 1292da6c28aaSamw mutex_exit(&of->f_mutex); 1293*811599a4SMatt Barden 1294*811599a4SMatt Barden /* 1295*811599a4SMatt Barden * Keep f_notify state, lease, and 1296*811599a4SMatt Barden * keep on node ofile list. 1297*811599a4SMatt Barden * Keep of->f_cr until reclaim. 1298*811599a4SMatt Barden */ 1299*811599a4SMatt Barden 1300*811599a4SMatt Barden ASSERT(of->f_fid != 0); 1301*811599a4SMatt Barden smb_idpool_free(&tree->t_fid_pool, of->f_fid); 1302*811599a4SMatt Barden of->f_fid = 0; 1303*811599a4SMatt Barden smb_tree_release(of->f_tree); 1304*811599a4SMatt Barden of->f_tree = NULL; 1305*811599a4SMatt Barden smb_user_release(of->f_user); 1306*811599a4SMatt Barden of->f_user = NULL; 1307*811599a4SMatt Barden of->f_session = NULL; 1308*811599a4SMatt Barden 1309*811599a4SMatt Barden /* 1310*811599a4SMatt Barden * Make it "orphaned" so it can now be reclaimed. 1311*811599a4SMatt Barden * Note that smb_ofile_hold_olbrk() may have blocked 1312*811599a4SMatt Barden * for state SMB_OFILE_STATE_SAVING, so wake it. 1313*811599a4SMatt Barden */ 1314*811599a4SMatt Barden mutex_enter(&of->f_mutex); 1315*811599a4SMatt Barden of->dh_expire_time = gethrtime() + of->dh_timeout_offset; 1316*811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_ORPHANED; 1317*811599a4SMatt Barden cv_broadcast(&of->f_cv); 1318da6c28aaSamw mutex_exit(&of->f_mutex); 1319da6c28aaSamw } 1320da6c28aaSamw 1321da6c28aaSamw /* 13229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Delete an ofile. 1323da6c28aaSamw * 1324*811599a4SMatt Barden * Called via smb_llist_post (after smb_llist_exit) 1325*811599a4SMatt Barden * when the last ref. on this ofile has gone. 1326*811599a4SMatt Barden * 1327*811599a4SMatt Barden * Normally,this removes the ofile from the tree list and 1328*811599a4SMatt Barden * then frees resources held on the ofile. However, when 1329*811599a4SMatt Barden * we're expiring an orphaned durable handle, the linkage 1330*811599a4SMatt Barden * into the tree lists etc. have already been destroyed. 1331*811599a4SMatt Barden * This case is distinguished by of->f_tree == NULL. 1332da6c28aaSamw */ 1333*811599a4SMatt Barden static void 13349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_delete(void *arg) 1335da6c28aaSamw { 13369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_t *of = (smb_ofile_t *)arg; 1337*811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 13389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 13399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OFILE_VALID(of); 1340da6c28aaSamw ASSERT(of->f_refcnt == 0); 1341da6c28aaSamw ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED); 13421fdeec65Sjoyce mcintosh ASSERT(!SMB_OFILE_OPLOCK_GRANTED(of)); 1343da6c28aaSamw 1344*811599a4SMatt Barden if (tree != NULL) { 1345*811599a4SMatt Barden ASSERT(of->f_user != NULL); 1346*811599a4SMatt Barden ASSERT(of->f_session != NULL); 1347*811599a4SMatt Barden atomic_dec_32(&of->f_session->s_file_cnt); 1348*811599a4SMatt Barden atomic_dec_32(&of->f_tree->t_open_files); 13499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 13509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_remove(&tree->t_ofile_list, of); 13519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_exit(&tree->t_ofile_list); 1352*811599a4SMatt Barden } 13539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1354bfe5e737SGordon Ross /* 1355bfe5e737SGordon Ross * Remove this ofile from the node's n_ofile_list so it 1356bfe5e737SGordon Ross * can't be found by list walkers like notify or oplock. 1357bfe5e737SGordon Ross * Keep the node ref. until later in this function so 1358bfe5e737SGordon Ross * of->f_node remains valid while we destroy the ofile. 1359bfe5e737SGordon Ross */ 1360bfe5e737SGordon Ross if (of->f_ftype == SMB_FTYPE_DISK || 1361bfe5e737SGordon Ross of->f_ftype == SMB_FTYPE_PRINTER) { 1362bfe5e737SGordon Ross ASSERT(of->f_node != NULL); 1363bfe5e737SGordon Ross /* 1364bfe5e737SGordon Ross * Note smb_ofile_close did smb_node_dec_open_ofiles() 1365bfe5e737SGordon Ross */ 1366bfe5e737SGordon Ross smb_node_rem_ofile(of->f_node, of); 1367bfe5e737SGordon Ross } 1368bfe5e737SGordon Ross 1369*811599a4SMatt Barden /* 1370*811599a4SMatt Barden * This ofile is no longer on any lists, however... 1371*811599a4SMatt Barden * 1372*811599a4SMatt Barden * This is called via smb_llist_post, which means it may run 1373*811599a4SMatt Barden * BEFORE smb_ofile_release drops f_mutex (if another thread 1374*811599a4SMatt Barden * flushes the delete queue before we do). Synchronize. 1375*811599a4SMatt Barden */ 13769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&of->f_mutex); 13779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&of->f_mutex); 1378da6c28aaSamw 1379a90cf9f2SGordon Ross switch (of->f_ftype) { 1380a90cf9f2SGordon Ross case SMB_FTYPE_BYTE_PIPE: 1381a90cf9f2SGordon Ross case SMB_FTYPE_MESG_PIPE: 13829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_dealloc(of->f_pipe); 13833db3f65cSamw of->f_pipe = NULL; 1384a90cf9f2SGordon Ross break; 1385a90cf9f2SGordon Ross case SMB_FTYPE_DISK: 1386bfe5e737SGordon Ross ASSERT(of->f_notify.nc_subscribed == B_FALSE); 1387bfe5e737SGordon Ross MBC_FLUSH(&of->f_notify.nc_buffer); 1388a90cf9f2SGordon Ross if (of->f_odir != NULL) 1389a90cf9f2SGordon Ross smb_odir_release(of->f_odir); 1390bfe5e737SGordon Ross /* FALLTHROUGH */ 1391bfe5e737SGordon Ross case SMB_FTYPE_PRINTER: 1392bfe5e737SGordon Ross /* 1393bfe5e737SGordon Ross * Did smb_node_rem_ofile above. 1394bfe5e737SGordon Ross */ 1395bfe5e737SGordon Ross ASSERT(of->f_node != NULL); 1396da6c28aaSamw smb_node_release(of->f_node); 1397a90cf9f2SGordon Ross break; 1398a90cf9f2SGordon Ross default: 1399a90cf9f2SGordon Ross ASSERT(!"f_ftype"); 1400a90cf9f2SGordon Ross break; 1401da6c28aaSamw } 1402da6c28aaSamw 1403*811599a4SMatt Barden if (tree != NULL) { 1404*811599a4SMatt Barden if (of->f_fid != 0) 1405*811599a4SMatt Barden smb_idpool_free(&tree->t_fid_pool, of->f_fid); 1406*811599a4SMatt Barden smb_tree_release(of->f_tree); 1407*811599a4SMatt Barden smb_user_release(of->f_user); 1408*811599a4SMatt Barden } 1409*811599a4SMatt Barden 1410*811599a4SMatt Barden if (of->f_cr != NULL) 1411*811599a4SMatt Barden crfree(of->f_cr); 1412*811599a4SMatt Barden 1413da6c28aaSamw of->f_magic = (uint32_t)~SMB_OFILE_MAGIC; 1414bfe5e737SGordon Ross list_destroy(&of->f_notify.nc_waiters); 1415da6c28aaSamw mutex_destroy(&of->f_mutex); 14168622ec45SGordon Ross kmem_cache_free(smb_cache_ofile, of); 1417da6c28aaSamw } 1418da6c28aaSamw 1419da6c28aaSamw /* 1420da6c28aaSamw * smb_ofile_access 1421da6c28aaSamw * 1422da6c28aaSamw * This function will check to see if the access requested is granted. 1423da6c28aaSamw * Returns NT status codes. 1424da6c28aaSamw */ 1425da6c28aaSamw uint32_t 1426da6c28aaSamw smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access) 1427da6c28aaSamw { 1428da6c28aaSamw 14298622ec45SGordon Ross if ((of == NULL) || (cr == zone_kcred())) 1430da6c28aaSamw return (NT_STATUS_SUCCESS); 1431da6c28aaSamw 1432da6c28aaSamw /* 1433da6c28aaSamw * If the request is for something 1434da6c28aaSamw * I don't grant it is an error 1435da6c28aaSamw */ 1436da6c28aaSamw if (~(of->f_granted_access) & access) { 1437da6c28aaSamw if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) && 1438da6c28aaSamw (access & ACCESS_SYSTEM_SECURITY)) { 1439da6c28aaSamw return (NT_STATUS_PRIVILEGE_NOT_HELD); 1440da6c28aaSamw } 1441da6c28aaSamw return (NT_STATUS_ACCESS_DENIED); 1442da6c28aaSamw } 1443da6c28aaSamw 1444da6c28aaSamw return (NT_STATUS_SUCCESS); 1445da6c28aaSamw } 14463ad684d6Sjb150015 1447cb174861Sjoyce mcintosh /* 1448cb174861Sjoyce mcintosh * smb_ofile_share_check 1449cb174861Sjoyce mcintosh * 1450cb174861Sjoyce mcintosh * Check if ofile was opened with share access NONE (0). 1451cb174861Sjoyce mcintosh * Returns: B_TRUE - share access non-zero 1452cb174861Sjoyce mcintosh * B_FALSE - share access NONE 1453cb174861Sjoyce mcintosh */ 1454cb174861Sjoyce mcintosh boolean_t 1455cb174861Sjoyce mcintosh smb_ofile_share_check(smb_ofile_t *of) 1456cb174861Sjoyce mcintosh { 1457cb174861Sjoyce mcintosh return (!SMB_DENY_ALL(of->f_share_access)); 1458cb174861Sjoyce mcintosh } 14593ad684d6Sjb150015 14603ad684d6Sjb150015 /* 14613ad684d6Sjb150015 * check file sharing rules for current open request 14623ad684d6Sjb150015 * against existing open instances of the same file 14633ad684d6Sjb150015 * 14643ad684d6Sjb150015 * Returns NT_STATUS_SHARING_VIOLATION if there is any 14653ad684d6Sjb150015 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 14663ad684d6Sjb150015 */ 14673ad684d6Sjb150015 uint32_t 14689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_open_check(smb_ofile_t *of, uint32_t desired_access, 14693ad684d6Sjb150015 uint32_t share_access) 14703ad684d6Sjb150015 { 1471*811599a4SMatt Barden uint32_t ret; 1472*811599a4SMatt Barden 14733ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 14743ad684d6Sjb150015 14753ad684d6Sjb150015 mutex_enter(&of->f_mutex); 14763ad684d6Sjb150015 1477*811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1478*811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1479*811599a4SMatt Barden goto out; 14803ad684d6Sjb150015 } 14813ad684d6Sjb150015 14823ad684d6Sjb150015 /* if it's just meta data */ 14833ad684d6Sjb150015 if ((of->f_granted_access & FILE_DATA_ALL) == 0) { 1484*811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1485*811599a4SMatt Barden goto out; 14863ad684d6Sjb150015 } 14873ad684d6Sjb150015 14883ad684d6Sjb150015 /* 14893ad684d6Sjb150015 * Check requested share access against the 14903ad684d6Sjb150015 * open granted (desired) access 14913ad684d6Sjb150015 */ 14923ad684d6Sjb150015 if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE)) { 1493*811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1494*811599a4SMatt Barden goto out; 14953ad684d6Sjb150015 } 14963ad684d6Sjb150015 14973ad684d6Sjb150015 if (SMB_DENY_READ(share_access) && 14983ad684d6Sjb150015 (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) { 1499*811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1500*811599a4SMatt Barden goto out; 15013ad684d6Sjb150015 } 15023ad684d6Sjb150015 15033ad684d6Sjb150015 if (SMB_DENY_WRITE(share_access) && 15043ad684d6Sjb150015 (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 1505*811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1506*811599a4SMatt Barden goto out; 15073ad684d6Sjb150015 } 15083ad684d6Sjb150015 15093ad684d6Sjb150015 /* check requested desired access against the open share access */ 15103ad684d6Sjb150015 if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE)) { 1511*811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1512*811599a4SMatt Barden goto out; 15133ad684d6Sjb150015 } 15143ad684d6Sjb150015 15153ad684d6Sjb150015 if (SMB_DENY_READ(of->f_share_access) && 15163ad684d6Sjb150015 (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) { 1517*811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1518*811599a4SMatt Barden goto out; 15193ad684d6Sjb150015 } 15203ad684d6Sjb150015 15213ad684d6Sjb150015 if (SMB_DENY_WRITE(of->f_share_access) && 15223ad684d6Sjb150015 (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 1523*811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1524*811599a4SMatt Barden goto out; 15253ad684d6Sjb150015 } 15263ad684d6Sjb150015 1527*811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1528*811599a4SMatt Barden out: 15293ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1530*811599a4SMatt Barden return (ret); 15313ad684d6Sjb150015 } 15323ad684d6Sjb150015 15333ad684d6Sjb150015 /* 15343ad684d6Sjb150015 * smb_ofile_rename_check 15353ad684d6Sjb150015 * 1536575d359dSGordon Ross * This does the work described in MS-FSA 2.1.5.1.2.2 (Algorithm 1537575d359dSGordon Ross * to Check Sharing Access to an Existing Stream or Directory), 1538575d359dSGordon Ross * where the "open in-progress" has DesiredAccess = DELETE and 1539575d359dSGordon Ross * SharingMode = SHARE_READ | SHARE_WRITE | SHARE_DELETE. 15403ad684d6Sjb150015 */ 15413ad684d6Sjb150015 15423ad684d6Sjb150015 uint32_t 15433ad684d6Sjb150015 smb_ofile_rename_check(smb_ofile_t *of) 15443ad684d6Sjb150015 { 1545*811599a4SMatt Barden uint32_t ret; 1546*811599a4SMatt Barden 15473ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 15483ad684d6Sjb150015 15493ad684d6Sjb150015 mutex_enter(&of->f_mutex); 15503ad684d6Sjb150015 1551*811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1552*811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1553*811599a4SMatt Barden goto out; 15543ad684d6Sjb150015 } 15553ad684d6Sjb150015 1556575d359dSGordon Ross if ((of->f_granted_access & FILE_DATA_ALL) == 0) { 1557*811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1558*811599a4SMatt Barden goto out; 15593ad684d6Sjb150015 } 15603ad684d6Sjb150015 15613ad684d6Sjb150015 if ((of->f_share_access & FILE_SHARE_DELETE) == 0) { 1562*811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1563*811599a4SMatt Barden goto out; 15643ad684d6Sjb150015 } 15653ad684d6Sjb150015 1566*811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1567*811599a4SMatt Barden out: 15683ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1569*811599a4SMatt Barden return (ret); 15703ad684d6Sjb150015 } 15713ad684d6Sjb150015 15723ad684d6Sjb150015 /* 15733ad684d6Sjb150015 * smb_ofile_delete_check 15743ad684d6Sjb150015 * 15753ad684d6Sjb150015 * An open file can be deleted only if opened for 15763ad684d6Sjb150015 * accessing meta data. Share modes aren't important 15773ad684d6Sjb150015 * in this case. 15783ad684d6Sjb150015 * 15793ad684d6Sjb150015 * NOTE: there is another mechanism for deleting an 15803ad684d6Sjb150015 * open file that NT clients usually use. 15813ad684d6Sjb150015 * That's setting "Delete on close" flag for an open 15823ad684d6Sjb150015 * file. In this way the file will be deleted after 15833ad684d6Sjb150015 * last close. This flag can be set by SmbTrans2SetFileInfo 15843ad684d6Sjb150015 * with FILE_DISPOSITION_INFO information level. 15853ad684d6Sjb150015 * For setting this flag, the file should be opened by 15863ad684d6Sjb150015 * DELETE access in the FID that is passed in the Trans2 15873ad684d6Sjb150015 * request. 15883ad684d6Sjb150015 */ 15893ad684d6Sjb150015 15903ad684d6Sjb150015 uint32_t 15913ad684d6Sjb150015 smb_ofile_delete_check(smb_ofile_t *of) 15923ad684d6Sjb150015 { 1593*811599a4SMatt Barden uint32_t ret; 1594*811599a4SMatt Barden 15953ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 15963ad684d6Sjb150015 15973ad684d6Sjb150015 mutex_enter(&of->f_mutex); 15983ad684d6Sjb150015 1599*811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1600*811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1601*811599a4SMatt Barden goto out; 16023ad684d6Sjb150015 } 16033ad684d6Sjb150015 16043ad684d6Sjb150015 if (of->f_granted_access & 16053ad684d6Sjb150015 (FILE_READ_DATA | FILE_WRITE_DATA | 16063ad684d6Sjb150015 FILE_APPEND_DATA | FILE_EXECUTE | DELETE)) { 1607*811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1608*811599a4SMatt Barden goto out; 16093ad684d6Sjb150015 } 16103ad684d6Sjb150015 1611*811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1612*811599a4SMatt Barden out: 16133ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1614*811599a4SMatt Barden return (ret); 16153ad684d6Sjb150015 } 1616b89a8333Snatalie li - Sun Microsystems - Irvine United States 1617b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t * 1618b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ofile_getcred(smb_ofile_t *of) 1619b89a8333Snatalie li - Sun Microsystems - Irvine United States { 1620b89a8333Snatalie li - Sun Microsystems - Irvine United States return (of->f_cr); 1621b89a8333Snatalie li - Sun Microsystems - Irvine United States } 16228b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 16238b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* 16248b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * smb_ofile_set_delete_on_close 16258b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 16268b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * Set the DeleteOnClose flag on the smb file. When the file is closed, 16278b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * the flag will be transferred to the smb node, which will commit the 16288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * delete operation and inhibit subsequent open requests. 16298b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 16308b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * When DeleteOnClose is set on an smb_node, the common open code will 16318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * reject subsequent open requests for the file. Observation of Windows 16328b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 2000 indicates that subsequent opens should be allowed (assuming 16338b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * there would be no sharing violation) until the file is closed using 16348b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * the fid on which the DeleteOnClose was requested. 16358b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */ 16368b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States void 16378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_set_delete_on_close(smb_ofile_t *of) 16388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States { 16398b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&of->f_mutex); 16408b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States of->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE; 16418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&of->f_mutex); 16428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 16431fcced4cSJordan Brown 16441fcced4cSJordan Brown /* 16451fcced4cSJordan Brown * Encode open file information into a buffer; needed in user space to 16461fcced4cSJordan Brown * support RPC requests. 16471fcced4cSJordan Brown */ 16481fcced4cSJordan Brown static int 16491fcced4cSJordan Brown smb_ofile_netinfo_encode(smb_ofile_t *of, uint8_t *buf, size_t buflen, 16501fcced4cSJordan Brown uint32_t *nbytes) 16511fcced4cSJordan Brown { 16521fcced4cSJordan Brown smb_netfileinfo_t fi; 16531fcced4cSJordan Brown int rc; 16541fcced4cSJordan Brown 16551fcced4cSJordan Brown rc = smb_ofile_netinfo_init(of, &fi); 16561fcced4cSJordan Brown if (rc == 0) { 16571fcced4cSJordan Brown rc = smb_netfileinfo_encode(&fi, buf, buflen, nbytes); 16581fcced4cSJordan Brown smb_ofile_netinfo_fini(&fi); 16591fcced4cSJordan Brown } 16601fcced4cSJordan Brown 16611fcced4cSJordan Brown return (rc); 16621fcced4cSJordan Brown } 16631fcced4cSJordan Brown 16641fcced4cSJordan Brown static int 16651fcced4cSJordan Brown smb_ofile_netinfo_init(smb_ofile_t *of, smb_netfileinfo_t *fi) 16661fcced4cSJordan Brown { 16671fcced4cSJordan Brown smb_user_t *user; 16681fcced4cSJordan Brown smb_tree_t *tree; 16691fcced4cSJordan Brown smb_node_t *node; 16701fcced4cSJordan Brown char *path; 16711fcced4cSJordan Brown char *buf; 16721fcced4cSJordan Brown int rc; 16731fcced4cSJordan Brown 16741fcced4cSJordan Brown ASSERT(of); 16751fcced4cSJordan Brown user = of->f_user; 16761fcced4cSJordan Brown tree = of->f_tree; 16771fcced4cSJordan Brown ASSERT(user); 16781fcced4cSJordan Brown ASSERT(tree); 16791fcced4cSJordan Brown 16801fcced4cSJordan Brown buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 16811fcced4cSJordan Brown 16821fcced4cSJordan Brown switch (of->f_ftype) { 16831fcced4cSJordan Brown case SMB_FTYPE_DISK: 16841fcced4cSJordan Brown node = of->f_node; 16851fcced4cSJordan Brown ASSERT(node); 16861fcced4cSJordan Brown 16871fcced4cSJordan Brown fi->fi_permissions = of->f_granted_access; 1688148c5f43SAlan Wright fi->fi_numlocks = smb_lock_get_lock_count(node, of); 16891fcced4cSJordan Brown 16901fcced4cSJordan Brown path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 16911fcced4cSJordan Brown 16921fcced4cSJordan Brown if (node != tree->t_snode) { 1693148c5f43SAlan Wright rc = smb_node_getshrpath(node, tree, path, MAXPATHLEN); 1694148c5f43SAlan Wright if (rc != 0) 16951fcced4cSJordan Brown (void) strlcpy(path, node->od_name, MAXPATHLEN); 16961fcced4cSJordan Brown } 16971fcced4cSJordan Brown 16981fcced4cSJordan Brown (void) snprintf(buf, MAXPATHLEN, "%s:%s", tree->t_sharename, 16991fcced4cSJordan Brown path); 17001fcced4cSJordan Brown kmem_free(path, MAXPATHLEN); 17011fcced4cSJordan Brown break; 17021fcced4cSJordan Brown 17031fcced4cSJordan Brown case SMB_FTYPE_MESG_PIPE: 17041fcced4cSJordan Brown ASSERT(of->f_pipe); 17051fcced4cSJordan Brown 17061fcced4cSJordan Brown fi->fi_permissions = FILE_READ_DATA | FILE_WRITE_DATA | 17071fcced4cSJordan Brown FILE_EXECUTE; 17081fcced4cSJordan Brown fi->fi_numlocks = 0; 17091fcced4cSJordan Brown (void) snprintf(buf, MAXPATHLEN, "\\PIPE\\%s", 17101fcced4cSJordan Brown of->f_pipe->p_name); 17111fcced4cSJordan Brown break; 17121fcced4cSJordan Brown 17131fcced4cSJordan Brown default: 17141fcced4cSJordan Brown kmem_free(buf, MAXPATHLEN); 17151fcced4cSJordan Brown return (-1); 17161fcced4cSJordan Brown } 17171fcced4cSJordan Brown 17181fcced4cSJordan Brown fi->fi_fid = of->f_fid; 17191fcced4cSJordan Brown fi->fi_uniqid = of->f_uniqid; 17201fcced4cSJordan Brown fi->fi_pathlen = strlen(buf) + 1; 17219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States fi->fi_path = smb_mem_strdup(buf); 17221fcced4cSJordan Brown kmem_free(buf, MAXPATHLEN); 17231fcced4cSJordan Brown 17241fcced4cSJordan Brown fi->fi_namelen = user->u_domain_len + user->u_name_len + 2; 17251fcced4cSJordan Brown fi->fi_username = kmem_alloc(fi->fi_namelen, KM_SLEEP); 17261fcced4cSJordan Brown (void) snprintf(fi->fi_username, fi->fi_namelen, "%s\\%s", 17271fcced4cSJordan Brown user->u_domain, user->u_name); 17281fcced4cSJordan Brown return (0); 17291fcced4cSJordan Brown } 17301fcced4cSJordan Brown 17311fcced4cSJordan Brown static void 17321fcced4cSJordan Brown smb_ofile_netinfo_fini(smb_netfileinfo_t *fi) 17331fcced4cSJordan Brown { 17341fcced4cSJordan Brown if (fi == NULL) 17351fcced4cSJordan Brown return; 17361fcced4cSJordan Brown 17371fcced4cSJordan Brown if (fi->fi_path) 17389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(fi->fi_path); 17391fcced4cSJordan Brown if (fi->fi_username) 17401fcced4cSJordan Brown kmem_free(fi->fi_username, fi->fi_namelen); 17411fcced4cSJordan Brown 17421fcced4cSJordan Brown bzero(fi, sizeof (smb_netfileinfo_t)); 17431fcced4cSJordan Brown } 17449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 17469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * A query of user and group quotas may span multiple requests. 17479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * f_quota_resume is used to determine where the query should 17489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * be resumed, in a subsequent request. f_quota_resume contains 17499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * the SID of the last quota entry returned to the client. 17509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 17519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 17529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_set_quota_resume(smb_ofile_t *ofile, char *resume) 17539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 17549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(ofile); 17559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&ofile->f_mutex); 17569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (resume == NULL) 17579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States bzero(ofile->f_quota_resume, SMB_SID_STRSZ); 17589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States else 17599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcpy(ofile->f_quota_resume, resume, SMB_SID_STRSZ); 17609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&ofile->f_mutex); 17619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 17629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 17649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_get_quota_resume(smb_ofile_t *ofile, char *buf, int bufsize) 17659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 17669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(ofile); 17679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&ofile->f_mutex); 17689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcpy(buf, ofile->f_quota_resume, bufsize); 17699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&ofile->f_mutex); 17709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 1771