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