+ a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
+ if (a == NULL) {
+ CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ a->argl = argl;
+ a->argp = argp;
+ a->new_func = new_func;
+ a->dup_func = dup_func;
+ a->free_func = free_func;
+
+ if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
+ CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
+ OPENSSL_free(a);
+ goto err;
+ }
+ toret = sk_EX_CALLBACK_num(ip->meth) - 1;
+ (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
+
+ err:
+ CRYPTO_THREAD_unlock(ex_data_lock);
+ return toret;
+}
+
+/*
+ * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
+ * calling new() callbacks for each index in the class used by this variable
+ * Thread-safe by copying a class's array of "EX_CALLBACK" entries
+ * in the lock, then using them outside the lock. Note this only applies
+ * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
+ */
+int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
+{
+ int mx, i;
+ void *ptr;
+ EX_CALLBACK **storage = NULL;
+ EX_CALLBACK *stack[10];
+ EX_CALLBACKS *ip = get_and_lock(class_index);
+
+ if (ip == NULL)
+ return 0;
+
+ ad->sk = NULL;
+
+ mx = sk_EX_CALLBACK_num(ip->meth);
+ if (mx > 0) {
+ if (mx < (int)OSSL_NELEM(stack))
+ storage = stack;
+ else
+ storage = OPENSSL_malloc(sizeof(*storage) * mx);
+ if (storage != NULL)
+ for (i = 0; i < mx; i++)
+ storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
+ }
+ CRYPTO_THREAD_unlock(ex_data_lock);
+
+ if (mx > 0 && storage == NULL) {
+ CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ for (i = 0; i < mx; i++) {
+ if (storage[i] && storage[i]->new_func) {
+ ptr = CRYPTO_get_ex_data(ad, i);
+ storage[i]->new_func(obj, ptr, ad, i,
+ storage[i]->argl, storage[i]->argp);
+ }
+ }
+ if (storage != stack)
+ OPENSSL_free(storage);
+ return 1;
+}
+
+/*
+ * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
+ * for each index in the class used by this variable
+ */
+int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
+ const CRYPTO_EX_DATA *from)
+{
+ int mx, j, i;
+ char *ptr;
+ EX_CALLBACK *stack[10];
+ EX_CALLBACK **storage = NULL;
+ EX_CALLBACKS *ip;
+
+ if (from->sk == NULL)
+ /* Nothing to copy over */
+ return 1;
+ if ((ip = get_and_lock(class_index)) == NULL)
+ return 0;
+
+ mx = sk_EX_CALLBACK_num(ip->meth);
+ j = sk_void_num(from->sk);
+ if (j < mx)
+ mx = j;
+ if (mx > 0) {
+ if (mx < (int)OSSL_NELEM(stack))
+ storage = stack;
+ else
+ storage = OPENSSL_malloc(sizeof(*storage) * mx);
+ if (storage != NULL)
+ for (i = 0; i < mx; i++)
+ storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
+ }
+ CRYPTO_THREAD_unlock(ex_data_lock);
+
+ if (mx > 0 && storage == NULL) {
+ CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ for (i = 0; i < mx; i++) {
+ ptr = CRYPTO_get_ex_data(from, i);
+ if (storage[i] && storage[i]->dup_func)
+ storage[i]->dup_func(to, from, &ptr, i,
+ storage[i]->argl, storage[i]->argp);
+ CRYPTO_set_ex_data(to, i, ptr);
+ }
+ if (storage != stack)
+ OPENSSL_free(storage);
+ return 1;
+}
+
+
+/*
+ * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
+ * each index in the class used by this variable
+ */
+void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
+{
+ int mx, i;
+ EX_CALLBACKS *ip;
+ void *ptr;
+ EX_CALLBACK *stack[10];
+ EX_CALLBACK **storage = NULL;
+
+ if ((ip = get_and_lock(class_index)) == NULL)
+ return;
+
+ mx = sk_EX_CALLBACK_num(ip->meth);
+ if (mx > 0) {
+ if (mx < (int)OSSL_NELEM(stack))
+ storage = stack;
+ else
+ storage = OPENSSL_malloc(sizeof(*storage) * mx);
+ if (storage != NULL)
+ for (i = 0; i < mx; i++)
+ storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
+ }
+ CRYPTO_THREAD_unlock(ex_data_lock);
+
+ if (mx > 0 && storage == NULL) {
+ CRYPTOerr(CRYPTO_F_CRYPTO_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);
+ return;
+ }
+ for (i = 0; i < mx; i++) {
+ if (storage[i] && storage[i]->free_func) {
+ ptr = CRYPTO_get_ex_data(ad, i);
+ storage[i]->free_func(obj, ptr, ad, i,
+ storage[i]->argl, storage[i]->argp);
+ }
+ }
+
+ if (storage != stack)
+ OPENSSL_free(storage);
+ sk_void_free(ad->sk);
+ ad->sk = NULL;
+}
+
+/*
+ * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
+ * particular index in the class used by this variable
+ */
+int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
+{
+ int i;
+
+ if (ad->sk == NULL) {
+ if ((ad->sk = sk_void_new_null()) == NULL) {
+ CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+
+ for (i = sk_void_num(ad->sk); i <= idx; ++i) {
+ if (!sk_void_push(ad->sk, NULL)) {
+ CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ sk_void_set(ad->sk, idx, val);
+ return 1;
+}
+
+/*
+ * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
+ * particular index in the class used by this variable
+ */
+void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
+{
+ if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
+ return NULL;
+ return sk_void_value(ad->sk, idx);
+}