diff --git a/tmate-slave.c b/tmate-slave.c index 51fcdb21..7277d086 100644 --- a/tmate-slave.c +++ b/tmate-slave.c @@ -33,14 +33,15 @@ extern int server_create_socket(void); extern int client_connect(struct event_base *base, const char *path, int start_server); struct tmate_settings _tmate_settings = { - .keys_dir = TMATE_SSH_DEFAULT_KEYS_DIR, - .ssh_port = TMATE_SSH_DEFAULT_PORT, - .proxy_hostname = NULL, - .bind_addr = NULL, - .proxy_port = TMATE_DEFAULT_PROXY_PORT, - .tmate_host = NULL, - .log_level = LOG_NOTICE, - .use_syslog = false, + .keys_dir = TMATE_SSH_DEFAULT_KEYS_DIR, + .authorized_keys_path = NULL, + .ssh_port = TMATE_SSH_DEFAULT_PORT, + .proxy_hostname = NULL, + .bind_addr = NULL, + .proxy_port = TMATE_DEFAULT_PROXY_PORT, + .tmate_host = NULL, + .log_level = LOG_NOTICE, + .use_syslog = false, }; struct tmate_settings *tmate_settings = &_tmate_settings; @@ -102,7 +103,7 @@ void request_server_termination(void) static void usage(void) { - fprintf(stderr, "usage: tmate-slave [-b ip] [-h hostname] [-k keys_dir] [-p port] [-x proxy_hostname] [-q proxy_port] [-s] [-v]\n"); + fprintf(stderr, "usage: tmate-slave [-b ip] [-h hostname] [-k keys_dir] [-a authorized_keys_path] [-p port] [-x proxy_hostname] [-q proxy_port] [-s] [-v]\n"); } static char* get_full_hostname(void) @@ -155,7 +156,7 @@ int main(int argc, char **argv, char **envp) { int opt; - while ((opt = getopt(argc, argv, "b:h:k:p:x:q:sv")) != -1) { + while ((opt = getopt(argc, argv, "b:h:k:a:p:x:q:sv")) != -1) { switch (opt) { case 'b': tmate_settings->bind_addr = xstrdup(optarg); @@ -166,6 +167,9 @@ int main(int argc, char **argv, char **envp) case 'k': tmate_settings->keys_dir = xstrdup(optarg); break; + case 'a': + tmate_settings->authorized_keys_path = xstrdup(optarg); + break; case 'p': tmate_settings->ssh_port = atoi(optarg); break; diff --git a/tmate-ssh-server.c b/tmate-ssh-server.c index 271c83f6..bb8b0885 100644 --- a/tmate-ssh-server.c +++ b/tmate-ssh-server.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +107,61 @@ static ssh_channel channel_open_request_cb(ssh_session session, void *userdata) return client->channel; } +static int check_authorized_keys(struct ssh_key_struct *client_pubkey) { + #define MAX_PUBKEY_SIZE 0x4000 + + const char *authorized_keys_path = tmate_settings->authorized_keys_path; + const char *token_delim = " "; + + FILE *file; + char key_buf[MAX_PUBKEY_SIZE], *key_type, *key_content; + enum ssh_keytypes_e type; + ssh_key pkey; + + if (authorized_keys_path == NULL) + return SSH_AUTH_SUCCESS; + + file = fopen(authorized_keys_path, "rb"); + if (file == NULL) { + tmate_fatal("Could not open authorized_keys file: \"%s\"", authorized_keys_path); + return SSH_AUTH_DENIED; + } + + while (fgets(key_buf, MAX_PUBKEY_SIZE, file)) { + if (key_buf[0] == '#' || key_buf[0] == '\0') + continue; + + key_type = strtok(key_buf, token_delim); + if (key_type == NULL) + continue; + + type = ssh_key_type_from_name(key_type); + if (type == SSH_KEYTYPE_UNKNOWN) + continue; + + key_content = strtok(NULL, token_delim); + if (key_content == NULL) + continue; + + pkey = ssh_key_new(); + if (ssh_pki_import_pubkey_base64(key_content, type, &pkey) != SSH_OK) { + ssh_key_free(pkey); + continue; + } + + if (!ssh_key_cmp(pkey, client_pubkey, SSH_KEY_CMP_PUBLIC)) { + ssh_key_free(pkey); + fclose(file); + return SSH_AUTH_SUCCESS; + } + + ssh_key_free(pkey); + } + + fclose(file); + return SSH_AUTH_DENIED; +} + static int auth_pubkey_cb(__unused ssh_session session, const char *user, struct ssh_key_struct *pubkey, @@ -118,7 +174,8 @@ static int auth_pubkey_cb(__unused ssh_session session, client->username = xstrdup(user); if (ssh_pki_export_pubkey_base64(pubkey, &client->pubkey) != SSH_OK) tmate_fatal("error getting public key"); - return SSH_AUTH_SUCCESS; + + return check_authorized_keys(pubkey); case SSH_PUBLICKEY_STATE_NONE: return SSH_AUTH_SUCCESS; default: diff --git a/tmate.h b/tmate.h index fe257f3e..7335b3a0 100644 --- a/tmate.h +++ b/tmate.h @@ -205,6 +205,7 @@ extern void tmate_ssh_server_main(struct tmate_session *session, struct tmate_settings { const char *keys_dir; + const char *authorized_keys_path; int ssh_port; const char *proxy_hostname; int proxy_port;