refactored credential builder

allow enumeration of matching builders
	try a second builder if the first one fails
	builder clones resources internally on demand
	caller frees added resources on failure and success
	stricter handling of non-supported build parts
This commit is contained in:
Martin Willi
2008-09-02 11:00:13 +00:00
parent 4da0116d78
commit f7c17aa15c
29 changed files with 437 additions and 376 deletions
+2 -1
View File
@@ -15,8 +15,9 @@
#include "builder.h"
ENUM(builder_part_names, BUILD_BLOB_ASN1_DER, BUILD_END,
ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_FROM_FILE",
"BUILD_AGENT_SOCKET",
"BUILD_BLOB_ASN1_DER",
"BUILD_BLOB_ASN1_PEM",
"BUILD_KEY_SIZE",
+10 -2
View File
@@ -40,6 +40,8 @@ typedef builder_t* (*builder_constructor_t)(int subtype);
enum builder_part_t {
/** path to a file containing an ASN1 blob, char* */
BUILD_FROM_FILE,
/** unix socket of a ssh/pgp agent, char* */
BUILD_AGENT_SOCKET,
/** DER encoded ASN1 blob, chunk_t */
BUILD_BLOB_ASN1_DER,
/** PEM encoded ASN1 blob, null terminated char* */
@@ -94,8 +96,8 @@ struct builder_t {
/**
* Add a part to the construct.
*
* Any added parts get owned by the builder/construct, so clone/refcount
* them if needed.
* Any added parts are cloned/refcounted by the builder implementation, a
* caller may need to free the passed ressources themself.
*
* @param part kind of part
* @param ... part specific variable argument
@@ -112,4 +114,10 @@ struct builder_t {
void* (*build)(builder_t *this);
};
/**
* Helper macro to cancel a build in a builder
*/
#define builder_cancel(builder) { (builder)->add = (void*)nop; \
(builder)->build = (void*)free; }
#endif /* BUILDER_H_ @}*/
@@ -62,31 +62,36 @@ struct entry_t {
};
/**
* Implementation of credential_factory_t.create_builder.
* type/subtype filter function for builder_enumerator
*/
static builder_t* create_builder(private_credential_factory_t *this,
credential_type_t type, int subtype)
static bool builder_filter(entry_t *data, entry_t **in, builder_t **out)
{
enumerator_t *enumerator;
entry_t *entry;
builder_t *builder = NULL;
if (data->type == (*in)->type &&
data->subtype == (*in)->subtype)
{
*out = (*in)->constructor(data->subtype);
return TRUE;
}
return FALSE;
}
/**
* Implementation of credential_factory_t.create_builder_enumerator.
*/
static enumerator_t* create_builder_enumerator(
private_credential_factory_t *this, credential_type_t type, int subtype)
{
entry_t *data = malloc_thing(entry_t);
data->type = type;
data->subtype = subtype;
this->mutex->lock(this->mutex);
enumerator = this->constructors->create_enumerator(this->constructors);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->type == type && entry->subtype == subtype)
{
builder = entry->constructor(subtype);
if (builder)
{
break;
}
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
return builder;
return enumerator_create_cleaner(
enumerator_create_filter(
this->constructors->create_enumerator(this->constructors),
(void*)builder_filter, data, free),
(void*)this->mutex->unlock, this->mutex);
}
/**
@@ -135,18 +140,19 @@ static void remove_builder(private_credential_factory_t *this,
static void* create(private_credential_factory_t *this, credential_type_t type,
int subtype, ...)
{
enumerator_t *enumerator;
builder_t *builder;
builder_part_t part;
va_list args;
void* construct = NULL;
builder = create_builder(this, type, subtype);
if (builder)
enumerator = create_builder_enumerator(this, type, subtype);
while (enumerator->enumerate(enumerator, &builder))
{
va_start(args, subtype);
while (TRUE)
{
part = va_arg(args, builder_part_t);
switch (part)
{
case BUILD_END:
@@ -167,6 +173,7 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
continue;
case BUILD_BLOB_ASN1_PEM:
case BUILD_FROM_FILE:
case BUILD_AGENT_SOCKET:
case BUILD_SIGNING_KEY:
case BUILD_PUBLIC_KEY:
case BUILD_SUBJECT:
@@ -179,105 +186,25 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
case BUILD_IETF_GROUP_ATTR:
builder->add(builder, part, va_arg(args, void*));
continue;
default:
DBG1("builder part %N not supported by factory",
builder_part_names, part);
break;
/* no default to get a compiler warning */
}
break;
}
va_end(args);
return builder->build(builder);
construct = builder->build(builder);
if (construct)
{
break;
}
}
else
enumerator->destroy(enumerator);
if (!construct)
{
DBG1("failed to create a builder for credential type %N,"
" subtype (%d)", credential_type_names, type, subtype);
" subtype (%d)", credential_type_names, type, subtype);
}
/** shredder all data on failure */
va_start(args, subtype);
while (TRUE)
{
part = va_arg(args, builder_part_t);
switch (part)
{
case BUILD_END:
break;
case BUILD_BLOB_ASN1_DER:
{
chunk_t chunk = va_arg(args, chunk_t);
free(chunk.ptr);
continue;
}
case BUILD_SERIAL:
{
va_arg(args, chunk_t);
continue;
}
case BUILD_X509_FLAG:
{
va_arg(args, x509_flag_t);
continue;
}
case BUILD_KEY_SIZE:
{
va_arg(args, u_int);
continue;
}
case BUILD_NOT_BEFORE_TIME:
case BUILD_NOT_AFTER_TIME:
{
va_arg(args, time_t);
continue;
}
case BUILD_SIGNING_KEY:
{
private_key_t *private = va_arg(args, private_key_t*);
private->destroy(private);
continue;
}
case BUILD_PUBLIC_KEY:
{
public_key_t *public = va_arg(args, public_key_t*);
public->destroy(public);
continue;
}
case BUILD_SUBJECT:
case BUILD_SUBJECT_ALTNAME:
case BUILD_ISSUER:
case BUILD_ISSUER_ALTNAME:
{
identification_t *id = va_arg(args, identification_t*);
id->destroy(id);
continue;
}
case BUILD_SIGNING_CERT:
case BUILD_CA_CERT:
case BUILD_CERT:
{
certificate_t *cert = va_arg(args, certificate_t*);
cert->destroy(cert);
continue;
}
case BUILD_BLOB_ASN1_PEM:
case BUILD_FROM_FILE:
case BUILD_IETF_GROUP_ATTR:
{
va_arg(args, void*);
continue;
}
default:
DBG1("builder part %N not supported by factory",
builder_part_names, part);
continue;
}
break;
}
va_end(args);
return NULL;
return construct;
}
/**
@@ -298,7 +225,7 @@ credential_factory_t *credential_factory_create()
private_credential_factory_t *this = malloc_thing(private_credential_factory_t);
this->public.create = (void*(*)(credential_factory_t*, credential_type_t type, int subtype, ...))create;
this->public.create_builder = (builder_t*(*)(credential_factory_t*, credential_type_t type, int subtype))create_builder;
this->public.create_builder_enumerator = (enumerator_t*(*)(credential_factory_t*, credential_type_t type, int subtype))create_builder_enumerator;
this->public.add_builder = (void(*)(credential_factory_t*,credential_type_t type, int subtype, builder_constructor_t constructor))add_builder;
this->public.remove_builder = (void(*)(credential_factory_t*,builder_constructor_t constructor))remove_builder;
this->public.destroy = (void(*)(credential_factory_t*))destroy;
@@ -56,6 +56,9 @@ struct credential_factory_t {
*
* The variable argument list takes builder_part_t types followed
* by the type specific value. The list must be terminated using BUILD_END.
* All passed parts get cloned/refcounted by the builder implementations,
* so free up allocated ressources after successful and unsuccessful
* invocations.
*
* @param type credential type to build
* @param subtype subtype specific for type of the credential
@@ -66,14 +69,18 @@ struct credential_factory_t {
int subtype, ...);
/**
* Create a builder instance to build credentials.
* Create an enumerator for a builder type.
*
* The build() method has to be called on each enumerated builder to
* cleanup associated ressources.
*
* @param type type of credentials the builder creates
* @param subtype type specific subtype, such as certificate_type_t
* @return builder instance
* @return enumerator over builder_t
*/
builder_t* (*create_builder)(credential_factory_t *this,
credential_type_t type, int subtype);
enumerator_t* (*create_builder_enumerator)(credential_factory_t *this,
credential_type_t type, int subtype);
/**
* Register a builder_t constructor function.
*