* https://www.openssl.org/source/license.html
*/
+#include "e_os.h"
#include <stdlib.h>
#include <string.h>
-
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/store.h>
OSSL_STORE_post_process_info_fn post_process,
void *post_process_data)
{
- const OSSL_STORE_LOADER *loader;
+ const OSSL_STORE_LOADER *loader = NULL;
OSSL_STORE_LOADER_CTX *loader_ctx = NULL;
OSSL_STORE_CTX *ctx = NULL;
- char scheme_copy[256], *p;
-
+ char scheme_copy[256], *p, *schemes[2];
+ size_t schemes_n = 0;
+ size_t i;
+
+ /*
+ * Put the file scheme first. If the uri does represent an existing file,
+ * possible device name and all, then it should be loaded. Only a failed
+ * attempt at loading a local file should have us try something else.
+ */
+ schemes[schemes_n++] = "file";
+
+ /*
+ * Now, check if we have something that looks like a scheme, and add it
+ * as a second scheme. However, also check if there's an authority start
+ * (://), because that will invalidate the previous file scheme. Also,
+ * check that this isn't actually the file scheme, as there's no point
+ * going through that one twice!
+ */
OPENSSL_strlcpy(scheme_copy, uri, sizeof(scheme_copy));
if ((p = strchr(scheme_copy, ':')) != NULL) {
- *p = '\0';
- p = scheme_copy;
- } else {
- p = "file";
+ *p++ = '\0';
+ if (strcasecmp(scheme_copy, "file") != 0) {
+ if (strncmp(p, "//", 2) == 0)
+ schemes_n--; /* Invalidate the file scheme */
+ schemes[schemes_n++] = scheme_copy;
+ }
}
- if ((loader = ossl_store_get0_loader_int(p)) == NULL
- || (loader_ctx = loader->open(loader, uri, ui_method, ui_data)) == NULL)
- goto done;
+ ERR_set_mark();
+
+ /* Try each scheme until we find one that could open the URI */
+ for (i = 0; loader_ctx == NULL && i < schemes_n; i++) {
+ if ((loader = ossl_store_get0_loader_int(schemes[i])) != NULL)
+ loader_ctx = loader->open(loader, uri, ui_method, ui_data);
+ }
+ if (loader_ctx == NULL)
+ goto err;
+
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_OPEN, ERR_R_MALLOC_FAILURE);
- goto done;
+ goto err;
}
ctx->loader = loader;
ctx->loader_ctx = loader_ctx;
- loader_ctx = NULL;
ctx->ui_method = ui_method;
ctx->ui_data = ui_data;
ctx->post_process = post_process;
ctx->post_process_data = post_process_data;
- done:
+ /*
+ * If the attempt to open with the 'file' scheme loader failed and the
+ * other scheme loader succeeded, the failure to open with the 'file'
+ * scheme loader leaves an error on the error stack. Let's remove it.
+ */
+ ERR_pop_to_mark();
+
+ return ctx;
+
+ err:
+ ERR_clear_last_mark();
if (loader_ctx != NULL) {
/*
* We ignore a returned error because we will return NULL anyway in
*/
(void)loader->close(loader_ctx);
}
- return ctx;
+ return NULL;
}
int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ...)
{
va_list args;
- int ret = 0;
+ int ret;
va_start(args, cmd);
- if (ctx->loader->ctrl != NULL)
- ret = ctx->loader->ctrl(ctx->loader_ctx, cmd, args);
+ ret = OSSL_STORE_vctrl(ctx, cmd, args);
va_end(args);
return ret;
}
+int OSSL_STORE_vctrl(OSSL_STORE_CTX *ctx, int cmd, va_list args)
+{
+ if (ctx->loader->ctrl != NULL)
+ return ctx->loader->ctrl(ctx->loader_ctx, cmd, args);
+ return 0;
+}
+
OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx)
{
OSSL_STORE_INFO *v = NULL;
again:
+ if (OSSL_STORE_eof(ctx))
+ return NULL;
+
v = ctx->loader->load(ctx->loader_ctx, ctx->ui_method, ctx->ui_data);
if (ctx->post_process != NULL && v != NULL) {
/*
* Functions to generate OSSL_STORE_INFOs, one function for each type we
- * support having in them. Along with each of them, one macro that
- * can be used to determine what types are supported.
+ * support having in them as well as a generic constructor.
*
* In all cases, ownership of the object is transfered to the OSSL_STORE_INFO
* and will therefore be freed when the OSSL_STORE_INFO is freed.