2011-09-27 10:53:45 +04:00
/*
Unix SMB / CIFS implementation .
DNS Server
Copyright ( C ) Amitay Isaacs 2011
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 "dnsserver.h"
# include "lib/util/dlinklist.h"
# include "librpc/gen_ndr/ndr_dnsp.h"
2011-12-15 10:44:32 +04:00
# include "dsdb/samdb/samdb.h"
/* There are only 2 fixed partitions for DNS */
struct dnsserver_partition * dnsserver_db_enumerate_partitions ( TALLOC_CTX * mem_ctx ,
struct dnsserver_serverinfo * serverinfo ,
struct ldb_context * samdb )
{
struct dnsserver_partition * partitions , * p ;
partitions = NULL ;
/* Domain partition */
p = talloc_zero ( mem_ctx , struct dnsserver_partition ) ;
if ( p = = NULL ) {
goto failed ;
}
p - > partition_dn = ldb_dn_new ( p , samdb , serverinfo - > pszDomainDirectoryPartition ) ;
if ( p - > partition_dn = = NULL ) {
goto failed ;
}
p - > pszDpFqdn = samdb_dn_to_dns_domain ( p , p - > partition_dn ) ;
p - > dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_DOMAIN_DEFAULT | DNS_DP_ENLISTED ;
p - > is_forest = false ;
DLIST_ADD_END ( partitions , p , NULL ) ;
/* Forest Partition */
p = talloc_zero ( mem_ctx , struct dnsserver_partition ) ;
if ( p = = NULL ) {
goto failed ;
}
p - > partition_dn = ldb_dn_new ( p , samdb , serverinfo - > pszForestDirectoryPartition ) ;
if ( p - > partition_dn = = NULL ) {
goto failed ;
}
p - > pszDpFqdn = samdb_dn_to_dns_domain ( p , p - > partition_dn ) ;
p - > dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_FOREST_DEFAULT | DNS_DP_ENLISTED ;
p - > is_forest = true ;
DLIST_ADD_END ( partitions , p , NULL ) ;
return partitions ;
failed :
return NULL ;
}
2011-09-27 10:53:45 +04:00
2011-12-15 11:27:39 +04:00
/* Search for all dnsZone records */
2011-09-27 10:53:45 +04:00
struct dnsserver_zone * dnsserver_db_enumerate_zones ( TALLOC_CTX * mem_ctx ,
struct ldb_context * samdb ,
2011-12-15 10:44:32 +04:00
struct dnsserver_partition * p )
2011-09-27 10:53:45 +04:00
{
TALLOC_CTX * tmp_ctx ;
const char * const attrs [ ] = { " name " , NULL } ;
2011-12-15 10:44:32 +04:00
struct ldb_dn * dn ;
2011-09-27 10:53:45 +04:00
struct ldb_result * res ;
struct dnsserver_zone * zones , * z ;
int i , ret ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( tmp_ctx = = NULL ) {
return NULL ;
}
2011-12-15 10:44:32 +04:00
dn = ldb_dn_copy ( tmp_ctx , p - > partition_dn ) ;
2011-09-27 10:53:45 +04:00
if ( dn = = NULL ) {
goto failed ;
}
if ( ! ldb_dn_add_child_fmt ( dn , " CN=MicrosoftDNS " ) ) {
goto failed ;
}
ret = ldb_search ( samdb , tmp_ctx , & res , dn , LDB_SCOPE_SUBTREE ,
2011-12-15 10:44:32 +04:00
attrs , " (objectClass=dnsZone) " ) ;
2011-09-27 10:53:45 +04:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " dnsserver: Failed to find DNS Zones in %s \n " ,
ldb_dn_get_linearized ( dn ) ) ) ;
goto failed ;
}
zones = NULL ;
for ( i = 0 ; i < res - > count ; i + + ) {
2011-12-15 10:44:32 +04:00
char * name ;
2011-09-27 10:53:45 +04:00
z = talloc_zero ( mem_ctx , struct dnsserver_zone ) ;
if ( z = = NULL ) {
goto failed ;
}
2011-12-15 10:44:32 +04:00
z - > partition = p ;
name = talloc_strdup ( z ,
2011-09-27 10:53:45 +04:00
ldb_msg_find_attr_as_string ( res - > msgs [ i ] , " name " , NULL ) ) ;
2011-12-15 10:44:32 +04:00
if ( strcmp ( name , " RootDNSServers " ) = = 0 ) {
talloc_free ( name ) ;
z - > name = talloc_strdup ( z , " . " ) ;
} else {
z - > name = name ;
}
2011-09-27 10:53:45 +04:00
z - > zone_dn = talloc_steal ( z , res - > msgs [ i ] - > dn ) ;
DLIST_ADD_END ( zones , z , NULL ) ;
2011-12-15 10:44:32 +04:00
DEBUG ( 2 , ( " dnsserver: Found DNS zone %s \n " , z - > name ) ) ;
2011-09-27 10:53:45 +04:00
}
return zones ;
failed :
talloc_free ( tmp_ctx ) ;
return NULL ;
}
2011-12-16 05:11:42 +04:00
/* Find DNS partition information */
struct dnsserver_partition_info * dnsserver_db_partition_info ( TALLOC_CTX * mem_ctx ,
struct ldb_context * samdb ,
struct dnsserver_partition * p )
{
const char * const attrs [ ] = { " instanceType " , " msDs-masteredBy " , NULL } ;
const char * const attrs_none [ ] = { NULL } ;
struct ldb_result * res ;
struct ldb_message_element * el ;
struct ldb_dn * dn ;
struct dnsserver_partition_info * partinfo ;
int i , ret , instance_type ;
TALLOC_CTX * tmp_ctx ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( tmp_ctx = = NULL ) {
return NULL ;
}
partinfo = talloc_zero ( mem_ctx , struct dnsserver_partition_info ) ;
if ( partinfo = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
/* Search for the active replica and state */
ret = ldb_search ( samdb , tmp_ctx , & res , p - > partition_dn , LDB_SCOPE_BASE ,
attrs , NULL ) ;
if ( ret ! = LDB_SUCCESS | | res - > count ! = 1 ) {
goto failed ;
}
/* Set the state of the partition */
instance_type = ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] , " instanceType " , - 1 ) ;
if ( instance_type = = - 1 ) {
partinfo - > dwState = DNS_DP_STATE_UNKNOWN ;
} else if ( instance_type & INSTANCE_TYPE_NC_COMING ) {
partinfo - > dwState = DNS_DP_STATE_REPL_INCOMING ;
} else if ( instance_type & INSTANCE_TYPE_NC_GOING ) {
partinfo - > dwState = DNS_DP_STATE_REPL_OUTGOING ;
} else {
partinfo - > dwState = DNS_DP_OKAY ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " msDs-masteredBy " ) ;
if ( el = = NULL ) {
partinfo - > dwReplicaCount = 0 ;
partinfo - > ReplicaArray = NULL ;
} else {
partinfo - > dwReplicaCount = el - > num_values ;
partinfo - > ReplicaArray = talloc_zero_array ( partinfo ,
struct DNS_RPC_DP_REPLICA * ,
el - > num_values ) ;
if ( partinfo - > ReplicaArray = = NULL ) {
goto failed ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
partinfo - > ReplicaArray [ i ] = talloc_zero ( partinfo ,
struct DNS_RPC_DP_REPLICA ) ;
if ( partinfo - > ReplicaArray [ i ] = = NULL ) {
goto failed ;
}
partinfo - > ReplicaArray [ i ] - > pszReplicaDn = talloc_strdup (
partinfo ,
( const char * ) el - > values [ i ] . data ) ;
if ( partinfo - > ReplicaArray [ i ] - > pszReplicaDn = = NULL ) {
goto failed ;
}
}
}
talloc_free ( res ) ;
/* Search for cross-reference object */
dn = ldb_dn_copy ( tmp_ctx , ldb_get_config_basedn ( samdb ) ) ;
if ( dn = = NULL ) {
goto failed ;
}
ret = ldb_search ( samdb , tmp_ctx , & res , dn , LDB_SCOPE_DEFAULT , attrs_none ,
" (nCName=%s) " , ldb_dn_get_linearized ( p - > partition_dn ) ) ;
if ( ret ! = LDB_SUCCESS | | res - > count ! = 1 ) {
goto failed ;
}
partinfo - > pszCrDn = talloc_strdup ( partinfo , ldb_dn_get_linearized ( res - > msgs [ 0 ] - > dn ) ) ;
if ( partinfo - > pszCrDn = = NULL ) {
goto failed ;
}
talloc_free ( res ) ;
talloc_free ( tmp_ctx ) ;
return partinfo ;
failed :
talloc_free ( tmp_ctx ) ;
talloc_free ( partinfo ) ;
return NULL ;
}
2011-10-18 08:20:14 +04:00
static unsigned int dnsserver_update_soa ( TALLOC_CTX * mem_ctx ,
struct ldb_context * samdb ,
struct dnsserver_zone * z )
{
const char * const attrs [ ] = { " dnsRecord " , NULL } ;
struct ldb_result * res ;
struct dnsp_DnssrvRpcRecord rec ;
struct ldb_message_element * el ;
enum ndr_err_code ndr_err ;
int ret , i , serial = - 1 ;
NTTIME t ;
unix_to_nt_time ( & t , time ( NULL ) ) ;
t / = 10 * 1000 * 1000 ; /* convert to seconds (NT time is in 100ns units) */
t / = 3600 ; /* convert to hours */
ret = ldb_search ( samdb , mem_ctx , & res , z - > zone_dn , LDB_SCOPE_ONELEVEL , attrs ,
" (&(objectClass=dnsNode)(name=@)) " ) ;
if ( ret ! = LDB_SUCCESS | | res - > count = = 0 ) {
return - 1 ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL ) {
return - 1 ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , mem_ctx , & rec ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
continue ;
}
if ( rec . wType = = DNS_TYPE_SOA ) {
serial = rec . data . soa . serial + 1 ;
rec . dwSerial = serial ;
rec . dwTimeStamp = ( uint32_t ) t ;
rec . data . soa . serial = serial ;
ndr_err = ndr_push_struct_blob ( & el - > values [ i ] , mem_ctx , & rec ,
( ndr_push_flags_fn_t ) ndr_push_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return - 1 ;
}
break ;
}
}
if ( serial ! = - 1 ) {
el - > flags = LDB_FLAG_MOD_REPLACE ;
ret = ldb_modify ( samdb , res - > msgs [ 0 ] ) ;
if ( ret ! = LDB_SUCCESS ) {
return - 1 ;
}
}
return serial ;
}
2011-09-27 10:53:45 +04:00
static WERROR dnsserver_db_do_add_rec ( TALLOC_CTX * mem_ctx ,
struct ldb_context * samdb ,
struct ldb_dn * dn ,
struct dnsp_DnssrvRpcRecord * rec )
{
struct ldb_message * msg ;
struct ldb_val v ;
int ret ;
enum ndr_err_code ndr_err ;
msg = ldb_msg_new ( mem_ctx ) ;
W_ERROR_HAVE_NO_MEMORY ( msg ) ;
msg - > dn = dn ;
ret = ldb_msg_add_string ( msg , " objectClass " , " dnsNode " ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_NOMEM ;
}
if ( rec ) {
ndr_err = ndr_push_struct_blob ( & v , mem_ctx , rec ,
( ndr_push_flags_fn_t ) ndr_push_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_GENERAL_FAILURE ;
}
ret = ldb_msg_add_value ( msg , " dnsRecord " , & v , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_NOMEM ;
}
}
ret = ldb_add ( samdb , msg ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_INTERNAL_DB_ERROR ;
}
return WERR_OK ;
}
WERROR dnsserver_db_add_empty_node ( TALLOC_CTX * mem_ctx ,
struct ldb_context * samdb ,
struct dnsserver_zone * z ,
const char * name )
{
const char * const attrs [ ] = { " name " , NULL } ;
struct ldb_result * res ;
struct ldb_dn * dn ;
int ret ;
ret = ldb_search ( samdb , mem_ctx , & res , z - > zone_dn , LDB_SCOPE_BASE , attrs ,
" (&(objectClass=dnsNode)(name=%s)) " , name ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_INTERNAL_DB_ERROR ;
}
if ( res - > count > 0 ) {
talloc_free ( res ) ;
return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS ;
}
dn = ldb_dn_copy ( mem_ctx , z - > zone_dn ) ;
W_ERROR_HAVE_NO_MEMORY ( dn ) ;
if ( ! ldb_dn_add_child_fmt ( dn , " DC=%s " , name ) ) {
return WERR_NOMEM ;
}
return dnsserver_db_do_add_rec ( mem_ctx , samdb , dn , NULL ) ;
}
WERROR dnsserver_db_add_record ( TALLOC_CTX * mem_ctx ,
struct ldb_context * samdb ,
struct dnsserver_zone * z ,
const char * name ,
struct DNS_RPC_RECORD * add_record )
{
const char * const attrs [ ] = { " dnsRecord " , NULL } ;
struct ldb_result * res ;
struct dnsp_DnssrvRpcRecord * rec ;
struct ldb_message_element * el ;
struct ldb_dn * dn ;
enum ndr_err_code ndr_err ;
NTTIME t ;
int ret , i ;
2011-10-18 08:20:14 +04:00
int serial ;
2011-09-27 10:53:45 +04:00
rec = dns_to_dnsp_copy ( mem_ctx , add_record ) ;
W_ERROR_HAVE_NO_MEMORY ( rec ) ;
2011-10-18 08:20:14 +04:00
serial = dnsserver_update_soa ( mem_ctx , samdb , z ) ;
if ( serial < 0 ) {
return WERR_INTERNAL_DB_ERROR ;
}
2011-09-27 10:53:45 +04:00
unix_to_nt_time ( & t , time ( NULL ) ) ;
2011-10-18 08:20:14 +04:00
t / = 10 * 1000 * 1000 ; /* convert to seconds (NT time is in 100ns units) */
t / = 3600 ; /* convert to hours */
2011-09-27 10:53:45 +04:00
2011-10-18 08:20:14 +04:00
rec - > dwSerial = serial ;
2011-09-27 10:53:45 +04:00
rec - > dwTimeStamp = t ;
ret = ldb_search ( samdb , mem_ctx , & res , z - > zone_dn , LDB_SCOPE_ONELEVEL , attrs ,
" (&(objectClass=dnsNode)(name=%s)) " , name ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_INTERNAL_DB_ERROR ;
}
if ( res - > count = = 0 ) {
dn = dnsserver_name_to_dn ( mem_ctx , z , name ) ;
W_ERROR_HAVE_NO_MEMORY ( dn ) ;
return dnsserver_db_do_add_rec ( mem_ctx , samdb , dn , rec ) ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL ) {
ret = ldb_msg_add_empty ( res - > msgs [ 0 ] , " dnsRecord " , 0 , & el ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_NOMEM ;
}
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec2 ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , mem_ctx , & rec2 ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_GENERAL_FAILURE ;
}
if ( dns_record_match ( rec , & rec2 ) ) {
break ;
}
}
if ( i < el - > num_values ) {
return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS ;
}
if ( i = = el - > num_values ) {
/* adding a new value */
el - > values = talloc_realloc ( el , el - > values , struct ldb_val , el - > num_values + 1 ) ;
W_ERROR_HAVE_NO_MEMORY ( el - > values ) ;
el - > num_values + + ;
}
ndr_err = ndr_push_struct_blob ( & el - > values [ i ] , mem_ctx , rec ,
( ndr_push_flags_fn_t ) ndr_push_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_GENERAL_FAILURE ;
}
el - > flags = LDB_FLAG_MOD_REPLACE ;
ret = ldb_modify ( samdb , res - > msgs [ 0 ] ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_INTERNAL_DB_ERROR ;
}
return WERR_OK ;
}
WERROR dnsserver_db_update_record ( TALLOC_CTX * mem_ctx ,
struct ldb_context * samdb ,
struct dnsserver_zone * z ,
const char * name ,
struct DNS_RPC_RECORD * add_record ,
struct DNS_RPC_RECORD * del_record )
{
const char * const attrs [ ] = { " dnsRecord " , NULL } ;
struct ldb_result * res ;
struct dnsp_DnssrvRpcRecord * arec , * drec ;
struct ldb_message_element * el ;
enum ndr_err_code ndr_err ;
NTTIME t ;
int ret , i ;
2011-10-18 08:20:14 +04:00
int serial ;
serial = dnsserver_update_soa ( mem_ctx , samdb , z ) ;
if ( serial < 0 ) {
return WERR_INTERNAL_DB_ERROR ;
}
2011-09-27 10:53:45 +04:00
arec = dns_to_dnsp_copy ( mem_ctx , add_record ) ;
W_ERROR_HAVE_NO_MEMORY ( arec ) ;
drec = dns_to_dnsp_copy ( mem_ctx , del_record ) ;
W_ERROR_HAVE_NO_MEMORY ( drec ) ;
unix_to_nt_time ( & t , time ( NULL ) ) ;
t / = 10 * 1000 * 1000 ;
2011-10-18 08:20:14 +04:00
arec - > dwSerial = serial ;
2011-09-27 10:53:45 +04:00
arec - > dwTimeStamp = t ;
ret = ldb_search ( samdb , mem_ctx , & res , z - > zone_dn , LDB_SCOPE_ONELEVEL , attrs ,
" (&(objectClass=dnsNode)(name=%s)) " , name ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_INTERNAL_DB_ERROR ;
}
if ( res - > count = = 0 ) {
return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL | | el - > num_values = = 0 ) {
return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec2 ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , mem_ctx , & rec2 ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_GENERAL_FAILURE ;
}
if ( dns_record_match ( arec , & rec2 ) ) {
break ;
}
}
if ( i < el - > num_values ) {
return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec2 ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , mem_ctx , & rec2 ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_GENERAL_FAILURE ;
}
if ( dns_record_match ( drec , & rec2 ) ) {
break ;
}
}
if ( i = = el - > num_values ) {
return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST ;
}
ndr_err = ndr_push_struct_blob ( & el - > values [ i ] , mem_ctx , arec ,
( ndr_push_flags_fn_t ) ndr_push_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_GENERAL_FAILURE ;
}
el - > flags = LDB_FLAG_MOD_REPLACE ;
ret = ldb_modify ( samdb , res - > msgs [ 0 ] ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_INTERNAL_DB_ERROR ;
}
return WERR_OK ;
}
WERROR dnsserver_db_delete_record ( TALLOC_CTX * mem_ctx ,
struct ldb_context * samdb ,
struct dnsserver_zone * z ,
const char * name ,
struct DNS_RPC_RECORD * del_record )
{
const char * const attrs [ ] = { " dnsRecord " , NULL } ;
struct ldb_result * res ;
struct dnsp_DnssrvRpcRecord * rec ;
struct ldb_message_element * el ;
enum ndr_err_code ndr_err ;
int ret , i ;
2011-10-18 08:20:14 +04:00
int serial ;
serial = dnsserver_update_soa ( mem_ctx , samdb , z ) ;
if ( serial < 0 ) {
return WERR_INTERNAL_DB_ERROR ;
}
2011-09-27 10:53:45 +04:00
rec = dns_to_dnsp_copy ( mem_ctx , del_record ) ;
W_ERROR_HAVE_NO_MEMORY ( rec ) ;
ret = ldb_search ( samdb , mem_ctx , & res , z - > zone_dn , LDB_SCOPE_ONELEVEL , attrs ,
" (&(objectClass=dnsNode)(name=%s)) " , name ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_INTERNAL_DB_ERROR ;
}
if ( res - > count = = 0 ) {
return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL | | el - > num_values = = 0 ) {
return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec2 ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , mem_ctx , & rec2 ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_GENERAL_FAILURE ;
}
if ( dns_record_match ( rec , & rec2 ) ) {
break ;
}
}
if ( i = = el - > num_values ) {
return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST ;
}
if ( i < el - > num_values - 1 ) {
memmove ( & el - > values [ i ] , & el - > values [ i + 1 ] , sizeof ( el - > values [ 0 ] ) * ( ( el - > num_values - 1 ) - i ) ) ;
}
el - > num_values - - ;
if ( el - > num_values = = 0 ) {
ret = ldb_delete ( samdb , res - > msgs [ 0 ] - > dn ) ;
} else {
el - > flags = LDB_FLAG_MOD_REPLACE ;
ret = ldb_modify ( samdb , res - > msgs [ 0 ] ) ;
}
if ( ret ! = LDB_SUCCESS ) {
return WERR_INTERNAL_DB_ERROR ;
}
return WERR_OK ;
}