ENGINE module additions.

Add "init" command to control ENGINE
initialization.

Call ENGINE_finish on initialized ENGINEs on exit.

Reorder shutdown in apps.c: modules should be shut
down first.

Add test private key loader to openssl ENGINE: this
just loads a private key in PEM format.

Fix print format for dh length parameter.
diff --git a/CHANGES b/CHANGES
index 0541062..761cd45 100644
--- a/CHANGES
+++ b/CHANGES
@@ -43,6 +43,14 @@
          *) applies to 0.9.6a ... 0.9.6d and 0.9.7
          +) applies to 0.9.7 only
 
+  +) Add an "init" command to the ENGINE config module and auto initialize
+     ENGINEs. Without any "init" command the ENGINE will be initialized 
+     after all ctrl commands have been executed on it. If init=1 the 
+     ENGINE is initailized at that point (ctrls before that point are run
+     on the uninitialized ENGINE and after on the initialized one). If
+     init=0 then the ENGINE will not be iniatialized at all.
+     [Steve Henson]
+
   +) Fix the 'app_verify_callback' interface so that the user-defined
      argument is actually passed to the callback: In the
      SSL_CTX_set_cert_verify_callback() prototype, the callback
diff --git a/apps/apps.h b/apps/apps.h
index 24aa447..a05ba71 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -195,10 +195,10 @@
 		setup_ui_method(); } while(0)
 #  endif
 #  define apps_shutdown() \
-		do { destroy_ui_method(); EVP_cleanup(); \
-		ENGINE_cleanup(); CRYPTO_cleanup_all_ex_data(); \
-		ERR_remove_state(0); ERR_free_strings(); \
-		CONF_modules_unload(1); } while(0)
+		do { CONF_modules_unload(1); destroy_ui_method(); \
+		EVP_cleanup(); ENGINE_cleanup(); \
+		CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); \
+		ERR_free_strings(); } while(0)
 #endif
 
 typedef struct args_st
diff --git a/apps/dhparam.c b/apps/dhparam.c
index f1664a5..ea15ef3 100644
--- a/apps/dhparam.c
+++ b/apps/dhparam.c
@@ -490,7 +490,7 @@
 		printf("\tif ((dh->p == NULL) || (dh->g == NULL))\n");
 		printf("\t\t{ DH_free(dh); return(NULL); }\n");
 		if (dh->length)
-			printf("\tdh->length = %d;\n", dh->length);
+			printf("\tdh->length = %ld;\n", dh->length);
 		printf("\treturn(dh);\n\t}\n");
 		OPENSSL_free(data);
 		}
diff --git a/crypto/engine/eng_cnf.c b/crypto/engine/eng_cnf.c
index d8d3092..8c0ae8a 100644
--- a/crypto/engine/eng_cnf.c
+++ b/crypto/engine/eng_cnf.c
@@ -75,10 +75,28 @@
 	return name;
 	}
 
+static STACK_OF(ENGINE) *initialized_engines = NULL;
+
+static int int_engine_init(ENGINE *e)
+	{
+	if (!ENGINE_init(e))
+		return 0;
+	if (!initialized_engines)
+		initialized_engines = sk_ENGINE_new_null();
+	if (!initialized_engines || !sk_ENGINE_push(initialized_engines, e))
+		{
+		ENGINE_finish(e);
+		return 0;
+		}
+	return 1;
+	}
+	
+
 int int_engine_configure(char *name, char *value, const CONF *cnf)
 	{
 	int i;
 	int ret = 0;
+	long do_init = -1;
 	STACK_OF(CONF_VALUE) *ecmds;
 	CONF_VALUE *ecmd;
 	char *ctrlname, *ctrlvalue;
@@ -140,7 +158,22 @@
 		 	 */
 			if (!strcmp(ctrlvalue, "EMPTY"))
 				ctrlvalue = NULL;
-			if (!strcmp(ctrlname, "default_algorithms"))
+			else if (!strcmp(ctrlname, "init"))
+				{
+				if (!NCONF_get_number_e(cnf, value, "init", &do_init))
+					goto err;
+				if (do_init == 1)
+					{
+					if (!int_engine_init(e))
+						goto err;
+					}
+				else if (do_init != 0)
+					{
+					ENGINEerr(ENGINE_F_INT_ENGINE_CONFIGURE, ENGINE_R_INVALID_INIT_VALUE);
+					goto err;
+					}
+				}
+			else if (!strcmp(ctrlname, "default_algorithms"))
 				{
 				if (!ENGINE_set_default_string(e, ctrlvalue))
 					goto err;
@@ -151,7 +184,10 @@
 			}
 
 
+
 		}
+	if (e && (do_init == -1) && !int_engine_init(e))
+		goto err;
 	ret = 1;
 	err:
 	if (e)
@@ -188,7 +224,19 @@
 	return 1;
 	}
 
+static void int_engine_module_finish(CONF_IMODULE *md)
+	{
+	ENGINE *e;
+	while ((e = sk_ENGINE_pop(initialized_engines)))
+		ENGINE_finish(e);
+	sk_ENGINE_free(initialized_engines);
+	initialized_engines = NULL;
+	}
+	
+
 void ENGINE_add_conf_module(void)
 	{
-	CONF_module_add("engines", int_engine_module_init, 0);
+	CONF_module_add("engines",
+			int_engine_module_init,
+			int_engine_module_finish);
 	}
diff --git a/crypto/engine/eng_err.c b/crypto/engine/eng_err.c
index fa59c87..f6c5630 100644
--- a/crypto/engine/eng_err.c
+++ b/crypto/engine/eng_err.c
@@ -129,6 +129,7 @@
 {ENGINE_R_INVALID_ARGUMENT               ,"invalid argument"},
 {ENGINE_R_INVALID_CMD_NAME               ,"invalid cmd name"},
 {ENGINE_R_INVALID_CMD_NUMBER             ,"invalid cmd number"},
+{ENGINE_R_INVALID_INIT_VALUE             ,"invalid init value"},
 {ENGINE_R_INVALID_STRING                 ,"invalid string"},
 {ENGINE_R_NOT_INITIALISED                ,"not initialised"},
 {ENGINE_R_NOT_LOADED                     ,"not loaded"},
diff --git a/crypto/engine/eng_openssl.c b/crypto/engine/eng_openssl.c
index 97642ae..e9d976f 100644
--- a/crypto/engine/eng_openssl.c
+++ b/crypto/engine/eng_openssl.c
@@ -62,11 +62,13 @@
 #include "cryptlib.h"
 #include <openssl/engine.h>
 #include <openssl/dso.h>
+#include <openssl/pem.h>
 
 /* This testing gunk is implemented (and explained) lower down. It also assumes
  * the application explicitly calls "ENGINE_load_openssl()" because this is no
  * longer automatic in ENGINE_load_builtin_engines(). */
 #define TEST_ENG_OPENSSL_RC4
+#define TEST_ENG_OPENSSL_PKEY
 /* #define TEST_ENG_OPENSSL_RC4_OTHERS */
 #define TEST_ENG_OPENSSL_RC4_P_INIT
 /* #define TEST_ENG_OPENSSL_RC4_P_CIPHER */
@@ -85,6 +87,11 @@
 				const int **nids, int nid);
 #endif
 
+#ifdef TEST_ENG_OPENSSL_PKEY
+static EVP_PKEY *openssl_load_privkey(ENGINE *eng, const char *key_id,
+	UI_METHOD *ui_method, void *callback_data);
+#endif
+
 /* The constants used when creating the ENGINE */
 static const char *engine_openssl_id = "openssl";
 static const char *engine_openssl_name = "Software engine support";
@@ -95,6 +102,7 @@
 	{
 	if(!ENGINE_set_id(e, engine_openssl_id)
 			|| !ENGINE_set_name(e, engine_openssl_name)
+#ifndef TEST_ENG_OPENSSL_NO_ALGORITHMS
 #ifndef OPENSSL_NO_RSA
 			|| !ENGINE_set_RSA(e, RSA_get_default_method())
 #endif
@@ -111,6 +119,10 @@
 #ifdef TEST_ENG_OPENSSL_SHA
 			|| !ENGINE_set_digests(e, openssl_digests)
 #endif
+#endif
+#ifdef TEST_ENG_OPENSSL_PKEY
+			|| !ENGINE_set_load_privkey_function(e, openssl_load_privkey)
+#endif
 			)
 		return 0;
 	/* If we add errors to this ENGINE, ensure the error handling is setup here */
@@ -317,3 +329,19 @@
 	return 1;
 	}
 #endif
+
+#ifdef TEST_ENG_OPENSSL_PKEY
+static EVP_PKEY *openssl_load_privkey(ENGINE *eng, const char *key_id,
+	UI_METHOD *ui_method, void *callback_data)
+	{
+	BIO *in;
+	EVP_PKEY *key;
+	fprintf(stderr, "(TEST_ENG_OPENSSL_PKEY)Loading Private key %s\n", key_id);
+	in = BIO_new_file(key_id, "r");
+	if (!in)
+		return NULL;
+	key = PEM_read_bio_PrivateKey(in, NULL, 0, NULL);
+	BIO_free(in);
+	return key;
+	}
+#endif
diff --git a/crypto/engine/engine.h b/crypto/engine/engine.h
index 3a9ad0f..6c8b043 100644
--- a/crypto/engine/engine.h
+++ b/crypto/engine/engine.h
@@ -707,6 +707,7 @@
 #define ENGINE_R_INVALID_ARGUMENT			 143
 #define ENGINE_R_INVALID_CMD_NAME			 137
 #define ENGINE_R_INVALID_CMD_NUMBER			 138
+#define ENGINE_R_INVALID_INIT_VALUE			 151
 #define ENGINE_R_INVALID_STRING				 150
 #define ENGINE_R_NOT_INITIALISED			 117
 #define ENGINE_R_NOT_LOADED				 112