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 2013 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 /*
40 * smb_nt_transact_create
41 *
42 * This command is used to create or open a file or directory, when EAs
43 * or an SD must be applied to the file. The request parameter block
44 * encoding, data block encoding and output parameter block encoding are
45 * described in CIFS section 4.2.2.
46 *
47 * The format of the command is SmbNtTransact but it is basically the same
48 * as SmbNtCreateAndx with the option to supply extended attributes or a
49 * security descriptor. For information not defined in CIFS section 4.2.2
50 * see section 4.2.1 (NT_CREATE_ANDX).
51 */
52 smb_sdrc_t
smb_pre_nt_transact_create(smb_request_t * sr,smb_xa_t * xa)53 smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
54 {
55 struct open_param *op = &sr->arg.open;
56 uint8_t SecurityFlags;
57 uint32_t EaLength;
58 uint32_t ImpersonationLevel;
59 uint32_t NameLength;
60 uint32_t sd_len;
61 uint32_t status;
62 smb_sd_t sd;
63 int rc;
64
65 bzero(op, sizeof (sr->arg.open));
66
67 rc = smb_mbc_decodef(&xa->req_param_mb, "%lllqllllllllb",
68 sr,
69 &op->nt_flags,
70 &op->rootdirfid,
71 &op->desired_access,
72 &op->dsize,
73 &op->dattr,
74 &op->share_access,
75 &op->create_disposition,
76 &op->create_options,
77 &sd_len,
78 &EaLength,
79 &NameLength,
80 &ImpersonationLevel,
81 &SecurityFlags);
82
83 if (rc == 0) {
84 if (NameLength == 0) {
85 op->fqi.fq_path.pn_path = "\\";
86 } else if (NameLength >= MAXPATHLEN) {
87 smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND,
88 ERRDOS, ERROR_PATH_NOT_FOUND);
89 rc = -1;
90 } else {
91 rc = smb_mbc_decodef(&xa->req_param_mb, "%#u",
92 sr, NameLength, &op->fqi.fq_path.pn_path);
93 }
94 }
95
96 op->op_oplock_level = SMB_OPLOCK_NONE;
97 if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
98 if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH)
99 op->op_oplock_level = SMB_OPLOCK_BATCH;
100 else
101 op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
102 }
103
104 if (sd_len) {
105 status = smb_decode_sd(xa, &sd);
106 if (status != NT_STATUS_SUCCESS) {
107 smbsr_error(sr, status, 0, 0);
108 return (SDRC_ERROR);
109 }
110 op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
111 *op->sd = sd;
112 } else {
113 op->sd = NULL;
114 }
115
116 DTRACE_SMB_2(op__NtTransactCreate__start, smb_request_t *, sr,
117 struct open_param *, op);
118
119 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
120 }
121
122 void
smb_post_nt_transact_create(smb_request_t * sr,smb_xa_t * xa)123 smb_post_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
124 {
125 smb_sd_t *sd = sr->arg.open.sd;
126
127 DTRACE_SMB_2(op__NtTransactCreate__done, smb_request_t *, sr,
128 smb_xa_t *, xa);
129
130 if (sd) {
131 smb_sd_term(sd);
132 kmem_free(sd, sizeof (smb_sd_t));
133 }
134
135 if (sr->arg.open.dir != NULL)
136 smb_ofile_release(sr->arg.open.dir);
137 }
138
139 smb_sdrc_t
smb_nt_transact_create(smb_request_t * sr,smb_xa_t * xa)140 smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
141 {
142 struct open_param *op = &sr->arg.open;
143 uint8_t DirFlag;
144 smb_attr_t attr;
145 smb_ofile_t *of;
146 int rc;
147
148 if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
149 !(op->desired_access & DELETE)) {
150 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
151 ERRDOS, ERRbadaccess);
152 return (SDRC_ERROR);
153 }
154
155 if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
156 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
157 ERRDOS, ERRbadaccess);
158 return (SDRC_ERROR);
159 }
160
161 if (op->dattr & FILE_FLAG_WRITE_THROUGH)
162 op->create_options |= FILE_WRITE_THROUGH;
163
164 if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
165 op->create_options |= FILE_DELETE_ON_CLOSE;
166
167 if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
168 op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
169
170 if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
171 sr->user_cr = smb_user_getprivcred(sr->uid_user);
172
173 if (op->rootdirfid == 0) {
174 op->fqi.fq_dnode = sr->tid_tree->t_snode;
175 } else {
176 op->dir = smb_ofile_lookup_by_fid(sr, (uint16_t)op->rootdirfid);
177 if (op->dir == NULL) {
178 smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
179 ERRDOS, ERRbadfid);
180 return (SDRC_ERROR);
181 }
182 op->fqi.fq_dnode = op->dir->f_node;
183 }
184
185 op->op_oplock_levelII = B_TRUE;
186
187 if (smb_common_open(sr) != NT_STATUS_SUCCESS)
188 return (SDRC_ERROR);
189
190 /*
191 * NB: after the above smb_common_open() success,
192 * we have a handle allocated (sr->fid_ofile).
193 * If we don't return success, we must close it.
194 */
195 of = sr->fid_ofile;
196
197 switch (sr->tid_tree->t_res_type & STYPE_MASK) {
198 case STYPE_DISKTREE:
199 case STYPE_PRINTQ:
200 if (op->create_options & FILE_DELETE_ON_CLOSE)
201 smb_ofile_set_delete_on_close(of);
202
203 DirFlag = smb_node_is_dir(of->f_node) ? 1 : 0;
204 bzero(&attr, sizeof (attr));
205 attr.sa_mask = SMB_AT_ALL;
206 rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr);
207 if (rc != 0) {
208 smbsr_errno(sr, rc);
209 goto errout;
210 }
211
212 (void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
213 op->op_oplock_level,
214 sr->smb_fid,
215 op->action_taken,
216 0, /* EaErrorOffset */
217 &attr.sa_crtime,
218 &attr.sa_vattr.va_atime,
219 &attr.sa_vattr.va_mtime,
220 &attr.sa_vattr.va_ctime,
221 op->dattr & FILE_ATTRIBUTE_MASK,
222 attr.sa_allocsz,
223 attr.sa_vattr.va_size,
224 op->ftype,
225 op->devstate,
226 DirFlag);
227 break;
228
229 case STYPE_IPC:
230 bzero(&attr, sizeof (smb_attr_t));
231 (void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
232 0,
233 sr->smb_fid,
234 op->action_taken,
235 0, /* EaErrorOffset */
236 &attr.sa_crtime,
237 &attr.sa_vattr.va_atime,
238 &attr.sa_vattr.va_mtime,
239 &attr.sa_vattr.va_ctime,
240 op->dattr,
241 0x1000LL,
242 0LL,
243 op->ftype,
244 op->devstate,
245 0);
246 break;
247
248 default:
249 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
250 ERRDOS, ERROR_INVALID_FUNCTION);
251 goto errout;
252 }
253 return (SDRC_SUCCESS);
254
255 errout:
256 smb_ofile_close(of, 0);
257 return (SDRC_ERROR);
258 }
259