xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_common_open.c (revision 8b2cc8ac894f2d58f38cf2fb7c3ac778f4c57c09)
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 *);
42faa1795aSjb extern uint32_t smb_is_executable(char *);
43*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static void smb_delete_new_object(smb_request_t *);
44da6c28aaSamw 
45da6c28aaSamw /*
46da6c28aaSamw  * smb_access_generic_to_file
47da6c28aaSamw  *
48da6c28aaSamw  * Search MSDN for IoCreateFile to see following mapping.
49da6c28aaSamw  *
50da6c28aaSamw  * GENERIC_READ		STANDARD_RIGHTS_READ, FILE_READ_DATA,
51da6c28aaSamw  *			FILE_READ_ATTRIBUTES and FILE_READ_EA
52da6c28aaSamw  *
53da6c28aaSamw  * GENERIC_WRITE	STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA,
54da6c28aaSamw  *               FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
55da6c28aaSamw  *
56da6c28aaSamw  * GENERIC_EXECUTE	STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE.
57da6c28aaSamw  */
58da6c28aaSamw uint32_t
59da6c28aaSamw smb_access_generic_to_file(uint32_t desired_access)
60da6c28aaSamw {
61da6c28aaSamw 	uint32_t access = 0;
62da6c28aaSamw 
63da6c28aaSamw 	if (desired_access & GENERIC_ALL)
64da6c28aaSamw 		return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
65da6c28aaSamw 
66da6c28aaSamw 	if (desired_access & GENERIC_EXECUTE) {
67da6c28aaSamw 		desired_access &= ~GENERIC_EXECUTE;
68da6c28aaSamw 		access |= (STANDARD_RIGHTS_EXECUTE |
69da6c28aaSamw 		    SYNCHRONIZE | FILE_EXECUTE);
70da6c28aaSamw 	}
71da6c28aaSamw 
72da6c28aaSamw 	if (desired_access & GENERIC_WRITE) {
73da6c28aaSamw 		desired_access &= ~GENERIC_WRITE;
74da6c28aaSamw 		access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE);
75da6c28aaSamw 	}
76da6c28aaSamw 
77da6c28aaSamw 	if (desired_access & GENERIC_READ) {
78da6c28aaSamw 		desired_access &= ~GENERIC_READ;
79da6c28aaSamw 		access |= FILE_GENERIC_READ;
80da6c28aaSamw 	}
81da6c28aaSamw 
82da6c28aaSamw 	return (access | desired_access);
83da6c28aaSamw }
84da6c28aaSamw 
85da6c28aaSamw /*
86da6c28aaSamw  * smb_omode_to_amask
87da6c28aaSamw  *
88da6c28aaSamw  * This function converts open modes used by Open and Open AndX
89da6c28aaSamw  * commands to desired access bits used by NT Create AndX command.
90da6c28aaSamw  */
91da6c28aaSamw uint32_t
92da6c28aaSamw smb_omode_to_amask(uint32_t desired_access)
93da6c28aaSamw {
94da6c28aaSamw 	switch (desired_access & SMB_DA_ACCESS_MASK) {
95da6c28aaSamw 	case SMB_DA_ACCESS_READ:
96da6c28aaSamw 		return (FILE_GENERIC_READ);
97da6c28aaSamw 
98da6c28aaSamw 	case SMB_DA_ACCESS_WRITE:
99da6c28aaSamw 		return (FILE_GENERIC_WRITE);
100da6c28aaSamw 
101da6c28aaSamw 	case SMB_DA_ACCESS_READ_WRITE:
102da6c28aaSamw 		return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
103da6c28aaSamw 
104da6c28aaSamw 	case SMB_DA_ACCESS_EXECUTE:
105da6c28aaSamw 		return (FILE_GENERIC_EXECUTE);
106da6c28aaSamw 
1072c2961f8Sjose borrego 	default:
1082c2961f8Sjose borrego 		return (FILE_GENERIC_ALL);
1092c2961f8Sjose borrego 	}
110da6c28aaSamw }
111da6c28aaSamw 
112da6c28aaSamw /*
113da6c28aaSamw  * smb_denymode_to_sharemode
114da6c28aaSamw  *
115da6c28aaSamw  * This function converts deny modes used by Open and Open AndX
116da6c28aaSamw  * commands to share access bits used by NT Create AndX command.
117da6c28aaSamw  */
118da6c28aaSamw uint32_t
119da6c28aaSamw smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
120da6c28aaSamw {
121da6c28aaSamw 	switch (desired_access & SMB_DA_SHARE_MASK) {
122da6c28aaSamw 	case SMB_DA_SHARE_COMPATIBILITY:
123da6c28aaSamw 		if (smb_is_executable(fname))
124da6c28aaSamw 			return (FILE_SHARE_READ | FILE_SHARE_WRITE);
125c8ec8eeaSjose borrego 
126c8ec8eeaSjose borrego 		return (FILE_SHARE_ALL);
127da6c28aaSamw 
128da6c28aaSamw 	case SMB_DA_SHARE_EXCLUSIVE:
129da6c28aaSamw 		return (FILE_SHARE_NONE);
130da6c28aaSamw 
131da6c28aaSamw 	case SMB_DA_SHARE_DENY_WRITE:
132da6c28aaSamw 		return (FILE_SHARE_READ);
133da6c28aaSamw 
134da6c28aaSamw 	case SMB_DA_SHARE_DENY_READ:
135da6c28aaSamw 		return (FILE_SHARE_WRITE);
136da6c28aaSamw 
137da6c28aaSamw 	case SMB_DA_SHARE_DENY_NONE:
1382c2961f8Sjose borrego 	default:
139da6c28aaSamw 		return (FILE_SHARE_READ | FILE_SHARE_WRITE);
140da6c28aaSamw 	}
141da6c28aaSamw }
142da6c28aaSamw 
143da6c28aaSamw /*
144da6c28aaSamw  * smb_ofun_to_crdisposition
145da6c28aaSamw  *
146da6c28aaSamw  * This function converts open function values used by Open and Open AndX
147da6c28aaSamw  * commands to create disposition values used by NT Create AndX command.
148da6c28aaSamw  */
149da6c28aaSamw uint32_t
150da6c28aaSamw smb_ofun_to_crdisposition(uint16_t  ofun)
151da6c28aaSamw {
152da6c28aaSamw 	static int ofun_cr_map[3][2] =
153da6c28aaSamw 	{
154da6c28aaSamw 		{ -1,			FILE_CREATE },
155da6c28aaSamw 		{ FILE_OPEN,		FILE_OPEN_IF },
156da6c28aaSamw 		{ FILE_OVERWRITE,	FILE_OVERWRITE_IF }
157da6c28aaSamw 	};
158da6c28aaSamw 
159da6c28aaSamw 	int row = ofun & SMB_OFUN_OPEN_MASK;
160da6c28aaSamw 	int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
161da6c28aaSamw 
162da6c28aaSamw 	if (row == 3)
1632c2961f8Sjose borrego 		return (FILE_MAXIMUM_DISPOSITION + 1);
164da6c28aaSamw 
165da6c28aaSamw 	return (ofun_cr_map[row][col]);
166da6c28aaSamw }
167da6c28aaSamw 
1687b59d02dSjb /*
1697b59d02dSjb  * Retry opens to avoid spurious sharing violations, due to timing
1707b59d02dSjb  * issues between closes and opens.  The client that already has the
1717b59d02dSjb  * file open may be in the process of closing it.
1727b59d02dSjb  */
1737b59d02dSjb uint32_t
1747b59d02dSjb smb_common_open(smb_request_t *sr)
1757b59d02dSjb {
1767b59d02dSjb 	uint32_t status = NT_STATUS_SUCCESS;
1777b59d02dSjb 	int count;
1787b59d02dSjb 
1797b59d02dSjb 	for (count = 0; count <= 4; count++) {
1807b59d02dSjb 		if (count)
1817b59d02dSjb 			delay(MSEC_TO_TICK(400));
1827b59d02dSjb 
183faa1795aSjb 		status = smb_open_subr(sr);
184faa1795aSjb 		if (status != NT_STATUS_SHARING_VIOLATION)
1857b59d02dSjb 			break;
1867b59d02dSjb 	}
1877b59d02dSjb 
188faa1795aSjb 	if (status == NT_STATUS_SHARING_VIOLATION) {
1897b59d02dSjb 		smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
1907b59d02dSjb 		    ERRDOS, ERROR_SHARING_VIOLATION);
1917b59d02dSjb 	}
1927b59d02dSjb 
1932c2961f8Sjose borrego 	if (status == NT_STATUS_NO_SUCH_FILE) {
1942c2961f8Sjose borrego 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1952c2961f8Sjose borrego 		    ERRDOS, ERROR_FILE_NOT_FOUND);
1962c2961f8Sjose borrego 	}
1972c2961f8Sjose borrego 
1987b59d02dSjb 	return (status);
1997b59d02dSjb }
2007b59d02dSjb 
201da6c28aaSamw /*
202da6c28aaSamw  * smb_open_subr
203da6c28aaSamw  *
204da6c28aaSamw  * Notes on write-through behaviour. It looks like pre-LM0.12 versions
205da6c28aaSamw  * of the protocol specify the write-through mode when a file is opened,
206da6c28aaSamw  * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose,
207da6c28aaSamw  * SmbWriteAndUnlock) don't need to contain a write-through flag.
208da6c28aaSamw  *
209da6c28aaSamw  * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate)
210da6c28aaSamw  * don't indicate which write-through mode to use. Instead the write
211da6c28aaSamw  * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call
212da6c28aaSamw  * basis.
213da6c28aaSamw  *
214da6c28aaSamw  * We don't care which open call was used to get us here, we just need
215da6c28aaSamw  * to ensure that the write-through mode flag is copied from the open
216da6c28aaSamw  * parameters to the node. We test the omode write-through flag in all
217da6c28aaSamw  * write functions.
218da6c28aaSamw  *
219da6c28aaSamw  * This function will return NT status codes but it also raises errors,
220da6c28aaSamw  * in which case it won't return to the caller. Be careful how you
221da6c28aaSamw  * handle things in here.
2228c10a865Sas  *
2238c10a865Sas  * The following rules apply when processing a file open request:
2248c10a865Sas  *
2258c10a865Sas  * - Oplocks must be broken prior to share checking to prevent open
2268c10a865Sas  * starvation due to batch oplocks.  Checking share reservations first
2278c10a865Sas  * could potentially result in unnecessary open failures due to
2288c10a865Sas  * open/close batching on the client.
2298c10a865Sas  *
2308c10a865Sas  * - Share checks must take place prior to access checks for correct
2318c10a865Sas  * Windows semantics and to prevent unnecessary NFS delegation recalls.
2328c10a865Sas  *
2338c10a865Sas  * - Oplocks must be acquired after open to ensure the correct
2348c10a865Sas  * synchronization with NFS delegation and FEM installation.
235c8ec8eeaSjose borrego  *
236c8ec8eeaSjose borrego  *
237c8ec8eeaSjose borrego  * DOS readonly bit rules
238c8ec8eeaSjose borrego  *
239c8ec8eeaSjose borrego  * 1. The creator of a readonly file can write to/modify the size of the file
240c8ec8eeaSjose borrego  * using the original create fid, even though the file will appear as readonly
241c8ec8eeaSjose borrego  * to all other fids and via a CIFS getattr call.
242c8ec8eeaSjose borrego  *
243c8ec8eeaSjose borrego  * 2. A setinfo operation (using either an open fid or a path) to set/unset
244c8ec8eeaSjose borrego  * readonly will be successful regardless of whether a creator of a readonly
245c8ec8eeaSjose borrego  * file has an open fid (and has the special privilege mentioned in #1,
246c8ec8eeaSjose borrego  * above).  I.e., the creator of a readonly fid holding that fid will no longer
247c8ec8eeaSjose borrego  * have a special privilege.
248c8ec8eeaSjose borrego  *
249c8ec8eeaSjose borrego  * 3. The DOS readonly bit affects only data and some metadata.
250c8ec8eeaSjose borrego  * The following metadata can be changed regardless of the readonly bit:
251c8ec8eeaSjose borrego  * 	- security descriptors
252c8ec8eeaSjose borrego  *	- DOS attributes
253c8ec8eeaSjose borrego  *	- timestamps
254c8ec8eeaSjose borrego  *
255c8ec8eeaSjose borrego  * In the current implementation, the file size cannot be changed (except for
256c8ec8eeaSjose borrego  * the exceptions in #1 and #2, above).
2572c1b14e5Sjose borrego  *
2582c1b14e5Sjose borrego  *
2592c1b14e5Sjose borrego  * DOS attribute rules
2602c1b14e5Sjose borrego  *
2612c1b14e5Sjose borrego  * These rules are specific to creating / opening files and directories.
2622c1b14e5Sjose borrego  * How the attribute value (specifically ZERO or FILE_ATTRIBUTE_NORMAL)
2632c1b14e5Sjose borrego  * should be interpreted may differ in other requests.
2642c1b14e5Sjose borrego  *
2652c1b14e5Sjose borrego  * - An attribute value equal to ZERO or FILE_ATTRIBUTE_NORMAL means that the
2662c1b14e5Sjose borrego  *   file's attributes should be cleared.
2672c1b14e5Sjose borrego  * - If FILE_ATTRIBUTE_NORMAL is specified with any other attributes,
2682c1b14e5Sjose borrego  *   FILE_ATTRIBUTE_NORMAL is ignored.
2692c1b14e5Sjose borrego  *
2702c1b14e5Sjose borrego  * 1. Creating a new file
2712c1b14e5Sjose borrego  * - The request attributes + FILE_ATTRIBUTE_ARCHIVE are applied to the file.
2722c1b14e5Sjose borrego  *
2732c1b14e5Sjose borrego  * 2. Creating a new directory
2742c1b14e5Sjose borrego  * - The request attributes + FILE_ATTRIBUTE_DIRECTORY are applied to the file.
2752c1b14e5Sjose borrego  * - FILE_ATTRIBUTE_ARCHIVE does not get set.
2762c1b14e5Sjose borrego  *
2772c1b14e5Sjose borrego  * 3. Overwriting an existing file
2782c1b14e5Sjose borrego  * - the request attributes are used as search attributes. If the existing
2792c1b14e5Sjose borrego  *   file does not meet the search criteria access is denied.
2802c1b14e5Sjose borrego  * - otherwise, applies attributes + FILE_ATTRIBUTE_ARCHIVE.
2812c1b14e5Sjose borrego  *
2822c1b14e5Sjose borrego  * 4. Opening an existing file or directory
2832c1b14e5Sjose borrego  *    The request attributes are ignored.
284da6c28aaSamw  */
2857b59d02dSjb static uint32_t
2867b59d02dSjb smb_open_subr(smb_request_t *sr)
287da6c28aaSamw {
2882c2961f8Sjose borrego 	int		created = 0;
2892c2961f8Sjose borrego 	smb_node_t	*node = NULL;
2902c2961f8Sjose borrego 	smb_node_t	*dnode = NULL;
2912c2961f8Sjose borrego 	smb_node_t	*cur_node;
2922c2961f8Sjose borrego 	open_param_t	*op = &sr->arg.open;
2932c2961f8Sjose borrego 	int		rc;
2942c2961f8Sjose borrego 	smb_ofile_t	*of;
2952c2961f8Sjose borrego 	smb_attr_t	new_attr;
2962c2961f8Sjose borrego 	int		pathlen;
2972c2961f8Sjose borrego 	int		max_requested = 0;
2982c2961f8Sjose borrego 	uint32_t	max_allowed;
2992c2961f8Sjose borrego 	uint32_t	status = NT_STATUS_SUCCESS;
3002c2961f8Sjose borrego 	int		is_dir;
3012c2961f8Sjose borrego 	smb_error_t	err;
3022c2961f8Sjose borrego 	boolean_t	is_stream = B_FALSE;
3032c2961f8Sjose borrego 	int		lookup_flags = SMB_FOLLOW_LINKS;
3042c2961f8Sjose borrego 	uint32_t	daccess;
3052c2961f8Sjose borrego 	uint32_t	uniq_fid;
306da6c28aaSamw 
307da6c28aaSamw 	is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
308da6c28aaSamw 
309da6c28aaSamw 	if (is_dir) {
310da6c28aaSamw 		/*
3117b59d02dSjb 		 * The object being created or opened is a directory,
3127b59d02dSjb 		 * and the Disposition parameter must be one of
3137b59d02dSjb 		 * FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF
314da6c28aaSamw 		 */
315da6c28aaSamw 		if ((op->create_disposition != FILE_CREATE) &&
316da6c28aaSamw 		    (op->create_disposition != FILE_OPEN_IF) &&
317da6c28aaSamw 		    (op->create_disposition != FILE_OPEN)) {
318dc20a302Sas 			smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
319da6c28aaSamw 			    ERRDOS, ERROR_INVALID_ACCESS);
3207b59d02dSjb 			return (NT_STATUS_INVALID_PARAMETER);
321da6c28aaSamw 		}
322da6c28aaSamw 	}
323da6c28aaSamw 
324da6c28aaSamw 	if (op->desired_access & MAXIMUM_ALLOWED) {
325da6c28aaSamw 		max_requested = 1;
326da6c28aaSamw 		op->desired_access &= ~MAXIMUM_ALLOWED;
327da6c28aaSamw 	}
328da6c28aaSamw 	op->desired_access = smb_access_generic_to_file(op->desired_access);
329da6c28aaSamw 
330da6c28aaSamw 	if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) {
331da6c28aaSamw 		ASSERT(sr->uid_user);
332da6c28aaSamw 		cmn_err(CE_NOTE, "smbd[%s\\%s]: %s", sr->uid_user->u_domain,
333da6c28aaSamw 		    sr->uid_user->u_name,
334da6c28aaSamw 		    xlate_nt_status(NT_STATUS_TOO_MANY_OPENED_FILES));
335da6c28aaSamw 
336dc20a302Sas 		smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
337da6c28aaSamw 		    ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
3387b59d02dSjb 		return (NT_STATUS_TOO_MANY_OPENED_FILES);
339da6c28aaSamw 	}
340da6c28aaSamw 
341da6c28aaSamw 	/* This must be NULL at this point */
342da6c28aaSamw 	sr->fid_ofile = NULL;
343da6c28aaSamw 
344da6c28aaSamw 	op->devstate = 0;
345da6c28aaSamw 
346da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
347da6c28aaSamw 	case STYPE_DISKTREE:
348da6c28aaSamw 		break;
349da6c28aaSamw 
350da6c28aaSamw 	case STYPE_IPC:
351da6c28aaSamw 		/*
352da6c28aaSamw 		 * No further processing for IPC, we need to either
353da6c28aaSamw 		 * raise an exception or return success here.
354da6c28aaSamw 		 */
3553db3f65cSamw 		if ((status = smb_opipe_open(sr)) != NT_STATUS_SUCCESS)
3567b59d02dSjb 			smbsr_error(sr, status, 0, 0);
3577b59d02dSjb 		return (status);
358da6c28aaSamw 
359da6c28aaSamw 	default:
3607b59d02dSjb 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
3617b59d02dSjb 		    ERRDOS, ERROR_BAD_DEV_TYPE);
3627b59d02dSjb 		return (NT_STATUS_BAD_DEVICE_TYPE);
363da6c28aaSamw 	}
364da6c28aaSamw 
365da6c28aaSamw 	if ((pathlen = strlen(op->fqi.path)) >= MAXPATHLEN) {
366dc20a302Sas 		smbsr_error(sr, 0, ERRSRV, ERRfilespecs);
3677b59d02dSjb 		return (NT_STATUS_NAME_TOO_LONG);
368da6c28aaSamw 	}
369da6c28aaSamw 
370da6c28aaSamw 	/*
371da6c28aaSamw 	 * Some clients pass null file names; NT interprets this as "\".
372da6c28aaSamw 	 */
373da6c28aaSamw 	if (pathlen == 0) {
374da6c28aaSamw 		op->fqi.path = "\\";
375da6c28aaSamw 		pathlen = 1;
376da6c28aaSamw 	}
377da6c28aaSamw 
378da6c28aaSamw 	op->fqi.srch_attr = op->fqi.srch_attr;
379da6c28aaSamw 
380da6c28aaSamw 	if ((status = smb_validate_object_name(op->fqi.path, is_dir)) != 0) {
381dc20a302Sas 		smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
3827b59d02dSjb 		return (status);
383da6c28aaSamw 	}
384da6c28aaSamw 
385da6c28aaSamw 	cur_node = op->fqi.dir_snode ?
386da6c28aaSamw 	    op->fqi.dir_snode : sr->tid_tree->t_snode;
387da6c28aaSamw 
388da6c28aaSamw 	if (rc = smb_pathname_reduce(sr, sr->user_cr, op->fqi.path,
389da6c28aaSamw 	    sr->tid_tree->t_snode, cur_node, &op->fqi.dir_snode,
390da6c28aaSamw 	    op->fqi.last_comp)) {
391dc20a302Sas 		smbsr_errno(sr, rc);
3927b59d02dSjb 		return (sr->smb_error.status);
393da6c28aaSamw 	}
394da6c28aaSamw 
395da6c28aaSamw 	/*
396da6c28aaSamw 	 * If the access mask has only DELETE set (ignore
397da6c28aaSamw 	 * FILE_READ_ATTRIBUTES), then assume that this
398da6c28aaSamw 	 * is a request to delete the link (if a link)
399da6c28aaSamw 	 * and do not follow links.  Otherwise, follow
400da6c28aaSamw 	 * the link to the target.
401da6c28aaSamw 	 */
402da6c28aaSamw 
403da6c28aaSamw 	daccess = op->desired_access & ~FILE_READ_ATTRIBUTES;
404da6c28aaSamw 
405da6c28aaSamw 	if (daccess == DELETE)
406da6c28aaSamw 		lookup_flags &= ~SMB_FOLLOW_LINKS;
407da6c28aaSamw 
408da6c28aaSamw 	rc = smb_fsop_lookup_name(sr, kcred, lookup_flags,
409da6c28aaSamw 	    sr->tid_tree->t_snode, op->fqi.dir_snode, op->fqi.last_comp,
410da6c28aaSamw 	    &op->fqi.last_snode, &op->fqi.last_attr);
411da6c28aaSamw 
412da6c28aaSamw 	if (rc == 0) {
413da6c28aaSamw 		op->fqi.last_comp_was_found = 1;
414da6c28aaSamw 		(void) strcpy(op->fqi.last_comp_od,
415da6c28aaSamw 		    op->fqi.last_snode->od_name);
416da6c28aaSamw 	} else if (rc == ENOENT) {
417da6c28aaSamw 		op->fqi.last_comp_was_found = 0;
418da6c28aaSamw 		op->fqi.last_snode = NULL;
419da6c28aaSamw 		rc = 0;
420da6c28aaSamw 	} else {
421da6c28aaSamw 		smb_node_release(op->fqi.dir_snode);
422da6c28aaSamw 		SMB_NULL_FQI_NODES(op->fqi);
423dc20a302Sas 		smbsr_errno(sr, rc);
4247b59d02dSjb 		return (sr->smb_error.status);
425da6c28aaSamw 	}
426da6c28aaSamw 
427dc20a302Sas 	/*
428dc20a302Sas 	 * The uniq_fid is a CIFS-server-wide unique identifier for an ofile
429dc20a302Sas 	 * which is used to uniquely identify open instances for the
430c8ec8eeaSjose borrego 	 * VFS share reservation and POSIX locks.
431dc20a302Sas 	 */
432dc20a302Sas 
433dc20a302Sas 	uniq_fid = SMB_UNIQ_FID();
434dc20a302Sas 
435da6c28aaSamw 	if (op->fqi.last_comp_was_found) {
4366537f381Sas 
4376537f381Sas 		if ((op->fqi.last_attr.sa_vattr.va_type != VREG) &&
4386537f381Sas 		    (op->fqi.last_attr.sa_vattr.va_type != VDIR) &&
4396537f381Sas 		    (op->fqi.last_attr.sa_vattr.va_type != VLNK)) {
4406537f381Sas 
4416537f381Sas 			smb_node_release(op->fqi.last_snode);
4426537f381Sas 			smb_node_release(op->fqi.dir_snode);
4436537f381Sas 			SMB_NULL_FQI_NODES(op->fqi);
4446537f381Sas 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
4456537f381Sas 			    ERRnoaccess);
4466537f381Sas 			return (NT_STATUS_ACCESS_DENIED);
4476537f381Sas 		}
4486537f381Sas 
449da6c28aaSamw 		node = op->fqi.last_snode;
450da6c28aaSamw 		dnode = op->fqi.dir_snode;
451da6c28aaSamw 
452da6c28aaSamw 		/*
4532c1b14e5Sjose borrego 		 * Reject this request if either:
4542c1b14e5Sjose borrego 		 * - the target IS a directory and the client requires that
4552c1b14e5Sjose borrego 		 *   it must NOT be (required by Lotus Notes)
4562c1b14e5Sjose borrego 		 * - the target is NOT a directory and client requires that
4572c1b14e5Sjose borrego 		 *   it MUST be.
458da6c28aaSamw 		 */
459da6c28aaSamw 		if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
4602c1b14e5Sjose borrego 			if (op->create_options & FILE_NON_DIRECTORY_FILE) {
461da6c28aaSamw 				smb_node_release(node);
462da6c28aaSamw 				smb_node_release(dnode);
463da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
464dc20a302Sas 				smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
465da6c28aaSamw 				    ERRDOS, ERROR_ACCESS_DENIED);
4667b59d02dSjb 				return (NT_STATUS_FILE_IS_A_DIRECTORY);
467da6c28aaSamw 			}
4682c1b14e5Sjose borrego 		} else {
4692c1b14e5Sjose borrego 			if ((op->create_options & FILE_DIRECTORY_FILE) ||
4702c2961f8Sjose borrego 			    (op->nt_flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)) {
4712c1b14e5Sjose borrego 				smb_node_release(node);
4722c1b14e5Sjose borrego 				smb_node_release(dnode);
4732c1b14e5Sjose borrego 				SMB_NULL_FQI_NODES(op->fqi);
4742c1b14e5Sjose borrego 				smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
4752c1b14e5Sjose borrego 				    ERRDOS, ERROR_DIRECTORY);
4762c1b14e5Sjose borrego 				return (NT_STATUS_NOT_A_DIRECTORY);
4772c1b14e5Sjose borrego 			}
478da6c28aaSamw 		}
479da6c28aaSamw 
480da6c28aaSamw 		/*
481da6c28aaSamw 		 * No more open should be accepted when "Delete on close"
482da6c28aaSamw 		 * flag is set.
483da6c28aaSamw 		 */
484da6c28aaSamw 		if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
485da6c28aaSamw 			smb_node_release(node);
486da6c28aaSamw 			smb_node_release(dnode);
487da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
488dc20a302Sas 			smbsr_error(sr, NT_STATUS_DELETE_PENDING,
489da6c28aaSamw 			    ERRDOS, ERROR_ACCESS_DENIED);
4907b59d02dSjb 			return (NT_STATUS_DELETE_PENDING);
491da6c28aaSamw 		}
492da6c28aaSamw 
493da6c28aaSamw 		/*
494da6c28aaSamw 		 * Specified file already exists so the operation should fail.
495da6c28aaSamw 		 */
496da6c28aaSamw 		if (op->create_disposition == FILE_CREATE) {
497da6c28aaSamw 			smb_node_release(node);
498da6c28aaSamw 			smb_node_release(dnode);
499da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
500dc20a302Sas 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
501b89a8333Snatalie li - Sun Microsystems - Irvine United States 			    ERRDOS, ERROR_FILE_EXISTS);
5027b59d02dSjb 			return (NT_STATUS_OBJECT_NAME_COLLISION);
503da6c28aaSamw 		}
504da6c28aaSamw 
505da6c28aaSamw 		/*
506da6c28aaSamw 		 * Windows seems to check read-only access before file
507da6c28aaSamw 		 * sharing check.
508c8ec8eeaSjose borrego 		 *
509c8ec8eeaSjose borrego 		 * Check to see if the file is currently readonly (irrespective
510c8ec8eeaSjose borrego 		 * of whether this open will make it readonly).
511da6c28aaSamw 		 */
512c8ec8eeaSjose borrego 		if (SMB_PATHFILE_IS_READONLY(sr, node)) {
513da6c28aaSamw 			/* Files data only */
514da6c28aaSamw 			if (node->attr.sa_vattr.va_type != VDIR) {
515da6c28aaSamw 				if (op->desired_access & (FILE_WRITE_DATA |
516da6c28aaSamw 				    FILE_APPEND_DATA)) {
517da6c28aaSamw 					smb_node_release(node);
518da6c28aaSamw 					smb_node_release(dnode);
519da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
520dc20a302Sas 					smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
521dc20a302Sas 					    ERRDOS, ERRnoaccess);
5227b59d02dSjb 					return (NT_STATUS_ACCESS_DENIED);
523da6c28aaSamw 				}
524da6c28aaSamw 			}
525da6c28aaSamw 		}
526da6c28aaSamw 
5278c10a865Sas 		if (smb_oplock_conflict(node, sr->session, op))
528fc724630SAlan Wright 			(void) smb_oplock_break(node, sr->session, B_FALSE);
5298c10a865Sas 
5302c2961f8Sjose borrego 		smb_node_wrlock(node);
531dc20a302Sas 
532dc20a302Sas 		if ((op->create_disposition == FILE_SUPERSEDE) ||
533dc20a302Sas 		    (op->create_disposition == FILE_OVERWRITE_IF) ||
534dc20a302Sas 		    (op->create_disposition == FILE_OVERWRITE)) {
535dc20a302Sas 
5362c1b14e5Sjose borrego 			if ((!(op->desired_access &
5378c10a865Sas 			    (FILE_WRITE_DATA | FILE_APPEND_DATA |
5382c1b14e5Sjose borrego 			    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) ||
5397f667e74Sjose borrego 			    (!smb_sattr_check(node->attr.sa_dosattr,
5402c2961f8Sjose borrego 			    op->dattr))) {
5412c2961f8Sjose borrego 				smb_node_unlock(node);
542dc20a302Sas 				smb_node_release(node);
543dc20a302Sas 				smb_node_release(dnode);
544dc20a302Sas 				SMB_NULL_FQI_NODES(op->fqi);
545dc20a302Sas 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
546dc20a302Sas 				    ERRDOS, ERRnoaccess);
5477b59d02dSjb 				return (NT_STATUS_ACCESS_DENIED);
548dc20a302Sas 			}
549dc20a302Sas 		}
550dc20a302Sas 
551dc20a302Sas 		status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
552c8ec8eeaSjose borrego 		    op->desired_access, op->share_access);
553dc20a302Sas 
554da6c28aaSamw 		if (status == NT_STATUS_SHARING_VIOLATION) {
5552c2961f8Sjose borrego 			smb_node_unlock(node);
556da6c28aaSamw 			smb_node_release(node);
557da6c28aaSamw 			smb_node_release(dnode);
558da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
559da6c28aaSamw 			return (status);
560da6c28aaSamw 		}
561da6c28aaSamw 
562da6c28aaSamw 		status = smb_fsop_access(sr, sr->user_cr, node,
563da6c28aaSamw 		    op->desired_access);
564da6c28aaSamw 
565da6c28aaSamw 		if (status != NT_STATUS_SUCCESS) {
566dc20a302Sas 			smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
567dc20a302Sas 
5682c2961f8Sjose borrego 			smb_node_unlock(node);
569da6c28aaSamw 			smb_node_release(node);
570da6c28aaSamw 			smb_node_release(dnode);
571da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
572dc20a302Sas 
573da6c28aaSamw 			if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
574dc20a302Sas 				smbsr_error(sr, status,
575dc20a302Sas 				    ERRDOS, ERROR_PRIVILEGE_NOT_HELD);
5767b59d02dSjb 				return (status);
577da6c28aaSamw 			} else {
578dc20a302Sas 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
579dc20a302Sas 				    ERRDOS, ERROR_ACCESS_DENIED);
5807b59d02dSjb 				return (NT_STATUS_ACCESS_DENIED);
581da6c28aaSamw 			}
582da6c28aaSamw 		}
583da6c28aaSamw 
584da6c28aaSamw 		switch (op->create_disposition) {
585da6c28aaSamw 		case FILE_SUPERSEDE:
586da6c28aaSamw 		case FILE_OVERWRITE_IF:
587da6c28aaSamw 		case FILE_OVERWRITE:
588da6c28aaSamw 			if (node->attr.sa_vattr.va_type == VDIR) {
589dc20a302Sas 				smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
5902c2961f8Sjose borrego 				smb_node_unlock(node);
591da6c28aaSamw 				smb_node_release(node);
592da6c28aaSamw 				smb_node_release(dnode);
593da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
594dc20a302Sas 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
595dc20a302Sas 				    ERRDOS, ERROR_ACCESS_DENIED);
5967b59d02dSjb 				return (NT_STATUS_ACCESS_DENIED);
597da6c28aaSamw 			}
598da6c28aaSamw 
599da6c28aaSamw 			if (node->attr.sa_vattr.va_size != op->dsize) {
600da6c28aaSamw 				node->flags &= ~NODE_FLAGS_SET_SIZE;
601dc20a302Sas 				bzero(&new_attr, sizeof (new_attr));
602da6c28aaSamw 				new_attr.sa_vattr.va_size = op->dsize;
603da6c28aaSamw 				new_attr.sa_mask = SMB_AT_SIZE;
604dc20a302Sas 
605dc20a302Sas 				rc = smb_fsop_setattr(sr, sr->user_cr,
606dc20a302Sas 				    node, &new_attr, &op->fqi.last_attr);
607dc20a302Sas 
608dc20a302Sas 				if (rc) {
609faa1795aSjb 					smb_fsop_unshrlock(sr->user_cr, node,
610faa1795aSjb 					    uniq_fid);
6112c2961f8Sjose borrego 					smb_node_unlock(node);
612da6c28aaSamw 					smb_node_release(node);
613da6c28aaSamw 					smb_node_release(dnode);
614da6c28aaSamw 					SMB_NULL_FQI_NODES(op->fqi);
615dc20a302Sas 					smbsr_errno(sr, rc);
6167b59d02dSjb 					return (sr->smb_error.status);
617da6c28aaSamw 				}
618da6c28aaSamw 
619dc20a302Sas 				op->dsize = op->fqi.last_attr.sa_vattr.va_size;
620da6c28aaSamw 			}
621da6c28aaSamw 
6222c1b14e5Sjose borrego 			op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
6232c1b14e5Sjose borrego 			if (op->dattr & FILE_ATTRIBUTE_READONLY) {
6242c1b14e5Sjose borrego 				op->created_readonly = B_TRUE;
6252c1b14e5Sjose borrego 				op->dattr &= ~FILE_ATTRIBUTE_READONLY;
6262c1b14e5Sjose borrego 			}
6272c1b14e5Sjose borrego 
6282c1b14e5Sjose borrego 			smb_node_set_dosattr(node, op->dattr);
6292c1b14e5Sjose borrego 			(void) smb_sync_fsattr(sr, sr->user_cr, node);
6302c1b14e5Sjose borrego 
631da6c28aaSamw 			/*
632da6c28aaSamw 			 * If file is being replaced,
633da6c28aaSamw 			 * we should remove existing streams
634da6c28aaSamw 			 */
635da6c28aaSamw 			if (SMB_IS_STREAM(node) == 0)
636da6c28aaSamw 				(void) smb_fsop_remove_streams(sr, sr->user_cr,
637da6c28aaSamw 				    node);
638da6c28aaSamw 
639da6c28aaSamw 			op->action_taken = SMB_OACT_TRUNCATED;
640da6c28aaSamw 			break;
641da6c28aaSamw 
642da6c28aaSamw 		default:
643da6c28aaSamw 			/*
644da6c28aaSamw 			 * FILE_OPEN or FILE_OPEN_IF.
645da6c28aaSamw 			 */
646da6c28aaSamw 			op->action_taken = SMB_OACT_OPENED;
647da6c28aaSamw 			break;
648da6c28aaSamw 		}
649da6c28aaSamw 	} else {
650da6c28aaSamw 		/* Last component was not found. */
651da6c28aaSamw 		dnode = op->fqi.dir_snode;
652da6c28aaSamw 
6537b59d02dSjb 		if (is_dir == 0)
6548d7e4166Sjose borrego 			is_stream = smb_is_stream_name(op->fqi.path);
6557b59d02dSjb 
656da6c28aaSamw 		if ((op->create_disposition == FILE_OPEN) ||
657da6c28aaSamw 		    (op->create_disposition == FILE_OVERWRITE)) {
658da6c28aaSamw 			smb_node_release(dnode);
659da6c28aaSamw 			SMB_NULL_FQI_NODES(op->fqi);
660faa1795aSjb 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
661faa1795aSjb 			    ERRDOS, ERROR_FILE_NOT_FOUND);
6627b59d02dSjb 			return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
663da6c28aaSamw 		}
664da6c28aaSamw 
6652c2961f8Sjose borrego 		if ((is_dir == 0) && (!is_stream) &&
6662c2961f8Sjose borrego 		    smb_is_invalid_filename(op->fqi.last_comp)) {
6672c2961f8Sjose borrego 			smb_node_release(dnode);
6682c2961f8Sjose borrego 			SMB_NULL_FQI_NODES(op->fqi);
6692c2961f8Sjose borrego 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
6702c2961f8Sjose borrego 			    ERRDOS, ERROR_INVALID_NAME);
6712c2961f8Sjose borrego 			return (NT_STATUS_OBJECT_NAME_INVALID);
6722c2961f8Sjose borrego 		}
6732c2961f8Sjose borrego 
674da6c28aaSamw 		/*
675da6c28aaSamw 		 * lock the parent dir node in case another create
676da6c28aaSamw 		 * request to the same parent directory comes in.
677da6c28aaSamw 		 */
6782c2961f8Sjose borrego 		smb_node_wrlock(dnode);
679da6c28aaSamw 
680da6c28aaSamw 		bzero(&new_attr, sizeof (new_attr));
6812c1b14e5Sjose borrego 		new_attr.sa_dosattr = op->dattr;
6822c1b14e5Sjose borrego 		new_attr.sa_mask |= SMB_AT_DOSATTR;
683c8ec8eeaSjose borrego 
684c8ec8eeaSjose borrego 		/*
685c8ec8eeaSjose borrego 		 * A file created with the readonly bit should not
686c8ec8eeaSjose borrego 		 * stop the creator writing to the file until it is
687c8ec8eeaSjose borrego 		 * closed.  Although the readonly bit will not be set
688c8ec8eeaSjose borrego 		 * on the file until it is closed, it will be accounted
689c8ec8eeaSjose borrego 		 * for on other fids and on queries based on the node
690c8ec8eeaSjose borrego 		 * state.
691c8ec8eeaSjose borrego 		 */
6922c1b14e5Sjose borrego 		if (op->dattr & FILE_ATTRIBUTE_READONLY)
6932c1b14e5Sjose borrego 			new_attr.sa_dosattr &= ~FILE_ATTRIBUTE_READONLY;
694c8ec8eeaSjose borrego 
695c8ec8eeaSjose borrego 
696c8ec8eeaSjose borrego 		if ((op->crtime.tv_sec != 0) &&
697c8ec8eeaSjose borrego 		    (op->crtime.tv_sec != UINT_MAX)) {
698c8ec8eeaSjose borrego 
699c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_CRTIME;
700c8ec8eeaSjose borrego 			new_attr.sa_crtime = op->crtime;
701c8ec8eeaSjose borrego 		}
702c8ec8eeaSjose borrego 
703da6c28aaSamw 		if (is_dir == 0) {
7042c1b14e5Sjose borrego 			new_attr.sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
705da6c28aaSamw 			new_attr.sa_vattr.va_type = VREG;
7067b59d02dSjb 			new_attr.sa_vattr.va_mode = is_stream ? S_IRUSR :
7077b59d02dSjb 			    S_IRUSR | S_IRGRP | S_IROTH |
7087b59d02dSjb 			    S_IWUSR | S_IWGRP | S_IWOTH;
709c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
710dc20a302Sas 
7116537f381Sas 			if (op->dsize) {
7126537f381Sas 				new_attr.sa_vattr.va_size = op->dsize;
7136537f381Sas 				new_attr.sa_mask |= SMB_AT_SIZE;
714dc20a302Sas 			}
715dc20a302Sas 
716da6c28aaSamw 			rc = smb_fsop_create(sr, sr->user_cr, dnode,
717da6c28aaSamw 			    op->fqi.last_comp, &new_attr,
718da6c28aaSamw 			    &op->fqi.last_snode, &op->fqi.last_attr);
719dc20a302Sas 
720da6c28aaSamw 			if (rc != 0) {
7212c2961f8Sjose borrego 				smb_node_unlock(dnode);
722da6c28aaSamw 				smb_node_release(dnode);
723da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
724dc20a302Sas 				smbsr_errno(sr, rc);
7257b59d02dSjb 				return (sr->smb_error.status);
726da6c28aaSamw 			}
727da6c28aaSamw 
728dc20a302Sas 			node = op->fqi.last_snode;
729dc20a302Sas 
730c8ec8eeaSjose borrego 			op->fqi.last_attr = node->attr;
731c8ec8eeaSjose borrego 
7322c2961f8Sjose borrego 			smb_node_wrlock(node);
733dc20a302Sas 
734faa1795aSjb 			status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
735c8ec8eeaSjose borrego 			    op->desired_access, op->share_access);
736dc20a302Sas 
737dc20a302Sas 			if (status == NT_STATUS_SHARING_VIOLATION) {
7382c2961f8Sjose borrego 				smb_node_unlock(node);
739*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 				if (created)
740*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 					smb_delete_new_object(sr);
741dc20a302Sas 				smb_node_release(node);
7422c2961f8Sjose borrego 				smb_node_unlock(dnode);
743dc20a302Sas 				smb_node_release(dnode);
744dc20a302Sas 				SMB_NULL_FQI_NODES(op->fqi);
745dc20a302Sas 				return (status);
746dc20a302Sas 			}
747da6c28aaSamw 		} else {
7483db3f65cSamw 			op->dattr |= FILE_ATTRIBUTE_DIRECTORY;
749da6c28aaSamw 			new_attr.sa_vattr.va_type = VDIR;
750da6c28aaSamw 			new_attr.sa_vattr.va_mode = 0777;
751c8ec8eeaSjose borrego 			new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
752c8ec8eeaSjose borrego 
753da6c28aaSamw 			rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
754da6c28aaSamw 			    op->fqi.last_comp, &new_attr,
755da6c28aaSamw 			    &op->fqi.last_snode, &op->fqi.last_attr);
756da6c28aaSamw 			if (rc != 0) {
7572c2961f8Sjose borrego 				smb_node_unlock(dnode);
758da6c28aaSamw 				smb_node_release(dnode);
759da6c28aaSamw 				SMB_NULL_FQI_NODES(op->fqi);
760dc20a302Sas 				smbsr_errno(sr, rc);
7617b59d02dSjb 				return (sr->smb_error.status);
762da6c28aaSamw 			}
763dc20a302Sas 
764dc20a302Sas 			node = op->fqi.last_snode;
7652c2961f8Sjose borrego 			smb_node_wrlock(node);
766da6c28aaSamw 		}
767da6c28aaSamw 
768da6c28aaSamw 		created = 1;
769da6c28aaSamw 		op->action_taken = SMB_OACT_CREATED;
770c8ec8eeaSjose borrego 		node->flags |= NODE_FLAGS_CREATED;
771c8ec8eeaSjose borrego 
772c8ec8eeaSjose borrego 		if (op->dattr & FILE_ATTRIBUTE_READONLY) {
773c8ec8eeaSjose borrego 			op->created_readonly = B_TRUE;
774c8ec8eeaSjose borrego 			op->dattr &= ~FILE_ATTRIBUTE_READONLY;
775c8ec8eeaSjose borrego 		}
7762c1b14e5Sjose borrego 	}
777c8ec8eeaSjose borrego 
7782c1b14e5Sjose borrego 	op->dattr = smb_node_get_dosattr(node);
779c8ec8eeaSjose borrego 
7802c1b14e5Sjose borrego 	if (max_requested) {
7812c1b14e5Sjose borrego 		smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed);
7822c1b14e5Sjose borrego 		op->desired_access |= max_allowed;
783c8ec8eeaSjose borrego 	}
784c8ec8eeaSjose borrego 
7852c1b14e5Sjose borrego 	/*
7862c1b14e5Sjose borrego 	 * if last_write time was in request and is not 0 or -1,
7872c1b14e5Sjose borrego 	 * use it as file's mtime
7882c1b14e5Sjose borrego 	 */
7892c1b14e5Sjose borrego 	if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) {
7902c1b14e5Sjose borrego 		smb_node_set_time(node, NULL, &op->mtime, NULL, NULL,
7912c1b14e5Sjose borrego 		    SMB_AT_MTIME);
7922c1b14e5Sjose borrego 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
7932c1b14e5Sjose borrego 	}
794c8ec8eeaSjose borrego 
795c8ec8eeaSjose borrego 	of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op, SMB_FTYPE_DISK,
796c8ec8eeaSjose borrego 	    uniq_fid, &err);
797da6c28aaSamw 
798da6c28aaSamw 	if (of == NULL) {
799dc20a302Sas 		smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
800*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (created)
801*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_delete_new_object(sr);
8022c2961f8Sjose borrego 		smb_node_unlock(node);
803da6c28aaSamw 		smb_node_release(node);
804da6c28aaSamw 		if (created)
8052c2961f8Sjose borrego 			smb_node_unlock(dnode);
806da6c28aaSamw 		smb_node_release(dnode);
807da6c28aaSamw 		SMB_NULL_FQI_NODES(op->fqi);
808dc20a302Sas 		smbsr_error(sr, err.status, err.errcls, err.errcode);
8097b59d02dSjb 		return (err.status);
810da6c28aaSamw 	}
811da6c28aaSamw 
812*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (!smb_tree_is_connected(sr->tid_tree)) {
813*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_ofile_close(of, 0);
814*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_ofile_release(of);
815*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (created)
816*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_delete_new_object(sr);
817*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_unlock(node);
818*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(node);
819*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (created)
820*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_unlock(dnode);
821*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(dnode);
822*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		SMB_NULL_FQI_NODES(op->fqi);
823*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_error(sr, 0, ERRSRV, ERRinvnid);
824*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (NT_STATUS_UNSUCCESSFUL);
825*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
826*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
8278c10a865Sas 	/*
8288c10a865Sas 	 * Propagate the write-through mode from the open params
8298c10a865Sas 	 * to the node: see the notes in the function header.
8308c10a865Sas 	 */
8318c10a865Sas 	if (sr->sr_cfg->skc_sync_enable ||
8328c10a865Sas 	    (op->create_options & FILE_WRITE_THROUGH))
8338c10a865Sas 		node->flags |= NODE_FLAGS_WRITE_THROUGH;
8348c10a865Sas 
8358c10a865Sas 	op->fileid = op->fqi.last_attr.sa_vattr.va_nodeid;
8368c10a865Sas 
837da6c28aaSamw 	/*
838da6c28aaSamw 	 * Set up the file type in open_param for the response
839da6c28aaSamw 	 */
840da6c28aaSamw 	op->ftype = SMB_FTYPE_DISK;
841da6c28aaSamw 	sr->smb_fid = of->f_fid;
842da6c28aaSamw 	sr->fid_ofile = of;
843da6c28aaSamw 
8442c2961f8Sjose borrego 	smb_node_unlock(node);
845dc20a302Sas 	if (created)
8462c2961f8Sjose borrego 		smb_node_unlock(dnode);
8472c2961f8Sjose borrego 
8482c2961f8Sjose borrego 	if (op->fqi.last_attr.sa_vattr.va_type == VREG) {
8492c2961f8Sjose borrego 		smb_oplock_acquire(node, of, op);
8502c2961f8Sjose borrego 		op->dsize = op->fqi.last_attr.sa_vattr.va_size;
8512c2961f8Sjose borrego 	} else { /* VDIR or VLNK */
8522c2961f8Sjose borrego 		op->op_oplock_level = SMB_OPLOCK_NONE;
8532c2961f8Sjose borrego 		op->dsize = 0;
8542c2961f8Sjose borrego 	}
855dc20a302Sas 
856*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_release(node);
857da6c28aaSamw 	smb_node_release(dnode);
858da6c28aaSamw 	SMB_NULL_FQI_NODES(op->fqi);
859da6c28aaSamw 
860da6c28aaSamw 	return (NT_STATUS_SUCCESS);
861da6c28aaSamw }
862da6c28aaSamw 
863da6c28aaSamw /*
864da6c28aaSamw  * smb_validate_object_name
865da6c28aaSamw  *
8668d7e4166Sjose borrego  * Very basic file name validation.
8678d7e4166Sjose borrego  * Directory validation is handed off to smb_validate_dirname.
8688d7e4166Sjose borrego  * For filenames, we check for names of the form "AAAn:". Names that
8698d7e4166Sjose borrego  * contain three characters, a single digit and a colon (:) are reserved
8708d7e4166Sjose borrego  * as DOS device names, i.e. "COM1:".
8718d7e4166Sjose borrego  * Stream name validation is handed off to smb_validate_stream_name
872da6c28aaSamw  *
873da6c28aaSamw  * Returns NT status codes.
874da6c28aaSamw  */
875da6c28aaSamw uint32_t
876da6c28aaSamw smb_validate_object_name(char *path, unsigned int ftype)
877da6c28aaSamw {
878da6c28aaSamw 	char *filename;
879da6c28aaSamw 
880da6c28aaSamw 	if (path == 0)
881da6c28aaSamw 		return (0);
882da6c28aaSamw 
883da6c28aaSamw 	if (ftype)
884da6c28aaSamw 		return (smb_validate_dirname(path));
885da6c28aaSamw 
886da6c28aaSamw 	/*
887da6c28aaSamw 	 * Basename with backslashes.
888da6c28aaSamw 	 */
889da6c28aaSamw 	if ((filename = strrchr(path, '\\')) != 0)
890da6c28aaSamw 		++filename;
891da6c28aaSamw 	else
892da6c28aaSamw 		filename = path;
893da6c28aaSamw 
894da6c28aaSamw 	if (strlen(filename) == 5 &&
895da6c28aaSamw 	    mts_isdigit(filename[3]) &&
896da6c28aaSamw 	    filename[4] == ':') {
897da6c28aaSamw 		return (NT_STATUS_OBJECT_NAME_INVALID);
898da6c28aaSamw 	}
899da6c28aaSamw 
9008d7e4166Sjose borrego 	if (smb_is_stream_name(path))
9018d7e4166Sjose borrego 		return (smb_validate_stream_name(path));
9028d7e4166Sjose borrego 
903da6c28aaSamw 	return (0);
904da6c28aaSamw }
905da6c28aaSamw 
906*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
907da6c28aaSamw /*
908*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * This function is used to delete a newly created object (file or
909*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * directory) if an error occurs after creation of the object.
910da6c28aaSamw  */
911*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static void
912*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_delete_new_object(smb_request_t *sr)
913da6c28aaSamw {
914*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	open_param_t	*op = &sr->arg.open;
915*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	smb_fqi_t	*fqi = &(op->fqi);
916*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	flags = 0;
917*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
918*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
919*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_IGNORE_CASE;
920*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_TREE_SUPPORTS_CATIA(sr))
921*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags |= SMB_CATIA;
922*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
923*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (op->create_options & FILE_DIRECTORY_FILE)
924*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		(void) smb_fsop_rmdir(sr, sr->user_cr, fqi->dir_snode,
925*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    fqi->last_comp, flags);
926*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	else
927*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		(void) smb_fsop_remove(sr, sr->user_cr, fqi->dir_snode,
928*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    fqi->last_comp, flags);
929da6c28aaSamw }
930