eng_table.c
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:9k
源码类别:

其他游戏

开发平台:

Visual C++

  1. /* ====================================================================
  2.  * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the OpenSSL Project
  19.  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
  20.  *
  21.  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    licensing@OpenSSL.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "OpenSSL"
  27.  *    nor may "OpenSSL" appear in their names without prior written
  28.  *    permission of the OpenSSL Project.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the OpenSSL Project
  33.  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This product includes cryptographic software written by Eric Young
  50.  * (eay@cryptsoft.com).  This product includes software written by Tim
  51.  * Hudson (tjh@cryptsoft.com).
  52.  *
  53.  */
  54. #include "cryptlib.h"
  55. #include <openssl/evp.h>
  56. #include <openssl/lhash.h>
  57. #include "eng_int.h"
  58. /* The type of the items in the table */
  59. typedef struct st_engine_pile
  60. {
  61. /* The 'nid' of this algorithm/mode */
  62. int nid;
  63. /* ENGINEs that implement this algorithm/mode. */
  64. STACK_OF(ENGINE) *sk;
  65. /* The default ENGINE to perform this algorithm/mode. */
  66. ENGINE *funct;
  67. /* Zero if 'sk' is newer than the cached 'funct', non-zero otherwise */
  68. int uptodate;
  69. } ENGINE_PILE;
  70. /* The type exposed in eng_int.h */
  71. struct st_engine_table
  72. {
  73. LHASH piles;
  74. }; /* ENGINE_TABLE */
  75. /* Global flags (ENGINE_TABLE_FLAG_***). */
  76. static unsigned int table_flags = 0;
  77. /* API function manipulating 'table_flags' */
  78. unsigned int ENGINE_get_table_flags(void)
  79. {
  80. return table_flags;
  81. }
  82. void ENGINE_set_table_flags(unsigned int flags)
  83. {
  84. table_flags = flags;
  85. }
  86. /* Internal functions for the "piles" hash table */
  87. static unsigned long engine_pile_hash(const ENGINE_PILE *c)
  88. {
  89. return c->nid;
  90. }
  91. static int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b)
  92. {
  93. return a->nid - b->nid;
  94. }
  95. static IMPLEMENT_LHASH_HASH_FN(engine_pile_hash, const ENGINE_PILE *)
  96. static IMPLEMENT_LHASH_COMP_FN(engine_pile_cmp, const ENGINE_PILE *)
  97. static int int_table_check(ENGINE_TABLE **t, int create)
  98. {
  99. LHASH *lh;
  100. if(*t) return 1;
  101. if(!create) return 0;
  102. if((lh = lh_new(LHASH_HASH_FN(engine_pile_hash),
  103. LHASH_COMP_FN(engine_pile_cmp))) == NULL)
  104. return 0;
  105. *t = (ENGINE_TABLE *)lh;
  106. return 1;
  107. }
  108. /* Privately exposed (via eng_int.h) functions for adding and/or removing
  109.  * ENGINEs from the implementation table */
  110. int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
  111. ENGINE *e, const int *nids, int num_nids, int setdefault)
  112. {
  113. int ret = 0, added = 0;
  114. ENGINE_PILE tmplate, *fnd;
  115. CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
  116. if(!(*table))
  117. added = 1;
  118. if(!int_table_check(table, 1))
  119. goto end;
  120. if(added)
  121. /* The cleanup callback needs to be added */
  122. engine_cleanup_add_first(cleanup);
  123. while(num_nids--)
  124. {
  125. tmplate.nid = *nids;
  126. fnd = lh_retrieve(&(*table)->piles, &tmplate);
  127. if(!fnd)
  128. {
  129. fnd = OPENSSL_malloc(sizeof(ENGINE_PILE));
  130. if(!fnd) goto end;
  131. fnd->uptodate = 0;
  132. fnd->nid = *nids;
  133. fnd->sk = sk_ENGINE_new_null();
  134. if(!fnd->sk)
  135. {
  136. OPENSSL_free(fnd);
  137. goto end;
  138. }
  139. fnd->funct = NULL;
  140. lh_insert(&(*table)->piles, fnd);
  141. }
  142. /* A registration shouldn't add duplciate entries */
  143. sk_ENGINE_delete_ptr(fnd->sk, e);
  144. /* if 'setdefault', this ENGINE goes to the head of the list */
  145. if(!sk_ENGINE_push(fnd->sk, e))
  146. goto end;
  147. /* "touch" this ENGINE_PILE */
  148. fnd->uptodate = 1;
  149. if(setdefault)
  150. {
  151. if(!engine_unlocked_init(e))
  152. {
  153. ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER,
  154. ENGINE_R_INIT_FAILED);
  155. goto end;
  156. }
  157. if(fnd->funct)
  158. engine_unlocked_finish(fnd->funct, 0);
  159. fnd->funct = e;
  160. }
  161. nids++;
  162. }
  163. ret = 1;
  164. end:
  165. CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
  166. return ret;
  167. }
  168. static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e)
  169. {
  170. int n;
  171. /* Iterate the 'c->sk' stack removing any occurance of 'e' */
  172. while((n = sk_ENGINE_find(pile->sk, e)) >= 0)
  173. {
  174. sk_ENGINE_delete(pile->sk, n);
  175. /* "touch" this ENGINE_CIPHER */
  176. pile->uptodate = 1;
  177. }
  178. if(pile->funct == e)
  179. {
  180. engine_unlocked_finish(e, 0);
  181. pile->funct = NULL;
  182. }
  183. }
  184. static IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb,ENGINE_PILE *,ENGINE *)
  185. void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
  186. {
  187. CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
  188. if(int_table_check(table, 0))
  189. lh_doall_arg(&(*table)->piles,
  190. LHASH_DOALL_ARG_FN(int_unregister_cb), e);
  191. CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
  192. }
  193. static void int_cleanup_cb(ENGINE_PILE *p)
  194. {
  195. sk_ENGINE_free(p->sk);
  196. if(p->funct)
  197. engine_unlocked_finish(p->funct, 0);
  198. OPENSSL_free(p);
  199. }
  200. static IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb,ENGINE_PILE *)
  201. void engine_table_cleanup(ENGINE_TABLE **table)
  202. {
  203. CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
  204. if(*table)
  205. {
  206. lh_doall(&(*table)->piles, LHASH_DOALL_FN(int_cleanup_cb));
  207. lh_free(&(*table)->piles);
  208. *table = NULL;
  209. }
  210. CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
  211. }
  212. /* return a functional reference for a given 'nid' */
  213. #ifndef ENGINE_TABLE_DEBUG
  214. ENGINE *engine_table_select(ENGINE_TABLE **table, int nid)
  215. #else
  216. ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, int l)
  217. #endif
  218. {
  219. ENGINE *ret = NULL;
  220. ENGINE_PILE tmplate, *fnd=NULL;
  221. int initres, loop = 0;
  222. if(!(*table))
  223. {
  224. #ifdef ENGINE_TABLE_DEBUG
  225. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
  226. "registered!n", f, l, nid);
  227. #endif
  228. return NULL;
  229. }
  230. CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
  231. /* Check again inside the lock otherwise we could race against cleanup
  232.  * operations. But don't worry about a fprintf(stderr). */
  233. if(!int_table_check(table, 0)) goto end;
  234. tmplate.nid = nid;
  235. fnd = lh_retrieve(&(*table)->piles, &tmplate);
  236. if(!fnd) goto end;
  237. if(fnd->funct && engine_unlocked_init(fnd->funct))
  238. {
  239. #ifdef ENGINE_TABLE_DEBUG
  240. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
  241. "ENGINE '%s' cachedn", f, l, nid, fnd->funct->id);
  242. #endif
  243. ret = fnd->funct;
  244. goto end;
  245. }
  246. if(fnd->uptodate)
  247. {
  248. ret = fnd->funct;
  249. goto end;
  250. }
  251. trynext:
  252. ret = sk_ENGINE_value(fnd->sk, loop++);
  253. if(!ret)
  254. {
  255. #ifdef ENGINE_TABLE_DEBUG
  256. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
  257. "registered implementations would initialisen",
  258. f, l, nid);
  259. #endif
  260. goto end;
  261. }
  262. /* Try to initialise the ENGINE? */
  263. if((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
  264. initres = engine_unlocked_init(ret);
  265. else
  266. initres = 0;
  267. if(initres)
  268. {
  269. /* Update 'funct' */
  270. if((fnd->funct != ret) && engine_unlocked_init(ret))
  271. {
  272. /* If there was a previous default we release it. */
  273. if(fnd->funct)
  274. engine_unlocked_finish(fnd->funct, 0);
  275. fnd->funct = ret;
  276. #ifdef ENGINE_TABLE_DEBUG
  277. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
  278. "setting default to '%s'n", f, l, nid, ret->id);
  279. #endif
  280. }
  281. #ifdef ENGINE_TABLE_DEBUG
  282. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
  283. "newly initialised '%s'n", f, l, nid, ret->id);
  284. #endif
  285. goto end;
  286. }
  287. goto trynext;
  288. end:
  289. /* If it failed, it is unlikely to succeed again until some future
  290.  * registrations have taken place. In all cases, we cache. */
  291. if(fnd) fnd->uptodate = 1;
  292. #ifdef ENGINE_TABLE_DEBUG
  293. if(ret)
  294. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
  295. "ENGINE '%s'n", f, l, nid, ret->id);
  296. else
  297. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
  298. "'no matching ENGINE'n", f, l, nid);
  299. #endif
  300. CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
  301. /* Whatever happened, any failed init()s are not failures in this
  302.  * context, so clear our error state. */
  303. ERR_clear_error();
  304. return ret;
  305. }