diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 573 |
1 files changed, 361 insertions, 212 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 7b478f16d..faa8ec589 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.210 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.223 2015/01/30 11:43:14 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -70,6 +70,7 @@ | |||
70 | #include "pathnames.h" | 70 | #include "pathnames.h" |
71 | #include "uidswap.h" | 71 | #include "uidswap.h" |
72 | #include "hostfile.h" | 72 | #include "hostfile.h" |
73 | #include "ssherr.h" | ||
73 | 74 | ||
74 | #ifdef GSSAPI | 75 | #ifdef GSSAPI |
75 | #include "ssh-gss.h" | 76 | #include "ssh-gss.h" |
@@ -90,10 +91,8 @@ u_int session_id2_len = 0; | |||
90 | char *xxx_host; | 91 | char *xxx_host; |
91 | struct sockaddr *xxx_hostaddr; | 92 | struct sockaddr *xxx_hostaddr; |
92 | 93 | ||
93 | Kex *xxx_kex = NULL; | ||
94 | |||
95 | static int | 94 | static int |
96 | verify_host_key_callback(Key *hostkey) | 95 | verify_host_key_callback(Key *hostkey, struct ssh *ssh) |
97 | { | 96 | { |
98 | if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) | 97 | if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) |
99 | fatal("Host key verification failed."); | 98 | fatal("Host key verification failed."); |
@@ -131,16 +130,17 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) | |||
131 | } while (0) | 130 | } while (0) |
132 | 131 | ||
133 | while ((alg = strsep(&avail, ",")) && *alg != '\0') { | 132 | while ((alg = strsep(&avail, ",")) && *alg != '\0') { |
134 | if ((ktype = key_type_from_name(alg)) == KEY_UNSPEC) | 133 | if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) |
135 | fatal("%s: unknown alg %s", __func__, alg); | 134 | fatal("%s: unknown alg %s", __func__, alg); |
136 | if (lookup_key_in_hostkeys_by_type(hostkeys, | 135 | if (lookup_key_in_hostkeys_by_type(hostkeys, |
137 | key_type_plain(ktype), NULL)) | 136 | sshkey_type_plain(ktype), NULL)) |
138 | ALG_APPEND(first, alg); | 137 | ALG_APPEND(first, alg); |
139 | else | 138 | else |
140 | ALG_APPEND(last, alg); | 139 | ALG_APPEND(last, alg); |
141 | } | 140 | } |
142 | #undef ALG_APPEND | 141 | #undef ALG_APPEND |
143 | xasprintf(&ret, "%s%s%s", first, *first == '\0' ? "" : ",", last); | 142 | xasprintf(&ret, "%s%s%s", first, |
143 | (*first == '\0' || *last == '\0') ? "" : ",", last); | ||
144 | if (*first != '\0') | 144 | if (*first != '\0') |
145 | debug3("%s: prefer hostkeyalgs: %s", __func__, first); | 145 | debug3("%s: prefer hostkeyalgs: %s", __func__, first); |
146 | 146 | ||
@@ -157,7 +157,8 @@ void | |||
157 | ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | 157 | ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) |
158 | { | 158 | { |
159 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; | 159 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
160 | Kex *kex; | 160 | struct kex *kex; |
161 | int r; | ||
161 | 162 | ||
162 | #ifdef GSSAPI | 163 | #ifdef GSSAPI |
163 | char *orig = NULL, *gss = NULL; | 164 | char *orig = NULL, *gss = NULL; |
@@ -240,13 +241,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
240 | (time_t)options.rekey_interval); | 241 | (time_t)options.rekey_interval); |
241 | 242 | ||
242 | /* start key exchange */ | 243 | /* start key exchange */ |
243 | kex = kex_setup(myproposal); | 244 | if ((r = kex_setup(active_state, myproposal)) != 0) |
245 | fatal("kex_setup: %s", ssh_err(r)); | ||
246 | kex = active_state->kex; | ||
244 | #ifdef WITH_OPENSSL | 247 | #ifdef WITH_OPENSSL |
245 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; | 248 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; |
246 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 249 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
247 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | 250 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
248 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | 251 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; |
252 | # ifdef OPENSSL_HAS_ECC | ||
249 | kex->kex[KEX_ECDH_SHA2] = kexecdh_client; | 253 | kex->kex[KEX_ECDH_SHA2] = kexecdh_client; |
254 | # endif | ||
250 | #endif | 255 | #endif |
251 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; | 256 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; |
252 | #ifdef GSSAPI | 257 | #ifdef GSSAPI |
@@ -273,9 +278,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
273 | } | 278 | } |
274 | #endif | 279 | #endif |
275 | 280 | ||
276 | xxx_kex = kex; | 281 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
277 | |||
278 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | ||
279 | 282 | ||
280 | if (options.use_roaming && !kex->roaming) { | 283 | if (options.use_roaming && !kex->roaming) { |
281 | debug("Roaming not allowed by server"); | 284 | debug("Roaming not allowed by server"); |
@@ -298,15 +301,15 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
298 | * Authenticate user | 301 | * Authenticate user |
299 | */ | 302 | */ |
300 | 303 | ||
301 | typedef struct Authctxt Authctxt; | 304 | typedef struct cauthctxt Authctxt; |
302 | typedef struct Authmethod Authmethod; | 305 | typedef struct cauthmethod Authmethod; |
303 | typedef struct identity Identity; | 306 | typedef struct identity Identity; |
304 | typedef struct idlist Idlist; | 307 | typedef struct idlist Idlist; |
305 | 308 | ||
306 | struct identity { | 309 | struct identity { |
307 | TAILQ_ENTRY(identity) next; | 310 | TAILQ_ENTRY(identity) next; |
308 | AuthenticationConnection *ac; /* set if agent supports key */ | 311 | int agent_fd; /* >=0 if agent supports key */ |
309 | Key *key; /* public/private key */ | 312 | struct sshkey *key; /* public/private key */ |
310 | char *filename; /* comment for agent-only keys */ | 313 | char *filename; /* comment for agent-only keys */ |
311 | int tried; | 314 | int tried; |
312 | int isprivate; /* key points to the private key */ | 315 | int isprivate; /* key points to the private key */ |
@@ -314,25 +317,29 @@ struct identity { | |||
314 | }; | 317 | }; |
315 | TAILQ_HEAD(idlist, identity); | 318 | TAILQ_HEAD(idlist, identity); |
316 | 319 | ||
317 | struct Authctxt { | 320 | struct cauthctxt { |
318 | const char *server_user; | 321 | const char *server_user; |
319 | const char *local_user; | 322 | const char *local_user; |
320 | const char *host; | 323 | const char *host; |
321 | const char *service; | 324 | const char *service; |
322 | Authmethod *method; | 325 | struct cauthmethod *method; |
323 | sig_atomic_t success; | 326 | sig_atomic_t success; |
324 | char *authlist; | 327 | char *authlist; |
328 | int attempt; | ||
325 | /* pubkey */ | 329 | /* pubkey */ |
326 | Idlist keys; | 330 | struct idlist keys; |
327 | AuthenticationConnection *agent; | 331 | int agent_fd; |
328 | /* hostbased */ | 332 | /* hostbased */ |
329 | Sensitive *sensitive; | 333 | Sensitive *sensitive; |
334 | char *oktypes, *ktypes; | ||
335 | const char *active_ktype; | ||
330 | /* kbd-interactive */ | 336 | /* kbd-interactive */ |
331 | int info_req_seen; | 337 | int info_req_seen; |
332 | /* generic */ | 338 | /* generic */ |
333 | void *methoddata; | 339 | void *methoddata; |
334 | }; | 340 | }; |
335 | struct Authmethod { | 341 | |
342 | struct cauthmethod { | ||
336 | char *name; /* string to compare against server's list */ | 343 | char *name; /* string to compare against server's list */ |
337 | int (*userauth)(Authctxt *authctxt); | 344 | int (*userauth)(Authctxt *authctxt); |
338 | void (*cleanup)(Authctxt *authctxt); | 345 | void (*cleanup)(Authctxt *authctxt); |
@@ -340,14 +347,14 @@ struct Authmethod { | |||
340 | int *batch_flag; /* flag in option struct that disables method */ | 347 | int *batch_flag; /* flag in option struct that disables method */ |
341 | }; | 348 | }; |
342 | 349 | ||
343 | void input_userauth_success(int, u_int32_t, void *); | 350 | int input_userauth_success(int, u_int32_t, void *); |
344 | void input_userauth_success_unexpected(int, u_int32_t, void *); | 351 | int input_userauth_success_unexpected(int, u_int32_t, void *); |
345 | void input_userauth_failure(int, u_int32_t, void *); | 352 | int input_userauth_failure(int, u_int32_t, void *); |
346 | void input_userauth_banner(int, u_int32_t, void *); | 353 | int input_userauth_banner(int, u_int32_t, void *); |
347 | void input_userauth_error(int, u_int32_t, void *); | 354 | int input_userauth_error(int, u_int32_t, void *); |
348 | void input_userauth_info_req(int, u_int32_t, void *); | 355 | int input_userauth_info_req(int, u_int32_t, void *); |
349 | void input_userauth_pk_ok(int, u_int32_t, void *); | 356 | int input_userauth_pk_ok(int, u_int32_t, void *); |
350 | void input_userauth_passwd_changereq(int, u_int32_t, void *); | 357 | int input_userauth_passwd_changereq(int, u_int32_t, void *); |
351 | 358 | ||
352 | int userauth_none(Authctxt *); | 359 | int userauth_none(Authctxt *); |
353 | int userauth_pubkey(Authctxt *); | 360 | int userauth_pubkey(Authctxt *); |
@@ -357,11 +364,11 @@ int userauth_hostbased(Authctxt *); | |||
357 | 364 | ||
358 | #ifdef GSSAPI | 365 | #ifdef GSSAPI |
359 | int userauth_gssapi(Authctxt *authctxt); | 366 | int userauth_gssapi(Authctxt *authctxt); |
360 | void input_gssapi_response(int type, u_int32_t, void *); | 367 | int input_gssapi_response(int type, u_int32_t, void *); |
361 | void input_gssapi_token(int type, u_int32_t, void *); | 368 | int input_gssapi_token(int type, u_int32_t, void *); |
362 | void input_gssapi_hash(int type, u_int32_t, void *); | 369 | int input_gssapi_hash(int type, u_int32_t, void *); |
363 | void input_gssapi_error(int, u_int32_t, void *); | 370 | int input_gssapi_error(int, u_int32_t, void *); |
364 | void input_gssapi_errtok(int, u_int32_t, void *); | 371 | int input_gssapi_errtok(int, u_int32_t, void *); |
365 | int userauth_gsskeyex(Authctxt *authctxt); | 372 | int userauth_gsskeyex(Authctxt *authctxt); |
366 | #endif | 373 | #endif |
367 | 374 | ||
@@ -460,7 +467,9 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
460 | authctxt.authlist = NULL; | 467 | authctxt.authlist = NULL; |
461 | authctxt.methoddata = NULL; | 468 | authctxt.methoddata = NULL; |
462 | authctxt.sensitive = sensitive; | 469 | authctxt.sensitive = sensitive; |
470 | authctxt.active_ktype = authctxt.oktypes = authctxt.ktypes = NULL; | ||
463 | authctxt.info_req_seen = 0; | 471 | authctxt.info_req_seen = 0; |
472 | authctxt.agent_fd = -1; | ||
464 | if (authctxt.method == NULL) | 473 | if (authctxt.method == NULL) |
465 | fatal("ssh_userauth2: internal error: cannot send userauth none request"); | 474 | fatal("ssh_userauth2: internal error: cannot send userauth none request"); |
466 | 475 | ||
@@ -515,15 +524,16 @@ userauth(Authctxt *authctxt, char *authlist) | |||
515 | } | 524 | } |
516 | 525 | ||
517 | /* ARGSUSED */ | 526 | /* ARGSUSED */ |
518 | void | 527 | int |
519 | input_userauth_error(int type, u_int32_t seq, void *ctxt) | 528 | input_userauth_error(int type, u_int32_t seq, void *ctxt) |
520 | { | 529 | { |
521 | fatal("input_userauth_error: bad message during authentication: " | 530 | fatal("input_userauth_error: bad message during authentication: " |
522 | "type %d", type); | 531 | "type %d", type); |
532 | return 0; | ||
523 | } | 533 | } |
524 | 534 | ||
525 | /* ARGSUSED */ | 535 | /* ARGSUSED */ |
526 | void | 536 | int |
527 | input_userauth_banner(int type, u_int32_t seq, void *ctxt) | 537 | input_userauth_banner(int type, u_int32_t seq, void *ctxt) |
528 | { | 538 | { |
529 | char *msg, *raw, *lang; | 539 | char *msg, *raw, *lang; |
@@ -542,10 +552,11 @@ input_userauth_banner(int type, u_int32_t seq, void *ctxt) | |||
542 | } | 552 | } |
543 | free(raw); | 553 | free(raw); |
544 | free(lang); | 554 | free(lang); |
555 | return 0; | ||
545 | } | 556 | } |
546 | 557 | ||
547 | /* ARGSUSED */ | 558 | /* ARGSUSED */ |
548 | void | 559 | int |
549 | input_userauth_success(int type, u_int32_t seq, void *ctxt) | 560 | input_userauth_success(int type, u_int32_t seq, void *ctxt) |
550 | { | 561 | { |
551 | Authctxt *authctxt = ctxt; | 562 | Authctxt *authctxt = ctxt; |
@@ -559,9 +570,10 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt) | |||
559 | free(authctxt->methoddata); | 570 | free(authctxt->methoddata); |
560 | authctxt->methoddata = NULL; | 571 | authctxt->methoddata = NULL; |
561 | authctxt->success = 1; /* break out */ | 572 | authctxt->success = 1; /* break out */ |
573 | return 0; | ||
562 | } | 574 | } |
563 | 575 | ||
564 | void | 576 | int |
565 | input_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt) | 577 | input_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt) |
566 | { | 578 | { |
567 | Authctxt *authctxt = ctxt; | 579 | Authctxt *authctxt = ctxt; |
@@ -571,10 +583,11 @@ input_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt) | |||
571 | 583 | ||
572 | fatal("Unexpected authentication success during %s.", | 584 | fatal("Unexpected authentication success during %s.", |
573 | authctxt->method->name); | 585 | authctxt->method->name); |
586 | return 0; | ||
574 | } | 587 | } |
575 | 588 | ||
576 | /* ARGSUSED */ | 589 | /* ARGSUSED */ |
577 | void | 590 | int |
578 | input_userauth_failure(int type, u_int32_t seq, void *ctxt) | 591 | input_userauth_failure(int type, u_int32_t seq, void *ctxt) |
579 | { | 592 | { |
580 | Authctxt *authctxt = ctxt; | 593 | Authctxt *authctxt = ctxt; |
@@ -597,10 +610,11 @@ input_userauth_failure(int type, u_int32_t seq, void *ctxt) | |||
597 | debug("Authentications that can continue: %s", authlist); | 610 | debug("Authentications that can continue: %s", authlist); |
598 | 611 | ||
599 | userauth(authctxt, authlist); | 612 | userauth(authctxt, authlist); |
613 | return 0; | ||
600 | } | 614 | } |
601 | 615 | ||
602 | /* ARGSUSED */ | 616 | /* ARGSUSED */ |
603 | void | 617 | int |
604 | input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) | 618 | input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) |
605 | { | 619 | { |
606 | Authctxt *authctxt = ctxt; | 620 | Authctxt *authctxt = ctxt; |
@@ -644,7 +658,9 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) | |||
644 | key->type, pktype); | 658 | key->type, pktype); |
645 | goto done; | 659 | goto done; |
646 | } | 660 | } |
647 | fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); | 661 | if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, |
662 | SSH_FP_DEFAULT)) == NULL) | ||
663 | goto done; | ||
648 | debug2("input_userauth_pk_ok: fp %s", fp); | 664 | debug2("input_userauth_pk_ok: fp %s", fp); |
649 | free(fp); | 665 | free(fp); |
650 | 666 | ||
@@ -668,6 +684,7 @@ done: | |||
668 | /* try another method if we did not send a packet */ | 684 | /* try another method if we did not send a packet */ |
669 | if (sent == 0) | 685 | if (sent == 0) |
670 | userauth(authctxt, NULL); | 686 | userauth(authctxt, NULL); |
687 | return 0; | ||
671 | } | 688 | } |
672 | 689 | ||
673 | #ifdef GSSAPI | 690 | #ifdef GSSAPI |
@@ -795,7 +812,7 @@ process_gssapi_token(void *ctxt, gss_buffer_t recv_tok) | |||
795 | } | 812 | } |
796 | 813 | ||
797 | /* ARGSUSED */ | 814 | /* ARGSUSED */ |
798 | void | 815 | int |
799 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) | 816 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) |
800 | { | 817 | { |
801 | Authctxt *authctxt = ctxt; | 818 | Authctxt *authctxt = ctxt; |
@@ -816,7 +833,7 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
816 | free(oidv); | 833 | free(oidv); |
817 | debug("Badly encoded mechanism OID received"); | 834 | debug("Badly encoded mechanism OID received"); |
818 | userauth(authctxt, NULL); | 835 | userauth(authctxt, NULL); |
819 | return; | 836 | return 0; |
820 | } | 837 | } |
821 | 838 | ||
822 | if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) | 839 | if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) |
@@ -830,12 +847,13 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
830 | /* Start again with next method on list */ | 847 | /* Start again with next method on list */ |
831 | debug("Trying to start again"); | 848 | debug("Trying to start again"); |
832 | userauth(authctxt, NULL); | 849 | userauth(authctxt, NULL); |
833 | return; | 850 | return 0; |
834 | } | 851 | } |
852 | return 0; | ||
835 | } | 853 | } |
836 | 854 | ||
837 | /* ARGSUSED */ | 855 | /* ARGSUSED */ |
838 | void | 856 | int |
839 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) | 857 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) |
840 | { | 858 | { |
841 | Authctxt *authctxt = ctxt; | 859 | Authctxt *authctxt = ctxt; |
@@ -858,12 +876,13 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt) | |||
858 | if (GSS_ERROR(status)) { | 876 | if (GSS_ERROR(status)) { |
859 | /* Start again with the next method in the list */ | 877 | /* Start again with the next method in the list */ |
860 | userauth(authctxt, NULL); | 878 | userauth(authctxt, NULL); |
861 | return; | 879 | return 0; |
862 | } | 880 | } |
881 | return 0; | ||
863 | } | 882 | } |
864 | 883 | ||
865 | /* ARGSUSED */ | 884 | /* ARGSUSED */ |
866 | void | 885 | int |
867 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | 886 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) |
868 | { | 887 | { |
869 | Authctxt *authctxt = ctxt; | 888 | Authctxt *authctxt = ctxt; |
@@ -890,10 +909,11 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | |||
890 | gss_release_buffer(&ms, &send_tok); | 909 | gss_release_buffer(&ms, &send_tok); |
891 | 910 | ||
892 | /* Server will be returning a failed packet after this one */ | 911 | /* Server will be returning a failed packet after this one */ |
912 | return 0; | ||
893 | } | 913 | } |
894 | 914 | ||
895 | /* ARGSUSED */ | 915 | /* ARGSUSED */ |
896 | void | 916 | int |
897 | input_gssapi_error(int type, u_int32_t plen, void *ctxt) | 917 | input_gssapi_error(int type, u_int32_t plen, void *ctxt) |
898 | { | 918 | { |
899 | char *msg; | 919 | char *msg; |
@@ -909,6 +929,7 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
909 | debug("Server GSSAPI Error:\n%s", msg); | 929 | debug("Server GSSAPI Error:\n%s", msg); |
910 | free(msg); | 930 | free(msg); |
911 | free(lang); | 931 | free(lang); |
932 | return 0; | ||
912 | } | 933 | } |
913 | 934 | ||
914 | int | 935 | int |
@@ -1005,7 +1026,7 @@ userauth_passwd(Authctxt *authctxt) | |||
1005 | * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST | 1026 | * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST |
1006 | */ | 1027 | */ |
1007 | /* ARGSUSED */ | 1028 | /* ARGSUSED */ |
1008 | void | 1029 | int |
1009 | input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | 1030 | input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) |
1010 | { | 1031 | { |
1011 | Authctxt *authctxt = ctxt; | 1032 | Authctxt *authctxt = ctxt; |
@@ -1046,7 +1067,7 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
1046 | password = read_passphrase(prompt, RP_ALLOW_EOF); | 1067 | password = read_passphrase(prompt, RP_ALLOW_EOF); |
1047 | if (password == NULL) { | 1068 | if (password == NULL) { |
1048 | /* bail out */ | 1069 | /* bail out */ |
1049 | return; | 1070 | return 0; |
1050 | } | 1071 | } |
1051 | snprintf(prompt, sizeof(prompt), | 1072 | snprintf(prompt, sizeof(prompt), |
1052 | "Retype %.30s@%.128s's new password: ", | 1073 | "Retype %.30s@%.128s's new password: ", |
@@ -1069,30 +1090,33 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
1069 | 1090 | ||
1070 | dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, | 1091 | dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, |
1071 | &input_userauth_passwd_changereq); | 1092 | &input_userauth_passwd_changereq); |
1093 | return 0; | ||
1072 | } | 1094 | } |
1073 | 1095 | ||
1074 | static int | 1096 | static int |
1075 | identity_sign(Identity *id, u_char **sigp, u_int *lenp, | 1097 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, |
1076 | u_char *data, u_int datalen) | 1098 | const u_char *data, size_t datalen, u_int compat) |
1077 | { | 1099 | { |
1078 | Key *prv; | 1100 | Key *prv; |
1079 | int ret; | 1101 | int ret; |
1080 | 1102 | ||
1081 | /* the agent supports this key */ | 1103 | /* the agent supports this key */ |
1082 | if (id->ac) | 1104 | if (id->agent_fd) |
1083 | return (ssh_agent_sign(id->ac, id->key, sigp, lenp, | 1105 | return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, |
1084 | data, datalen)); | 1106 | data, datalen, compat); |
1107 | |||
1085 | /* | 1108 | /* |
1086 | * we have already loaded the private key or | 1109 | * we have already loaded the private key or |
1087 | * the private key is stored in external hardware | 1110 | * the private key is stored in external hardware |
1088 | */ | 1111 | */ |
1089 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) | 1112 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) |
1090 | return (key_sign(id->key, sigp, lenp, data, datalen)); | 1113 | return (sshkey_sign(id->key, sigp, lenp, data, datalen, |
1114 | compat)); | ||
1091 | /* load the private key from the file */ | 1115 | /* load the private key from the file */ |
1092 | if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) | 1116 | if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) |
1093 | return (-1); | 1117 | return (-1); /* XXX return decent error code */ |
1094 | ret = key_sign(prv, sigp, lenp, data, datalen); | 1118 | ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat); |
1095 | key_free(prv); | 1119 | sshkey_free(prv); |
1096 | return (ret); | 1120 | return (ret); |
1097 | } | 1121 | } |
1098 | 1122 | ||
@@ -1101,13 +1125,16 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | |||
1101 | { | 1125 | { |
1102 | Buffer b; | 1126 | Buffer b; |
1103 | u_char *blob, *signature; | 1127 | u_char *blob, *signature; |
1104 | u_int bloblen, slen; | 1128 | u_int bloblen; |
1129 | size_t slen; | ||
1105 | u_int skip = 0; | 1130 | u_int skip = 0; |
1106 | int ret = -1; | 1131 | int ret = -1; |
1107 | int have_sig = 1; | 1132 | int have_sig = 1; |
1108 | char *fp; | 1133 | char *fp; |
1109 | 1134 | ||
1110 | fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); | 1135 | if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, |
1136 | SSH_FP_DEFAULT)) == NULL) | ||
1137 | return 0; | ||
1111 | debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); | 1138 | debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); |
1112 | free(fp); | 1139 | free(fp); |
1113 | 1140 | ||
@@ -1142,8 +1169,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | |||
1142 | 1169 | ||
1143 | /* generate signature */ | 1170 | /* generate signature */ |
1144 | ret = identity_sign(id, &signature, &slen, | 1171 | ret = identity_sign(id, &signature, &slen, |
1145 | buffer_ptr(&b), buffer_len(&b)); | 1172 | buffer_ptr(&b), buffer_len(&b), datafellows); |
1146 | if (ret == -1) { | 1173 | if (ret != 0) { |
1147 | free(blob); | 1174 | free(blob); |
1148 | buffer_free(&b); | 1175 | buffer_free(&b); |
1149 | return 0; | 1176 | return 0; |
@@ -1218,7 +1245,7 @@ load_identity_file(char *filename, int userprovided) | |||
1218 | { | 1245 | { |
1219 | Key *private; | 1246 | Key *private; |
1220 | char prompt[300], *passphrase; | 1247 | char prompt[300], *passphrase; |
1221 | int perm_ok = 0, quit, i; | 1248 | int r, perm_ok = 0, quit = 0, i; |
1222 | struct stat st; | 1249 | struct stat st; |
1223 | 1250 | ||
1224 | if (stat(filename, &st) < 0) { | 1251 | if (stat(filename, &st) < 0) { |
@@ -1226,33 +1253,50 @@ load_identity_file(char *filename, int userprovided) | |||
1226 | filename, strerror(errno)); | 1253 | filename, strerror(errno)); |
1227 | return NULL; | 1254 | return NULL; |
1228 | } | 1255 | } |
1229 | private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok); | 1256 | snprintf(prompt, sizeof prompt, |
1230 | if (!perm_ok) { | 1257 | "Enter passphrase for key '%.100s': ", filename); |
1231 | if (private != NULL) | 1258 | for (i = 0; i <= options.number_of_password_prompts; i++) { |
1232 | key_free(private); | 1259 | if (i == 0) |
1233 | return NULL; | 1260 | passphrase = ""; |
1234 | } | 1261 | else { |
1235 | if (private == NULL) { | ||
1236 | if (options.batch_mode) | ||
1237 | return NULL; | ||
1238 | snprintf(prompt, sizeof prompt, | ||
1239 | "Enter passphrase for key '%.100s': ", filename); | ||
1240 | for (i = 0; i < options.number_of_password_prompts; i++) { | ||
1241 | passphrase = read_passphrase(prompt, 0); | 1262 | passphrase = read_passphrase(prompt, 0); |
1242 | if (strcmp(passphrase, "") != 0) { | 1263 | if (*passphrase == '\0') { |
1243 | private = key_load_private_type(KEY_UNSPEC, | ||
1244 | filename, passphrase, NULL, NULL); | ||
1245 | quit = 0; | ||
1246 | } else { | ||
1247 | debug2("no passphrase given, try next key"); | 1264 | debug2("no passphrase given, try next key"); |
1265 | free(passphrase); | ||
1266 | break; | ||
1267 | } | ||
1268 | } | ||
1269 | switch ((r = sshkey_load_private_type(KEY_UNSPEC, filename, | ||
1270 | passphrase, &private, NULL, &perm_ok))) { | ||
1271 | case 0: | ||
1272 | break; | ||
1273 | case SSH_ERR_KEY_WRONG_PASSPHRASE: | ||
1274 | if (options.batch_mode) { | ||
1275 | quit = 1; | ||
1276 | break; | ||
1277 | } | ||
1278 | if (i != 0) | ||
1279 | debug2("bad passphrase given, try again..."); | ||
1280 | break; | ||
1281 | case SSH_ERR_SYSTEM_ERROR: | ||
1282 | if (errno == ENOENT) { | ||
1283 | debug2("Load key \"%s\": %s", | ||
1284 | filename, ssh_err(r)); | ||
1248 | quit = 1; | 1285 | quit = 1; |
1286 | break; | ||
1249 | } | 1287 | } |
1288 | /* FALLTHROUGH */ | ||
1289 | default: | ||
1290 | error("Load key \"%s\": %s", filename, ssh_err(r)); | ||
1291 | quit = 1; | ||
1292 | break; | ||
1293 | } | ||
1294 | if (i > 0) { | ||
1250 | explicit_bzero(passphrase, strlen(passphrase)); | 1295 | explicit_bzero(passphrase, strlen(passphrase)); |
1251 | free(passphrase); | 1296 | free(passphrase); |
1252 | if (private != NULL || quit) | ||
1253 | break; | ||
1254 | debug2("bad passphrase given, try again..."); | ||
1255 | } | 1297 | } |
1298 | if (private != NULL || quit) | ||
1299 | break; | ||
1256 | } | 1300 | } |
1257 | return private; | 1301 | return private; |
1258 | } | 1302 | } |
@@ -1266,12 +1310,12 @@ load_identity_file(char *filename, int userprovided) | |||
1266 | static void | 1310 | static void |
1267 | pubkey_prepare(Authctxt *authctxt) | 1311 | pubkey_prepare(Authctxt *authctxt) |
1268 | { | 1312 | { |
1269 | Identity *id, *id2, *tmp; | 1313 | struct identity *id, *id2, *tmp; |
1270 | Idlist agent, files, *preferred; | 1314 | struct idlist agent, files, *preferred; |
1271 | Key *key; | 1315 | struct sshkey *key; |
1272 | AuthenticationConnection *ac; | 1316 | int agent_fd, i, r, found; |
1273 | char *comment; | 1317 | size_t j; |
1274 | int i, found; | 1318 | struct ssh_identitylist *idlist; |
1275 | 1319 | ||
1276 | TAILQ_INIT(&agent); /* keys from the agent */ | 1320 | TAILQ_INIT(&agent); /* keys from the agent */ |
1277 | TAILQ_INIT(&files); /* keys from the config file */ | 1321 | TAILQ_INIT(&files); /* keys from the config file */ |
@@ -1301,7 +1345,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1301 | if (id2->key == NULL || | 1345 | if (id2->key == NULL || |
1302 | (id2->key->flags & SSHKEY_FLAG_EXT) == 0) | 1346 | (id2->key->flags & SSHKEY_FLAG_EXT) == 0) |
1303 | continue; | 1347 | continue; |
1304 | if (key_equal(id->key, id2->key)) { | 1348 | if (sshkey_equal(id->key, id2->key)) { |
1305 | TAILQ_REMOVE(&files, id, next); | 1349 | TAILQ_REMOVE(&files, id, next); |
1306 | TAILQ_INSERT_TAIL(preferred, id, next); | 1350 | TAILQ_INSERT_TAIL(preferred, id, next); |
1307 | found = 1; | 1351 | found = 1; |
@@ -1316,37 +1360,48 @@ pubkey_prepare(Authctxt *authctxt) | |||
1316 | } | 1360 | } |
1317 | } | 1361 | } |
1318 | /* list of keys supported by the agent */ | 1362 | /* list of keys supported by the agent */ |
1319 | if ((ac = ssh_get_authentication_connection())) { | 1363 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { |
1320 | for (key = ssh_get_first_identity(ac, &comment, 2); | 1364 | if (r != SSH_ERR_AGENT_NOT_PRESENT) |
1321 | key != NULL; | 1365 | debug("%s: ssh_get_authentication_socket: %s", |
1322 | key = ssh_get_next_identity(ac, &comment, 2)) { | 1366 | __func__, ssh_err(r)); |
1367 | } else if ((r = ssh_fetch_identitylist(agent_fd, 2, &idlist)) != 0) { | ||
1368 | if (r != SSH_ERR_AGENT_NO_IDENTITIES) | ||
1369 | debug("%s: ssh_fetch_identitylist: %s", | ||
1370 | __func__, ssh_err(r)); | ||
1371 | } else { | ||
1372 | for (j = 0; j < idlist->nkeys; j++) { | ||
1323 | found = 0; | 1373 | found = 0; |
1324 | TAILQ_FOREACH(id, &files, next) { | 1374 | TAILQ_FOREACH(id, &files, next) { |
1325 | /* agent keys from the config file are preferred */ | 1375 | /* |
1326 | if (key_equal(key, id->key)) { | 1376 | * agent keys from the config file are |
1327 | key_free(key); | 1377 | * preferred |
1328 | free(comment); | 1378 | */ |
1379 | if (sshkey_equal(idlist->keys[j], id->key)) { | ||
1329 | TAILQ_REMOVE(&files, id, next); | 1380 | TAILQ_REMOVE(&files, id, next); |
1330 | TAILQ_INSERT_TAIL(preferred, id, next); | 1381 | TAILQ_INSERT_TAIL(preferred, id, next); |
1331 | id->ac = ac; | 1382 | id->agent_fd = agent_fd; |
1332 | found = 1; | 1383 | found = 1; |
1333 | break; | 1384 | break; |
1334 | } | 1385 | } |
1335 | } | 1386 | } |
1336 | if (!found && !options.identities_only) { | 1387 | if (!found && !options.identities_only) { |
1337 | id = xcalloc(1, sizeof(*id)); | 1388 | id = xcalloc(1, sizeof(*id)); |
1338 | id->key = key; | 1389 | /* XXX "steals" key/comment from idlist */ |
1339 | id->filename = comment; | 1390 | id->key = idlist->keys[j]; |
1340 | id->ac = ac; | 1391 | id->filename = idlist->comments[j]; |
1392 | idlist->keys[j] = NULL; | ||
1393 | idlist->comments[j] = NULL; | ||
1394 | id->agent_fd = agent_fd; | ||
1341 | TAILQ_INSERT_TAIL(&agent, id, next); | 1395 | TAILQ_INSERT_TAIL(&agent, id, next); |
1342 | } | 1396 | } |
1343 | } | 1397 | } |
1398 | ssh_free_identitylist(idlist); | ||
1344 | /* append remaining agent keys */ | 1399 | /* append remaining agent keys */ |
1345 | for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { | 1400 | for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { |
1346 | TAILQ_REMOVE(&agent, id, next); | 1401 | TAILQ_REMOVE(&agent, id, next); |
1347 | TAILQ_INSERT_TAIL(preferred, id, next); | 1402 | TAILQ_INSERT_TAIL(preferred, id, next); |
1348 | } | 1403 | } |
1349 | authctxt->agent = ac; | 1404 | authctxt->agent_fd = agent_fd; |
1350 | } | 1405 | } |
1351 | /* append remaining keys from the config file */ | 1406 | /* append remaining keys from the config file */ |
1352 | for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { | 1407 | for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { |
@@ -1364,13 +1419,13 @@ pubkey_cleanup(Authctxt *authctxt) | |||
1364 | { | 1419 | { |
1365 | Identity *id; | 1420 | Identity *id; |
1366 | 1421 | ||
1367 | if (authctxt->agent != NULL) | 1422 | if (authctxt->agent_fd != -1) |
1368 | ssh_close_authentication_connection(authctxt->agent); | 1423 | ssh_close_authentication_socket(authctxt->agent_fd); |
1369 | for (id = TAILQ_FIRST(&authctxt->keys); id; | 1424 | for (id = TAILQ_FIRST(&authctxt->keys); id; |
1370 | id = TAILQ_FIRST(&authctxt->keys)) { | 1425 | id = TAILQ_FIRST(&authctxt->keys)) { |
1371 | TAILQ_REMOVE(&authctxt->keys, id, next); | 1426 | TAILQ_REMOVE(&authctxt->keys, id, next); |
1372 | if (id->key) | 1427 | if (id->key) |
1373 | key_free(id->key); | 1428 | sshkey_free(id->key); |
1374 | free(id->filename); | 1429 | free(id->filename); |
1375 | free(id); | 1430 | free(id); |
1376 | } | 1431 | } |
@@ -1462,7 +1517,7 @@ userauth_kbdint(Authctxt *authctxt) | |||
1462 | /* | 1517 | /* |
1463 | * parse INFO_REQUEST, prompt user and send INFO_RESPONSE | 1518 | * parse INFO_REQUEST, prompt user and send INFO_RESPONSE |
1464 | */ | 1519 | */ |
1465 | void | 1520 | int |
1466 | input_userauth_info_req(int type, u_int32_t seq, void *ctxt) | 1521 | input_userauth_info_req(int type, u_int32_t seq, void *ctxt) |
1467 | { | 1522 | { |
1468 | Authctxt *authctxt = ctxt; | 1523 | Authctxt *authctxt = ctxt; |
@@ -1514,81 +1569,120 @@ input_userauth_info_req(int type, u_int32_t seq, void *ctxt) | |||
1514 | 1569 | ||
1515 | packet_add_padding(64); | 1570 | packet_add_padding(64); |
1516 | packet_send(); | 1571 | packet_send(); |
1572 | return 0; | ||
1517 | } | 1573 | } |
1518 | 1574 | ||
1519 | static int | 1575 | static int |
1520 | ssh_keysign(Key *key, u_char **sigp, u_int *lenp, | 1576 | ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, |
1521 | u_char *data, u_int datalen) | 1577 | const u_char *data, size_t datalen) |
1522 | { | 1578 | { |
1523 | Buffer b; | 1579 | struct sshbuf *b; |
1524 | struct stat st; | 1580 | struct stat st; |
1525 | pid_t pid; | 1581 | pid_t pid; |
1526 | int to[2], from[2], status, version = 2; | 1582 | int i, r, to[2], from[2], status, sock = packet_get_connection_in(); |
1583 | u_char rversion = 0, version = 2; | ||
1584 | void (*osigchld)(int); | ||
1527 | 1585 | ||
1528 | debug2("ssh_keysign called"); | 1586 | *sigp = NULL; |
1587 | *lenp = 0; | ||
1529 | 1588 | ||
1530 | if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { | 1589 | if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { |
1531 | error("ssh_keysign: not installed: %s", strerror(errno)); | 1590 | error("%s: not installed: %s", __func__, strerror(errno)); |
1591 | return -1; | ||
1592 | } | ||
1593 | if (fflush(stdout) != 0) { | ||
1594 | error("%s: fflush: %s", __func__, strerror(errno)); | ||
1532 | return -1; | 1595 | return -1; |
1533 | } | 1596 | } |
1534 | if (fflush(stdout) != 0) | ||
1535 | error("ssh_keysign: fflush: %s", strerror(errno)); | ||
1536 | if (pipe(to) < 0) { | 1597 | if (pipe(to) < 0) { |
1537 | error("ssh_keysign: pipe: %s", strerror(errno)); | 1598 | error("%s: pipe: %s", __func__, strerror(errno)); |
1538 | return -1; | 1599 | return -1; |
1539 | } | 1600 | } |
1540 | if (pipe(from) < 0) { | 1601 | if (pipe(from) < 0) { |
1541 | error("ssh_keysign: pipe: %s", strerror(errno)); | 1602 | error("%s: pipe: %s", __func__, strerror(errno)); |
1542 | return -1; | 1603 | return -1; |
1543 | } | 1604 | } |
1544 | if ((pid = fork()) < 0) { | 1605 | if ((pid = fork()) < 0) { |
1545 | error("ssh_keysign: fork: %s", strerror(errno)); | 1606 | error("%s: fork: %s", __func__, strerror(errno)); |
1546 | return -1; | 1607 | return -1; |
1547 | } | 1608 | } |
1609 | osigchld = signal(SIGCHLD, SIG_DFL); | ||
1548 | if (pid == 0) { | 1610 | if (pid == 0) { |
1549 | /* keep the socket on exec */ | 1611 | /* keep the socket on exec */ |
1550 | fcntl(packet_get_connection_in(), F_SETFD, 0); | 1612 | fcntl(sock, F_SETFD, 0); |
1551 | permanently_drop_suid(getuid()); | 1613 | permanently_drop_suid(getuid()); |
1552 | close(from[0]); | 1614 | close(from[0]); |
1553 | if (dup2(from[1], STDOUT_FILENO) < 0) | 1615 | if (dup2(from[1], STDOUT_FILENO) < 0) |
1554 | fatal("ssh_keysign: dup2: %s", strerror(errno)); | 1616 | fatal("%s: dup2: %s", __func__, strerror(errno)); |
1555 | close(to[1]); | 1617 | close(to[1]); |
1556 | if (dup2(to[0], STDIN_FILENO) < 0) | 1618 | if (dup2(to[0], STDIN_FILENO) < 0) |
1557 | fatal("ssh_keysign: dup2: %s", strerror(errno)); | 1619 | fatal("%s: dup2: %s", __func__, strerror(errno)); |
1558 | close(from[1]); | 1620 | close(from[1]); |
1559 | close(to[0]); | 1621 | close(to[0]); |
1622 | /* Close everything but stdio and the socket */ | ||
1623 | for (i = STDERR_FILENO + 1; i < sock; i++) | ||
1624 | close(i); | ||
1625 | closefrom(sock + 1); | ||
1626 | debug3("%s: [child] pid=%ld, exec %s", | ||
1627 | __func__, (long)getpid(), _PATH_SSH_KEY_SIGN); | ||
1560 | execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); | 1628 | execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); |
1561 | fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN, | 1629 | fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN, |
1562 | strerror(errno)); | 1630 | strerror(errno)); |
1563 | } | 1631 | } |
1564 | close(from[1]); | 1632 | close(from[1]); |
1565 | close(to[0]); | 1633 | close(to[0]); |
1566 | 1634 | ||
1567 | buffer_init(&b); | 1635 | if ((b = sshbuf_new()) == NULL) |
1568 | buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */ | 1636 | fatal("%s: sshbuf_new failed", __func__); |
1569 | buffer_put_string(&b, data, datalen); | 1637 | /* send # of sock, data to be signed */ |
1570 | if (ssh_msg_send(to[1], version, &b) == -1) | 1638 | if ((r = sshbuf_put_u32(b, sock) != 0) || |
1571 | fatal("ssh_keysign: couldn't send request"); | 1639 | (r = sshbuf_put_string(b, data, datalen)) != 0) |
1572 | 1640 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | |
1573 | if (ssh_msg_recv(from[0], &b) < 0) { | 1641 | if (ssh_msg_send(to[1], version, b) == -1) |
1574 | error("ssh_keysign: no reply"); | 1642 | fatal("%s: couldn't send request", __func__); |
1575 | buffer_free(&b); | 1643 | sshbuf_reset(b); |
1576 | return -1; | 1644 | r = ssh_msg_recv(from[0], b); |
1577 | } | ||
1578 | close(from[0]); | 1645 | close(from[0]); |
1579 | close(to[1]); | 1646 | close(to[1]); |
1647 | if (r < 0) { | ||
1648 | error("%s: no reply", __func__); | ||
1649 | goto fail; | ||
1650 | } | ||
1580 | 1651 | ||
1581 | while (waitpid(pid, &status, 0) < 0) | 1652 | errno = 0; |
1582 | if (errno != EINTR) | 1653 | while (waitpid(pid, &status, 0) < 0) { |
1583 | break; | 1654 | if (errno != EINTR) { |
1584 | 1655 | error("%s: waitpid %ld: %s", | |
1585 | if (buffer_get_char(&b) != version) { | 1656 | __func__, (long)pid, strerror(errno)); |
1586 | error("ssh_keysign: bad version"); | 1657 | goto fail; |
1587 | buffer_free(&b); | 1658 | } |
1659 | } | ||
1660 | if (!WIFEXITED(status)) { | ||
1661 | error("%s: exited abnormally", __func__); | ||
1662 | goto fail; | ||
1663 | } | ||
1664 | if (WEXITSTATUS(status) != 0) { | ||
1665 | error("%s: exited with status %d", | ||
1666 | __func__, WEXITSTATUS(status)); | ||
1667 | goto fail; | ||
1668 | } | ||
1669 | if ((r = sshbuf_get_u8(b, &rversion)) != 0) { | ||
1670 | error("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1671 | goto fail; | ||
1672 | } | ||
1673 | if (rversion != version) { | ||
1674 | error("%s: bad version", __func__); | ||
1675 | goto fail; | ||
1676 | } | ||
1677 | if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) { | ||
1678 | error("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1679 | fail: | ||
1680 | signal(SIGCHLD, osigchld); | ||
1681 | sshbuf_free(b); | ||
1588 | return -1; | 1682 | return -1; |
1589 | } | 1683 | } |
1590 | *sigp = buffer_get_string(&b, lenp); | 1684 | signal(SIGCHLD, osigchld); |
1591 | buffer_free(&b); | 1685 | sshbuf_free(b); |
1592 | 1686 | ||
1593 | return 0; | 1687 | return 0; |
1594 | } | 1688 | } |
@@ -1596,94 +1690,149 @@ ssh_keysign(Key *key, u_char **sigp, u_int *lenp, | |||
1596 | int | 1690 | int |
1597 | userauth_hostbased(Authctxt *authctxt) | 1691 | userauth_hostbased(Authctxt *authctxt) |
1598 | { | 1692 | { |
1599 | Key *private = NULL; | 1693 | struct ssh *ssh = active_state; |
1600 | Sensitive *sensitive = authctxt->sensitive; | 1694 | struct sshkey *private = NULL; |
1601 | Buffer b; | 1695 | struct sshbuf *b = NULL; |
1602 | u_char *signature, *blob; | ||
1603 | char *chost, *pkalg, *p; | ||
1604 | const char *service; | 1696 | const char *service; |
1605 | u_int blen, slen; | 1697 | u_char *sig = NULL, *keyblob = NULL; |
1606 | int ok, i, found = 0; | 1698 | char *fp = NULL, *chost = NULL, *lname = NULL; |
1607 | 1699 | size_t siglen = 0, keylen = 0; | |
1608 | /* check for a useful key */ | 1700 | int i, r, success = 0; |
1609 | for (i = 0; i < sensitive->nkeys; i++) { | 1701 | |
1610 | private = sensitive->keys[i]; | 1702 | if (authctxt->ktypes == NULL) { |
1611 | if (private && private->type != KEY_RSA1) { | 1703 | authctxt->oktypes = xstrdup(options.hostbased_key_types); |
1612 | found = 1; | 1704 | authctxt->ktypes = authctxt->oktypes; |
1705 | } | ||
1706 | |||
1707 | /* | ||
1708 | * Work through each listed type pattern in HostbasedKeyTypes, | ||
1709 | * trying each hostkey that matches the type in turn. | ||
1710 | */ | ||
1711 | for (;;) { | ||
1712 | if (authctxt->active_ktype == NULL) | ||
1713 | authctxt->active_ktype = strsep(&authctxt->ktypes, ","); | ||
1714 | if (authctxt->active_ktype == NULL || | ||
1715 | *authctxt->active_ktype == '\0') | ||
1716 | break; | ||
1717 | debug3("%s: trying key type %s", __func__, | ||
1718 | authctxt->active_ktype); | ||
1719 | |||
1720 | /* check for a useful key */ | ||
1721 | private = NULL; | ||
1722 | for (i = 0; i < authctxt->sensitive->nkeys; i++) { | ||
1723 | if (authctxt->sensitive->keys[i] == NULL || | ||
1724 | authctxt->sensitive->keys[i]->type == KEY_RSA1 || | ||
1725 | authctxt->sensitive->keys[i]->type == KEY_UNSPEC) | ||
1726 | continue; | ||
1727 | if (match_pattern_list( | ||
1728 | sshkey_ssh_name(authctxt->sensitive->keys[i]), | ||
1729 | authctxt->active_ktype, | ||
1730 | strlen(authctxt->active_ktype), 0) != 1) | ||
1731 | continue; | ||
1613 | /* we take and free the key */ | 1732 | /* we take and free the key */ |
1614 | sensitive->keys[i] = NULL; | 1733 | private = authctxt->sensitive->keys[i]; |
1734 | authctxt->sensitive->keys[i] = NULL; | ||
1615 | break; | 1735 | break; |
1616 | } | 1736 | } |
1737 | /* Found one */ | ||
1738 | if (private != NULL) | ||
1739 | break; | ||
1740 | /* No more keys of this type; advance */ | ||
1741 | authctxt->active_ktype = NULL; | ||
1617 | } | 1742 | } |
1618 | if (!found) { | 1743 | if (private == NULL) { |
1744 | free(authctxt->oktypes); | ||
1745 | authctxt->oktypes = authctxt->ktypes = NULL; | ||
1746 | authctxt->active_ktype = NULL; | ||
1619 | debug("No more client hostkeys for hostbased authentication."); | 1747 | debug("No more client hostkeys for hostbased authentication."); |
1620 | return 0; | 1748 | goto out; |
1621 | } | 1749 | } |
1622 | if (key_to_blob(private, &blob, &blen) == 0) { | 1750 | |
1623 | key_free(private); | 1751 | if ((fp = sshkey_fingerprint(private, options.fingerprint_hash, |
1624 | return 0; | 1752 | SSH_FP_DEFAULT)) == NULL) { |
1753 | error("%s: sshkey_fingerprint failed", __func__); | ||
1754 | goto out; | ||
1625 | } | 1755 | } |
1756 | debug("%s: trying hostkey %s %s", | ||
1757 | __func__, sshkey_ssh_name(private), fp); | ||
1758 | |||
1626 | /* figure out a name for the client host */ | 1759 | /* figure out a name for the client host */ |
1627 | p = get_local_name(packet_get_connection_in()); | 1760 | if ((lname = get_local_name(packet_get_connection_in())) == NULL) { |
1628 | if (p == NULL) { | 1761 | error("%s: cannot get local ipaddr/name", __func__); |
1629 | error("userauth_hostbased: cannot get local ipaddr/name"); | 1762 | goto out; |
1630 | key_free(private); | ||
1631 | free(blob); | ||
1632 | return 0; | ||
1633 | } | 1763 | } |
1634 | xasprintf(&chost, "%s.", p); | 1764 | |
1635 | debug2("userauth_hostbased: chost %s", chost); | 1765 | /* XXX sshbuf_put_stringf? */ |
1636 | free(p); | 1766 | xasprintf(&chost, "%s.", lname); |
1767 | debug2("%s: chost %s", __func__, chost); | ||
1637 | 1768 | ||
1638 | service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : | 1769 | service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : |
1639 | authctxt->service; | 1770 | authctxt->service; |
1640 | pkalg = xstrdup(key_ssh_name(private)); | 1771 | |
1641 | buffer_init(&b); | ||
1642 | /* construct data */ | 1772 | /* construct data */ |
1643 | buffer_put_string(&b, session_id2, session_id2_len); | 1773 | if ((b = sshbuf_new()) == NULL) { |
1644 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); | 1774 | error("%s: sshbuf_new failed", __func__); |
1645 | buffer_put_cstring(&b, authctxt->server_user); | 1775 | goto out; |
1646 | buffer_put_cstring(&b, service); | 1776 | } |
1647 | buffer_put_cstring(&b, authctxt->method->name); | 1777 | if ((r = sshkey_to_blob(private, &keyblob, &keylen)) != 0) { |
1648 | buffer_put_cstring(&b, pkalg); | 1778 | error("%s: sshkey_to_blob: %s", __func__, ssh_err(r)); |
1649 | buffer_put_string(&b, blob, blen); | 1779 | goto out; |
1650 | buffer_put_cstring(&b, chost); | 1780 | } |
1651 | buffer_put_cstring(&b, authctxt->local_user); | 1781 | if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || |
1782 | (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || | ||
1783 | (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || | ||
1784 | (r = sshbuf_put_cstring(b, service)) != 0 || | ||
1785 | (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 || | ||
1786 | (r = sshbuf_put_cstring(b, key_ssh_name(private))) != 0 || | ||
1787 | (r = sshbuf_put_string(b, keyblob, keylen)) != 0 || | ||
1788 | (r = sshbuf_put_cstring(b, chost)) != 0 || | ||
1789 | (r = sshbuf_put_cstring(b, authctxt->local_user)) != 0) { | ||
1790 | error("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1791 | goto out; | ||
1792 | } | ||
1793 | |||
1652 | #ifdef DEBUG_PK | 1794 | #ifdef DEBUG_PK |
1653 | buffer_dump(&b); | 1795 | sshbuf_dump(b, stderr); |
1654 | #endif | 1796 | #endif |
1655 | if (sensitive->external_keysign) | 1797 | if (authctxt->sensitive->external_keysign) |
1656 | ok = ssh_keysign(private, &signature, &slen, | 1798 | r = ssh_keysign(private, &sig, &siglen, |
1657 | buffer_ptr(&b), buffer_len(&b)); | 1799 | sshbuf_ptr(b), sshbuf_len(b)); |
1658 | else | 1800 | else if ((r = sshkey_sign(private, &sig, &siglen, |
1659 | ok = key_sign(private, &signature, &slen, | 1801 | sshbuf_ptr(b), sshbuf_len(b), datafellows)) != 0) |
1660 | buffer_ptr(&b), buffer_len(&b)); | 1802 | debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); |
1661 | key_free(private); | 1803 | if (r != 0) { |
1662 | buffer_free(&b); | 1804 | error("sign using hostkey %s %s failed", |
1663 | if (ok != 0) { | 1805 | sshkey_ssh_name(private), fp); |
1664 | error("key_sign failed"); | 1806 | goto out; |
1665 | free(chost); | ||
1666 | free(pkalg); | ||
1667 | free(blob); | ||
1668 | return 0; | ||
1669 | } | 1807 | } |
1670 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | 1808 | if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
1671 | packet_put_cstring(authctxt->server_user); | 1809 | (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || |
1672 | packet_put_cstring(authctxt->service); | 1810 | (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || |
1673 | packet_put_cstring(authctxt->method->name); | 1811 | (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || |
1674 | packet_put_cstring(pkalg); | 1812 | (r = sshpkt_put_cstring(ssh, key_ssh_name(private))) != 0 || |
1675 | packet_put_string(blob, blen); | 1813 | (r = sshpkt_put_string(ssh, keyblob, keylen)) != 0 || |
1676 | packet_put_cstring(chost); | 1814 | (r = sshpkt_put_cstring(ssh, chost)) != 0 || |
1677 | packet_put_cstring(authctxt->local_user); | 1815 | (r = sshpkt_put_cstring(ssh, authctxt->local_user)) != 0 || |
1678 | packet_put_string(signature, slen); | 1816 | (r = sshpkt_put_string(ssh, sig, siglen)) != 0 || |
1679 | explicit_bzero(signature, slen); | 1817 | (r = sshpkt_send(ssh)) != 0) { |
1680 | free(signature); | 1818 | error("%s: packet error: %s", __func__, ssh_err(r)); |
1819 | goto out; | ||
1820 | } | ||
1821 | success = 1; | ||
1822 | |||
1823 | out: | ||
1824 | if (sig != NULL) { | ||
1825 | explicit_bzero(sig, siglen); | ||
1826 | free(sig); | ||
1827 | } | ||
1828 | free(keyblob); | ||
1829 | free(lname); | ||
1830 | free(fp); | ||
1681 | free(chost); | 1831 | free(chost); |
1682 | free(pkalg); | 1832 | sshkey_free(private); |
1683 | free(blob); | 1833 | sshbuf_free(b); |
1684 | 1834 | ||
1685 | packet_send(); | 1835 | return success; |
1686 | return 1; | ||
1687 | } | 1836 | } |
1688 | 1837 | ||
1689 | /* find auth method */ | 1838 | /* find auth method */ |