Использование SSH-аутентификации с libgit2

Я пытаюсь пройти аутентификацию на сервере git с помощью libgit2 используя ключи SSH. Пока что это работает для таких URL, как ssh://myuser@host.domain:1234/dirs/repo.git где мое приложение принимает URL-адрес в качестве аргумента.

Тем не менее, если я удаляю имя пользователя из URL (т.е. ssh://host.domain:1234/dirs/repo.git) соединение не устанавливается, даже если я установил имя пользователя программно (см. ниже).

Рассмотрим следующий MCVE для программы, которая проверяет, доступен ли определенный репозиторий (без проверок на ошибки, кроме необходимых):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <git2.h>
#include <git2/sys/repository.h>

int my_cred_cb(git_cred **out, const char *url,
    const char *username_from_url, unsigned int allowed_types, void *payload)
{
  uid_t uid = geteuid();             // Get effective user ID
  struct passwd* pw = getpwuid(uid); // Get password file entry

  char privkeypath[strlen(pw->pw_dir) + 13];
  strcpy(privkeypath, pw->pw_dir);
  strcat(privkeypath, "/.ssh/id_rsa"); // "~user/.ssh/id_rsa"

  char publkeypath[strlen(privkeypath) + 5]; 
  strcpy(publkeypath, privkeypath);
  strcat(publkeypath, ".pub"); // "~user/.ssh/id_rsa.pub"

  const char* username = (username_from_url != NULL ? username_from_url : pw->pw_name);

  printf("Using username: %s, priv key %s and publ key %s\n", username, privkeypath, publkeypath);
  return git_cred_ssh_key_new(out, username, publkeypath, privkeypath, ""); // No passphrase for keys
}

int main(int argc, char** argv)
{
  git_remote* remote = NULL;
  git_repository* repo = NULL;
  git_remote_callbacks cbs;
  const git_error* err;

  if (argc != 2) return EXIT_FAILURE;

  git_libgit2_init();
  git_repository_new(&repo);
  git_remote_create_anonymous(&remote, repo, argv[1]);
  git_remote_init_callbacks(&cbs, GIT_REMOTE_CALLBACKS_VERSION);
  cbs.credentials = my_cred_cb;

  if (git_remote_connect(remote, GIT_DIRECTION_FETCH, &cbs, NULL, NULL)) {
    err = giterr_last();
    printf ("Error %d: %s\n", err->klass, err->message);
    return EXIT_FAILURE;
  }

  git_libgit2_shutdown();
  printf("git repo exists and is reachable.\n");
}

Это может быть скомпилировано с gcc -Wall -pedantic -std=c99 -o myapp main.c -lssh2 -lgit2 при условии, что пути включения и библиотеки установлены правильно.

Теперь рассмотрим вывод для разных URL:

$ ./myapp ssh://myuser@host.domain:1234/dirs/repo.git
Using username: myuser, priv key /home/myuser/.ssh/id_rsa and publ key /home/myuser/.ssh/id_rsa.pub
git repo exists and is reachable.

А теперь провальный случай:

$ ./myapp ssh://host.domain:1234/dirs/repo.git # Note the missing user name
Using username: myuser, priv key /home/myuser/.ssh/id_rsa and publ key /home/myuser/.ssh/id_rsa.pub
Error 23: callback returned unsupported credentials type

Я не понимаю, почему я получаю эту ошибку, так как я передаю ту же самую информацию в библиотеку (почему это "неподдерживаемый тип учетных данных" в первую очередь?).

Еще хуже, я обычно использую Host записи в моем ~/.ssh/config так, что вместо того, чтобы ставить host.domain:1234 Я могу просто использовать myhost (например git clone ssh://myhost/dirs/repo.git работает просто отлично). Для моего приложения это вывод:

$ ./myapp ssh://myhost/dirs/repo.git
Error 12: failed to resolve address for myhost: Name or service not known

Это выглядит как libgit2 не настраивает libssh2 читать в ssh-конфиге. Это связанная, но, вероятно, другая проблема. Тем не менее я чувствую, что эти две проблемы связаны друг с другом.

Подводя итог моим вопросам:

  1. Как передать имя пользователя в учетные данные git программно (вместо URL-адреса)?
  2. Как мне сказать libgit2 получить информацию из моего ssh-config перед попыткой подключения?

1 ответ

Решение

Это действительно два отдельных не связанных вопроса.

  1. Вы должны проверять allowed_types параметр в вашем обратном вызове и только вернуть git_cred_ssh_key_new учетные данные, если он содержит GIT_CREDTYPE_SSH_KEY, Бэкэнд, вероятно, запрашивает учетные данные типа GIT_CREDTYPE_USERNAME потому что URL не имеет. В этом случае вы должны вернуть учетные данные, созданные git_cred_username_new, Ваш обратный вызов будет вызван дважды: один раз, чтобы получить имя пользователя, и второй раз, чтобы создать учетные данные ssh.

  2. Чтение параметров конфигурации из вашего конфигурационного файла OpenSSH в ~/.ssh/config не поддерживается libgit2, потому что это не поддерживается libssh2. Если вы хотите прочитать настройки оттуда, вы должны сделать это самостоятельно.

Другие вопросы по тегам