Move the registration of callback functions to special functions
designed for that.  This removes the potential error to mix data and
function pointers.

Please note that I'm a little unsure how incorrect calls to the old
ctrl functions should be handled, in som cases.  I currently return 0
and that's it, but it may be more correct to generate a genuine error
in those cases.
diff --git a/crypto/bio/bf_buff.c b/crypto/bio/bf_buff.c
index acd8148..ff0c907 100644
--- a/crypto/bio/bf_buff.c
+++ b/crypto/bio/bf_buff.c
@@ -69,6 +69,7 @@
 static long buffer_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int buffer_new(BIO *h);
 static int buffer_free(BIO *data);
+static long buffer_callback_ctrl(BIO *h,int cmd, void (*fp)());
 #define DEFAULT_BUFFER_SIZE	1024
 
 static BIO_METHOD methods_buffer=
@@ -82,6 +83,7 @@
 	buffer_ctrl,
 	buffer_new,
 	buffer_free,
+	buffer_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_buffer(void)
@@ -284,6 +286,7 @@
 		ctx->ibuf_len=0;
 		ctx->obuf_off=0;
 		ctx->obuf_len=0;
+		if (b->next_bio == NULL) return(0);
 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 		break;
 	case BIO_CTRL_INFO:
@@ -300,12 +303,18 @@
 	case BIO_CTRL_WPENDING:
 		ret=(long)ctx->obuf_len;
 		if (ret == 0)
+			{
+			if (b->next_bio == NULL) return(0);
 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+			}
 		break;
 	case BIO_CTRL_PENDING:
 		ret=(long)ctx->ibuf_len;
 		if (ret == 0)
+			{
+			if (b->next_bio == NULL) return(0);
 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+			}
 		break;
 	case BIO_C_SET_BUFF_READ_DATA:
 		if (num > ctx->ibuf_size)
@@ -374,12 +383,14 @@
 			}
 		break;
 	case BIO_C_DO_STATE_MACHINE:
+		if (b->next_bio == NULL) return(0);
 		BIO_clear_retry_flags(b);
 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 		BIO_copy_next_retry(b);
 		break;
 
 	case BIO_CTRL_FLUSH:
+		if (b->next_bio == NULL) return(0);
 		if (ctx->obuf_len <= 0)
 			{
 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
@@ -418,6 +429,7 @@
 			ret=0;
 		break;
 	default:
+		if (b->next_bio == NULL) return(0);
 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 		break;
 		}
@@ -427,6 +439,20 @@
 	return(0);
 	}
 
+static long buffer_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	long ret=1;
+
+	if (b->next_bio == NULL) return(0);
+	switch (cmd)
+		{
+	default:
+		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
 static int buffer_gets(BIO *b, char *buf, int size)
 	{
 	BIO_F_BUFFER_CTX *ctx;
diff --git a/crypto/bio/bf_nbio.c b/crypto/bio/bf_nbio.c
index a525e79..5e574b7 100644
--- a/crypto/bio/bf_nbio.c
+++ b/crypto/bio/bf_nbio.c
@@ -73,6 +73,7 @@
 static long nbiof_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int nbiof_new(BIO *h);
 static int nbiof_free(BIO *data);
+static long nbiof_callback_ctrl(BIO *h,int cmd,void (*fp)());
 typedef struct nbio_test_st
 	{
 	/* only set if we sent a 'should retry' error */
@@ -91,6 +92,7 @@
 	nbiof_ctrl,
 	nbiof_new,
 	nbiof_free,
+	nbiof_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_nbio_test(void)
@@ -224,6 +226,20 @@
 	return(ret);
 	}
 
+static long nbiof_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	long ret=1;
+
+	if (b->next_bio == NULL) return(0);
+	switch (cmd)
+		{
+	default:
+		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
 static int nbiof_gets(BIO *bp, char *buf, int size)
 	{
 	if (bp->next_bio == NULL) return(0);
diff --git a/crypto/bio/bf_null.c b/crypto/bio/bf_null.c
index 3254a55..0d183a6 100644
--- a/crypto/bio/bf_null.c
+++ b/crypto/bio/bf_null.c
@@ -72,6 +72,7 @@
 static long nullf_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int nullf_new(BIO *h);
 static int nullf_free(BIO *data);
+static long nullf_callback_ctrl(BIO *h,int cmd,void (*fp)());
 static BIO_METHOD methods_nullf=
 	{
 	BIO_TYPE_NULL_FILTER,
@@ -83,6 +84,7 @@
 	nullf_ctrl,
 	nullf_new,
 	nullf_free,
+	nullf_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_null(void)
@@ -152,6 +154,20 @@
 	return(ret);
 	}
 
+static long nullf_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	long ret=1;
+
+	if (b->next_bio == NULL) return(0);
+	switch (cmd)
+		{
+	default:
+		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
 static int nullf_gets(BIO *bp, char *buf, int size)
 	{
 	if (bp->next_bio == NULL) return(0);
diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h
index 30fdb4a..8842a11 100644
--- a/crypto/bio/bio.h
+++ b/crypto/bio/bio.h
@@ -219,6 +219,7 @@
 	long (*ctrl)();
 	int (*create)();
 	int (*destroy)();
+	long (*callback_ctrl)();
 	} BIO_METHOD;
 #else
 typedef struct bio_method_st
@@ -232,6 +233,7 @@
 	long (_far *ctrl)();
 	int (_far *create)();
 	int (_far *destroy)();
+	long (_fat *callback_ctrl)();
 	} BIO_METHOD;
 #endif
 
@@ -373,7 +375,7 @@
 /* BIO_set_nbio(b,n) */
 #define BIO_set_filter_bio(b,s) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,2,(char *)(s))
 /* BIO *BIO_get_filter_bio(BIO *bio); */
-#define BIO_set_proxy_cb(b,cb) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,3,(char *)(cb))
+#define BIO_set_proxy_cb(b,cb) BIO_callback_ctrl(b,BIO_C_SET_PROXY_PARAM,3,(void *(*cb)()))
 #define BIO_set_proxy_header(b,sk) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,4,(char *)sk)
 #define BIO_set_no_connect_return(b,bool) BIO_int_ctrl(b,BIO_C_SET_PROXY_PARAM,5,bool)
 
@@ -452,8 +454,8 @@
 size_t BIO_ctrl_pending(BIO *b);
 size_t BIO_ctrl_wpending(BIO *b);
 #define BIO_flush(b)		(int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL)
-#define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0,(char *)cbp)
-#define BIO_set_info_callback(b,cb) (int)BIO_ctrl(b,BIO_CTRL_SET_CALLBACK,0,(char *)cb)
+#define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0,(void (**)())(cbp))
+#define BIO_set_info_callback(b,cb) (int)BIO_callback_ctrl(b,BIO_CTRL_SET_CALLBACK,(void (*)())(cb))
 
 /* For the BIO_f_buffer() type */
 #define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL)
@@ -508,6 +510,7 @@
 int	BIO_write(BIO *b, const char *data, int len);
 int	BIO_puts(BIO *bp,const char *buf);
 long	BIO_ctrl(BIO *bp,int cmd,long larg,void *parg);
+long	BIO_callback_ctrl(BIO *bp,int cmd,void (*fp)());
 char *	BIO_ptr_ctrl(BIO *bp,int cmd,long larg);
 long	BIO_int_ctrl(BIO *bp,int cmd,long larg,int iarg);
 BIO *	BIO_push(BIO *b,BIO *append);
diff --git a/crypto/bio/bio_lib.c b/crypto/bio/bio_lib.c
index ae225da..cf8e615 100644
--- a/crypto/bio/bio_lib.c
+++ b/crypto/bio/bio_lib.c
@@ -317,16 +317,43 @@
 	return(ret);
 	}
 
+long BIO_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	long ret;
+	long (*cb)();
+
+	if (b == NULL) return(0);
+
+	if ((b->method == NULL) || (b->method->callback_ctrl == NULL))
+		{
+		BIOerr(BIO_F_BIO_CTRL,BIO_R_UNSUPPORTED_METHOD);
+		return(-2);
+		}
+
+	cb=b->callback;
+
+	if ((cb != NULL) &&
+		((ret=cb(b,BIO_CB_CTRL,(void *)&fp,cmd,0,1L)) <= 0))
+		return(ret);
+
+	ret=b->method->callback_ctrl(b,cmd,fp);
+
+	if (cb != NULL)
+		ret=cb(b,BIO_CB_CTRL|BIO_CB_RETURN,(void *)&fp,cmd,
+			0,ret);
+	return(ret);
+	}
+
 /* It is unfortunate to duplicate in functions what the BIO_(w)pending macros
  * do; but those macros have inappropriate return type, and for interfacing
  * from other programming languages, C macros aren't much of a help anyway. */
 size_t BIO_ctrl_pending(BIO *bio)
-    {
+	{
 	return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL);
 	}
 
 size_t BIO_ctrl_wpending(BIO *bio)
-    {
+	{
 	return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL);
 	}
 
diff --git a/crypto/bio/bss_acpt.c b/crypto/bio/bss_acpt.c
index 47af80f..9afa636 100644
--- a/crypto/bio/bss_acpt.c
+++ b/crypto/bio/bss_acpt.c
@@ -118,6 +118,7 @@
 	acpt_ctrl,
 	acpt_new,
 	acpt_free,
+	NULL,
 	};
 
 BIO_METHOD *BIO_s_accept(void)
diff --git a/crypto/bio/bss_bio.c b/crypto/bio/bss_bio.c
index 36c89cc..0d0f935 100644
--- a/crypto/bio/bss_bio.c
+++ b/crypto/bio/bss_bio.c
@@ -41,7 +41,8 @@
 	NULL /* no bio_gets */,
 	bio_ctrl,
 	bio_new,
-	bio_free
+	bio_free,
+	NULL /* no bio_callback_ctrl */
 };
 
 BIO_METHOD *BIO_s_bio(void)
diff --git a/crypto/bio/bss_conn.c b/crypto/bio/bss_conn.c
index 6deee1a..22d00b3 100644
--- a/crypto/bio/bss_conn.c
+++ b/crypto/bio/bss_conn.c
@@ -98,18 +98,13 @@
 	int (*info_callback)();
 	} BIO_CONNECT;
 
-union int_fn_to_char_u
-	{
-	char *char_p;
-	int (*fn_p)();
-	};
-
 static int conn_write(BIO *h,char *buf,int num);
 static int conn_read(BIO *h,char *buf,int size);
 static int conn_puts(BIO *h,char *str);
 static long conn_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int conn_new(BIO *h);
 static int conn_free(BIO *data);
+static long conn_callback_ctrl(BIO *h,int cmd,void *(*fp)());
 
 static int conn_state(BIO *b, BIO_CONNECT *c);
 static void conn_close_socket(BIO *data);
@@ -127,6 +122,7 @@
 	conn_ctrl,
 	conn_new,
 	conn_free,
+	conn_callback_ctrl,
 	};
 
 static int conn_state(BIO *b, BIO_CONNECT *c)
@@ -571,24 +567,23 @@
 		break;
 	case BIO_CTRL_DUP:
 		{
-		union int_fn_to_char_u tmp_cb;
-		
 		dbio=(BIO *)ptr;
 		if (data->param_port)
 			BIO_set_conn_port(dbio,data->param_port);
 		if (data->param_hostname)
 			BIO_set_conn_hostname(dbio,data->param_hostname);
 		BIO_set_nbio(dbio,data->nbio);
-		tmp_cb.fn_p=data->info_callback;
-		(void)BIO_set_info_callback(dbio,tmp_cb.char_p);
+		(void)BIO_set_info_callback(dbio,(void *(*)())(data->info_callback));
 		}
 		break;
 	case BIO_CTRL_SET_CALLBACK:
 		{
-		union int_fn_to_char_u tmp_cb;
-		
-		tmp_cb.char_p=ptr;
-		data->info_callback=tmp_cb.fn_p;
+#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
+		BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		ret = -1;
+#else
+		ret=0;
+#endif
 		}
 		break;
 	case BIO_CTRL_GET_CALLBACK:
@@ -606,6 +601,27 @@
 	return(ret);
 	}
 
+static long conn_callback_ctrl(BIO *b, int cmd, void *(*fp)())
+	{
+	long ret=1;
+	BIO_CONNECT *data;
+
+	data=(BIO_CONNECT *)b->ptr;
+
+	switch (cmd)
+		{
+	case BIO_CTRL_SET_CALLBACK:
+		{
+		data->info_callback=(int (*)())fp;
+		}
+		break;
+	default:
+		ret=0;
+		break;
+		}
+	return(ret);
+	}
+
 static int conn_puts(BIO *bp, char *str)
 	{
 	int n,ret;
diff --git a/crypto/bio/bss_file.c b/crypto/bio/bss_file.c
index 2a113cb..0d44dc3 100644
--- a/crypto/bio/bss_file.c
+++ b/crypto/bio/bss_file.c
@@ -91,6 +91,7 @@
 	file_ctrl,
 	file_new,
 	file_free,
+	NULL,
 	};
 
 BIO *BIO_new_file(const char *filename, const char *mode)
diff --git a/crypto/bio/bss_log.c b/crypto/bio/bss_log.c
index b52fbe1..4308b19 100644
--- a/crypto/bio/bss_log.c
+++ b/crypto/bio/bss_log.c
@@ -100,6 +100,7 @@
 	slg_ctrl,
 	slg_new,
 	slg_free,
+	NULL,
 	};
 
 BIO_METHOD *BIO_s_log(void)
diff --git a/crypto/bio/bss_mem.c b/crypto/bio/bss_mem.c
index d9a2280..41eab92 100644
--- a/crypto/bio/bss_mem.c
+++ b/crypto/bio/bss_mem.c
@@ -79,6 +79,7 @@
 	mem_ctrl,
 	mem_new,
 	mem_free,
+	NULL,
 	};
 
 /* bio->num is used to hold the value to return on 'empty', if it is
diff --git a/crypto/bio/bss_null.c b/crypto/bio/bss_null.c
index d04be88..aee18e3 100644
--- a/crypto/bio/bss_null.c
+++ b/crypto/bio/bss_null.c
@@ -79,6 +79,7 @@
 	null_ctrl,
 	null_new,
 	null_free,
+	NULL,
 	};
 
 BIO_METHOD *BIO_s_null(void)
diff --git a/crypto/bio/bss_rtcp.c b/crypto/bio/bss_rtcp.c
index 2ef0400..4ad0739 100644
--- a/crypto/bio/bss_rtcp.c
+++ b/crypto/bio/bss_rtcp.c
@@ -107,6 +107,7 @@
 	rtcp_ctrl,
 	rtcp_new,
 	rtcp_free,
+	NULL,
 	};
 
 BIO_METHOD *BIO_s_rtcp(void)
diff --git a/crypto/bio/bss_sock.c b/crypto/bio/bss_sock.c
index 1b8d040..8ce80ef 100644
--- a/crypto/bio/bss_sock.c
+++ b/crypto/bio/bss_sock.c
@@ -95,6 +95,7 @@
 	sock_ctrl,
 	sock_new,
 	sock_free,
+	NULL,
 	};
 
 BIO_METHOD *BIO_s_socket(void)
@@ -112,6 +113,7 @@
 	fd_ctrl,
 	fd_new,
 	fd_free,
+	NULL,
 	};
 
 BIO_METHOD *BIO_s_fd(void)
diff --git a/crypto/comp/comp.h b/crypto/comp/comp.h
index 93bd9c3..811cb58 100644
--- a/crypto/comp/comp.h
+++ b/crypto/comp/comp.h
@@ -17,6 +17,7 @@
 	int (*compress)();
 	int (*expand)();
 	long (*ctrl)();
+	long (*callback_ctrl)();
 	} COMP_METHOD;
 
 typedef struct comp_ctx_st
diff --git a/crypto/evp/bio_b64.c b/crypto/evp/bio_b64.c
index 913bafa..bd5e24f 100644
--- a/crypto/evp/bio_b64.c
+++ b/crypto/evp/bio_b64.c
@@ -69,6 +69,7 @@
 static long b64_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int b64_new(BIO *h);
 static int b64_free(BIO *data);
+static long b64_callback_ctrl(BIO *h,int cmd,void (*fp)());
 #define B64_BLOCK_SIZE	1024
 #define B64_BLOCK_SIZE2	768
 #define B64_NONE	0
@@ -100,6 +101,7 @@
 	b64_ctrl,
 	b64_new,
 	b64_free,
+	b64_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_base64(void)
@@ -522,3 +524,17 @@
 	return(ret);
 	}
 
+static long b64_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	long ret=1;
+
+	if (b->next_bio == NULL) return(0);
+	switch (cmd)
+		{
+	default:
+		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
diff --git a/crypto/evp/bio_enc.c b/crypto/evp/bio_enc.c
index 36a6018..629bf4b 100644
--- a/crypto/evp/bio_enc.c
+++ b/crypto/evp/bio_enc.c
@@ -69,6 +69,7 @@
 static long enc_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int enc_new(BIO *h);
 static int enc_free(BIO *data);
+static long enc_callback_ctrl(BIO *h,int cmd,void (*fp)());
 #define ENC_BLOCK_SIZE	(1024*4)
 
 typedef struct enc_struct
@@ -92,6 +93,7 @@
 	enc_ctrl,
 	enc_new,
 	enc_free,
+	enc_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_cipher(void)
@@ -368,6 +370,20 @@
 	return(ret);
 	}
 
+static long enc_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	long ret=1;
+
+	if (b->next_bio == NULL) return(0);
+	switch (cmd)
+		{
+	default:
+		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
 /*
 void BIO_set_cipher_ctx(b,c)
 BIO *b;
diff --git a/crypto/evp/bio_md.c b/crypto/evp/bio_md.c
index 317167f..aef928d 100644
--- a/crypto/evp/bio_md.c
+++ b/crypto/evp/bio_md.c
@@ -72,6 +72,8 @@
 static long md_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int md_new(BIO *h);
 static int md_free(BIO *data);
+static long md_callback_ctrl(BIO *h,int cmd,void (*fp)());
+
 static BIO_METHOD methods_md=
 	{
 	BIO_TYPE_MD,"message digest",
@@ -82,6 +84,7 @@
 	md_ctrl,
 	md_new,
 	md_free,
+	md_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_md(void)
@@ -220,6 +223,20 @@
 	return(ret);
 	}
 
+static long md_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	long ret=1;
+
+	if (b->next_bio == NULL) return(0);
+	switch (cmd)
+		{
+	default:
+		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
 static int md_gets(BIO *bp, char *buf, int size)
 	{
 	EVP_MD_CTX *ctx;
diff --git a/crypto/evp/bio_ok.c b/crypto/evp/bio_ok.c
index a04efa7..e6ff5f2 100644
--- a/crypto/evp/bio_ok.c
+++ b/crypto/evp/bio_ok.c
@@ -130,6 +130,8 @@
 static long ok_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int ok_new(BIO *h);
 static int ok_free(BIO *data);
+static long ok_callback_ctrl(BIO *h,int cmd,void (*fp)());
+
 static void sig_out(BIO* b);
 static void sig_in(BIO* b);
 static void block_out(BIO* b);
@@ -173,6 +175,7 @@
 	ok_ctrl,
 	ok_new,
 	ok_free,
+	ok_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_reliable(void)
@@ -428,6 +431,20 @@
 	return(ret);
 	}
 
+static long ok_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	long ret=1;
+
+	if (b->next_bio == NULL) return(0);
+	switch (cmd)
+		{
+	default:
+		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
 static void longswap(void *_ptr, int len)
 {
 #ifndef L_ENDIAN
diff --git a/crypto/pkcs7/bio_ber.c b/crypto/pkcs7/bio_ber.c
index 25831e5..4803966 100644
--- a/crypto/pkcs7/bio_ber.c
+++ b/crypto/pkcs7/bio_ber.c
@@ -69,6 +69,7 @@
 static long ber_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int ber_new(BIO *h);
 static int ber_free(BIO *data);
+static long ber_callback_ctrl(BIO *h,int cmd,void *(*fp)());
 #define BER_BUF_SIZE	(32)
 
 /* This is used to hold the state of the BER objects being read. */
@@ -115,6 +116,7 @@
 	ber_ctrl,
 	ber_new,
 	ber_free,
+	ber_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_ber(void)
@@ -409,6 +411,20 @@
 	return(ret);
 	}
 
+static long ber_callback_ctrl(BIO *b, int cmd, void *(*fp)())
+	{
+	long ret=1;
+
+	if (b->next_bio == NULL) return(0);
+	switch (cmd)
+		{
+	default:
+		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
 /*
 void BIO_set_cipher_ctx(b,c)
 BIO *b;
diff --git a/ssl/bio_ssl.c b/ssl/bio_ssl.c
index aa29699..d73c41a 100644
--- a/ssl/bio_ssl.c
+++ b/ssl/bio_ssl.c
@@ -71,6 +71,7 @@
 static long ssl_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 static int ssl_new(BIO *h);
 static int ssl_free(BIO *data);
+static long ssl_callback_ctrl(BIO *h,int cmd,void (*fp)());
 typedef struct bio_ssl_st
 	{
 	SSL *ssl; /* The ssl handle :-) */
@@ -92,12 +93,7 @@
 	ssl_ctrl,
 	ssl_new,
 	ssl_free,
-	};
-
-union void_fn_to_char_u
-	{
-	char *char_p;
-	void (*fn_p)();
+	ssl_callback_ctrl,
 	};
 
 BIO_METHOD *BIO_f_ssl(void)
@@ -451,10 +447,12 @@
 		break;
 	case BIO_CTRL_SET_CALLBACK:
 		{
-		union void_fn_to_char_u tmp_cb;
-
-		tmp_cb.char_p = ptr;
-		SSL_set_info_callback(ssl,tmp_cb.fn_p);
+#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
+		BIOerr(SSL_F_SSL_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		ret = -1;
+#else
+		ret=0;
+#endif
 		}
 		break;
 	case BIO_CTRL_GET_CALLBACK:
@@ -472,6 +470,28 @@
 	return(ret);
 	}
 
+static long ssl_callback_ctrl(BIO *b, int cmd, void (*fp)())
+	{
+	SSL *ssl;
+	BIO_SSL *bs;
+	long ret=1;
+
+	bs=(BIO_SSL *)b->ptr;
+	ssl=bs->ssl;
+	switch (cmd)
+		{
+	case BIO_CTRL_SET_CALLBACK:
+		{
+		SSL_set_info_callback(ssl,fp);
+		}
+		break;
+	default:
+		ret=BIO_callback_ctrl(ssl->rbio,cmd,fp);
+		break;
+		}
+	return(ret);
+	}
+
 static int ssl_puts(BIO *bp, char *str)
 	{
 	int n,ret;
diff --git a/ssl/s23_lib.c b/ssl/s23_lib.c
index 41843df..dded7a1 100644
--- a/ssl/s23_lib.c
+++ b/ssl/s23_lib.c
@@ -92,6 +92,9 @@
 	ssl_bad_method,
 	ssl23_default_timeout,
 	&ssl3_undef_enc_method,
+	ssl_undefined_function,
+	ssl3_callback_ctrl,
+	ssl3_ctx_callback_ctrl,
 	};
 
 static long ssl23_default_timeout(void)
diff --git a/ssl/s2_lib.c b/ssl/s2_lib.c
index 47713ec..5ddba23 100644
--- a/ssl/s2_lib.c
+++ b/ssl/s2_lib.c
@@ -230,6 +230,9 @@
 	ssl_bad_method,
 	ssl2_default_timeout,
 	&ssl3_undef_enc_method,
+	ssl_undefined_function,
+	ssl2_callback_ctrl,	/* local */
+	ssl2_ctx_callback_ctrl,	/* local */
 	};
 
 static long ssl2_default_timeout(void)
@@ -335,11 +338,21 @@
 	return(ret);
 	}
 
+long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp)())
+	{
+	return(0);
+	}
+
 long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, char *parg)
 	{
 	return(0);
 	}
 
+long ssl2_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)())
+	{
+	return(0);
+	}
+
 /* This function needs to check if the ciphers required are actually
  * available */
 SSL_CIPHER *ssl2_get_cipher_by_char(const unsigned char *p)
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 7c71f5e..87525fa 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -608,18 +608,9 @@
 	ssl_bad_method,
 	ssl3_default_timeout,
 	&SSLv3_enc_data,
-	};
-
-union rsa_fn_to_char_u
-	{
-	char *char_p;
-	RSA *(*fn_p)(SSL *, int, int);
-	};
-
-union dh_fn_to_char_u
-	{
-	char *char_p;
-	DH *(*fn_p)(SSL *, int, int);
+	ssl_undefined_function,
+	ssl3_callback_ctrl,
+	ssl3_ctx_callback_ctrl,
 	};
 
 static long ssl3_default_timeout(void)
@@ -792,10 +783,8 @@
 		break;
 	case SSL_CTRL_SET_TMP_RSA_CB:
 		{
-		union rsa_fn_to_char_u rsa_tmp_cb;
-
-		rsa_tmp_cb.char_p = parg;
-		s->cert->rsa_tmp_cb = rsa_tmp_cb.fn_p;
+		SSLerr(SSL_F_SSL3_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(ret);
 		}
 		break;
 #endif
@@ -824,10 +813,52 @@
 		break;
 	case SSL_CTRL_SET_TMP_DH_CB:
 		{
-		union dh_fn_to_char_u dh_tmp_cb;
+		SSLerr(SSL_F_SSL3_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(ret);
+		}
+		break;
+#endif
+	default:
+		break;
+		}
+	return(ret);
+	}
 
-		dh_tmp_cb.char_p = parg;
-		s->cert->dh_tmp_cb = dh_tmp_cb.fn_p;
+long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)())
+	{
+	int ret=0;
+
+#if !defined(NO_DSA) || !defined(NO_RSA)
+	if (
+#ifndef NO_RSA
+	    cmd == SSL_CTRL_SET_TMP_RSA_CB ||
+#endif
+#ifndef NO_DSA
+	    cmd == SSL_CTRL_SET_TMP_DH_CB ||
+#endif
+		0)
+		{
+		if (!ssl_cert_inst(&s->cert))
+		    	{
+			SSLerr(SSL_F_SSL3_CTRL, ERR_R_MALLOC_FAILURE);
+			return(0);
+			}
+		}
+#endif
+
+	switch (cmd)
+		{
+#ifndef NO_RSA
+	case SSL_CTRL_SET_TMP_RSA_CB:
+		{
+		s->cert->rsa_tmp_cb = (RSA *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+#ifndef NO_DH
+	case SSL_CTRL_SET_TMP_DH_CB:
+		{
+		s->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
 		}
 		break;
 #endif
@@ -885,10 +916,8 @@
 		/* break; */
 	case SSL_CTRL_SET_TMP_RSA_CB:
 		{
-		union rsa_fn_to_char_u rsa_tmp_cb;
-
-		rsa_tmp_cb.char_p = parg;
-		cert->rsa_tmp_cb = rsa_tmp_cb.fn_p;
+		SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(0);
 		}
 		break;
 #endif
@@ -917,10 +946,8 @@
 		/*break; */
 	case SSL_CTRL_SET_TMP_DH_CB:
 		{
-		union dh_fn_to_char_u dh_tmp_cb;
-
-		dh_tmp_cb.char_p = parg;
-		cert->dh_tmp_cb = dh_tmp_cb.fn_p;
+		SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(0);
 		}
 		break;
 #endif
@@ -940,6 +967,34 @@
 	return(1);
 	}
 
+long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)())
+	{
+	CERT *cert;
+
+	cert=ctx->cert;
+
+	switch (cmd)
+		{
+#ifndef NO_RSA
+	case SSL_CTRL_SET_TMP_RSA_CB:
+		{
+		cert->rsa_tmp_cb = (RSA *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+#ifndef NO_DH
+	case SSL_CTRL_SET_TMP_DH_CB:
+		{
+		cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+	default:
+		return(0);
+		}
+	return(1);
+	}
+
 /* This function needs to check if the ciphers required are actually
  * available */
 SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p)
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 6f31992..040304b 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -210,6 +210,8 @@
 	long (*get_timeout)(void);
 	struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
 	int (*ssl_version)();
+	long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)());
+	long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)());
 	} SSL_METHOD;
 
 /* Lets make this into an ASN.1 type structure as follows
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 3c71d5b..8a9d289 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -794,6 +794,15 @@
 		}
 	}
 
+long SSL_callback_ctrl(SSL *s, int cmd, void (*fp)())
+	{
+	switch(cmd)
+		{
+	default:
+		return(s->method->ssl_callback_ctrl(s,cmd,fp));
+		}
+	}
+
 long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,char *parg)
 	{
 	long l;
@@ -853,6 +862,15 @@
 		}
 	}
 
+long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)())
+	{
+	switch(cmd)
+		{
+	default:
+		return(ctx->method->ssl_ctx_callback_ctrl(ctx,cmd,fp));
+		}
+	}
+
 int ssl_cipher_id_cmp(SSL_CIPHER *a,SSL_CIPHER *b)
 	{
 	long l;
@@ -1988,21 +2006,14 @@
 							  int is_export,
 							  int keylength))
     {
-    union rsa_fn_to_char_u rsa_tmp_cb;
-
-    rsa_tmp_cb.fn_p = cb;
-    SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,0,rsa_tmp_cb.char_p);
+    SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,(void (*)())cb);
     }
-#endif
 
-#ifndef NO_RSA
-void SSL_set_tmp_rsa_callback(SSL *ssl,RSA *(*cb)(SSL *ssl,int is_export,
-							  int keylength))
+void SSL_set_tmp_rsa_callback(SSL *ssl,RSA *(*cb)(SSL *ssl,
+						  int is_export,
+						  int keylength))
     {
-    union rsa_fn_to_char_u rsa_tmp_cb;
-
-    rsa_tmp_cb.fn_p = cb;
-    SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA_CB,0,rsa_tmp_cb.char_p);
+    SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_RSA_CB,(void (*)())cb);
     }
 #endif
 
@@ -2031,19 +2042,13 @@
 void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int is_export,
 							int keylength))
     {
-    union dh_fn_to_char_u dh_tmp_cb;
-
-    dh_tmp_cb.fn_p = dh;
-    SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,0,dh_tmp_cb.char_p);
+    SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,(void (*)())dh);
     }
 
 void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export,
-							int keylength))
+						int keylength))
     {
-    union dh_fn_to_char_u dh_tmp_cb;
-
-    dh_tmp_cb.fn_p = dh;
-    SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,0,dh_tmp_cb.char_p);
+    SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)())dh);
     }
 #endif
 
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index eb28917..0f81902 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -468,6 +468,8 @@
 void	ssl2_clear(SSL *s);
 long	ssl2_ctrl(SSL *s,int cmd, long larg, char *parg);
 long	ssl2_ctx_ctrl(SSL_CTX *s,int cmd, long larg, char *parg);
+long	ssl2_callback_ctrl(SSL *s,int cmd, void (*fp)());
+long	ssl2_ctx_callback_ctrl(SSL_CTX *s,int cmd, void (*fp)());
 int	ssl2_pending(SSL *s);
 
 SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
@@ -514,6 +516,8 @@
 void	ssl3_clear(SSL *s);
 long	ssl3_ctrl(SSL *s,int cmd, long larg, char *parg);
 long	ssl3_ctx_ctrl(SSL_CTX *s,int cmd, long larg, char *parg);
+long	ssl3_callback_ctrl(SSL *s,int cmd, void (*fp)());
+long	ssl3_ctx_callback_ctrl(SSL_CTX *s,int cmd, void (*fp)());
 int	ssl3_pending(SSL *s);
 
 int ssl23_accept(SSL *s);
@@ -525,6 +529,7 @@
 void tls1_free(SSL *s);
 void tls1_clear(SSL *s);
 long tls1_ctrl(SSL *s,int cmd, long larg, char *parg);
+long tls1_callback_ctrl(SSL *s,int cmd, void (*fp)());
 SSL_METHOD *tlsv1_base_method(void );
 
 int ssl_init_wbio_buffer(SSL *s, int push);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 531969b..ca6c03d 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -101,6 +101,9 @@
 	ssl_bad_method,
 	tls1_default_timeout,
 	&TLSv1_enc_data,
+	ssl_undefined_function,
+	ssl3_callback_ctrl,
+	ssl3_ctx_callback_ctrl,
 	};
 
 static long tls1_default_timeout(void)
@@ -138,4 +141,9 @@
 	{
 	return(0);
 	}
+
+long tls1_callback_ctrl(SSL *s, int cmd, void *(*fp)())
+	{
+	return(0);
+	}
 #endif