Add optional authentication methods for ssh pubkey and interactive.
diff --git a/src/session_p.h b/src/session_p.h
index 845fd3f..fdfbd7c 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -169,6 +169,14 @@
     int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data);
     void *passwd_auth_data;
     void (*passwd_auth_data_free)(void *data);
+
+    int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, void *user_data);
+    void *pubkey_auth_data;
+    void (*pubkey_auth_data_free)(void *data);
+
+    int (*interactive_auth_clb)(const struct nc_session *session, const char* password,void *user_data);
+    void *interactive_auth_data;
+    void (*interactive_auth_data_free)(void *data);
 #endif
 #ifdef NC_ENABLED_TLS
     int (*user_verify_clb)(const struct nc_session *session);
diff --git a/src/session_server.h b/src/session_server.h
index 106a1a1..08ddbba 100644
--- a/src/session_server.h
+++ b/src/session_server.h
@@ -22,6 +22,12 @@
 #   include <openssl/x509.h>
 #endif
 
+#ifdef NC_ENABLED_SSH
+#   include <libssh/libssh.h>
+#   include <libssh/callbacks.h>
+#   include <libssh/server.h>
+#endif
+
 #include "session.h"
 #include "netconf.h"
 
@@ -508,6 +514,29 @@
                                        void *user_data, void (*free_user_data)(void *user_data));
 
 /**
+ * @brief Set the callback for SSH interactive authentication. If none is set, local system users are used.
+ *
+ * @param[in] interactive_auth_clb Callback that should authenticate the user.
+ *                            Zero return indicates success, non-zero an error.
+ * @param[in] user_data Optional arbitrary user data that will be passed to \p passwd_auth_clb.
+ * @param[in] free_user_data Optional callback that will be called during cleanup to free any \p user_data.
+ */
+void ncserver_ssh_set_interactive_auth_clb(int (*interactive_auth_clb)(const struct nc_session *session, const char *password,
+                                                              void *user_data),
+                                           void *user_data, void (*free_user_data)(void *user_data));
+
+/**
+ * @brief Set the callback for SSH public key authentication. If none is set, local system users are used.
+ *
+ * @param[in] pubkey_auth_clb Callback that should authenticate the user.
+ *                            Zero return indicates success, non-zero an error.
+ * @param[in] user_data Optional arbitrary user data that will be passed to \p passwd_auth_clb.
+ * @param[in] free_user_data Optional callback that will be called during cleanup to free any \p user_data.
+ */
+ void ncserver_ssh_set_pubkey_auth_clb(int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, void *user_data),
+                                       void *user_data, void (*free_user_data)(void *user_data));
+
+/**
  * @brief Set the callback for retrieving host keys. Any RSA, DSA, and ECDSA keys can be added. However,
  *        a maximum of one key of each type will be used during SSH authentication, later keys replacing
  *        the earlier ones.
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index 88aa0a3..b261738 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -820,33 +820,43 @@
 static void
 nc_sshcb_auth_kbdint(struct nc_session *session, ssh_message msg)
 {
+    int auth_ret = 1;
     char *pass_hash;
-
+    // Print message for interactive SSH
     if (!ssh_message_auth_kbdint_is_response(msg)) {
         const char *prompts[] = {"Password: "};
         char echo[] = {0};
 
         ssh_message_auth_interactive_request(msg, "Interactive SSH Authentication", "Type your password:", 1, prompts, echo);
     } else {
-        if (ssh_userauth_kbdint_getnanswers(session->ti.libssh.session) != 1) {
+        if (ssh_userauth_kbdint_getnanswers(session->ti.libssh.session) != 1) {// failed session
             ssh_message_reply_default(msg);
-            return;
+            return auth_ret;
         }
-        pass_hash = auth_password_get_pwd_hash(session->username);
-        if (!pass_hash) {
-            ssh_message_reply_default(msg);
-            return;
+        // Check the authentication type
+        if (server_opts.interactive_auth_clb)
+        {
+            auth_ret = server_opts.interactive_auth_clb(session, ssh_message_auth_password(msg), server_opts.interactive_auth_clb);  
         }
-        if (!auth_password_compare_pwd(pass_hash, ssh_userauth_kbdint_getanswer(session->ti.libssh.session, 0))) {
-            VRB("User \"%s\" authenticated.", session->username);
+        else {
+            pass_hash = auth_password_get_pwd_hash(session->username);// get hashed password
+            if (pass_hash) {
+                auth_ret = auth_password_compare_pwd(pass_hash, ssh_userauth_kbdint_getanswer(session->ti.libssh.session, 0));
+                free(pass_hash);// free hashed password
+            }
+        }
+        // Authenticate message based on outcome
+        if (!auth_ret)
+        {
             session->flags |= NC_SESSION_SSH_AUTHENTICATED;
+            VRB("User \"%s\" authenticated.", session->username);
             ssh_message_auth_reply_success(msg, 0);
-        } else {
+        }
+        else {
             ++session->opts.server.ssh_auth_attempts;
             VRB("Failed user \"%s\" authentication attempt (#%d).", session->username, session->opts.server.ssh_auth_attempts);
             ssh_message_reply_default(msg);
         }
-        free(pass_hash);
     }
 }
 
@@ -909,12 +919,19 @@
     const char *username;
     int signature_state;
 
-    if ((username = auth_pubkey_compare_key(ssh_message_auth_pubkey(msg))) == NULL) {
-        VRB("User \"%s\" tried to use an unknown (unauthorized) public key.", session->username);
-        goto fail;
-    } else if (strcmp(session->username, username)) {
-        VRB("User \"%s\" is not the username identified with the presented public key.", session->username);
-        goto fail;
+    if(server_opts.pubkey_auth_clb){
+        if(server_opts.pubkey_auth_clb(session, ssh_message_auth_pubkey(msg), server_opts.pubkey_auth_data)){
+            goto fail;
+        }
+    }
+    else{
+        if ((username = auth_pubkey_compare_key(ssh_message_auth_pubkey(msg))) == NULL) {
+            VRB("User \"%s\" tried to use an unknown (unauthorized) public key.", session->username);
+            goto fail;
+        } else if (strcmp(session->username, username)) {
+            VRB("User \"%s\" is not the username identified with the presented public key.", session->username);
+            goto fail;
+        }
     }
 
     signature_state = ssh_message_auth_publickey_state(msg);