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
39 extern 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 */
54 smb_sdrc_t
smb_pre_nt_transact_create(smb_request_t * sr,smb_xa_t * xa)55 smb_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
123 void
smb_post_nt_transact_create(smb_request_t * sr,smb_xa_t * xa)124 smb_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 */
145 smb_sdrc_t
smb_nt_transact_create(smb_request_t * sr,smb_xa_t * xa)146 smb_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
291 errout:
292 smb_ofile_close(of, 0);
293 return (SDRC_ERROR);
294 }
295