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