2007-01-09 11:15:56 +00:00
/*
Unix SMB / CIFS mplementation .
Helper functions for applying replicated objects
2007-03-14 19:10:21 +00:00
Copyright ( C ) Stefan Metzmacher < metze @ samba . org > 2007
2007-01-09 11:15:56 +00: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 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2007-01-09 11:15:56 +00:00
( 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
2007-07-10 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2007-01-09 11:15:56 +00:00
*/
# include "includes.h"
# include "dsdb/samdb/samdb.h"
# include "lib/ldb/include/ldb_errors.h"
# include "lib/util/dlinklist.h"
# include "librpc/gen_ndr/ndr_misc.h"
# include "librpc/gen_ndr/ndr_drsuapi.h"
# include "librpc/gen_ndr/ndr_drsblobs.h"
2007-02-12 11:46:35 +00:00
# include "lib/crypto/crypto.h"
2007-02-15 12:40:13 +00:00
# include "libcli/auth/libcli_auth.h"
2008-01-01 22:05:05 -06:00
# include "param/param.h"
2007-02-12 11:46:35 +00:00
static WERROR dsdb_decrypt_attribute_value ( TALLOC_CTX * mem_ctx ,
const DATA_BLOB * gensec_skey ,
2007-02-15 12:40:13 +00:00
bool rid_crypt ,
uint32_t rid ,
2007-02-12 11:46:35 +00:00
DATA_BLOB * in ,
DATA_BLOB * out )
{
DATA_BLOB confounder ;
DATA_BLOB enc_buffer ;
struct MD5Context md5 ;
uint8_t _enc_key [ 16 ] ;
DATA_BLOB enc_key ;
DATA_BLOB dec_buffer ;
uint32_t crc32_given ;
uint32_t crc32_calc ;
DATA_BLOB checked_buffer ;
DATA_BLOB plain_buffer ;
2007-02-15 12:40:13 +00:00
/*
* users with rid = = 0 should not exist
*/
if ( rid_crypt & & rid = = 0 ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
2007-02-12 11:46:35 +00:00
/*
* the first 16 bytes at the beginning are the confounder
* followed by the 4 byte crc32 checksum
*/
if ( in - > length < 20 ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
confounder = data_blob_const ( in - > data , 16 ) ;
enc_buffer = data_blob_const ( in - > data + 16 , in - > length - 16 ) ;
/*
* build the encryption key md5 over the session key followed
* by the confounder
*
* here the gensec session key is used and
* not the dcerpc ncacn_ip_tcp " SystemLibraryDTC " key !
*/
enc_key = data_blob_const ( _enc_key , sizeof ( _enc_key ) ) ;
MD5Init ( & md5 ) ;
MD5Update ( & md5 , gensec_skey - > data , gensec_skey - > length ) ;
MD5Update ( & md5 , confounder . data , confounder . length ) ;
MD5Final ( enc_key . data , & md5 ) ;
/*
* copy the encrypted buffer part and
* decrypt it using the created encryption key using arcfour
*/
dec_buffer = data_blob_const ( enc_buffer . data , enc_buffer . length ) ;
arcfour_crypt_blob ( dec_buffer . data , dec_buffer . length , & enc_key ) ;
/*
* the first 4 byte are the crc32 checksum
* of the remaining bytes
*/
crc32_given = IVAL ( dec_buffer . data , 0 ) ;
crc32_calc = crc32_calc_buffer ( dec_buffer . data + 4 , dec_buffer . length - 4 ) ;
if ( crc32_given ! = crc32_calc ) {
return WERR_SEC_E_DECRYPT_FAILURE ;
}
checked_buffer = data_blob_const ( dec_buffer . data + 4 , dec_buffer . length - 4 ) ;
2007-02-15 12:40:13 +00:00
plain_buffer = data_blob_talloc ( mem_ctx , checked_buffer . data , checked_buffer . length ) ;
W_ERROR_HAVE_NO_MEMORY ( plain_buffer . data ) ;
2007-03-16 16:35:44 +00:00
/*
* The following rid_crypt obfuscation isn ' t session specific
* and not really needed here , because we allways know the rid of the
* user account .
*
* But for the rest of samba it ' s easier when we remove this static
* obfuscation here
*/
2007-02-15 12:40:13 +00:00
if ( rid_crypt ) {
uint32_t i , num_hashes ;
if ( ( checked_buffer . length % 16 ) ! = 0 ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
num_hashes = plain_buffer . length / 16 ;
for ( i = 0 ; i < num_hashes ; i + + ) {
uint32_t offset = i * 16 ;
sam_rid_crypt ( rid , checked_buffer . data + offset , plain_buffer . data + offset , 0 ) ;
}
2007-02-12 11:46:35 +00:00
}
* out = plain_buffer ;
return WERR_OK ;
}
static WERROR dsdb_decrypt_attribute ( const DATA_BLOB * gensec_skey ,
2007-02-15 12:40:13 +00:00
uint32_t rid ,
2007-02-12 11:46:35 +00:00
struct drsuapi_DsReplicaAttribute * attr )
{
WERROR status ;
TALLOC_CTX * mem_ctx ;
DATA_BLOB * enc_data ;
DATA_BLOB plain_data ;
2007-02-15 12:40:13 +00:00
bool rid_crypt = false ;
2007-02-12 11:46:35 +00:00
if ( attr - > value_ctr . num_values = = 0 ) {
return WERR_OK ;
}
switch ( attr - > attid ) {
case DRSUAPI_ATTRIBUTE_dBCSPwd :
case DRSUAPI_ATTRIBUTE_unicodePwd :
case DRSUAPI_ATTRIBUTE_ntPwdHistory :
case DRSUAPI_ATTRIBUTE_lmPwdHistory :
2007-02-15 12:40:13 +00:00
rid_crypt = true ;
break ;
2007-02-12 11:46:35 +00:00
case DRSUAPI_ATTRIBUTE_supplementalCredentials :
case DRSUAPI_ATTRIBUTE_priorValue :
case DRSUAPI_ATTRIBUTE_currentValue :
case DRSUAPI_ATTRIBUTE_trustAuthOutgoing :
case DRSUAPI_ATTRIBUTE_trustAuthIncoming :
case DRSUAPI_ATTRIBUTE_initialAuthOutgoing :
case DRSUAPI_ATTRIBUTE_initialAuthIncoming :
break ;
default :
return WERR_OK ;
}
if ( attr - > value_ctr . num_values > 1 ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
if ( ! attr - > value_ctr . values [ 0 ] . blob ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
mem_ctx = attr - > value_ctr . values [ 0 ] . blob ;
enc_data = attr - > value_ctr . values [ 0 ] . blob ;
status = dsdb_decrypt_attribute_value ( mem_ctx ,
gensec_skey ,
2007-02-15 12:40:13 +00:00
rid_crypt ,
rid ,
2007-02-12 11:46:35 +00:00
enc_data ,
& plain_data ) ;
W_ERROR_NOT_OK_RETURN ( status ) ;
talloc_free ( attr - > value_ctr . values [ 0 ] . blob - > data ) ;
* attr - > value_ctr . values [ 0 ] . blob = plain_data ;
return WERR_OK ;
}
2007-01-09 11:15:56 +00:00
static WERROR dsdb_convert_object ( struct ldb_context * ldb ,
const struct dsdb_schema * schema ,
struct dsdb_extended_replicated_objects * ctr ,
const struct drsuapi_DsReplicaObjectListItemEx * in ,
2007-02-12 11:46:35 +00:00
const DATA_BLOB * gensec_skey ,
2007-01-09 11:15:56 +00:00
TALLOC_CTX * mem_ctx ,
struct dsdb_extended_replicated_object * out )
{
NTSTATUS nt_status ;
2007-11-09 19:24:51 +01:00
enum ndr_err_code ndr_err ;
2007-01-09 11:15:56 +00:00
WERROR status ;
uint32_t i ;
struct ldb_message * msg ;
2007-01-11 09:45:30 +00:00
struct replPropertyMetaDataBlob * md ;
2007-01-09 11:15:56 +00:00
struct ldb_val guid_value ;
NTTIME whenChanged = 0 ;
time_t whenChanged_t ;
const char * whenChanged_s ;
2007-01-13 10:53:12 +00:00
const char * rdn_name = NULL ;
const struct ldb_val * rdn_value = NULL ;
const struct dsdb_attribute * rdn_attr = NULL ;
2007-01-09 11:15:56 +00:00
uint32_t rdn_attid ;
2007-01-13 10:53:12 +00:00
struct drsuapi_DsReplicaAttribute * name_a = NULL ;
struct drsuapi_DsReplicaMetaData * name_d = NULL ;
struct replPropertyMetaData1 * rdn_m = NULL ;
2007-02-15 12:40:13 +00:00
struct dom_sid * sid = NULL ;
uint32_t rid = 0 ;
2007-01-09 11:15:56 +00:00
int ret ;
if ( ! in - > object . identifier ) {
return WERR_FOOBAR ;
}
if ( ! in - > object . identifier - > dn | | ! in - > object . identifier - > dn [ 0 ] ) {
return WERR_FOOBAR ;
}
2007-02-11 17:36:33 +00:00
if ( in - > object . attribute_ctr . num_attributes ! = 0 & & ! in - > meta_data_ctr ) {
return WERR_FOOBAR ;
}
if ( in - > object . attribute_ctr . num_attributes ! = in - > meta_data_ctr - > count ) {
return WERR_FOOBAR ;
}
2007-02-15 12:40:13 +00:00
sid = & in - > object . identifier - > sid ;
if ( sid - > num_auths > 0 ) {
rid = sid - > sub_auths [ sid - > num_auths - 1 ] ;
}
2007-01-09 11:15:56 +00:00
msg = ldb_msg_new ( mem_ctx ) ;
W_ERROR_HAVE_NO_MEMORY ( msg ) ;
msg - > dn = ldb_dn_new ( msg , ldb , in - > object . identifier - > dn ) ;
W_ERROR_HAVE_NO_MEMORY ( msg - > dn ) ;
rdn_name = ldb_dn_get_rdn_name ( msg - > dn ) ;
rdn_attr = dsdb_attribute_by_lDAPDisplayName ( schema , rdn_name ) ;
if ( ! rdn_attr ) {
return WERR_FOOBAR ;
}
rdn_attid = rdn_attr - > attributeID_id ;
rdn_value = ldb_dn_get_rdn_val ( msg - > dn ) ;
msg - > num_elements = in - > object . attribute_ctr . num_attributes ;
msg - > elements = talloc_array ( msg , struct ldb_message_element ,
msg - > num_elements ) ;
W_ERROR_HAVE_NO_MEMORY ( msg - > elements ) ;
2007-01-11 09:45:30 +00:00
md = talloc ( mem_ctx , struct replPropertyMetaDataBlob ) ;
W_ERROR_HAVE_NO_MEMORY ( md ) ;
2007-01-09 11:15:56 +00:00
2007-01-11 09:45:30 +00:00
md - > version = 1 ;
md - > reserved = 0 ;
md - > ctr . ctr1 . count = in - > meta_data_ctr - > count ;
md - > ctr . ctr1 . reserved = 0 ;
md - > ctr . ctr1 . array = talloc_array ( mem_ctx ,
struct replPropertyMetaData1 ,
md - > ctr . ctr1 . count + 1 ) ; /* +1 because of the RDN attribute */
W_ERROR_HAVE_NO_MEMORY ( md - > ctr . ctr1 . array ) ;
2007-01-09 11:15:56 +00:00
for ( i = 0 ; i < in - > meta_data_ctr - > count ; i + + ) {
struct drsuapi_DsReplicaAttribute * a ;
struct drsuapi_DsReplicaMetaData * d ;
struct replPropertyMetaData1 * m ;
2007-02-11 17:51:38 +00:00
struct ldb_message_element * e ;
2007-01-09 11:15:56 +00:00
a = & in - > object . attribute_ctr . attributes [ i ] ;
d = & in - > meta_data_ctr - > meta_data [ i ] ;
2007-01-11 09:45:30 +00:00
m = & md - > ctr . ctr1 . array [ i ] ;
2007-02-11 17:51:38 +00:00
e = & msg - > elements [ i ] ;
2007-02-15 12:40:13 +00:00
status = dsdb_decrypt_attribute ( gensec_skey , rid , a ) ;
2007-02-12 11:46:35 +00:00
W_ERROR_NOT_OK_RETURN ( status ) ;
2007-02-11 17:51:38 +00:00
status = dsdb_attribute_drsuapi_to_ldb ( schema , a , msg - > elements , e ) ;
W_ERROR_NOT_OK_RETURN ( status ) ;
2007-01-09 11:15:56 +00:00
m - > attid = a - > attid ;
m - > version = d - > version ;
2007-03-09 10:09:37 +00:00
m - > originating_change_time = d - > originating_change_time ;
m - > originating_invocation_id = d - > originating_invocation_id ;
m - > originating_usn = d - > originating_usn ;
2007-01-09 11:15:56 +00:00
m - > local_usn = 0 ;
2007-03-09 10:09:37 +00:00
if ( d - > originating_change_time > whenChanged ) {
whenChanged = d - > originating_change_time ;
2007-01-09 11:15:56 +00:00
}
if ( a - > attid = = DRSUAPI_ATTRIBUTE_name ) {
name_a = a ;
name_d = d ;
2007-01-11 09:45:30 +00:00
rdn_m = & md - > ctr . ctr1 . array [ md - > ctr . ctr1 . count ] ;
2007-01-09 11:15:56 +00:00
}
}
2007-01-13 10:53:12 +00:00
if ( rdn_m ) {
ret = ldb_msg_add_value ( msg , rdn_attr - > lDAPDisplayName , rdn_value , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_FOOBAR ;
}
2007-01-09 11:15:56 +00:00
2007-01-13 10:53:12 +00:00
rdn_m - > attid = rdn_attid ;
rdn_m - > version = name_d - > version ;
2007-03-09 10:09:37 +00:00
rdn_m - > originating_change_time = name_d - > originating_change_time ;
rdn_m - > originating_invocation_id = name_d - > originating_invocation_id ;
rdn_m - > originating_usn = name_d - > originating_usn ;
2007-01-13 10:53:12 +00:00
rdn_m - > local_usn = 0 ;
md - > ctr . ctr1 . count + + ;
2007-01-09 11:15:56 +00:00
}
whenChanged_t = nt_time_to_unix ( whenChanged ) ;
whenChanged_s = ldb_timestring ( msg , whenChanged_t ) ;
W_ERROR_HAVE_NO_MEMORY ( whenChanged_s ) ;
2007-01-13 10:53:12 +00:00
2008-01-01 22:05:05 -06:00
ndr_err = ndr_push_struct_blob ( & guid_value , msg ,
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) ,
& in - > object . identifier - > guid ,
2007-01-13 10:53:12 +00:00
( ndr_push_flags_fn_t ) ndr_push_GUID ) ;
2007-11-09 19:24:51 +01:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
2007-01-13 10:53:12 +00:00
return ntstatus_to_werror ( nt_status ) ;
2007-01-09 11:15:56 +00:00
}
2007-01-13 10:53:12 +00:00
out - > msg = msg ;
out - > guid_value = guid_value ;
out - > when_changed = whenChanged_s ;
out - > meta_data = md ;
2007-01-09 11:15:56 +00:00
return WERR_OK ;
}
WERROR dsdb_extended_replicated_objects_commit ( struct ldb_context * ldb ,
const char * partition_dn ,
2007-01-11 10:21:38 +00:00
const struct drsuapi_DsReplicaOIDMapping_Ctr * mapping_ctr ,
uint32_t object_count ,
const struct drsuapi_DsReplicaObjectListItemEx * first_object ,
uint32_t linked_attributes_count ,
const struct drsuapi_DsReplicaLinkedAttribute * linked_attributes ,
2007-01-12 16:02:10 +00:00
const struct repsFromTo1 * source_dsa ,
2007-01-11 10:21:38 +00:00
const struct drsuapi_DsReplicaCursor2CtrEx * uptodateness_vector ,
2007-02-12 11:46:35 +00:00
const DATA_BLOB * gensec_skey ,
2007-01-09 11:15:56 +00:00
TALLOC_CTX * mem_ctx ,
struct dsdb_extended_replicated_objects * * _out )
{
WERROR status ;
2007-01-14 15:35:10 +00:00
const struct dsdb_schema * schema ;
2007-01-09 11:15:56 +00:00
struct dsdb_extended_replicated_objects * out ;
struct ldb_result * ext_res ;
2007-01-11 10:21:38 +00:00
const struct drsuapi_DsReplicaObjectListItemEx * cur ;
2007-01-09 11:15:56 +00:00
uint32_t i ;
int ret ;
2007-01-14 15:35:10 +00:00
schema = dsdb_get_schema ( ldb ) ;
if ( ! schema ) {
return WERR_DS_SCHEMA_NOT_LOADED ;
}
2007-01-13 15:29:47 +00:00
status = dsdb_verify_oid_mappings_drsuapi ( schema , mapping_ctr ) ;
2007-01-09 11:15:56 +00:00
W_ERROR_NOT_OK_RETURN ( status ) ;
out = talloc_zero ( mem_ctx , struct dsdb_extended_replicated_objects ) ;
W_ERROR_HAVE_NO_MEMORY ( out ) ;
2007-01-13 11:37:13 +00:00
out - > version = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION ;
2007-01-09 11:15:56 +00:00
2007-01-13 11:37:13 +00:00
out - > partition_dn = ldb_dn_new ( out , ldb , partition_dn ) ;
2007-01-09 11:15:56 +00:00
W_ERROR_HAVE_NO_MEMORY ( out - > partition_dn ) ;
2007-01-12 16:02:10 +00:00
out - > source_dsa = source_dsa ;
out - > uptodateness_vector = uptodateness_vector ;
2007-01-12 13:17:25 +00:00
2007-01-09 11:15:56 +00:00
out - > num_objects = object_count ;
out - > objects = talloc_array ( out ,
struct dsdb_extended_replicated_object ,
out - > num_objects ) ;
W_ERROR_HAVE_NO_MEMORY ( out - > objects ) ;
for ( i = 0 , cur = first_object ; cur ; cur = cur - > next_object , i + + ) {
if ( i = = out - > num_objects ) {
return WERR_FOOBAR ;
}
2007-02-12 11:46:35 +00:00
status = dsdb_convert_object ( ldb , schema , out , cur , gensec_skey , out - > objects , & out - > objects [ i ] ) ;
2007-01-09 11:15:56 +00:00
W_ERROR_NOT_OK_RETURN ( status ) ;
}
if ( i ! = out - > num_objects ) {
return WERR_FOOBAR ;
}
/* TODO: handle linked attributes */
ret = ldb_extended ( ldb , DSDB_EXTENDED_REPLICATED_OBJECTS_OID , out , & ext_res ) ;
if ( ret ! = LDB_SUCCESS ) {
2008-01-23 15:44:02 +11:00
DEBUG ( 0 , ( " Failed to apply records: %s: %s \n " ,
ldb_errstring ( ldb ) , ldb_strerror ( ret ) ) ) ;
2007-01-09 11:15:56 +00:00
talloc_free ( out ) ;
return WERR_FOOBAR ;
}
talloc_free ( ext_res ) ;
if ( _out ) {
* _out = out ;
} else {
talloc_free ( out ) ;
}
return WERR_OK ;
}