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);