xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_common_open.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
1*da6c28aaSamw /*
2*da6c28aaSamw  * CDDL HEADER START
3*da6c28aaSamw  *
4*da6c28aaSamw  * The contents of this file are subject to the terms of the
5*da6c28aaSamw  * Common Development and Distribution License (the "License").
6*da6c28aaSamw  * You may not use this file except in compliance with the License.
7*da6c28aaSamw  *
8*da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10*da6c28aaSamw  * See the License for the specific language governing permissions
11*da6c28aaSamw  * and limitations under the License.
12*da6c28aaSamw  *
13*da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14*da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16*da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17*da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*da6c28aaSamw  *
19*da6c28aaSamw  * CDDL HEADER END
20*da6c28aaSamw  */
21*da6c28aaSamw /*
22*da6c28aaSamw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*da6c28aaSamw  * Use is subject to license terms.
24*da6c28aaSamw  */
25*da6c28aaSamw 
26*da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*da6c28aaSamw 
28*da6c28aaSamw /*
29*da6c28aaSamw  * This module provides the common open functionality to the various
30*da6c28aaSamw  * open and create SMB interface functions.
31*da6c28aaSamw  */
32*da6c28aaSamw 
33*da6c28aaSamw #include <smbsrv/smb_incl.h>
34*da6c28aaSamw #include <smbsrv/smb_fsops.h>
35*da6c28aaSamw #include <smbsrv/mlsvc.h>
36*da6c28aaSamw #include <smbsrv/nterror.h>
37*da6c28aaSamw #include <smbsrv/ntstatus.h>
38*da6c28aaSamw #include <smbsrv/smbinfo.h>
39*da6c28aaSamw #include <sys/fcntl.h>
40*da6c28aaSamw 
41*da6c28aaSamw extern uint32_t smb_is_executable(char *path);
42*da6c28aaSamw 
43*da6c28aaSamw #define	DENY_READ(share_access) ((share_access & FILE_SHARE_READ) == 0)
44*da6c28aaSamw 
45*da6c28aaSamw #define	DENY_WRITE(share_access) ((share_access & FILE_SHARE_WRITE) == 0)
46*da6c28aaSamw 
47*da6c28aaSamw #define	DENY_DELETE(share_access) ((share_access & FILE_SHARE_DELETE) == 0)
48*da6c28aaSamw 
49*da6c28aaSamw #define	DENY_RW(share_access) \
50*da6c28aaSamw 	((share_access & (FILE_SHARE_READ | FILE_SHARE_WRITE)) == 0)
51*da6c28aaSamw 
52*da6c28aaSamw #define	DENY_ALL(share_access) (share_access == 0)
53*da6c28aaSamw 
54*da6c28aaSamw #define	DENY_NONE(share_access) (share_access == FILE_SHARE_ALL)
55*da6c28aaSamw 
56*da6c28aaSamw /*
57*da6c28aaSamw  * The default stability mode is to perform the write-through
58*da6c28aaSamw  * behaviour requested by the client.
59*da6c28aaSamw  */
60*da6c28aaSamw int smb_stable_mode = 0;
61*da6c28aaSamw 
62*da6c28aaSamw 
63*da6c28aaSamw /*
64*da6c28aaSamw  * This macro is used to delete a newly created object
65*da6c28aaSamw  * if any error happens after creation of object.
66*da6c28aaSamw  */
67*da6c28aaSamw #define	SMB_DEL_NEWOBJ(obj) \
68*da6c28aaSamw 	if (created) {							\
69*da6c28aaSamw 		if (is_dir)						\
70*da6c28aaSamw 			(void) smb_fsop_rmdir(sr, sr->user_cr,		\
71*da6c28aaSamw 			    obj.dir_snode, obj.last_comp, 0);		\
72*da6c28aaSamw 		else							\
73*da6c28aaSamw 			(void) smb_fsop_remove(sr, sr->user_cr,		\
74*da6c28aaSamw 			    obj.dir_snode, obj.last_comp, 0);		\
75*da6c28aaSamw 	}
76*da6c28aaSamw 
77*da6c28aaSamw /*
78*da6c28aaSamw  * smb_set_stability
79*da6c28aaSamw  *
80*da6c28aaSamw  * Set the default stability mode. Normal (mode is zero) means perform
81*da6c28aaSamw  * the write-through behaviour requested by the client. Synchronous
82*da6c28aaSamw  * (mode is non-zero) means journal everything regardless of the write
83*da6c28aaSamw  * through behaviour requested by the client.
84*da6c28aaSamw  */
85*da6c28aaSamw void
86*da6c28aaSamw smb_set_stability(int mode)
87*da6c28aaSamw {
88*da6c28aaSamw 	smb_stable_mode = mode;
89*da6c28aaSamw }
90*da6c28aaSamw 
91*da6c28aaSamw /*
92*da6c28aaSamw  * smb_access_generic_to_file
93*da6c28aaSamw  *
94*da6c28aaSamw  * Search MSDN for IoCreateFile to see following mapping.
95*da6c28aaSamw  *
96*da6c28aaSamw  * GENERIC_READ		STANDARD_RIGHTS_READ, FILE_READ_DATA,
97*da6c28aaSamw  *			FILE_READ_ATTRIBUTES and FILE_READ_EA
98*da6c28aaSamw  *
99*da6c28aaSamw  * GENERIC_WRITE	STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA,
100*da6c28aaSamw  *               FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
101*da6c28aaSamw  *
102*da6c28aaSamw  * GENERIC_EXECUTE	STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE.
103*da6c28aaSamw  */
104*da6c28aaSamw uint32_t
105*da6c28aaSamw smb_access_generic_to_file(uint32_t desired_access)
106*da6c28aaSamw {
107*da6c28aaSamw 	uint32_t access = 0;
108*da6c28aaSamw 
109*da6c28aaSamw 	if (desired_access & GENERIC_ALL)
110*da6c28aaSamw 		return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
111*da6c28aaSamw 
112*da6c28aaSamw 	if (desired_access & GENERIC_EXECUTE) {
113*da6c28aaSamw 		desired_access &= ~GENERIC_EXECUTE;
114*da6c28aaSamw 		access |= (STANDARD_RIGHTS_EXECUTE |
115*da6c28aaSamw 		    SYNCHRONIZE | FILE_EXECUTE);
116*da6c28aaSamw 	}
117*da6c28aaSamw 
118*da6c28aaSamw 	if (desired_access & GENERIC_WRITE) {
119*da6c28aaSamw 		desired_access &= ~GENERIC_WRITE;
120*da6c28aaSamw 		access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE);
121*da6c28aaSamw 	}
122*da6c28aaSamw 
123*da6c28aaSamw 	if (desired_access & GENERIC_READ) {
124*da6c28aaSamw 		desired_access &= ~GENERIC_READ;
125*da6c28aaSamw 		access |= FILE_GENERIC_READ;
126*da6c28aaSamw 	}
127*da6c28aaSamw 
128*da6c28aaSamw 	return (access | desired_access);
129*da6c28aaSamw }
130*da6c28aaSamw 
131*da6c28aaSamw /*
132*da6c28aaSamw  * smb_omode_to_amask
133*da6c28aaSamw  *
134*da6c28aaSamw  * This function converts open modes used by Open and Open AndX
135*da6c28aaSamw  * commands to desired access bits used by NT Create AndX command.
136*da6c28aaSamw  */
137*da6c28aaSamw uint32_t
138*da6c28aaSamw smb_omode_to_amask(uint32_t desired_access)
139*da6c28aaSamw {
140*da6c28aaSamw 	switch (desired_access & SMB_DA_ACCESS_MASK) {
141*da6c28aaSamw 	case SMB_DA_ACCESS_READ:
142*da6c28aaSamw 		return (FILE_GENERIC_READ);
143*da6c28aaSamw 
144*da6c28aaSamw 	case SMB_DA_ACCESS_WRITE:
145*da6c28aaSamw 		return (FILE_GENERIC_WRITE);
146*da6c28aaSamw 
147*da6c28aaSamw 	case SMB_DA_ACCESS_READ_WRITE:
148*da6c28aaSamw 		return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
149*da6c28aaSamw 
150*da6c28aaSamw 	case SMB_DA_ACCESS_EXECUTE:
151*da6c28aaSamw 		return (FILE_GENERIC_EXECUTE);
152*da6c28aaSamw 	}
153*da6c28aaSamw 
154*da6c28aaSamw 	/* invalid open mode */
155*da6c28aaSamw 	return ((uint32_t)SMB_INVALID_AMASK);
156*da6c28aaSamw }
157*da6c28aaSamw 
158*da6c28aaSamw /*
159*da6c28aaSamw  * smb_denymode_to_sharemode
160*da6c28aaSamw  *
161*da6c28aaSamw  * This function converts deny modes used by Open and Open AndX
162*da6c28aaSamw  * commands to share access bits used by NT Create AndX command.
163*da6c28aaSamw  */
164*da6c28aaSamw uint32_t
165*da6c28aaSamw smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
166*da6c28aaSamw {
167*da6c28aaSamw 	switch (desired_access & SMB_DA_SHARE_MASK) {
168*da6c28aaSamw 	case SMB_DA_SHARE_COMPATIBILITY:
169*da6c28aaSamw 		if (smb_is_executable(fname))
170*da6c28aaSamw 			return (FILE_SHARE_READ | FILE_SHARE_WRITE);
171*da6c28aaSamw 		else {
172*da6c28aaSamw 			if ((desired_access &
173*da6c28aaSamw 			    SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_READ)
174*da6c28aaSamw 				return (FILE_SHARE_READ);
175*da6c28aaSamw 			else
176*da6c28aaSamw 				return (FILE_SHARE_NONE);
177*da6c28aaSamw 		}
178*da6c28aaSamw 
179*da6c28aaSamw 	case SMB_DA_SHARE_EXCLUSIVE:
180*da6c28aaSamw 		return (FILE_SHARE_NONE);
181*da6c28aaSamw 
182*da6c28aaSamw 	case SMB_DA_SHARE_DENY_WRITE:
183*da6c28aaSamw 		return (FILE_SHARE_READ);
184*da6c28aaSamw 
185*da6c28aaSamw 	case SMB_DA_SHARE_DENY_READ:
186*da6c28aaSamw 		return (FILE_SHARE_WRITE);
187*da6c28aaSamw 
188*da6c28aaSamw 	case SMB_DA_SHARE_DENY_NONE:
189*da6c28aaSamw 		return (FILE_SHARE_READ | FILE_SHARE_WRITE);
190*da6c28aaSamw 	}
191*da6c28aaSamw 
192*da6c28aaSamw 	/* invalid deny mode */
193*da6c28aaSamw 	return ((uint32_t)SMB_INVALID_SHAREMODE);
194*da6c28aaSamw }
195*da6c28aaSamw 
196*da6c28aaSamw /*
197*da6c28aaSamw  * smb_ofun_to_crdisposition
198*da6c28aaSamw  *
199*da6c28aaSamw  * This function converts open function values used by Open and Open AndX
200*da6c28aaSamw  * commands to create disposition values used by NT Create AndX command.
201*da6c28aaSamw  */
202*da6c28aaSamw uint32_t
203*da6c28aaSamw smb_ofun_to_crdisposition(uint16_t  ofun)
204*da6c28aaSamw {
205*da6c28aaSamw 	static int ofun_cr_map[3][2] =
206*da6c28aaSamw 	{
207*da6c28aaSamw 		{ -1,			FILE_CREATE },
208*da6c28aaSamw 		{ FILE_OPEN,		FILE_OPEN_IF },
209*da6c28aaSamw 		{ FILE_OVERWRITE,	FILE_OVERWRITE_IF }
210*da6c28aaSamw 	};
211*da6c28aaSamw 
212*da6c28aaSamw 	int row = ofun & SMB_OFUN_OPEN_MASK;
213*da6c28aaSamw 	int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
214*da6c28aaSamw 
215*da6c28aaSamw 	if (row == 3)
216*da6c28aaSamw 		return ((uint32_t)SMB_INVALID_CRDISPOSITION);
217*da6c28aaSamw 
218*da6c28aaSamw 	return (ofun_cr_map[row][col]);
219*da6c28aaSamw }
220*da6c28aaSamw 
221*da6c28aaSamw /*
222*da6c28aaSamw  * smb_open_share_check
223*da6c28aaSamw  *
224*da6c28aaSamw  * check file sharing rules for current open request
225*da6c28aaSamw  * against the given existing open.
226*da6c28aaSamw  *
227*da6c28aaSamw  * Returns NT_STATUS_SHARING_VIOLATION if there is any
228*da6c28aaSamw  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
229*da6c28aaSamw  */
230*da6c28aaSamw uint32_t
231*da6c28aaSamw smb_open_share_check(struct smb_request *sr,
232*da6c28aaSamw     struct smb_node *node,
233*da6c28aaSamw     struct smb_ofile *open)
234*da6c28aaSamw {
235*da6c28aaSamw 	uint32_t desired_access;
236*da6c28aaSamw 	uint32_t share_access;
237*da6c28aaSamw 
238*da6c28aaSamw 	desired_access = sr->arg.open.desired_access;
239*da6c28aaSamw 	share_access   = sr->arg.open.share_access;
240*da6c28aaSamw 
241*da6c28aaSamw 	/*
242*da6c28aaSamw 	 * As far as I can tell share modes are not relevant to
243*da6c28aaSamw 	 * directories. The check for exclusive access (Deny RW)
244*da6c28aaSamw 	 * remains because I don't know whether or not it was here
245*da6c28aaSamw 	 * for a reason.
246*da6c28aaSamw 	 */
247*da6c28aaSamw 	if (node->attr.sa_vattr.va_type == VDIR) {
248*da6c28aaSamw 		if (DENY_RW(open->f_share_access) &&
249*da6c28aaSamw 		    (node->n_orig_uid != crgetuid(sr->user_cr))) {
250*da6c28aaSamw 			return (NT_STATUS_SHARING_VIOLATION);
251*da6c28aaSamw 		}
252*da6c28aaSamw 
253*da6c28aaSamw 		return (NT_STATUS_SUCCESS);
254*da6c28aaSamw 	}
255*da6c28aaSamw 
256*da6c28aaSamw 	/* if it's just meta data */
257*da6c28aaSamw 	if ((open->f_granted_access & FILE_DATA_ALL) == 0)
258*da6c28aaSamw 		return (NT_STATUS_SUCCESS);
259*da6c28aaSamw 
260*da6c28aaSamw 	/*
261*da6c28aaSamw 	 * Check requested share access against the
262*da6c28aaSamw 	 * open granted (desired) access
263*da6c28aaSamw 	 */
264*da6c28aaSamw 	if (DENY_DELETE(share_access) && (open->f_granted_access & DELETE))
265*da6c28aaSamw 		return (NT_STATUS_SHARING_VIOLATION);
266*da6c28aaSamw 
267*da6c28aaSamw 	if (DENY_READ(share_access) &&
268*da6c28aaSamw 	    (open->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE)))
269*da6c28aaSamw 		return (NT_STATUS_SHARING_VIOLATION);
270*da6c28aaSamw 
271*da6c28aaSamw 	if (DENY_WRITE(share_access) &&
272*da6c28aaSamw 	    (open->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
273*da6c28aaSamw 		return (NT_STATUS_SHARING_VIOLATION);
274*da6c28aaSamw 
275*da6c28aaSamw 	/* check requested desired access against the open share access */
276*da6c28aaSamw 	if (DENY_DELETE(open->f_share_access) && (desired_access & DELETE))
277*da6c28aaSamw 		return (NT_STATUS_SHARING_VIOLATION);
278*da6c28aaSamw 
279*da6c28aaSamw 	if (DENY_READ(open->f_share_access) &&
280*da6c28aaSamw 	    (desired_access & (FILE_READ_DATA | FILE_EXECUTE)))
281*da6c28aaSamw 		return (NT_STATUS_SHARING_VIOLATION);
282*da6c28aaSamw 
283*da6c28aaSamw 	if (DENY_WRITE(open->f_share_access) &&
284*da6c28aaSamw 	    (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
285*da6c28aaSamw 		return (NT_STATUS_SHARING_VIOLATION);
286*da6c28aaSamw 
287*da6c28aaSamw 	return (NT_STATUS_SUCCESS);
288*da6c28aaSamw }
289*da6c28aaSamw 
290*da6c28aaSamw /*
291*da6c28aaSamw  * smb_file_share_check
292*da6c28aaSamw  *
293*da6c28aaSamw  * check file sharing rules for current open request
294*da6c28aaSamw  * against all existing opens for a file.
295*da6c28aaSamw  *
296*da6c28aaSamw  * Returns NT_STATUS_SHARING_VIOLATION if there is any
297*da6c28aaSamw  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
298*da6c28aaSamw  */
299*da6c28aaSamw uint32_t
300*da6c28aaSamw smb_file_share_check(struct smb_request *sr, struct smb_node *node)
301*da6c28aaSamw {
302*da6c28aaSamw 	struct smb_ofile *open;
303*da6c28aaSamw 	uint32_t status;
304*da6c28aaSamw 
305*da6c28aaSamw 	if (node == 0 || node->n_refcnt <= 1)
306*da6c28aaSamw 		return (NT_STATUS_SUCCESS);
307*da6c28aaSamw 
308*da6c28aaSamw 	/* if it's just meta data */
309*da6c28aaSamw 	if ((sr->arg.open.desired_access & FILE_DATA_ALL) == 0)
310*da6c28aaSamw 		return (NT_STATUS_SUCCESS);
311*da6c28aaSamw 
312*da6c28aaSamw 	smb_llist_enter(&node->n_ofile_list, RW_READER);
313*da6c28aaSamw 	open = smb_llist_head(&node->n_ofile_list);
314*da6c28aaSamw 	while (open) {
315*da6c28aaSamw 		status = smb_open_share_check(sr, node, open);
316*da6c28aaSamw 		if (status == NT_STATUS_SHARING_VIOLATION) {
317*da6c28aaSamw 			smb_llist_exit(&node->n_ofile_list);
318*da6c28aaSamw 			return (status);
319*da6c28aaSamw 		}
320*da6c28aaSamw 		open = smb_llist_next(&node->n_ofile_list, open);
321*da6c28aaSamw 	}
322*da6c28aaSamw 	smb_llist_exit(&node->n_ofile_list);
323*da6c28aaSamw 
324*da6c28aaSamw 	return (NT_STATUS_SUCCESS);
325*da6c28aaSamw }
326*da6c28aaSamw 
327*da6c28aaSamw /*
328*da6c28aaSamw  * smb_amask_to_amode
329*da6c28aaSamw  * Converts specific read/write access rights of access mask to access
330*da6c28aaSamw  * mode flags.
331*da6c28aaSamw  */
332*da6c28aaSamw int
333*da6c28aaSamw smb_amask_to_amode(unsigned long amask)
334*da6c28aaSamw {
335*da6c28aaSamw 	if ((amask & FILE_READ_DATA) &&
336*da6c28aaSamw 	    (amask & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
337*da6c28aaSamw 		return (O_RDWR);
338*da6c28aaSamw 
339*da6c28aaSamw 	if (amask & (FILE_WRITE_DATA | FILE_APPEND_DATA))
340*da6c28aaSamw 		return (O_WRONLY);
341*da6c28aaSamw 
342*da6c28aaSamw 	return (O_RDONLY);
343*da6c28aaSamw }
344*da6c28aaSamw 
345*da6c28aaSamw /*
346*da6c28aaSamw  * smb_open_subr
347*da6c28aaSamw  *
348*da6c28aaSamw  * Notes on write-through behaviour. It looks like pre-LM0.12 versions
349*da6c28aaSamw  * of the protocol specify the write-through mode when a file is opened,
350*da6c28aaSamw  * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose,
351*da6c28aaSamw  * SmbWriteAndUnlock) don't need to contain a write-through flag.
352*da6c28aaSamw  *
353*da6c28aaSamw  * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate)
354*da6c28aaSamw  * don't indicate which write-through mode to use. Instead the write
355*da6c28aaSamw  * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call
356*da6c28aaSamw  * basis.
357*da6c28aaSamw  *
358*da6c28aaSamw  * We don't care which open call was used to get us here, we just need
359*da6c28aaSamw  * to ensure that the write-through mode flag is copied from the open
360*da6c28aaSamw  * parameters to the node. We test the omode write-through flag in all
361*da6c28aaSamw  * write functions.
362*da6c28aaSamw  *
363*da6c28aaSamw  * This function will return NT status codes but it also raises errors,
364*da6c28aaSamw  * in which case it won't return to the caller. Be careful how you
365*da6c28aaSamw  * handle things in here.
366*da6c28aaSamw  */
367*da6c28aaSamw uint32_t
368*da6c28aaSamw smb_open_subr(struct smb_request *sr)
369*da6c28aaSamw {
370*da6c28aaSamw 	int			created = 0;
371*da6c28aaSamw 	struct smb_node		*node = 0;
372*da6c28aaSamw 	struct smb_node		*dnode = 0;
373*da6c28aaSamw 	struct smb_node		*cur_node;
374*da6c28aaSamw 	struct open_param	*op = &sr->arg.open;
375*da6c28aaSamw 	int			rc;
376*da6c28aaSamw 	struct smb_ofile	*of;
377*da6c28aaSamw 	smb_attr_t		new_attr;
378*da6c28aaSamw 	int			pathlen;
379*da6c28aaSamw 	int			max_requested = 0;
380*da6c28aaSamw 	uint32_t		max_allowed;
381*da6c28aaSamw 	unsigned int		granted_oplock;
382*da6c28aaSamw 	uint32_t		status = NT_STATUS_SUCCESS;
383*da6c28aaSamw 	int			is_dir;
384*da6c28aaSamw 	smb_error_t		err;
385*da6c28aaSamw 	int			is_stream;
386*da6c28aaSamw 	int			lookup_flags = SMB_FOLLOW_LINKS;
387*da6c28aaSamw 	uint32_t		daccess;
388*da6c28aaSamw 
389*da6c28aaSamw 	is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
390*da6c28aaSamw 
391*da6c28aaSamw 	if (is_dir) {
392*da6c28aaSamw 		/*
393*da6c28aaSamw 		 * The file being created or opened is a directory file.
394*da6c28aaSamw 		 * With this flag, the Disposition parameter must be set to
395*da6c28aaSamw 		 * one of FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF
396*da6c28aaSamw 		 */
397*da6c28aaSamw 		if ((op->create_disposition != FILE_CREATE) &&
398*da6c28aaSamw 		    (op->create_disposition != FILE_OPEN_IF) &&
399*da6c28aaSamw 		    (op->create_disposition != FILE_OPEN)) {
400*da6c28aaSamw 			smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
401*da6c28aaSamw 			    ERRDOS, ERROR_INVALID_ACCESS);
402*da6c28aaSamw 			/* invalid open mode */
403*da6c28aaSamw 			/* NOTREACHED */
404*da6c28aaSamw 		}
405*da6c28aaSamw 	}
406*da6c28aaSamw 
407*da6c28aaSamw 	if (op->desired_access & MAXIMUM_ALLOWED) {
408*da6c28aaSamw 		max_requested = 1;
409*da6c28aaSamw 		op->desired_access &= ~MAXIMUM_ALLOWED;
410*da6c28aaSamw 	}
411*da6c28aaSamw 	op->desired_access = smb_access_generic_to_file(op->desired_access);
412*da6c28aaSamw 
413*da6c28aaSamw 	if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) {
414*da6c28aaSamw 
415*da6c28aaSamw 		ASSERT(sr->uid_user);
416*da6c28aaSamw 		cmn_err(CE_NOTE, "smbd[%s\\%s]: %s", sr->uid_user->u_domain,
417*da6c28aaSamw 		    sr->uid_user->u_name,
418*da6c28aaSamw 		    xlate_nt_status(NT_STATUS_TOO_MANY_OPENED_FILES));
419*da6c28aaSamw 
420*da6c28aaSamw 		smbsr_raise_cifs_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
421*da6c28aaSamw 		    ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
422*da6c28aaSamw 		/* NOTREACHED */
423*da6c28aaSamw 	}
424*da6c28aaSamw 
425*da6c28aaSamw 	/* This must be NULL at this point */
426*da6c28aaSamw 	sr->fid_ofile = NULL;
427*da6c28aaSamw 
428*da6c28aaSamw 	op->devstate = 0;
429*da6c28aaSamw 
430*da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
431*da6c28aaSamw 	case STYPE_DISKTREE:
432*da6c28aaSamw 		break;
433*da6c28aaSamw 
434*da6c28aaSamw 	case STYPE_IPC:
435*da6c28aaSamw 		/*
436*da6c28aaSamw 		 * No further processing for IPC, we need to either
437*da6c28aaSamw 		 * raise an exception or return success here.
438*da6c28aaSamw 		 */
439*da6c28aaSamw 		if ((rc = smb_rpc_open(sr)) != 0) {
440*da6c28aaSamw 			smbsr_raise_nt_error(sr, rc);
441*da6c28aaSamw 			/* NOTREACHED */
442*da6c28aaSamw 		} else {
443*da6c28aaSamw 			return (NT_STATUS_SUCCESS);
444*da6c28aaSamw 		}
445*da6c28aaSamw 		break;
446*da6c28aaSamw 
447*da6c28aaSamw 	default:
448*da6c28aaSamw 		smbsr_raise_error(sr, ERRSRV, ERRinvdevice);
449*da6c28aaSamw 		/* NOTREACHED */
450*da6c28aaSamw 		break;
451*da6c28aaSamw 	}
452*da6c28aaSamw 
453*da6c28aaSamw 	if ((pathlen = strlen(op->fqi.path)) >= MAXPATHLEN) {
454*da6c28aaSamw 		smbsr_raise_error(sr, ERRSRV, ERRfilespecs);
455*da6c28aaSamw 		/* NOTREACHED */
456*da6c28aaSamw 	}
457*da6c28aaSamw 
458*da6c28aaSamw 	/*
459*da6c28aaSamw 	 * Some clients pass null file names; NT interprets this as "\".
460*da6c28aaSamw 	 */
461*da6c28aaSamw 	if (pathlen == 0) {
462*da6c28aaSamw 		op->fqi.path = "\\";
463*da6c28aaSamw 		pathlen = 1;
464*da6c28aaSamw 	}
465*da6c28aaSamw 
466*da6c28aaSamw 	op->fqi.srch_attr = op->fqi.srch_attr;
467*da6c28aaSamw 
468*da6c28aaSamw 	if ((status = smb_validate_object_name(op->fqi.path, is_dir)) != 0) {
469*da6c28aaSamw 		smbsr_raise_cifs_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
470*da6c28aaSamw 		/* NOTREACHED */
471*da6c28aaSamw 	}
472*da6c28aaSamw 
473*da6c28aaSamw 	cur_node = op->fqi.dir_snode ?
474*da6c28aaSamw 	    op->fqi.dir_snode : sr->tid_tree->t_snode;
475*da6c28aaSamw 
476*da6c28aaSamw 	if (rc = smb_pathname_reduce(sr, sr->user_cr, op->fqi.path,
477*da6c28aaSamw 	    sr->tid_tree->t_snode, cur_node, &op->fqi.dir_snode,
478*da6c28aaSamw 	    op->fqi.last_comp)) {
479*da6c28aaSamw 		smbsr_raise_errno(sr, rc);
480*da6c28aaSamw 		/* NOTREACHED */
481*da6c28aaSamw 	}
482*da6c28aaSamw 
483*da6c28aaSamw 	/*
484*da6c28aaSamw 	 * If the access mask has only DELETE set (ignore
485*da6c28aaSamw 	 * FILE_READ_ATTRIBUTES), then assume that this
486*da6c28aaSamw 	 * is a request to delete the link (if a link)
487*da6c28aaSamw 	 * and do not follow links.  Otherwise, follow
488*da6c28aaSamw 	 * the link to the target.
489*da6c28aaSamw 	 */
490*da6c28aaSamw 
491*da6c28aaSamw 	daccess = op->desired_access & ~FILE_READ_ATTRIBUTES;
492*da6c28aaSamw 
493*da6c28aaSamw 	if (daccess == DELETE)
494*da6c28aaSamw 		lookup_flags &= ~SMB_FOLLOW_LINKS;
495*da6c28aaSamw 
496*da6c28aaSamw 	rc = smb_fsop_lookup_name(sr, kcred, lookup_flags,
497*da6c28aaSamw 	    sr->tid_tree->t_snode, op->fqi.dir_snode, op->fqi.last_comp,
498*da6c28aaSamw 	    &op->fqi.last_snode, &op->fqi.last_attr);
499*da6c28aaSamw 
500*da6c28aaSamw 	if (rc == 0) {
501*da6c28aaSamw 		op->fqi.last_comp_was_found = 1;
502*da6c28aaSamw 		(void) strcpy(op->fqi.last_comp_od,
503*da6c28aaSamw 		    op->fqi.last_snode->od_name);
504*da6c28aaSamw 	} else if (rc == ENOENT) {
505*da6c28aaSamw 		op->fqi.last_comp_was_found = 0;
506*da6c28aaSamw 		op->fqi.last_snode = NULL;
507*da6c28aaSamw 		rc = 0;
508*da6c28aaSamw 	} else {
509*da6c28aaSamw 		smb_node_release(op->fqi.dir_snode);
510*da6c28aaSamw 		SMB_NULL_FQI_NODES(op->fqi);
511*da6c28aaSamw 		smbsr_raise_errno(sr, rc);
512*da6c28aaSamw 		/* NOTREACHED */
513*da6c28aaSamw 	}
514*da6c28aaSamw 
515*da6c28aaSamw 	if (op->fqi.last_comp_was_found) {
516*da6c28aaSamw 		node = op->fqi.last_snode;
517*da6c28aaSamw 		dnode = op->fqi.dir_snode;
518*da6c28aaSamw 
519*da6c28aaSamw 		/*
520*da6c28aaSamw 		 * Reject this request if the target is a directory
521*da6c28aaSamw 		 * and the client has specified that it must not be
522*da6c28aaSamw 		 * a directory (required by Lotus Notes).
523*da6c28aaSamw 		 */
524*da6c28aaSamw 		if ((op->create_options & FILE_NON_DIRECTORY_FILE) &&
525*da6c28aaSamw 		    (op->fqi.last_attr.sa_vattr.va_type == VDIR)) {
526*da6c28aaSamw 			smb_node_release(node);
527*da6c28aaSamw 			smb_node_release(dnode);
528*da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
529*da6c28aaSamw 			smbsr_raise_cifs_error(sr,
530*da6c28aaSamw 			    NT_STATUS_FILE_IS_A_DIRECTORY,
531*da6c28aaSamw 			    ERRDOS, ERROR_ACCESS_DENIED);
532*da6c28aaSamw 			/* NOTREACHED */
533*da6c28aaSamw 		}
534*da6c28aaSamw 
535*da6c28aaSamw 		if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
536*da6c28aaSamw 			if ((sr->smb_com == SMB_COM_OPEN_ANDX) ||
537*da6c28aaSamw 			    (sr->smb_com == SMB_COM_OPEN)) {
538*da6c28aaSamw 				/*
539*da6c28aaSamw 				 * Directories cannot be opened
540*da6c28aaSamw 				 * with the above commands
541*da6c28aaSamw 				 */
542*da6c28aaSamw 				smb_node_release(node);
543*da6c28aaSamw 				smb_node_release(dnode);
544*da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
545*da6c28aaSamw 				smbsr_raise_cifs_error(sr,
546*da6c28aaSamw 				    NT_STATUS_FILE_IS_A_DIRECTORY,
547*da6c28aaSamw 				    ERRDOS, ERROR_ACCESS_DENIED);
548*da6c28aaSamw 				/* NOTREACHED */
549*da6c28aaSamw 			}
550*da6c28aaSamw 		} else if (op->my_flags & MYF_MUST_BE_DIRECTORY) {
551*da6c28aaSamw 			smb_node_release(node);
552*da6c28aaSamw 			smb_node_release(dnode);
553*da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
554*da6c28aaSamw 			smbsr_raise_cifs_error(sr, NT_STATUS_NOT_A_DIRECTORY,
555*da6c28aaSamw 			    ERRDOS, ERROR_DIRECTORY);
556*da6c28aaSamw 			/* NOTREACHED */
557*da6c28aaSamw 		}
558*da6c28aaSamw 
559*da6c28aaSamw 		/*
560*da6c28aaSamw 		 * No more open should be accepted when "Delete on close"
561*da6c28aaSamw 		 * flag is set.
562*da6c28aaSamw 		 */
563*da6c28aaSamw 		if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
564*da6c28aaSamw 			smb_node_release(node);
565*da6c28aaSamw 			smb_node_release(dnode);
566*da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
567*da6c28aaSamw 			smbsr_raise_cifs_error(sr, NT_STATUS_DELETE_PENDING,
568*da6c28aaSamw 			    ERRDOS, ERROR_ACCESS_DENIED);
569*da6c28aaSamw 			/* NOTREACHED */
570*da6c28aaSamw 		}
571*da6c28aaSamw 
572*da6c28aaSamw 		/*
573*da6c28aaSamw 		 * Specified file already exists so the operation should fail.
574*da6c28aaSamw 		 */
575*da6c28aaSamw 		if (op->create_disposition == FILE_CREATE) {
576*da6c28aaSamw 			smb_node_release(node);
577*da6c28aaSamw 			smb_node_release(dnode);
578*da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
579*da6c28aaSamw 			smbsr_raise_cifs_error(sr,
580*da6c28aaSamw 			    NT_STATUS_OBJECT_NAME_COLLISION, ERRDOS,
581*da6c28aaSamw 			    ERROR_ALREADY_EXISTS);
582*da6c28aaSamw 			/* NOTREACHED */
583*da6c28aaSamw 		}
584*da6c28aaSamw 
585*da6c28aaSamw 		/*
586*da6c28aaSamw 		 * Windows seems to check read-only access before file
587*da6c28aaSamw 		 * sharing check.
588*da6c28aaSamw 		 */
589*da6c28aaSamw 		if (NODE_IS_READONLY(node)) {
590*da6c28aaSamw 			/* Files data only */
591*da6c28aaSamw 			if (node->attr.sa_vattr.va_type != VDIR) {
592*da6c28aaSamw 				if (op->desired_access & (FILE_WRITE_DATA |
593*da6c28aaSamw 				    FILE_APPEND_DATA)) {
594*da6c28aaSamw 					smb_node_release(node);
595*da6c28aaSamw 					smb_node_release(dnode);
596*da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
597*da6c28aaSamw 					smbsr_raise_error(sr, ERRDOS,
598*da6c28aaSamw 					    ERRnoaccess);
599*da6c28aaSamw 					/* NOTREACHED */
600*da6c28aaSamw 				}
601*da6c28aaSamw 			}
602*da6c28aaSamw 		}
603*da6c28aaSamw 
604*da6c28aaSamw 		status = smb_file_share_check(sr, node);
605*da6c28aaSamw 		if (status == NT_STATUS_SHARING_VIOLATION) {
606*da6c28aaSamw 			smb_node_release(node);
607*da6c28aaSamw 			smb_node_release(dnode);
608*da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
609*da6c28aaSamw 			return (status);
610*da6c28aaSamw 		}
611*da6c28aaSamw 
612*da6c28aaSamw 		status = smb_fsop_access(sr, sr->user_cr, node,
613*da6c28aaSamw 		    op->desired_access);
614*da6c28aaSamw 
615*da6c28aaSamw 		if (status != NT_STATUS_SUCCESS) {
616*da6c28aaSamw 			smb_node_release(node);
617*da6c28aaSamw 			smb_node_release(dnode);
618*da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
619*da6c28aaSamw 			if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
620*da6c28aaSamw 				smbsr_raise_cifs_error(sr,
621*da6c28aaSamw 				    status,
622*da6c28aaSamw 				    ERRDOS,
623*da6c28aaSamw 				    ERROR_PRIVILEGE_NOT_HELD);
624*da6c28aaSamw 			} else {
625*da6c28aaSamw 				smbsr_raise_cifs_error(sr,
626*da6c28aaSamw 				    NT_STATUS_ACCESS_DENIED,
627*da6c28aaSamw 				    ERRDOS,
628*da6c28aaSamw 				    ERROR_ACCESS_DENIED);
629*da6c28aaSamw 			}
630*da6c28aaSamw 		}
631*da6c28aaSamw 
632*da6c28aaSamw 		/*
633*da6c28aaSamw 		 * Break the oplock before share checks. If another client
634*da6c28aaSamw 		 * has the file open, this will force a flush or close,
635*da6c28aaSamw 		 * which may affect the outcome of any share checking.
636*da6c28aaSamw 		 */
637*da6c28aaSamw 		if (OPLOCKS_IN_FORCE(node)) {
638*da6c28aaSamw 			status = smb_break_oplock(sr, node);
639*da6c28aaSamw 
640*da6c28aaSamw 			if (status != NT_STATUS_SUCCESS) {
641*da6c28aaSamw 				smb_node_release(node);
642*da6c28aaSamw 				smb_node_release(dnode);
643*da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
644*da6c28aaSamw 				smbsr_raise_cifs_error(sr, status,
645*da6c28aaSamw 				    ERRDOS, ERROR_VC_DISCONNECTED);
646*da6c28aaSamw 				/* NOTREACHED */
647*da6c28aaSamw 			}
648*da6c28aaSamw 		}
649*da6c28aaSamw 
650*da6c28aaSamw 		switch (op->create_disposition) {
651*da6c28aaSamw 		case FILE_SUPERSEDE:
652*da6c28aaSamw 		case FILE_OVERWRITE_IF:
653*da6c28aaSamw 		case FILE_OVERWRITE:
654*da6c28aaSamw 			if (node->attr.sa_vattr.va_type == VDIR) {
655*da6c28aaSamw 				smb_node_release(node);
656*da6c28aaSamw 				smb_node_release(dnode);
657*da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
658*da6c28aaSamw 				smbsr_raise_cifs_error(sr,
659*da6c28aaSamw 				    NT_STATUS_ACCESS_DENIED, ERRDOS,
660*da6c28aaSamw 				    ERROR_ACCESS_DENIED);
661*da6c28aaSamw 				/* NOTREACHED */
662*da6c28aaSamw 			}
663*da6c28aaSamw 
664*da6c28aaSamw 			if (node->attr.sa_vattr.va_size != op->dsize) {
665*da6c28aaSamw 				node->flags &= ~NODE_FLAGS_SET_SIZE;
666*da6c28aaSamw 				new_attr.sa_vattr.va_size = op->dsize;
667*da6c28aaSamw 				new_attr.sa_mask = SMB_AT_SIZE;
668*da6c28aaSamw 				if ((rc = smb_fsop_setattr(sr, sr->user_cr,
669*da6c28aaSamw 				    (&op->fqi)->last_snode, &new_attr,
670*da6c28aaSamw 				    &op->fqi.last_attr)) != 0) {
671*da6c28aaSamw 					smb_node_release(node);
672*da6c28aaSamw 					smb_node_release(dnode);
673*da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
674*da6c28aaSamw 					smbsr_raise_errno(sr, rc);
675*da6c28aaSamw 					/* NOTREACHED */
676*da6c28aaSamw 				}
677*da6c28aaSamw 
678*da6c28aaSamw 			}
679*da6c28aaSamw 
680*da6c28aaSamw 			/*
681*da6c28aaSamw 			 * If file is being replaced,
682*da6c28aaSamw 			 * we should remove existing streams
683*da6c28aaSamw 			 */
684*da6c28aaSamw 			if (SMB_IS_STREAM(node) == 0)
685*da6c28aaSamw 				(void) smb_fsop_remove_streams(sr, sr->user_cr,
686*da6c28aaSamw 				    node);
687*da6c28aaSamw 
688*da6c28aaSamw 			op->action_taken = SMB_OACT_TRUNCATED;
689*da6c28aaSamw 			break;
690*da6c28aaSamw 
691*da6c28aaSamw 		default:
692*da6c28aaSamw 			/*
693*da6c28aaSamw 			 * FILE_OPEN or FILE_OPEN_IF.
694*da6c28aaSamw 			 */
695*da6c28aaSamw 			op->action_taken = SMB_OACT_OPENED;
696*da6c28aaSamw 			break;
697*da6c28aaSamw 		}
698*da6c28aaSamw 	} else {
699*da6c28aaSamw 
700*da6c28aaSamw 		/* Last component was not found. */
701*da6c28aaSamw 		dnode = op->fqi.dir_snode;
702*da6c28aaSamw 
703*da6c28aaSamw 		if ((op->create_disposition == FILE_OPEN) ||
704*da6c28aaSamw 		    (op->create_disposition == FILE_OVERWRITE)) {
705*da6c28aaSamw 			smb_node_release(dnode);
706*da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
707*da6c28aaSamw 
708*da6c28aaSamw 			is_stream = smb_stream_parse_name(op->fqi.path,
709*da6c28aaSamw 			    NULL, NULL);
710*da6c28aaSamw 			/*
711*da6c28aaSamw 			 * The requested file not found so the operation should
712*da6c28aaSamw 			 * fail with these two dispositions
713*da6c28aaSamw 			 */
714*da6c28aaSamw 			if (is_stream)
715*da6c28aaSamw 				smbsr_raise_cifs_error(sr,
716*da6c28aaSamw 				    NT_STATUS_OBJECT_NAME_NOT_FOUND,
717*da6c28aaSamw 				    ERRDOS, ERROR_FILE_NOT_FOUND);
718*da6c28aaSamw 			else
719*da6c28aaSamw 				smbsr_raise_error(sr, ERRDOS, ERRbadfile);
720*da6c28aaSamw 			/* NOTREACHED */
721*da6c28aaSamw 		}
722*da6c28aaSamw 
723*da6c28aaSamw 		/*
724*da6c28aaSamw 		 * lock the parent dir node in case another create
725*da6c28aaSamw 		 * request to the same parent directory comes in.
726*da6c28aaSamw 		 */
727*da6c28aaSamw 		smb_rwx_rwenter(&dnode->n_lock, RW_WRITER);
728*da6c28aaSamw 
729*da6c28aaSamw 		bzero(&new_attr, sizeof (new_attr));
730*da6c28aaSamw 		if (is_dir == 0) {
731*da6c28aaSamw 			new_attr.sa_vattr.va_type = VREG;
732*da6c28aaSamw 			new_attr.sa_vattr.va_mode = 0666;
733*da6c28aaSamw 			new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE;
734*da6c28aaSamw 			rc = smb_fsop_create(sr, sr->user_cr, dnode,
735*da6c28aaSamw 			    op->fqi.last_comp, &new_attr,
736*da6c28aaSamw 			    &op->fqi.last_snode, &op->fqi.last_attr);
737*da6c28aaSamw 			if (rc != 0) {
738*da6c28aaSamw 				smb_rwx_rwexit(&dnode->n_lock);
739*da6c28aaSamw 				smb_node_release(dnode);
740*da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
741*da6c28aaSamw 				smbsr_raise_errno(sr, rc);
742*da6c28aaSamw 				/* NOTREACHED */
743*da6c28aaSamw 			}
744*da6c28aaSamw 
745*da6c28aaSamw 			if (op->dsize) {
746*da6c28aaSamw 				new_attr.sa_vattr.va_size = op->dsize;
747*da6c28aaSamw 				new_attr.sa_mask = SMB_AT_SIZE;
748*da6c28aaSamw 				rc = smb_fsop_setattr(sr, sr->user_cr,
749*da6c28aaSamw 				    op->fqi.last_snode, &new_attr,
750*da6c28aaSamw 				    &op->fqi.last_attr);
751*da6c28aaSamw 				if (rc != 0) {
752*da6c28aaSamw 					smb_node_release(op->fqi.last_snode);
753*da6c28aaSamw 					(void) smb_fsop_remove(sr, sr->user_cr,
754*da6c28aaSamw 					    dnode, op->fqi.last_comp, 0);
755*da6c28aaSamw 					smb_rwx_rwexit(&dnode->n_lock);
756*da6c28aaSamw 					smb_node_release(dnode);
757*da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
758*da6c28aaSamw 					smbsr_raise_errno(sr, rc);
759*da6c28aaSamw 					/* NOTREACHED */
760*da6c28aaSamw 				}
761*da6c28aaSamw 			}
762*da6c28aaSamw 
763*da6c28aaSamw 		} else {
764*da6c28aaSamw 			op->dattr |= SMB_FA_DIRECTORY;
765*da6c28aaSamw 			new_attr.sa_vattr.va_type = VDIR;
766*da6c28aaSamw 			new_attr.sa_vattr.va_mode = 0777;
767*da6c28aaSamw 			new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE;
768*da6c28aaSamw 			rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
769*da6c28aaSamw 			    op->fqi.last_comp, &new_attr,
770*da6c28aaSamw 			    &op->fqi.last_snode, &op->fqi.last_attr);
771*da6c28aaSamw 			if (rc != 0) {
772*da6c28aaSamw 				smb_rwx_rwexit(&dnode->n_lock);
773*da6c28aaSamw 				smb_node_release(dnode);
774*da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
775*da6c28aaSamw 				smbsr_raise_errno(sr, rc);
776*da6c28aaSamw 				/* NOTREACHED */
777*da6c28aaSamw 			}
778*da6c28aaSamw 		}
779*da6c28aaSamw 
780*da6c28aaSamw 		created = 1;
781*da6c28aaSamw 		op->action_taken = SMB_OACT_CREATED;
782*da6c28aaSamw 	}
783*da6c28aaSamw 
784*da6c28aaSamw 	if (node == 0) {
785*da6c28aaSamw 		node = op->fqi.last_snode;
786*da6c28aaSamw 	}
787*da6c28aaSamw 
788*da6c28aaSamw 	if ((op->fqi.last_attr.sa_vattr.va_type != VREG) &&
789*da6c28aaSamw 	    (op->fqi.last_attr.sa_vattr.va_type != VDIR) &&
790*da6c28aaSamw 	    (op->fqi.last_attr.sa_vattr.va_type != VLNK)) {
791*da6c28aaSamw 		/* not allowed to do this */
792*da6c28aaSamw 		SMB_DEL_NEWOBJ(op->fqi);
793*da6c28aaSamw 		smb_node_release(node);
794*da6c28aaSamw 		if (created)
795*da6c28aaSamw 			smb_rwx_rwexit(&dnode->n_lock);
796*da6c28aaSamw 		smb_node_release(dnode);
797*da6c28aaSamw 		SMB_NULL_FQI_NODES(op->fqi);
798*da6c28aaSamw 		smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
799*da6c28aaSamw 		/* NOTREACHED */
800*da6c28aaSamw 	}
801*da6c28aaSamw 
802*da6c28aaSamw 	if (max_requested) {
803*da6c28aaSamw 		smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed);
804*da6c28aaSamw 		op->desired_access |= max_allowed;
805*da6c28aaSamw 	}
806*da6c28aaSamw 
807*da6c28aaSamw 	/*
808*da6c28aaSamw 	 * smb_ofile_open() will copy node to of->node.  Hence
809*da6c28aaSamw 	 * the hold on node (i.e. op->fqi.last_snode) will be "transferred"
810*da6c28aaSamw 	 * to the "of" structure.
811*da6c28aaSamw 	 */
812*da6c28aaSamw 
813*da6c28aaSamw 	of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op->desired_access,
814*da6c28aaSamw 	    op->create_options, op->share_access, SMB_FTYPE_DISK, NULL, 0,
815*da6c28aaSamw 	    &err);
816*da6c28aaSamw 
817*da6c28aaSamw 	if (of == NULL) {
818*da6c28aaSamw 		SMB_DEL_NEWOBJ(op->fqi);
819*da6c28aaSamw 		smb_node_release(node);
820*da6c28aaSamw 		if (created)
821*da6c28aaSamw 			smb_rwx_rwexit(&dnode->n_lock);
822*da6c28aaSamw 		smb_node_release(dnode);
823*da6c28aaSamw 		SMB_NULL_FQI_NODES(op->fqi);
824*da6c28aaSamw 		smbsr_raise_cifs_error(sr, err.status, err.errcls, err.errcode);
825*da6c28aaSamw 		/* NOTREACHED */
826*da6c28aaSamw 	}
827*da6c28aaSamw 
828*da6c28aaSamw 	/*
829*da6c28aaSamw 	 * Propagate the write-through mode from the open params
830*da6c28aaSamw 	 * to the node: see the notes in the function header.
831*da6c28aaSamw 	 *
832*da6c28aaSamw 	 * IR #102318 Mirroring may force synchronous
833*da6c28aaSamw 	 * writes regardless of what we specify here.
834*da6c28aaSamw 	 */
835*da6c28aaSamw 	if (smb_stable_mode || (op->create_options & FILE_WRITE_THROUGH))
836*da6c28aaSamw 		node->flags |= NODE_FLAGS_WRITE_THROUGH;
837*da6c28aaSamw 
838*da6c28aaSamw 	op->fileid = op->fqi.last_attr.sa_vattr.va_nodeid;
839*da6c28aaSamw 
840*da6c28aaSamw 	if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
841*da6c28aaSamw 		/* We don't oplock directories */
842*da6c28aaSamw 		op->my_flags &= ~MYF_OPLOCK_MASK;
843*da6c28aaSamw 		op->dsize = 0;
844*da6c28aaSamw 	} else {
845*da6c28aaSamw 		status = smb_acquire_oplock(sr, of, op->my_flags,
846*da6c28aaSamw 		    &granted_oplock);
847*da6c28aaSamw 		op->my_flags &= ~MYF_OPLOCK_MASK;
848*da6c28aaSamw 
849*da6c28aaSamw 		if (status != NT_STATUS_SUCCESS) {
850*da6c28aaSamw 			(void) smb_ofile_close(of, 0);
851*da6c28aaSamw 			smb_ofile_release(of);
852*da6c28aaSamw 			if (created)
853*da6c28aaSamw 				smb_rwx_rwexit(&dnode->n_lock);
854*da6c28aaSamw 			smb_node_release(dnode);
855*da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
856*da6c28aaSamw 
857*da6c28aaSamw 			smbsr_raise_cifs_error(sr, status,
858*da6c28aaSamw 			    ERRDOS, ERROR_SHARING_VIOLATION);
859*da6c28aaSamw 			/* NOTREACHED */
860*da6c28aaSamw 		}
861*da6c28aaSamw 
862*da6c28aaSamw 		op->my_flags |= granted_oplock;
863*da6c28aaSamw 		op->dsize = op->fqi.last_attr.sa_vattr.va_size;
864*da6c28aaSamw 	}
865*da6c28aaSamw 
866*da6c28aaSamw 	if (created) {
867*da6c28aaSamw 		node->flags |= NODE_FLAGS_CREATED;
868*da6c28aaSamw 		/*
869*da6c28aaSamw 		 * Clients may set the DOS readonly bit on create but they
870*da6c28aaSamw 		 * expect subsequent write operations on the open fid to
871*da6c28aaSamw 		 * succeed.  Thus the DOS readonly bit is not set until the
872*da6c28aaSamw 		 * file is closed.  The NODE_CREATED_READONLY flag will
873*da6c28aaSamw 		 * inhibit other attempts to open the file with write access
874*da6c28aaSamw 		 * and act as the indicator to set the DOS readonly bit on
875*da6c28aaSamw 		 * close.
876*da6c28aaSamw 		 */
877*da6c28aaSamw 		if (op->dattr & SMB_FA_READONLY) {
878*da6c28aaSamw 			node->flags |= NODE_CREATED_READONLY;
879*da6c28aaSamw 			op->dattr &= ~SMB_FA_READONLY;
880*da6c28aaSamw 		}
881*da6c28aaSamw 		smb_node_set_dosattr(node, op->dattr | SMB_FA_ARCHIVE);
882*da6c28aaSamw 		if (op->utime.tv_sec == 0 || op->utime.tv_sec == 0xffffffff)
883*da6c28aaSamw 			(void) microtime(&op->utime);
884*da6c28aaSamw 		smb_node_set_time(node, NULL, &op->utime, 0, 0, SMB_AT_MTIME);
885*da6c28aaSamw 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
886*da6c28aaSamw 	} else {
887*da6c28aaSamw 		/*
888*da6c28aaSamw 		 * If we reach here, it means that file already exists
889*da6c28aaSamw 		 * and if create disposition is one of: FILE_SUPERSEDE,
890*da6c28aaSamw 		 * FILE_OVERWRITE_IF, or FILE_OVERWRITE it
891*da6c28aaSamw 		 * means that client wants to overwrite (or truncate)
892*da6c28aaSamw 		 * the existing file. So we should overwrite the dos
893*da6c28aaSamw 		 * attributes of destination file with the dos attributes
894*da6c28aaSamw 		 * of source file.
895*da6c28aaSamw 		 */
896*da6c28aaSamw 
897*da6c28aaSamw 		switch (op->create_disposition) {
898*da6c28aaSamw 		case FILE_SUPERSEDE:
899*da6c28aaSamw 		case FILE_OVERWRITE_IF:
900*da6c28aaSamw 		case FILE_OVERWRITE:
901*da6c28aaSamw 			smb_node_set_dosattr(node,
902*da6c28aaSamw 			    op->dattr | SMB_FA_ARCHIVE);
903*da6c28aaSamw 			(void) smb_sync_fsattr(sr, sr->user_cr, node);
904*da6c28aaSamw 		}
905*da6c28aaSamw 		op->utime = *smb_node_get_crtime(node);
906*da6c28aaSamw 		op->dattr = smb_node_get_dosattr(node);
907*da6c28aaSamw 	}
908*da6c28aaSamw 
909*da6c28aaSamw 	/*
910*da6c28aaSamw 	 * Set up the file type in open_param for the response
911*da6c28aaSamw 	 */
912*da6c28aaSamw 	op->ftype = SMB_FTYPE_DISK;
913*da6c28aaSamw 	sr->smb_fid = of->f_fid;
914*da6c28aaSamw 	sr->fid_ofile = of;
915*da6c28aaSamw 
916*da6c28aaSamw 	if (created) {
917*da6c28aaSamw 		smb_rwx_rwexit(&dnode->n_lock);
918*da6c28aaSamw 	}
919*da6c28aaSamw 	smb_node_release(dnode);
920*da6c28aaSamw 	SMB_NULL_FQI_NODES(op->fqi);
921*da6c28aaSamw 
922*da6c28aaSamw 	return (NT_STATUS_SUCCESS);
923*da6c28aaSamw }
924*da6c28aaSamw 
925*da6c28aaSamw /*
926*da6c28aaSamw  * smb_validate_object_name
927*da6c28aaSamw  *
928*da6c28aaSamw  * Very basic file name validation. Directory validation is handed off
929*da6c28aaSamw  * to smb_validate_dirname. For filenames, we check for names of the
930*da6c28aaSamw  * form "AAAn:". Names that contain three characters, a single digit
931*da6c28aaSamw  * and a colon (:) are reserved as DOS device names, i.e. "COM1:".
932*da6c28aaSamw  *
933*da6c28aaSamw  * Returns NT status codes.
934*da6c28aaSamw  */
935*da6c28aaSamw uint32_t
936*da6c28aaSamw smb_validate_object_name(char *path, unsigned int ftype)
937*da6c28aaSamw {
938*da6c28aaSamw 	char *filename;
939*da6c28aaSamw 
940*da6c28aaSamw 	if (path == 0)
941*da6c28aaSamw 		return (0);
942*da6c28aaSamw 
943*da6c28aaSamw 	if (ftype)
944*da6c28aaSamw 		return (smb_validate_dirname(path));
945*da6c28aaSamw 
946*da6c28aaSamw 	/*
947*da6c28aaSamw 	 * Basename with backslashes.
948*da6c28aaSamw 	 */
949*da6c28aaSamw 	if ((filename = strrchr(path, '\\')) != 0)
950*da6c28aaSamw 		++filename;
951*da6c28aaSamw 	else
952*da6c28aaSamw 		filename = path;
953*da6c28aaSamw 
954*da6c28aaSamw 	if (strlen(filename) == 5 &&
955*da6c28aaSamw 	    mts_isdigit(filename[3]) &&
956*da6c28aaSamw 	    filename[4] == ':') {
957*da6c28aaSamw 		return (NT_STATUS_OBJECT_NAME_INVALID);
958*da6c28aaSamw 	}
959*da6c28aaSamw 
960*da6c28aaSamw 	return (0);
961*da6c28aaSamw }
962*da6c28aaSamw 
963*da6c28aaSamw /*
964*da6c28aaSamw  * smb_preset_delete_on_close
965*da6c28aaSamw  *
966*da6c28aaSamw  * Set the DeleteOnClose flag on the smb file. When the file is closed,
967*da6c28aaSamw  * the flag will be transferred to the smb node, which will commit the
968*da6c28aaSamw  * delete operation and inhibit subsequent open requests.
969*da6c28aaSamw  *
970*da6c28aaSamw  * When DeleteOnClose is set on an smb_node, the common open code will
971*da6c28aaSamw  * reject subsequent open requests for the file. Observation of Windows
972*da6c28aaSamw  * 2000 indicates that subsequent opens should be allowed (assuming
973*da6c28aaSamw  * there would be no sharing violation) until the file is closed using
974*da6c28aaSamw  * the fid on which the DeleteOnClose was requested.
975*da6c28aaSamw  */
976*da6c28aaSamw void
977*da6c28aaSamw smb_preset_delete_on_close(smb_ofile_t *file)
978*da6c28aaSamw {
979*da6c28aaSamw 	mutex_enter(&file->f_mutex);
980*da6c28aaSamw 	file->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
981*da6c28aaSamw 	mutex_exit(&file->f_mutex);
982*da6c28aaSamw }
983