diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | CMakeLists.txt | 13 | ||||
-rw-r--r-- | cmake/modules/FindGSSAPI.cmake | 325 | ||||
m--------- | libssh | 0 | ||||
-rw-r--r-- | patch/libssh-0.10.4.patch | 157 |
6 files changed, 497 insertions, 2 deletions
@@ -1,2 +1,3 @@ build +libssh-installed .*.swp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0ea1fcd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libssh"] + path = libssh + url = https://git.libssh.org/projects/libssh.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 26f6267..af022a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,17 +7,26 @@ project(mscp LANGUAGES C) set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG") +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) if(APPLE) list(APPEND CMAKE_PREFIX_PATH /usr/local) # intel mac homebrew prefix list(APPEND CMAKE_PREFIX_PATH /opt/homebrew) # arm mac homebrew prefix endif() # APPLE -find_package(libssh REQUIRED) add_executable(mscp src/main.c src/platform.c src/ssh.c src/file.c src/pprint.c) target_include_directories(mscp PUBLIC ./src) -target_link_libraries(mscp ssh pthread m) +if (LIBSSH_PATH) + find_package(GSSAPI) + target_include_directories(mscp PUBLIC ${LIBSSH_PATH}/include) + target_link_directories(mscp PRIVATE ${LIBSSH_PATH}/lib) + target_link_libraries(mscp pthread m libssh.a ssl crypto z ${GSSAPI_LIBRARIES}) +else() + find_package(libssh REQUIRED) + target_link_libraries(mscp pthread m ssh) +endif() + target_compile_definitions(mscp PUBLIC _VERSION="${PROJECT_VERSION}") install(TARGETS mscp diff --git a/cmake/modules/FindGSSAPI.cmake b/cmake/modules/FindGSSAPI.cmake new file mode 100644 index 0000000..4c3f44b --- /dev/null +++ b/cmake/modules/FindGSSAPI.cmake @@ -0,0 +1,325 @@ +# - Try to find GSSAPI +# Once done this will define +# +# KRB5_CONFIG - Path to krb5-config +# GSSAPI_ROOT_DIR - Set this variable to the root installation of GSSAPI +# +# Read-Only variables: +# GSSAPI_FLAVOR_MIT - set to TURE if MIT Kerberos has been found +# GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Keberos has been found +# GSSAPI_FOUND - system has GSSAPI +# GSSAPI_INCLUDE_DIR - the GSSAPI include directory +# GSSAPI_LIBRARIES - Link these to use GSSAPI +# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI +# +#============================================================================= +# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# + +find_path(GSSAPI_ROOT_DIR + NAMES + include/gssapi.h + include/gssapi/gssapi.h + HINTS + ${_GSSAPI_ROOT_HINTS} + PATHS + ${_GSSAPI_ROOT_PATHS} +) +mark_as_advanced(GSSAPI_ROOT_DIR) + +if (UNIX) + find_program(KRB5_CONFIG + NAMES + krb5-config + PATHS + ${GSSAPI_ROOT_DIR}/bin + /opt/local/bin) + mark_as_advanced(KRB5_CONFIG) + + if (KRB5_CONFIG) + # Check if we have MIT KRB5 + execute_process( + COMMAND + ${KRB5_CONFIG} --vendor + RESULT_VARIABLE + _GSSAPI_VENDOR_RESULT + OUTPUT_VARIABLE + _GSSAPI_VENDOR_STRING) + + if ((_GSSAPI_VENDOR_STRING MATCHES ".*Massachusetts.*") OR (_GSSAPI_VENDOR_STRING + MATCHES ".*MITKerberosShim.*")) + set(GSSAPI_FLAVOR_MIT TRUE) + else() + execute_process( + COMMAND + ${KRB5_CONFIG} --libs gssapi + RESULT_VARIABLE + _GSSAPI_LIBS_RESULT + OUTPUT_VARIABLE + _GSSAPI_LIBS_STRING) + + if (_GSSAPI_LIBS_STRING MATCHES ".*roken.*") + set(GSSAPI_FLAVOR_HEIMDAL TRUE) + endif() + endif() + + # Get the include dir + execute_process( + COMMAND + ${KRB5_CONFIG} --cflags gssapi + RESULT_VARIABLE + _GSSAPI_INCLUDE_RESULT + OUTPUT_VARIABLE + _GSSAPI_INCLUDE_STRING) + string(REGEX REPLACE "(\r?\n)+$" "" _GSSAPI_INCLUDE_STRING "${_GSSAPI_INCLUDE_STRING}") + string(REGEX REPLACE " *-I" "" _GSSAPI_INCLUDEDIR "${_GSSAPI_INCLUDE_STRING}") + endif() + + if (NOT GSSAPI_FLAVOR_MIT AND NOT GSSAPI_FLAVOR_HEIMDAL) + # Check for HEIMDAL + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(_GSSAPI heimdal-gssapi) + endif (PKG_CONFIG_FOUND) + + if (_GSSAPI_FOUND) + set(GSSAPI_FLAVOR_HEIMDAL TRUE) + else() + find_path(_GSSAPI_ROKEN + NAMES + roken.h + PATHS + ${GSSAPI_ROOT_DIR}/include + ${_GSSAPI_INCLUDEDIR}) + if (_GSSAPI_ROKEN) + set(GSSAPI_FLAVOR_HEIMDAL TRUE) + endif() + endif () + endif() +endif (UNIX) + +find_path(GSSAPI_INCLUDE_DIR + NAMES + gssapi.h + gssapi/gssapi.h + PATHS + ${GSSAPI_ROOT_DIR}/include + ${_GSSAPI_INCLUDEDIR} +) + +if (GSSAPI_FLAVOR_MIT) + find_library(GSSAPI_LIBRARY + NAMES + gssapi_krb5 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(KRB5_LIBRARY + NAMES + krb5 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(K5CRYPTO_LIBRARY + NAMES + k5crypto + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(COM_ERR_LIBRARY + NAMES + com_err + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + if (GSSAPI_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${GSSAPI_LIBRARY} + ) + endif (GSSAPI_LIBRARY) + + if (KRB5_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${KRB5_LIBRARY} + ) + endif (KRB5_LIBRARY) + + if (K5CRYPTO_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${K5CRYPTO_LIBRARY} + ) + endif (K5CRYPTO_LIBRARY) + + if (COM_ERR_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${COM_ERR_LIBRARY} + ) + endif (COM_ERR_LIBRARY) +endif (GSSAPI_FLAVOR_MIT) + +if (GSSAPI_FLAVOR_HEIMDAL) + find_library(GSSAPI_LIBRARY + NAMES + gssapi + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(KRB5_LIBRARY + NAMES + krb5 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(HCRYPTO_LIBRARY + NAMES + hcrypto + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(COM_ERR_LIBRARY + NAMES + com_err + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(HEIMNTLM_LIBRARY + NAMES + heimntlm + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(HX509_LIBRARY + NAMES + hx509 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(ASN1_LIBRARY + NAMES + asn1 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(WIND_LIBRARY + NAMES + wind + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(ROKEN_LIBRARY + NAMES + roken + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + if (GSSAPI_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${GSSAPI_LIBRARY} + ) + endif (GSSAPI_LIBRARY) + + if (KRB5_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${KRB5_LIBRARY} + ) + endif (KRB5_LIBRARY) + + if (HCRYPTO_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${HCRYPTO_LIBRARY} + ) + endif (HCRYPTO_LIBRARY) + + if (COM_ERR_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${COM_ERR_LIBRARY} + ) + endif (COM_ERR_LIBRARY) + + if (HEIMNTLM_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${HEIMNTLM_LIBRARY} + ) + endif (HEIMNTLM_LIBRARY) + + if (HX509_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${HX509_LIBRARY} + ) + endif (HX509_LIBRARY) + + if (ASN1_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${ASN1_LIBRARY} + ) + endif (ASN1_LIBRARY) + + if (WIND_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${WIND_LIBRARY} + ) + endif (WIND_LIBRARY) + + if (ROKEN_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${WIND_LIBRARY} + ) + endif (ROKEN_LIBRARY) +endif (GSSAPI_FLAVOR_HEIMDAL) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR) + +if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES) + set(GSSAPI_FOUND TRUE) +endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES) + +# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view +mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES) diff --git a/libssh b/libssh new file mode 160000 +Subproject e8322817a9e5aaef0698d779ddd467a209a85d8 diff --git a/patch/libssh-0.10.4.patch b/patch/libssh-0.10.4.patch new file mode 100644 index 0000000..bd6dc0e --- /dev/null +++ b/patch/libssh-0.10.4.patch @@ -0,0 +1,157 @@ +diff --git a/DefineOptions.cmake b/DefineOptions.cmake +index 068db988..7f42c2f3 100644 +--- a/DefineOptions.cmake ++++ b/DefineOptions.cmake +@@ -25,6 +25,7 @@ option(WITH_GEX "Enable DH Group exchange mechanisms" ON) + option(WITH_INSECURE_NONE "Enable insecure none cipher and MAC algorithms (not suitable for production!)" OFF) + option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF) + option(PICKY_DEVELOPER "Build with picky developer flags" OFF) ++option(WITH_STATIC_LIB "Build static library" ON) + + if (WITH_ZLIB) + set(WITH_LIBZ ON) +@@ -60,3 +61,7 @@ endif (NOT GLOBAL_CLIENT_CONFIG) + if (FUZZ_TESTING) + set(WITH_INSECURE_NONE ON) + endif (FUZZ_TESTING) ++ ++if (WITH_STATIC_LIB) ++ set(BUILD_STATIC_LIB ON) ++endif() +diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h +index c855df8a..1fd1710a 100644 +--- a/include/libssh/sftp.h ++++ b/include/libssh/sftp.h +@@ -565,6 +565,9 @@ LIBSSH_API int sftp_async_read(sftp_file file, void *data, uint32_t len, uint32_ + */ + LIBSSH_API ssize_t sftp_write(sftp_file file, const void *buf, size_t count); + ++LIBSSH_API int sftp_async_write(sftp_file file, const void *buf, size_t count, uint32_t* id); ++LIBSSH_API int sftp_async_write_end(sftp_file file, uint32_t id, int blocking); ++ + /** + * @brief Seek to a specific location in a file. + * +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index c090fef7..e2f86309 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -435,6 +435,11 @@ if (BUILD_STATIC_LIB) + if (WIN32) + target_compile_definitions(ssh-static PUBLIC "LIBSSH_STATIC") + endif (WIN32) ++ ++ install(TARGETS ssh-static ++ EXPORT libssh-config ++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ++ COMPONENT libraries) + endif (BUILD_STATIC_LIB) + + message(STATUS "Threads_FOUND=${Threads_FOUND}") +diff --git a/src/sftp.c b/src/sftp.c +index e01012a8..7b5dc249 100644 +--- a/src/sftp.c ++++ b/src/sftp.c +@@ -2228,6 +2228,102 @@ ssize_t sftp_write(sftp_file file, const void *buf, size_t count) { + return -1; /* not reached */ + } + ++/* ++ * sftp_async_write and sftp_async_write_end are copied from ++ * https://github.com/limes-datentechnik-gmbh/libssh ++ */ ++int sftp_async_write(sftp_file file, const void *buf, size_t count, uint32_t* id) { ++ sftp_session sftp = file->sftp; ++ ssh_buffer buffer; ++ int len; ++ int packetlen; ++ int rc; ++ ++ buffer = ssh_buffer_new(); ++ if (buffer == NULL) { ++ ssh_set_error_oom(sftp->session); ++ return -1; ++ } ++ ++ *id = sftp_get_new_id(file->sftp); ++ ++ rc = ssh_buffer_pack(buffer, ++ "dSqdP", ++ *id, ++ file->handle, ++ file->offset, ++ count, /* len of datastring */ ++ (size_t)count, buf); ++ if (rc != SSH_OK){ ++ ssh_set_error_oom(sftp->session); ++ ssh_buffer_free(buffer); ++ return SSH_ERROR; ++ } ++ packetlen=ssh_buffer_get_len(buffer)+5; ++ len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer); ++ ssh_buffer_free(buffer); ++ if (len < 0) { ++ return SSH_ERROR; ++ } else if (len != packetlen) { ++ ssh_set_error(sftp->session, SSH_FATAL, ++ "Could only send %d of %d bytes to remote host!", len, packetlen); ++ SSH_LOG(SSH_LOG_PACKET, ++ "Could not write as much data as expected"); ++ return SSH_ERROR; ++ } ++ ++ file->offset += count; ++ ++ return SSH_OK; ++} ++ ++int sftp_async_write_end(sftp_file file, uint32_t id, int blocking) { ++ sftp_session sftp = file->sftp; ++ sftp_message msg = NULL; ++ sftp_status_message status; ++ ++ msg = sftp_dequeue(sftp, id); ++ while (msg == NULL) { ++ if (!blocking && ssh_channel_poll(sftp->channel, 0) == 0) { ++ /* we cannot block */ ++ return SSH_AGAIN; ++ } ++ if (sftp_read_and_dispatch(sftp) < 0) { ++ /* something nasty has happened */ ++ return SSH_ERROR; ++ } ++ msg = sftp_dequeue(sftp, id); ++ } ++ ++ switch (msg->packet_type) { ++ case SSH_FXP_STATUS: ++ status = parse_status_msg(msg); ++ sftp_message_free(msg); ++ if (status == NULL) { ++ return SSH_ERROR; ++ } ++ sftp_set_error(sftp, status->status); ++ switch (status->status) { ++ case SSH_FX_OK: ++ status_msg_free(status); ++ return SSH_OK; ++ default: ++ break; ++ } ++ ssh_set_error(sftp->session, SSH_REQUEST_DENIED, ++ "SFTP server: %s", status->errormsg); ++ status_msg_free(status); ++ return SSH_ERROR; ++ default: ++ ssh_set_error(sftp->session, SSH_FATAL, ++ "Received message %d during write!", msg->packet_type); ++ sftp_message_free(msg); ++ return SSH_ERROR; ++ } ++ ++ return SSH_ERROR; /* not reached */ ++} ++ + /* Seek to a specific location in a file. */ + int sftp_seek(sftp_file file, uint32_t new_offset) { + if (file == NULL) { |