2005-06-19 08:20:27 +04:00
/*
Unix SMB / CIFS implementation .
transport layer security handling code
2006-05-03 00:15:47 +04:00
Copyright ( C ) Andrew Tridgell 2004 - 2005
Copyright ( C ) Stefan Metzmacher 2004
Copyright ( C ) Andrew Bartlett 2006
2005-06-19 08:20:27 +04: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 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-06-19 08:20:27 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-06-19 08:20:27 +04:00
*/
# include "includes.h"
# include "lib/events/events.h"
# include "lib/socket/socket.h"
2007-09-08 17:27:14 +04:00
# include "lib/tls/tls.h"
2007-09-08 19:06:47 +04:00
# include "param/param.h"
2005-06-19 08:20:27 +04:00
2006-08-22 03:00:53 +04:00
# if ENABLE_GNUTLS
2005-06-19 08:20:27 +04:00
# include "gnutls/gnutls.h"
# define DH_BITS 1024
2006-08-05 03:46:03 +04:00
# if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
2006-08-05 09:03:10 +04:00
typedef gnutls_datum gnutls_datum_t ;
2006-08-05 03:46:03 +04:00
# endif
2005-06-19 08:20:27 +04:00
/* hold persistent tls data */
struct tls_params {
gnutls_certificate_credentials x509_cred ;
gnutls_dh_params dh_params ;
2007-10-05 22:03:01 +04:00
bool tls_enabled ;
2005-06-19 08:20:27 +04:00
} ;
2006-05-03 00:15:47 +04:00
# endif
2005-06-19 08:20:27 +04:00
/* hold per connection tls data */
struct tls_context {
struct socket_context * socket ;
2008-12-29 22:24:57 +03:00
struct tevent_fd * fde ;
2007-10-05 22:03:01 +04:00
bool tls_enabled ;
2006-08-22 03:00:53 +04:00
# if ENABLE_GNUTLS
2005-06-19 08:20:27 +04:00
gnutls_session session ;
2007-10-05 22:03:01 +04:00
bool done_handshake ;
bool have_first_byte ;
2005-06-19 08:20:27 +04:00
uint8_t first_byte ;
2007-10-05 22:03:01 +04:00
bool tls_detect ;
2005-06-19 08:20:27 +04:00
const char * plain_chars ;
2007-10-05 22:03:01 +04:00
bool output_pending ;
2005-06-20 05:15:47 +04:00
gnutls_certificate_credentials xcred ;
2007-10-05 22:03:01 +04:00
bool interrupted ;
2006-05-03 00:15:47 +04:00
# endif
2005-06-19 08:20:27 +04:00
} ;
2007-10-05 22:03:01 +04:00
bool tls_enabled ( struct socket_context * sock )
2006-05-03 00:15:47 +04:00
{
struct tls_context * tls ;
if ( ! sock ) {
2007-10-05 22:03:01 +04:00
return false ;
2006-05-03 00:15:47 +04:00
}
if ( strcmp ( sock - > backend_name , " tls " ) ! = 0 ) {
2007-10-05 22:03:01 +04:00
return false ;
2006-05-03 00:15:47 +04:00
}
tls = talloc_get_type ( sock - > private_data , struct tls_context ) ;
if ( ! tls ) {
2007-10-05 22:03:01 +04:00
return false ;
2006-05-03 00:15:47 +04:00
}
return tls - > tls_enabled ;
}
2006-08-22 03:00:53 +04:00
# if ENABLE_GNUTLS
2006-05-03 00:15:47 +04:00
static const struct socket_ops tls_socket_ops ;
static NTSTATUS tls_socket_init ( struct socket_context * sock )
{
switch ( sock - > type ) {
case SOCKET_TYPE_STREAM :
break ;
default :
return NT_STATUS_INVALID_PARAMETER ;
}
sock - > backend_name = " tls " ;
return NT_STATUS_OK ;
}
2005-06-20 05:15:47 +04:00
# define TLSCHECK(call) do { \
ret = call ; \
if ( ret < 0 ) { \
DEBUG ( 0 , ( " TLS %s - %s \n " , # call , gnutls_strerror ( ret ) ) ) ; \
goto failed ; \
} \
} while ( 0 )
2005-06-19 08:20:27 +04:00
/*
callback for reading from a socket
*/
static ssize_t tls_pull ( gnutls_transport_ptr ptr , void * buf , size_t size )
{
struct tls_context * tls = talloc_get_type ( ptr , struct tls_context ) ;
NTSTATUS status ;
size_t nread ;
if ( tls - > have_first_byte ) {
* ( uint8_t * ) buf = tls - > first_byte ;
2007-10-05 22:03:01 +04:00
tls - > have_first_byte = false ;
2005-06-19 08:20:27 +04:00
return 1 ;
}
2006-04-30 09:58:31 +04:00
status = socket_recv ( tls - > socket , buf , size , & nread ) ;
2005-06-19 11:19:42 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_END_OF_FILE ) ) {
return 0 ;
}
if ( NT_STATUS_IS_ERR ( status ) ) {
EVENT_FD_NOT_READABLE ( tls - > fde ) ;
EVENT_FD_NOT_WRITEABLE ( tls - > fde ) ;
errno = EBADF ;
return - 1 ;
}
2005-06-19 08:20:27 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
EVENT_FD_READABLE ( tls - > fde ) ;
2005-06-19 11:19:42 +04:00
errno = EAGAIN ;
2005-06-19 08:20:27 +04:00
return - 1 ;
}
if ( tls - > output_pending ) {
EVENT_FD_WRITEABLE ( tls - > fde ) ;
}
if ( size ! = nread ) {
EVENT_FD_READABLE ( tls - > fde ) ;
}
return nread ;
}
/*
callback for writing to a socket
*/
static ssize_t tls_push ( gnutls_transport_ptr ptr , const void * buf , size_t size )
{
struct tls_context * tls = talloc_get_type ( ptr , struct tls_context ) ;
NTSTATUS status ;
size_t nwritten ;
DATA_BLOB b ;
if ( ! tls - > tls_enabled ) {
return size ;
}
b . data = discard_const ( buf ) ;
b . length = size ;
2006-04-30 09:58:31 +04:00
status = socket_send ( tls - > socket , & b , & nwritten ) ;
2005-06-19 15:00:13 +04:00
if ( NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) {
errno = EAGAIN ;
return - 1 ;
}
2005-06-19 08:20:27 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
EVENT_FD_WRITEABLE ( tls - > fde ) ;
return - 1 ;
}
if ( size ! = nwritten ) {
EVENT_FD_WRITEABLE ( tls - > fde ) ;
}
return nwritten ;
}
/*
destroy a tls session
*/
2006-05-24 11:34:11 +04:00
static int tls_destructor ( struct tls_context * tls )
2005-06-19 08:20:27 +04:00
{
int ret ;
ret = gnutls_bye ( tls - > session , GNUTLS_SHUT_WR ) ;
if ( ret < 0 ) {
2009-08-12 09:19:42 +04:00
DEBUG ( 4 , ( " TLS gnutls_bye failed - %s \n " , gnutls_strerror ( ret ) ) ) ;
2005-06-19 08:20:27 +04:00
}
return 0 ;
}
/*
possibly continue the handshake process
*/
static NTSTATUS tls_handshake ( struct tls_context * tls )
{
int ret ;
if ( tls - > done_handshake ) {
return NT_STATUS_OK ;
}
ret = gnutls_handshake ( tls - > session ) ;
if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
2005-06-20 05:15:47 +04:00
if ( gnutls_record_get_direction ( tls - > session ) = = 1 ) {
EVENT_FD_WRITEABLE ( tls - > fde ) ;
}
2005-06-19 08:20:27 +04:00
return STATUS_MORE_ENTRIES ;
}
if ( ret < 0 ) {
DEBUG ( 0 , ( " TLS gnutls_handshake failed - %s \n " , gnutls_strerror ( ret ) ) ) ;
return NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
}
2007-10-05 22:03:01 +04:00
tls - > done_handshake = true ;
2005-06-19 08:20:27 +04:00
return NT_STATUS_OK ;
}
2005-06-20 05:15:47 +04:00
/*
possibly continue an interrupted operation
*/
static NTSTATUS tls_interrupted ( struct tls_context * tls )
{
int ret ;
if ( ! tls - > interrupted ) {
return NT_STATUS_OK ;
}
if ( gnutls_record_get_direction ( tls - > session ) = = 1 ) {
ret = gnutls_record_send ( tls - > session , NULL , 0 ) ;
} else {
ret = gnutls_record_recv ( tls - > session , NULL , 0 ) ;
}
if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
return STATUS_MORE_ENTRIES ;
}
2007-10-05 22:03:01 +04:00
tls - > interrupted = false ;
2005-06-20 05:15:47 +04:00
return NT_STATUS_OK ;
}
2005-06-19 13:31:34 +04:00
/*
see how many bytes are pending on the connection
*/
2006-05-03 00:15:47 +04:00
static NTSTATUS tls_socket_pending ( struct socket_context * sock , size_t * npending )
2005-06-19 13:31:34 +04:00
{
2006-05-03 00:15:47 +04:00
struct tls_context * tls = talloc_get_type ( sock - > private_data , struct tls_context ) ;
2005-06-19 13:31:34 +04:00
if ( ! tls - > tls_enabled | | tls - > tls_detect ) {
return socket_pending ( tls - > socket , npending ) ;
}
* npending = gnutls_record_check_pending ( tls - > session ) ;
if ( * npending = = 0 ) {
2005-06-20 05:15:47 +04:00
NTSTATUS status = socket_pending ( tls - > socket , npending ) ;
if ( * npending = = 0 ) {
/* seems to be a gnutls bug */
( * npending ) = 100 ;
}
return status ;
2005-06-19 13:31:34 +04:00
}
return NT_STATUS_OK ;
}
2005-06-19 08:20:27 +04:00
/*
receive data either by tls or normal socket_recv
*/
2006-05-03 00:15:47 +04:00
static NTSTATUS tls_socket_recv ( struct socket_context * sock , void * buf ,
size_t wantlen , size_t * nread )
2005-06-19 08:20:27 +04:00
{
int ret ;
NTSTATUS status ;
2006-05-03 00:15:47 +04:00
struct tls_context * tls = talloc_get_type ( sock - > private_data , struct tls_context ) ;
2005-06-19 08:20:27 +04:00
if ( tls - > tls_enabled & & tls - > tls_detect ) {
2006-04-30 09:58:31 +04:00
status = socket_recv ( tls - > socket , & tls - > first_byte , 1 , nread ) ;
2005-06-19 08:20:27 +04:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
if ( * nread = = 0 ) return NT_STATUS_OK ;
2007-10-05 22:03:01 +04:00
tls - > tls_detect = false ;
2005-06-19 08:20:27 +04:00
/* look for the first byte of a valid HTTP operation */
if ( strchr ( tls - > plain_chars , tls - > first_byte ) ) {
/* not a tls link */
2007-10-05 22:03:01 +04:00
tls - > tls_enabled = false ;
2005-06-19 08:20:27 +04:00
* ( uint8_t * ) buf = tls - > first_byte ;
return NT_STATUS_OK ;
}
2007-10-05 22:03:01 +04:00
tls - > have_first_byte = true ;
2005-06-19 08:20:27 +04:00
}
if ( ! tls - > tls_enabled ) {
2006-04-30 09:58:31 +04:00
return socket_recv ( tls - > socket , buf , wantlen , nread ) ;
2005-06-19 08:20:27 +04:00
}
status = tls_handshake ( tls ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-06-20 05:15:47 +04:00
status = tls_interrupted ( tls ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-06-19 08:20:27 +04:00
ret = gnutls_record_recv ( tls - > session , buf , wantlen ) ;
if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
2005-06-20 05:15:47 +04:00
if ( gnutls_record_get_direction ( tls - > session ) = = 1 ) {
EVENT_FD_WRITEABLE ( tls - > fde ) ;
}
2007-10-05 22:03:01 +04:00
tls - > interrupted = true ;
2005-06-19 08:20:27 +04:00
return STATUS_MORE_ENTRIES ;
}
if ( ret < 0 ) {
return NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
}
* nread = ret ;
return NT_STATUS_OK ;
}
/*
send data either by tls or normal socket_recv
*/
2006-05-03 00:15:47 +04:00
static NTSTATUS tls_socket_send ( struct socket_context * sock ,
const DATA_BLOB * blob , size_t * sendlen )
2005-06-19 08:20:27 +04:00
{
NTSTATUS status ;
int ret ;
2006-05-03 00:15:47 +04:00
struct tls_context * tls = talloc_get_type ( sock - > private_data , struct tls_context ) ;
2005-06-19 08:20:27 +04:00
if ( ! tls - > tls_enabled ) {
2006-04-30 09:58:31 +04:00
return socket_send ( tls - > socket , blob , sendlen ) ;
2005-06-19 08:20:27 +04:00
}
status = tls_handshake ( tls ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-06-20 05:15:47 +04:00
status = tls_interrupted ( tls ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-06-19 08:20:27 +04:00
ret = gnutls_record_send ( tls - > session , blob - > data , blob - > length ) ;
if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
2005-06-20 05:15:47 +04:00
if ( gnutls_record_get_direction ( tls - > session ) = = 1 ) {
EVENT_FD_WRITEABLE ( tls - > fde ) ;
}
2007-10-05 22:03:01 +04:00
tls - > interrupted = true ;
2005-06-19 08:20:27 +04:00
return STATUS_MORE_ENTRIES ;
}
if ( ret < 0 ) {
2006-09-09 14:05:58 +04:00
DEBUG ( 0 , ( " gnutls_record_send of %d failed - %s \n " , ( int ) blob - > length , gnutls_strerror ( ret ) ) ) ;
2005-06-19 08:20:27 +04:00
return NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
}
* sendlen = ret ;
tls - > output_pending = ( ret < blob - > length ) ;
return NT_STATUS_OK ;
}
/*
initialise global tls state
*/
2007-12-03 02:28:22 +03:00
struct tls_params * tls_initialise ( TALLOC_CTX * mem_ctx , struct loadparm_context * lp_ctx )
2005-06-19 08:20:27 +04:00
{
struct tls_params * params ;
int ret ;
2005-06-26 04:12:44 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
2008-10-23 23:49:40 +04:00
const char * keyfile = lp_tls_keyfile ( tmp_ctx , lp_ctx ) ;
const char * certfile = lp_tls_certfile ( tmp_ctx , lp_ctx ) ;
const char * cafile = lp_tls_cafile ( tmp_ctx , lp_ctx ) ;
const char * crlfile = lp_tls_crlfile ( tmp_ctx , lp_ctx ) ;
const char * dhpfile = lp_tls_dhpfile ( tmp_ctx , lp_ctx ) ;
2009-02-18 06:46:57 +03:00
void tls_cert_generate ( TALLOC_CTX * , const char * , const char * , const char * , const char * ) ;
2005-06-19 08:20:27 +04:00
params = talloc ( mem_ctx , struct tls_params ) ;
2005-06-26 04:12:44 +04:00
if ( params = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
2005-06-19 08:20:27 +04:00
2007-12-03 02:28:22 +03:00
if ( ! lp_tls_enabled ( lp_ctx ) | | keyfile = = NULL | | * keyfile = = 0 ) {
2007-10-05 22:03:01 +04:00
params - > tls_enabled = false ;
2005-06-26 04:12:44 +04:00
talloc_free ( tmp_ctx ) ;
2005-06-19 08:20:27 +04:00
return params ;
}
if ( ! file_exist ( cafile ) ) {
2009-02-18 06:46:57 +03:00
char * hostname = talloc_asprintf ( mem_ctx , " %s.%s " ,
2009-10-12 21:09:18 +04:00
lp_netbios_name ( lp_ctx ) ,
lp_dnsdomain ( lp_ctx ) ) ;
2009-02-18 06:46:57 +03:00
if ( hostname = = NULL ) {
goto init_failed ;
}
tls_cert_generate ( params , hostname , keyfile , certfile , cafile ) ;
talloc_free ( hostname ) ;
2005-06-19 08:20:27 +04:00
}
ret = gnutls_global_init ( ) ;
if ( ret < 0 ) goto init_failed ;
gnutls_certificate_allocate_credentials ( & params - > x509_cred ) ;
if ( ret < 0 ) goto init_failed ;
if ( cafile & & * cafile ) {
ret = gnutls_certificate_set_x509_trust_file ( params - > x509_cred , cafile ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " TLS failed to initialise cafile %s \n " , cafile ) ) ;
goto init_failed ;
}
}
if ( crlfile & & * crlfile ) {
ret = gnutls_certificate_set_x509_crl_file ( params - > x509_cred ,
crlfile ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " TLS failed to initialise crlfile %s \n " , crlfile ) ) ;
goto init_failed ;
}
}
ret = gnutls_certificate_set_x509_key_file ( params - > x509_cred ,
certfile , keyfile ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " TLS failed to initialise certfile %s and keyfile %s \n " ,
certfile , keyfile ) ) ;
goto init_failed ;
}
2006-08-03 12:02:54 +04:00
2005-06-19 08:20:27 +04:00
ret = gnutls_dh_params_init ( & params - > dh_params ) ;
if ( ret < 0 ) goto init_failed ;
2006-10-10 08:22:00 +04:00
if ( dhpfile & & * dhpfile ) {
2006-08-03 12:02:54 +04:00
gnutls_datum_t dhparms ;
2006-09-09 14:05:58 +04:00
size_t size ;
2008-10-12 19:34:43 +04:00
dhparms . data = ( uint8_t * ) file_load ( dhpfile , & size , 0 , mem_ctx ) ;
2005-06-19 08:20:27 +04:00
2006-08-03 12:02:54 +04:00
if ( ! dhparms . data ) {
2006-10-10 08:22:00 +04:00
DEBUG ( 0 , ( " Failed to read DH Parms from %s \n " , dhpfile ) ) ;
2006-08-03 12:02:54 +04:00
goto init_failed ;
}
2006-09-09 14:05:58 +04:00
dhparms . size = size ;
2006-08-03 12:02:54 +04:00
ret = gnutls_dh_params_import_pkcs3 ( params - > dh_params , & dhparms , GNUTLS_X509_FMT_PEM ) ;
if ( ret < 0 ) goto init_failed ;
} else {
ret = gnutls_dh_params_generate2 ( params - > dh_params , DH_BITS ) ;
if ( ret < 0 ) goto init_failed ;
}
2005-06-19 08:20:27 +04:00
gnutls_certificate_set_dh_params ( params - > x509_cred , params - > dh_params ) ;
2007-10-05 22:03:01 +04:00
params - > tls_enabled = true ;
2005-06-20 05:15:47 +04:00
2005-06-26 04:12:44 +04:00
talloc_free ( tmp_ctx ) ;
2005-06-19 08:20:27 +04:00
return params ;
init_failed :
DEBUG ( 0 , ( " GNUTLS failed to initialise - %s \n " , gnutls_strerror ( ret ) ) ) ;
2007-10-05 22:03:01 +04:00
params - > tls_enabled = false ;
2005-06-26 04:12:44 +04:00
talloc_free ( tmp_ctx ) ;
2005-06-19 08:20:27 +04:00
return params ;
}
/*
setup for a new connection
*/
2006-05-03 00:15:47 +04:00
struct socket_context * tls_init_server ( struct tls_params * params ,
2008-12-24 01:22:57 +03:00
struct socket_context * socket_ctx ,
2008-12-29 22:24:57 +03:00
struct tevent_fd * fde ,
2006-07-25 04:57:27 +04:00
const char * plain_chars )
2005-06-19 08:20:27 +04:00
{
struct tls_context * tls ;
int ret ;
2006-05-03 00:15:47 +04:00
struct socket_context * new_sock ;
NTSTATUS nt_status ;
2008-12-24 01:22:57 +03:00
nt_status = socket_create_with_ops ( socket_ctx , & tls_socket_ops , & new_sock ,
2006-07-21 05:34:56 +04:00
SOCKET_TYPE_STREAM ,
2008-12-24 01:22:57 +03:00
socket_ctx - > flags | SOCKET_FLAG_ENCRYPT ) ;
2006-05-03 00:15:47 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return NULL ;
}
2005-06-19 08:20:27 +04:00
2006-05-03 00:15:47 +04:00
tls = talloc ( new_sock , struct tls_context ) ;
if ( tls = = NULL ) {
return NULL ;
}
2005-06-19 08:20:27 +04:00
2008-12-24 01:22:57 +03:00
tls - > socket = socket_ctx ;
2009-07-30 10:40:29 +04:00
talloc_steal ( tls , socket_ctx ) ;
2005-06-19 08:20:27 +04:00
tls - > fde = fde ;
2006-05-03 00:15:47 +04:00
new_sock - > private_data = tls ;
2005-06-19 08:20:27 +04:00
2006-05-03 00:15:47 +04:00
if ( ! params - > tls_enabled ) {
2006-07-25 04:57:27 +04:00
talloc_free ( new_sock ) ;
return NULL ;
2005-06-19 08:20:27 +04:00
}
TLSCHECK ( gnutls_init ( & tls - > session , GNUTLS_SERVER ) ) ;
talloc_set_destructor ( tls , tls_destructor ) ;
TLSCHECK ( gnutls_set_default_priority ( tls - > session ) ) ;
TLSCHECK ( gnutls_credentials_set ( tls - > session , GNUTLS_CRD_CERTIFICATE ,
params - > x509_cred ) ) ;
gnutls_certificate_server_set_request ( tls - > session , GNUTLS_CERT_REQUEST ) ;
gnutls_dh_set_prime_bits ( tls - > session , DH_BITS ) ;
gnutls_transport_set_ptr ( tls - > session , ( gnutls_transport_ptr ) tls ) ;
gnutls_transport_set_pull_function ( tls - > session , ( gnutls_pull_func ) tls_pull ) ;
gnutls_transport_set_push_function ( tls - > session , ( gnutls_push_func ) tls_push ) ;
gnutls_transport_set_lowat ( tls - > session , 0 ) ;
tls - > plain_chars = plain_chars ;
if ( plain_chars ) {
2007-10-05 22:03:01 +04:00
tls - > tls_detect = true ;
2005-06-19 08:20:27 +04:00
} else {
2007-10-05 22:03:01 +04:00
tls - > tls_detect = false ;
2005-06-19 08:20:27 +04:00
}
2007-10-05 22:03:01 +04:00
tls - > output_pending = false ;
tls - > done_handshake = false ;
tls - > have_first_byte = false ;
tls - > tls_enabled = true ;
tls - > interrupted = false ;
2005-06-19 08:20:27 +04:00
2006-05-03 00:15:47 +04:00
new_sock - > state = SOCKET_STATE_SERVER_CONNECTED ;
return new_sock ;
2005-06-19 08:20:27 +04:00
failed :
DEBUG ( 0 , ( " TLS init connection failed - %s \n " , gnutls_strerror ( ret ) ) ) ;
2006-07-25 04:57:27 +04:00
talloc_free ( new_sock ) ;
return NULL ;
2005-06-19 08:20:27 +04:00
}
2005-06-20 05:15:47 +04:00
/*
setup for a new client connection
*/
2008-12-24 01:22:57 +03:00
struct socket_context * tls_init_client ( struct socket_context * socket_ctx ,
2008-12-29 22:24:57 +03:00
struct tevent_fd * fde ,
2007-12-03 02:28:22 +03:00
const char * ca_path )
2005-06-20 05:15:47 +04:00
{
struct tls_context * tls ;
2006-05-03 00:15:47 +04:00
int ret = 0 ;
2005-06-20 05:15:47 +04:00
const int cert_type_priority [ ] = { GNUTLS_CRT_X509 , GNUTLS_CRT_OPENPGP , 0 } ;
2006-05-03 00:15:47 +04:00
struct socket_context * new_sock ;
NTSTATUS nt_status ;
2008-12-24 01:22:57 +03:00
nt_status = socket_create_with_ops ( socket_ctx , & tls_socket_ops , & new_sock ,
2006-07-21 05:34:56 +04:00
SOCKET_TYPE_STREAM ,
2008-12-24 01:22:57 +03:00
socket_ctx - > flags | SOCKET_FLAG_ENCRYPT ) ;
2006-05-03 00:15:47 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return NULL ;
}
2005-06-26 04:12:44 +04:00
2006-05-03 00:15:47 +04:00
tls = talloc ( new_sock , struct tls_context ) ;
2005-06-20 05:15:47 +04:00
if ( tls = = NULL ) return NULL ;
2008-12-24 01:22:57 +03:00
tls - > socket = socket_ctx ;
2009-07-30 10:42:42 +04:00
talloc_steal ( tls , socket_ctx ) ;
2005-06-20 05:15:47 +04:00
tls - > fde = fde ;
2009-07-30 10:42:42 +04:00
2006-05-03 00:15:47 +04:00
new_sock - > private_data = tls ;
2005-06-20 05:15:47 +04:00
gnutls_global_init ( ) ;
gnutls_certificate_allocate_credentials ( & tls - > xcred ) ;
2009-06-18 13:16:16 +04:00
gnutls_certificate_set_x509_trust_file ( tls - > xcred , ca_path , GNUTLS_X509_FMT_PEM ) ;
2005-06-20 05:15:47 +04:00
TLSCHECK ( gnutls_init ( & tls - > session , GNUTLS_CLIENT ) ) ;
TLSCHECK ( gnutls_set_default_priority ( tls - > session ) ) ;
gnutls_certificate_type_set_priority ( tls - > session , cert_type_priority ) ;
TLSCHECK ( gnutls_credentials_set ( tls - > session , GNUTLS_CRD_CERTIFICATE , tls - > xcred ) ) ;
talloc_set_destructor ( tls , tls_destructor ) ;
gnutls_transport_set_ptr ( tls - > session , ( gnutls_transport_ptr ) tls ) ;
gnutls_transport_set_pull_function ( tls - > session , ( gnutls_pull_func ) tls_pull ) ;
gnutls_transport_set_push_function ( tls - > session , ( gnutls_push_func ) tls_push ) ;
gnutls_transport_set_lowat ( tls - > session , 0 ) ;
2007-10-05 22:03:01 +04:00
tls - > tls_detect = false ;
2005-06-20 05:15:47 +04:00
2007-10-05 22:03:01 +04:00
tls - > output_pending = false ;
tls - > done_handshake = false ;
tls - > have_first_byte = false ;
tls - > tls_enabled = true ;
tls - > interrupted = false ;
2005-06-20 05:15:47 +04:00
2006-05-03 00:15:47 +04:00
new_sock - > state = SOCKET_STATE_CLIENT_CONNECTED ;
return new_sock ;
2005-06-20 05:15:47 +04:00
failed :
DEBUG ( 0 , ( " TLS init connection failed - %s \n " , gnutls_strerror ( ret ) ) ) ;
2007-10-05 22:03:01 +04:00
tls - > tls_enabled = false ;
2006-05-03 00:15:47 +04:00
return new_sock ;
2005-06-20 05:15:47 +04:00
}
2006-05-03 00:15:47 +04:00
static NTSTATUS tls_socket_set_option ( struct socket_context * sock , const char * option , const char * val )
2005-06-19 08:20:27 +04:00
{
2006-05-03 00:15:47 +04:00
set_socket_options ( socket_get_fd ( sock ) , option ) ;
return NT_STATUS_OK ;
2005-06-19 08:20:27 +04:00
}
2006-05-03 00:15:47 +04:00
static char * tls_socket_get_peer_name ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
2005-06-19 08:20:27 +04:00
{
2006-05-03 00:15:47 +04:00
struct tls_context * tls = talloc_get_type ( sock - > private_data , struct tls_context ) ;
return socket_get_peer_name ( tls - > socket , mem_ctx ) ;
2005-06-19 08:20:27 +04:00
}
2006-05-03 00:15:47 +04:00
static struct socket_address * tls_socket_get_peer_addr ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
2005-06-19 08:20:27 +04:00
{
2006-05-03 00:15:47 +04:00
struct tls_context * tls = talloc_get_type ( sock - > private_data , struct tls_context ) ;
return socket_get_peer_addr ( tls - > socket , mem_ctx ) ;
2005-06-19 08:20:27 +04:00
}
2006-05-03 00:15:47 +04:00
static struct socket_address * tls_socket_get_my_addr ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
2005-06-19 08:20:27 +04:00
{
2006-05-03 00:15:47 +04:00
struct tls_context * tls = talloc_get_type ( sock - > private_data , struct tls_context ) ;
return socket_get_my_addr ( tls - > socket , mem_ctx ) ;
2005-06-19 08:20:27 +04:00
}
2006-05-03 00:15:47 +04:00
static int tls_socket_get_fd ( struct socket_context * sock )
2005-06-20 05:15:47 +04:00
{
2006-05-03 00:15:47 +04:00
struct tls_context * tls = talloc_get_type ( sock - > private_data , struct tls_context ) ;
return socket_get_fd ( tls - > socket ) ;
2005-06-20 05:15:47 +04:00
}
2006-05-03 00:15:47 +04:00
static const struct socket_ops tls_socket_ops = {
. name = " tls " ,
. fn_init = tls_socket_init ,
. fn_recv = tls_socket_recv ,
. fn_send = tls_socket_send ,
. fn_pending = tls_socket_pending ,
. fn_set_option = tls_socket_set_option ,
2005-06-19 08:20:27 +04:00
2006-05-03 00:15:47 +04:00
. fn_get_peer_name = tls_socket_get_peer_name ,
. fn_get_peer_addr = tls_socket_get_peer_addr ,
. fn_get_my_addr = tls_socket_get_my_addr ,
. fn_get_fd = tls_socket_get_fd
} ;
2007-10-05 22:03:01 +04:00
bool tls_support ( struct tls_params * params )
2005-06-19 08:20:27 +04:00
{
2006-05-03 00:15:47 +04:00
return params - > tls_enabled ;
2005-06-19 08:20:27 +04:00
}
2006-05-03 00:15:47 +04:00
# else
2006-07-28 07:51:20 +04:00
/* for systems without tls we just fail the operations, and the caller
* will retain the original socket */
2006-05-03 00:15:47 +04:00
2007-12-03 02:28:22 +03:00
struct tls_params * tls_initialise ( TALLOC_CTX * mem_ctx , struct loadparm_context * lp_ctx )
2005-06-19 08:20:27 +04:00
{
2006-05-03 00:15:47 +04:00
return talloc_new ( mem_ctx ) ;
2005-06-19 08:20:27 +04:00
}
2006-05-03 00:15:47 +04:00
/*
setup for a new connection
*/
struct socket_context * tls_init_server ( struct tls_params * params ,
struct socket_context * socket ,
2008-12-29 22:24:57 +03:00
struct tevent_fd * fde ,
2006-05-03 00:15:47 +04:00
const char * plain_chars )
2005-06-19 08:20:27 +04:00
{
2006-07-25 04:57:27 +04:00
return NULL ;
2005-06-19 08:20:27 +04:00
}
2006-05-03 00:15:47 +04:00
/*
setup for a new client connection
*/
struct socket_context * tls_init_client ( struct socket_context * socket ,
2008-12-29 22:24:57 +03:00
struct tevent_fd * fde ,
2007-12-03 02:28:22 +03:00
const char * ca_path )
2005-06-19 08:20:27 +04:00
{
2006-07-25 04:57:27 +04:00
return NULL ;
2005-06-19 08:20:27 +04:00
}
2007-10-05 22:03:01 +04:00
bool tls_support ( struct tls_params * params )
2005-06-19 13:31:34 +04:00
{
2007-10-05 22:03:01 +04:00
return false ;
2005-06-19 13:31:34 +04:00
}
2005-06-19 08:20:27 +04:00
# endif
2006-05-03 00:15:47 +04:00