changeset 21738:29066a72703a

lib-oauth2: Fix memory leak if HTTP URL parsing fails. Also delay calling the callback. The callers don't necessarily expect an immediate callback (auth/db-oauth2.c doesn't).
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Thu, 16 Mar 2017 01:12:57 +0200
parents 036d9f649c8b
children 69f17440719c
files src/lib-oauth2/oauth2-introspect.c src/lib-oauth2/oauth2-private.h src/lib-oauth2/oauth2-refresh.c src/lib-oauth2/oauth2-token-validate.c src/lib-oauth2/oauth2.c
diffstat 5 files changed, 48 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-oauth2/oauth2-introspect.c	Thu Mar 16 00:54:44 2017 +0200
+++ b/src/lib-oauth2/oauth2-introspect.c	Thu Mar 16 01:12:57 2017 +0200
@@ -55,6 +55,16 @@
 	}
 }
 
+static void oauth2_introspection_delayed_error(struct oauth2_request *req)
+{
+	struct oauth2_introspection_result fail = {
+		.success = FALSE,
+		.error = req->delayed_error
+	};
+	oauth2_introspection_callback(req, &fail);
+	oauth2_request_free_internal(req);
+}
+
 #undef oauth2_introspection_start
 struct oauth2_request*
 oauth2_introspection_start(const struct oauth2_settings *set,
@@ -67,9 +77,6 @@
 	pool_t pool = pool_alloconly_create_clean("oauth2 introspection", 1024);
 	struct oauth2_request *req =
 		p_new(pool, struct oauth2_request, 1);
-	struct oauth2_introspection_result fail = {
-		.success = FALSE,
-	};
 	struct http_url *url;
 	const char *error;
 
@@ -87,9 +94,10 @@
 
 	if (http_url_parse(str_c(enc), NULL, HTTP_URL_ALLOW_USERINFO_PART, pool,
 			   &url, &error) < 0) {
-		fail.error = t_strdup_printf("http_url_parse(%s) failed: %s",
-					     str_c(enc), error);
-		oauth2_introspection_callback(req, &fail);
+		req->delayed_error = p_strdup_printf(pool,
+			"http_url_parse(%s) failed: %s", str_c(enc), error);
+		req->to_delayed_error = timeout_add_short(0,
+			oauth2_introspection_delayed_error, req);
 		return req;
 	}
 
--- a/src/lib-oauth2/oauth2-private.h	Thu Mar 16 00:54:44 2017 +0200
+++ b/src/lib-oauth2/oauth2-private.h	Thu Mar 16 01:12:57 2017 +0200
@@ -11,6 +11,9 @@
 	struct istream *is;
 	struct io *io;
 
+	const char *delayed_error;
+	struct timeout *to_delayed_error;
+
 	const char *username;
 
 	void (*json_parsed_cb)(struct oauth2_request*, bool success,
--- a/src/lib-oauth2/oauth2-refresh.c	Thu Mar 16 00:54:44 2017 +0200
+++ b/src/lib-oauth2/oauth2-refresh.c	Thu Mar 16 01:12:57 2017 +0200
@@ -95,6 +95,16 @@
 	}
 }
 
+static void oauth2_refresh_delayed_error(struct oauth2_request *req)
+{
+	struct oauth2_refresh_result fail = {
+		.success = FALSE,
+		.error = req->delayed_error
+	};
+	oauth2_refresh_callback(req, &fail);
+	oauth2_request_free_internal(req);
+}
+
 #undef oauth2_refresh_start
 struct oauth2_request*
 oauth2_refresh_start(const struct oauth2_settings *set,
@@ -109,9 +119,6 @@
 		p_new(pool, struct oauth2_request, 1);
 	struct http_url *url;
 	const char *error;
-	struct oauth2_refresh_result fail = {
-		.success = FALSE
-	};
 
 	req->pool = pool;
 	req->set = set;
@@ -121,9 +128,11 @@
 
 	if (http_url_parse(req->set->refresh_url, NULL, HTTP_URL_ALLOW_USERINFO_PART,
 			   pool, &url, &error) < 0) {
-		fail.error = t_strdup_printf("http_url_parse(%s) failed: %s",
-					     req->set->refresh_url, error);
-		oauth2_refresh_callback(req, &fail);
+		req->delayed_error = p_strdup_printf(pool,
+			"http_url_parse(%s) failed: %s",
+			req->set->refresh_url, error);
+		req->to_delayed_error = timeout_add_short(0,
+			oauth2_refresh_delayed_error, req);
 		return req;
 	}
 
--- a/src/lib-oauth2/oauth2-token-validate.c	Thu Mar 16 00:54:44 2017 +0200
+++ b/src/lib-oauth2/oauth2-token-validate.c	Thu Mar 16 01:12:57 2017 +0200
@@ -83,6 +83,16 @@
 	}
 }
 
+static void oauth2_token_validation_delayed_error(struct oauth2_request *req)
+{
+	struct oauth2_token_validation_result fail = {
+		.success = FALSE,
+		.error = req->delayed_error
+	};
+	oauth2_token_validation_callback(req, &fail);
+	oauth2_request_free_internal(req);
+}
+
 #undef oauth2_token_validation_start
 struct oauth2_request*
 oauth2_token_validation_start(const struct oauth2_settings *set,
@@ -94,9 +104,6 @@
 
 	struct http_url *url;
 	const char *error;
-	struct oauth2_token_validation_result fail = {
-		.success = FALSE
-	};
 
 	pool_t pool = pool_alloconly_create_clean("oauth2 token_validation", 1024);
 	struct oauth2_request *req =
@@ -113,9 +120,10 @@
 
 	if (http_url_parse(str_c(enc), NULL, HTTP_URL_ALLOW_USERINFO_PART, pool,
 			   &url, &error) < 0) {
-		fail.error = t_strdup_printf("http_url_parse(%s) failed: %s",
-					     str_c(enc), error);
-		oauth2_token_validation_callback(req, &fail);
+		req->delayed_error = p_strdup_printf(pool,
+			"http_url_parse(%s) failed: %s", str_c(enc), error);
+		req->to_delayed_error = timeout_add_short(0,
+			oauth2_token_validation_delayed_error, req);
 		return req;
 	}
 
--- a/src/lib-oauth2/oauth2.c	Thu Mar 16 00:54:44 2017 +0200
+++ b/src/lib-oauth2/oauth2.c	Thu Mar 16 01:12:57 2017 +0200
@@ -73,6 +73,8 @@
 void
 oauth2_request_free_internal(struct oauth2_request *req)
 {
+	if (req->to_delayed_error != NULL)
+		timeout_remove(&req->to_delayed_error);
 	pool_unref(&req->pool);
 }