2010-01-28 02:05:05 -05:00
/*
2005-09-17 01:11:50 +00:00
Unix SMB / CIFS implementation .
Wrapper for krb5_init_context
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2005
2005-09-28 01:09:10 +00:00
Copyright ( C ) Andrew Tridgell 2005
Copyright ( C ) Stefan Metzmacher 2004
2005-09-17 01:11:50 +00:00
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
2007-07-10 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2005-09-17 01:11:50 +00:00
( at your option ) any later version .
2010-01-28 02:05:05 -05:00
2005-09-17 01:11:50 +00:00
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 .
2010-01-28 02:05:05 -05:00
2005-09-17 01:11:50 +00:00
You should have received a copy of the GNU General Public License
2007-07-10 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-09-17 01:11:50 +00:00
*/
# include "includes.h"
# include "system/kerberos.h"
2009-01-03 12:48:20 +01:00
# include <tevent.h>
2005-09-17 01:11:50 +00:00
# include "auth/kerberos/kerberos.h"
2005-09-28 01:09:10 +00:00
# include "lib/socket/socket.h"
2007-05-17 05:46:45 +00:00
# include "lib/stream/packet.h"
2006-03-11 08:11:33 +00:00
# include "system/network.h"
2007-09-08 12:42:09 +00:00
# include "param/param.h"
2007-12-10 18:41:19 +01:00
# include "libcli/resolve/resolve.h"
2010-11-05 17:08:52 +11:00
# include "../lib/tsocket/tsocket.h"
2012-04-20 13:14:30 -04:00
# include "krb5_init_context.h"
2016-02-03 14:58:47 +01:00
# ifdef SAMBA4_USES_HEIMDAL
# include "../lib/dbwrap/dbwrap.h"
# include "../lib/dbwrap/dbwrap_rbt.h"
# include "../lib/util/util_tdb.h"
# include <krb5/send_to_kdc_plugin.h>
# endif
2005-09-28 01:09:10 +00:00
/*
context structure for operations on cldap packets
*/
struct smb_krb5_socket {
struct socket_context * sock ;
/* the fd event */
2008-12-29 20:24:57 +01:00
struct tevent_fd * fde ;
2005-09-28 01:09:10 +00:00
NTSTATUS status ;
2007-05-17 05:46:45 +00:00
DATA_BLOB request , reply ;
2010-01-28 02:05:05 -05:00
2007-05-17 05:46:45 +00:00
struct packet_context * packet ;
2005-09-28 01:09:10 +00:00
size_t partial_read ;
2012-04-25 10:31:12 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2005-09-28 01:09:10 +00:00
krb5_krbhst_info * hi ;
2012-04-25 10:31:12 -04:00
# endif
2005-09-28 01:09:10 +00:00
} ;
2005-09-17 01:11:50 +00:00
2010-01-31 13:28:04 -05:00
static krb5_error_code smb_krb5_context_destroy ( struct smb_krb5_context * ctx )
2005-09-17 01:11:50 +00:00
{
2012-04-20 13:14:30 -04:00
# ifdef SAMBA4_USES_HEIMDAL
if ( ctx - > pvt_log_data ) {
/* Otherwise krb5_free_context will try and close what we
* have already free ( ) ed */
krb5_set_warn_dest ( ctx - > krb5_context , NULL ) ;
krb5_closelog ( ctx - > krb5_context ,
( krb5_log_facility * ) ctx - > pvt_log_data ) ;
}
# endif
2010-01-31 13:28:04 -05:00
krb5_free_context ( ctx - > krb5_context ) ;
2005-09-17 01:11:50 +00:00
return 0 ;
}
2012-04-25 10:31:12 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2005-09-17 01:11:50 +00:00
/* We never close down the DEBUG system, and no need to unreference the use */
2009-02-02 08:17:20 +01:00
static void smb_krb5_debug_close ( void * private_data ) {
2005-09-17 01:11:50 +00:00
return ;
}
2012-04-25 10:31:12 -04:00
# endif
2005-09-17 01:11:50 +00:00
2012-04-20 13:14:30 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2021-12-08 15:30:12 +13:00
static void smb_krb5_debug_wrapper (
# ifdef HAVE_KRB5_ADDLOG_FUNC_NEED_CONTEXT
krb5_context ctx ,
# endif /* HAVE_KRB5_ADDLOG_FUNC_NEED_CONTEXT */
const char * timestr , const char * msg , void * private_data )
2005-09-17 01:11:50 +00:00
{
2017-05-16 08:32:03 +12:00
DEBUGC ( DBGC_KERBEROS , 3 , ( " Kerberos: %s \n " , msg ) ) ;
2005-09-17 01:11:50 +00:00
}
2012-04-20 13:14:30 -04:00
# endif
2005-09-17 01:11:50 +00:00
2012-04-21 16:35:48 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2005-09-28 01:09:10 +00:00
/*
handle recv events on a smb_krb5 socket
*/
static void smb_krb5_socket_recv ( struct smb_krb5_socket * smb_krb5 )
{
TALLOC_CTX * tmp_ctx = talloc_new ( smb_krb5 ) ;
DATA_BLOB blob ;
size_t nread , dsize ;
2007-05-17 05:46:45 +00:00
smb_krb5 - > status = socket_pending ( smb_krb5 - > sock , & dsize ) ;
if ( ! NT_STATUS_IS_OK ( smb_krb5 - > status ) ) {
2005-09-28 01:09:10 +00:00
talloc_free ( tmp_ctx ) ;
return ;
}
2010-01-28 02:05:05 -05:00
2007-05-17 05:46:45 +00:00
blob = data_blob_talloc ( tmp_ctx , NULL , dsize ) ;
if ( blob . data = = NULL & & dsize ! = 0 ) {
smb_krb5 - > status = NT_STATUS_NO_MEMORY ;
talloc_free ( tmp_ctx ) ;
return ;
}
2010-01-28 02:05:05 -05:00
2007-05-17 05:46:45 +00:00
smb_krb5 - > status = socket_recv ( smb_krb5 - > sock , blob . data , blob . length , & nread ) ;
if ( ! NT_STATUS_IS_OK ( smb_krb5 - > status ) ) {
talloc_free ( tmp_ctx ) ;
return ;
}
blob . length = nread ;
2010-01-28 02:05:05 -05:00
2007-05-17 05:46:45 +00:00
if ( nread = = 0 ) {
smb_krb5 - > status = NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
talloc_free ( tmp_ctx ) ;
return ;
}
2010-01-28 02:05:05 -05:00
2011-04-01 15:57:39 +11:00
DEBUG ( 4 , ( " Received smb_krb5 packet of length %d \n " ,
2007-05-17 05:46:45 +00:00
( int ) blob . length ) ) ;
2010-01-28 02:05:05 -05:00
2007-05-17 05:46:45 +00:00
talloc_steal ( smb_krb5 , blob . data ) ;
smb_krb5 - > reply = blob ;
talloc_free ( tmp_ctx ) ;
}
2009-02-02 08:17:20 +01:00
static NTSTATUS smb_krb5_full_packet ( void * private_data , DATA_BLOB data )
2007-05-17 05:46:45 +00:00
{
2009-02-02 08:17:20 +01:00
struct smb_krb5_socket * smb_krb5 = talloc_get_type ( private_data , struct smb_krb5_socket ) ;
2007-05-17 05:46:45 +00:00
talloc_steal ( smb_krb5 , data . data ) ;
smb_krb5 - > reply = data ;
smb_krb5 - > reply . length - = 4 ;
smb_krb5 - > reply . data + = 4 ;
return NT_STATUS_OK ;
2005-09-28 01:09:10 +00:00
}
/*
handle request timeouts
*/
2010-01-28 02:05:05 -05:00
static void smb_krb5_request_timeout ( struct tevent_context * event_ctx ,
2008-12-29 20:24:57 +01:00
struct tevent_timer * te , struct timeval t ,
2009-02-02 08:17:20 +01:00
void * private_data )
2005-09-28 01:09:10 +00:00
{
2009-02-02 08:17:20 +01:00
struct smb_krb5_socket * smb_krb5 = talloc_get_type ( private_data , struct smb_krb5_socket ) ;
2005-10-14 06:06:18 +00:00
DEBUG ( 5 , ( " Timed out smb_krb5 packet \n " ) ) ;
2007-05-17 05:46:45 +00:00
smb_krb5 - > status = NT_STATUS_IO_TIMEOUT ;
}
2009-02-02 08:17:20 +01:00
static void smb_krb5_error_handler ( void * private_data , NTSTATUS status )
2007-05-17 05:46:45 +00:00
{
2009-02-02 08:17:20 +01:00
struct smb_krb5_socket * smb_krb5 = talloc_get_type ( private_data , struct smb_krb5_socket ) ;
2007-05-17 05:46:45 +00:00
smb_krb5 - > status = status ;
2005-09-28 01:09:10 +00:00
}
/*
handle send events on a smb_krb5 socket
*/
static void smb_krb5_socket_send ( struct smb_krb5_socket * smb_krb5 )
{
NTSTATUS status ;
size_t len ;
2010-01-28 02:05:05 -05:00
2005-09-28 01:09:10 +00:00
len = smb_krb5 - > request . length ;
2006-04-30 05:58:31 +00:00
status = socket_send ( smb_krb5 - > sock , & smb_krb5 - > request , & len ) ;
2005-09-28 01:09:10 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) return ;
2010-01-28 02:05:05 -05:00
2009-01-03 12:48:20 +01:00
TEVENT_FD_READABLE ( smb_krb5 - > fde ) ;
2005-09-28 01:09:10 +00:00
2009-01-03 12:48:20 +01:00
TEVENT_FD_NOT_WRITEABLE ( smb_krb5 - > fde ) ;
2005-09-28 01:09:10 +00:00
return ;
}
/*
handle fd events on a smb_krb5_socket
*/
2008-12-29 20:24:57 +01:00
static void smb_krb5_socket_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
2009-02-02 08:17:20 +01:00
uint16_t flags , void * private_data )
2005-09-28 01:09:10 +00:00
{
2009-02-02 08:17:20 +01:00
struct smb_krb5_socket * smb_krb5 = talloc_get_type ( private_data , struct smb_krb5_socket ) ;
2007-05-17 05:46:45 +00:00
switch ( smb_krb5 - > hi - > proto ) {
case KRB5_KRBHST_UDP :
2009-01-03 12:48:20 +01:00
if ( flags & TEVENT_FD_READ ) {
2007-05-17 05:46:45 +00:00
smb_krb5_socket_recv ( smb_krb5 ) ;
2007-05-18 05:47:33 +00:00
return ;
2007-05-17 05:46:45 +00:00
}
2009-01-03 12:48:20 +01:00
if ( flags & TEVENT_FD_WRITE ) {
2007-05-18 05:47:33 +00:00
smb_krb5_socket_send ( smb_krb5 ) ;
return ;
}
/* not reached */
return ;
2007-05-17 05:46:45 +00:00
case KRB5_KRBHST_TCP :
2009-01-03 12:48:20 +01:00
if ( flags & TEVENT_FD_READ ) {
2007-05-17 05:46:45 +00:00
packet_recv ( smb_krb5 - > packet ) ;
2007-05-18 05:47:33 +00:00
return ;
2007-05-17 05:46:45 +00:00
}
2009-01-03 12:48:20 +01:00
if ( flags & TEVENT_FD_WRITE ) {
2007-05-17 05:46:45 +00:00
packet_queue_run ( smb_krb5 - > packet ) ;
2007-05-18 05:47:33 +00:00
return ;
2007-05-17 05:46:45 +00:00
}
2007-05-18 05:47:33 +00:00
/* not reached */
return ;
2007-05-17 05:46:45 +00:00
case KRB5_KRBHST_HTTP :
/* can't happen */
break ;
2005-09-28 01:09:10 +00:00
}
}
2016-02-03 14:58:47 +01:00
static krb5_error_code smb_krb5_send_and_recv_func_int ( struct smb_krb5_context * smb_krb5_context ,
2015-01-05 14:54:45 +13:00
struct tevent_context * ev ,
krb5_krbhst_info * hi ,
struct addrinfo * ai ,
2016-02-03 14:58:47 +01:00
smb_krb5_send_to_kdc_func func ,
2015-01-05 14:54:45 +13:00
void * data ,
time_t timeout ,
const krb5_data * send_buf ,
krb5_data * recv_buf )
2005-09-28 01:09:10 +00:00
{
krb5_error_code ret ;
NTSTATUS status ;
const char * name ;
2015-01-05 14:54:45 +13:00
struct addrinfo * a ;
2005-09-28 01:09:10 +00:00
struct smb_krb5_socket * smb_krb5 ;
2010-10-11 16:53:08 +11:00
DATA_BLOB send_blob ;
2005-09-28 01:09:10 +00:00
2015-02-06 08:53:21 +13:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( frame = = NULL ) {
2010-10-11 16:53:08 +11:00
return ENOMEM ;
}
send_blob = data_blob_const ( send_buf - > data , send_buf - > length ) ;
2005-09-28 01:09:10 +00:00
2010-11-14 14:26:06 +11:00
for ( a = ai ; a ; a = a - > ai_next ) {
2010-11-14 13:40:02 +11:00
struct socket_address * remote_addr ;
2015-02-06 08:53:21 +13:00
smb_krb5 = talloc ( frame , struct smb_krb5_socket ) ;
2005-09-28 01:09:10 +00:00
if ( ! smb_krb5 ) {
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2005-09-28 01:09:10 +00:00
return ENOMEM ;
}
smb_krb5 - > hi = hi ;
2010-01-28 02:05:05 -05:00
2005-09-28 01:09:10 +00:00
switch ( a - > ai_family ) {
case PF_INET :
name = " ipv4 " ;
break ;
2007-04-30 11:27:41 +00:00
# ifdef HAVE_IPV6
2005-09-28 01:09:10 +00:00
case PF_INET6 :
name = " ipv6 " ;
break ;
2006-05-24 22:17:01 +00:00
# endif
2005-09-28 01:09:10 +00:00
default :
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2005-09-28 01:09:10 +00:00
return EINVAL ;
}
2010-01-28 02:05:05 -05:00
2005-09-28 01:09:10 +00:00
status = NT_STATUS_INVALID_PARAMETER ;
switch ( hi - > proto ) {
case KRB5_KRBHST_UDP :
2018-02-15 16:43:59 +01:00
status = socket_create ( smb_krb5 , name ,
SOCKET_TYPE_DGRAM ,
& smb_krb5 - > sock , 0 ) ;
2006-03-13 06:56:31 +00:00
break ;
2005-09-28 01:09:10 +00:00
case KRB5_KRBHST_TCP :
2018-02-15 16:43:59 +01:00
status = socket_create ( smb_krb5 , name ,
SOCKET_TYPE_STREAM ,
& smb_krb5 - > sock , 0 ) ;
2006-03-13 06:56:31 +00:00
break ;
2005-09-28 01:09:10 +00:00
case KRB5_KRBHST_HTTP :
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2005-09-28 01:09:10 +00:00
return EINVAL ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( smb_krb5 ) ;
continue ;
}
2010-01-28 02:05:05 -05:00
remote_addr = socket_address_from_sockaddr ( smb_krb5 , a - > ai_addr , a - > ai_addrlen ) ;
2006-01-09 22:12:53 +00:00
if ( ! remote_addr ) {
2005-09-28 01:09:10 +00:00
talloc_free ( smb_krb5 ) ;
2006-01-09 22:12:53 +00:00
continue ;
2005-09-28 01:09:10 +00:00
}
2006-01-09 22:12:53 +00:00
2008-12-17 23:13:44 +01:00
status = socket_connect_ev ( smb_krb5 - > sock , NULL , remote_addr , 0 , ev ) ;
2005-09-28 01:09:10 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( smb_krb5 ) ;
continue ;
}
2007-05-18 05:47:33 +00:00
/* Setup the FDE, start listening for read events
* from the start ( otherwise we may miss a socket
* drop ) and mark as AUTOCLOSE along with the fde */
/* Ths is equivilant to EVENT_FD_READABLE(smb_krb5->fde) */
2009-01-03 12:47:24 +01:00
smb_krb5 - > fde = tevent_add_fd ( ev , smb_krb5 - > sock ,
socket_get_fd ( smb_krb5 - > sock ) ,
TEVENT_FD_READ ,
smb_krb5_socket_handler , smb_krb5 ) ;
2007-05-17 02:21:07 +00:00
/* its now the job of the event layer to close the socket */
2009-01-03 12:47:24 +01:00
tevent_fd_set_close_fn ( smb_krb5 - > fde , socket_tevent_fd_close_fn ) ;
2007-05-17 02:21:07 +00:00
socket_set_flags ( smb_krb5 - > sock , SOCKET_FLAG_NOCLOSE ) ;
2005-09-28 01:09:10 +00:00
2009-01-03 12:48:20 +01:00
tevent_add_timer ( ev , smb_krb5 ,
timeval_current_ofs ( timeout , 0 ) ,
smb_krb5_request_timeout , smb_krb5 ) ;
2005-09-28 01:09:10 +00:00
2007-05-17 05:46:45 +00:00
smb_krb5 - > status = NT_STATUS_OK ;
smb_krb5 - > reply = data_blob ( NULL , 0 ) ;
2005-09-28 01:09:10 +00:00
switch ( hi - > proto ) {
case KRB5_KRBHST_UDP :
2009-01-03 12:48:20 +01:00
TEVENT_FD_WRITEABLE ( smb_krb5 - > fde ) ;
2005-09-28 01:09:10 +00:00
smb_krb5 - > request = send_blob ;
break ;
case KRB5_KRBHST_TCP :
2007-05-17 05:46:45 +00:00
smb_krb5 - > packet = packet_init ( smb_krb5 ) ;
if ( smb_krb5 - > packet = = NULL ) {
talloc_free ( smb_krb5 ) ;
return ENOMEM ;
}
packet_set_private ( smb_krb5 - > packet , smb_krb5 ) ;
packet_set_socket ( smb_krb5 - > packet , smb_krb5 - > sock ) ;
packet_set_callback ( smb_krb5 - > packet , smb_krb5_full_packet ) ;
packet_set_full_request ( smb_krb5 - > packet , packet_full_request_u32 ) ;
packet_set_error_handler ( smb_krb5 - > packet , smb_krb5_error_handler ) ;
packet_set_event_context ( smb_krb5 - > packet , ev ) ;
packet_set_fde ( smb_krb5 - > packet , smb_krb5 - > fde ) ;
2005-09-28 01:09:10 +00:00
smb_krb5 - > request = data_blob_talloc ( smb_krb5 , NULL , send_blob . length + 4 ) ;
RSIVAL ( smb_krb5 - > request . data , 0 , send_blob . length ) ;
memcpy ( smb_krb5 - > request . data + 4 , send_blob . data , send_blob . length ) ;
2007-05-17 05:46:45 +00:00
packet_send ( smb_krb5 - > packet , smb_krb5 - > request ) ;
2005-09-28 01:09:10 +00:00
break ;
case KRB5_KRBHST_HTTP :
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2005-09-28 01:09:10 +00:00
return EINVAL ;
}
2007-05-17 05:46:45 +00:00
while ( ( NT_STATUS_IS_OK ( smb_krb5 - > status ) ) & & ! smb_krb5 - > reply . length ) {
2009-01-03 12:48:20 +01:00
if ( tevent_loop_once ( ev ) ! = 0 ) {
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2005-09-28 01:09:10 +00:00
return EINVAL ;
}
2010-10-11 16:53:08 +11:00
2015-01-05 14:54:45 +13:00
if ( func ) {
/* After each and every event loop, reset the
* send_to_kdc pointers to what they were when
* we entered this loop . That way , if a
* nested event has invalidated them , we put
* it back before we return to the heimdal
* code */
2016-02-03 14:58:47 +01:00
ret = smb_krb5_set_send_to_kdc_func ( smb_krb5_context ,
NULL , /* send_to_realm */
func ,
data ) ;
2015-01-05 14:54:45 +13:00
if ( ret ! = 0 ) {
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2015-01-05 14:54:45 +13:00
return ret ;
}
2010-10-11 16:53:08 +11:00
}
2005-09-28 01:09:10 +00:00
}
2007-05-17 05:46:45 +00:00
if ( NT_STATUS_EQUAL ( smb_krb5 - > status , NT_STATUS_IO_TIMEOUT ) ) {
2005-09-28 01:09:10 +00:00
talloc_free ( smb_krb5 ) ;
continue ;
}
2007-05-17 05:46:45 +00:00
if ( ! NT_STATUS_IS_OK ( smb_krb5 - > status ) ) {
2010-11-05 17:08:52 +11:00
struct tsocket_address * addr = socket_address_to_tsocket_address ( smb_krb5 , remote_addr ) ;
const char * addr_string = NULL ;
if ( addr ) {
addr_string = tsocket_address_inet_addr_string ( addr , smb_krb5 ) ;
} else {
addr_string = NULL ;
}
DEBUG ( 2 , ( " Error reading smb_krb5 reply packet: %s from %s \n " , nt_errstr ( smb_krb5 - > status ) ,
addr_string ) ) ;
2005-09-28 01:09:10 +00:00
talloc_free ( smb_krb5 ) ;
continue ;
}
ret = krb5_data_copy ( recv_buf , smb_krb5 - > reply . data , smb_krb5 - > reply . length ) ;
if ( ret ) {
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2005-09-28 01:09:10 +00:00
return ret ;
}
talloc_free ( smb_krb5 ) ;
2010-01-28 02:05:05 -05:00
2005-09-28 01:09:10 +00:00
break ;
}
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2005-09-28 01:09:10 +00:00
if ( a ) {
return 0 ;
}
return KRB5_KDC_UNREACH ;
}
2015-01-05 14:54:45 +13:00
2016-02-03 14:58:47 +01:00
krb5_error_code smb_krb5_send_and_recv_func ( struct smb_krb5_context * smb_krb5_context ,
2015-01-05 14:54:45 +13:00
void * data ,
krb5_krbhst_info * hi ,
time_t timeout ,
const krb5_data * send_buf ,
krb5_data * recv_buf )
{
krb5_error_code ret ;
struct addrinfo * ai ;
struct tevent_context * ev ;
2015-02-06 08:53:21 +13:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( frame = = NULL ) {
2015-01-05 14:54:45 +13:00
return ENOMEM ;
}
2015-02-06 08:53:21 +13:00
if ( data = = NULL ) {
2015-01-05 14:54:45 +13:00
/* If no event context was available, then create one for this loop */
2015-02-06 08:53:21 +13:00
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
TALLOC_FREE ( frame ) ;
2015-01-05 14:54:45 +13:00
return ENOMEM ;
}
} else {
ev = talloc_get_type_abort ( data , struct tevent_context ) ;
}
2016-02-03 14:58:47 +01:00
ret = krb5_krbhst_get_addrinfo ( smb_krb5_context - > krb5_context , hi , & ai ) ;
2015-01-05 14:54:45 +13:00
if ( ret ) {
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
2015-01-05 14:54:45 +13:00
return ret ;
}
2015-02-06 08:53:21 +13:00
2016-02-03 14:58:47 +01:00
ret = smb_krb5_send_and_recv_func_int ( smb_krb5_context ,
ev , hi , ai ,
smb_krb5_send_and_recv_func ,
data , timeout , send_buf , recv_buf ) ;
2015-02-06 08:53:21 +13:00
TALLOC_FREE ( frame ) ;
return ret ;
2015-01-05 14:54:45 +13:00
}
2016-02-03 14:58:47 +01:00
krb5_error_code smb_krb5_send_and_recv_func_forced_tcp ( struct smb_krb5_context * smb_krb5_context ,
struct addrinfo * ai ,
time_t timeout ,
const krb5_data * send_buf ,
krb5_data * recv_buf )
2015-01-05 14:54:45 +13:00
{
2015-02-06 08:53:21 +13:00
krb5_error_code k5ret ;
2016-02-03 14:58:47 +01:00
krb5_krbhst_info hi = {
. proto = KRB5_KRBHST_TCP ,
} ;
2015-01-05 14:54:45 +13:00
struct tevent_context * ev ;
2015-02-06 08:53:21 +13:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( frame = = NULL ) {
2015-01-05 14:54:45 +13:00
return ENOMEM ;
}
2015-02-06 08:53:21 +13:00
/* no event context is passed in, create one for this loop */
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
TALLOC_FREE ( frame ) ;
2015-01-05 14:54:45 +13:00
return ENOMEM ;
}
/* No need to pass in send_and_recv functions, we won't nest on this private event loop */
2016-02-03 14:58:47 +01:00
k5ret = smb_krb5_send_and_recv_func_int ( smb_krb5_context , ev , & hi , ai , NULL , NULL ,
2015-02-06 08:53:21 +13:00
timeout , send_buf , recv_buf ) ;
TALLOC_FREE ( frame ) ;
return k5ret ;
2015-01-05 14:54:45 +13:00
}
2016-02-03 14:58:47 +01:00
static struct db_context * smb_krb5_plugin_db ;
struct smb_krb5_send_to_kdc_state {
intptr_t key_ptr ;
struct smb_krb5_context * smb_krb5_context ;
smb_krb5_send_to_realm_func send_to_realm ;
smb_krb5_send_to_kdc_func send_to_kdc ;
void * private_data ;
} ;
static int smb_krb5_send_to_kdc_state_destructor ( struct smb_krb5_send_to_kdc_state * state )
{
TDB_DATA key = make_tdb_data ( ( uint8_t * ) & state - > key_ptr , sizeof ( state - > key_ptr ) ) ;
struct db_record * rec = NULL ;
NTSTATUS status ;
rec = dbwrap_fetch_locked ( smb_krb5_plugin_db , state , key ) ;
if ( rec = = NULL ) {
return 0 ;
}
status = dbwrap_record_delete ( rec ) ;
TALLOC_FREE ( rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return - 1 ;
}
state - > smb_krb5_context = NULL ;
return 0 ;
}
krb5_error_code smb_krb5_set_send_to_kdc_func ( struct smb_krb5_context * smb_krb5_context ,
smb_krb5_send_to_realm_func send_to_realm ,
smb_krb5_send_to_kdc_func send_to_kdc ,
void * private_data )
{
intptr_t key_ptr = ( intptr_t ) smb_krb5_context - > krb5_context ;
TDB_DATA key = make_tdb_data ( ( uint8_t * ) & key_ptr , sizeof ( key_ptr ) ) ;
intptr_t value_ptr = ( intptr_t ) NULL ;
TDB_DATA value = make_tdb_data ( NULL , 0 ) ;
struct db_record * rec = NULL ;
struct smb_krb5_send_to_kdc_state * state = NULL ;
NTSTATUS status ;
rec = dbwrap_fetch_locked ( smb_krb5_plugin_db , smb_krb5_context , key ) ;
if ( rec = = NULL ) {
return ENOMEM ;
}
value = dbwrap_record_get_value ( rec ) ;
if ( value . dsize ! = 0 ) {
SMB_ASSERT ( value . dsize = = sizeof ( value_ptr ) ) ;
memcpy ( & value_ptr , value . dptr , sizeof ( value_ptr ) ) ;
state = talloc_get_type_abort ( ( const void * ) value_ptr ,
struct smb_krb5_send_to_kdc_state ) ;
if ( send_to_realm = = NULL & & send_to_kdc = = NULL ) {
status = dbwrap_record_delete ( rec ) ;
TALLOC_FREE ( rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return EINVAL ;
}
return 0 ;
}
state - > send_to_realm = send_to_realm ;
state - > send_to_kdc = send_to_kdc ;
state - > private_data = private_data ;
TALLOC_FREE ( rec ) ;
return 0 ;
}
if ( send_to_kdc = = NULL & & send_to_realm = = NULL ) {
TALLOC_FREE ( rec ) ;
return 0 ;
}
state = talloc_zero ( smb_krb5_context ,
struct smb_krb5_send_to_kdc_state ) ;
if ( state = = NULL ) {
TALLOC_FREE ( rec ) ;
return ENOMEM ;
}
state - > key_ptr = key_ptr ;
state - > smb_krb5_context = smb_krb5_context ;
state - > send_to_realm = send_to_realm ;
state - > send_to_kdc = send_to_kdc ;
state - > private_data = private_data ;
value_ptr = ( intptr_t ) state ;
value = make_tdb_data ( ( uint8_t * ) & value_ptr , sizeof ( value_ptr ) ) ;
status = dbwrap_record_store ( rec , value , TDB_INSERT ) ;
TALLOC_FREE ( rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return EINVAL ;
}
talloc_set_destructor ( state , smb_krb5_send_to_kdc_state_destructor ) ;
return 0 ;
}
static krb5_error_code smb_krb5_plugin_init ( krb5_context context , void * * pctx )
{
* pctx = NULL ;
return 0 ;
}
static void smb_krb5_plugin_fini ( void * ctx )
{
}
static void smb_krb5_send_to_kdc_state_parser ( TDB_DATA key , TDB_DATA value ,
void * private_data )
{
struct smb_krb5_send_to_kdc_state * * state =
( struct smb_krb5_send_to_kdc_state * * ) private_data ;
intptr_t value_ptr ;
SMB_ASSERT ( value . dsize = = sizeof ( value_ptr ) ) ;
memcpy ( & value_ptr , value . dptr , sizeof ( value_ptr ) ) ;
* state = talloc_get_type_abort ( ( const void * ) value_ptr ,
struct smb_krb5_send_to_kdc_state ) ;
}
static struct smb_krb5_send_to_kdc_state *
smb_krb5_send_to_kdc_get_state ( krb5_context context )
{
intptr_t key_ptr = ( intptr_t ) context ;
TDB_DATA key = make_tdb_data ( ( uint8_t * ) & key_ptr , sizeof ( key_ptr ) ) ;
struct smb_krb5_send_to_kdc_state * state = NULL ;
NTSTATUS status ;
status = dbwrap_parse_record ( smb_krb5_plugin_db , key ,
smb_krb5_send_to_kdc_state_parser ,
& state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
return state ;
}
static krb5_error_code smb_krb5_plugin_send_to_kdc ( krb5_context context ,
void * ctx ,
krb5_krbhst_info * ho ,
time_t timeout ,
const krb5_data * in ,
krb5_data * out )
{
struct smb_krb5_send_to_kdc_state * state = NULL ;
state = smb_krb5_send_to_kdc_get_state ( context ) ;
if ( state = = NULL ) {
return KRB5_PLUGIN_NO_HANDLE ;
}
if ( state - > send_to_kdc = = NULL ) {
return KRB5_PLUGIN_NO_HANDLE ;
}
return state - > send_to_kdc ( state - > smb_krb5_context ,
state - > private_data ,
ho , timeout , in , out ) ;
}
static krb5_error_code smb_krb5_plugin_send_to_realm ( krb5_context context ,
void * ctx ,
krb5_const_realm realm ,
time_t timeout ,
const krb5_data * in ,
krb5_data * out )
{
struct smb_krb5_send_to_kdc_state * state = NULL ;
state = smb_krb5_send_to_kdc_get_state ( context ) ;
if ( state = = NULL ) {
return KRB5_PLUGIN_NO_HANDLE ;
}
if ( state - > send_to_realm = = NULL ) {
return KRB5_PLUGIN_NO_HANDLE ;
}
return state - > send_to_realm ( state - > smb_krb5_context ,
state - > private_data ,
realm , timeout , in , out ) ;
}
static krb5plugin_send_to_kdc_ftable smb_krb5_plugin_ftable = {
KRB5_PLUGIN_SEND_TO_KDC_VERSION_2 ,
smb_krb5_plugin_init ,
smb_krb5_plugin_fini ,
smb_krb5_plugin_send_to_kdc ,
smb_krb5_plugin_send_to_realm
} ;
2012-04-21 16:35:48 -04:00
# endif
2005-09-28 01:09:10 +00:00
2010-01-31 13:28:04 -05:00
krb5_error_code
smb_krb5_init_context_basic ( TALLOC_CTX * tmp_ctx ,
struct loadparm_context * lp_ctx ,
krb5_context * _krb5_context )
2005-09-17 01:11:50 +00:00
{
krb5_error_code ret ;
2012-04-25 10:31:12 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2007-01-24 02:48:40 +00:00
char * * config_files ;
2009-10-12 19:09:18 +02:00
const char * config_file , * realm ;
2012-04-25 10:31:12 -04:00
# endif
2010-01-31 13:28:04 -05:00
krb5_context krb5_ctx ;
2010-01-28 02:05:05 -05:00
2018-12-05 10:29:44 +01:00
ret = smb_krb5_init_context_common ( & krb5_ctx ) ;
2005-09-17 01:11:50 +00:00
if ( ret ) {
return ret ;
}
2012-04-25 10:31:12 -04:00
/* The MIT Kerberos build relies on using the system krb5.conf file.
* If you really want to use another file please set KRB5_CONFIG
* accordingly . */
# ifdef SAMBA4_USES_HEIMDAL
2011-04-29 12:46:10 +10:00
config_file = lpcfg_config_path ( tmp_ctx , lp_ctx , " krb5.conf " ) ;
2007-01-24 02:48:40 +00:00
if ( ! config_file ) {
2010-01-31 13:28:04 -05:00
krb5_free_context ( krb5_ctx ) ;
2007-01-24 02:48:40 +00:00
return ENOMEM ;
}
2010-01-28 02:05:05 -05:00
2007-01-24 02:48:40 +00:00
/* Use our local krb5.conf file by default */
2012-04-25 10:19:07 -04:00
ret = krb5_prepend_config_files_default ( config_file , & config_files ) ;
2007-01-24 02:48:40 +00:00
if ( ret ) {
2010-01-28 02:05:05 -05:00
DEBUG ( 1 , ( " krb5_prepend_config_files_default failed (%s) \n " ,
2010-01-31 13:28:04 -05:00
smb_get_krb5_error_message ( krb5_ctx , ret , tmp_ctx ) ) ) ;
krb5_free_context ( krb5_ctx ) ;
2007-01-24 02:48:40 +00:00
return ret ;
}
2010-01-31 13:28:04 -05:00
ret = krb5_set_config_files ( krb5_ctx , config_files ) ;
2007-01-24 02:48:40 +00:00
krb5_free_config_files ( config_files ) ;
if ( ret ) {
2010-01-28 02:05:05 -05:00
DEBUG ( 1 , ( " krb5_set_config_files failed (%s) \n " ,
2010-01-31 13:28:04 -05:00
smb_get_krb5_error_message ( krb5_ctx , ret , tmp_ctx ) ) ) ;
krb5_free_context ( krb5_ctx ) ;
2007-01-24 02:48:40 +00:00
return ret ;
}
2010-01-28 02:05:05 -05:00
2019-11-22 22:39:09 +01:00
/*
* This is already called in smb_krb5_init_context_common ( ) ,
* but krb5_set_config_files ( ) may resets it .
*/
krb5_set_dns_canonicalize_hostname ( krb5_ctx , false ) ;
2010-07-16 14:32:42 +10:00
realm = lpcfg_realm ( lp_ctx ) ;
2009-10-12 19:09:18 +02:00
if ( realm ! = NULL ) {
2010-01-31 13:28:04 -05:00
ret = krb5_set_default_realm ( krb5_ctx , realm ) ;
2005-09-17 01:11:50 +00:00
if ( ret ) {
2010-01-28 02:05:05 -05:00
DEBUG ( 1 , ( " krb5_set_default_realm failed (%s) \n " ,
2010-01-31 13:28:04 -05:00
smb_get_krb5_error_message ( krb5_ctx , ret , tmp_ctx ) ) ) ;
krb5_free_context ( krb5_ctx ) ;
2005-09-17 01:11:50 +00:00
return ret ;
}
}
2016-02-03 14:58:47 +01:00
if ( smb_krb5_plugin_db = = NULL ) {
/*
* while krb5_plugin_register ( ) takes a krb5_context ,
* plugins are registered into a global list , so
* we only do that once
*
* We maintain a separate dispatch table for per
* krb5_context state .
*/
ret = krb5_plugin_register ( krb5_ctx , PLUGIN_TYPE_DATA ,
KRB5_PLUGIN_SEND_TO_KDC ,
& smb_krb5_plugin_ftable ) ;
if ( ret ) {
DEBUG ( 1 , ( " krb5_plugin_register(KRB5_PLUGIN_SEND_TO_KDC) failed (%s) \n " ,
smb_get_krb5_error_message ( krb5_ctx , ret , tmp_ctx ) ) ) ;
krb5_free_context ( krb5_ctx ) ;
return ret ;
}
smb_krb5_plugin_db = db_open_rbt ( NULL ) ;
if ( smb_krb5_plugin_db = = NULL ) {
DEBUG ( 1 , ( " db_open_rbt() failed \n " ) ) ;
krb5_free_context ( krb5_ctx ) ;
return ENOMEM ;
}
}
2012-04-25 10:31:12 -04:00
# endif
2010-01-31 13:28:04 -05:00
* _krb5_context = krb5_ctx ;
return 0 ;
}
krb5_error_code smb_krb5_init_context ( void * parent_ctx ,
struct loadparm_context * lp_ctx ,
2010-10-11 16:53:08 +11:00
struct smb_krb5_context * * smb_krb5_context )
2010-01-31 13:28:04 -05:00
{
krb5_error_code ret ;
TALLOC_CTX * tmp_ctx ;
2012-04-20 13:14:30 -04:00
krb5_context kctx ;
# ifdef SAMBA4_USES_HEIMDAL
krb5_log_facility * logf ;
# endif
2010-01-31 13:28:04 -05:00
tmp_ctx = talloc_new ( parent_ctx ) ;
2010-10-11 16:53:08 +11:00
* smb_krb5_context = talloc_zero ( tmp_ctx , struct smb_krb5_context ) ;
2010-01-31 13:28:04 -05:00
if ( ! * smb_krb5_context | | ! tmp_ctx ) {
talloc_free ( tmp_ctx ) ;
return ENOMEM ;
}
2012-04-20 13:14:30 -04:00
ret = smb_krb5_init_context_basic ( tmp_ctx , lp_ctx , & kctx ) ;
2010-01-31 13:28:04 -05:00
if ( ret ) {
DEBUG ( 1 , ( " smb_krb5_context_init_basic failed (%s) \n " ,
error_message ( ret ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2012-04-20 13:14:30 -04:00
( * smb_krb5_context ) - > krb5_context = kctx ;
2010-01-31 13:28:04 -05:00
2012-04-20 13:14:30 -04:00
talloc_set_destructor ( * smb_krb5_context , smb_krb5_context_destroy ) ;
# ifdef SAMBA4_USES_HEIMDAL
2005-09-17 01:11:50 +00:00
/* TODO: Should we have a different name here? */
2012-04-20 13:14:30 -04:00
ret = krb5_initlog ( kctx , " Samba " , & logf ) ;
2010-01-28 02:05:05 -05:00
2005-09-17 01:11:50 +00:00
if ( ret ) {
2010-01-28 02:05:05 -05:00
DEBUG ( 1 , ( " krb5_initlog failed (%s) \n " ,
2012-04-20 13:14:30 -04:00
smb_get_krb5_error_message ( kctx , ret , tmp_ctx ) ) ) ;
2005-09-17 01:11:50 +00:00
talloc_free ( tmp_ctx ) ;
return ret ;
}
2012-04-20 13:14:30 -04:00
( * smb_krb5_context ) - > pvt_log_data = logf ;
2005-09-17 01:11:50 +00:00
2012-04-20 13:14:30 -04:00
ret = krb5_addlog_func ( kctx , logf , 0 /* min */ , - 1 /* max */ ,
smb_krb5_debug_wrapper ,
smb_krb5_debug_close , NULL ) ;
2005-09-17 01:11:50 +00:00
if ( ret ) {
2010-01-28 02:05:05 -05:00
DEBUG ( 1 , ( " krb5_addlog_func failed (%s) \n " ,
2012-04-20 13:14:30 -04:00
smb_get_krb5_error_message ( kctx , ret , tmp_ctx ) ) ) ;
2005-09-17 01:11:50 +00:00
talloc_free ( tmp_ctx ) ;
return ret ;
}
2012-04-20 13:14:30 -04:00
krb5_set_warn_dest ( kctx , logf ) ;
# endif
talloc_steal ( parent_ctx , * smb_krb5_context ) ;
talloc_free ( tmp_ctx ) ;
2005-09-28 01:09:10 +00:00
2005-09-17 01:11:50 +00:00
return 0 ;
}
2012-04-21 16:35:48 -04:00
# ifdef SAMBA4_USES_HEIMDAL
2010-10-11 16:53:08 +11:00
krb5_error_code smb_krb5_context_set_event_ctx ( struct smb_krb5_context * smb_krb5_context ,
struct tevent_context * ev ,
struct tevent_context * * previous_ev )
{
int ret ;
if ( ! ev ) {
return EINVAL ;
}
2010-11-04 12:52:08 +11:00
* previous_ev = smb_krb5_context - > current_ev ;
2010-10-11 16:53:08 +11:00
smb_krb5_context - > current_ev = talloc_reference ( smb_krb5_context , ev ) ;
if ( ! smb_krb5_context - > current_ev ) {
return ENOMEM ;
}
/* Set use of our socket lib */
2016-02-03 14:58:47 +01:00
ret = smb_krb5_set_send_to_kdc_func ( smb_krb5_context ,
NULL , /* send_to_realm */
smb_krb5_send_and_recv_func ,
ev ) ;
2010-10-11 16:53:08 +11:00
if ( ret ) {
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
2016-02-03 14:58:47 +01:00
DEBUG ( 1 , ( " smb_krb5_set_send_recv_func failed (%s) \n " ,
2010-10-11 16:53:08 +11:00
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context , ret , tmp_ctx ) ) ) ;
talloc_free ( tmp_ctx ) ;
talloc_unlink ( smb_krb5_context , smb_krb5_context - > current_ev ) ;
smb_krb5_context - > current_ev = NULL ;
return ret ;
}
return 0 ;
}
krb5_error_code smb_krb5_context_remove_event_ctx ( struct smb_krb5_context * smb_krb5_context ,
struct tevent_context * previous_ev ,
struct tevent_context * ev )
{
int ret ;
talloc_unlink ( smb_krb5_context , ev ) ;
/* If there was a mismatch with things happening on a stack, then don't wipe things */
smb_krb5_context - > current_ev = previous_ev ;
/* Set use of our socket lib */
2016-02-03 14:58:47 +01:00
ret = smb_krb5_set_send_to_kdc_func ( smb_krb5_context ,
NULL , /* send_to_realm */
smb_krb5_send_and_recv_func ,
previous_ev ) ;
2010-10-11 16:53:08 +11:00
if ( ret ) {
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
2016-02-03 14:58:47 +01:00
DEBUG ( 1 , ( " smb_krb5_set_send_recv_func failed (%s) \n " ,
2010-10-11 16:53:08 +11:00
smb_get_krb5_error_message ( smb_krb5_context - > krb5_context , ret , tmp_ctx ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
return 0 ;
}
2012-04-21 16:35:48 -04:00
# endif