xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_common_open.c (revision 2c2961f8403049d948b9f3e6c35d6488b6b7e1aa)
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 /*
227f667e74Sjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * This module provides the common open functionality to the various
28da6c28aaSamw  * open and create SMB interface functions.
29da6c28aaSamw  */
30da6c28aaSamw 
31da6c28aaSamw #include <smbsrv/smb_incl.h>
32da6c28aaSamw #include <smbsrv/smb_fsops.h>
33da6c28aaSamw #include <smbsrv/nterror.h>
34da6c28aaSamw #include <smbsrv/ntstatus.h>
35da6c28aaSamw #include <smbsrv/smbinfo.h>
36da6c28aaSamw #include <sys/fcntl.h>
37dc20a302Sas #include <sys/nbmlock.h>
38da6c28aaSamw 
39faa1795aSjb volatile uint32_t smb_fids = 0;
407b59d02dSjb 
417b59d02dSjb static uint32_t smb_open_subr(smb_request_t *);
42da6c28aaSamw 
43faa1795aSjb extern uint32_t smb_is_executable(char *);
44da6c28aaSamw 
45da6c28aaSamw /*
46da6c28aaSamw  * This macro is used to delete a newly created object
47da6c28aaSamw  * if any error happens after creation of object.
48da6c28aaSamw  */
49da6c28aaSamw #define	SMB_DEL_NEWOBJ(obj) \
50da6c28aaSamw 	if (created) {							\
51da6c28aaSamw 		if (is_dir)						\
52da6c28aaSamw 			(void) smb_fsop_rmdir(sr, sr->user_cr,		\
53da6c28aaSamw 			    obj.dir_snode, obj.last_comp, 0);		\
54da6c28aaSamw 		else							\
55da6c28aaSamw 			(void) smb_fsop_remove(sr, sr->user_cr,		\
56da6c28aaSamw 			    obj.dir_snode, obj.last_comp, 0);		\
57da6c28aaSamw 	}
58da6c28aaSamw 
59da6c28aaSamw /*
60da6c28aaSamw  * smb_access_generic_to_file
61da6c28aaSamw  *
62da6c28aaSamw  * Search MSDN for IoCreateFile to see following mapping.
63da6c28aaSamw  *
64da6c28aaSamw  * GENERIC_READ		STANDARD_RIGHTS_READ, FILE_READ_DATA,
65da6c28aaSamw  *			FILE_READ_ATTRIBUTES and FILE_READ_EA
66da6c28aaSamw  *
67da6c28aaSamw  * GENERIC_WRITE	STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA,
68da6c28aaSamw  *               FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
69da6c28aaSamw  *
70da6c28aaSamw  * GENERIC_EXECUTE	STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE.
71da6c28aaSamw  */
72da6c28aaSamw uint32_t
73da6c28aaSamw smb_access_generic_to_file(uint32_t desired_access)
74da6c28aaSamw {
75da6c28aaSamw 	uint32_t access = 0;
76da6c28aaSamw 
77da6c28aaSamw 	if (desired_access & GENERIC_ALL)
78da6c28aaSamw 		return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
79da6c28aaSamw 
80da6c28aaSamw 	if (desired_access & GENERIC_EXECUTE) {
81da6c28aaSamw 		desired_access &= ~GENERIC_EXECUTE;
82da6c28aaSamw 		access |= (STANDARD_RIGHTS_EXECUTE |
83da6c28aaSamw 		    SYNCHRONIZE | FILE_EXECUTE);
84da6c28aaSamw 	}
85da6c28aaSamw 
86da6c28aaSamw 	if (desired_access & GENERIC_WRITE) {
87da6c28aaSamw 		desired_access &= ~GENERIC_WRITE;
88da6c28aaSamw 		access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE);
89da6c28aaSamw 	}
90da6c28aaSamw 
91da6c28aaSamw 	if (desired_access & GENERIC_READ) {
92da6c28aaSamw 		desired_access &= ~GENERIC_READ;
93da6c28aaSamw 		access |= FILE_GENERIC_READ;
94da6c28aaSamw 	}
95da6c28aaSamw 
96da6c28aaSamw 	return (access | desired_access);
97da6c28aaSamw }
98da6c28aaSamw 
99da6c28aaSamw /*
100da6c28aaSamw  * smb_omode_to_amask
101da6c28aaSamw  *
102da6c28aaSamw  * This function converts open modes used by Open and Open AndX
103da6c28aaSamw  * commands to desired access bits used by NT Create AndX command.
104da6c28aaSamw  */
105da6c28aaSamw uint32_t
106da6c28aaSamw smb_omode_to_amask(uint32_t desired_access)
107da6c28aaSamw {
108da6c28aaSamw 	switch (desired_access & SMB_DA_ACCESS_MASK) {
109da6c28aaSamw 	case SMB_DA_ACCESS_READ:
110da6c28aaSamw 		return (FILE_GENERIC_READ);
111da6c28aaSamw 
112da6c28aaSamw 	case SMB_DA_ACCESS_WRITE:
113da6c28aaSamw 		return (FILE_GENERIC_WRITE);
114da6c28aaSamw 
115da6c28aaSamw 	case SMB_DA_ACCESS_READ_WRITE:
116da6c28aaSamw 		return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
117da6c28aaSamw 
118da6c28aaSamw 	case SMB_DA_ACCESS_EXECUTE:
119da6c28aaSamw 		return (FILE_GENERIC_EXECUTE);
120da6c28aaSamw 
121*2c2961f8Sjose borrego 	default:
122*2c2961f8Sjose borrego 		return (FILE_GENERIC_ALL);
123*2c2961f8Sjose borrego 	}
124da6c28aaSamw }
125da6c28aaSamw 
126da6c28aaSamw /*
127da6c28aaSamw  * smb_denymode_to_sharemode
128da6c28aaSamw  *
129da6c28aaSamw  * This function converts deny modes used by Open and Open AndX
130da6c28aaSamw  * commands to share access bits used by NT Create AndX command.
131da6c28aaSamw  */
132da6c28aaSamw uint32_t
133da6c28aaSamw smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
134da6c28aaSamw {
135da6c28aaSamw 	switch (desired_access & SMB_DA_SHARE_MASK) {
136da6c28aaSamw 	case SMB_DA_SHARE_COMPATIBILITY:
137da6c28aaSamw 		if (smb_is_executable(fname))
138da6c28aaSamw 			return (FILE_SHARE_READ | FILE_SHARE_WRITE);
139c8ec8eeaSjose borrego 
140c8ec8eeaSjose borrego 		return (FILE_SHARE_ALL);
141da6c28aaSamw 
142da6c28aaSamw 	case SMB_DA_SHARE_EXCLUSIVE:
143da6c28aaSamw 		return (FILE_SHARE_NONE);
144da6c28aaSamw 
145da6c28aaSamw 	case SMB_DA_SHARE_DENY_WRITE:
146da6c28aaSamw 		return (FILE_SHARE_READ);
147da6c28aaSamw 
148da6c28aaSamw 	case SMB_DA_SHARE_DENY_READ:
149da6c28aaSamw 		return (FILE_SHARE_WRITE);
150da6c28aaSamw 
151da6c28aaSamw 	case SMB_DA_SHARE_DENY_NONE:
152*2c2961f8Sjose borrego 	default:
153da6c28aaSamw 		return (FILE_SHARE_READ | FILE_SHARE_WRITE);
154da6c28aaSamw 	}
155da6c28aaSamw }
156da6c28aaSamw 
157da6c28aaSamw /*
158da6c28aaSamw  * smb_ofun_to_crdisposition
159da6c28aaSamw  *
160da6c28aaSamw  * This function converts open function values used by Open and Open AndX
161da6c28aaSamw  * commands to create disposition values used by NT Create AndX command.
162da6c28aaSamw  */
163da6c28aaSamw uint32_t
164da6c28aaSamw smb_ofun_to_crdisposition(uint16_t  ofun)
165da6c28aaSamw {
166da6c28aaSamw 	static int ofun_cr_map[3][2] =
167da6c28aaSamw 	{
168da6c28aaSamw 		{ -1,			FILE_CREATE },
169da6c28aaSamw 		{ FILE_OPEN,		FILE_OPEN_IF },
170da6c28aaSamw 		{ FILE_OVERWRITE,	FILE_OVERWRITE_IF }
171da6c28aaSamw 	};
172da6c28aaSamw 
173da6c28aaSamw 	int row = ofun & SMB_OFUN_OPEN_MASK;
174da6c28aaSamw 	int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
175da6c28aaSamw 
176da6c28aaSamw 	if (row == 3)
177*2c2961f8Sjose borrego 		return (FILE_MAXIMUM_DISPOSITION + 1);
178da6c28aaSamw 
179da6c28aaSamw 	return (ofun_cr_map[row][col]);
180da6c28aaSamw }
181da6c28aaSamw 
1827b59d02dSjb /*
1837b59d02dSjb  * Retry opens to avoid spurious sharing violations, due to timing
1847b59d02dSjb  * issues between closes and opens.  The client that already has the
1857b59d02dSjb  * file open may be in the process of closing it.
1867b59d02dSjb  */
1877b59d02dSjb uint32_t
1887b59d02dSjb smb_common_open(smb_request_t *sr)
1897b59d02dSjb {
1907b59d02dSjb 	uint32_t status = NT_STATUS_SUCCESS;
1917b59d02dSjb 	int count;
1927b59d02dSjb 
1937b59d02dSjb 	for (count = 0; count <= 4; count++) {
1947b59d02dSjb 		if (count)
1957b59d02dSjb 			delay(MSEC_TO_TICK(400));
1967b59d02dSjb 
197faa1795aSjb 		status = smb_open_subr(sr);
198faa1795aSjb 		if (status != NT_STATUS_SHARING_VIOLATION)
1997b59d02dSjb 			break;
2007b59d02dSjb 	}
2017b59d02dSjb 
202faa1795aSjb 	if (status == NT_STATUS_SHARING_VIOLATION) {
2037b59d02dSjb 		smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
2047b59d02dSjb 		    ERRDOS, ERROR_SHARING_VIOLATION);
2057b59d02dSjb 	}
2067b59d02dSjb 
207*2c2961f8Sjose borrego 	if (status == NT_STATUS_NO_SUCH_FILE) {
208*2c2961f8Sjose borrego 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
209*2c2961f8Sjose borrego 		    ERRDOS, ERROR_FILE_NOT_FOUND);
210*2c2961f8Sjose borrego 	}
211*2c2961f8Sjose borrego 
2127b59d02dSjb 	return (status);
2137b59d02dSjb }
2147b59d02dSjb 
215da6c28aaSamw /*
216da6c28aaSamw  * smb_open_subr
217da6c28aaSamw  *
218da6c28aaSamw  * Notes on write-through behaviour. It looks like pre-LM0.12 versions
219da6c28aaSamw  * of the protocol specify the write-through mode when a file is opened,
220da6c28aaSamw  * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose,
221da6c28aaSamw  * SmbWriteAndUnlock) don't need to contain a write-through flag.
222da6c28aaSamw  *
223da6c28aaSamw  * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate)
224da6c28aaSamw  * don't indicate which write-through mode to use. Instead the write
225da6c28aaSamw  * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call
226da6c28aaSamw  * basis.
227da6c28aaSamw  *
228da6c28aaSamw  * We don't care which open call was used to get us here, we just need
229da6c28aaSamw  * to ensure that the write-through mode flag is copied from the open
230da6c28aaSamw  * parameters to the node. We test the omode write-through flag in all
231da6c28aaSamw  * write functions.
232da6c28aaSamw  *
233da6c28aaSamw  * This function will return NT status codes but it also raises errors,
234da6c28aaSamw  * in which case it won't return to the caller. Be careful how you
235da6c28aaSamw  * handle things in here.
2368c10a865Sas  *
2378c10a865Sas  * The following rules apply when processing a file open request:
2388c10a865Sas  *
2398c10a865Sas  * - Oplocks must be broken prior to share checking to prevent open
2408c10a865Sas  * starvation due to batch oplocks.  Checking share reservations first
2418c10a865Sas  * could potentially result in unnecessary open failures due to
2428c10a865Sas  * open/close batching on the client.
2438c10a865Sas  *
2448c10a865Sas  * - Share checks must take place prior to access checks for correct
2458c10a865Sas  * Windows semantics and to prevent unnecessary NFS delegation recalls.
2468c10a865Sas  *
2478c10a865Sas  * - Oplocks must be acquired after open to ensure the correct
2488c10a865Sas  * synchronization with NFS delegation and FEM installation.
249c8ec8eeaSjose borrego  *
250c8ec8eeaSjose borrego  *
251c8ec8eeaSjose borrego  * DOS readonly bit rules
252c8ec8eeaSjose borrego  *
253c8ec8eeaSjose borrego  * 1. The creator of a readonly file can write to/modify the size of the file
254c8ec8eeaSjose borrego  * using the original create fid, even though the file will appear as readonly
255c8ec8eeaSjose borrego  * to all other fids and via a CIFS getattr call.
256c8ec8eeaSjose borrego  *
257c8ec8eeaSjose borrego  * 2. A setinfo operation (using either an open fid or a path) to set/unset
258c8ec8eeaSjose borrego  * readonly will be successful regardless of whether a creator of a readonly
259c8ec8eeaSjose borrego  * file has an open fid (and has the special privilege mentioned in #1,
260c8ec8eeaSjose borrego  * above).  I.e., the creator of a readonly fid holding that fid will no longer
261c8ec8eeaSjose borrego  * have a special privilege.
262c8ec8eeaSjose borrego  *
263c8ec8eeaSjose borrego  * 3. The DOS readonly bit affects only data and some metadata.
264c8ec8eeaSjose borrego  * The following metadata can be changed regardless of the readonly bit:
265c8ec8eeaSjose borrego  * 	- security descriptors
266c8ec8eeaSjose borrego  *	- DOS attributes
267c8ec8eeaSjose borrego  *	- timestamps
268c8ec8eeaSjose borrego  *
269c8ec8eeaSjose borrego  * In the current implementation, the file size cannot be changed (except for
270c8ec8eeaSjose borrego  * the exceptions in #1 and #2, above).
2712c1b14e5Sjose borrego  *
2722c1b14e5Sjose borrego  *
2732c1b14e5Sjose borrego  * DOS attribute rules
2742c1b14e5Sjose borrego  *
2752c1b14e5Sjose borrego  * These rules are specific to creating / opening files and directories.
2762c1b14e5Sjose borrego  * How the attribute value (specifically ZERO or FILE_ATTRIBUTE_NORMAL)
2772c1b14e5Sjose borrego  * should be interpreted may differ in other requests.
2782c1b14e5Sjose borrego  *
2792c1b14e5Sjose borrego  * - An attribute value equal to ZERO or FILE_ATTRIBUTE_NORMAL means that the
2802c1b14e5Sjose borrego  *   file's attributes should be cleared.
2812c1b14e5Sjose borrego  * - If FILE_ATTRIBUTE_NORMAL is specified with any other attributes,
2822c1b14e5Sjose borrego  *   FILE_ATTRIBUTE_NORMAL is ignored.
2832c1b14e5Sjose borrego  *
2842c1b14e5Sjose borrego  * 1. Creating a new file
2852c1b14e5Sjose borrego  * - The request attributes + FILE_ATTRIBUTE_ARCHIVE are applied to the file.
2862c1b14e5Sjose borrego  *
2872c1b14e5Sjose borrego  * 2. Creating a new directory
2882c1b14e5Sjose borrego  * - The request attributes + FILE_ATTRIBUTE_DIRECTORY are applied to the file.
2892c1b14e5Sjose borrego  * - FILE_ATTRIBUTE_ARCHIVE does not get set.
2902c1b14e5Sjose borrego  *
2912c1b14e5Sjose borrego  * 3. Overwriting an existing file
2922c1b14e5Sjose borrego  * - the request attributes are used as search attributes. If the existing
2932c1b14e5Sjose borrego  *   file does not meet the search criteria access is denied.
2942c1b14e5Sjose borrego  * - otherwise, applies attributes + FILE_ATTRIBUTE_ARCHIVE.
2952c1b14e5Sjose borrego  *
2962c1b14e5Sjose borrego  * 4. Opening an existing file or directory
2972c1b14e5Sjose borrego  *    The request attributes are ignored.
298da6c28aaSamw  */
2997b59d02dSjb static uint32_t
3007b59d02dSjb smb_open_subr(smb_request_t *sr)
301da6c28aaSamw {
302*2c2961f8Sjose borrego 	int		created = 0;
303*2c2961f8Sjose borrego 	smb_node_t	*node = NULL;
304*2c2961f8Sjose borrego 	smb_node_t	*dnode = NULL;
305*2c2961f8Sjose borrego 	smb_node_t	*cur_node;
306*2c2961f8Sjose borrego 	open_param_t	*op = &sr->arg.open;
307*2c2961f8Sjose borrego 	int		rc;
308*2c2961f8Sjose borrego 	smb_ofile_t	*of;
309*2c2961f8Sjose borrego 	smb_attr_t	new_attr;
310*2c2961f8Sjose borrego 	int		pathlen;
311*2c2961f8Sjose borrego 	int		max_requested = 0;
312*2c2961f8Sjose borrego 	uint32_t	max_allowed;
313*2c2961f8Sjose borrego 	uint32_t	status = NT_STATUS_SUCCESS;
314*2c2961f8Sjose borrego 	int		is_dir;
315*2c2961f8Sjose borrego 	smb_error_t	err;
316*2c2961f8Sjose borrego 	boolean_t	is_stream = B_FALSE;
317*2c2961f8Sjose borrego 	int		lookup_flags = SMB_FOLLOW_LINKS;
318*2c2961f8Sjose borrego 	uint32_t	daccess;
319*2c2961f8Sjose borrego 	uint32_t	uniq_fid;
320da6c28aaSamw 
321da6c28aaSamw 	is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
322da6c28aaSamw 
323da6c28aaSamw 	if (is_dir) {
324da6c28aaSamw 		/*
3257b59d02dSjb 		 * The object being created or opened is a directory,
3267b59d02dSjb 		 * and the Disposition parameter must be one of
3277b59d02dSjb 		 * FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF
328da6c28aaSamw 		 */
329da6c28aaSamw 		if ((op->create_disposition != FILE_CREATE) &&
330da6c28aaSamw 		    (op->create_disposition != FILE_OPEN_IF) &&
331da6c28aaSamw 		    (op->create_disposition != FILE_OPEN)) {
332dc20a302Sas 			smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
333da6c28aaSamw 			    ERRDOS, ERROR_INVALID_ACCESS);
3347b59d02dSjb 			return (NT_STATUS_INVALID_PARAMETER);
335da6c28aaSamw 		}
336da6c28aaSamw 	}
337da6c28aaSamw 
338da6c28aaSamw 	if (op->desired_access & MAXIMUM_ALLOWED) {
339da6c28aaSamw 		max_requested = 1;
340da6c28aaSamw 		op->desired_access &= ~MAXIMUM_ALLOWED;
341da6c28aaSamw 	}
342da6c28aaSamw 	op->desired_access = smb_access_generic_to_file(op->desired_access);
343da6c28aaSamw 
344da6c28aaSamw 	if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) {
345da6c28aaSamw 		ASSERT(sr->uid_user);
346da6c28aaSamw 		cmn_err(CE_NOTE, "smbd[%s\\%s]: %s", sr->uid_user->u_domain,
347da6c28aaSamw 		    sr->uid_user->u_name,
348da6c28aaSamw 		    xlate_nt_status(NT_STATUS_TOO_MANY_OPENED_FILES));
349da6c28aaSamw 
350dc20a302Sas 		smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
351da6c28aaSamw 		    ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
3527b59d02dSjb 		return (NT_STATUS_TOO_MANY_OPENED_FILES);
353da6c28aaSamw 	}
354da6c28aaSamw 
355da6c28aaSamw 	/* This must be NULL at this point */
356da6c28aaSamw 	sr->fid_ofile = NULL;
357da6c28aaSamw 
358da6c28aaSamw 	op->devstate = 0;
359da6c28aaSamw 
360da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
361da6c28aaSamw 	case STYPE_DISKTREE:
362da6c28aaSamw 		break;
363da6c28aaSamw 
364da6c28aaSamw 	case STYPE_IPC:
365da6c28aaSamw 		/*
366da6c28aaSamw 		 * No further processing for IPC, we need to either
367da6c28aaSamw 		 * raise an exception or return success here.
368da6c28aaSamw 		 */
3693db3f65cSamw 		if ((status = smb_opipe_open(sr)) != NT_STATUS_SUCCESS)
3707b59d02dSjb 			smbsr_error(sr, status, 0, 0);
3717b59d02dSjb 		return (status);
372da6c28aaSamw 
373da6c28aaSamw 	default:
3747b59d02dSjb 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
3757b59d02dSjb 		    ERRDOS, ERROR_BAD_DEV_TYPE);
3767b59d02dSjb 		return (NT_STATUS_BAD_DEVICE_TYPE);
377da6c28aaSamw 	}
378da6c28aaSamw 
379da6c28aaSamw 	if ((pathlen = strlen(op->fqi.path)) >= MAXPATHLEN) {
380dc20a302Sas 		smbsr_error(sr, 0, ERRSRV, ERRfilespecs);
3817b59d02dSjb 		return (NT_STATUS_NAME_TOO_LONG);
382da6c28aaSamw 	}
383da6c28aaSamw 
384da6c28aaSamw 	/*
385da6c28aaSamw 	 * Some clients pass null file names; NT interprets this as "\".
386da6c28aaSamw 	 */
387da6c28aaSamw 	if (pathlen == 0) {
388da6c28aaSamw 		op->fqi.path = "\\";
389da6c28aaSamw 		pathlen = 1;
390da6c28aaSamw 	}
391da6c28aaSamw 
392da6c28aaSamw 	op->fqi.srch_attr = op->fqi.srch_attr;
393da6c28aaSamw 
394da6c28aaSamw 	if ((status = smb_validate_object_name(op->fqi.path, is_dir)) != 0) {
395dc20a302Sas 		smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
3967b59d02dSjb 		return (status);
397da6c28aaSamw 	}
398da6c28aaSamw 
399da6c28aaSamw 	cur_node = op->fqi.dir_snode ?
400da6c28aaSamw 	    op->fqi.dir_snode : sr->tid_tree->t_snode;
401da6c28aaSamw 
402da6c28aaSamw 	if (rc = smb_pathname_reduce(sr, sr->user_cr, op->fqi.path,
403da6c28aaSamw 	    sr->tid_tree->t_snode, cur_node, &op->fqi.dir_snode,
404da6c28aaSamw 	    op->fqi.last_comp)) {
405dc20a302Sas 		smbsr_errno(sr, rc);
4067b59d02dSjb 		return (sr->smb_error.status);
407da6c28aaSamw 	}
408da6c28aaSamw 
409da6c28aaSamw 	/*
410da6c28aaSamw 	 * If the access mask has only DELETE set (ignore
411da6c28aaSamw 	 * FILE_READ_ATTRIBUTES), then assume that this
412da6c28aaSamw 	 * is a request to delete the link (if a link)
413da6c28aaSamw 	 * and do not follow links.  Otherwise, follow
414da6c28aaSamw 	 * the link to the target.
415da6c28aaSamw 	 */
416da6c28aaSamw 
417da6c28aaSamw 	daccess = op->desired_access & ~FILE_READ_ATTRIBUTES;
418da6c28aaSamw 
419da6c28aaSamw 	if (daccess == DELETE)
420da6c28aaSamw 		lookup_flags &= ~SMB_FOLLOW_LINKS;
421da6c28aaSamw 
422da6c28aaSamw 	rc = smb_fsop_lookup_name(sr, kcred, lookup_flags,
423da6c28aaSamw 	    sr->tid_tree->t_snode, op->fqi.dir_snode, op->fqi.last_comp,
424da6c28aaSamw 	    &op->fqi.last_snode, &op->fqi.last_attr);
425da6c28aaSamw 
426da6c28aaSamw 	if (rc == 0) {
427da6c28aaSamw 		op->fqi.last_comp_was_found = 1;
428da6c28aaSamw 		(void) strcpy(op->fqi.last_comp_od,
429da6c28aaSamw 		    op->fqi.last_snode->od_name);
430da6c28aaSamw 	} else if (rc == ENOENT) {
431da6c28aaSamw 		op->fqi.last_comp_was_found = 0;
432da6c28aaSamw 		op->fqi.last_snode = NULL;
433da6c28aaSamw 		rc = 0;
434da6c28aaSamw 	} else {
435da6c28aaSamw 		smb_node_release(op->fqi.dir_snode);
436da6c28aaSamw 		SMB_NULL_FQI_NODES(op->fqi);
437dc20a302Sas 		smbsr_errno(sr, rc);
4387b59d02dSjb 		return (sr->smb_error.status);
439da6c28aaSamw 	}
440da6c28aaSamw 
441dc20a302Sas 	/*
442dc20a302Sas 	 * The uniq_fid is a CIFS-server-wide unique identifier for an ofile
443dc20a302Sas 	 * which is used to uniquely identify open instances for the
444c8ec8eeaSjose borrego 	 * VFS share reservation and POSIX locks.
445dc20a302Sas 	 */
446dc20a302Sas 
447dc20a302Sas 	uniq_fid = SMB_UNIQ_FID();
448dc20a302Sas 
449da6c28aaSamw 	if (op->fqi.last_comp_was_found) {
4506537f381Sas 
4516537f381Sas 		if ((op->fqi.last_attr.sa_vattr.va_type != VREG) &&
4526537f381Sas 		    (op->fqi.last_attr.sa_vattr.va_type != VDIR) &&
4536537f381Sas 		    (op->fqi.last_attr.sa_vattr.va_type != VLNK)) {
4546537f381Sas 
4556537f381Sas 			smb_node_release(op->fqi.last_snode);
4566537f381Sas 			smb_node_release(op->fqi.dir_snode);
4576537f381Sas 			SMB_NULL_FQI_NODES(op->fqi);
4586537f381Sas 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
4596537f381Sas 			    ERRnoaccess);
4606537f381Sas 			return (NT_STATUS_ACCESS_DENIED);
4616537f381Sas 		}
4626537f381Sas 
463da6c28aaSamw 		node = op->fqi.last_snode;
464da6c28aaSamw 		dnode = op->fqi.dir_snode;
465da6c28aaSamw 
466da6c28aaSamw 		/*
4672c1b14e5Sjose borrego 		 * Reject this request if either:
4682c1b14e5Sjose borrego 		 * - the target IS a directory and the client requires that
4692c1b14e5Sjose borrego 		 *   it must NOT be (required by Lotus Notes)
4702c1b14e5Sjose borrego 		 * - the target is NOT a directory and client requires that
4712c1b14e5Sjose borrego 		 *   it MUST be.
472da6c28aaSamw 		 */
473da6c28aaSamw 		if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
4742c1b14e5Sjose borrego 			if (op->create_options & FILE_NON_DIRECTORY_FILE) {
475da6c28aaSamw 				smb_node_release(node);
476da6c28aaSamw 				smb_node_release(dnode);
477da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
478dc20a302Sas 				smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
479da6c28aaSamw 				    ERRDOS, ERROR_ACCESS_DENIED);
4807b59d02dSjb 				return (NT_STATUS_FILE_IS_A_DIRECTORY);
481da6c28aaSamw 			}
4822c1b14e5Sjose borrego 		} else {
4832c1b14e5Sjose borrego 			if ((op->create_options & FILE_DIRECTORY_FILE) ||
484*2c2961f8Sjose borrego 			    (op->nt_flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)) {
4852c1b14e5Sjose borrego 				smb_node_release(node);
4862c1b14e5Sjose borrego 				smb_node_release(dnode);
4872c1b14e5Sjose borrego 				SMB_NULL_FQI_NODES(op->fqi);
4882c1b14e5Sjose borrego 				smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
4892c1b14e5Sjose borrego 				    ERRDOS, ERROR_DIRECTORY);
4902c1b14e5Sjose borrego 				return (NT_STATUS_NOT_A_DIRECTORY);
4912c1b14e5Sjose borrego 			}
492da6c28aaSamw 		}
493da6c28aaSamw 
494da6c28aaSamw 		/*
495da6c28aaSamw 		 * No more open should be accepted when "Delete on close"
496da6c28aaSamw 		 * flag is set.
497da6c28aaSamw 		 */
498da6c28aaSamw 		if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
499da6c28aaSamw 			smb_node_release(node);
500da6c28aaSamw 			smb_node_release(dnode);
501da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
502dc20a302Sas 			smbsr_error(sr, NT_STATUS_DELETE_PENDING,
503da6c28aaSamw 			    ERRDOS, ERROR_ACCESS_DENIED);
5047b59d02dSjb 			return (NT_STATUS_DELETE_PENDING);
505da6c28aaSamw 		}
506da6c28aaSamw 
507da6c28aaSamw 		/*
508da6c28aaSamw 		 * Specified file already exists so the operation should fail.
509da6c28aaSamw 		 */
510da6c28aaSamw 		if (op->create_disposition == FILE_CREATE) {
511da6c28aaSamw 			smb_node_release(node);
512da6c28aaSamw 			smb_node_release(dnode);
513da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
514dc20a302Sas 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
515b89a8333Snatalie li - Sun Microsystems - Irvine United States 			    ERRDOS, ERROR_FILE_EXISTS);
5167b59d02dSjb 			return (NT_STATUS_OBJECT_NAME_COLLISION);
517da6c28aaSamw 		}
518da6c28aaSamw 
519da6c28aaSamw 		/*
520da6c28aaSamw 		 * Windows seems to check read-only access before file
521da6c28aaSamw 		 * sharing check.
522c8ec8eeaSjose borrego 		 *
523c8ec8eeaSjose borrego 		 * Check to see if the file is currently readonly (irrespective
524c8ec8eeaSjose borrego 		 * of whether this open will make it readonly).
525da6c28aaSamw 		 */
526c8ec8eeaSjose borrego 		if (SMB_PATHFILE_IS_READONLY(sr, node)) {
527da6c28aaSamw 			/* Files data only */
528da6c28aaSamw 			if (node->attr.sa_vattr.va_type != VDIR) {
529da6c28aaSamw 				if (op->desired_access & (FILE_WRITE_DATA |
530da6c28aaSamw 				    FILE_APPEND_DATA)) {
531da6c28aaSamw 					smb_node_release(node);
532da6c28aaSamw 					smb_node_release(dnode);
533da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
534dc20a302Sas 					smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
535dc20a302Sas 					    ERRDOS, ERRnoaccess);
5367b59d02dSjb 					return (NT_STATUS_ACCESS_DENIED);
537da6c28aaSamw 				}
538da6c28aaSamw 			}
539da6c28aaSamw 		}
540da6c28aaSamw 
5418c10a865Sas 		if (smb_oplock_conflict(node, sr->session, op))
542*2c2961f8Sjose borrego 			(void) smb_oplock_break(node,
543*2c2961f8Sjose borrego 			    SMB_SESSION_GET_ID(sr->session), B_FALSE);
5448c10a865Sas 
545*2c2961f8Sjose borrego 		smb_node_wrlock(node);
546dc20a302Sas 
547dc20a302Sas 		if ((op->create_disposition == FILE_SUPERSEDE) ||
548dc20a302Sas 		    (op->create_disposition == FILE_OVERWRITE_IF) ||
549dc20a302Sas 		    (op->create_disposition == FILE_OVERWRITE)) {
550dc20a302Sas 
5512c1b14e5Sjose borrego 			if ((!(op->desired_access &
5528c10a865Sas 			    (FILE_WRITE_DATA | FILE_APPEND_DATA |
5532c1b14e5Sjose borrego 			    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) ||
5547f667e74Sjose borrego 			    (!smb_sattr_check(node->attr.sa_dosattr,
555*2c2961f8Sjose borrego 			    op->dattr))) {
556*2c2961f8Sjose borrego 				smb_node_unlock(node);
557dc20a302Sas 				smb_node_release(node);
558dc20a302Sas 				smb_node_release(dnode);
559dc20a302Sas 				SMB_NULL_FQI_NODES(op->fqi);
560dc20a302Sas 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
561dc20a302Sas 				    ERRDOS, ERRnoaccess);
5627b59d02dSjb 				return (NT_STATUS_ACCESS_DENIED);
563dc20a302Sas 			}
564dc20a302Sas 		}
565dc20a302Sas 
566dc20a302Sas 		status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
567c8ec8eeaSjose borrego 		    op->desired_access, op->share_access);
568dc20a302Sas 
569da6c28aaSamw 		if (status == NT_STATUS_SHARING_VIOLATION) {
570*2c2961f8Sjose borrego 			smb_node_unlock(node);
571da6c28aaSamw 			smb_node_release(node);
572da6c28aaSamw 			smb_node_release(dnode);
573da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
574da6c28aaSamw 			return (status);
575da6c28aaSamw 		}
576da6c28aaSamw 
577da6c28aaSamw 		status = smb_fsop_access(sr, sr->user_cr, node,
578da6c28aaSamw 		    op->desired_access);
579da6c28aaSamw 
580da6c28aaSamw 		if (status != NT_STATUS_SUCCESS) {
581dc20a302Sas 			smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
582dc20a302Sas 
583*2c2961f8Sjose borrego 			smb_node_unlock(node);
584da6c28aaSamw 			smb_node_release(node);
585da6c28aaSamw 			smb_node_release(dnode);
586da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
587dc20a302Sas 
588da6c28aaSamw 			if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
589dc20a302Sas 				smbsr_error(sr, status,
590dc20a302Sas 				    ERRDOS, ERROR_PRIVILEGE_NOT_HELD);
5917b59d02dSjb 				return (status);
592da6c28aaSamw 			} else {
593dc20a302Sas 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
594dc20a302Sas 				    ERRDOS, ERROR_ACCESS_DENIED);
5957b59d02dSjb 				return (NT_STATUS_ACCESS_DENIED);
596da6c28aaSamw 			}
597da6c28aaSamw 		}
598da6c28aaSamw 
599da6c28aaSamw 		switch (op->create_disposition) {
600da6c28aaSamw 		case FILE_SUPERSEDE:
601da6c28aaSamw 		case FILE_OVERWRITE_IF:
602da6c28aaSamw 		case FILE_OVERWRITE:
603da6c28aaSamw 			if (node->attr.sa_vattr.va_type == VDIR) {
604dc20a302Sas 				smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
605*2c2961f8Sjose borrego 				smb_node_unlock(node);
606da6c28aaSamw 				smb_node_release(node);
607da6c28aaSamw 				smb_node_release(dnode);
608da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
609dc20a302Sas 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
610dc20a302Sas 				    ERRDOS, ERROR_ACCESS_DENIED);
6117b59d02dSjb 				return (NT_STATUS_ACCESS_DENIED);
612da6c28aaSamw 			}
613da6c28aaSamw 
614da6c28aaSamw 			if (node->attr.sa_vattr.va_size != op->dsize) {
615da6c28aaSamw 				node->flags &= ~NODE_FLAGS_SET_SIZE;
616dc20a302Sas 				bzero(&new_attr, sizeof (new_attr));
617da6c28aaSamw 				new_attr.sa_vattr.va_size = op->dsize;
618da6c28aaSamw 				new_attr.sa_mask = SMB_AT_SIZE;
619dc20a302Sas 
620dc20a302Sas 				rc = smb_fsop_setattr(sr, sr->user_cr,
621dc20a302Sas 				    node, &new_attr, &op->fqi.last_attr);
622dc20a302Sas 
623dc20a302Sas 				if (rc) {
624faa1795aSjb 					smb_fsop_unshrlock(sr->user_cr, node,
625faa1795aSjb 					    uniq_fid);
626*2c2961f8Sjose borrego 					smb_node_unlock(node);
627da6c28aaSamw 					smb_node_release(node);
628da6c28aaSamw 					smb_node_release(dnode);
629da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
630dc20a302Sas 					smbsr_errno(sr, rc);
6317b59d02dSjb 					return (sr->smb_error.status);
632da6c28aaSamw 				}
633da6c28aaSamw 
634dc20a302Sas 				op->dsize = op->fqi.last_attr.sa_vattr.va_size;
635da6c28aaSamw 			}
636da6c28aaSamw 
6372c1b14e5Sjose borrego 			op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
6382c1b14e5Sjose borrego 			if (op->dattr & FILE_ATTRIBUTE_READONLY) {
6392c1b14e5Sjose borrego 				op->created_readonly = B_TRUE;
6402c1b14e5Sjose borrego 				op->dattr &= ~FILE_ATTRIBUTE_READONLY;
6412c1b14e5Sjose borrego 			}
6422c1b14e5Sjose borrego 
6432c1b14e5Sjose borrego 			smb_node_set_dosattr(node, op->dattr);
6442c1b14e5Sjose borrego 			(void) smb_sync_fsattr(sr, sr->user_cr, node);
6452c1b14e5Sjose borrego 
646da6c28aaSamw 			/*
647da6c28aaSamw 			 * If file is being replaced,
648da6c28aaSamw 			 * we should remove existing streams
649da6c28aaSamw 			 */
650da6c28aaSamw 			if (SMB_IS_STREAM(node) == 0)
651da6c28aaSamw 				(void) smb_fsop_remove_streams(sr, sr->user_cr,
652da6c28aaSamw 				    node);
653da6c28aaSamw 
654da6c28aaSamw 			op->action_taken = SMB_OACT_TRUNCATED;
655da6c28aaSamw 			break;
656da6c28aaSamw 
657da6c28aaSamw 		default:
658da6c28aaSamw 			/*
659da6c28aaSamw 			 * FILE_OPEN or FILE_OPEN_IF.
660da6c28aaSamw 			 */
661da6c28aaSamw 			op->action_taken = SMB_OACT_OPENED;
662da6c28aaSamw 			break;
663da6c28aaSamw 		}
664da6c28aaSamw 	} else {
665da6c28aaSamw 		/* Last component was not found. */
666da6c28aaSamw 		dnode = op->fqi.dir_snode;
667da6c28aaSamw 
6687b59d02dSjb 		if (is_dir == 0)
6698d7e4166Sjose borrego 			is_stream = smb_is_stream_name(op->fqi.path);
6707b59d02dSjb 
671da6c28aaSamw 		if ((op->create_disposition == FILE_OPEN) ||
672da6c28aaSamw 		    (op->create_disposition == FILE_OVERWRITE)) {
673da6c28aaSamw 			smb_node_release(dnode);
674da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
675faa1795aSjb 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
676faa1795aSjb 			    ERRDOS, ERROR_FILE_NOT_FOUND);
6777b59d02dSjb 			return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
678da6c28aaSamw 		}
679da6c28aaSamw 
680*2c2961f8Sjose borrego 		if ((is_dir == 0) && (!is_stream) &&
681*2c2961f8Sjose borrego 		    smb_is_invalid_filename(op->fqi.last_comp)) {
682*2c2961f8Sjose borrego 			smb_node_release(dnode);
683*2c2961f8Sjose borrego 			SMB_NULL_FQI_NODES(op->fqi);
684*2c2961f8Sjose borrego 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
685*2c2961f8Sjose borrego 			    ERRDOS, ERROR_INVALID_NAME);
686*2c2961f8Sjose borrego 			return (NT_STATUS_OBJECT_NAME_INVALID);
687*2c2961f8Sjose borrego 		}
688*2c2961f8Sjose borrego 
689da6c28aaSamw 		/*
690da6c28aaSamw 		 * lock the parent dir node in case another create
691da6c28aaSamw 		 * request to the same parent directory comes in.
692da6c28aaSamw 		 */
693*2c2961f8Sjose borrego 		smb_node_wrlock(dnode);
694da6c28aaSamw 
695da6c28aaSamw 		bzero(&new_attr, sizeof (new_attr));
6962c1b14e5Sjose borrego 		new_attr.sa_dosattr = op->dattr;
6972c1b14e5Sjose borrego 		new_attr.sa_mask |= SMB_AT_DOSATTR;
698c8ec8eeaSjose borrego 
699c8ec8eeaSjose borrego 		/*
700c8ec8eeaSjose borrego 		 * A file created with the readonly bit should not
701c8ec8eeaSjose borrego 		 * stop the creator writing to the file until it is
702c8ec8eeaSjose borrego 		 * closed.  Although the readonly bit will not be set
703c8ec8eeaSjose borrego 		 * on the file until it is closed, it will be accounted
704c8ec8eeaSjose borrego 		 * for on other fids and on queries based on the node
705c8ec8eeaSjose borrego 		 * state.
706c8ec8eeaSjose borrego 		 */
7072c1b14e5Sjose borrego 		if (op->dattr & FILE_ATTRIBUTE_READONLY)
7082c1b14e5Sjose borrego 			new_attr.sa_dosattr &= ~FILE_ATTRIBUTE_READONLY;
709c8ec8eeaSjose borrego 
710c8ec8eeaSjose borrego 
711c8ec8eeaSjose borrego 		if ((op->crtime.tv_sec != 0) &&
712c8ec8eeaSjose borrego 		    (op->crtime.tv_sec != UINT_MAX)) {
713c8ec8eeaSjose borrego 
714c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_CRTIME;
715c8ec8eeaSjose borrego 			new_attr.sa_crtime = op->crtime;
716c8ec8eeaSjose borrego 		}
717c8ec8eeaSjose borrego 
718da6c28aaSamw 		if (is_dir == 0) {
7192c1b14e5Sjose borrego 			new_attr.sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
720da6c28aaSamw 			new_attr.sa_vattr.va_type = VREG;
7217b59d02dSjb 			new_attr.sa_vattr.va_mode = is_stream ? S_IRUSR :
7227b59d02dSjb 			    S_IRUSR | S_IRGRP | S_IROTH |
7237b59d02dSjb 			    S_IWUSR | S_IWGRP | S_IWOTH;
724c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
725dc20a302Sas 
7266537f381Sas 			if (op->dsize) {
7276537f381Sas 				new_attr.sa_vattr.va_size = op->dsize;
7286537f381Sas 				new_attr.sa_mask |= SMB_AT_SIZE;
729dc20a302Sas 			}
730dc20a302Sas 
731da6c28aaSamw 			rc = smb_fsop_create(sr, sr->user_cr, dnode,
732da6c28aaSamw 			    op->fqi.last_comp, &new_attr,
733da6c28aaSamw 			    &op->fqi.last_snode, &op->fqi.last_attr);
734dc20a302Sas 
735da6c28aaSamw 			if (rc != 0) {
736*2c2961f8Sjose borrego 				smb_node_unlock(dnode);
737da6c28aaSamw 				smb_node_release(dnode);
738da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
739dc20a302Sas 				smbsr_errno(sr, rc);
7407b59d02dSjb 				return (sr->smb_error.status);
741da6c28aaSamw 			}
742da6c28aaSamw 
743dc20a302Sas 			node = op->fqi.last_snode;
744dc20a302Sas 
745c8ec8eeaSjose borrego 			op->fqi.last_attr = node->attr;
746c8ec8eeaSjose borrego 
747*2c2961f8Sjose borrego 			smb_node_wrlock(node);
748dc20a302Sas 
749faa1795aSjb 			status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
750c8ec8eeaSjose borrego 			    op->desired_access, op->share_access);
751dc20a302Sas 
752dc20a302Sas 			if (status == NT_STATUS_SHARING_VIOLATION) {
753*2c2961f8Sjose borrego 				smb_node_unlock(node);
754c8ec8eeaSjose borrego 				SMB_DEL_NEWOBJ(op->fqi);
755dc20a302Sas 				smb_node_release(node);
756*2c2961f8Sjose borrego 				smb_node_unlock(dnode);
757dc20a302Sas 				smb_node_release(dnode);
758dc20a302Sas 				SMB_NULL_FQI_NODES(op->fqi);
759dc20a302Sas 				return (status);
760dc20a302Sas 			}
761da6c28aaSamw 		} else {
7623db3f65cSamw 			op->dattr |= FILE_ATTRIBUTE_DIRECTORY;
763da6c28aaSamw 			new_attr.sa_vattr.va_type = VDIR;
764da6c28aaSamw 			new_attr.sa_vattr.va_mode = 0777;
765c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
766c8ec8eeaSjose borrego 
767da6c28aaSamw 			rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
768da6c28aaSamw 			    op->fqi.last_comp, &new_attr,
769da6c28aaSamw 			    &op->fqi.last_snode, &op->fqi.last_attr);
770da6c28aaSamw 			if (rc != 0) {
771*2c2961f8Sjose borrego 				smb_node_unlock(dnode);
772da6c28aaSamw 				smb_node_release(dnode);
773da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
774dc20a302Sas 				smbsr_errno(sr, rc);
7757b59d02dSjb 				return (sr->smb_error.status);
776da6c28aaSamw 			}
777dc20a302Sas 
778dc20a302Sas 			node = op->fqi.last_snode;
779*2c2961f8Sjose borrego 			smb_node_wrlock(node);
780da6c28aaSamw 		}
781da6c28aaSamw 
782da6c28aaSamw 		created = 1;
783da6c28aaSamw 		op->action_taken = SMB_OACT_CREATED;
784c8ec8eeaSjose borrego 		node->flags |= NODE_FLAGS_CREATED;
785c8ec8eeaSjose borrego 
786c8ec8eeaSjose borrego 		if (op->dattr & FILE_ATTRIBUTE_READONLY) {
787c8ec8eeaSjose borrego 			op->created_readonly = B_TRUE;
788c8ec8eeaSjose borrego 			op->dattr &= ~FILE_ATTRIBUTE_READONLY;
789c8ec8eeaSjose borrego 		}
7902c1b14e5Sjose borrego 	}
791c8ec8eeaSjose borrego 
7922c1b14e5Sjose borrego 	op->dattr = smb_node_get_dosattr(node);
793c8ec8eeaSjose borrego 
7942c1b14e5Sjose borrego 	if (max_requested) {
7952c1b14e5Sjose borrego 		smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed);
7962c1b14e5Sjose borrego 		op->desired_access |= max_allowed;
797c8ec8eeaSjose borrego 	}
798c8ec8eeaSjose borrego 
7992c1b14e5Sjose borrego 	/*
8002c1b14e5Sjose borrego 	 * if last_write time was in request and is not 0 or -1,
8012c1b14e5Sjose borrego 	 * use it as file's mtime
8022c1b14e5Sjose borrego 	 */
8032c1b14e5Sjose borrego 	if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) {
8042c1b14e5Sjose borrego 		smb_node_set_time(node, NULL, &op->mtime, NULL, NULL,
8052c1b14e5Sjose borrego 		    SMB_AT_MTIME);
8062c1b14e5Sjose borrego 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
8072c1b14e5Sjose borrego 	}
808c8ec8eeaSjose borrego 
809da6c28aaSamw 	/*
810da6c28aaSamw 	 * smb_ofile_open() will copy node to of->node.  Hence
811da6c28aaSamw 	 * the hold on node (i.e. op->fqi.last_snode) will be "transferred"
812da6c28aaSamw 	 * to the "of" structure.
813da6c28aaSamw 	 */
814da6c28aaSamw 
815c8ec8eeaSjose borrego 	of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op, SMB_FTYPE_DISK,
816c8ec8eeaSjose borrego 	    uniq_fid, &err);
817da6c28aaSamw 
818da6c28aaSamw 	if (of == NULL) {
819dc20a302Sas 		smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
820dc20a302Sas 
821da6c28aaSamw 		SMB_DEL_NEWOBJ(op->fqi);
822*2c2961f8Sjose borrego 		smb_node_unlock(node);
823da6c28aaSamw 		smb_node_release(node);
824da6c28aaSamw 		if (created)
825*2c2961f8Sjose borrego 			smb_node_unlock(dnode);
826da6c28aaSamw 		smb_node_release(dnode);
827da6c28aaSamw 		SMB_NULL_FQI_NODES(op->fqi);
828dc20a302Sas 		smbsr_error(sr, err.status, err.errcls, err.errcode);
8297b59d02dSjb 		return (err.status);
830da6c28aaSamw 	}
831da6c28aaSamw 
8328c10a865Sas 	/*
8338c10a865Sas 	 * Propagate the write-through mode from the open params
8348c10a865Sas 	 * to the node: see the notes in the function header.
8358c10a865Sas 	 */
8368c10a865Sas 	if (sr->sr_cfg->skc_sync_enable ||
8378c10a865Sas 	    (op->create_options & FILE_WRITE_THROUGH))
8388c10a865Sas 		node->flags |= NODE_FLAGS_WRITE_THROUGH;
8398c10a865Sas 
8408c10a865Sas 	op->fileid = op->fqi.last_attr.sa_vattr.va_nodeid;
8418c10a865Sas 
842da6c28aaSamw 	/*
843da6c28aaSamw 	 * Set up the file type in open_param for the response
844da6c28aaSamw 	 */
845da6c28aaSamw 	op->ftype = SMB_FTYPE_DISK;
846da6c28aaSamw 	sr->smb_fid = of->f_fid;
847da6c28aaSamw 	sr->fid_ofile = of;
848da6c28aaSamw 
849*2c2961f8Sjose borrego 	smb_node_unlock(node);
850dc20a302Sas 
851dc20a302Sas 	if (created)
852*2c2961f8Sjose borrego 		smb_node_unlock(dnode);
853*2c2961f8Sjose borrego 
854*2c2961f8Sjose borrego 	if (op->fqi.last_attr.sa_vattr.va_type == VREG) {
855*2c2961f8Sjose borrego 		smb_oplock_acquire(node, of, op);
856*2c2961f8Sjose borrego 		op->dsize = op->fqi.last_attr.sa_vattr.va_size;
857*2c2961f8Sjose borrego 	} else { /* VDIR or VLNK */
858*2c2961f8Sjose borrego 		op->op_oplock_level = SMB_OPLOCK_NONE;
859*2c2961f8Sjose borrego 		op->dsize = 0;
860*2c2961f8Sjose borrego 	}
861dc20a302Sas 
862da6c28aaSamw 	smb_node_release(dnode);
863da6c28aaSamw 	SMB_NULL_FQI_NODES(op->fqi);
864da6c28aaSamw 
865da6c28aaSamw 	return (NT_STATUS_SUCCESS);
866da6c28aaSamw }
867da6c28aaSamw 
868da6c28aaSamw /*
869da6c28aaSamw  * smb_validate_object_name
870da6c28aaSamw  *
8718d7e4166Sjose borrego  * Very basic file name validation.
8728d7e4166Sjose borrego  * Directory validation is handed off to smb_validate_dirname.
8738d7e4166Sjose borrego  * For filenames, we check for names of the form "AAAn:". Names that
8748d7e4166Sjose borrego  * contain three characters, a single digit and a colon (:) are reserved
8758d7e4166Sjose borrego  * as DOS device names, i.e. "COM1:".
8768d7e4166Sjose borrego  * Stream name validation is handed off to smb_validate_stream_name
877da6c28aaSamw  *
878da6c28aaSamw  * Returns NT status codes.
879da6c28aaSamw  */
880da6c28aaSamw uint32_t
881da6c28aaSamw smb_validate_object_name(char *path, unsigned int ftype)
882da6c28aaSamw {
883da6c28aaSamw 	char *filename;
884da6c28aaSamw 
885da6c28aaSamw 	if (path == 0)
886da6c28aaSamw 		return (0);
887da6c28aaSamw 
888da6c28aaSamw 	if (ftype)
889da6c28aaSamw 		return (smb_validate_dirname(path));
890da6c28aaSamw 
891da6c28aaSamw 	/*
892da6c28aaSamw 	 * Basename with backslashes.
893da6c28aaSamw 	 */
894da6c28aaSamw 	if ((filename = strrchr(path, '\\')) != 0)
895da6c28aaSamw 		++filename;
896da6c28aaSamw 	else
897da6c28aaSamw 		filename = path;
898da6c28aaSamw 
899da6c28aaSamw 	if (strlen(filename) == 5 &&
900da6c28aaSamw 	    mts_isdigit(filename[3]) &&
901da6c28aaSamw 	    filename[4] == ':') {
902da6c28aaSamw 		return (NT_STATUS_OBJECT_NAME_INVALID);
903da6c28aaSamw 	}
904da6c28aaSamw 
9058d7e4166Sjose borrego 	if (smb_is_stream_name(path))
9068d7e4166Sjose borrego 		return (smb_validate_stream_name(path));
9078d7e4166Sjose borrego 
908da6c28aaSamw 	return (0);
909da6c28aaSamw }
910da6c28aaSamw 
911da6c28aaSamw /*
912da6c28aaSamw  * smb_preset_delete_on_close
913da6c28aaSamw  *
914da6c28aaSamw  * Set the DeleteOnClose flag on the smb file. When the file is closed,
915da6c28aaSamw  * the flag will be transferred to the smb node, which will commit the
916da6c28aaSamw  * delete operation and inhibit subsequent open requests.
917da6c28aaSamw  *
918da6c28aaSamw  * When DeleteOnClose is set on an smb_node, the common open code will
919da6c28aaSamw  * reject subsequent open requests for the file. Observation of Windows
920da6c28aaSamw  * 2000 indicates that subsequent opens should be allowed (assuming
921da6c28aaSamw  * there would be no sharing violation) until the file is closed using
922da6c28aaSamw  * the fid on which the DeleteOnClose was requested.
923da6c28aaSamw  */
924da6c28aaSamw void
925da6c28aaSamw smb_preset_delete_on_close(smb_ofile_t *file)
926da6c28aaSamw {
927da6c28aaSamw 	mutex_enter(&file->f_mutex);
928da6c28aaSamw 	file->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
929da6c28aaSamw 	mutex_exit(&file->f_mutex);
930da6c28aaSamw }
931