Skip to content

Commit c97d302

Browse files
authored
Merge pull request libgit2#4879 from libgit2/ethomson/defer_cert_cred_cb
Allow certificate and credential callbacks to decline to act
2 parents c3b427b + a2e6e0e commit c97d302

File tree

7 files changed

+35
-8
lines changed

7 files changed

+35
-8
lines changed

include/git2/errors.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ typedef enum {
5252
GIT_EDIRECTORY = -23, /**< The operation is not valid for a directory */
5353
GIT_EMERGECONFLICT = -24, /**< A merge conflict exists and cannot continue */
5454

55-
GIT_PASSTHROUGH = -30, /**< Internal only */
55+
GIT_PASSTHROUGH = -30, /**< A user-configured callback refused to act */
5656
GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */
5757
GIT_RETRY = -32, /**< Internal only */
5858
GIT_EMISMATCH = -33, /**< Hashsum mismatch in object */

include/git2/sys/transport.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,10 @@ GIT_EXTERN(int) git_transport_smart(
226226
* @param cert the certificate to pass to the caller
227227
* @param valid whether we believe the certificate is valid
228228
* @param hostname the hostname we connected to
229-
* @return the return value of the callback
229+
* @return the return value of the callback: 0 for no error, GIT_PASSTHROUGH
230+
* to indicate that there is no callback registered (or the callback
231+
* refused to validate the certificate and callers should behave as
232+
* if no callback was set), or < 0 for an error
230233
*/
231234
GIT_EXTERN(int) git_transport_smart_certificate_check(git_transport *transport, git_cert *cert, int valid, const char *hostname);
232235

@@ -237,7 +240,10 @@ GIT_EXTERN(int) git_transport_smart_certificate_check(git_transport *transport,
237240
* @param transport a smart transport
238241
* @param user the user we saw on the url (if any)
239242
* @param methods available methods for authentication
240-
* @return the return value of the callback
243+
* @return the return value of the callback: 0 for no error, GIT_PASSTHROUGH
244+
* to indicate that there is no callback registered (or the callback
245+
* refused to provide credentials and callers should behave as if no
246+
* callback was set), or < 0 for an error
241247
*/
242248
GIT_EXTERN(int) git_transport_smart_credentials(git_cred **out, git_transport *transport, const char *user, int methods);
243249

include/git2/types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ typedef struct {
333333
* this certificate is valid
334334
* @param host Hostname of the host libgit2 connected to
335335
* @param payload Payload provided by the caller
336+
* @return 0 to proceed with the connection, < 0 to fail the connection
337+
* or > 0 to indicate that the callback refused to act and that
338+
* the existing validity determination should be honored
336339
*/
337340
typedef int (*git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload);
338341

src/transports/http.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ static int on_headers_complete(http_parser *parser)
371371
allowed_auth_types,
372372
t->owner->cred_acquire_payload);
373373

374+
/* treat GIT_PASSTHROUGH as if callback isn't set */
374375
if (error == GIT_PASSTHROUGH) {
375376
no_callback = 1;
376377
} else if (error < 0) {
@@ -639,6 +640,9 @@ static int http_connect(http_subtransport *t)
639640
giterr_clear();
640641
error = t->owner->certificate_check_cb(cert, is_valid, t->connection_data.host, t->owner->message_cb_payload);
641642

643+
if (error == GIT_PASSTHROUGH)
644+
error = is_valid ? 0 : GIT_ECERTIFICATE;
645+
642646
if (error < 0) {
643647
if (!giterr_last())
644648
giterr_set(GITERR_NET, "user cancelled certificate check");

src/transports/smart.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,23 @@ int git_transport_smart_certificate_check(git_transport *transport, git_cert *ce
481481
{
482482
transport_smart *t = (transport_smart *)transport;
483483

484+
assert(transport && cert && hostname);
485+
486+
if (!t->certificate_check_cb)
487+
return GIT_PASSTHROUGH;
488+
484489
return t->certificate_check_cb(cert, valid, hostname, t->message_cb_payload);
485490
}
486491

487492
int git_transport_smart_credentials(git_cred **out, git_transport *transport, const char *user, int methods)
488493
{
489494
transport_smart *t = (transport_smart *)transport;
490495

496+
assert(out && transport);
497+
498+
if (!t->cred_acquire_cb)
499+
return GIT_PASSTHROUGH;
500+
491501
return t->cred_acquire_cb(out, t->url, user, methods, t->cred_acquire_payload);
492502
}
493503

src/transports/ssh.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,11 @@ static int request_creds(git_cred **out, ssh_subtransport *t, const char *user,
447447
error = t->owner->cred_acquire_cb(&cred, t->owner->url, user, auth_methods,
448448
t->owner->cred_acquire_payload);
449449

450-
if (error == GIT_PASSTHROUGH)
450+
if (error == GIT_PASSTHROUGH) {
451451
no_callback = 1;
452-
else if (error < 0)
452+
} else if (error < 0) {
453453
return error;
454-
else if (!cred) {
454+
} else if (!cred) {
455455
giterr_set(GITERR_SSH, "callback failed to initialize SSH credentials");
456456
return -1;
457457
}
@@ -584,7 +584,8 @@ static int _git_ssh_setup_conn(
584584
cert_ptr = &cert;
585585

586586
error = t->owner->certificate_check_cb((git_cert *) cert_ptr, 0, host, t->owner->message_cb_payload);
587-
if (error < 0) {
587+
588+
if (error < 0 && error != GIT_PASSTHROUGH) {
588589
if (!giterr_last())
589590
giterr_set(GITERR_NET, "user cancelled hostkey check");
590591

src/transports/winhttp.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ static int fallback_cred_acquire_cb(
228228
}
229229

230230
hCoInitResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
231-
231+
232232
if (SUCCEEDED(hCoInitResult) || hCoInitResult == RPC_E_CHANGED_MODE) {
233233
IInternetSecurityManager* pISM;
234234

@@ -295,6 +295,9 @@ static int certificate_check(winhttp_stream *s, int valid)
295295
error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->connection_data.host, t->owner->message_cb_payload);
296296
CertFreeCertificateContext(cert_ctx);
297297

298+
if (error == GIT_PASSTHROUGH)
299+
error = valid ? 0 : GIT_ECERTIFICATE;
300+
298301
if (error < 0 && !giterr_last())
299302
giterr_set(GITERR_NET, "user cancelled certificate check");
300303

0 commit comments

Comments
 (0)