xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_ofile.c (revision 811599a462e8920d70cf548f4002182d3c222d13)
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