diff --git a/doc/changes.md b/doc/changes.md index 3a4ffb39..2c9ff17a 100644 --- a/doc/changes.md +++ b/doc/changes.md @@ -11,62 +11,21 @@ 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 - -In Kermit 95 2.1.3 and earlier, the user known hosts file was -`\v(appdata)ssh/known_hosts2`. In Kermit 95 3.0 beta 2, when the new SSH backend -was introduced, this was *accidentally* changed to `\v(home).ssh/known_hosts` -(the default location used by libssh). - -It wasn't really appropriate for K95 to be picking up known hosts from other -SSH packages, or for K95 to go adding hosts to another SSH packages known hosts -file without the user being aware of this. As a result this accidental change -has been reversed and as of Kermit 95 3.0 beta 7, the *default* SSH user known -hosts file is once again `\v(appdata)ssh/known_hosts2`. - -If you'd like Kermit 95 to share a known hosts file with OpenSSH or any -other SSH packages using `\v(home).ssh/known_hosts`, you can add the following -to your k95custom.ini to explicitly opt in to this: -`set ssh v2 user-known-hosts-file \v(home).ssh/known_hosts`. - -If you do not do the above, you may be effectively starting off with an -empty `known_hosts` file when upgrading to beta 7 resulting in host verification -prompts for previously known hosts. If you want to keep the K95 known hosts file -separate in its new default location, but don't want all the host verification prompts, -you can *copy* the known hosts file from its previous location to the new one by -entering the following commands at the K95 prompt: -``` -mkdir \v(appdata)ssh -copy \v(home).ssh/known_hosts \v(appdata)ssh/known_hosts2 -``` - -If `\v(appdata)ssh/known_hosts2` already exists the above will overwrite it. -> [!TIP] -> To find out where `\v(appdata)`, `\v(home)` and other such directories are -> on your disk, you can use the `orient` command. +#### The default SSH directory has changed! +The default SSH directory in beta 7 has changed from `\v(home).ssh` back to +`\v(appdata)ssh`, the location used by Kermit 95 2.1.3 and earlier. -#### Default location for identity files has changed +This means Kermit 95 may not find your known hosts file, or your identity +(public key authentication) files after upgrading to beta 7. -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 prefer to keep these files in `\v(home).ssh`, the same location used +by OpenSSH on modern versions of windows, add the command +`set ssh directory \v(home).ssh` to your k95custom.ini -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 -``` +> [!TIP] +> To find out where `\v(appdata)`, `\v(home)` and other such directories are +> on your disk, you can use the `orient` command. ### New features @@ -123,14 +82,13 @@ if > \Flength(\m(idf)) 21 idf (`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` +* Implemented the `set ssh identity-file` command +* Added new command `set ssh directory` which allows you to set the default + location where K95 looks for user known hosts and identity files. +* The default SSH directory has changed from `\v(home).ssh` back to + `\v(appdata)ssh` +* The `ssh key` commands will now default to opening or saving keys in the + SSH directory. ### 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 b146ae74..0e97b789 100644 --- a/doc/ssh-readme.md +++ b/doc/ssh-readme.md @@ -91,11 +91,16 @@ SSH REMOVE LOCAL-PORT-FORWARD local-port the local port forwarding list. This has no effect on any active connection. -SSH REMOVE REMOTE-PORT-FORWARD remote-port", +SSH REMOVE REMOTE-PORT-FORWARD remote-port Removes the remote port forward with the specified remote-port from the remote port forwarding list. This has no effect on any active connection. +SET SSH DIRECTORY directory + Specifies where Kermit 95 should look for the default SSH user files + such as the user-known-hosts file and identity files (id_rsa, etc). + By default Kermit 95 looks for these in \\v(appdata)ssh. + set ssh v2 key-exchange-methods {CURVE25519-SHA256, CURVE25519-SHA256@LIBSSH.ORG, DIFFIE-HELLMAN-GROUP1-SHA1, DIFFIE-HELLMAN-GROUP14-SHA1, DIFFIE-HELLMAN-GROUP14-SHA256, diff --git a/kermit/k95/ckolssh.c b/kermit/k95/ckolssh.c index d9fcee15..dbd6370d 100644 --- a/kermit/k95/ckolssh.c +++ b/kermit/k95/ckolssh.c @@ -490,6 +490,7 @@ static char /* The following are to be malloc'd */ * ssh2_unh = NULL, /* v2 user known hosts file */ * ssh2_kex = NULL, /* Key Exchange Methods */ * ssh_pxc = NULL, /* Proxy command */ + * ssh_dir = NULL, /* SSH Directory */ * xxx_dummy = NULL; static const char **ssh_idf = NULL; /* Identity files */ @@ -1015,6 +1016,9 @@ int ssh_set_sparam(int param, const char* value) { case SSH_SPARAM_PXC: copy_set_sparam(&ssh_pxc, value); break; + case SSH_SPARAM_DIR: + copy_set_sparam(&ssh_dir, value); + break; default: return 1; } @@ -1053,6 +1057,8 @@ const char* ssh_get_sparam(int param) { return ssh2_kex; case SSH_SPARAM_PXC: return ssh_pxc; + case SSH_SPARAM_DIR: + return ssh_dir; default: return NULL; } @@ -1201,6 +1207,24 @@ static int get_ssh_error() { return error; } +/* Returns the SSH directory in a new string. The string must be freed by + * the caller. + * + * @returns A new string containing the SSH directory. + */ +char* ssh_directory() { + + char* dir; + if (ssh_dir != NULL) { /* SSH Directory */ + dir = _strdup(ssh_dir); + } else { + dir = malloc(sizeof(char)*MAX_PATH); + + /* \v(appdata)ssh/ */ + ckmakmsg(dir, MAX_PATH, GetAppData(0), "Kermit 95/", "ssh/", NULL); + } + return dir; +} /** Opens an SSH connection. Connection parameters are passed through global * variables @@ -1335,16 +1359,29 @@ int ssh_open() { } /* Sort out default files and directories */ - if (ssh2_unh != NULL) { + if (ssh2_unh != NULL) { /* SSHv2 User Known Hosts file */ unh = _strdup(ssh2_unh); - } else { + } else if (ssh_dir == NULL) { + /* Set the default user known hosts file to + * \v(appdata)ssh/known_hosts2 only if: + * -> The user has not specified the user known hosts file with the + * set ssh v2 user-known-hosts-file + * -> The user has not specified an SSH directory + * This is to retain compatibility with Kermit 95 2.1.3 and earlier + * which named the SSHv2 UNH file "known_hosts2" and the SSHv1 UNH file + * "known_hosts". If the user changes their SSH directory to something + * else, we don't need to worry about K95 2.1.3 and earlier named this + * file, and we'll just go with "known_hosts" which is what OpenSSH + * uses. + */ + unh = malloc(sizeof(char)*NHPATHMAX); /* \v(appdata) = GetAppData(0) + "Kermit 95/" */ ckmakmsg(unh, NHPATHMAX, GetAppData(0), "Kermit 95/", "ssh/", "known_hosts2"); } - if (ssh2_gnh != NULL) { + if (ssh2_gnh != NULL) { /* SSHv2 Global Known Hosts file */ gnh = _strdup(ssh2_gnh); } else { gnh = malloc(sizeof(char)*NHPATHMAX); @@ -1353,9 +1390,7 @@ int ssh_open() { ckmakmsg(gnh, NHPATHMAX, GetAppData(1), "Kermit 95/", "ssh/", "known_hosts2"); } - /* Set libssh SSH dir to \v(appdata)ssh/ */ - dir = malloc(sizeof(char)*NHPATHMAX); - ckmakmsg(dir, NHPATHMAX, GetAppData(0), "Kermit 95/", "ssh/", NULL); + dir = ssh_directory(); /* The SSH Subsystem will take ownership of this and handle cleaning it up * on disconnect */ @@ -2241,15 +2276,20 @@ int sshkey_create(char * filename, int bits, char * pp, int type, char * cmd_com output_filename = _strdup(filename); } else { char* default_pathname; + char* dir; output_filename = malloc(MAX_PATH * sizeof(char)); default_pathname = malloc(MAX_PATH * sizeof(char)); - /* We'll suggest the user save in %USERPROFILE%\.ssh by default as thats - * where both C-Kermit and the windows builds of OpenSSH look */ - snprintf(default_pathname, MAX_PATH, "%s%s.ssh/%s", - GetHomeDrive(), GetHomePath(), default_filename); + dir = ssh_directory(); + + /* We'll suggest the user save in their ssh directory by default as + * that's where K95 looks by default */ + snprintf(default_pathname, MAX_PATH, "%s%s", + dir, default_filename); + free(dir); + #ifdef CK_MKDIR - /* Make the .ssh directory if it doesn't already exist */ + /* Make the ssh directory if it doesn't already exist */ zmkdir(default_pathname); #endif @@ -2373,6 +2413,26 @@ int sshkey_create(char * filename, int bits, char * pp, int type, char * cmd_com return SSH_ERR_NO_ERROR; } +/** Gets the default key filename. This will be something like id_rsa + * in the SSH directory. + * + * The returned string must be freed by the caller. + * + * @return Default SSH key filename. Must be freed by caller. + */ +char* default_key_filename() { + char *default_filename, *dir; + dir = ssh_directory(); + default_filename = malloc(MAX_PATH * sizeof(char)); + + /* We'll suggest the user save in their ssh directory by default as + * that's where K95 looks by default */ + snprintf(default_filename, MAX_PATH, "%s%s", + dir, "id_rsa"); + free(dir); + return default_filename; +} + /** Displays the fingerprint for the specified public key * * @param filename Key file to display the fingerprint for. If not supplied, one @@ -2406,6 +2466,8 @@ int sshkey_display_fingerprint(char * filename, int babble) { /* printf("sshkey_display_fingerprint\nFilename: %s\nBabble: %d\n", filename, babble);*/ if (filename == NULL) { + char *default_filename = default_key_filename(); + fn = malloc(MAX_PATH); int rc = uq_file( /* Text mode only, text above the prompt */ @@ -2413,10 +2475,11 @@ int sshkey_display_fingerprint(char * filename, int babble) { "Open Key File", /* file dialog title or text-mode prompt*/ 1, /* existing file */ NULL, /* Help text - not used */ - "id_rsa", + default_filename, fn, MAX_PATH ); + free(default_filename); if (rc == 0) { free(fn); return SSH_ERR_USER_CANCELED; @@ -2469,6 +2532,8 @@ int sshkey_display_public(char * filename, char *identity_passphrase) { */ if (filename == NULL) { + char *default_filename = default_key_filename(); + fn = malloc(MAX_PATH); rc = uq_file( /* Text mode only, text above the prompt */ @@ -2476,10 +2541,11 @@ int sshkey_display_public(char * filename, char *identity_passphrase) { "Open Key File", /* file dialog title or text-mode prompt*/ 1, /* existing file */ NULL, /* Help text - not used */ - "id_rsa", + default_filename, fn, MAX_PATH ); + free(default_filename); if (rc == 0) { free(fn); return SSH_ERR_USER_CANCELED; @@ -2522,16 +2588,13 @@ int sshkey_display_public(char * filename, char *identity_passphrase) { int sshkey_display_public_as_ssh2(char * filename,char *identity_passphrase) { /* ssh key display /format:ssh.com id_rsa */ - ssh_key key = NULL; int rc; char* fn = NULL, * blob; - /* We get here with the following: - * ssh key display /format:openssh id_rsa - */ - if (filename == NULL) { + char *default_filename = default_key_filename(); + fn = malloc(MAX_PATH); rc = uq_file( /* Text mode only, text above the prompt */ @@ -2539,10 +2602,11 @@ int sshkey_display_public_as_ssh2(char * filename,char *identity_passphrase) { "Open Key File", /* file dialog title or text-mode prompt*/ 1, /* existing file */ NULL, /* Help text - not used */ - "id_rsa", + default_filename, fn, MAX_PATH ); + free(default_filename); if (rc == 0) { free(fn); return SSH_ERR_USER_CANCELED; @@ -2597,6 +2661,7 @@ int sshkey_change_passphrase(char * filename, char * oldpp, char * newpp) { char* pp = NULL; if (filename == NULL) { + char *default_filename = default_key_filename(); fn = malloc(MAX_PATH); rc = uq_file( /* Text mode only, text above the prompt */ @@ -2604,10 +2669,11 @@ int sshkey_change_passphrase(char * filename, char * oldpp, char * newpp) { "Open Key File", /* file dialog title or text-mode prompt*/ 1, /* existing file */ NULL, /* Help text - not used */ - "id_rsa", + default_filename, fn, MAX_PATH ); + free(default_filename); if (rc == 0) { free(fn); return SSH_ERR_USER_CANCELED; diff --git a/kermit/k95/ckonssh.c b/kermit/k95/ckonssh.c index 4865cf12..ff054759 100644 --- a/kermit/k95/ckonssh.c +++ b/kermit/k95/ckonssh.c @@ -241,6 +241,7 @@ static char /* The following are to be malloc'd */ * ssh2_unh = NULL, /* v2 user known hosts file */ * ssh2_kex = NULL, /* Key Exchange Methods */ * ssh_pxc = NULL, /* Proxy command */ +* ssh_dir = NULL, /* SSH Directory */ * xxx_dummy = NULL; #ifdef SSH_DLL @@ -728,6 +729,9 @@ int ssh_set_sparam(int param, const char* value) { case SSH_SPARAM_PXC: copy_set_sparam(&ssh_pxc, value); break; + case SSH_SPARAM_DIR: + copy_set_sparam(&ssh_dir, value); + break; default: return 1; } @@ -771,6 +775,8 @@ const char* ssh_get_sparam(int param) { return ssh2_kex; case SSH_SPARAM_PXC: return ssh_pxc; + case SSH_SPARAM_DIR: + return ssh_dir; default: return NULL; } diff --git a/kermit/k95/ckossh.h b/kermit/k95/ckossh.h index bb21d3ba..a7c0e5c2 100644 --- a/kermit/k95/ckossh.h +++ b/kermit/k95/ckossh.h @@ -88,6 +88,7 @@ typedef struct ssh_port_forward { #define SSH_SPARAM_2_UNH 13 /* v2 user known hosts file */ #define SSH_SPARAM_2_KEX 14 /* Key Exchange Methods */ #define SSH_SPARAM_PXC 15 /* Proxy command */ +#define SSH_SPARAM_DIR 16 /* SSH Directory */ /* Setters and getters for the various "set ssh" options. set_ssh_sparam takes * a copy of the supplied string rather than taking ownership of it.*/ diff --git a/kermit/k95/ckuus2.c b/kermit/k95/ckuus2.c index 0cb84ddb..ea855802 100644 --- a/kermit/k95/ckuus2.c +++ b/kermit/k95/ckuus2.c @@ -970,6 +970,11 @@ static char *hmxyssh[] = { "SET SSH COMPRESSION { ON, OFF }", " Specifies whether compression will be used. The default is ON.", " ", +"SET SSH DIRECTORY directory", +" Specifies where Kermit 95 should look for the default SSH user files", +" such as the user-known-hosts file and identity files (id_rsa, etc).", +" By default Kermit 95 looks for these in \\v(appdata)ssh.", +" ", "SET SSH DYNAMIC-FORWARDING { ON, OFF }", " Specifies whether Kermit is to act as a SOCKS4 service on port 1080", " when connected to a remote host via SSH. When Kermit acts as a SOCKS4", diff --git a/kermit/k95/ckuus3.c b/kermit/k95/ckuus3.c index 832e588e..fd4d0461 100644 --- a/kermit/k95/ckuus3.c +++ b/kermit/k95/ckuus3.c @@ -7984,6 +7984,7 @@ setprinter(xx) int xx; #define SSH_CFG 22 /* Use OpenSSH Config */ #define SSH_HBT 23 /* Heartbeat Interval */ #define SSH_PXC 24 /* Proxy Command */ +#define SSH_DIR 25 /* SSH Directory */ #endif /* SSHBUILTIN */ static struct keytab sshtab[] = { /* SET SSH command table */ @@ -7991,6 +7992,7 @@ static struct keytab sshtab[] = { /* SET SSH command table */ { "agent-forwarding", SSH_AFW, 0 }, /* SSH_FEAT_AGENT_FWD */ { "check-host-ip", SSH_CHI, 0 }, { "compression", SSH_CMP, 0 }, + { "directory", SSH_DIR, 0 }, { "dynamic-forwarding", SSH_DYF, 0 }, /* SSH_FEAT_PORT_FWD */ { "gateway-ports", SSH_GWP, 0 }, /* SSH_FEAT_PORT_FWD */ { "gssapi", SSH_GSS, 0 }, /* SSH_FEAT_ADV_GSSAPI */ @@ -8147,6 +8149,7 @@ shossh() { } printf(" ssh check-host-ip: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_CHKIP))); printf(" ssh compression: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_CMP))); + printf(" ssh directory: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_DIR))); if (ssh_feature_supported(SSH_FEAT_DYN_PORT_FWD)) { printf(" ssh dynamic-forwarding: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_DYF))); } @@ -8449,6 +8452,21 @@ dosetssh() { case SSH_CMP: /* Compression */ return(success = set_ssh_iparam_on(SSH_IPARAM_CMP)); + case SSH_DIR: + if ((x = cmdir("SSH Directory","",&s,xxstring)) < 0) { + if (x != -3) + return(x); + } else { + ckstrncpy(line,s,LINBUFSIZ); + if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) + ckstrncpy(line,tmpbuf,LINBUFSIZ); + } + s = (x == -3) ? NULL : line; + if ((x = cmcfm()) < 0) + return(x); + ssh_set_sparam(SSH_SPARAM_DIR, s); + return(1); + case SSH_DYF: /* Dynamic Forwarding */ if (!ssh_feature_supported(SSH_FEAT_DYN_PORT_FWD)) { printf("\r\nDynamic port forwarding is not supported by the current SSH backend\r\n"); diff --git a/kermit/k95/k95custom.ini b/kermit/k95/k95custom.ini index 5c80166a..399d5307 100644 --- a/kermit/k95/k95custom.ini +++ b/kermit/k95/k95custom.ini @@ -59,26 +59,14 @@ if available ssh { ; connection from becoming idle and timing out set ssh heartbeat-interval 60 - ; 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 + ; Kermit 95 3.0 beta 2 changed the default SSH directory (where your known + ; hosts and identity files are stored by default) from \v(appdata)ssh to + ; \v(home).ssh, the same location used by the version of OpenSSH that comes + ; with modern versions of Windows. Kermit 95 beta 7 undoes this change. + + ; If you'd like to use the same known hosts and identity files as OpenSSH, + ; uncomment this line: + ;set ssh directory \v(home).ssh } ; Set the default download directory to the normal location on Windows 10/11