Home | History | Annotate | Line # | Download | only in overlays
      1  1.1  christos /*	$NetBSD: autoca.c,v 1.3 2025/09/05 21:16:32 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* autoca.c - Automatic Certificate Authority */
      4  1.1  christos /* $OpenLDAP$ */
      5  1.1  christos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  1.1  christos  *
      7  1.3  christos  * Copyright 2009-2024 The OpenLDAP Foundation.
      8  1.1  christos  * Copyright 2009-2018 by Howard Chu.
      9  1.1  christos  * All rights reserved.
     10  1.1  christos  *
     11  1.1  christos  * Redistribution and use in source and binary forms, with or without
     12  1.1  christos  * modification, are permitted only as authorized by the OpenLDAP
     13  1.1  christos  * Public License.
     14  1.1  christos  *
     15  1.1  christos  * A copy of this license is available in the file LICENSE in the
     16  1.1  christos  * top-level directory of the distribution or, alternatively, at
     17  1.1  christos  * <http://www.OpenLDAP.org/license.html>.
     18  1.1  christos  */
     19  1.1  christos /* ACKNOWLEDGEMENTS:
     20  1.1  christos  * This work was initially developed by Howard Chu for inclusion in
     21  1.1  christos  * OpenLDAP Software.
     22  1.1  christos  */
     23  1.1  christos 
     24  1.1  christos #include <sys/cdefs.h>
     25  1.1  christos __RCSID("$NetBSD: autoca.c,v 1.3 2025/09/05 21:16:32 christos Exp $");
     26  1.1  christos 
     27  1.1  christos #include "portable.h"
     28  1.1  christos 
     29  1.1  christos #ifdef SLAPD_OVER_AUTOCA
     30  1.1  christos 
     31  1.1  christos #include <stdio.h>
     32  1.1  christos 
     33  1.1  christos #include <ac/string.h>
     34  1.1  christos #include <ac/socket.h>
     35  1.1  christos 
     36  1.1  christos #include "lutil.h"
     37  1.1  christos #include "slap.h"
     38  1.1  christos #include "slap-config.h"
     39  1.1  christos 
     40  1.1  christos #include <openssl/x509.h>
     41  1.1  christos #include <openssl/x509v3.h>
     42  1.1  christos #include <openssl/evp.h>
     43  1.1  christos #include <openssl/bn.h>
     44  1.1  christos 
     45  1.1  christos /* Starting with OpenSSL 1.1.0, rsa.h is no longer included in
     46  1.1  christos  * x509.h, so we need to explicitly include it for the
     47  1.1  christos  * call to EVP_PKEY_CTX_set_rsa_keygen_bits
     48  1.1  christos  */
     49  1.1  christos 
     50  1.1  christos #if OPENSSL_VERSION_NUMBER >= 0x10100000
     51  1.1  christos #include <openssl/rsa.h>
     52  1.1  christos #define X509_get_notBefore(x)	X509_getm_notBefore(x)
     53  1.1  christos #define X509_get_notAfter(x)	X509_getm_notAfter(x)
     54  1.1  christos #endif
     55  1.1  christos 
     56  1.3  christos #if OPENSSL_VERSION_MAJOR >= 3
     57  1.3  christos #define BN_pseudo_rand(bn, bits, top, bottom)	BN_rand(bn, bits, top, bottom)
     58  1.3  christos #endif
     59  1.3  christos 
     60  1.1  christos /* This overlay implements a certificate authority that can generate
     61  1.1  christos  * certificates automatically for any entry in the directory.
     62  1.1  christos  * On startup it generates a self-signed CA cert for the directory's
     63  1.1  christos  * suffix entry and uses this to sign all other certs that it generates.
     64  1.1  christos  * User and server certs are generated on demand, using a Search request.
     65  1.1  christos  */
     66  1.1  christos 
     67  1.1  christos #define LBER_TAG_OID        ((ber_tag_t) 0x06UL)
     68  1.1  christos #define LBER_TAG_UTF8       ((ber_tag_t) 0x0cUL)
     69  1.1  christos 
     70  1.1  christos #define KEYBITS	2048
     71  1.1  christos #define MIN_KEYBITS	512
     72  1.1  christos 
     73  1.1  christos #define ACA_SCHEMA_ROOT	"1.3.6.1.4.1.4203.666.11.11"
     74  1.1  christos 
     75  1.1  christos #define ACA_SCHEMA_AT ACA_SCHEMA_ROOT ".1"
     76  1.1  christos #define ACA_SCHEMA_OC ACA_SCHEMA_ROOT ".2"
     77  1.1  christos 
     78  1.1  christos static AttributeDescription *ad_caCert, *ad_caPkey, *ad_usrCert, *ad_usrPkey;
     79  1.1  christos static AttributeDescription *ad_mail, *ad_ipaddr;
     80  1.1  christos static ObjectClass *oc_caObj, *oc_usrObj;
     81  1.1  christos 
     82  1.1  christos static char *aca_attrs[] = {
     83  1.1  christos 	"( " ACA_SCHEMA_AT ".1 NAME 'cAPrivateKey' "
     84  1.1  christos 		"DESC 'X.509 CA private key, use ;binary' "
     85  1.1  christos 		"SUP pKCS8PrivateKey )",
     86  1.1  christos 	"( " ACA_SCHEMA_AT ".2 NAME 'userPrivateKey' "
     87  1.1  christos 		"DESC 'X.509 user private key, use ;binary' "
     88  1.1  christos 		"SUP pKCS8PrivateKey )",
     89  1.1  christos 	NULL
     90  1.1  christos };
     91  1.1  christos 
     92  1.1  christos static struct {
     93  1.1  christos 	char *at;
     94  1.1  christos 	AttributeDescription **ad;
     95  1.1  christos } aca_attr2[] = {
     96  1.1  christos 	{ "cACertificate;binary", &ad_caCert },
     97  1.1  christos 	{ "cAPrivateKey;binary", &ad_caPkey },
     98  1.1  christos 	{ "userCertificate;binary", &ad_usrCert },
     99  1.1  christos 	{ "userPrivateKey;binary", &ad_usrPkey },
    100  1.1  christos 	{ "mail", &ad_mail },
    101  1.1  christos 	{ NULL }
    102  1.1  christos };
    103  1.1  christos 
    104  1.1  christos static struct {
    105  1.1  christos 	char *ot;
    106  1.1  christos 	ObjectClass **oc;
    107  1.1  christos } aca_ocs[] = {
    108  1.1  christos 	{ "( " ACA_SCHEMA_OC ".1 NAME 'autoCA' "
    109  1.1  christos 		"DESC 'Automated PKI certificate authority' "
    110  1.1  christos 		"SUP pkiCA AUXILIARY "
    111  1.1  christos 		"MAY cAPrivateKey )", &oc_caObj },
    112  1.1  christos 	{ "( " ACA_SCHEMA_OC ".2 NAME 'autoCAuser' "
    113  1.1  christos 		"DESC 'Automated PKI CA user' "
    114  1.1  christos 		"SUP pkiUser AUXILIARY "
    115  1.1  christos 		"MAY userPrivateKey )", &oc_usrObj },
    116  1.1  christos 	{ NULL }
    117  1.1  christos };
    118  1.1  christos 
    119  1.1  christos typedef struct autoca_info {
    120  1.1  christos 	X509 *ai_cert;
    121  1.1  christos 	EVP_PKEY *ai_pkey;
    122  1.1  christos 	ObjectClass *ai_usrclass;
    123  1.1  christos 	ObjectClass *ai_srvclass;
    124  1.1  christos 	struct berval ai_localdn;
    125  1.1  christos 	struct berval ai_localndn;
    126  1.1  christos 	int ai_usrkeybits;
    127  1.1  christos 	int ai_srvkeybits;
    128  1.1  christos 	int ai_cakeybits;
    129  1.1  christos 	int ai_usrdays;
    130  1.1  christos 	int ai_srvdays;
    131  1.1  christos 	int ai_cadays;
    132  1.1  christos } autoca_info;
    133  1.1  christos 
    134  1.1  christos /* Rewrite an LDAP DN in DER form
    135  1.1  christos  * Input must be valid DN, therefore no error checking is done here.
    136  1.1  christos  */
    137  1.1  christos static int autoca_dnbv2der( Operation *op, struct berval *bv, struct berval *der )
    138  1.1  christos {
    139  1.1  christos 	BerElementBuffer berbuf;
    140  1.1  christos 	BerElement *ber = (BerElement *)&berbuf;
    141  1.1  christos 	LDAPDN dn;
    142  1.1  christos 	LDAPRDN rdn;
    143  1.1  christos 	LDAPAVA *ava;
    144  1.1  christos 	AttributeDescription *ad;
    145  1.1  christos 	int irdn, iava;
    146  1.1  christos 
    147  1.1  christos 	ldap_bv2dn_x( bv, &dn, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx );
    148  1.1  christos 
    149  1.1  christos 	ber_init2( ber, NULL, LBER_USE_DER );
    150  1.1  christos 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
    151  1.1  christos 
    152  1.1  christos 	/* count RDNs, we need them in reverse order */
    153  1.1  christos 	for (irdn = 0; dn[irdn]; irdn++);
    154  1.1  christos 	irdn--;
    155  1.1  christos 
    156  1.1  christos 	/* DN is a SEQuence of RDNs */
    157  1.1  christos 	ber_start_seq( ber, LBER_SEQUENCE );
    158  1.1  christos 	for (; irdn >=0; irdn--)
    159  1.1  christos 	{
    160  1.1  christos 		/* RDN is a SET of AVAs */
    161  1.1  christos 		ber_start_set( ber, LBER_SET );
    162  1.1  christos 		rdn = dn[irdn];
    163  1.1  christos 		for (iava = 0; rdn[iava]; iava++)
    164  1.1  christos 		{
    165  1.1  christos 			const char *text;
    166  1.1  christos 			char oid[1024];
    167  1.1  christos 			struct berval bvo = { sizeof(oid), oid };
    168  1.1  christos 			struct berval bva;
    169  1.1  christos 
    170  1.1  christos 			/* AVA is a SEQuence of attr and value */
    171  1.1  christos 			ber_start_seq( ber, LBER_SEQUENCE );
    172  1.1  christos 			ava = rdn[iava];
    173  1.1  christos 			ad = NULL;
    174  1.1  christos 			slap_bv2ad( &ava->la_attr, &ad, &text );
    175  1.1  christos 			ber_str2bv( ad->ad_type->sat_oid, 0, 0, &bva );
    176  1.1  christos 			ber_encode_oid( &bva, &bvo );
    177  1.1  christos 			ber_put_berval( ber, &bvo, LBER_TAG_OID );
    178  1.1  christos 			ber_put_berval( ber, &ava->la_value, LBER_TAG_UTF8 );
    179  1.1  christos 			ber_put_seq( ber );
    180  1.1  christos 		}
    181  1.1  christos 		ber_put_set( ber );
    182  1.1  christos 	}
    183  1.1  christos 	ber_put_seq( ber );
    184  1.1  christos 	ber_flatten2( ber, der, 0 );
    185  1.1  christos 	ldap_dnfree_x( dn, op->o_tmpmemctx );
    186  1.1  christos 	return 0;
    187  1.1  christos }
    188  1.1  christos 
    189  1.1  christos static int autoca_genpkey(int bits, EVP_PKEY **pkey)
    190  1.1  christos {
    191  1.1  christos 	EVP_PKEY_CTX *kctx;
    192  1.1  christos 	int rc;
    193  1.1  christos 
    194  1.1  christos 	kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
    195  1.1  christos 	if (kctx == NULL)
    196  1.1  christos 		return -1;
    197  1.1  christos 	if (EVP_PKEY_keygen_init(kctx) <= 0)
    198  1.1  christos 	{
    199  1.1  christos 		EVP_PKEY_CTX_free(kctx);
    200  1.1  christos 		return -1;
    201  1.1  christos 	}
    202  1.1  christos 	if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, bits) <= 0)
    203  1.1  christos 	{
    204  1.1  christos 		EVP_PKEY_CTX_free(kctx);
    205  1.1  christos 		return -1;
    206  1.1  christos 	}
    207  1.1  christos 	rc = EVP_PKEY_keygen(kctx, pkey);
    208  1.1  christos 	EVP_PKEY_CTX_free(kctx);
    209  1.1  christos 	return rc;
    210  1.1  christos }
    211  1.1  christos 
    212  1.1  christos static int autoca_signcert(X509 *cert, EVP_PKEY *pkey)
    213  1.1  christos {
    214  1.1  christos 	EVP_MD_CTX *ctx = EVP_MD_CTX_create();
    215  1.1  christos 	EVP_PKEY_CTX *pkctx = NULL;
    216  1.1  christos 	int rc = -1;
    217  1.1  christos 
    218  1.1  christos 	if ( ctx == NULL )
    219  1.1  christos 		return -1;
    220  1.1  christos 	if (EVP_DigestSignInit(ctx, &pkctx, NULL, NULL, pkey))
    221  1.1  christos 	{
    222  1.1  christos 		rc = X509_sign_ctx(cert, ctx);
    223  1.1  christos 	}
    224  1.1  christos 	EVP_MD_CTX_destroy(ctx);
    225  1.1  christos 	return rc;
    226  1.1  christos }
    227  1.1  christos 
    228  1.1  christos #define SERIAL_BITS	64	/* should be less than 160 */
    229  1.1  christos 
    230  1.1  christos typedef struct myext {
    231  1.1  christos 	char *name;
    232  1.1  christos 	char *value;
    233  1.1  christos } myext;
    234  1.1  christos 
    235  1.1  christos static myext CAexts[] = {
    236  1.1  christos 	{ "subjectKeyIdentifier", "hash" },
    237  1.1  christos 	{ "authorityKeyIdentifier", "keyid:always,issuer" },
    238  1.1  christos 	{ "basicConstraints", "critical,CA:true" },
    239  1.1  christos 	{ "keyUsage", "digitalSignature,cRLSign,keyCertSign" },
    240  1.1  christos 	{ "nsComment", "OpenLDAP automatic certificate" },
    241  1.1  christos 	{ NULL }
    242  1.1  christos };
    243  1.1  christos 
    244  1.1  christos static myext usrExts[] = {
    245  1.1  christos 	{ "subjectKeyIdentifier", "hash" },
    246  1.1  christos 	{ "authorityKeyIdentifier", "keyid:always,issuer" },
    247  1.1  christos 	{ "basicConstraints", "CA:false" },
    248  1.1  christos 	{ "keyUsage", "digitalSignature,nonRepudiation,keyEncipherment" },
    249  1.1  christos 	{ "extendedKeyUsage", "clientAuth,emailProtection,codeSigning" },
    250  1.1  christos 	{ "nsComment", "OpenLDAP automatic certificate" },
    251  1.1  christos 	{ NULL }
    252  1.1  christos };
    253  1.1  christos 
    254  1.1  christos static myext srvExts[] = {
    255  1.1  christos 	{ "subjectKeyIdentifier", "hash" },
    256  1.1  christos 	{ "authorityKeyIdentifier", "keyid:always,issuer" },
    257  1.1  christos 	{ "basicConstraints", "CA:false" },
    258  1.1  christos 	{ "keyUsage", "digitalSignature,keyEncipherment" },
    259  1.1  christos 	{ "extendedKeyUsage", "serverAuth,clientAuth" },
    260  1.1  christos 	{ "nsComment", "OpenLDAP automatic certificate" },
    261  1.1  christos 	{ NULL }
    262  1.1  christos };
    263  1.1  christos 
    264  1.1  christos typedef struct genargs {
    265  1.1  christos 	X509 *issuer_cert;
    266  1.1  christos 	EVP_PKEY *issuer_pkey;
    267  1.1  christos 	struct berval *subjectDN;
    268  1.1  christos 	myext *cert_exts;
    269  1.1  christos 	myext *more_exts;
    270  1.1  christos 	X509 *newcert;
    271  1.1  christos 	EVP_PKEY *newpkey;
    272  1.1  christos 	struct berval dercert;
    273  1.1  christos 	struct berval derpkey;
    274  1.1  christos 	int keybits;
    275  1.1  christos 	int days;
    276  1.1  christos } genargs;
    277  1.1  christos 
    278  1.1  christos static int autoca_gencert( Operation *op, genargs *args )
    279  1.1  christos {
    280  1.1  christos 	X509_NAME *subj_name, *issuer_name;
    281  1.1  christos 	X509 *subj_cert;
    282  1.1  christos 	struct berval derdn;
    283  1.1  christos 	unsigned char *pp;
    284  1.1  christos 	EVP_PKEY *evpk = NULL;
    285  1.1  christos 	int rc;
    286  1.1  christos 
    287  1.1  christos 	if ((subj_cert = X509_new()) == NULL)
    288  1.1  christos 		return -1;
    289  1.1  christos 
    290  1.1  christos 	autoca_dnbv2der( op, args->subjectDN, &derdn );
    291  1.1  christos 	pp = (unsigned char *)derdn.bv_val;
    292  1.1  christos 	subj_name = d2i_X509_NAME( NULL, (const unsigned char **)&pp, derdn.bv_len );
    293  1.1  christos 	op->o_tmpfree( derdn.bv_val, op->o_tmpmemctx );
    294  1.1  christos 	if ( subj_name == NULL )
    295  1.1  christos 	{
    296  1.1  christos fail1:
    297  1.1  christos 		X509_free( subj_cert );
    298  1.1  christos 		return -1;
    299  1.1  christos 	}
    300  1.1  christos 
    301  1.1  christos 	rc = autoca_genpkey( args->keybits, &evpk );
    302  1.1  christos 	if ( rc <= 0 )
    303  1.1  christos 	{
    304  1.1  christos fail2:
    305  1.1  christos 		if ( subj_name ) X509_NAME_free( subj_name );
    306  1.1  christos 		goto fail1;
    307  1.1  christos 	}
    308  1.1  christos 	/* encode DER in PKCS#8 */
    309  1.1  christos 	{
    310  1.1  christos 		PKCS8_PRIV_KEY_INFO *p8inf;
    311  1.1  christos 		if (( p8inf = EVP_PKEY2PKCS8( evpk )) == NULL )
    312  1.1  christos 			goto fail2;
    313  1.1  christos 		args->derpkey.bv_len = i2d_PKCS8_PRIV_KEY_INFO( p8inf, NULL );
    314  1.1  christos 		args->derpkey.bv_val = op->o_tmpalloc( args->derpkey.bv_len, op->o_tmpmemctx );
    315  1.1  christos 		pp = (unsigned char *)args->derpkey.bv_val;
    316  1.1  christos 		i2d_PKCS8_PRIV_KEY_INFO( p8inf, &pp );
    317  1.1  christos 		PKCS8_PRIV_KEY_INFO_free( p8inf );
    318  1.1  christos 	}
    319  1.1  christos 	args->newpkey = evpk;
    320  1.1  christos 
    321  1.1  christos 	/* set random serial */
    322  1.1  christos 	{
    323  1.1  christos 		BIGNUM *bn = BN_new();
    324  1.1  christos 		if ( bn == NULL )
    325  1.1  christos 		{
    326  1.1  christos fail3:
    327  1.1  christos 			EVP_PKEY_free( evpk );
    328  1.1  christos 			goto fail2;
    329  1.1  christos 		}
    330  1.1  christos 		if (!BN_pseudo_rand(bn, SERIAL_BITS, 0, 0))
    331  1.1  christos 		{
    332  1.1  christos 			BN_free( bn );
    333  1.1  christos 			goto fail3;
    334  1.1  christos 		}
    335  1.1  christos 		if (!BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(subj_cert)))
    336  1.1  christos 		{
    337  1.1  christos 			BN_free( bn );
    338  1.1  christos 			goto fail3;
    339  1.1  christos 		}
    340  1.1  christos 		BN_free(bn);
    341  1.1  christos 	}
    342  1.1  christos 	if (args->issuer_cert) {
    343  1.1  christos 		issuer_name = X509_get_subject_name(args->issuer_cert);
    344  1.1  christos 	} else {
    345  1.1  christos 		issuer_name = subj_name;
    346  1.1  christos 		args->issuer_cert = subj_cert;
    347  1.1  christos 		args->issuer_pkey = evpk;
    348  1.1  christos 	}
    349  1.1  christos 	if (!X509_set_version(subj_cert, 2) ||	/* set version to V3 */
    350  1.1  christos 		!X509_set_issuer_name(subj_cert, issuer_name) ||
    351  1.1  christos 		!X509_set_subject_name(subj_cert, subj_name) ||
    352  1.1  christos 		!X509_gmtime_adj(X509_get_notBefore(subj_cert), 0) ||
    353  1.1  christos 		!X509_time_adj_ex(X509_get_notAfter(subj_cert), args->days, 0, NULL) ||
    354  1.1  christos 		!X509_set_pubkey(subj_cert, evpk))
    355  1.1  christos 	{
    356  1.1  christos 		goto fail3;
    357  1.1  christos 	}
    358  1.1  christos 	X509_NAME_free(subj_name);
    359  1.1  christos 	subj_name = NULL;
    360  1.1  christos 
    361  1.1  christos 	/* set cert extensions */
    362  1.1  christos 	{
    363  1.1  christos 		X509V3_CTX ctx;
    364  1.1  christos 		X509_EXTENSION *ext;
    365  1.1  christos 		int i;
    366  1.1  christos 
    367  1.1  christos 		X509V3_set_ctx(&ctx, args->issuer_cert, subj_cert, NULL, NULL, 0);
    368  1.1  christos 		for (i=0; args->cert_exts[i].name; i++) {
    369  1.1  christos 			ext = X509V3_EXT_nconf(NULL, &ctx, args->cert_exts[i].name, args->cert_exts[i].value);
    370  1.1  christos 			if ( ext == NULL )
    371  1.1  christos 				goto fail3;
    372  1.1  christos 			rc = X509_add_ext(subj_cert, ext, -1);
    373  1.1  christos 			X509_EXTENSION_free(ext);
    374  1.1  christos 			if ( !rc )
    375  1.1  christos 				goto fail3;
    376  1.1  christos 		}
    377  1.1  christos 		if (args->more_exts) {
    378  1.1  christos 			for (i=0; args->more_exts[i].name; i++) {
    379  1.1  christos 				ext = X509V3_EXT_nconf(NULL, &ctx, args->more_exts[i].name, args->more_exts[i].value);
    380  1.1  christos 				if ( ext == NULL )
    381  1.1  christos 					goto fail3;
    382  1.1  christos 				rc = X509_add_ext(subj_cert, ext, -1);
    383  1.1  christos 				X509_EXTENSION_free(ext);
    384  1.1  christos 				if ( !rc )
    385  1.1  christos 					goto fail3;
    386  1.1  christos 			}
    387  1.1  christos 		}
    388  1.1  christos 	}
    389  1.1  christos 	rc = autoca_signcert( subj_cert, args->issuer_pkey );
    390  1.1  christos 	if ( rc < 0 )
    391  1.1  christos 		goto fail3;
    392  1.1  christos 	args->dercert.bv_len = i2d_X509( subj_cert, NULL );
    393  1.1  christos 	args->dercert.bv_val = op->o_tmpalloc( args->dercert.bv_len, op->o_tmpmemctx );
    394  1.1  christos 	pp = (unsigned char *)args->dercert.bv_val;
    395  1.1  christos 	i2d_X509( subj_cert, &pp );
    396  1.1  christos 	args->newcert = subj_cert;
    397  1.1  christos 	return 0;
    398  1.1  christos }
    399  1.1  christos 
    400  1.1  christos typedef struct saveargs {
    401  1.1  christos 	ObjectClass *oc;
    402  1.1  christos 	struct berval *dercert;
    403  1.1  christos 	struct berval *derpkey;
    404  1.1  christos 	slap_overinst *on;
    405  1.1  christos 	struct berval *dn;
    406  1.1  christos 	struct berval *ndn;
    407  1.1  christos 	int isca;
    408  1.1  christos } saveargs;
    409  1.1  christos 
    410  1.1  christos static int autoca_savecert( Operation *op, saveargs *args )
    411  1.1  christos {
    412  1.1  christos 	Modifications mod[3], *mp = mod;
    413  1.1  christos 	struct berval bvs[6], *bp = bvs;
    414  1.1  christos 	BackendInfo *bi;
    415  1.1  christos 	slap_callback cb = {0};
    416  1.1  christos 	SlapReply rs = {REP_RESULT};
    417  1.1  christos 
    418  1.1  christos 	if ( args->oc ) {
    419  1.1  christos 		mp->sml_numvals = 1;
    420  1.1  christos 		mp->sml_values = bp;
    421  1.1  christos 		mp->sml_nvalues = NULL;
    422  1.1  christos 		mp->sml_desc = slap_schema.si_ad_objectClass;
    423  1.1  christos 		mp->sml_op = LDAP_MOD_ADD;
    424  1.1  christos 		mp->sml_flags = SLAP_MOD_INTERNAL;
    425  1.1  christos 		*bp++ = args->oc->soc_cname;
    426  1.1  christos 		BER_BVZERO( bp );
    427  1.1  christos 		bp++;
    428  1.1  christos 		mp->sml_next = mp+1;
    429  1.1  christos 		mp++;
    430  1.1  christos 	}
    431  1.1  christos 	mp->sml_numvals = 1;
    432  1.1  christos 	mp->sml_values = bp;
    433  1.1  christos 	mp->sml_nvalues = NULL;
    434  1.1  christos 	mp->sml_desc = args->isca ? ad_caCert : ad_usrCert;
    435  1.1  christos 	mp->sml_op = LDAP_MOD_REPLACE;
    436  1.1  christos 	mp->sml_flags = SLAP_MOD_INTERNAL;
    437  1.1  christos 	*bp++ = *args->dercert;
    438  1.1  christos 	BER_BVZERO( bp );
    439  1.1  christos 	bp++;
    440  1.1  christos 	mp->sml_next = mp+1;
    441  1.1  christos 	mp++;
    442  1.1  christos 
    443  1.1  christos 	mp->sml_numvals = 1;
    444  1.1  christos 	mp->sml_values = bp;
    445  1.1  christos 	mp->sml_nvalues = NULL;
    446  1.1  christos 	mp->sml_desc = args->isca ? ad_caPkey : ad_usrPkey;
    447  1.1  christos 	mp->sml_op = LDAP_MOD_ADD;
    448  1.1  christos 	mp->sml_flags = SLAP_MOD_INTERNAL;
    449  1.1  christos 	*bp++ = *args->derpkey;
    450  1.1  christos 	BER_BVZERO( bp );
    451  1.1  christos 	mp->sml_next = NULL;
    452  1.1  christos 
    453  1.1  christos 	cb.sc_response = slap_null_cb;
    454  1.1  christos 	bi = op->o_bd->bd_info;
    455  1.1  christos 	op->o_bd->bd_info = args->on->on_info->oi_orig;
    456  1.1  christos 	op->o_tag = LDAP_REQ_MODIFY;
    457  1.1  christos 	op->o_callback = &cb;
    458  1.1  christos 	op->orm_modlist = mod;
    459  1.1  christos 	op->orm_no_opattrs = 1;
    460  1.1  christos 	op->o_req_dn = *args->dn;
    461  1.1  christos 	op->o_req_ndn = *args->ndn;
    462  1.1  christos 	op->o_bd->be_modify( op, &rs );
    463  1.1  christos 	op->o_bd->bd_info = bi;
    464  1.1  christos 	return rs.sr_err;
    465  1.1  christos }
    466  1.1  christos 
    467  1.1  christos static const struct berval configDN = BER_BVC("cn=config");
    468  1.1  christos 
    469  1.1  christos /* must run as a pool thread to avoid cn=config deadlock */
    470  1.1  christos static void *
    471  1.1  christos autoca_setca_task( void *ctx, void *arg )
    472  1.1  christos {
    473  1.1  christos 	Connection conn = { 0 };
    474  1.1  christos 	OperationBuffer opbuf;
    475  1.1  christos 	Operation *op;
    476  1.1  christos 	struct berval *cacert = arg;
    477  1.1  christos 	Modifications mod;
    478  1.1  christos 	struct berval bvs[2];
    479  1.1  christos 	slap_callback cb = {0};
    480  1.1  christos 	SlapReply rs = {REP_RESULT};
    481  1.1  christos 	const char *text;
    482  1.1  christos 
    483  1.1  christos 	connection_fake_init( &conn, &opbuf, ctx );
    484  1.1  christos 	op = &opbuf.ob_op;
    485  1.1  christos 
    486  1.1  christos 	mod.sml_numvals = 1;
    487  1.1  christos 	mod.sml_values = bvs;
    488  1.1  christos 	mod.sml_nvalues = NULL;
    489  1.1  christos 	mod.sml_desc = NULL;
    490  1.1  christos 	if ( slap_str2ad( "olcTLSCACertificate;binary", &mod.sml_desc, &text ))
    491  1.1  christos 		goto leave;
    492  1.1  christos 	mod.sml_op = LDAP_MOD_REPLACE;
    493  1.1  christos 	mod.sml_flags = SLAP_MOD_INTERNAL;
    494  1.1  christos 	bvs[0] = *cacert;
    495  1.1  christos 	BER_BVZERO( &bvs[1] );
    496  1.1  christos 	mod.sml_next = NULL;
    497  1.1  christos 
    498  1.1  christos 	cb.sc_response = slap_null_cb;
    499  1.1  christos 	op->o_bd = select_backend( (struct berval *)&configDN, 0 );
    500  1.1  christos 	if ( !op->o_bd )
    501  1.1  christos 		goto leave;
    502  1.1  christos 
    503  1.1  christos 	op->o_tag = LDAP_REQ_MODIFY;
    504  1.1  christos 	op->o_callback = &cb;
    505  1.1  christos 	op->orm_modlist = &mod;
    506  1.1  christos 	op->orm_no_opattrs = 1;
    507  1.1  christos 	op->o_req_dn = configDN;
    508  1.1  christos 	op->o_req_ndn = configDN;
    509  1.1  christos 	op->o_dn = op->o_bd->be_rootdn;
    510  1.1  christos 	op->o_ndn = op->o_bd->be_rootndn;
    511  1.1  christos 	op->o_bd->be_modify( op, &rs );
    512  1.1  christos leave:
    513  1.1  christos 	ch_free( arg );
    514  1.1  christos 	return NULL;
    515  1.1  christos }
    516  1.1  christos 
    517  1.1  christos static int
    518  1.1  christos autoca_setca( struct berval *cacert )
    519  1.1  christos {
    520  1.1  christos 	struct berval *bv = ch_malloc( sizeof(struct berval) + cacert->bv_len );
    521  1.1  christos 	bv->bv_len = cacert->bv_len;
    522  1.1  christos 	bv->bv_val = (char *)(bv+1);
    523  1.1  christos 	AC_MEMCPY( bv->bv_val, cacert->bv_val, bv->bv_len );
    524  1.1  christos 	return ldap_pvt_thread_pool_submit( &connection_pool, autoca_setca_task, bv );
    525  1.1  christos }
    526  1.1  christos 
    527  1.1  christos static int
    528  1.1  christos autoca_setlocal( Operation *op, struct berval *cert, struct berval *pkey )
    529  1.1  christos {
    530  1.1  christos 	Modifications mod[2];
    531  1.1  christos 	struct berval bvs[4];
    532  1.1  christos 	slap_callback cb = {0};
    533  1.1  christos 	SlapReply rs = {REP_RESULT};
    534  1.1  christos 	const char *text;
    535  1.1  christos 
    536  1.1  christos 	mod[0].sml_numvals = 1;
    537  1.1  christos 	mod[0].sml_values = bvs;
    538  1.1  christos 	mod[0].sml_nvalues = NULL;
    539  1.1  christos 	mod[0].sml_desc = NULL;
    540  1.1  christos 	if ( slap_str2ad( "olcTLSCertificate;binary", &mod[0].sml_desc, &text ))
    541  1.1  christos 		return -1;
    542  1.1  christos 	mod[0].sml_op = LDAP_MOD_REPLACE;
    543  1.1  christos 	mod[0].sml_flags = SLAP_MOD_INTERNAL;
    544  1.1  christos 	bvs[0] = *cert;
    545  1.1  christos 	BER_BVZERO( &bvs[1] );
    546  1.1  christos 	mod[0].sml_next = &mod[1];
    547  1.1  christos 
    548  1.1  christos 	mod[1].sml_numvals = 1;
    549  1.1  christos 	mod[1].sml_values = &bvs[2];
    550  1.1  christos 	mod[1].sml_nvalues = NULL;
    551  1.1  christos 	mod[1].sml_desc = NULL;
    552  1.1  christos 	if ( slap_str2ad( "olcTLSCertificateKey;binary", &mod[1].sml_desc, &text ))
    553  1.1  christos 		return -1;
    554  1.1  christos 	mod[1].sml_op = LDAP_MOD_REPLACE;
    555  1.1  christos 	mod[1].sml_flags = SLAP_MOD_INTERNAL;
    556  1.1  christos 	bvs[2] = *pkey;
    557  1.1  christos 	BER_BVZERO( &bvs[3] );
    558  1.1  christos 	mod[1].sml_next = NULL;
    559  1.1  christos 
    560  1.1  christos 	cb.sc_response = slap_null_cb;
    561  1.1  christos 	op->o_bd = select_backend( (struct berval *)&configDN, 0 );
    562  1.1  christos 	if ( !op->o_bd )
    563  1.1  christos 		return -1;
    564  1.1  christos 
    565  1.1  christos 	op->o_tag = LDAP_REQ_MODIFY;
    566  1.1  christos 	op->o_callback = &cb;
    567  1.1  christos 	op->orm_modlist = mod;
    568  1.1  christos 	op->orm_no_opattrs = 1;
    569  1.1  christos 	op->o_req_dn = configDN;
    570  1.1  christos 	op->o_req_ndn = configDN;
    571  1.1  christos 	op->o_dn = op->o_bd->be_rootdn;
    572  1.1  christos 	op->o_ndn = op->o_bd->be_rootndn;
    573  1.1  christos 	op->o_bd->be_modify( op, &rs );
    574  1.1  christos 	return rs.sr_err;
    575  1.1  christos }
    576  1.1  christos 
    577  1.1  christos enum {
    578  1.1  christos 	ACA_USRCLASS = 1,
    579  1.1  christos 	ACA_SRVCLASS,
    580  1.1  christos 	ACA_USRKEYBITS,
    581  1.1  christos 	ACA_SRVKEYBITS,
    582  1.1  christos 	ACA_CAKEYBITS,
    583  1.1  christos 	ACA_USRDAYS,
    584  1.1  christos 	ACA_SRVDAYS,
    585  1.1  christos 	ACA_CADAYS,
    586  1.1  christos 	ACA_LOCALDN
    587  1.1  christos };
    588  1.1  christos 
    589  1.1  christos static int autoca_cf( ConfigArgs *c )
    590  1.1  christos {
    591  1.1  christos 	slap_overinst *on = (slap_overinst *)c->bi;
    592  1.1  christos 	autoca_info *ai = on->on_bi.bi_private;
    593  1.1  christos 	int rc = 0;
    594  1.1  christos 
    595  1.1  christos 	switch( c->op ) {
    596  1.1  christos 	case SLAP_CONFIG_EMIT:
    597  1.1  christos 		switch( c->type ) {
    598  1.1  christos 		case ACA_USRCLASS:
    599  1.1  christos 			if ( ai->ai_usrclass ) {
    600  1.1  christos 				c->value_string = ch_strdup( ai->ai_usrclass->soc_cname.bv_val );
    601  1.1  christos 			} else {
    602  1.1  christos 				rc = 1;
    603  1.1  christos 			}
    604  1.1  christos 			break;
    605  1.1  christos 		case ACA_SRVCLASS:
    606  1.1  christos 			if ( ai->ai_srvclass ) {
    607  1.1  christos 				c->value_string = ch_strdup( ai->ai_srvclass->soc_cname.bv_val );
    608  1.1  christos 			} else {
    609  1.1  christos 				rc = 1;
    610  1.1  christos 			}
    611  1.1  christos 			break;
    612  1.1  christos 		case ACA_USRKEYBITS:
    613  1.1  christos 			c->value_int = ai->ai_usrkeybits;
    614  1.1  christos 			break;
    615  1.1  christos 		case ACA_SRVKEYBITS:
    616  1.1  christos 			c->value_int = ai->ai_srvkeybits;
    617  1.1  christos 			break;
    618  1.1  christos 		case ACA_CAKEYBITS:
    619  1.1  christos 			c->value_int = ai->ai_cakeybits;
    620  1.1  christos 			break;
    621  1.1  christos 		case ACA_USRDAYS:
    622  1.1  christos 			c->value_int = ai->ai_usrdays;
    623  1.1  christos 			break;
    624  1.1  christos 		case ACA_SRVDAYS:
    625  1.1  christos 			c->value_int = ai->ai_srvdays;
    626  1.1  christos 			break;
    627  1.1  christos 		case ACA_CADAYS:
    628  1.1  christos 			c->value_int = ai->ai_cadays;
    629  1.1  christos 			break;
    630  1.1  christos 		case ACA_LOCALDN:
    631  1.1  christos 			if ( !BER_BVISNULL( &ai->ai_localdn )) {
    632  1.1  christos 				rc = value_add_one( &c->rvalue_vals, &ai->ai_localdn );
    633  1.1  christos 			} else {
    634  1.1  christos 				rc = 1;
    635  1.1  christos 			}
    636  1.1  christos 			break;
    637  1.1  christos 		}
    638  1.1  christos 		break;
    639  1.1  christos 	case LDAP_MOD_DELETE:
    640  1.1  christos 		switch( c->type ) {
    641  1.1  christos 		case ACA_USRCLASS:
    642  1.1  christos 			ai->ai_usrclass = NULL;
    643  1.1  christos 			break;
    644  1.1  christos 		case ACA_SRVCLASS:
    645  1.1  christos 			ai->ai_srvclass = NULL;
    646  1.1  christos 			break;
    647  1.1  christos 		case ACA_LOCALDN:
    648  1.1  christos 			if ( ai->ai_localdn.bv_val ) {
    649  1.1  christos 				ch_free( ai->ai_localdn.bv_val );
    650  1.1  christos 				ch_free( ai->ai_localndn.bv_val );
    651  1.1  christos 				BER_BVZERO( &ai->ai_localdn );
    652  1.1  christos 				BER_BVZERO( &ai->ai_localndn );
    653  1.1  christos 			}
    654  1.1  christos 			break;
    655  1.1  christos 		/* single-valued attrs, all no-ops */
    656  1.1  christos 		}
    657  1.1  christos 		break;
    658  1.1  christos 	case SLAP_CONFIG_ADD:
    659  1.1  christos 	case LDAP_MOD_ADD:
    660  1.1  christos 		switch( c->type ) {
    661  1.1  christos 		case ACA_USRCLASS:
    662  1.1  christos 			{
    663  1.1  christos 				ObjectClass *oc = oc_find( c->value_string );
    664  1.1  christos 				if ( oc )
    665  1.1  christos 					ai->ai_usrclass = oc;
    666  1.1  christos 				else
    667  1.1  christos 					rc = 1;
    668  1.1  christos 			}
    669  1.1  christos 			break;
    670  1.1  christos 		case ACA_SRVCLASS:
    671  1.1  christos 			{
    672  1.1  christos 				ObjectClass *oc = oc_find( c->value_string );
    673  1.1  christos 				if ( oc )
    674  1.1  christos 					ai->ai_srvclass = oc;
    675  1.1  christos 				else
    676  1.1  christos 					rc = 1;
    677  1.1  christos 			}
    678  1.3  christos 			break;
    679  1.1  christos 		case ACA_USRKEYBITS:
    680  1.1  christos 			if ( c->value_int < MIN_KEYBITS )
    681  1.1  christos 				rc = 1;
    682  1.1  christos 			else
    683  1.1  christos 				ai->ai_usrkeybits = c->value_int;
    684  1.1  christos 			break;
    685  1.1  christos 		case ACA_SRVKEYBITS:
    686  1.1  christos 			if ( c->value_int < MIN_KEYBITS )
    687  1.1  christos 				rc = 1;
    688  1.1  christos 			else
    689  1.1  christos 				ai->ai_srvkeybits = c->value_int;
    690  1.1  christos 			break;
    691  1.1  christos 		case ACA_CAKEYBITS:
    692  1.1  christos 			if ( c->value_int < MIN_KEYBITS )
    693  1.1  christos 				rc = 1;
    694  1.1  christos 			else
    695  1.1  christos 				ai->ai_cakeybits = c->value_int;
    696  1.1  christos 			break;
    697  1.1  christos 		case ACA_USRDAYS:
    698  1.1  christos 			ai->ai_usrdays = c->value_int;
    699  1.1  christos 			break;
    700  1.1  christos 		case ACA_SRVDAYS:
    701  1.1  christos 			ai->ai_srvdays = c->value_int;
    702  1.1  christos 			break;
    703  1.1  christos 		case ACA_CADAYS:
    704  1.1  christos 			ai->ai_cadays = c->value_int;
    705  1.1  christos 			break;
    706  1.1  christos 		case ACA_LOCALDN:
    707  1.1  christos 			if ( c->be->be_nsuffix == NULL ) {
    708  1.1  christos 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
    709  1.1  christos 					"suffix must be set" );
    710  1.1  christos 				Debug( LDAP_DEBUG_CONFIG, "autoca_config: %s\n",
    711  1.1  christos 					c->cr_msg );
    712  1.1  christos 				rc = ARG_BAD_CONF;
    713  1.1  christos 				break;
    714  1.1  christos 			}
    715  1.1  christos 			if ( !dnIsSuffix( &c->value_ndn, c->be->be_nsuffix )) {
    716  1.1  christos 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
    717  1.1  christos 					"DN is not a subordinate of backend" );
    718  1.1  christos 				Debug( LDAP_DEBUG_CONFIG, "autoca_config: %s\n",
    719  1.1  christos 					c->cr_msg );
    720  1.1  christos 				rc = ARG_BAD_CONF;
    721  1.1  christos 				break;
    722  1.1  christos 			}
    723  1.1  christos 			if ( ai->ai_localdn.bv_val ) {
    724  1.1  christos 				ch_free( ai->ai_localdn.bv_val );
    725  1.1  christos 				ch_free( ai->ai_localndn.bv_val );
    726  1.1  christos 			}
    727  1.1  christos 			ai->ai_localdn = c->value_dn;
    728  1.1  christos 			ai->ai_localndn = c->value_ndn;
    729  1.1  christos 		}
    730  1.1  christos 	}
    731  1.1  christos 	return rc;
    732  1.1  christos }
    733  1.1  christos 
    734  1.1  christos static ConfigTable autoca_cfg[] = {
    735  1.1  christos 	{ "userClass", "objectclass", 2, 2, 0,
    736  1.1  christos 	  ARG_STRING|ARG_MAGIC|ACA_USRCLASS, autoca_cf,
    737  1.1  christos 	  "( OLcfgOvAt:22.1 NAME 'olcAutoCAuserClass' "
    738  1.1  christos 	  "DESC 'ObjectClass of user entries' "
    739  1.1  christos 	  "EQUALITY caseIgnoreMatch "
    740  1.1  christos 	  "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    741  1.1  christos 	{ "serverClass", "objectclass", 2, 2, 0,
    742  1.1  christos 	  ARG_STRING|ARG_MAGIC|ACA_SRVCLASS, autoca_cf,
    743  1.1  christos 	  "( OLcfgOvAt:22.2 NAME 'olcAutoCAserverClass' "
    744  1.1  christos 	  "DESC 'ObjectClass of server entries' "
    745  1.1  christos 	  "EQUALITY caseIgnoreMatch "
    746  1.1  christos 	  "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    747  1.1  christos 	{ "userKeybits", "integer", 2, 2, 0,
    748  1.1  christos 	  ARG_INT|ARG_MAGIC|ACA_USRKEYBITS, autoca_cf,
    749  1.1  christos 	  "( OLcfgOvAt:22.3 NAME 'olcAutoCAuserKeybits' "
    750  1.1  christos 	  "DESC 'Size of PrivateKey for user entries' "
    751  1.1  christos 	  "EQUALITY integerMatch "
    752  1.1  christos 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
    753  1.1  christos 	{ "serverKeybits", "integer", 2, 2, 0,
    754  1.1  christos 	  ARG_INT|ARG_MAGIC|ACA_SRVKEYBITS, autoca_cf,
    755  1.1  christos 	  "( OLcfgOvAt:22.4 NAME 'olcAutoCAserverKeybits' "
    756  1.1  christos 	  "DESC 'Size of PrivateKey for server entries' "
    757  1.1  christos 	  "EQUALITY integerMatch "
    758  1.1  christos 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
    759  1.1  christos 	{ "caKeybits", "integer", 2, 2, 0,
    760  1.1  christos 	  ARG_INT|ARG_MAGIC|ACA_CAKEYBITS, autoca_cf,
    761  1.1  christos 	  "( OLcfgOvAt:22.5 NAME 'olcAutoCAKeybits' "
    762  1.1  christos 	  "DESC 'Size of PrivateKey for CA certificate' "
    763  1.1  christos 	  "EQUALITY integerMatch "
    764  1.1  christos 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
    765  1.1  christos 	{ "userDays", "integer", 2, 2, 0,
    766  1.1  christos 	  ARG_INT|ARG_MAGIC|ACA_USRDAYS, autoca_cf,
    767  1.1  christos 	  "( OLcfgOvAt:22.6 NAME 'olcAutoCAuserDays' "
    768  1.1  christos 	  "DESC 'Lifetime of user certificates in days' "
    769  1.1  christos 	  "EQUALITY integerMatch "
    770  1.1  christos 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
    771  1.1  christos 	{ "serverDays", "integer", 2, 2, 0,
    772  1.1  christos 	  ARG_INT|ARG_MAGIC|ACA_SRVDAYS, autoca_cf,
    773  1.1  christos 	  "( OLcfgOvAt:22.7 NAME 'olcAutoCAserverDays' "
    774  1.1  christos 	  "DESC 'Lifetime of server certificates in days' "
    775  1.1  christos 	  "EQUALITY integerMatch "
    776  1.1  christos 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
    777  1.1  christos 	{ "caDays", "integer", 2, 2, 0,
    778  1.1  christos 	  ARG_INT|ARG_MAGIC|ACA_CADAYS, autoca_cf,
    779  1.1  christos 	  "( OLcfgOvAt:22.8 NAME 'olcAutoCADays' "
    780  1.1  christos 	  "DESC 'Lifetime of CA certificate in days' "
    781  1.1  christos 	  "EQUALITY integerMatch "
    782  1.1  christos 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
    783  1.1  christos 	{ "localdn", "dn", 2, 2, 0,
    784  1.1  christos 	  ARG_DN|ARG_QUOTE|ARG_MAGIC|ACA_LOCALDN, autoca_cf,
    785  1.1  christos 	  "( OLcfgOvAt:22.9 NAME 'olcAutoCAlocalDN' "
    786  1.1  christos 	  "DESC 'DN of local server cert' "
    787  1.1  christos 	  "EQUALITY distinguishedNameMatch "
    788  1.1  christos 	  "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
    789  1.1  christos 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
    790  1.1  christos };
    791  1.1  christos 
    792  1.1  christos static ConfigOCs autoca_ocs[] = {
    793  1.1  christos 	{ "( OLcfgOvOc:22.1 "
    794  1.1  christos 	  "NAME 'olcAutoCAConfig' "
    795  1.1  christos 	  "DESC 'AutoCA configuration' "
    796  1.1  christos 	  "SUP olcOverlayConfig "
    797  1.1  christos 	  "MAY ( olcAutoCAuserClass $ olcAutoCAserverClass $ "
    798  1.1  christos 	   "olcAutoCAuserKeybits $ olcAutoCAserverKeybits $ olcAutoCAKeyBits $ "
    799  1.1  christos 	   "olcAutoCAuserDays $ olcAutoCAserverDays $ olcAutoCADays $ "
    800  1.1  christos 	   "olcAutoCAlocalDN ) )",
    801  1.1  christos 	  Cft_Overlay, autoca_cfg },
    802  1.1  christos 	{ NULL, 0, NULL }
    803  1.1  christos };
    804  1.1  christos 
    805  1.1  christos static int
    806  1.1  christos autoca_op_response(
    807  1.1  christos 	Operation *op,
    808  1.1  christos 	SlapReply *rs
    809  1.1  christos )
    810  1.1  christos {
    811  1.1  christos 	slap_overinst *on = op->o_callback->sc_private;
    812  1.1  christos 	autoca_info *ai = on->on_bi.bi_private;
    813  1.1  christos 	Attribute *a;
    814  1.1  christos 	int isusr = 0;
    815  1.1  christos 
    816  1.1  christos 	if (rs->sr_type != REP_SEARCH)
    817  1.1  christos 		return SLAP_CB_CONTINUE;
    818  1.1  christos 
    819  1.1  christos 	/* If root or self */
    820  1.1  christos 	if ( !be_isroot( op ) &&
    821  1.1  christos 		!dn_match( &rs->sr_entry->e_nname, &op->o_ndn ))
    822  1.1  christos 		return SLAP_CB_CONTINUE;
    823  1.1  christos 
    824  1.1  christos 	isusr = is_entry_objectclass( rs->sr_entry, ai->ai_usrclass, SLAP_OCF_CHECK_SUP );
    825  1.1  christos 	if ( !isusr )
    826  1.1  christos 	{
    827  1.1  christos 		if (!is_entry_objectclass( rs->sr_entry, ai->ai_srvclass, SLAP_OCF_CHECK_SUP ))
    828  1.1  christos 			return SLAP_CB_CONTINUE;
    829  1.1  christos 	}
    830  1.1  christos 	a = attr_find( rs->sr_entry->e_attrs, ad_usrPkey );
    831  1.1  christos 	if ( !a )
    832  1.1  christos 	{
    833  1.1  christos 		Operation op2;
    834  1.1  christos 		genargs args;
    835  1.1  christos 		saveargs arg2;
    836  1.1  christos 		myext extras[2];
    837  1.1  christos 		int rc;
    838  1.1  christos 
    839  1.1  christos 		args.issuer_cert = ai->ai_cert;
    840  1.1  christos 		args.issuer_pkey = ai->ai_pkey;
    841  1.1  christos 		args.subjectDN = &rs->sr_entry->e_name;
    842  1.1  christos 		args.more_exts = NULL;
    843  1.1  christos 		if ( isusr )
    844  1.1  christos 		{
    845  1.1  christos 			args.cert_exts = usrExts;
    846  1.1  christos 			args.keybits = ai->ai_usrkeybits;
    847  1.1  christos 			args.days = ai->ai_usrdays;
    848  1.1  christos 			a = attr_find( rs->sr_entry->e_attrs, ad_mail );
    849  1.1  christos 			if ( a )
    850  1.1  christos 			{
    851  1.1  christos 				extras[0].name = "subjectAltName";
    852  1.1  christos 				extras[1].name = NULL;
    853  1.1  christos 				extras[0].value = op->o_tmpalloc( sizeof("email:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
    854  1.1  christos 				sprintf(extras[0].value, "email:%s", a->a_vals[0].bv_val);
    855  1.1  christos 				args.more_exts = extras;
    856  1.1  christos 			}
    857  1.1  christos 		} else
    858  1.1  christos 		{
    859  1.1  christos 			args.cert_exts = srvExts;
    860  1.1  christos 			args.keybits = ai->ai_srvkeybits;
    861  1.1  christos 			args.days = ai->ai_srvdays;
    862  1.1  christos 			if ( ad_ipaddr && (a = attr_find( rs->sr_entry->e_attrs, ad_ipaddr )))
    863  1.1  christos 			{
    864  1.1  christos 				extras[0].name = "subjectAltName";
    865  1.1  christos 				extras[1].name = NULL;
    866  1.1  christos 				extras[0].value = op->o_tmpalloc( sizeof("IP:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
    867  1.1  christos 				sprintf(extras[0].value, "IP:%s", a->a_vals[0].bv_val);
    868  1.1  christos 				args.more_exts = extras;
    869  1.1  christos 			}
    870  1.1  christos 		}
    871  1.1  christos 		rc = autoca_gencert( op, &args );
    872  1.1  christos 		if ( rc )
    873  1.1  christos 			return SLAP_CB_CONTINUE;
    874  1.1  christos 		X509_free( args.newcert );
    875  1.1  christos 		EVP_PKEY_free( args.newpkey );
    876  1.1  christos 
    877  1.1  christos 		if ( is_entry_objectclass( rs->sr_entry, oc_usrObj, 0 ))
    878  1.1  christos 			arg2.oc = NULL;
    879  1.1  christos 		else
    880  1.1  christos 			arg2.oc = oc_usrObj;
    881  1.1  christos 		if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ))
    882  1.1  christos 		{
    883  1.1  christos 			Entry *e = entry_dup( rs->sr_entry );
    884  1.1  christos 			rs_replace_entry( op, rs, on, e );
    885  1.1  christos 			rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
    886  1.1  christos 		}
    887  1.1  christos 		arg2.dercert = &args.dercert;
    888  1.1  christos 		arg2.derpkey = &args.derpkey;
    889  1.1  christos 		arg2.on = on;
    890  1.1  christos 		arg2.dn = &rs->sr_entry->e_name;
    891  1.1  christos 		arg2.ndn = &rs->sr_entry->e_nname;
    892  1.1  christos 		arg2.isca = 0;
    893  1.1  christos 		op2 = *op;
    894  1.1  christos 		rc = autoca_savecert( &op2, &arg2 );
    895  1.1  christos 		if ( !rc )
    896  1.1  christos 		{
    897  1.1  christos 			/* If this is our cert DN, configure it */
    898  1.1  christos 			if ( dn_match( &rs->sr_entry->e_nname, &ai->ai_localndn ))
    899  1.1  christos 				autoca_setlocal( &op2, &args.dercert, &args.derpkey );
    900  1.1  christos 			attr_merge_one( rs->sr_entry, ad_usrCert, &args.dercert, NULL );
    901  1.1  christos 			attr_merge_one( rs->sr_entry, ad_usrPkey, &args.derpkey, NULL );
    902  1.1  christos 		}
    903  1.1  christos 		op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
    904  1.1  christos 		op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
    905  1.1  christos 	}
    906  1.1  christos 
    907  1.1  christos 	return SLAP_CB_CONTINUE;
    908  1.1  christos }
    909  1.1  christos 
    910  1.1  christos static int
    911  1.1  christos autoca_op_search(
    912  1.1  christos 	Operation *op,
    913  1.1  christos 	SlapReply *rs
    914  1.1  christos )
    915  1.1  christos {
    916  1.1  christos 	/* we only act on a search that returns just our cert/key attrs */
    917  1.1  christos 	if ( op->ors_attrs && op->ors_attrs[0].an_desc == ad_usrCert &&
    918  1.1  christos 		op->ors_attrs[1].an_desc == ad_usrPkey &&
    919  1.1  christos 		op->ors_attrs[2].an_name.bv_val == NULL )
    920  1.1  christos 	{
    921  1.1  christos 		slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    922  1.1  christos 		slap_callback *sc = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
    923  1.1  christos 		sc->sc_response = autoca_op_response;
    924  1.1  christos 		sc->sc_private = on;
    925  1.1  christos 		sc->sc_next = op->o_callback;
    926  1.1  christos 		op->o_callback = sc;
    927  1.1  christos 	}
    928  1.1  christos 	return SLAP_CB_CONTINUE;
    929  1.1  christos }
    930  1.1  christos 
    931  1.1  christos static int
    932  1.1  christos autoca_db_init(
    933  1.1  christos 	BackendDB *be,
    934  1.1  christos 	ConfigReply *cr
    935  1.1  christos )
    936  1.1  christos {
    937  1.1  christos 	slap_overinst *on = (slap_overinst *) be->bd_info;
    938  1.1  christos 	autoca_info *ai;
    939  1.1  christos 
    940  1.1  christos 	ai = ch_calloc(1, sizeof(autoca_info));
    941  1.1  christos 	on->on_bi.bi_private = ai;
    942  1.1  christos 
    943  1.1  christos 	/* set defaults */
    944  1.1  christos 	ai->ai_usrclass = oc_find( "person" );
    945  1.1  christos 	ai->ai_srvclass = oc_find( "ipHost" );
    946  1.1  christos 	ai->ai_usrkeybits = KEYBITS;
    947  1.1  christos 	ai->ai_srvkeybits = KEYBITS;
    948  1.1  christos 	ai->ai_cakeybits = KEYBITS;
    949  1.1  christos 	ai->ai_usrdays = 365;	/* 1 year */
    950  1.1  christos 	ai->ai_srvdays = 1826;	/* 5 years */
    951  1.1  christos 	ai->ai_cadays = 3652;	/* 10 years */
    952  1.1  christos 	return 0;
    953  1.1  christos }
    954  1.1  christos 
    955  1.1  christos static int
    956  1.1  christos autoca_db_destroy(
    957  1.1  christos 	BackendDB *be,
    958  1.1  christos 	ConfigReply *cr
    959  1.1  christos )
    960  1.1  christos {
    961  1.1  christos 	slap_overinst *on = (slap_overinst *) be->bd_info;
    962  1.1  christos 	autoca_info *ai = on->on_bi.bi_private;
    963  1.1  christos 
    964  1.1  christos 	if ( ai->ai_cert )
    965  1.1  christos 		X509_free( ai->ai_cert );
    966  1.1  christos 	if ( ai->ai_pkey )
    967  1.1  christos 		EVP_PKEY_free( ai->ai_pkey );
    968  1.1  christos 	ch_free( ai );
    969  1.1  christos 
    970  1.1  christos 	return 0;
    971  1.1  christos }
    972  1.1  christos 
    973  1.1  christos static int
    974  1.1  christos autoca_db_open(
    975  1.1  christos 	BackendDB *be,
    976  1.1  christos 	ConfigReply *cr
    977  1.1  christos )
    978  1.1  christos {
    979  1.1  christos 	slap_overinst *on = (slap_overinst *)be->bd_info;
    980  1.1  christos 	autoca_info *ai = on->on_bi.bi_private;
    981  1.1  christos 
    982  1.1  christos 	Connection conn = { 0 };
    983  1.1  christos 	OperationBuffer opbuf;
    984  1.1  christos 	Operation *op;
    985  1.1  christos 	void *thrctx;
    986  1.1  christos 	Entry *e = NULL;
    987  1.1  christos 	Attribute *a;
    988  1.1  christos 	int rc;
    989  1.1  christos 
    990  1.1  christos 	if (slapMode & SLAP_TOOL_MODE)
    991  1.1  christos 		return 0;
    992  1.1  christos 
    993  1.1  christos 	if ( ! *aca_attr2[0].ad ) {
    994  1.1  christos 		int i, code;
    995  1.1  christos 		const char *text;
    996  1.1  christos 
    997  1.1  christos 		for ( i=0; aca_attr2[i].at; i++ ) {
    998  1.1  christos 			code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
    999  1.1  christos 			if ( code ) return code;
   1000  1.1  christos 		}
   1001  1.1  christos 
   1002  1.1  christos 		/* Schema may not be loaded, ignore if missing */
   1003  1.1  christos 		slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );
   1004  1.1  christos 
   1005  1.1  christos 		for ( i=0; aca_ocs[i].ot; i++ ) {
   1006  1.1  christos 			code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
   1007  1.1  christos 			if ( code ) return code;
   1008  1.1  christos 		}
   1009  1.1  christos 	}
   1010  1.1  christos 
   1011  1.1  christos 	thrctx = ldap_pvt_thread_pool_context();
   1012  1.1  christos 	connection_fake_init2( &conn, &opbuf, thrctx, 0 );
   1013  1.1  christos 	op = &opbuf.ob_op;
   1014  1.1  christos 	op->o_bd = be;
   1015  1.1  christos 	op->o_dn = be->be_rootdn;
   1016  1.1  christos 	op->o_ndn = be->be_rootndn;
   1017  1.1  christos 	rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL,
   1018  1.1  christos 		NULL, 0, &e, on );
   1019  1.1  christos 
   1020  1.1  christos 	if ( e ) {
   1021  1.1  christos 		int gotoc = 0, gotat = 0;
   1022  1.1  christos 		if ( is_entry_objectclass( e, oc_caObj, 0 )) {
   1023  1.1  christos 			gotoc = 1;
   1024  1.1  christos 			a = attr_find( e->e_attrs, ad_caPkey );
   1025  1.1  christos 			if ( a ) {
   1026  1.1  christos 				const unsigned char *pp;
   1027  1.1  christos 				pp = (unsigned char *)a->a_vals[0].bv_val;
   1028  1.1  christos 				ai->ai_pkey = d2i_AutoPrivateKey( NULL, &pp, a->a_vals[0].bv_len );
   1029  1.1  christos 				if ( ai->ai_pkey )
   1030  1.1  christos 				{
   1031  1.1  christos 					a = attr_find( e->e_attrs, ad_caCert );
   1032  1.1  christos 					if ( a )
   1033  1.1  christos 					{
   1034  1.1  christos 						pp = (unsigned char *)a->a_vals[0].bv_val;
   1035  1.1  christos 						ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
   1036  1.1  christos 						/* If TLS wasn't configured yet, set this as our CA */
   1037  1.1  christos 						if ( !slap_tls_ctx )
   1038  1.1  christos 							autoca_setca( a->a_vals );
   1039  1.1  christos 					}
   1040  1.1  christos 				}
   1041  1.1  christos 				gotat = 1;
   1042  1.1  christos 			}
   1043  1.1  christos 		}
   1044  1.1  christos 		overlay_entry_release_ov( op, e, 0, on );
   1045  1.1  christos 		/* generate attrs, store... */
   1046  1.1  christos 		if ( !gotat ) {
   1047  1.1  christos 			genargs args;
   1048  1.1  christos 			saveargs arg2;
   1049  1.1  christos 
   1050  1.1  christos 			args.issuer_cert = NULL;
   1051  1.1  christos 			args.issuer_pkey = NULL;
   1052  1.1  christos 			args.subjectDN = &be->be_suffix[0];
   1053  1.1  christos 			args.cert_exts = CAexts;
   1054  1.1  christos 			args.more_exts = NULL;
   1055  1.1  christos 			args.keybits = ai->ai_cakeybits;
   1056  1.1  christos 			args.days = ai->ai_cadays;
   1057  1.1  christos 
   1058  1.1  christos 			rc = autoca_gencert( op, &args );
   1059  1.1  christos 			if ( rc )
   1060  1.1  christos 				return -1;
   1061  1.1  christos 
   1062  1.1  christos 			ai->ai_cert = args.newcert;
   1063  1.1  christos 			ai->ai_pkey = args.newpkey;
   1064  1.1  christos 
   1065  1.1  christos 			arg2.dn = be->be_suffix;
   1066  1.1  christos 			arg2.ndn = be->be_nsuffix;
   1067  1.1  christos 			arg2.isca = 1;
   1068  1.1  christos 			if ( !gotoc )
   1069  1.1  christos 				arg2.oc = oc_caObj;
   1070  1.1  christos 			else
   1071  1.1  christos 				arg2.oc = NULL;
   1072  1.1  christos 			arg2.on = on;
   1073  1.1  christos 			arg2.dercert = &args.dercert;
   1074  1.1  christos 			arg2.derpkey = &args.derpkey;
   1075  1.1  christos 
   1076  1.1  christos 			autoca_savecert( op, &arg2 );
   1077  1.1  christos 
   1078  1.1  christos 			/* If TLS wasn't configured yet, set this as our CA */
   1079  1.1  christos 			if ( !slap_tls_ctx )
   1080  1.1  christos 				autoca_setca( &args.dercert );
   1081  1.1  christos 
   1082  1.1  christos 			op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
   1083  1.1  christos 			op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
   1084  1.1  christos 		}
   1085  1.1  christos 	}
   1086  1.1  christos 
   1087  1.1  christos 	return 0;
   1088  1.1  christos }
   1089  1.1  christos 
   1090  1.1  christos static slap_overinst autoca;
   1091  1.1  christos 
   1092  1.1  christos /* This overlay is set up for dynamic loading via moduleload. For static
   1093  1.1  christos  * configuration, you'll need to arrange for the slap_overinst to be
   1094  1.1  christos  * initialized and registered by some other function inside slapd.
   1095  1.1  christos  */
   1096  1.1  christos 
   1097  1.1  christos int autoca_initialize() {
   1098  1.1  christos 	int i, code;
   1099  1.1  christos 
   1100  1.1  christos 	autoca.on_bi.bi_type = "autoca";
   1101  1.1  christos 	autoca.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
   1102  1.1  christos 	autoca.on_bi.bi_db_init = autoca_db_init;
   1103  1.1  christos 	autoca.on_bi.bi_db_destroy = autoca_db_destroy;
   1104  1.1  christos 	autoca.on_bi.bi_db_open = autoca_db_open;
   1105  1.1  christos 	autoca.on_bi.bi_op_search = autoca_op_search;
   1106  1.1  christos 
   1107  1.1  christos 	autoca.on_bi.bi_cf_ocs = autoca_ocs;
   1108  1.1  christos 	code = config_register_schema( autoca_cfg, autoca_ocs );
   1109  1.1  christos 	if ( code ) return code;
   1110  1.1  christos 
   1111  1.1  christos 	for ( i=0; aca_attrs[i]; i++ ) {
   1112  1.1  christos 		code = register_at( aca_attrs[i], NULL, 0 );
   1113  1.1  christos 		if ( code ) return code;
   1114  1.1  christos 	}
   1115  1.1  christos 
   1116  1.1  christos 	return overlay_register( &autoca );
   1117  1.1  christos }
   1118  1.1  christos 
   1119  1.1  christos #if SLAPD_OVER_AUTOCA == SLAPD_MOD_DYNAMIC
   1120  1.1  christos int
   1121  1.1  christos init_module( int argc, char *argv[] )
   1122  1.1  christos {
   1123  1.1  christos 	return autoca_initialize();
   1124  1.1  christos }
   1125  1.1  christos #endif
   1126  1.1  christos 
   1127  1.1  christos #endif /* defined(SLAPD_OVER_AUTOCA) */
   1128