2010-12-06 06:12:07 +03:00
/*
Unix SMB / CIFS implementation .
bind9 dlz driver for Samba
Copyright ( C ) 2010 Andrew Tridgell
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 "talloc.h"
# include "param/param.h"
2010-12-08 01:04:49 +03:00
# include "lib/events/events.h"
2010-12-06 06:12:07 +03:00
# include "dsdb/samdb/samdb.h"
# include "dsdb/common/util.h"
2011-11-02 07:32:37 +04:00
# include "auth/auth.h"
2010-12-06 06:12:07 +03:00
# include "auth/session.h"
2010-12-08 01:04:49 +03:00
# include "auth/gensec/gensec.h"
2011-11-02 07:32:37 +04:00
# include "librpc/gen_ndr/security.h"
# include "auth/credentials/credentials.h"
# include "system/kerberos.h"
# include "auth/kerberos/kerberos.h"
2010-12-06 06:12:07 +03:00
# include "gen_ndr/ndr_dnsp.h"
2011-11-02 07:32:37 +04:00
# include "gen_ndr/server_id.h"
# include "messaging/messaging.h"
2011-12-06 05:01:42 +04:00
# include "lib/cmdline/popt_common.h"
2013-10-02 11:28:45 +04:00
# include "lib/util/dlinklist.h"
2010-12-15 07:02:09 +03:00
# include "dlz_minimal.h"
2010-12-06 06:12:07 +03:00
2011-11-02 07:32:37 +04:00
struct b9_options {
const char * url ;
2011-12-06 05:01:42 +04:00
const char * debug ;
2011-11-02 07:32:37 +04:00
} ;
2013-10-02 11:28:45 +04:00
struct b9_zone {
char * name ;
struct b9_zone * prev , * next ;
} ;
2010-12-06 06:12:07 +03:00
struct dlz_bind9_data {
2011-11-02 07:32:37 +04:00
struct b9_options options ;
2010-12-06 06:12:07 +03:00
struct ldb_context * samdb ;
struct tevent_context * ev_ctx ;
struct loadparm_context * lp ;
2010-12-15 13:46:05 +03:00
int * transaction_token ;
2010-12-21 12:53:58 +03:00
uint32_t soa_serial ;
2013-10-02 11:28:45 +04:00
struct b9_zone * zonelist ;
2010-12-06 06:12:07 +03:00
2011-11-02 07:32:37 +04:00
/* Used for dynamic update */
struct smb_krb5_context * smb_krb5_ctx ;
2012-01-03 08:39:20 +04:00
struct auth4_context * auth_context ;
2011-11-30 09:06:08 +04:00
struct auth_session_info * session_info ;
char * update_name ;
2011-11-02 07:32:37 +04:00
2010-12-06 06:12:07 +03:00
/* helper functions from the dlz_dlopen driver */
2012-03-08 11:34:04 +04:00
log_t * log ;
dns_sdlz_putrr_t * putrr ;
dns_sdlz_putnamedrr_t * putnamedrr ;
dns_dlz_writeablezone_t * writeable_zone ;
2010-12-15 07:02:09 +03:00
} ;
2012-05-23 05:52:16 +04:00
static struct dlz_bind9_data * dlz_bind9_state = NULL ;
static int dlz_bind9_state_ref_count = 0 ;
2010-12-15 07:02:09 +03:00
static const char * zone_prefixes [ ] = {
" CN=MicrosoftDNS,DC=DomainDnsZones " ,
" CN=MicrosoftDNS,DC=ForestDnsZones " ,
2011-09-16 17:36:08 +04:00
" CN=MicrosoftDNS,CN=System " ,
2010-12-15 07:02:09 +03:00
NULL
2010-12-06 06:12:07 +03:00
} ;
/*
return the version of the API
*/
2010-12-06 08:56:18 +03:00
_PUBLIC_ int dlz_version ( unsigned int * flags )
2010-12-06 06:12:07 +03:00
{
return DLZ_DLOPEN_VERSION ;
}
/*
remember a helper function from the bind9 dlz_dlopen driver
*/
static void b9_add_helper ( struct dlz_bind9_data * state , const char * helper_name , void * ptr )
{
if ( strcmp ( helper_name , " log " ) = = 0 ) {
state - > log = ptr ;
}
if ( strcmp ( helper_name , " putrr " ) = = 0 ) {
state - > putrr = ptr ;
}
if ( strcmp ( helper_name , " putnamedrr " ) = = 0 ) {
state - > putnamedrr = ptr ;
}
2010-12-15 07:02:09 +03:00
if ( strcmp ( helper_name , " writeable_zone " ) = = 0 ) {
state - > writeable_zone = ptr ;
}
2010-12-06 06:12:07 +03:00
}
/*
format a record for bind9
*/
static bool b9_format ( struct dlz_bind9_data * state ,
TALLOC_CTX * mem_ctx ,
struct dnsp_DnssrvRpcRecord * rec ,
const char * * type , const char * * data )
{
2012-02-28 07:14:07 +04:00
uint32_t i ;
char * tmp ;
2010-12-06 06:12:07 +03:00
switch ( rec - > wType ) {
case DNS_TYPE_A :
* type = " a " ;
* data = rec - > data . ipv4 ;
break ;
case DNS_TYPE_AAAA :
* type = " aaaa " ;
* data = rec - > data . ipv6 ;
break ;
case DNS_TYPE_CNAME :
* type = " cname " ;
* data = rec - > data . cname ;
break ;
case DNS_TYPE_TXT :
* type = " txt " ;
2012-02-28 07:14:07 +04:00
tmp = talloc_asprintf ( mem_ctx , " \" %s \" " , rec - > data . txt . str [ 0 ] ) ;
for ( i = 1 ; i < rec - > data . txt . count ; i + + ) {
tmp = talloc_asprintf_append ( tmp , " \" %s \" " , rec - > data . txt . str [ i ] ) ;
}
* data = tmp ;
2010-12-06 06:12:07 +03:00
break ;
case DNS_TYPE_PTR :
* type = " ptr " ;
* data = rec - > data . ptr ;
break ;
case DNS_TYPE_SRV :
* type = " srv " ;
* data = talloc_asprintf ( mem_ctx , " %u %u %u %s " ,
rec - > data . srv . wPriority ,
rec - > data . srv . wWeight ,
rec - > data . srv . wPort ,
rec - > data . srv . nameTarget ) ;
break ;
case DNS_TYPE_MX :
* type = " mx " ;
* data = talloc_asprintf ( mem_ctx , " %u %s " ,
2010-12-15 13:46:05 +03:00
rec - > data . mx . wPriority ,
rec - > data . mx . nameTarget ) ;
2010-12-06 06:12:07 +03:00
break ;
case DNS_TYPE_HINFO :
* type = " hinfo " ;
* data = talloc_asprintf ( mem_ctx , " %s %s " ,
rec - > data . hinfo . cpu ,
rec - > data . hinfo . os ) ;
break ;
case DNS_TYPE_NS :
* type = " ns " ;
* data = rec - > data . ns ;
break ;
2010-12-21 05:26:15 +03:00
case DNS_TYPE_SOA : {
const char * mname ;
2010-12-06 06:12:07 +03:00
* type = " soa " ;
2010-12-21 05:26:15 +03:00
/* we need to fake the authoritative nameserver to
2010-12-22 04:13:44 +03:00
* point at ourselves . This is how AD DNS servers
2010-12-21 05:26:15 +03:00
* force clients to send updates to the right local DC
*/
mname = talloc_asprintf ( mem_ctx , " %s.%s " ,
lpcfg_netbios_name ( state - > lp ) , lpcfg_dnsdomain ( state - > lp ) ) ;
if ( mname = = NULL ) {
return false ;
}
mname = strlower_talloc ( mem_ctx , mname ) ;
if ( mname = = NULL ) {
return false ;
}
2010-12-21 12:53:58 +03:00
state - > soa_serial = rec - > data . soa . serial ;
2010-12-06 06:12:07 +03:00
* data = talloc_asprintf ( mem_ctx , " %s %s %u %u %u %u %u " ,
2010-12-21 05:26:15 +03:00
mname ,
2010-12-06 06:12:07 +03:00
rec - > data . soa . rname ,
rec - > data . soa . serial ,
rec - > data . soa . refresh ,
rec - > data . soa . retry ,
rec - > data . soa . expire ,
rec - > data . soa . minimum ) ;
break ;
2010-12-21 05:26:15 +03:00
}
2010-12-06 06:12:07 +03:00
default :
state - > log ( ISC_LOG_ERROR , " samba b9_putrr: unhandled record type %u " ,
rec - > wType ) ;
return false ;
}
return true ;
}
2010-12-15 13:46:05 +03:00
static const struct {
enum dns_record_type dns_type ;
const char * typestr ;
bool single_valued ;
} dns_typemap [ ] = {
{ DNS_TYPE_A , " A " , false } ,
{ DNS_TYPE_AAAA , " AAAA " , false } ,
{ DNS_TYPE_CNAME , " CNAME " , true } ,
{ DNS_TYPE_TXT , " TXT " , false } ,
{ DNS_TYPE_PTR , " PTR " , false } ,
{ DNS_TYPE_SRV , " SRV " , false } ,
{ DNS_TYPE_MX , " MX " , false } ,
{ DNS_TYPE_HINFO , " HINFO " , false } ,
{ DNS_TYPE_NS , " NS " , false } ,
{ DNS_TYPE_SOA , " SOA " , true } ,
} ;
/*
see if a DNS type is single valued
*/
static bool b9_single_valued ( enum dns_record_type dns_type )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( dns_typemap ) ; i + + ) {
if ( dns_typemap [ i ] . dns_type = = dns_type ) {
return dns_typemap [ i ] . single_valued ;
}
}
return false ;
}
/*
see if a DNS type is single valued
*/
2011-01-13 03:10:27 +03:00
static bool b9_dns_type ( const char * type , enum dns_record_type * dtype )
2010-12-15 13:46:05 +03:00
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( dns_typemap ) ; i + + ) {
if ( strcasecmp ( dns_typemap [ i ] . typestr , type ) = = 0 ) {
2011-01-13 03:10:27 +03:00
* dtype = dns_typemap [ i ] . dns_type ;
return true ;
2010-12-15 13:46:05 +03:00
}
}
2011-01-13 03:10:27 +03:00
return false ;
2010-12-15 13:46:05 +03:00
}
# define DNS_PARSE_STR(ret, str, sep, saveptr) do { \
( ret ) = strtok_r ( str , sep , & saveptr ) ; \
if ( ( ret ) = = NULL ) return false ; \
} while ( 0 )
# define DNS_PARSE_UINT(ret, str, sep, saveptr) do { \
char * istr = strtok_r ( str , sep , & saveptr ) ; \
if ( ( istr ) = = NULL ) return false ; \
( ret ) = strtoul ( istr , NULL , 10 ) ; \
} while ( 0 )
2010-12-15 07:02:09 +03:00
/*
parse a record from bind9
*/
static bool b9_parse ( struct dlz_bind9_data * state ,
2010-12-15 13:46:05 +03:00
const char * rdatastr ,
struct dnsp_DnssrvRpcRecord * rec )
2010-12-15 07:02:09 +03:00
{
2010-12-15 13:46:05 +03:00
char * full_name , * dclass , * type ;
2012-02-28 07:14:07 +04:00
char * str , * tmp , * saveptr = NULL ;
2010-12-15 13:46:05 +03:00
int i ;
str = talloc_strdup ( rec , rdatastr ) ;
if ( str = = NULL ) {
return false ;
}
/* parse the SDLZ string form */
DNS_PARSE_STR ( full_name , str , " \t " , saveptr ) ;
DNS_PARSE_UINT ( rec - > dwTtlSeconds , NULL , " \t " , saveptr ) ;
DNS_PARSE_STR ( dclass , NULL , " \t " , saveptr ) ;
DNS_PARSE_STR ( type , NULL , " \t " , saveptr ) ;
/* construct the record */
for ( i = 0 ; i < ARRAY_SIZE ( dns_typemap ) ; i + + ) {
if ( strcasecmp ( type , dns_typemap [ i ] . typestr ) = = 0 ) {
rec - > wType = dns_typemap [ i ] . dns_type ;
break ;
}
}
if ( i = = ARRAY_SIZE ( dns_typemap ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: unsupported record type '%s' for '%s' " ,
type , full_name ) ;
return false ;
}
switch ( rec - > wType ) {
case DNS_TYPE_A :
DNS_PARSE_STR ( rec - > data . ipv4 , NULL , " " , saveptr ) ;
break ;
case DNS_TYPE_AAAA :
DNS_PARSE_STR ( rec - > data . ipv6 , NULL , " " , saveptr ) ;
break ;
case DNS_TYPE_CNAME :
DNS_PARSE_STR ( rec - > data . cname , NULL , " " , saveptr ) ;
break ;
case DNS_TYPE_TXT :
2012-02-28 07:14:07 +04:00
rec - > data . txt . count = 0 ;
rec - > data . txt . str = talloc_array ( rec , const char * , rec - > data . txt . count ) ;
tmp = strtok_r ( NULL , " \t " , & saveptr ) ;
while ( tmp ) {
rec - > data . txt . str = talloc_realloc ( rec , rec - > data . txt . str , const char * ,
rec - > data . txt . count + 1 ) ;
if ( tmp [ 0 ] = = ' " ' ) {
/* Strip quotes */
rec - > data . txt . str [ rec - > data . txt . count ] = talloc_strndup ( rec , & tmp [ 1 ] , strlen ( tmp ) - 2 ) ;
} else {
rec - > data . txt . str [ rec - > data . txt . count ] = talloc_strdup ( rec , tmp ) ;
}
rec - > data . txt . count + + ;
tmp = strtok_r ( NULL , " " , & saveptr ) ;
}
2010-12-15 13:46:05 +03:00
break ;
case DNS_TYPE_PTR :
DNS_PARSE_STR ( rec - > data . ptr , NULL , " " , saveptr ) ;
break ;
case DNS_TYPE_SRV :
DNS_PARSE_UINT ( rec - > data . srv . wPriority , NULL , " " , saveptr ) ;
DNS_PARSE_UINT ( rec - > data . srv . wWeight , NULL , " " , saveptr ) ;
DNS_PARSE_UINT ( rec - > data . srv . wPort , NULL , " " , saveptr ) ;
DNS_PARSE_STR ( rec - > data . srv . nameTarget , NULL , " " , saveptr ) ;
break ;
case DNS_TYPE_MX :
DNS_PARSE_UINT ( rec - > data . mx . wPriority , NULL , " " , saveptr ) ;
DNS_PARSE_STR ( rec - > data . mx . nameTarget , NULL , " " , saveptr ) ;
break ;
case DNS_TYPE_HINFO :
DNS_PARSE_STR ( rec - > data . hinfo . cpu , NULL , " " , saveptr ) ;
DNS_PARSE_STR ( rec - > data . hinfo . os , NULL , " " , saveptr ) ;
break ;
case DNS_TYPE_NS :
DNS_PARSE_STR ( rec - > data . ns , NULL , " " , saveptr ) ;
break ;
case DNS_TYPE_SOA :
DNS_PARSE_STR ( rec - > data . soa . mname , NULL , " " , saveptr ) ;
DNS_PARSE_STR ( rec - > data . soa . rname , NULL , " " , saveptr ) ;
DNS_PARSE_UINT ( rec - > data . soa . serial , NULL , " " , saveptr ) ;
DNS_PARSE_UINT ( rec - > data . soa . refresh , NULL , " " , saveptr ) ;
DNS_PARSE_UINT ( rec - > data . soa . retry , NULL , " " , saveptr ) ;
DNS_PARSE_UINT ( rec - > data . soa . expire , NULL , " " , saveptr ) ;
DNS_PARSE_UINT ( rec - > data . soa . minimum , NULL , " " , saveptr ) ;
break ;
default :
state - > log ( ISC_LOG_ERROR , " samba b9_parse: unhandled record type %u " ,
rec - > wType ) ;
return false ;
}
/* we should be at the end of the buffer now */
if ( strtok_r ( NULL , " \t " , & saveptr ) ! = NULL ) {
2012-11-04 18:09:28 +04:00
state - > log ( ISC_LOG_ERROR , " samba b9_parse: unexpected data at end of string for '%s' " ,
rdatastr ) ;
2010-12-15 13:46:05 +03:00
return false ;
}
return true ;
2010-12-15 07:02:09 +03:00
}
2010-12-06 06:12:07 +03:00
/*
2012-11-04 18:09:28 +04:00
send a resource record to bind9
2010-12-06 06:12:07 +03:00
*/
static isc_result_t b9_putrr ( struct dlz_bind9_data * state ,
void * handle , struct dnsp_DnssrvRpcRecord * rec ,
const char * * types )
{
isc_result_t result ;
const char * type , * data ;
TALLOC_CTX * tmp_ctx = talloc_new ( state ) ;
if ( ! b9_format ( state , tmp_ctx , rec , & type , & data ) ) {
return ISC_R_FAILURE ;
}
if ( data = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
if ( types ) {
int i ;
for ( i = 0 ; types [ i ] ; i + + ) {
if ( strcmp ( types [ i ] , type ) = = 0 ) break ;
}
if ( types [ i ] = = NULL ) {
/* skip it */
return ISC_R_SUCCESS ;
}
}
2010-12-06 09:18:30 +03:00
result = state - > putrr ( handle , type , rec - > dwTtlSeconds , data ) ;
2010-12-06 06:12:07 +03:00
if ( result ! = ISC_R_SUCCESS ) {
state - > log ( ISC_LOG_ERROR , " Failed to put rr " ) ;
}
talloc_free ( tmp_ctx ) ;
return result ;
}
/*
2012-11-04 18:09:28 +04:00
send a named resource record to bind9
2010-12-06 06:12:07 +03:00
*/
static isc_result_t b9_putnamedrr ( struct dlz_bind9_data * state ,
void * handle , const char * name ,
struct dnsp_DnssrvRpcRecord * rec )
{
isc_result_t result ;
const char * type , * data ;
TALLOC_CTX * tmp_ctx = talloc_new ( state ) ;
if ( ! b9_format ( state , tmp_ctx , rec , & type , & data ) ) {
return ISC_R_FAILURE ;
}
if ( data = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
2010-12-06 09:18:30 +03:00
result = state - > putnamedrr ( handle , name , type , rec - > dwTtlSeconds , data ) ;
2010-12-06 06:12:07 +03:00
if ( result ! = ISC_R_SUCCESS ) {
state - > log ( ISC_LOG_ERROR , " Failed to put named rr '%s' " , name ) ;
}
talloc_free ( tmp_ctx ) ;
return result ;
}
2010-12-06 08:57:12 +03:00
/*
parse options
*/
static isc_result_t parse_options ( struct dlz_bind9_data * state ,
2010-12-08 01:04:49 +03:00
unsigned int argc , char * argv [ ] ,
struct b9_options * options )
2010-12-06 08:57:12 +03:00
{
2011-12-06 05:01:42 +04:00
int opt ;
poptContext pc ;
struct poptOption long_options [ ] = {
{ " url " , ' H ' , POPT_ARG_STRING , & options - > url , 0 , " database URL " , " URL " } ,
{ " debug " , ' d ' , POPT_ARG_STRING , & options - > debug , 0 , " debug level " , " DEBUG " } ,
{ NULL }
} ;
pc = poptGetContext ( " dlz_bind9 " , argc , ( const char * * ) argv , long_options ,
POPT_CONTEXT_KEEP_FIRST ) ;
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
switch ( opt ) {
default :
state - > log ( ISC_LOG_ERROR , " dlz_bind9: Invalid option %s: %s " ,
poptBadOption ( pc , 0 ) , poptStrerror ( opt ) ) ;
return ISC_R_FAILURE ;
2010-12-06 08:57:12 +03:00
}
2010-12-08 01:04:49 +03:00
}
return ISC_R_SUCCESS ;
}
2012-01-03 08:39:20 +04:00
/*
* Create session info from PAC
* This is called as auth_context - > generate_session_info_pac ( )
*/
static NTSTATUS b9_generate_session_info_pac ( struct auth4_context * auth_context ,
TALLOC_CTX * mem_ctx ,
struct smb_krb5_context * smb_krb5_context ,
DATA_BLOB * pac_blob ,
const char * principal_name ,
const struct tsocket_address * remote_addr ,
uint32_t session_info_flags ,
struct auth_session_info * * session_info )
{
NTSTATUS status ;
struct auth_user_info_dc * user_info_dc ;
TALLOC_CTX * tmp_ctx ;
tmp_ctx = talloc_new ( mem_ctx ) ;
NT_STATUS_HAVE_NO_MEMORY ( tmp_ctx ) ;
status = kerberos_pac_blob_to_user_info_dc ( tmp_ctx ,
* pac_blob ,
smb_krb5_context - > krb5_context ,
& user_info_dc ,
NULL ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return status ;
}
2012-01-25 03:00:31 +04:00
if ( user_info_dc - > info - > authenticated ) {
session_info_flags | = AUTH_SESSION_INFO_AUTHENTICATED ;
}
2012-01-03 08:39:20 +04:00
session_info_flags | = AUTH_SESSION_INFO_SIMPLE_PRIVILEGES ;
2012-01-25 03:00:31 +04:00
2012-01-03 08:39:20 +04:00
status = auth_generate_session_info ( mem_ctx , NULL , NULL , user_info_dc ,
session_info_flags , session_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return status ;
}
talloc_free ( tmp_ctx ) ;
return status ;
}
2012-03-08 05:21:56 +04:00
/* Callback for the DEBUG() system, to catch the remaining messages */
static void b9_debug ( void * private_ptr , int msg_level , const char * msg )
{
static const int isc_log_map [ ] = {
ISC_LOG_CRITICAL , /* 0 */
ISC_LOG_ERROR , /* 1 */
ISC_LOG_WARNING , /* 2 */
ISC_LOG_NOTICE /* 3 */
} ;
struct dlz_bind9_data * state = private_ptr ;
int isc_log_level ;
if ( msg_level > = ARRAY_SIZE ( isc_log_map ) | | msg_level < 0 ) {
isc_log_level = ISC_LOG_INFO ;
} else {
isc_log_level = isc_log_map [ msg_level ] ;
}
state - > log ( isc_log_level , " samba_dlz: %s " , msg ) ;
}
2012-05-23 05:53:59 +04:00
static int dlz_state_debug_unregister ( struct dlz_bind9_data * state )
2012-03-08 05:21:56 +04:00
{
/* Stop logging (to the bind9 logs) */
debug_set_callback ( NULL , NULL ) ;
2012-05-23 05:53:59 +04:00
return 0 ;
2012-03-08 05:21:56 +04:00
}
2012-01-03 08:39:20 +04:00
2010-12-06 06:12:07 +03:00
/*
called to initialise the driver
*/
_PUBLIC_ isc_result_t dlz_create ( const char * dlzname ,
unsigned int argc , char * argv [ ] ,
2010-12-15 07:02:09 +03:00
void * * dbdata , . . . )
2010-12-06 06:12:07 +03:00
{
struct dlz_bind9_data * state ;
const char * helper_name ;
va_list ap ;
isc_result_t result ;
struct ldb_dn * dn ;
2011-11-02 07:32:37 +04:00
NTSTATUS nt_status ;
2010-12-06 06:12:07 +03:00
2012-05-23 05:52:16 +04:00
if ( dlz_bind9_state ! = NULL ) {
* dbdata = dlz_bind9_state ;
dlz_bind9_state_ref_count + + ;
return ISC_R_SUCCESS ;
}
2010-12-06 06:12:07 +03:00
state = talloc_zero ( NULL , struct dlz_bind9_data ) ;
if ( state = = NULL ) {
return ISC_R_NOMEMORY ;
}
2012-03-08 05:21:56 +04:00
talloc_set_destructor ( state , dlz_state_debug_unregister ) ;
2010-12-06 06:12:07 +03:00
/* fill in the helper functions */
va_start ( ap , dbdata ) ;
while ( ( helper_name = va_arg ( ap , const char * ) ) ! = NULL ) {
b9_add_helper ( state , helper_name , va_arg ( ap , void * ) ) ;
}
va_end ( ap ) ;
2011-12-06 05:01:42 +04:00
/* Do not install samba signal handlers */
fault_setup_disable ( ) ;
2012-03-08 05:21:56 +04:00
/* Start logging (to the bind9 logs) */
debug_set_callback ( state , b9_debug ) ;
2011-12-06 03:51:01 +04:00
2010-12-08 01:04:49 +03:00
state - > ev_ctx = s4_event_context_init ( state ) ;
2010-12-06 06:12:07 +03:00
if ( state - > ev_ctx = = NULL ) {
result = ISC_R_NOMEMORY ;
goto failed ;
}
2011-11-02 07:32:37 +04:00
result = parse_options ( state , argc , argv , & state - > options ) ;
2010-12-08 01:58:52 +03:00
if ( result ! = ISC_R_SUCCESS ) {
goto failed ;
}
state - > lp = loadparm_init_global ( true ) ;
if ( state - > lp = = NULL ) {
result = ISC_R_NOMEMORY ;
goto failed ;
}
2011-12-06 05:01:42 +04:00
if ( state - > options . debug ) {
lpcfg_do_global_parameter ( state - > lp , " log level " , state - > options . debug ) ;
} else {
lpcfg_do_global_parameter ( state - > lp , " log level " , " 0 " ) ;
}
2011-11-02 07:32:37 +04:00
if ( smb_krb5_init_context ( state , state - > ev_ctx , state - > lp , & state - > smb_krb5_ctx ) ! = 0 ) {
result = ISC_R_NOMEMORY ;
goto failed ;
}
nt_status = gensec_init ( ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2012-01-03 08:39:20 +04:00
result = ISC_R_NOMEMORY ;
goto failed ;
}
state - > auth_context = talloc_zero ( state , struct auth4_context ) ;
if ( state - > auth_context = = NULL ) {
result = ISC_R_NOMEMORY ;
goto failed ;
2011-11-02 07:32:37 +04:00
}
if ( state - > options . url = = NULL ) {
state - > options . url = lpcfg_private_path ( state , state - > lp , " dns/sam.ldb " ) ;
if ( state - > options . url = = NULL ) {
2010-12-08 01:04:49 +03:00
result = ISC_R_NOMEMORY ;
goto failed ;
}
}
2011-09-16 02:54:05 +04:00
state - > samdb = samdb_connect_url ( state , state - > ev_ctx , state - > lp ,
2011-11-02 07:32:37 +04:00
system_session ( state - > lp ) , 0 , state - > options . url ) ;
2011-09-16 02:54:05 +04:00
if ( state - > samdb = = NULL ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: Failed to connect to %s " ,
2011-11-02 07:32:37 +04:00
state - > options . url ) ;
2010-12-06 06:12:07 +03:00
result = ISC_R_FAILURE ;
goto failed ;
}
dn = ldb_get_default_basedn ( state - > samdb ) ;
if ( dn = = NULL ) {
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: Unable to get basedn for %s - %s " ,
2011-11-02 07:32:37 +04:00
state - > options . url , ldb_errstring ( state - > samdb ) ) ;
2010-12-06 06:12:07 +03:00
result = ISC_R_FAILURE ;
goto failed ;
}
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_INFO , " samba_dlz: started for DN %s " ,
2010-12-06 06:12:07 +03:00
ldb_dn_get_linearized ( dn ) ) ;
2012-01-03 08:39:20 +04:00
state - > auth_context - > event_ctx = state - > ev_ctx ;
state - > auth_context - > lp_ctx = state - > lp ;
state - > auth_context - > sam_ctx = state - > samdb ;
state - > auth_context - > generate_session_info_pac = b9_generate_session_info_pac ;
2010-12-06 06:12:07 +03:00
* dbdata = state ;
2012-05-23 05:52:16 +04:00
dlz_bind9_state = state ;
dlz_bind9_state_ref_count + + ;
2010-12-06 06:12:07 +03:00
return ISC_R_SUCCESS ;
failed :
talloc_free ( state ) ;
return result ;
}
/*
shutdown the backend
*/
2010-12-15 07:02:09 +03:00
_PUBLIC_ void dlz_destroy ( void * dbdata )
2010-12-06 06:12:07 +03:00
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_INFO , " samba_dlz: shutting down " ) ;
2012-05-23 05:52:16 +04:00
dlz_bind9_state_ref_count - - ;
if ( dlz_bind9_state_ref_count = = 0 ) {
talloc_unlink ( state , state - > samdb ) ;
talloc_free ( state ) ;
dlz_bind9_state = NULL ;
}
2010-12-06 06:12:07 +03:00
}
/*
2010-12-15 13:46:05 +03:00
return the base DN for a zone
2010-12-06 06:12:07 +03:00
*/
2010-12-15 13:46:05 +03:00
static isc_result_t b9_find_zone_dn ( struct dlz_bind9_data * state , const char * zone_name ,
TALLOC_CTX * mem_ctx , struct ldb_dn * * zone_dn )
2010-12-06 06:12:07 +03:00
{
2010-12-15 07:02:09 +03:00
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( state ) ;
const char * attrs [ ] = { NULL } ;
int i ;
for ( i = 0 ; zone_prefixes [ i ] ; i + + ) {
struct ldb_dn * dn ;
struct ldb_result * res ;
dn = ldb_dn_copy ( tmp_ctx , ldb_get_default_basedn ( state - > samdb ) ) ;
if ( dn = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
2010-12-15 13:46:05 +03:00
if ( ! ldb_dn_add_child_fmt ( dn , " DC=%s,%s " , zone_name , zone_prefixes [ i ] ) ) {
2010-12-15 07:02:09 +03:00
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
ret = ldb_search ( state - > samdb , tmp_ctx , & res , dn , LDB_SCOPE_BASE , attrs , " objectClass=dnsZone " ) ;
if ( ret = = LDB_SUCCESS ) {
2010-12-15 13:46:05 +03:00
if ( zone_dn ! = NULL ) {
* zone_dn = talloc_steal ( mem_ctx , dn ) ;
}
2010-12-15 07:02:09 +03:00
talloc_free ( tmp_ctx ) ;
return ISC_R_SUCCESS ;
}
talloc_free ( dn ) ;
2010-12-06 06:12:07 +03:00
}
2010-12-15 07:02:09 +03:00
talloc_free ( tmp_ctx ) ;
2010-12-06 06:12:07 +03:00
return ISC_R_NOTFOUND ;
}
2010-12-15 13:46:05 +03:00
/*
return the DN for a name . The record does not need to exist , but the
zone must exist
*/
static isc_result_t b9_find_name_dn ( struct dlz_bind9_data * state , const char * name ,
TALLOC_CTX * mem_ctx , struct ldb_dn * * dn )
{
const char * p ;
/* work through the name piece by piece, until we find a zone */
for ( p = name ; p ; ) {
isc_result_t result ;
result = b9_find_zone_dn ( state , p , mem_ctx , dn ) ;
if ( result = = ISC_R_SUCCESS ) {
/* we found a zone, now extend the DN to get
* the full DN
*/
bool ret ;
if ( p = = name ) {
ret = ldb_dn_add_child_fmt ( * dn , " DC=@ " ) ;
} else {
ret = ldb_dn_add_child_fmt ( * dn , " DC=%.*s " , ( int ) ( p - name ) - 1 , name ) ;
}
if ( ! ret ) {
talloc_free ( * dn ) ;
return ISC_R_NOMEMORY ;
}
return ISC_R_SUCCESS ;
}
p = strchr ( p , ' . ' ) ;
if ( p = = NULL ) {
break ;
}
p + + ;
}
return ISC_R_NOTFOUND ;
}
/*
see if we handle a given zone
*/
_PUBLIC_ isc_result_t dlz_findzonedb ( void * dbdata , const char * name )
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
return b9_find_zone_dn ( state , name , NULL , NULL ) ;
}
2010-12-06 06:12:07 +03:00
/*
lookup one record
*/
2010-12-08 01:04:49 +03:00
static isc_result_t dlz_lookup_types ( struct dlz_bind9_data * state ,
const char * zone , const char * name ,
2010-12-15 07:02:09 +03:00
dns_sdlzlookup_t * lookup ,
2010-12-08 01:04:49 +03:00
const char * * types )
2010-12-06 06:12:07 +03:00
{
TALLOC_CTX * tmp_ctx = talloc_new ( state ) ;
const char * attrs [ ] = { " dnsRecord " , NULL } ;
2011-01-09 00:32:12 +03:00
int ret = LDB_SUCCESS , i ;
2010-12-06 06:12:07 +03:00
struct ldb_result * res ;
struct ldb_message_element * el ;
2010-12-15 07:02:09 +03:00
struct ldb_dn * dn ;
2010-12-06 06:12:07 +03:00
2010-12-15 07:02:09 +03:00
for ( i = 0 ; zone_prefixes [ i ] ; i + + ) {
dn = ldb_dn_copy ( tmp_ctx , ldb_get_default_basedn ( state - > samdb ) ) ;
if ( dn = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
2010-12-06 06:12:07 +03:00
2010-12-15 07:02:09 +03:00
if ( ! ldb_dn_add_child_fmt ( dn , " DC=%s,DC=%s,%s " , name , zone , zone_prefixes [ i ] ) ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
2010-12-06 06:12:07 +03:00
2010-12-15 07:02:09 +03:00
ret = ldb_search ( state - > samdb , tmp_ctx , & res , dn , LDB_SCOPE_BASE ,
attrs , " objectClass=dnsNode " ) ;
if ( ret = = LDB_SUCCESS ) {
break ;
}
}
s4-dns: dlz_bind9: Check result to avoid segfault
We saw this issue in a customer environment with many CNF objects. I
wasn't able to reproduce it, but I got the following core dump:
(gdb) directory samba4-4.0.0~rc6/source4/dns_server/
Source directories searched: /root/samba4-4.0.0~rc6/source4/dns_server:$cdir:$cwd
(gdb) bt
#0 0xb4b0bc13 in dlz_lookup_types (state=0x9648e48, zone=0xb659b9a8 "xxxxxx.xxxxx.de", name=0xb659bda8 "client9173", lookup=0xb6db7588, types=0x0) at ../source4/dns_server/dlz_bind9.c:830
#1 0xb4b0bdb8 in dlz_lookup (zone=0xb659b9a8 "xxxxxx.xxxxx.de", name=0xb659bda8 "client9173", dbdata=0x9648e48, lookup=0xb6db7588) at ../source4/dns_server/dlz_bind9.c:875
#2 0x080b43d8 in dlopen_dlz_lookup ()
#3 0xb7701755 in findnode () from /usr/lib/libdns.so.81
#4 0xb7701d22 in find () from /usr/lib/libdns.so.81
#5 0xb7639e5f in dns_db_find () from /usr/lib/libdns.so.81
#6 0x08075476 in query_find ()
#7 0x0807acb9 in ns_query_start ()
#8 0x08060712 in client_request ()
#9 0xb743022b in run () from /usr/lib/libisc.so.81
#10 0xb7216955 in start_thread () from /lib/i686/cmov/libpthread.so.0
#11 0xb706c1de in clone () from /lib/i686/cmov/libc.so.6
(gdb) f 0
#0 0xb4b0bc13 in dlz_lookup_types (state=0x9648e48, zone=0xb659b9a8 "xxxxxx.xxxxx.de", name=0xb659bda8 "client9173", lookup=0xb6db7588, types=0x0) at ../source4/dns_server/dlz_bind9.c:830
830 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
(gdb) p res->msgs
$1 = (struct ldb_message **) 0x0
(gdb) p res->count
$2 = 0
(gdb)
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2013-03-08 23:57:31 +04:00
if ( ret ! = LDB_SUCCESS | | res - > count = = 0 ) {
2010-12-06 06:12:07 +03:00
talloc_free ( tmp_ctx ) ;
return ISC_R_NOTFOUND ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL | | el - > num_values = = 0 ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOTFOUND ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec ;
enum ndr_err_code ndr_err ;
isc_result_t result ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , tmp_ctx , & rec ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to parse dnsRecord for %s " ,
2010-12-06 06:12:07 +03:00
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( tmp_ctx ) ;
return ISC_R_FAILURE ;
}
result = b9_putrr ( state , lookup , & rec , types ) ;
if ( result ! = ISC_R_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return result ;
}
}
talloc_free ( tmp_ctx ) ;
return ISC_R_SUCCESS ;
}
/*
lookup one record
*/
2012-04-05 10:45:01 +04:00
# ifdef BIND_VERSION_9_8
_PUBLIC_ isc_result_t dlz_lookup ( const char * zone , const char * name ,
void * dbdata , dns_sdlzlookup_t * lookup )
# else
2010-12-15 07:02:09 +03:00
_PUBLIC_ isc_result_t dlz_lookup ( const char * zone , const char * name ,
2012-03-08 11:34:04 +04:00
void * dbdata , dns_sdlzlookup_t * lookup ,
dns_clientinfomethods_t * methods ,
dns_clientinfo_t * clientinfo )
2012-04-05 10:45:01 +04:00
# endif
2010-12-06 06:12:07 +03:00
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
2010-12-15 07:02:09 +03:00
return dlz_lookup_types ( state , zone , name , lookup , NULL ) ;
2010-12-06 06:12:07 +03:00
}
/*
see if a zone transfer is allowed
*/
2010-12-15 07:02:09 +03:00
_PUBLIC_ isc_result_t dlz_allowzonexfr ( void * dbdata , const char * name , const char * client )
2010-12-06 06:12:07 +03:00
{
2010-12-15 07:02:09 +03:00
/* just say yes for all our zones for now */
return dlz_findzonedb ( dbdata , name ) ;
2010-12-06 06:12:07 +03:00
}
/*
perform a zone transfer
*/
2010-12-15 07:02:09 +03:00
_PUBLIC_ isc_result_t dlz_allnodes ( const char * zone , void * dbdata ,
2010-12-06 06:12:07 +03:00
dns_sdlzallnodes_t * allnodes )
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
const char * attrs [ ] = { " dnsRecord " , NULL } ;
2011-01-09 00:32:12 +03:00
int ret = LDB_SUCCESS , i , j ;
2010-12-06 06:12:07 +03:00
struct ldb_dn * dn ;
struct ldb_result * res ;
TALLOC_CTX * tmp_ctx = talloc_new ( state ) ;
2010-12-15 07:02:09 +03:00
for ( i = 0 ; zone_prefixes [ i ] ; i + + ) {
dn = ldb_dn_copy ( tmp_ctx , ldb_get_default_basedn ( state - > samdb ) ) ;
if ( dn = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
2010-12-06 06:12:07 +03:00
2010-12-15 07:02:09 +03:00
if ( ! ldb_dn_add_child_fmt ( dn , " DC=%s,%s " , zone , zone_prefixes [ i ] ) ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
2010-12-06 06:12:07 +03:00
2010-12-15 07:02:09 +03:00
ret = ldb_search ( state - > samdb , tmp_ctx , & res , dn , LDB_SCOPE_SUBTREE ,
attrs , " objectClass=dnsNode " ) ;
if ( ret = = LDB_SUCCESS ) {
break ;
}
2010-12-06 06:12:07 +03:00
}
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOTFOUND ;
}
for ( i = 0 ; i < res - > count ; i + + ) {
struct ldb_message_element * el ;
TALLOC_CTX * el_ctx = talloc_new ( tmp_ctx ) ;
const char * rdn , * name ;
const struct ldb_val * v ;
el = ldb_msg_find_element ( res - > msgs [ i ] , " dnsRecord " ) ;
if ( el = = NULL | | el - > num_values = = 0 ) {
state - > log ( ISC_LOG_INFO , " failed to find dnsRecord for %s " ,
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( el_ctx ) ;
continue ;
}
v = ldb_dn_get_rdn_val ( res - > msgs [ i ] - > dn ) ;
if ( v = = NULL ) {
state - > log ( ISC_LOG_INFO , " failed to find RDN for %s " ,
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( el_ctx ) ;
continue ;
}
rdn = talloc_strndup ( el_ctx , ( char * ) v - > data , v - > length ) ;
if ( rdn = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
if ( strcmp ( rdn , " @ " ) = = 0 ) {
name = zone ;
} else {
name = talloc_asprintf ( el_ctx , " %s.%s " , rdn , zone ) ;
}
if ( name = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
for ( j = 0 ; j < el - > num_values ; j + + ) {
struct dnsp_DnssrvRpcRecord rec ;
enum ndr_err_code ndr_err ;
isc_result_t result ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ j ] , el_ctx , & rec ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to parse dnsRecord for %s " ,
2010-12-06 06:12:07 +03:00
ldb_dn_get_linearized ( dn ) ) ;
continue ;
}
result = b9_putnamedrr ( state , allnodes , name , & rec ) ;
if ( result ! = ISC_R_SUCCESS ) {
continue ;
}
}
}
talloc_free ( tmp_ctx ) ;
return ISC_R_SUCCESS ;
}
2010-12-15 07:02:09 +03:00
/*
start a transaction
*/
_PUBLIC_ isc_result_t dlz_newversion ( const char * zone , void * dbdata , void * * versionp )
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_INFO , " samba_dlz: starting transaction on zone %s " , zone ) ;
2010-12-15 07:02:09 +03:00
2010-12-15 13:46:05 +03:00
if ( state - > transaction_token ! = NULL ) {
state - > log ( ISC_LOG_INFO , " samba_dlz: transaction already started for zone %s " , zone ) ;
2010-12-15 07:02:09 +03:00
return ISC_R_FAILURE ;
}
2010-12-15 13:46:05 +03:00
state - > transaction_token = talloc_zero ( state , int ) ;
if ( state - > transaction_token = = NULL ) {
return ISC_R_NOMEMORY ;
}
if ( ldb_transaction_start ( state - > samdb ) ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_INFO , " samba_dlz: failed to start a transaction for zone %s " , zone ) ;
talloc_free ( state - > transaction_token ) ;
state - > transaction_token = NULL ;
return ISC_R_FAILURE ;
}
2010-12-15 07:02:09 +03:00
2010-12-15 13:46:05 +03:00
* versionp = ( void * ) state - > transaction_token ;
2010-12-15 07:02:09 +03:00
return ISC_R_SUCCESS ;
}
/*
end a transaction
*/
_PUBLIC_ void dlz_closeversion ( const char * zone , isc_boolean_t commit ,
void * dbdata , void * * versionp )
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
2010-12-15 13:46:05 +03:00
if ( state - > transaction_token ! = ( int * ) * versionp ) {
state - > log ( ISC_LOG_INFO , " samba_dlz: transaction not started for zone %s " , zone ) ;
2010-12-15 07:02:09 +03:00
return ;
}
if ( commit ) {
2010-12-15 13:46:05 +03:00
if ( ldb_transaction_commit ( state - > samdb ) ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_INFO , " samba_dlz: failed to commit a transaction for zone %s " , zone ) ;
return ;
}
state - > log ( ISC_LOG_INFO , " samba_dlz: committed transaction on zone %s " , zone ) ;
2010-12-15 07:02:09 +03:00
} else {
2010-12-15 13:46:05 +03:00
if ( ldb_transaction_cancel ( state - > samdb ) ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_INFO , " samba_dlz: failed to cancel a transaction for zone %s " , zone ) ;
return ;
}
state - > log ( ISC_LOG_INFO , " samba_dlz: cancelling transaction on zone %s " , zone ) ;
2010-12-15 07:02:09 +03:00
}
2010-12-15 13:46:05 +03:00
talloc_free ( state - > transaction_token ) ;
state - > transaction_token = NULL ;
* versionp = NULL ;
2010-12-15 07:02:09 +03:00
}
/*
see if there is a SOA record for a zone
*/
static bool b9_has_soa ( struct dlz_bind9_data * state , struct ldb_dn * dn , const char * zone )
{
const char * attrs [ ] = { " dnsRecord " , NULL } ;
struct ldb_result * res ;
struct ldb_message_element * el ;
TALLOC_CTX * tmp_ctx = talloc_new ( state ) ;
int ret , i ;
if ( ! ldb_dn_add_child_fmt ( dn , " DC=@,DC=%s " , zone ) ) {
talloc_free ( tmp_ctx ) ;
return false ;
}
ret = ldb_search ( state - > samdb , tmp_ctx , & res , dn , LDB_SCOPE_BASE ,
attrs , " objectClass=dnsNode " ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return false ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL ) {
talloc_free ( tmp_ctx ) ;
return false ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec ;
enum ndr_err_code ndr_err ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , tmp_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 ) {
talloc_free ( tmp_ctx ) ;
return true ;
}
}
talloc_free ( tmp_ctx ) ;
return false ;
}
2013-10-02 11:28:45 +04:00
static bool b9_zone_add ( struct dlz_bind9_data * state , const char * name )
{
struct b9_zone * zone ;
zone = talloc_zero ( state , struct b9_zone ) ;
if ( zone = = NULL ) {
return false ;
}
zone - > name = talloc_strdup ( zone , name ) ;
if ( zone - > name = = NULL ) {
talloc_free ( zone ) ;
return false ;
}
DLIST_ADD ( state - > zonelist , zone ) ;
return true ;
}
static bool b9_zone_exists ( struct dlz_bind9_data * state , const char * name )
{
struct b9_zone * zone = state - > zonelist ;
bool found = false ;
while ( zone ! = NULL ) {
if ( strcasecmp ( name , zone - > name ) = = 0 ) {
found = true ;
break ;
}
zone = zone - > next ;
}
return found ;
}
2010-12-15 07:02:09 +03:00
/*
configure a writeable zone
*/
_PUBLIC_ isc_result_t dlz_configure ( dns_view_t * view , void * dbdata )
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
TALLOC_CTX * tmp_ctx ;
struct ldb_dn * dn ;
int i ;
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_INFO , " samba_dlz: starting configure " ) ;
2010-12-15 07:02:09 +03:00
if ( state - > writeable_zone = = NULL ) {
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_INFO , " samba_dlz: no writeable_zone method available " ) ;
2010-12-15 07:02:09 +03:00
return ISC_R_FAILURE ;
}
tmp_ctx = talloc_new ( state ) ;
for ( i = 0 ; zone_prefixes [ i ] ; i + + ) {
const char * attrs [ ] = { " name " , NULL } ;
int j , ret ;
struct ldb_result * res ;
dn = ldb_dn_copy ( tmp_ctx , ldb_get_default_basedn ( state - > samdb ) ) ;
if ( dn = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
if ( ! ldb_dn_add_child_fmt ( dn , " %s " , zone_prefixes [ i ] ) ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
ret = ldb_search ( state - > samdb , tmp_ctx , & res , dn , LDB_SCOPE_SUBTREE ,
attrs , " objectClass=dnsZone " ) ;
if ( ret ! = LDB_SUCCESS ) {
continue ;
}
for ( j = 0 ; j < res - > count ; j + + ) {
isc_result_t result ;
const char * zone = ldb_msg_find_attr_as_string ( res - > msgs [ j ] , " name " , NULL ) ;
2011-10-13 17:23:58 +04:00
struct ldb_dn * zone_dn ;
2010-12-15 07:02:09 +03:00
if ( zone = = NULL ) {
continue ;
}
2012-10-02 07:00:50 +04:00
/* Ignore zones that are not handled in BIND */
if ( ( strcmp ( zone , " RootDNSServers " ) = = 0 ) | |
( strcmp ( zone , " ..TrustAnchors " ) = = 0 ) ) {
continue ;
}
2011-10-13 17:23:58 +04:00
zone_dn = ldb_dn_copy ( tmp_ctx , dn ) ;
2011-10-17 14:10:10 +04:00
if ( zone_dn = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
2011-10-13 17:23:58 +04:00
if ( ! b9_has_soa ( state , zone_dn , zone ) ) {
2010-12-15 07:02:09 +03:00
continue ;
}
2013-10-02 11:28:45 +04:00
if ( b9_zone_exists ( state , zone ) ) {
state - > log ( ISC_LOG_WARNING , " samba_dlz: Ignoring duplicate zone '%s' from '%s' " ,
zone , ldb_dn_get_linearized ( zone_dn ) ) ;
continue ;
}
if ( ! b9_zone_add ( state , zone ) ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOMEMORY ;
}
2010-12-15 07:02:09 +03:00
result = state - > writeable_zone ( view , zone ) ;
if ( result ! = ISC_R_SUCCESS ) {
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: Failed to configure zone '%s' " ,
2010-12-15 07:02:09 +03:00
zone ) ;
talloc_free ( tmp_ctx ) ;
return result ;
}
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_INFO , " samba_dlz: configured writeable zone '%s' " , zone ) ;
2010-12-15 07:02:09 +03:00
}
}
talloc_free ( tmp_ctx ) ;
return ISC_R_SUCCESS ;
}
/*
authorize a zone update
*/
_PUBLIC_ isc_boolean_t dlz_ssumatch ( const char * signer , const char * name , const char * tcpaddr ,
const char * type , const char * key , uint32_t keydatalen , uint8_t * keydata ,
void * dbdata )
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
2011-11-02 07:32:37 +04:00
TALLOC_CTX * tmp_ctx ;
DATA_BLOB ap_req ;
struct cli_credentials * server_credentials ;
2011-12-06 07:18:41 +04:00
char * keytab_name ;
int ret ;
2011-11-02 07:32:37 +04:00
int ldb_ret ;
NTSTATUS nt_status ;
struct gensec_security * gensec_ctx ;
struct auth_session_info * session_info ;
struct ldb_dn * dn ;
isc_result_t result ;
struct ldb_result * res ;
const char * attrs [ ] = { NULL } ;
uint32_t access_mask ;
2011-11-30 09:06:08 +04:00
/* Remove cached credentials, if any */
if ( state - > session_info ) {
talloc_free ( state - > session_info ) ;
state - > session_info = NULL ;
}
if ( state - > update_name ) {
talloc_free ( state - > update_name ) ;
state - > update_name = NULL ;
}
2011-11-02 07:32:37 +04:00
tmp_ctx = talloc_new ( NULL ) ;
if ( tmp_ctx = = NULL ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: no memory " ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
ap_req = data_blob_const ( keydata , keydatalen ) ;
server_credentials = cli_credentials_init ( tmp_ctx ) ;
if ( ! server_credentials ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to init server credentials " ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
cli_credentials_set_krb5_context ( server_credentials , state - > smb_krb5_ctx ) ;
cli_credentials_set_conf ( server_credentials , state - > lp ) ;
keytab_name = talloc_asprintf ( tmp_ctx , " file:%s/dns.keytab " ,
lpcfg_private_dir ( state - > lp ) ) ;
ret = cli_credentials_set_keytab_name ( server_credentials , state - > lp , keytab_name ,
CRED_SPECIFIED ) ;
if ( ret ! = 0 ) {
2011-12-06 07:18:41 +04:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to obtain server credentials from %s " ,
keytab_name ) ;
2011-11-02 07:32:37 +04:00
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
2011-12-06 07:18:41 +04:00
talloc_free ( keytab_name ) ;
2011-11-02 07:32:37 +04:00
nt_status = gensec_server_start ( tmp_ctx ,
lpcfg_gensec_settings ( tmp_ctx , state - > lp ) ,
2012-01-03 08:39:20 +04:00
state - > auth_context , & gensec_ctx ) ;
2011-11-02 07:32:37 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to start gensec server " ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
gensec_set_credentials ( gensec_ctx , server_credentials ) ;
nt_status = gensec_start_mech_by_name ( gensec_ctx , " spnego " ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to start spnego " ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
2013-12-13 22:35:07 +04:00
nt_status = gensec_update_ev ( gensec_ctx , tmp_ctx , state - > ev_ctx , ap_req , & ap_req ) ;
2011-11-02 07:32:37 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: spnego update failed " ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
nt_status = gensec_session_info ( gensec_ctx , tmp_ctx , & session_info ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to create session info " ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
/* Get the DN from name */
result = b9_find_name_dn ( state , name , tmp_ctx , & dn ) ;
if ( result ! = ISC_R_SUCCESS ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to find name %s " , name ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
2010-12-15 07:02:09 +03:00
2011-11-02 07:32:37 +04:00
/* make sure the dn exists, or find parent dn in case new object is being added */
ldb_ret = ldb_search ( state - > samdb , tmp_ctx , & res , dn , LDB_SCOPE_BASE ,
attrs , " objectClass=dnsNode " ) ;
if ( ldb_ret = = LDB_ERR_NO_SUCH_OBJECT ) {
ldb_dn_remove_child_components ( dn , 1 ) ;
2011-11-30 03:37:14 +04:00
access_mask = SEC_ADS_CREATE_CHILD ;
2011-11-02 07:32:37 +04:00
talloc_free ( res ) ;
} else if ( ldb_ret = = LDB_SUCCESS ) {
access_mask = SEC_STD_REQUIRED | SEC_ADS_SELF_WRITE ;
talloc_free ( res ) ;
} else {
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
/* Do ACL check */
ldb_ret = dsdb_check_access_on_dn ( state - > samdb , tmp_ctx , dn ,
session_info - > security_token ,
access_mask , NULL ) ;
if ( ldb_ret ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_INFO ,
" samba_dlz: disallowing update of signer=%s name=%s type=%s error=%s " ,
signer , name , type , ldb_strerror ( ldb_ret ) ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-02 07:32:37 +04:00
}
2011-11-30 09:06:08 +04:00
/* Cache session_info, so it can be used in the actual add/delete operation */
state - > update_name = talloc_strdup ( state , name ) ;
if ( state - > update_name = = NULL ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: memory allocation error " ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_FALSE ;
2011-11-30 09:06:08 +04:00
}
state - > session_info = talloc_steal ( state , session_info ) ;
2011-11-02 07:32:37 +04:00
state - > log ( ISC_LOG_INFO , " samba_dlz: allowing update of signer=%s name=%s tcpaddr=%s type=%s key=%s " ,
signer , name , tcpaddr , type , key ) ;
talloc_free ( tmp_ctx ) ;
2012-03-08 11:34:04 +04:00
return ISC_TRUE ;
2010-12-15 07:02:09 +03:00
}
2010-12-15 13:46:05 +03:00
/*
add a new record
*/
static isc_result_t b9_add_record ( struct dlz_bind9_data * state , const char * name ,
struct ldb_dn * dn ,
struct dnsp_DnssrvRpcRecord * rec )
{
struct ldb_message * msg ;
enum ndr_err_code ndr_err ;
struct ldb_val v ;
int ret ;
msg = ldb_msg_new ( rec ) ;
if ( msg = = NULL ) {
return ISC_R_NOMEMORY ;
}
msg - > dn = dn ;
ret = ldb_msg_add_string ( msg , " objectClass " , " dnsNode " ) ;
if ( ret ! = LDB_SUCCESS ) {
return ISC_R_FAILURE ;
}
ndr_err = ndr_push_struct_blob ( & v , rec , rec , ( ndr_push_flags_fn_t ) ndr_push_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ISC_R_FAILURE ;
}
ret = ldb_msg_add_value ( msg , " dnsRecord " , & v , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ISC_R_FAILURE ;
}
ret = ldb_add ( state - > samdb , msg ) ;
if ( ret ! = LDB_SUCCESS ) {
return ISC_R_FAILURE ;
}
return ISC_R_SUCCESS ;
}
2010-12-21 12:53:11 +03:00
/*
see if two DNS names are the same
*/
static bool dns_name_equal ( const char * name1 , const char * name2 )
{
size_t len1 = strlen ( name1 ) ;
size_t len2 = strlen ( name2 ) ;
if ( name1 [ len1 - 1 ] = = ' . ' ) len1 - - ;
if ( name2 [ len2 - 1 ] = = ' . ' ) len2 - - ;
if ( len1 ! = len2 ) {
return false ;
}
return strncasecmp_m ( name1 , name2 , len1 ) = = 0 ;
}
2010-12-15 13:46:05 +03:00
/*
see if two dns records match
*/
static bool b9_record_match ( struct dlz_bind9_data * state ,
struct dnsp_DnssrvRpcRecord * rec1 , struct dnsp_DnssrvRpcRecord * rec2 )
{
2012-02-28 07:14:07 +04:00
bool status ;
int i ;
2010-12-15 13:46:05 +03:00
if ( rec1 - > wType ! = rec2 - > wType ) {
return false ;
}
/* see if this type is single valued */
if ( b9_single_valued ( rec1 - > wType ) ) {
return true ;
}
/* see if the data matches */
switch ( rec1 - > wType ) {
case DNS_TYPE_A :
return strcmp ( rec1 - > data . ipv4 , rec2 - > data . ipv4 ) = = 0 ;
case DNS_TYPE_AAAA :
return strcmp ( rec1 - > data . ipv6 , rec2 - > data . ipv6 ) = = 0 ;
case DNS_TYPE_CNAME :
2010-12-21 12:53:11 +03:00
return dns_name_equal ( rec1 - > data . cname , rec2 - > data . cname ) ;
2010-12-15 13:46:05 +03:00
case DNS_TYPE_TXT :
2012-02-28 07:14:07 +04:00
status = ( rec1 - > data . txt . count = = rec2 - > data . txt . count ) ;
if ( ! status ) return status ;
for ( i = 0 ; i < rec1 - > data . txt . count ; i + + ) {
status & = ( strcmp ( rec1 - > data . txt . str [ i ] , rec2 - > data . txt . str [ i ] ) = = 0 ) ;
}
return status ;
2010-12-15 13:46:05 +03:00
case DNS_TYPE_PTR :
2012-03-01 17:23:00 +04:00
return dns_name_equal ( rec1 - > data . ptr , rec2 - > data . ptr ) ;
2010-12-15 13:46:05 +03:00
case DNS_TYPE_NS :
2010-12-21 12:53:11 +03:00
return dns_name_equal ( rec1 - > data . ns , rec2 - > data . ns ) ;
2010-12-15 13:46:05 +03:00
case DNS_TYPE_SRV :
return rec1 - > data . srv . wPriority = = rec2 - > data . srv . wPriority & &
rec1 - > data . srv . wWeight = = rec2 - > data . srv . wWeight & &
rec1 - > data . srv . wPort = = rec2 - > data . srv . wPort & &
2010-12-21 12:53:11 +03:00
dns_name_equal ( rec1 - > data . srv . nameTarget , rec2 - > data . srv . nameTarget ) ;
2010-12-15 13:46:05 +03:00
case DNS_TYPE_MX :
return rec1 - > data . mx . wPriority = = rec2 - > data . mx . wPriority & &
2010-12-21 12:53:11 +03:00
dns_name_equal ( rec1 - > data . mx . nameTarget , rec2 - > data . mx . nameTarget ) ;
2010-12-15 13:46:05 +03:00
case DNS_TYPE_HINFO :
return strcmp ( rec1 - > data . hinfo . cpu , rec2 - > data . hinfo . cpu ) = = 0 & &
strcmp ( rec1 - > data . hinfo . os , rec2 - > data . hinfo . os ) = = 0 ;
case DNS_TYPE_SOA :
2010-12-21 12:53:11 +03:00
return dns_name_equal ( rec1 - > data . soa . mname , rec2 - > data . soa . mname ) & &
dns_name_equal ( rec1 - > data . soa . rname , rec2 - > data . soa . rname ) & &
2010-12-15 13:46:05 +03:00
rec1 - > data . soa . serial = = rec2 - > data . soa . serial & &
rec1 - > data . soa . refresh = = rec2 - > data . soa . refresh & &
rec1 - > data . soa . retry = = rec2 - > data . soa . retry & &
rec1 - > data . soa . expire = = rec2 - > data . soa . expire & &
rec1 - > data . soa . minimum = = rec2 - > data . soa . minimum ;
default :
state - > log ( ISC_LOG_ERROR , " samba b9_putrr: unhandled record type %u " ,
rec1 - > wType ) ;
break ;
}
return false ;
}
2011-11-30 09:06:08 +04:00
/*
* Update session_info on samdb using the cached credentials
*/
static bool b9_set_session_info ( struct dlz_bind9_data * state , const char * name )
{
int ret ;
if ( state - > update_name = = NULL | | state - > session_info = = NULL ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: invalid credentials " ) ;
return false ;
}
2012-11-04 18:09:28 +04:00
/* Do not use client credentials, if we're not updating the client specified name */
2011-11-30 09:06:08 +04:00
if ( strcmp ( state - > update_name , name ) ! = 0 ) {
return true ;
}
ret = ldb_set_opaque ( state - > samdb , " sessionInfo " , state - > session_info ) ;
if ( ret ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: unable to set session info " ) ;
return false ;
}
return true ;
}
/*
* Reset session_info on samdb as system session
*/
static void b9_reset_session_info ( struct dlz_bind9_data * state )
{
ldb_set_opaque ( state - > samdb , " sessionInfo " , system_session ( state - > lp ) ) ;
}
2010-12-15 13:46:05 +03:00
/*
add or modify a rdataset
*/
2010-12-15 07:02:09 +03:00
_PUBLIC_ isc_result_t dlz_addrdataset ( const char * name , const char * rdatastr , void * dbdata , void * version )
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
2010-12-15 13:46:05 +03:00
struct dnsp_DnssrvRpcRecord * rec ;
struct ldb_dn * dn ;
isc_result_t result ;
struct ldb_result * res ;
const char * attrs [ ] = { " dnsRecord " , NULL } ;
int ret , i ;
struct ldb_message_element * el ;
enum ndr_err_code ndr_err ;
2010-12-22 04:13:44 +03:00
NTTIME t ;
2010-12-15 13:46:05 +03:00
if ( state - > transaction_token ! = ( void * ) version ) {
state - > log ( ISC_LOG_INFO , " samba_dlz: bad transaction version " ) ;
return ISC_R_FAILURE ;
}
rec = talloc_zero ( state , struct dnsp_DnssrvRpcRecord ) ;
if ( rec = = NULL ) {
return ISC_R_NOMEMORY ;
}
2010-12-22 04:13:44 +03:00
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 */
rec - > rank = DNS_RANK_ZONE ;
rec - > dwSerial = state - > soa_serial ;
rec - > dwTimeStamp = ( uint32_t ) t ;
2010-12-21 12:53:58 +03:00
2010-12-15 13:46:05 +03:00
if ( ! b9_parse ( state , rdatastr , rec ) ) {
state - > log ( ISC_LOG_INFO , " samba_dlz: failed to parse rdataset '%s' " , rdatastr ) ;
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
2010-12-15 07:02:09 +03:00
2010-12-15 13:46:05 +03:00
/* find the DN of the record */
result = b9_find_name_dn ( state , name , rec , & dn ) ;
if ( result ! = ISC_R_SUCCESS ) {
talloc_free ( rec ) ;
return result ;
}
/* get any existing records */
ret = ldb_search ( state - > samdb , rec , & res , dn , LDB_SCOPE_BASE , attrs , " objectClass=dnsNode " ) ;
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
2011-11-30 09:06:08 +04:00
if ( ! b9_set_session_info ( state , name ) ) {
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
2010-12-15 13:46:05 +03:00
result = b9_add_record ( state , name , dn , rec ) ;
2011-11-30 09:06:08 +04:00
b9_reset_session_info ( state ) ;
2010-12-15 13:46:05 +03:00
talloc_free ( rec ) ;
if ( result = = ISC_R_SUCCESS ) {
2012-02-02 02:27:28 +04:00
state - > log ( ISC_LOG_INFO , " samba_dlz: added %s %s " , name , rdatastr ) ;
2010-12-15 13:46:05 +03:00
}
return result ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL ) {
2012-02-27 10:09:10 +04:00
ret = ldb_msg_add_empty ( res - > msgs [ 0 ] , " dnsRecord " , LDB_FLAG_MOD_ADD , & el ) ;
if ( ret ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to add dnsRecord for %s " ,
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
2010-12-15 07:02:09 +03:00
}
2012-02-27 10:09:10 +04:00
/* there are existing records. We need to see if this will
* replace a record or add to it
*/
2010-12-15 13:46:05 +03:00
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec2 ;
2010-12-15 07:02:09 +03:00
2010-12-15 13:46:05 +03:00
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , rec , & rec2 ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to parse dnsRecord for %s " ,
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
if ( b9_record_match ( state , rec , & rec2 ) ) {
break ;
}
}
if ( i = = el - > num_values ) {
/* adding a new value */
el - > values = talloc_realloc ( el , el - > values , struct ldb_val , el - > num_values + 1 ) ;
if ( el - > values = = NULL ) {
talloc_free ( rec ) ;
return ISC_R_NOMEMORY ;
}
el - > num_values + + ;
}
ndr_err = ndr_push_struct_blob ( & el - > values [ i ] , rec , rec ,
( ndr_push_flags_fn_t ) ndr_push_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to push dnsRecord for %s " ,
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
2011-11-30 09:06:08 +04:00
if ( ! b9_set_session_info ( state , name ) ) {
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
2010-12-15 13:46:05 +03:00
/* modify the record */
el - > flags = LDB_FLAG_MOD_REPLACE ;
ret = ldb_modify ( state - > samdb , res - > msgs [ 0 ] ) ;
2011-11-30 09:06:08 +04:00
b9_reset_session_info ( state ) ;
2010-12-15 13:46:05 +03:00
if ( ret ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to modify %s - %s " ,
ldb_dn_get_linearized ( dn ) , ldb_errstring ( state - > samdb ) ) ;
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
state - > log ( ISC_LOG_INFO , " samba_dlz: added rdataset %s '%s' " , name , rdatastr ) ;
talloc_free ( rec ) ;
2010-12-15 07:02:09 +03:00
return ISC_R_SUCCESS ;
}
2010-12-15 13:46:05 +03:00
/*
remove a rdataset
*/
2010-12-15 07:02:09 +03:00
_PUBLIC_ isc_result_t dlz_subrdataset ( const char * name , const char * rdatastr , void * dbdata , void * version )
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
2010-12-15 13:46:05 +03:00
struct dnsp_DnssrvRpcRecord * rec ;
struct ldb_dn * dn ;
isc_result_t result ;
struct ldb_result * res ;
const char * attrs [ ] = { " dnsRecord " , NULL } ;
int ret , i ;
struct ldb_message_element * el ;
enum ndr_err_code ndr_err ;
if ( state - > transaction_token ! = ( void * ) version ) {
2012-02-02 02:27:28 +04:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: bad transaction version " ) ;
2010-12-15 13:46:05 +03:00
return ISC_R_FAILURE ;
}
2010-12-15 07:02:09 +03:00
2010-12-15 13:46:05 +03:00
rec = talloc_zero ( state , struct dnsp_DnssrvRpcRecord ) ;
if ( rec = = NULL ) {
return ISC_R_NOMEMORY ;
}
if ( ! b9_parse ( state , rdatastr , rec ) ) {
2012-02-02 02:27:28 +04:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to parse rdataset '%s' " , rdatastr ) ;
2010-12-15 13:46:05 +03:00
talloc_free ( rec ) ;
2010-12-15 07:02:09 +03:00
return ISC_R_FAILURE ;
}
2010-12-15 13:46:05 +03:00
/* find the DN of the record */
result = b9_find_name_dn ( state , name , rec , & dn ) ;
if ( result ! = ISC_R_SUCCESS ) {
talloc_free ( rec ) ;
return result ;
}
/* get the existing records */
ret = ldb_search ( state - > samdb , rec , & res , dn , LDB_SCOPE_BASE , attrs , " objectClass=dnsNode " ) ;
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
talloc_free ( rec ) ;
return ISC_R_NOTFOUND ;
}
2010-12-15 07:02:09 +03:00
2010-12-15 13:46:05 +03:00
/* there are existing records. We need to see if any match
*/
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL | | el - > num_values = = 0 ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: no dnsRecord attribute for %s " ,
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec2 ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , rec , & rec2 ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to parse dnsRecord for %s " ,
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
if ( b9_record_match ( state , rec , & rec2 ) ) {
break ;
}
}
if ( i = = el - > num_values ) {
talloc_free ( rec ) ;
return ISC_R_NOTFOUND ;
}
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 - - ;
2011-11-30 09:06:08 +04:00
if ( ! b9_set_session_info ( state , name ) ) {
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
2010-12-15 13:46:05 +03:00
if ( el - > num_values = = 0 ) {
2012-02-27 10:09:10 +04:00
el - > flags = LDB_FLAG_MOD_DELETE ;
} else {
el - > flags = LDB_FLAG_MOD_REPLACE ;
2010-12-15 13:46:05 +03:00
}
2012-02-09 03:17:02 +04:00
ret = ldb_modify ( state - > samdb , res - > msgs [ 0 ] ) ;
2011-11-30 09:06:08 +04:00
b9_reset_session_info ( state ) ;
2010-12-15 13:46:05 +03:00
if ( ret ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to modify %s - %s " ,
ldb_dn_get_linearized ( dn ) , ldb_errstring ( state - > samdb ) ) ;
talloc_free ( rec ) ;
return ISC_R_FAILURE ;
}
state - > log ( ISC_LOG_INFO , " samba_dlz: subtracted rdataset %s '%s' " , name , rdatastr ) ;
talloc_free ( rec ) ;
2010-12-15 07:02:09 +03:00
return ISC_R_SUCCESS ;
}
2010-12-15 13:46:05 +03:00
/*
delete all records of the given type
*/
_PUBLIC_ isc_result_t dlz_delrdataset ( const char * name , const char * type , void * dbdata , void * version )
2010-12-15 07:02:09 +03:00
{
struct dlz_bind9_data * state = talloc_get_type_abort ( dbdata , struct dlz_bind9_data ) ;
2010-12-15 13:46:05 +03:00
TALLOC_CTX * tmp_ctx ;
struct ldb_dn * dn ;
isc_result_t result ;
struct ldb_result * res ;
const char * attrs [ ] = { " dnsRecord " , NULL } ;
int ret , i ;
struct ldb_message_element * el ;
enum ndr_err_code ndr_err ;
enum dns_record_type dns_type ;
bool found = false ;
if ( state - > transaction_token ! = ( void * ) version ) {
2012-02-02 02:27:28 +04:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: bad transaction version " ) ;
2010-12-15 13:46:05 +03:00
return ISC_R_FAILURE ;
}
2011-01-13 03:10:27 +03:00
if ( ! b9_dns_type ( type , & dns_type ) ) {
2012-02-02 02:27:28 +04:00
state - > log ( ISC_LOG_ERROR , " samba_dlz: bad dns type %s in delete " , type ) ;
2010-12-15 13:46:05 +03:00
return ISC_R_FAILURE ;
}
tmp_ctx = talloc_new ( state ) ;
/* find the DN of the record */
result = b9_find_name_dn ( state , name , tmp_ctx , & dn ) ;
if ( result ! = ISC_R_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return result ;
}
/* get the existing records */
ret = ldb_search ( state - > samdb , tmp_ctx , & res , dn , LDB_SCOPE_BASE , attrs , " objectClass=dnsNode " ) ;
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOTFOUND ;
}
/* there are existing records. We need to see if any match the type
*/
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " dnsRecord " ) ;
if ( el = = NULL | | el - > num_values = = 0 ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_NOTFOUND ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dnsp_DnssrvRpcRecord rec2 ;
2010-12-15 07:02:09 +03:00
2010-12-15 13:46:05 +03:00
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] , tmp_ctx , & rec2 ,
( ndr_pull_flags_fn_t ) ndr_pull_dnsp_DnssrvRpcRecord ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to parse dnsRecord for %s " ,
ldb_dn_get_linearized ( dn ) ) ;
talloc_free ( tmp_ctx ) ;
return ISC_R_FAILURE ;
}
if ( dns_type = = rec2 . wType ) {
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 - - ;
i - - ;
found = true ;
}
}
if ( ! found ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_FAILURE ;
}
2011-11-30 09:06:08 +04:00
if ( ! b9_set_session_info ( state , name ) ) {
talloc_free ( tmp_ctx ) ;
return ISC_R_FAILURE ;
}
2010-12-15 13:46:05 +03:00
if ( el - > num_values = = 0 ) {
2012-02-27 10:09:10 +04:00
el - > flags = LDB_FLAG_MOD_DELETE ;
} else {
el - > flags = LDB_FLAG_MOD_REPLACE ;
2010-12-15 13:46:05 +03:00
}
2012-02-09 03:17:02 +04:00
ret = ldb_modify ( state - > samdb , res - > msgs [ 0 ] ) ;
2011-11-30 09:06:08 +04:00
b9_reset_session_info ( state ) ;
2010-12-15 13:46:05 +03:00
if ( ret ! = LDB_SUCCESS ) {
state - > log ( ISC_LOG_ERROR , " samba_dlz: failed to delete type %s in %s - %s " ,
type , ldb_dn_get_linearized ( dn ) , ldb_errstring ( state - > samdb ) ) ;
talloc_free ( tmp_ctx ) ;
2010-12-15 07:02:09 +03:00
return ISC_R_FAILURE ;
}
2010-12-15 13:46:05 +03:00
state - > log ( ISC_LOG_INFO , " samba_dlz: deleted rdataset %s of type %s " , name , type ) ;
2010-12-15 07:02:09 +03:00
2010-12-15 13:46:05 +03:00
talloc_free ( tmp_ctx ) ;
2010-12-15 07:02:09 +03:00
return ISC_R_SUCCESS ;
}