+/*!
+ * Add a file of certs to a stack.
+ * \param stack the stack to add to.
+ * \param file the file to add from. All certs in this file that are not
+ * already in the stack will be added.
+ * \return 1 for success, 0 for failure. Note that in the case of failure some
+ * certs may have been added to \c stack.
+ */
+
+int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ const char *file)
+ {
+ BIO *in;
+ X509 *x=NULL;
+ X509_NAME *xn=NULL;
+ int ret=1;
+ int (*oldcmp)(const X509_NAME * const *a, const X509_NAME * const *b);
+
+ oldcmp=sk_X509_NAME_set_cmp_func(stack,xname_cmp);
+
+ in=BIO_new(BIO_s_file_internal());
+
+ if (in == NULL)
+ {
+ SSLerr(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BIO_read_filename(in,file))
+ goto err;
+
+ for (;;)
+ {
+ if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL)
+ break;
+ if ((xn=X509_get_subject_name(x)) == NULL) goto err;
+ xn=X509_NAME_dup(xn);
+ if (xn == NULL) goto err;
+ if (sk_X509_NAME_find(stack,xn) >= 0)
+ X509_NAME_free(xn);
+ else
+ sk_X509_NAME_push(stack,xn);
+ }
+
+ if (0)
+ {
+err:
+ ret=0;
+ }
+ if(in != NULL)
+ BIO_free(in);
+ if(x != NULL)
+ X509_free(x);
+
+ sk_X509_NAME_set_cmp_func(stack,oldcmp);
+
+ return ret;
+ }
+
+/*!
+ * Add a directory of certs to a stack.
+ * \param stack the stack to append to.
+ * \param dir the directory to append from. All files in this directory will be
+ * examined as potential certs. Any that are acceptable to
+ * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will be
+ * included.
+ * \return 1 for success, 0 for failure. Note that in the case of failure some
+ * certs may have been added to \c stack.
+ */
+
+#ifndef OPENSSL_SYS_WIN32
+#ifndef OPENSSL_SYS_VMS /* XXXX This may be fixed in the future */
+#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! */
+
+int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ const char *dir)
+ {
+ DIR *d;
+ struct dirent *dstruct;
+ int ret = 0;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_READDIR);
+ d = opendir(dir);
+
+ /* Note that a side effect is that the CAs will be sorted by name */
+ if(!d)
+ {
+ SYSerr(SYS_F_OPENDIR, get_last_sys_error());
+ ERR_add_error_data(3, "opendir('", dir, "')");
+ SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB);
+ goto err;
+ }
+
+ while((dstruct=readdir(d)))
+ {
+ char buf[1024];
+ int r;
+
+ if(strlen(dir)+strlen(dstruct->d_name)+2 > sizeof buf)
+ {
+ SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,SSL_R_PATH_TOO_LONG);
+ goto err;
+ }
+
+ r = BIO_snprintf(buf,sizeof buf,"%s/%s",dir,dstruct->d_name);
+ if (r <= 0 || r >= sizeof buf)
+ goto err;
+ if(!SSL_add_file_cert_subjects_to_stack(stack,buf))
+ goto err;
+ }
+ ret = 1;
+
+err:
+ CRYPTO_w_unlock(CRYPTO_LOCK_READDIR);
+ return ret;
+ }
+
+#endif
+#endif
+
+#else
+
+int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ const char *dir)
+ {
+ WIN32_FIND_DATA FindFileData;
+ HANDLE hFind;
+ int ret = 0;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_READDIR);
+
+ hFind = FindFirstFile(dir, &FindFileData);
+ /* Note that a side effect is that the CAs will be sorted by name */
+ if(hFind == INVALID_HANDLE_VALUE)
+ {
+ SYSerr(SYS_F_OPENDIR, get_last_sys_error());
+ ERR_add_error_data(3, "opendir('", dir, "')");
+ SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB);
+ goto err;
+ }
+
+ do
+ {
+ char buf[1024];
+ int r;
+
+ if(strlen(dir)+strlen(FindFileData.cFileName)+2 > sizeof buf)
+ {
+ SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,SSL_R_PATH_TOO_LONG);
+ goto err;
+ }
+
+ r = BIO_snprintf(buf,sizeof buf,"%s/%s",dir,FindFileData.cFileName);
+ if (r <= 0 || r >= sizeof buf)
+ goto err;
+ if(!SSL_add_file_cert_subjects_to_stack(stack,buf))
+ goto err;
+ }
+ while (FindNextFile(hFind, &FindFileData) != FALSE);
+ FindClose(hFind);
+ ret = 1;
+
+err:
+ CRYPTO_w_unlock(CRYPTO_LOCK_READDIR);
+ return ret;
+ }
+
+#endif