Fallback on invalid SSH key
This commit is contained in:
@@ -639,8 +639,9 @@ static void sink_accept(struct csink *s)
|
||||
|
||||
/* Transparent source spoofing */
|
||||
|
||||
// Runs ip(8) without a shell. Returns its exit status, -1 if it did not run.
|
||||
static int run_ip(const char *const argv[])
|
||||
// Runs a program without a shell, output discarded. Returns its exit status,
|
||||
// -1 if it did not run.
|
||||
static int run_cmd(const char *const argv[])
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
@@ -651,7 +652,7 @@ static int run_ip(const char *const argv[])
|
||||
dup2(nul, STDOUT_FILENO);
|
||||
dup2(nul, STDERR_FILENO);
|
||||
}
|
||||
execvp("ip", (char *const *)argv);
|
||||
execvp(argv[0], (char *const *)argv);
|
||||
_exit(127);
|
||||
}
|
||||
int st;
|
||||
@@ -676,16 +677,16 @@ static void spoof_routing(int add)
|
||||
// Remove copies left by an earlier run, then add exactly one.
|
||||
for (int k = 0; k < 16; k++) {
|
||||
const char *del[] = { "ip", fam, "rule", "del", "pref", tab, NULL };
|
||||
if (run_ip(del) != 0)
|
||||
if (run_cmd(del) != 0)
|
||||
break;
|
||||
}
|
||||
const char *flush[] = { "ip", fam, "route", "flush", "table", tab, NULL };
|
||||
run_ip(flush);
|
||||
run_cmd(flush);
|
||||
if (!add)
|
||||
continue;
|
||||
const char *rule[] = { "ip", fam, "rule", "add", "pref", tab, "from", fams[i][1], "iif", "lo", "lookup", tab, NULL };
|
||||
const char *route[] = { "ip", fam, "route", "replace", "local", fams[i][2], "dev", "lo", "table", tab, NULL };
|
||||
int ok = run_ip(rule) == 0 && run_ip(route) == 0;
|
||||
int ok = run_cmd(rule) == 0 && run_cmd(route) == 0;
|
||||
if (i == 0)
|
||||
ok4 = ok;
|
||||
else if (!ok)
|
||||
@@ -835,23 +836,86 @@ static int process_ctl_input(void)
|
||||
|
||||
/* Session setup */
|
||||
|
||||
// libssh2 before 1.11 signs RSA keys only with SHA-1 ("ssh-rsa"), which
|
||||
// OpenSSH 8.8+ rejects by default.
|
||||
static int rsa_usable(void)
|
||||
{
|
||||
return libssh2_version(0x010b00) != NULL;
|
||||
}
|
||||
|
||||
// Identifies RSA keys by the public key file or a PEM private key header.
|
||||
static int key_is_rsa(const char *path)
|
||||
{
|
||||
char pub[300], head[64] = "";
|
||||
snprintf(pub, sizeof(pub), "%s.pub", path);
|
||||
FILE *f = fopen(pub, "r");
|
||||
if (!f)
|
||||
f = fopen(path, "r");
|
||||
if (!f)
|
||||
return 0;
|
||||
size_t n = fread(head, 1, sizeof(head) - 1, f);
|
||||
head[n] = '\0';
|
||||
fclose(f);
|
||||
return !strncmp(head, "ssh-rsa ", 8) || strstr(head, "BEGIN RSA PRIVATE KEY") != NULL;
|
||||
}
|
||||
|
||||
// Creates PB_CLIENT_KEY with ssh-keygen unless it exists. Returns 0 if usable.
|
||||
static int ensure_own_key(void)
|
||||
{
|
||||
if (access(PB_CLIENT_KEY, R_OK) == 0)
|
||||
return 0;
|
||||
char host[64], comment[96];
|
||||
if (gethostname(host, sizeof(host)) < 0)
|
||||
strcpy(host, "client");
|
||||
host[sizeof(host) - 1] = '\0';
|
||||
snprintf(comment, sizeof(comment), "patchbay@%s", host);
|
||||
const char *argv[] = { "ssh-keygen", "-q", "-t", "ed25519", "-N", "", "-C", comment, "-f", PB_CLIENT_KEY, NULL };
|
||||
if (run_cmd(argv) != 0 || access(PB_CLIENT_KEY, R_OK) != 0) {
|
||||
log_err("cannot create %s with ssh-keygen (is openssh-client installed?)", PB_CLIENT_KEY);
|
||||
return -1;
|
||||
}
|
||||
log_warn("created %s; add its public key in the web UI (patchbayd --pubkey)", PB_CLIENT_KEY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int client_identity(const struct pb_config *c, char *out, size_t outsz)
|
||||
{
|
||||
const char *cands[] = { c->identity_file, "/root/.ssh/id_ed25519", "/root/.ssh/id_rsa",
|
||||
"/etc/ssh/ssh_host_ed25519_key", NULL };
|
||||
for (int i = 0; cands[i]; i++) {
|
||||
if (!cands[i][0])
|
||||
continue;
|
||||
if (access(cands[i], R_OK) == 0) {
|
||||
snprintf(out, outsz, "%s", cands[i]);
|
||||
return 0;
|
||||
}
|
||||
if (i == 0) {
|
||||
log_err("IdentityFile %s is not readable", cands[i]);
|
||||
if (c->identity_file[0]) {
|
||||
if (access(c->identity_file, R_OK) != 0) {
|
||||
log_err("IdentityFile %s is not readable", c->identity_file);
|
||||
return -1;
|
||||
}
|
||||
if (key_is_rsa(c->identity_file) && !rsa_usable())
|
||||
log_warn("IdentityFile %s is an RSA key, which libssh2 %s can only sign with SHA-1; "
|
||||
"the target will reject it. Use an ed25519 key or libssh2 1.11+", c->identity_file,
|
||||
libssh2_version(0));
|
||||
snprintf(out, outsz, "%s", c->identity_file);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
|
||||
const char *cands[] = { "/root/.ssh/id_ed25519", "/root/.ssh/id_rsa", "/etc/ssh/ssh_host_ed25519_key", NULL };
|
||||
for (int i = 0; cands[i]; i++) {
|
||||
if (access(cands[i], R_OK) != 0)
|
||||
continue;
|
||||
if (key_is_rsa(cands[i]) && !rsa_usable()) {
|
||||
// A key the target rejects is worse than none: use our own instead.
|
||||
static int told;
|
||||
if (!told++)
|
||||
log_warn("%s is an RSA key that libssh2 %s cannot sign acceptably; using %s instead", cands[i],
|
||||
libssh2_version(0), PB_CLIENT_KEY);
|
||||
if (ensure_own_key() < 0)
|
||||
return -1;
|
||||
snprintf(out, outsz, "%s", PB_CLIENT_KEY);
|
||||
return 0;
|
||||
}
|
||||
snprintf(out, outsz, "%s", cands[i]);
|
||||
return 0;
|
||||
}
|
||||
// No usable key at all: create our own (or reuse one created earlier).
|
||||
if (ensure_own_key() < 0)
|
||||
return -1;
|
||||
snprintf(out, outsz, "%s", PB_CLIENT_KEY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_host_key(void)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define PB_DEFAULT_CONF "/etc/patchbay/patchbay.conf"
|
||||
#define PB_DEFAULT_DB "/etc/patchbay/patchbay.db"
|
||||
#define PB_RUN_DIR "/run/patchbay"
|
||||
#define PB_CLIENT_KEY "/etc/patchbay/id_ed25519" // created when root only has an unusable RSA key
|
||||
|
||||
enum pb_role { ROLE_CLIENT, ROLE_TARGET };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user