Skip to content

Commit

Permalink
Add a new SET SSH DIRECTORY command
Browse files Browse the repository at this point in the history
Which will make it much easier for users upgrading from betas 2-6 to deal with the fact the default SSH directory has changed.
  • Loading branch information
davidrg committed Oct 9, 2024
1 parent 064d5a8 commit 42be0ea
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 101 deletions.
78 changes: 18 additions & 60 deletions doc/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion doc/ssh-readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
[email protected], DIFFIE-HELLMAN-GROUP1-SHA1,
DIFFIE-HELLMAN-GROUP14-SHA1, DIFFIE-HELLMAN-GROUP14-SHA256,
Expand Down
106 changes: 86 additions & 20 deletions kermit/k95/ckolssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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 */
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2406,17 +2466,20 @@ 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 */
"Enter the filename of the key to display the fingerprint for:",
"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;
Expand Down Expand Up @@ -2469,17 +2532,20 @@ 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 */
"Enter the filename of the key to display the fingerprint for:",
"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;
Expand Down Expand Up @@ -2522,27 +2588,25 @@ 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 */
"Enter the filename of the key to display the fingerprint for:",
"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;
Expand Down Expand Up @@ -2597,17 +2661,19 @@ 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 */
"Enter the filename of the key to display the fingerprint for:",
"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;
Expand Down
6 changes: 6 additions & 0 deletions kermit/k95/ckonssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions kermit/k95/ckossh.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.*/
Expand Down
Loading

0 comments on commit 42be0ea

Please sign in to comment.