From d86a03e974e21f5a3d5f0f0c506b30e7cb693f95 Mon Sep 17 00:00:00 2001 From: Vishesh Handa Date: Wed, 15 May 2019 17:58:14 +0200 Subject: [PATCH] c lib: Avoid the infinite loop of trying invalid credentials LibGit2 has been designed in a strange way. It doesn't give us an easy way of knowing if and why the credentials has failed, it jusst keep calling the credentials failed method. We are now working around this. --- git_test/gitjournal.c | 63 ++++++++++++++++++++++++++++++++----------- git_test/gitjournal.h | 3 +++ git_test/make.sh | 2 +- 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/git_test/gitjournal.c b/git_test/gitjournal.c index ca31ec81..d5fb520f 100644 --- a/git_test/gitjournal.c +++ b/git_test/gitjournal.c @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -16,6 +15,7 @@ gj_error *gj_error_info(int err) return NULL; gj_error *error = (gj_error *)malloc(sizeof(gj_error)); + error->message_allocated = false; if (err == GJ_ERR_EMPTY_COMMIT) { error->code = 954; @@ -24,16 +24,26 @@ gj_error *gj_error_info(int err) } const git_error *e = git_error_last(); - error->code = e->klass; - error->message = (char *)malloc(strlen(e->message)); - strcpy(error->message, e->message); + if (e) + { + error->code = e->klass; + error->message = (char *)malloc(strlen(e->message)); + strcpy(error->message, e->message); + error->message_allocated = true; + } + else + { + error->code = 1000; + error->message = "Unknown Message"; + } return error; } void gj_error_free(const gj_error *err) { - free(err->message); + if (err->message_allocated) + free(err->message); free((void *)err); } @@ -80,7 +90,7 @@ int rm_match_cb(const char *path, const char *spec, void *payload) char *git_base_path = (char *)payload; if (!git_base_path) { - printf("git_base_path not in payload. Why?"); + printf("git_base_path not in payload. Why?\n"); return 1; } @@ -284,9 +294,26 @@ void gj_set_ssh_keys_paths(char *public_key, char *private_key, char *passcode) g_passcode = passcode; } +typedef struct +{ + bool first_time; +} gj_credentials_payload; + int credentials_cb(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, void *payload) { + if (!payload) + { + printf("credentials_cb has no payload\n"); + return -1; + } + gj_credentials_payload *gj_payload = (gj_credentials_payload *)payload; + if (!gj_payload->first_time) + { + printf("GitJournal: Credentials have been tried and they failed\n"); + return -1; + } + printf("UsernameProvided: %s\n", username_from_url); printf("Allowed Types: %d\n", allowed_types); printf("Payload: %p\n", payload); @@ -297,15 +324,10 @@ int credentials_cb(git_cred **out, const char *url, const char *username_from_ur return -1; } - int err = git_cred_ssh_key_new(out, username_from_url, - g_public_key_path, g_private_key_path, g_passcode); - if (err < 0) - { - printf("Credentials CB Error"); - return err; - } - - return 0; + printf("gj_paylaod: %p\n", gj_payload); + gj_payload->first_time = false; + return git_cred_ssh_key_new(out, username_from_url, + g_public_key_path, g_private_key_path, g_passcode); } int certificate_check_cb(git_cert *cert, int valid, const char *host, void *payload) @@ -332,9 +354,12 @@ int gj_git_clone(char *clone_url, char *git_base_path) git_repository *repo = NULL; git_clone_options options = GIT_CLONE_OPTIONS_INIT; options.fetch_opts.callbacks.transfer_progress = fetch_progress; - options.fetch_opts.callbacks.credentials = credentials_cb; options.fetch_opts.callbacks.certificate_check = certificate_check_cb; + gj_credentials_payload gj_payload = {true}; + options.fetch_opts.callbacks.payload = (void *)&gj_payload; + options.fetch_opts.callbacks.credentials = credentials_cb; + err = git_clone(&repo, clone_url, git_base_path, &options); if (err < 0) goto cleanup; @@ -365,6 +390,9 @@ int gj_git_push(char *git_base_path) const git_strarray refs = {&name, 1}; git_push_options options = GIT_PUSH_OPTIONS_INIT; + + gj_credentials_payload gj_payload = {true}; + options.callbacks.payload = (void *)&gj_payload; options.callbacks.credentials = credentials_cb; err = git_remote_push(remote, &refs, &options); @@ -397,6 +425,9 @@ int gj_git_pull(char *git_base_path, char *author_name, char *author_email) goto cleanup; git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + + gj_credentials_payload gj_payload = {true}; + options.callbacks.payload = (void *)&gj_payload; options.callbacks.credentials = credentials_cb; err = git_remote_fetch(remote, NULL, &options, NULL); diff --git a/git_test/gitjournal.h b/git_test/gitjournal.h index cf326d4c..51fcb37b 100644 --- a/git_test/gitjournal.h +++ b/git_test/gitjournal.h @@ -1,6 +1,8 @@ #ifndef _GITJOURNAL_H_ #define _GITJOURNAL_H_ +#include + int gj_init(); int gj_shutdown(); @@ -20,6 +22,7 @@ void gj_set_ssh_keys_paths(char *public_key, char *private_key, char *passcode); typedef struct { char *message; + bool message_allocated; int code; } gj_error; diff --git a/git_test/make.sh b/git_test/make.sh index fe936e34..38133112 100755 --- a/git_test/make.sh +++ b/git_test/make.sh @@ -2,4 +2,4 @@ set -euv -clang test.c gitjournal.c -lgit2 +clang -g test.c gitjournal.c -lgit2