diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 185 |
1 files changed, 102 insertions, 83 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 933c223ec..3a218113c 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: sshconnect2.c,v 1.124 2003/08/25 10:33:33 djm Exp $"); | 26 | RCSID("$OpenBSD: sshconnect2.c,v 1.134 2004/01/19 21:25:15 markus Exp $"); |
27 | 27 | ||
28 | #include "openbsd-compat/sys-queue.h" | 28 | #include "openbsd-compat/sys-queue.h" |
29 | 29 | ||
@@ -222,7 +222,7 @@ static char *authmethods_get(void); | |||
222 | 222 | ||
223 | Authmethod authmethods[] = { | 223 | Authmethod authmethods[] = { |
224 | #ifdef GSSAPI | 224 | #ifdef GSSAPI |
225 | {"gssapi", | 225 | {"gssapi-with-mic", |
226 | userauth_gssapi, | 226 | userauth_gssapi, |
227 | &options.gss_authentication, | 227 | &options.gss_authentication, |
228 | NULL}, | 228 | NULL}, |
@@ -358,10 +358,12 @@ void | |||
358 | input_userauth_banner(int type, u_int32_t seq, void *ctxt) | 358 | input_userauth_banner(int type, u_int32_t seq, void *ctxt) |
359 | { | 359 | { |
360 | char *msg, *lang; | 360 | char *msg, *lang; |
361 | |||
361 | debug3("input_userauth_banner"); | 362 | debug3("input_userauth_banner"); |
362 | msg = packet_get_string(NULL); | 363 | msg = packet_get_string(NULL); |
363 | lang = packet_get_string(NULL); | 364 | lang = packet_get_string(NULL); |
364 | logit("%s", msg); | 365 | if (options.log_level > SYSLOG_LEVEL_QUIET) |
366 | fprintf(stderr, "%s", msg); | ||
365 | xfree(msg); | 367 | xfree(msg); |
366 | xfree(lang); | 368 | xfree(lang); |
367 | } | 369 | } |
@@ -372,10 +374,14 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt) | |||
372 | Authctxt *authctxt = ctxt; | 374 | Authctxt *authctxt = ctxt; |
373 | if (authctxt == NULL) | 375 | if (authctxt == NULL) |
374 | fatal("input_userauth_success: no authentication context"); | 376 | fatal("input_userauth_success: no authentication context"); |
375 | if (authctxt->authlist) | 377 | if (authctxt->authlist) { |
376 | xfree(authctxt->authlist); | 378 | xfree(authctxt->authlist); |
377 | if (authctxt->methoddata) | 379 | authctxt->authlist = NULL; |
380 | } | ||
381 | if (authctxt->methoddata) { | ||
378 | xfree(authctxt->methoddata); | 382 | xfree(authctxt->methoddata); |
383 | authctxt->methoddata = NULL; | ||
384 | } | ||
379 | authctxt->success = 1; /* break out */ | 385 | authctxt->success = 1; /* break out */ |
380 | } | 386 | } |
381 | 387 | ||
@@ -447,7 +453,12 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) | |||
447 | debug2("input_userauth_pk_ok: fp %s", fp); | 453 | debug2("input_userauth_pk_ok: fp %s", fp); |
448 | xfree(fp); | 454 | xfree(fp); |
449 | 455 | ||
450 | TAILQ_FOREACH(id, &authctxt->keys, next) { | 456 | /* |
457 | * search keys in the reverse order, because last candidate has been | ||
458 | * moved to the end of the queue. this also avoids confusion by | ||
459 | * duplicate keys | ||
460 | */ | ||
461 | TAILQ_FOREACH_REVERSE(id, &authctxt->keys, next, idlist) { | ||
451 | if (key_equal(key, id->key)) { | 462 | if (key_equal(key, id->key)) { |
452 | sent = sign_and_send_pubkey(authctxt, id); | 463 | sent = sign_and_send_pubkey(authctxt, id); |
453 | break; | 464 | break; |
@@ -465,11 +476,11 @@ done: | |||
465 | } | 476 | } |
466 | 477 | ||
467 | #ifdef GSSAPI | 478 | #ifdef GSSAPI |
468 | int | 479 | int |
469 | userauth_gssapi(Authctxt *authctxt) | 480 | userauth_gssapi(Authctxt *authctxt) |
470 | { | 481 | { |
471 | Gssctxt *gssctxt = NULL; | 482 | Gssctxt *gssctxt = NULL; |
472 | static gss_OID_set supported = NULL; | 483 | static gss_OID_set gss_supported = NULL; |
473 | static int mech = 0; | 484 | static int mech = 0; |
474 | OM_uint32 min; | 485 | OM_uint32 min; |
475 | int ok = 0; | 486 | int ok = 0; |
@@ -477,18 +488,18 @@ userauth_gssapi(Authctxt *authctxt) | |||
477 | /* Try one GSSAPI method at a time, rather than sending them all at | 488 | /* Try one GSSAPI method at a time, rather than sending them all at |
478 | * once. */ | 489 | * once. */ |
479 | 490 | ||
480 | if (supported == NULL) | 491 | if (gss_supported == NULL) |
481 | gss_indicate_mechs(&min, &supported); | 492 | gss_indicate_mechs(&min, &gss_supported); |
482 | 493 | ||
483 | /* Check to see if the mechanism is usable before we offer it */ | 494 | /* Check to see if the mechanism is usable before we offer it */ |
484 | while (mech<supported->count && !ok) { | 495 | while (mech < gss_supported->count && !ok) { |
485 | if (gssctxt) | 496 | if (gssctxt) |
486 | ssh_gssapi_delete_ctx(&gssctxt); | 497 | ssh_gssapi_delete_ctx(&gssctxt); |
487 | ssh_gssapi_build_ctx(&gssctxt); | 498 | ssh_gssapi_build_ctx(&gssctxt); |
488 | ssh_gssapi_set_oid(gssctxt, &supported->elements[mech]); | 499 | ssh_gssapi_set_oid(gssctxt, &gss_supported->elements[mech]); |
489 | 500 | ||
490 | /* My DER encoding requires length<128 */ | 501 | /* My DER encoding requires length<128 */ |
491 | if (supported->elements[mech].length < 128 && | 502 | if (gss_supported->elements[mech].length < 128 && |
492 | !GSS_ERROR(ssh_gssapi_import_name(gssctxt, | 503 | !GSS_ERROR(ssh_gssapi_import_name(gssctxt, |
493 | authctxt->host))) { | 504 | authctxt->host))) { |
494 | ok = 1; /* Mechanism works */ | 505 | ok = 1; /* Mechanism works */ |
@@ -508,17 +519,11 @@ userauth_gssapi(Authctxt *authctxt) | |||
508 | 519 | ||
509 | packet_put_int(1); | 520 | packet_put_int(1); |
510 | 521 | ||
511 | /* Some servers encode the OID incorrectly (as we used to) */ | 522 | packet_put_int((gss_supported->elements[mech].length) + 2); |
512 | if (datafellows & SSH_BUG_GSSAPI_BER) { | 523 | packet_put_char(SSH_GSS_OIDTYPE); |
513 | packet_put_string(supported->elements[mech].elements, | 524 | packet_put_char(gss_supported->elements[mech].length); |
514 | supported->elements[mech].length); | 525 | packet_put_raw(gss_supported->elements[mech].elements, |
515 | } else { | 526 | gss_supported->elements[mech].length); |
516 | packet_put_int((supported->elements[mech].length)+2); | ||
517 | packet_put_char(SSH_GSS_OIDTYPE); | ||
518 | packet_put_char(supported->elements[mech].length); | ||
519 | packet_put_raw(supported->elements[mech].elements, | ||
520 | supported->elements[mech].length); | ||
521 | } | ||
522 | 527 | ||
523 | packet_send(); | 528 | packet_send(); |
524 | 529 | ||
@@ -532,15 +537,66 @@ userauth_gssapi(Authctxt *authctxt) | |||
532 | return 1; | 537 | return 1; |
533 | } | 538 | } |
534 | 539 | ||
540 | static OM_uint32 | ||
541 | process_gssapi_token(void *ctxt, gss_buffer_t recv_tok) | ||
542 | { | ||
543 | Authctxt *authctxt = ctxt; | ||
544 | Gssctxt *gssctxt = authctxt->methoddata; | ||
545 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
546 | gss_buffer_desc gssbuf, mic; | ||
547 | OM_uint32 status, ms, flags; | ||
548 | Buffer b; | ||
549 | |||
550 | status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | ||
551 | recv_tok, &send_tok, &flags); | ||
552 | |||
553 | if (send_tok.length > 0) { | ||
554 | if (GSS_ERROR(status)) | ||
555 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); | ||
556 | else | ||
557 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | ||
558 | |||
559 | packet_put_string(send_tok.value, send_tok.length); | ||
560 | packet_send(); | ||
561 | gss_release_buffer(&ms, &send_tok); | ||
562 | } | ||
563 | |||
564 | if (status == GSS_S_COMPLETE) { | ||
565 | /* send either complete or MIC, depending on mechanism */ | ||
566 | if (!(flags & GSS_C_INTEG_FLAG)) { | ||
567 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); | ||
568 | packet_send(); | ||
569 | } else { | ||
570 | ssh_gssapi_buildmic(&b, authctxt->server_user, | ||
571 | authctxt->service, "gssapi-with-mic"); | ||
572 | |||
573 | gssbuf.value = buffer_ptr(&b); | ||
574 | gssbuf.length = buffer_len(&b); | ||
575 | |||
576 | status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic); | ||
577 | |||
578 | if (!GSS_ERROR(status)) { | ||
579 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC); | ||
580 | packet_put_string(mic.value, mic.length); | ||
581 | |||
582 | packet_send(); | ||
583 | } | ||
584 | |||
585 | buffer_free(&b); | ||
586 | gss_release_buffer(&ms, &mic); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | return status; | ||
591 | } | ||
592 | |||
535 | void | 593 | void |
536 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) | 594 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) |
537 | { | 595 | { |
538 | Authctxt *authctxt = ctxt; | 596 | Authctxt *authctxt = ctxt; |
539 | Gssctxt *gssctxt; | 597 | Gssctxt *gssctxt; |
540 | OM_uint32 status, ms; | ||
541 | int oidlen; | 598 | int oidlen; |
542 | char *oidv; | 599 | char *oidv; |
543 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
544 | 600 | ||
545 | if (authctxt == NULL) | 601 | if (authctxt == NULL) |
546 | fatal("input_gssapi_response: no authentication context"); | 602 | fatal("input_gssapi_response: no authentication context"); |
@@ -549,94 +605,55 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
549 | /* Setup our OID */ | 605 | /* Setup our OID */ |
550 | oidv = packet_get_string(&oidlen); | 606 | oidv = packet_get_string(&oidlen); |
551 | 607 | ||
552 | if (datafellows & SSH_BUG_GSSAPI_BER) { | 608 | if (oidlen <= 2 || |
553 | if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen)) | 609 | oidv[0] != SSH_GSS_OIDTYPE || |
554 | fatal("Server returned different OID than expected"); | 610 | oidv[1] != oidlen - 2) { |
555 | } else { | 611 | xfree(oidv); |
556 | if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) { | 612 | debug("Badly encoded mechanism OID received"); |
557 | debug("Badly encoded mechanism OID received"); | 613 | userauth(authctxt, NULL); |
558 | userauth(authctxt, NULL); | 614 | return; |
559 | xfree(oidv); | ||
560 | return; | ||
561 | } | ||
562 | if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2)) | ||
563 | fatal("Server returned different OID than expected"); | ||
564 | } | 615 | } |
565 | 616 | ||
617 | if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) | ||
618 | fatal("Server returned different OID than expected"); | ||
619 | |||
566 | packet_check_eom(); | 620 | packet_check_eom(); |
567 | 621 | ||
568 | xfree(oidv); | 622 | xfree(oidv); |
569 | 623 | ||
570 | status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | 624 | if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) { |
571 | GSS_C_NO_BUFFER, &send_tok, NULL); | ||
572 | if (GSS_ERROR(status)) { | ||
573 | if (send_tok.length > 0) { | ||
574 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); | ||
575 | packet_put_string(send_tok.value, send_tok.length); | ||
576 | packet_send(); | ||
577 | gss_release_buffer(&ms, &send_tok); | ||
578 | } | ||
579 | /* Start again with next method on list */ | 625 | /* Start again with next method on list */ |
580 | debug("Trying to start again"); | 626 | debug("Trying to start again"); |
581 | userauth(authctxt, NULL); | 627 | userauth(authctxt, NULL); |
582 | return; | 628 | return; |
583 | } | 629 | } |
584 | |||
585 | /* We must have data to send */ | ||
586 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | ||
587 | packet_put_string(send_tok.value, send_tok.length); | ||
588 | packet_send(); | ||
589 | gss_release_buffer(&ms, &send_tok); | ||
590 | } | 630 | } |
591 | 631 | ||
592 | void | 632 | void |
593 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) | 633 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) |
594 | { | 634 | { |
595 | Authctxt *authctxt = ctxt; | 635 | Authctxt *authctxt = ctxt; |
596 | Gssctxt *gssctxt; | ||
597 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
598 | gss_buffer_desc recv_tok; | 636 | gss_buffer_desc recv_tok; |
599 | OM_uint32 status, ms; | 637 | OM_uint32 status; |
600 | u_int slen; | 638 | u_int slen; |
601 | 639 | ||
602 | if (authctxt == NULL) | 640 | if (authctxt == NULL) |
603 | fatal("input_gssapi_response: no authentication context"); | 641 | fatal("input_gssapi_response: no authentication context"); |
604 | gssctxt = authctxt->methoddata; | ||
605 | 642 | ||
606 | recv_tok.value = packet_get_string(&slen); | 643 | recv_tok.value = packet_get_string(&slen); |
607 | recv_tok.length = slen; /* safe typecast */ | 644 | recv_tok.length = slen; /* safe typecast */ |
608 | 645 | ||
609 | packet_check_eom(); | 646 | packet_check_eom(); |
610 | 647 | ||
611 | status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | 648 | status = process_gssapi_token(ctxt, &recv_tok); |
612 | &recv_tok, &send_tok, NULL); | ||
613 | 649 | ||
614 | xfree(recv_tok.value); | 650 | xfree(recv_tok.value); |
615 | 651 | ||
616 | if (GSS_ERROR(status)) { | 652 | if (GSS_ERROR(status)) { |
617 | if (send_tok.length > 0) { | ||
618 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); | ||
619 | packet_put_string(send_tok.value, send_tok.length); | ||
620 | packet_send(); | ||
621 | gss_release_buffer(&ms, &send_tok); | ||
622 | } | ||
623 | /* Start again with the next method in the list */ | 653 | /* Start again with the next method in the list */ |
624 | userauth(authctxt, NULL); | 654 | userauth(authctxt, NULL); |
625 | return; | 655 | return; |
626 | } | 656 | } |
627 | |||
628 | if (send_tok.length > 0) { | ||
629 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | ||
630 | packet_put_string(send_tok.value, send_tok.length); | ||
631 | packet_send(); | ||
632 | gss_release_buffer(&ms, &send_tok); | ||
633 | } | ||
634 | |||
635 | if (status == GSS_S_COMPLETE) { | ||
636 | /* If that succeeded, send a exchange complete message */ | ||
637 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); | ||
638 | packet_send(); | ||
639 | } | ||
640 | } | 657 | } |
641 | 658 | ||
642 | void | 659 | void |
@@ -1016,7 +1033,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1016 | key = ssh_get_next_identity(ac, &comment, 2)) { | 1033 | key = ssh_get_next_identity(ac, &comment, 2)) { |
1017 | found = 0; | 1034 | found = 0; |
1018 | TAILQ_FOREACH(id, &files, next) { | 1035 | TAILQ_FOREACH(id, &files, next) { |
1019 | /* agent keys from the config file are preferred */ | 1036 | /* agent keys from the config file are preferred */ |
1020 | if (key_equal(key, id->key)) { | 1037 | if (key_equal(key, id->key)) { |
1021 | key_free(key); | 1038 | key_free(key); |
1022 | xfree(comment); | 1039 | xfree(comment); |
@@ -1080,6 +1097,7 @@ userauth_pubkey(Authctxt *authctxt) | |||
1080 | while ((id = TAILQ_FIRST(&authctxt->keys))) { | 1097 | while ((id = TAILQ_FIRST(&authctxt->keys))) { |
1081 | if (id->tried++) | 1098 | if (id->tried++) |
1082 | return (0); | 1099 | return (0); |
1100 | /* move key to the end of the queue */ | ||
1083 | TAILQ_REMOVE(&authctxt->keys, id, next); | 1101 | TAILQ_REMOVE(&authctxt->keys, id, next); |
1084 | TAILQ_INSERT_TAIL(&authctxt->keys, id, next); | 1102 | TAILQ_INSERT_TAIL(&authctxt->keys, id, next); |
1085 | /* | 1103 | /* |
@@ -1244,11 +1262,12 @@ ssh_keysign(Key *key, u_char **sigp, u_int *lenp, | |||
1244 | buffer_init(&b); | 1262 | buffer_init(&b); |
1245 | buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */ | 1263 | buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */ |
1246 | buffer_put_string(&b, data, datalen); | 1264 | buffer_put_string(&b, data, datalen); |
1247 | ssh_msg_send(to[1], version, &b); | 1265 | if (ssh_msg_send(to[1], version, &b) == -1) |
1266 | fatal("ssh_keysign: couldn't send request"); | ||
1248 | 1267 | ||
1249 | if (ssh_msg_recv(from[0], &b) < 0) { | 1268 | if (ssh_msg_recv(from[0], &b) < 0) { |
1250 | error("ssh_keysign: no reply"); | 1269 | error("ssh_keysign: no reply"); |
1251 | buffer_clear(&b); | 1270 | buffer_free(&b); |
1252 | return -1; | 1271 | return -1; |
1253 | } | 1272 | } |
1254 | close(from[0]); | 1273 | close(from[0]); |
@@ -1260,11 +1279,11 @@ ssh_keysign(Key *key, u_char **sigp, u_int *lenp, | |||
1260 | 1279 | ||
1261 | if (buffer_get_char(&b) != version) { | 1280 | if (buffer_get_char(&b) != version) { |
1262 | error("ssh_keysign: bad version"); | 1281 | error("ssh_keysign: bad version"); |
1263 | buffer_clear(&b); | 1282 | buffer_free(&b); |
1264 | return -1; | 1283 | return -1; |
1265 | } | 1284 | } |
1266 | *sigp = buffer_get_string(&b, lenp); | 1285 | *sigp = buffer_get_string(&b, lenp); |
1267 | buffer_clear(&b); | 1286 | buffer_free(&b); |
1268 | 1287 | ||
1269 | return 0; | 1288 | return 0; |
1270 | } | 1289 | } |