xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c (revision 94047d49916b669576decf2f622a1ee718646882)
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
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
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
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