1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/* We need to use some engine deprecated APIs */
11e1051a39Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED
12e1051a39Sopenharmony_ci
13e1051a39Sopenharmony_ci#include "e_os.h"
14e1051a39Sopenharmony_ci#include "eng_local.h"
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci/*
17e1051a39Sopenharmony_ci * Initialise a engine type for use (or up its functional reference count if
18e1051a39Sopenharmony_ci * it's already in use). This version is only used internally.
19e1051a39Sopenharmony_ci */
20e1051a39Sopenharmony_ciint engine_unlocked_init(ENGINE *e)
21e1051a39Sopenharmony_ci{
22e1051a39Sopenharmony_ci    int to_return = 1;
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ci    if ((e->funct_ref == 0) && e->init)
25e1051a39Sopenharmony_ci        /*
26e1051a39Sopenharmony_ci         * This is the first functional reference and the engine requires
27e1051a39Sopenharmony_ci         * initialisation so we do it now.
28e1051a39Sopenharmony_ci         */
29e1051a39Sopenharmony_ci        to_return = e->init(e);
30e1051a39Sopenharmony_ci    if (to_return) {
31e1051a39Sopenharmony_ci        /*
32e1051a39Sopenharmony_ci         * OK, we return a functional reference which is also a structural
33e1051a39Sopenharmony_ci         * reference.
34e1051a39Sopenharmony_ci         */
35e1051a39Sopenharmony_ci        e->struct_ref++;
36e1051a39Sopenharmony_ci        e->funct_ref++;
37e1051a39Sopenharmony_ci        ENGINE_REF_PRINT(e, 0, 1);
38e1051a39Sopenharmony_ci        ENGINE_REF_PRINT(e, 1, 1);
39e1051a39Sopenharmony_ci    }
40e1051a39Sopenharmony_ci    return to_return;
41e1051a39Sopenharmony_ci}
42e1051a39Sopenharmony_ci
43e1051a39Sopenharmony_ci/*
44e1051a39Sopenharmony_ci * Free a functional reference to a engine type. This version is only used
45e1051a39Sopenharmony_ci * internally.
46e1051a39Sopenharmony_ci */
47e1051a39Sopenharmony_ciint engine_unlocked_finish(ENGINE *e, int unlock_for_handlers)
48e1051a39Sopenharmony_ci{
49e1051a39Sopenharmony_ci    int to_return = 1;
50e1051a39Sopenharmony_ci
51e1051a39Sopenharmony_ci    /*
52e1051a39Sopenharmony_ci     * Reduce the functional reference count here so if it's the terminating
53e1051a39Sopenharmony_ci     * case, we can release the lock safely and call the finish() handler
54e1051a39Sopenharmony_ci     * without risk of a race. We get a race if we leave the count until
55e1051a39Sopenharmony_ci     * after and something else is calling "finish" at the same time -
56e1051a39Sopenharmony_ci     * there's a chance that both threads will together take the count from 2
57e1051a39Sopenharmony_ci     * to 0 without either calling finish().
58e1051a39Sopenharmony_ci     */
59e1051a39Sopenharmony_ci    e->funct_ref--;
60e1051a39Sopenharmony_ci    ENGINE_REF_PRINT(e, 1, -1);
61e1051a39Sopenharmony_ci    if ((e->funct_ref == 0) && e->finish) {
62e1051a39Sopenharmony_ci        if (unlock_for_handlers)
63e1051a39Sopenharmony_ci            CRYPTO_THREAD_unlock(global_engine_lock);
64e1051a39Sopenharmony_ci        to_return = e->finish(e);
65e1051a39Sopenharmony_ci        if (unlock_for_handlers)
66e1051a39Sopenharmony_ci            if (!CRYPTO_THREAD_write_lock(global_engine_lock))
67e1051a39Sopenharmony_ci                return 0;
68e1051a39Sopenharmony_ci        if (!to_return)
69e1051a39Sopenharmony_ci            return 0;
70e1051a39Sopenharmony_ci    }
71e1051a39Sopenharmony_ci    REF_ASSERT_ISNT(e->funct_ref < 0);
72e1051a39Sopenharmony_ci    /* Release the structural reference too */
73e1051a39Sopenharmony_ci    if (!engine_free_util(e, 0)) {
74e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_FINISH_FAILED);
75e1051a39Sopenharmony_ci        return 0;
76e1051a39Sopenharmony_ci    }
77e1051a39Sopenharmony_ci    return to_return;
78e1051a39Sopenharmony_ci}
79e1051a39Sopenharmony_ci
80e1051a39Sopenharmony_ci/* The API (locked) version of "init" */
81e1051a39Sopenharmony_ciint ENGINE_init(ENGINE *e)
82e1051a39Sopenharmony_ci{
83e1051a39Sopenharmony_ci    int ret;
84e1051a39Sopenharmony_ci    if (e == NULL) {
85e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
86e1051a39Sopenharmony_ci        return 0;
87e1051a39Sopenharmony_ci    }
88e1051a39Sopenharmony_ci    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
89e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE);
90e1051a39Sopenharmony_ci        return 0;
91e1051a39Sopenharmony_ci    }
92e1051a39Sopenharmony_ci    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
93e1051a39Sopenharmony_ci        return 0;
94e1051a39Sopenharmony_ci    ret = engine_unlocked_init(e);
95e1051a39Sopenharmony_ci    CRYPTO_THREAD_unlock(global_engine_lock);
96e1051a39Sopenharmony_ci    return ret;
97e1051a39Sopenharmony_ci}
98e1051a39Sopenharmony_ci
99e1051a39Sopenharmony_ci/* The API (locked) version of "finish" */
100e1051a39Sopenharmony_ciint ENGINE_finish(ENGINE *e)
101e1051a39Sopenharmony_ci{
102e1051a39Sopenharmony_ci    int to_return = 1;
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_ci    if (e == NULL)
105e1051a39Sopenharmony_ci        return 1;
106e1051a39Sopenharmony_ci    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
107e1051a39Sopenharmony_ci        return 0;
108e1051a39Sopenharmony_ci    to_return = engine_unlocked_finish(e, 1);
109e1051a39Sopenharmony_ci    CRYPTO_THREAD_unlock(global_engine_lock);
110e1051a39Sopenharmony_ci    if (!to_return) {
111e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_FINISH_FAILED);
112e1051a39Sopenharmony_ci        return 0;
113e1051a39Sopenharmony_ci    }
114e1051a39Sopenharmony_ci    return to_return;
115e1051a39Sopenharmony_ci}
116