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 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 #include <smbsrv/smb_kproto.h>
28 
29 static void smb_encode_sacl(mbuf_chain_t *, smb_acl_t *);
30 static void smb_encode_dacl(mbuf_chain_t *, smb_acl_t *);
31 static smb_acl_t *smb_decode_acl(mbuf_chain_t *, uint32_t);
32 
33 /*
34  * smb_nt_transact_query_security_info
35  *
36  * This command allows the client to retrieve the security descriptor
37  * on a file. The result of the call is returned to the client in the
38  * Data part of the transaction response.
39  *
40  * Some clients specify a non-zero maximum data return size (mdrcnt)
41  * for the SD and some specify zero. In either case, if the mdrcnt is
42  * too small we need to return NT_STATUS_BUFFER_TOO_SMALL and a buffer
43  * size hint. The client should then retry with the appropriate buffer
44  * size.
45  *
46  *  Client Parameter Block             Description
47  *  ================================== =================================
48  *
49  *  USHORT Fid;                        FID of target
50  *  USHORT Reserved;                   MBZ
51  *  ULONG secinfo;                     Fields of descriptor to set
52  *
53  *   Data Block Encoding                Description
54  *   ================================== ==================================
55  *
56  *   Data[TotalDataCount]               Security Descriptor information
57  */
58 
59 smb_sdrc_t
smb_nt_transact_query_security_info(struct smb_request * sr,struct smb_xa * xa)60 smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
61 {
62 	smb_sd_t sd;
63 	uint32_t secinfo;
64 	uint32_t sdlen;
65 	uint32_t status;
66 	smb_error_t err;
67 
68 	if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
69 	    &sr->smb_fid, &secinfo) != 0) {
70 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
71 		return (SDRC_ERROR);
72 	}
73 
74 	smbsr_lookup_file(sr);
75 	if (sr->fid_ofile == NULL) {
76 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
77 		return (SDRC_ERROR);
78 	}
79 
80 
81 	if ((sr->fid_ofile->f_node == NULL) ||
82 	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
83 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
84 		    ERRDOS, ERROR_ACCESS_DENIED);
85 		return (SDRC_ERROR);
86 	}
87 
88 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
89 
90 	if (sr->tid_tree->t_acltype != ACE_T) {
91 		/*
92 		 * If target filesystem doesn't support ACE_T acls then
93 		 * don't process SACL
94 		 */
95 		secinfo &= ~SMB_SACL_SECINFO;
96 	}
97 
98 	status = smb_sd_read(sr, &sd, secinfo);
99 	if (status != NT_STATUS_SUCCESS) {
100 		smbsr_error(sr, status, 0, 0);
101 		return (SDRC_ERROR);
102 	}
103 
104 	sdlen = smb_sd_len(&sd, secinfo);
105 	if (sdlen == 0) {
106 		smb_sd_term(&sd);
107 		smbsr_error(sr, NT_STATUS_INVALID_SECURITY_DESCR, 0, 0);
108 		return (SDRC_ERROR);
109 	}
110 
111 	if (sdlen > xa->smb_mdrcnt) {
112 		/*
113 		 * The maximum data return count specified by the
114 		 * client is not big enough to hold the security
115 		 * descriptor. We have to return an error but we
116 		 * should provide a buffer size hint for the client.
117 		 */
118 		(void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
119 		err.status   = NT_STATUS_BUFFER_TOO_SMALL;
120 		err.errcls   = ERRDOS;
121 		err.errcode  = ERROR_INSUFFICIENT_BUFFER;
122 		smbsr_set_error(sr, &err);
123 		smb_sd_term(&sd);
124 		return (SDRC_SUCCESS);
125 	}
126 
127 	smb_encode_sd(&xa->rep_data_mb, &sd, secinfo);
128 	(void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
129 	smb_sd_term(&sd);
130 	return (SDRC_SUCCESS);
131 }
132 
133 /*
134  * smb_nt_transact_set_security_info
135  *
136  * This command allows the client to change the security descriptor on a
137  * file. All we do here is decode the parameters and the data. The data
138  * is passed directly to smb_nt_set_security_object, with the security
139  * information describing the information to set. There are no response
140  * parameters or data.
141  *
142  *   Client Parameter Block Encoding    Description
143  *   ================================== ==================================
144  *   USHORT Fid;                        FID of target
145  *   USHORT Reserved;                   MBZ
146  *   ULONG SecurityInformation;         Fields of SD that to set
147  *
148  *   Data Block Encoding                Description
149  *   ================================== ==================================
150  *   Data[TotalDataCount]               Security Descriptor information
151  */
152 smb_sdrc_t
smb_nt_transact_set_security_info(struct smb_request * sr,struct smb_xa * xa)153 smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
154 {
155 	smb_sd_t sd;
156 	uint32_t secinfo;
157 	uint32_t status;
158 
159 	if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
160 	    &sr->smb_fid, &secinfo) != 0) {
161 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
162 		return (SDRC_ERROR);
163 	}
164 
165 	smbsr_lookup_file(sr);
166 	if (sr->fid_ofile == NULL) {
167 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
168 		return (SDRC_ERROR);
169 	}
170 
171 	if ((sr->fid_ofile->f_node == NULL) ||
172 	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
173 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 0, 0);
174 		return (SDRC_ERROR);
175 	}
176 
177 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
178 
179 	if (SMB_TREE_IS_READONLY(sr)) {
180 		smbsr_error(sr, NT_STATUS_MEDIA_WRITE_PROTECTED, 0, 0);
181 		return (SDRC_ERROR);
182 	}
183 
184 	if (sr->tid_tree->t_acltype != ACE_T) {
185 		/*
186 		 * If target filesystem doesn't support ACE_T acls then
187 		 * don't process SACL
188 		 */
189 		secinfo &= ~SMB_SACL_SECINFO;
190 	}
191 
192 	if ((secinfo & SMB_ALL_SECINFO) == 0) {
193 		return (NT_STATUS_SUCCESS);
194 	}
195 
196 	status = smb_decode_sd(&xa->req_data_mb, &sd);
197 	if (status != NT_STATUS_SUCCESS) {
198 		smbsr_error(sr, status, 0, 0);
199 		return (SDRC_ERROR);
200 	}
201 
202 	if (((secinfo & SMB_OWNER_SECINFO) && (sd.sd_owner == NULL)) ||
203 	    ((secinfo & SMB_GROUP_SECINFO) && (sd.sd_group == NULL))) {
204 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
205 		return (SDRC_ERROR);
206 	}
207 
208 	if (!smb_node_is_system(sr->fid_ofile->f_node))
209 		status = smb_sd_write(sr, &sd, secinfo);
210 
211 	smb_sd_term(&sd);
212 	if (status != NT_STATUS_SUCCESS) {
213 		smbsr_error(sr, status, 0, 0);
214 		return (SDRC_ERROR);
215 	}
216 
217 	return (SDRC_SUCCESS);
218 }
219 
220 /*
221  * smb_encode_sd
222  *
223  * Encodes given security descriptor in the reply buffer.
224  */
225 void
smb_encode_sd(mbuf_chain_t * mbc,smb_sd_t * sd,uint32_t secinfo)226 smb_encode_sd(mbuf_chain_t *mbc, smb_sd_t *sd, uint32_t secinfo)
227 {
228 	uint32_t offset = SMB_SD_HDRSIZE;
229 
230 	/* encode header */
231 	(void) smb_mbc_encodef(mbc, "b.w",
232 	    sd->sd_revision, sd->sd_control | SE_SELF_RELATIVE);
233 
234 	/* owner offset */
235 	if (secinfo & SMB_OWNER_SECINFO) {
236 		ASSERT(sd->sd_owner);
237 		(void) smb_mbc_encodef(mbc, "l", offset);
238 		offset += smb_sid_len(sd->sd_owner);
239 	} else {
240 		(void) smb_mbc_encodef(mbc, "l", 0);
241 	}
242 
243 	/* group offset */
244 	if (secinfo & SMB_GROUP_SECINFO) {
245 		ASSERT(sd->sd_group);
246 		(void) smb_mbc_encodef(mbc, "l", offset);
247 		offset += smb_sid_len(sd->sd_group);
248 	} else {
249 		(void) smb_mbc_encodef(mbc, "l", 0);
250 	}
251 
252 	/* SACL offset */
253 	if ((secinfo & SMB_SACL_SECINFO) && (sd->sd_sacl)) {
254 		(void) smb_mbc_encodef(mbc, "l", offset);
255 		offset += smb_acl_len(sd->sd_sacl);
256 	} else {
257 		(void) smb_mbc_encodef(mbc, "l", 0);
258 	}
259 
260 	/* DACL offset */
261 	if ((secinfo & SMB_DACL_SECINFO) && (sd->sd_dacl))
262 		(void) smb_mbc_encodef(mbc, "l", offset);
263 	else
264 		(void) smb_mbc_encodef(mbc, "l", 0);
265 
266 	if (secinfo & SMB_OWNER_SECINFO)
267 		smb_encode_sid(mbc, sd->sd_owner);
268 
269 	if (secinfo & SMB_GROUP_SECINFO)
270 		smb_encode_sid(mbc, sd->sd_group);
271 
272 	if (secinfo & SMB_SACL_SECINFO)
273 		smb_encode_sacl(mbc, sd->sd_sacl);
274 
275 	if (secinfo & SMB_DACL_SECINFO)
276 		smb_encode_dacl(mbc, sd->sd_dacl);
277 }
278 
279 /*
280  * smb_encode_sid
281  *
282  * Encodes given SID in the reply buffer.
283  */
284 void
smb_encode_sid(mbuf_chain_t * mbc,smb_sid_t * sid)285 smb_encode_sid(mbuf_chain_t *mbc, smb_sid_t *sid)
286 {
287 	int i;
288 
289 	(void) smb_mbc_encodef(mbc, "bb",
290 	    sid->sid_revision, sid->sid_subauthcnt);
291 
292 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
293 		(void) smb_mbc_encodef(mbc, "b",
294 		    sid->sid_authority[i]);
295 	}
296 
297 	for (i = 0; i < sid->sid_subauthcnt; i++) {
298 		(void) smb_mbc_encodef(mbc, "l",
299 		    sid->sid_subauth[i]);
300 	}
301 }
302 
303 /*
304  * smb_encode_sacl
305  *
306  * Encodes given SACL in the reply buffer.
307  */
308 static void
smb_encode_sacl(mbuf_chain_t * mbc,smb_acl_t * acl)309 smb_encode_sacl(mbuf_chain_t *mbc, smb_acl_t *acl)
310 {
311 	smb_ace_t *ace;
312 	int i;
313 
314 	if (acl == NULL)
315 		return;
316 
317 	/* encode header */
318 	(void) smb_mbc_encodef(mbc, "b.ww2.", acl->sl_revision,
319 	    acl->sl_bsize, acl->sl_acecnt);
320 
321 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
322 		(void) smb_mbc_encodef(mbc, "bbwl",
323 		    ace->se_hdr.se_type, ace->se_hdr.se_flags,
324 		    ace->se_hdr.se_bsize, ace->se_mask);
325 
326 		smb_encode_sid(mbc, ace->se_sid);
327 	}
328 }
329 
330 /*
331  * smb_encode_dacl
332  *
333  * Encodes given DACL in the reply buffer.
334  */
335 static void
smb_encode_dacl(mbuf_chain_t * mbc,smb_acl_t * acl)336 smb_encode_dacl(mbuf_chain_t *mbc, smb_acl_t *acl)
337 {
338 	smb_ace_t *ace;
339 
340 	if (acl == NULL)
341 		return;
342 
343 	/* encode header */
344 	(void) smb_mbc_encodef(mbc, "b.ww2.", acl->sl_revision,
345 	    acl->sl_bsize, acl->sl_acecnt);
346 
347 	ace = list_head(&acl->sl_sorted);
348 	while (ace) {
349 		(void) smb_mbc_encodef(mbc, "bbwl",
350 		    ace->se_hdr.se_type, ace->se_hdr.se_flags,
351 		    ace->se_hdr.se_bsize, ace->se_mask);
352 
353 		smb_encode_sid(mbc, ace->se_sid);
354 		ace = list_next(&acl->sl_sorted, ace);
355 	}
356 }
357 
358 /*
359  * smb_decode_sd
360  *
361  * Decodes the security descriptor in the request buffer
362  * and set the fields of 'sd' appropraitely. Upon successful
363  * return, caller must free allocated memories by calling
364  * smb_sd_term().
365  */
366 uint32_t
smb_decode_sd(mbuf_chain_t * mbc,smb_sd_t * sd)367 smb_decode_sd(mbuf_chain_t *mbc, smb_sd_t *sd)
368 {
369 	struct mbuf_chain sdbuf;
370 	uint32_t owner_offs;
371 	uint32_t group_offs;
372 	uint32_t sacl_offs;
373 	uint32_t dacl_offs;
374 	int rc;
375 
376 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
377 
378 	(void) MBC_SHADOW_CHAIN(&sdbuf, mbc,
379 	    mbc->chain_offset,
380 	    mbc->max_bytes - mbc->chain_offset);
381 
382 	rc = smb_mbc_decodef(&sdbuf, "b.wllll",
383 	    &sd->sd_revision, &sd->sd_control,
384 	    &owner_offs, &group_offs, &sacl_offs, &dacl_offs);
385 
386 	/* Prevent disallowed flags in smb_sd_term. */
387 	sd->sd_control &= ~SE_SELF_RELATIVE;
388 	if (rc != 0)
389 		goto decode_error;
390 
391 	if (owner_offs != 0) {
392 		if (owner_offs < SMB_SD_HDRSIZE)
393 			goto decode_error;
394 
395 		sd->sd_owner = smb_decode_sid(mbc, owner_offs);
396 		if (sd->sd_owner == NULL)
397 			goto decode_error;
398 	}
399 
400 	if (group_offs != 0) {
401 		if (group_offs < SMB_SD_HDRSIZE)
402 			goto decode_error;
403 
404 		sd->sd_group = smb_decode_sid(mbc, group_offs);
405 		if (sd->sd_group == NULL)
406 			goto decode_error;
407 	}
408 
409 	if (sacl_offs != 0) {
410 		if ((sd->sd_control & SE_SACL_PRESENT) == 0)
411 			goto decode_error;
412 
413 		if (sacl_offs < SMB_SD_HDRSIZE)
414 			goto decode_error;
415 
416 		sd->sd_sacl = smb_decode_acl(mbc, sacl_offs);
417 		if (sd->sd_sacl == NULL)
418 			goto decode_error;
419 	}
420 
421 	if (dacl_offs != 0) {
422 		if ((sd->sd_control & SE_DACL_PRESENT) == 0)
423 			goto decode_error;
424 
425 		if (dacl_offs < SMB_SD_HDRSIZE)
426 			goto decode_error;
427 
428 		sd->sd_dacl = smb_decode_acl(mbc, dacl_offs);
429 		if (sd->sd_dacl == NULL)
430 			goto decode_error;
431 	}
432 
433 	return (NT_STATUS_SUCCESS);
434 
435 decode_error:
436 	smb_sd_term(sd);
437 	return (NT_STATUS_INVALID_SECURITY_DESCR);
438 }
439 
440 /*
441  * smb_decode_sid
442  *
443  * Allocates memory and decodes the SID in the request buffer
444  * Upon successful return, caller must free the allocated memory
445  * by calling smb_sid_free()
446  */
447 smb_sid_t *
smb_decode_sid(mbuf_chain_t * mbc,uint32_t offset)448 smb_decode_sid(mbuf_chain_t *mbc, uint32_t offset)
449 {
450 	uint8_t revision;
451 	uint8_t subauth_cnt;
452 	struct mbuf_chain sidbuf;
453 	smb_sid_t *sid;
454 	int sidlen;
455 	int bytes_left;
456 	int i;
457 
458 	offset += mbc->chain_offset;
459 	bytes_left = mbc->max_bytes - offset;
460 	if (bytes_left < (int)sizeof (smb_sid_t))
461 		return (NULL);
462 
463 	if (MBC_SHADOW_CHAIN(&sidbuf, mbc, offset, bytes_left) != 0)
464 		return (NULL);
465 
466 	if (smb_mbc_decodef(&sidbuf, "bb", &revision, &subauth_cnt))
467 		return (NULL);
468 
469 	sidlen = sizeof (smb_sid_t) - sizeof (uint32_t) +
470 	    (subauth_cnt * sizeof (uint32_t));
471 	sid = kmem_alloc(sidlen, KM_SLEEP);
472 
473 	sid->sid_revision = revision;
474 	sid->sid_subauthcnt = subauth_cnt;
475 
476 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
477 		if (smb_mbc_decodef(&sidbuf, "b", &sid->sid_authority[i]))
478 			goto decode_err;
479 	}
480 
481 	for (i = 0; i < sid->sid_subauthcnt; i++) {
482 		if (smb_mbc_decodef(&sidbuf, "l", &sid->sid_subauth[i]))
483 			goto decode_err;
484 	}
485 
486 	return (sid);
487 
488 decode_err:
489 	kmem_free(sid, sidlen);
490 	return (NULL);
491 }
492 
493 /*
494  * smb_decode_acl
495  *
496  * Allocates memory and decodes the ACL in the request buffer
497  * Upon successful return, caller must free the allocated memory
498  * by calling smb_acl_free().
499  */
500 static smb_acl_t *
smb_decode_acl(mbuf_chain_t * mbc,uint32_t offset)501 smb_decode_acl(mbuf_chain_t *mbc, uint32_t offset)
502 {
503 	struct mbuf_chain aclbuf;
504 	smb_acl_t *acl;
505 	smb_ace_t *ace;
506 	uint8_t revision;
507 	uint16_t size;
508 	uint16_t acecnt;
509 	int bytes_left;
510 	uint32_t sid_offs = offset;
511 	int sidlen;
512 	int i;
513 
514 	offset += mbc->chain_offset;
515 	bytes_left = mbc->max_bytes - offset;
516 	if (bytes_left < SMB_ACL_HDRSIZE)
517 		return (NULL);
518 
519 	if (MBC_SHADOW_CHAIN(&aclbuf, mbc, offset, bytes_left) != 0)
520 		return (NULL);
521 
522 	if (smb_mbc_decodef(&aclbuf, "b.ww2.", &revision, &size, &acecnt))
523 		return (NULL);
524 
525 	if (size == 0)
526 		return (NULL);
527 
528 	acl = smb_acl_alloc(revision, size, acecnt);
529 
530 	sid_offs += SMB_ACL_HDRSIZE;
531 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
532 		if (smb_mbc_decodef(&aclbuf, "bbwl",
533 		    &ace->se_hdr.se_type, &ace->se_hdr.se_flags,
534 		    &ace->se_hdr.se_bsize, &ace->se_mask))
535 			goto decode_error;
536 
537 		sid_offs += SMB_ACE_HDRSIZE + sizeof (ace->se_mask);
538 		ace->se_sid = smb_decode_sid(mbc, sid_offs);
539 		if (ace->se_sid == NULL)
540 			goto decode_error;
541 		/* This is SID length plus any paddings between ACEs */
542 		sidlen = ace->se_hdr.se_bsize -
543 		    (SMB_ACE_HDRSIZE + sizeof (ace->se_mask));
544 		aclbuf.chain_offset += sidlen;
545 		sid_offs += sidlen;
546 	}
547 
548 	return (acl);
549 
550 decode_error:
551 	smb_acl_free(acl);
552 	return (NULL);
553 }
554