mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-08 08:58:00 +00:00
Merge the 0.74 release branch back to master.
Two minor memory-leak fixes on 0.74 seem not to be needed on master: the fix in an early exit path of pageant_add_keyfile is done already on master in a different way, and the missing sfree(fdlist) in uxsftp.c is in code that's been completely rewritten in the uxcliloop refactoring. Other minor conflicts: the rework in commit b52641644905 of ssh1login.c collided with the change from FLAG_VERBOSE to seat_verbose(), and master and 0.74 each added an unrelated extra field to the end of struct SshServerConfig.
This commit is contained in:
commit
2762a2025f
2
Buildscr
2
Buildscr
@ -35,7 +35,7 @@ module putty
|
||||
ifeq "$(RELEASE)" "" set Ndate $(!builddate)
|
||||
ifneq "$(Ndate)" "" in . do echo $(Ndate) | perl -pe 's/(....)(..)(..)/$$1-$$2-$$3/' > date
|
||||
ifneq "$(Ndate)" "" read Date date
|
||||
set Epoch 17161 # update this at every release
|
||||
set Epoch 17433 # update this at every release
|
||||
ifneq "$(Ndate)" "" in . do echo $(Ndate) | perl -ne 'use Time::Local; /(....)(..)(..)/ and print timegm(0,0,0,$$3,$$2-1,$$1) / 86400 - $(Epoch)' > days
|
||||
ifneq "$(Ndate)" "" read Days days
|
||||
|
||||
|
@ -1 +1 @@
|
||||
0.73
|
||||
0.74
|
||||
|
8
config.c
8
config.c
@ -1430,7 +1430,7 @@ static void clipboard_selector_handler(union control *ctrl, dlgparam *dlg,
|
||||
#endif
|
||||
) {
|
||||
#ifdef NAMED_CLIPBOARDS
|
||||
const char *sval = dlg_editbox_get(ctrl, dlg);
|
||||
char *sval = dlg_editbox_get(ctrl, dlg);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lenof(options); i++)
|
||||
@ -1445,6 +1445,8 @@ static void clipboard_selector_handler(union control *ctrl, dlgparam *dlg,
|
||||
sval++;
|
||||
conf_set_str(conf, strsetting, sval);
|
||||
}
|
||||
|
||||
sfree(sval);
|
||||
#else
|
||||
int index = dlg_listbox_index(ctrl, dlg);
|
||||
if (index >= 0) {
|
||||
@ -2570,6 +2572,10 @@ void setup_config_box(struct controlbox *b, bool midsession,
|
||||
HELPCTX(ssh_hklist),
|
||||
hklist_handler, P(NULL));
|
||||
c->listbox.height = 5;
|
||||
|
||||
ctrl_checkbox(s, "Prefer algorithms for which a host key is known",
|
||||
'p', HELPCTX(ssh_hk_known), conf_checkbox_handler,
|
||||
I(CONF_ssh_prefer_known_hostkeys));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2602,6 +2602,27 @@ If the first key type PuTTY finds is below the \q{warn below here}
|
||||
line, you will see a warning box when you make the connection, similar
|
||||
to that for cipher selection (see \k{config-ssh-encryption}).
|
||||
|
||||
\S{config-ssh-prefer-known-hostkeys} Preferring known host keys
|
||||
|
||||
By default, PuTTY will adjust the preference order for host key
|
||||
algorithms so that any host keys it already knows are moved to the top
|
||||
of the list.
|
||||
|
||||
This prevents you from having to check and confirm a new host key for
|
||||
a server you already had one for (e.g. because the server has
|
||||
generated an alternative key of a type higher in PuTTY's preference
|
||||
order, or because you changed the preference order itself).
|
||||
|
||||
However, on the other hand, it can leak information to a listener in
|
||||
the network about \e{whether} you already know a host key for this
|
||||
server.
|
||||
|
||||
For this reason, this policy is configurable. By turning this checkbox
|
||||
off, you can reset PuTTY to always use the exact order of host key
|
||||
algorithms configured in the preference list described in
|
||||
\k{config-ssh-hostkey-order}, so that a listener will find out nothing
|
||||
about what keys you had stored.
|
||||
|
||||
\S{config-ssh-kex-manual-hostkeys} \ii{Manually configuring host keys}
|
||||
|
||||
In some situations, if PuTTY's automated host key management is not
|
||||
|
@ -39,9 +39,9 @@ Once you've got a console window to type into, you can just type
|
||||
version of Plink you're using, and gives you a brief summary of how to
|
||||
use Plink:
|
||||
|
||||
\c Z:\sysosd>plink
|
||||
\c C:\>plink
|
||||
\c Plink: command-line connection utility
|
||||
\c Release 0.73
|
||||
\c Release 0.74
|
||||
\c Usage: plink [options] [user@]host [command]
|
||||
\c ("host" can also be a PuTTY saved session name)
|
||||
\c Options:
|
||||
@ -100,7 +100,7 @@ Once this works, you are ready to use Plink.
|
||||
To make a simple interactive connection to a remote server, just
|
||||
type \c{plink} and then the host name:
|
||||
|
||||
\c Z:\sysosd>plink login.example.com
|
||||
\c C:\>plink login.example.com
|
||||
\c
|
||||
\c Debian GNU/Linux 2.2 flunky.example.com
|
||||
\c flunky login:
|
||||
@ -117,7 +117,7 @@ In order to connect with a different protocol, you can give the
|
||||
command line options \c{-ssh}, \c{-telnet}, \c{-rlogin} or \c{-raw}.
|
||||
To make an SSH connection, for example:
|
||||
|
||||
\c Z:\sysosd>plink -ssh login.example.com
|
||||
\c C:\>plink -ssh login.example.com
|
||||
\c login as:
|
||||
|
||||
If you have already set up a PuTTY saved session, then instead of
|
||||
@ -125,7 +125,7 @@ supplying a host name, you can give the saved session name. This
|
||||
allows you to use public-key authentication, specify a user name,
|
||||
and use most of the other features of PuTTY:
|
||||
|
||||
\c Z:\sysosd>plink my-ssh-session
|
||||
\c C:\>plink my-ssh-session
|
||||
\c Sent username "fred"
|
||||
\c Authenticating with public key "fred@winbox"
|
||||
\c Last login: Thu Dec 6 19:25:33 2001 from :0.0
|
||||
@ -196,18 +196,18 @@ Once you have done all this, you should be able to run a remote
|
||||
command on the SSH server machine and have it execute automatically
|
||||
with no prompting:
|
||||
|
||||
\c Z:\sysosd>plink login.example.com -l fred echo hello, world
|
||||
\c C:\>plink login.example.com -l fred echo hello, world
|
||||
\c hello, world
|
||||
\c
|
||||
\c Z:\sysosd>
|
||||
\c C:\>
|
||||
|
||||
Or, if you have set up a saved session with all the connection
|
||||
details:
|
||||
|
||||
\c Z:\sysosd>plink mysession echo hello, world
|
||||
\c C:\>plink mysession echo hello, world
|
||||
\c hello, world
|
||||
\c
|
||||
\c Z:\sysosd>
|
||||
\c C:\>
|
||||
|
||||
Then you can set up other programs to run this Plink command and
|
||||
talk to it as if it were a process on the server machine.
|
||||
|
@ -37,9 +37,9 @@ Once you've got a console window to type into, you can just type
|
||||
version of PSCP you're using, and gives you a brief summary of how to
|
||||
use PSCP:
|
||||
|
||||
\c Z:\owendadmin>pscp
|
||||
\c C:\>pscp
|
||||
\c PuTTY Secure Copy client
|
||||
\c Release 0.73
|
||||
\c Release 0.74
|
||||
\c Usage: pscp [options] [user@]host:source target
|
||||
\c pscp [options] source [source...] [user@]host:target
|
||||
\c pscp [options] -ls [user@]host:filespec
|
||||
|
4
import.c
4
import.c
@ -572,8 +572,10 @@ static ssh2_userkey *openssh_pem_read(
|
||||
strbuf *blob = strbuf_new_nm();
|
||||
int privptr = 0, publen;
|
||||
|
||||
if (!key)
|
||||
if (!key) {
|
||||
strbuf_free(blob);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (key->encrypted) {
|
||||
unsigned char keybuf[32];
|
||||
|
1
putty.h
1
putty.h
@ -1256,6 +1256,7 @@ NORETURN void cleanup_exit(int);
|
||||
X(BOOL, NONE, compression) \
|
||||
X(INT, INT, ssh_kexlist) \
|
||||
X(INT, INT, ssh_hklist) \
|
||||
X(BOOL, NONE, ssh_prefer_known_hostkeys) \
|
||||
X(INT, NONE, ssh_rekey_time) /* in minutes */ \
|
||||
X(STR, NONE, ssh_rekey_data) /* string encoding e.g. "100K", "2M", "1G" */ \
|
||||
X(BOOL, NONE, tryagent) \
|
||||
|
@ -640,10 +640,10 @@ static void sesschan_notify_remote_exit(Seat *seat)
|
||||
sshfwd_send_exit_signal(
|
||||
sess->c, signame, false, ptrlen_from_asciz(sigmsg));
|
||||
|
||||
sfree(sigmsg);
|
||||
|
||||
got_signal = true;
|
||||
}
|
||||
|
||||
sfree(sigmsg);
|
||||
} else {
|
||||
int signum = pty_backend_exit_signum(sess->backend);
|
||||
|
||||
|
@ -602,6 +602,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
|
||||
wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist);
|
||||
wprefs(sesskey, "KEX", kexnames, KEX_MAX, conf, CONF_ssh_kexlist);
|
||||
wprefs(sesskey, "HostKey", hknames, HK_MAX, conf, CONF_ssh_hklist);
|
||||
write_setting_b(sesskey, "PreferKnownHostKeys", conf_get_bool(conf, CONF_ssh_prefer_known_hostkeys));
|
||||
write_setting_i(sesskey, "RekeyTime", conf_get_int(conf, CONF_ssh_rekey_time));
|
||||
#ifndef NO_GSSAPI
|
||||
write_setting_i(sesskey, "GssapiRekey", conf_get_int(conf, CONF_gssapirekey));
|
||||
@ -1006,6 +1007,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
|
||||
}
|
||||
gprefs(sesskey, "HostKey", "ed25519,ecdsa,rsa,dsa,WARN",
|
||||
hknames, HK_MAX, conf, CONF_ssh_hklist);
|
||||
gppb(sesskey, "PreferKnownHostKeys", true, conf, CONF_ssh_prefer_known_hostkeys);
|
||||
gppi(sesskey, "RekeyTime", 60, conf, CONF_ssh_rekey_time);
|
||||
#ifndef NO_GSSAPI
|
||||
gppi(sesskey, "GssapiRekey", GSS_DEF_REKEY_MINS, conf, CONF_gssapirekey);
|
||||
|
@ -298,18 +298,34 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
|
||||
mp_int *modulus = get_mp_ssh1(pktin);
|
||||
s->authkey = auth_publickey_ssh1(
|
||||
s->authpolicy, s->username, modulus);
|
||||
|
||||
if (!s->authkey &&
|
||||
s->ssc->stunt_pretend_to_accept_any_pubkey) {
|
||||
mp_int *zero = mp_from_integer(0);
|
||||
mp_int *fake_challenge = mp_random_in_range(zero, modulus);
|
||||
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_SMSG_AUTH_RSA_CHALLENGE);
|
||||
put_mp_ssh1(pktout, fake_challenge);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
mp_free(zero);
|
||||
mp_free(fake_challenge);
|
||||
}
|
||||
|
||||
mp_free(modulus);
|
||||
}
|
||||
|
||||
if (!s->authkey)
|
||||
if (!s->authkey &&
|
||||
!s->ssc->stunt_pretend_to_accept_any_pubkey)
|
||||
continue;
|
||||
|
||||
if (s->authkey->bytes < 32) {
|
||||
if (s->authkey && s->authkey->bytes < 32) {
|
||||
ppl_logevent("Auth key far too small");
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
if (s->authkey) {
|
||||
unsigned char *rsabuf =
|
||||
snewn(s->authkey->bytes, unsigned char);
|
||||
|
||||
@ -349,6 +365,9 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->authkey)
|
||||
continue;
|
||||
|
||||
{
|
||||
ptrlen response = get_data(pktin, 16);
|
||||
ptrlen expected = make_ptrlen(
|
||||
|
272
ssh1login.c
272
ssh1login.c
@ -12,6 +12,12 @@
|
||||
#include "sshppl.h"
|
||||
#include "sshcr.h"
|
||||
|
||||
typedef struct agent_key {
|
||||
RSAKey key;
|
||||
strbuf *comment;
|
||||
ptrlen blob; /* only used during initial parsing of agent response */
|
||||
} agent_key;
|
||||
|
||||
struct ssh1_login_state {
|
||||
int crState;
|
||||
|
||||
@ -47,11 +53,11 @@ struct ssh1_login_state {
|
||||
void *agent_response_to_free;
|
||||
ptrlen agent_response;
|
||||
BinarySource asrc[1]; /* response from SSH agent */
|
||||
int keyi, nkeys;
|
||||
size_t agent_keys_len;
|
||||
agent_key *agent_keys;
|
||||
size_t agent_key_index, agent_key_limit;
|
||||
bool authed;
|
||||
RSAKey key;
|
||||
mp_int *challenge;
|
||||
strbuf *agent_comment;
|
||||
int dlgret;
|
||||
Filename *keyfile;
|
||||
RSAKey servkey, hostkey;
|
||||
@ -99,7 +105,6 @@ PacketProtocolLayer *ssh1_login_new(
|
||||
s->savedhost = dupstr(host);
|
||||
s->savedport = port;
|
||||
s->successor_layer = successor_layer;
|
||||
s->agent_comment = strbuf_new();
|
||||
return &s->ppl;
|
||||
}
|
||||
|
||||
@ -118,9 +123,15 @@ static void ssh1_login_free(PacketProtocolLayer *ppl)
|
||||
if (s->publickey_blob)
|
||||
strbuf_free(s->publickey_blob);
|
||||
sfree(s->publickey_comment);
|
||||
strbuf_free(s->agent_comment);
|
||||
if (s->cur_prompt)
|
||||
free_prompts(s->cur_prompt);
|
||||
if (s->agent_keys) {
|
||||
for (size_t i = 0; i < s->agent_keys_len; i++) {
|
||||
freersakey(&s->agent_keys[i].key);
|
||||
strbuf_free(s->agent_keys[i].comment);
|
||||
}
|
||||
sfree(s->agent_keys);
|
||||
}
|
||||
sfree(s->agent_response_to_free);
|
||||
if (s->auth_agent_query)
|
||||
agent_cancel_query(s->auth_agent_query);
|
||||
@ -504,122 +515,165 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
get_uint32(s->asrc); /* skip length field */
|
||||
if (get_byte(s->asrc) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
|
||||
s->nkeys = toint(get_uint32(s->asrc));
|
||||
if (s->nkeys < 0) {
|
||||
ppl_logevent("Pageant reported negative key count %d",
|
||||
s->nkeys);
|
||||
s->nkeys = 0;
|
||||
}
|
||||
ppl_logevent("Pageant has %d SSH-1 keys", s->nkeys);
|
||||
for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {
|
||||
size_t start, end;
|
||||
start = s->asrc->pos;
|
||||
get_rsa_ssh1_pub(s->asrc, &s->key,
|
||||
RSA_SSH1_EXPONENT_FIRST);
|
||||
end = s->asrc->pos;
|
||||
strbuf_clear(s->agent_comment);
|
||||
put_datapl(s->agent_comment, get_string(s->asrc));
|
||||
if (get_err(s->asrc)) {
|
||||
ppl_logevent("Pageant key list packet was truncated");
|
||||
break;
|
||||
}
|
||||
if (s->publickey_blob) {
|
||||
ptrlen keystr = make_ptrlen(
|
||||
(const char *)s->asrc->data + start, end - start);
|
||||
size_t nkeys = get_uint32(s->asrc);
|
||||
size_t origpos = s->asrc->pos;
|
||||
|
||||
if (keystr.len == s->publickey_blob->len &&
|
||||
!memcmp(keystr.ptr, s->publickey_blob->s,
|
||||
s->publickey_blob->len)) {
|
||||
ppl_logevent("Pageant key #%d matches "
|
||||
"configured key file", s->keyi);
|
||||
s->tried_publickey = true;
|
||||
} else
|
||||
/* Skip non-configured key */
|
||||
continue;
|
||||
/*
|
||||
* Check that the agent response is well formed.
|
||||
*/
|
||||
for (size_t i = 0; i < nkeys; i++) {
|
||||
get_rsa_ssh1_pub(s->asrc, NULL, RSA_SSH1_EXPONENT_FIRST);
|
||||
get_string(s->asrc); /* comment */
|
||||
if (get_err(s->asrc)) {
|
||||
ppl_logevent("Pageant's response was truncated");
|
||||
goto parsed_agent_query;
|
||||
}
|
||||
ppl_logevent("Trying Pageant key #%d", s->keyi);
|
||||
pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_RSA);
|
||||
put_mp_ssh1(pkt, s->key.modulus);
|
||||
pq_push(s->ppl.out_pq, pkt);
|
||||
crMaybeWaitUntilV((pktin = ssh1_login_pop(s))
|
||||
!= NULL);
|
||||
if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
|
||||
ppl_logevent("Key refused");
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the list of public-key blobs out of the Pageant
|
||||
* response.
|
||||
*/
|
||||
BinarySource_REWIND_TO(s->asrc, origpos);
|
||||
s->agent_keys_len = nkeys;
|
||||
s->agent_keys = snewn(s->agent_keys_len, agent_key);
|
||||
for (size_t i = 0; i < nkeys; i++) {
|
||||
memset(&s->agent_keys[i].key, 0,
|
||||
sizeof(s->agent_keys[i].key));
|
||||
|
||||
const char *blobstart = get_ptr(s->asrc);
|
||||
get_rsa_ssh1_pub(s->asrc, &s->agent_keys[i].key,
|
||||
RSA_SSH1_EXPONENT_FIRST);
|
||||
const char *blobend = get_ptr(s->asrc);
|
||||
|
||||
s->agent_keys[i].comment = strbuf_new();
|
||||
put_datapl(s->agent_keys[i].comment, get_string(s->asrc));
|
||||
|
||||
s->agent_keys[i].blob = make_ptrlen(
|
||||
blobstart, blobend - blobstart);
|
||||
}
|
||||
|
||||
ppl_logevent("Pageant has %"SIZEu" SSH-1 keys", nkeys);
|
||||
|
||||
if (s->publickey_blob) {
|
||||
/*
|
||||
* If we've been given a specific public key blob,
|
||||
* filter the list of keys to try from the agent
|
||||
* down to only that one, or none if it's not
|
||||
* there.
|
||||
*/
|
||||
ptrlen our_blob = ptrlen_from_strbuf(s->publickey_blob);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nkeys; i++) {
|
||||
if (ptrlen_eq_ptrlen(our_blob, s->agent_keys[i].blob))
|
||||
break;
|
||||
}
|
||||
ppl_logevent("Received RSA challenge");
|
||||
s->challenge = get_mp_ssh1(pktin);
|
||||
|
||||
if (i < nkeys) {
|
||||
ppl_logevent("Pageant key #%"SIZEu" matches "
|
||||
"configured key file", i);
|
||||
s->agent_key_index = i;
|
||||
s->agent_key_limit = i+1;
|
||||
} else {
|
||||
ppl_logevent("Configured key file not in Pageant");
|
||||
s->agent_key_index = 0;
|
||||
s->agent_key_limit = 0;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Otherwise, try them all.
|
||||
*/
|
||||
s->agent_key_index = 0;
|
||||
s->agent_key_limit = nkeys;
|
||||
}
|
||||
} else {
|
||||
ppl_logevent("Failed to get reply from Pageant");
|
||||
}
|
||||
parsed_agent_query:;
|
||||
|
||||
for (; s->agent_key_index < s->agent_key_limit;
|
||||
s->agent_key_index++) {
|
||||
ppl_logevent("Trying Pageant key #%"SIZEu, s->agent_key_index);
|
||||
pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_RSA);
|
||||
put_mp_ssh1(pkt,
|
||||
s->agent_keys[s->agent_key_index].key.modulus);
|
||||
pq_push(s->ppl.out_pq, pkt);
|
||||
crMaybeWaitUntilV((pktin = ssh1_login_pop(s))
|
||||
!= NULL);
|
||||
if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
|
||||
ppl_logevent("Key refused");
|
||||
continue;
|
||||
}
|
||||
ppl_logevent("Received RSA challenge");
|
||||
|
||||
{
|
||||
mp_int *challenge = get_mp_ssh1(pktin);
|
||||
if (get_err(pktin)) {
|
||||
mp_free(s->challenge);
|
||||
mp_free(challenge);
|
||||
ssh_proto_error(s->ppl.ssh, "Server's RSA challenge "
|
||||
"was badly formatted");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
strbuf *agentreq;
|
||||
const char *ret;
|
||||
strbuf *agentreq = strbuf_new_for_agent_query();
|
||||
put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE);
|
||||
|
||||
agentreq = strbuf_new_for_agent_query();
|
||||
put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE);
|
||||
put_uint32(agentreq, mp_get_nbits(s->key.modulus));
|
||||
put_mp_ssh1(agentreq, s->key.exponent);
|
||||
put_mp_ssh1(agentreq, s->key.modulus);
|
||||
put_mp_ssh1(agentreq, s->challenge);
|
||||
put_data(agentreq, s->session_id, 16);
|
||||
put_uint32(agentreq, 1); /* response format */
|
||||
ssh1_login_agent_query(s, agentreq);
|
||||
strbuf_free(agentreq);
|
||||
crMaybeWaitUntilV(!s->auth_agent_query);
|
||||
rsa_ssh1_public_blob(
|
||||
BinarySink_UPCAST(agentreq),
|
||||
&s->agent_keys[s->agent_key_index].key,
|
||||
RSA_SSH1_EXPONENT_FIRST);
|
||||
|
||||
ret = s->agent_response.ptr;
|
||||
if (ret) {
|
||||
if (s->agent_response.len >= 5+16 &&
|
||||
ret[4] == SSH1_AGENT_RSA_RESPONSE) {
|
||||
ppl_logevent("Sending Pageant's response");
|
||||
pkt = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_CMSG_AUTH_RSA_RESPONSE);
|
||||
put_data(pkt, ret + 5, 16);
|
||||
pq_push(s->ppl.out_pq, pkt);
|
||||
crMaybeWaitUntilV(
|
||||
(pktin = ssh1_login_pop(s))
|
||||
!= NULL);
|
||||
if (pktin->type == SSH1_SMSG_SUCCESS) {
|
||||
ppl_logevent("Pageant's response "
|
||||
"accepted");
|
||||
if (seat_verbose(s->ppl.seat)) {
|
||||
ptrlen comment = ptrlen_from_strbuf(
|
||||
s->agent_comment);
|
||||
ppl_printf("Authenticated using RSA "
|
||||
"key \"%.*s\" from "
|
||||
"agent\r\n",
|
||||
PTRLEN_PRINTF(comment));
|
||||
}
|
||||
s->authed = true;
|
||||
} else
|
||||
ppl_logevent("Pageant's response not "
|
||||
"accepted");
|
||||
} else {
|
||||
ppl_logevent("Pageant failed to answer "
|
||||
"challenge");
|
||||
sfree((char *)ret);
|
||||
}
|
||||
} else {
|
||||
ppl_logevent("No reply received from Pageant");
|
||||
}
|
||||
}
|
||||
mp_free(s->key.exponent);
|
||||
mp_free(s->key.modulus);
|
||||
mp_free(s->challenge);
|
||||
if (s->authed)
|
||||
break;
|
||||
put_mp_ssh1(agentreq, challenge);
|
||||
mp_free(challenge);
|
||||
|
||||
put_data(agentreq, s->session_id, 16);
|
||||
put_uint32(agentreq, 1); /* response format */
|
||||
ssh1_login_agent_query(s, agentreq);
|
||||
strbuf_free(agentreq);
|
||||
crMaybeWaitUntilV(!s->auth_agent_query);
|
||||
}
|
||||
sfree(s->agent_response_to_free);
|
||||
s->agent_response_to_free = NULL;
|
||||
if (s->publickey_blob && !s->tried_publickey)
|
||||
ppl_logevent("Configured key file not in Pageant");
|
||||
} else {
|
||||
ppl_logevent("Failed to get reply from Pageant");
|
||||
|
||||
{
|
||||
const unsigned char *ret = s->agent_response.ptr;
|
||||
if (ret) {
|
||||
if (s->agent_response.len >= 5+16 &&
|
||||
ret[4] == SSH1_AGENT_RSA_RESPONSE) {
|
||||
ppl_logevent("Sending Pageant's response");
|
||||
pkt = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_CMSG_AUTH_RSA_RESPONSE);
|
||||
put_data(pkt, ret + 5, 16);
|
||||
pq_push(s->ppl.out_pq, pkt);
|
||||
crMaybeWaitUntilV(
|
||||
(pktin = ssh1_login_pop(s))
|
||||
!= NULL);
|
||||
if (pktin->type == SSH1_SMSG_SUCCESS) {
|
||||
ppl_logevent("Pageant's response "
|
||||
"accepted");
|
||||
if (seat_verbose(s->ppl.seat)) {
|
||||
ptrlen comment = ptrlen_from_strbuf(
|
||||
s->agent_keys[s->agent_key_index].
|
||||
comment);
|
||||
ppl_printf("Authenticated using RSA "
|
||||
"key \"%.*s\" from "
|
||||
"agent\r\n",
|
||||
PTRLEN_PRINTF(comment));
|
||||
}
|
||||
s->authed = true;
|
||||
} else
|
||||
ppl_logevent("Pageant's response not "
|
||||
"accepted");
|
||||
} else {
|
||||
ppl_logevent("Pageant failed to answer "
|
||||
"challenge");
|
||||
sfree((char *)ret);
|
||||
}
|
||||
} else {
|
||||
ppl_logevent("No reply received from Pageant");
|
||||
}
|
||||
}
|
||||
if (s->authed)
|
||||
break;
|
||||
}
|
||||
if (s->authed)
|
||||
break;
|
||||
|
@ -576,9 +576,10 @@ static void ssh2_write_kexinit_lists(
|
||||
}
|
||||
} else if (first_time) {
|
||||
/*
|
||||
* In the first key exchange, we list all the algorithms
|
||||
* we're prepared to cope with, but prefer those algorithms
|
||||
* for which we have a host key for this host.
|
||||
* In the first key exchange, we list all the algorithms we're
|
||||
* prepared to cope with, but (if configured to) we prefer
|
||||
* those algorithms for which we have a host key for this
|
||||
* host.
|
||||
*
|
||||
* If the host key algorithm is below the warning
|
||||
* threshold, we warn even if we did already have a key
|
||||
@ -594,7 +595,8 @@ static void ssh2_write_kexinit_lists(
|
||||
for (j = 0; j < lenof(ssh2_hostkey_algs); j++) {
|
||||
if (ssh2_hostkey_algs[j].id != preferred_hk[i])
|
||||
continue;
|
||||
if (have_ssh_host_key(hk_host, hk_port,
|
||||
if (conf_get_bool(conf, CONF_ssh_prefer_known_hostkeys) &&
|
||||
have_ssh_host_key(hk_host, hk_port,
|
||||
ssh2_hostkey_algs[j].alg->cache_id)) {
|
||||
alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY],
|
||||
ssh2_hostkey_algs[j].alg->ssh_id);
|
||||
|
@ -199,7 +199,7 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl)
|
||||
goto failure;
|
||||
}
|
||||
} else if (ptrlen_eq_string(s->method, "publickey")) {
|
||||
bool has_signature, success;
|
||||
bool has_signature, success, send_pk_ok, key_really_ok;
|
||||
ptrlen algorithm, blob, signature;
|
||||
const ssh_keyalg *keyalg;
|
||||
ssh_key *key;
|
||||
@ -213,7 +213,23 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl)
|
||||
algorithm = get_string(pktin);
|
||||
blob = get_string(pktin);
|
||||
|
||||
if (!auth_publickey(s->authpolicy, s->username, blob))
|
||||
key_really_ok = auth_publickey(s->authpolicy, s->username, blob);
|
||||
send_pk_ok = key_really_ok ||
|
||||
s->ssc->stunt_pretend_to_accept_any_pubkey;
|
||||
|
||||
if (!has_signature) {
|
||||
if (!send_pk_ok)
|
||||
goto failure;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH2_MSG_USERAUTH_PK_OK);
|
||||
put_stringpl(pktout, algorithm);
|
||||
put_stringpl(pktout, blob);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
continue; /* skip USERAUTH_{SUCCESS,FAILURE} epilogue */
|
||||
}
|
||||
|
||||
if (!key_really_ok)
|
||||
goto failure;
|
||||
|
||||
keyalg = find_pubkey_alg_len(algorithm);
|
||||
@ -223,16 +239,6 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl)
|
||||
if (!key)
|
||||
goto failure;
|
||||
|
||||
if (!has_signature) {
|
||||
ssh_key_free(key);
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH2_MSG_USERAUTH_PK_OK);
|
||||
put_stringpl(pktout, algorithm);
|
||||
put_stringpl(pktout, blob);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
continue; /* skip USERAUTH_{SUCCESS,FAILURE} epilogue */
|
||||
}
|
||||
|
||||
sigdata = strbuf_new();
|
||||
ssh2_userauth_server_add_session_id(s, sigdata);
|
||||
put_byte(sigdata, SSH2_MSG_USERAUTH_REQUEST);
|
||||
|
173
ssh2userauth.c
173
ssh2userauth.c
@ -18,6 +18,11 @@
|
||||
|
||||
#define BANNER_LIMIT 131072
|
||||
|
||||
typedef struct agent_key {
|
||||
strbuf *blob, *comment;
|
||||
ptrlen algorithm;
|
||||
} agent_key;
|
||||
|
||||
struct ssh2_userauth_state {
|
||||
int crState;
|
||||
|
||||
@ -69,9 +74,9 @@ struct ssh2_userauth_state {
|
||||
void *agent_response_to_free;
|
||||
ptrlen agent_response;
|
||||
BinarySource asrc[1]; /* for reading SSH agent response */
|
||||
size_t pkblob_pos_in_agent;
|
||||
int keyi, nkeys;
|
||||
ptrlen pk, alg, comment;
|
||||
size_t agent_keys_len;
|
||||
agent_key *agent_keys;
|
||||
size_t agent_key_index, agent_key_limit;
|
||||
int len;
|
||||
PktOut *pktout;
|
||||
bool want_user_input;
|
||||
@ -173,6 +178,13 @@ static void ssh2_userauth_free(PacketProtocolLayer *ppl)
|
||||
if (s->successor_layer)
|
||||
ssh_ppl_free(s->successor_layer);
|
||||
|
||||
if (s->agent_keys) {
|
||||
for (size_t i = 0; i < s->agent_keys_len; i++) {
|
||||
strbuf_free(s->agent_keys[i].blob);
|
||||
strbuf_free(s->agent_keys[i].comment);
|
||||
}
|
||||
sfree(s->agent_keys);
|
||||
}
|
||||
sfree(s->agent_response_to_free);
|
||||
if (s->auth_agent_query)
|
||||
agent_cancel_query(s->auth_agent_query);
|
||||
@ -298,8 +310,6 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
* Find out about any keys Pageant has (but if there's a public
|
||||
* key configured, filter out all others).
|
||||
*/
|
||||
s->nkeys = 0;
|
||||
s->pkblob_pos_in_agent = 0;
|
||||
if (s->tryagent && agent_exists()) {
|
||||
ppl_logevent("Pageant is running. Requesting keys.");
|
||||
|
||||
@ -315,48 +325,75 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
get_uint32(s->asrc); /* skip length field */
|
||||
if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) {
|
||||
int keyi;
|
||||
|
||||
s->nkeys = toint(get_uint32(s->asrc));
|
||||
size_t nkeys = get_uint32(s->asrc);
|
||||
size_t origpos = s->asrc->pos;
|
||||
|
||||
/*
|
||||
* Vet the Pageant response to ensure that the key count
|
||||
* and blob lengths make sense.
|
||||
* Check that the agent response is well formed.
|
||||
*/
|
||||
if (s->nkeys < 0) {
|
||||
ppl_logevent("Pageant response contained a negative"
|
||||
" key count %d", s->nkeys);
|
||||
s->nkeys = 0;
|
||||
goto done_agent_query;
|
||||
} else {
|
||||
ppl_logevent("Pageant has %d SSH-2 keys", s->nkeys);
|
||||
for (size_t i = 0; i < nkeys; i++) {
|
||||
get_string(s->asrc); /* blob */
|
||||
get_string(s->asrc); /* comment */
|
||||
if (get_err(s->asrc)) {
|
||||
ppl_logevent("Pageant's response was truncated");
|
||||
goto done_agent_query;
|
||||
}
|
||||
}
|
||||
|
||||
/* See if configured key is in agent. */
|
||||
for (keyi = 0; keyi < s->nkeys; keyi++) {
|
||||
size_t pos = s->asrc->pos;
|
||||
ptrlen blob = get_string(s->asrc);
|
||||
get_string(s->asrc); /* skip comment */
|
||||
if (get_err(s->asrc)) {
|
||||
ppl_logevent("Pageant response was truncated");
|
||||
s->nkeys = 0;
|
||||
goto done_agent_query;
|
||||
}
|
||||
/*
|
||||
* Copy the list of public-key blobs out of the Pageant
|
||||
* response.
|
||||
*/
|
||||
BinarySource_REWIND_TO(s->asrc, origpos);
|
||||
s->agent_keys_len = nkeys;
|
||||
s->agent_keys = snewn(s->agent_keys_len, agent_key);
|
||||
for (size_t i = 0; i < nkeys; i++) {
|
||||
s->agent_keys[i].blob = strbuf_new();
|
||||
put_datapl(s->agent_keys[i].blob, get_string(s->asrc));
|
||||
s->agent_keys[i].comment = strbuf_new();
|
||||
put_datapl(s->agent_keys[i].comment, get_string(s->asrc));
|
||||
|
||||
if (s->publickey_blob &&
|
||||
blob.len == s->publickey_blob->len &&
|
||||
!memcmp(blob.ptr, s->publickey_blob->s,
|
||||
s->publickey_blob->len)) {
|
||||
ppl_logevent("Pageant key #%d matches "
|
||||
"configured key file", keyi);
|
||||
s->keyi = keyi;
|
||||
s->pkblob_pos_in_agent = pos;
|
||||
/* Also, extract the algorithm string from the start
|
||||
* of the public-key blob. */
|
||||
BinarySource src[1];
|
||||
BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(
|
||||
s->agent_keys[i].blob));
|
||||
s->agent_keys[i].algorithm = get_string(src);
|
||||
}
|
||||
|
||||
ppl_logevent("Pageant has %"SIZEu" SSH-2 keys", nkeys);
|
||||
|
||||
if (s->publickey_blob) {
|
||||
/*
|
||||
* If we've been given a specific public key blob,
|
||||
* filter the list of keys to try from the agent down
|
||||
* to only that one, or none if it's not there.
|
||||
*/
|
||||
ptrlen our_blob = ptrlen_from_strbuf(s->publickey_blob);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nkeys; i++) {
|
||||
if (ptrlen_eq_ptrlen(our_blob, ptrlen_from_strbuf(
|
||||
s->agent_keys[i].blob)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s->publickey_blob && !s->pkblob_pos_in_agent) {
|
||||
|
||||
if (i < nkeys) {
|
||||
ppl_logevent("Pageant key #%"SIZEu" matches "
|
||||
"configured key file", i);
|
||||
s->agent_key_index = i;
|
||||
s->agent_key_limit = i+1;
|
||||
} else {
|
||||
ppl_logevent("Configured key file not in Pageant");
|
||||
s->nkeys = 0;
|
||||
s->agent_key_index = 0;
|
||||
s->agent_key_limit = 0;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Otherwise, try them all.
|
||||
*/
|
||||
s->agent_key_index = 0;
|
||||
s->agent_key_limit = nkeys;
|
||||
}
|
||||
} else {
|
||||
ppl_logevent("Failed to get reply from Pageant");
|
||||
@ -455,17 +492,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
s->tried_pubkey_config = false;
|
||||
s->kbd_inter_refused = false;
|
||||
|
||||
/* Reset agent request state. */
|
||||
s->done_agent = false;
|
||||
if (s->agent_response.ptr) {
|
||||
if (s->pkblob_pos_in_agent) {
|
||||
s->asrc->pos = s->pkblob_pos_in_agent;
|
||||
} else {
|
||||
s->asrc->pos = 9; /* skip length + type + key count */
|
||||
s->keyi = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
@ -686,7 +713,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
} else
|
||||
#endif /* NO_GSSAPI */
|
||||
|
||||
if (s->can_pubkey && !s->done_agent && s->nkeys) {
|
||||
if (s->can_pubkey && !s->done_agent &&
|
||||
s->agent_key_index < s->agent_key_limit) {
|
||||
|
||||
/*
|
||||
* Attempt public-key authentication using a key from Pageant.
|
||||
@ -694,16 +722,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY;
|
||||
|
||||
ppl_logevent("Trying Pageant key #%d", s->keyi);
|
||||
|
||||
/* Unpack key from agent response */
|
||||
s->pk = get_string(s->asrc);
|
||||
s->comment = get_string(s->asrc);
|
||||
{
|
||||
BinarySource src[1];
|
||||
BinarySource_BARE_INIT_PL(src, s->pk);
|
||||
s->alg = get_string(src);
|
||||
}
|
||||
ppl_logevent("Trying Pageant key #%"SIZEu, s->agent_key_index);
|
||||
|
||||
/* See if server will accept it */
|
||||
s->pktout = ssh_bpp_new_pktout(
|
||||
@ -713,8 +732,10 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
put_stringz(s->pktout, "publickey");
|
||||
/* method */
|
||||
put_bool(s->pktout, false); /* no signature included */
|
||||
put_stringpl(s->pktout, s->alg);
|
||||
put_stringpl(s->pktout, s->pk);
|
||||
put_stringpl(s->pktout,
|
||||
s->agent_keys[s->agent_key_index].algorithm);
|
||||
put_stringpl(s->pktout, ptrlen_from_strbuf(
|
||||
s->agent_keys[s->agent_key_index].blob));
|
||||
pq_push(s->ppl.out_pq, s->pktout);
|
||||
s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;
|
||||
|
||||
@ -727,11 +748,13 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
} else {
|
||||
strbuf *agentreq, *sigdata;
|
||||
ptrlen comment = ptrlen_from_strbuf(
|
||||
s->agent_keys[s->agent_key_index].comment);
|
||||
|
||||
if (seat_verbose(s->ppl.seat))
|
||||
ppl_printf("Authenticating with public key "
|
||||
"\"%.*s\" from agent\r\n",
|
||||
PTRLEN_PRINTF(s->comment));
|
||||
PTRLEN_PRINTF(comment));
|
||||
|
||||
/*
|
||||
* Server is willing to accept the key.
|
||||
@ -744,13 +767,16 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
put_stringz(s->pktout, "publickey");
|
||||
/* method */
|
||||
put_bool(s->pktout, true); /* signature included */
|
||||
put_stringpl(s->pktout, s->alg);
|
||||
put_stringpl(s->pktout, s->pk);
|
||||
put_stringpl(s->pktout,
|
||||
s->agent_keys[s->agent_key_index].algorithm);
|
||||
put_stringpl(s->pktout, ptrlen_from_strbuf(
|
||||
s->agent_keys[s->agent_key_index].blob));
|
||||
|
||||
/* Ask agent for signature. */
|
||||
agentreq = strbuf_new_for_agent_query();
|
||||
put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST);
|
||||
put_stringpl(agentreq, s->pk);
|
||||
put_stringpl(agentreq, ptrlen_from_strbuf(
|
||||
s->agent_keys[s->agent_key_index].blob));
|
||||
/* Now the data to be signed... */
|
||||
sigdata = strbuf_new();
|
||||
ssh2_userauth_add_session_id(s, sigdata);
|
||||
@ -772,8 +798,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
if (get_byte(src) == SSH2_AGENT_SIGN_RESPONSE &&
|
||||
(sigblob = get_string(src), !get_err(src))) {
|
||||
ppl_logevent("Sending Pageant's response");
|
||||
ssh2_userauth_add_sigblob(s, s->pktout,
|
||||
s->pk, sigblob);
|
||||
ssh2_userauth_add_sigblob(
|
||||
s, s->pktout,
|
||||
ptrlen_from_strbuf(
|
||||
s->agent_keys[s->agent_key_index].blob),
|
||||
sigblob);
|
||||
pq_push(s->ppl.out_pq, s->pktout);
|
||||
s->type = AUTH_TYPE_PUBLICKEY;
|
||||
} else {
|
||||
@ -794,14 +823,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
}
|
||||
|
||||
/* Do we have any keys left to try? */
|
||||
if (s->pkblob_pos_in_agent) {
|
||||
if (++s->agent_key_index >= s->agent_key_limit)
|
||||
s->done_agent = true;
|
||||
s->tried_pubkey_config = true;
|
||||
} else {
|
||||
s->keyi++;
|
||||
if (s->keyi >= s->nkeys)
|
||||
s->done_agent = true;
|
||||
}
|
||||
|
||||
} else if (s->can_pubkey && s->publickey_blob &&
|
||||
s->privatekey_available && !s->tried_pubkey_config) {
|
||||
@ -1786,7 +1809,7 @@ static void ssh2_userauth_add_sigblob(
|
||||
/* debug("modulus length is %d\n", len); */
|
||||
/* debug("signature length is %d\n", siglen); */
|
||||
|
||||
if (mod_mp.len != sig_mp.len) {
|
||||
if (mod_mp.len > sig_mp.len) {
|
||||
strbuf *substr = strbuf_new();
|
||||
put_data(substr, sigblob.ptr, sig_prefix_len);
|
||||
put_uint32(substr, mod_mp.len);
|
||||
|
4
sshdss.c
4
sshdss.c
@ -72,8 +72,10 @@ static char *dss_cache_str(ssh_key *key)
|
||||
struct dss_key *dss = container_of(key, struct dss_key, sshk);
|
||||
strbuf *sb = strbuf_new();
|
||||
|
||||
if (!dss->p)
|
||||
if (!dss->p) {
|
||||
strbuf_free(sb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
append_hex_to_strbuf(sb, dss->p);
|
||||
append_hex_to_strbuf(sb, dss->q);
|
||||
|
@ -17,6 +17,8 @@ struct SshServerConfig {
|
||||
unsigned long ssh1_cipher_mask;
|
||||
bool ssh1_allow_compression;
|
||||
bool bare_connection;
|
||||
|
||||
bool stunt_pretend_to_accept_any_pubkey;
|
||||
};
|
||||
|
||||
Plug *ssh_server_plug(
|
||||
|
@ -2072,7 +2072,9 @@ static void swap_screen(Terminal *term, int which,
|
||||
ttr = term->alt_screen;
|
||||
term->alt_screen = term->screen;
|
||||
term->screen = ttr;
|
||||
term->alt_sblines = find_last_nonempty_line(term, term->alt_screen) + 1;
|
||||
term->alt_sblines = (
|
||||
term->alt_screen ?
|
||||
find_last_nonempty_line(term, term->alt_screen) + 1 : 0);
|
||||
t = term->curs.x;
|
||||
if (!reset && !keep_cur_pos)
|
||||
term->curs.x = term->alt_x;
|
||||
|
@ -315,22 +315,25 @@ bool do_cmdline(int argc, char **argv, bool do_everything, Conf *conf)
|
||||
char *val;
|
||||
|
||||
/*
|
||||
* Macros to make argument handling easier. Note that because
|
||||
* they need to call `continue', they cannot be contained in
|
||||
* the usual do {...} while (0) wrapper to make them
|
||||
* syntactically single statements; hence it is not legal to
|
||||
* use one of these macros as an unbraced statement between
|
||||
* `if' and `else'.
|
||||
* Macros to make argument handling easier.
|
||||
*
|
||||
* Note that because they need to call `continue', they cannot be
|
||||
* contained in the usual do {...} while (0) wrapper to make them
|
||||
* syntactically single statements. I use the alternative if (1)
|
||||
* {...} else ((void)0).
|
||||
*/
|
||||
#define EXPECTS_ARG { \
|
||||
if (--argc <= 0) { \
|
||||
err = true; \
|
||||
fprintf(stderr, "%s: %s expects an argument\n", appname, p); \
|
||||
continue; \
|
||||
} else \
|
||||
val = *++argv; \
|
||||
}
|
||||
#define SECOND_PASS_ONLY do { if (!do_everything) continue; } while (0)
|
||||
#define EXPECTS_ARG if (1) { \
|
||||
if (--argc <= 0) { \
|
||||
err = true; \
|
||||
fprintf(stderr, "%s: %s expects an argument\n", appname, p); \
|
||||
continue; \
|
||||
} else \
|
||||
val = *++argv; \
|
||||
} else ((void)0)
|
||||
#define SECOND_PASS_ONLY if (1) { \
|
||||
if (!do_everything) \
|
||||
continue; \
|
||||
} else ((void)0)
|
||||
|
||||
while (--argc > 0) {
|
||||
const char *p = *++argv;
|
||||
|
@ -29,6 +29,7 @@ Socket *platform_make_agent_socket(
|
||||
if ((errw = make_dir_and_check_ours(socketdir)) != NULL) {
|
||||
*error = dupprintf("%s: %s\n", socketdir, errw);
|
||||
sfree(errw);
|
||||
sfree(socketdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -206,6 +206,8 @@ static void setup_utmp(char *ttyname, char *location)
|
||||
struct timeval tv;
|
||||
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw)
|
||||
return; /* can't stamp utmp if we don't have a username */
|
||||
memset(&utmp_entry, 0, sizeof(utmp_entry));
|
||||
utmp_entry.ut_type = USER_PROCESS;
|
||||
utmp_entry.ut_pid = getpid();
|
||||
|
@ -775,6 +775,8 @@ int main(int argc, char **argv)
|
||||
filename_free(logfile);
|
||||
conf_set_int(conf, CONF_logtype, LGTYP_SSHRAW);
|
||||
conf_set_int(conf, CONF_logxfovr, LGXF_OVR);
|
||||
} else if (!strcmp(arg, "--pretend-to-accept-any-pubkey")) {
|
||||
ssc.stunt_pretend_to_accept_any_pubkey = true;
|
||||
} else {
|
||||
fprintf(stderr, "%s: unrecognised option '%s'\n", appname, arg);
|
||||
exit(1);
|
||||
|
@ -5225,7 +5225,7 @@ static void wintw_clip_write(
|
||||
(int)udata[uindex]);
|
||||
alen = 1; strcpy(after, "}");
|
||||
} else {
|
||||
blen = sprintf(before, "\\u%d", udata[uindex]);
|
||||
blen = sprintf(before, "\\u%d", (int)udata[uindex]);
|
||||
alen = 0; after[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +106,7 @@
|
||||
#define WINHELP_CTX_ssh_share "config-ssh-sharing"
|
||||
#define WINHELP_CTX_ssh_kexlist "config-ssh-kex-order"
|
||||
#define WINHELP_CTX_ssh_hklist "config-ssh-hostkey-order"
|
||||
#define WINHELP_CTX_ssh_hk_known "config-ssh-prefer-known-hostkeys"
|
||||
#define WINHELP_CTX_ssh_gssapi_kex_delegation "config-ssh-kex-gssapi-delegation"
|
||||
#define WINHELP_CTX_ssh_kex_repeat "config-ssh-kex-rekey"
|
||||
#define WINHELP_CTX_ssh_kex_manual_hostkeys "config-ssh-kex-manual-hostkeys"
|
||||
|
Loading…
Reference in New Issue
Block a user