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