Commit af95615faa87d3181fb5e8bc140c1aa6a8eda085

Patrick Steinhardt 2019-04-26T08:48:17

Merge pull request #5051 from pks-t/pks/examples-ssh-auth examples: implement SSH authentication

diff --git a/examples/blame.c b/examples/blame.c
index 0ddbfc6..fa586b3 100644
--- a/examples/blame.c
+++ b/examples/blame.c
@@ -14,11 +14,6 @@
 
 #include "common.h"
 
-#ifdef _MSC_VER
-#define snprintf sprintf_s
-#define strcasecmp strcmpi
-#endif
-
 /**
  * This example demonstrates how to invoke the libgit2 blame API to roughly
  * simulate the output of `git blame` and a few of its command line arguments.
diff --git a/examples/common.c b/examples/common.c
index f1ee27e..4cd9f2b 100644
--- a/examples/common.c
+++ b/examples/common.c
@@ -330,38 +330,64 @@ error:
 	return error;
 }
 
+static int ask(char **out, const char *prompt, char optional)
+{
+	printf("%s ", prompt);
+	fflush(stdout);
+
+	if (!readline(out) && !optional) {
+		fprintf(stderr, "Could not read response: %s", strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
 int cred_acquire_cb(git_cred **out,
 		const char *url,
 		const char *username_from_url,
 		unsigned int allowed_types,
 		void *payload)
 {
-	char *username = NULL, *password = NULL;
-	int error;
+	char *username = NULL, *password = NULL, *privkey = NULL, *pubkey = NULL;
+	int error = 1;
 
 	UNUSED(url);
-	UNUSED(username_from_url);
-	UNUSED(allowed_types);
 	UNUSED(payload);
 
-	printf("Username: ");
-	if (readline(&username) < 0) {
-		fprintf(stderr, "Unable to read username: %s", strerror(errno));
-		return -1;
+	if (username_from_url) {
+		if ((username = strdup(username_from_url)) == NULL)
+			goto out;
+	} else if ((error = ask(&username, "Username:", 0)) < 0) {
+		goto out;
 	}
 
-	/* Yup. Right there on your terminal. Careful where you copy/paste output. */
-	printf("Password: ");
-	if (readline(&password) < 0) {
-		fprintf(stderr, "Unable to read password: %s", strerror(errno));
-		free(username);
-		return -1;
-	}
+	if (allowed_types & GIT_CREDTYPE_SSH_KEY) {
+		int n;
+
+		if ((error = ask(&privkey, "SSH Key:", 0)) < 0 ||
+		    (error = ask(&password, "Password:", 1)) < 0)
+			goto out;
 
-	error = git_cred_userpass_plaintext_new(out, username, password);
+		if ((n = snprintf(NULL, 0, "%s.pub", privkey)) < 0 ||
+		    (pubkey = malloc(n + 1)) == NULL ||
+		    (n = snprintf(pubkey, n + 1, "%s.pub", privkey)) < 0)
+			goto out;
 
+		error = git_cred_ssh_key_new(out, username, pubkey, privkey, password);
+	} else if (allowed_types & GIT_CREDTYPE_USERPASS_PLAINTEXT) {
+		if ((error = ask(&password, "Password:", 1)) < 0)
+			goto out;
+
+		error = git_cred_userpass_plaintext_new(out, username, password);
+	} else if (allowed_types & GIT_CREDTYPE_USERNAME) {
+		error = git_cred_username_new(out, username);
+	}
+
+out:
 	free(username);
 	free(password);
-
+	free(privkey);
+	free(pubkey);
 	return error;
 }
diff --git a/examples/common.h b/examples/common.h
index ac1c067..c1d444e 100644
--- a/examples/common.h
+++ b/examples/common.h
@@ -26,6 +26,11 @@
 #endif
 #endif
 
+#ifdef _MSC_VER
+#define snprintf sprintf_s
+#define strcasecmp strcmpi
+#endif
+
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
 #define UNUSED(x) (void)(x)
 
diff --git a/examples/merge.c b/examples/merge.c
index a275ecb..8ddb79b 100644
--- a/examples/merge.c
+++ b/examples/merge.c
@@ -15,10 +15,6 @@
 #include "common.h"
 #include <assert.h>
 
-#ifdef _MSC_VER
-#define snprintf sprintf_s
-#endif
-
 /** The following example demonstrates how to do merges with libgit2.
  *
  * It will merge whatever commit-ish you pass in into the current branch.