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
*/
# include "dns.h"
# include <ctype.h>
2012-05-21 13:45:12 +04:00
# ifdef HAVE_GSSAPI
2006-08-24 22:09:05 +04:00
2006-08-24 19:43:32 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-08-27 01:50:28 +04:00
# ifndef HAVE_STRUPR
2006-08-24 19:43:32 +04:00
static int strupr ( char * szDomainName )
{
if ( ! szDomainName ) {
return ( 0 ) ;
}
while ( * szDomainName ! = ' \0 ' ) {
* szDomainName = toupper ( * szDomainName ) ;
szDomainName + + ;
}
return ( 0 ) ;
}
2009-08-27 01:50:28 +04:00
# endif
2006-08-24 19:43:32 +04:00
2006-12-14 19:27:45 +03:00
#if 0
2006-08-24 19:43:32 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-11-18 00:46:26 +03:00
static void display_status_1 ( const char * m , OM_uint32 code , int type )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
OM_uint32 maj_stat , min_stat ;
gss_buffer_desc msg ;
OM_uint32 msg_ctx ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
msg_ctx = 0 ;
while ( 1 ) {
maj_stat = gss_display_status ( & min_stat , code ,
type , GSS_C_NULL_OID ,
& msg_ctx , & msg ) ;
fprintf ( stdout , " GSS-API error %s: %s \n " , m ,
( char * ) msg . value ) ;
( void ) gss_release_buffer ( & min_stat , & msg ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! msg_ctx )
break ;
2006-08-24 19:43:32 +04:00
}
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-11-18 00:46:26 +03:00
void display_status ( const char * msg , OM_uint32 maj_stat , OM_uint32 min_stat )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
display_status_1 ( msg , maj_stat , GSS_C_GSS_CODE ) ;
display_status_1 ( msg , min_stat , GSS_C_MECH_CODE ) ;
2006-08-24 19:43:32 +04:00
}
2006-12-14 19:27:45 +03:00
# endif
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
static DNS_ERROR dns_negotiate_gss_ctx_int ( TALLOC_CTX * mem_ctx ,
struct dns_connection * conn ,
const char * keyname ,
const gss_name_t target_name ,
2006-12-14 19:27:45 +03:00
gss_ctx_id_t * ctx ,
enum dns_ServerType srv_type )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct gss_buffer_desc_struct input_desc , * input_ptr , output_desc ;
OM_uint32 major , minor ;
OM_uint32 ret_flags ;
2016-04-22 03:35:37 +03:00
struct dns_request * req = NULL ;
struct dns_buffer * buf = NULL ;
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
gss_OID_desc krb5_oid_desc =
2012-11-09 12:08:51 +04:00
{ 9 , discard_const ( " \x2a \x86 \x48 \x86 \xf7 \x12 \x01 \x02 \x02 " ) } ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* ctx = GSS_C_NO_CONTEXT ;
input_ptr = NULL ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
do {
major = gss_init_sec_context (
& minor , NULL , ctx , target_name , & krb5_oid_desc ,
GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
2010-12-10 07:30:22 +03:00
GSS_C_CONF_FLAG |
2010-12-10 07:32:08 +03:00
GSS_C_INTEG_FLAG ,
2006-11-18 00:46:26 +03:00
0 , NULL , input_ptr , NULL , & output_desc ,
& ret_flags , NULL ) ;
if ( input_ptr ! = NULL ) {
TALLOC_FREE ( input_desc . value ) ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
if ( output_desc . length ! = 0 ) {
2006-08-24 19:43:32 +04:00
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
2006-11-18 00:46:26 +03:00
err = dns_create_query ( mem_ctx , keyname , QTYPE_TKEY ,
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 ,
2012-07-05 22:47:58 +04:00
output_desc . length , ( uint8_t * ) output_desc . value ,
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
2016-04-22 03:35:37 +03:00
err = dns_marshall_request ( mem_ctx , 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
2006-11-18 00:46:26 +03:00
gss_release_buffer ( & minor , & output_desc ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ( major ! = GSS_S_COMPLETE ) & &
( major ! = GSS_S_CONTINUE_NEEDED ) ) {
return ERROR_DNS_GSS_ERROR ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( major = = GSS_S_CONTINUE_NEEDED ) {
2006-08-24 19:43:32 +04:00
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
2006-11-18 00:46:26 +03:00
err = dns_receive ( mem_ctx , conn , & buf ) ;
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_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 (
mem_ctx , resp - > answers [ 0 ] , & tkey ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
input_desc . length = tkey - > key_length ;
input_desc . value = talloc_move ( mem_ctx , & tkey - > key ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
input_ptr = & input_desc ;
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
2006-11-18 00:46:26 +03:00
} while ( major = = GSS_S_CONTINUE_NEEDED ) ;
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 :
2016-04-22 03:35:37 +03:00
TALLOC_FREE ( buf ) ;
TALLOC_FREE ( req ) ;
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_negotiate_sec_ctx ( const char * target_realm ,
const char * servername ,
const char * keyname ,
2006-12-14 19:27:45 +03:00
gss_ctx_id_t * gss_ctx ,
enum dns_ServerType srv_type )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
OM_uint32 major , minor ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
char * upcaserealm , * targetname ;
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
gss_buffer_desc input_name ;
struct dns_connection * conn ;
2006-08-24 19:43:32 +04:00
gss_name_t targ_name ;
gss_OID_desc nt_host_oid_desc =
2012-11-09 12:08:51 +04:00
{ 10 , discard_const ( " \x2a \x86 \x48 \x86 \xf7 \x12 \x01 \x02 \x02 \x01 " ) } ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
TALLOC_CTX * mem_ctx ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( mem_ctx = talloc_init ( " dns_negotiate_sec_ctx " ) ) ) {
return ERROR_DNS_NO_MEMORY ;
}
2006-08-24 19:43:32 +04:00
2006-12-31 09:45:24 +03:00
err = dns_open_connection ( servername , DNS_TCP , mem_ctx , & 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
2006-11-18 00:46:26 +03:00
if ( ! ( upcaserealm = talloc_strdup ( mem_ctx , target_realm ) ) ) {
err = ERROR_DNS_NO_MEMORY ;
goto error ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
strupr ( upcaserealm ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( targetname = talloc_asprintf ( mem_ctx , " dns/%s@%s " ,
servername , upcaserealm ) ) ) {
err = ERROR_DNS_NO_MEMORY ;
goto error ;
}
2006-08-24 19:43:32 +04:00
2007-09-13 20:11:46 +04:00
input_name . value = targetname ;
input_name . length = strlen ( targetname ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
major = gss_import_name ( & minor , & input_name ,
& nt_host_oid_desc , & targ_name ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( major ) {
err = ERROR_DNS_GSS_ERROR ;
goto error ;
}
2006-08-24 19:43:32 +04:00
2006-12-14 19:27:45 +03:00
err = dns_negotiate_gss_ctx_int ( mem_ctx , conn , keyname ,
targ_name , gss_ctx , srv_type ) ;
2007-03-16 01:09:03 +03:00
2006-12-14 19:27:45 +03:00
gss_release_name ( & minor , & targ_name ) ;
2007-03-16 01:09:03 +03:00
2006-11-18 00:46:26 +03:00
error :
TALLOC_FREE ( mem_ctx ) ;
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 ,
gss_ctx_id_t gss_ctx ,
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
{
2006-11-18 00:46:26 +03:00
struct dns_buffer * buf ;
DNS_ERROR err ;
struct dns_domain_name * key , * algorithm ;
struct gss_buffer_desc_struct msg , mic ;
OM_uint32 major , minor ;
struct dns_rrec * rec ;
err = dns_marshall_update_request ( req , req , & buf ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) return err ;
err = dns_domain_name_from_string ( buf , keyname , & key ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
err = dns_domain_name_from_string ( buf , algorithmname , & algorithm ) ;
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 ;
msg . value = ( void * ) buf - > data ;
msg . length = buf - > offset ;
major = gss_get_mic ( & minor , gss_ctx , 0 , & msg , & mic ) ;
if ( major ! = 0 ) {
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 ) {
gss_release_buffer ( & minor , & mic ) ;
err = ERROR_DNS_GSS_ERROR ;
goto error ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
err = dns_create_tsig_record ( buf , keyname , algorithmname , time_signed ,
2012-07-05 22:47:58 +04:00
fudge , mic . length , ( uint8_t * ) mic . value ,
2006-11-18 00:46:26 +03:00
req - > id , 0 , & rec ) ;
gss_release_buffer ( & minor , & mic ) ;
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 :
TALLOC_FREE ( buf ) ;
return err ;
2006-08-24 19:43:32 +04:00
}
2006-08-24 22:09:05 +04:00
2012-05-21 13:45:12 +04:00
# endif /* HAVE_GSSAPI */