diff options
author | Darren Tucker <dtucker@zip.com.au> | 2003-08-26 11:49:55 +1000 |
---|---|---|
committer | Darren Tucker <dtucker@zip.com.au> | 2003-08-26 11:49:55 +1000 |
commit | 0efd155c3c184f0eaa2e1eb244eaaf066e6906e0 (patch) | |
tree | 10f24586373d825d68cefd4a3746fe738cf0614a /sshconnect2.c | |
parent | 30912f7259b771a1cf705c0bc47a6c3f3edffb43 (diff) |
- markus@cvs.openbsd.org 2003/08/22 10:56:09
[auth2.c auth2-gss.c auth.h compat.c compat.h gss-genr.c gss-serv-krb5.c
gss-serv.c monitor.c monitor.h monitor_wrap.c monitor_wrap.h readconf.c
readconf.h servconf.c servconf.h session.c session.h ssh-gss.h
ssh_config.5 sshconnect2.c sshd_config sshd_config.5]
support GSS API user authentication; patches from Simon Wilkinson,
stripped down and tested by Jakob and myself.
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 252 |
1 files changed, 251 insertions, 1 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 6a0bd409a..c71ad506b 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.120 2003/06/24 08:23:46 markus Exp $"); | 26 | RCSID("$OpenBSD: sshconnect2.c,v 1.121 2003/08/22 10:56:09 markus Exp $"); |
27 | 27 | ||
28 | #ifdef KRB5 | 28 | #ifdef KRB5 |
29 | #include <krb5.h> | 29 | #include <krb5.h> |
@@ -57,6 +57,10 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.120 2003/06/24 08:23:46 markus Exp $"); | |||
57 | #include "msg.h" | 57 | #include "msg.h" |
58 | #include "pathnames.h" | 58 | #include "pathnames.h" |
59 | 59 | ||
60 | #ifdef GSSAPI | ||
61 | #include "ssh-gss.h" | ||
62 | #endif | ||
63 | |||
60 | /* import */ | 64 | /* import */ |
61 | extern char *client_version_string; | 65 | extern char *client_version_string; |
62 | extern char *server_version_string; | 66 | extern char *server_version_string; |
@@ -178,6 +182,8 @@ struct Authctxt { | |||
178 | Sensitive *sensitive; | 182 | Sensitive *sensitive; |
179 | /* kbd-interactive */ | 183 | /* kbd-interactive */ |
180 | int info_req_seen; | 184 | int info_req_seen; |
185 | /* generic */ | ||
186 | void *methoddata; | ||
181 | }; | 187 | }; |
182 | struct Authmethod { | 188 | struct Authmethod { |
183 | char *name; /* string to compare against server's list */ | 189 | char *name; /* string to compare against server's list */ |
@@ -201,6 +207,15 @@ int userauth_kbdint(Authctxt *); | |||
201 | int userauth_hostbased(Authctxt *); | 207 | int userauth_hostbased(Authctxt *); |
202 | int userauth_kerberos(Authctxt *); | 208 | int userauth_kerberos(Authctxt *); |
203 | 209 | ||
210 | #ifdef GSSAPI | ||
211 | int userauth_gssapi(Authctxt *authctxt); | ||
212 | void input_gssapi_response(int type, u_int32_t, void *); | ||
213 | void input_gssapi_token(int type, u_int32_t, void *); | ||
214 | void input_gssapi_hash(int type, u_int32_t, void *); | ||
215 | void input_gssapi_error(int, u_int32_t, void *); | ||
216 | void input_gssapi_errtok(int, u_int32_t, void *); | ||
217 | #endif | ||
218 | |||
204 | void userauth(Authctxt *, char *); | 219 | void userauth(Authctxt *, char *); |
205 | 220 | ||
206 | static int sign_and_send_pubkey(Authctxt *, Identity *); | 221 | static int sign_and_send_pubkey(Authctxt *, Identity *); |
@@ -213,6 +228,12 @@ static Authmethod *authmethod_lookup(const char *name); | |||
213 | static char *authmethods_get(void); | 228 | static char *authmethods_get(void); |
214 | 229 | ||
215 | Authmethod authmethods[] = { | 230 | Authmethod authmethods[] = { |
231 | #ifdef GSSAPI | ||
232 | {"gssapi", | ||
233 | userauth_gssapi, | ||
234 | &options.gss_authentication, | ||
235 | NULL}, | ||
236 | #endif | ||
216 | {"hostbased", | 237 | {"hostbased", |
217 | userauth_hostbased, | 238 | userauth_hostbased, |
218 | &options.hostbased_authentication, | 239 | &options.hostbased_authentication, |
@@ -283,6 +304,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
283 | authctxt.success = 0; | 304 | authctxt.success = 0; |
284 | authctxt.method = authmethod_lookup("none"); | 305 | authctxt.method = authmethod_lookup("none"); |
285 | authctxt.authlist = NULL; | 306 | authctxt.authlist = NULL; |
307 | authctxt.methoddata = NULL; | ||
286 | authctxt.sensitive = sensitive; | 308 | authctxt.sensitive = sensitive; |
287 | authctxt.info_req_seen = 0; | 309 | authctxt.info_req_seen = 0; |
288 | if (authctxt.method == NULL) | 310 | if (authctxt.method == NULL) |
@@ -306,6 +328,10 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
306 | void | 328 | void |
307 | userauth(Authctxt *authctxt, char *authlist) | 329 | userauth(Authctxt *authctxt, char *authlist) |
308 | { | 330 | { |
331 | if (authctxt->methoddata) { | ||
332 | xfree(authctxt->methoddata); | ||
333 | authctxt->methoddata = NULL; | ||
334 | } | ||
309 | if (authlist == NULL) { | 335 | if (authlist == NULL) { |
310 | authlist = authctxt->authlist; | 336 | authlist = authctxt->authlist; |
311 | } else { | 337 | } else { |
@@ -361,6 +387,8 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt) | |||
361 | fatal("input_userauth_success: no authentication context"); | 387 | fatal("input_userauth_success: no authentication context"); |
362 | if (authctxt->authlist) | 388 | if (authctxt->authlist) |
363 | xfree(authctxt->authlist); | 389 | xfree(authctxt->authlist); |
390 | if (authctxt->methoddata) | ||
391 | xfree(authctxt->methoddata); | ||
364 | authctxt->success = 1; /* break out */ | 392 | authctxt->success = 1; /* break out */ |
365 | } | 393 | } |
366 | 394 | ||
@@ -449,6 +477,228 @@ done: | |||
449 | userauth(authctxt, NULL); | 477 | userauth(authctxt, NULL); |
450 | } | 478 | } |
451 | 479 | ||
480 | #ifdef GSSAPI | ||
481 | int | ||
482 | userauth_gssapi(Authctxt *authctxt) | ||
483 | { | ||
484 | Gssctxt *gssctxt = NULL; | ||
485 | static gss_OID_set supported = NULL; | ||
486 | static int mech = 0; | ||
487 | OM_uint32 min; | ||
488 | int ok = 0; | ||
489 | |||
490 | /* Try one GSSAPI method at a time, rather than sending them all at | ||
491 | * once. */ | ||
492 | |||
493 | if (supported == NULL) | ||
494 | gss_indicate_mechs(&min, &supported); | ||
495 | |||
496 | /* Check to see if the mechanism is usable before we offer it */ | ||
497 | while (mech<supported->count && !ok) { | ||
498 | if (gssctxt) | ||
499 | ssh_gssapi_delete_ctx(&gssctxt); | ||
500 | ssh_gssapi_build_ctx(&gssctxt); | ||
501 | ssh_gssapi_set_oid(gssctxt, &supported->elements[mech]); | ||
502 | |||
503 | /* My DER encoding requires length<128 */ | ||
504 | if (supported->elements[mech].length < 128 && | ||
505 | !GSS_ERROR(ssh_gssapi_import_name(gssctxt, | ||
506 | authctxt->host))) { | ||
507 | ok = 1; /* Mechanism works */ | ||
508 | } else { | ||
509 | mech++; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | if (!ok) return 0; | ||
514 | |||
515 | authctxt->methoddata=(void *)gssctxt; | ||
516 | |||
517 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
518 | packet_put_cstring(authctxt->server_user); | ||
519 | packet_put_cstring(authctxt->service); | ||
520 | packet_put_cstring(authctxt->method->name); | ||
521 | |||
522 | packet_put_int(1); | ||
523 | |||
524 | /* Some servers encode the OID incorrectly (as we used to) */ | ||
525 | if (datafellows & SSH_BUG_GSSAPI_BER) { | ||
526 | packet_put_string(supported->elements[mech].elements, | ||
527 | supported->elements[mech].length); | ||
528 | } else { | ||
529 | packet_put_int((supported->elements[mech].length)+2); | ||
530 | packet_put_char(SSH_GSS_OIDTYPE); | ||
531 | packet_put_char(supported->elements[mech].length); | ||
532 | packet_put_raw(supported->elements[mech].elements, | ||
533 | supported->elements[mech].length); | ||
534 | } | ||
535 | |||
536 | packet_send(); | ||
537 | |||
538 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); | ||
539 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); | ||
540 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); | ||
541 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); | ||
542 | |||
543 | mech++; /* Move along to next candidate */ | ||
544 | |||
545 | return 1; | ||
546 | } | ||
547 | |||
548 | void | ||
549 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) | ||
550 | { | ||
551 | Authctxt *authctxt = ctxt; | ||
552 | Gssctxt *gssctxt; | ||
553 | OM_uint32 status, ms; | ||
554 | int oidlen; | ||
555 | char *oidv; | ||
556 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
557 | |||
558 | if (authctxt == NULL) | ||
559 | fatal("input_gssapi_response: no authentication context"); | ||
560 | gssctxt = authctxt->methoddata; | ||
561 | |||
562 | /* Setup our OID */ | ||
563 | oidv = packet_get_string(&oidlen); | ||
564 | |||
565 | if (datafellows & SSH_BUG_GSSAPI_BER) { | ||
566 | if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen)) | ||
567 | fatal("Server returned different OID than expected"); | ||
568 | } else { | ||
569 | if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) { | ||
570 | debug("Badly encoded mechanism OID received"); | ||
571 | userauth(authctxt, NULL); | ||
572 | xfree(oidv); | ||
573 | return; | ||
574 | } | ||
575 | if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2)) | ||
576 | fatal("Server returned different OID than expected"); | ||
577 | } | ||
578 | |||
579 | packet_check_eom(); | ||
580 | |||
581 | xfree(oidv); | ||
582 | |||
583 | status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | ||
584 | GSS_C_NO_BUFFER, &send_tok, NULL); | ||
585 | if (GSS_ERROR(status)) { | ||
586 | if (send_tok.length > 0) { | ||
587 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); | ||
588 | packet_put_string(send_tok.value, send_tok.length); | ||
589 | packet_send(); | ||
590 | gss_release_buffer(&ms, &send_tok); | ||
591 | } | ||
592 | /* Start again with next method on list */ | ||
593 | debug("Trying to start again"); | ||
594 | userauth(authctxt, NULL); | ||
595 | return; | ||
596 | } | ||
597 | |||
598 | /* We must have data to send */ | ||
599 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | ||
600 | packet_put_string(send_tok.value, send_tok.length); | ||
601 | packet_send(); | ||
602 | gss_release_buffer(&ms, &send_tok); | ||
603 | } | ||
604 | |||
605 | void | ||
606 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) | ||
607 | { | ||
608 | Authctxt *authctxt = ctxt; | ||
609 | Gssctxt *gssctxt; | ||
610 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
611 | gss_buffer_desc recv_tok; | ||
612 | OM_uint32 status, ms; | ||
613 | u_int slen; | ||
614 | |||
615 | if (authctxt == NULL) | ||
616 | fatal("input_gssapi_response: no authentication context"); | ||
617 | gssctxt = authctxt->methoddata; | ||
618 | |||
619 | recv_tok.value = packet_get_string(&slen); | ||
620 | recv_tok.length = slen; /* safe typecast */ | ||
621 | |||
622 | packet_check_eom(); | ||
623 | |||
624 | status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | ||
625 | &recv_tok, &send_tok, NULL); | ||
626 | |||
627 | xfree(recv_tok.value); | ||
628 | |||
629 | if (GSS_ERROR(status)) { | ||
630 | if (send_tok.length > 0) { | ||
631 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); | ||
632 | packet_put_string(send_tok.value, send_tok.length); | ||
633 | packet_send(); | ||
634 | gss_release_buffer(&ms, &send_tok); | ||
635 | } | ||
636 | /* Start again with the next method in the list */ | ||
637 | userauth(authctxt, NULL); | ||
638 | return; | ||
639 | } | ||
640 | |||
641 | if (send_tok.length > 0) { | ||
642 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | ||
643 | packet_put_string(send_tok.value, send_tok.length); | ||
644 | packet_send(); | ||
645 | gss_release_buffer(&ms, &send_tok); | ||
646 | } | ||
647 | |||
648 | if (status == GSS_S_COMPLETE) { | ||
649 | /* If that succeeded, send a exchange complete message */ | ||
650 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); | ||
651 | packet_send(); | ||
652 | } | ||
653 | } | ||
654 | |||
655 | void | ||
656 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | ||
657 | { | ||
658 | Authctxt *authctxt = ctxt; | ||
659 | Gssctxt *gssctxt; | ||
660 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
661 | gss_buffer_desc recv_tok; | ||
662 | OM_uint32 status, ms; | ||
663 | |||
664 | if (authctxt == NULL) | ||
665 | fatal("input_gssapi_response: no authentication context"); | ||
666 | gssctxt = authctxt->methoddata; | ||
667 | |||
668 | recv_tok.value = packet_get_string(&recv_tok.length); | ||
669 | |||
670 | packet_check_eom(); | ||
671 | |||
672 | /* Stick it into GSSAPI and see what it says */ | ||
673 | status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | ||
674 | &recv_tok, &send_tok, NULL); | ||
675 | |||
676 | xfree(recv_tok.value); | ||
677 | gss_release_buffer(&ms, &send_tok); | ||
678 | |||
679 | /* Server will be returning a failed packet after this one */ | ||
680 | } | ||
681 | |||
682 | void | ||
683 | input_gssapi_error(int type, u_int32_t plen, void *ctxt) | ||
684 | { | ||
685 | OM_uint32 maj, min; | ||
686 | char *msg; | ||
687 | char *lang; | ||
688 | |||
689 | maj=packet_get_int(); | ||
690 | min=packet_get_int(); | ||
691 | msg=packet_get_string(NULL); | ||
692 | lang=packet_get_string(NULL); | ||
693 | |||
694 | packet_check_eom(); | ||
695 | |||
696 | debug("Server GSSAPI Error:\n%s\n", msg); | ||
697 | xfree(msg); | ||
698 | xfree(lang); | ||
699 | } | ||
700 | #endif /* GSSAPI */ | ||
701 | |||
452 | int | 702 | int |
453 | userauth_none(Authctxt *authctxt) | 703 | userauth_none(Authctxt *authctxt) |
454 | { | 704 | { |