+int ossl_provider_activate(OSSL_PROVIDER *prov)
+{
+ if (provider_activate(prov)) {
+ CRYPTO_THREAD_write_lock(prov->store->lock);
+ prov->store->use_fallbacks = 0;
+ CRYPTO_THREAD_unlock(prov->store->lock);
+ return 1;
+ }
+
+ return 0;
+}
+
+void *ossl_provider_ctx(const OSSL_PROVIDER *prov)
+{
+ return prov->provctx;
+}
+
+
+static int provider_forall_loaded(struct provider_store_st *store,
+ int *found_activated,
+ int (*cb)(OSSL_PROVIDER *provider,
+ void *cbdata),
+ void *cbdata)
+{
+ int i;
+ int ret = 1;
+ int num_provs;
+
+ num_provs = sk_OSSL_PROVIDER_num(store->providers);
+
+ if (found_activated != NULL)
+ *found_activated = 0;
+ for (i = 0; i < num_provs; i++) {
+ OSSL_PROVIDER *prov =
+ sk_OSSL_PROVIDER_value(store->providers, i);
+
+ if (prov->flag_initialized) {
+ if (found_activated != NULL)
+ *found_activated = 1;
+ if (!(ret = cb(prov, cbdata)))
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * This function only does something once when store->use_fallbacks == 1,
+ * and then sets store->use_fallbacks = 0, so the second call and so on is
+ * effectively a no-op.
+ */
+static void provider_activate_fallbacks(struct provider_store_st *store)
+{
+ if (store->use_fallbacks) {
+ int num_provs = sk_OSSL_PROVIDER_num(store->providers);
+ int activated_fallback_count = 0;
+ int i;
+
+ for (i = 0; i < num_provs; i++) {
+ OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(store->providers, i);
+
+ /*
+ * Activated fallback providers get an extra refcount, to
+ * simulate a regular load.
+ * Note that we don't care if the activation succeeds or not,
+ * other than to maintain a correct refcount. If the activation
+ * doesn't succeed, then any future attempt to use the fallback
+ * provider will fail anyway.
+ */
+ if (prov->flag_fallback) {
+ if (ossl_provider_up_ref(prov)) {
+ if (!provider_activate(prov)) {
+ ossl_provider_free(prov);
+ } else {
+ prov->flag_activated_as_fallback = 1;
+ activated_fallback_count++;
+ }
+ }
+ }
+ }
+
+ /*
+ * We assume that all fallbacks have been added to the store before
+ * any fallback is activated.
+ * TODO: We may have to reconsider this, IF we find ourselves adding
+ * fallbacks after any previous fallback has been activated.
+ */
+ if (activated_fallback_count > 0)
+ store->use_fallbacks = 0;
+ }
+}
+
+int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
+ int (*cb)(OSSL_PROVIDER *provider,
+ void *cbdata),
+ void *cbdata)
+{
+ int ret = 1;
+ struct provider_store_st *store = get_provider_store(ctx);
+
+#ifndef FIPS_MODULE
+ /*
+ * Make sure any providers are loaded from config before we try to use
+ * them.
+ */
+ OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+#endif
+
+ if (store != NULL) {
+ CRYPTO_THREAD_read_lock(store->lock);
+
+ provider_activate_fallbacks(store);
+
+ /*
+ * Now, we sweep through all providers
+ */
+ ret = provider_forall_loaded(store, NULL, cb, cbdata);
+
+ CRYPTO_THREAD_unlock(store->lock);
+ }
+
+ return ret;
+}
+
+int ossl_provider_available(OSSL_PROVIDER *prov)
+{
+ if (prov != NULL) {
+ CRYPTO_THREAD_read_lock(prov->store->lock);
+ provider_activate_fallbacks(prov->store);
+ CRYPTO_THREAD_unlock(prov->store->lock);
+
+ return prov->flag_initialized;
+ }
+ return 0;
+}
+
+/* Setters of Provider Object data */
+int ossl_provider_set_fallback(OSSL_PROVIDER *prov)
+{
+ if (prov == NULL)
+ return 0;
+
+ prov->flag_fallback = 1;