2007-11-09 13:50:14 +03:00
/*
Unix SMB / CIFS implementation .
UUID / GUID functions
Copyright ( C ) Theodore Ts ' o 1996 , 1997 ,
Copyright ( C ) Jim McDonough 2002.
Copyright ( C ) Andrew Tridgell 2003.
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
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "librpc/ndr/libndr.h"
2008-11-13 23:27:10 +03:00
# include "librpc/gen_ndr/ndr_misc.h"
2007-11-09 13:50:14 +03:00
2009-12-10 06:29:19 +03:00
/**
build a NDR blob from a GUID
*/
_PUBLIC_ NTSTATUS GUID_to_ndr_blob ( const struct GUID * guid , TALLOC_CTX * mem_ctx , DATA_BLOB * b )
{
enum ndr_err_code ndr_err ;
2016-06-17 04:29:51 +03:00
* b = data_blob_talloc ( mem_ctx , NULL , 16 ) ;
if ( b - > data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
ndr_err = ndr_push_struct_into_fixed_blob (
b , guid , ( ndr_push_flags_fn_t ) ndr_push_GUID ) ;
2009-12-10 06:29:19 +03:00
return ndr_map_error2ntstatus ( ndr_err ) ;
}
2009-12-10 03:22:20 +03:00
/**
build a GUID from a NDR data blob
*/
_PUBLIC_ NTSTATUS GUID_from_ndr_blob ( const DATA_BLOB * b , struct GUID * guid )
{
2016-04-22 03:02:57 +03:00
enum ndr_err_code ndr_err =
ndr_pull_struct_blob_all_noalloc ( b , guid ,
( ndr_pull_flags_fn_t ) ndr_pull_GUID ) ;
2009-12-10 03:22:20 +03:00
return ndr_map_error2ntstatus ( ndr_err ) ;
}
2016-12-07 01:54:41 +03:00
static NTSTATUS read_hex_bytes ( const char * s , uint hexchars , uint64_t * dest )
{
uint64_t x = 0 ;
uint i ;
char c ;
if ( ( hexchars & 1 ) | | hexchars > 16 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
for ( i = 0 ; i < hexchars ; i + + ) {
x < < = 4 ;
c = s [ i ] ;
if ( c > = ' 0 ' & & c < = ' 9 ' ) {
x + = c - ' 0 ' ;
}
else if ( c > = ' a ' & & c < = ' f ' ) {
x + = c - ' a ' + 10 ;
}
else if ( c > = ' A ' & & c < = ' F ' ) {
x + = c - ' A ' + 10 ;
}
else {
/* BAD character (including '\0') */
return NT_STATUS_INVALID_PARAMETER ;
}
}
* dest = x ;
return NT_STATUS_OK ;
}
static NTSTATUS parse_guid_string ( const char * s ,
uint32_t * time_low ,
uint32_t * time_mid ,
uint32_t * time_hi_and_version ,
uint32_t * clock_seq ,
uint32_t * node )
{
uint64_t tmp ;
NTSTATUS status ;
int i ;
/* "e12b56b6-0a95-11d1-adbb-00c04fd8d5cd"
| | | | |
| | | | \ node [ 6 ]
| | | \ _____ clock_seq [ 2 ]
| | \ __________ time_hi_and_version
| \ _______________ time_mid
\ _____________________ time_low
*/
status = read_hex_bytes ( s , 8 , & tmp ) ;
if ( ! NT_STATUS_IS_OK ( status ) | | s [ 8 ] ! = ' - ' ) {
return NT_STATUS_INVALID_PARAMETER ;
}
* time_low = tmp ;
s + = 9 ;
status = read_hex_bytes ( s , 4 , & tmp ) ;
if ( ! NT_STATUS_IS_OK ( status ) | | s [ 4 ] ! = ' - ' ) {
return NT_STATUS_INVALID_PARAMETER ;
}
* time_mid = tmp ;
s + = 5 ;
status = read_hex_bytes ( s , 4 , & tmp ) ;
if ( ! NT_STATUS_IS_OK ( status ) | | s [ 4 ] ! = ' - ' ) {
return NT_STATUS_INVALID_PARAMETER ;
}
* time_hi_and_version = tmp ;
s + = 5 ;
for ( i = 0 ; i < 2 ; i + + ) {
status = read_hex_bytes ( s , 2 , & tmp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
clock_seq [ i ] = tmp ;
s + = 2 ;
}
if ( s [ 0 ] ! = ' - ' ) {
return NT_STATUS_INVALID_PARAMETER ;
}
s + + ;
for ( i = 0 ; i < 6 ; i + + ) {
status = read_hex_bytes ( s , 2 , & tmp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
node [ i ] = tmp ;
s + = 2 ;
}
return NT_STATUS_OK ;
}
2009-12-10 03:22:20 +03:00
2007-11-09 13:50:14 +03:00
/**
build a GUID from a string
*/
2008-11-10 03:40:31 +03:00
_PUBLIC_ NTSTATUS GUID_from_data_blob ( const DATA_BLOB * s , struct GUID * guid )
2007-11-09 13:50:14 +03:00
{
NTSTATUS status = NT_STATUS_INVALID_PARAMETER ;
uint32_t time_low ;
uint32_t time_mid , time_hi_and_version ;
uint32_t clock_seq [ 2 ] ;
uint32_t node [ 6 ] ;
2008-11-13 23:27:10 +03:00
uint8_t buf16 [ 16 ] ;
2008-12-20 04:05:48 +03:00
2008-11-13 23:27:10 +03:00
DATA_BLOB blob16 = data_blob_const ( buf16 , sizeof ( buf16 ) ) ;
2007-11-09 13:50:14 +03:00
int i ;
2008-11-10 03:40:31 +03:00
if ( s - > data = = NULL ) {
2007-11-09 13:50:14 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
2010-06-07 12:00:39 +04:00
switch ( s - > length ) {
case 36 :
{
2016-12-07 01:54:41 +03:00
status = parse_guid_string ( ( char * ) s - > data ,
& time_low ,
& time_mid ,
& time_hi_and_version ,
clock_seq ,
node ) ;
2010-06-07 12:00:39 +04:00
break ;
}
case 38 :
{
2016-12-07 01:54:41 +03:00
if ( s - > data [ 0 ] ! = ' { ' | | s - > data [ 37 ] ! = ' } ' ) {
break ;
2008-12-20 04:05:48 +03:00
}
2016-12-07 01:54:41 +03:00
status = parse_guid_string ( ( char * ) s - > data + 1 ,
& time_low ,
& time_mid ,
& time_hi_and_version ,
clock_seq ,
node ) ;
2010-06-07 12:00:39 +04:00
break ;
}
case 32 :
{
2008-11-13 23:27:10 +03:00
size_t rlen = strhex_to_str ( ( char * ) blob16 . data , blob16 . length ,
( const char * ) s - > data , s - > length ) ;
2010-06-28 23:00:30 +04:00
if ( rlen ! = blob16 . length ) {
return NT_STATUS_INVALID_PARAMETER ;
2008-11-13 23:27:10 +03:00
}
2010-06-28 23:00:30 +04:00
s = & blob16 ;
return GUID_from_ndr_blob ( s , guid ) ;
2008-11-13 23:27:10 +03:00
}
2010-06-07 12:00:39 +04:00
case 16 :
2009-12-10 03:22:20 +03:00
return GUID_from_ndr_blob ( s , guid ) ;
2010-06-07 12:00:39 +04:00
default :
status = NT_STATUS_INVALID_PARAMETER ;
break ;
2007-11-09 13:50:14 +03:00
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
guid - > time_low = time_low ;
guid - > time_mid = time_mid ;
guid - > time_hi_and_version = time_hi_and_version ;
guid - > clock_seq [ 0 ] = clock_seq [ 0 ] ;
guid - > clock_seq [ 1 ] = clock_seq [ 1 ] ;
for ( i = 0 ; i < 6 ; i + + ) {
guid - > node [ i ] = node [ i ] ;
}
return NT_STATUS_OK ;
}
2008-11-10 03:40:31 +03:00
/**
build a GUID from a string
*/
_PUBLIC_ NTSTATUS GUID_from_string ( const char * s , struct GUID * guid )
{
DATA_BLOB blob = data_blob_string_const ( s ) ;
return GUID_from_data_blob ( & blob , guid ) ;
}
2007-11-09 13:50:14 +03:00
/**
* generate a random GUID
*/
2008-10-13 17:01:28 +04:00
_PUBLIC_ struct GUID GUID_random ( void )
2007-11-09 13:50:14 +03:00
{
struct GUID guid ;
generate_random_buffer ( ( uint8_t * ) & guid , sizeof ( guid ) ) ;
guid . clock_seq [ 0 ] = ( guid . clock_seq [ 0 ] & 0x3F ) | 0x80 ;
guid . time_hi_and_version = ( guid . time_hi_and_version & 0x0FFF ) | 0x4000 ;
return guid ;
}
/**
* generate an empty GUID
*/
_PUBLIC_ struct GUID GUID_zero ( void )
{
struct GUID guid ;
ZERO_STRUCT ( guid ) ;
return guid ;
}
_PUBLIC_ bool GUID_all_zero ( const struct GUID * u )
{
if ( u - > time_low ! = 0 | |
u - > time_mid ! = 0 | |
u - > time_hi_and_version ! = 0 | |
u - > clock_seq [ 0 ] ! = 0 | |
u - > clock_seq [ 1 ] ! = 0 | |
! all_zero ( u - > node , 6 ) ) {
return false ;
}
return true ;
}
_PUBLIC_ bool GUID_equal ( const struct GUID * u1 , const struct GUID * u2 )
{
2014-06-05 13:56:55 +04:00
return ( GUID_compare ( u1 , u2 ) = = 0 ) ;
2007-11-09 13:50:14 +03:00
}
_PUBLIC_ int GUID_compare ( const struct GUID * u1 , const struct GUID * u2 )
{
if ( u1 - > time_low ! = u2 - > time_low ) {
2009-12-20 02:25:46 +03:00
return u1 - > time_low > u2 - > time_low ? 1 : - 1 ;
2007-11-09 13:50:14 +03:00
}
if ( u1 - > time_mid ! = u2 - > time_mid ) {
2009-12-20 02:25:46 +03:00
return u1 - > time_mid > u2 - > time_mid ? 1 : - 1 ;
2007-11-09 13:50:14 +03:00
}
if ( u1 - > time_hi_and_version ! = u2 - > time_hi_and_version ) {
2009-12-20 02:25:46 +03:00
return u1 - > time_hi_and_version > u2 - > time_hi_and_version ? 1 : - 1 ;
2007-11-09 13:50:14 +03:00
}
if ( u1 - > clock_seq [ 0 ] ! = u2 - > clock_seq [ 0 ] ) {
2009-12-20 02:25:46 +03:00
return u1 - > clock_seq [ 0 ] > u2 - > clock_seq [ 0 ] ? 1 : - 1 ;
2007-11-09 13:50:14 +03:00
}
if ( u1 - > clock_seq [ 1 ] ! = u2 - > clock_seq [ 1 ] ) {
2009-12-20 02:25:46 +03:00
return u1 - > clock_seq [ 1 ] > u2 - > clock_seq [ 1 ] ? 1 : - 1 ;
2007-11-09 13:50:14 +03:00
}
return memcmp ( u1 - > node , u2 - > node , 6 ) ;
}
/**
its useful to be able to display these in debugging messages
*/
_PUBLIC_ char * GUID_string ( TALLOC_CTX * mem_ctx , const struct GUID * guid )
{
2014-09-30 10:32:36 +04:00
struct GUID_txt_buf buf ;
return talloc_strdup ( mem_ctx , GUID_buf_string ( guid , & buf ) ) ;
2007-11-09 13:50:14 +03:00
}
2014-09-25 12:14:27 +04:00
/**
* Does the same without allocating memory , using the structure buffer .
* Useful for debug messages , so that you do not have to talloc_free the result
*/
_PUBLIC_ char * GUID_buf_string ( const struct GUID * guid ,
struct GUID_txt_buf * dst )
{
if ( ! guid ) {
return NULL ;
}
snprintf ( dst - > buf , sizeof ( dst - > buf ) ,
" %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x " ,
guid - > time_low , guid - > time_mid ,
guid - > time_hi_and_version ,
guid - > clock_seq [ 0 ] ,
guid - > clock_seq [ 1 ] ,
guid - > node [ 0 ] , guid - > node [ 1 ] ,
guid - > node [ 2 ] , guid - > node [ 3 ] ,
guid - > node [ 4 ] , guid - > node [ 5 ] ) ;
return dst - > buf ;
}
2007-11-09 13:50:14 +03:00
_PUBLIC_ char * GUID_string2 ( TALLOC_CTX * mem_ctx , const struct GUID * guid )
{
char * ret , * s = GUID_string ( mem_ctx , guid ) ;
ret = talloc_asprintf ( mem_ctx , " {%s} " , s ) ;
talloc_free ( s ) ;
return ret ;
}
2008-11-13 23:28:02 +03:00
_PUBLIC_ char * GUID_hexstring ( TALLOC_CTX * mem_ctx , const struct GUID * guid )
{
char * ret ;
DATA_BLOB guid_blob ;
TALLOC_CTX * tmp_mem ;
2009-12-10 06:29:19 +03:00
NTSTATUS status ;
2008-11-13 23:28:02 +03:00
tmp_mem = talloc_new ( mem_ctx ) ;
if ( ! tmp_mem ) {
return NULL ;
}
2009-12-10 06:29:19 +03:00
status = GUID_to_ndr_blob ( guid , tmp_mem , & guid_blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-11-13 23:28:02 +03:00
talloc_free ( tmp_mem ) ;
return NULL ;
}
2009-11-04 09:42:53 +03:00
ret = data_blob_hex_string_upper ( mem_ctx , & guid_blob ) ;
2008-11-13 23:28:02 +03:00
talloc_free ( tmp_mem ) ;
return ret ;
}
2012-03-18 20:44:24 +04:00
_PUBLIC_ bool ndr_policy_handle_empty ( const struct policy_handle * h )
2007-11-09 13:50:14 +03:00
{
return ( h - > handle_type = = 0 & & GUID_all_zero ( & h - > uuid ) ) ;
}
2011-02-08 02:04:20 +03:00
2012-03-18 19:54:21 +04:00
_PUBLIC_ bool ndr_policy_handle_equal ( const struct policy_handle * hnd1 ,
2011-02-08 02:04:20 +03:00
const struct policy_handle * hnd2 )
{
if ( ! hnd1 | | ! hnd2 ) {
return false ;
}
return ( memcmp ( hnd1 , hnd2 , sizeof ( * hnd1 ) ) = = 0 ) ;
}