rugged 0.21.4 → 0.22.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (224) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -5
  3. data/ext/rugged/extconf.rb +9 -9
  4. data/ext/rugged/rugged.c +4 -2
  5. data/ext/rugged/rugged.h +3 -7
  6. data/ext/rugged/rugged_blob.c +57 -0
  7. data/ext/rugged/rugged_cred.c +23 -0
  8. data/ext/rugged/rugged_index.c +6 -2
  9. data/ext/rugged/rugged_remote.c +65 -52
  10. data/ext/rugged/rugged_remote_collection.c +59 -10
  11. data/ext/rugged/rugged_repo.c +345 -11
  12. data/ext/rugged/rugged_revwalk.c +10 -0
  13. data/ext/rugged/rugged_submodule.c +1042 -0
  14. data/ext/rugged/rugged_submodule_collection.c +236 -0
  15. data/ext/rugged/rugged_tag_collection.c +70 -2
  16. data/ext/rugged/rugged_tree.c +29 -10
  17. data/lib/rugged.rb +3 -0
  18. data/lib/rugged/attributes.rb +41 -0
  19. data/lib/rugged/blob.rb +28 -0
  20. data/lib/rugged/diff.rb +0 -1
  21. data/lib/rugged/diff/line.rb +1 -3
  22. data/lib/rugged/patch.rb +12 -2
  23. data/lib/rugged/repository.rb +7 -0
  24. data/lib/rugged/submodule_collection.rb +48 -0
  25. data/lib/rugged/version.rb +1 -1
  26. data/vendor/libgit2/CMakeLists.txt +27 -3
  27. data/vendor/libgit2/cmake/Modules/FindGSSAPI.cmake +324 -0
  28. data/vendor/libgit2/deps/http-parser/http_parser.h +2 -0
  29. data/vendor/libgit2/deps/zlib/adler32.c +39 -29
  30. data/vendor/libgit2/deps/zlib/crc32.c +33 -50
  31. data/vendor/libgit2/deps/zlib/crc32.h +1 -1
  32. data/vendor/libgit2/deps/zlib/deflate.c +198 -65
  33. data/vendor/libgit2/deps/zlib/deflate.h +8 -4
  34. data/vendor/libgit2/deps/zlib/infback.c +640 -0
  35. data/vendor/libgit2/deps/zlib/inffast.c +3 -3
  36. data/vendor/libgit2/deps/zlib/inffixed.h +3 -3
  37. data/vendor/libgit2/deps/zlib/inflate.c +84 -52
  38. data/vendor/libgit2/deps/zlib/inftrees.c +15 -39
  39. data/vendor/libgit2/deps/zlib/trees.c +18 -36
  40. data/vendor/libgit2/deps/zlib/zconf.h +4 -0
  41. data/vendor/libgit2/deps/zlib/zlib.h +250 -95
  42. data/vendor/libgit2/deps/zlib/zutil.c +13 -10
  43. data/vendor/libgit2/deps/zlib/zutil.h +41 -62
  44. data/vendor/libgit2/include/git2.h +4 -0
  45. data/vendor/libgit2/include/git2/annotated_commit.h +99 -0
  46. data/vendor/libgit2/include/git2/attr.h +16 -13
  47. data/vendor/libgit2/include/git2/branch.h +11 -0
  48. data/vendor/libgit2/include/git2/buffer.h +16 -0
  49. data/vendor/libgit2/include/git2/checkout.h +12 -12
  50. data/vendor/libgit2/include/git2/cherrypick.h +15 -15
  51. data/vendor/libgit2/include/git2/clone.h +77 -69
  52. data/vendor/libgit2/include/git2/common.h +13 -1
  53. data/vendor/libgit2/include/git2/config.h +0 -14
  54. data/vendor/libgit2/include/git2/describe.h +162 -0
  55. data/vendor/libgit2/include/git2/diff.h +13 -8
  56. data/vendor/libgit2/include/git2/errors.h +5 -0
  57. data/vendor/libgit2/include/git2/global.h +38 -0
  58. data/vendor/libgit2/include/git2/merge.h +38 -64
  59. data/vendor/libgit2/include/git2/net.h +2 -2
  60. data/vendor/libgit2/include/git2/notes.h +17 -0
  61. data/vendor/libgit2/include/git2/oid.h +8 -4
  62. data/vendor/libgit2/include/git2/oidarray.h +40 -0
  63. data/vendor/libgit2/include/git2/rebase.h +261 -0
  64. data/vendor/libgit2/include/git2/reflog.h +1 -1
  65. data/vendor/libgit2/include/git2/remote.h +25 -47
  66. data/vendor/libgit2/include/git2/repository.h +4 -1
  67. data/vendor/libgit2/include/git2/reset.h +10 -1
  68. data/vendor/libgit2/include/git2/revert.h +1 -1
  69. data/vendor/libgit2/include/git2/revwalk.h +28 -23
  70. data/vendor/libgit2/include/git2/status.h +19 -15
  71. data/vendor/libgit2/include/git2/submodule.h +18 -0
  72. data/vendor/libgit2/include/git2/sys/config.h +0 -1
  73. data/vendor/libgit2/{src → include/git2/sys}/hashsig.h +11 -7
  74. data/vendor/libgit2/include/git2/sys/refdb_backend.h +13 -0
  75. data/vendor/libgit2/include/git2/sys/refs.h +0 -11
  76. data/vendor/libgit2/include/git2/sys/repository.h +13 -0
  77. data/vendor/libgit2/include/git2/sys/transport.h +352 -0
  78. data/vendor/libgit2/include/git2/threads.h +10 -20
  79. data/vendor/libgit2/include/git2/transaction.h +111 -0
  80. data/vendor/libgit2/include/git2/transport.h +79 -313
  81. data/vendor/libgit2/include/git2/tree.h +4 -2
  82. data/vendor/libgit2/include/git2/types.h +77 -8
  83. data/vendor/libgit2/include/git2/version.h +2 -2
  84. data/vendor/libgit2/src/annotated_commit.c +121 -0
  85. data/vendor/libgit2/src/annotated_commit.h +22 -0
  86. data/vendor/libgit2/src/attr.c +8 -4
  87. data/vendor/libgit2/src/attr_file.c +24 -2
  88. data/vendor/libgit2/src/blame.c +0 -1
  89. data/vendor/libgit2/src/branch.c +32 -3
  90. data/vendor/libgit2/src/buf_text.c +9 -5
  91. data/vendor/libgit2/src/buf_text.h +3 -2
  92. data/vendor/libgit2/src/buffer.c +67 -10
  93. data/vendor/libgit2/src/buffer.h +4 -2
  94. data/vendor/libgit2/src/cache.c +9 -9
  95. data/vendor/libgit2/src/cache.h +1 -1
  96. data/vendor/libgit2/src/cc-compat.h +2 -0
  97. data/vendor/libgit2/src/checkout.c +263 -82
  98. data/vendor/libgit2/src/checkout.h +1 -0
  99. data/vendor/libgit2/src/cherrypick.c +41 -44
  100. data/vendor/libgit2/src/clone.c +96 -58
  101. data/vendor/libgit2/src/commit.c +5 -31
  102. data/vendor/libgit2/src/commit_list.h +3 -1
  103. data/vendor/libgit2/src/config.c +0 -17
  104. data/vendor/libgit2/src/config_cache.c +0 -2
  105. data/vendor/libgit2/src/config_file.c +12 -15
  106. data/vendor/libgit2/src/crlf.c +2 -1
  107. data/vendor/libgit2/src/describe.c +886 -0
  108. data/vendor/libgit2/src/diff.c +29 -3
  109. data/vendor/libgit2/src/diff_file.c +1 -0
  110. data/vendor/libgit2/src/diff_patch.c +2 -3
  111. data/vendor/libgit2/src/diff_print.c +11 -9
  112. data/vendor/libgit2/src/diff_tform.c +4 -4
  113. data/vendor/libgit2/src/errors.c +9 -7
  114. data/vendor/libgit2/src/fetch.c +6 -6
  115. data/vendor/libgit2/src/fetchhead.h +2 -4
  116. data/vendor/libgit2/src/filebuf.c +0 -2
  117. data/vendor/libgit2/src/filebuf.h +2 -3
  118. data/vendor/libgit2/src/fileops.c +9 -7
  119. data/vendor/libgit2/src/global.c +44 -35
  120. data/vendor/libgit2/src/global.h +2 -0
  121. data/vendor/libgit2/src/graph.c +2 -2
  122. data/vendor/libgit2/src/hash.h +3 -1
  123. data/vendor/libgit2/src/hash/hash_common_crypto.h +44 -0
  124. data/vendor/libgit2/src/hash/hash_win32.c +1 -1
  125. data/vendor/libgit2/src/hashsig.c +1 -1
  126. data/vendor/libgit2/src/ignore.c +5 -88
  127. data/vendor/libgit2/src/index.c +70 -57
  128. data/vendor/libgit2/src/index.h +1 -0
  129. data/vendor/libgit2/src/indexer.c +16 -5
  130. data/vendor/libgit2/src/iterator.c +70 -1
  131. data/vendor/libgit2/src/iterator.h +5 -1
  132. data/vendor/libgit2/src/map.h +0 -1
  133. data/vendor/libgit2/src/merge.c +203 -327
  134. data/vendor/libgit2/src/merge.h +3 -13
  135. data/vendor/libgit2/src/mwindow.c +119 -8
  136. data/vendor/libgit2/src/mwindow.h +9 -1
  137. data/vendor/libgit2/src/netops.c +7 -8
  138. data/vendor/libgit2/src/netops.h +6 -16
  139. data/vendor/libgit2/src/notes.c +31 -4
  140. data/vendor/libgit2/src/notes.h +3 -0
  141. data/vendor/libgit2/src/odb.c +23 -1
  142. data/vendor/libgit2/src/odb_loose.c +1 -1
  143. data/vendor/libgit2/src/odb_pack.c +6 -3
  144. data/vendor/libgit2/src/oid.c +9 -1
  145. data/vendor/libgit2/src/oid.h +11 -0
  146. data/vendor/libgit2/src/oidarray.c +21 -0
  147. data/vendor/libgit2/src/oidarray.h +18 -0
  148. data/vendor/libgit2/src/oidmap.h +16 -0
  149. data/vendor/libgit2/src/pack.c +20 -7
  150. data/vendor/libgit2/src/pack.h +3 -0
  151. data/vendor/libgit2/src/path.c +120 -293
  152. data/vendor/libgit2/src/path.h +21 -44
  153. data/vendor/libgit2/src/pathspec.c +1 -1
  154. data/vendor/libgit2/src/pool.c +5 -11
  155. data/vendor/libgit2/src/pool.h +0 -2
  156. data/vendor/libgit2/src/posix.c +6 -6
  157. data/vendor/libgit2/src/posix.h +48 -28
  158. data/vendor/libgit2/src/push.c +19 -48
  159. data/vendor/libgit2/src/push.h +2 -4
  160. data/vendor/libgit2/src/rebase.c +1125 -0
  161. data/vendor/libgit2/src/refdb.c +19 -0
  162. data/vendor/libgit2/src/refdb.h +2 -1
  163. data/vendor/libgit2/src/refdb_fs.c +101 -29
  164. data/vendor/libgit2/src/reflog.c +1 -1
  165. data/vendor/libgit2/src/refs.c +38 -3
  166. data/vendor/libgit2/src/refs.h +13 -2
  167. data/vendor/libgit2/src/refspec.c +20 -2
  168. data/vendor/libgit2/src/remote.c +288 -154
  169. data/vendor/libgit2/src/remote.h +5 -1
  170. data/vendor/libgit2/src/repository.c +75 -36
  171. data/vendor/libgit2/src/repository.h +3 -25
  172. data/vendor/libgit2/src/reset.c +5 -1
  173. data/vendor/libgit2/src/revert.c +4 -6
  174. data/vendor/libgit2/src/revparse.c +15 -18
  175. data/vendor/libgit2/src/revwalk.c +96 -22
  176. data/vendor/libgit2/src/revwalk.h +5 -4
  177. data/vendor/libgit2/src/settings.c +22 -0
  178. data/vendor/libgit2/src/signature.c +37 -2
  179. data/vendor/libgit2/src/signature.h +3 -0
  180. data/vendor/libgit2/src/stash.c +17 -12
  181. data/vendor/libgit2/src/status.c +13 -3
  182. data/vendor/libgit2/src/strnlen.h +2 -1
  183. data/vendor/libgit2/src/submodule.c +75 -35
  184. data/vendor/libgit2/src/thread-utils.h +4 -9
  185. data/vendor/libgit2/src/trace.h +9 -1
  186. data/vendor/libgit2/src/transaction.c +352 -0
  187. data/vendor/libgit2/src/transport.c +91 -97
  188. data/vendor/libgit2/src/transports/auth.c +71 -0
  189. data/vendor/libgit2/src/transports/auth.h +63 -0
  190. data/vendor/libgit2/src/transports/auth_negotiate.c +275 -0
  191. data/vendor/libgit2/src/transports/auth_negotiate.h +27 -0
  192. data/vendor/libgit2/src/transports/cred.c +58 -0
  193. data/vendor/libgit2/src/transports/cred.h +14 -0
  194. data/vendor/libgit2/src/transports/cred_helpers.c +3 -0
  195. data/vendor/libgit2/src/transports/git.c +1 -0
  196. data/vendor/libgit2/src/transports/http.c +208 -82
  197. data/vendor/libgit2/src/transports/local.c +2 -2
  198. data/vendor/libgit2/src/transports/smart.c +2 -0
  199. data/vendor/libgit2/src/transports/smart.h +2 -0
  200. data/vendor/libgit2/src/transports/smart_protocol.c +10 -10
  201. data/vendor/libgit2/src/transports/ssh.c +243 -57
  202. data/vendor/libgit2/src/transports/winhttp.c +139 -35
  203. data/vendor/libgit2/src/tree-cache.c +118 -31
  204. data/vendor/libgit2/src/tree-cache.h +12 -7
  205. data/vendor/libgit2/src/tree.c +83 -64
  206. data/vendor/libgit2/src/tree.h +2 -3
  207. data/vendor/libgit2/src/unix/map.c +8 -2
  208. data/vendor/libgit2/src/unix/posix.h +23 -9
  209. data/vendor/libgit2/src/unix/realpath.c +8 -7
  210. data/vendor/libgit2/src/userdiff.h +3 -3
  211. data/vendor/libgit2/src/util.c +2 -92
  212. data/vendor/libgit2/src/util.h +3 -15
  213. data/vendor/libgit2/src/win32/findfile.c +0 -1
  214. data/vendor/libgit2/src/win32/map.c +3 -2
  215. data/vendor/libgit2/src/win32/mingw-compat.h +5 -12
  216. data/vendor/libgit2/src/win32/msvc-compat.h +3 -32
  217. data/vendor/libgit2/src/win32/posix.h +20 -32
  218. data/vendor/libgit2/src/win32/posix_w32.c +103 -31
  219. data/vendor/libgit2/src/win32/utf-conv.c +6 -36
  220. data/vendor/libgit2/src/win32/utf-conv.h +39 -0
  221. data/vendor/libgit2/src/win32/w32_util.h +0 -1
  222. metadata +32 -7
  223. data/vendor/libgit2/src/win32/path_w32.c +0 -305
  224. data/vendor/libgit2/src/win32/path_w32.h +0 -82
@@ -405,7 +405,7 @@ static int local_push(
405
405
  git_vector_foreach(&push->specs, j, spec) {
406
406
  push_status *status;
407
407
  const git_error *last;
408
- char *ref = spec->rref ? spec->rref : spec->lref;
408
+ char *ref = spec->refspec.dst;
409
409
 
410
410
  status = git__calloc(sizeof(push_status), 1);
411
411
  if (!status)
@@ -417,7 +417,7 @@ static int local_push(
417
417
  goto on_error;
418
418
  }
419
419
 
420
- error = local_push_update_remote_ref(remote_repo, spec->lref, spec->rref,
420
+ error = local_push_update_remote_ref(remote_repo, spec->refspec.src, spec->refspec.dst,
421
421
  &spec->loid, &spec->roid);
422
422
 
423
423
  switch (error) {
@@ -53,12 +53,14 @@ static int git_smart__set_callbacks(
53
53
  git_transport *transport,
54
54
  git_transport_message_cb progress_cb,
55
55
  git_transport_message_cb error_cb,
56
+ git_transport_certificate_check_cb certificate_check_cb,
56
57
  void *message_cb_payload)
57
58
  {
58
59
  transport_smart *t = (transport_smart *)transport;
59
60
 
60
61
  t->progress_cb = progress_cb;
61
62
  t->error_cb = error_cb;
63
+ t->certificate_check_cb = certificate_check_cb;
62
64
  t->message_cb_payload = message_cb_payload;
63
65
 
64
66
  return 0;
@@ -9,6 +9,7 @@
9
9
  #include "netops.h"
10
10
  #include "buffer.h"
11
11
  #include "push.h"
12
+ #include "git2/sys/transport.h"
12
13
 
13
14
  #define GIT_SIDE_BAND_DATA 1
14
15
  #define GIT_SIDE_BAND_PROGRESS 2
@@ -136,6 +137,7 @@ typedef struct {
136
137
  int flags;
137
138
  git_transport_message_cb progress_cb;
138
139
  git_transport_message_cb error_cb;
140
+ git_transport_certificate_check_cb certificate_check_cb;
139
141
  void *message_cb_payload;
140
142
  git_smart_subtransport *wrapped;
141
143
  git_smart_subtransport_stream *current_stream;
@@ -314,7 +314,7 @@ static int wait_while_ack(gitno_buffer *buf)
314
314
  break;
315
315
 
316
316
  if (pkt->type == GIT_PKT_ACK &&
317
- (pkt->status != GIT_ACK_CONTINUE ||
317
+ (pkt->status != GIT_ACK_CONTINUE &&
318
318
  pkt->status != GIT_ACK_COMMON)) {
319
319
  git__free(pkt);
320
320
  return 0;
@@ -640,12 +640,12 @@ static int gen_pktline(git_buf *buf, git_push *push)
640
640
  {
641
641
  push_spec *spec;
642
642
  size_t i, len;
643
- char old_id[41], new_id[41];
643
+ char old_id[GIT_OID_HEXSZ+1], new_id[GIT_OID_HEXSZ+1];
644
644
 
645
- old_id[40] = '\0'; new_id[40] = '\0';
645
+ old_id[GIT_OID_HEXSZ] = '\0'; new_id[GIT_OID_HEXSZ] = '\0';
646
646
 
647
647
  git_vector_foreach(&push->specs, i, spec) {
648
- len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->rref);
648
+ len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->refspec.dst);
649
649
 
650
650
  if (i == 0) {
651
651
  ++len; /* '\0' */
@@ -657,7 +657,7 @@ static int gen_pktline(git_buf *buf, git_push *push)
657
657
  git_oid_fmt(old_id, &spec->roid);
658
658
  git_oid_fmt(new_id, &spec->loid);
659
659
 
660
- git_buf_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->rref);
660
+ git_buf_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->refspec.dst);
661
661
 
662
662
  if (i == 0) {
663
663
  git_buf_putc(buf, '\0');
@@ -816,7 +816,7 @@ static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec)
816
816
 
817
817
  added->type = GIT_PKT_REF;
818
818
  git_oid_cpy(&added->head.oid, &push_spec->loid);
819
- added->head.name = git__strdup(push_spec->rref);
819
+ added->head.name = git__strdup(push_spec->refspec.dst);
820
820
 
821
821
  if (!added->head.name ||
822
822
  git_vector_insert(refs, added) < 0) {
@@ -855,7 +855,7 @@ static int update_refs_from_report(
855
855
 
856
856
  /* For each push spec we sent to the server, we should have
857
857
  * gotten back a status packet in the push report which matches */
858
- if (strcmp(push_spec->rref, push_status->ref)) {
858
+ if (strcmp(push_spec->refspec.dst, push_status->ref)) {
859
859
  giterr_set(GITERR_NET, "report-status: protocol error");
860
860
  return -1;
861
861
  }
@@ -872,7 +872,7 @@ static int update_refs_from_report(
872
872
  push_status = git_vector_get(push_report, i);
873
873
  ref = git_vector_get(refs, j);
874
874
 
875
- cmp = strcmp(push_spec->rref, ref->head.name);
875
+ cmp = strcmp(push_spec->refspec.dst, ref->head.name);
876
876
 
877
877
  /* Iterate appropriately */
878
878
  if (cmp <= 0) i++;
@@ -963,7 +963,7 @@ int git_smart__push(git_transport *transport, git_push *push)
963
963
  #ifdef PUSH_DEBUG
964
964
  {
965
965
  git_remote_head *head;
966
- char hex[41]; hex[40] = '\0';
966
+ char hex[GIT_OID_HEXSZ+1]; hex[GIT_OID_HEXSZ] = '\0';
967
967
 
968
968
  git_vector_foreach(&push->remote->refs, i, head) {
969
969
  git_oid_fmt(hex, &head->oid);
@@ -985,7 +985,7 @@ int git_smart__push(git_transport *transport, git_push *push)
985
985
  * cases except when we only send delete commands
986
986
  */
987
987
  git_vector_foreach(&push->specs, i, spec) {
988
- if (spec->lref) {
988
+ if (spec->refspec.src && spec->refspec.src[0] != '\0') {
989
989
  need_pack = 1;
990
990
  break;
991
991
  }
@@ -13,6 +13,7 @@
13
13
  #include "buffer.h"
14
14
  #include "netops.h"
15
15
  #include "smart.h"
16
+ #include "cred.h"
16
17
 
17
18
  #ifdef GIT_SSH
18
19
 
@@ -37,8 +38,12 @@ typedef struct {
37
38
  transport_smart *owner;
38
39
  ssh_stream *current_stream;
39
40
  git_cred *cred;
41
+ char *cmd_uploadpack;
42
+ char *cmd_receivepack;
40
43
  } ssh_subtransport;
41
44
 
45
+ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username);
46
+
42
47
  static void ssh_error(LIBSSH2_SESSION *session, const char *errmsg)
43
48
  {
44
49
  char *ssherr;
@@ -357,6 +362,9 @@ static int _git_ssh_authenticate_session(
357
362
  }
358
363
  } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
359
364
 
365
+ if (rc == LIBSSH2_ERROR_PASSWORD_EXPIRED || rc == LIBSSH2_ERROR_AUTHENTICATION_FAILED)
366
+ return GIT_EAUTH;
367
+
360
368
  if (rc != LIBSSH2_ERROR_NONE) {
361
369
  if (!giterr_last())
362
370
  ssh_error(session, "Failed to authenticate SSH session");
@@ -366,6 +374,43 @@ static int _git_ssh_authenticate_session(
366
374
  return 0;
367
375
  }
368
376
 
377
+ static int request_creds(git_cred **out, ssh_subtransport *t, const char *user, int auth_methods)
378
+ {
379
+ int error, no_callback = 0;
380
+ git_cred *cred = NULL;
381
+
382
+ if (!t->owner->cred_acquire_cb) {
383
+ no_callback = 1;
384
+ } else {
385
+ error = t->owner->cred_acquire_cb(&cred, t->owner->url, user, auth_methods,
386
+ t->owner->cred_acquire_payload);
387
+
388
+ if (error == GIT_PASSTHROUGH)
389
+ no_callback = 1;
390
+ else if (error < 0)
391
+ return error;
392
+ else if (!cred) {
393
+ giterr_set(GITERR_SSH, "Callback failed to initialize SSH credentials");
394
+ return -1;
395
+ }
396
+ }
397
+
398
+ if (no_callback) {
399
+ giterr_set(GITERR_SSH, "authentication required but no callback set");
400
+ return -1;
401
+ }
402
+
403
+ if (!(cred->credtype & auth_methods)) {
404
+ cred->free(cred);
405
+ giterr_set(GITERR_SSH, "callback returned unsupported credentials type");
406
+ return -1;
407
+ }
408
+
409
+ *out = cred;
410
+
411
+ return 0;
412
+ }
413
+
369
414
  static int _git_ssh_session_create(
370
415
  LIBSSH2_SESSION** session,
371
416
  gitno_socket socket)
@@ -406,70 +451,125 @@ static int _git_ssh_setup_conn(
406
451
  {
407
452
  char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL;
408
453
  const char *default_port="22";
409
- int no_callback = 0;
454
+ int auth_methods, error = 0;
410
455
  ssh_stream *s;
456
+ git_cred *cred = NULL;
411
457
  LIBSSH2_SESSION* session=NULL;
412
458
  LIBSSH2_CHANNEL* channel=NULL;
413
459
 
460
+ t->current_stream = NULL;
461
+
414
462
  *stream = NULL;
415
463
  if (ssh_stream_alloc(t, url, cmd, stream) < 0)
416
464
  return -1;
417
465
 
418
466
  s = (ssh_stream *)*stream;
467
+ s->session = NULL;
468
+ s->channel = NULL;
419
469
 
420
470
  if (!git__prefixcmp(url, prefix_ssh)) {
421
- if (gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port) < 0)
422
- goto on_error;
471
+ if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0)
472
+ goto done;
423
473
  } else {
424
- if (git_ssh_extract_url_parts(&host, &user, url) < 0)
425
- goto on_error;
474
+ if ((error = git_ssh_extract_url_parts(&host, &user, url)) < 0)
475
+ goto done;
426
476
  port = git__strdup(default_port);
427
477
  GITERR_CHECK_ALLOC(port);
428
478
  }
429
479
 
430
- if (gitno_connect(&s->socket, host, port, 0) < 0)
431
- goto on_error;
480
+ if ((error = gitno_connect(&s->socket, host, port, 0)) < 0)
481
+ goto done;
432
482
 
433
- if (user && pass) {
434
- if (git_cred_userpass_plaintext_new(&t->cred, user, pass) < 0)
435
- goto on_error;
436
- } else if (!t->owner->cred_acquire_cb) {
437
- no_callback = 1;
438
- } else {
439
- int error;
440
- error = t->owner->cred_acquire_cb(&t->cred, t->owner->url, user,
441
- GIT_CREDTYPE_USERPASS_PLAINTEXT |
442
- GIT_CREDTYPE_SSH_KEY | GIT_CREDTYPE_SSH_CUSTOM |
443
- GIT_CREDTYPE_SSH_INTERACTIVE,
444
- t->owner->cred_acquire_payload);
483
+ if ((error = _git_ssh_session_create(&session, s->socket)) < 0)
484
+ goto done;
445
485
 
446
- if (error == GIT_PASSTHROUGH)
447
- no_callback = 1;
448
- else if (error < 0)
449
- goto on_error;
450
- else if (!t->cred) {
451
- giterr_set(GITERR_SSH, "Callback failed to initialize SSH credentials");
452
- goto on_error;
486
+ if (t->owner->certificate_check_cb != NULL) {
487
+ git_cert_hostkey cert = { 0 }, *cert_ptr;
488
+ const char *key;
489
+
490
+ cert.cert_type = GIT_CERT_HOSTKEY_LIBSSH2;
491
+
492
+ key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
493
+ if (key != NULL) {
494
+ cert.type |= GIT_CERT_SSH_SHA1;
495
+ memcpy(&cert.hash_sha1, key, 20);
496
+ }
497
+
498
+ key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
499
+ if (key != NULL) {
500
+ cert.type |= GIT_CERT_SSH_MD5;
501
+ memcpy(&cert.hash_md5, key, 16);
502
+ }
503
+
504
+ if (cert.type == 0) {
505
+ giterr_set(GITERR_SSH, "unable to get the host key");
506
+ error = -1;
507
+ goto done;
508
+ }
509
+
510
+ /* We don't currently trust any hostkeys */
511
+ giterr_clear();
512
+
513
+ cert_ptr = &cert;
514
+
515
+ error = t->owner->certificate_check_cb((git_cert *) cert_ptr, 0, host, t->owner->message_cb_payload);
516
+ if (error < 0) {
517
+ if (!giterr_last())
518
+ giterr_set(GITERR_NET, "user cancelled hostkey check");
519
+
520
+ goto done;
453
521
  }
454
522
  }
455
523
 
456
- if (no_callback) {
457
- giterr_set(GITERR_SSH, "authentication required but no callback set");
458
- goto on_error;
524
+ /* we need the username to ask for auth methods */
525
+ if (!user) {
526
+ if ((error = request_creds(&cred, t, NULL, GIT_CREDTYPE_USERNAME)) < 0)
527
+ goto done;
528
+
529
+ user = git__strdup(((git_cred_username *) cred)->username);
530
+ cred->free(cred);
531
+ cred = NULL;
532
+ if (!user)
533
+ goto done;
534
+ } else if (user && pass) {
535
+ if ((error = git_cred_userpass_plaintext_new(&cred, user, pass)) < 0)
536
+ goto done;
459
537
  }
460
538
 
461
- assert(t->cred);
539
+ if ((error = list_auth_methods(&auth_methods, session, user)) < 0)
540
+ goto done;
541
+
542
+ error = GIT_EAUTH;
543
+ /* if we already have something to try */
544
+ if (cred && auth_methods & cred->credtype)
545
+ error = _git_ssh_authenticate_session(session, cred);
546
+
547
+ while (error == GIT_EAUTH) {
548
+ if (cred) {
549
+ cred->free(cred);
550
+ cred = NULL;
551
+ }
552
+
553
+ if ((error = request_creds(&cred, t, user, auth_methods)) < 0)
554
+ goto done;
462
555
 
463
- if (_git_ssh_session_create(&session, s->socket) < 0)
464
- goto on_error;
556
+ if (strcmp(user, git_cred__username(cred))) {
557
+ giterr_set(GITERR_SSH, "username does not match previous request");
558
+ error = -1;
559
+ goto done;
560
+ }
465
561
 
466
- if (_git_ssh_authenticate_session(session, t->cred) < 0)
467
- goto on_error;
562
+ error = _git_ssh_authenticate_session(session, cred);
563
+ }
564
+
565
+ if (error < 0)
566
+ goto done;
468
567
 
469
568
  channel = libssh2_channel_open_session(session);
470
569
  if (!channel) {
570
+ error = -1;
471
571
  ssh_error(session, "Failed to open SSH channel");
472
- goto on_error;
572
+ goto done;
473
573
  }
474
574
 
475
575
  libssh2_channel_set_blocking(channel, 1);
@@ -478,31 +578,26 @@ static int _git_ssh_setup_conn(
478
578
  s->channel = channel;
479
579
 
480
580
  t->current_stream = s;
481
- git__free(host);
482
- git__free(port);
483
- git__free(path);
484
- git__free(user);
485
- git__free(pass);
486
581
 
487
- return 0;
582
+ done:
583
+ if (error < 0) {
584
+ if (*stream)
585
+ ssh_stream_free(*stream);
488
586
 
489
- on_error:
490
- s->session = NULL;
491
- s->channel = NULL;
492
- t->current_stream = NULL;
587
+ if (session)
588
+ libssh2_session_free(session);
589
+ }
493
590
 
494
- if (*stream)
495
- ssh_stream_free(*stream);
591
+ if (cred)
592
+ cred->free(cred);
496
593
 
497
594
  git__free(host);
498
595
  git__free(port);
596
+ git__free(path);
499
597
  git__free(user);
500
598
  git__free(pass);
501
599
 
502
- if (session)
503
- libssh2_session_free(session);
504
-
505
- return -1;
600
+ return error;
506
601
  }
507
602
 
508
603
  static int ssh_uploadpack_ls(
@@ -510,10 +605,9 @@ static int ssh_uploadpack_ls(
510
605
  const char *url,
511
606
  git_smart_subtransport_stream **stream)
512
607
  {
513
- if (_git_ssh_setup_conn(t, url, cmd_uploadpack, stream) < 0)
514
- return -1;
608
+ const char *cmd = t->cmd_uploadpack ? t->cmd_uploadpack : cmd_uploadpack;
515
609
 
516
- return 0;
610
+ return _git_ssh_setup_conn(t, url, cmd, stream);
517
611
  }
518
612
 
519
613
  static int ssh_uploadpack(
@@ -537,10 +631,10 @@ static int ssh_receivepack_ls(
537
631
  const char *url,
538
632
  git_smart_subtransport_stream **stream)
539
633
  {
540
- if (_git_ssh_setup_conn(t, url, cmd_receivepack, stream) < 0)
541
- return -1;
634
+ const char *cmd = t->cmd_receivepack ? t->cmd_receivepack : cmd_receivepack;
542
635
 
543
- return 0;
636
+
637
+ return _git_ssh_setup_conn(t, url, cmd, stream);
544
638
  }
545
639
 
546
640
  static int ssh_receivepack(
@@ -602,8 +696,57 @@ static void _ssh_free(git_smart_subtransport *subtransport)
602
696
 
603
697
  assert(!t->current_stream);
604
698
 
699
+ git__free(t->cmd_uploadpack);
700
+ git__free(t->cmd_receivepack);
605
701
  git__free(t);
606
702
  }
703
+
704
+ #define SSH_AUTH_PUBLICKEY "publickey"
705
+ #define SSH_AUTH_PASSWORD "password"
706
+ #define SSH_AUTH_KEYBOARD_INTERACTIVE "keyboard-interactive"
707
+
708
+ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username)
709
+ {
710
+ const char *list, *ptr;
711
+
712
+ *out = 0;
713
+
714
+ list = libssh2_userauth_list(session, username, strlen(username));
715
+
716
+ /* either error, or the remote accepts NONE auth, which is bizarre, let's punt */
717
+ if (list == NULL && !libssh2_userauth_authenticated(session))
718
+ return -1;
719
+
720
+ ptr = list;
721
+ while (ptr) {
722
+ if (*ptr == ',')
723
+ ptr++;
724
+
725
+ if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) {
726
+ *out |= GIT_CREDTYPE_SSH_KEY;
727
+ *out |= GIT_CREDTYPE_SSH_CUSTOM;
728
+ ptr += strlen(SSH_AUTH_PUBLICKEY);
729
+ continue;
730
+ }
731
+
732
+ if (!git__prefixcmp(ptr, SSH_AUTH_PASSWORD)) {
733
+ *out |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
734
+ ptr += strlen(SSH_AUTH_PASSWORD);
735
+ continue;
736
+ }
737
+
738
+ if (!git__prefixcmp(ptr, SSH_AUTH_KEYBOARD_INTERACTIVE)) {
739
+ *out |= GIT_CREDTYPE_SSH_INTERACTIVE;
740
+ ptr += strlen(SSH_AUTH_KEYBOARD_INTERACTIVE);
741
+ continue;
742
+ }
743
+
744
+ /* Skipt it if we don't know it */
745
+ ptr = strchr(ptr, ',');
746
+ }
747
+
748
+ return 0;
749
+ }
607
750
  #endif
608
751
 
609
752
  int git_smart_subtransport_ssh(
@@ -634,3 +777,46 @@ int git_smart_subtransport_ssh(
634
777
  return -1;
635
778
  #endif
636
779
  }
780
+
781
+ int git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *payload)
782
+ {
783
+ #ifdef GIT_SSH
784
+ git_strarray *paths = (git_strarray *) payload;
785
+ git_transport *transport;
786
+ transport_smart *smart;
787
+ ssh_subtransport *t;
788
+ int error;
789
+ git_smart_subtransport_definition ssh_definition = {
790
+ git_smart_subtransport_ssh,
791
+ 0, /* no RPC */
792
+ };
793
+
794
+ if (paths->count != 2) {
795
+ giterr_set(GITERR_SSH, "invalid ssh paths, must be two strings");
796
+ return GIT_EINVALIDSPEC;
797
+ }
798
+
799
+ if ((error = git_transport_smart(&transport, owner, &ssh_definition)) < 0)
800
+ return error;
801
+
802
+ smart = (transport_smart *) transport;
803
+ t = (ssh_subtransport *) smart->wrapped;
804
+
805
+ t->cmd_uploadpack = git__strdup(paths->strings[0]);
806
+ GITERR_CHECK_ALLOC(t->cmd_uploadpack);
807
+ t->cmd_receivepack = git__strdup(paths->strings[1]);
808
+ GITERR_CHECK_ALLOC(t->cmd_receivepack);
809
+
810
+ *out = transport;
811
+ return 0;
812
+ #else
813
+ GIT_UNUSED(owner);
814
+ GIT_UNUSED(payload);
815
+
816
+ assert(out);
817
+ *out = NULL;
818
+
819
+ giterr_set(GITERR_INVALID, "Cannot create SSH transport. Library was built without SSH support");
820
+ return -1;
821
+ #endif
822
+ }