]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/autoca.c
Happy New Year
[openldap] / servers / slapd / overlays / autoca.c
index a109d4fea76c53f6fef5e696932ec912972dcc26..73a57476174dc938cb57fa90b56a7aa21b32310f 100644 (file)
@@ -2,8 +2,8 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2009-2017 The OpenLDAP Foundation.
- * Copyright 2009-2017 by Howard Chu.
+ * Copyright 2009-2018 The OpenLDAP Foundation.
+ * Copyright 2009-2018 by Howard Chu.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -21,8 +21,6 @@
 
 #include "portable.h"
 
-#define SLAPD_OVER_AUTOCA      SLAPD_MOD_DYNAMIC
-
 #ifdef SLAPD_OVER_AUTOCA
 
 #include <stdio.h>
 #include "slap.h"
 #include "config.h"
 
+#include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/evp.h>
+#include <openssl/bn.h>
+
+/* Starting with OpenSSL 1.1.0, rsa.h is no longer included in
+ * x509.h, so we need to explicitly include it for the
+ * call to EVP_PKEY_CTX_set_rsa_keygen_bits
+ */
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+#include <openssl/rsa.h>
+#define X509_get_notBefore(x)  X509_getm_notBefore(x)
+#define X509_get_notAfter(x)   X509_getm_notAfter(x)
+#endif
 
 /* This overlay implements a certificate authority that can generate
  * certificates automatically for any entry in the directory.
@@ -260,17 +271,16 @@ static int autoca_gencert( Operation *op, genargs *args )
        X509_NAME *subj_name, *issuer_name;
        X509 *subj_cert;
        struct berval derdn;
-       const unsigned char *p;
+       unsigned char *pp;
        EVP_PKEY *evpk = NULL;
        int rc;
-       unsigned char *pp;
 
        if ((subj_cert = X509_new()) == NULL)
                return -1;
 
        autoca_dnbv2der( op, args->subjectDN, &derdn );
-       p = (const unsigned char *)derdn.bv_val;
-       subj_name = d2i_X509_NAME( NULL, &p, derdn.bv_len );
+       pp = (unsigned char *)derdn.bv_val;
+       subj_name = d2i_X509_NAME( NULL, (const unsigned char **)&pp, derdn.bv_len );
        op->o_tmpfree( derdn.bv_val, op->o_tmpmemctx );
        if ( subj_name == NULL )
        {
@@ -286,10 +296,17 @@ fail2:
                if ( subj_name ) X509_NAME_free( subj_name );
                goto fail1;
        }
-       args->derpkey.bv_len = i2d_PrivateKey( evpk, NULL );
-       args->derpkey.bv_val = op->o_tmpalloc( args->derpkey.bv_len, op->o_tmpmemctx );
-       pp = args->derpkey.bv_val;
-       i2d_PrivateKey( evpk, &pp );
+       /* encode DER in PKCS#8 */
+       {
+               PKCS8_PRIV_KEY_INFO *p8inf;
+               if (( p8inf = EVP_PKEY2PKCS8( evpk )) == NULL )
+                       goto fail2;
+               args->derpkey.bv_len = i2d_PKCS8_PRIV_KEY_INFO( p8inf, NULL );
+               args->derpkey.bv_val = op->o_tmpalloc( args->derpkey.bv_len, op->o_tmpmemctx );
+               pp = (unsigned char *)args->derpkey.bv_val;
+               i2d_PKCS8_PRIV_KEY_INFO( p8inf, &pp );
+               PKCS8_PRIV_KEY_INFO_free( p8inf );
+       }
        args->newpkey = evpk;
 
        /* set random serial */
@@ -365,7 +382,7 @@ fail3:
                goto fail3;
        args->dercert.bv_len = i2d_X509( subj_cert, NULL );
        args->dercert.bv_val = op->o_tmpalloc( args->dercert.bv_len, op->o_tmpmemctx );
-       pp = args->dercert.bv_val;
+       pp = (unsigned char *)args->dercert.bv_val;
        i2d_X509( subj_cert, &pp );
        args->newcert = subj_cert;
        return 0;
@@ -440,24 +457,29 @@ static int autoca_savecert( Operation *op, saveargs *args )
 
 static const struct berval configDN = BER_BVC("cn=config");
 
-static int
-autoca_setca( Operation *op, struct berval *cacert )
+/* must run as a pool thread to avoid cn=config deadlock */
+static void *
+autoca_setca_task( void *ctx, void *arg )
 {
-       Operation op2;
+       Connection conn = { 0 };
+       OperationBuffer opbuf;
+       Operation *op;
+       struct berval *cacert = arg;
        Modifications mod;
        struct berval bvs[2];
-       BackendInfo *bi;
        slap_callback cb = {0};
        SlapReply rs = {REP_RESULT};
        const char *text;
 
-       op2 = *op;
+       connection_fake_init( &conn, &opbuf, ctx );
+       op = &opbuf.ob_op;
+
        mod.sml_numvals = 1;
        mod.sml_values = bvs;
        mod.sml_nvalues = NULL;
        mod.sml_desc = NULL;
        if ( slap_str2ad( "olcTLSCACertificate;binary", &mod.sml_desc, &text ))
-               return -1;
+               goto leave;
        mod.sml_op = LDAP_MOD_REPLACE;
        mod.sml_flags = SLAP_MOD_INTERNAL;
        bvs[0] = *cacert;
@@ -465,20 +487,32 @@ autoca_setca( Operation *op, struct berval *cacert )
        mod.sml_next = NULL;
 
        cb.sc_response = slap_null_cb;
-       op2.o_bd = select_backend( (struct berval *)&configDN, 0 );
-       if ( !op2.o_bd )
-               return -1;
+       op->o_bd = select_backend( (struct berval *)&configDN, 0 );
+       if ( !op->o_bd )
+               goto leave;
 
-       op2.o_tag = LDAP_REQ_MODIFY;
-       op2.o_callback = &cb;
-       op2.orm_modlist = &mod;
-       op2.orm_no_opattrs = 1;
-       op2.o_req_dn = configDN;
-       op2.o_req_ndn = configDN;
-       op2.o_dn = op2.o_bd->be_rootdn;
-       op2.o_ndn = op2.o_bd->be_rootndn;
-       op2.o_bd->be_modify( &op2, &rs );
-       return rs.sr_err;
+       op->o_tag = LDAP_REQ_MODIFY;
+       op->o_callback = &cb;
+       op->orm_modlist = &mod;
+       op->orm_no_opattrs = 1;
+       op->o_req_dn = configDN;
+       op->o_req_ndn = configDN;
+       op->o_dn = op->o_bd->be_rootdn;
+       op->o_ndn = op->o_bd->be_rootndn;
+       op->o_bd->be_modify( op, &rs );
+leave:
+       ch_free( arg );
+       return NULL;
+}
+
+static int
+autoca_setca( struct berval *cacert )
+{
+       struct berval *bv = ch_malloc( sizeof(struct berval) + cacert->bv_len );
+       bv->bv_len = cacert->bv_len;
+       bv->bv_val = (char *)(bv+1);
+       AC_MEMCPY( bv->bv_val, cacert->bv_val, bv->bv_len );
+       return ldap_pvt_thread_pool_submit( &connection_pool, autoca_setca_task, bv );
 }
 
 static int
@@ -486,11 +520,9 @@ autoca_setlocal( Operation *op, struct berval *cert, struct berval *pkey )
 {
        Modifications mod[2];
        struct berval bvs[4];
-       BackendInfo *bi;
        slap_callback cb = {0};
        SlapReply rs = {REP_RESULT};
        const char *text;
-       static const struct berval config = BER_BVC("cn=config");
 
        mod[0].sml_numvals = 1;
        mod[0].sml_values = bvs;
@@ -827,6 +859,12 @@ autoca_op_response(
                        arg2.oc = NULL;
                else
                        arg2.oc = oc_usrObj;
+               if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ))
+               {
+                       Entry *e = entry_dup( rs->sr_entry );
+                       rs_replace_entry( op, rs, on, e );
+                       rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
+               }
                arg2.dercert = &args.dercert;
                arg2.derpkey = &args.derpkey;
                arg2.on = on;
@@ -840,12 +878,6 @@ autoca_op_response(
                        /* If this is our cert DN, configure it */
                        if ( dn_match( &rs->sr_entry->e_nname, &ai->ai_localndn ))
                                autoca_setlocal( &op2, &args.dercert, &args.derpkey );
-                       if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ))
-                       {
-                               Entry *e = entry_dup( rs->sr_entry );
-                               rs_replace_entry( op, rs, on, e );
-                               rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
-                       }
                        attr_merge_one( rs->sr_entry, ad_usrCert, &args.dercert, NULL );
                        attr_merge_one( rs->sr_entry, ad_usrPkey, &args.derpkey, NULL );
                }
@@ -863,7 +895,7 @@ autoca_op_search(
 )
 {
        /* we only act on a search that returns just our cert/key attrs */
-       if ( op->ors_attrs[0].an_desc == ad_usrCert &&
+       if ( op->ors_attrs && op->ors_attrs[0].an_desc == ad_usrCert &&
                op->ors_attrs[1].an_desc == ad_usrPkey &&
                op->ors_attrs[2].an_name.bv_val == NULL )
        {
@@ -939,6 +971,24 @@ autoca_db_open(
        if (slapMode & SLAP_TOOL_MODE)
                return 0;
 
+       if ( ! *aca_attr2[0].ad ) {
+               int i, code;
+               const char *text;
+
+               for ( i=0; aca_attr2[i].at; i++ ) {
+                       code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
+                       if ( code ) return code;
+               }
+
+               /* Schema may not be loaded, ignore if missing */
+               slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );
+
+               for ( i=0; aca_ocs[i].ot; i++ ) {
+                       code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
+                       if ( code ) return code;
+               }
+       }
+
        thrctx = ldap_pvt_thread_pool_context();
        connection_fake_init2( &conn, &opbuf, thrctx, 0 );
        op = &opbuf.ob_op;
@@ -955,18 +1005,18 @@ autoca_db_open(
                        a = attr_find( e->e_attrs, ad_caPkey );
                        if ( a ) {
                                const unsigned char *pp;
-                               pp = a->a_vals[0].bv_val;
+                               pp = (unsigned char *)a->a_vals[0].bv_val;
                                ai->ai_pkey = d2i_AutoPrivateKey( NULL, &pp, a->a_vals[0].bv_len );
                                if ( ai->ai_pkey )
                                {
                                        a = attr_find( e->e_attrs, ad_caCert );
                                        if ( a )
                                        {
-                                               pp = a->a_vals[0].bv_val;
+                                               pp = (unsigned char *)a->a_vals[0].bv_val;
                                                ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
                                                /* If TLS wasn't configured yet, set this as our CA */
                                                if ( !slap_tls_ctx )
-                                                       autoca_setca( op, a->a_vals );
+                                                       autoca_setca( a->a_vals );
                                        }
                                }
                                gotat = 1;
@@ -1008,7 +1058,7 @@ autoca_db_open(
 
                        /* If TLS wasn't configured yet, set this as our CA */
                        if ( !slap_tls_ctx )
-                               autoca_setca( op, &args.dercert );
+                               autoca_setca( &args.dercert );
 
                        op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
                        op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
@@ -1027,7 +1077,6 @@ static slap_overinst autoca;
 
 int autoca_initialize() {
        int i, code;
-       const char *text;
 
        autoca.on_bi.bi_type = "autoca";
        autoca.on_bi.bi_db_init = autoca_db_init;
@@ -1044,19 +1093,6 @@ int autoca_initialize() {
                if ( code ) return code;
        }
 
-       for ( i=0; aca_attr2[i].at; i++ ) {
-               code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
-               if ( code ) return code;
-       }
-
-       /* Schema may not be loaded, ignore if missing */
-       slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );
-
-       for ( i=0; aca_ocs[i].ot; i++ ) {
-               code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
-               if ( code ) return code;
-       }
-
        return overlay_register( &autoca );
 }