| ︙ | | | ︙ | |
454
455
456
457
458
459
460
461
462
463
464
465
466
467
|
* channels.
*/
#define SSH1_BUFFER_LIMIT 32768
#define SSH_MAX_BACKLOG 32768
#define OUR_V2_WINSIZE 16384
#define OUR_V2_MAXPKT 0x4000UL
const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
const static struct ssh_mac *macs[] = {
&ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
};
const static struct ssh_mac *buggymacs[] = {
|
>
>
>
|
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
|
* channels.
*/
#define SSH1_BUFFER_LIMIT 32768
#define SSH_MAX_BACKLOG 32768
#define OUR_V2_WINSIZE 16384
#define OUR_V2_MAXPKT 0x4000UL
/* Maximum length of passwords/passphrases (arbitrary) */
#define SSH_MAX_PASSWORD_LEN 100
const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
const static struct ssh_mac *macs[] = {
&ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
};
const static struct ssh_mac *buggymacs[] = {
|
| ︙ | | | ︙ | |
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
|
* scp1 if that fails. This variable is the means by which
* scp.c can reach into the SSH code and find out which one it
* got.
*/
int fallback_cmd;
bufchain banner; /* accumulates banners during do_ssh2_authconn */
/*
* Used for username and password input.
*/
char *userpass_input_buffer;
int userpass_input_buflen;
int userpass_input_bufpos;
int userpass_input_echo;
int pkt_ctx;
void *x11auth;
int version;
int v1_throttle_count;
|
<
<
<
<
<
<
<
|
751
752
753
754
755
756
757
758
759
760
761
762
763
764
|
* scp1 if that fails. This variable is the means by which
* scp.c can reach into the SSH code and find out which one it
* got.
*/
int fallback_cmd;
bufchain banner; /* accumulates banners during do_ssh2_authconn */
int pkt_ctx;
void *x11auth;
int version;
int v1_throttle_count;
|
| ︙ | | | ︙ | |
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
|
*/
{
unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;
assert(NULL == find234(ssh->channels, &i, ssh_channelfind));
}
return low + 1 + CHANNEL_NUMBER_OFFSET;
}
static void c_write(Ssh ssh, const char *buf, int len)
{
if ((flags & FLAG_STDERR)) {
int i;
for (i = 0; i < len; i++)
if (buf[i] != '\r')
fputc(buf[i], stderr);
return;
}
from_backend(ssh->frontend, 1, buf, len);
}
static void c_write_untrusted(Ssh ssh, const char *buf, int len)
{
int i;
for (i = 0; i < len; i++) {
if (buf[i] == '\n')
c_write(ssh, "\r\n", 2);
else if ((buf[i] & 0x60) || (buf[i] == '\r'))
c_write(ssh, buf + i, 1);
}
}
static void c_write_str(Ssh ssh, const char *buf)
{
c_write(ssh, buf, strlen(buf));
}
|
>
>
>
>
>
>
>
>
|
<
<
<
|
|
<
|
<
<
|
|
|
|
<
|
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
|
*/
{
unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;
assert(NULL == find234(ssh->channels, &i, ssh_channelfind));
}
return low + 1 + CHANNEL_NUMBER_OFFSET;
}
static void c_write_stderr(int trusted, const char *buf, int len)
{
int i;
for (i = 0; i < len; i++)
if (buf[i] != '\r' && (trusted || buf[i] & 0x60))
fputc(buf[i], stderr);
}
static void c_write(Ssh ssh, const char *buf, int len)
{
if (flags & FLAG_STDERR)
c_write_stderr(1, buf, len);
else
from_backend(ssh->frontend, 1, buf, len);
}
static void c_write_untrusted(Ssh ssh, const char *buf, int len)
{
if (flags & FLAG_STDERR)
c_write_stderr(0, buf, len);
else
from_backend_untrusted(ssh->frontend, buf, len);
}
static void c_write_str(Ssh ssh, const char *buf)
{
c_write(ssh, buf, strlen(buf));
}
|
| ︙ | | | ︙ | |
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
|
case CHAN_SOCKDATA:
pfd_override_throttle(c->u.pfd.s, enable);
break;
}
}
}
/*
* Username and password input, abstracted off into routines
* reusable in several places - even between SSH-1 and SSH-2.
*/
/* Set up a username or password input loop on a given buffer. */
static void setup_userpass_input(Ssh ssh, char *buffer, int buflen, int echo)
{
ssh->userpass_input_buffer = buffer;
ssh->userpass_input_buflen = buflen;
ssh->userpass_input_bufpos = 0;
ssh->userpass_input_echo = echo;
}
/*
* Process some terminal data in the course of username/password
* input. Returns >0 for success (line of input returned in
* buffer), <0 for failure (user hit ^C/^D, bomb out and exit), 0
* for inconclusive (keep waiting for more input please).
*/
static int process_userpass_input(Ssh ssh, unsigned char *in, int inlen)
{
char c;
while (inlen--) {
switch (c = *in++) {
case 10:
case 13:
ssh->userpass_input_buffer[ssh->userpass_input_bufpos] = 0;
ssh->userpass_input_buffer[ssh->userpass_input_buflen-1] = 0;
return +1;
break;
case 8:
case 127:
if (ssh->userpass_input_bufpos > 0) {
if (ssh->userpass_input_echo)
c_write_str(ssh, "\b \b");
ssh->userpass_input_bufpos--;
}
break;
case 21:
case 27:
while (ssh->userpass_input_bufpos > 0) {
if (ssh->userpass_input_echo)
c_write_str(ssh, "\b \b");
ssh->userpass_input_bufpos--;
}
break;
case 3:
case 4:
return -1;
break;
default:
/*
* This simplistic check for printability is disabled
* when we're doing password input, because some people
* have control characters in their passwords.o
*/
if ((!ssh->userpass_input_echo ||
(c >= ' ' && c <= '~') ||
((unsigned char) c >= 160))
&& ssh->userpass_input_bufpos < ssh->userpass_input_buflen-1) {
ssh->userpass_input_buffer[ssh->userpass_input_bufpos++] = c;
if (ssh->userpass_input_echo)
c_write(ssh, &c, 1);
}
break;
}
}
return 0;
}
static void ssh_agent_callback(void *sshv, void *reply, int replylen)
{
Ssh ssh = (Ssh) sshv;
ssh->agent_response = reply;
ssh->agent_response_len = replylen;
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
|
case CHAN_SOCKDATA:
pfd_override_throttle(c->u.pfd.s, enable);
break;
}
}
}
static void ssh_agent_callback(void *sshv, void *reply, int replylen)
{
Ssh ssh = (Ssh) sshv;
ssh->agent_response = reply;
ssh->agent_response_len = replylen;
|
| ︙ | | | ︙ | |
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
|
int tried_publickey, tried_agent;
int tis_auth_refused, ccard_auth_refused;
unsigned char session_id[16];
int cipher_type;
char username[100];
void *publickey_blob;
int publickey_bloblen;
char password[100];
char prompt[200];
int pos;
char c;
int pwpkt_type;
unsigned char request[5], *response, *p;
int responselen;
int keyi, nkeys;
int authed;
struct RSAKey key;
|
<
|
|
>
|
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
|
int tried_publickey, tried_agent;
int tis_auth_refused, ccard_auth_refused;
unsigned char session_id[16];
int cipher_type;
char username[100];
void *publickey_blob;
int publickey_bloblen;
char *publickey_comment;
int publickey_encrypted;
prompts_t *cur_prompt;
char c;
int pwpkt_type;
unsigned char request[5], *response, *p;
int responselen;
int keyi, nkeys;
int authed;
struct RSAKey key;
|
| ︙ | | | ︙ | |
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
|
if (pktin->type != SSH1_SMSG_SUCCESS) {
bombout(("Encryption not successfully enabled"));
crStop(0);
}
logevent("Successfully started encryption");
fflush(stdout);
{
if (!*ssh->cfg.username) {
if (ssh_get_line && !ssh_getline_pw_only) {
if (!ssh_get_line("login as: ",
s->username, sizeof(s->username), FALSE)) {
/*
* get_line failed to get a username.
* Terminate.
*/
ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);
crStop(1);
}
} else {
int ret; /* need not be kept over crReturn */
c_write_str(ssh, "login as: ");
ssh->send_ok = 1;
setup_userpass_input(ssh, s->username, sizeof(s->username), 1);
do {
crWaitUntil(!pktin);
ret = process_userpass_input(ssh, in, inlen);
} while (ret == 0);
if (ret < 0)
cleanup_exit(0);
c_write_str(ssh, "\r\n");
}
} else {
strncpy(s->username, ssh->cfg.username, sizeof(s->username));
s->username[sizeof(s->username)-1] = '\0';
}
send_packet(ssh, SSH1_CMSG_USER, PKT_STR, s->username, PKT_END);
{
char userlog[22 + sizeof(s->username)];
sprintf(userlog, "Sent username \"%s\"", s->username);
logevent(userlog);
if (flags & FLAG_INTERACTIVE &&
(!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) {
strcat(userlog, "\r\n");
c_write_str(ssh, userlog);
}
}
}
crWaitUntil(pktin);
if ((ssh->remote_bugs & BUG_CHOKES_ON_RSA)) {
/* We must not attempt PK auth. Pretend we've already tried it. */
s->tried_publickey = s->tried_agent = 1;
} else {
s->tried_publickey = s->tried_agent = 0;
}
s->tis_auth_refused = s->ccard_auth_refused = 0;
/* Load the public half of ssh->cfg.keyfile so we notice if it's in Pageant */
if (!filename_is_null(ssh->cfg.keyfile)) {
if (!rsakey_pubblob(&ssh->cfg.keyfile,
&s->publickey_blob, &s->publickey_bloblen,
NULL, NULL))
s->publickey_blob = NULL;
} else
s->publickey_blob = NULL;
while (pktin->type == SSH1_SMSG_FAILURE) {
s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;
if (agent_exists() && !s->tried_agent) {
|
|
|
>
>
>
|
|
>
>
>
>
>
>
>
>
|
|
<
|
>
|
|
|
<
<
<
<
|
|
<
<
<
<
|
<
<
<
<
|
|
|
>
>
|
>
>
>
>
>
>
>
|
|
>
>
|
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
|
if (pktin->type != SSH1_SMSG_SUCCESS) {
bombout(("Encryption not successfully enabled"));
crStop(0);
}
logevent("Successfully started encryption");
fflush(stdout); /* FIXME eh? */
{
if (!*ssh->cfg.username) {
int ret; /* need not be kept over crReturn */
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH login name");
add_prompt(s->cur_prompt, dupstr("login as: "), TRUE,
lenof(s->username));
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
ssh->send_ok = 1;
crWaitUntil(!pktin);
ret = get_userpass_input(s->cur_prompt, in, inlen);
ssh->send_ok = 0;
}
if (!ret) {
/*
* Failed to get a username. Terminate.
*/
free_prompts(s->cur_prompt);
ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);
crStop(0);
}
memcpy(s->username, s->cur_prompt->prompts[0]->result,
lenof(s->username));
free_prompts(s->cur_prompt);
} else {
strncpy(s->username, ssh->cfg.username, sizeof(s->username));
s->username[sizeof(s->username)-1] = '\0';
}
send_packet(ssh, SSH1_CMSG_USER, PKT_STR, s->username, PKT_END);
{
char *userlog = dupprintf("Sent username \"%s\"", s->username);
logevent(userlog);
if (flags & FLAG_INTERACTIVE &&
(!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) {
c_write_str(ssh, userlog);
c_write_str(ssh, "\r\n");
}
sfree(userlog);
}
}
crWaitUntil(pktin);
if ((ssh->remote_bugs & BUG_CHOKES_ON_RSA)) {
/* We must not attempt PK auth. Pretend we've already tried it. */
s->tried_publickey = s->tried_agent = 1;
} else {
s->tried_publickey = s->tried_agent = 0;
}
s->tis_auth_refused = s->ccard_auth_refused = 0;
/*
* Load the public half of any configured keyfile for later use.
*/
if (!filename_is_null(ssh->cfg.keyfile)) {
int keytype;
logeventf(ssh, "Reading private key file \"%.150s\"",
filename_to_str(&ssh->cfg.keyfile));
keytype = key_type(&ssh->cfg.keyfile);
if (keytype == SSH_KEYTYPE_SSH1) {
const char *error;
if (rsakey_pubblob(&ssh->cfg.keyfile,
&s->publickey_blob, &s->publickey_bloblen,
&s->publickey_comment, &error)) {
s->publickey_encrypted = rsakey_encrypted(&ssh->cfg.keyfile,
NULL);
} else {
char *msgbuf;
logeventf(ssh, "Unable to load private key (%s)", error);
msgbuf = dupprintf("Unable to load private key file "
"\"%.150s\" (%s)\r\n",
filename_to_str(&ssh->cfg.keyfile),
error);
c_write_str(ssh, msgbuf);
sfree(msgbuf);
s->publickey_blob = NULL;
}
} else {
char *msgbuf;
logeventf(ssh, "Unable to use this key file (%s)",
key_type_to_str(keytype));
msgbuf = dupprintf("Unable to use key file \"%.150s\""
" (%s)\r\n",
filename_to_str(&ssh->cfg.keyfile),
key_type_to_str(keytype));
c_write_str(ssh, msgbuf);
sfree(msgbuf);
s->publickey_blob = NULL;
}
} else
s->publickey_blob = NULL;
while (pktin->type == SSH1_SMSG_FAILURE) {
s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;
if (agent_exists() && !s->tried_agent) {
|
| ︙ | | | ︙ | |
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
|
break;
}
sfree(s->response);
}
if (s->authed)
break;
}
if (!filename_is_null(ssh->cfg.keyfile) && !s->tried_publickey)
s->pwpkt_type = SSH1_CMSG_AUTH_RSA;
if (ssh->cfg.try_tis_auth &&
(s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) &&
!s->tis_auth_refused) {
s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
logevent("Requested TIS authentication");
send_packet(ssh, SSH1_CMSG_AUTH_TIS, PKT_END);
crWaitUntil(pktin);
if (pktin->type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
logevent("TIS authentication declined");
if (flags & FLAG_INTERACTIVE)
c_write_str(ssh, "TIS authentication refused.\r\n");
s->tis_auth_refused = 1;
continue;
} else {
char *challenge;
int challengelen;
ssh_pkt_getstring(pktin, &challenge, &challengelen);
if (!challenge) {
bombout(("TIS challenge packet was badly formed"));
crStop(0);
}
c_write_str(ssh, "Using TIS authentication.\r\n");
logevent("Received TIS challenge");
if (challengelen > sizeof(s->prompt) - 1)
challengelen = sizeof(s->prompt) - 1;/* prevent overrun */
memcpy(s->prompt, challenge, challengelen);
/* Prompt heuristic comes from OpenSSH */
strncpy(s->prompt + challengelen,
memchr(s->prompt, '\n', challengelen) ?
"": "\r\nResponse: ",
(sizeof s->prompt) - challengelen);
s->prompt[(sizeof s->prompt) - 1] = '\0';
}
}
if (ssh->cfg.try_tis_auth &&
(s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) &&
!s->ccard_auth_refused) {
s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
logevent("Requested CryptoCard authentication");
send_packet(ssh, SSH1_CMSG_AUTH_CCARD, PKT_END);
crWaitUntil(pktin);
if (pktin->type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
logevent("CryptoCard authentication declined");
c_write_str(ssh, "CryptoCard authentication refused.\r\n");
s->ccard_auth_refused = 1;
continue;
} else {
char *challenge;
int challengelen;
ssh_pkt_getstring(pktin, &challenge, &challengelen);
if (!challenge) {
bombout(("CryptoCard challenge packet was badly formed"));
crStop(0);
}
c_write_str(ssh, "Using CryptoCard authentication.\r\n");
logevent("Received CryptoCard challenge");
if (challengelen > sizeof(s->prompt) - 1)
challengelen = sizeof(s->prompt) - 1;/* prevent overrun */
memcpy(s->prompt, challenge, challengelen);
strncpy(s->prompt + challengelen,
memchr(s->prompt, '\n', challengelen) ?
"" : "\r\nResponse: ",
sizeof(s->prompt) - challengelen);
s->prompt[sizeof(s->prompt) - 1] = '\0';
}
}
if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
sprintf(s->prompt, "%.90s@%.90s's password: ",
s->username, ssh->savedhost);
}
if (s->pwpkt_type == SSH1_CMSG_AUTH_RSA) {
char *comment = NULL;
int type;
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "Trying public key authentication.\r\n");
logeventf(ssh, "Trying public key \"%s\"",
filename_to_str(&ssh->cfg.keyfile));
type = key_type(&ssh->cfg.keyfile);
if (type != SSH_KEYTYPE_SSH1) {
char *msg = dupprintf("Key is of wrong type (%s)",
key_type_to_str(type));
logevent(msg);
c_write_str(ssh, msg);
c_write_str(ssh, "\r\n");
sfree(msg);
s->tried_publickey = 1;
continue;
}
if (!rsakey_encrypted(&ssh->cfg.keyfile, &comment)) {
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "No passphrase required.\r\n");
goto tryauth;
}
sprintf(s->prompt, "Passphrase for key \"%.100s\": ", comment);
sfree(comment);
}
/*
* Show password prompt, having first obtained it via a TIS
* or CryptoCard exchange if we're doing TIS or CryptoCard
* authentication.
*/
if (ssh_get_line) {
if (!ssh_get_line(s->prompt, s->password,
sizeof(s->password), TRUE)) {
/*
* get_line failed to get a password (for example
* because one was supplied on the command line
* which has already failed to work). Terminate.
*/
ssh_disconnect(ssh, NULL, "Unable to authenticate", 0, FALSE);
crStop(1);
}
} else {
/* Prompt may have come from server. We've munged it a bit, so
* we know it to be zero-terminated at least once. */
int ret; /* need not be saved over crReturn */
c_write_untrusted(ssh, s->prompt, strlen(s->prompt));
s->pos = 0;
setup_userpass_input(ssh, s->password, sizeof(s->password), 0);
do {
crWaitUntil(!pktin);
ret = process_userpass_input(ssh, in, inlen);
} while (ret == 0);
if (ret < 0)
cleanup_exit(0);
c_write_str(ssh, "\r\n");
}
tryauth:
if (s->pwpkt_type == SSH1_CMSG_AUTH_RSA) {
/*
* Try public key authentication with the specified
* key file.
*/
s->tried_publickey = 1;
{
const char *error = NULL;
int ret = loadrsakey(&ssh->cfg.keyfile, &s->key, s->password,
&error);
if (ret == 0) {
c_write_str(ssh, "Couldn't load private key from ");
c_write_str(ssh, filename_to_str(&ssh->cfg.keyfile));
c_write_str(ssh, " (");
c_write_str(ssh, error);
c_write_str(ssh, ").\r\n");
continue; /* go and try password */
}
if (ret == -1) {
c_write_str(ssh, "Wrong passphrase.\r\n");
s->tried_publickey = 0;
continue; /* try again */
}
}
/*
* Send a public key attempt.
*/
send_packet(ssh, SSH1_CMSG_AUTH_RSA,
PKT_BIGNUM, s->key.modulus, PKT_END);
crWaitUntil(pktin);
if (pktin->type == SSH1_SMSG_FAILURE) {
c_write_str(ssh, "Server refused our public key.\r\n");
continue; /* go and try password */
}
if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
bombout(("Bizarre response to offer of public key"));
crStop(0);
}
{
int i;
unsigned char buffer[32];
Bignum challenge, response;
if ((challenge = ssh1_pkt_getmp(pktin)) == NULL) {
bombout(("Server's RSA challenge was badly formatted"));
crStop(0);
}
response = rsadecrypt(challenge, &s->key);
freebn(s->key.private_exponent);/* burn the evidence */
for (i = 0; i < 32; i++) {
buffer[i] = bignum_byte(response, 31 - i);
}
MD5Init(&md5c);
MD5Update(&md5c, buffer, 32);
MD5Update(&md5c, s->session_id, 16);
MD5Final(buffer, &md5c);
send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,
PKT_DATA, buffer, 16, PKT_END);
freebn(challenge);
freebn(response);
}
crWaitUntil(pktin);
if (pktin->type == SSH1_SMSG_FAILURE) {
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "Failed to authenticate with"
" our public key.\r\n");
continue; /* go and try password */
} else if (pktin->type != SSH1_SMSG_SUCCESS) {
bombout(("Bizarre response to RSA authentication response"));
crStop(0);
}
break; /* we're through! */
} else {
if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
/*
* Defence against traffic analysis: we send a
* whole bunch of packets containing strings of
* different lengths. One of these strings is the
* password, in a SSH1_CMSG_AUTH_PASSWORD packet.
* The others are all random data in
* SSH1_MSG_IGNORE packets. This way a passive
* listener can't tell which is the password, and
* hence can't deduce the password length.
*
* Anybody with a password length greater than 16
* bytes is going to have enough entropy in their
* password that a listener won't find it _that_
* much help to know how long it is. So what we'll
* do is:
*
* - if password length < 16, we send 15 packets
* containing string lengths 1 through 15
*
* - otherwise, we let N be the nearest multiple
* of 8 below the password length, and send 8
* packets containing string lengths N through
* N+7. This won't obscure the order of
* magnitude of the password length, but it will
* introduce a bit of extra uncertainty.
*
* A few servers (the old 1.2.18 through 1.2.22)
* can't deal with SSH1_MSG_IGNORE. For these
* servers, we need an alternative defence. We make
* use of the fact that the password is interpreted
* as a C string: so we can append a NUL, then some
* random data.
*
* One server (a Cisco one) can deal with neither
* SSH1_MSG_IGNORE _nor_ a padded password string.
* For this server we are left with no defences
* against password length sniffing.
*/
if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) {
/*
* The server can deal with SSH1_MSG_IGNORE, so
* we can use the primary defence.
*/
int bottom, top, pwlen, i;
char *randomstr;
pwlen = strlen(s->password);
if (pwlen < 16) {
bottom = 0; /* zero length passwords are OK! :-) */
top = 15;
} else {
bottom = pwlen & ~7;
top = bottom + 7;
}
assert(pwlen >= bottom && pwlen <= top);
randomstr = snewn(top + 1, char);
for (i = bottom; i <= top; i++) {
if (i == pwlen) {
defer_packet(ssh, s->pwpkt_type,
PKTT_PASSWORD, PKT_STR, s->password,
PKTT_OTHER, PKT_END);
} else {
for (j = 0; j < i; j++) {
do {
randomstr[j] = random_byte();
} while (randomstr[j] == '\0');
}
randomstr[i] = '\0';
defer_packet(ssh, SSH1_MSG_IGNORE,
PKT_STR, randomstr, PKT_END);
}
}
logevent("Sending password with camouflage packets");
ssh_pkt_defersend(ssh);
sfree(randomstr);
}
else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {
/*
* The server can't deal with SSH1_MSG_IGNORE
* but can deal with padded passwords, so we
* can use the secondary defence.
*/
char string[64];
char *ss;
int len;
len = strlen(s->password);
if (len < sizeof(string)) {
ss = string;
strcpy(string, s->password);
len++; /* cover the zero byte */
while (len < sizeof(string)) {
string[len++] = (char) random_byte();
}
} else {
ss = s->password;
}
logevent("Sending length-padded password");
send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,
PKT_INT, len, PKT_DATA, ss, len,
PKTT_OTHER, PKT_END);
} else {
/*
* The server has _both_
* BUG_CHOKES_ON_SSH1_IGNORE and
* BUG_NEEDS_SSH1_PLAIN_PASSWORD. There is
* therefore nothing we can do.
*/
int len;
len = strlen(s->password);
logevent("Sending unpadded password");
send_packet(ssh, s->pwpkt_type,
PKTT_PASSWORD, PKT_INT, len,
PKT_DATA, s->password, len,
PKTT_OTHER, PKT_END);
}
} else {
send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,
PKT_STR, s->password, PKTT_OTHER, PKT_END);
}
}
logevent("Sent password");
memset(s->password, 0, strlen(s->password));
crWaitUntil(pktin);
if (pktin->type == SSH1_SMSG_FAILURE) {
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "Access denied\r\n");
logevent("Authentication refused");
} else if (pktin->type != SSH1_SMSG_SUCCESS) {
bombout(("Strange packet received, type %d", pktin->type));
crStop(0);
}
}
logevent("Authentication successful");
crFinish(1);
}
void sshfwd_close(struct ssh_channel *c)
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
<
|
<
|
|
>
|
>
>
|
>
|
>
>
>
|
>
>
>
<
|
>
|
>
|
>
|
>
|
|
>
|
>
>
>
|
>
>
>
>
|
|
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
>
>
>
|
>
|
>
>
|
|
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
<
|
>
>
>
>
>
>
|
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
|
break;
}
sfree(s->response);
}
if (s->authed)
break;
}
if (s->publickey_blob && !s->tried_publickey) {
/*
* Try public key authentication with the specified
* key file.
*/
int got_passphrase; /* need not be kept over crReturn */
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "Trying public key authentication.\r\n");
logeventf(ssh, "Trying public key \"%s\"",
filename_to_str(&ssh->cfg.keyfile));
s->tried_publickey = 1;
got_passphrase = FALSE;
while (!got_passphrase) {
/*
* Get a passphrase, if necessary.
*/
char *passphrase = NULL; /* only written after crReturn */
const char *error;
if (!s->publickey_encrypted) {
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "No passphrase required.\r\n");
passphrase = NULL;
} else {
int ret; /* need not be kept over crReturn */
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = FALSE;
s->cur_prompt->name = dupstr("SSH key passphrase");
add_prompt(s->cur_prompt,
dupprintf("Passphrase for key \"%.100s\": ",
s->publickey_comment),
FALSE, SSH_MAX_PASSWORD_LEN);
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
ssh->send_ok = 1;
crWaitUntil(!pktin);
ret = get_userpass_input(s->cur_prompt, in, inlen);
ssh->send_ok = 0;
}
if (!ret) {
/* Failed to get a passphrase. Terminate. */
free_prompts(s->cur_prompt);
ssh_disconnect(ssh, NULL, "Unable to authenticate",
0, TRUE);
crStop(0);
}
passphrase = dupstr(s->cur_prompt->prompts[0]->result);
free_prompts(s->cur_prompt);
}
/*
* Try decrypting key with passphrase.
*/
ret = loadrsakey(&ssh->cfg.keyfile, &s->key, passphrase,
&error);
if (passphrase) {
memset(passphrase, 0, strlen(passphrase));
sfree(passphrase);
}
if (ret == 1) {
/* Correct passphrase. */
got_passphrase = TRUE;
} else if (ret == 0) {
c_write_str(ssh, "Couldn't load private key from ");
c_write_str(ssh, filename_to_str(&ssh->cfg.keyfile));
c_write_str(ssh, " (");
c_write_str(ssh, error);
c_write_str(ssh, ").\r\n");
got_passphrase = FALSE;
break; /* go and try something else */
} else if (ret == -1) {
c_write_str(ssh, "Wrong passphrase.\r\n"); /* FIXME */
s->tried_publickey = 0;
got_passphrase = FALSE;
/* and try again */
}
}
if (got_passphrase) {
/*
* Send a public key attempt.
*/
send_packet(ssh, SSH1_CMSG_AUTH_RSA,
PKT_BIGNUM, s->key.modulus, PKT_END);
crWaitUntil(pktin);
if (pktin->type == SSH1_SMSG_FAILURE) {
c_write_str(ssh, "Server refused our public key.\r\n");
continue; /* go and try password */
}
if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
bombout(("Bizarre response to offer of public key"));
crStop(0);
}
{
int i;
unsigned char buffer[32];
Bignum challenge, response;
if ((challenge = ssh1_pkt_getmp(pktin)) == NULL) {
bombout(("Server's RSA challenge was badly formatted"));
crStop(0);
}
response = rsadecrypt(challenge, &s->key);
freebn(s->key.private_exponent);/* burn the evidence */
for (i = 0; i < 32; i++) {
buffer[i] = bignum_byte(response, 31 - i);
}
MD5Init(&md5c);
MD5Update(&md5c, buffer, 32);
MD5Update(&md5c, s->session_id, 16);
MD5Final(buffer, &md5c);
send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,
PKT_DATA, buffer, 16, PKT_END);
freebn(challenge);
freebn(response);
}
crWaitUntil(pktin);
if (pktin->type == SSH1_SMSG_FAILURE) {
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "Failed to authenticate with"
" our public key.\r\n");
continue; /* go and try password */
} else if (pktin->type != SSH1_SMSG_SUCCESS) {
bombout(("Bizarre response to RSA authentication response"));
crStop(0);
}
break; /* we're through! */
}
}
/*
* Otherwise, try various forms of password-like authentication.
*/
s->cur_prompt = new_prompts(ssh->frontend);
if (ssh->cfg.try_tis_auth &&
(s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) &&
!s->tis_auth_refused) {
s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
logevent("Requested TIS authentication");
send_packet(ssh, SSH1_CMSG_AUTH_TIS, PKT_END);
crWaitUntil(pktin);
if (pktin->type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
logevent("TIS authentication declined");
if (flags & FLAG_INTERACTIVE)
c_write_str(ssh, "TIS authentication refused.\r\n");
s->tis_auth_refused = 1;
continue;
} else {
char *challenge;
int challengelen;
char *instr_suf, *prompt;
ssh_pkt_getstring(pktin, &challenge, &challengelen);
if (!challenge) {
bombout(("TIS challenge packet was badly formed"));
crStop(0);
}
logevent("Received TIS challenge");
s->cur_prompt->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH TIS authentication");
/* Prompt heuristic comes from OpenSSH */
if (memchr(challenge, '\n', challengelen)) {
instr_suf = dupstr("");
prompt = dupprintf("%.*s", challengelen, challenge);
} else {
instr_suf = dupprintf("%.*s", challengelen, challenge);
prompt = dupstr("Response: ");
}
s->cur_prompt->instruction =
dupprintf("Using TIS authentication.%s%s",
(*instr_suf) ? "\n" : "",
instr_suf);
s->cur_prompt->instr_reqd = TRUE;
add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN);
sfree(instr_suf);
}
}
if (ssh->cfg.try_tis_auth &&
(s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) &&
!s->ccard_auth_refused) {
s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
logevent("Requested CryptoCard authentication");
send_packet(ssh, SSH1_CMSG_AUTH_CCARD, PKT_END);
crWaitUntil(pktin);
if (pktin->type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
logevent("CryptoCard authentication declined");
c_write_str(ssh, "CryptoCard authentication refused.\r\n");
s->ccard_auth_refused = 1;
continue;
} else {
char *challenge;
int challengelen;
char *instr_suf, *prompt;
ssh_pkt_getstring(pktin, &challenge, &challengelen);
if (!challenge) {
bombout(("CryptoCard challenge packet was badly formed"));
crStop(0);
}
logevent("Received CryptoCard challenge");
s->cur_prompt->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH CryptoCard authentication");
s->cur_prompt->name_reqd = FALSE;
/* Prompt heuristic comes from OpenSSH */
if (memchr(challenge, '\n', challengelen)) {
instr_suf = dupstr("");
prompt = dupprintf("%.*s", challengelen, challenge);
} else {
instr_suf = dupprintf("%.*s", challengelen, challenge);
prompt = dupstr("Response: ");
}
s->cur_prompt->instruction =
dupprintf("Using CryptoCard authentication.%s%s",
(*instr_suf) ? "\n" : "",
instr_suf);
s->cur_prompt->instr_reqd = TRUE;
add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN);
sfree(instr_suf);
}
}
if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
s->cur_prompt->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH password");
add_prompt(s->cur_prompt, dupprintf("%.90s@%.90s's password: ",
s->username, ssh->savedhost),
FALSE, SSH_MAX_PASSWORD_LEN);
}
/*
* Show password prompt, having first obtained it via a TIS
* or CryptoCard exchange if we're doing TIS or CryptoCard
* authentication.
*/
{
int ret; /* need not be kept over crReturn */
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
ssh->send_ok = 1;
crWaitUntil(!pktin);
ret = get_userpass_input(s->cur_prompt, in, inlen);
ssh->send_ok = 0;
}
if (!ret) {
/*
* Failed to get a password (for example
* because one was supplied on the command line
* which has already failed to work). Terminate.
*/
free_prompts(s->cur_prompt);
ssh_disconnect(ssh, NULL, "Unable to authenticate", 0, TRUE);
crStop(0);
}
}
if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
/*
* Defence against traffic analysis: we send a
* whole bunch of packets containing strings of
* different lengths. One of these strings is the
* password, in a SSH1_CMSG_AUTH_PASSWORD packet.
* The others are all random data in
* SSH1_MSG_IGNORE packets. This way a passive
* listener can't tell which is the password, and
* hence can't deduce the password length.
*
* Anybody with a password length greater than 16
* bytes is going to have enough entropy in their
* password that a listener won't find it _that_
* much help to know how long it is. So what we'll
* do is:
*
* - if password length < 16, we send 15 packets
* containing string lengths 1 through 15
*
* - otherwise, we let N be the nearest multiple
* of 8 below the password length, and send 8
* packets containing string lengths N through
* N+7. This won't obscure the order of
* magnitude of the password length, but it will
* introduce a bit of extra uncertainty.
*
* A few servers (the old 1.2.18 through 1.2.22)
* can't deal with SSH1_MSG_IGNORE. For these
* servers, we need an alternative defence. We make
* use of the fact that the password is interpreted
* as a C string: so we can append a NUL, then some
* random data.
*
* One server (a Cisco one) can deal with neither
* SSH1_MSG_IGNORE _nor_ a padded password string.
* For this server we are left with no defences
* against password length sniffing.
*/
if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) {
/*
* The server can deal with SSH1_MSG_IGNORE, so
* we can use the primary defence.
*/
int bottom, top, pwlen, i;
char *randomstr;
pwlen = strlen(s->cur_prompt->prompts[0]->result);
if (pwlen < 16) {
bottom = 0; /* zero length passwords are OK! :-) */
top = 15;
} else {
bottom = pwlen & ~7;
top = bottom + 7;
}
assert(pwlen >= bottom && pwlen <= top);
randomstr = snewn(top + 1, char);
for (i = bottom; i <= top; i++) {
if (i == pwlen) {
defer_packet(ssh, s->pwpkt_type,
PKTT_PASSWORD, PKT_STR,
s->cur_prompt->prompts[0]->result,
PKTT_OTHER, PKT_END);
} else {
for (j = 0; j < i; j++) {
do {
randomstr[j] = random_byte();
} while (randomstr[j] == '\0');
}
randomstr[i] = '\0';
defer_packet(ssh, SSH1_MSG_IGNORE,
PKT_STR, randomstr, PKT_END);
}
}
logevent("Sending password with camouflage packets");
ssh_pkt_defersend(ssh);
sfree(randomstr);
}
else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {
/*
* The server can't deal with SSH1_MSG_IGNORE
* but can deal with padded passwords, so we
* can use the secondary defence.
*/
char string[64];
char *ss;
int len;
len = strlen(s->cur_prompt->prompts[0]->result);
if (len < sizeof(string)) {
ss = string;
strcpy(string, s->cur_prompt->prompts[0]->result);
len++; /* cover the zero byte */
while (len < sizeof(string)) {
string[len++] = (char) random_byte();
}
} else {
ss = s->cur_prompt->prompts[0]->result;
}
logevent("Sending length-padded password");
send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,
PKT_INT, len, PKT_DATA, ss, len,
PKTT_OTHER, PKT_END);
} else {
/*
* The server has _both_
* BUG_CHOKES_ON_SSH1_IGNORE and
* BUG_NEEDS_SSH1_PLAIN_PASSWORD. There is
* therefore nothing we can do.
*/
int len;
len = strlen(s->cur_prompt->prompts[0]->result);
logevent("Sending unpadded password");
send_packet(ssh, s->pwpkt_type,
PKTT_PASSWORD, PKT_INT, len,
PKT_DATA, s->cur_prompt->prompts[0]->result, len,
PKTT_OTHER, PKT_END);
}
} else {
send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,
PKT_STR, s->cur_prompt->prompts[0]->result,
PKTT_OTHER, PKT_END);
}
logevent("Sent password");
free_prompts(s->cur_prompt);
crWaitUntil(pktin);
if (pktin->type == SSH1_SMSG_FAILURE) {
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "Access denied\r\n");
logevent("Authentication refused");
} else if (pktin->type != SSH1_SMSG_SUCCESS) {
bombout(("Strange packet received, type %d", pktin->type));
crStop(0);
}
}
/* Clear up */
if (s->publickey_blob) {
sfree(s->publickey_blob);
sfree(s->publickey_comment);
}
logevent("Authentication successful");
crFinish(1);
}
void sshfwd_close(struct ssh_channel *c)
|
| ︙ | | | ︙ | |
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
|
AUTH_TYPE_PASSWORD,
AUTH_TYPE_KEYBOARD_INTERACTIVE,
AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
} type;
int done_service_req;
int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;
int tried_pubkey_config, tried_agent;
int kbd_inter_running, kbd_inter_refused;
int we_are_in;
int num_prompts, curr_prompt, echo;
char username[100];
int got_username;
char pwprompt[512];
char password[100];
void *publickey_blob;
int publickey_bloblen;
unsigned char request[5], *response, *p;
int responselen;
int keyi, nkeys;
int authed;
char *pkblob, *alg, *commentp;
int pklen, alglen, commentlen;
int siglen, retlen, len;
|
|
>
|
<
<
>
>
>
|
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
|
AUTH_TYPE_PASSWORD,
AUTH_TYPE_KEYBOARD_INTERACTIVE,
AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
} type;
int done_service_req;
int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;
int tried_pubkey_config, tried_agent;
int kbd_inter_refused;
int we_are_in;
prompts_t *cur_prompt;
int num_prompts;
char username[100];
int got_username;
void *publickey_blob;
int publickey_bloblen;
int publickey_encrypted;
char *publickey_algorithm;
char *publickey_comment;
unsigned char request[5], *response, *p;
int responselen;
int keyi, nkeys;
int authed;
char *pkblob, *alg, *commentp;
int pklen, alglen, commentlen;
int siglen, retlen, len;
|
| ︙ | | | ︙ | |
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
|
if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) {
s->we_are_in = TRUE; /* no auth required */
} else {
bombout(("Server refused service request"));
crStopV;
}
}
/*
* We repeat this whole loop, including the username prompt,
* until we manage a successful authentication. If the user
* types the wrong _password_, they can be sent back to the
* beginning to try another username, if this is configured on.
* (If they specify a username in the config, they are never
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
|
if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) {
s->we_are_in = TRUE; /* no auth required */
} else {
bombout(("Server refused service request"));
crStopV;
}
}
/*
* Misc one-time setup for authentication.
*/
s->publickey_blob = NULL;
if (!s->we_are_in) {
/*
* Load the public half of any configured public key file
* for later use.
*/
if (!filename_is_null(ssh->cfg.keyfile)) {
int keytype;
logeventf(ssh, "Reading private key file \"%.150s\"",
filename_to_str(&ssh->cfg.keyfile));
keytype = key_type(&ssh->cfg.keyfile);
if (keytype == SSH_KEYTYPE_SSH2) {
const char *error;
s->publickey_blob =
ssh2_userkey_loadpub(&ssh->cfg.keyfile,
&s->publickey_algorithm,
&s->publickey_bloblen,
&s->publickey_comment, &error);
if (s->publickey_blob) {
s->publickey_encrypted =
ssh2_userkey_encrypted(&ssh->cfg.keyfile, NULL);
} else {
char *msgbuf;
logeventf(ssh, "Unable to load private key (%s)",
error);
msgbuf = dupprintf("Unable to load private key file "
"\"%.150s\" (%s)\r\n",
filename_to_str(&ssh->cfg.keyfile),
error);
c_write_str(ssh, msgbuf);
sfree(msgbuf);
}
} else {
char *msgbuf;
logeventf(ssh, "Unable to use this key file (%s)",
key_type_to_str(keytype));
msgbuf = dupprintf("Unable to use key file \"%.150s\""
" (%s)\r\n",
filename_to_str(&ssh->cfg.keyfile),
key_type_to_str(keytype));
c_write_str(ssh, msgbuf);
sfree(msgbuf);
s->publickey_blob = NULL;
}
}
}
/*
* We repeat this whole loop, including the username prompt,
* until we manage a successful authentication. If the user
* types the wrong _password_, they can be sent back to the
* beginning to try another username, if this is configured on.
* (If they specify a username in the config, they are never
|
| ︙ | | | ︙ | |
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6609
|
if (s->got_username && !ssh->cfg.change_username) {
/*
* We got a username last time round this loop, and
* with change_username turned off we don't try to get
* it again.
*/
} else if (!*ssh->cfg.username) {
if (ssh_get_line && !ssh_getline_pw_only) {
if (!ssh_get_line("login as: ",
s->username, sizeof(s->username), FALSE)) {
/*
* get_line failed to get a username.
* Terminate.
*/
ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);
crStopV;
}
} else {
int ret; /* need not be saved across crReturn */
c_write_str(ssh, "login as: ");
ssh->send_ok = 1;
setup_userpass_input(ssh, s->username, sizeof(s->username), 1);
do {
crWaitUntilV(!pktin);
ret = process_userpass_input(ssh, in, inlen);
} while (ret == 0);
if (ret < 0)
cleanup_exit(0);
c_write_str(ssh, "\r\n");
}
s->username[strcspn(s->username, "\n\r")] = '\0';
} else {
char *stuff;
strncpy(s->username, ssh->cfg.username, sizeof(s->username));
s->username[sizeof(s->username)-1] = '\0';
if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
stuff = dupprintf("Using username \"%s\".\r\n", s->username);
c_write_str(ssh, stuff);
|
|
>
>
>
|
|
>
>
>
>
>
>
>
>
|
|
|
|
>
|
|
|
<
<
<
<
|
<
<
<
<
<
<
<
<
|
>
|
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
|
if (s->got_username && !ssh->cfg.change_username) {
/*
* We got a username last time round this loop, and
* with change_username turned off we don't try to get
* it again.
*/
} else if (!*ssh->cfg.username) {
int ret; /* need not be kept over crReturn */
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH login name");
add_prompt(s->cur_prompt, dupstr("login as: "), TRUE,
lenof(s->username));
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
ssh->send_ok = 1;
crWaitUntilV(!pktin);
ret = get_userpass_input(s->cur_prompt, in, inlen);
ssh->send_ok = 0;
}
if (!ret) {
/*
* get_userpass_input() failed to get a username.
* Terminate.
*/
free_prompts(s->cur_prompt);
ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);
crStopV;
}
memcpy(s->username, s->cur_prompt->prompts[0]->result,
lenof(s->username));
free_prompts(s->cur_prompt);
} else {
char *stuff;
strncpy(s->username, ssh->cfg.username, sizeof(s->username));
s->username[sizeof(s->username)-1] = '\0';
if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
stuff = dupprintf("Using username \"%s\".\r\n", s->username);
c_write_str(ssh, stuff);
|
| ︙ | | | ︙ | |
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
|
ssh2_pkt_send(ssh, s->pktout);
s->type = AUTH_TYPE_NONE;
s->gotit = FALSE;
s->we_are_in = FALSE;
s->tried_pubkey_config = FALSE;
s->tried_agent = FALSE;
s->kbd_inter_running = FALSE;
s->kbd_inter_refused = FALSE;
/* Load the pub half of ssh->cfg.keyfile so we notice if it's in Pageant */
if (!filename_is_null(ssh->cfg.keyfile)) {
int keytype;
logeventf(ssh, "Reading private key file \"%.150s\"",
filename_to_str(&ssh->cfg.keyfile));
keytype = key_type(&ssh->cfg.keyfile);
if (keytype == SSH_KEYTYPE_SSH2) {
s->publickey_blob =
ssh2_userkey_loadpub(&ssh->cfg.keyfile, NULL,
&s->publickey_bloblen, NULL, NULL);
} else {
char *msgbuf;
logeventf(ssh, "Unable to use this key file (%s)",
key_type_to_str(keytype));
msgbuf = dupprintf("Unable to use key file \"%.150s\""
" (%s)\r\n",
filename_to_str(&ssh->cfg.keyfile),
key_type_to_str(keytype));
c_write_str(ssh, msgbuf);
sfree(msgbuf);
s->publickey_blob = NULL;
}
} else
s->publickey_blob = NULL;
while (1) {
/*
* Wait for the result of the last authentication request.
*/
if (!s->gotit)
crWaitUntilV(pktin);
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
|
ssh2_pkt_send(ssh, s->pktout);
s->type = AUTH_TYPE_NONE;
s->gotit = FALSE;
s->we_are_in = FALSE;
s->tried_pubkey_config = FALSE;
s->tried_agent = FALSE;
s->kbd_inter_refused = FALSE;
while (1) {
/*
* Wait for the result of the last authentication request.
*/
if (!s->gotit)
crWaitUntilV(pktin);
|
| ︙ | | | ︙ | |
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
|
}
if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
logevent("Access granted");
s->we_are_in = TRUE;
break;
}
if (s->kbd_inter_running &&
pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {
/*
* This is either a further set-of-prompts packet
* in keyboard-interactive authentication, or it's
* the same one and we came back here with `gotit'
* set. In the former case, we must reset the
* curr_prompt variable.
*/
if (!s->gotit)
s->curr_prompt = 0;
} else if (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {
/* FIXME: perhaps we should support this? */
bombout(("PASSWD_CHANGEREQ not yet supported"));
crStopV;
} else if (pktin->type != SSH2_MSG_USERAUTH_FAILURE) {
bombout(("Strange packet received during authentication: type %d",
pktin->type));
crStopV;
}
s->gotit = FALSE;
/*
* OK, we're now sitting on a USERAUTH_FAILURE message, so
* we can look at the string in it and know what we can
* helpfully try next.
*/
if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) {
char *methods;
int methlen;
ssh_pkt_getstring(pktin, &methods, &methlen);
s->kbd_inter_running = FALSE;
if (!ssh2_pkt_getbool(pktin)) {
/*
* We have received an unequivocal Access
* Denied. This can translate to a variety of
* messages:
*
* - if we'd just tried "none" authentication,
|
<
<
<
<
<
<
<
<
<
<
<
|
<
|
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
|
}
if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
logevent("Access granted");
s->we_are_in = TRUE;
break;
}
if (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {
/* FIXME: perhaps we should support this? */
bombout(("PASSWD_CHANGEREQ not yet supported"));
crStopV;
} else if (pktin->type != SSH2_MSG_USERAUTH_FAILURE) {
bombout(("Strange packet received during authentication: type %d",
pktin->type));
crStopV;
}
s->gotit = FALSE;
/*
* OK, we're now sitting on a USERAUTH_FAILURE message, so
* we can look at the string in it and know what we can
* helpfully try next.
*/
if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) {
char *methods;
int methlen;
ssh_pkt_getstring(pktin, &methods, &methlen);
if (!ssh2_pkt_getbool(pktin)) {
/*
* We have received an unequivocal Access
* Denied. This can translate to a variety of
* messages:
*
* - if we'd just tried "none" authentication,
|
| ︙ | | | ︙ | |
6778
6779
6780
6781
6782
6783
6784
6785
6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804
6805
|
in_commasep_string("publickey", methods, methlen);
s->can_passwd =
in_commasep_string("password", methods, methlen);
s->can_keyb_inter = ssh->cfg.try_ki_auth &&
in_commasep_string("keyboard-interactive", methods, methlen);
}
s->method = 0;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
s->need_pw = FALSE;
/*
* Most password/passphrase prompts will be
* non-echoing, so we set this to 0 by default.
* Exception is that some keyboard-interactive prompts
* can be echoing, in which case we'll set this to 1.
*/
s->echo = 0;
if (!s->method && s->can_pubkey &&
agent_exists() && !s->tried_agent) {
/*
* Attempt public-key authentication using Pageant.
*/
void *r;
s->authed = FALSE;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
|
<
<
<
<
<
<
<
<
<
>
<
<
|
6804
6805
6806
6807
6808
6809
6810
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
|
in_commasep_string("publickey", methods, methlen);
s->can_passwd =
in_commasep_string("password", methods, methlen);
s->can_keyb_inter = ssh->cfg.try_ki_auth &&
in_commasep_string("keyboard-interactive", methods, methlen);
}
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
if (s->can_pubkey && agent_exists() && !s->tried_agent) {
/*
* Attempt public-key authentication using Pageant.
*/
void *r;
s->authed = FALSE;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
|
| ︙ | | | ︙ | |
6956
6957
6958
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051
7052
7053
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072
7073
7074
7075
7076
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
7198
7199
7200
7201
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
7309
7310
|
}
}
}
if (s->authed)
continue;
}
sfree(s->response);
}
if (!s->method && s->can_pubkey && s->publickey_blob
&& !s->tried_pubkey_config) {
unsigned char *pub_blob;
char *algorithm, *comment;
int pub_blob_len;
s->tried_pubkey_config = TRUE;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
ssh->pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
/*
* Try the public key supplied in the configuration.
*
* First, offer the public blob to see if the server is
* willing to accept it.
*/
pub_blob =
(unsigned char *)ssh2_userkey_loadpub(&ssh->cfg.keyfile,
&algorithm,
&pub_blob_len,
NULL, NULL);
if (pub_blob) {
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */
ssh2_pkt_addstring(s->pktout, "publickey"); /* method */
ssh2_pkt_addbool(s->pktout, FALSE); /* no signature included */
ssh2_pkt_addstring(s->pktout, algorithm);
ssh2_pkt_addstring_start(s->pktout);
ssh2_pkt_addstring_data(s->pktout, (char *)pub_blob,
pub_blob_len);
ssh2_pkt_send(ssh, s->pktout);
logevent("Offered public key");
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {
s->gotit = TRUE;
s->type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD;
continue; /* key refused; give up on it */
}
logevent("Offer of public key accepted");
/*
* Actually attempt a serious authentication using
* the key.
*/
if (ssh2_userkey_encrypted(&ssh->cfg.keyfile, &comment)) {
sprintf(s->pwprompt,
"Passphrase for key \"%.100s\": ",
comment);
s->need_pw = TRUE;
} else {
s->need_pw = FALSE;
}
if (flags & FLAG_VERBOSE) {
c_write_str(ssh, "Authenticating with public key \"");
c_write_str(ssh, comment);
c_write_str(ssh, "\"\r\n");
}
s->method = AUTH_PUBLICKEY_FILE;
}
}
if (!s->method && s->can_keyb_inter && !s->kbd_inter_refused &&
!s->kbd_inter_running) {
s->method = AUTH_KEYBOARD_INTERACTIVE;
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
ssh->pkt_ctx |= SSH2_PKTCTX_KBDINTER;
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */
ssh2_pkt_addstring(s->pktout, "keyboard-interactive"); /* method */
ssh2_pkt_addstring(s->pktout, ""); /* lang */
ssh2_pkt_addstring(s->pktout, "");
ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {
if (pktin->type == SSH2_MSG_USERAUTH_FAILURE)
s->gotit = TRUE;
logevent("Keyboard-interactive authentication refused");
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;
s->kbd_inter_refused = TRUE; /* don't try it again */
continue;
}
c_write_str(ssh, "Using keyboard-interactive authentication.\r\n");
s->kbd_inter_running = TRUE;
s->curr_prompt = 0;
}
if (s->kbd_inter_running) {
s->method = AUTH_KEYBOARD_INTERACTIVE;
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
ssh->pkt_ctx |= SSH2_PKTCTX_KBDINTER;
if (s->curr_prompt == 0) {
/*
* We've got a fresh USERAUTH_INFO_REQUEST.
* Display header data, and start going through
* the prompts.
*/
char *name, *inst, *lang;
int name_len, inst_len, lang_len;
ssh_pkt_getstring(pktin, &name, &name_len);
ssh_pkt_getstring(pktin, &inst, &inst_len);
ssh_pkt_getstring(pktin, &lang, &lang_len);
if (name_len > 0) {
c_write_untrusted(ssh, name, name_len);
c_write_str(ssh, "\r\n");
}
if (inst_len > 0) {
c_write_untrusted(ssh, inst, inst_len);
c_write_str(ssh, "\r\n");
}
s->num_prompts = ssh_pkt_getuint32(pktin);
}
/*
* If there are prompts remaining in the packet,
* display one and get a response.
*/
if (s->curr_prompt < s->num_prompts) {
char *prompt;
int prompt_len;
ssh_pkt_getstring(pktin, &prompt, &prompt_len);
if (prompt_len > 0) {
static const char trunc[] = "<prompt truncated>: ";
static const int prlen = sizeof(s->pwprompt) -
lenof(trunc);
if (prompt_len > prlen) {
memcpy(s->pwprompt, prompt, prlen);
strcpy(s->pwprompt + prlen, trunc);
} else {
memcpy(s->pwprompt, prompt, prompt_len);
s->pwprompt[prompt_len] = '\0';
}
} else {
strcpy(s->pwprompt,
"<server failed to send prompt>: ");
}
s->echo = ssh2_pkt_getbool(pktin);
s->need_pw = TRUE;
} else
s->need_pw = FALSE;
}
if (!s->method && s->can_passwd) {
s->method = AUTH_PASSWORD;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
ssh->pkt_ctx |= SSH2_PKTCTX_PASSWORD;
sprintf(s->pwprompt, "%.90s@%.90s's password: ", s->username,
ssh->savedhost);
s->need_pw = TRUE;
}
if (s->need_pw) {
if (ssh_get_line) {
if (!ssh_get_line(s->pwprompt, s->password,
sizeof(s->password), TRUE)) {
/*
* get_line failed to get a password (for
* example because one was supplied on the
* command line which has already failed to
* work). Terminate.
*/
ssh_disconnect(ssh, NULL, "Unable to authenticate",
SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,
FALSE);
crStopV;
}
} else {
int ret; /* need not be saved across crReturn */
c_write_untrusted(ssh, s->pwprompt, strlen(s->pwprompt));
ssh->send_ok = 1;
setup_userpass_input(ssh, s->password,
sizeof(s->password), s->echo);
do {
crWaitUntilV(!pktin);
ret = process_userpass_input(ssh, in, inlen);
} while (ret == 0);
if (ret < 0)
cleanup_exit(0);
c_write_str(ssh, "\r\n");
}
}
if (s->method == AUTH_PUBLICKEY_FILE) {
/*
* We have our passphrase. Now try the actual authentication.
*/
struct ssh2_userkey *key;
const char *error = NULL;
key = ssh2_load_userkey(&ssh->cfg.keyfile, s->password,
&error);
if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {
if (key == SSH2_WRONG_PASSPHRASE) {
c_write_str(ssh, "Wrong passphrase\r\n");
s->tried_pubkey_config = FALSE;
} else {
c_write_str(ssh, "Unable to load private key (");
c_write_str(ssh, error);
c_write_str(ssh, ")\r\n");
s->tried_pubkey_config = TRUE;
}
/* Send a spurious AUTH_NONE to return to the top. */
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */
ssh2_pkt_addstring(s->pktout, "none"); /* method */
ssh2_pkt_send(ssh, s->pktout);
s->type = AUTH_TYPE_NONE;
} else {
unsigned char *pkblob, *sigblob, *sigdata;
int pkblob_len, sigblob_len, sigdata_len;
int p;
/*
* We have loaded the private key and the server
* has announced that it's willing to accept it.
* Hallelujah. Generate a signature and send it.
*/
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */
ssh2_pkt_addstring(s->pktout, "publickey"); /* method */
ssh2_pkt_addbool(s->pktout, TRUE);
ssh2_pkt_addstring(s->pktout, key->alg->name);
pkblob = key->alg->public_blob(key->data, &pkblob_len);
ssh2_pkt_addstring_start(s->pktout);
ssh2_pkt_addstring_data(s->pktout, (char *)pkblob, pkblob_len);
/*
* The data to be signed is:
*
* string session-id
*
* followed by everything so far placed in the
* outgoing packet.
*/
sigdata_len = s->pktout->length - 5 + 4 +
ssh->v2_session_id_len;
if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)
sigdata_len -= 4;
sigdata = snewn(sigdata_len, unsigned char);
p = 0;
if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {
PUT_32BIT(sigdata+p, ssh->v2_session_id_len);
p += 4;
}
memcpy(sigdata+p, ssh->v2_session_id,
ssh->v2_session_id_len);
p += ssh->v2_session_id_len;
memcpy(sigdata+p, s->pktout->data + 5,
s->pktout->length - 5);
p += s->pktout->length - 5;
assert(p == sigdata_len);
sigblob = key->alg->sign(key->data, (char *)sigdata,
sigdata_len, &sigblob_len);
ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len,
sigblob, sigblob_len);
sfree(pkblob);
sfree(sigblob);
sfree(sigdata);
ssh2_pkt_send(ssh, s->pktout);
s->type = AUTH_TYPE_PUBLICKEY;
key->alg->freekey(key->data);
}
} else if (s->method == AUTH_PASSWORD) {
/*
* We pad out the password packet to 256 bytes to make
* it harder for an attacker to find the length of the
* user's password.
*
* Anyone using a password longer than 256 bytes
* probably doesn't have much to worry about from
* people who find out how long their password is!
*/
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
s->pktout->forcepad = 256;
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */
ssh2_pkt_addstring(s->pktout, "password");
ssh2_pkt_addbool(s->pktout, FALSE);
dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(s->pktout, s->password);
memset(s->password, 0, sizeof(s->password));
end_log_omission(ssh, s->pktout);
ssh2_pkt_send(ssh, s->pktout);
logevent("Sent password");
s->type = AUTH_TYPE_PASSWORD;
} else if (s->method == AUTH_KEYBOARD_INTERACTIVE) {
if (s->curr_prompt == 0) {
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
s->pktout->forcepad = 256;
ssh2_pkt_adduint32(s->pktout, s->num_prompts);
}
if (s->need_pw) { /* only add pw if we just got one! */
dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(s->pktout, s->password);
memset(s->password, 0, sizeof(s->password));
end_log_omission(ssh, s->pktout);
s->curr_prompt++;
}
if (s->curr_prompt >= s->num_prompts) {
ssh2_pkt_send(ssh, s->pktout);
} else {
/*
* If there are prompts remaining, we set
* `gotit' so that we won't attempt to get
* another packet. Then we go back round the
* loop and will end up retrieving another
* prompt out of the existing packet. Funky or
* what?
*/
s->gotit = TRUE;
}
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
} else {
ssh_disconnect(ssh, NULL,
"No supported authentication methods available",
SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
FALSE);
crStopV;
}
}
}
ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;
/*
* Now the connection protocol has started, one way or another.
*/
ssh->channels = newtree234(ssh_channelcmp);
|
|
<
|
|
<
<
<
<
>
>
>
>
<
<
<
<
<
<
|
|
|
>
|
|
>
|
|
|
>
|
|
|
|
|
>
|
|
|
|
|
|
>
|
|
|
|
<
<
<
<
<
<
<
<
|
|
|
|
|
<
<
<
|
<
<
<
<
|
<
<
|
<
<
<
<
<
|
<
|
<
<
<
<
|
<
>
|
<
<
|
<
<
|
<
|
|
<
<
|
|
|
|
|
<
<
<
<
<
<
<
|
|
<
<
>
|
<
|
|
|
<
<
<
<
<
|
<
<
<
<
<
<
|
|
<
<
|
<
>
|
<
<
<
<
<
<
>
|
|
|
<
<
<
|
<
<
|
<
<
<
<
<
<
<
|
<
<
<
<
|
<
<
<
<
>
|
<
<
>
|
<
>
>
>
>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
>
|
|
|
>
|
|
|
|
|
>
|
>
>
|
<
<
<
<
<
<
|
|
|
>
|
>
>
|
>
|
>
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
|
|
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
|
<
<
|
>
>
>
>
>
>
>
>
|
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051
7052
7053
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072
7073
7074
7075
7076
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
7198
7199
7200
7201
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
|
}
}
}
if (s->authed)
continue;
}
sfree(s->response);
} else if (s->can_pubkey && s->publickey_blob &&
!s->tried_pubkey_config) {
struct ssh2_userkey *key; /* not live over crReturn */
char *passphrase; /* not live over crReturn */
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
ssh->pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
s->tried_pubkey_config = TRUE;
/*
* Try the public key supplied in the configuration.
*
* First, offer the public blob to see if the server is
* willing to accept it.
*/
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection");
/* service requested */
ssh2_pkt_addstring(s->pktout, "publickey"); /* method */
ssh2_pkt_addbool(s->pktout, FALSE);
/* no signature included */
ssh2_pkt_addstring(s->pktout, s->publickey_algorithm);
ssh2_pkt_addstring_start(s->pktout);
ssh2_pkt_addstring_data(s->pktout,
(char *)s->publickey_blob,
s->publickey_bloblen);
ssh2_pkt_send(ssh, s->pktout);
logevent("Offered public key");
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {
/* Key refused. Give up. */
s->gotit = TRUE; /* reconsider message next loop */
s->type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD;
continue; /* process this new message */
}
s->method = AUTH_PUBLICKEY_FILE;
logevent("Offer of public key accepted");
/*
* Actually attempt a serious authentication using
* the key.
*/
if (flags & FLAG_VERBOSE) {
c_write_str(ssh, "Authenticating with public key \"");
c_write_str(ssh, s->publickey_comment);
c_write_str(ssh, "\"\r\n");
}
key = NULL;
while (!key) {
const char *error; /* not live over crReturn */
if (s->publickey_encrypted) {
/*
* Get a passphrase from the user.
*/
int ret; /* need not be kept over crReturn */
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = FALSE;
s->cur_prompt->name = dupstr("SSH key passphrase");
add_prompt(s->cur_prompt,
dupprintf("Passphrase for key \"%.100s\": ",
s->publickey_comment),
FALSE, SSH_MAX_PASSWORD_LEN);
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
ssh->send_ok = 1;
crWaitUntilV(!pktin);
ret = get_userpass_input(s->cur_prompt,
in, inlen);
ssh->send_ok = 0;
}
if (!ret) {
/* Failed to get a passphrase. Terminate. */
free_prompts(s->cur_prompt);
ssh_disconnect(ssh, NULL,
"Unable to authenticate",
SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,
TRUE);
crStopV;
}
passphrase =
dupstr(s->cur_prompt->prompts[0]->result);
free_prompts(s->cur_prompt);
} else {
passphrase = NULL; /* no passphrase needed */
}
/*
* Try decrypting the key.
*/
key = ssh2_load_userkey(&ssh->cfg.keyfile, passphrase,
&error);
if (passphrase) {
/* burn the evidence */
memset(passphrase, 0, strlen(passphrase));
sfree(passphrase);
}
if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {
if (passphrase &&
(key == SSH2_WRONG_PASSPHRASE)) {
c_write_str(ssh, "Wrong passphrase\r\n");
key = NULL;
/* and loop again */
} else {
c_write_str(ssh, "Unable to load private key (");
c_write_str(ssh, error);
c_write_str(ssh, ")\r\n");
key = NULL;
break; /* try something else */
}
}
}
if (key) {
unsigned char *pkblob, *sigblob, *sigdata;
int pkblob_len, sigblob_len, sigdata_len;
int p;
/*
* We have loaded the private key and the server
* has announced that it's willing to accept it.
* Hallelujah. Generate a signature and send it.
*/
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection");
/* service requested */
ssh2_pkt_addstring(s->pktout, "publickey");
/* method */
ssh2_pkt_addbool(s->pktout, TRUE);
/* signature follows */
ssh2_pkt_addstring(s->pktout, key->alg->name);
pkblob = key->alg->public_blob(key->data,
&pkblob_len);
ssh2_pkt_addstring_start(s->pktout);
ssh2_pkt_addstring_data(s->pktout, (char *)pkblob,
pkblob_len);
/*
* The data to be signed is:
*
* string session-id
*
* followed by everything so far placed in the
* outgoing packet.
*/
sigdata_len = s->pktout->length - 5 + 4 +
ssh->v2_session_id_len;
if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)
sigdata_len -= 4;
sigdata = snewn(sigdata_len, unsigned char);
p = 0;
if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {
PUT_32BIT(sigdata+p, ssh->v2_session_id_len);
p += 4;
}
memcpy(sigdata+p, ssh->v2_session_id,
ssh->v2_session_id_len);
p += ssh->v2_session_id_len;
memcpy(sigdata+p, s->pktout->data + 5,
s->pktout->length - 5);
p += s->pktout->length - 5;
assert(p == sigdata_len);
sigblob = key->alg->sign(key->data, (char *)sigdata,
sigdata_len, &sigblob_len);
ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len,
sigblob, sigblob_len);
sfree(pkblob);
sfree(sigblob);
sfree(sigdata);
ssh2_pkt_send(ssh, s->pktout);
s->type = AUTH_TYPE_PUBLICKEY;
key->alg->freekey(key->data);
}
} else if (s->can_keyb_inter && !s->kbd_inter_refused) {
/*
* Keyboard-interactive authentication.
*/
char *name, *inst, *lang;
int name_len, inst_len, lang_len;
int i;
s->method = AUTH_KEYBOARD_INTERACTIVE;
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
ssh->pkt_ctx |= SSH2_PKTCTX_KBDINTER;
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection");
/* service requested */
ssh2_pkt_addstring(s->pktout, "keyboard-interactive");
/* method */
ssh2_pkt_addstring(s->pktout, ""); /* lang */
ssh2_pkt_addstring(s->pktout, ""); /* submethods */
ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {
/* Server is not willing to do keyboard-interactive
* at all. Give up on it entirely. */
s->gotit = TRUE;
if (pktin->type == SSH2_MSG_USERAUTH_FAILURE)
logevent("Keyboard-interactive authentication refused");
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;
s->kbd_inter_refused = TRUE; /* don't try it again */
continue;
}
/*
* We've got a fresh USERAUTH_INFO_REQUEST.
* Get the preamble and start building a prompt.
*/
ssh_pkt_getstring(pktin, &name, &name_len);
ssh_pkt_getstring(pktin, &inst, &inst_len);
ssh_pkt_getstring(pktin, &lang, &lang_len);
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
if (name_len) {
/* FIXME: better prefix to distinguish from
* local prompts? */
s->cur_prompt->name = dupprintf("SSH server: %.*s",
name_len, name);
s->cur_prompt->name_reqd = TRUE;
} else {
s->cur_prompt->name = dupstr("SSH server authentication");
s->cur_prompt->name_reqd = FALSE;
}
s->cur_prompt->instruction =
dupprintf("Using keyboard-interactive authentication.%s%.*s",
inst_len ? "\n" : "", inst_len, inst);
s->cur_prompt->instr_reqd = TRUE;
/*
* Get the prompts from the packet.
*/
s->num_prompts = ssh_pkt_getuint32(pktin);
for (i = 0; i < s->num_prompts; i++) {
char *prompt;
int prompt_len;
int echo;
static char noprompt[] =
"<server failed to send prompt>: ";
ssh_pkt_getstring(pktin, &prompt, &prompt_len);
echo = ssh2_pkt_getbool(pktin);
if (!prompt_len) {
prompt = noprompt;
prompt_len = lenof(noprompt)-1;
}
add_prompt(s->cur_prompt,
dupprintf("%.*s", prompt_len, prompt),
echo, SSH_MAX_PASSWORD_LEN);
}
/*
* Get the user's responses.
*/
if (s->num_prompts) {
int ret; /* not live over crReturn */
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
ssh->send_ok = 1;
crWaitUntilV(!pktin);
ret = get_userpass_input(s->cur_prompt, in, inlen);
ssh->send_ok = 0;
}
if (!ret) {
/*
* Failed to get responses. Terminate.
*/
free_prompts(s->cur_prompt);
ssh_disconnect(ssh, NULL, "Unable to authenticate",
SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,
TRUE);
crStopV;
}
}
/*
* Send the responses to the server.
*/
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
s->pktout->forcepad = 256;
ssh2_pkt_adduint32(s->pktout, s->num_prompts);
for (i=0; i < s->num_prompts; i++) {
dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(s->pktout,
s->cur_prompt->prompts[i]->result);
end_log_omission(ssh, s->pktout);
}
ssh2_pkt_send(ssh, s->pktout);
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; /*FIXME?*/
} else if (s->can_passwd) {
/*
* Plain old password authentication.
*/
int ret; /* not live over crReturn */
s->method = AUTH_PASSWORD;
ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
ssh->pkt_ctx |= SSH2_PKTCTX_PASSWORD;
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH password");
add_prompt(s->cur_prompt, dupprintf("%.90s@%.90s's password: ",
s->username,
ssh->savedhost),
FALSE, SSH_MAX_PASSWORD_LEN);
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
ssh->send_ok = 1;
crWaitUntilV(!pktin);
ret = get_userpass_input(s->cur_prompt, in, inlen);
ssh->send_ok = 0;
}
if (!ret) {
/*
* Failed to get responses. Terminate.
*/
free_prompts(s->cur_prompt);
ssh_disconnect(ssh, NULL, "Unable to authenticate",
SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,
TRUE);
crStopV;
}
/*
* Send the password packet.
*
* We pad out the password packet to 256 bytes to make
* it harder for an attacker to find the length of the
* user's password.
*
* Anyone using a password longer than 256 bytes
* probably doesn't have much to worry about from
* people who find out how long their password is!
*/
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
s->pktout->forcepad = 256;
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "ssh-connection");
/* service requested */
ssh2_pkt_addstring(s->pktout, "password");
ssh2_pkt_addbool(s->pktout, FALSE);
dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(s->pktout,
s->cur_prompt->prompts[0]->result);
free_prompts(s->cur_prompt);
end_log_omission(ssh, s->pktout);
ssh2_pkt_send(ssh, s->pktout);
logevent("Sent password");
s->type = AUTH_TYPE_PASSWORD; /*FIXME?*/
} else {
ssh_disconnect(ssh, NULL,
"No supported authentication methods available",
SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
FALSE);
crStopV;
}
}
}
ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;
/* Clear up various bits and pieces from authentication. */
if (s->publickey_blob) {
sfree(s->publickey_blob);
sfree(s->publickey_comment);
}
/*
* Now the connection protocol has started, one way or another.
*/
ssh->channels = newtree234(ssh_channelcmp);
|
| ︙ | | | ︙ | |