[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] examples: add public key authentication to ssh_server_fork


I noticed that there was no example showing server side public key encryption in the examples
so I added this one. I used authorizedkeys as a global to minimize the changes to the original
code as well as I was not sure the correct methodology of determining the .ssh directory location
for a user not using Linux. One code using the user parameter to determine the location to use
instead if desired.

Eric Bentley (1):
  examples: add public key authentication to ssh_server_fork

 examples/ssh_server_fork.c | 68 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 2 deletions(-)

-- 
2.6.0.GIT

From 900a67d9a3c0811dd134c1b854d09acbc2edad9f Mon Sep 17 00:00:00 2001
From: Eric Bentley <ebentley66@xxxxxxxxx>
Date: Sat, 25 Nov 2017 17:10:30 -0500
Subject: [PATCH] examples: add public key authentication to ssh_server_fork

Signed-off-by: ebentley66@xxxxxxxxx
---
 examples/ssh_server_fork.c | 68 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 2 deletions(-)

diff --git a/examples/ssh_server_fork.c b/examples/ssh_server_fork.c
index 18320c8..6a505c7 100644
--- a/examples/ssh_server_fork.c
+++ b/examples/ssh_server_fork.c
@@ -37,6 +37,7 @@ The goal is to show the API in action.
 #endif
 #include <sys/ioctl.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
 #include <stdio.h>
 
 #ifndef KEYS_FOLDER
@@ -70,7 +71,8 @@ static void set_default_keys(ssh_bind sshbind,
                              KEYS_FOLDER "ssh_host_ecdsa_key");
     }
 }
-
+#define DEF_STR_SIZE 1024
+char authorizedkeys[DEF_STR_SIZE] = {0};
 #ifdef HAVE_ARGP_H
 const char *argp_program_version = "libssh server example "
 SSH_STRINGIFY(LIBSSH_VERSION);
@@ -126,6 +128,14 @@ static struct argp_option options[] = {
         .group = 0
     },
     {
+        .name  = "authorizedkeys",
+        .key   = 'a',
+        .arg   = "FILE",
+        .flags = 0,
+        .doc   = "Set the authorized keys file.",
+        .group = 0
+    },
+    {
         .name  = "no-default-keys",
         .key   = 'n',
         .arg   = NULL,
@@ -178,6 +188,9 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
             ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, arg);
             ecdsa_already_set = 1;
             break;
+        case 'a':
+            strncpy(authorizedkeys, arg, DEF_STR_SIZE-1);
+            break;
         case 'v':
             ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
                                  "3");
@@ -434,6 +447,52 @@ static int auth_password(ssh_session session, const char *user,
     return SSH_AUTH_DENIED;
 }
 
+static int auth_publickey(ssh_session session, const char *user,
+                                        struct ssh_key_struct *pubkey,
+                                        char signature_state,
+                                        void *userdata)
+{
+    struct session_data_struct *sdata = (struct session_data_struct *) userdata;
+
+    (void) user;
+    (void) session;
+
+    if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
+        return SSH_AUTH_SUCCESS;
+    }
+
+    if (signature_state != SSH_PUBLICKEY_STATE_VALID) {
+        return SSH_AUTH_DENIED;
+    }
+
+    // valid so far.  Now look through authorized keys for a match
+    if (authorizedkeys[0])
+    {
+        ssh_key key;
+        int result;
+        struct stat buf;
+
+        if (stat(authorizedkeys, &buf) == 0) {
+            result = ssh_pki_import_pubkey_file( authorizedkeys, &key );
+            if ((result != SSH_OK) || (key==NULL))
+                fprintf(stderr, "unable to import public key file %s\n", authorizedkeys);
+            else {
+                result = ssh_key_cmp( key, pubkey, SSH_KEY_CMP_PUBLIC );
+                ssh_key_free(key);
+                if (result == 0) {
+                    sdata->authenticated = 1;
+                    return SSH_AUTH_SUCCESS;
+                }
+            }
+        }
+
+    }
+
+    // no matches
+    sdata->authenticated = 0;
+    return SSH_AUTH_DENIED;
+}
+
 static ssh_channel channel_open(ssh_session session, void *userdata) {
     struct session_data_struct *sdata = (struct session_data_struct *) userdata;
 
@@ -517,6 +576,12 @@ static void handle_session(ssh_event event, ssh_session session) {
         .channel_open_request_session_function = channel_open,
     };
 
+    if (authorizedkeys[0]) {
+        server_cb.auth_pubkey_function = auth_publickey;
+        ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY);
+    } else
+        ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
+
     ssh_callbacks_init(&server_cb);
     ssh_callbacks_init(&channel_cb);
 
@@ -527,7 +592,6 @@ static void handle_session(ssh_event event, ssh_session session) {
         return;
     }
 
-    ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
     ssh_event_add_session(event, session);
 
     n = 0;
-- 
2.6.0.GIT


Archive administrator: postmaster@lists.cynapses.org