2006-08-24 19:43:32 +04:00
/*
Public Interface file for Linux DNS client library implementation
Copyright ( C ) 2006 Krishna Ganugapati < krishnag @ centeris . com >
Copyright ( C ) 2006 Gerald Carter < jerry @ samba . org >
* * NOTE ! The following LGPL license applies to the libaddns
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2.1 of the License , or ( at your option ) any later version .
This library 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
2007-07-10 07:52:17 +04:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2006-08-24 19:43:32 +04:00
*/
2024-03-07 14:03:05 +03:00
# include "replace.h"
# include <talloc.h>
# include "lib/util/talloc_stack.h"
# include "lib/util/data_blob.h"
# include "lib/util/time.h"
# include "lib/util/charset/charset.h"
# include "libcli/util/ntstatus.h"
# include "auth/gensec/gensec.h"
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
# include "dns.h"
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
static DNS_ERROR dns_negotiate_gss_ctx_int ( struct dns_connection * conn ,
const char * keyname ,
struct gensec_security * gensec ,
enum dns_ServerType srv_type )
2006-08-24 19:43:32 +04:00
{
2024-03-07 14:03:05 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2016-04-22 03:35:37 +03:00
struct dns_request * req = NULL ;
struct dns_buffer * buf = NULL ;
2024-03-07 14:03:05 +03:00
DATA_BLOB in = { . length = 0 , } ;
DATA_BLOB out = { . length = 0 , } ;
NTSTATUS status ;
2006-11-18 00:46:26 +03:00
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
do {
2024-03-07 14:03:05 +03:00
status = gensec_update ( gensec , frame , in , & out ) ;
data_blob_free ( & in ) ;
if ( GENSEC_UPDATE_IS_NTERROR ( status ) ) {
err = ERROR_DNS_GSS_ERROR ;
goto error ;
2006-08-24 19:43:32 +04:00
}
2024-03-07 14:03:05 +03:00
if ( out . length ! = 0 ) {
2006-11-18 00:46:26 +03:00
struct dns_rrec * rec ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
time_t t = time ( NULL ) ;
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
err = dns_create_query ( frame , keyname , QTYPE_TKEY ,
2006-11-18 00:46:26 +03:00
DNS_CLASS_IN , & req ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_create_tkey_record (
req , keyname , " gss.microsoft.com " , t ,
t + 86400 , DNS_TKEY_MODE_GSSAPI , 0 ,
2024-03-07 14:03:05 +03:00
out . length , out . data ,
2006-12-14 19:27:45 +03:00
& rec ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-12-14 19:27:45 +03:00
/* Windows 2000 DNS is broken and requires the
TKEY payload in the Answer section instead
2018-06-15 15:56:57 +03:00
of the Additional section like Windows 2003 */
2006-12-14 19:27:45 +03:00
if ( srv_type = = DNS_SRV_WIN2000 ) {
err = dns_add_rrec ( req , rec , & req - > num_answers ,
& req - > answers ) ;
} else {
err = dns_add_rrec ( req , rec , & req - > num_additionals ,
2023-03-31 12:00:50 +03:00
& req - > additional ) ;
2006-12-14 19:27:45 +03:00
}
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
err = dns_marshall_request ( frame , req , & buf ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_send ( conn , buf ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2016-04-22 03:35:37 +03:00
TALLOC_FREE ( buf ) ;
2006-11-18 00:46:26 +03:00
TALLOC_FREE ( req ) ;
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
err = dns_receive ( frame , conn , & buf ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-11-18 00:46:26 +03:00
}
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
2006-11-18 00:46:26 +03:00
struct dns_request * resp ;
struct dns_tkey_record * tkey ;
2012-11-09 11:59:36 +04:00
struct dns_rrec * tkey_answer = NULL ;
uint16_t i ;
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
if ( buf = = NULL ) {
err = ERROR_DNS_BAD_RESPONSE ;
goto error ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_unmarshall_request ( buf , buf , & resp ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
/*
* TODO : Compare id and keyname
*/
2012-11-09 11:59:36 +04:00
for ( i = 0 ; i < resp - > num_answers ; i + + ) {
if ( resp - > answers [ i ] - > type ! = QTYPE_TKEY ) {
continue ;
}
tkey_answer = resp - > answers [ i ] ;
}
if ( tkey_answer = = NULL ) {
2006-11-18 00:46:26 +03:00
err = ERROR_DNS_INVALID_MESSAGE ;
goto error ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_unmarshall_tkey_record (
2024-03-07 14:03:05 +03:00
frame , resp - > answers [ 0 ] , & tkey ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
in = data_blob_const ( tkey - > key , tkey - > key_length ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
TALLOC_FREE ( buf ) ;
}
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
} while ( NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
/* If we arrive here, we have a valid security context */
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
error :
2024-03-07 14:03:05 +03:00
TALLOC_FREE ( frame ) ;
2006-11-18 00:46:26 +03:00
return err ;
2006-08-24 19:43:32 +04:00
}
2024-03-07 14:03:05 +03:00
DNS_ERROR dns_negotiate_sec_ctx ( const char * servername ,
const char * keyname ,
struct gensec_security * gensec ,
enum dns_ServerType srv_type )
2006-08-24 19:43:32 +04:00
{
2024-03-07 14:03:05 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2006-11-18 00:46:26 +03:00
DNS_ERROR err ;
2024-03-07 14:03:05 +03:00
struct dns_connection * conn = NULL ;
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
err = dns_open_connection ( servername , DNS_TCP , frame , & conn ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2024-03-07 14:03:05 +03:00
err = dns_negotiate_gss_ctx_int ( conn , keyname ,
gensec ,
srv_type ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2007-03-16 01:09:03 +03:00
2006-11-18 00:46:26 +03:00
error :
2024-03-07 14:03:05 +03:00
TALLOC_FREE ( frame ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
return err ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_sign_update ( struct dns_update_request * req ,
2024-03-07 14:03:05 +03:00
struct gensec_security * gensec ,
2006-11-18 00:46:26 +03:00
const char * keyname ,
const char * algorithmname ,
2012-07-05 22:47:58 +04:00
time_t time_signed , uint16_t fudge )
2006-08-24 19:43:32 +04:00
{
2024-03-07 14:03:05 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2006-11-18 00:46:26 +03:00
struct dns_buffer * buf ;
DNS_ERROR err ;
struct dns_domain_name * key , * algorithm ;
struct dns_rrec * rec ;
2024-03-07 14:03:05 +03:00
DATA_BLOB mic = { . length = 0 , } ;
NTSTATUS status ;
2006-11-18 00:46:26 +03:00
2024-03-07 14:03:05 +03:00
err = dns_marshall_update_request ( frame , req , & buf ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) return err ;
2024-03-07 14:03:05 +03:00
err = dns_domain_name_from_string ( frame , keyname , & key ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2024-03-07 14:03:05 +03:00
err = dns_domain_name_from_string ( frame , algorithmname , & algorithm ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
dns_marshall_domain_name ( buf , key ) ;
dns_marshall_uint16 ( buf , DNS_CLASS_ANY ) ;
dns_marshall_uint32 ( buf , 0 ) ; /* TTL */
dns_marshall_domain_name ( buf , algorithm ) ;
dns_marshall_uint16 ( buf , 0 ) ; /* Time prefix for 48-bit time_t */
dns_marshall_uint32 ( buf , time_signed ) ;
dns_marshall_uint16 ( buf , fudge ) ;
dns_marshall_uint16 ( buf , 0 ) ; /* error */
dns_marshall_uint16 ( buf , 0 ) ; /* other len */
err = buf - > error ;
if ( ! ERR_DNS_IS_OK ( buf - > error ) ) goto error ;
2024-03-07 14:03:05 +03:00
status = gensec_sign_packet ( gensec ,
frame ,
buf - > data ,
buf - > offset ,
buf - > data ,
buf - > offset ,
& mic ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-11-18 00:46:26 +03:00
err = ERROR_DNS_GSS_ERROR ;
goto error ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( mic . length > 0xffff ) {
err = ERROR_DNS_GSS_ERROR ;
goto error ;
2006-08-24 19:43:32 +04:00
}
2024-03-07 14:03:05 +03:00
err = dns_create_tsig_record ( frame , keyname , algorithmname , time_signed ,
fudge , mic . length , mic . data ,
2006-11-18 00:46:26 +03:00
req - > id , 0 , & rec ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2023-03-31 12:00:50 +03:00
err = dns_add_rrec ( req , rec , & req - > num_additionals , & req - > additional ) ;
2006-11-18 00:46:26 +03:00
error :
2024-03-07 14:03:05 +03:00
TALLOC_FREE ( frame ) ;
2006-11-18 00:46:26 +03:00
return err ;
2006-08-24 19:43:32 +04:00
}