xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c (revision b89a8333f5e1f75ec0c269b22524bd2eccb972ba)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22dc20a302Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
2655bf511dSas200622 #include <smbsrv/smb_kproto.h>
2755bf511dSas200622 #include <smbsrv/ntstatus.h>
2855bf511dSas200622 #include <smbsrv/nterror.h>
2955bf511dSas200622 #include <smbsrv/doserror.h>
3055bf511dSas200622 #include <smbsrv/cifs.h>
31da6c28aaSamw 
3255bf511dSas200622 static void smb_encode_sd(struct smb_xa *, smb_sd_t *, uint32_t);
336537f381Sas200622 static void smb_encode_sid(struct smb_xa *, smb_sid_t *);
3455bf511dSas200622 static void smb_encode_sacl(struct smb_xa *, smb_acl_t *);
3555bf511dSas200622 static void smb_encode_dacl(struct smb_xa *, smb_acl_t *);
3655bf511dSas200622 
3755bf511dSas200622 uint32_t smb_decode_sd(struct smb_xa *, smb_sd_t *);
386537f381Sas200622 static smb_sid_t *smb_decode_sid(struct smb_xa *, uint32_t);
3955bf511dSas200622 static smb_acl_t *smb_decode_acl(struct smb_xa *, uint32_t);
40da6c28aaSamw 
41da6c28aaSamw /*
42da6c28aaSamw  * smb_nt_transact_query_security_info
43da6c28aaSamw  *
44da6c28aaSamw  * This command allows the client to retrieve the security descriptor
45da6c28aaSamw  * on a file. The result of the call is returned to the client in the
46da6c28aaSamw  * Data part of the transaction response.
47da6c28aaSamw  *
48da6c28aaSamw  * Some clients specify a non-zero maximum data return size (mdrcnt)
49da6c28aaSamw  * for the SD and some specify zero. In either case, if the mdrcnt is
50da6c28aaSamw  * too small we need to return NT_STATUS_BUFFER_TOO_SMALL and a buffer
51da6c28aaSamw  * size hint. The client should then retry with the appropriate buffer
52da6c28aaSamw  * size.
53da6c28aaSamw  *
54da6c28aaSamw  *  Client Parameter Block             Description
55da6c28aaSamw  *  ================================== =================================
56da6c28aaSamw  *
57da6c28aaSamw  *  USHORT Fid;                        FID of target
58da6c28aaSamw  *  USHORT Reserved;                   MBZ
59da6c28aaSamw  *  ULONG secinfo;                     Fields of descriptor to set
60da6c28aaSamw  *
61da6c28aaSamw  *   Data Block Encoding                Description
62da6c28aaSamw  *   ================================== ==================================
63da6c28aaSamw  *
64da6c28aaSamw  *   Data[TotalDataCount]               Security Descriptor information
65da6c28aaSamw  */
66da6c28aaSamw 
677b59d02dSjb150015 smb_sdrc_t
68da6c28aaSamw smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
69da6c28aaSamw {
7055bf511dSas200622 	smb_sd_t sd;
71da6c28aaSamw 	uint32_t secinfo;
7255bf511dSas200622 	uint32_t sdlen;
73da6c28aaSamw 	uint32_t status;
74dc20a302Sas200622 	smb_error_t err;
7555bf511dSas200622 
763db3f65cSamw 	if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
77da6c28aaSamw 	    &sr->smb_fid, &secinfo) != 0) {
78dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
79faa1795aSjb150015 		return (SDRC_ERROR);
80da6c28aaSamw 	}
81da6c28aaSamw 
82da6c28aaSamw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
83da6c28aaSamw 	if (sr->fid_ofile == NULL) {
84dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
85faa1795aSjb150015 		return (SDRC_ERROR);
86da6c28aaSamw 	}
87da6c28aaSamw 
88da6c28aaSamw 
89da6c28aaSamw 	if ((sr->fid_ofile->f_node == NULL) ||
90da6c28aaSamw 	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
91dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
9255bf511dSas200622 		    ERRDOS, ERROR_ACCESS_DENIED);
93faa1795aSjb150015 		return (SDRC_ERROR);
94da6c28aaSamw 	}
95da6c28aaSamw 
96*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
97*b89a8333Snatalie li - Sun Microsystems - Irvine United States 
98da6c28aaSamw 	if (sr->tid_tree->t_acltype != ACE_T) {
99da6c28aaSamw 		/*
100da6c28aaSamw 		 * If target filesystem doesn't support ACE_T acls then
101da6c28aaSamw 		 * don't process SACL
102da6c28aaSamw 		 */
103da6c28aaSamw 		secinfo &= ~SMB_SACL_SECINFO;
104da6c28aaSamw 	}
105da6c28aaSamw 
10655bf511dSas200622 	status = smb_sd_read(sr, &sd, secinfo);
107da6c28aaSamw 	if (status != NT_STATUS_SUCCESS) {
108dc20a302Sas200622 		smbsr_error(sr, status, 0, 0);
109faa1795aSjb150015 		return (SDRC_ERROR);
110da6c28aaSamw 	}
111da6c28aaSamw 
11255bf511dSas200622 	sdlen = smb_sd_len(&sd, secinfo);
11355bf511dSas200622 	if (sdlen == 0) {
11455bf511dSas200622 		smb_sd_term(&sd);
115dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_SECURITY_DESCR, 0, 0);
116faa1795aSjb150015 		return (SDRC_ERROR);
11755bf511dSas200622 	}
118da6c28aaSamw 
11955bf511dSas200622 	if (sdlen > xa->smb_mdrcnt) {
12055bf511dSas200622 		/*
12155bf511dSas200622 		 * The maximum data return count specified by the
12255bf511dSas200622 		 * client is not big enough to hold the security
12355bf511dSas200622 		 * descriptor. We have to return an error but we
12455bf511dSas200622 		 * should provide a buffer size hint for the client.
12555bf511dSas200622 		 */
1263db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
127dc20a302Sas200622 		err.severity = ERROR_SEVERITY_ERROR;
128dc20a302Sas200622 		err.status   = NT_STATUS_BUFFER_TOO_SMALL;
129dc20a302Sas200622 		err.errcls   = ERRDOS;
130dc20a302Sas200622 		err.errcode  = ERROR_INSUFFICIENT_BUFFER;
131dc20a302Sas200622 		smbsr_set_error(sr, &err);
13255bf511dSas200622 		smb_sd_term(&sd);
133faa1795aSjb150015 		return (SDRC_SUCCESS);
13455bf511dSas200622 	}
13555bf511dSas200622 
13655bf511dSas200622 	smb_encode_sd(xa, &sd, secinfo);
1373db3f65cSamw 	(void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
13855bf511dSas200622 	smb_sd_term(&sd);
139faa1795aSjb150015 	return (SDRC_SUCCESS);
140da6c28aaSamw }
141da6c28aaSamw 
142da6c28aaSamw /*
143da6c28aaSamw  * smb_nt_transact_set_security_info
144da6c28aaSamw  *
145da6c28aaSamw  * This command allows the client to change the security descriptor on a
146da6c28aaSamw  * file. All we do here is decode the parameters and the data. The data
147da6c28aaSamw  * is passed directly to smb_nt_set_security_object, with the security
148da6c28aaSamw  * information describing the information to set. There are no response
149da6c28aaSamw  * parameters or data.
150da6c28aaSamw  *
151da6c28aaSamw  *   Client Parameter Block Encoding    Description
152da6c28aaSamw  *   ================================== ==================================
153da6c28aaSamw  *   USHORT Fid;                        FID of target
154da6c28aaSamw  *   USHORT Reserved;                   MBZ
155da6c28aaSamw  *   ULONG SecurityInformation;         Fields of SD that to set
156da6c28aaSamw  *
157da6c28aaSamw  *   Data Block Encoding                Description
158da6c28aaSamw  *   ================================== ==================================
159da6c28aaSamw  *   Data[TotalDataCount]               Security Descriptor information
160da6c28aaSamw  */
1617b59d02dSjb150015 smb_sdrc_t
162da6c28aaSamw smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
163da6c28aaSamw {
16455bf511dSas200622 	smb_sd_t sd;
16555bf511dSas200622 	uint32_t secinfo;
166da6c28aaSamw 	uint32_t status;
167da6c28aaSamw 
1683db3f65cSamw 	if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
16955bf511dSas200622 	    &sr->smb_fid, &secinfo) != 0) {
170dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
171faa1795aSjb150015 		return (SDRC_ERROR);
172da6c28aaSamw 	}
173da6c28aaSamw 
174da6c28aaSamw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
175da6c28aaSamw 	if (sr->fid_ofile == NULL) {
176dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
177faa1795aSjb150015 		return (SDRC_ERROR);
178da6c28aaSamw 	}
179da6c28aaSamw 
180da6c28aaSamw 	if ((sr->fid_ofile->f_node == NULL) ||
181da6c28aaSamw 	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
182dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 0, 0);
183faa1795aSjb150015 		return (SDRC_ERROR);
184da6c28aaSamw 	}
185da6c28aaSamw 
186*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
187*b89a8333Snatalie li - Sun Microsystems - Irvine United States 
188c8ec8eeaSjose borrego 	if (SMB_TREE_IS_READONLY(sr)) {
189dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_MEDIA_WRITE_PROTECTED, 0, 0);
190faa1795aSjb150015 		return (SDRC_ERROR);
191da6c28aaSamw 	}
192da6c28aaSamw 
193da6c28aaSamw 	if (sr->tid_tree->t_acltype != ACE_T) {
194da6c28aaSamw 		/*
195da6c28aaSamw 		 * If target filesystem doesn't support ACE_T acls then
196da6c28aaSamw 		 * don't process SACL
197da6c28aaSamw 		 */
19855bf511dSas200622 		secinfo &= ~SMB_SACL_SECINFO;
199da6c28aaSamw 	}
200da6c28aaSamw 
20155bf511dSas200622 	if ((secinfo & SMB_ALL_SECINFO) == 0) {
202da6c28aaSamw 		return (NT_STATUS_SUCCESS);
203da6c28aaSamw 	}
204da6c28aaSamw 
20555bf511dSas200622 	status = smb_decode_sd(xa, &sd);
20655bf511dSas200622 	if (status != NT_STATUS_SUCCESS) {
207dc20a302Sas200622 		smbsr_error(sr, status, 0, 0);
208faa1795aSjb150015 		return (SDRC_ERROR);
209da6c28aaSamw 	}
210da6c28aaSamw 
21155bf511dSas200622 	if (((secinfo & SMB_OWNER_SECINFO) && (sd.sd_owner == NULL)) ||
21255bf511dSas200622 	    ((secinfo & SMB_GROUP_SECINFO) && (sd.sd_group == NULL))) {
213dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
214faa1795aSjb150015 		return (SDRC_ERROR);
21555bf511dSas200622 	}
216da6c28aaSamw 
21755bf511dSas200622 	status = smb_sd_write(sr, &sd, secinfo);
21855bf511dSas200622 	smb_sd_term(&sd);
219da6c28aaSamw 	if (status != NT_STATUS_SUCCESS) {
220dc20a302Sas200622 		smbsr_error(sr, status, 0, 0);
221faa1795aSjb150015 		return (SDRC_ERROR);
222da6c28aaSamw 	}
223da6c28aaSamw 
224faa1795aSjb150015 	return (SDRC_SUCCESS);
225da6c28aaSamw }
22655bf511dSas200622 
22755bf511dSas200622 /*
22855bf511dSas200622  * smb_encode_sd
22955bf511dSas200622  *
23055bf511dSas200622  * Encodes given security descriptor in the reply buffer.
23155bf511dSas200622  */
23255bf511dSas200622 static void
23355bf511dSas200622 smb_encode_sd(struct smb_xa *xa, smb_sd_t *sd, uint32_t secinfo)
23455bf511dSas200622 {
23555bf511dSas200622 	uint32_t offset = SMB_SD_HDRSIZE;
23655bf511dSas200622 
23755bf511dSas200622 	/* encode header */
2383db3f65cSamw 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.w",
23955bf511dSas200622 	    sd->sd_revision, sd->sd_control | SE_SELF_RELATIVE);
24055bf511dSas200622 
24155bf511dSas200622 	/* owner offset */
24255bf511dSas200622 	if (secinfo & SMB_OWNER_SECINFO) {
24355bf511dSas200622 		ASSERT(sd->sd_owner);
2443db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
2456537f381Sas200622 		offset += smb_sid_len(sd->sd_owner);
24655bf511dSas200622 	} else {
2473db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
24855bf511dSas200622 	}
24955bf511dSas200622 
25055bf511dSas200622 	/* group offset */
25155bf511dSas200622 	if (secinfo & SMB_GROUP_SECINFO) {
25255bf511dSas200622 		ASSERT(sd->sd_group);
2533db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
2546537f381Sas200622 		offset += smb_sid_len(sd->sd_group);
25555bf511dSas200622 	} else {
2563db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
25755bf511dSas200622 	}
25855bf511dSas200622 
25955bf511dSas200622 	/* SACL offset */
26055bf511dSas200622 	if ((secinfo & SMB_SACL_SECINFO) && (sd->sd_sacl)) {
2613db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
26255bf511dSas200622 		offset += smb_acl_len(sd->sd_sacl);
26355bf511dSas200622 	} else {
2643db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
26555bf511dSas200622 	}
26655bf511dSas200622 
26755bf511dSas200622 	/* DACL offset */
26855bf511dSas200622 	if ((secinfo & SMB_DACL_SECINFO) && (sd->sd_dacl))
2693db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
27055bf511dSas200622 	else
2713db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
27255bf511dSas200622 
27355bf511dSas200622 	if (secinfo & SMB_OWNER_SECINFO)
27455bf511dSas200622 		smb_encode_sid(xa, sd->sd_owner);
27555bf511dSas200622 
27655bf511dSas200622 	if (secinfo & SMB_GROUP_SECINFO)
27755bf511dSas200622 		smb_encode_sid(xa, sd->sd_group);
27855bf511dSas200622 
27955bf511dSas200622 	if (secinfo & SMB_SACL_SECINFO)
28055bf511dSas200622 		smb_encode_sacl(xa, sd->sd_sacl);
28155bf511dSas200622 
28255bf511dSas200622 	if (secinfo & SMB_DACL_SECINFO)
28355bf511dSas200622 		smb_encode_dacl(xa, sd->sd_dacl);
28455bf511dSas200622 }
28555bf511dSas200622 
28655bf511dSas200622 /*
28755bf511dSas200622  * smb_encode_sid
28855bf511dSas200622  *
28955bf511dSas200622  * Encodes given SID in the reply buffer.
29055bf511dSas200622  */
29155bf511dSas200622 static void
2926537f381Sas200622 smb_encode_sid(struct smb_xa *xa, smb_sid_t *sid)
29355bf511dSas200622 {
29455bf511dSas200622 	int i;
29555bf511dSas200622 
2963db3f65cSamw 	(void) smb_mbc_encodef(&xa->rep_data_mb, "bb",
2976537f381Sas200622 	    sid->sid_revision, sid->sid_subauthcnt);
29855bf511dSas200622 
29955bf511dSas200622 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
3003db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "b",
3016537f381Sas200622 		    sid->sid_authority[i]);
30255bf511dSas200622 	}
30355bf511dSas200622 
3046537f381Sas200622 	for (i = 0; i < sid->sid_subauthcnt; i++) {
3053db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
3066537f381Sas200622 		    sid->sid_subauth[i]);
30755bf511dSas200622 	}
30855bf511dSas200622 }
30955bf511dSas200622 
31055bf511dSas200622 /*
31155bf511dSas200622  * smb_encode_sacl
31255bf511dSas200622  *
31355bf511dSas200622  * Encodes given SACL in the reply buffer.
31455bf511dSas200622  */
31555bf511dSas200622 static void
31655bf511dSas200622 smb_encode_sacl(struct smb_xa *xa, smb_acl_t *acl)
31755bf511dSas200622 {
31855bf511dSas200622 	smb_ace_t *ace;
31955bf511dSas200622 	int i;
32055bf511dSas200622 
32155bf511dSas200622 	if (acl == NULL)
32255bf511dSas200622 		return;
32355bf511dSas200622 
32455bf511dSas200622 	/* encode header */
3253db3f65cSamw 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.ww2.", acl->sl_revision,
32655bf511dSas200622 	    acl->sl_bsize, acl->sl_acecnt);
32755bf511dSas200622 
32855bf511dSas200622 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
3293db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "bbwl",
33055bf511dSas200622 		    ace->se_hdr.se_type, ace->se_hdr.se_flags,
33155bf511dSas200622 		    ace->se_hdr.se_bsize, ace->se_mask);
33255bf511dSas200622 
33355bf511dSas200622 		smb_encode_sid(xa, ace->se_sid);
33455bf511dSas200622 	}
33555bf511dSas200622 }
33655bf511dSas200622 
33755bf511dSas200622 /*
33855bf511dSas200622  * smb_encode_dacl
33955bf511dSas200622  *
34055bf511dSas200622  * Encodes given DACL in the reply buffer.
34155bf511dSas200622  */
34255bf511dSas200622 static void
34355bf511dSas200622 smb_encode_dacl(struct smb_xa *xa, smb_acl_t *acl)
34455bf511dSas200622 {
34555bf511dSas200622 	smb_ace_t *ace;
34655bf511dSas200622 
34755bf511dSas200622 	if (acl == NULL)
34855bf511dSas200622 		return;
34955bf511dSas200622 
35055bf511dSas200622 	/* encode header */
3513db3f65cSamw 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.ww2.", acl->sl_revision,
35255bf511dSas200622 	    acl->sl_bsize, acl->sl_acecnt);
35355bf511dSas200622 
35455bf511dSas200622 	ace = list_head(&acl->sl_sorted);
35555bf511dSas200622 	while (ace) {
3563db3f65cSamw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "bbwl",
35755bf511dSas200622 		    ace->se_hdr.se_type, ace->se_hdr.se_flags,
35855bf511dSas200622 		    ace->se_hdr.se_bsize, ace->se_mask);
35955bf511dSas200622 
36055bf511dSas200622 		smb_encode_sid(xa, ace->se_sid);
36155bf511dSas200622 		ace = list_next(&acl->sl_sorted, ace);
36255bf511dSas200622 	}
36355bf511dSas200622 }
36455bf511dSas200622 
36555bf511dSas200622 /*
36655bf511dSas200622  * smb_decode_sd
36755bf511dSas200622  *
36855bf511dSas200622  * Decodes the security descriptor in the request buffer
36955bf511dSas200622  * and set the fields of 'sd' appropraitely. Upon successful
37055bf511dSas200622  * return, caller must free allocated memories by calling
37155bf511dSas200622  * smb_sd_term().
37255bf511dSas200622  */
37355bf511dSas200622 uint32_t
37455bf511dSas200622 smb_decode_sd(struct smb_xa *xa, smb_sd_t *sd)
37555bf511dSas200622 {
37655bf511dSas200622 	struct mbuf_chain sdbuf;
37755bf511dSas200622 	uint32_t owner_offs;
37855bf511dSas200622 	uint32_t group_offs;
37955bf511dSas200622 	uint32_t sacl_offs;
38055bf511dSas200622 	uint32_t dacl_offs;
38155bf511dSas200622 
38255bf511dSas200622 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
38355bf511dSas200622 
38455bf511dSas200622 	(void) MBC_SHADOW_CHAIN(&sdbuf, &xa->req_data_mb,
38555bf511dSas200622 	    xa->req_data_mb.chain_offset,
38655bf511dSas200622 	    xa->req_data_mb.max_bytes - xa->req_data_mb.chain_offset);
38755bf511dSas200622 
3883db3f65cSamw 	if (smb_mbc_decodef(&sdbuf, "b.wllll",
38955bf511dSas200622 	    &sd->sd_revision, &sd->sd_control,
39055bf511dSas200622 	    &owner_offs, &group_offs, &sacl_offs, &dacl_offs))
39155bf511dSas200622 		goto decode_error;
39255bf511dSas200622 
39355bf511dSas200622 	sd->sd_control &= ~SE_SELF_RELATIVE;
39455bf511dSas200622 
39555bf511dSas200622 	if (owner_offs != 0) {
39655bf511dSas200622 		if (owner_offs < SMB_SD_HDRSIZE)
39755bf511dSas200622 			goto decode_error;
39855bf511dSas200622 
39955bf511dSas200622 		sd->sd_owner = smb_decode_sid(xa, owner_offs);
40055bf511dSas200622 		if (sd->sd_owner == NULL)
40155bf511dSas200622 			goto decode_error;
40255bf511dSas200622 	}
40355bf511dSas200622 
40455bf511dSas200622 	if (group_offs != 0) {
40555bf511dSas200622 		if (group_offs < SMB_SD_HDRSIZE)
40655bf511dSas200622 			goto decode_error;
40755bf511dSas200622 
40855bf511dSas200622 		sd->sd_group = smb_decode_sid(xa, group_offs);
40955bf511dSas200622 		if (sd->sd_group == NULL)
41055bf511dSas200622 			goto decode_error;
41155bf511dSas200622 	}
41255bf511dSas200622 
41355bf511dSas200622 	if (sacl_offs != 0) {
41455bf511dSas200622 		if ((sd->sd_control & SE_SACL_PRESENT) == 0)
41555bf511dSas200622 			goto decode_error;
41655bf511dSas200622 
41755bf511dSas200622 		if (sacl_offs < SMB_SD_HDRSIZE)
41855bf511dSas200622 			goto decode_error;
41955bf511dSas200622 
42055bf511dSas200622 		sd->sd_sacl = smb_decode_acl(xa, sacl_offs);
42155bf511dSas200622 		if (sd->sd_sacl == NULL)
42255bf511dSas200622 			goto decode_error;
42355bf511dSas200622 	}
42455bf511dSas200622 
42555bf511dSas200622 	if (dacl_offs != 0) {
42655bf511dSas200622 		if ((sd->sd_control & SE_DACL_PRESENT) == 0)
42755bf511dSas200622 			goto decode_error;
42855bf511dSas200622 
42955bf511dSas200622 		if (dacl_offs < SMB_SD_HDRSIZE)
43055bf511dSas200622 			goto decode_error;
43155bf511dSas200622 
43255bf511dSas200622 		sd->sd_dacl = smb_decode_acl(xa, dacl_offs);
43355bf511dSas200622 		if (sd->sd_dacl == NULL)
43455bf511dSas200622 			goto decode_error;
43555bf511dSas200622 	}
43655bf511dSas200622 
43755bf511dSas200622 	return (NT_STATUS_SUCCESS);
43855bf511dSas200622 
43955bf511dSas200622 decode_error:
44055bf511dSas200622 	smb_sd_term(sd);
44155bf511dSas200622 	return (NT_STATUS_INVALID_SECURITY_DESCR);
44255bf511dSas200622 }
44355bf511dSas200622 
44455bf511dSas200622 /*
44555bf511dSas200622  * smb_decode_sid
44655bf511dSas200622  *
44755bf511dSas200622  * Allocates memory and decodes the SID in the request buffer
44855bf511dSas200622  * Upon successful return, caller must free the allocated memory
4496537f381Sas200622  * by calling smb_sid_free()
45055bf511dSas200622  */
4516537f381Sas200622 static smb_sid_t *
45255bf511dSas200622 smb_decode_sid(struct smb_xa *xa, uint32_t offset)
45355bf511dSas200622 {
45455bf511dSas200622 	uint8_t revision;
45555bf511dSas200622 	uint8_t subauth_cnt;
45655bf511dSas200622 	struct mbuf_chain sidbuf;
4576537f381Sas200622 	smb_sid_t *sid;
45855bf511dSas200622 	int sidlen;
45955bf511dSas200622 	int bytes_left;
46055bf511dSas200622 	int i;
46155bf511dSas200622 
46255bf511dSas200622 	offset += xa->req_data_mb.chain_offset;
46355bf511dSas200622 	bytes_left = xa->req_data_mb.max_bytes - offset;
4646537f381Sas200622 	if (bytes_left < sizeof (smb_sid_t))
46555bf511dSas200622 		return (NULL);
46655bf511dSas200622 
46755bf511dSas200622 	(void) MBC_SHADOW_CHAIN(&sidbuf, &xa->req_data_mb, offset, bytes_left);
46855bf511dSas200622 
4693db3f65cSamw 	if (smb_mbc_decodef(&sidbuf, "bb", &revision, &subauth_cnt))
47055bf511dSas200622 		return (NULL);
47155bf511dSas200622 
4726537f381Sas200622 	sidlen = sizeof (smb_sid_t) - sizeof (uint32_t) +
47355bf511dSas200622 	    (subauth_cnt * sizeof (uint32_t));
4746537f381Sas200622 	sid = kmem_alloc(sidlen, KM_SLEEP);
47555bf511dSas200622 
4766537f381Sas200622 	sid->sid_revision = revision;
4776537f381Sas200622 	sid->sid_subauthcnt = subauth_cnt;
47855bf511dSas200622 
47955bf511dSas200622 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
4803db3f65cSamw 		if (smb_mbc_decodef(&sidbuf, "b", &sid->sid_authority[i]))
48155bf511dSas200622 			goto decode_err;
48255bf511dSas200622 	}
48355bf511dSas200622 
4846537f381Sas200622 	for (i = 0; i < sid->sid_subauthcnt; i++) {
4853db3f65cSamw 		if (smb_mbc_decodef(&sidbuf, "l", &sid->sid_subauth[i]))
48655bf511dSas200622 			goto decode_err;
48755bf511dSas200622 	}
48855bf511dSas200622 
48955bf511dSas200622 	return (sid);
49055bf511dSas200622 
49155bf511dSas200622 decode_err:
4926537f381Sas200622 	kmem_free(sid, sidlen);
49355bf511dSas200622 	return (NULL);
49455bf511dSas200622 }
49555bf511dSas200622 
49655bf511dSas200622 /*
49755bf511dSas200622  * smb_decode_acl
49855bf511dSas200622  *
49955bf511dSas200622  * Allocates memory and decodes the ACL in the request buffer
50055bf511dSas200622  * Upon successful return, caller must free the allocated memory
50155bf511dSas200622  * by calling smb_acl_free().
50255bf511dSas200622  */
50355bf511dSas200622 static smb_acl_t *
50455bf511dSas200622 smb_decode_acl(struct smb_xa *xa, uint32_t offset)
50555bf511dSas200622 {
50655bf511dSas200622 	struct mbuf_chain aclbuf;
50755bf511dSas200622 	smb_acl_t *acl;
50855bf511dSas200622 	smb_ace_t *ace;
50955bf511dSas200622 	uint8_t revision;
51055bf511dSas200622 	uint16_t size;
51155bf511dSas200622 	uint16_t acecnt;
51255bf511dSas200622 	int bytes_left;
51355bf511dSas200622 	uint32_t sid_offs = offset;
51455bf511dSas200622 	int sidlen;
51555bf511dSas200622 	int i;
51655bf511dSas200622 
51755bf511dSas200622 	offset += xa->req_data_mb.chain_offset;
51855bf511dSas200622 	bytes_left = xa->req_data_mb.max_bytes - offset;
51955bf511dSas200622 	if (bytes_left < SMB_ACL_HDRSIZE)
52055bf511dSas200622 		return (NULL);
52155bf511dSas200622 
52255bf511dSas200622 	(void) MBC_SHADOW_CHAIN(&aclbuf, &xa->req_data_mb, offset, bytes_left);
52355bf511dSas200622 
5243db3f65cSamw 	if (smb_mbc_decodef(&aclbuf, "b.ww2.", &revision, &size, &acecnt))
52555bf511dSas200622 		return (NULL);
52655bf511dSas200622 
52755bf511dSas200622 	if (size == 0)
52855bf511dSas200622 		return (NULL);
52955bf511dSas200622 
53055bf511dSas200622 	acl = smb_acl_alloc(revision, size, acecnt);
53155bf511dSas200622 
53255bf511dSas200622 	sid_offs += SMB_ACL_HDRSIZE;
53355bf511dSas200622 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
5343db3f65cSamw 		if (smb_mbc_decodef(&aclbuf, "bbwl",
53555bf511dSas200622 		    &ace->se_hdr.se_type, &ace->se_hdr.se_flags,
53655bf511dSas200622 		    &ace->se_hdr.se_bsize, &ace->se_mask))
53755bf511dSas200622 			goto decode_error;
53855bf511dSas200622 
53955bf511dSas200622 		sid_offs += SMB_ACE_HDRSIZE + sizeof (ace->se_mask);
54055bf511dSas200622 		ace->se_sid = smb_decode_sid(xa, sid_offs);
54155bf511dSas200622 		if (ace->se_sid == NULL)
54255bf511dSas200622 			goto decode_error;
543*b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/* This is SID length plus any paddings between ACEs */
544*b89a8333Snatalie li - Sun Microsystems - Irvine United States 		sidlen = ace->se_hdr.se_bsize -
545*b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    (SMB_ACE_HDRSIZE + sizeof (ace->se_mask));
54655bf511dSas200622 		aclbuf.chain_offset += sidlen;
54755bf511dSas200622 		sid_offs += sidlen;
54855bf511dSas200622 	}
54955bf511dSas200622 
55055bf511dSas200622 	return (acl);
55155bf511dSas200622 
55255bf511dSas200622 decode_error:
55355bf511dSas200622 	smb_acl_free(acl);
55455bf511dSas200622 	return (NULL);
55555bf511dSas200622 }
556