2010-10-01 23:59:22 +04:00
/*
Unix SMB / CIFS implementation .
DNS server handler for queries
Copyright ( C ) 2010 Kai Blin < kai @ samba . org >
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"
2012-03-27 17:00:01 +04:00
# include "smbd/service_task.h"
2010-10-12 01:39:44 +04:00
# include "libcli/util/werror.h"
2010-10-01 23:59:22 +04:00
# include "librpc/ndr/libndr.h"
# include "librpc/gen_ndr/ndr_dns.h"
# include "librpc/gen_ndr/ndr_dnsp.h"
# include <ldb.h>
2012-03-27 17:00:01 +04:00
# include "param/param.h"
2010-10-01 23:59:22 +04:00
# include "dsdb/samdb/samdb.h"
# include "dsdb/common/util.h"
# include "dns_server/dns_server.h"
2012-03-27 10:42:22 +04:00
# include "libcli/dns/libdns.h"
2012-03-27 17:00:01 +04:00
# include "lib/util/util_net.h"
2012-05-24 15:49:41 +04:00
# include "lib/util/tevent_werror.h"
2012-08-30 11:04:07 +04:00
# include "auth/auth.h"
# include "auth/credentials/credentials.h"
# include "auth/gensec/gensec.h"
2010-10-01 23:59:22 +04:00
2011-09-28 04:36:42 +04:00
static WERROR create_response_rr ( const struct dns_name_question * question ,
const struct dnsp_DnssrvRpcRecord * rec ,
struct dns_res_rec * * answers , uint16_t * ancount )
{
struct dns_res_rec * ans = * answers ;
uint16_t ai = * ancount ;
2012-03-11 02:47:29 +04:00
char * tmp ;
uint32_t i ;
2011-09-28 04:36:42 +04:00
ZERO_STRUCT ( ans [ ai ] ) ;
switch ( rec - > wType ) {
case DNS_QTYPE_CNAME :
ans [ ai ] . rdata . cname_record = talloc_strdup ( ans , rec - > data . cname ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . cname_record ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_QTYPE_A :
ans [ ai ] . rdata . ipv4_record = talloc_strdup ( ans , rec - > data . ipv4 ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . ipv4_record ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_QTYPE_AAAA :
2012-05-30 02:23:14 +04:00
ans [ ai ] . rdata . ipv6_record = talloc_strdup ( ans , rec - > data . ipv6 ) ;
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . ipv6_record ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_TYPE_NS :
2012-05-30 02:23:33 +04:00
ans [ ai ] . rdata . ns_record = talloc_strdup ( ans , rec - > data . ns ) ;
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . ns_record ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_QTYPE_SRV :
ans [ ai ] . rdata . srv_record . priority = rec - > data . srv . wPriority ;
ans [ ai ] . rdata . srv_record . weight = rec - > data . srv . wWeight ;
ans [ ai ] . rdata . srv_record . port = rec - > data . srv . wPort ;
2012-05-29 17:20:21 +04:00
ans [ ai ] . rdata . srv_record . target = talloc_strdup (
ans , rec - > data . srv . nameTarget ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . srv_record . target ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_QTYPE_SOA :
2012-05-29 17:20:21 +04:00
ans [ ai ] . rdata . soa_record . mname = talloc_strdup (
ans , rec - > data . soa . mname ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . soa_record . mname ) ;
2012-05-29 17:20:21 +04:00
ans [ ai ] . rdata . soa_record . rname = talloc_strdup (
ans , rec - > data . soa . rname ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . soa_record . rname ) ;
2011-09-28 04:36:42 +04:00
ans [ ai ] . rdata . soa_record . serial = rec - > data . soa . serial ;
ans [ ai ] . rdata . soa_record . refresh = rec - > data . soa . refresh ;
ans [ ai ] . rdata . soa_record . retry = rec - > data . soa . retry ;
ans [ ai ] . rdata . soa_record . expire = rec - > data . soa . expire ;
ans [ ai ] . rdata . soa_record . minimum = rec - > data . soa . minimum ;
break ;
2012-03-09 13:43:27 +04:00
case DNS_QTYPE_PTR :
ans [ ai ] . rdata . ptr_record = talloc_strdup ( ans , rec - > data . ptr ) ;
break ;
2012-03-11 02:47:29 +04:00
case DNS_QTYPE_TXT :
tmp = talloc_asprintf ( ans , " \" %s \" " , rec - > data . txt . str [ 0 ] ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( tmp ) ;
2012-03-11 02:47:29 +04:00
for ( i = 1 ; i < rec - > data . txt . count ; i + + ) {
2012-05-24 16:57:49 +04:00
tmp = talloc_asprintf_append_buffer (
tmp , " \" %s \" " , rec - > data . txt . str [ i ] ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( tmp ) ;
2012-03-11 02:47:29 +04:00
}
ans [ ai ] . rdata . txt_record . txt = tmp ;
break ;
2011-09-28 04:36:42 +04:00
default :
2012-03-11 02:47:29 +04:00
DEBUG ( 0 , ( " Got unhandled type %u query. \n " , rec - > wType ) ) ;
2011-09-28 04:36:42 +04:00
return DNS_ERR ( NOT_IMPLEMENTED ) ;
}
ans [ ai ] . name = talloc_strdup ( ans , question - > name ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . name ) ;
2011-09-28 04:36:42 +04:00
ans [ ai ] . rr_type = rec - > wType ;
ans [ ai ] . rr_class = DNS_QCLASS_IN ;
ans [ ai ] . ttl = rec - > dwTtlSeconds ;
ans [ ai ] . length = UINT16_MAX ;
ai + + ;
* answers = ans ;
* ancount = ai ;
return WERR_OK ;
}
2012-05-24 15:49:41 +04:00
struct ask_forwarder_state {
struct tevent_context * ev ;
uint16_t id ;
struct dns_name_packet in_packet ;
} ;
static void ask_forwarder_done ( struct tevent_req * subreq ) ;
static struct tevent_req * ask_forwarder_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
const char * forwarder , struct dns_name_question * question )
2012-03-27 10:42:22 +04:00
{
2012-05-24 15:49:41 +04:00
struct tevent_req * req , * subreq ;
struct ask_forwarder_state * state ;
struct dns_name_packet out_packet = { 0 , } ;
DATA_BLOB out_blob ;
2012-03-27 10:42:22 +04:00
enum ndr_err_code ndr_err ;
2012-05-24 15:49:41 +04:00
req = tevent_req_create ( mem_ctx , & state , struct ask_forwarder_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
generate_random_buffer ( ( uint8_t * ) & state - > id , sizeof ( state - > id ) ) ;
2012-03-27 17:00:01 +04:00
if ( ! is_ipaddress ( forwarder ) ) {
DEBUG ( 0 , ( " Invalid 'dns forwarder' setting '%s', needs to be "
" an IP address \n " , forwarder ) ) ;
2012-05-24 15:49:41 +04:00
tevent_req_werror ( req , DNS_ERR ( NAME_ERROR ) ) ;
return tevent_req_post ( req , ev ) ;
2012-03-27 17:00:01 +04:00
}
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
out_packet . id = state - > id ;
out_packet . operation | = DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED ;
out_packet . qdcount = 1 ;
out_packet . questions = question ;
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
ndr_err = ndr_push_struct_blob (
& out_blob , state , & out_packet ,
( ndr_push_flags_fn_t ) ndr_push_dns_name_packet ) ;
2012-03-27 10:42:22 +04:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2012-05-24 15:49:41 +04:00
tevent_req_werror ( req , DNS_ERR ( SERVER_FAILURE ) ) ;
return tevent_req_post ( req , ev ) ;
2012-03-27 10:42:22 +04:00
}
2012-05-24 15:49:41 +04:00
subreq = dns_udp_request_send ( state , ev , forwarder , out_blob . data ,
out_blob . length ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2012-03-27 10:42:22 +04:00
}
2012-05-24 15:49:41 +04:00
tevent_req_set_callback ( subreq , ask_forwarder_done , req ) ;
return req ;
}
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
static void ask_forwarder_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct ask_forwarder_state * state = tevent_req_data (
req , struct ask_forwarder_state ) ;
DATA_BLOB in_blob ;
enum ndr_err_code ndr_err ;
WERROR ret ;
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
ret = dns_udp_request_recv ( subreq , state ,
& in_blob . data , & in_blob . length ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_werror ( req , ret ) ) {
return ;
}
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
ndr_err = ndr_pull_struct_blob (
& in_blob , state , & state - > in_packet ,
( ndr_pull_flags_fn_t ) ndr_pull_dns_name_packet ) ;
2012-03-27 10:42:22 +04:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2012-05-24 15:49:41 +04:00
tevent_req_werror ( req , DNS_ERR ( SERVER_FAILURE ) ) ;
return ;
2012-03-27 10:42:22 +04:00
}
2012-05-24 15:49:41 +04:00
if ( state - > in_packet . id ! = state - > id ) {
tevent_req_werror ( req , DNS_ERR ( NAME_ERROR ) ) ;
return ;
}
tevent_req_done ( req ) ;
}
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
static WERROR ask_forwarder_recv (
struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct dns_res_rec * * answers , uint16_t * ancount ,
struct dns_res_rec * * nsrecs , uint16_t * nscount ,
struct dns_res_rec * * additional , uint16_t * arcount )
{
struct ask_forwarder_state * state = tevent_req_data (
req , struct ask_forwarder_state ) ;
struct dns_name_packet * in_packet = & state - > in_packet ;
WERROR err ;
if ( tevent_req_is_werror ( req , & err ) ) {
return err ;
2012-03-27 10:42:22 +04:00
}
* ancount = in_packet - > ancount ;
* answers = talloc_move ( mem_ctx , & in_packet - > answers ) ;
* nscount = in_packet - > nscount ;
* nsrecs = talloc_move ( mem_ctx , & in_packet - > nsrecs ) ;
* arcount = in_packet - > arcount ;
* additional = talloc_move ( mem_ctx , & in_packet - > additional ) ;
2012-05-24 15:49:41 +04:00
return WERR_OK ;
}
2010-10-12 01:39:44 +04:00
static WERROR handle_question ( struct dns_server * dns ,
TALLOC_CTX * mem_ctx ,
const struct dns_name_question * question ,
struct dns_res_rec * * answers , uint16_t * ancount )
2010-10-01 23:59:22 +04:00
{
2012-06-01 10:05:54 +04:00
struct dns_res_rec * ans = * answers ;
2010-10-12 01:39:44 +04:00
WERROR werror ;
2010-10-23 17:52:34 +04:00
unsigned int ri ;
2010-10-01 23:59:22 +04:00
struct dnsp_DnssrvRpcRecord * recs ;
2012-06-01 10:05:54 +04:00
uint16_t rec_count , ai = * ancount ;
2011-12-16 12:43:47 +04:00
struct ldb_dn * dn = NULL ;
2010-10-01 23:59:22 +04:00
2010-10-12 01:39:44 +04:00
werror = dns_name2dn ( dns , mem_ctx , question - > name , & dn ) ;
W_ERROR_NOT_OK_RETURN ( werror ) ;
2010-10-01 23:59:22 +04:00
2011-12-16 12:43:47 +04:00
werror = dns_lookup_records ( dns , mem_ctx , dn , & recs , & rec_count ) ;
W_ERROR_NOT_OK_RETURN ( werror ) ;
2010-10-01 23:59:22 +04:00
2012-06-01 10:05:54 +04:00
ans = talloc_realloc ( mem_ctx , ans , struct dns_res_rec , rec_count + ai ) ;
if ( ans = = NULL ) {
return WERR_NOMEM ;
}
2010-10-01 23:59:22 +04:00
2011-12-16 12:43:47 +04:00
for ( ri = 0 ; ri < rec_count ; ri + + ) {
2012-06-01 10:05:54 +04:00
if ( ( recs [ ri ] . wType = = DNS_TYPE_CNAME ) & &
( ( question - > question_type = = DNS_QTYPE_A ) | |
( question - > question_type = = DNS_QTYPE_AAAA ) ) ) {
struct dns_name_question * new_q =
talloc ( mem_ctx , struct dns_name_question ) ;
if ( new_q = = NULL ) {
return WERR_NOMEM ;
}
/* We reply with one more record, so grow the array */
ans = talloc_realloc ( mem_ctx , ans , struct dns_res_rec ,
rec_count + 1 ) ;
if ( ans = = NULL ) {
TALLOC_FREE ( new_q ) ;
return WERR_NOMEM ;
}
/* First put in the CNAME record */
werror = create_response_rr ( question , & recs [ ri ] , & ans , & ai ) ;
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
/* And then look up the name it points at.. */
/* First build up the new question */
new_q - > question_type = question - > question_type ;
new_q - > question_class = question - > question_class ;
if ( new_q - > question_type = = DNS_QTYPE_A ) {
new_q - > name = talloc_strdup ( new_q , recs [ ri ] . data . ipv4 ) ;
} else if ( new_q - > question_type = = DNS_QTYPE_AAAA ) {
new_q - > name = talloc_strdup ( new_q , recs [ ri ] . data . ipv6 ) ;
}
if ( new_q - > name = = NULL ) {
TALLOC_FREE ( new_q ) ;
return WERR_NOMEM ;
}
/* and then call the lookup again */
werror = handle_question ( dns , mem_ctx , new_q , & ans , & ai ) ;
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
continue ;
}
2011-09-28 04:36:42 +04:00
if ( ( question - > question_type ! = DNS_QTYPE_ALL ) & &
( recs [ ri ] . wType ! = question - > question_type ) ) {
continue ;
2010-10-01 23:59:22 +04:00
}
2012-03-09 13:43:27 +04:00
werror = create_response_rr ( question , & recs [ ri ] , & ans , & ai ) ;
2012-06-01 10:05:54 +04:00
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
2010-10-01 23:59:22 +04:00
}
2011-12-16 12:43:47 +04:00
if ( ai = = 0 ) {
2010-10-12 01:39:44 +04:00
return DNS_ERR ( NAME_ERROR ) ;
2010-10-01 23:59:22 +04:00
}
* ancount = ai ;
* answers = ans ;
2010-10-12 01:39:44 +04:00
return WERR_OK ;
2010-10-01 23:59:22 +04:00
}
2012-09-05 13:07:55 +04:00
static NTSTATUS accept_gss_ticket ( TALLOC_CTX * mem_ctx ,
struct dns_server * dns ,
struct dns_server_tkey * tkey ,
const DATA_BLOB * key ,
DATA_BLOB * reply ,
uint16_t * dns_auth_error )
{
NTSTATUS status ;
status = gensec_update ( tkey - > gensec , mem_ctx , dns - > task - > event_ctx ,
* key , reply ) ;
if ( NT_STATUS_EQUAL ( NT_STATUS_MORE_PROCESSING_REQUIRED , status ) ) {
* dns_auth_error = DNS_RCODE_OK ;
return status ;
}
if ( NT_STATUS_IS_OK ( status ) ) {
status = gensec_session_info ( tkey - > gensec , tkey , & tkey - > session_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
* dns_auth_error = DNS_RCODE_BADKEY ;
return status ;
}
* dns_auth_error = DNS_RCODE_OK ;
}
return status ;
}
static struct dns_server_tkey * find_tkey ( struct dns_server_tkey_store * store ,
const char * name )
{
struct dns_server_tkey * tkey = NULL ;
uint16_t i = 0 ;
do {
struct dns_server_tkey * tmp_key = store - > tkeys [ i ] ;
i + + ;
i % = TKEY_BUFFER_SIZE ;
if ( tmp_key = = NULL ) {
continue ;
}
if ( dns_name_equal ( name , tmp_key - > name ) ) {
tkey = tmp_key ;
break ;
}
} while ( i ! = 0 ) ;
return tkey ;
}
2012-08-31 15:41:19 +04:00
static NTSTATUS create_tkey ( struct dns_server * dns ,
const char * name ,
struct dns_server_tkey * * tkey )
2012-08-30 11:04:07 +04:00
{
NTSTATUS status ;
2012-08-31 15:41:19 +04:00
struct dns_server_tkey_store * store = dns - > tkeys ;
struct dns_server_tkey * k = talloc_zero ( store , struct dns_server_tkey ) ;
2012-08-30 11:04:07 +04:00
if ( k = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-08-31 15:41:19 +04:00
k - > name = talloc_strdup ( k , name ) ;
2012-08-30 11:04:07 +04:00
if ( k - > name = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = samba_server_gensec_start ( k ,
dns - > task - > event_ctx ,
dns - > task - > msg_ctx ,
dns - > task - > lp_ctx ,
dns - > server_credentials ,
" dns " ,
& k - > gensec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to start GENSEC server code: %s \n " , nt_errstr ( status ) ) ) ;
* tkey = NULL ;
return status ;
}
gensec_want_feature ( k - > gensec , GENSEC_FEATURE_SIGN ) ;
status = gensec_start_mech_by_oid ( k - > gensec , GENSEC_OID_SPNEGO ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to start GENSEC server code: %s \n " ,
nt_errstr ( status ) ) ) ;
* tkey = NULL ;
return status ;
}
2012-08-31 15:41:19 +04:00
if ( store - > tkeys [ store - > next_idx ] ! = NULL ) {
TALLOC_FREE ( store - > tkeys [ store - > next_idx ] ) ;
2012-08-30 11:04:07 +04:00
}
2012-08-31 15:41:19 +04:00
store - > tkeys [ store - > next_idx ] = k ;
( store - > next_idx ) + + ;
store - > next_idx % = store - > size ;
2012-08-30 11:04:07 +04:00
2012-08-31 15:41:19 +04:00
* tkey = k ;
return NT_STATUS_OK ;
2012-08-30 11:04:07 +04:00
}
static WERROR handle_tkey ( struct dns_server * dns ,
TALLOC_CTX * mem_ctx ,
const struct dns_name_packet * in ,
struct dns_res_rec * * answers ,
uint16_t * ancount )
{
struct dns_res_rec * in_tkey = NULL ;
struct dns_res_rec * ret_tkey ;
uint16_t i ;
for ( i = 0 ; i < in - > arcount ; i + + ) {
if ( in - > additional [ i ] . rr_type = = DNS_QTYPE_TKEY ) {
in_tkey = & in - > additional [ i ] ;
break ;
}
}
/* If this is a TKEY query, it should have a TKEY RR.
* Behaviour is not really specified in RFC 2930 or RFC 3645 , but
* FORMAT_ERROR seems to be what BIND uses . */
if ( in_tkey = = NULL ) {
return DNS_ERR ( FORMAT_ERROR ) ;
}
ret_tkey = talloc_zero ( mem_ctx , struct dns_res_rec ) ;
if ( ret_tkey = = NULL ) {
return WERR_NOMEM ;
}
ret_tkey - > name = talloc_strdup ( ret_tkey , in_tkey - > name ) ;
if ( ret_tkey - > name = = NULL ) {
return WERR_NOMEM ;
}
ret_tkey - > rr_type = DNS_QTYPE_TKEY ;
ret_tkey - > rr_class = DNS_QCLASS_ANY ;
ret_tkey - > length = UINT16_MAX ;
2012-09-05 13:07:55 +04:00
ret_tkey - > rdata . tkey_record . algorithm = talloc_strdup ( ret_tkey , ret_tkey - > name ) ;
2012-08-30 11:04:07 +04:00
if ( ret_tkey - > rdata . tkey_record . algorithm = = NULL ) {
return WERR_NOMEM ;
}
ret_tkey - > rdata . tkey_record . inception = in_tkey - > rdata . tkey_record . inception ;
ret_tkey - > rdata . tkey_record . expiration = in_tkey - > rdata . tkey_record . expiration ;
ret_tkey - > rdata . tkey_record . mode = in_tkey - > rdata . tkey_record . mode ;
switch ( in_tkey - > rdata . tkey_record . mode ) {
case DNS_TKEY_MODE_DH :
/* FIXME: According to RFC 2930, we MUST support this, but we don't.
* Still , claim it ' s a bad key instead of a bad mode */
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADKEY ;
break ;
case DNS_TKEY_MODE_GSSAPI : {
NTSTATUS status ;
struct dns_server_tkey * tkey ;
DATA_BLOB key ;
DATA_BLOB reply ;
2012-09-05 13:07:55 +04:00
tkey = find_tkey ( dns - > tkeys , in - > questions [ 0 ] . name ) ;
2012-08-30 11:04:07 +04:00
if ( tkey ! = NULL & & tkey - > complete ) {
/* TODO: check if the key is still valid */
DEBUG ( 1 , ( " Rejecting tkey negotiation for already established key \n " ) ) ;
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADNAME ;
break ;
}
if ( tkey = = NULL ) {
2012-08-31 15:41:19 +04:00
status = create_tkey ( dns , in - > questions [ 0 ] . name ,
& tkey ) ;
2012-08-30 11:04:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADKEY ;
return ntstatus_to_werror ( status ) ;
}
}
key . data = in_tkey - > rdata . tkey_record . key_data ;
key . length = in_tkey - > rdata . tkey_record . key_size ;
status = accept_gss_ticket ( ret_tkey , dns , tkey , & key , & reply ,
& ret_tkey - > rdata . tkey_record . error ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
DEBUG ( 1 , ( " More processing required \n " ) ) ;
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADKEY ;
} else if ( NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Tkey handshake completed \n " ) ) ;
} else {
DEBUG ( 0 , ( " GSS key negotiation returned %s \n " , nt_errstr ( status ) ) ) ;
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADKEY ;
}
break ;
}
case DNS_TKEY_MODE_DELETE :
/* TODO: implement me */
DEBUG ( 1 , ( " Should delete tkey here \n " ) ) ;
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_OK ;
break ;
case DNS_TKEY_MODE_NULL :
case DNS_TKEY_MODE_SERVER :
case DNS_TKEY_MODE_CLIENT :
case DNS_TKEY_MODE_LAST :
/* We don't have to implement these, return a mode error */
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADMODE ;
break ;
default :
DEBUG ( 1 , ( " Unsupported TKEY mode %d \n " ,
in_tkey - > rdata . tkey_record . mode ) ) ;
}
* answers = ret_tkey ;
* ancount = 1 ;
return WERR_OK ;
}
2012-05-24 16:53:47 +04:00
struct dns_server_process_query_state {
struct dns_res_rec * answers ;
uint16_t ancount ;
struct dns_res_rec * nsrecs ;
uint16_t nscount ;
struct dns_res_rec * additional ;
uint16_t arcount ;
} ;
static void dns_server_process_query_got_response ( struct tevent_req * subreq ) ;
2012-05-24 19:02:57 +04:00
struct tevent_req * dns_server_process_query_send (
2012-05-24 16:53:47 +04:00
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct dns_server * dns , struct dns_request_state * req_state ,
const struct dns_name_packet * in )
2010-10-01 23:59:22 +04:00
{
2012-05-24 16:53:47 +04:00
struct tevent_req * req , * subreq ;
struct dns_server_process_query_state * state ;
2010-10-01 23:59:22 +04:00
2012-05-24 16:53:47 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct dns_server_process_query_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2011-09-27 09:31:46 +04:00
if ( in - > qdcount ! = 1 ) {
2012-05-24 16:53:47 +04:00
tevent_req_werror ( req , DNS_ERR ( FORMAT_ERROR ) ) ;
return tevent_req_post ( req , ev ) ;
2011-09-27 09:31:46 +04:00
}
2011-09-28 05:05:38 +04:00
/* Windows returns NOT_IMPLEMENTED on this as well */
if ( in - > questions [ 0 ] . question_class = = DNS_QCLASS_NONE ) {
2012-05-24 16:53:47 +04:00
tevent_req_werror ( req , DNS_ERR ( NOT_IMPLEMENTED ) ) ;
return tevent_req_post ( req , ev ) ;
2011-09-28 05:05:38 +04:00
}
2012-08-30 11:04:07 +04:00
if ( in - > questions [ 0 ] . question_type = = DNS_QTYPE_TKEY ) {
WERROR err ;
2012-09-05 13:07:55 +04:00
err = handle_tkey ( dns , state , in , & state - > answers ,
& state - > ancount ) ;
2012-08-30 11:04:07 +04:00
if ( tevent_req_werror ( req , err ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
2012-03-27 15:36:16 +04:00
if ( dns_authorative_for_zone ( dns , in - > questions [ 0 ] . name ) ) {
2012-05-24 16:53:47 +04:00
WERROR err ;
req_state - > flags | = DNS_FLAG_AUTHORITATIVE ;
err = handle_question ( dns , state , & in - > questions [ 0 ] ,
& state - > answers , & state - > ancount ) ;
if ( tevent_req_werror ( req , err ) ) {
return tevent_req_post ( req , ev ) ;
2012-03-27 17:00:01 +04:00
}
2012-05-24 16:53:47 +04:00
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
2012-03-27 10:42:22 +04:00
}
2010-10-01 23:59:22 +04:00
2012-05-24 16:53:47 +04:00
if ( ( req_state - > flags & DNS_FLAG_RECURSION_DESIRED ) & &
( req_state - > flags & DNS_FLAG_RECURSION_AVAIL ) ) {
DEBUG ( 2 , ( " Not authoritative for '%s', forwarding \n " ,
in - > questions [ 0 ] . name ) ) ;
subreq = ask_forwarder_send (
state , ev , lpcfg_dns_forwarder ( dns - > task - > lp_ctx ) ,
& in - > questions [ 0 ] ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback (
subreq , dns_server_process_query_got_response , req ) ;
return req ;
}
tevent_req_werror ( req , DNS_ERR ( NAME_ERROR ) ) ;
return tevent_req_post ( req , ev ) ;
}
2010-10-01 23:59:22 +04:00
2012-05-24 16:53:47 +04:00
static void dns_server_process_query_got_response ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct dns_server_process_query_state * state = tevent_req_data (
req , struct dns_server_process_query_state ) ;
WERROR err ;
err = ask_forwarder_recv ( subreq , state ,
& state - > answers , & state - > ancount ,
& state - > nsrecs , & state - > nscount ,
& state - > additional , & state - > arcount ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_werror ( req , err ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2010-10-01 23:59:22 +04:00
2012-05-24 19:02:57 +04:00
WERROR dns_server_process_query_recv (
2012-05-24 16:53:47 +04:00
struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct dns_res_rec * * answers , uint16_t * ancount ,
struct dns_res_rec * * nsrecs , uint16_t * nscount ,
struct dns_res_rec * * additional , uint16_t * arcount )
{
struct dns_server_process_query_state * state = tevent_req_data (
req , struct dns_server_process_query_state ) ;
WERROR err ;
2010-10-01 23:59:22 +04:00
2012-05-24 16:53:47 +04:00
if ( tevent_req_is_werror ( req , & err ) ) {
return err ;
}
* answers = talloc_move ( mem_ctx , & state - > answers ) ;
* ancount = state - > ancount ;
* nsrecs = talloc_move ( mem_ctx , & state - > nsrecs ) ;
* nscount = state - > nscount ;
* additional = talloc_move ( mem_ctx , & state - > additional ) ;
* arcount = state - > arcount ;
2010-10-12 01:39:44 +04:00
return WERR_OK ;
2012-05-24 16:53:47 +04:00
}