- djm@cvs.openbsd.org 2013/12/05 22:59:45
     [sftp-client.c]
     fix memory leak in error path in do_readdir(); pointed out by
     Loganaden Velvindron @ AfriNIC in bz#2163
diff --git a/sftp-client.c b/sftp-client.c
index 246e949..1eb8210 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.110 2013/12/04 04:20:01 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.111 2013/12/05 22:59:45 djm Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
  *
@@ -460,6 +460,10 @@
 	Buffer msg;
 	u_int count, type, id, handle_len, i, expected_id, ents = 0;
 	char *handle;
+	int status = SSH2_FX_FAILURE;
+
+	if (dir)
+		*dir = NULL;
 
 	id = conn->msg_id++;
 
@@ -506,20 +510,12 @@
 			fatal("ID mismatch (%u != %u)", id, expected_id);
 
 		if (type == SSH2_FXP_STATUS) {
-			int status = buffer_get_int(&msg);
-
+			status = buffer_get_int(&msg);
 			debug3("Received SSH2_FXP_STATUS %d", status);
-
-			if (status == SSH2_FX_EOF) {
+			if (status == SSH2_FX_EOF)
 				break;
-			} else {
-				error("Couldn't read directory: %s",
-				    fx2txt(status));
-				do_close(conn, handle, handle_len);
-				free(handle);
-				buffer_free(&msg);
-				return(status);
-			}
+			error("Couldn't read directory: %s", fx2txt(status));
+			goto out;
 		} else if (type != SSH2_FXP_NAME)
 			fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
 			    SSH2_FXP_NAME, type);
@@ -547,10 +543,7 @@
 			if (strchr(filename, '/') != NULL) {
 				error("Server sent suspect path \"%s\" "
 				    "during readdir of \"%s\"", filename, path);
-				goto next;
-			}
-
-			if (dir) {
+			} else if (dir) {
 				*dir = xrealloc(*dir, ents + 2, sizeof(**dir));
 				(*dir)[ents] = xcalloc(1, sizeof(***dir));
 				(*dir)[ents]->filename = xstrdup(filename);
@@ -558,24 +551,29 @@
 				memcpy(&(*dir)[ents]->a, a, sizeof(*a));
 				(*dir)[++ents] = NULL;
 			}
- next:
 			free(filename);
 			free(longname);
 		}
 	}
+	status = 0;
 
+ out:
 	buffer_free(&msg);
 	do_close(conn, handle, handle_len);
 	free(handle);
 
-	/* Don't return partial matches on interrupt */
-	if (interrupted && dir != NULL && *dir != NULL) {
+	if (status != 0 && dir != NULL) {
+		/* Don't return results on error */
+		free_sftp_dirents(*dir);
+		*dir = NULL;
+	} else if (interrupted && dir != NULL && *dir != NULL) {
+		/* Don't return partial matches on interrupt */
 		free_sftp_dirents(*dir);
 		*dir = xcalloc(1, sizeof(**dir));
 		**dir = NULL;
 	}
 
-	return 0;
+	return status;
 }
 
 int
@@ -588,6 +586,8 @@
 {
 	int i;
 
+	if (s == NULL)
+		return;
 	for (i = 0; s[i]; i++) {
 		free(s[i]->filename);
 		free(s[i]->longname);