2023-07-13 12:31:50 +03:00
/*
2005-04-11 03:08:04 +04:00
Unix SMB / CIFS implementation .
fast routines for getting the wire size of security objects
Copyright ( C ) Andrew Tridgell 2003
2008-11-07 18:45:37 +03:00
Copyright ( C ) Stefan Metzmacher 2006 - 2008
2023-07-13 12:31:50 +03:00
2005-04-11 03:08:04 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-04-11 03:08:04 +04:00
( at your option ) any later version .
2023-07-13 12:31:50 +03:00
2005-04-11 03:08:04 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2023-07-13 12:31:50 +03:00
2005-04-11 03:08:04 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-04-11 03:08:04 +04:00
*/
# include "includes.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/ndr_security.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2005-04-11 03:08:04 +04:00
2023-07-13 12:31:50 +03:00
2005-04-11 03:08:04 +04:00
/*
2023-07-13 12:31:50 +03:00
* Find the wire size of a security_ace that has no trailing coda .
* This is used in ndr_pull_security_ace ( ) generated from security . idl
* to work out where the coda starts ( and in ndr_size_security_ace ( )
* just below ) .
*/
2023-07-10 06:47:03 +03:00
static size_t ndr_size_security_ace_core ( const struct security_ace * ace , libndr_flags flags )
2005-04-11 03:08:04 +04:00
{
2007-01-15 12:54:08 +03:00
size_t ret ;
2005-04-11 03:08:04 +04:00
if ( ! ace ) return 0 ;
2010-05-09 19:20:01 +04:00
ret = 8 + ndr_size_dom_sid ( & ace - > trustee , flags ) ;
2023-08-23 02:25:41 +03:00
if ( sec_ace_object ( ace - > type ) ) {
2007-01-15 12:54:08 +03:00
ret + = 4 ; /* uint32 bitmap ace->object.object.flags */
if ( ace - > object . object . flags & SEC_ACE_OBJECT_TYPE_PRESENT ) {
ret + = 16 ; /* GUID ace->object.object.type.type */
}
if ( ace - > object . object . flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT ) {
2023-08-23 02:24:46 +03:00
ret + = 16 ; /* GUID ace->object.object.inherited_type.inherited_type */
2007-01-15 12:54:08 +03:00
}
}
return ret ;
}
2005-04-11 03:08:04 +04:00
2023-07-13 12:31:50 +03:00
/*
return the wire size of a security_ace
*/
2023-07-10 06:47:03 +03:00
size_t ndr_size_security_ace ( const struct security_ace * ace , libndr_flags flags )
2023-07-13 12:31:50 +03:00
{
2023-08-17 01:46:23 +03:00
size_t base = ndr_size_security_ace_core ( ace , flags ) ;
size_t ret = base ;
if ( sec_ace_callback ( ace - > type ) ) {
ret + = ace - > coda . conditions . length ;
} else if ( ace - > type = = SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE ) {
ret + = ndr_size_security_ace_coda ( & ace - > coda , ace - > type , flags ) ;
} else {
ret + = ace - > coda . ignored . length ;
}
2023-08-30 03:14:14 +03:00
/* round up to a multiple of 4 (MS-DTYP 2.4.4.1) */
ret = ( ret + 3ULL ) & ~ 3ULL ;
2023-08-17 01:46:23 +03:00
if ( unlikely ( ret < base ) ) {
/* overflow, and there's not much we can do anyway */
return 0 ;
}
2023-07-13 12:31:50 +03:00
return ret ;
}
2023-12-31 03:03:32 +03:00
_PUBLIC_ enum ndr_err_code ndr_pull_security_ace ( struct ndr_pull * ndr , ndr_flags_type ndr_flags , struct security_ace * r )
{
NDR_PULL_CHECK_FLAGS ( ndr , ndr_flags ) ;
if ( ndr_flags & NDR_SCALARS ) {
2023-12-31 03:06:40 +03:00
ssize_t sub_size ;
2023-12-31 03:03:32 +03:00
NDR_CHECK ( ndr_pull_align ( ndr , 5 ) ) ;
NDR_CHECK ( ndr_pull_security_ace_type ( ndr , NDR_SCALARS , & r - > type ) ) ;
NDR_CHECK ( ndr_pull_security_ace_flags ( ndr , NDR_SCALARS , & r - > flags ) ) ;
NDR_CHECK ( ndr_pull_uint16 ( ndr , NDR_SCALARS , & r - > size ) ) ;
NDR_CHECK ( ndr_pull_uint32 ( ndr , NDR_SCALARS , & r - > access_mask ) ) ;
NDR_CHECK ( ndr_pull_set_switch_value ( ndr , & r - > object , sec_ace_object ( r - > type ) ) ) ;
NDR_CHECK ( ndr_pull_security_ace_object_ctr ( ndr , NDR_SCALARS , & r - > object ) ) ;
NDR_CHECK ( ndr_pull_dom_sid ( ndr , NDR_SCALARS , & r - > trustee ) ) ;
2023-12-31 03:06:40 +03:00
sub_size = ndr_subcontext_size_of_ace_coda ( r , r - > size , ndr - > flags ) ;
if ( sub_size = = 0 ) {
r - > coda . ignored . data = NULL ;
r - > coda . ignored . length = 0 ;
} else {
2023-12-31 03:03:32 +03:00
struct ndr_pull * _ndr_coda ;
NDR_CHECK ( ndr_pull_subcontext_start ( ndr , & _ndr_coda , 0 , sub_size ) ) ;
NDR_CHECK ( ndr_pull_set_switch_value ( _ndr_coda , & r - > coda , r - > type ) ) ;
NDR_CHECK ( ndr_pull_security_ace_coda ( _ndr_coda , NDR_SCALARS | NDR_BUFFERS , & r - > coda ) ) ;
NDR_CHECK ( ndr_pull_subcontext_end ( ndr , _ndr_coda , 0 , sub_size ) ) ;
}
NDR_CHECK ( ndr_pull_trailer_align ( ndr , 5 ) ) ;
}
if ( ndr_flags & NDR_BUFFERS ) {
NDR_CHECK ( ndr_pull_set_switch_value ( ndr , & r - > object , sec_ace_object ( r - > type ) ) ) ;
NDR_CHECK ( ndr_pull_security_ace_object_ctr ( ndr , NDR_BUFFERS , & r - > object ) ) ;
}
return NDR_ERR_SUCCESS ;
}
2023-07-13 12:31:50 +03:00
/*
* An ACE coda can ' t be bigger than the space allowed for by
* ace - > size , so we need to check this from the context of the ACE .
*
* Usually the coda also can ' t be any smaller than the remaining
* space , because it is defined as a blob consuming everything it can .
*
* This is only used to find the size for the coda subcontext in
* security . idl .
*/
size_t ndr_subcontext_size_of_ace_coda ( const struct security_ace * ace ,
size_t ace_size ,
2023-07-10 06:47:03 +03:00
libndr_flags flags )
2008-11-07 12:49:59 +03:00
{
2023-07-13 12:31:50 +03:00
size_t core_size ;
if ( ace_size = = 0 ) {
return 0 ;
2008-11-07 12:49:59 +03:00
}
2023-07-13 12:31:50 +03:00
core_size = ndr_size_security_ace_core ( ace , flags ) ;
if ( ace_size < core_size ) {
return 0 ;
2008-11-07 12:49:59 +03:00
}
2023-07-13 12:31:50 +03:00
return ace_size - core_size ;
2008-11-07 12:49:59 +03:00
}
2005-04-11 03:08:04 +04:00
/*
return the wire size of a security_acl
*/
2023-07-10 06:47:03 +03:00
size_t ndr_size_security_acl ( const struct security_acl * theacl , libndr_flags flags )
2005-04-11 03:08:04 +04:00
{
size_t ret ;
int i ;
2009-02-24 02:03:29 +03:00
if ( ! theacl ) return 0 ;
2005-04-11 03:08:04 +04:00
ret = 8 ;
2009-02-24 02:03:29 +03:00
for ( i = 0 ; i < theacl - > num_aces ; i + + ) {
2010-05-09 19:20:01 +04:00
ret + = ndr_size_security_ace ( & theacl - > aces [ i ] , flags ) ;
2005-04-11 03:08:04 +04:00
}
return ret ;
}
/*
return the wire size of a security descriptor
*/
2023-07-10 06:47:03 +03:00
size_t ndr_size_security_descriptor ( const struct security_descriptor * sd , libndr_flags flags )
2005-04-11 03:08:04 +04:00
{
size_t ret ;
if ( ! sd ) return 0 ;
2023-07-13 12:31:50 +03:00
2005-04-11 03:08:04 +04:00
ret = 20 ;
2010-05-09 19:20:01 +04:00
ret + = ndr_size_dom_sid ( sd - > owner_sid , flags ) ;
ret + = ndr_size_dom_sid ( sd - > group_sid , flags ) ;
ret + = ndr_size_security_acl ( sd - > dacl , flags ) ;
ret + = ndr_size_security_acl ( sd - > sacl , flags ) ;
2005-04-11 03:08:04 +04:00
return ret ;
}
2008-12-12 22:20:01 +03:00
/*
return the wire size of a dom_sid
*/
2023-07-10 06:47:03 +03:00
size_t ndr_size_dom_sid ( const struct dom_sid * sid , libndr_flags flags )
2008-12-12 22:20:01 +03:00
{
if ( ! sid ) return 0 ;
return 8 + 4 * sid - > num_auths ;
}
2023-07-10 06:47:03 +03:00
size_t ndr_size_dom_sid28 ( const struct dom_sid * sid , libndr_flags flags )
2008-12-12 22:20:01 +03:00
{
2016-12-31 15:45:51 +03:00
if ( all_zero ( ( const uint8_t * ) sid , sizeof ( struct dom_sid ) ) ) {
2008-12-12 22:20:01 +03:00
return 0 ;
}
2022-08-31 18:35:42 +03:00
return ndr_size_dom_sid ( sid , flags ) ;
2008-12-12 22:20:01 +03:00
}
2023-07-10 06:47:03 +03:00
size_t ndr_size_dom_sid0 ( const struct dom_sid * sid , libndr_flags flags )
2008-12-12 22:20:01 +03:00
{
return ndr_size_dom_sid28 ( sid , flags ) ;
}
/*
print a dom_sid
*/
void ndr_print_dom_sid ( struct ndr_print * ndr , const char * name , const struct dom_sid * sid )
{
2018-12-21 11:32:41 +03:00
struct dom_sid_buf buf ;
ndr - > print ( ndr , " %-25s: %s " , name , dom_sid_str_buf ( sid , & buf ) ) ;
2008-12-12 22:20:01 +03:00
}
void ndr_print_dom_sid2 ( struct ndr_print * ndr , const char * name , const struct dom_sid * sid )
{
ndr_print_dom_sid ( ndr , name , sid ) ;
}
void ndr_print_dom_sid28 ( struct ndr_print * ndr , const char * name , const struct dom_sid * sid )
{
ndr_print_dom_sid ( ndr , name , sid ) ;
}
void ndr_print_dom_sid0 ( struct ndr_print * ndr , const char * name , const struct dom_sid * sid )
{
ndr_print_dom_sid ( ndr , name , sid ) ;
}
/*
parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
*/
2023-10-27 04:41:17 +03:00
enum ndr_err_code ndr_pull_dom_sid2 ( struct ndr_pull * ndr , ndr_flags_type ndr_flags , struct dom_sid * sid )
2008-12-12 22:20:01 +03:00
{
uint32_t num_auths ;
if ( ! ( ndr_flags & NDR_SCALARS ) ) {
return NDR_ERR_SUCCESS ;
}
2009-09-18 02:15:24 +04:00
NDR_CHECK ( ndr_pull_uint3264 ( ndr , NDR_SCALARS , & num_auths ) ) ;
2008-12-12 22:20:01 +03:00
NDR_CHECK ( ndr_pull_dom_sid ( ndr , ndr_flags , sid ) ) ;
if ( sid - > num_auths ! = num_auths ) {
2023-07-13 12:31:50 +03:00
return ndr_pull_error ( ndr , NDR_ERR_ARRAY_SIZE ,
2021-05-11 01:28:07 +03:00
" Bad num_auths % " PRIu32 " ; should equal % " PRId8 ,
2008-12-12 22:20:01 +03:00
num_auths , sid - > num_auths ) ;
}
return NDR_ERR_SUCCESS ;
}
/*
parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
*/
2023-10-27 04:41:17 +03:00
enum ndr_err_code ndr_push_dom_sid2 ( struct ndr_push * ndr , ndr_flags_type ndr_flags , const struct dom_sid * sid )
2008-12-12 22:20:01 +03:00
{
if ( ! ( ndr_flags & NDR_SCALARS ) ) {
return NDR_ERR_SUCCESS ;
}
2009-09-18 02:15:24 +04:00
NDR_CHECK ( ndr_push_uint3264 ( ndr , NDR_SCALARS , sid - > num_auths ) ) ;
2008-12-12 22:20:01 +03:00
return ndr_push_dom_sid ( ndr , ndr_flags , sid ) ;
}
/*
2019-08-29 23:19:42 +03:00
parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer , so we need to ensure there are only up to 5 sub_auth
2008-12-12 22:20:01 +03:00
*/
2023-10-27 04:41:17 +03:00
enum ndr_err_code ndr_pull_dom_sid28 ( struct ndr_pull * ndr , ndr_flags_type ndr_flags , struct dom_sid * sid )
2008-12-12 22:20:01 +03:00
{
enum ndr_err_code status ;
struct ndr_pull * subndr ;
if ( ! ( ndr_flags & NDR_SCALARS ) ) {
return NDR_ERR_SUCCESS ;
}
subndr = talloc_zero ( ndr , struct ndr_pull ) ;
NDR_ERR_HAVE_NO_MEMORY ( subndr ) ;
subndr - > flags = ndr - > flags ;
subndr - > current_mem_ctx = ndr - > current_mem_ctx ;
subndr - > data = ndr - > data + ndr - > offset ;
subndr - > data_size = 28 ;
subndr - > offset = 0 ;
2023-08-07 04:46:50 +03:00
status = ndr_pull_advance ( ndr , 28 ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( status ) ) {
talloc_free ( subndr ) ;
return status ;
}
2008-12-12 22:20:01 +03:00
status = ndr_pull_dom_sid ( subndr , ndr_flags , sid ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( status ) ) {
/* handle a w2k bug which send random data in the buffer */
ZERO_STRUCTP ( sid ) ;
2013-02-18 20:08:21 +04:00
} else if ( sid - > num_auths = = 0 ) {
2008-12-12 22:20:01 +03:00
ZERO_STRUCT ( sid - > sub_auths ) ;
}
2023-08-07 04:46:50 +03:00
talloc_free ( subndr ) ;
2008-12-12 22:20:01 +03:00
return NDR_ERR_SUCCESS ;
}
/*
push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer
*/
2023-10-27 04:41:17 +03:00
enum ndr_err_code ndr_push_dom_sid28 ( struct ndr_push * ndr , ndr_flags_type ndr_flags , const struct dom_sid * sid )
2008-12-12 22:20:01 +03:00
{
uint32_t old_offset ;
uint32_t padding ;
if ( ! ( ndr_flags & NDR_SCALARS ) ) {
return NDR_ERR_SUCCESS ;
}
if ( sid - > num_auths > 5 ) {
2023-07-13 12:31:50 +03:00
return ndr_push_error ( ndr , NDR_ERR_RANGE ,
2021-05-11 01:28:07 +03:00
" dom_sid28 allows only up to 5 sub auths [% " PRId8 " ] " ,
2008-12-12 22:20:01 +03:00
sid - > num_auths ) ;
}
old_offset = ndr - > offset ;
NDR_CHECK ( ndr_push_dom_sid ( ndr , ndr_flags , sid ) ) ;
padding = 28 - ( ndr - > offset - old_offset ) ;
if ( padding > 0 ) {
NDR_CHECK ( ndr_push_zero ( ndr , padding ) ) ;
}
return NDR_ERR_SUCCESS ;
}
/*
parse a dom_sid0 - this is a dom_sid in a variable byte buffer , which is maybe empty
*/
2023-10-27 04:41:17 +03:00
enum ndr_err_code ndr_pull_dom_sid0 ( struct ndr_pull * ndr , ndr_flags_type ndr_flags , struct dom_sid * sid )
2008-12-12 22:20:01 +03:00
{
if ( ! ( ndr_flags & NDR_SCALARS ) ) {
return NDR_ERR_SUCCESS ;
}
if ( ndr - > data_size = = ndr - > offset ) {
ZERO_STRUCTP ( sid ) ;
return NDR_ERR_SUCCESS ;
}
return ndr_pull_dom_sid ( ndr , ndr_flags , sid ) ;
}
/*
push a dom_sid0 - this is a dom_sid in a variable byte buffer , which is maybe empty
*/
2023-10-27 04:41:17 +03:00
enum ndr_err_code ndr_push_dom_sid0 ( struct ndr_push * ndr , ndr_flags_type ndr_flags , const struct dom_sid * sid )
2008-12-12 22:20:01 +03:00
{
if ( ! ( ndr_flags & NDR_SCALARS ) ) {
return NDR_ERR_SUCCESS ;
}
if ( ! sid ) {
return NDR_ERR_SUCCESS ;
}
2016-12-31 15:45:51 +03:00
if ( all_zero ( ( const uint8_t * ) sid , sizeof ( struct dom_sid ) ) ) {
2008-12-12 22:20:01 +03:00
return NDR_ERR_SUCCESS ;
}
return ndr_push_dom_sid ( ndr , ndr_flags , sid ) ;
}
2023-10-27 04:41:17 +03:00
_PUBLIC_ enum ndr_err_code ndr_push_dom_sid ( struct ndr_push * ndr , ndr_flags_type ndr_flags , const struct dom_sid * r )
2008-12-12 22:20:01 +03:00
{
uint32_t cntr_sub_auths_0 ;
if ( ndr_flags & NDR_SCALARS ) {
NDR_CHECK ( ndr_push_align ( ndr , 4 ) ) ;
NDR_CHECK ( ndr_push_uint8 ( ndr , NDR_SCALARS , r - > sid_rev_num ) ) ;
NDR_CHECK ( ndr_push_int8 ( ndr , NDR_SCALARS , r - > num_auths ) ) ;
NDR_CHECK ( ndr_push_array_uint8 ( ndr , NDR_SCALARS , r - > id_auth , 6 ) ) ;
2011-09-05 10:41:21 +04:00
if ( r - > num_auths < 0 | | r - > num_auths > ARRAY_SIZE ( r - > sub_auths ) ) {
2021-05-04 05:09:44 +03:00
return ndr_push_error ( ndr , NDR_ERR_RANGE , " value (% " PRId8 " ) out of range ( 0 - % zu ) " , r->num_auths, ARRAY_SIZE(r->sub_auths)) ;
2011-09-05 10:41:21 +04:00
}
2008-12-12 22:20:01 +03:00
for ( cntr_sub_auths_0 = 0 ; cntr_sub_auths_0 < r - > num_auths ; cntr_sub_auths_0 + + ) {
NDR_CHECK ( ndr_push_uint32 ( ndr , NDR_SCALARS , r - > sub_auths [ cntr_sub_auths_0 ] ) ) ;
}
}
return NDR_ERR_SUCCESS ;
}
2023-10-27 04:41:17 +03:00
_PUBLIC_ enum ndr_err_code ndr_pull_dom_sid ( struct ndr_pull * ndr , ndr_flags_type ndr_flags , struct dom_sid * r )
2008-12-12 22:20:01 +03:00
{
uint32_t cntr_sub_auths_0 ;
if ( ndr_flags & NDR_SCALARS ) {
NDR_CHECK ( ndr_pull_align ( ndr , 4 ) ) ;
NDR_CHECK ( ndr_pull_uint8 ( ndr , NDR_SCALARS , & r - > sid_rev_num ) ) ;
NDR_CHECK ( ndr_pull_int8 ( ndr , NDR_SCALARS , & r - > num_auths ) ) ;
2011-09-05 10:41:21 +04:00
if ( r - > num_auths < 0 | | r - > num_auths > ARRAY_SIZE ( r - > sub_auths ) ) {
2021-05-04 05:09:44 +03:00
return ndr_pull_error ( ndr , NDR_ERR_RANGE , " value (% " PRId8 " ) out of range ( 0 - % zu ) " , r->num_auths, ARRAY_SIZE(r->sub_auths)) ;
2008-12-12 22:20:01 +03:00
}
NDR_CHECK ( ndr_pull_array_uint8 ( ndr , NDR_SCALARS , r - > id_auth , 6 ) ) ;
2012-06-26 14:07:32 +04:00
ZERO_STRUCT ( r - > sub_auths ) ;
2008-12-12 22:20:01 +03:00
for ( cntr_sub_auths_0 = 0 ; cntr_sub_auths_0 < r - > num_auths ; cntr_sub_auths_0 + + ) {
NDR_CHECK ( ndr_pull_uint32 ( ndr , NDR_SCALARS , & r - > sub_auths [ cntr_sub_auths_0 ] ) ) ;
}
}
return NDR_ERR_SUCCESS ;
}