xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c (revision 12508:edb7861a1533)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
21*12508Samw@Sun.COM 
225331Samw /*
23*12508Samw@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245331Samw  */
255331Samw 
265521Sas200622 #include <smbsrv/smb_kproto.h>
275331Samw 
285521Sas200622 static void smb_encode_sd(struct smb_xa *, smb_sd_t *, uint32_t);
295521Sas200622 static void smb_encode_sacl(struct smb_xa *, smb_acl_t *);
305521Sas200622 static void smb_encode_dacl(struct smb_xa *, smb_acl_t *);
315521Sas200622 static smb_acl_t *smb_decode_acl(struct smb_xa *, uint32_t);
325331Samw 
335331Samw /*
345331Samw  * smb_nt_transact_query_security_info
355331Samw  *
365331Samw  * This command allows the client to retrieve the security descriptor
375331Samw  * on a file. The result of the call is returned to the client in the
385331Samw  * Data part of the transaction response.
395331Samw  *
405331Samw  * Some clients specify a non-zero maximum data return size (mdrcnt)
415331Samw  * for the SD and some specify zero. In either case, if the mdrcnt is
425331Samw  * too small we need to return NT_STATUS_BUFFER_TOO_SMALL and a buffer
435331Samw  * size hint. The client should then retry with the appropriate buffer
445331Samw  * size.
455331Samw  *
465331Samw  *  Client Parameter Block             Description
475331Samw  *  ================================== =================================
485331Samw  *
495331Samw  *  USHORT Fid;                        FID of target
505331Samw  *  USHORT Reserved;                   MBZ
515331Samw  *  ULONG secinfo;                     Fields of descriptor to set
525331Samw  *
535331Samw  *   Data Block Encoding                Description
545331Samw  *   ================================== ==================================
555331Samw  *
565331Samw  *   Data[TotalDataCount]               Security Descriptor information
575331Samw  */
585331Samw 
596030Sjb150015 smb_sdrc_t
smb_nt_transact_query_security_info(struct smb_request * sr,struct smb_xa * xa)605331Samw smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
615331Samw {
625521Sas200622 	smb_sd_t sd;
635521Sas200622 	uint32_t secinfo;
645521Sas200622 	uint32_t sdlen;
655521Sas200622 	uint32_t status;
665772Sas200622 	smb_error_t err;
675331Samw 
687052Samw 	if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
695331Samw 	    &sr->smb_fid, &secinfo) != 0) {
705772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
716139Sjb150015 		return (SDRC_ERROR);
725331Samw 	}
735331Samw 
748934SJose.Borrego@Sun.COM 	smbsr_lookup_file(sr);
755331Samw 	if (sr->fid_ofile == NULL) {
765772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
776139Sjb150015 		return (SDRC_ERROR);
785331Samw 	}
795331Samw 
805331Samw 
815331Samw 	if ((sr->fid_ofile->f_node == NULL) ||
825331Samw 	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
835772Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
845521Sas200622 		    ERRDOS, ERROR_ACCESS_DENIED);
856139Sjb150015 		return (SDRC_ERROR);
865331Samw 	}
875331Samw 
887961SNatalie.Li@Sun.COM 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
897961SNatalie.Li@Sun.COM 
905331Samw 	if (sr->tid_tree->t_acltype != ACE_T) {
915331Samw 		/*
925331Samw 		 * If target filesystem doesn't support ACE_T acls then
935331Samw 		 * don't process SACL
945331Samw 		 */
955331Samw 		secinfo &= ~SMB_SACL_SECINFO;
965331Samw 	}
975331Samw 
985521Sas200622 	status = smb_sd_read(sr, &sd, secinfo);
995331Samw 	if (status != NT_STATUS_SUCCESS) {
1005772Sas200622 		smbsr_error(sr, status, 0, 0);
1016139Sjb150015 		return (SDRC_ERROR);
1025331Samw 	}
1035331Samw 
1045521Sas200622 	sdlen = smb_sd_len(&sd, secinfo);
1055521Sas200622 	if (sdlen == 0) {
1065521Sas200622 		smb_sd_term(&sd);
1075772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_SECURITY_DESCR, 0, 0);
1086139Sjb150015 		return (SDRC_ERROR);
1095521Sas200622 	}
1105331Samw 
1115521Sas200622 	if (sdlen > xa->smb_mdrcnt) {
1125521Sas200622 		/*
1135521Sas200622 		 * The maximum data return count specified by the
1145521Sas200622 		 * client is not big enough to hold the security
1155521Sas200622 		 * descriptor. We have to return an error but we
1165521Sas200622 		 * should provide a buffer size hint for the client.
1175521Sas200622 		 */
1187052Samw 		(void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
1195772Sas200622 		err.status   = NT_STATUS_BUFFER_TOO_SMALL;
1205772Sas200622 		err.errcls   = ERRDOS;
1215772Sas200622 		err.errcode  = ERROR_INSUFFICIENT_BUFFER;
1225772Sas200622 		smbsr_set_error(sr, &err);
1235521Sas200622 		smb_sd_term(&sd);
1246139Sjb150015 		return (SDRC_SUCCESS);
1255521Sas200622 	}
1265521Sas200622 
1275521Sas200622 	smb_encode_sd(xa, &sd, secinfo);
1287052Samw 	(void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
1295521Sas200622 	smb_sd_term(&sd);
1306139Sjb150015 	return (SDRC_SUCCESS);
1315331Samw }
1325331Samw 
1335331Samw /*
1345331Samw  * smb_nt_transact_set_security_info
1355331Samw  *
1365331Samw  * This command allows the client to change the security descriptor on a
1375331Samw  * file. All we do here is decode the parameters and the data. The data
1385331Samw  * is passed directly to smb_nt_set_security_object, with the security
1395331Samw  * information describing the information to set. There are no response
1405331Samw  * parameters or data.
1415331Samw  *
1425331Samw  *   Client Parameter Block Encoding    Description
1435331Samw  *   ================================== ==================================
1445331Samw  *   USHORT Fid;                        FID of target
1455331Samw  *   USHORT Reserved;                   MBZ
1465331Samw  *   ULONG SecurityInformation;         Fields of SD that to set
1475331Samw  *
1485331Samw  *   Data Block Encoding                Description
1495331Samw  *   ================================== ==================================
1505331Samw  *   Data[TotalDataCount]               Security Descriptor information
1515331Samw  */
1526030Sjb150015 smb_sdrc_t
smb_nt_transact_set_security_info(struct smb_request * sr,struct smb_xa * xa)1535331Samw smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
1545331Samw {
1555521Sas200622 	smb_sd_t sd;
1565521Sas200622 	uint32_t secinfo;
1575331Samw 	uint32_t status;
1585331Samw 
1597052Samw 	if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
1605521Sas200622 	    &sr->smb_fid, &secinfo) != 0) {
1615772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
1626139Sjb150015 		return (SDRC_ERROR);
1635331Samw 	}
1645331Samw 
1658934SJose.Borrego@Sun.COM 	smbsr_lookup_file(sr);
1665331Samw 	if (sr->fid_ofile == NULL) {
1675772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
1686139Sjb150015 		return (SDRC_ERROR);
1695331Samw 	}
1705331Samw 
1715331Samw 	if ((sr->fid_ofile->f_node == NULL) ||
1725331Samw 	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
1735772Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 0, 0);
1746139Sjb150015 		return (SDRC_ERROR);
1755331Samw 	}
1765331Samw 
1777961SNatalie.Li@Sun.COM 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
1787961SNatalie.Li@Sun.COM 
1797348SJose.Borrego@Sun.COM 	if (SMB_TREE_IS_READONLY(sr)) {
1805772Sas200622 		smbsr_error(sr, NT_STATUS_MEDIA_WRITE_PROTECTED, 0, 0);
1816139Sjb150015 		return (SDRC_ERROR);
1825331Samw 	}
1835331Samw 
1845331Samw 	if (sr->tid_tree->t_acltype != ACE_T) {
1855331Samw 		/*
1865331Samw 		 * If target filesystem doesn't support ACE_T acls then
1875331Samw 		 * don't process SACL
1885331Samw 		 */
1895521Sas200622 		secinfo &= ~SMB_SACL_SECINFO;
1905331Samw 	}
1915331Samw 
1925521Sas200622 	if ((secinfo & SMB_ALL_SECINFO) == 0) {
1935331Samw 		return (NT_STATUS_SUCCESS);
1945331Samw 	}
1955331Samw 
1965521Sas200622 	status = smb_decode_sd(xa, &sd);
1975521Sas200622 	if (status != NT_STATUS_SUCCESS) {
1985772Sas200622 		smbsr_error(sr, status, 0, 0);
1996139Sjb150015 		return (SDRC_ERROR);
2005331Samw 	}
2015331Samw 
2025521Sas200622 	if (((secinfo & SMB_OWNER_SECINFO) && (sd.sd_owner == NULL)) ||
2035521Sas200622 	    ((secinfo & SMB_GROUP_SECINFO) && (sd.sd_group == NULL))) {
2045772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
2056139Sjb150015 		return (SDRC_ERROR);
2065521Sas200622 	}
2075331Samw 
20811963SAfshin.Ardakani@Sun.COM 	if (!smb_node_is_system(sr->fid_ofile->f_node))
20911963SAfshin.Ardakani@Sun.COM 		status = smb_sd_write(sr, &sd, secinfo);
21011963SAfshin.Ardakani@Sun.COM 
2115521Sas200622 	smb_sd_term(&sd);
2125331Samw 	if (status != NT_STATUS_SUCCESS) {
2135772Sas200622 		smbsr_error(sr, status, 0, 0);
2146139Sjb150015 		return (SDRC_ERROR);
2155331Samw 	}
2165331Samw 
2176139Sjb150015 	return (SDRC_SUCCESS);
2185331Samw }
2195521Sas200622 
2205521Sas200622 /*
2215521Sas200622  * smb_encode_sd
2225521Sas200622  *
2235521Sas200622  * Encodes given security descriptor in the reply buffer.
2245521Sas200622  */
2255521Sas200622 static void
smb_encode_sd(struct smb_xa * xa,smb_sd_t * sd,uint32_t secinfo)2265521Sas200622 smb_encode_sd(struct smb_xa *xa, smb_sd_t *sd, uint32_t secinfo)
2275521Sas200622 {
2285521Sas200622 	uint32_t offset = SMB_SD_HDRSIZE;
2295521Sas200622 
2305521Sas200622 	/* encode header */
2317052Samw 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.w",
2325521Sas200622 	    sd->sd_revision, sd->sd_control | SE_SELF_RELATIVE);
2335521Sas200622 
2345521Sas200622 	/* owner offset */
2355521Sas200622 	if (secinfo & SMB_OWNER_SECINFO) {
2365521Sas200622 		ASSERT(sd->sd_owner);
2377052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
2386432Sas200622 		offset += smb_sid_len(sd->sd_owner);
2395521Sas200622 	} else {
2407052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
2415521Sas200622 	}
2425521Sas200622 
2435521Sas200622 	/* group offset */
2445521Sas200622 	if (secinfo & SMB_GROUP_SECINFO) {
2455521Sas200622 		ASSERT(sd->sd_group);
2467052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
2476432Sas200622 		offset += smb_sid_len(sd->sd_group);
2485521Sas200622 	} else {
2497052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
2505521Sas200622 	}
2515521Sas200622 
2525521Sas200622 	/* SACL offset */
2535521Sas200622 	if ((secinfo & SMB_SACL_SECINFO) && (sd->sd_sacl)) {
2547052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
2555521Sas200622 		offset += smb_acl_len(sd->sd_sacl);
2565521Sas200622 	} else {
2577052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
2585521Sas200622 	}
2595521Sas200622 
2605521Sas200622 	/* DACL offset */
2615521Sas200622 	if ((secinfo & SMB_DACL_SECINFO) && (sd->sd_dacl))
2627052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
2635521Sas200622 	else
2647052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
2655521Sas200622 
2665521Sas200622 	if (secinfo & SMB_OWNER_SECINFO)
2675521Sas200622 		smb_encode_sid(xa, sd->sd_owner);
2685521Sas200622 
2695521Sas200622 	if (secinfo & SMB_GROUP_SECINFO)
2705521Sas200622 		smb_encode_sid(xa, sd->sd_group);
2715521Sas200622 
2725521Sas200622 	if (secinfo & SMB_SACL_SECINFO)
2735521Sas200622 		smb_encode_sacl(xa, sd->sd_sacl);
2745521Sas200622 
2755521Sas200622 	if (secinfo & SMB_DACL_SECINFO)
2765521Sas200622 		smb_encode_dacl(xa, sd->sd_dacl);
2775521Sas200622 }
2785521Sas200622 
2795521Sas200622 /*
2805521Sas200622  * smb_encode_sid
2815521Sas200622  *
2825521Sas200622  * Encodes given SID in the reply buffer.
2835521Sas200622  */
2849914Samw@Sun.COM void
smb_encode_sid(struct smb_xa * xa,smb_sid_t * sid)2856432Sas200622 smb_encode_sid(struct smb_xa *xa, smb_sid_t *sid)
2865521Sas200622 {
2875521Sas200622 	int i;
2885521Sas200622 
2897052Samw 	(void) smb_mbc_encodef(&xa->rep_data_mb, "bb",
2906432Sas200622 	    sid->sid_revision, sid->sid_subauthcnt);
2915521Sas200622 
2925521Sas200622 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
2937052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "b",
2946432Sas200622 		    sid->sid_authority[i]);
2955521Sas200622 	}
2965521Sas200622 
2976432Sas200622 	for (i = 0; i < sid->sid_subauthcnt; i++) {
2987052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
2996432Sas200622 		    sid->sid_subauth[i]);
3005521Sas200622 	}
3015521Sas200622 }
3025521Sas200622 
3035521Sas200622 /*
3045521Sas200622  * smb_encode_sacl
3055521Sas200622  *
3065521Sas200622  * Encodes given SACL in the reply buffer.
3075521Sas200622  */
3085521Sas200622 static void
smb_encode_sacl(struct smb_xa * xa,smb_acl_t * acl)3095521Sas200622 smb_encode_sacl(struct smb_xa *xa, smb_acl_t *acl)
3105521Sas200622 {
3115521Sas200622 	smb_ace_t *ace;
3125521Sas200622 	int i;
3135521Sas200622 
3145521Sas200622 	if (acl == NULL)
3155521Sas200622 		return;
3165521Sas200622 
3175521Sas200622 	/* encode header */
3187052Samw 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.ww2.", acl->sl_revision,
3195521Sas200622 	    acl->sl_bsize, acl->sl_acecnt);
3205521Sas200622 
3215521Sas200622 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
3227052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "bbwl",
3235521Sas200622 		    ace->se_hdr.se_type, ace->se_hdr.se_flags,
3245521Sas200622 		    ace->se_hdr.se_bsize, ace->se_mask);
3255521Sas200622 
3265521Sas200622 		smb_encode_sid(xa, ace->se_sid);
3275521Sas200622 	}
3285521Sas200622 }
3295521Sas200622 
3305521Sas200622 /*
3315521Sas200622  * smb_encode_dacl
3325521Sas200622  *
3335521Sas200622  * Encodes given DACL in the reply buffer.
3345521Sas200622  */
3355521Sas200622 static void
smb_encode_dacl(struct smb_xa * xa,smb_acl_t * acl)3365521Sas200622 smb_encode_dacl(struct smb_xa *xa, smb_acl_t *acl)
3375521Sas200622 {
3385521Sas200622 	smb_ace_t *ace;
3395521Sas200622 
3405521Sas200622 	if (acl == NULL)
3415521Sas200622 		return;
3425521Sas200622 
3435521Sas200622 	/* encode header */
3447052Samw 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.ww2.", acl->sl_revision,
3455521Sas200622 	    acl->sl_bsize, acl->sl_acecnt);
3465521Sas200622 
3475521Sas200622 	ace = list_head(&acl->sl_sorted);
3485521Sas200622 	while (ace) {
3497052Samw 		(void) smb_mbc_encodef(&xa->rep_data_mb, "bbwl",
3505521Sas200622 		    ace->se_hdr.se_type, ace->se_hdr.se_flags,
3515521Sas200622 		    ace->se_hdr.se_bsize, ace->se_mask);
3525521Sas200622 
3535521Sas200622 		smb_encode_sid(xa, ace->se_sid);
3545521Sas200622 		ace = list_next(&acl->sl_sorted, ace);
3555521Sas200622 	}
3565521Sas200622 }
3575521Sas200622 
3585521Sas200622 /*
3595521Sas200622  * smb_decode_sd
3605521Sas200622  *
3615521Sas200622  * Decodes the security descriptor in the request buffer
3625521Sas200622  * and set the fields of 'sd' appropraitely. Upon successful
3635521Sas200622  * return, caller must free allocated memories by calling
3645521Sas200622  * smb_sd_term().
3655521Sas200622  */
3665521Sas200622 uint32_t
smb_decode_sd(struct smb_xa * xa,smb_sd_t * sd)3675521Sas200622 smb_decode_sd(struct smb_xa *xa, smb_sd_t *sd)
3685521Sas200622 {
3695521Sas200622 	struct mbuf_chain sdbuf;
3705521Sas200622 	uint32_t owner_offs;
3715521Sas200622 	uint32_t group_offs;
3725521Sas200622 	uint32_t sacl_offs;
3735521Sas200622 	uint32_t dacl_offs;
3745521Sas200622 
3755521Sas200622 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
3765521Sas200622 
3775521Sas200622 	(void) MBC_SHADOW_CHAIN(&sdbuf, &xa->req_data_mb,
3785521Sas200622 	    xa->req_data_mb.chain_offset,
3795521Sas200622 	    xa->req_data_mb.max_bytes - xa->req_data_mb.chain_offset);
3805521Sas200622 
3817052Samw 	if (smb_mbc_decodef(&sdbuf, "b.wllll",
3825521Sas200622 	    &sd->sd_revision, &sd->sd_control,
3835521Sas200622 	    &owner_offs, &group_offs, &sacl_offs, &dacl_offs))
3845521Sas200622 		goto decode_error;
3855521Sas200622 
3865521Sas200622 	sd->sd_control &= ~SE_SELF_RELATIVE;
3875521Sas200622 
3885521Sas200622 	if (owner_offs != 0) {
3895521Sas200622 		if (owner_offs < SMB_SD_HDRSIZE)
3905521Sas200622 			goto decode_error;
3915521Sas200622 
3925521Sas200622 		sd->sd_owner = smb_decode_sid(xa, owner_offs);
3935521Sas200622 		if (sd->sd_owner == NULL)
3945521Sas200622 			goto decode_error;
3955521Sas200622 	}
3965521Sas200622 
3975521Sas200622 	if (group_offs != 0) {
3985521Sas200622 		if (group_offs < SMB_SD_HDRSIZE)
3995521Sas200622 			goto decode_error;
4005521Sas200622 
4015521Sas200622 		sd->sd_group = smb_decode_sid(xa, group_offs);
4025521Sas200622 		if (sd->sd_group == NULL)
4035521Sas200622 			goto decode_error;
4045521Sas200622 	}
4055521Sas200622 
4065521Sas200622 	if (sacl_offs != 0) {
4075521Sas200622 		if ((sd->sd_control & SE_SACL_PRESENT) == 0)
4085521Sas200622 			goto decode_error;
4095521Sas200622 
4105521Sas200622 		if (sacl_offs < SMB_SD_HDRSIZE)
4115521Sas200622 			goto decode_error;
4125521Sas200622 
4135521Sas200622 		sd->sd_sacl = smb_decode_acl(xa, sacl_offs);
4145521Sas200622 		if (sd->sd_sacl == NULL)
4155521Sas200622 			goto decode_error;
4165521Sas200622 	}
4175521Sas200622 
4185521Sas200622 	if (dacl_offs != 0) {
4195521Sas200622 		if ((sd->sd_control & SE_DACL_PRESENT) == 0)
4205521Sas200622 			goto decode_error;
4215521Sas200622 
4225521Sas200622 		if (dacl_offs < SMB_SD_HDRSIZE)
4235521Sas200622 			goto decode_error;
4245521Sas200622 
4255521Sas200622 		sd->sd_dacl = smb_decode_acl(xa, dacl_offs);
4265521Sas200622 		if (sd->sd_dacl == NULL)
4275521Sas200622 			goto decode_error;
4285521Sas200622 	}
4295521Sas200622 
4305521Sas200622 	return (NT_STATUS_SUCCESS);
4315521Sas200622 
4325521Sas200622 decode_error:
4335521Sas200622 	smb_sd_term(sd);
4345521Sas200622 	return (NT_STATUS_INVALID_SECURITY_DESCR);
4355521Sas200622 }
4365521Sas200622 
4375521Sas200622 /*
4385521Sas200622  * smb_decode_sid
4395521Sas200622  *
4405521Sas200622  * Allocates memory and decodes the SID in the request buffer
4415521Sas200622  * Upon successful return, caller must free the allocated memory
4426432Sas200622  * by calling smb_sid_free()
4435521Sas200622  */
44411963SAfshin.Ardakani@Sun.COM smb_sid_t *
smb_decode_sid(struct smb_xa * xa,uint32_t offset)4455521Sas200622 smb_decode_sid(struct smb_xa *xa, uint32_t offset)
4465521Sas200622 {
4475521Sas200622 	uint8_t revision;
4485521Sas200622 	uint8_t subauth_cnt;
4495521Sas200622 	struct mbuf_chain sidbuf;
4506432Sas200622 	smb_sid_t *sid;
4515521Sas200622 	int sidlen;
4525521Sas200622 	int bytes_left;
4535521Sas200622 	int i;
4545521Sas200622 
4555521Sas200622 	offset += xa->req_data_mb.chain_offset;
4565521Sas200622 	bytes_left = xa->req_data_mb.max_bytes - offset;
4576432Sas200622 	if (bytes_left < sizeof (smb_sid_t))
4585521Sas200622 		return (NULL);
4595521Sas200622 
4605521Sas200622 	(void) MBC_SHADOW_CHAIN(&sidbuf, &xa->req_data_mb, offset, bytes_left);
4615521Sas200622 
4627052Samw 	if (smb_mbc_decodef(&sidbuf, "bb", &revision, &subauth_cnt))
4635521Sas200622 		return (NULL);
4645521Sas200622 
4656432Sas200622 	sidlen = sizeof (smb_sid_t) - sizeof (uint32_t) +
4665521Sas200622 	    (subauth_cnt * sizeof (uint32_t));
4676432Sas200622 	sid = kmem_alloc(sidlen, KM_SLEEP);
4685521Sas200622 
4696432Sas200622 	sid->sid_revision = revision;
4706432Sas200622 	sid->sid_subauthcnt = subauth_cnt;
4715521Sas200622 
4725521Sas200622 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
4737052Samw 		if (smb_mbc_decodef(&sidbuf, "b", &sid->sid_authority[i]))
4745521Sas200622 			goto decode_err;
4755521Sas200622 	}
4765521Sas200622 
4776432Sas200622 	for (i = 0; i < sid->sid_subauthcnt; i++) {
4787052Samw 		if (smb_mbc_decodef(&sidbuf, "l", &sid->sid_subauth[i]))
4795521Sas200622 			goto decode_err;
4805521Sas200622 	}
4815521Sas200622 
4825521Sas200622 	return (sid);
4835521Sas200622 
4845521Sas200622 decode_err:
4856432Sas200622 	kmem_free(sid, sidlen);
4865521Sas200622 	return (NULL);
4875521Sas200622 }
4885521Sas200622 
4895521Sas200622 /*
4905521Sas200622  * smb_decode_acl
4915521Sas200622  *
4925521Sas200622  * Allocates memory and decodes the ACL in the request buffer
4935521Sas200622  * Upon successful return, caller must free the allocated memory
4945521Sas200622  * by calling smb_acl_free().
4955521Sas200622  */
4965521Sas200622 static smb_acl_t *
smb_decode_acl(struct smb_xa * xa,uint32_t offset)4975521Sas200622 smb_decode_acl(struct smb_xa *xa, uint32_t offset)
4985521Sas200622 {
4995521Sas200622 	struct mbuf_chain aclbuf;
5005521Sas200622 	smb_acl_t *acl;
5015521Sas200622 	smb_ace_t *ace;
5025521Sas200622 	uint8_t revision;
5035521Sas200622 	uint16_t size;
5045521Sas200622 	uint16_t acecnt;
5055521Sas200622 	int bytes_left;
5065521Sas200622 	uint32_t sid_offs = offset;
5075521Sas200622 	int sidlen;
5085521Sas200622 	int i;
5095521Sas200622 
5105521Sas200622 	offset += xa->req_data_mb.chain_offset;
5115521Sas200622 	bytes_left = xa->req_data_mb.max_bytes - offset;
5125521Sas200622 	if (bytes_left < SMB_ACL_HDRSIZE)
5135521Sas200622 		return (NULL);
5145521Sas200622 
5155521Sas200622 	(void) MBC_SHADOW_CHAIN(&aclbuf, &xa->req_data_mb, offset, bytes_left);
5165521Sas200622 
5177052Samw 	if (smb_mbc_decodef(&aclbuf, "b.ww2.", &revision, &size, &acecnt))
5185521Sas200622 		return (NULL);
5195521Sas200622 
5205521Sas200622 	if (size == 0)
5215521Sas200622 		return (NULL);
5225521Sas200622 
5235521Sas200622 	acl = smb_acl_alloc(revision, size, acecnt);
5245521Sas200622 
5255521Sas200622 	sid_offs += SMB_ACL_HDRSIZE;
5265521Sas200622 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
5277052Samw 		if (smb_mbc_decodef(&aclbuf, "bbwl",
5285521Sas200622 		    &ace->se_hdr.se_type, &ace->se_hdr.se_flags,
5295521Sas200622 		    &ace->se_hdr.se_bsize, &ace->se_mask))
5305521Sas200622 			goto decode_error;
5315521Sas200622 
5325521Sas200622 		sid_offs += SMB_ACE_HDRSIZE + sizeof (ace->se_mask);
5335521Sas200622 		ace->se_sid = smb_decode_sid(xa, sid_offs);
5345521Sas200622 		if (ace->se_sid == NULL)
5355521Sas200622 			goto decode_error;
5367961SNatalie.Li@Sun.COM 		/* This is SID length plus any paddings between ACEs */
5377961SNatalie.Li@Sun.COM 		sidlen = ace->se_hdr.se_bsize -
5387961SNatalie.Li@Sun.COM 		    (SMB_ACE_HDRSIZE + sizeof (ace->se_mask));
5395521Sas200622 		aclbuf.chain_offset += sidlen;
5405521Sas200622 		sid_offs += sidlen;
5415521Sas200622 	}
5425521Sas200622 
5435521Sas200622 	return (acl);
5445521Sas200622 
5455521Sas200622 decode_error:
5465521Sas200622 	smb_acl_free(acl);
5475521Sas200622 	return (NULL);
5485521Sas200622 }
549