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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
24 */
25
26/*
27 * This command is used to create or open a file or directory, when EAs
28 * or an SD must be applied to the file. The functionality is similar
29 * to SmbNtCreateAndx with the option to supply extended attributes or
30 * a security descriptor.
31 *
32 * Note: we don't decode the extended attributes because we don't
33 * support them at this time.
34 */
35
36#include <smbsrv/smb_kproto.h>
37#include <smbsrv/smb_fsops.h>
38
39extern int smb_nt_create_enable_extended_response;
40
41/*
42 * smb_nt_transact_create
43 *
44 * This command is used to create or open a file or directory, when EAs
45 * or an SD must be applied to the file. The request parameter block
46 * encoding, data block encoding and output parameter block encoding are
47 * described in CIFS section 4.2.2.
48 *
49 * The format of the command is SmbNtTransact but it is basically the same
50 * as SmbNtCreateAndx with the option to supply extended attributes or a
51 * security descriptor. For information not defined in CIFS section 4.2.2
52 * see section 4.2.1 (NT_CREATE_ANDX).
53 */
54smb_sdrc_t
55smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
56{
57	struct open_param *op = &sr->arg.open;
58	uint8_t SecurityFlags;
59	uint32_t EaLength;
60	uint32_t ImpersonationLevel;
61	uint32_t NameLength;
62	uint32_t sd_len;
63	uint32_t status;
64	smb_sd_t sd;
65	int rc;
66
67	bzero(op, sizeof (sr->arg.open));
68
69	rc = smb_mbc_decodef(&xa->req_param_mb, "%lllqllllllllb",
70	    sr,
71	    &op->nt_flags,
72	    &op->rootdirfid,
73	    &op->desired_access,
74	    &op->dsize,
75	    &op->dattr,
76	    &op->share_access,
77	    &op->create_disposition,
78	    &op->create_options,
79	    &sd_len,
80	    &EaLength,
81	    &NameLength,
82	    &ImpersonationLevel,
83	    &SecurityFlags);
84
85	if (rc == 0) {
86		if (NameLength == 0) {
87			op->fqi.fq_path.pn_path = "\\";
88		} else if (NameLength >= SMB_MAXPATHLEN) {
89			smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
90			    ERRDOS, ERROR_INVALID_NAME);
91			rc = -1;
92		} else {
93			rc = smb_mbc_decodef(&xa->req_param_mb, "%#u",
94			    sr, NameLength, &op->fqi.fq_path.pn_path);
95		}
96	}
97
98	op->op_oplock_level = SMB_OPLOCK_NONE;
99	if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
100		if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH)
101			op->op_oplock_level = SMB_OPLOCK_BATCH;
102		else
103			op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
104	}
105
106	if (sd_len) {
107		status = smb_decode_sd(&xa->req_data_mb, &sd);
108		if (status != NT_STATUS_SUCCESS) {
109			smbsr_error(sr, status, 0, 0);
110			return (SDRC_ERROR);
111		}
112		op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
113		*op->sd = sd;
114	} else {
115		op->sd = NULL;
116	}
117
118	DTRACE_SMB_START(op__NtTransactCreate, smb_request_t *, sr);
119
120	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
121}
122
123void
124smb_post_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
125{
126	smb_sd_t *sd = sr->arg.open.sd;
127	_NOTE(ARGUNUSED(xa))
128
129	DTRACE_SMB_DONE(op__NtTransactCreate, smb_request_t *, sr);
130
131	if (sd) {
132		smb_sd_term(sd);
133		kmem_free(sd, sizeof (smb_sd_t));
134	}
135
136	if (sr->arg.open.dir != NULL) {
137		smb_ofile_release(sr->arg.open.dir);
138		sr->arg.open.dir = NULL;
139	}
140}
141
142/*
143 * A lot like smb_com_nt_create_andx
144 */
145smb_sdrc_t
146smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
147{
148	struct open_param	*op = &sr->arg.open;
149	smb_attr_t		*ap = &op->fqi.fq_fattr;
150	smb_ofile_t		*of;
151	int			rc;
152	uint8_t			DirFlag;
153	uint32_t		status;
154
155	if (op->create_options & ~SMB_NTCREATE_VALID_OPTIONS) {
156		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
157		    ERRDOS, ERROR_INVALID_PARAMETER);
158		return (SDRC_ERROR);
159	}
160
161	if (op->create_options & FILE_OPEN_BY_FILE_ID) {
162		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
163		    ERRDOS, ERROR_NOT_SUPPORTED);
164		return (SDRC_ERROR);
165	}
166
167	if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
168	    !(op->desired_access & DELETE)) {
169		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
170		    ERRDOS, ERRbadaccess);
171		return (SDRC_ERROR);
172	}
173
174	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
175		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
176		    ERRDOS, ERRbadaccess);
177		return (SDRC_ERROR);
178	}
179
180	if (op->dattr & FILE_FLAG_WRITE_THROUGH)
181		op->create_options |= FILE_WRITE_THROUGH;
182
183	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
184		op->create_options |= FILE_DELETE_ON_CLOSE;
185
186	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
187		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
188
189	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
190		sr->user_cr = smb_user_getprivcred(sr->uid_user);
191
192	if (op->rootdirfid == 0) {
193		op->fqi.fq_dnode = sr->tid_tree->t_snode;
194	} else {
195		op->dir = smb_ofile_lookup_by_fid(sr, (uint16_t)op->rootdirfid);
196		if (op->dir == NULL) {
197			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
198			    ERRDOS, ERRbadfid);
199			return (SDRC_ERROR);
200		}
201		op->fqi.fq_dnode = op->dir->f_node;
202	}
203
204	status = smb_common_open(sr);
205	if (status != NT_STATUS_SUCCESS) {
206		smbsr_status(sr, status, 0, 0);
207		return (SDRC_ERROR);
208	}
209	if (op->op_oplock_level != SMB_OPLOCK_NONE) {
210		/* Oplock req. in op->op_oplock_level etc. */
211		smb1_oplock_acquire(sr, B_TRUE);
212	}
213
214	/*
215	 * NB: after the above smb_common_open() success,
216	 * we have a handle allocated (sr->fid_ofile).
217	 * If we don't return success, we must close it.
218	 */
219	of = sr->fid_ofile;
220
221	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
222	case STYPE_DISKTREE:
223	case STYPE_PRINTQ:
224		if (op->create_options & FILE_DELETE_ON_CLOSE)
225			smb_ofile_set_delete_on_close(sr, of);
226		DirFlag = smb_node_is_dir(of->f_node) ? 1 : 0;
227		break;
228
229	case STYPE_IPC:
230		DirFlag = 0;
231		break;
232
233	default:
234		smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
235		    ERRDOS, ERROR_INVALID_FUNCTION);
236		goto errout;
237	}
238
239	if ((op->nt_flags & NT_CREATE_FLAG_EXTENDED_RESPONSE) != 0 &&
240	    smb_nt_create_enable_extended_response != 0) {
241		uint32_t MaxAccess = 0;
242		if (of->f_node != NULL) {
243			smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);
244		}
245		MaxAccess |= of->f_granted_access;
246
247		rc = smb_mbc_encodef(
248		    &xa->rep_param_mb, "bbwllTTTTlqqwwb16.qll",
249		    op->op_oplock_level,	/* (b) */
250		    1,		/* ResponseType	   (b) */
251		    sr->smb_fid,		/* (w) */
252		    op->action_taken,		/* (l) */
253		    0,		/* EaErrorOffset   (l) */
254		    &ap->sa_crtime,		/* (T) */
255		    &ap->sa_vattr.va_atime,	/* (T) */
256		    &ap->sa_vattr.va_mtime,	/* (T) */
257		    &ap->sa_vattr.va_ctime,	/* (T) */
258		    op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
259		    ap->sa_allocsz,		/* (q) */
260		    ap->sa_vattr.va_size,	/* (q) */
261		    op->ftype,			/* (w) */
262		    op->devstate,		/* (w) */
263		    DirFlag,			/* (b) */
264		    /* volume guid		  (16.) */
265		    op->fileid,			/* (q) */
266		    MaxAccess,			/* (l) */
267		    0);		/* guest access	   (l) */
268	} else {
269		rc = smb_mbc_encodef(
270		    &xa->rep_param_mb, "bbwllTTTTlqqwwb",
271		    op->op_oplock_level,	/* (b) */
272		    0,		/* ResponseType	   (b) */
273		    sr->smb_fid,		/* (w) */
274		    op->action_taken,		/* (l) */
275		    0,		/* EaErrorOffset   (l) */
276		    &ap->sa_crtime,		/* (T) */
277		    &ap->sa_vattr.va_atime,	/* (T) */
278		    &ap->sa_vattr.va_mtime,	/* (T) */
279		    &ap->sa_vattr.va_ctime,	/* (T) */
280		    op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
281		    ap->sa_allocsz,		/* (q) */
282		    ap->sa_vattr.va_size,	/* (q) */
283		    op->ftype,			/* (w) */
284		    op->devstate,		/* (w) */
285		    DirFlag);			/* (b) */
286	}
287
288	if (rc == 0)
289		return (SDRC_SUCCESS);
290
291errout:
292	smb_ofile_close(of, 0);
293	return (SDRC_ERROR);
294}
295