static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname) { shl_t ptr; void *sym; if ((dso == NULL) || (symname == NULL)) { DSOerr(DSO_F_DL_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER); return (NULL); } if (sk_num(dso->meth_data) < 1) { DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_STACK_ERROR); return (NULL); } ptr = (shl_t) sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); if (ptr == NULL) { DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_NULL_HANDLE); return (NULL); } if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0) { char errbuf[160]; DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_SYM_FAILURE); if (openssl_strerror_r(errno, errbuf, sizeof(errbuf))) ERR_add_error_data(4, "symname(", symname, "): ", errbuf); return (NULL); } return ((DSO_FUNC_TYPE)sym); }
static void build_SYS_str_reasons(void) { /* OPENSSL_malloc cannot be used here, use static storage instead */ static char strerror_tab[NUM_SYS_STR_REASONS][LEN_SYS_STR_REASON]; static int init = 1; int i; CRYPTO_THREAD_write_lock(err_string_lock); if (!init) { CRYPTO_THREAD_unlock(err_string_lock); return; } for (i = 1; i <= NUM_SYS_STR_REASONS; i++) { ERR_STRING_DATA *str = &SYS_str_reasons[i - 1]; str->error = (unsigned long)i; if (str->string == NULL) { char (*dest)[LEN_SYS_STR_REASON] = &(strerror_tab[i - 1]); if (openssl_strerror_r(i, *dest, sizeof(*dest))) str->string = *dest; } if (str->string == NULL) str->string = "unknown"; } /* * Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL}, as * required by ERR_load_strings. */ init = 0; CRYPTO_THREAD_unlock(err_string_lock); }
static void build_SYS_str_reasons(void) { /* OPENSSL_malloc cannot be used here, use static storage instead */ static char strerror_pool[SPACE_SYS_STR_REASONS]; char *cur = strerror_pool; size_t cnt = 0; static int init = 1; int i; int saveerrno = get_last_sys_error(); CRYPTO_THREAD_write_lock(err_string_lock); if (!init) { CRYPTO_THREAD_unlock(err_string_lock); return; } for (i = 1; i <= NUM_SYS_STR_REASONS; i++) { ERR_STRING_DATA *str = &SYS_str_reasons[i - 1]; str->error = ERR_PACK(ERR_LIB_SYS, 0, i); if (str->string == NULL) { if (openssl_strerror_r(i, cur, sizeof(strerror_pool) - cnt)) { size_t l = strlen(cur); str->string = cur; cnt += l; if (cnt > sizeof(strerror_pool)) cnt = sizeof(strerror_pool); cur += l; /* * VMS has an unusual quirk of adding spaces at the end of * some (most? all?) messages. Lets trim them off. */ while (ossl_isspace(cur[-1])) { cur--; cnt--; } *cur++ = '\0'; cnt++; } } if (str->string == NULL) str->string = "unknown"; } /* * Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL}, as * required by ERR_load_strings. */ init = 0; CRYPTO_THREAD_unlock(err_string_lock); /* openssl_strerror_r could change errno, but we want to preserve it */ set_sys_error(saveerrno); err_load_strings(SYS_str_reasons); }
static int dl_load(DSO *dso) { shl_t ptr = NULL; /* * We don't do any fancy retries or anything, just take the method's (or * DSO's if it has the callback set) best translation of the * platform-independent filename and try once with that. */ char *filename = DSO_convert_filename(dso, NULL); if (filename == NULL) { DSOerr(DSO_F_DL_LOAD, DSO_R_NO_FILENAME); goto err; } ptr = shl_load(filename, BIND_IMMEDIATE | (dso->flags & DSO_FLAG_NO_NAME_TRANSLATION ? 0 : DYNAMIC_PATH), 0L); if (ptr == NULL) { char errbuf[160]; DSOerr(DSO_F_DL_LOAD, DSO_R_LOAD_FAILED); if (openssl_strerror_r(errno, errbuf, sizeof(errbuf))) ERR_add_error_data(4, "filename(", filename, "): ", errbuf); goto err; } if (!sk_push(dso->meth_data, (char *)ptr)) { DSOerr(DSO_F_DL_LOAD, DSO_R_STACK_ERROR); goto err; } /* * Success, stick the converted filename we've loaded under into the DSO * (it also serves as the indicator that we are currently loaded). */ dso->loaded_filename = filename; return (1); err: /* Cleanup! */ OPENSSL_free(filename); if (ptr != NULL) shl_unload(ptr); return (0); }
static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, const char *uri, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_LOADER_CTX *ctx = NULL; struct stat st; struct { const char *path; unsigned int check_absolute:1; } path_data[2]; size_t path_data_n = 0, i; const char *path; /* * First step, just take the URI as is. */ path_data[path_data_n].check_absolute = 0; path_data[path_data_n++].path = uri; /* * Second step, if the URI appears to start with the 'file' scheme, * extract the path and make that the second path to check. * There's a special case if the URI also contains an authority, then * the full URI shouldn't be used as a path anywhere. */ if (strncasecmp(uri, "file:", 5) == 0) { const char *p = &uri[5]; if (strncmp(&uri[5], "//", 2) == 0) { path_data_n--; /* Invalidate using the full URI */ if (strncasecmp(&uri[7], "localhost/", 10) == 0) { p = &uri[16]; } else if (uri[7] == '/') { p = &uri[7]; } else { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED); return NULL; } } path_data[path_data_n].check_absolute = 1; #ifdef _WIN32 /* Windows file: URIs with a drive letter start with a / */ if (p[0] == '/' && p[2] == ':' && p[3] == '/') { char c = ossl_tolower(p[1]); if (c >= 'a' && c <= 'z') { p++; /* We know it's absolute, so no need to check */ path_data[path_data_n].check_absolute = 0; } } #endif path_data[path_data_n++].path = p; } for (i = 0, path = NULL; path == NULL && i < path_data_n; i++) { /* * If the scheme "file" was an explicit part of the URI, the path must * be absolute. So says RFC 8089 */ if (path_data[i].check_absolute && path_data[i].path[0] != '/') { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE); ERR_add_error_data(1, path_data[i].path); return NULL; } if (stat(path_data[i].path, &st) < 0) { SYSerr(SYS_F_STAT, errno); ERR_add_error_data(1, path_data[i].path); } else { path = path_data[i].path; } } if (path == NULL) { return NULL; } /* Successfully found a working path, clear possible collected errors */ ERR_clear_error(); ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx == NULL) { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE); return NULL; } if ((st.st_mode & S_IFDIR) == S_IFDIR) { /* * Try to copy everything, even if we know that some of them must be * NULL for the moment. This prevents errors in the future, when more * components may be used. */ ctx->_.dir.uri = OPENSSL_strdup(uri); ctx->type = is_dir; if (ctx->_.dir.uri == NULL) goto err; ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path); ctx->_.dir.last_errno = errno; if (ctx->_.dir.last_entry == NULL) { if (ctx->_.dir.last_errno != 0) { char errbuf[256]; errno = ctx->_.dir.last_errno; openssl_strerror_r(errno, errbuf, sizeof(errbuf)); OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_SYS_LIB); ERR_add_error_data(1, errbuf); goto err; } ctx->_.dir.end_reached = 1; } } else { BIO *buff = NULL; char peekbuf[4096] = { 0, }; if ((buff = BIO_new(BIO_f_buffer())) == NULL || (ctx->_.file.file = BIO_new_file(path, "rb")) == NULL) { BIO_free_all(buff); goto err; } ctx->_.file.file = BIO_push(buff, ctx->_.file.file); if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf) - 1) > 0) { peekbuf[sizeof(peekbuf) - 1] = '\0'; if (strstr(peekbuf, "-----BEGIN ") != NULL) ctx->type = is_pem; } } return ctx; err: OSSL_STORE_LOADER_CTX_free(ctx); return NULL; }
static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *result = NULL; ctx->errcnt = 0; ERR_clear_error(); if (ctx->type == is_dir) { do { char *newname = NULL; if (ctx->_.dir.last_entry == NULL) { if (!ctx->_.dir.end_reached) { char errbuf[256]; assert(ctx->_.dir.last_errno != 0); errno = ctx->_.dir.last_errno; ctx->errcnt++; openssl_strerror_r(errno, errbuf, sizeof(errbuf)); OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_SYS_LIB); ERR_add_error_data(1, errbuf); } return NULL; } if (ctx->_.dir.last_entry[0] != '.' && file_name_check(ctx, ctx->_.dir.last_entry) && !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname)) return NULL; /* * On the first call (with a NULL context), OPENSSL_DIR_read() * cares about the second argument. On the following calls, it * only cares that it isn't NULL. Therefore, we can safely give * it our URI here. */ ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->_.dir.uri); ctx->_.dir.last_errno = errno; if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0) ctx->_.dir.end_reached = 1; if (newname != NULL && (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) { OPENSSL_free(newname); OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_OSSL_STORE_LIB); return NULL; } } while (result == NULL && !file_eof(ctx)); } else { int matchcount = -1; again: result = file_load_try_repeat(ctx, ui_method, ui_data); if (result != NULL) return result; if (file_eof(ctx)) return NULL; do { char *pem_name = NULL; /* PEM record name */ char *pem_header = NULL; /* PEM record header */ unsigned char *data = NULL; /* DER encoded data */ long len = 0; /* DER encoded data length */ matchcount = -1; if (ctx->type == is_pem) { if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header, &data, &len, ui_method, ui_data, (ctx->flags & FILE_FLAG_SECMEM) != 0)) { ctx->errcnt++; goto endloop; } } else { if (!file_read_asn1(ctx->_.file.file, &data, &len)) { ctx->errcnt++; goto endloop; } } result = file_load_try_decode(ctx, pem_name, pem_header, data, len, ui_method, ui_data, &matchcount); if (result != NULL) goto endloop; /* * If a PEM name matches more than one handler, the handlers are * badly coded. */ if (!ossl_assert(pem_name == NULL || matchcount <= 1)) { ctx->errcnt++; goto endloop; } if (matchcount > 1) { OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE); } else if (matchcount == 1) { /* * If there are other errors on the stack, they already show * what the problem is. */ if (ERR_peek_error() == 0) { OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE); if (pem_name != NULL) ERR_add_error_data(3, "PEM type is '", pem_name, "'"); } } if (matchcount > 0) ctx->errcnt++; endloop: pem_free_flag(pem_name, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0); pem_free_flag(pem_header, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0); pem_free_flag(data, (ctx->flags & FILE_FLAG_SECMEM) != 0, len); } while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx)); /* We bail out on ambiguity */ if (matchcount > 1) return NULL; if (result != NULL && ctx->expected_type != 0 && ctx->expected_type != OSSL_STORE_INFO_get_type(result)) { OSSL_STORE_INFO_free(result); goto again; } } return result; }