1777 lines
54 KiB
Diff
1777 lines
54 KiB
Diff
|
diff --git a/configure.in b/configure.in
|
||
|
index b251b6b06..8a836eabb 100644
|
||
|
--- a/configure.in
|
||
|
+++ b/configure.in
|
||
|
@@ -237,6 +237,7 @@ dnl OL_ARG_ENABLE(referrals,[ --enable-referrals enable LDAPv2+ Referrals (ex
|
||
|
ol_enable_referrals=${ol_enable_referrals-no}
|
||
|
OL_ARG_ENABLE(ipv6,[ --enable-ipv6 enable IPv6 support], auto)dnl
|
||
|
OL_ARG_ENABLE(local,[ --enable-local enable AF_LOCAL (AF_UNIX) socket support], auto)dnl
|
||
|
+OL_ARG_ENABLE(moznss_compatibility,[ --enable-moznss-compatibility enable MozNSS compatibility], no)dnl
|
||
|
|
||
|
dnl ----------------------------------------------------------------
|
||
|
dnl General "with" options
|
||
|
@@ -1256,6 +1257,26 @@ if test $ol_link_tls = no ; then
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
+if test $ol_enable_moznss_compatibility = yes ; then
|
||
|
+ if test $have_openssl = yes ; then
|
||
|
+ if test $ol_with_tls = openssl ; then
|
||
|
+ PKG_CHECK_MODULES(MOZNSS, [nss nspr], [have_moznss_libs=yes], [have_moznss_libs=no])
|
||
|
+ if test $have_moznss_libs = yes ; then
|
||
|
+ AC_DEFINE(HAVE_MOZNSS_COMPATIBILITY, 1,
|
||
|
+ [define if you want to support MozNSS databases when compiled with OpenSSL])
|
||
|
+ TLS_LIBS="$TLS_LIBS $MOZNSS_LIBS"
|
||
|
+ CFLAGS="$CFLAGS $MOZNSS_CFLAGS"
|
||
|
+ else
|
||
|
+ AC_MSG_ERROR([For MOZNSS_COMPATIBILITY you have to have MozNSS present.])
|
||
|
+ fi
|
||
|
+ else
|
||
|
+ AC_MSG_ERROR([For MOZNSS_COMPATIBILITY you have to compile with OpenSSL for crypto. (see --with-tls flag)])
|
||
|
+ fi
|
||
|
+ else
|
||
|
+ AC_MSG_ERROR([For MOZNSS_COMPATIBILITY you have to have OpenSSL devel available. (unable to build with OpenSSL)])
|
||
|
+ fi
|
||
|
+fi
|
||
|
+
|
||
|
WITH_TLS=no
|
||
|
if test $ol_link_tls = yes ; then
|
||
|
AC_DEFINE(HAVE_TLS, 1, [define if you have TLS])
|
||
|
diff --git a/doc/man/man3/ldap_get_option.3 b/doc/man/man3/ldap_get_option.3
|
||
|
index 389e1c4fd..60c7d05a5 100644
|
||
|
--- a/doc/man/man3/ldap_get_option.3
|
||
|
+++ b/doc/man/man3/ldap_get_option.3
|
||
|
@@ -772,6 +772,19 @@ must be
|
||
|
When using the OpenSSL library this is an SSL*. When using other
|
||
|
crypto libraries this is a pointer to an OpenLDAP private structure.
|
||
|
Applications generally should not use this option.
|
||
|
+.TP
|
||
|
+.B LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY
|
||
|
+Sets/gets the status of the MozNSS database compatibility layer for TLS options. This options is available only if OpenLDAP is compiled with OpenSSL. This has effect only before the TLS context is established.
|
||
|
+This option defaults to be on.
|
||
|
+.BR invalue
|
||
|
+should either be
|
||
|
+.BR LDAP_OPT_OFF
|
||
|
+or
|
||
|
+.BR LDAP_OPT_ON ;
|
||
|
+.BR outvalue
|
||
|
+must be
|
||
|
+.BR "int *" .
|
||
|
+When set, just before TLS context initialization the library will first check if TLS settings are MozNSS-specific and if so it will export certificates from a preconfigured database and set other TLS settings so that OpenSSL can continue without issues.
|
||
|
.SH ERRORS
|
||
|
On success, the functions return
|
||
|
.BR LDAP_OPT_SUCCESS ,
|
||
|
diff --git a/doc/man/man5/ldap.conf.5 b/doc/man/man5/ldap.conf.5
|
||
|
index b6735bab5..612b63a2b 100644
|
||
|
--- a/doc/man/man5/ldap.conf.5
|
||
|
+++ b/doc/man/man5/ldap.conf.5
|
||
|
@@ -483,6 +483,11 @@ Check the CRL for a whole certificate chain
|
||
|
Specifies the file containing a Certificate Revocation List to be used
|
||
|
to verify if the server certificates have not been revoked. This
|
||
|
parameter is only supported with GnuTLS and Mozilla NSS.
|
||
|
+.RE
|
||
|
+.TP
|
||
|
+.B TLS_MOZNSS_COMPATIBILITY <on/true/yes/off/false/no>
|
||
|
+Specifies whether the MozNSS database compatibility layer for TLS options should be enabled. This options is available only if OpenLDAP is compiled with OpenSSL.
|
||
|
+This option defaults to be on.
|
||
|
.SH "ENVIRONMENT VARIABLES"
|
||
|
.TP
|
||
|
LDAPNOINIT
|
||
|
diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5
|
||
|
index 6afbd7d6b..2893cd4a5 100644
|
||
|
--- a/doc/man/man5/slapd-config.5
|
||
|
+++ b/doc/man/man5/slapd-config.5
|
||
|
@@ -1004,6 +1004,11 @@ Check the CRL for a whole certificate chain
|
||
|
Specifies a file containing a Certificate Revocation List to be used
|
||
|
for verifying that certificates have not been revoked. This parameter
|
||
|
is only valid when using GnuTLS or Mozilla NSS.
|
||
|
+.RE
|
||
|
+.TP
|
||
|
+.B olcTLSMozNSSCompatibility <on/true/yes/off/false/no>
|
||
|
+Specifies whether the MozNSS database compatibility layer for TLS options should be enabled. This options is available only if OpenLDAP is compiled with OpenSSL.
|
||
|
+This option defaults to be on.
|
||
|
.SH DYNAMIC MODULE OPTIONS
|
||
|
If
|
||
|
.B slapd
|
||
|
diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5
|
||
|
index 86abeca80..742568393 100644
|
||
|
--- a/doc/man/man5/slapd.conf.5
|
||
|
+++ b/doc/man/man5/slapd.conf.5
|
||
|
@@ -1235,6 +1235,11 @@ Check the CRL for a whole certificate chain
|
||
|
Specifies a file containing a Certificate Revocation List to be used
|
||
|
for verifying that certificates have not been revoked. This directive is
|
||
|
only valid when using GnuTLS and Mozilla NSS.
|
||
|
+.RE
|
||
|
+.TP
|
||
|
+.B TLSMozNSSCompatibility <on/true/yes/off/false/no>
|
||
|
+Specifies whether the MozNSS database compatibility layer for TLS options should be enabled. This options is available only if OpenLDAP is compiled with OpenSSL.
|
||
|
+This option defaults to be on.
|
||
|
.SH GENERAL BACKEND OPTIONS
|
||
|
Options in this section only apply to the configuration file section
|
||
|
for the specified backend. They are supported by every
|
||
|
diff --git a/include/ldap.h b/include/ldap.h
|
||
|
index db6869da8..aae8bebd8 100644
|
||
|
--- a/include/ldap.h
|
||
|
+++ b/include/ldap.h
|
||
|
@@ -158,6 +158,10 @@ LDAP_BEGIN_DECL
|
||
|
#define LDAP_OPT_X_TLS_NEWCTX 0x600f
|
||
|
#define LDAP_OPT_X_TLS_CRLFILE 0x6010 /* GNUtls only */
|
||
|
#define LDAP_OPT_X_TLS_PACKAGE 0x6011
|
||
|
+#define LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY 0x6050
|
||
|
+
|
||
|
+#define LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY_DISABLED 0
|
||
|
+#define LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY_ENABLED 1
|
||
|
|
||
|
#define LDAP_OPT_X_TLS_NEVER 0
|
||
|
#define LDAP_OPT_X_TLS_HARD 1
|
||
|
diff --git a/libraries/libldap/Makefile.in b/libraries/libldap/Makefile.in
|
||
|
index 636b15506..a1445312f 100644
|
||
|
--- a/libraries/libldap/Makefile.in
|
||
|
+++ b/libraries/libldap/Makefile.in
|
||
|
@@ -26,7 +26,7 @@ SRCS = bind.c open.c result.c error.c compare.c search.c \
|
||
|
request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \
|
||
|
init.c options.c print.c string.c util-int.c schema.c \
|
||
|
charray.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
|
||
|
- tls2.c tls_o.c tls_g.c tls_m.c \
|
||
|
+ tls2.c tls_o.c tls_g.c tls_m.c tls_mc.c tls_mc_ossl.c \
|
||
|
turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c \
|
||
|
assertion.c deref.c ldif.c fetch.c
|
||
|
|
||
|
@@ -39,7 +39,7 @@ OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \
|
||
|
request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \
|
||
|
init.lo options.lo print.lo string.lo util-int.lo schema.lo \
|
||
|
charray.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \
|
||
|
- tls2.lo tls_o.lo tls_g.lo tls_m.lo \
|
||
|
+ tls2.lo tls_o.lo tls_g.lo tls_m.lo tls_mc.lo tls_mc_ossl.lo \
|
||
|
turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo \
|
||
|
assertion.lo deref.lo ldif.lo fetch.lo
|
||
|
|
||
|
diff --git a/libraries/libldap/init.c b/libraries/libldap/init.c
|
||
|
index 39ad7ce7c..689144ca3 100644
|
||
|
--- a/libraries/libldap/init.c
|
||
|
+++ b/libraries/libldap/init.c
|
||
|
@@ -137,7 +137,9 @@ static const struct ol_attribute {
|
||
|
#ifdef HAVE_GNUTLS
|
||
|
{0, ATTR_TLS, "TLS_CRLFILE", NULL, LDAP_OPT_X_TLS_CRLFILE},
|
||
|
#endif
|
||
|
-
|
||
|
+#ifdef HAVE_MOZNSS_COMPATIBILITY
|
||
|
+ {0, ATTR_TLS, "TLS_MOZNSS_COMPATIBILITY", NULL, LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY},
|
||
|
+#endif
|
||
|
#endif
|
||
|
|
||
|
{0, ATTR_NONE, NULL, NULL, 0}
|
||
|
@@ -582,6 +584,9 @@ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl
|
||
|
gopts->ldo_tls_connect_cb = NULL;
|
||
|
gopts->ldo_tls_connect_arg = NULL;
|
||
|
gopts->ldo_tls_require_cert = LDAP_OPT_X_TLS_DEMAND;
|
||
|
+#ifdef HAVE_MOZNSS_COMPATIBILITY
|
||
|
+ gopts->ldo_tls_moznss_compatibility = LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY_ENABLED;
|
||
|
+#endif
|
||
|
#endif
|
||
|
gopts->ldo_keepalive_probes = 0;
|
||
|
gopts->ldo_keepalive_interval = 0;
|
||
|
diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h
|
||
|
index bcc58f367..d42b82627 100644
|
||
|
--- a/libraries/libldap/ldap-int.h
|
||
|
+++ b/libraries/libldap/ldap-int.h
|
||
|
@@ -260,7 +260,8 @@ struct ldapoptions {
|
||
|
int ldo_tls_require_cert;
|
||
|
int ldo_tls_impl;
|
||
|
int ldo_tls_crlcheck;
|
||
|
-#define LDAP_LDO_TLS_NULLARG ,0,0,0,{0,0,0,0,0,0,0,0,0},0,0,0,0
|
||
|
+ int ldo_tls_moznss_compatibility;
|
||
|
+#define LDAP_LDO_TLS_NULLARG ,0,0,0,{0,0,0,0,0,0,0,0,0},0,0,0,0,0
|
||
|
#else
|
||
|
#define LDAP_LDO_TLS_NULLARG
|
||
|
#endif
|
||
|
diff --git a/libraries/libldap/tls2.c b/libraries/libldap/tls2.c
|
||
|
index 8f842278a..878e1a0a8 100644
|
||
|
--- a/libraries/libldap/tls2.c
|
||
|
+++ b/libraries/libldap/tls2.c
|
||
|
@@ -37,6 +37,8 @@
|
||
|
|
||
|
#include "ldap-tls.h"
|
||
|
|
||
|
+#include "tls_mc.h"
|
||
|
+
|
||
|
static tls_impl *tls_imp = &ldap_int_tls_impl;
|
||
|
#define HAS_TLS( sb ) ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \
|
||
|
(void *)tls_imp->ti_sbio )
|
||
|
@@ -96,6 +98,7 @@ tls_ctx_ref( tls_ctx *ctx )
|
||
|
* an extra mutex for the default ctx.
|
||
|
*/
|
||
|
static ldap_pvt_thread_mutex_t tls_def_ctx_mutex;
|
||
|
+ldap_pvt_thread_mutex_t tlsmc_mutex;
|
||
|
#endif
|
||
|
|
||
|
void
|
||
|
@@ -161,6 +164,7 @@ tls_init(tls_impl *impl )
|
||
|
if ( !tls_initialized++ ) {
|
||
|
#ifdef LDAP_R_COMPILE
|
||
|
ldap_pvt_thread_mutex_init( &tls_def_ctx_mutex );
|
||
|
+ ldap_pvt_thread_mutex_init( &tlsmc_mutex );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
@@ -196,6 +200,27 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server )
|
||
|
|
||
|
tls_init( ti );
|
||
|
|
||
|
+#ifdef HAVE_MOZNSS_COMPATIBILITY
|
||
|
+ if ( LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY_ENABLED == lo->ldo_tls_moznss_compatibility ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "TLSMC: MozNSS compatibility interception begins.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ if ( 0 == tlsmc_intercept_initialization( lo, is_server ) ) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "TLSMC: ERROR: MozNSS compatibility layer failed.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ }
|
||
|
+ lts = lo->ldo_tls_info;
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "TLSMC: MozNSS compatibility interception ends.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ } else {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "TLS: MozNSS compatibility layer disabled.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
if ( is_server && !lts.lt_certfile && !lts.lt_keyfile &&
|
||
|
!lts.lt_cacertfile && !lts.lt_cacertdir ) {
|
||
|
/* minimum configuration not provided */
|
||
|
@@ -573,6 +598,21 @@ ldap_int_tls_config( LDAP *ld, int option, const char *arg )
|
||
|
}
|
||
|
return -1;
|
||
|
#endif
|
||
|
+#ifdef HAVE_MOZNSS_COMPATIBILITY
|
||
|
+ case LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY:
|
||
|
+ i = -1;
|
||
|
+ if ( (strcasecmp( arg, "yes" ) == 0) ||
|
||
|
+ (strcasecmp( arg, "true" ) == 0) ||
|
||
|
+ (strcasecmp( arg, "on" ) == 0) ) {
|
||
|
+ i = LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY_ENABLED;
|
||
|
+ }
|
||
|
+ if ( (strcasecmp( arg, "no" ) == 0) ||
|
||
|
+ (strcasecmp( arg, "false" ) == 0) ||
|
||
|
+ (strcasecmp( arg, "off" ) == 0) ) {
|
||
|
+ i = LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY_DISABLED;
|
||
|
+ }
|
||
|
+ return ldap_pvt_tls_set_option( ld, option, &i );
|
||
|
+#endif
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
@@ -675,6 +715,9 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
|
||
|
case LDAP_OPT_X_TLS_CONNECT_ARG:
|
||
|
*(void **)arg = lo->ldo_tls_connect_arg;
|
||
|
break;
|
||
|
+ case LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY:
|
||
|
+ *(int *)arg = lo->ldo_tls_moznss_compatibility;
|
||
|
+ break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
@@ -802,6 +845,10 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
|
||
|
ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
|
||
|
lo->ldo_tls_ctx = NULL;
|
||
|
return ldap_int_tls_init_ctx( lo, *(int *)arg );
|
||
|
+ case LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY:
|
||
|
+ if ( !arg ) return -1;
|
||
|
+ lo->ldo_tls_moznss_compatibility = *(int *)arg;
|
||
|
+ break;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
diff --git a/libraries/libldap/tls_mc.c b/libraries/libldap/tls_mc.c
|
||
|
new file mode 100644
|
||
|
index 000000000..8383cb4ec
|
||
|
--- /dev/null
|
||
|
+++ b/libraries/libldap/tls_mc.c
|
||
|
@@ -0,0 +1,1323 @@
|
||
|
+#include "portable.h"
|
||
|
+
|
||
|
+#ifdef HAVE_MOZNSS_COMPATIBILITY
|
||
|
+
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <ac/unistd.h>
|
||
|
+#include <ac/errno.h>
|
||
|
+#include <ac/termios.h>
|
||
|
+#include <fcntl.h>
|
||
|
+
|
||
|
+#include <nspr/nspr.h>
|
||
|
+#include <nspr/private/pprio.h>
|
||
|
+
|
||
|
+#include <nss/nss.h>
|
||
|
+#include <nss/pk11pub.h>
|
||
|
+#include <nss/cert.h>
|
||
|
+
|
||
|
+#include <nss/base64.h>
|
||
|
+#include <nss/key.h>
|
||
|
+#include <nss/keyt.h>
|
||
|
+#include <nss/blapi.h>
|
||
|
+#include <nss/certdb.h>
|
||
|
+
|
||
|
+#include "ldap-int.h"
|
||
|
+#include "ldap-tls.h"
|
||
|
+#include "ldap_pvt_thread.h"
|
||
|
+
|
||
|
+#include "tls_mc.h"
|
||
|
+#include "tls_mc_ossl.h"
|
||
|
+
|
||
|
+#define TLSMC_CHECKSUM_LEN 32
|
||
|
+
|
||
|
+#define TLSMC_CACERTS_DIR_NAME "cacerts"
|
||
|
+#define TLSMC_CERT_FILE_NAME "cert.pem"
|
||
|
+#define TLSMC_KEY_FILE_NAME "key.pem"
|
||
|
+#define TLSMC_README_FILE_NAME "README"
|
||
|
+
|
||
|
+#define TLSM_CERTDB_DESC "ldap"
|
||
|
+#define DEFAULT_TOKEN_NAME "default"
|
||
|
+
|
||
|
+#define TLSMC_IS_INPLACE 1
|
||
|
+#define TLSMC_IS_TEMPORARY 2
|
||
|
+
|
||
|
+#define DONOTEDIT \
|
||
|
+ "This file is auto-generated by MOZNSS Compatibility Layer of OpenLDAP software.\n" \
|
||
|
+ "This layer is not a part of upstream distributed OpenLDAP software.\n" \
|
||
|
+ "Please, file any related bugs with your GNU/Linux distribution.\n" \
|
||
|
+ "Do not edit directly. Rather, change your configuration to use OpenSSL-style TLS options, so that this does not need to be generated anymore.\n" \
|
||
|
+ "Please, refer to man (5) of slapd.conf, slapd-config, and ldap.conf for more information."
|
||
|
+#define PEM_CERT_HEADER "-----BEGIN CERTIFICATE-----"
|
||
|
+#define PEM_CERT_FOOTER "-----END CERTIFICATE-----"
|
||
|
+#define PEM_KEY_HEADER "-----BEGIN PRIVATE KEY-----"
|
||
|
+#define PEM_KEY_FOOTER "-----END PRIVATE KEY-----"
|
||
|
+#define README_HEADER "Contents of this file are hashed and used as a part of a name of the parent directory.\n"
|
||
|
+
|
||
|
+#ifdef LDAP_R_COMPILE
|
||
|
+ldap_pvt_thread_mutex_t tlsmc_mutex;
|
||
|
+#endif
|
||
|
+/*******************************************************************/
|
||
|
+
|
||
|
+
|
||
|
+char *
|
||
|
+tlsmc_path2name( char *path )
|
||
|
+{
|
||
|
+ if ( NULL == path ) return NULL;
|
||
|
+ char *last_slash = strrchr( path, '/' );
|
||
|
+ if ( NULL == last_slash )
|
||
|
+ return path;
|
||
|
+ else
|
||
|
+ return last_slash + 1;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_write_file( char *filename, char *buf, mode_t final_mode )
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ int fd = -1;
|
||
|
+ if ( 0 > ( fd = open( filename, O_WRONLY | O_CREAT | O_EXCL, S_IWUSR ) ) ) {
|
||
|
+ perror("IO ERROR: could not open file");
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ if ( -1 >= write( fd, buf, strlen(buf) ) ) {
|
||
|
+ perror("IO ERROR: could not write file");
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ if ( -1 >= fchmod( fd, final_mode ) ) {
|
||
|
+ perror("IO ERROR: could not set file mode");
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ if ( 0 > close( fd ) ) {
|
||
|
+ perror("IO ERROR: could not close file");
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ rv = 1;
|
||
|
+bail:
|
||
|
+ if ( fd > -1 ) close( fd );
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+void
|
||
|
+tlsmc_debug_nspr_msg()
|
||
|
+{
|
||
|
+ int _errno = errno;
|
||
|
+ PRInt32 oserror = PR_GetOSError();
|
||
|
+ char *errno_str = strerror(_errno);
|
||
|
+ char *errstr = PR_Malloc( PR_GetErrorTextLength() + 1 );
|
||
|
+ PR_GetErrorText( errstr );
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "... NSPR error %d:`%s'\n",
|
||
|
+ PR_GetError(), errstr, 0 );
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "... NSPR OS-error %d, errno %d:%s\n",
|
||
|
+ oserror, _errno, errno_str );
|
||
|
+ PR_Free( errstr );
|
||
|
+}
|
||
|
+
|
||
|
+/* BORROWED FROM tls_m.c */
|
||
|
+static void
|
||
|
+tlsmc_get_certdb_prefix( const char *certdir, char **realcertdir, char **prefix )
|
||
|
+{
|
||
|
+ char sep = PR_GetDirectorySeparator();
|
||
|
+ char *ptr = NULL;
|
||
|
+ struct PRFileInfo prfi;
|
||
|
+ PRStatus prc;
|
||
|
+
|
||
|
+ *realcertdir = (char *)certdir; /* default is the one passed in */
|
||
|
+ if ( !certdir ) return;
|
||
|
+
|
||
|
+ prc = PR_GetFileInfo( certdir, &prfi );
|
||
|
+ /* if certdir exists (file or directory) then it cannot specify a prefix */
|
||
|
+ if ( prc == PR_SUCCESS ) {
|
||
|
+ /* and drop potential last '/' */
|
||
|
+ ptr = strrchr( *realcertdir, sep );
|
||
|
+ if ( ptr && (! *(ptr+1) ) ) {
|
||
|
+ *ptr = '\0';
|
||
|
+ }
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* if certdir was given, and there is a '/' in certdir, see if there
|
||
|
+ is anything after the last '/' - if so, assume it is the prefix */
|
||
|
+ if ( ( ( ptr = strrchr( certdir, sep ) ) ) && *(ptr+1) ) {
|
||
|
+ *realcertdir = PL_strndup( certdir, ptr-certdir );
|
||
|
+ *prefix = PL_strdup( ptr+1 );
|
||
|
+ }
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static char *
|
||
|
+tlsmc_get_pin_from_file(const char *token_name, char *filename)
|
||
|
+{
|
||
|
+ char *pwdstr = NULL;
|
||
|
+ char *contents = NULL;
|
||
|
+ char *lasts = NULL;
|
||
|
+ char *line = NULL;
|
||
|
+ char *candidate = NULL;
|
||
|
+ PRFileInfo file_info;
|
||
|
+ PRFileDesc *pwd_fileptr = NULL;
|
||
|
+ pwd_fileptr = PR_Open( filename, PR_RDONLY, 00400 );
|
||
|
+
|
||
|
+ /* open the password file */
|
||
|
+ if ( !pwd_fileptr ) {
|
||
|
+ PRErrorCode errcode = PR_GetError();
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_get_pin_from_file: could not open security pin file %s - error %d:%s.\n",
|
||
|
+ filename, errcode,
|
||
|
+ PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* get the file size */
|
||
|
+ if ( PR_SUCCESS != PR_GetFileInfo( filename, &file_info ) ) {
|
||
|
+ PRErrorCode errcode = PR_GetError();
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_get_pin_from_file: could not get file info from pin file %s - error %d:%s.\n",
|
||
|
+ filename, errcode,
|
||
|
+ PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* create a buffer to hold the file contents */
|
||
|
+ if ( !( contents = PR_CALLOC( file_info.size + 1 ) ) ) {
|
||
|
+ PRErrorCode errcode = PR_GetError();
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_get_pin_from_file: could not alloc a buffer for contents of pin file %s - error %d:%s.\n",
|
||
|
+ filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* read file into the buffer */
|
||
|
+ if( PR_Read( pwd_fileptr, contents, file_info.size ) <= 0 ) {
|
||
|
+ PRErrorCode errcode = PR_GetError();
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_get_pin_from_file: could not read the file contents from pin file %s - error %d:%s.\n",
|
||
|
+ filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* format is [tokenname:]password EOL [tokenname:]password EOL ... */
|
||
|
+ /* if you want to use a password containing a colon character, use
|
||
|
+ the special tokenname "default" */
|
||
|
+ for ( line = PL_strtok_r( contents, "\r\n", &lasts ); line;
|
||
|
+ line = PL_strtok_r( NULL, "\r\n", &lasts ) ) {
|
||
|
+ char *colon;
|
||
|
+
|
||
|
+ if ( !*line ) {
|
||
|
+ continue; /* skip blank lines */
|
||
|
+ }
|
||
|
+ colon = PL_strchr( line, ':' );
|
||
|
+ if ( colon ) {
|
||
|
+ if ( *(colon + 1) && token_name &&
|
||
|
+ !PL_strncmp( token_name, line, colon-line ) ) {
|
||
|
+ candidate = colon + 1; /* found a definite match */
|
||
|
+ break;
|
||
|
+ } else if ( !PL_strncmp( DEFAULT_TOKEN_NAME, line, colon-line ) ) {
|
||
|
+ candidate = colon + 1; /* found possible match */
|
||
|
+ }
|
||
|
+ } else { /* no token name */
|
||
|
+ candidate = line;
|
||
|
+ }
|
||
|
+ }
|
||
|
+done:
|
||
|
+ if ( pwd_fileptr ) {
|
||
|
+ PR_Close( pwd_fileptr );
|
||
|
+ }
|
||
|
+ if ( candidate ) {
|
||
|
+ pwdstr = PL_strdup( candidate );
|
||
|
+ }
|
||
|
+ PL_strfree( contents );
|
||
|
+
|
||
|
+ return pwdstr;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/*
|
||
|
+ * Turn the echoing off on a tty.
|
||
|
+ */
|
||
|
+static void
|
||
|
+echoOff(int fd)
|
||
|
+{
|
||
|
+ if ( isatty( fd ) ) {
|
||
|
+ struct termios tio;
|
||
|
+ tcgetattr( fd, &tio );
|
||
|
+ tio.c_lflag &= ~ECHO;
|
||
|
+ tcsetattr( fd, TCSAFLUSH, &tio );
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Turn the echoing on on a tty.
|
||
|
+ */
|
||
|
+static void
|
||
|
+echoOn(int fd)
|
||
|
+{
|
||
|
+ if ( isatty( fd ) ) {
|
||
|
+ struct termios tio;
|
||
|
+ tcgetattr( fd, &tio );
|
||
|
+ tio.c_lflag |= ECHO;
|
||
|
+ tcsetattr( fd, TCSAFLUSH, &tio );
|
||
|
+ tcsetattr( fd, TCSAFLUSH, &tio );
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* Borrowed from tlsm_get_pin() */
|
||
|
+char *
|
||
|
+tlsmc_get_pin( PK11SlotInfo *slot, PRBool retry, void * filename)
|
||
|
+{
|
||
|
+ char *token_name = NULL;
|
||
|
+ char *pwdstr = NULL;
|
||
|
+
|
||
|
+ token_name = PK11_GetTokenName( slot );
|
||
|
+ /* Try to get the passwords from the password file if it exists.
|
||
|
+ * THIS IS UNSAFE and is provided for convenience only. Without this
|
||
|
+ * capability the server would have to be started in foreground mode
|
||
|
+ * if using an encrypted key.
|
||
|
+ */
|
||
|
+ if ( filename ) {
|
||
|
+ pwdstr = tlsmc_get_pin_from_file( token_name, (char *)filename );
|
||
|
+ if ( retry && pwdstr != NULL )
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ if ( !pwdstr ) {
|
||
|
+ int infd = PR_FileDesc2NativeHandle( PR_STDIN );
|
||
|
+ int isTTY = isatty( infd );
|
||
|
+ unsigned char phrase[200];
|
||
|
+ /* Prompt for password */
|
||
|
+ if ( isTTY ) {
|
||
|
+ fprintf( stdout,
|
||
|
+ "Please enter pin, password, or pass phrase for security token '%s': ",
|
||
|
+ token_name ? token_name : DEFAULT_TOKEN_NAME );
|
||
|
+ echoOff( infd );
|
||
|
+ }
|
||
|
+ fgets( (char*)phrase, sizeof(phrase), stdin );
|
||
|
+ if ( isTTY ) {
|
||
|
+ fprintf( stdout, "\n" );
|
||
|
+ echoOn( infd );
|
||
|
+ }
|
||
|
+ /* stomp on newline */
|
||
|
+ phrase[strlen((char*)phrase)-1] = 0;
|
||
|
+
|
||
|
+ pwdstr = PL_strdup( (char*)phrase );
|
||
|
+ }
|
||
|
+
|
||
|
+ return pwdstr;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_hash( unsigned char **dest, char *src )
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ unsigned char fp[SHA256_LENGTH];
|
||
|
+ SECItem fpItem;
|
||
|
+
|
||
|
+ if ( SECSuccess != ( rv = PK11_HashBuf( SEC_OID_SHA256, fp, src, strlen(src) ) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_hash: could not hash a buffer",
|
||
|
+ NULL, NULL, NULL );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ fpItem.data = fp;
|
||
|
+ fpItem.len = SHA256_LENGTH;
|
||
|
+ if ( NULL == ( *dest = CERT_Hexify( &fpItem, 0 ) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_hash: could not hexify the hash",
|
||
|
+ NULL, NULL, NULL );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ rv = 1;
|
||
|
+bail:
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* BORROWED FROM tls_m.c */
|
||
|
+static PK11SlotInfo *
|
||
|
+tlsmc_init_open_certdb( const char *nssdb_dir, const char *prefix )
|
||
|
+{
|
||
|
+ PK11SlotInfo *slot = NULL;
|
||
|
+ char *config = NULL;
|
||
|
+
|
||
|
+ config = PR_smprintf( "configDir='%s' tokenDescription='%s' "
|
||
|
+ "certPrefix='%s' keyPrefix='%s' flags=readOnly",
|
||
|
+ nssdb_dir, TLSM_CERTDB_DESC,
|
||
|
+ prefix, prefix );
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_init_open_certdb: INFO: certdb config: `%s`.\n",
|
||
|
+ config, 0, 0 );
|
||
|
+
|
||
|
+ slot = SECMOD_OpenUserDB( config );
|
||
|
+ if ( !slot ) {
|
||
|
+ PRErrorCode errcode = PR_GetError();
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_init_open_certdb: ERROR: cannot open certdb `%s`, error `%d:%s`.\n",
|
||
|
+ nssdb_dir, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( config ) PR_smprintf_free( config );
|
||
|
+
|
||
|
+ return slot;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* Borrowed from tlsm_deferred_init */
|
||
|
+int
|
||
|
+tlsmc_open_nssdb( char *ld_cacertdir, NSSInitContext **out_initctx, char **out_nssdb_dir, char **out_nssdb_prefix )
|
||
|
+{
|
||
|
+#define SECURITYDIRS_COUNT 3
|
||
|
+ int rc = 0;
|
||
|
+ PRErrorCode errcode = 1;
|
||
|
+
|
||
|
+ /* restart secmod modules */
|
||
|
+#ifdef HAVE_SECMOD_RESTARTMODULES
|
||
|
+ /* NSS enforces the pkcs11 requirement that modules should be unloaded after
|
||
|
+ a fork() - since there is no portable way to determine if NSS has been
|
||
|
+ already initialized in a parent process, we just call SECMOD_RestartModules
|
||
|
+ with force == FALSE - if the module has been unloaded due to a fork, it will
|
||
|
+ be reloaded, otherwise, it is a no-op */
|
||
|
+ if ( 0 == ( rc = SECMOD_RestartModules(PR_FALSE /* do not force */) ) ) {
|
||
|
+ errcode = PORT_GetError();
|
||
|
+ if ( errcode != SEC_ERROR_NOT_INITIALIZED ) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_open_nssdb: WARN: could not restart the security modules: %d:%s.\n",
|
||
|
+ errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
|
||
|
+ } else {
|
||
|
+ errcode = 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
+
|
||
|
+ /* context and certdb */
|
||
|
+ char *dir_moznss = PR_GetEnv( "MOZNSS_DIR" );
|
||
|
+ char *dir_default_moznss = PR_GetEnv( "DEFAULT_MOZNSS_DIR" );
|
||
|
+ const char *securitydirs[SECURITYDIRS_COUNT] = { dir_moznss, ld_cacertdir, dir_default_moznss };
|
||
|
+ int done = 0;
|
||
|
+ int ii = 0;
|
||
|
+ for ( ii = 0; !done && ( ii < SECURITYDIRS_COUNT ); ++ii ) {
|
||
|
+ // get certdb prefix
|
||
|
+ const char *securitydir = securitydirs[ii];
|
||
|
+ char *realcertdir = NULL;
|
||
|
+ const char *defprefix = "";
|
||
|
+ char *prefix = (char *)defprefix;
|
||
|
+ if ( securitydir == NULL ) continue;
|
||
|
+ tlsmc_get_certdb_prefix( securitydir, &realcertdir, &prefix ); //FIXME
|
||
|
+ *out_nssdb_dir = strdup( realcertdir );
|
||
|
+ *out_nssdb_prefix = strdup( prefix );
|
||
|
+
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_open_nssdb: INFO: trying to initialize moznss using security dir `%s` prefix `%s`.\n",
|
||
|
+ realcertdir, prefix, NULL);
|
||
|
+
|
||
|
+ // init context
|
||
|
+ NSSInitContext *initctx = NULL;
|
||
|
+ NSSInitParameters initparams;
|
||
|
+ memset( &initparams, 0, sizeof( initparams ) );
|
||
|
+ initparams.length = sizeof( initparams );
|
||
|
+
|
||
|
+ initctx = NSS_InitContext( realcertdir,
|
||
|
+ prefix,
|
||
|
+ prefix,
|
||
|
+ SECMOD_DB,
|
||
|
+ &initparams,
|
||
|
+ NSS_INIT_READONLY // | NSS_INIT_NOCERTDB
|
||
|
+ );
|
||
|
+ rc = initctx ? 1 : 0;
|
||
|
+
|
||
|
+ *out_initctx = initctx;
|
||
|
+
|
||
|
+ if ( rc != 1 ) {
|
||
|
+ errcode = PORT_GetError();
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_open_nssdb: WARN: could not initialize MozNSS context - error %d.\n",
|
||
|
+ errcode, 0, 0 );
|
||
|
+ } else {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_open_nssdb: INFO: initialized MozNSS context.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ errcode = 0;
|
||
|
+ done = 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ PR_Free( dir_moznss );
|
||
|
+ PR_Free( dir_default_moznss );
|
||
|
+
|
||
|
+ PK11_SetPasswordFunc( tlsmc_get_pin );
|
||
|
+
|
||
|
+ if ( done && (errcode == 0) && out_initctx ) {
|
||
|
+ return 1;
|
||
|
+ } else {
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int
|
||
|
+tlsmc_is_sql_nssdb( const char *ld_cacertdir )
|
||
|
+{
|
||
|
+ if ( 0 == strncmp( "sql:", ld_cacertdir, 4 ) ) {
|
||
|
+ return 1;
|
||
|
+ } else {
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_filestamp( char **filestamp, char *path )
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ struct stat attr;
|
||
|
+ char stime[20];
|
||
|
+
|
||
|
+ if ( 0 != stat( path, &attr ) ) {
|
||
|
+ perror("IO ERROR: could not stat file");
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ if ( 0 == strftime(stime, sizeof(stime), "%FT%T", localtime(&attr.st_mtime)) ) {
|
||
|
+ perror("IO ERROR: could not format mtime");
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ *filestamp = PR_smprintf("mtime %s.%d, size %lld",
|
||
|
+ stime, attr.st_mtim.tv_nsec, (long long) attr.st_size);
|
||
|
+
|
||
|
+ rv = 1;
|
||
|
+bail:
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+char *
|
||
|
+tlsmc_compute_checksum( char *nssdb_dir, char *nssdb_prefix,
|
||
|
+ char *ld_cacertdir, char *ld_cert, char *ld_key,
|
||
|
+ char **out_data)
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ char *data = NULL;
|
||
|
+
|
||
|
+ /* gather data */
|
||
|
+ data = PR_sprintf_append( data,
|
||
|
+ DONOTEDIT "\n"
|
||
|
+ README_HEADER "\n"
|
||
|
+ "PARAMETERS:\n"
|
||
|
+ "nssdb_dir: %s\n"
|
||
|
+ "nssdb_prefix: %s\n"
|
||
|
+ "ld_cacertdir: %s\n"
|
||
|
+ "ld_cert: %s\n"
|
||
|
+ "ld_key: %s\n"
|
||
|
+ "euid: %d\n\n"
|
||
|
+ "FILES:\n",
|
||
|
+ nssdb_dir, nssdb_prefix, ld_cacertdir, ld_cert, ld_key, geteuid() );
|
||
|
+
|
||
|
+ char *bdb_files[] = { "cert8.db", "key3.db", "secmod.db", NULL };
|
||
|
+ char *sql_files[] = { "cert9.db", "key4.db", "secmod.db", NULL };
|
||
|
+ char **files = ( 1 == tlsmc_is_sql_nssdb( ld_cacertdir ) ) ? sql_files : bdb_files; // FIXME we should do all files as default prefix may (and will) change and thus change the semantics of the ld_cacertdir
|
||
|
+ char *file = *files;
|
||
|
+ while ( NULL != ( file = *(files++) ) ) {
|
||
|
+ char *filestamp = NULL;
|
||
|
+ char *path = NULL;
|
||
|
+ path = PR_smprintf( "%s/%s%s", nssdb_dir, nssdb_prefix, file );
|
||
|
+ if ( 0 == tlsmc_filestamp( &filestamp, path ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_compute_checksum: ERROR: could not stat file `%s'.\n",
|
||
|
+ path, 0, 0 );
|
||
|
+ rv = -1;
|
||
|
+ } else {
|
||
|
+ data = PR_sprintf_append( data, "%s: %s\n", file, filestamp );
|
||
|
+ }
|
||
|
+ bail_one:
|
||
|
+ if ( filestamp ) PR_smprintf_free( filestamp );
|
||
|
+ if ( path ) PR_smprintf_free( path );
|
||
|
+ if ( -1 == rv ) goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* compute data checksum */
|
||
|
+ unsigned char *checksum = NULL;
|
||
|
+ if ( 1 != tlsmc_hash( &checksum, data ) ) {
|
||
|
+ checksum = NULL;
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* possibly supply data */
|
||
|
+ if ( out_data ) {
|
||
|
+ *out_data = strdup( data );
|
||
|
+ }
|
||
|
+
|
||
|
+ /* return checksum */
|
||
|
+bail:
|
||
|
+ if ( data ) PR_smprintf_free( data );
|
||
|
+ return checksum;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_prepare_dir( char *dir )
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ PRFileInfo info;
|
||
|
+ PRStatus prv;
|
||
|
+ char *cacerts_dir = NULL;
|
||
|
+
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_prepare_dir: INFO: preparing PEM directory `%s'.\n",
|
||
|
+ dir, 0, 0 );
|
||
|
+
|
||
|
+ if ( 0 != mkdir( dir, S_IRWXU /* u+rwx */ ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_prepare_dir: WARN: cound not create the PEM directory.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ perror( "tlsmc_prepare_dir: WARN: cound not create the PEM directory" );
|
||
|
+ rv = 0;
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_prepare_dir: INFO: creating a subdirectory `%s'.\n",
|
||
|
+ TLSMC_CACERTS_DIR_NAME, 0, 0 );
|
||
|
+ cacerts_dir = PR_smprintf( "%s/%s", dir, TLSMC_CACERTS_DIR_NAME );
|
||
|
+ if ( 0 != mkdir( cacerts_dir, S_IRWXU /* u+rwx */ ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_prepare_dir: WARN: cound not create the subdirectory.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ perror( "tlsmc_prepare_dir: WARN: cound not create the subdirectory" );
|
||
|
+ rv = 0;
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_prepare_dir: INFO: successfully created PEM directory structure.\n",
|
||
|
+ TLSMC_CACERTS_DIR_NAME, 0, 0 );
|
||
|
+ rv = 1;
|
||
|
+
|
||
|
+bail:
|
||
|
+ if ( cacerts_dir ) PR_smprintf_free( cacerts_dir );
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_extract_cert_to_file(CERTCertDBHandle *certdb_handle, CERTCertificate *cert, char *file_path)
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ SECItem data;
|
||
|
+ char *b64 = NULL;
|
||
|
+ char *output = NULL;
|
||
|
+
|
||
|
+ if ( ! cert ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cert_to_file: ERROR: cert empty.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ data.data = cert->derCert.data;
|
||
|
+ data.len = cert->derCert.len;
|
||
|
+ b64 = BTOA_DataToAscii(data.data, data.len);
|
||
|
+ if ( ! b64 ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cert_to_file: ERROR: could not base64 encode.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ output = PR_smprintf( DONOTEDIT "\n\n"
|
||
|
+ "NSS nickname: %s\n"
|
||
|
+ "Issuer: %s\n"
|
||
|
+ "Subject: %s\n"
|
||
|
+ PEM_CERT_HEADER "\n"
|
||
|
+ "%s\n"
|
||
|
+ PEM_CERT_FOOTER "\n",
|
||
|
+ cert->nickname,
|
||
|
+ cert->issuerName,
|
||
|
+ cert->subjectName,
|
||
|
+ b64 );
|
||
|
+
|
||
|
+ if ( 0 == tlsmc_write_file( file_path, output, S_IRUSR ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cert_to_file: ERROR: could not write certificate.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ rv = 1;
|
||
|
+bail:
|
||
|
+ if ( output ) PR_smprintf_free( output );
|
||
|
+ if ( b64 ) PORT_Free( b64 );
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
+/* borrowed from 389-ds-base, ssl.c, DecryptKey */
|
||
|
+int
|
||
|
+tlsmc_decrypt_key(SECKEYEncryptedPrivateKeyInfo *epki,
|
||
|
+ SECOidTag algTag,
|
||
|
+ SECItem *pwitem,
|
||
|
+ void *pin_arg,
|
||
|
+ SECItem *derPKI)
|
||
|
+{
|
||
|
+ SECItem *cryptoParam = NULL;
|
||
|
+ PK11SymKey *symKey = NULL;
|
||
|
+ PK11Context *ctx = NULL;
|
||
|
+ int rv = 0;
|
||
|
+
|
||
|
+ if (!pwitem) return rv;
|
||
|
+
|
||
|
+ do {
|
||
|
+ SECAlgorithmID algid = epki->algorithm;
|
||
|
+ CK_MECHANISM_TYPE cryptoMechType;
|
||
|
+ CK_ATTRIBUTE_TYPE operation = CKA_DECRYPT;
|
||
|
+ PK11SlotInfo *slot = NULL;
|
||
|
+
|
||
|
+ cryptoMechType = PK11_GetPBECryptoMechanism(&algid, &cryptoParam, pwitem);
|
||
|
+ if (cryptoMechType == CKM_INVALID_MECHANISM) {
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( NULL == ( slot = PK11_GetBestSlot(cryptoMechType, NULL) ) ) {
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( NULL == ( symKey = PK11_PBEKeyGen(slot, &algid, pwitem, PR_FALSE, pin_arg) ) ) {
|
||
|
+ rv = -1;
|
||
|
+ goto bail_one;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( NULL == ( ctx = PK11_CreateContextBySymKey(
|
||
|
+ cryptoMechType, operation, symKey, cryptoParam) ) ) {
|
||
|
+ rv = -1;
|
||
|
+ goto bail_one;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( SECSuccess != PK11_CipherOp(ctx,
|
||
|
+ derPKI->data, /* out */
|
||
|
+ (int *)(&derPKI->len), /* out len */
|
||
|
+ (int)epki->encryptedData.len, /* max out */
|
||
|
+ epki->encryptedData.data, /* in */
|
||
|
+ (int)epki->encryptedData.len /* in len */ ) ) {
|
||
|
+ rv = -1;
|
||
|
+ goto bail_one;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( derPKI->len != epki->encryptedData.len ) goto bail_one;
|
||
|
+ if ( SECSuccess != PK11_Finalize(ctx) ) goto bail_one;
|
||
|
+ bail_one:
|
||
|
+ if (slot) PK11_FreeSlot(slot);
|
||
|
+ } while (0);
|
||
|
+
|
||
|
+ rv = ((rv == 0) ? 1 : 0);
|
||
|
+bail:
|
||
|
+ if (symKey) PK11_FreeSymKey(symKey);
|
||
|
+ if (cryptoParam) {
|
||
|
+ SECITEM_ZfreeItem(cryptoParam, PR_TRUE);
|
||
|
+ cryptoParam = NULL;
|
||
|
+ }
|
||
|
+ if (ctx) PK11_DestroyContext(ctx, PR_TRUE);
|
||
|
+
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_extract_key_of_cert_to_file(CERTCertificate *cert,
|
||
|
+ char *pin_filename,
|
||
|
+ char *filename)
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ SECKEYPrivateKey *key = NULL;
|
||
|
+ SECItem pwitem;
|
||
|
+ SECKEYEncryptedPrivateKeyInfo *epki = NULL;
|
||
|
+ PLArenaPool *arenaForPKI = NULL;
|
||
|
+ SECItem clearKeyDER;
|
||
|
+ char *b64 = NULL;
|
||
|
+ char *output = NULL;
|
||
|
+ //SECItem *data = PK11_ExportDERPrivateKeyInfo(key, (void *)pin_filename); // FIXME NULL? // probably won't work
|
||
|
+
|
||
|
+ // establish password
|
||
|
+ pwitem.data = "secretpw"; // FIXME use pin_filename
|
||
|
+ pwitem.len = strlen(pwitem.data);
|
||
|
+ pwitem.type = siBuffer;
|
||
|
+
|
||
|
+ // get key
|
||
|
+ if ( NULL == ( key = PK11_FindKeyByAnyCert(cert, (void *)pin_filename) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_key_of_cert_to_file: ERROR: PK11_FindKeyByAnyCert failed.\n",
|
||
|
+ 0,0,0);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ // get key info
|
||
|
+ if ( NULL == ( epki = PK11_ExportEncryptedPrivKeyInfo(
|
||
|
+ NULL, SEC_OID_DES_EDE3_CBC, &pwitem, key, 1000, (void *)pin_filename) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_key_of_cert_to_file: ERROR: PK11_ExportEncryptedPrivKeyInfo returned NULL.\n",
|
||
|
+ 0,0,0);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ // get clear DER
|
||
|
+ if ( NULL == ( arenaForPKI = PORT_NewArena(2048) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_key_of_cert_to_file: ERROR: PORT_NewArena failed.\n",
|
||
|
+ 0,0,0);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ clearKeyDER.data = PORT_ArenaAlloc(arenaForPKI, epki->encryptedData.len);
|
||
|
+ clearKeyDER.len = epki->encryptedData.len;
|
||
|
+ clearKeyDER.type = siBuffer;
|
||
|
+
|
||
|
+ if ( 0 == tlsmc_decrypt_key(epki, SEC_OID_DES_EDE3_CBC, &pwitem,
|
||
|
+ (void *)pin_filename, &clearKeyDER) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_key_of_cert_to_file: ERROR: could not decrypt the key.\n",
|
||
|
+ 0,0,0);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ // base64 encode
|
||
|
+ if ( NULL == ( b64 = BTOA_ConvertItemToAscii(&clearKeyDER) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_key_of_cert_to_file: ERROR: could not base64 encode.\n",
|
||
|
+ 0,0,0);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ // print out
|
||
|
+ output = PR_smprintf( DONOTEDIT "\n"
|
||
|
+ PEM_KEY_HEADER "\n"
|
||
|
+ "%s\n"
|
||
|
+ PEM_KEY_FOOTER "\n",
|
||
|
+ b64 );
|
||
|
+
|
||
|
+ if ( 0 == tlsmc_write_file( filename, output, S_IRUSR ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_key_of_cert_to_file: ERROR: could not write PK.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ rv = 1;
|
||
|
+
|
||
|
+bail:
|
||
|
+ if (b64) PORT_Free(b64);
|
||
|
+ if (arenaForPKI) PORT_FreeArena(arenaForPKI, PR_FALSE);
|
||
|
+ if (epki) SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
|
||
|
+ if (key) SECKEY_DestroyPrivateKey(key);
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+//TODO drop?
|
||
|
+int
|
||
|
+tlsmc_extract_cert_key_pair(char *nickname, char *pin_filename, char *dir_name)
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ int fd = -1;
|
||
|
+ CERTCertDBHandle *certHandle = NULL;
|
||
|
+ CERTCertificate *cert = NULL;
|
||
|
+ char *cert_file_path = NULL;
|
||
|
+ char *key_file_path = NULL;
|
||
|
+
|
||
|
+ if ( NULL == ( certHandle = CERT_GetDefaultCertDB() ) ) {
|
||
|
+ // FIXME see same in tlsmc_extract_cacerts()
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cert_key_pair: ERROR: could not get certificate handle.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ if ( NULL == ( cert = PK11_FindCertFromNickname(nickname, NULL) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cert_key_pair: ERROR: could not find certificate with nickname `%s'.\n",
|
||
|
+ nickname, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* cert */
|
||
|
+ cert_file_path = PR_smprintf( "%s/cert.pem", dir_name );
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_extract_cert_key_pair: INFO: extracting certificate `%s' to file `%s'.\n",
|
||
|
+ nickname, cert_file_path, 0 );
|
||
|
+ if ( 0 == tlsmc_extract_cert_to_file(certHandle, cert, cert_file_path) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cert_key_pair: ERROR: could not extract certificate.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* key */
|
||
|
+ key_file_path = PR_smprintf( "%s/key.pem", dir_name );
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_extract_cert_key_pair: INFO: extracting associated PK to file `%s'.\n",
|
||
|
+ key_file_path, 0, 0 );
|
||
|
+ if ( 0 == tlsmc_extract_key_of_cert_to_file( cert, pin_filename, key_file_path ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cert_key_pair: ERROR: could not extract PK.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ rv = 1;
|
||
|
+
|
||
|
+bail:
|
||
|
+ if (key_file_path) PR_smprintf_free(key_file_path);
|
||
|
+ if (cert_file_path) PR_smprintf_free(cert_file_path);
|
||
|
+ if (cert) CERT_DestroyCertificate(cert);
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* Adopted from 389DS. */
|
||
|
+static int
|
||
|
+tlsmc_list_certs(CERTCertDBHandle *handle,
|
||
|
+ CERTCertificate *cert,
|
||
|
+ PK11SlotInfo *slot,
|
||
|
+ PRFileDesc *outfile,
|
||
|
+ void *pwarg)
|
||
|
+{
|
||
|
+ SECItem data;
|
||
|
+ int rv = 0;
|
||
|
+ CERTCertList *certs;
|
||
|
+ CERTCertListNode *node;
|
||
|
+ CERTCertificate *the_cert = NULL;
|
||
|
+ char *name = NULL;
|
||
|
+
|
||
|
+ if (!cert) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_list_certs: WARN: no cert given.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ return rv;
|
||
|
+ }
|
||
|
+ name = cert->nickname;
|
||
|
+
|
||
|
+ if (!name) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_list_certs: WARN: no cert nickname.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ return rv;
|
||
|
+ }
|
||
|
+ the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
|
||
|
+ if (!the_cert) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_list_certs: WARN: could not find cert: %s.\n",
|
||
|
+ name, 0, 0 );
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ PR_fprintf(outfile, "%s\n", DONOTEDIT);
|
||
|
+ /* Here, we have one cert with the desired nickname or email
|
||
|
+ * address. Now, we will attempt to get a list of ALL certs
|
||
|
+ * with the same subject name as the cert we have. That list
|
||
|
+ * should contain, at a minimum, the one cert we have already found.
|
||
|
+ * If the list of certs is empty (NULL), the libraries have failed.
|
||
|
+ */
|
||
|
+ certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject,
|
||
|
+ PR_Now(), PR_FALSE);
|
||
|
+ CERT_DestroyCertificate(the_cert);
|
||
|
+ if (!certs) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_list_certs: WARN: problem printing certificates.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs); node = CERT_LIST_NEXT(node)) {
|
||
|
+ the_cert = node->cert;
|
||
|
+ PR_fprintf(outfile, "Issuer: %s\n", the_cert->issuerName);
|
||
|
+ PR_fprintf(outfile, "Subject: %s\n", the_cert->subjectName);
|
||
|
+ /* now get the subjectList that matches this cert */
|
||
|
+ data.data = the_cert->derCert.data;
|
||
|
+ data.len = the_cert->derCert.len;
|
||
|
+ PR_fprintf(outfile, "\n%s\n%s\n%s\n",
|
||
|
+ PEM_CERT_HEADER,
|
||
|
+ BTOA_DataToAscii(data.data, data.len),
|
||
|
+ PEM_CERT_FOOTER);
|
||
|
+ rv = 1;
|
||
|
+ }
|
||
|
+ if (certs) {
|
||
|
+ CERT_DestroyCertList(certs);
|
||
|
+ }
|
||
|
+ if (rv) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_list_certs: WARN: problem printing certificate nicknames.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+static char*
|
||
|
+tlsmc_extract_key()
|
||
|
+{
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+/* Adopted from 389DS. */
|
||
|
+static int
|
||
|
+tlsmc_extract_cert(char *token_colon_name, char *filename)
|
||
|
+{
|
||
|
+ CERTCertListNode *node;
|
||
|
+ CERTCertList *list = PK11_ListCerts(PK11CertListAll, NULL);
|
||
|
+ for (node = CERT_LIST_HEAD(list);
|
||
|
+ !CERT_LIST_END(node, list);
|
||
|
+ node = CERT_LIST_NEXT(node)) {
|
||
|
+ CERTCertificate *cert = node->cert;
|
||
|
+ CERTCertTrust trust;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_extract_cacerts( char *dir_name )
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ CERTCertDBHandle *certHandle = NULL;
|
||
|
+ CERTCertListNode *node = NULL;
|
||
|
+ CERTCertList *list = NULL;
|
||
|
+ char *cacerts_dir = NULL;
|
||
|
+ int cert_cnt = 0;
|
||
|
+
|
||
|
+ cacerts_dir = PR_smprintf( "%s/" TLSMC_CACERTS_DIR_NAME, dir_name );
|
||
|
+
|
||
|
+ certHandle = CERT_GetDefaultCertDB(); // FIXME maybe we should really use certdb_slot?
|
||
|
+ if ( ! certHandle ) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_extract_cacerts: could not get certificate database handle.\n",
|
||
|
+ 0, 0, 0);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ list = PK11_ListCerts(PK11CertListAll, NULL);
|
||
|
+ if ( ! list ) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_extract_cacerts: could not get list of certificates.\n",
|
||
|
+ 0, 0, 0);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ for ( node = CERT_LIST_HEAD(list);
|
||
|
+ !CERT_LIST_END(node, list);
|
||
|
+ node = CERT_LIST_NEXT(node)) {
|
||
|
+
|
||
|
+ CERTCertificate *cert = NULL;
|
||
|
+ CERTCertTrust trust;
|
||
|
+ char *cert_file_path = NULL;
|
||
|
+ int is_ca = 0;
|
||
|
+
|
||
|
+ cert = node->cert;
|
||
|
+ if ( SECFailure == CERT_GetCertTrust( cert, &trust ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cacerts: ERROR: could not get trust flags of certificate nick=`%s'.\n",
|
||
|
+ cert->nickname, 0, 0);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ if (trust.sslFlags &
|
||
|
+ (CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA)) {
|
||
|
+ is_ca = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ Debug(LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_extract_cacerts: INFO: found cert nick=`%s'%s.\n",
|
||
|
+ cert->nickname, is_ca ? ", a trusted CA" : ", _not_ a trusted CA, skipping", 0);
|
||
|
+ if ( ! is_ca ) continue;
|
||
|
+
|
||
|
+ cert_file_path = PR_smprintf( "%s/cert%d.pem", cacerts_dir, cert_cnt );
|
||
|
+ cert_cnt++;
|
||
|
+ Debug(LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_extract_cacerts: INFO: extracting cert nick=`%s' to file `%s'.\n",
|
||
|
+ cert->nickname, cert_file_path, 0);
|
||
|
+ if ( 0 == tlsmc_extract_cert_to_file( certHandle, cert, cert_file_path ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cacerts: ERROR: could not extract the certificate.\n",
|
||
|
+ 0, 0, 0);
|
||
|
+ goto bail_one;
|
||
|
+ }
|
||
|
+ if ( 0 == tlsmc_cert_create_hash_symlink( cert_file_path, cacerts_dir ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_cacerts: ERROR: could not rehash the certificate.\n",
|
||
|
+ 0, 0, 0);
|
||
|
+ goto bail_one;
|
||
|
+ }
|
||
|
+ if ( cert_file_path ) PR_smprintf_free( cert_file_path );
|
||
|
+ continue;
|
||
|
+ bail_one:
|
||
|
+ if ( cert_file_path ) PR_smprintf_free( cert_file_path );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ rv = 1;
|
||
|
+bail:
|
||
|
+ if ( cacerts_dir ) PR_smprintf_free( cacerts_dir );
|
||
|
+ if ( list ) CERT_DestroyCertList( list );
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* returns 1 if successfull;
|
||
|
+ returns -1 if only cert-key pair is NULL or could not be extracted;
|
||
|
+ returns 0 if any other error
|
||
|
+*/
|
||
|
+int
|
||
|
+tlsmc_extract_nssdb( char *dir_name, char **ld_cacertdir, char **ld_cert, char **ld_key )
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+
|
||
|
+ if ( ! dir_name ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_nssdb: FATAL: target dir name empty.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( 0 == tlsmc_extract_cacerts( dir_name ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_nssdb: ERROR: could not export CA certificates.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( ( ! *ld_cert ) || ( ! *ld_key ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_nssdb: ERROR: cert or key empty.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ rv = -1;
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( 0 == tlsmc_extract_cert_key_pair( *ld_cert, *ld_key, dir_name ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_extract_nssdb: ERROR: could not export user cert and/or key.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ rv = -1;
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ rv = 1;
|
||
|
+bail:
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_close_nssdb(NSSInitContext **initctx)
|
||
|
+{
|
||
|
+ if ( *initctx && NSS_ShutdownContext( *initctx ) ) {
|
||
|
+ PRErrorCode errcode = PR_GetError();
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_close_nssdb: ERROR: could not shutdown NSS - error %d:%s.\n",
|
||
|
+ errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
|
||
|
+ return 0;
|
||
|
+ } else {
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_convert( char **ld_cacertdir, char **ld_cert, char **ld_key )
|
||
|
+{
|
||
|
+
|
||
|
+ int rv = 0;
|
||
|
+
|
||
|
+ NSSInitContext *nss_ctx = NULL;
|
||
|
+ char *nssdb_dir_path = NULL;
|
||
|
+ char *nssdb_dir_name = NULL;
|
||
|
+ char *nssdb_prefix = NULL;
|
||
|
+ char *pem_dirs[] = { NULL, NULL, NULL };
|
||
|
+ char *readme_path = NULL;
|
||
|
+ char *data = NULL; // data before checksum
|
||
|
+ char *checksum = NULL; // checksummed data
|
||
|
+ char **dirs = pem_dirs;
|
||
|
+ char *dir = *dirs;
|
||
|
+ struct stat stat_buf;
|
||
|
+
|
||
|
+#ifdef LDAP_R_COMPILE
|
||
|
+ ldap_pvt_thread_mutex_lock( &tlsmc_mutex );
|
||
|
+#endif
|
||
|
+
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_convert: INFO: trying to open NSS DB with CACertDir = `%s'.\n",
|
||
|
+ *ld_cacertdir, 0, 0 );
|
||
|
+ if ( 0 == tlsmc_open_nssdb( *ld_cacertdir, &nss_ctx, &nssdb_dir_path, &nssdb_prefix ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_convert: INFO: cannot open the NSS DB, expecting PEM configuration is present.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ rv = 1;
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( NULL == ( checksum = tlsmc_compute_checksum( nssdb_dir_path, nssdb_prefix,
|
||
|
+ *ld_cacertdir, *ld_cert, *ld_key,
|
||
|
+ &data ) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_convert: ERROR: could not compute checksum.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ pem_dirs[0] = PR_smprintf( "%s-%s-tlsmc-%s", nssdb_dir_path, nssdb_prefix, checksum );
|
||
|
+ pem_dirs[1] = PR_smprintf( "/tmp/%s", tlsmc_path2name( pem_dirs[0] ) );
|
||
|
+
|
||
|
+ int i=0;
|
||
|
+ while ( NULL != ( dir = *(dirs++) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_convert: INFO: trying with PEM dir = `%s'.\n",
|
||
|
+ dir, 0, 0 );
|
||
|
+ if ( 0 == stat( dir, &stat_buf ) ) {
|
||
|
+ if ( S_ISDIR(stat_buf.st_mode) ) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_convert: INFO: using the existing PEM dir.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ break;
|
||
|
+ } else {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_convert: WARN: tried to stat the PEM dir but it is not a directory, will try another one.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_convert: WARN: could not stat PEM dir, will try to create it.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ if ( 0 == tlsmc_prepare_dir( dir ) ) {
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_convert: WARN: cannot prepare the PEM dir, will try another one.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if ( 0 == tlsmc_extract_nssdb( dir, ld_cacertdir, ld_cert, ld_key ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_convert: FATAL: could not extract from the NSS DB.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ readme_path = PR_smprintf( "%s/" TLSMC_README_FILE_NAME, dir );
|
||
|
+ tlsmc_write_file( readme_path, data, S_IRUSR );
|
||
|
+ rv = 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( dir == NULL ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_convert: FATAL: no usable PEM dir.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (*ld_cacertdir) free(*ld_cacertdir);
|
||
|
+ *ld_cacertdir = PR_smprintf( "%s/" TLSMC_CACERTS_DIR_NAME, dir );
|
||
|
+ if ( ! ( ( 0 == stat( *ld_cacertdir, &stat_buf ) )
|
||
|
+ && S_ISDIR(stat_buf.st_mode) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_convert: WARN: extracted cacerts dir is not present.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ *ld_cacertdir = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (*ld_cert) free(*ld_cert);
|
||
|
+ *ld_cert = PR_smprintf( "%s/" TLSMC_CERT_FILE_NAME, dir );
|
||
|
+ if ( ! ( ( 0 == stat( *ld_cert, &stat_buf ) )
|
||
|
+ && S_ISREG(stat_buf.st_mode) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_convert: WARN: extracted cert file is not present.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ *ld_cert = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (*ld_key) free(*ld_key);
|
||
|
+ *ld_key = PR_smprintf( "%s/" TLSMC_KEY_FILE_NAME, dir );
|
||
|
+ if ( ! ( ( 0 == stat( *ld_key, &stat_buf ) )
|
||
|
+ && S_ISREG(stat_buf.st_mode) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_convert: WARN: extracted key file is not present.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ *ld_key = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ rv = 1;
|
||
|
+
|
||
|
+bail:
|
||
|
+ if ( pem_dirs[0] ) PR_smprintf_free( pem_dirs[0] );
|
||
|
+ if ( pem_dirs[1] ) PR_smprintf_free( pem_dirs[1] );
|
||
|
+ if ( nssdb_prefix ) free( nssdb_prefix );
|
||
|
+ if ( nssdb_dir_path ) free( nssdb_dir_path );
|
||
|
+ if ( nss_ctx ) tlsmc_close_nssdb( &nss_ctx );
|
||
|
+
|
||
|
+#ifdef LDAP_R_COMPILE
|
||
|
+ ldap_pvt_thread_mutex_unlock( &tlsmc_mutex );
|
||
|
+#endif
|
||
|
+
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
+// returns 0 when successful
|
||
|
+int
|
||
|
+tlsmc_intercept_initialization( struct ldapoptions *lo, int is_server )
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ char *ld_cacertdir = NULL;
|
||
|
+ char *ld_cert = NULL;
|
||
|
+ char *ld_key = NULL;
|
||
|
+
|
||
|
+ ld_cacertdir = lo->ldo_tls_cacertdir ? LDAP_STRDUP( (char *) lo->ldo_tls_cacertdir ) : NULL;
|
||
|
+ ld_cert = lo->ldo_tls_certfile ? LDAP_STRDUP( (char *) lo->ldo_tls_certfile ) : NULL;
|
||
|
+ ld_key = lo->ldo_tls_keyfile ? LDAP_STRDUP( (char *) lo->ldo_tls_keyfile ) : NULL;
|
||
|
+
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_intercept_initialization: INFO: entry options follow:\n"
|
||
|
+ "tlsmc_intercept_initialization: INFO: cacertdir = `%s'\n"
|
||
|
+ "tlsmc_intercept_initialization: INFO: certfile = `%s'\n"
|
||
|
+ "tlsmc_intercept_initialization: INFO: keyfile = `%s'\n",
|
||
|
+ lo->ldo_tls_cacertdir, lo->ldo_tls_certfile, lo->ldo_tls_keyfile );
|
||
|
+
|
||
|
+ if ( 0 == tlsmc_convert( &ld_cacertdir, &ld_cert, &ld_key ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_intercept_initialization: FATAL: could not intercept TLS initialization. TLS will not work!\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( lo->ldo_tls_cacertdir ) LDAP_FREE( lo->ldo_tls_cacertdir );
|
||
|
+ lo->ldo_tls_cacertdir = ld_cacertdir ? LDAP_STRDUP( (char *) ld_cacertdir ) : NULL;
|
||
|
+
|
||
|
+ if ( lo->ldo_tls_certfile ) LDAP_FREE( lo->ldo_tls_certfile );
|
||
|
+ lo->ldo_tls_certfile = ld_cert ? LDAP_STRDUP( (char *) ld_cert ) : NULL;
|
||
|
+
|
||
|
+ if ( lo->ldo_tls_keyfile ) LDAP_FREE( lo->ldo_tls_keyfile );
|
||
|
+ lo->ldo_tls_keyfile = ld_key ? LDAP_STRDUP( (char *) ld_key ) : NULL;
|
||
|
+
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_intercept_initialization: INFO: altered options follow:\n"
|
||
|
+ "tlsmc_intercept_initialization: INFO: cacertdir = `%s'\n"
|
||
|
+ "tlsmc_intercept_initialization: INFO: certfile = `%s'\n"
|
||
|
+ "tlsmc_intercept_initialization: INFO: keyfile = `%s'\n",
|
||
|
+ lo->ldo_tls_cacertdir, lo->ldo_tls_certfile, lo->ldo_tls_keyfile );
|
||
|
+
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_intercept_initialization: INFO: successfully intercepted TLS initialization. Continuing with OpenSSL only.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ rv = 1;
|
||
|
+bail:
|
||
|
+ if ( ld_cacertdir ) LDAP_FREE( ld_cacertdir );
|
||
|
+ if ( ld_cert ) LDAP_FREE( ld_cert );
|
||
|
+ if ( ld_key ) LDAP_FREE( ld_key );
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+#endif /* HAVE_MOZNSS_COMPATIBILITY */
|
||
|
+/*
|
||
|
+ emacs settings
|
||
|
+ Local Variables:
|
||
|
+ indent-tabs-mode: t
|
||
|
+ tab-width: 4
|
||
|
+ End:
|
||
|
+*/
|
||
|
diff --git a/libraries/libldap/tls_mc.h b/libraries/libldap/tls_mc.h
|
||
|
new file mode 100644
|
||
|
index 000000000..2e6e567dc
|
||
|
--- /dev/null
|
||
|
+++ b/libraries/libldap/tls_mc.h
|
||
|
@@ -0,0 +1,18 @@
|
||
|
+#ifndef _LDAP_TLSMC_H
|
||
|
+#define _LDAP_TLSMC_H
|
||
|
+
|
||
|
+#include "portable.h"
|
||
|
+
|
||
|
+#ifdef HAVE_MOZNSS_COMPATIBILITY
|
||
|
+
|
||
|
+#include "ldap-int.h"
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_convert( char **ld_cacertdir, char **ld_cert, char **ld_key );
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_intercept_initialization( struct ldapoptions *lo, int is_server );
|
||
|
+
|
||
|
+
|
||
|
+#endif /* HAVE_MOZNSS_COMPATIBILITY */
|
||
|
+#endif /* _LDAP_TLSMC_H */
|
||
|
diff --git a/libraries/libldap/tls_mc_ossl.c b/libraries/libldap/tls_mc_ossl.c
|
||
|
new file mode 100644
|
||
|
index 000000000..d61ec207c
|
||
|
--- /dev/null
|
||
|
+++ b/libraries/libldap/tls_mc_ossl.c
|
||
|
@@ -0,0 +1,90 @@
|
||
|
+#include "portable.h"
|
||
|
+
|
||
|
+/* This file contains functions that require OpenSSL headers due to some
|
||
|
+ conflicts with what MozNSS defines.
|
||
|
+*/
|
||
|
+
|
||
|
+#ifdef HAVE_MOZNSS_COMPATIBILITY
|
||
|
+
|
||
|
+#include <openssl/x509.h>
|
||
|
+#include <openssl/pem.h>
|
||
|
+#include "ldap-int.h"
|
||
|
+#include <nspr/nspr.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_cert_create_hash_symlink( char *cert_path, char *cacerts_dir )
|
||
|
+{
|
||
|
+ int rv = 0;
|
||
|
+ X509 *cert = NULL;
|
||
|
+ FILE *fp = NULL;
|
||
|
+ unsigned long hash = 0;
|
||
|
+ char *cert_filename_p = NULL;
|
||
|
+ char *last_slash_p = NULL;
|
||
|
+ char *symlink_path = NULL;
|
||
|
+ int cnt = 0;
|
||
|
+
|
||
|
+ if ( NULL == ( fp = fopen( cert_path, "r" ) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_cert_create_hash_symlink: ERROR: could not open the cert file.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ perror( "tlsmc_cert_create_hash_symlink: ERROR: OS error" );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ if ( NULL == PEM_read_X509( fp, &cert, NULL, NULL ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_cert_create_hash_symlink: ERROR: could not read PEM data.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ if ( 0 == ( hash = X509_subject_name_hash( cert ) ) ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_cert_create_hash_symlink: ERROR: could not hash subject.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+
|
||
|
+ last_slash_p = strrchr( cert_path, '/' );
|
||
|
+ cert_filename_p = last_slash_p ? last_slash_p + 1 : cert_path;
|
||
|
+ for ( cnt = 0; cnt < 10; cnt++ ) {
|
||
|
+ symlink_path = PR_smprintf( "%s/%08lx.%d", cacerts_dir, hash, cnt );
|
||
|
+ if ( 0 != symlink( cert_filename_p, symlink_path ) ) {
|
||
|
+ if ( errno == EEXIST ) {
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_cert_create_hash_symlink: INFO: symlink `%s' already exists.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ if ( symlink_path ) PR_smprintf( symlink_path );
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_cert_create_hash_symlink: ERROR: could not create symlink.\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+ perror( "tlsmc_cert_create_hash_symlink: ERROR: OS error" );
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ Debug( LDAP_DEBUG_TRACE,
|
||
|
+ "tlsmc_cert_create_hash_symlink: INFO: the cert is now symlinked to %s.\n",
|
||
|
+ symlink_path, 0, 0 );
|
||
|
+ rv = 1;
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
+ Debug( LDAP_DEBUG_ANY,
|
||
|
+ "tlsmc_cert_create_hash_symlink: INFO: could not create symlink (all possible file names taken).\n",
|
||
|
+ 0, 0, 0 );
|
||
|
+bail:
|
||
|
+ if ( symlink_path ) PR_smprintf_free( symlink_path );
|
||
|
+ if ( cert ) X509_free( cert );
|
||
|
+ if ( fp ) fclose( fp );
|
||
|
+ return rv;
|
||
|
+}
|
||
|
+
|
||
|
+#endif /* HAVE_MOZNSS_COMPATIBILITY */
|
||
|
+/*
|
||
|
+ emacs settings
|
||
|
+ Local Variables:
|
||
|
+ indent-tabs-mode: t
|
||
|
+ tab-width: 4
|
||
|
+ End:
|
||
|
+*/
|
||
|
diff --git a/libraries/libldap/tls_mc_ossl.h b/libraries/libldap/tls_mc_ossl.h
|
||
|
new file mode 100644
|
||
|
index 000000000..1b4284576
|
||
|
--- /dev/null
|
||
|
+++ b/libraries/libldap/tls_mc_ossl.h
|
||
|
@@ -0,0 +1,12 @@
|
||
|
+#ifndef _LDAP_TLSMC_OSSL_H
|
||
|
+#define _LDAP_TLSMC_OSSL_H
|
||
|
+
|
||
|
+#include "portable.h"
|
||
|
+
|
||
|
+#ifdef HAVE_MOZNSS_COMPATIBILITY
|
||
|
+
|
||
|
+int
|
||
|
+tlsmc_cert_create_hash_symlink( char *cert_path, char *cacerts_dir );
|
||
|
+
|
||
|
+#endif
|
||
|
+#endif
|
||
|
diff --git a/libraries/libldap_r/Makefile.in b/libraries/libldap_r/Makefile.in
|
||
|
index cdf4070dd..c7a86c95f 100644
|
||
|
--- a/libraries/libldap_r/Makefile.in
|
||
|
+++ b/libraries/libldap_r/Makefile.in
|
||
|
@@ -28,7 +28,7 @@ XXSRCS = apitest.c test.c \
|
||
|
request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \
|
||
|
init.c options.c print.c string.c util-int.c schema.c \
|
||
|
charray.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
|
||
|
- tls2.c tls_o.c tls_g.c tls_m.c \
|
||
|
+ tls2.c tls_o.c tls_g.c tls_m.c tls_mc.c tls_mc_ossl.c \
|
||
|
turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c \
|
||
|
assertion.c deref.c ldif.c fetch.c
|
||
|
SRCS = threads.c rdwr.c rmutex.c tpool.c rq.c \
|
||
|
@@ -46,7 +46,7 @@ OBJS = threads.lo rdwr.lo rmutex.lo tpool.lo rq.lo \
|
||
|
request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \
|
||
|
init.lo options.lo print.lo string.lo util-int.lo schema.lo \
|
||
|
charray.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \
|
||
|
- tls2.lo tls_o.lo tls_g.lo tls_m.lo \
|
||
|
+ tls2.lo tls_o.lo tls_g.lo tls_m.lo tls_mc.lo tls_mc_ossl.lo \
|
||
|
turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo \
|
||
|
assertion.lo deref.lo ldif.lo fetch.lo
|
||
|
|