From 2c0707cf13d05b85c78faa806fa14585e6daff30 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 22 Jul 2021 15:26:29 +0100 Subject: [PATCH] ITS#9157 save TLS errmsg in ld->ld_error --- libraries/libldap/ldap-tls.h | 3 ++- libraries/libldap/tls2.c | 25 ++++++++++++++++++++----- libraries/libldap/tls_g.c | 23 +++++++++++++++++++---- libraries/libldap/tls_o.c | 36 +++++++++++++++++++----------------- servers/slapd/config.c | 7 +++++-- servers/slapd/main.c | 7 +++++-- 6 files changed, 70 insertions(+), 31 deletions(-) diff --git a/libraries/libldap/ldap-tls.h b/libraries/libldap/ldap-tls.h index 378d08b6b0..423d18195f 100644 --- a/libraries/libldap/ldap-tls.h +++ b/libraries/libldap/ldap-tls.h @@ -31,7 +31,8 @@ typedef void (TI_tls_destroy)(void); typedef tls_ctx *(TI_ctx_new)(struct ldapoptions *lo); typedef void (TI_ctx_ref)(tls_ctx *ctx); typedef void (TI_ctx_free)(tls_ctx *ctx); -typedef int (TI_ctx_init)(struct ldapoptions *lo, struct ldaptls *lt, int is_server); +#define ERRBUFSIZE 256 +typedef int (TI_ctx_init)(struct ldapoptions *lo, struct ldaptls *lt, int is_server, char *errmsg); typedef tls_session *(TI_session_new)(tls_ctx *ctx, int is_server); typedef int (TI_session_connect)(LDAP *ld, tls_session *s, const char *name_in); diff --git a/libraries/libldap/tls2.c b/libraries/libldap/tls2.c index d76ac6adfc..a3a8399bf5 100644 --- a/libraries/libldap/tls2.c +++ b/libraries/libldap/tls2.c @@ -199,7 +199,7 @@ ldap_pvt_tls_init( int do_threads ) * initialize a new TLS context */ static int -ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) +ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server, char *errmsg ) { int rc = 0; tls_impl *ti = tls_imp; @@ -261,7 +261,7 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) goto error_exit; } - rc = ti->ti_ctx_init( lo, <s, is_server ); + rc = ti->ti_ctx_init( lo, <s, is_server, errmsg ); error_exit: if ( rc < 0 && lo->ldo_tls_ctx != NULL ) { @@ -288,10 +288,15 @@ int ldap_pvt_tls_init_def_ctx( int is_server ) { struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); + char errmsg[ERRBUFSIZE]; int rc; + errmsg[0] = 0; LDAP_MUTEX_LOCK( &tls_def_ctx_mutex ); - rc = ldap_int_tls_init_ctx( lo, is_server ); + rc = ldap_int_tls_init_ctx( lo, is_server, errmsg ); LDAP_MUTEX_UNLOCK( &tls_def_ctx_mutex ); + if ( rc ) { + Debug1( LDAP_DEBUG_ANY,"TLS: init_def_ctx: %s.\n", errmsg ); + } return rc; } @@ -975,12 +980,22 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) if ( lo->ldo_tls_randfile ) LDAP_FREE (lo->ldo_tls_randfile ); lo->ldo_tls_randfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; break; - case LDAP_OPT_X_TLS_NEWCTX: + case LDAP_OPT_X_TLS_NEWCTX: { + int rc; + char errmsg[ERRBUFSIZE]; if ( !arg ) return -1; if ( lo->ldo_tls_ctx ) ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = NULL; - return ldap_int_tls_init_ctx( lo, *(int *)arg ); + errmsg[0] = 0; + rc = ldap_int_tls_init_ctx( lo, *(int *)arg, errmsg ); + if ( rc && errmsg[0] ) { + if ( ld->ld_error ) + LDAP_FREE( ld->ld_error ); + ld->ld_error = LDAP_STRDUP( errmsg ); + } + return rc; + } case LDAP_OPT_X_TLS_CACERT: if ( lo->ldo_tls_cacert.bv_val ) LDAP_FREE( lo->ldo_tls_cacert.bv_val ); diff --git a/libraries/libldap/tls_g.c b/libraries/libldap/tls_g.c index f45c33a672..17bcc69f15 100644 --- a/libraries/libldap/tls_g.c +++ b/libraries/libldap/tls_g.c @@ -181,7 +181,7 @@ tlsg_getfile( const char *path, gnutls_datum_t *buf ) * initialize a new TLS context */ static int -tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) +tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server, char *errmsg ) { tlsg_ctx *ctx = lo->ldo_tls_ctx; int rc; @@ -208,6 +208,7 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) "TLS: warning: no certificate found in CA certificate directory `%s'.\n", lt->lt_cacertdir ); /* only warn, no return */ + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); } } @@ -228,6 +229,7 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) "TLS: warning: no certificate loaded from CA certificate file `%s'.\n", lo->ldo_tls_cacertfile ); /* only warn, no return */ + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); } } @@ -244,6 +246,7 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) "TLS: could not use CA certificate: %s (%d)\n", gnutls_strerror( rc ), rc ); + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); return -1; } } @@ -256,7 +259,10 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) unsigned int max = VERIFY_DEPTH; rc = gnutls_x509_privkey_init( &key ); - if ( rc ) return -1; + if ( rc ) { + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); + return -1; + } /* OpenSSL builds the cert chain for us, but GnuTLS * expects it to be present in the certfile. If it's @@ -285,6 +291,7 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) "TLS: could not use private key: %s (%d)\n", gnutls_strerror( rc ), rc ); + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); return rc; } @@ -310,6 +317,7 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) "TLS: could not use certificate: %s (%d)\n", gnutls_strerror( rc ), rc ); + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); return rc; } @@ -333,6 +341,7 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) "TLS: could not use certificate with key: %s (%d)\n", gnutls_strerror( rc ), rc ); + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); return -1; } } else if (( lo->ldo_tls_certfile || lo->ldo_tls_keyfile )) { @@ -350,7 +359,10 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) ctx->cred, lt->lt_crlfile, GNUTLS_X509_FMT_PEM ); - if ( rc < 0 ) return -1; + if ( rc < 0 ) { + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); + return -1; + } rc = 0; } @@ -369,7 +381,10 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) rc = gnutls_dh_params_import_pkcs3( ctx->dh_params, &buf, GNUTLS_X509_FMT_PEM ); LDAP_FREE( buf.data ); - if ( rc ) return -1; + if ( rc ) { + strncpy( errmsg, gnutls_strerror( rc ), ERRBUFSIZE ); + return -1; + } gnutls_certificate_set_dh_params( ctx->cred, ctx->dh_params ); } diff --git a/libraries/libldap/tls_o.c b/libraries/libldap/tls_o.c index 92f70afc64..175bb14181 100644 --- a/libraries/libldap/tls_o.c +++ b/libraries/libldap/tls_o.c @@ -60,7 +60,7 @@ static BIO_METHOD * tlso_bio_setup( void ); static int tlso_opt_trace = 1; -static void tlso_report_error( void ); +static void tlso_report_error( char *errmsg ); static void tlso_info_cb( const SSL *ssl, int where, int ret ); static int tlso_verify_cb( int ok, X509_STORE_CTX *ctx ); @@ -349,7 +349,7 @@ tlso_ctx_cipher13( tlso_ctx *ctx, char *suites ) * initialize a new TLS context */ static int -tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) +tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server, char *errmsg ) { tlso_ctx *ctx = (tlso_ctx *)lo->ldo_tls_ctx; int i; @@ -419,7 +419,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) Debug1( LDAP_DEBUG_ANY, "TLS: could not set cipher list %s.\n", lo->ldo_tls_ciphersuite ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } } @@ -429,7 +429,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) if ( !SSL_CTX_set_default_verify_paths( ctx ) ) { Debug0( LDAP_DEBUG_ANY, "TLS: " "could not use default certificate paths" ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } } else { @@ -441,7 +441,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) if ( !X509_STORE_add_cert( store, cert )) { Debug0( LDAP_DEBUG_ANY, "TLS: " "could not use CA certificate" ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } } @@ -452,7 +452,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) "could not load verify locations (file:`%s',dir:`%s').\n", lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "" ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } @@ -465,7 +465,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) "could not load client CA list (file:`%s',dir:`%s').\n", lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "" ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } @@ -482,7 +482,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) if ( !SSL_CTX_use_certificate( ctx, cert )) { Debug0( LDAP_DEBUG_ANY, "TLS: could not use certificate.\n" ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } X509_free( cert ); @@ -493,7 +493,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) Debug1( LDAP_DEBUG_ANY, "TLS: could not use certificate file `%s'.\n", lo->ldo_tls_certfile ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } @@ -506,7 +506,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) { Debug0( LDAP_DEBUG_ANY, "TLS: could not use private key.\n" ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } EVP_PKEY_free( pkey ); @@ -518,7 +518,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) Debug1( LDAP_DEBUG_ANY, "TLS: could not use key file `%s'.\n", lo->ldo_tls_keyfile ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } @@ -530,14 +530,14 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) Debug1( LDAP_DEBUG_ANY, "TLS: could not use DH parameters file `%s'.\n", lo->ldo_tls_dhfile ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } if (!( dh=PEM_read_bio_DHparams( bio, NULL, NULL, NULL ))) { Debug1( LDAP_DEBUG_ANY, "TLS: could not read DH parameters file `%s'.\n", lo->ldo_tls_dhfile ); - tlso_report_error(); + tlso_report_error( errmsg ); BIO_free( bio ); return -1; } @@ -557,7 +557,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) Debug1( LDAP_DEBUG_ANY, "TLS: could not set EC name `%s'.\n", lo->ldo_tls_ecname ); - tlso_report_error(); + tlso_report_error( errmsg ); return -1; } /* @@ -1531,15 +1531,17 @@ tlso_verify_ok( int ok, X509_STORE_CTX *ctx ) /* Inspired by ERR_print_errors in OpenSSL */ static void -tlso_report_error( void ) +tlso_report_error( char *errmsg ) { unsigned long l; - char buf[200]; + char buf[ERRBUFSIZE]; const char *file; int line; while ( ( l = ERR_get_error_line( &file, &line ) ) != 0 ) { - ERR_error_string_n( l, buf, sizeof( buf ) ); + ERR_error_string_n( l, buf, ERRBUFSIZE ); + if ( !*errmsg ) + strcpy(errmsg, buf ); #ifdef HAVE_EBCDIC if ( file ) { file = LDAP_STRDUP( file ); diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 64c8951b5f..8b9ec0f5f0 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -2160,10 +2160,13 @@ slap_client_connect( LDAP **ldp, slap_bindconf *sb ) #ifdef HAVE_TLS rc = bindconf_tls_set( sb, ld ); if ( rc ) { + char *errmsg = NULL; + ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &errmsg ); Debug( LDAP_DEBUG_ANY, "slap_client_connect: " - "URI=%s TLS context initialization failed (%d)\n", - sb->sb_uri.bv_val, rc ); + "URI=%s TLS context initialization failed (%d) %s\n", + sb->sb_uri.bv_val, rc, errmsg ? errmsg : "" ); + ldap_memfree( errmsg ); goto done; } #endif diff --git a/servers/slapd/main.c b/servers/slapd/main.c index d8be4082b9..d92f978dd0 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -928,9 +928,12 @@ unhandled_option:; ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx ); load_extop( &slap_EXOP_START_TLS, 0, starttls_extop ); } else if ( rc != LDAP_NOT_SUPPORTED ) { + char *errmsg = NULL; + ldap_get_option( slap_tls_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &errmsg ); Debug( LDAP_DEBUG_ANY, - "main: TLS init def ctx failed: %d\n", - rc ); + "main: TLS init def ctx failed: %d %s\n", + rc, errmsg ? errmsg : "" ); + ldap_memfree( errmsg ); rc = 1; SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 ); goto destroy;