Merge "Fix failures when eng_dyn scans multiple directories"
diff --git a/crypto/dso/dso_lib.c b/crypto/dso/dso_lib.c
index 8a15b79..7801529 100644
--- a/crypto/dso/dso_lib.c
+++ b/crypto/dso/dso_lib.c
@@ -237,11 +237,19 @@
 	if(ret->meth->dso_load == NULL)
 		{
 		DSOerr(DSO_F_DSO_LOAD,DSO_R_UNSUPPORTED);
+		/* Make sure we unset the filename on failure, because we use
+		 * this to determine when the DSO has been loaded above. */
+		OPENSSL_free(ret->filename);
+		ret->filename = NULL;
 		goto err;
 		}
 	if(!ret->meth->dso_load(ret))
 		{
 		DSOerr(DSO_F_DSO_LOAD,DSO_R_LOAD_FAILED);
+		/* Make sure we unset the filename on failure, because we use
+		 * this to determine when the DSO has been loaded above. */
+		OPENSSL_free(ret->filename);
+		ret->filename = NULL;
 		goto err;
 		}
 	/* Load succeeded */
diff --git a/crypto/engine/eng_dyn.c b/crypto/engine/eng_dyn.c
index 807da7a..8fb8634 100644
--- a/crypto/engine/eng_dyn.c
+++ b/crypto/engine/eng_dyn.c
@@ -408,7 +408,7 @@
 	int num, loop;
 	/* Unless told not to, try a direct load */
 	if((ctx->dir_load != 2) && (DSO_load(ctx->dynamic_dso,
-				ctx->DYNAMIC_LIBNAME, NULL, 0)) != NULL)
+				ctx->DYNAMIC_LIBNAME, NULL, 0) != NULL))
 		return 1;
 	/* If we're not allowed to use 'dirs' or we have none, fail */
 	if(!ctx->dir_load || (num = sk_OPENSSL_STRING_num(ctx->dirs)) < 1)
@@ -423,6 +423,9 @@
 			{
 			/* Found what we're looking for */
 			OPENSSL_free(merge);
+			/* Previous failed loop iterations, if any, will have resulted in
+			 * errors. Clear them out before returning success. */
+			ERR_clear_error();
 			return 1;
 			}
 		OPENSSL_free(merge);
diff --git a/patches/README b/patches/README
index 6e2af83..1fcf68f 100644
--- a/patches/README
+++ b/patches/README
@@ -18,3 +18,7 @@
 
 Implements TLS Channel ID support as both a client and a server.
 See http://tools.ietf.org/html/draft-balfanz-tls-channelid-00.
+
+eng_dyn_dirs.patch
+
+Fixes the case of having multiple DIR_ADD commands sent to eng_dyn
diff --git a/patches/eng_dyn_dirs.patch b/patches/eng_dyn_dirs.patch
new file mode 100644
index 0000000..ad137e5
--- /dev/null
+++ b/patches/eng_dyn_dirs.patch
@@ -0,0 +1,72 @@
+From b53cd994adaff887ec126de259e37d769ad585cb Mon Sep 17 00:00:00 2001
+From: Kenny Root <kroot@google.com>
+Date: Fri, 8 Feb 2013 11:22:25 -0800
+Subject: [PATCH] Fix failures when eng_dyn scans multiple directories
+
+If DIR_ADD is called with multiple directories, and the target file
+does not exist in the first directory scanned, the DSO object will still
+be considered "loaded" for the next call of DSO_load(...) and cause
+subsequent calls to DSO_load(...) fail with the reason code of "already
+loaded" even though the load failed.
+
+Additionally, with multiple directories used in eng_dyn, another problem
+manifests because the errors pushed onto the error stack will linger even
+if another library is loaded successfully on subsequent calls to
+DSO_load(...) in the directory scanning loop.
+
+Change-Id: I4ddd24f7b39bd88663e1783f30914870a907acfa
+---
+ crypto/dso/dso_lib.c    | 8 ++++++++
+ crypto/engine/eng_dyn.c | 5 ++++-
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/dso/dso_lib.c b/crypto/dso/dso_lib.c
+index 8a15b79..7801529 100644
+--- a/crypto/dso/dso_lib.c
++++ b/crypto/dso/dso_lib.c
+@@ -237,11 +237,19 @@ DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
+ 	if(ret->meth->dso_load == NULL)
+ 		{
+ 		DSOerr(DSO_F_DSO_LOAD,DSO_R_UNSUPPORTED);
++		/* Make sure we unset the filename on failure, because we use
++		 * this to determine when the DSO has been loaded above. */
++		OPENSSL_free(ret->filename);
++		ret->filename = NULL;
+ 		goto err;
+ 		}
+ 	if(!ret->meth->dso_load(ret))
+ 		{
+ 		DSOerr(DSO_F_DSO_LOAD,DSO_R_LOAD_FAILED);
++		/* Make sure we unset the filename on failure, because we use
++		 * this to determine when the DSO has been loaded above. */
++		OPENSSL_free(ret->filename);
++		ret->filename = NULL;
+ 		goto err;
+ 		}
+ 	/* Load succeeded */
+diff --git a/crypto/engine/eng_dyn.c b/crypto/engine/eng_dyn.c
+index 807da7a..8fb8634 100644
+--- a/crypto/engine/eng_dyn.c
++++ b/crypto/engine/eng_dyn.c
+@@ -408,7 +408,7 @@ static int int_load(dynamic_data_ctx *ctx)
+ 	int num, loop;
+ 	/* Unless told not to, try a direct load */
+ 	if((ctx->dir_load != 2) && (DSO_load(ctx->dynamic_dso,
+-				ctx->DYNAMIC_LIBNAME, NULL, 0)) != NULL)
++				ctx->DYNAMIC_LIBNAME, NULL, 0) != NULL))
+ 		return 1;
+ 	/* If we're not allowed to use 'dirs' or we have none, fail */
+ 	if(!ctx->dir_load || (num = sk_OPENSSL_STRING_num(ctx->dirs)) < 1)
+@@ -423,6 +423,9 @@ static int int_load(dynamic_data_ctx *ctx)
+ 			{
+ 			/* Found what we're looking for */
+ 			OPENSSL_free(merge);
++			/* Previous failed loop iterations, if any, will have resulted in
++			 * errors. Clear them out before returning success. */
++			ERR_clear_error();
+ 			return 1;
+ 			}
+ 		OPENSSL_free(merge);
+-- 
+1.7.12.3-x20-1
+