@@ -525,26 +525,45 @@ int nc_server_ssh_set_authkey_path_format(const char *path);
525525 * @brief Keyboard interactive authentication callback.
526526 *
527527 * The callback has to handle sending interactive challenges and receiving responses by itself.
528- * An example callback may fit the following description:
529- * Prepare all prompts for the user and send them via `ssh_message_auth_interactive_request()`.
530- * Get the answers either by calling `ssh_message_get()` or `nc_server_ssh_kbdint_get_nanswers()`.
531- * Return value based on your authentication logic and user answers retrieved by
532- * calling `ssh_userauth_kbdint_getanswer()`.
528+ * The exact workflow depends on the libssh version the library was compiled with.
529+ *
530+ * **libssh older than 0.12 (message-based workflow):**
531+ * The callback is invoked exactly once per authentication attempt, with the initial
532+ * keyboard-interactive request message. Prepare all prompts for the user and send them via
533+ * `ssh_message_auth_interactive_request()`. Get the answers either by calling `ssh_message_get()`
534+ * or `nc_server_ssh_kbdint_get_nanswers()`, and then `ssh_userauth_kbdint_getanswer()` for each
535+ * of them. Multiple challenge-response rounds can be performed within this single invocation.
536+ *
537+ * **libssh 0.12 and newer (callback-based workflow):**
538+ * Authentication is driven by libssh server callbacks, so this callback is invoked separately
539+ * for every stage of the keyboard-interactive exchange and each invocation must return promptly
540+ * (blocking helpers such as `ssh_message_get()` or `nc_server_ssh_kbdint_get_nanswers()` must
541+ * not be used). Determine the current stage with `ssh_message_auth_kbdint_is_response()`:
542+ * - not a response: send a challenge via `ssh_message_auth_interactive_request()` and return
543+ * `SSH_AUTH_INFO`;
544+ * - a response: retrieve the answers with `ssh_userauth_kbdint_getnanswers()` and
545+ * `ssh_userauth_kbdint_getanswer()` and return the authentication result, or send another
546+ * challenge and return `SSH_AUTH_INFO` to start the next round.
533547 *
534548 * @param[in] session NETCONF session.
535549 * @param[in] ssh_sess libssh session.
536- * @param[in] msg SSH message that contains the interactive request and which expects a reply with prompts .
550+ * @param[in] msg SSH message with the interactive request (a response message with libssh 0.12+) .
537551 * @param[in] user_data Arbitrary user data.
538- * @return 0 for successful authentication, non-zero to deny the user.
552+ * @return 0 for successful authentication, non-zero to deny the user; with libssh 0.12+
553+ * `SSH_AUTH_INFO` may be returned when a challenge was sent and the client's response
554+ * is expected (the callback is then invoked again once it arrives). With libssh 0.12+,
555+ * `SSH_AUTH_PARTIAL` may also be returned if the method succeeded but more authentication
556+ * methods are required based on the server configuration; if none are required, the
557+ * authentication completes instead of returning a partial success.
539558 */
540559typedef int (* nc_server_ssh_interactive_auth_clb )(const struct nc_session * session ,
541560 ssh_session ssh_sess , ssh_message msg , void * user_data );
542561
543562/**
544563 * @brief Set the callback for SSH interactive authentication.
545564 *
546- * @param[in] auth_clb Keyboard interactive authentication callback. This callback is only called once per authentication .
547- * @param[in] user_data Optional arbitrary user data that will be passed to @p interactive_auth_clb .
565+ * @param[in] auth_clb Keyboard interactive authentication callback. Called once per authentication (libssh < 0.12) or once per stage (libssh >= 0.12) .
566+ * @param[in] user_data Optional arbitrary user data that will be passed to @p auth_clb .
548567 * @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
549568 */
550569void nc_server_ssh_set_interactive_auth_clb (nc_server_ssh_interactive_auth_clb auth_clb , void * user_data , void (* free_user_data )(void * user_data ));
0 commit comments