将 SSH 身份验证与 libgit2 结合使用

and*_*eee 5 c git ssh libgit2 libssh2

我正在尝试libgit2使用 SSH 密钥对 git 服务器进行身份验证。到目前为止,这适用于像 的 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");
}
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

现在失败的情况:

$ ./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
Run Code Online (Sandbox Code Playgroud)

我不明白为什么会收到此错误,因为我将完全相同的信息传递给库(为什么它首先是“不受支持的凭据类型”?)。

更糟糕的是,我通常Host在 my 中使用条目~/.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
Run Code Online (Sandbox Code Playgroud)

看起来libgit2没有配置libssh2读取ssh-config。这是一个相关的,但可能是一个不同的问题。我仍然觉得这两个问题是一体的。

总结我的问题:

  1. 如何以编程方式将用户名传递给 git 凭据(与在 URL 中相比)?
  2. libgit2在尝试连接之前,如何告诉从我的 ssh-config 中检索信息?

Jas*_*lam 5

这确实是两个独立的不相关的问题。

  1. 您应该检查allowed_types回调中的参数,git_cred_ssh_key_new如果它包含GIT_CREDTYPE_SSH_KEY. 后端可能正在请求类型凭据,GIT_CREDTYPE_USERNAME因为 URL 没有。在这种情况下,您应该返回由git_cred_username_new. 您的回调将被调用两次,一次是为了获取用户名,第二次是为了创建 ssh 凭证。

  2. libgit2 不支持从位于 ~/.ssh/config 的 OpenSSH 配置文件中读取配置设置,因为 libssh2 不支持它。如果你想从那里读取设置,你必须自己做。