- {
- int j,len;
- int *ip;
- const char *s,*ss,*p;
- char **pp;
-
- if (dir == NULL || !*dir)
- {
- X509err(X509_F_ADD_CERT_DIR,X509_R_INVALID_DIRECTORY);
- return 0;
- }
-
- s=dir;
- p=s;
- for (;;)
- {
- if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0'))
- {
- ss=s;
- s=p+1;
- len=(int)(p-ss);
- if (len == 0) continue;
- for (j=0; j<ctx->num_dirs; j++)
- if (strncmp(ctx->dirs[j],ss,(unsigned int)len) == 0)
- continue;
- if (ctx->num_dirs_alloced < (ctx->num_dirs+1))
- {
- ctx->num_dirs_alloced+=10;
- pp=(char **)Malloc(ctx->num_dirs_alloced*
- sizeof(char *));
- ip=(int *)Malloc(ctx->num_dirs_alloced*
- sizeof(int));
- if ((pp == NULL) || (ip == NULL))
- {
- X509err(X509_F_ADD_CERT_DIR,ERR_R_MALLOC_FAILURE);
- return(0);
- }
- memcpy(pp,ctx->dirs,(ctx->num_dirs_alloced-10)*
- sizeof(char *));
- memcpy(ip,ctx->dirs_type,(ctx->num_dirs_alloced-10)*
- sizeof(int));
- if (ctx->dirs != NULL)
- Free((char *)ctx->dirs);
- if (ctx->dirs_type != NULL)
- Free((char *)ctx->dirs_type);
- ctx->dirs=pp;
- ctx->dirs_type=ip;
- }
- ctx->dirs_type[ctx->num_dirs]=type;
- ctx->dirs[ctx->num_dirs]=(char *)Malloc((unsigned int)len+1);
- if (ctx->dirs[ctx->num_dirs] == NULL) return(0);
- strncpy(ctx->dirs[ctx->num_dirs],ss,(unsigned int)len);
- ctx->dirs[ctx->num_dirs][len]='\0';
- ctx->num_dirs++;
- }
- if (*p == '\0') break;
- p++;
- }
- return(1);
- }
-
-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 (;;)
- {
- sprintf(b->data,"%s/%08lx.%s%d",ctx->dirs[i],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);
- tmp=(X509_OBJECT *)lh_retrieve(xl->store_ctx->certs,
- (char *)&stmp);
- 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);
- }
+{
+ int j;
+ size_t len;
+ const char *s, *ss, *p;
+
+ if (dir == NULL || !*dir) {
+ X509err(X509_F_ADD_CERT_DIR, X509_R_INVALID_DIRECTORY);
+ return 0;
+ }
+
+ s = dir;
+ p = s;
+ do {
+ if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0')) {
+ BY_DIR_ENTRY *ent;
+
+ ss = s;
+ s = p + 1;
+ len = p - ss;
+ if (len == 0)
+ continue;
+ for (j = 0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++) {
+ ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j);
+ if (strlen(ent->dir) == len && strncmp(ent->dir, ss, len) == 0)
+ break;
+ }
+ if (j < sk_BY_DIR_ENTRY_num(ctx->dirs))
+ continue;
+ if (ctx->dirs == NULL) {
+ ctx->dirs = sk_BY_DIR_ENTRY_new_null();
+ if (!ctx->dirs) {
+ X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ ent = OPENSSL_malloc(sizeof(*ent));
+ if (ent == NULL) {
+ X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ent->dir_type = type;
+ ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp);
+ ent->dir = OPENSSL_strndup(ss, len);
+ if (ent->dir == NULL || ent->hashes == NULL) {
+ by_dir_entry_free(ent);
+ return 0;
+ }
+ if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) {
+ by_dir_entry_free(ent);
+ X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ } while (*p++ != '\0');
+ return 1;
+}
+
+static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
+ X509_NAME *name, X509_OBJECT *ret)
+{
+ BY_DIR *ctx;
+ union {
+ X509 st_x509;
+ X509_CRL crl;
+ } data;
+ int ok = 0;
+ int i, j, k;
+ unsigned long h;
+ BUF_MEM *b = NULL;
+ X509_OBJECT stmp, *tmp;
+ const char *postfix = "";
+
+ if (name == NULL)
+ return 0;
+
+ stmp.type = type;
+ if (type == X509_LU_X509) {
+ data.st_x509.cert_info.subject = name;
+ stmp.data.x509 = &data.st_x509;
+ postfix = "";
+ } else if (type == X509_LU_CRL) {
+ data.crl.crl.issuer = name;
+ stmp.data.crl = &data.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 < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) {
+ BY_DIR_ENTRY *ent;
+ int idx;
+ BY_DIR_HASH htmp, *hent;
+
+ ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i);
+ j = strlen(ent->dir) + 1 + 8 + 6 + 1 + 1;
+ if (!BUF_MEM_grow(b, j)) {
+ X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE);
+ goto finish;
+ }
+ if (type == X509_LU_CRL && ent->hashes) {
+ htmp.hash = h;
+ CRYPTO_THREAD_read_lock(ctx->lock);
+ idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp);
+ if (idx >= 0) {
+ hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
+ k = hent->suffix;
+ } else {
+ hent = NULL;
+ k = 0;
+ }
+ CRYPTO_THREAD_unlock(ctx->lock);
+ } else {
+ k = 0;
+ hent = NULL;
+ }
+ for (;;) {
+ char c = '/';
+#ifdef OPENSSL_SYS_VMS
+ c = ent->dir[strlen(ent->dir) - 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", ent->dir, h, postfix, k);
+ } else {
+ BIO_snprintf(b->data, b->max,
+ "%s%c%08lx.%s%d", ent->dir, c, h, postfix, k);
+ }
+#ifndef OPENSSL_NO_POSIX_IO
+# ifdef _WIN32
+# define stat _stat
+# endif
+ {
+ struct stat st;
+ if (stat(b->data, &st) < 0)
+ break;
+ }
+#endif
+ /* found one. */
+ if (type == X509_LU_X509) {
+ if ((X509_load_cert_file(xl, b->data, ent->dir_type)) == 0)
+ break;
+ } else if (type == X509_LU_CRL) {
+ if ((X509_load_crl_file(xl, b->data, ent->dir_type)) == 0)
+ break;
+ }
+ /* else case will caught higher up */
+ k++;
+ }
+
+ /*
+ * we have added it to the cache so now pull it out again
+ */
+ CRYPTO_THREAD_write_lock(ctx->lock);
+ 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_THREAD_unlock(ctx->lock);
+
+ /* If a CRL, update the last file suffix added for this */
+
+ if (type == X509_LU_CRL) {
+ CRYPTO_THREAD_write_lock(ctx->lock);
+ /*
+ * Look for entry again in case another thread added an entry
+ * first.
+ */
+ if (!hent) {
+ htmp.hash = h;
+ idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp);
+ if (idx >= 0)
+ hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
+ }
+ if (hent == NULL) {
+ hent = OPENSSL_malloc(sizeof(*hent));
+ if (hent == NULL) {
+ CRYPTO_THREAD_unlock(ctx->lock);
+ X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE);
+ ok = 0;
+ goto finish;
+ }
+ hent->hash = h;
+ hent->suffix = k;
+ if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) {
+ CRYPTO_THREAD_unlock(ctx->lock);
+ OPENSSL_free(hent);
+ X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE);
+ ok = 0;
+ goto finish;
+ }
+ } else if (hent->suffix < k) {
+ hent->suffix = k;
+ }
+
+ CRYPTO_THREAD_unlock(ctx->lock);
+
+ }
+
+ if (tmp != NULL) {
+ ok = 1;
+ ret->type = tmp->type;
+ memcpy(&ret->data, &tmp->data, sizeof(ret->data));
+
+ /*
+ * Clear any errors that might have been raised processing empty
+ * or malformed files.
+ */
+ ERR_clear_error();