2010-02-03 16:36:10 +03:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Stefan Metzmacher 2010
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"
# include "system/network.h"
2013-10-29 20:53:59 +04:00
# include "system/filesys.h"
2015-12-23 18:17:04 +03:00
# include "system/time.h"
2010-02-03 16:36:10 +03:00
# include "../util/tevent_unix.h"
# include "../lib/tsocket/tsocket.h"
# include "../lib/tsocket/tsocket_internal.h"
2015-12-23 18:17:04 +03:00
# include "../lib/util/util_net.h"
2010-02-03 16:36:10 +03:00
# include "lib/tls/tls.h"
2012-02-18 01:58:07 +04:00
# include <gnutls/gnutls.h>
2015-12-23 18:17:04 +03:00
# include <gnutls/x509.h>
2010-02-03 16:36:10 +03:00
2015-09-02 13:37:12 +03:00
# define DH_BITS 2048
2010-02-03 16:36:10 +03:00
2015-12-23 18:17:04 +03:00
const char * tls_verify_peer_string ( enum tls_verify_peer_state verify_peer )
{
switch ( verify_peer ) {
case TLS_VERIFY_PEER_NO_CHECK :
return TLS_VERIFY_PEER_NO_CHECK_STRING ;
case TLS_VERIFY_PEER_CA_ONLY :
return TLS_VERIFY_PEER_CA_ONLY_STRING ;
case TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE :
return TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING ;
case TLS_VERIFY_PEER_CA_AND_NAME :
return TLS_VERIFY_PEER_CA_AND_NAME_STRING ;
case TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE :
return TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING ;
}
return " unknown tls_verify_peer_state " ;
}
2010-02-03 16:36:10 +03:00
static const struct tstream_context_ops tstream_tls_ops ;
struct tstream_tls {
struct tstream_context * plain_stream ;
int error ;
2017-05-09 14:17:13 +03:00
gnutls_session_t tls_session ;
2010-02-03 16:36:10 +03:00
2015-12-23 18:17:04 +03:00
enum tls_verify_peer_state verify_peer ;
const char * peer_name ;
2010-02-03 16:36:10 +03:00
struct tevent_context * current_ev ;
2010-10-08 11:39:49 +04:00
struct tevent_immediate * retry_im ;
2010-02-03 16:36:10 +03:00
2010-10-08 12:19:07 +04:00
struct {
2010-11-29 14:27:11 +03:00
uint8_t * buf ;
2010-10-08 12:19:07 +04:00
off_t ofs ;
struct iovec iov ;
struct tevent_req * subreq ;
struct tevent_immediate * im ;
} push ;
2010-02-03 16:36:10 +03:00
struct {
2010-12-14 17:24:22 +03:00
uint8_t * buf ;
2010-02-03 16:36:10 +03:00
struct iovec iov ;
struct tevent_req * subreq ;
2010-10-08 12:19:07 +04:00
} pull ;
2010-02-03 16:36:10 +03:00
struct {
struct tevent_req * req ;
} handshake ;
struct {
off_t ofs ;
size_t left ;
uint8_t buffer [ 1024 ] ;
struct tevent_req * req ;
} write ;
struct {
off_t ofs ;
size_t left ;
uint8_t buffer [ 1024 ] ;
struct tevent_req * req ;
} read ;
struct {
struct tevent_req * req ;
} disconnect ;
} ;
static void tstream_tls_retry_handshake ( struct tstream_context * stream ) ;
static void tstream_tls_retry_read ( struct tstream_context * stream ) ;
static void tstream_tls_retry_write ( struct tstream_context * stream ) ;
static void tstream_tls_retry_disconnect ( struct tstream_context * stream ) ;
static void tstream_tls_retry_trigger ( struct tevent_context * ctx ,
struct tevent_immediate * im ,
void * private_data ) ;
static void tstream_tls_retry ( struct tstream_context * stream , bool deferred )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
if ( tlss - > disconnect . req ) {
tstream_tls_retry_disconnect ( stream ) ;
return ;
}
if ( tlss - > handshake . req ) {
tstream_tls_retry_handshake ( stream ) ;
return ;
}
if ( tlss - > write . req & & tlss - > read . req & & ! deferred ) {
2010-10-08 11:39:49 +04:00
tevent_schedule_immediate ( tlss - > retry_im , tlss - > current_ev ,
2010-02-03 16:36:10 +03:00
tstream_tls_retry_trigger ,
stream ) ;
}
if ( tlss - > write . req ) {
tstream_tls_retry_write ( stream ) ;
return ;
}
if ( tlss - > read . req ) {
tstream_tls_retry_read ( stream ) ;
return ;
}
}
static void tstream_tls_retry_trigger ( struct tevent_context * ctx ,
struct tevent_immediate * im ,
void * private_data )
{
struct tstream_context * stream =
talloc_get_type_abort ( private_data ,
struct tstream_context ) ;
tstream_tls_retry ( stream , true ) ;
}
2010-10-08 12:19:07 +04:00
static void tstream_tls_push_trigger_write ( struct tevent_context * ev ,
struct tevent_immediate * im ,
void * private_data ) ;
2010-02-03 16:36:10 +03:00
2017-05-09 14:17:13 +03:00
static ssize_t tstream_tls_push_function ( gnutls_transport_ptr_t ptr ,
2010-02-03 16:36:10 +03:00
const void * buf , size_t size )
{
struct tstream_context * stream =
talloc_get_type_abort ( ptr ,
struct tstream_context ) ;
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
2010-11-29 14:27:11 +03:00
uint8_t * nbuf ;
2010-10-08 12:19:07 +04:00
size_t len ;
2010-02-03 16:36:10 +03:00
if ( tlss - > error ! = 0 ) {
errno = tlss - > error ;
return - 1 ;
}
if ( tlss - > push . subreq ) {
errno = EAGAIN ;
return - 1 ;
}
2010-11-29 14:27:11 +03:00
len = MIN ( size , UINT16_MAX - tlss - > push . ofs ) ;
if ( len = = 0 ) {
2010-10-08 12:19:07 +04:00
errno = EAGAIN ;
return - 1 ;
}
2010-11-29 14:27:11 +03:00
nbuf = talloc_realloc ( tlss , tlss - > push . buf ,
uint8_t , tlss - > push . ofs + len ) ;
if ( nbuf = = NULL ) {
if ( tlss - > push . buf ) {
errno = EAGAIN ;
return - 1 ;
}
return - 1 ;
}
tlss - > push . buf = nbuf ;
memcpy ( tlss - > push . buf + tlss - > push . ofs , buf , len ) ;
2010-10-08 12:19:07 +04:00
if ( tlss - > push . im = = NULL ) {
tlss - > push . im = tevent_create_immediate ( tlss ) ;
if ( tlss - > push . im = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
}
if ( tlss - > push . ofs = = 0 ) {
/*
* We ' ll do start the tstream_writev
* in the next event cycle .
*
* This way we can batch all push requests ,
2010-11-29 14:27:11 +03:00
* if they fit into a UINT16_MAX buffer .
2010-10-08 12:19:07 +04:00
*
* This is important as gnutls_handshake ( )
* had a bug in some versions e . g . 2.4 .1
* and others ( See bug # 7218 ) and it doesn ' t
* handle EAGAIN .
*/
tevent_schedule_immediate ( tlss - > push . im ,
tlss - > current_ev ,
tstream_tls_push_trigger_write ,
stream ) ;
}
tlss - > push . ofs + = len ;
return len ;
}
static void tstream_tls_push_done ( struct tevent_req * subreq ) ;
2010-02-03 16:36:10 +03:00
2010-10-08 12:19:07 +04:00
static void tstream_tls_push_trigger_write ( struct tevent_context * ev ,
struct tevent_immediate * im ,
void * private_data )
{
struct tstream_context * stream =
talloc_get_type_abort ( private_data ,
struct tstream_context ) ;
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * subreq ;
if ( tlss - > push . subreq ) {
/* nothing todo */
return ;
}
2010-11-29 14:27:11 +03:00
tlss - > push . iov . iov_base = ( char * ) tlss - > push . buf ;
2010-10-08 12:19:07 +04:00
tlss - > push . iov . iov_len = tlss - > push . ofs ;
2010-02-03 16:36:10 +03:00
subreq = tstream_writev_send ( tlss ,
tlss - > current_ev ,
tlss - > plain_stream ,
& tlss - > push . iov , 1 ) ;
if ( subreq = = NULL ) {
2010-10-08 12:19:07 +04:00
tlss - > error = ENOMEM ;
tstream_tls_retry ( stream , false ) ;
return ;
2010-02-03 16:36:10 +03:00
}
tevent_req_set_callback ( subreq , tstream_tls_push_done , stream ) ;
tlss - > push . subreq = subreq ;
}
static void tstream_tls_push_done ( struct tevent_req * subreq )
{
struct tstream_context * stream =
tevent_req_callback_data ( subreq ,
struct tstream_context ) ;
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
int ret ;
int sys_errno ;
tlss - > push . subreq = NULL ;
ZERO_STRUCT ( tlss - > push . iov ) ;
2010-11-29 14:27:11 +03:00
TALLOC_FREE ( tlss - > push . buf ) ;
2010-10-08 12:19:07 +04:00
tlss - > push . ofs = 0 ;
2010-02-03 16:36:10 +03:00
ret = tstream_writev_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
if ( ret = = - 1 ) {
tlss - > error = sys_errno ;
tstream_tls_retry ( stream , false ) ;
return ;
}
tstream_tls_retry ( stream , false ) ;
}
static void tstream_tls_pull_done ( struct tevent_req * subreq ) ;
2017-05-09 14:17:13 +03:00
static ssize_t tstream_tls_pull_function ( gnutls_transport_ptr_t ptr ,
2010-02-03 16:36:10 +03:00
void * buf , size_t size )
{
struct tstream_context * stream =
talloc_get_type_abort ( ptr ,
struct tstream_context ) ;
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * subreq ;
2010-12-14 17:24:22 +03:00
size_t len ;
2010-02-03 16:36:10 +03:00
if ( tlss - > error ! = 0 ) {
errno = tlss - > error ;
return - 1 ;
}
if ( tlss - > pull . subreq ) {
errno = EAGAIN ;
return - 1 ;
}
if ( tlss - > pull . iov . iov_base ) {
2010-12-14 17:00:15 +03:00
uint8_t * b ;
2010-02-03 16:36:10 +03:00
size_t n ;
2010-12-14 17:00:15 +03:00
b = ( uint8_t * ) tlss - > pull . iov . iov_base ;
2010-02-03 16:36:10 +03:00
n = MIN ( tlss - > pull . iov . iov_len , size ) ;
2010-12-14 17:00:15 +03:00
memcpy ( buf , b , n ) ;
2010-02-03 16:36:10 +03:00
tlss - > pull . iov . iov_len - = n ;
2010-12-14 17:00:15 +03:00
b + = n ;
tlss - > pull . iov . iov_base = ( char * ) b ;
2010-02-03 16:36:10 +03:00
if ( tlss - > pull . iov . iov_len = = 0 ) {
tlss - > pull . iov . iov_base = NULL ;
2010-12-14 17:24:22 +03:00
TALLOC_FREE ( tlss - > pull . buf ) ;
2010-02-03 16:36:10 +03:00
}
return n ;
}
if ( size = = 0 ) {
return 0 ;
}
2010-12-14 17:24:22 +03:00
len = MIN ( size , UINT16_MAX ) ;
tlss - > pull . buf = talloc_array ( tlss , uint8_t , len ) ;
if ( tlss - > pull . buf = = NULL ) {
return - 1 ;
}
tlss - > pull . iov . iov_base = ( char * ) tlss - > pull . buf ;
tlss - > pull . iov . iov_len = len ;
2010-02-03 16:36:10 +03:00
subreq = tstream_readv_send ( tlss ,
tlss - > current_ev ,
tlss - > plain_stream ,
& tlss - > pull . iov , 1 ) ;
if ( subreq = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
tevent_req_set_callback ( subreq , tstream_tls_pull_done , stream ) ;
tlss - > pull . subreq = subreq ;
errno = EAGAIN ;
return - 1 ;
}
static void tstream_tls_pull_done ( struct tevent_req * subreq )
{
struct tstream_context * stream =
tevent_req_callback_data ( subreq ,
struct tstream_context ) ;
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
int ret ;
int sys_errno ;
tlss - > pull . subreq = NULL ;
ret = tstream_readv_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
if ( ret = = - 1 ) {
tlss - > error = sys_errno ;
tstream_tls_retry ( stream , false ) ;
return ;
}
tstream_tls_retry ( stream , false ) ;
}
static int tstream_tls_destructor ( struct tstream_tls * tlss )
{
if ( tlss - > tls_session ) {
gnutls_deinit ( tlss - > tls_session ) ;
tlss - > tls_session = NULL ;
}
2018-10-10 15:24:51 +03:00
2010-02-03 16:36:10 +03:00
return 0 ;
}
static ssize_t tstream_tls_pending_bytes ( struct tstream_context * stream )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
size_t ret ;
if ( tlss - > error ! = 0 ) {
errno = tlss - > error ;
return - 1 ;
}
ret = gnutls_record_check_pending ( tlss - > tls_session ) ;
ret + = tlss - > read . left ;
2018-10-10 15:24:51 +03:00
2010-02-03 16:36:10 +03:00
return ret ;
}
struct tstream_tls_readv_state {
struct tstream_context * stream ;
struct iovec * vector ;
int count ;
int ret ;
} ;
static void tstream_tls_readv_crypt_next ( struct tevent_req * req ) ;
static struct tevent_req * tstream_tls_readv_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * stream ,
struct iovec * vector ,
size_t count )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * req ;
struct tstream_tls_readv_state * state ;
tlss - > read . req = NULL ;
tlss - > current_ev = ev ;
req = tevent_req_create ( mem_ctx , & state ,
struct tstream_tls_readv_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > stream = stream ;
state - > ret = 0 ;
if ( tlss - > error ! = 0 ) {
tevent_req_error ( req , tlss - > error ) ;
return tevent_req_post ( req , ev ) ;
}
/*
* we make a copy of the vector so we can change the structure
*/
state - > vector = talloc_array ( state , struct iovec , count ) ;
if ( tevent_req_nomem ( state - > vector , req ) ) {
return tevent_req_post ( req , ev ) ;
}
memcpy ( state - > vector , vector , sizeof ( struct iovec ) * count ) ;
state - > count = count ;
tstream_tls_readv_crypt_next ( req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void tstream_tls_readv_crypt_next ( struct tevent_req * req )
{
struct tstream_tls_readv_state * state =
tevent_req_data ( req ,
struct tstream_tls_readv_state ) ;
struct tstream_tls * tlss =
tstream_context_data ( state - > stream ,
struct tstream_tls ) ;
/*
* copy the pending buffer first
*/
while ( tlss - > read . left > 0 & & state - > count > 0 ) {
uint8_t * base = ( uint8_t * ) state - > vector [ 0 ] . iov_base ;
size_t len = MIN ( tlss - > read . left , state - > vector [ 0 ] . iov_len ) ;
memcpy ( base , tlss - > read . buffer + tlss - > read . ofs , len ) ;
base + = len ;
2010-11-29 16:35:19 +03:00
state - > vector [ 0 ] . iov_base = ( char * ) base ;
2010-02-03 16:36:10 +03:00
state - > vector [ 0 ] . iov_len - = len ;
tlss - > read . ofs + = len ;
tlss - > read . left - = len ;
if ( state - > vector [ 0 ] . iov_len = = 0 ) {
state - > vector + = 1 ;
state - > count - = 1 ;
}
state - > ret + = len ;
}
if ( state - > count = = 0 ) {
tevent_req_done ( req ) ;
return ;
}
tlss - > read . req = req ;
tstream_tls_retry_read ( state - > stream ) ;
}
static void tstream_tls_retry_read ( struct tstream_context * stream )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * req = tlss - > read . req ;
int ret ;
if ( tlss - > error ! = 0 ) {
tevent_req_error ( req , tlss - > error ) ;
return ;
}
tlss - > read . left = 0 ;
tlss - > read . ofs = 0 ;
ret = gnutls_record_recv ( tlss - > tls_session ,
tlss - > read . buffer ,
sizeof ( tlss - > read . buffer ) ) ;
if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
return ;
}
tlss - > read . req = NULL ;
if ( gnutls_error_is_fatal ( ret ) ! = 0 ) {
DEBUG ( 1 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tlss - > error = EIO ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
if ( ret = = 0 ) {
tlss - > error = EPIPE ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
tlss - > read . left = ret ;
tstream_tls_readv_crypt_next ( req ) ;
}
static int tstream_tls_readv_recv ( struct tevent_req * req ,
int * perrno )
{
struct tstream_tls_readv_state * state =
tevent_req_data ( req ,
struct tstream_tls_readv_state ) ;
struct tstream_tls * tlss =
tstream_context_data ( state - > stream ,
struct tstream_tls ) ;
int ret ;
tlss - > read . req = NULL ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
if ( ret = = 0 ) {
ret = state - > ret ;
}
tevent_req_received ( req ) ;
return ret ;
}
struct tstream_tls_writev_state {
struct tstream_context * stream ;
struct iovec * vector ;
int count ;
int ret ;
} ;
static void tstream_tls_writev_crypt_next ( struct tevent_req * req ) ;
static struct tevent_req * tstream_tls_writev_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * stream ,
const struct iovec * vector ,
size_t count )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * req ;
struct tstream_tls_writev_state * state ;
tlss - > write . req = NULL ;
tlss - > current_ev = ev ;
req = tevent_req_create ( mem_ctx , & state ,
struct tstream_tls_writev_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > stream = stream ;
state - > ret = 0 ;
if ( tlss - > error ! = 0 ) {
tevent_req_error ( req , tlss - > error ) ;
return tevent_req_post ( req , ev ) ;
}
/*
* we make a copy of the vector so we can change the structure
*/
state - > vector = talloc_array ( state , struct iovec , count ) ;
if ( tevent_req_nomem ( state - > vector , req ) ) {
return tevent_req_post ( req , ev ) ;
}
memcpy ( state - > vector , vector , sizeof ( struct iovec ) * count ) ;
state - > count = count ;
tstream_tls_writev_crypt_next ( req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void tstream_tls_writev_crypt_next ( struct tevent_req * req )
{
struct tstream_tls_writev_state * state =
tevent_req_data ( req ,
struct tstream_tls_writev_state ) ;
struct tstream_tls * tlss =
tstream_context_data ( state - > stream ,
struct tstream_tls ) ;
tlss - > write . left = sizeof ( tlss - > write . buffer ) ;
tlss - > write . ofs = 0 ;
/*
* first fill our buffer
*/
while ( tlss - > write . left > 0 & & state - > count > 0 ) {
uint8_t * base = ( uint8_t * ) state - > vector [ 0 ] . iov_base ;
size_t len = MIN ( tlss - > write . left , state - > vector [ 0 ] . iov_len ) ;
memcpy ( tlss - > write . buffer + tlss - > write . ofs , base , len ) ;
base + = len ;
2010-11-29 16:35:19 +03:00
state - > vector [ 0 ] . iov_base = ( char * ) base ;
2010-02-03 16:36:10 +03:00
state - > vector [ 0 ] . iov_len - = len ;
tlss - > write . ofs + = len ;
tlss - > write . left - = len ;
if ( state - > vector [ 0 ] . iov_len = = 0 ) {
state - > vector + = 1 ;
state - > count - = 1 ;
}
state - > ret + = len ;
}
if ( tlss - > write . ofs = = 0 ) {
tevent_req_done ( req ) ;
return ;
}
tlss - > write . left = tlss - > write . ofs ;
tlss - > write . ofs = 0 ;
tlss - > write . req = req ;
tstream_tls_retry_write ( state - > stream ) ;
}
static void tstream_tls_retry_write ( struct tstream_context * stream )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * req = tlss - > write . req ;
int ret ;
if ( tlss - > error ! = 0 ) {
tevent_req_error ( req , tlss - > error ) ;
return ;
}
ret = gnutls_record_send ( tlss - > tls_session ,
tlss - > write . buffer + tlss - > write . ofs ,
tlss - > write . left ) ;
if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
return ;
}
tlss - > write . req = NULL ;
if ( gnutls_error_is_fatal ( ret ) ! = 0 ) {
DEBUG ( 1 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tlss - > error = EIO ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
if ( ret = = 0 ) {
tlss - > error = EPIPE ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
tlss - > write . ofs + = ret ;
tlss - > write . left - = ret ;
if ( tlss - > write . left > 0 ) {
tlss - > write . req = req ;
tstream_tls_retry_write ( stream ) ;
return ;
}
tstream_tls_writev_crypt_next ( req ) ;
}
static int tstream_tls_writev_recv ( struct tevent_req * req ,
int * perrno )
{
struct tstream_tls_writev_state * state =
tevent_req_data ( req ,
struct tstream_tls_writev_state ) ;
struct tstream_tls * tlss =
tstream_context_data ( state - > stream ,
struct tstream_tls ) ;
int ret ;
tlss - > write . req = NULL ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
if ( ret = = 0 ) {
ret = state - > ret ;
}
tevent_req_received ( req ) ;
return ret ;
}
struct tstream_tls_disconnect_state {
uint8_t _dummy ;
} ;
static struct tevent_req * tstream_tls_disconnect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * stream )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * req ;
struct tstream_tls_disconnect_state * state ;
tlss - > disconnect . req = NULL ;
tlss - > current_ev = ev ;
req = tevent_req_create ( mem_ctx , & state ,
struct tstream_tls_disconnect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
if ( tlss - > error ! = 0 ) {
tevent_req_error ( req , tlss - > error ) ;
return tevent_req_post ( req , ev ) ;
}
tlss - > disconnect . req = req ;
tstream_tls_retry_disconnect ( stream ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void tstream_tls_retry_disconnect ( struct tstream_context * stream )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * req = tlss - > disconnect . req ;
int ret ;
if ( tlss - > error ! = 0 ) {
tevent_req_error ( req , tlss - > error ) ;
return ;
}
ret = gnutls_bye ( tlss - > tls_session , GNUTLS_SHUT_WR ) ;
if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
return ;
}
tlss - > disconnect . req = NULL ;
if ( gnutls_error_is_fatal ( ret ) ! = 0 ) {
DEBUG ( 1 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tlss - > error = EIO ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 1 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tlss - > error = EIO ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
tevent_req_done ( req ) ;
}
static int tstream_tls_disconnect_recv ( struct tevent_req * req ,
int * perrno )
{
int ret ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
tevent_req_received ( req ) ;
return ret ;
}
static const struct tstream_context_ops tstream_tls_ops = {
. name = " tls " ,
. pending_bytes = tstream_tls_pending_bytes ,
. readv_send = tstream_tls_readv_send ,
. readv_recv = tstream_tls_readv_recv ,
. writev_send = tstream_tls_writev_send ,
. writev_recv = tstream_tls_writev_recv ,
. disconnect_send = tstream_tls_disconnect_send ,
. disconnect_recv = tstream_tls_disconnect_recv ,
} ;
struct tstream_tls_params {
2017-05-09 14:17:13 +03:00
gnutls_certificate_credentials_t x509_cred ;
gnutls_dh_params_t dh_params ;
2015-07-20 02:22:46 +03:00
const char * tls_priority ;
2010-02-03 16:36:10 +03:00
bool tls_enabled ;
2015-12-23 18:17:04 +03:00
enum tls_verify_peer_state verify_peer ;
const char * peer_name ;
2010-02-03 16:36:10 +03:00
} ;
static int tstream_tls_params_destructor ( struct tstream_tls_params * tlsp )
{
if ( tlsp - > x509_cred ) {
gnutls_certificate_free_credentials ( tlsp - > x509_cred ) ;
tlsp - > x509_cred = NULL ;
}
if ( tlsp - > dh_params ) {
gnutls_dh_params_deinit ( tlsp - > dh_params ) ;
tlsp - > dh_params = NULL ;
}
2018-10-10 15:24:51 +03:00
2010-02-03 16:36:10 +03:00
return 0 ;
}
bool tstream_tls_params_enabled ( struct tstream_tls_params * tlsp )
{
return tlsp - > tls_enabled ;
}
NTSTATUS tstream_tls_params_client ( TALLOC_CTX * mem_ctx ,
const char * ca_file ,
const char * crl_file ,
2015-07-20 02:22:46 +03:00
const char * tls_priority ,
2015-12-23 18:17:04 +03:00
enum tls_verify_peer_state verify_peer ,
const char * peer_name ,
2010-02-03 16:36:10 +03:00
struct tstream_tls_params * * _tlsp )
{
struct tstream_tls_params * tlsp ;
int ret ;
ret = gnutls_global_init ( ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
return NT_STATUS_NOT_SUPPORTED ;
}
tlsp = talloc_zero ( mem_ctx , struct tstream_tls_params ) ;
NT_STATUS_HAVE_NO_MEMORY ( tlsp ) ;
talloc_set_destructor ( tlsp , tstream_tls_params_destructor ) ;
2015-12-23 18:17:04 +03:00
tlsp - > verify_peer = verify_peer ;
if ( peer_name ! = NULL ) {
tlsp - > peer_name = talloc_strdup ( tlsp , peer_name ) ;
if ( tlsp - > peer_name = = NULL ) {
talloc_free ( tlsp ) ;
return NT_STATUS_NO_MEMORY ;
}
} else if ( tlsp - > verify_peer > = TLS_VERIFY_PEER_CA_AND_NAME ) {
DEBUG ( 0 , ( " TLS failed to missing peer_name - "
" with 'tls verify peer = %s' \n " ,
tls_verify_peer_string ( tlsp - > verify_peer ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2010-02-03 16:36:10 +03:00
ret = gnutls_certificate_allocate_credentials ( & tlsp - > x509_cred ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_NO_MEMORY ;
}
2015-06-19 14:30:10 +03:00
if ( ca_file & & * ca_file & & file_exist ( ca_file ) ) {
2010-02-03 16:36:10 +03:00
ret = gnutls_certificate_set_x509_trust_file ( tlsp - > x509_cred ,
ca_file ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " TLS failed to initialise cafile %s - %s \n " ,
ca_file , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
2015-12-23 18:17:04 +03:00
} else if ( tlsp - > verify_peer > = TLS_VERIFY_PEER_CA_ONLY ) {
DEBUG ( 0 , ( " TLS failed to missing cafile %s - "
" with 'tls verify peer = %s' \n " ,
ca_file ,
tls_verify_peer_string ( tlsp - > verify_peer ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_INVALID_PARAMETER_MIX ;
2010-02-03 16:36:10 +03:00
}
2015-06-19 14:30:10 +03:00
if ( crl_file & & * crl_file & & file_exist ( crl_file ) ) {
2010-02-03 16:36:10 +03:00
ret = gnutls_certificate_set_x509_crl_file ( tlsp - > x509_cred ,
crl_file ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " TLS failed to initialise crlfile %s - %s \n " ,
crl_file , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
2015-12-23 18:17:04 +03:00
} else if ( tlsp - > verify_peer > = TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE ) {
DEBUG ( 0 , ( " TLS failed to missing crlfile %s - "
" with 'tls verify peer = %s' \n " ,
crl_file ,
tls_verify_peer_string ( tlsp - > verify_peer ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_INVALID_PARAMETER_MIX ;
2010-02-03 16:36:10 +03:00
}
2015-07-20 02:22:46 +03:00
tlsp - > tls_priority = talloc_strdup ( tlsp , tls_priority ) ;
if ( tlsp - > tls_priority = = NULL ) {
talloc_free ( tlsp ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-02-03 16:36:10 +03:00
tlsp - > tls_enabled = true ;
* _tlsp = tlsp ;
return NT_STATUS_OK ;
}
struct tstream_tls_connect_state {
struct tstream_context * tls_stream ;
} ;
struct tevent_req * _tstream_tls_connect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * plain_stream ,
struct tstream_tls_params * tls_params ,
const char * location )
{
struct tevent_req * req ;
struct tstream_tls_connect_state * state ;
2016-09-17 19:03:12 +03:00
const char * error_pos ;
2010-02-03 16:36:10 +03:00
struct tstream_tls * tlss ;
int ret ;
req = tevent_req_create ( mem_ctx , & state ,
struct tstream_tls_connect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > tls_stream = tstream_context_create ( state ,
& tstream_tls_ops ,
& tlss ,
struct tstream_tls ,
location ) ;
if ( tevent_req_nomem ( state - > tls_stream , req ) ) {
return tevent_req_post ( req , ev ) ;
}
ZERO_STRUCTP ( tlss ) ;
talloc_set_destructor ( tlss , tstream_tls_destructor ) ;
tlss - > plain_stream = plain_stream ;
2015-12-23 18:17:04 +03:00
tlss - > verify_peer = tls_params - > verify_peer ;
if ( tls_params - > peer_name ! = NULL ) {
tlss - > peer_name = talloc_strdup ( tlss , tls_params - > peer_name ) ;
if ( tevent_req_nomem ( tlss - > peer_name , req ) ) {
return tevent_req_post ( req , ev ) ;
}
}
2010-02-03 16:36:10 +03:00
tlss - > current_ev = ev ;
2010-10-08 11:39:49 +04:00
tlss - > retry_im = tevent_create_immediate ( tlss ) ;
if ( tevent_req_nomem ( tlss - > retry_im , req ) ) {
2010-02-03 16:36:10 +03:00
return tevent_req_post ( req , ev ) ;
}
ret = gnutls_init ( & tlss - > tls_session , GNUTLS_CLIENT ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tevent_req_error ( req , EINVAL ) ;
return tevent_req_post ( req , ev ) ;
}
2015-07-20 02:22:46 +03:00
ret = gnutls_priority_set_direct ( tlss - > tls_session ,
tls_params - > tls_priority ,
& error_pos ) ;
2010-02-03 16:36:10 +03:00
if ( ret ! = GNUTLS_E_SUCCESS ) {
2015-07-20 02:22:46 +03:00
DEBUG ( 0 , ( " TLS %s - %s. Check 'tls priority' option at '%s' \n " ,
__location__ , gnutls_strerror ( ret ) , error_pos ) ) ;
2010-02-03 16:36:10 +03:00
tevent_req_error ( req , EINVAL ) ;
return tevent_req_post ( req , ev ) ;
}
ret = gnutls_credentials_set ( tlss - > tls_session ,
GNUTLS_CRD_CERTIFICATE ,
tls_params - > x509_cred ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tevent_req_error ( req , EINVAL ) ;
return tevent_req_post ( req , ev ) ;
}
2017-05-09 14:17:13 +03:00
gnutls_transport_set_ptr ( tlss - > tls_session ,
( gnutls_transport_ptr_t ) state - > tls_stream ) ;
2010-02-03 16:36:10 +03:00
gnutls_transport_set_pull_function ( tlss - > tls_session ,
( gnutls_pull_func ) tstream_tls_pull_function ) ;
gnutls_transport_set_push_function ( tlss - > tls_session ,
( gnutls_push_func ) tstream_tls_push_function ) ;
tlss - > handshake . req = req ;
tstream_tls_retry_handshake ( state - > tls_stream ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
int tstream_tls_connect_recv ( struct tevent_req * req ,
int * perrno ,
TALLOC_CTX * mem_ctx ,
struct tstream_context * * tls_stream )
{
struct tstream_tls_connect_state * state =
tevent_req_data ( req ,
struct tstream_tls_connect_state ) ;
if ( tevent_req_is_unix_error ( req , perrno ) ) {
tevent_req_received ( req ) ;
return - 1 ;
}
* tls_stream = talloc_move ( mem_ctx , & state - > tls_stream ) ;
tevent_req_received ( req ) ;
return 0 ;
}
/*
initialise global tls state
*/
NTSTATUS tstream_tls_params_server ( TALLOC_CTX * mem_ctx ,
const char * dns_host_name ,
2010-10-07 13:16:48 +04:00
bool enabled ,
2010-02-03 16:36:10 +03:00
const char * key_file ,
const char * cert_file ,
const char * ca_file ,
const char * crl_file ,
const char * dhp_file ,
2015-07-20 02:22:46 +03:00
const char * tls_priority ,
2010-02-03 16:36:10 +03:00
struct tstream_tls_params * * _tlsp )
{
struct tstream_tls_params * tlsp ;
int ret ;
2013-10-29 20:53:59 +04:00
struct stat st ;
2010-02-03 16:36:10 +03:00
2010-10-07 13:16:48 +04:00
if ( ! enabled | | key_file = = NULL | | * key_file = = 0 ) {
tlsp = talloc_zero ( mem_ctx , struct tstream_tls_params ) ;
NT_STATUS_HAVE_NO_MEMORY ( tlsp ) ;
talloc_set_destructor ( tlsp , tstream_tls_params_destructor ) ;
tlsp - > tls_enabled = false ;
* _tlsp = tlsp ;
return NT_STATUS_OK ;
}
2010-02-03 16:36:10 +03:00
ret = gnutls_global_init ( ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
return NT_STATUS_NOT_SUPPORTED ;
}
tlsp = talloc_zero ( mem_ctx , struct tstream_tls_params ) ;
NT_STATUS_HAVE_NO_MEMORY ( tlsp ) ;
talloc_set_destructor ( tlsp , tstream_tls_params_destructor ) ;
if ( ! file_exist ( ca_file ) ) {
tls_cert_generate ( tlsp , dns_host_name ,
key_file , cert_file , ca_file ) ;
}
2013-10-29 20:53:59 +04:00
if ( file_exist ( key_file ) & &
! file_check_permissions ( key_file , geteuid ( ) , 0600 , & st ) )
{
DEBUG ( 0 , ( " Invalid permissions on TLS private key file '%s': \n "
2014-03-28 13:24:56 +04:00
" owner uid %u should be %u, mode 0%o should be 0%o \n "
2013-10-29 20:53:59 +04:00
" This is known as CVE-2013-4476. \n "
" Removing all tls .pem files will cause an "
" auto-regeneration with the correct permissions. \n " ,
key_file ,
( unsigned int ) st . st_uid , geteuid ( ) ,
2014-03-28 13:24:56 +04:00
( unsigned int ) ( st . st_mode & 0777 ) , 0600 ) ) ;
2013-10-29 20:53:59 +04:00
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
2010-02-03 16:36:10 +03:00
ret = gnutls_certificate_allocate_credentials ( & tlsp - > x509_cred ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_NO_MEMORY ;
}
if ( ca_file & & * ca_file ) {
ret = gnutls_certificate_set_x509_trust_file ( tlsp - > x509_cred ,
ca_file ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " TLS failed to initialise cafile %s - %s \n " ,
ca_file , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
}
if ( crl_file & & * crl_file ) {
ret = gnutls_certificate_set_x509_crl_file ( tlsp - > x509_cred ,
crl_file ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " TLS failed to initialise crlfile %s - %s \n " ,
crl_file , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
}
ret = gnutls_certificate_set_x509_key_file ( tlsp - > x509_cred ,
cert_file , key_file ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS failed to initialise certfile %s and keyfile %s - %s \n " ,
cert_file , key_file , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
ret = gnutls_dh_params_init ( & tlsp - > dh_params ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_NO_MEMORY ;
}
if ( dhp_file & & * dhp_file ) {
gnutls_datum_t dhparms ;
size_t size ;
dhparms . data = ( uint8_t * ) file_load ( dhp_file , & size , 0 , tlsp ) ;
if ( ! dhparms . data ) {
DEBUG ( 0 , ( " TLS failed to read DH Parms from %s - %d:%s \n " ,
dhp_file , errno , strerror ( errno ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
dhparms . size = size ;
ret = gnutls_dh_params_import_pkcs3 ( tlsp - > dh_params ,
& dhparms ,
GNUTLS_X509_FMT_PEM ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS failed to import pkcs3 %s - %s \n " ,
dhp_file , gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
} else {
ret = gnutls_dh_params_generate2 ( tlsp - > dh_params , DH_BITS ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS failed to generate dh_params - %s \n " ,
gnutls_strerror ( ret ) ) ) ;
talloc_free ( tlsp ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
}
gnutls_certificate_set_dh_params ( tlsp - > x509_cred , tlsp - > dh_params ) ;
2015-07-20 02:22:46 +03:00
tlsp - > tls_priority = talloc_strdup ( tlsp , tls_priority ) ;
if ( tlsp - > tls_priority = = NULL ) {
talloc_free ( tlsp ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-02-03 16:36:10 +03:00
tlsp - > tls_enabled = true ;
* _tlsp = tlsp ;
return NT_STATUS_OK ;
}
struct tstream_tls_accept_state {
struct tstream_context * tls_stream ;
} ;
struct tevent_req * _tstream_tls_accept_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * plain_stream ,
struct tstream_tls_params * tlsp ,
const char * location )
{
struct tevent_req * req ;
struct tstream_tls_accept_state * state ;
struct tstream_tls * tlss ;
2016-09-17 19:03:12 +03:00
const char * error_pos ;
2010-02-03 16:36:10 +03:00
int ret ;
req = tevent_req_create ( mem_ctx , & state ,
struct tstream_tls_accept_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > tls_stream = tstream_context_create ( state ,
& tstream_tls_ops ,
& tlss ,
struct tstream_tls ,
location ) ;
if ( tevent_req_nomem ( state - > tls_stream , req ) ) {
return tevent_req_post ( req , ev ) ;
}
ZERO_STRUCTP ( tlss ) ;
talloc_set_destructor ( tlss , tstream_tls_destructor ) ;
tlss - > plain_stream = plain_stream ;
tlss - > current_ev = ev ;
2010-10-08 11:39:49 +04:00
tlss - > retry_im = tevent_create_immediate ( tlss ) ;
if ( tevent_req_nomem ( tlss - > retry_im , req ) ) {
2010-02-03 16:36:10 +03:00
return tevent_req_post ( req , ev ) ;
}
ret = gnutls_init ( & tlss - > tls_session , GNUTLS_SERVER ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tevent_req_error ( req , EINVAL ) ;
return tevent_req_post ( req , ev ) ;
}
2015-07-20 02:22:46 +03:00
ret = gnutls_priority_set_direct ( tlss - > tls_session ,
tlsp - > tls_priority ,
& error_pos ) ;
2010-02-03 16:36:10 +03:00
if ( ret ! = GNUTLS_E_SUCCESS ) {
2015-07-20 02:22:46 +03:00
DEBUG ( 0 , ( " TLS %s - %s. Check 'tls priority' option at '%s' \n " ,
__location__ , gnutls_strerror ( ret ) , error_pos ) ) ;
2010-02-03 16:36:10 +03:00
tevent_req_error ( req , EINVAL ) ;
return tevent_req_post ( req , ev ) ;
}
ret = gnutls_credentials_set ( tlss - > tls_session , GNUTLS_CRD_CERTIFICATE ,
tlsp - > x509_cred ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 0 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tevent_req_error ( req , EINVAL ) ;
return tevent_req_post ( req , ev ) ;
}
gnutls_certificate_server_set_request ( tlss - > tls_session ,
GNUTLS_CERT_REQUEST ) ;
gnutls_dh_set_prime_bits ( tlss - > tls_session , DH_BITS ) ;
2017-05-09 14:17:13 +03:00
gnutls_transport_set_ptr ( tlss - > tls_session ,
( gnutls_transport_ptr_t ) state - > tls_stream ) ;
2010-02-03 16:36:10 +03:00
gnutls_transport_set_pull_function ( tlss - > tls_session ,
( gnutls_pull_func ) tstream_tls_pull_function ) ;
gnutls_transport_set_push_function ( tlss - > tls_session ,
( gnutls_push_func ) tstream_tls_push_function ) ;
tlss - > handshake . req = req ;
tstream_tls_retry_handshake ( state - > tls_stream ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void tstream_tls_retry_handshake ( struct tstream_context * stream )
{
struct tstream_tls * tlss =
tstream_context_data ( stream ,
struct tstream_tls ) ;
struct tevent_req * req = tlss - > handshake . req ;
int ret ;
if ( tlss - > error ! = 0 ) {
tevent_req_error ( req , tlss - > error ) ;
return ;
}
ret = gnutls_handshake ( tlss - > tls_session ) ;
if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
return ;
}
tlss - > handshake . req = NULL ;
if ( gnutls_error_is_fatal ( ret ) ! = 0 ) {
DEBUG ( 1 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tlss - > error = EIO ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 1 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tlss - > error = EIO ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
2015-12-23 18:17:04 +03:00
if ( tlss - > verify_peer > = TLS_VERIFY_PEER_CA_ONLY ) {
unsigned int status = UINT32_MAX ;
bool ip = true ;
const char * hostname = NULL ;
if ( tlss - > peer_name ! = NULL ) {
ip = is_ipaddress ( tlss - > peer_name ) ;
}
if ( ! ip ) {
hostname = tlss - > peer_name ;
}
if ( tlss - > verify_peer = = TLS_VERIFY_PEER_CA_ONLY ) {
hostname = NULL ;
}
if ( tlss - > verify_peer > = TLS_VERIFY_PEER_CA_AND_NAME ) {
if ( hostname = = NULL ) {
DEBUG ( 1 , ( " TLS %s - no hostname available for "
" verify_peer[%s] and peer_name[%s] \n " ,
__location__ ,
tls_verify_peer_string ( tlss - > verify_peer ) ,
tlss - > peer_name ) ) ;
tlss - > error = EINVAL ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
}
ret = gnutls_certificate_verify_peers3 ( tlss - > tls_session ,
hostname ,
& status ) ;
if ( ret ! = GNUTLS_E_SUCCESS ) {
DEBUG ( 1 , ( " TLS %s - %s \n " , __location__ , gnutls_strerror ( ret ) ) ) ;
tlss - > error = EIO ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
if ( status ! = 0 ) {
DEBUG ( 1 , ( " TLS %s - check failed for "
" verify_peer[%s] and peer_name[%s] "
" status 0x%x (%s%s%s%s%s%s%s%s) \n " ,
__location__ ,
tls_verify_peer_string ( tlss - > verify_peer ) ,
tlss - > peer_name ,
status ,
status & GNUTLS_CERT_INVALID ? " invalid " : " " ,
status & GNUTLS_CERT_REVOKED ? " revoked " : " " ,
status & GNUTLS_CERT_SIGNER_NOT_FOUND ?
" signer_not_found " : " " ,
status & GNUTLS_CERT_SIGNER_NOT_CA ?
" signer_not_ca " : " " ,
status & GNUTLS_CERT_INSECURE_ALGORITHM ?
" insecure_algorithm " : " " ,
status & GNUTLS_CERT_NOT_ACTIVATED ?
" not_activated " : " " ,
status & GNUTLS_CERT_EXPIRED ?
" expired " : " " ,
status & GNUTLS_CERT_UNEXPECTED_OWNER ?
" unexptected_owner " : " " ) ) ;
tlss - > error = EINVAL ;
tevent_req_error ( req , tlss - > error ) ;
return ;
}
}
2010-02-03 16:36:10 +03:00
tevent_req_done ( req ) ;
}
int tstream_tls_accept_recv ( struct tevent_req * req ,
int * perrno ,
TALLOC_CTX * mem_ctx ,
struct tstream_context * * tls_stream )
{
struct tstream_tls_accept_state * state =
tevent_req_data ( req ,
struct tstream_tls_accept_state ) ;
if ( tevent_req_is_unix_error ( req , perrno ) ) {
tevent_req_received ( req ) ;
return - 1 ;
}
* tls_stream = talloc_move ( mem_ctx , & state - > tls_stream ) ;
tevent_req_received ( req ) ;
return 0 ;
}