From 273d42aed07fdec3171b075e71eeae66dae92195 Mon Sep 17 00:00:00 2001 From: David Goodwin Date: Thu, 10 Oct 2024 07:23:20 +1300 Subject: [PATCH] Change SSH directory to \v(appdata)ssh This results in identity files being moved too --- doc/changes.md | 25 +++++++++++++++++++++++++ doc/ssh-readme.md | 7 ------- kermit/k95/ckolssh.c | 25 +++++++++++++++++++++++-- kermit/k95/ckolsshs.c | 19 +++++++++++++++++-- kermit/k95/ckolsshs.h | 4 +++- kermit/k95/ckonssh.c | 10 ++++++++++ kermit/k95/ckossh.c | 14 ++++++++++++++ kermit/k95/ckossh.h | 6 ++---- kermit/k95/ckuus2.c | 4 +++- kermit/k95/ckuus3.c | 11 +++++++++-- kermit/k95/ckuusr.c | 10 +++++++--- kermit/k95/k95custom.ini | 24 ++++++++++++++++++++---- 12 files changed, 133 insertions(+), 26 deletions(-) diff --git a/doc/changes.md b/doc/changes.md index a120cbf9..3a4ffb39 100644 --- a/doc/changes.md +++ b/doc/changes.md @@ -11,6 +11,10 @@ it carried from 1995 through to 2013. ### Things to be aware of when upgrading * K95G no longer opens COM1 by default. If you previously depended on this, you'll need to add `set port com1` to your k95custom.ini +* The default SSH home directory has been reverted from `\v(home).ssh` back to + the location used by Kermit 95 2.1.3 and earlier - `\v(appdata)ssh`. You + may wish to add some commands to your k95custom.ini if you'd rather keep + using the location used by C-Kermit for Windows betas 2-6 (K95 3.0 betas 2-6). #### SSH User Known Hosts File Has Moved @@ -47,6 +51,24 @@ If `\v(appdata)ssh/known_hosts2` already exists the above will overwrite it. > To find out where `\v(appdata)`, `\v(home)` and other such directories are > on your disk, you can use the `orient` command. +#### Default location for identity files has changed + +As of beta 7, Kermit 95 3.0 now looks in `\v(appdata)ssh` for identity files, +the same place Kermit 95 v2.1.3 and earlier used. + +If you'd rather not use the new old location, you can add the following to +your K95 custom: +``` +local idf +.idf := set ssh identity-file +if exist \v(home).ssh/id_rsa .idf := \m(idf) \v(home).ssh/id_rsa +if exist \v(home).ssh/id_dsa .idf := \m(idf) \v(home).ssh/id_dsa +if exist \v(home).ssh/id_ecdsa .idf := \m(idf) \v(home).ssh/id_ecdsa +if exist \v(home).ssh/id_ed25519 .idf := \m(idf) \v(home).ssh/id_ed25519 +if > \Flength(\m(idf)) 21 idf +``` + + ### New features * SSH Port forwarding (tunneling) is now supported again in both the Direct/Local and Reverse/Remote forms. You can add forwards before @@ -101,11 +123,14 @@ If `\v(appdata)ssh/known_hosts2` already exists the above will overwrite it. (`set gui menubar { off, on }`) is still accepted for compatibility with existing scripts. `set gui menubar on` still does nothing as it always has (disabling the menubar is a session lockdown feature) +* Implemented the `set ssh set ssh identity-file` command * The default location for the SSH user known hosts file has changed from `\v(home).ssh/known_hosts` (K95 3.0 betas 2-6) to the value used by Kermit 95 v2.1.3 and earlier: `\v(appdata)ssh/known_hosts2`. Placing this file in `\v(home).ssh` was never an intentional decision, but rather a detail overlooked when switching to a new SSH backend. +* Related to the above, the default location for SSH user identities has + changed from `\v(home).ssh/` to `\v(appdata)ssh` ### Fixed bugs * Fix `fopen` causing a crash. This issue seems to have come in some recent diff --git a/doc/ssh-readme.md b/doc/ssh-readme.md index 169e2068..b146ae74 100644 --- a/doc/ssh-readme.md +++ b/doc/ssh-readme.md @@ -12,12 +12,6 @@ for the built-in SSH client as delivered in Kermit 95 v2.1.3 is available here: https://kermitproject.org/k95manual/sshclien.html - SSH differences between Kermit 95 and Kermit 95 are discussed later in this document. -For convenience Kermit 95 currently looks for the known_hosts file as well as -your public and private keys in `%USERPROFILE%\.ssh`. This directory is also -used by the version of OpenSSH bundled with Windows 10+ so if you were -previously using that your keys and known hosts should be picked up -automatically by Kermit 95. - ## Known Issues * When connecting to modern linux hosts with the linux terminal type, you'll @@ -153,7 +147,6 @@ SET SSH CHECK-HOST-IP {ON,OFF} DYNAMIC-FORWARDING {ON,OFF} GATEWAY-PORTS {ON,OFF} - IDENTITY-FILE filename PRIVILEGED-PORT {ON,OFF} QUIET {ON,OFF} V2 AUTO-REKEY {ON,OFF} diff --git a/kermit/k95/ckolssh.c b/kermit/k95/ckolssh.c index acbb8585..d9fcee15 100644 --- a/kermit/k95/ckolssh.c +++ b/kermit/k95/ckolssh.c @@ -61,6 +61,7 @@ char *cksshv = "SSH support (LibSSH), 10.0, 18 Apr 2023"; #ifndef SSH_DLL #include "ckclib.h" +#include "ckoreg.h" #endif @@ -168,7 +169,7 @@ char *cksshv = "SSH support (LibSSH), 10.0, 18 Apr 2023"; * GSSAPI DELEGATE-CREDENTIALS {ON,OFF} * Value is stored in ssh_gsd * HEARTBEAT-INTERVAL interval - * TODO: IDENTITY-FILE filename + * IDENTITY-FILE filename * TODO: PRIVILEGED-PORT {ON,OFF} * TODO: QUIET {ON,OFF} * -> This should suppress all printfs @@ -491,6 +492,8 @@ static char /* The following are to be malloc'd */ * ssh_pxc = NULL, /* Proxy command */ * xxx_dummy = NULL; +static const char **ssh_idf = NULL; /* Identity files */ + /* The SSH subsystem actually tracks port forwards with a linked list so it has * no particular limit on the number it will support, but we need to be able to * track these things separately from the SSH subsystem to allow them to be set @@ -789,6 +792,7 @@ int ssh_dll_init(ssh_init_parameters_t *params) { params->p_install_funcs("ssh_get_iparam", ssh_get_iparam); params->p_install_funcs("ssh_set_sparam", ssh_set_sparam); params->p_install_funcs("ssh_get_sparam", ssh_get_sparam); + params->p_install_funcs("ssh_set_identity_files", ssh_set_identity_files); params->p_install_funcs("ssh_open", ssh_open); params->p_install_funcs("ssh_clos", ssh_clos); params->p_install_funcs("ssh_tchk", ssh_tchk); @@ -1055,6 +1059,22 @@ const char* ssh_get_sparam(int param) { return NULL; } +/** Set the list of SSH identity files to use for authentication + * + * @param identity_files List of identity files, null terminated. + * @returns 0 on success, -1 if not supported + */ +int ssh_set_identity_files(const char** identity_files) { + /* TODO: We really *should* make a copy of this rather than + * just holding on to the pointer given to us by K95. + * Currently its "ok" as the array of identity files is + * statically allocated by K95, and there is little + * reason for this to change in the future. + */ + ssh_idf = identity_files; + return 0; +} + /** This is called by ssh_dll_init when the DLL is loaded (SSH_DLL defined) * or directly by K95 on application startup (SSH_DLL not defined) at the * point where the DLL would normally have been loaded. @@ -1370,7 +1390,8 @@ int ssh_open() { x11_host, /* Host to forward X11 too */ display_number, /* X11 display number */ ssh_xal, /* Xauth location */ - dir /* SSH Dir*/ + dir, /* SSH Dir*/ + ssh_idf /* Identity files */ ); if (user) free(user); diff --git a/kermit/k95/ckolsshs.c b/kermit/k95/ckolsshs.c index 13361a86..2598b1cf 100644 --- a/kermit/k95/ckolsshs.c +++ b/kermit/k95/ckolsshs.c @@ -149,7 +149,8 @@ ssh_parameters_t* ssh_parameters_new( const char* macs, const char* key_exchange_methods, int nodelay, const char* proxy_command, const ssh_port_forward_t *port_forwards, BOOL forward_x, const char* display_host, int display_number, - const char* xauth_location, const char* ssh_dir) { + const char* xauth_location, const char* ssh_dir, + const char** identity_files) { ssh_parameters_t* params; params = (ssh_parameters_t*)malloc(sizeof(ssh_parameters_t)); @@ -171,6 +172,7 @@ ssh_parameters_t* ssh_parameters_new( params->nodelay = nodelay; params->proxy_command = NULL; params->ssh_dir = NULL; + params->identity_files = identity_files; /* Copy hostname and port*/ params->hostname = _strdup(hostname); @@ -321,6 +323,9 @@ void ssh_parameters_free(ssh_parameters_t* parameters) { if (parameters->xauth_location) free(parameters->xauth_location); + /* Note: parameters->identity_files should *not* be freed as we're not + * currently taking a copy of it */ + free(parameters); } @@ -1499,7 +1504,17 @@ static int configure_session(ssh_client_state_t * state) { if (state->parameters->global_known_hosts_file) ssh_options_set(state->session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, state->parameters->global_known_hosts_file); - // TODO: Set SSH_OPTIONS_SSH_DIR to where the known_hosts and keys live + + if (state->parameters->identity_files != NULL) { + int i = 0; + while (state->parameters->identity_files[i] != NULL) { + debug(F111, "Add identity file", state->parameters->identity_files[i], i); + ssh_options_set(state->session, SSH_OPTIONS_ADD_IDENTITY , + state->parameters->identity_files[i]); + i++; + } + } + // TODO: SSH_OPTIONS_STRICTHOSTKEYCHECK ? // identity fields (set ssh identity-file) diff --git a/kermit/k95/ckolsshs.h b/kermit/k95/ckolsshs.h index 6e5025a2..b0481712 100644 --- a/kermit/k95/ckolsshs.h +++ b/kermit/k95/ckolsshs.h @@ -158,6 +158,7 @@ typedef struct { int nodelay; /* Set to disable nagles agorithm */ char* proxy_command; /* Command to execute to connect to the server */ char* ssh_dir; /* SSH Directory */ + char** identity_files; /* SSH Identity Files */ /* Which authentication methods should be attempted and their order. */ int authentication_methods[MAX_AUTH_METHODS]; @@ -269,7 +270,8 @@ ssh_parameters_t* ssh_parameters_new( const char* macs, const char* key_exchange_methods, int nodelay, const char* proxy_command, const ssh_port_forward_t *port_forwards, BOOL forward_x, const char* display_host, int display_number, - const char* xauth_location, const char* ssh_dir); + const char* xauth_location, const char* ssh_dir, + const char** identity_files); /** Frees the ssh_parameters_t struct and all its members. * diff --git a/kermit/k95/ckonssh.c b/kermit/k95/ckonssh.c index 4ee14f72..4865cf12 100644 --- a/kermit/k95/ckonssh.c +++ b/kermit/k95/ckonssh.c @@ -414,6 +414,7 @@ int ssh_dll_init(ssh_init_parameters_t *params) { params->p_install_funcs("ssh_get_iparam", ssh_get_iparam); params->p_install_funcs("ssh_set_sparam", ssh_set_sparam); params->p_install_funcs("ssh_get_sparam", ssh_get_sparam); + params->p_install_funcs("ssh_set_identity_files", ssh_set_identity_files); params->p_install_funcs("ssh_open", ssh_open); params->p_install_funcs("ssh_clos", ssh_clos); params->p_install_funcs("ssh_tchk", ssh_tchk); @@ -776,6 +777,15 @@ const char* ssh_get_sparam(int param) { return NULL; } +/** Set the list of SSH identity files to use for authentication + * + * @param identity_files List of identity files, null terminated. + * @returns 0 on success, -1 if not supported + */ +int ssh_set_identity_files(const char** identity_files) { + return -1; +} + /** This is the equivalent of ssh_dll_init - when the SSH module is * compiled into the K95 executable (SSH_DLL not defined), this is * called on application startup to give the SSH subsystem an diff --git a/kermit/k95/ckossh.c b/kermit/k95/ckossh.c index 090fddbe..a27ab119 100644 --- a/kermit/k95/ckossh.c +++ b/kermit/k95/ckossh.c @@ -168,6 +168,7 @@ typedef int (*p_ssh_set_iparam_t)(int, int); typedef int (*p_ssh_get_iparam_t)(int); typedef int (*p_ssh_set_sparam_t)(int, const char*); typedef const char* (*p_ssh_get_sparam_t)(int); +typedef int (*p_ssh_set_identity_files_t)(const char**); typedef int (*p_ssh_open_t)(); typedef int (*p_ssh_clos_t)(); typedef int (*p_ssh_tchk_t)(); @@ -211,6 +212,7 @@ static p_ssh_set_iparam_t p_ssh_set_iparam = NULL; static p_ssh_get_iparam_t p_ssh_get_iparam = NULL; static p_ssh_set_sparam_t p_ssh_set_sparam = NULL; static p_ssh_get_sparam_t p_ssh_get_sparam = NULL; +static p_ssh_set_identity_files_t p_ssh_set_identity_files = NULL; static p_ssh_open_t p_ssh_open = NULL; static p_ssh_clos_t p_ssh_clos = NULL; static p_ssh_tchk_t p_ssh_tchk = NULL; @@ -285,6 +287,8 @@ void ssh_install_func(const char* function, const void* p_function) { p_ssh_set_sparam = F_CAST(p_ssh_set_sparam_t) p_function; else if ( !strcmp(function,"ssh_get_sparam") ) p_ssh_get_sparam = F_CAST(p_ssh_get_sparam_t) p_function; + else if ( !strcmp(function,"ssh_set_identity_files") ) + p_ssh_set_identity_files = F_CAST(p_ssh_set_identity_files_t) p_function; else if ( !strcmp(function,"ssh_open") ) p_ssh_open = F_CAST(p_ssh_open_t) p_function; else if ( !strcmp(function,"ssh_clos") ) @@ -482,6 +486,7 @@ int ssh_dll_unload(int quiet) { p_ssh_get_iparam = NULL; p_ssh_set_sparam = NULL; p_ssh_get_sparam = NULL; + p_ssh_set_identity_files = NULL; p_ssh_open = NULL; p_ssh_clos = NULL; p_ssh_tchk = NULL; @@ -665,6 +670,15 @@ const char* ssh_get_sparam(int param) { return NULL; } +/** Set the list of identity files to use for authentication. + * @param identity_files The list of identity file names, null terminated. + */ +int ssh_set_identity_files(const char** identity_files) { + if (p_ssh_set_identity_files) + return p_ssh_set_identity_files(identity_files); + return -1; +} + /** Opens an SSH connection. Connection parameters are passed through global * variables * diff --git a/kermit/k95/ckossh.h b/kermit/k95/ckossh.h index c1589027..bb21d3ba 100644 --- a/kermit/k95/ckossh.h +++ b/kermit/k95/ckossh.h @@ -1,10 +1,7 @@ #ifndef _CKOSSH_H #define _CKOSSH_H -/* TODO: These all need to be accessed via functions, not as globals. */ -extern char * ssh_idf[32]; /* identity files */ -extern int ssh_idf_n; - +/* TODO: This needs to be accessed via a function, not as a global. */ extern int ssh_sock; /* SSH socket */ #ifndef SSH_PF_T @@ -98,6 +95,7 @@ _PROTOTYP(int ssh_set_iparam,(int param, int value)); _PROTOTYP(int ssh_get_iparam,(int param)); _PROTOTYP(int ssh_set_sparam,(int param, const char* value)); _PROTOTYP(const char* ssh_get_sparam,(int param)); +_PROTOTYP(int ssh_set_identity_files,(const char** identity_files)); /* Getters for various global values within C-Kermit */ _PROTOTYP(const char* ssh_get_uid,(VOID)); diff --git a/kermit/k95/ckuus2.c b/kermit/k95/ckuus2.c index 8338dbd8..0cb84ddb 100644 --- a/kermit/k95/ckuus2.c +++ b/kermit/k95/ckuus2.c @@ -996,9 +996,11 @@ static char *hmxyssh[] = { " identities (private keys) are to be read when using public key", " authorization. These are files used in addition to the default files:", " ", -" \\v(appdata)ssh/identity V1 RSA", +/*" \\v(appdata)ssh/identity V1 RSA",*/ " \\v(appdata)ssh/id_rsa V2 RSA", " \\v(appdata)ssh/id_dsa V2 DSA", +" \\v(appdata)ssh/id_ecdsa ECDSA", +" \\v(appdata)ssh/id_ed25519 ED25519", " ", #ifdef SSH_DLL /* These commands aren't supported by the default SSH backend, but if the diff --git a/kermit/k95/ckuus3.c b/kermit/k95/ckuus3.c index 3114c24d..0096c000 100644 --- a/kermit/k95/ckuus3.c +++ b/kermit/k95/ckuus3.c @@ -8095,11 +8095,12 @@ static struct keytab gssapitab[] = { static int ngssapitab = (sizeof(gssapitab) / sizeof(struct keytab)) - 1; -char * ssh_idf[32] = { /* Identity file list */ +char * ssh_idf[33] = { /* Identity file list - null terminated */ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL }; char * ssh_tmp[32] = { /* Temp identity file list */ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, @@ -8987,6 +8988,12 @@ dosetssh() { } } ssh_idf_n = n; + + if (ssh_set_identity_files(ssh_idf) < 0) { + printf("\r\nCommand not supported by the current SSH backend\r\n"); + return(0); + } + return(success = 1); } case SSH_XFW: /* X11-forwarding */ diff --git a/kermit/k95/ckuusr.c b/kermit/k95/ckuusr.c index f03a41be..b28aab8b 100644 --- a/kermit/k95/ckuusr.c +++ b/kermit/k95/ckuusr.c @@ -148,6 +148,10 @@ extern tt_status[VNUM]; #ifdef KUI #include "ikui.h" #endif /* KUI */ +#ifdef SSHBUILTIN +extern char * ssh_idf[32]; /* identity files */ +extern int ssh_idf_n; +#endif /* SSHBUILTIN */ #endif /* OS2 */ int optlines = 0; @@ -2444,7 +2448,7 @@ static struct keytab sshkwtab[] = { { "load", XSSH_LOAD, CM_INV }, { "open", XSSH_OPN, 0 }, { "remove", XSSH_REM, 0 }, /* SSH_FEAT_PORT_FWD */ - { "v2", XSSH_V2, 0 }, /* SSH_FEAT_REKEY_MANUAL */ + { "v2", XSSH_V2, 0 }, /* */ { "", 0, 0 } }; static int nsshcmd = (sizeof(sshkwtab) / sizeof(struct keytab)) - 1; @@ -2459,7 +2463,7 @@ static int nsshloadcmd = (sizeof(sshloadkwtab) / sizeof(struct keytab)) - 1; #endif /* SSH_DLL */ static struct keytab ssh2tab[] = { - { "rekey", XSSH2_RKE, 0 }, /* Not supported by libssh */ + { "rekey", XSSH2_RKE, 0 }, /* SSH_FEAT_REKEY_MANUAL */ { "", 0, 0 } }; static int nssh2tab = (sizeof(ssh2tab) / sizeof(struct keytab)); @@ -10879,7 +10883,7 @@ necessary DLLs did not load. Use SHOW NETWORK to check network status.\n"); */ sshkwtab[z].flgs = CM_INV; } - else if (sshkwtab[z].kwval == XSSH_V2 + else if (sshkwtab[z].kwval == XSSH2_RKE && !ssh_feature_supported(SSH_FEAT_REKEY_MANUAL)) { /* * "ssh agent" diff --git a/kermit/k95/k95custom.ini b/kermit/k95/k95custom.ini index 93fe697c..5c80166a 100644 --- a/kermit/k95/k95custom.ini +++ b/kermit/k95/k95custom.ini @@ -53,16 +53,32 @@ if gui { ; Change your default userid to something other than your Windows username ;set login userid root +; Settings that apply only if you've got SSH support available if available ssh { ; Send an IGNORE message to the SSH server every 60 seconds to prevent the ; connection from becoming idle and timing out set ssh heartbeat-interval 60 - ; Look for the user known hosts file in the same place the version of - ; OpenSSH supplied with current Windows releases puts it. Kermit 95 3.0 - ; betas 2-6 also used this location, while the new default location (and - ; the location K95 2.1.3 and earlier used) is \v(appdata)ssh/known_hosts2 + ; Kermit 95 3.0 betas 2-6 used \v(home).ssh as your SSH directory, rather + ; than \v(appdata)ssh, the location used by Kermit 95 2.1.3 and earlier, + ; and Kermit 95 3.0 beta 7 and newer. \v(home).ssh is also used by the + ; version of OpenSSH supplied with modern versions of Windows, and possibly + ; other tools. + + ; If you'd like to look for your user known hosts file where OpenSSH and + ; Kermit 95 3.0 betas 2-6 put it, uncomment the following two lines: + ;if not exist \v(home).ssh/known_hosts touch \v(home).ssh/known_hosts ;set ssh v2 user-known-hosts-file \v(home).ssh/known_hosts + + ; And to look for identity files in the same place, uncomment the + ; following 7 lines: + ;local idf + ;.idf := set ssh identity-file + ;if exist \v(home).ssh/id_rsa .idf := \m(idf) \v(home).ssh/id_rsa + ;if exist \v(home).ssh/id_dsa .idf := \m(idf) \v(home).ssh/id_dsa + ;if exist \v(home).ssh/id_ecdsa .idf := \m(idf) \v(home).ssh/id_ecdsa + ;if exist \v(home).ssh/id_ed25519 .idf := \m(idf) \v(home).ssh/id_ed25519 + ;if > \Flength(\m(idf)) 21 idf } ; Set the default download directory to the normal location on Windows 10/11