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/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