diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h index 754a54c3..4bda8c8f 100644 --- a/include/libssh/sftp.h +++ b/include/libssh/sftp.h @@ -1144,6 +1144,27 @@ LIBSSH_API int sftp_server_version(sftp_session sftp); */ LIBSSH_API char *sftp_expand_path(sftp_session sftp, const char *path); +/** + * @brief Get the specified user's home directory + * + * This calls the "home-directory" extension. You should check if the extension + * is supported using: + * + * @code + * int supported = sftp_extension_supported(sftp, "home-directory", "1"); + * @endcode + * + * @param sftp The sftp session handle. + * + * @param username username of the user whose home directory is requested. + * + * @return On success, a newly allocated string containing the + * absolute real-path of the home directory of the user. + * NULL on error. The caller needs to free the memory + * using ssh_string_free_char(). + */ +LIBSSH_API char *sftp_home_directory(sftp_session sftp, const char *username); + #ifdef WITH_SERVER /** * @brief Create a new sftp server session. diff --git a/src/sftp.c b/src/sftp.c index 76a9e13e..ba198f99 100644 --- a/src/sftp.c +++ b/src/sftp.c @@ -3100,4 +3100,93 @@ char *sftp_expand_path(sftp_session sftp, const char *path) return NULL; } +char * +sftp_home_directory(sftp_session sftp, const char *username) +{ + sftp_status_message status = NULL; + sftp_message msg = NULL; + ssh_buffer buffer = NULL; + uint32_t id; + int rc; + + if (sftp == NULL) { + return NULL; + } + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(sftp->session); + sftp_set_error(sftp, SSH_FX_FAILURE); + return NULL; + } + + id = sftp_get_new_id(sftp); + + rc = ssh_buffer_pack(buffer, + "dss", + id, + "home-directory", + username ? username : ""); + if (rc != SSH_OK) { + ssh_set_error_oom(sftp->session); + SSH_BUFFER_FREE(buffer); + sftp_set_error(sftp, SSH_FX_FAILURE); + return NULL; + } + + rc = sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer); + SSH_BUFFER_FREE(buffer); + if (rc < 0) { + return NULL; + } + + while (msg == NULL) { + rc = sftp_read_and_dispatch(sftp); + if (rc < 0) { + return NULL; + } + msg = sftp_dequeue(sftp, id); + } + + if (msg->packet_type == SSH_FXP_NAME) { + uint32_t ignored = 0; + char *homepath = NULL; + + rc = ssh_buffer_unpack(msg->payload, "ds", &ignored, &homepath); + sftp_message_free(msg); + if (rc != SSH_OK) { + ssh_set_error(sftp->session, + SSH_ERROR, + "Failed to query user home directory"); + sftp_set_error(sftp, SSH_FX_FAILURE); + return NULL; + } + + return homepath; + } else if (msg->packet_type == SSH_FXP_STATUS) { + status = parse_status_msg(msg); + sftp_message_free(msg); + if (status == NULL) { + return NULL; + } + + sftp_set_error(sftp, status->status); + ssh_set_error(sftp->session, + SSH_REQUEST_DENIED, + "SFTP server: %s", + status->errormsg); + status_msg_free(status); + } else { + ssh_set_error( + sftp->session, + SSH_FATAL, + "Received message %d when attempting to query user home directory", + msg->packet_type); + sftp_message_free(msg); + sftp_set_error(sftp, SSH_FX_BAD_MESSAGE); + } + + return NULL; +} + #endif /* WITH_SFTP */