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
29static void smb_encode_sacl(mbuf_chain_t *, smb_acl_t *);
30static void smb_encode_dacl(mbuf_chain_t *, smb_acl_t *);
31static 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
59smb_sdrc_t
60smb_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 */
152smb_sdrc_t
153smb_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 */
225void
226smb_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 */
284void
285smb_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 */
308static void
309smb_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 */
335static void
336smb_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 */
366uint32_t
367smb_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
435decode_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 */
447smb_sid_t *
448smb_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
488decode_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 */
500static smb_acl_t *
501smb_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
550decode_error:
551	smb_acl_free(acl);
552	return (NULL);
553}
554