mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-24 00:29:35 -05:00
Add autoca overlay
Automated certificate authority
This commit is contained in:
parent
ec5af7b5e7
commit
2b920ecaec
4 changed files with 1091 additions and 0 deletions
15
configure.in
15
configure.in
|
|
@ -344,6 +344,7 @@ dnl ----------------------------------------------------------------
|
|||
dnl SLAPD Overlay Options
|
||||
Overlays="accesslog \
|
||||
auditlog \
|
||||
autoca \
|
||||
collect \
|
||||
constraint \
|
||||
dds \
|
||||
|
|
@ -372,6 +373,8 @@ OL_ARG_ENABLE(accesslog,[ --enable-accesslog In-Directory Access Logging ov
|
|||
no, [no yes mod], ol_enable_overlays)
|
||||
OL_ARG_ENABLE(auditlog,[ --enable-auditlog Audit Logging overlay],
|
||||
no, [no yes mod], ol_enable_overlays)
|
||||
OL_ARG_ENABLE(autoca,[ --enable-autoca Automatic Certificate Authority overlay],
|
||||
no, [no yes mod], ol_enable_overlays)
|
||||
OL_ARG_ENABLE(collect,[ --enable-collect Collect overlay],
|
||||
no, [no yes mod], ol_enable_overlays)
|
||||
OL_ARG_ENABLE(constraint,[ --enable-constraint Attribute Constraint overlay],
|
||||
|
|
@ -2903,6 +2906,18 @@ if test "$ol_enable_auditlog" != no ; then
|
|||
AC_DEFINE_UNQUOTED(SLAPD_OVER_AUDITLOG,$MFLAG,[define for Audit Logging overlay])
|
||||
fi
|
||||
|
||||
if test "$ol_enable_autoca" != no ; then
|
||||
BUILD_AUDITLOG=$ol_enable_autoca
|
||||
if test "$ol_enable_autoca" = mod ; then
|
||||
MFLAG=SLAPD_MOD_DYNAMIC
|
||||
SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS autoca.la"
|
||||
else
|
||||
MFLAG=SLAPD_MOD_STATIC
|
||||
SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS autoca.o"
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(SLAPD_OVER_AUTOCA,$MFLAG,[define for Automatic Certificate Authority overlay])
|
||||
fi
|
||||
|
||||
if test "$ol_enable_collect" != no ; then
|
||||
BUILD_COLLECT=$ol_enable_collect
|
||||
if test "$ol_enable_collect" = mod ; then
|
||||
|
|
|
|||
103
doc/man/man5/slapo-autoca.5
Normal file
103
doc/man/man5/slapo-autoca.5
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
.TH SLAPO-AUTOCA 5 "RELEASEDATE" "OpenLDAP LDVERSION"
|
||||
.\" Copyright 2009-2017 The OpenLDAP Foundation All Rights Reserved.
|
||||
.\" Copyright 2009-2017 Howard Chu All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.\" $OpenLDAP$
|
||||
.SH NAME
|
||||
slapo\-autoca \- Automatic Certificate Authority overlay to slapd
|
||||
.SH SYNOPSIS
|
||||
ETCDIR/slapd.conf
|
||||
.SH DESCRIPTION
|
||||
The Automatic CA overlay generates X.509 certificate/key pairs for
|
||||
entries in the directory. The DN of a generated certificate is
|
||||
identical to the DN of the entry containing it. On startup it
|
||||
checks for a CA certificate in the suffix entry of the database
|
||||
and generates and stores one if not found. This CA certificate
|
||||
is used to sign all subsequently generated certificates.
|
||||
.LP
|
||||
Certificates for users and servers are generated on demand using
|
||||
a Search request returning only the userCertificate;binary and
|
||||
userPrivateKey;binary attributes. Any Search for anything besides
|
||||
exactly these two attributes is ignored by the overlay. Note that
|
||||
these values are stored in ASN.1 DER form in the directory so the
|
||||
";binary" attribute option is mandatory.
|
||||
.LP
|
||||
Entries that do not belong to selected objectClasses will be
|
||||
ignored by the overlay. By default, entries of objectClass
|
||||
.B person
|
||||
will be treated as users, and entries of objectClass
|
||||
.B ipHost
|
||||
will be treated as servers. There are slight differences in the
|
||||
set of X.509V3 certificate extensions added to the certificate
|
||||
between users and servers.
|
||||
.LP
|
||||
The CA's private key is stored in a
|
||||
.B cAPrivateKey
|
||||
attribute, and user and server private keys are stored in the
|
||||
.B userPrivateKey
|
||||
attribute. It is essential that access to these attributes be
|
||||
properly secured with ACLs. Both of these attributes inherit
|
||||
from the
|
||||
.B x509PrivateKey
|
||||
attribute, so it is sufficient to use a single ACL rule like
|
||||
|
||||
.nf
|
||||
access to attrs=x509PrivateKey by self ssf=128 write
|
||||
.fi
|
||||
|
||||
at the beginning of the rules.
|
||||
|
||||
.SH CONFIGURATION
|
||||
These
|
||||
.B slapd.conf
|
||||
options apply to the Automatic CA overlay.
|
||||
They should appear after the
|
||||
.B overlay
|
||||
directive.
|
||||
.TP
|
||||
.B userClass <objectClass>
|
||||
Specify the objectClass to be treated as user entries.
|
||||
.TP
|
||||
.B serverClass <objectClass>
|
||||
Specify the objectClass to be treated as server entries.
|
||||
.TP
|
||||
.B userKeybits <integer>
|
||||
Specify the size of the private key to use for user certificates.
|
||||
The default is 2048 and the minimum is 512.
|
||||
.TP
|
||||
.B serverKeybits <integer>
|
||||
Specify the size of the private key to use for server certificates.
|
||||
The default is 2048 and the minimum is 512.
|
||||
.TP
|
||||
.B caKeybits <integer>
|
||||
Specify the size of the private key to use for the CA certificate.
|
||||
The default is 2048 and the minimum is 512.
|
||||
.TP
|
||||
.B userDays <integer>
|
||||
Specify the duration for a user certificate's validity.
|
||||
The default is 365, 1 year.
|
||||
.TP
|
||||
.B serverDays <integer>
|
||||
Specify the duration for a server certificate's validity.
|
||||
The default is 1826, 5 years.
|
||||
.TP
|
||||
.B caDays <integer>
|
||||
Specify the duration for the CA certificate's validity.
|
||||
The default is 3652, 10 years.
|
||||
|
||||
.SH EXAMPLES
|
||||
.nf
|
||||
database mdb
|
||||
...
|
||||
overlay autoca
|
||||
caKeybits 4096
|
||||
.fi
|
||||
.SH FILES
|
||||
.TP
|
||||
ETCDIR/slapd.conf
|
||||
default slapd configuration file
|
||||
.SH SEE ALSO
|
||||
.BR slapd.conf (5),
|
||||
.BR slapd\-config (5).
|
||||
.SH AUTHOR
|
||||
Howard Chu
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
SRCS = overlays.c \
|
||||
accesslog.c \
|
||||
auditlog.c \
|
||||
autoca.c \
|
||||
constraint.c \
|
||||
dds.c \
|
||||
deref.c \
|
||||
|
|
@ -68,6 +69,9 @@ accesslog.la : accesslog.lo
|
|||
auditlog.la : auditlog.lo
|
||||
$(LTLINK_MOD) -module -o $@ auditlog.lo version.lo $(LINK_LIBS)
|
||||
|
||||
autoca.la : autoca.lo
|
||||
$(LTLINK_MOD) -module -o $@ autoca.lo version.lo $(LINK_LIBS)
|
||||
|
||||
constraint.la : constraint.lo
|
||||
$(LTLINK_MOD) -module -o $@ constraint.lo version.lo $(LINK_LIBS)
|
||||
|
||||
|
|
|
|||
969
servers/slapd/overlays/autoca.c
Normal file
969
servers/slapd/overlays/autoca.c
Normal file
|
|
@ -0,0 +1,969 @@
|
|||
/* autoca.c - Automatic Certificate Authority */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2009-2017 The OpenLDAP Foundation.
|
||||
* Copyright 2009-2017 by Howard Chu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was initially developed by Howard Chu for inclusion in
|
||||
* OpenLDAP Software.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#define SLAPD_OVER_AUTOCA SLAPD_MOD_DYNAMIC
|
||||
|
||||
#ifdef SLAPD_OVER_AUTOCA
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/string.h>
|
||||
#include <ac/socket.h>
|
||||
|
||||
#include "lutil.h"
|
||||
#include "slap.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
/* This overlay implements a certificate authority that can generate
|
||||
* certificates automatically for any entry in the directory.
|
||||
* On startup it generates a self-signed CA cert for the directory's
|
||||
* suffix entry and uses this to sign all other certs that it generates.
|
||||
* User and server certs are generated on demand, using a Search request.
|
||||
*/
|
||||
|
||||
#define LBER_TAG_OID ((ber_tag_t) 0x06UL)
|
||||
#define LBER_TAG_UTF8 ((ber_tag_t) 0x0cUL)
|
||||
|
||||
#define KEYBITS 2048
|
||||
#define MIN_KEYBITS 512
|
||||
|
||||
#define ACA_SCHEMA_ROOT "1.3.6.1.4.1.4203.666.11.11"
|
||||
|
||||
#define ACA_SCHEMA_AT ACA_SCHEMA_ROOT ".1"
|
||||
#define ACA_SCHEMA_OC ACA_SCHEMA_ROOT ".2"
|
||||
#define ACA_SCHEMA_SYN ACA_SCHEMA_ROOT ".3"
|
||||
#define ACA_SCHEMA_MR ACA_SCHEMA_ROOT ".4"
|
||||
|
||||
static AttributeDescription *ad_caCert, *ad_caPkey, *ad_usrCert, *ad_usrPkey;
|
||||
static AttributeDescription *ad_mail, *ad_ipaddr;
|
||||
static ObjectClass *oc_caObj, *oc_usrObj;
|
||||
|
||||
/* OpenSSL privatekeys have no single specific format */
|
||||
static int
|
||||
privateKeyValidate(
|
||||
Syntax *syntax,
|
||||
struct berval *val )
|
||||
{
|
||||
BerElementBuffer berbuf;
|
||||
BerElement *ber = (BerElement *)&berbuf;
|
||||
ber_tag_t tag;
|
||||
ber_len_t len;
|
||||
ber_int_t version;
|
||||
|
||||
ber_init2( ber, val, LBER_USE_DER );
|
||||
tag = ber_skip_tag( ber, &len ); /* Sequence */
|
||||
if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
|
||||
tag = ber_peek_tag( ber, &len );
|
||||
if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
|
||||
tag = ber_get_int( ber, &version );
|
||||
/* the rest varies for RSA, DSA, EC, PKCS#8 */
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
static slap_syntax_defs_rec aca_syntax = {
|
||||
"( " ACA_SCHEMA_SYN ".1 DESC 'X.509 Private Key' "
|
||||
"X-BINARY-TRANSFER-REQUIRED 'TRUE' "
|
||||
"X-NOT-HUMAN-READABLE 'TRUE' )",
|
||||
SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
|
||||
NULL,
|
||||
privateKeyValidate,
|
||||
NULL };
|
||||
|
||||
static slap_mrule_defs_rec aca_mrule = {
|
||||
"( " ACA_SCHEMA_MR ".1 NAME 'privateKeyMatch' "
|
||||
"SYNTAX " ACA_SCHEMA_SYN ".1 )",
|
||||
SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
|
||||
NULL, NULL, octetStringMatch, octetStringIndexer,
|
||||
octetStringFilter, NULL };
|
||||
|
||||
static char *aca_attrs[] = {
|
||||
"( " ACA_SCHEMA_AT ".0 NAME 'x509PrivateKey' "
|
||||
"DESC 'X.509 private key, use ;binary' "
|
||||
"EQUALITY privateKeyMatch "
|
||||
"SYNTAX " ACA_SCHEMA_SYN ".1 )",
|
||||
"( " ACA_SCHEMA_AT ".1 NAME 'cAPrivateKey' "
|
||||
"DESC 'X.509 CA private key, use ;binary' "
|
||||
"SUP x509PrivateKey )",
|
||||
"( " ACA_SCHEMA_AT ".2 NAME 'userPrivateKey' "
|
||||
"DESC 'X.509 user private key, use ;binary' "
|
||||
"SUP x509PrivateKey )",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct {
|
||||
char *at;
|
||||
AttributeDescription **ad;
|
||||
} aca_attr2[] = {
|
||||
{ "cACertificate;binary", &ad_caCert },
|
||||
{ "cAPrivateKey;binary", &ad_caPkey },
|
||||
{ "userCertificate;binary", &ad_usrCert },
|
||||
{ "userPrivateKey;binary", &ad_usrPkey },
|
||||
{ "mail", &ad_mail },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static struct {
|
||||
char *ot;
|
||||
ObjectClass **oc;
|
||||
} aca_ocs[] = {
|
||||
{ "( " ACA_SCHEMA_OC ".1 NAME 'autoCA' "
|
||||
"DESC 'Automated PKI certificate authority' "
|
||||
"SUP pkiCA AUXILIARY "
|
||||
"MAY cAPrivateKey )", &oc_caObj },
|
||||
{ "( " ACA_SCHEMA_OC ".2 NAME 'autoCAuser' "
|
||||
"DESC 'Automated PKI CA user' "
|
||||
"SUP pkiUser AUXILIARY "
|
||||
"MAY userPrivateKey )", &oc_usrObj },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
typedef struct autoca_info {
|
||||
X509 *ai_cert;
|
||||
EVP_PKEY *ai_pkey;
|
||||
ObjectClass *ai_usrclass;
|
||||
ObjectClass *ai_srvclass;
|
||||
int ai_usrkeybits;
|
||||
int ai_srvkeybits;
|
||||
int ai_cakeybits;
|
||||
int ai_usrdays;
|
||||
int ai_srvdays;
|
||||
int ai_cadays;
|
||||
} autoca_info;
|
||||
|
||||
/* Rewrite an LDAP DN in DER form
|
||||
* Input must be valid DN, therefore no error checking is done here.
|
||||
*/
|
||||
static int autoca_dnbv2der( Operation *op, struct berval *bv, struct berval *der )
|
||||
{
|
||||
BerElementBuffer berbuf;
|
||||
BerElement *ber = (BerElement *)&berbuf;
|
||||
LDAPDN dn;
|
||||
LDAPRDN rdn;
|
||||
LDAPAVA *ava;
|
||||
AttributeDescription *ad;
|
||||
int irdn, iava;
|
||||
|
||||
ldap_bv2dn_x( bv, &dn, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx );
|
||||
|
||||
ber_init2( ber, NULL, LBER_USE_DER );
|
||||
ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
|
||||
|
||||
/* count RDNs, we need them in reverse order */
|
||||
for (irdn = 0; dn[irdn]; irdn++);
|
||||
irdn--;
|
||||
|
||||
/* DN is a SEQuence of RDNs */
|
||||
ber_start_seq( ber, LBER_SEQUENCE );
|
||||
for (; irdn >=0; irdn--)
|
||||
{
|
||||
/* RDN is a SET of AVAs */
|
||||
ber_start_set( ber, LBER_SET );
|
||||
rdn = dn[irdn];
|
||||
for (iava = 0; rdn[iava]; iava++)
|
||||
{
|
||||
const char *text;
|
||||
char oid[1024];
|
||||
struct berval bvo = { sizeof(oid), oid };
|
||||
struct berval bva;
|
||||
|
||||
/* AVA is a SEQuence of attr and value */
|
||||
ber_start_seq( ber, LBER_SEQUENCE );
|
||||
ava = rdn[iava];
|
||||
ad = NULL;
|
||||
slap_bv2ad( &ava->la_attr, &ad, &text );
|
||||
ber_str2bv( ad->ad_type->sat_oid, 0, 0, &bva );
|
||||
ber_encode_oid( &bva, &bvo );
|
||||
ber_put_berval( ber, &bvo, LBER_TAG_OID );
|
||||
ber_put_berval( ber, &ava->la_value, LBER_TAG_UTF8 );
|
||||
ber_put_seq( ber );
|
||||
}
|
||||
ber_put_set( ber );
|
||||
}
|
||||
ber_put_seq( ber );
|
||||
ber_flatten2( ber, der, 0 );
|
||||
ldap_dnfree_x( dn, op->o_tmpmemctx );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int autoca_genpkey(int bits, EVP_PKEY **pkey)
|
||||
{
|
||||
EVP_PKEY_CTX *kctx;
|
||||
int rc;
|
||||
|
||||
kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
||||
if (kctx == NULL)
|
||||
return -1;
|
||||
if (EVP_PKEY_keygen_init(kctx) <= 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(kctx);
|
||||
return -1;
|
||||
}
|
||||
if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, bits) <= 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(kctx);
|
||||
return -1;
|
||||
}
|
||||
rc = EVP_PKEY_keygen(kctx, pkey);
|
||||
EVP_PKEY_CTX_free(kctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int autoca_signcert(X509 *cert, EVP_PKEY *pkey)
|
||||
{
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
EVP_PKEY_CTX *pkctx = NULL;
|
||||
int rc = -1;
|
||||
|
||||
if ( ctx == NULL )
|
||||
return -1;
|
||||
if (EVP_DigestSignInit(ctx, &pkctx, NULL, NULL, pkey))
|
||||
{
|
||||
rc = X509_sign_ctx(cert, ctx);
|
||||
}
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define SERIAL_BITS 64 /* should be less than 160 */
|
||||
|
||||
typedef struct myext {
|
||||
char *name;
|
||||
char *value;
|
||||
} myext;
|
||||
|
||||
static myext CAexts[] = {
|
||||
{ "subjectKeyIdentifier", "hash" },
|
||||
{ "authorityKeyIdentifier", "keyid:always,issuer" },
|
||||
{ "basicConstraints", "critical,CA:true" },
|
||||
{ "keyUsage", "digitalSignature,cRLSign,keyCertSign" },
|
||||
{ "nsComment", "OpenLDAP automatic certificate" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static myext usrExts[] = {
|
||||
{ "subjectKeyIdentifier", "hash" },
|
||||
{ "authorityKeyIdentifier", "keyid:always,issuer" },
|
||||
{ "basicConstraints", "CA:false" },
|
||||
{ "keyUsage", "digitalSignature,nonRepudiation,keyEncipherment" },
|
||||
{ "extendedKeyUsage", "clientAuth,emailProtection,codeSigning" },
|
||||
{ "nsComment", "OpenLDAP automatic certificate" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static myext srvExts[] = {
|
||||
{ "subjectKeyIdentifier", "hash" },
|
||||
{ "authorityKeyIdentifier", "keyid:always,issuer" },
|
||||
{ "basicConstraints", "CA:false" },
|
||||
{ "keyUsage", "digitalSignature,keyEncipherment" },
|
||||
{ "extendedKeyUsage", "serverAuth,clientAuth" },
|
||||
{ "nsComment", "OpenLDAP automatic certificate" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
typedef struct genargs {
|
||||
X509 *issuer_cert;
|
||||
EVP_PKEY *issuer_pkey;
|
||||
struct berval *subjectDN;
|
||||
myext *cert_exts;
|
||||
myext *more_exts;
|
||||
X509 *newcert;
|
||||
EVP_PKEY *newpkey;
|
||||
struct berval dercert;
|
||||
struct berval derpkey;
|
||||
int keybits;
|
||||
int days;
|
||||
} genargs;
|
||||
|
||||
static int autoca_gencert( Operation *op, genargs *args )
|
||||
{
|
||||
X509_NAME *subj_name, *issuer_name;
|
||||
X509 *subj_cert;
|
||||
struct berval derdn;
|
||||
const unsigned char *p;
|
||||
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 );
|
||||
op->o_tmpfree( derdn.bv_val, op->o_tmpmemctx );
|
||||
if ( subj_name == NULL )
|
||||
{
|
||||
fail1:
|
||||
X509_free( subj_cert );
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = autoca_genpkey( args->keybits, &evpk );
|
||||
if ( rc <= 0 )
|
||||
{
|
||||
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 );
|
||||
args->newpkey = evpk;
|
||||
|
||||
/* set random serial */
|
||||
{
|
||||
BIGNUM *bn = BN_new();
|
||||
if ( bn == NULL )
|
||||
{
|
||||
fail3:
|
||||
EVP_PKEY_free( evpk );
|
||||
goto fail2;
|
||||
}
|
||||
if (!BN_pseudo_rand(bn, SERIAL_BITS, 0, 0))
|
||||
{
|
||||
BN_free( bn );
|
||||
goto fail3;
|
||||
}
|
||||
if (!BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(subj_cert)))
|
||||
{
|
||||
BN_free( bn );
|
||||
goto fail3;
|
||||
}
|
||||
BN_free(bn);
|
||||
}
|
||||
if (args->issuer_cert) {
|
||||
issuer_name = X509_get_subject_name(args->issuer_cert);
|
||||
} else {
|
||||
issuer_name = subj_name;
|
||||
args->issuer_cert = subj_cert;
|
||||
args->issuer_pkey = evpk;
|
||||
}
|
||||
if (!X509_set_version(subj_cert, 2) || /* set version to V3 */
|
||||
!X509_set_issuer_name(subj_cert, issuer_name) ||
|
||||
!X509_set_subject_name(subj_cert, subj_name) ||
|
||||
!X509_gmtime_adj(X509_get_notBefore(subj_cert), 0) ||
|
||||
!X509_time_adj_ex(X509_get_notAfter(subj_cert), args->days, 0, NULL) ||
|
||||
!X509_set_pubkey(subj_cert, evpk))
|
||||
{
|
||||
goto fail3;
|
||||
}
|
||||
X509_NAME_free(subj_name);
|
||||
subj_name = NULL;
|
||||
|
||||
/* set cert extensions */
|
||||
{
|
||||
X509V3_CTX ctx;
|
||||
X509_EXTENSION *ext;
|
||||
int i;
|
||||
|
||||
X509V3_set_ctx(&ctx, args->issuer_cert, subj_cert, NULL, NULL, 0);
|
||||
for (i=0; args->cert_exts[i].name; i++) {
|
||||
ext = X509V3_EXT_nconf(NULL, &ctx, args->cert_exts[i].name, args->cert_exts[i].value);
|
||||
if ( ext == NULL )
|
||||
goto fail3;
|
||||
rc = X509_add_ext(subj_cert, ext, -1);
|
||||
X509_EXTENSION_free(ext);
|
||||
if ( !rc )
|
||||
goto fail3;
|
||||
}
|
||||
if (args->more_exts) {
|
||||
for (i=0; args->more_exts[i].name; i++) {
|
||||
ext = X509V3_EXT_nconf(NULL, &ctx, args->more_exts[i].name, args->more_exts[i].value);
|
||||
if ( ext == NULL )
|
||||
goto fail3;
|
||||
rc = X509_add_ext(subj_cert, ext, -1);
|
||||
X509_EXTENSION_free(ext);
|
||||
if ( !rc )
|
||||
goto fail3;
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = autoca_signcert( subj_cert, args->issuer_pkey );
|
||||
if ( rc < 0 )
|
||||
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;
|
||||
i2d_X509( subj_cert, &pp );
|
||||
args->newcert = subj_cert;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct saveargs {
|
||||
ObjectClass *oc;
|
||||
struct berval *dercert;
|
||||
struct berval *derpkey;
|
||||
slap_overinst *on;
|
||||
struct berval *dn;
|
||||
struct berval *ndn;
|
||||
int isca;
|
||||
} saveargs;
|
||||
|
||||
static int autoca_savecert( Operation *op, saveargs *args )
|
||||
{
|
||||
Modifications mod[3], *mp = mod;
|
||||
struct berval bvs[6], *bp = bvs;
|
||||
BackendInfo *bi;
|
||||
slap_callback cb = {0};
|
||||
SlapReply rs = {REP_RESULT};
|
||||
|
||||
if ( args->oc ) {
|
||||
mp->sml_numvals = 1;
|
||||
mp->sml_values = bp;
|
||||
mp->sml_nvalues = NULL;
|
||||
mp->sml_desc = slap_schema.si_ad_objectClass;
|
||||
mp->sml_op = LDAP_MOD_ADD;
|
||||
mp->sml_flags = SLAP_MOD_INTERNAL;
|
||||
*bp++ = args->oc->soc_cname;
|
||||
BER_BVZERO( bp );
|
||||
bp++;
|
||||
mp->sml_next = mp+1;
|
||||
mp++;
|
||||
}
|
||||
mp->sml_numvals = 1;
|
||||
mp->sml_values = bp;
|
||||
mp->sml_nvalues = NULL;
|
||||
mp->sml_desc = args->isca ? ad_caCert : ad_usrCert;
|
||||
mp->sml_op = LDAP_MOD_REPLACE;
|
||||
mp->sml_flags = SLAP_MOD_INTERNAL;
|
||||
*bp++ = *args->dercert;
|
||||
BER_BVZERO( bp );
|
||||
bp++;
|
||||
mp->sml_next = mp+1;
|
||||
mp++;
|
||||
|
||||
mp->sml_numvals = 1;
|
||||
mp->sml_values = bp;
|
||||
mp->sml_nvalues = NULL;
|
||||
mp->sml_desc = args->isca ? ad_caPkey : ad_usrPkey;
|
||||
mp->sml_op = LDAP_MOD_ADD;
|
||||
mp->sml_flags = SLAP_MOD_INTERNAL;
|
||||
*bp++ = *args->derpkey;
|
||||
BER_BVZERO( bp );
|
||||
mp->sml_next = NULL;
|
||||
|
||||
cb.sc_response = slap_null_cb;
|
||||
bi = op->o_bd->bd_info;
|
||||
op->o_bd->bd_info = args->on->on_info->oi_orig;
|
||||
op->o_tag = LDAP_REQ_MODIFY;
|
||||
op->o_callback = &cb;
|
||||
op->orm_modlist = mod;
|
||||
op->orm_no_opattrs = 1;
|
||||
op->o_req_dn = *args->dn;
|
||||
op->o_req_ndn = *args->ndn;
|
||||
op->o_bd->be_modify( op, &rs );
|
||||
op->o_bd->bd_info = bi;
|
||||
return rs.sr_err;
|
||||
}
|
||||
|
||||
enum {
|
||||
ACA_USRCLASS = 1,
|
||||
ACA_SRVCLASS,
|
||||
ACA_USRKEYBITS,
|
||||
ACA_SRVKEYBITS,
|
||||
ACA_CAKEYBITS,
|
||||
ACA_USRDAYS,
|
||||
ACA_SRVDAYS,
|
||||
ACA_CADAYS
|
||||
};
|
||||
|
||||
static int autoca_cf( ConfigArgs *c )
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *)c->bi;
|
||||
autoca_info *ai = on->on_bi.bi_private;
|
||||
int rc = 0;
|
||||
|
||||
switch( c->op ) {
|
||||
case SLAP_CONFIG_EMIT:
|
||||
switch( c->type ) {
|
||||
case ACA_USRCLASS:
|
||||
if ( ai->ai_usrclass ) {
|
||||
c->value_string = ch_strdup( ai->ai_usrclass->soc_cname.bv_val );
|
||||
} else {
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
case ACA_SRVCLASS:
|
||||
if ( ai->ai_srvclass ) {
|
||||
c->value_string = ch_strdup( ai->ai_srvclass->soc_cname.bv_val );
|
||||
} else {
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
case ACA_USRKEYBITS:
|
||||
c->value_int = ai->ai_usrkeybits;
|
||||
break;
|
||||
case ACA_SRVKEYBITS:
|
||||
c->value_int = ai->ai_srvkeybits;
|
||||
break;
|
||||
case ACA_CAKEYBITS:
|
||||
c->value_int = ai->ai_cakeybits;
|
||||
break;
|
||||
case ACA_USRDAYS:
|
||||
c->value_int = ai->ai_usrdays;
|
||||
break;
|
||||
case ACA_SRVDAYS:
|
||||
c->value_int = ai->ai_srvdays;
|
||||
break;
|
||||
case ACA_CADAYS:
|
||||
c->value_int = ai->ai_cadays;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LDAP_MOD_DELETE:
|
||||
switch( c->type ) {
|
||||
case ACA_USRCLASS:
|
||||
ai->ai_usrclass = NULL;
|
||||
break;
|
||||
case ACA_SRVCLASS:
|
||||
ai->ai_srvclass = NULL;
|
||||
break;
|
||||
/* single-valued attrs, all no-ops */
|
||||
}
|
||||
break;
|
||||
case SLAP_CONFIG_ADD:
|
||||
case LDAP_MOD_ADD:
|
||||
switch( c->type ) {
|
||||
case ACA_USRCLASS:
|
||||
{
|
||||
ObjectClass *oc = oc_find( c->value_string );
|
||||
if ( oc )
|
||||
ai->ai_usrclass = oc;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
case ACA_SRVCLASS:
|
||||
{
|
||||
ObjectClass *oc = oc_find( c->value_string );
|
||||
if ( oc )
|
||||
ai->ai_srvclass = oc;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
case ACA_USRKEYBITS:
|
||||
if ( c->value_int < MIN_KEYBITS )
|
||||
rc = 1;
|
||||
else
|
||||
ai->ai_usrkeybits = c->value_int;
|
||||
break;
|
||||
case ACA_SRVKEYBITS:
|
||||
if ( c->value_int < MIN_KEYBITS )
|
||||
rc = 1;
|
||||
else
|
||||
ai->ai_srvkeybits = c->value_int;
|
||||
break;
|
||||
case ACA_CAKEYBITS:
|
||||
if ( c->value_int < MIN_KEYBITS )
|
||||
rc = 1;
|
||||
else
|
||||
ai->ai_cakeybits = c->value_int;
|
||||
break;
|
||||
case ACA_USRDAYS:
|
||||
ai->ai_usrdays = c->value_int;
|
||||
break;
|
||||
case ACA_SRVDAYS:
|
||||
ai->ai_srvdays = c->value_int;
|
||||
break;
|
||||
case ACA_CADAYS:
|
||||
ai->ai_cadays = c->value_int;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ConfigTable autoca_cfg[] = {
|
||||
{ "userClass", "objectclass", 2, 2, 0,
|
||||
ARG_STRING|ARG_MAGIC|ACA_USRCLASS, autoca_cf,
|
||||
"( OLcfgOvAt:22.1 NAME 'olcACAuserClass' "
|
||||
"DESC 'ObjectClass of user entries' "
|
||||
"SYNTAX OMsDirectoryString )", NULL, NULL },
|
||||
{ "servererClass", "objectclass", 2, 2, 0,
|
||||
ARG_STRING|ARG_MAGIC|ACA_SRVCLASS, autoca_cf,
|
||||
"( OLcfgOvAt:22.2 NAME 'olcACAserverClass' "
|
||||
"DESC 'ObjectClass of server entries' "
|
||||
"SYNTAX OMsDirectoryString )", NULL, NULL },
|
||||
{ "userKeybits", "integer", 2, 2, 0,
|
||||
ARG_INT|ARG_MAGIC|ACA_USRKEYBITS, autoca_cf,
|
||||
"( OLcfgOvAt:22.3 NAME 'olcACAuserKeybits' "
|
||||
"DESC 'Size of PrivateKey for user entries' "
|
||||
"SYNTAX OMsInteger )", NULL, NULL },
|
||||
{ "serverKeybits", "integer", 2, 2, 0,
|
||||
ARG_INT|ARG_MAGIC|ACA_SRVKEYBITS, autoca_cf,
|
||||
"( OLcfgOvAt:22.4 NAME 'olcACAserverKeybits' "
|
||||
"DESC 'Size of PrivateKey for server entries' "
|
||||
"SYNTAX OMsInteger )", NULL, NULL },
|
||||
{ "caKeybits", "integer", 2, 2, 0,
|
||||
ARG_INT|ARG_MAGIC|ACA_CAKEYBITS, autoca_cf,
|
||||
"( OLcfgOvAt:22.5 NAME 'olcACAKeybits' "
|
||||
"DESC 'Size of PrivateKey for CA certificate' "
|
||||
"SYNTAX OMsInteger )", NULL, NULL },
|
||||
{ "userDays", "integer", 2, 2, 0,
|
||||
ARG_INT|ARG_MAGIC|ACA_USRDAYS, autoca_cf,
|
||||
"( OLcfgOvAt:22.6 NAME 'olcACAuserDays' "
|
||||
"DESC 'Lifetime of user certificates in days' "
|
||||
"SYNTAX OMsInteger )", NULL, NULL },
|
||||
{ "serverDays", "integer", 2, 2, 0,
|
||||
ARG_INT|ARG_MAGIC|ACA_SRVDAYS, autoca_cf,
|
||||
"( OLcfgOvAt:22.7 NAME 'olcACAserverDays' "
|
||||
"DESC 'Lifetime of server certificates in days' "
|
||||
"SYNTAX OMsInteger )", NULL, NULL },
|
||||
{ "caDays", "integer", 2, 2, 0,
|
||||
ARG_INT|ARG_MAGIC|ACA_CADAYS, autoca_cf,
|
||||
"( OLcfgOvAt:22.8 NAME 'olcACADays' "
|
||||
"DESC 'Lifetime of CA certificate in days' "
|
||||
"SYNTAX OMsInteger )", NULL, NULL },
|
||||
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
|
||||
};
|
||||
|
||||
static ConfigOCs autoca_ocs[] = {
|
||||
{ "( OLcfgOvOc:22.1 "
|
||||
"NAME 'olcACAConfig' "
|
||||
"DESC 'AutoCA configuration' "
|
||||
"SUP olcOverlayConfig "
|
||||
"MAY ( olcACAuserClass $ olcACAserverClass $ "
|
||||
"olcACAuserKeybits $ olcACAserverKeybits $ olcACAKeyBits $ "
|
||||
"olcACAuserDays $ olcACAserverDays $ olcACADays ) )",
|
||||
Cft_Overlay, autoca_cfg },
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
autoca_op_response(
|
||||
Operation *op,
|
||||
SlapReply *rs
|
||||
)
|
||||
{
|
||||
slap_overinst *on = op->o_callback->sc_private;
|
||||
autoca_info *ai = on->on_bi.bi_private;
|
||||
Attribute *a;
|
||||
int isusr = 0;
|
||||
|
||||
if (rs->sr_type != REP_SEARCH)
|
||||
return SLAP_CB_CONTINUE;
|
||||
|
||||
/* If root or self */
|
||||
if ( !be_isroot( op ) &&
|
||||
!dn_match( &rs->sr_entry->e_nname, &op->o_ndn ))
|
||||
return SLAP_CB_CONTINUE;
|
||||
|
||||
isusr = is_entry_objectclass( rs->sr_entry, ai->ai_usrclass, SLAP_OCF_CHECK_SUP );
|
||||
if ( !isusr )
|
||||
{
|
||||
if (!is_entry_objectclass( rs->sr_entry, ai->ai_srvclass, SLAP_OCF_CHECK_SUP ))
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
a = attr_find( rs->sr_entry->e_attrs, ad_usrPkey );
|
||||
if ( !a )
|
||||
{
|
||||
Operation op2;
|
||||
genargs args;
|
||||
saveargs arg2;
|
||||
myext extras[2];
|
||||
int rc;
|
||||
|
||||
args.issuer_cert = ai->ai_cert;
|
||||
args.issuer_pkey = ai->ai_pkey;
|
||||
args.subjectDN = &rs->sr_entry->e_name;
|
||||
args.more_exts = NULL;
|
||||
if ( isusr )
|
||||
{
|
||||
args.cert_exts = usrExts;
|
||||
args.keybits = ai->ai_usrkeybits;
|
||||
args.days = ai->ai_usrdays;
|
||||
a = attr_find( rs->sr_entry->e_attrs, ad_mail );
|
||||
if ( a )
|
||||
{
|
||||
extras[0].name = "subjectAltName";
|
||||
extras[1].name = NULL;
|
||||
extras[0].value = op->o_tmpalloc( sizeof("email:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
|
||||
sprintf(extras[0].value, "email:%s", a->a_vals[0].bv_val);
|
||||
args.more_exts = extras;
|
||||
}
|
||||
} else
|
||||
{
|
||||
args.cert_exts = srvExts;
|
||||
args.keybits = ai->ai_srvkeybits;
|
||||
args.days = ai->ai_srvdays;
|
||||
if ( ad_ipaddr && (a = attr_find( rs->sr_entry->e_attrs, ad_ipaddr )))
|
||||
{
|
||||
extras[0].name = "subjectAltName";
|
||||
extras[1].name = NULL;
|
||||
extras[0].value = op->o_tmpalloc( sizeof("IP:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
|
||||
sprintf(extras[0].value, "IP:%s", a->a_vals[0].bv_val);
|
||||
args.more_exts = extras;
|
||||
}
|
||||
}
|
||||
rc = autoca_gencert( op, &args );
|
||||
if ( rc )
|
||||
return SLAP_CB_CONTINUE;
|
||||
X509_free( args.newcert );
|
||||
EVP_PKEY_free( args.newpkey );
|
||||
|
||||
if ( is_entry_objectclass( rs->sr_entry, oc_usrObj, 0 ))
|
||||
arg2.oc = NULL;
|
||||
else
|
||||
arg2.oc = oc_usrObj;
|
||||
arg2.dercert = &args.dercert;
|
||||
arg2.derpkey = &args.derpkey;
|
||||
arg2.on = on;
|
||||
arg2.dn = &rs->sr_entry->e_name;
|
||||
arg2.ndn = &rs->sr_entry->e_nname;
|
||||
arg2.isca = 0;
|
||||
op2 = *op;
|
||||
rc = autoca_savecert( &op2, &arg2 );
|
||||
if ( !rc )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
|
||||
op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
autoca_op_search(
|
||||
Operation *op,
|
||||
SlapReply *rs
|
||||
)
|
||||
{
|
||||
/* we only act on a search that returns just our cert/key attrs */
|
||||
if ( 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 )
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
||||
slap_callback *sc = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
|
||||
sc->sc_response = autoca_op_response;
|
||||
sc->sc_private = on;
|
||||
sc->sc_next = op->o_callback;
|
||||
op->o_callback = sc;
|
||||
}
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
autoca_db_init(
|
||||
BackendDB *be,
|
||||
ConfigReply *cr
|
||||
)
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *) be->bd_info;
|
||||
autoca_info *ai;
|
||||
|
||||
ai = ch_calloc(1, sizeof(autoca_info));
|
||||
on->on_bi.bi_private = ai;
|
||||
|
||||
/* set defaults */
|
||||
ai->ai_usrclass = oc_find( "person" );
|
||||
ai->ai_srvclass = oc_find( "ipHost" );
|
||||
ai->ai_usrkeybits = KEYBITS;
|
||||
ai->ai_srvkeybits = KEYBITS;
|
||||
ai->ai_cakeybits = KEYBITS;
|
||||
ai->ai_usrdays = 365; /* 1 year */
|
||||
ai->ai_srvdays = 1826; /* 5 years */
|
||||
ai->ai_cadays = 3652; /* 10 years */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
autoca_db_destroy(
|
||||
BackendDB *be,
|
||||
ConfigReply *cr
|
||||
)
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *) be->bd_info;
|
||||
autoca_info *ai = on->on_bi.bi_private;
|
||||
|
||||
if ( ai->ai_cert )
|
||||
X509_free( ai->ai_cert );
|
||||
if ( ai->ai_pkey )
|
||||
EVP_PKEY_free( ai->ai_pkey );
|
||||
ch_free( ai );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
autoca_db_open(
|
||||
BackendDB *be,
|
||||
ConfigReply *cr
|
||||
)
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *)be->bd_info;
|
||||
autoca_info *ai = on->on_bi.bi_private;
|
||||
|
||||
Connection conn = { 0 };
|
||||
OperationBuffer opbuf;
|
||||
Operation *op;
|
||||
void *thrctx;
|
||||
Entry *e;
|
||||
Attribute *a;
|
||||
int rc;
|
||||
|
||||
if (slapMode & SLAP_TOOL_MODE)
|
||||
return 0;
|
||||
|
||||
thrctx = ldap_pvt_thread_pool_context();
|
||||
connection_fake_init2( &conn, &opbuf, thrctx, 0 );
|
||||
op = &opbuf.ob_op;
|
||||
op->o_bd = be;
|
||||
op->o_dn = be->be_rootdn;
|
||||
op->o_ndn = be->be_rootndn;
|
||||
rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL,
|
||||
NULL, 0, &e, on );
|
||||
|
||||
if ( e ) {
|
||||
int gotoc = 0, gotat = 0;
|
||||
if ( is_entry_objectclass( e, oc_caObj, 0 )) {
|
||||
gotoc = 1;
|
||||
a = attr_find( e->e_attrs, ad_caPkey );
|
||||
if ( a ) {
|
||||
const unsigned char *pp;
|
||||
pp = 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;
|
||||
ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
|
||||
}
|
||||
}
|
||||
gotat = 1;
|
||||
}
|
||||
}
|
||||
overlay_entry_release_ov( op, e, 0, on );
|
||||
/* generate attrs, store... */
|
||||
if ( !gotat ) {
|
||||
genargs args;
|
||||
saveargs arg2;
|
||||
|
||||
args.issuer_cert = NULL;
|
||||
args.issuer_pkey = NULL;
|
||||
args.subjectDN = &be->be_suffix[0];
|
||||
args.cert_exts = CAexts;
|
||||
args.more_exts = NULL;
|
||||
args.keybits = ai->ai_cakeybits;
|
||||
args.days = ai->ai_cadays;
|
||||
|
||||
rc = autoca_gencert( op, &args );
|
||||
if ( rc )
|
||||
return -1;
|
||||
|
||||
ai->ai_cert = args.newcert;
|
||||
ai->ai_pkey = args.newpkey;
|
||||
|
||||
arg2.dn = be->be_suffix;
|
||||
arg2.ndn = be->be_nsuffix;
|
||||
arg2.isca = 1;
|
||||
if ( !gotoc )
|
||||
arg2.oc = oc_caObj;
|
||||
else
|
||||
arg2.oc = NULL;
|
||||
arg2.on = on;
|
||||
arg2.dercert = &args.dercert;
|
||||
arg2.derpkey = &args.derpkey;
|
||||
|
||||
autoca_savecert( op, &arg2 );
|
||||
op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
|
||||
op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static slap_overinst autoca;
|
||||
|
||||
/* This overlay is set up for dynamic loading via moduleload. For static
|
||||
* configuration, you'll need to arrange for the slap_overinst to be
|
||||
* initialized and registered by some other function inside slapd.
|
||||
*/
|
||||
|
||||
int autoca_initialize() {
|
||||
int i, code;
|
||||
const char *text;
|
||||
|
||||
autoca.on_bi.bi_type = "autoca";
|
||||
autoca.on_bi.bi_db_init = autoca_db_init;
|
||||
autoca.on_bi.bi_db_destroy = autoca_db_destroy;
|
||||
autoca.on_bi.bi_db_open = autoca_db_open;
|
||||
autoca.on_bi.bi_op_search = autoca_op_search;
|
||||
|
||||
autoca.on_bi.bi_cf_ocs = autoca_ocs;
|
||||
code = config_register_schema( autoca_cfg, autoca_ocs );
|
||||
if ( code ) return code;
|
||||
|
||||
code = register_syntax( &aca_syntax );
|
||||
if ( code ) return code;
|
||||
|
||||
code = register_matching_rule( &aca_mrule );
|
||||
if ( code ) return code;
|
||||
|
||||
for ( i=0; aca_attrs[i]; i++ ) {
|
||||
code = register_at( aca_attrs[i], NULL, 0 );
|
||||
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 );
|
||||
}
|
||||
|
||||
#if SLAPD_OVER_AUTOCA == SLAPD_MOD_DYNAMIC
|
||||
int
|
||||
init_module( int argc, char *argv[] )
|
||||
{
|
||||
return autoca_initialize();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(SLAPD_OVER_AUTOCA) */
|
||||
Loading…
Reference in a new issue