xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_common_open.c (revision 2c1b14e51525da2c09064641416fc4aed457c72f)
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 /*
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/mlsvc.h>
34da6c28aaSamw #include <smbsrv/nterror.h>
35da6c28aaSamw #include <smbsrv/ntstatus.h>
36da6c28aaSamw #include <smbsrv/smbinfo.h>
37da6c28aaSamw #include <sys/fcntl.h>
38dc20a302Sas200622 #include <sys/nbmlock.h>
39da6c28aaSamw 
40faa1795aSjb150015 volatile uint32_t smb_fids = 0;
417b59d02dSjb150015 
427b59d02dSjb150015 static uint32_t smb_open_subr(smb_request_t *);
43da6c28aaSamw 
44faa1795aSjb150015 extern uint32_t smb_is_executable(char *);
45da6c28aaSamw 
46da6c28aaSamw /*
47da6c28aaSamw  * This macro is used to delete a newly created object
48da6c28aaSamw  * if any error happens after creation of object.
49da6c28aaSamw  */
50da6c28aaSamw #define	SMB_DEL_NEWOBJ(obj) \
51da6c28aaSamw 	if (created) {							\
52da6c28aaSamw 		if (is_dir)						\
53da6c28aaSamw 			(void) smb_fsop_rmdir(sr, sr->user_cr,		\
54da6c28aaSamw 			    obj.dir_snode, obj.last_comp, 0);		\
55da6c28aaSamw 		else							\
56da6c28aaSamw 			(void) smb_fsop_remove(sr, sr->user_cr,		\
57da6c28aaSamw 			    obj.dir_snode, obj.last_comp, 0);		\
58da6c28aaSamw 	}
59da6c28aaSamw 
60da6c28aaSamw /*
61da6c28aaSamw  * smb_access_generic_to_file
62da6c28aaSamw  *
63da6c28aaSamw  * Search MSDN for IoCreateFile to see following mapping.
64da6c28aaSamw  *
65da6c28aaSamw  * GENERIC_READ		STANDARD_RIGHTS_READ, FILE_READ_DATA,
66da6c28aaSamw  *			FILE_READ_ATTRIBUTES and FILE_READ_EA
67da6c28aaSamw  *
68da6c28aaSamw  * GENERIC_WRITE	STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA,
69da6c28aaSamw  *               FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
70da6c28aaSamw  *
71da6c28aaSamw  * GENERIC_EXECUTE	STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE.
72da6c28aaSamw  */
73da6c28aaSamw uint32_t
74da6c28aaSamw smb_access_generic_to_file(uint32_t desired_access)
75da6c28aaSamw {
76da6c28aaSamw 	uint32_t access = 0;
77da6c28aaSamw 
78da6c28aaSamw 	if (desired_access & GENERIC_ALL)
79da6c28aaSamw 		return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
80da6c28aaSamw 
81da6c28aaSamw 	if (desired_access & GENERIC_EXECUTE) {
82da6c28aaSamw 		desired_access &= ~GENERIC_EXECUTE;
83da6c28aaSamw 		access |= (STANDARD_RIGHTS_EXECUTE |
84da6c28aaSamw 		    SYNCHRONIZE | FILE_EXECUTE);
85da6c28aaSamw 	}
86da6c28aaSamw 
87da6c28aaSamw 	if (desired_access & GENERIC_WRITE) {
88da6c28aaSamw 		desired_access &= ~GENERIC_WRITE;
89da6c28aaSamw 		access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE);
90da6c28aaSamw 	}
91da6c28aaSamw 
92da6c28aaSamw 	if (desired_access & GENERIC_READ) {
93da6c28aaSamw 		desired_access &= ~GENERIC_READ;
94da6c28aaSamw 		access |= FILE_GENERIC_READ;
95da6c28aaSamw 	}
96da6c28aaSamw 
97da6c28aaSamw 	return (access | desired_access);
98da6c28aaSamw }
99da6c28aaSamw 
100da6c28aaSamw /*
101da6c28aaSamw  * smb_omode_to_amask
102da6c28aaSamw  *
103da6c28aaSamw  * This function converts open modes used by Open and Open AndX
104da6c28aaSamw  * commands to desired access bits used by NT Create AndX command.
105da6c28aaSamw  */
106da6c28aaSamw uint32_t
107da6c28aaSamw smb_omode_to_amask(uint32_t desired_access)
108da6c28aaSamw {
109da6c28aaSamw 	switch (desired_access & SMB_DA_ACCESS_MASK) {
110da6c28aaSamw 	case SMB_DA_ACCESS_READ:
111da6c28aaSamw 		return (FILE_GENERIC_READ);
112da6c28aaSamw 
113da6c28aaSamw 	case SMB_DA_ACCESS_WRITE:
114da6c28aaSamw 		return (FILE_GENERIC_WRITE);
115da6c28aaSamw 
116da6c28aaSamw 	case SMB_DA_ACCESS_READ_WRITE:
117da6c28aaSamw 		return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
118da6c28aaSamw 
119da6c28aaSamw 	case SMB_DA_ACCESS_EXECUTE:
120da6c28aaSamw 		return (FILE_GENERIC_EXECUTE);
121da6c28aaSamw 	}
122da6c28aaSamw 
123da6c28aaSamw 	/* invalid open mode */
124da6c28aaSamw 	return ((uint32_t)SMB_INVALID_AMASK);
125da6c28aaSamw }
126da6c28aaSamw 
127da6c28aaSamw /*
128da6c28aaSamw  * smb_denymode_to_sharemode
129da6c28aaSamw  *
130da6c28aaSamw  * This function converts deny modes used by Open and Open AndX
131da6c28aaSamw  * commands to share access bits used by NT Create AndX command.
132da6c28aaSamw  */
133da6c28aaSamw uint32_t
134da6c28aaSamw smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
135da6c28aaSamw {
136da6c28aaSamw 	switch (desired_access & SMB_DA_SHARE_MASK) {
137da6c28aaSamw 	case SMB_DA_SHARE_COMPATIBILITY:
138da6c28aaSamw 		if (smb_is_executable(fname))
139da6c28aaSamw 			return (FILE_SHARE_READ | FILE_SHARE_WRITE);
140c8ec8eeaSjose borrego 
141c8ec8eeaSjose borrego 		return (FILE_SHARE_ALL);
142da6c28aaSamw 
143da6c28aaSamw 	case SMB_DA_SHARE_EXCLUSIVE:
144da6c28aaSamw 		return (FILE_SHARE_NONE);
145da6c28aaSamw 
146da6c28aaSamw 	case SMB_DA_SHARE_DENY_WRITE:
147da6c28aaSamw 		return (FILE_SHARE_READ);
148da6c28aaSamw 
149da6c28aaSamw 	case SMB_DA_SHARE_DENY_READ:
150da6c28aaSamw 		return (FILE_SHARE_WRITE);
151da6c28aaSamw 
152da6c28aaSamw 	case SMB_DA_SHARE_DENY_NONE:
153da6c28aaSamw 		return (FILE_SHARE_READ | FILE_SHARE_WRITE);
154da6c28aaSamw 	}
155da6c28aaSamw 
156da6c28aaSamw 	/* invalid deny mode */
157da6c28aaSamw 	return ((uint32_t)SMB_INVALID_SHAREMODE);
158da6c28aaSamw }
159da6c28aaSamw 
160da6c28aaSamw /*
161da6c28aaSamw  * smb_ofun_to_crdisposition
162da6c28aaSamw  *
163da6c28aaSamw  * This function converts open function values used by Open and Open AndX
164da6c28aaSamw  * commands to create disposition values used by NT Create AndX command.
165da6c28aaSamw  */
166da6c28aaSamw uint32_t
167da6c28aaSamw smb_ofun_to_crdisposition(uint16_t  ofun)
168da6c28aaSamw {
169da6c28aaSamw 	static int ofun_cr_map[3][2] =
170da6c28aaSamw 	{
171da6c28aaSamw 		{ -1,			FILE_CREATE },
172da6c28aaSamw 		{ FILE_OPEN,		FILE_OPEN_IF },
173da6c28aaSamw 		{ FILE_OVERWRITE,	FILE_OVERWRITE_IF }
174da6c28aaSamw 	};
175da6c28aaSamw 
176da6c28aaSamw 	int row = ofun & SMB_OFUN_OPEN_MASK;
177da6c28aaSamw 	int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
178da6c28aaSamw 
179da6c28aaSamw 	if (row == 3)
180da6c28aaSamw 		return ((uint32_t)SMB_INVALID_CRDISPOSITION);
181da6c28aaSamw 
182da6c28aaSamw 	return (ofun_cr_map[row][col]);
183da6c28aaSamw }
184da6c28aaSamw 
185da6c28aaSamw /*
1867b59d02dSjb150015  * Retry opens to avoid spurious sharing violations, due to timing
1877b59d02dSjb150015  * issues between closes and opens.  The client that already has the
1887b59d02dSjb150015  * file open may be in the process of closing it.
1897b59d02dSjb150015  */
1907b59d02dSjb150015 uint32_t
1917b59d02dSjb150015 smb_common_open(smb_request_t *sr)
1927b59d02dSjb150015 {
1937b59d02dSjb150015 	uint32_t status = NT_STATUS_SUCCESS;
1947b59d02dSjb150015 	int count;
1957b59d02dSjb150015 
1967b59d02dSjb150015 	for (count = 0; count <= 4; count++) {
1977b59d02dSjb150015 		if (count)
1987b59d02dSjb150015 			delay(MSEC_TO_TICK(400));
1997b59d02dSjb150015 
200faa1795aSjb150015 		status = smb_open_subr(sr);
201faa1795aSjb150015 		if (status != NT_STATUS_SHARING_VIOLATION)
2027b59d02dSjb150015 			break;
2037b59d02dSjb150015 	}
2047b59d02dSjb150015 
205faa1795aSjb150015 	if (status == NT_STATUS_SHARING_VIOLATION) {
2067b59d02dSjb150015 		smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
2077b59d02dSjb150015 		    ERRDOS, ERROR_SHARING_VIOLATION);
2087b59d02dSjb150015 	}
2097b59d02dSjb150015 
2107b59d02dSjb150015 	return (status);
2117b59d02dSjb150015 }
2127b59d02dSjb150015 
2137b59d02dSjb150015 /*
214da6c28aaSamw  * smb_open_subr
215da6c28aaSamw  *
216da6c28aaSamw  * Notes on write-through behaviour. It looks like pre-LM0.12 versions
217da6c28aaSamw  * of the protocol specify the write-through mode when a file is opened,
218da6c28aaSamw  * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose,
219da6c28aaSamw  * SmbWriteAndUnlock) don't need to contain a write-through flag.
220da6c28aaSamw  *
221da6c28aaSamw  * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate)
222da6c28aaSamw  * don't indicate which write-through mode to use. Instead the write
223da6c28aaSamw  * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call
224da6c28aaSamw  * basis.
225da6c28aaSamw  *
226da6c28aaSamw  * We don't care which open call was used to get us here, we just need
227da6c28aaSamw  * to ensure that the write-through mode flag is copied from the open
228da6c28aaSamw  * parameters to the node. We test the omode write-through flag in all
229da6c28aaSamw  * write functions.
230da6c28aaSamw  *
231da6c28aaSamw  * This function will return NT status codes but it also raises errors,
232da6c28aaSamw  * in which case it won't return to the caller. Be careful how you
233da6c28aaSamw  * handle things in here.
2348c10a865Sas200622  *
2358c10a865Sas200622  * The following rules apply when processing a file open request:
2368c10a865Sas200622  *
2378c10a865Sas200622  * - Oplocks must be broken prior to share checking to prevent open
2388c10a865Sas200622  * starvation due to batch oplocks.  Checking share reservations first
2398c10a865Sas200622  * could potentially result in unnecessary open failures due to
2408c10a865Sas200622  * open/close batching on the client.
2418c10a865Sas200622  *
2428c10a865Sas200622  * - Share checks must take place prior to access checks for correct
2438c10a865Sas200622  * Windows semantics and to prevent unnecessary NFS delegation recalls.
2448c10a865Sas200622  *
2458c10a865Sas200622  * - Oplocks must be acquired after open to ensure the correct
2468c10a865Sas200622  * synchronization with NFS delegation and FEM installation.
247c8ec8eeaSjose borrego  *
248c8ec8eeaSjose borrego  *
249c8ec8eeaSjose borrego  * DOS readonly bit rules
250c8ec8eeaSjose borrego  *
251c8ec8eeaSjose borrego  * 1. The creator of a readonly file can write to/modify the size of the file
252c8ec8eeaSjose borrego  * using the original create fid, even though the file will appear as readonly
253c8ec8eeaSjose borrego  * to all other fids and via a CIFS getattr call.
254c8ec8eeaSjose borrego  *
255c8ec8eeaSjose borrego  * 2. A setinfo operation (using either an open fid or a path) to set/unset
256c8ec8eeaSjose borrego  * readonly will be successful regardless of whether a creator of a readonly
257c8ec8eeaSjose borrego  * file has an open fid (and has the special privilege mentioned in #1,
258c8ec8eeaSjose borrego  * above).  I.e., the creator of a readonly fid holding that fid will no longer
259c8ec8eeaSjose borrego  * have a special privilege.
260c8ec8eeaSjose borrego  *
261c8ec8eeaSjose borrego  * 3. The DOS readonly bit affects only data and some metadata.
262c8ec8eeaSjose borrego  * The following metadata can be changed regardless of the readonly bit:
263c8ec8eeaSjose borrego  * 	- security descriptors
264c8ec8eeaSjose borrego  *	- DOS attributes
265c8ec8eeaSjose borrego  *	- timestamps
266c8ec8eeaSjose borrego  *
267c8ec8eeaSjose borrego  * In the current implementation, the file size cannot be changed (except for
268c8ec8eeaSjose borrego  * the exceptions in #1 and #2, above).
269*2c1b14e5Sjose borrego  *
270*2c1b14e5Sjose borrego  *
271*2c1b14e5Sjose borrego  * DOS attribute rules
272*2c1b14e5Sjose borrego  *
273*2c1b14e5Sjose borrego  * These rules are specific to creating / opening files and directories.
274*2c1b14e5Sjose borrego  * How the attribute value (specifically ZERO or FILE_ATTRIBUTE_NORMAL)
275*2c1b14e5Sjose borrego  * should be interpreted may differ in other requests.
276*2c1b14e5Sjose borrego  *
277*2c1b14e5Sjose borrego  * - An attribute value equal to ZERO or FILE_ATTRIBUTE_NORMAL means that the
278*2c1b14e5Sjose borrego  *   file's attributes should be cleared.
279*2c1b14e5Sjose borrego  * - If FILE_ATTRIBUTE_NORMAL is specified with any other attributes,
280*2c1b14e5Sjose borrego  *   FILE_ATTRIBUTE_NORMAL is ignored.
281*2c1b14e5Sjose borrego  *
282*2c1b14e5Sjose borrego  * 1. Creating a new file
283*2c1b14e5Sjose borrego  * - The request attributes + FILE_ATTRIBUTE_ARCHIVE are applied to the file.
284*2c1b14e5Sjose borrego  *
285*2c1b14e5Sjose borrego  * 2. Creating a new directory
286*2c1b14e5Sjose borrego  * - The request attributes + FILE_ATTRIBUTE_DIRECTORY are applied to the file.
287*2c1b14e5Sjose borrego  * - FILE_ATTRIBUTE_ARCHIVE does not get set.
288*2c1b14e5Sjose borrego  *
289*2c1b14e5Sjose borrego  * 3. Overwriting an existing file
290*2c1b14e5Sjose borrego  * - the request attributes are used as search attributes. If the existing
291*2c1b14e5Sjose borrego  *   file does not meet the search criteria access is denied.
292*2c1b14e5Sjose borrego  * - otherwise, applies attributes + FILE_ATTRIBUTE_ARCHIVE.
293*2c1b14e5Sjose borrego  *
294*2c1b14e5Sjose borrego  * 4. Opening an existing file or directory
295*2c1b14e5Sjose borrego  *    The request attributes are ignored.
296da6c28aaSamw  */
297dc20a302Sas200622 
2987b59d02dSjb150015 static uint32_t
2997b59d02dSjb150015 smb_open_subr(smb_request_t *sr)
300da6c28aaSamw {
301da6c28aaSamw 	int			created = 0;
302da6c28aaSamw 	struct smb_node		*node = 0;
303da6c28aaSamw 	struct smb_node		*dnode = 0;
304da6c28aaSamw 	struct smb_node		*cur_node;
305da6c28aaSamw 	struct open_param	*op = &sr->arg.open;
306da6c28aaSamw 	int			rc;
307da6c28aaSamw 	struct smb_ofile	*of;
308da6c28aaSamw 	smb_attr_t		new_attr;
309da6c28aaSamw 	int			pathlen;
310da6c28aaSamw 	int			max_requested = 0;
311da6c28aaSamw 	uint32_t		max_allowed;
312da6c28aaSamw 	uint32_t		status = NT_STATUS_SUCCESS;
313da6c28aaSamw 	int			is_dir;
314da6c28aaSamw 	smb_error_t		err;
3157b59d02dSjb150015 	int			is_stream = 0;
316da6c28aaSamw 	int			lookup_flags = SMB_FOLLOW_LINKS;
317da6c28aaSamw 	uint32_t		daccess;
318dc20a302Sas200622 	uint32_t		uniq_fid;
319da6c28aaSamw 
320da6c28aaSamw 	is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
321da6c28aaSamw 
322da6c28aaSamw 	if (is_dir) {
323da6c28aaSamw 		/*
3247b59d02dSjb150015 		 * The object being created or opened is a directory,
3257b59d02dSjb150015 		 * and the Disposition parameter must be one of
3267b59d02dSjb150015 		 * FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF
327da6c28aaSamw 		 */
328da6c28aaSamw 		if ((op->create_disposition != FILE_CREATE) &&
329da6c28aaSamw 		    (op->create_disposition != FILE_OPEN_IF) &&
330da6c28aaSamw 		    (op->create_disposition != FILE_OPEN)) {
331dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
332da6c28aaSamw 			    ERRDOS, ERROR_INVALID_ACCESS);
3337b59d02dSjb150015 			return (NT_STATUS_INVALID_PARAMETER);
334da6c28aaSamw 		}
335da6c28aaSamw 	}
336da6c28aaSamw 
337da6c28aaSamw 	if (op->desired_access & MAXIMUM_ALLOWED) {
338da6c28aaSamw 		max_requested = 1;
339da6c28aaSamw 		op->desired_access &= ~MAXIMUM_ALLOWED;
340da6c28aaSamw 	}
341da6c28aaSamw 	op->desired_access = smb_access_generic_to_file(op->desired_access);
342da6c28aaSamw 
343da6c28aaSamw 	if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) {
344da6c28aaSamw 		ASSERT(sr->uid_user);
345da6c28aaSamw 		cmn_err(CE_NOTE, "smbd[%s\\%s]: %s", sr->uid_user->u_domain,
346da6c28aaSamw 		    sr->uid_user->u_name,
347da6c28aaSamw 		    xlate_nt_status(NT_STATUS_TOO_MANY_OPENED_FILES));
348da6c28aaSamw 
349dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
350da6c28aaSamw 		    ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
3517b59d02dSjb150015 		return (NT_STATUS_TOO_MANY_OPENED_FILES);
352da6c28aaSamw 	}
353da6c28aaSamw 
354da6c28aaSamw 	/* This must be NULL at this point */
355da6c28aaSamw 	sr->fid_ofile = NULL;
356da6c28aaSamw 
357da6c28aaSamw 	op->devstate = 0;
358da6c28aaSamw 
359da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
360da6c28aaSamw 	case STYPE_DISKTREE:
361da6c28aaSamw 		break;
362da6c28aaSamw 
363da6c28aaSamw 	case STYPE_IPC:
364da6c28aaSamw 		/*
365da6c28aaSamw 		 * No further processing for IPC, we need to either
366da6c28aaSamw 		 * raise an exception or return success here.
367da6c28aaSamw 		 */
3683db3f65cSamw 		if ((status = smb_opipe_open(sr)) != NT_STATUS_SUCCESS)
3697b59d02dSjb150015 			smbsr_error(sr, status, 0, 0);
3707b59d02dSjb150015 		return (status);
371da6c28aaSamw 
372da6c28aaSamw 	default:
3737b59d02dSjb150015 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
3747b59d02dSjb150015 		    ERRDOS, ERROR_BAD_DEV_TYPE);
3757b59d02dSjb150015 		return (NT_STATUS_BAD_DEVICE_TYPE);
376da6c28aaSamw 	}
377da6c28aaSamw 
378da6c28aaSamw 	if ((pathlen = strlen(op->fqi.path)) >= MAXPATHLEN) {
379dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRfilespecs);
3807b59d02dSjb150015 		return (NT_STATUS_NAME_TOO_LONG);
381da6c28aaSamw 	}
382da6c28aaSamw 
383da6c28aaSamw 	/*
384da6c28aaSamw 	 * Some clients pass null file names; NT interprets this as "\".
385da6c28aaSamw 	 */
386da6c28aaSamw 	if (pathlen == 0) {
387da6c28aaSamw 		op->fqi.path = "\\";
388da6c28aaSamw 		pathlen = 1;
389da6c28aaSamw 	}
390da6c28aaSamw 
391da6c28aaSamw 	op->fqi.srch_attr = op->fqi.srch_attr;
392da6c28aaSamw 
393da6c28aaSamw 	if ((status = smb_validate_object_name(op->fqi.path, is_dir)) != 0) {
394dc20a302Sas200622 		smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
3957b59d02dSjb150015 		return (status);
396da6c28aaSamw 	}
397da6c28aaSamw 
398da6c28aaSamw 	cur_node = op->fqi.dir_snode ?
399da6c28aaSamw 	    op->fqi.dir_snode : sr->tid_tree->t_snode;
400da6c28aaSamw 
401da6c28aaSamw 	if (rc = smb_pathname_reduce(sr, sr->user_cr, op->fqi.path,
402da6c28aaSamw 	    sr->tid_tree->t_snode, cur_node, &op->fqi.dir_snode,
403da6c28aaSamw 	    op->fqi.last_comp)) {
404dc20a302Sas200622 		smbsr_errno(sr, rc);
4057b59d02dSjb150015 		return (sr->smb_error.status);
406da6c28aaSamw 	}
407da6c28aaSamw 
408da6c28aaSamw 	/*
409da6c28aaSamw 	 * If the access mask has only DELETE set (ignore
410da6c28aaSamw 	 * FILE_READ_ATTRIBUTES), then assume that this
411da6c28aaSamw 	 * is a request to delete the link (if a link)
412da6c28aaSamw 	 * and do not follow links.  Otherwise, follow
413da6c28aaSamw 	 * the link to the target.
414da6c28aaSamw 	 */
415da6c28aaSamw 
416da6c28aaSamw 	daccess = op->desired_access & ~FILE_READ_ATTRIBUTES;
417da6c28aaSamw 
418da6c28aaSamw 	if (daccess == DELETE)
419da6c28aaSamw 		lookup_flags &= ~SMB_FOLLOW_LINKS;
420da6c28aaSamw 
421da6c28aaSamw 	rc = smb_fsop_lookup_name(sr, kcred, lookup_flags,
422da6c28aaSamw 	    sr->tid_tree->t_snode, op->fqi.dir_snode, op->fqi.last_comp,
423da6c28aaSamw 	    &op->fqi.last_snode, &op->fqi.last_attr);
424da6c28aaSamw 
425da6c28aaSamw 	if (rc == 0) {
426da6c28aaSamw 		op->fqi.last_comp_was_found = 1;
427da6c28aaSamw 		(void) strcpy(op->fqi.last_comp_od,
428da6c28aaSamw 		    op->fqi.last_snode->od_name);
429da6c28aaSamw 	} else if (rc == ENOENT) {
430da6c28aaSamw 		op->fqi.last_comp_was_found = 0;
431da6c28aaSamw 		op->fqi.last_snode = NULL;
432da6c28aaSamw 		rc = 0;
433da6c28aaSamw 	} else {
434da6c28aaSamw 		smb_node_release(op->fqi.dir_snode);
435da6c28aaSamw 		SMB_NULL_FQI_NODES(op->fqi);
436dc20a302Sas200622 		smbsr_errno(sr, rc);
4377b59d02dSjb150015 		return (sr->smb_error.status);
438da6c28aaSamw 	}
439da6c28aaSamw 
440dc20a302Sas200622 	/*
441dc20a302Sas200622 	 * The uniq_fid is a CIFS-server-wide unique identifier for an ofile
442dc20a302Sas200622 	 * which is used to uniquely identify open instances for the
443c8ec8eeaSjose borrego 	 * VFS share reservation and POSIX locks.
444dc20a302Sas200622 	 */
445dc20a302Sas200622 
446dc20a302Sas200622 	uniq_fid = SMB_UNIQ_FID();
447dc20a302Sas200622 
448da6c28aaSamw 	if (op->fqi.last_comp_was_found) {
4496537f381Sas200622 
4506537f381Sas200622 		if ((op->fqi.last_attr.sa_vattr.va_type != VREG) &&
4516537f381Sas200622 		    (op->fqi.last_attr.sa_vattr.va_type != VDIR) &&
4526537f381Sas200622 		    (op->fqi.last_attr.sa_vattr.va_type != VLNK)) {
4536537f381Sas200622 
4546537f381Sas200622 			smb_node_release(op->fqi.last_snode);
4556537f381Sas200622 			smb_node_release(op->fqi.dir_snode);
4566537f381Sas200622 			SMB_NULL_FQI_NODES(op->fqi);
4576537f381Sas200622 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
4586537f381Sas200622 			    ERRnoaccess);
4596537f381Sas200622 			return (NT_STATUS_ACCESS_DENIED);
4606537f381Sas200622 		}
4616537f381Sas200622 
462da6c28aaSamw 		node = op->fqi.last_snode;
463da6c28aaSamw 		dnode = op->fqi.dir_snode;
464da6c28aaSamw 
465da6c28aaSamw 		/*
466*2c1b14e5Sjose borrego 		 * Reject this request if either:
467*2c1b14e5Sjose borrego 		 * - the target IS a directory and the client requires that
468*2c1b14e5Sjose borrego 		 *   it must NOT be (required by Lotus Notes)
469*2c1b14e5Sjose borrego 		 * - the target is NOT a directory and client requires that
470*2c1b14e5Sjose borrego 		 *   it MUST be.
471da6c28aaSamw 		 */
472da6c28aaSamw 		if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
473*2c1b14e5Sjose borrego 			if (op->create_options & FILE_NON_DIRECTORY_FILE) {
474da6c28aaSamw 				smb_node_release(node);
475da6c28aaSamw 				smb_node_release(dnode);
476da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
477dc20a302Sas200622 				smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
478da6c28aaSamw 				    ERRDOS, ERROR_ACCESS_DENIED);
4797b59d02dSjb150015 				return (NT_STATUS_FILE_IS_A_DIRECTORY);
480da6c28aaSamw 			}
481*2c1b14e5Sjose borrego 		} else {
482*2c1b14e5Sjose borrego 			if ((op->create_options & FILE_DIRECTORY_FILE) ||
483*2c1b14e5Sjose borrego 			    (op->my_flags & MYF_MUST_BE_DIRECTORY)) {
484da6c28aaSamw 				smb_node_release(node);
485da6c28aaSamw 				smb_node_release(dnode);
486da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
487dc20a302Sas200622 				smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
488da6c28aaSamw 				    ERRDOS, ERROR_DIRECTORY);
4897b59d02dSjb150015 				return (NT_STATUS_NOT_A_DIRECTORY);
490da6c28aaSamw 			}
491*2c1b14e5Sjose borrego 		}
492da6c28aaSamw 
493da6c28aaSamw 		/*
494da6c28aaSamw 		 * No more open should be accepted when "Delete on close"
495da6c28aaSamw 		 * flag is set.
496da6c28aaSamw 		 */
497da6c28aaSamw 		if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
498da6c28aaSamw 			smb_node_release(node);
499da6c28aaSamw 			smb_node_release(dnode);
500da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
501dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_DELETE_PENDING,
502da6c28aaSamw 			    ERRDOS, ERROR_ACCESS_DENIED);
5037b59d02dSjb150015 			return (NT_STATUS_DELETE_PENDING);
504da6c28aaSamw 		}
505da6c28aaSamw 
506da6c28aaSamw 		/*
507da6c28aaSamw 		 * Specified file already exists so the operation should fail.
508da6c28aaSamw 		 */
509da6c28aaSamw 		if (op->create_disposition == FILE_CREATE) {
510da6c28aaSamw 			smb_node_release(node);
511da6c28aaSamw 			smb_node_release(dnode);
512da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
513dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
514dc20a302Sas200622 			    ERRDOS, ERROR_ALREADY_EXISTS);
5157b59d02dSjb150015 			return (NT_STATUS_OBJECT_NAME_COLLISION);
516da6c28aaSamw 		}
517da6c28aaSamw 
518da6c28aaSamw 		/*
519da6c28aaSamw 		 * Windows seems to check read-only access before file
520da6c28aaSamw 		 * sharing check.
521c8ec8eeaSjose borrego 		 *
522c8ec8eeaSjose borrego 		 * Check to see if the file is currently readonly (irrespective
523c8ec8eeaSjose borrego 		 * of whether this open will make it readonly).
524da6c28aaSamw 		 */
525c8ec8eeaSjose borrego 		if (SMB_PATHFILE_IS_READONLY(sr, node)) {
526da6c28aaSamw 			/* Files data only */
527da6c28aaSamw 			if (node->attr.sa_vattr.va_type != VDIR) {
528da6c28aaSamw 				if (op->desired_access & (FILE_WRITE_DATA |
529da6c28aaSamw 				    FILE_APPEND_DATA)) {
530da6c28aaSamw 					smb_node_release(node);
531da6c28aaSamw 					smb_node_release(dnode);
532da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
533dc20a302Sas200622 					smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
534dc20a302Sas200622 					    ERRDOS, ERRnoaccess);
5357b59d02dSjb150015 					return (NT_STATUS_ACCESS_DENIED);
536da6c28aaSamw 				}
537da6c28aaSamw 			}
538da6c28aaSamw 		}
539da6c28aaSamw 
5408c10a865Sas200622 		if (smb_oplock_conflict(node, sr->session, op))
5418c10a865Sas200622 			smb_oplock_break(node);
5428c10a865Sas200622 
5438c10a865Sas200622 		rw_enter(&node->n_share_lock, RW_WRITER);
544dc20a302Sas200622 
545dc20a302Sas200622 		if ((op->create_disposition == FILE_SUPERSEDE) ||
546dc20a302Sas200622 		    (op->create_disposition == FILE_OVERWRITE_IF) ||
547dc20a302Sas200622 		    (op->create_disposition == FILE_OVERWRITE)) {
548dc20a302Sas200622 
549*2c1b14e5Sjose borrego 			if ((!(op->desired_access &
5508c10a865Sas200622 			    (FILE_WRITE_DATA | FILE_APPEND_DATA |
551*2c1b14e5Sjose borrego 			    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) ||
552*2c1b14e5Sjose borrego 			    (!smb_sattr_check(&node->attr, NULL, op->dattr))) {
553dc20a302Sas200622 				rw_exit(&node->n_share_lock);
554dc20a302Sas200622 				smb_node_release(node);
555dc20a302Sas200622 				smb_node_release(dnode);
556dc20a302Sas200622 				SMB_NULL_FQI_NODES(op->fqi);
557dc20a302Sas200622 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
558dc20a302Sas200622 				    ERRDOS, ERRnoaccess);
5597b59d02dSjb150015 				return (NT_STATUS_ACCESS_DENIED);
560dc20a302Sas200622 			}
561dc20a302Sas200622 		}
562dc20a302Sas200622 
563dc20a302Sas200622 		status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
564c8ec8eeaSjose borrego 		    op->desired_access, op->share_access);
565dc20a302Sas200622 
566da6c28aaSamw 		if (status == NT_STATUS_SHARING_VIOLATION) {
567dc20a302Sas200622 			rw_exit(&node->n_share_lock);
568da6c28aaSamw 			smb_node_release(node);
569da6c28aaSamw 			smb_node_release(dnode);
570da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
571da6c28aaSamw 			return (status);
572da6c28aaSamw 		}
573da6c28aaSamw 
574da6c28aaSamw 		status = smb_fsop_access(sr, sr->user_cr, node,
575da6c28aaSamw 		    op->desired_access);
576da6c28aaSamw 
577da6c28aaSamw 		if (status != NT_STATUS_SUCCESS) {
578dc20a302Sas200622 			smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
579dc20a302Sas200622 
580dc20a302Sas200622 			rw_exit(&node->n_share_lock);
581da6c28aaSamw 			smb_node_release(node);
582da6c28aaSamw 			smb_node_release(dnode);
583da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
584dc20a302Sas200622 
585da6c28aaSamw 			if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
586dc20a302Sas200622 				smbsr_error(sr, status,
587dc20a302Sas200622 				    ERRDOS, ERROR_PRIVILEGE_NOT_HELD);
5887b59d02dSjb150015 				return (status);
589da6c28aaSamw 			} else {
590dc20a302Sas200622 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
591dc20a302Sas200622 				    ERRDOS, ERROR_ACCESS_DENIED);
5927b59d02dSjb150015 				return (NT_STATUS_ACCESS_DENIED);
593da6c28aaSamw 			}
594da6c28aaSamw 		}
595da6c28aaSamw 
596da6c28aaSamw 		switch (op->create_disposition) {
597da6c28aaSamw 		case FILE_SUPERSEDE:
598da6c28aaSamw 		case FILE_OVERWRITE_IF:
599da6c28aaSamw 		case FILE_OVERWRITE:
600da6c28aaSamw 			if (node->attr.sa_vattr.va_type == VDIR) {
601dc20a302Sas200622 				smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
602dc20a302Sas200622 				rw_exit(&node->n_share_lock);
603da6c28aaSamw 				smb_node_release(node);
604da6c28aaSamw 				smb_node_release(dnode);
605da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
606dc20a302Sas200622 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
607dc20a302Sas200622 				    ERRDOS, ERROR_ACCESS_DENIED);
6087b59d02dSjb150015 				return (NT_STATUS_ACCESS_DENIED);
609da6c28aaSamw 			}
610da6c28aaSamw 
611da6c28aaSamw 			if (node->attr.sa_vattr.va_size != op->dsize) {
612da6c28aaSamw 				node->flags &= ~NODE_FLAGS_SET_SIZE;
613dc20a302Sas200622 				bzero(&new_attr, sizeof (new_attr));
614da6c28aaSamw 				new_attr.sa_vattr.va_size = op->dsize;
615da6c28aaSamw 				new_attr.sa_mask = SMB_AT_SIZE;
616dc20a302Sas200622 
617dc20a302Sas200622 				rc = smb_fsop_setattr(sr, sr->user_cr,
618dc20a302Sas200622 				    node, &new_attr, &op->fqi.last_attr);
619dc20a302Sas200622 
620dc20a302Sas200622 				if (rc) {
621faa1795aSjb150015 					smb_fsop_unshrlock(sr->user_cr, node,
622faa1795aSjb150015 					    uniq_fid);
623dc20a302Sas200622 					rw_exit(&node->n_share_lock);
624da6c28aaSamw 					smb_node_release(node);
625da6c28aaSamw 					smb_node_release(dnode);
626da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
627dc20a302Sas200622 					smbsr_errno(sr, rc);
6287b59d02dSjb150015 					return (sr->smb_error.status);
629da6c28aaSamw 				}
630da6c28aaSamw 
631dc20a302Sas200622 				op->dsize = op->fqi.last_attr.sa_vattr.va_size;
632da6c28aaSamw 			}
633da6c28aaSamw 
634*2c1b14e5Sjose borrego 			op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
635*2c1b14e5Sjose borrego 			if (op->dattr & FILE_ATTRIBUTE_READONLY) {
636*2c1b14e5Sjose borrego 				op->created_readonly = B_TRUE;
637*2c1b14e5Sjose borrego 				op->dattr &= ~FILE_ATTRIBUTE_READONLY;
638*2c1b14e5Sjose borrego 			}
639*2c1b14e5Sjose borrego 
640*2c1b14e5Sjose borrego 			smb_node_set_dosattr(node, op->dattr);
641*2c1b14e5Sjose borrego 			(void) smb_sync_fsattr(sr, sr->user_cr, node);
642*2c1b14e5Sjose borrego 
643da6c28aaSamw 			/*
644da6c28aaSamw 			 * If file is being replaced,
645da6c28aaSamw 			 * we should remove existing streams
646da6c28aaSamw 			 */
647da6c28aaSamw 			if (SMB_IS_STREAM(node) == 0)
648da6c28aaSamw 				(void) smb_fsop_remove_streams(sr, sr->user_cr,
649da6c28aaSamw 				    node);
650da6c28aaSamw 
651da6c28aaSamw 			op->action_taken = SMB_OACT_TRUNCATED;
652da6c28aaSamw 			break;
653da6c28aaSamw 
654da6c28aaSamw 		default:
655da6c28aaSamw 			/*
656da6c28aaSamw 			 * FILE_OPEN or FILE_OPEN_IF.
657da6c28aaSamw 			 */
658da6c28aaSamw 			op->action_taken = SMB_OACT_OPENED;
659da6c28aaSamw 			break;
660da6c28aaSamw 		}
661da6c28aaSamw 	} else {
662da6c28aaSamw 
663da6c28aaSamw 		/* Last component was not found. */
664da6c28aaSamw 		dnode = op->fqi.dir_snode;
665da6c28aaSamw 
6667b59d02dSjb150015 		if (is_dir == 0)
6677b59d02dSjb150015 			is_stream = smb_stream_parse_name(op->fqi.path,
6687b59d02dSjb150015 			    NULL, NULL);
6697b59d02dSjb150015 
670da6c28aaSamw 		if ((op->create_disposition == FILE_OPEN) ||
671da6c28aaSamw 		    (op->create_disposition == FILE_OVERWRITE)) {
672da6c28aaSamw 			smb_node_release(dnode);
673da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
674dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
675da6c28aaSamw 			    ERRDOS, ERROR_FILE_NOT_FOUND);
6767b59d02dSjb150015 			return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
677da6c28aaSamw 		}
678da6c28aaSamw 
679da6c28aaSamw 		/*
680da6c28aaSamw 		 * lock the parent dir node in case another create
681da6c28aaSamw 		 * request to the same parent directory comes in.
682da6c28aaSamw 		 */
683da6c28aaSamw 		smb_rwx_rwenter(&dnode->n_lock, RW_WRITER);
684da6c28aaSamw 
685da6c28aaSamw 		bzero(&new_attr, sizeof (new_attr));
686*2c1b14e5Sjose borrego 		new_attr.sa_dosattr = op->dattr;
687*2c1b14e5Sjose borrego 		new_attr.sa_mask |= SMB_AT_DOSATTR;
688c8ec8eeaSjose borrego 
689c8ec8eeaSjose borrego 		/*
690c8ec8eeaSjose borrego 		 * A file created with the readonly bit should not
691c8ec8eeaSjose borrego 		 * stop the creator writing to the file until it is
692c8ec8eeaSjose borrego 		 * closed.  Although the readonly bit will not be set
693c8ec8eeaSjose borrego 		 * on the file until it is closed, it will be accounted
694c8ec8eeaSjose borrego 		 * for on other fids and on queries based on the node
695c8ec8eeaSjose borrego 		 * state.
696c8ec8eeaSjose borrego 		 */
697c8ec8eeaSjose borrego 		if (op->dattr & FILE_ATTRIBUTE_READONLY)
698*2c1b14e5Sjose borrego 			new_attr.sa_dosattr &= ~FILE_ATTRIBUTE_READONLY;
699c8ec8eeaSjose borrego 
700c8ec8eeaSjose borrego 
701c8ec8eeaSjose borrego 		if ((op->crtime.tv_sec != 0) &&
702c8ec8eeaSjose borrego 		    (op->crtime.tv_sec != UINT_MAX)) {
703c8ec8eeaSjose borrego 
704c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_CRTIME;
705c8ec8eeaSjose borrego 			new_attr.sa_crtime = op->crtime;
706c8ec8eeaSjose borrego 		}
707c8ec8eeaSjose borrego 
708da6c28aaSamw 		if (is_dir == 0) {
709*2c1b14e5Sjose borrego 			new_attr.sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
710da6c28aaSamw 			new_attr.sa_vattr.va_type = VREG;
7117b59d02dSjb150015 			new_attr.sa_vattr.va_mode = is_stream ? S_IRUSR :
7127b59d02dSjb150015 			    S_IRUSR | S_IRGRP | S_IROTH |
7137b59d02dSjb150015 			    S_IWUSR | S_IWGRP | S_IWOTH;
714c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
715dc20a302Sas200622 
7166537f381Sas200622 			if (op->dsize) {
7176537f381Sas200622 				new_attr.sa_vattr.va_size = op->dsize;
7186537f381Sas200622 				new_attr.sa_mask |= SMB_AT_SIZE;
719dc20a302Sas200622 			}
720dc20a302Sas200622 
721da6c28aaSamw 			rc = smb_fsop_create(sr, sr->user_cr, dnode,
722da6c28aaSamw 			    op->fqi.last_comp, &new_attr,
723da6c28aaSamw 			    &op->fqi.last_snode, &op->fqi.last_attr);
724dc20a302Sas200622 
725da6c28aaSamw 			if (rc != 0) {
726da6c28aaSamw 				smb_rwx_rwexit(&dnode->n_lock);
727da6c28aaSamw 				smb_node_release(dnode);
728da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
729dc20a302Sas200622 				smbsr_errno(sr, rc);
7307b59d02dSjb150015 				return (sr->smb_error.status);
731da6c28aaSamw 			}
732da6c28aaSamw 
733dc20a302Sas200622 			node = op->fqi.last_snode;
734dc20a302Sas200622 
735c8ec8eeaSjose borrego 			op->fqi.last_attr = node->attr;
736c8ec8eeaSjose borrego 
737dc20a302Sas200622 			rw_enter(&node->n_share_lock, RW_WRITER);
738dc20a302Sas200622 
739faa1795aSjb150015 			status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
740c8ec8eeaSjose borrego 			    op->desired_access, op->share_access);
741dc20a302Sas200622 
742dc20a302Sas200622 			if (status == NT_STATUS_SHARING_VIOLATION) {
743dc20a302Sas200622 				rw_exit(&node->n_share_lock);
744c8ec8eeaSjose borrego 				SMB_DEL_NEWOBJ(op->fqi);
745dc20a302Sas200622 				smb_node_release(node);
746dc20a302Sas200622 				smb_node_release(dnode);
747dc20a302Sas200622 				SMB_NULL_FQI_NODES(op->fqi);
748dc20a302Sas200622 				return (status);
749dc20a302Sas200622 			}
750dc20a302Sas200622 
751da6c28aaSamw 
752da6c28aaSamw 		} else {
7533db3f65cSamw 			op->dattr |= FILE_ATTRIBUTE_DIRECTORY;
754da6c28aaSamw 			new_attr.sa_vattr.va_type = VDIR;
755da6c28aaSamw 			new_attr.sa_vattr.va_mode = 0777;
756c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
757c8ec8eeaSjose borrego 
758da6c28aaSamw 			rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
759da6c28aaSamw 			    op->fqi.last_comp, &new_attr,
760da6c28aaSamw 			    &op->fqi.last_snode, &op->fqi.last_attr);
761da6c28aaSamw 			if (rc != 0) {
762da6c28aaSamw 				smb_rwx_rwexit(&dnode->n_lock);
763da6c28aaSamw 				smb_node_release(dnode);
764da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
765dc20a302Sas200622 				smbsr_errno(sr, rc);
7667b59d02dSjb150015 				return (sr->smb_error.status);
767da6c28aaSamw 			}
768dc20a302Sas200622 
769dc20a302Sas200622 			node = op->fqi.last_snode;
770dc20a302Sas200622 			rw_enter(&node->n_share_lock, RW_WRITER);
771da6c28aaSamw 		}
772da6c28aaSamw 
773da6c28aaSamw 		created = 1;
774da6c28aaSamw 		op->action_taken = SMB_OACT_CREATED;
775c8ec8eeaSjose borrego 		node->flags |= NODE_FLAGS_CREATED;
776c8ec8eeaSjose borrego 
777c8ec8eeaSjose borrego 		if (op->dattr & FILE_ATTRIBUTE_READONLY) {
778c8ec8eeaSjose borrego 			op->created_readonly = B_TRUE;
779c8ec8eeaSjose borrego 			op->dattr &= ~FILE_ATTRIBUTE_READONLY;
780c8ec8eeaSjose borrego 		}
781c8ec8eeaSjose borrego 	}
782c8ec8eeaSjose borrego 
783c8ec8eeaSjose borrego 	op->dattr = smb_node_get_dosattr(node);
784c8ec8eeaSjose borrego 
785*2c1b14e5Sjose borrego 	if (max_requested) {
786*2c1b14e5Sjose borrego 		smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed);
787*2c1b14e5Sjose borrego 		op->desired_access |= max_allowed;
788*2c1b14e5Sjose borrego 	}
789*2c1b14e5Sjose borrego 
790*2c1b14e5Sjose borrego 	/*
791*2c1b14e5Sjose borrego 	 * if last_write time was in request and is not 0 or -1,
792*2c1b14e5Sjose borrego 	 * use it as file's mtime
793*2c1b14e5Sjose borrego 	 */
794*2c1b14e5Sjose borrego 	if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) {
795*2c1b14e5Sjose borrego 		smb_node_set_time(node, NULL, &op->mtime, NULL, NULL,
796*2c1b14e5Sjose borrego 		    SMB_AT_MTIME);
797*2c1b14e5Sjose borrego 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
798*2c1b14e5Sjose borrego 	}
799*2c1b14e5Sjose borrego 
800da6c28aaSamw 	/*
801da6c28aaSamw 	 * smb_ofile_open() will copy node to of->node.  Hence
802da6c28aaSamw 	 * the hold on node (i.e. op->fqi.last_snode) will be "transferred"
803da6c28aaSamw 	 * to the "of" structure.
804da6c28aaSamw 	 */
805da6c28aaSamw 
806c8ec8eeaSjose borrego 	of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op, SMB_FTYPE_DISK,
807c8ec8eeaSjose borrego 	    uniq_fid, &err);
808da6c28aaSamw 
809da6c28aaSamw 	if (of == NULL) {
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, err.status, err.errcls, err.errcode);
8207b59d02dSjb150015 		return (err.status);
821da6c28aaSamw 	}
822da6c28aaSamw 
8238c10a865Sas200622 	if (op->fqi.last_attr.sa_vattr.va_type == VREG) {
8248c10a865Sas200622 		status = smb_oplock_acquire(sr, of, op);
825da6c28aaSamw 
826da6c28aaSamw 		if (status != NT_STATUS_SUCCESS) {
827dc20a302Sas200622 			rw_exit(&node->n_share_lock);
828dc20a302Sas200622 			/*
829dc20a302Sas200622 			 * smb_fsop_unshrlock() and smb_fsop_close()
830dc20a302Sas200622 			 * are called from smb_ofile_close()
831dc20a302Sas200622 			 */
832c8ec8eeaSjose borrego 			smb_ofile_close(of, 0);
833da6c28aaSamw 			smb_ofile_release(of);
834da6c28aaSamw 			if (created)
835da6c28aaSamw 				smb_rwx_rwexit(&dnode->n_lock);
836dc20a302Sas200622 
837da6c28aaSamw 			smb_node_release(dnode);
838da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
839da6c28aaSamw 
840dc20a302Sas200622 			smbsr_error(sr, status,
841da6c28aaSamw 			    ERRDOS, ERROR_SHARING_VIOLATION);
8427b59d02dSjb150015 			return (status);
843da6c28aaSamw 		}
844da6c28aaSamw 
845da6c28aaSamw 		op->dsize = op->fqi.last_attr.sa_vattr.va_size;
8468c10a865Sas200622 	} else { /* VDIR or VLNK */
8478c10a865Sas200622 		op->my_flags &= ~MYF_OPLOCK_MASK;
8488c10a865Sas200622 		op->dsize = 0;
849da6c28aaSamw 	}
850da6c28aaSamw 
8518c10a865Sas200622 	/*
8528c10a865Sas200622 	 * Propagate the write-through mode from the open params
8538c10a865Sas200622 	 * to the node: see the notes in the function header.
8548c10a865Sas200622 	 */
8558c10a865Sas200622 	if (sr->sr_cfg->skc_sync_enable ||
8568c10a865Sas200622 	    (op->create_options & FILE_WRITE_THROUGH))
8578c10a865Sas200622 		node->flags |= NODE_FLAGS_WRITE_THROUGH;
8588c10a865Sas200622 
8598c10a865Sas200622 	op->fileid = op->fqi.last_attr.sa_vattr.va_nodeid;
8608c10a865Sas200622 
861da6c28aaSamw 	/*
862da6c28aaSamw 	 * Set up the file type in open_param for the response
863da6c28aaSamw 	 */
864da6c28aaSamw 	op->ftype = SMB_FTYPE_DISK;
865da6c28aaSamw 	sr->smb_fid = of->f_fid;
866da6c28aaSamw 	sr->fid_ofile = of;
867da6c28aaSamw 
868dc20a302Sas200622 	rw_exit(&node->n_share_lock);
869dc20a302Sas200622 
870dc20a302Sas200622 	if (created)
871da6c28aaSamw 		smb_rwx_rwexit(&dnode->n_lock);
872dc20a302Sas200622 
873da6c28aaSamw 	smb_node_release(dnode);
874da6c28aaSamw 	SMB_NULL_FQI_NODES(op->fqi);
875da6c28aaSamw 
876da6c28aaSamw 	return (NT_STATUS_SUCCESS);
877da6c28aaSamw }
878da6c28aaSamw 
879da6c28aaSamw /*
880da6c28aaSamw  * smb_validate_object_name
881da6c28aaSamw  *
882da6c28aaSamw  * Very basic file name validation. Directory validation is handed off
883da6c28aaSamw  * to smb_validate_dirname. For filenames, we check for names of the
884da6c28aaSamw  * form "AAAn:". Names that contain three characters, a single digit
885da6c28aaSamw  * and a colon (:) are reserved as DOS device names, i.e. "COM1:".
886da6c28aaSamw  *
887da6c28aaSamw  * Returns NT status codes.
888da6c28aaSamw  */
889da6c28aaSamw uint32_t
890da6c28aaSamw smb_validate_object_name(char *path, unsigned int ftype)
891da6c28aaSamw {
892da6c28aaSamw 	char *filename;
893da6c28aaSamw 
894da6c28aaSamw 	if (path == 0)
895da6c28aaSamw 		return (0);
896da6c28aaSamw 
897da6c28aaSamw 	if (ftype)
898da6c28aaSamw 		return (smb_validate_dirname(path));
899da6c28aaSamw 
900da6c28aaSamw 	/*
901da6c28aaSamw 	 * Basename with backslashes.
902da6c28aaSamw 	 */
903da6c28aaSamw 	if ((filename = strrchr(path, '\\')) != 0)
904da6c28aaSamw 		++filename;
905da6c28aaSamw 	else
906da6c28aaSamw 		filename = path;
907da6c28aaSamw 
908da6c28aaSamw 	if (strlen(filename) == 5 &&
909da6c28aaSamw 	    mts_isdigit(filename[3]) &&
910da6c28aaSamw 	    filename[4] == ':') {
911da6c28aaSamw 		return (NT_STATUS_OBJECT_NAME_INVALID);
912da6c28aaSamw 	}
913da6c28aaSamw 
914da6c28aaSamw 	return (0);
915da6c28aaSamw }
916da6c28aaSamw 
917da6c28aaSamw /*
918da6c28aaSamw  * smb_preset_delete_on_close
919da6c28aaSamw  *
920da6c28aaSamw  * Set the DeleteOnClose flag on the smb file. When the file is closed,
921da6c28aaSamw  * the flag will be transferred to the smb node, which will commit the
922da6c28aaSamw  * delete operation and inhibit subsequent open requests.
923da6c28aaSamw  *
924da6c28aaSamw  * When DeleteOnClose is set on an smb_node, the common open code will
925da6c28aaSamw  * reject subsequent open requests for the file. Observation of Windows
926da6c28aaSamw  * 2000 indicates that subsequent opens should be allowed (assuming
927da6c28aaSamw  * there would be no sharing violation) until the file is closed using
928da6c28aaSamw  * the fid on which the DeleteOnClose was requested.
929da6c28aaSamw  */
930da6c28aaSamw void
931da6c28aaSamw smb_preset_delete_on_close(smb_ofile_t *file)
932da6c28aaSamw {
933da6c28aaSamw 	mutex_enter(&file->f_mutex);
934da6c28aaSamw 	file->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
935da6c28aaSamw 	mutex_exit(&file->f_mutex);
936da6c28aaSamw }
937