static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
	     X509_OBJECT *ret)
	{
	BY_DIR *ctx;
	union	{
		struct	{
			X509 st_x509;
			X509_CINF st_x509_cinf;
			} x509;
		struct	{
			X509_CRL st_crl;
			X509_CRL_INFO st_crl_info;
			} crl;
		} data;
	int ok=0;
	int i,j,k;
	unsigned long h;
	BUF_MEM *b=NULL;
	struct stat st;
	X509_OBJECT stmp,*tmp;
	const char *postfix="";

	if (name == NULL) return(0);

	stmp.type=type;
	if (type == X509_LU_X509)
		{
		data.x509.st_x509.cert_info= &data.x509.st_x509_cinf;
		data.x509.st_x509_cinf.subject=name;
		stmp.data.x509= &data.x509.st_x509;
		postfix="";
		}
	else if (type == X509_LU_CRL)
		{
		data.crl.st_crl.crl= &data.crl.st_crl_info;
		data.crl.st_crl_info.issuer=name;
		stmp.data.crl= &data.crl.st_crl;
		postfix="r";
		}
	else
		{
		X509err(X509_F_GET_CERT_BY_SUBJECT,X509_R_WRONG_LOOKUP_TYPE);
		goto finish;
		}

	if ((b=BUF_MEM_new()) == NULL)
		{
		X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_BUF_LIB);
		goto finish;
		}
	
	ctx=(BY_DIR *)xl->method_data;

	h=X509_NAME_hash(name);
	for (i=0; i<ctx->num_dirs; i++)
		{
		j=strlen(ctx->dirs[i])+1+8+6+1+1;
		if (!BUF_MEM_grow(b,j))
			{
			X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_MALLOC_FAILURE);
			goto finish;
			}
		k=0;
		for (;;)
			{
			char c = '/';
#ifdef OPENSSL_SYS_VMS
			c = ctx->dirs[i][strlen(ctx->dirs[i])-1];
			if (c != ':' && c != '>' && c != ']')
				{
				/* If no separator is present, we assume the
				   directory specifier is a logical name, and
				   add a colon.  We really should use better
				   VMS routines for merging things like this,
				   but this will do for now...
				   -- Richard Levitte */
				c = ':';
				}
			else
				{
				c = '\0';
				}
#endif
			if (c == '\0')
				{
				/* This is special.  When c == '\0', no
				   directory separator should be added. */
				BIO_snprintf(b->data,b->max,
					"%s%08lx.%s%d",ctx->dirs[i],h,
					postfix,k);
				}
			else
				{
				BIO_snprintf(b->data,b->max,
					"%s%c%08lx.%s%d",ctx->dirs[i],c,h,
					postfix,k);
				}
			k++;
			if (stat(b->data,&st) < 0)
				break;
			/* found one. */
			if (type == X509_LU_X509)
				{
				if ((X509_load_cert_file(xl,b->data,
					ctx->dirs_type[i])) == 0)
					break;
				}
			else if (type == X509_LU_CRL)
				{
				if ((X509_load_crl_file(xl,b->data,
					ctx->dirs_type[i])) == 0)
					break;
				}
			/* else case will caught higher up */
			}

		/* we have added it to the cache so now pull
		 * it out again */
		CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
		j = sk_X509_OBJECT_find(xl->store_ctx->objs,&stmp);
		if(j != -1) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,j);
		else tmp = NULL;
		CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);

		if (tmp != NULL)
			{
			ok=1;
			ret->type=tmp->type;
			memcpy(&ret->data,&tmp->data,sizeof(ret->data));
			/* If we were going to up the reference count,
			 * we would need to do it on a perl 'type'
			 * basis */
	/*		CRYPTO_add(&tmp->data.x509->references,1,
				CRYPTO_LOCK_X509);*/
			goto finish;
			}
		}
finish:
	if (b != NULL) BUF_MEM_free(b);
	return(ok);
	}
Esempio n. 2
0
static int
ldaplookup_by_subject(
	X509_LOOKUP *ctx,
	int          type,
	X509_NAME   *name,
	X509_OBJECT *ret
) {
	int count = 0;
	ldaphost *lh;
	const char *attrs[2];
	char *filter = NULL;


	if (ctx == NULL) return(0);
	if (name == NULL) return(0);

	lh = (ldaphost*) ctx->method_data;
	if (lh == NULL) return(0);

	switch(type) {
	case X509_LU_X509: {
		attrs[0] = ATTR_CACERT;
		} break;
	case X509_LU_CRL: {
		attrs[0] = ATTR_CACRL;
		} break;
	default: {
		X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_WRONG_LOOKUP_TYPE);
		goto done;
		}
	}
	attrs[1] = NULL;

	filter = ldaplookup_filter(name, attrs[0]);
	if (filter == NULL) {
		X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_UNABLE_TO_GET_FILTER);
		goto done;
	}
#ifdef TRACE_BY_LDAP
fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: filter=%s\n", filter);
#endif

	for (; lh != NULL; lh = lh->next) {
		LDAPMessage *res = NULL;
		int result;

#ifdef TRACE_BY_LDAP
{
int version = -1;

ldap_get_option(lh->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject:"
" bind to \"%s://%s:%d\""
" using ldap v%d protocol\n"
, lh->ldapurl->lud_scheme, lh->ldapurl->lud_host, lh->ldapurl->lud_port
, version
);
}
#endif

		result = ldaplookup_bind_s(lh->ld);
		if (result != LDAP_SUCCESS) {
			X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_UNABLE_TO_BIND);
			{
				char	buf[1024];
				snprintf(buf, sizeof(buf),
					" url=\"%s://%s:%d\""
					" ldaperror=0x%x(%.256s)"
					, lh->ldapurl->lud_scheme, lh->ldapurl->lud_host, lh->ldapurl->lud_port
					, result, ldap_err2string(result)
				);
				ERR_add_error_data(1, buf);
			}
			continue;
		}

		result = ldaplookup_search_s(lh->ld, lh->ldapurl->lud_dn,
				LDAP_SCOPE_SUBTREE, filter, (char**)attrs, 0, &res);
		if (result != LDAP_SUCCESS) {
			X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_SEARCH_FAIL);
			ldap_msgfree(res);
			continue;
		}

		result = ldaplookup_result2store(type, name, lh->ld, res, ctx->store_ctx);
		if (result > 0) count += result;

		ldap_msgfree(res);

		/*do not call ldap_unbind_s*/
	}

#ifdef TRACE_BY_LDAP
fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: count=%d\n", count);
#endif
	if (count > 0) {
		/*
		 * we have added at least one to the cache so now pull one out again
		 */
		union {
			struct {
				X509_CINF st_x509_cinf;
				X509 st_x509;
			} x509;
			struct {
				X509_CRL_INFO st_crl_info;
				X509_CRL st_crl;
			} crl;
		} data;

		X509_OBJECT stmp, *tmp;
		int k;

		memset(&data, 0, sizeof(data));
		stmp.type = type;
		switch(type) {
		case X509_LU_X509: {
			data.x509.st_x509_cinf.subject = name;
			data.x509.st_x509.cert_info = &data.x509.st_x509_cinf;
			stmp.data.x509 = &data.x509.st_x509;
			} break;
		case X509_LU_CRL: {
			data.crl.st_crl_info.issuer = name;
			data.crl.st_crl.crl = &data.crl.st_crl_info;
			stmp.data.crl = &data.crl.st_crl;
			} break;
		default:
			count = 0;
			goto done;
		}

		CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
		k = sk_X509_OBJECT_find(ctx->store_ctx->objs, &stmp);
		if (k >= 0)
			tmp = sk_X509_OBJECT_value(ctx->store_ctx->objs, k);
		else
			tmp = NULL;
		CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
#ifdef TRACE_BY_LDAP
fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: k=%d, tmp=%p\n", k, (void*)tmp);
#endif

		if (tmp == NULL) {
			count = 0;
			goto done;
		}

		ret->type = tmp->type;
		memcpy(&ret->data, &tmp->data, sizeof(ret->data));
	}

done:
	if (filter != NULL) OPENSSL_free(filter);
	return(count > 0);
}