From b9f2b29e18c8b28fd97aecef4ceb74d070a067d1 Mon Sep 17 00:00:00 2001 From: laxy Date: Tue, 17 Dec 2024 10:02:21 +0800 Subject: [PATCH 01/15] fix: Fixed undeclared identifier 'ENXIO' in android --- lib/compat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compat.c b/lib/compat.c index 438e1790..b99606bb 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -181,6 +181,7 @@ int iop_connect(int sockfd, struct sockaddr *addr, socklen_t addrlen) #ifdef __ANDROID__ /* getlogin_r() was added in API 28 */ #if __ANDROID_API__ < 28 +#include #define NEED_GETLOGIN_R #define login_num ENXIO #endif From 3e0f7949c7db82ef427007d8de978fab02703a2f Mon Sep 17 00:00:00 2001 From: Thomas Guillem Date: Tue, 17 Dec 2024 08:18:03 +0100 Subject: [PATCH 02/15] cmake: add ENABLE_LIBKRB5 and ENABLE_GSSAPI options ON by default, but the user can now disable these components (like configure.ac). Fixes #384 --- CMakeLists.txt | 19 ++++++++++++++----- cmake/ConfigureChecks.cmake | 4 ++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0252451e..562b8e26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,14 +57,19 @@ endif() option(BUILD_SHARED_LIBS "Build shared libraries" ON) endif() option(ENABLE_EXAMPLES "Build example programs" OFF) - + option(ENABLE_LIBKRB5 "Enable libkrb5 support" ON) + option(ENABLE_GSSAPI "Enable gssapi support" ON) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules) endif() if(CMAKE_SYSTEM_NAME MATCHES Linux) - find_package(LibKrb5) + if (ENABLE_LIBKRB5) + find_package(LibKrb5) + endif() elseif(IOS) - find_package(GSSAPI) + if (ENABLE_GSSAPI) + find_package(GSSAPI) + endif() endif() if(NOT ESP_PLATFORM) @@ -95,9 +100,13 @@ endif() endif() if(CMAKE_SYSTEM_NAME MATCHES Linux) - set(core_DEPENDS ${LIBKRB5_LIBRARY} CACHE STRING "" FORCE) + if (ENABLE_LIBKRB5) + set(core_DEPENDS ${LIBKRB5_LIBRARY} CACHE STRING "" FORCE) + endif() elseif(IOS) - set(core_DEPENDS ${GSSAPI_LIBRARIES} CACHE STRING "" FORCE) + if (ENABLE_GSSAPI) + set(core_DEPENDS ${GSSAPI_LIBRARIES} CACHE STRING "" FORCE) + endif() endif() if(MSVC AND BUILD_SHARED_LIBS) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index a28846ad..d59d8905 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -6,8 +6,12 @@ endif() check_include_file("arpa/inet.h" HAVE_ARPA_INET_H) check_include_file("dlfcn.h" HAVE_DLFCN_H) check_include_file("fcntl.h" HAVE_FCNTL_H) +if (ENABLE_GSSAPI) check_include_file("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) +endif() +if (ENABLE_LIBKRB5) check_include_file("krb5/krb5.h" HAVE_LIBKRB5) +endif() check_include_file("inttypes.h" HAVE_INTTYPES_H) check_include_file("netdb.h" HAVE_NETDB_H) check_include_file("netinet/in.h" HAVE_NETINET_IN_H) From 6a161d055b099c709e59770e64d22350c20bc408 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 18 Dec 2024 16:15:16 +1000 Subject: [PATCH 03/15] opendir: don't dereference cb_data when in shutdown mode Signed-off-by: Ronnie Sahlberg --- include/smb2/smb2-errors.h | 2 +- lib/errors.c | 8 ++++---- lib/init.c | 6 +++--- lib/libsmb2.c | 3 ++- lib/sync.c | 3 +++ 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/smb2/smb2-errors.h b/include/smb2/smb2-errors.h index 921eb6f3..0c8c4449 100644 --- a/include/smb2/smb2-errors.h +++ b/include/smb2/smb2-errors.h @@ -34,7 +34,7 @@ /* Error codes */ #define SMB2_STATUS_SUCCESS 0x00000000 -#define SMB2_STATUS_ABORTED 0xffffffff +#define SMB2_STATUS_SHUTDOWN 0xffffffff #define SMB2_STATUS_PENDING 0x00000103 #define SMB2_STATUS_SMB_BAD_FID 0x00060001 #define SMB2_STATUS_NO_MORE_FILES 0x80000006 diff --git a/lib/errors.c b/lib/errors.c index 54434703..ca66eb69 100644 --- a/lib/errors.c +++ b/lib/errors.c @@ -46,8 +46,8 @@ const char *nterror_to_str(uint32_t status) { switch (status) { case SMB2_STATUS_SUCCESS: return "STATUS_SUCCESS"; - case SMB2_STATUS_ABORTED: - return "STATUS_ABORTED"; + case SMB2_STATUS_SHUTDOWN: + return "STATUS_SHUTDOWN"; case SMB2_STATUS_PENDING: return "STATUS_PENDING"; case SMB2_STATUS_NO_MORE_FILES: @@ -1072,8 +1072,8 @@ int nterror_to_errno(uint32_t status) { return 0; case SMB2_STATUS_PENDING: return EAGAIN; - case SMB2_STATUS_ABORTED: - return ECONNRESET; + case SMB2_STATUS_SHUTDOWN: + return -SMB2_STATUS_SHUTDOWN; case SMB2_STATUS_NO_SUCH_FILE: case SMB2_STATUS_NO_SUCH_DEVICE: case SMB2_STATUS_BAD_NETWORK_NAME: diff --git a/lib/init.c b/lib/init.c index bd7b13eb..8f4e32bf 100644 --- a/lib/init.c +++ b/lib/init.c @@ -329,7 +329,7 @@ void smb2_destroy_context(struct smb2_context *smb2) smb2->outqueue = pdu->next; if (pdu->cb) { - pdu->cb(smb2, SMB2_STATUS_CANCELLED, NULL, pdu->cb_data); + pdu->cb(smb2, SMB2_STATUS_SHUTDOWN, NULL, pdu->cb_data); } smb2_free_pdu(smb2, pdu); } @@ -337,7 +337,7 @@ void smb2_destroy_context(struct smb2_context *smb2) struct smb2_pdu *pdu = smb2->pdu; if (pdu->cb) { - pdu->cb(smb2, SMB2_STATUS_CANCELLED, NULL, pdu->cb_data); + pdu->cb(smb2, SMB2_STATUS_SHUTDOWN, NULL, pdu->cb_data); } smb2_free_pdu(smb2, smb2->pdu); } @@ -346,7 +346,7 @@ void smb2_destroy_context(struct smb2_context *smb2) smb2->waitqueue = pdu->next; if (pdu->cb) { - pdu->cb(smb2, SMB2_STATUS_CANCELLED, NULL, pdu->cb_data); + pdu->cb(smb2, SMB2_STATUS_SHUTDOWN, NULL, pdu->cb_data); } if (pdu == smb2->pdu) { smb2->pdu = NULL; diff --git a/lib/libsmb2.c b/lib/libsmb2.c index 06ee64ef..f841fcc8 100644 --- a/lib/libsmb2.c +++ b/lib/libsmb2.c @@ -350,7 +350,8 @@ od_close_cb(struct smb2_context *smb2, int status, struct smb2dir *dir = private_data; if (status != SMB2_STATUS_SUCCESS) { - dir->cb(smb2, -ENOMEM, NULL, dir->cb_data); + dir->cb(smb2, -nterror_to_errno(status), + NULL, dir->cb_data); free_smb2dir(smb2, dir); return; } diff --git a/lib/sync.c b/lib/sync.c index 1367758d..d1e33f9b 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -176,6 +176,9 @@ static void opendir_cb(struct smb2_context *smb2, int status, { struct sync_cb_data *cb_data = private_data; + if (status == SMB2_STATUS_SHUTDOWN) { + return; + } if (cb_data->status == SMB2_STATUS_CANCELLED) { return; } From ee2b57b13ae029f95061cea066c7047c364b56d4 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 19 Dec 2024 14:29:23 +1000 Subject: [PATCH 04/15] tests: add tests for smb2_open/_read/_write/_close Signed-off-by: Ronnie Sahlberg --- tests/test_0210_cp_basic.sh | 25 ++++++++++++++++++ tests/test_0211_cp_valgrind.sh | 26 ++++++++++++++++++ tests/test_0212_cp_valgrind_socket_error.sh | 29 +++++++++++++++++++++ tests/test_0401_cp_valgrind.sh | 20 -------------- 4 files changed, 80 insertions(+), 20 deletions(-) create mode 100755 tests/test_0210_cp_basic.sh create mode 100755 tests/test_0211_cp_valgrind.sh create mode 100755 tests/test_0212_cp_valgrind_socket_error.sh delete mode 100755 tests/test_0401_cp_valgrind.sh diff --git a/tests/test_0210_cp_basic.sh b/tests/test_0210_cp_basic.sh new file mode 100755 index 00000000..befabe25 --- /dev/null +++ b/tests/test_0210_cp_basic.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +. ./functions.sh + +echo "basic cp read/write test" + +echo -n "Testing cp to root of share ... " +rm testfile2 2>/dev/null +echo "HappyPenguins!" > testfile +../utils/smb2-cp testfile "${TESTURL}/testfile" > /dev/null || failure +success + +echo -n "Testing cp from root of share ... " +../utils/smb2-cp "${TESTURL}/testfile" testfile2 > /dev/null || failure +success + +echo -n "Verify file content match ... " +cmp testfile testfile2 || failure +success + +echo -n "Testing cp from a file that does not exist ... " +../utils/smb2-cp "${TESTURL}/testfile-not-exist" testfile2 2>/dev/null && failure +success + +exit 0 diff --git a/tests/test_0211_cp_valgrind.sh b/tests/test_0211_cp_valgrind.sh new file mode 100755 index 00000000..757b8fad --- /dev/null +++ b/tests/test_0211_cp_valgrind.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +. ./functions.sh + +echo "basic cp read/write test with valgrind" + +echo -n "Testing cp to root of share ... " +rm testfile2 2>/dev/null +echo "HappyPenguins!" > testfile +libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ../utils/smb2-cp testfile "${TESTURL}/testfile" >/dev/null 2>&1 || failure +success + +echo -n "Testing cp from root of share ... " +libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ../utils/smb2-cp "${TESTURL}/testfile" testfile2 >/dev/null 2>&1 || failure +success + +echo -n "Verify file content match ... " +cmp testfile testfile2 || failure +success + +echo -n "Testing cp from a file that does not exist ... " +libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ../utils/smb2-cp "${TESTURL}/testfile-not-exist" testfile2 >/dev/null 2>valgrind.out +expr $? "==" "77" >/dev/null && failure +success + +exit 0 diff --git a/tests/test_0212_cp_valgrind_socket_error.sh b/tests/test_0212_cp_valgrind_socket_error.sh new file mode 100755 index 00000000..73ba56ed --- /dev/null +++ b/tests/test_0212_cp_valgrind_socket_error.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +. ./functions.sh + +echo "basic cp read/write test with valgrind and socket errors" + +echo "Testing cp to root of share" +rm testfile2 2>/dev/null +echo "HappyPenguins!" > testfile +NUM_CALLS=`libtool --mode=execute strace ../utils/smb2-cp testfile "${TESTURL}/testfile" 2>&1 >/dev/null | grep readv |wc -l` + +for IDX in `seq 1 $NUM_CALLS`; do + echo -n "Testing cp to root of share with socket failure at #${IDX} ..." + READV_CLOSE=${IDX} LD_PRELOAD=./ld_sockerr.so libtool --mode=execute valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=77 ../utils/smb2-cp testfile "${TESTURL}/testfile" >/dev/null 2>valgrind.out + expr $? "==" "77" >/dev/null && failure + success +done + +echo "Testing cp from root of share" +NUM_CALLS=`libtool --mode=execute strace ../utils/smb2-cp "${TESTURL}/testfile" testfile 2>&1 >/dev/null | grep readv |wc -l` + +for IDX in `seq 1 $NUM_CALLS`; do + echo -n "Testing cp to root of share with socket failure at #${IDX} ..." + READV_CLOSE=${IDX} LD_PRELOAD=./ld_sockerr.so libtool --mode=execute valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=77 ../utils/smb2-cp "${TESTURL}/testfile" testfile >/dev/null 2>valgrind.out + expr $? "==" "77" >/dev/null && failure + success +done + +exit 0 diff --git a/tests/test_0401_cp_valgrind.sh b/tests/test_0401_cp_valgrind.sh deleted file mode 100755 index e03f82e9..00000000 --- a/tests/test_0401_cp_valgrind.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -. ./functions.sh - -echo "cp test with valgrind" - -echo -n "Copy a file to the root of the share ... " -libtool --mode=execute valgrind --leak-check=full --error-exitcode=1 ../utils/smb2-cp ./prog_cat.c "${TESTURL}/CAT" >/dev/null 2>&1 || failure -success - -echo -n "Copy a file from the root of the share ... " -rm foo.txt 2>/dev/null -libtool --mode=execute valgrind --leak-check=full --error-exitcode=1 ../utils/smb2-cp "${TESTURL}/CAT" foo.txt >/dev/null 2>&1 || failure -success - -echo -n "Verify file content match ... " -cmp prog_cat.c foo.txt || failure -success - -exit 0 From 3f5c3d5c15adcafef1228209fee9c626e0309f86 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 19 Dec 2024 14:29:49 +1000 Subject: [PATCH 05/15] Do not dereference data_cb during shutdown for smb2_close Signed-off-by: Ronnie Sahlberg --- lib/sync.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/sync.c b/lib/sync.c index d1e33f9b..74b79e3c 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -276,6 +276,9 @@ static void close_cb(struct smb2_context *smb2, int status, { struct sync_cb_data *cb_data = private_data; + if (status == SMB2_STATUS_SHUTDOWN) { + return; + } if (cb_data->status == SMB2_STATUS_CANCELLED) { free(cb_data); return; From aaa619337853dd256022249d79a9c100f08650fc Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 20 Dec 2024 04:25:44 +1000 Subject: [PATCH 06/15] tests: use prog_ls instead of smb2-ls Signed-off-by: Ronnie Sahlberg --- tests/Makefile.am | 2 +- tests/prog_ls.c | 135 +++++++++++++++++++++++ tests/test_0100_ls_basic.sh | 6 +- tests/test_0101_ls_basic_valgrind.sh | 6 +- tests/test_0102_ls_basic_socket_error.sh | 4 +- 5 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 tests/prog_ls.c diff --git a/tests/Makefile.am b/tests/Makefile.am index fff6e731..f951c984 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = -I${srcdir}/../include -I${srcdir}/../include/smb2 \ AM_CFLAGS = $(WARN_CFLAGS) LDADD = ../lib/libsmb2.la -noinst_PROGRAMS = prog_mkdir prog_rmdir prog_cat \ +noinst_PROGRAMS = prog_ls prog_mkdir prog_rmdir prog_cat \ smb2-dcerpc-coder-test EXTRA_PROGRAMS = ld_sockerr diff --git a/tests/prog_ls.c b/tests/prog_ls.c new file mode 100644 index 00000000..e951575a --- /dev/null +++ b/tests/prog_ls.c @@ -0,0 +1,135 @@ +/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ +/* + Copyright (C) 2016 by Ronnie Sahlberg + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) +#include +#endif +#include +#include +#include +#include +#include + +#include "smb2.h" +#include "libsmb2.h" +#include "libsmb2-raw.h" + +#ifdef __AROS__ +#include "asprintf.h" +#endif + +int usage(void) +{ + fprintf(stderr, "Usage:\n" + "smb2-ls-sync \n\n" + "URL format: " + "smb://[@][:]//\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + struct smb2_context *smb2; + struct smb2_url *url; + struct smb2dir *dir; + struct smb2dirent *ent; + char *link; + int rc = 1; + + if (argc < 2) { + usage(); + } + + smb2 = smb2_init_context(); + if (smb2 == NULL) { + fprintf(stderr, "Failed to init context\n"); + exit(1); + } + + url = smb2_parse_url(smb2, argv[1]); + if (url == NULL) { + fprintf(stderr, "Failed to parse url: %s\n", + smb2_get_error(smb2)); + exit(1); + } + + smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED); + if (smb2_connect_share(smb2, url->server, url->share, url->user) < 0) { + printf("smb2_connect_share failed. %s\n", smb2_get_error(smb2)); + goto out_context; + } + + dir = smb2_opendir(smb2, url->path); + if (dir == NULL) { + printf("smb2_opendir failed. %s\n", smb2_get_error(smb2)); + goto out_disconnect; + } + + while ((ent = smb2_readdir(smb2, dir))) { + char *type; + time_t t; + + t = (time_t)ent->st.smb2_mtime; + switch (ent->st.smb2_type) { + case SMB2_TYPE_LINK: + type = "LINK"; + break; + case SMB2_TYPE_FILE: + type = "FILE"; + break; + case SMB2_TYPE_DIRECTORY: + type = "DIRECTORY"; + break; + default: + type = "unknown"; + break; + } + printf("%-20s %-9s %15"PRIu64" %s", ent->name, type, ent->st.smb2_size, asctime(localtime(&t))); + if (ent->st.smb2_type == SMB2_TYPE_LINK) { + char buf[256]; + + if (url->path && url->path[0]) { + if (asprintf(&link, "%s/%s", url->path, ent->name) < 0) { + printf("asprintf failed\n"); + goto out_disconnect; + } + } else { + if (asprintf(&link, "%s", ent->name) < 0) { + printf("asprintf failed\n"); + goto out_disconnect; + } + } + if (smb2_readlink(smb2, link, buf, 256) == 0) { + printf(" -> [%s]\n", buf); + } else { + printf(" readlink failed\n"); + } + free(link); + } + } + + rc = 0; + smb2_closedir(smb2, dir); + out_disconnect: + smb2_disconnect_share(smb2); + out_context: + smb2_destroy_url(url); + smb2_destroy_context(smb2); + + return rc; +} diff --git a/tests/test_0100_ls_basic.sh b/tests/test_0100_ls_basic.sh index 223462c4..4ad6969f 100755 --- a/tests/test_0100_ls_basic.sh +++ b/tests/test_0100_ls_basic.sh @@ -5,17 +5,17 @@ echo "basic ls test" echo -n "Testing prog_ls on root of share ... " -../utils/smb2-ls "${TESTURL}/" > /dev/null || failure +./prog_ls "${TESTURL}/" > /dev/null || failure success echo -n "Testing prog_ls on a directory that does not exist ... " ./prog_rmdir "${TESTURL}/testdir" > /dev/null -../utils/smb2-ls "${TESTURL}/testdir" >/dev/null && failure +./prog_ls "${TESTURL}/testdir" >/dev/null && failure success echo -n "Testing prog_ls on a directory that does exist ... " ./prog_mkdir "${TESTURL}/testdir" > /dev/null -../utils/smb2-ls "${TESTURL}/testdir" >/dev/null || failure +./prog_ls "${TESTURL}/testdir" >/dev/null || failure ./prog_rmdir "${TESTURL}/testdir" > /dev/null success diff --git a/tests/test_0101_ls_basic_valgrind.sh b/tests/test_0101_ls_basic_valgrind.sh index 4ec6dbb4..be58649b 100755 --- a/tests/test_0101_ls_basic_valgrind.sh +++ b/tests/test_0101_ls_basic_valgrind.sh @@ -5,18 +5,18 @@ echo "basic ls test with valgrind" echo -n "Testing prog_ls on root of share ... " -libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ../utils/smb2-ls "${TESTURL}/" >/dev/null 2>&1 || failure +libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ./prog_ls "${TESTURL}/" >/dev/null 2>&1 || failure success echo -n "Testing prog_ls on a directory that does not exist ... " ./prog_rmdir "${TESTURL}/testdir" > /dev/null -libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ../utils/smb2-ls "${TESTURL}/testdir" >/dev/null 2>&1 +libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ./prog_ls "${TESTURL}/testdir" >/dev/null 2>&1 expr $? "==" "77" >/dev/null && failure success echo -n "Testing prog_ls on a directory that does exist ... " ./prog_mkdir "${TESTURL}/testdir" > /dev/null -libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ../utils/smb2-ls "${TESTURL}/testdir" >/dev/null 2>&1 || failure +libtool --mode=execute valgrind --leak-check=full --error-exitcode=77 ./prog_ls "${TESTURL}/testdir" >/dev/null 2>&1 || failure ./prog_rmdir "${TESTURL}/testdir" > /dev/null success diff --git a/tests/test_0102_ls_basic_socket_error.sh b/tests/test_0102_ls_basic_socket_error.sh index 67ee8fc8..f1339e72 100755 --- a/tests/test_0102_ls_basic_socket_error.sh +++ b/tests/test_0102_ls_basic_socket_error.sh @@ -4,11 +4,11 @@ echo "basic ls test with valgrind and session errors" -NUM_CALLS=`libtool --mode=execute strace ../utils/smb2-ls "${TESTURL}/" 2>&1 >/dev/null | grep readv |wc -l` +NUM_CALLS=`libtool --mode=execute strace ./prog_ls "${TESTURL}/" 2>&1 >/dev/null | grep readv |wc -l` for IDX in `seq 1 $NUM_CALLS`; do echo -n "Testing prog_ls on root of share with socket failure at #${IDX} ..." - READV_CLOSE=${IDX} LD_PRELOAD=./ld_sockerr.so libtool --mode=execute valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=77 ../utils/smb2-ls "${TESTURL}/" >/dev/null 2>valgrind.out + READV_CLOSE=${IDX} LD_PRELOAD=./ld_sockerr.so libtool --mode=execute valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=77 ./prog_ls "${TESTURL}/" >/dev/null 2>valgrind.out expr $? "==" "77" >/dev/null && failure success done From c58a6eb540653319e981b337815f138b214e6c27 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 20 Dec 2024 06:13:31 +1000 Subject: [PATCH 07/15] wip cause malloc to fail Signed-off-by: Ronnie Sahlberg --- tests/prog_ls.c | 47 +++++++++++++++++-- ...est_0103_ls_basic_valgrind_malloc_error.sh | 20 ++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) create mode 100755 tests/test_0103_ls_basic_valgrind_malloc_error.sh diff --git a/tests/prog_ls.c b/tests/prog_ls.c index e951575a..80a5bafc 100644 --- a/tests/prog_ls.c +++ b/tests/prog_ls.c @@ -29,9 +29,37 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include "libsmb2.h" #include "libsmb2-raw.h" -#ifdef __AROS__ -#include "asprintf.h" -#endif +#include +#include + +int alloc_fail = -1; + +void *(*real_malloc)(size_t size); +void *(*real_calloc)(size_t nelem, size_t size); + +void *malloc(size_t size) +{ + static int call_idx = 0; + + call_idx++; + + if (call_idx == alloc_fail) { + return NULL; + } + return real_malloc(size); +} + +void *calloc(size_t nelem, size_t size) +{ + static int call_idx = 0; + + call_idx++; + + if (call_idx == alloc_fail) { + return NULL; + } + return real_calloc(nelem, size); +} int usage(void) { @@ -51,6 +79,19 @@ int main(int argc, char *argv[]) char *link; int rc = 1; + if (getenv("ALLOC_FAIL") != NULL) { + alloc_fail = atoi(getenv("ALLOC_FAIL")); + } + /* https://bugzilla.redhat.com/show_bug.cgi?id=2333389 */ + //if (alloc_fail == 1) { + // alloc_fail = -1; + //} + + real_malloc = dlsym(RTLD_NEXT, "malloc"); + real_calloc = dlsym(RTLD_NEXT, "calloc"); + + printf("Alloc fail at %d\n", alloc_fail); + if (argc < 2) { usage(); } diff --git a/tests/test_0103_ls_basic_valgrind_malloc_error.sh b/tests/test_0103_ls_basic_valgrind_malloc_error.sh new file mode 100755 index 00000000..783b009c --- /dev/null +++ b/tests/test_0103_ls_basic_valgrind_malloc_error.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +. ./functions.sh + +echo "basic ls test with valgrind and [c|m]alloc errors" + +echo libtool --mode=execute ltrace -l \* ./prog_ls "${TESTURL}/" +NUM_CALLS=`libtool --mode=execute ltrace -l \* ./prog_ls "${TESTURL}/" 2>&1 >/dev/null | grep "[c|m]alloc" |wc -l` +echo "Num" $NUM_CALLS + +for IDX in `seq 1 $NUM_CALLS`; do + echo -n "Testing prog_ls on root of share with socket failure at #${IDX} ..." + #ALLOC_FAIL=${IDX} libtool --mode=execute valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=77 ./prog_ls "${TESTURL}/" # >/dev/null 2>valgrind.out + #expr $? "==" "77" >/dev/null && failure + ALLOC_FAIL=${IDX} ./prog_ls "${TESTURL}/" # >/dev/null 2>valgrind.out + echo $? + success +done + +exit 0 From 5518394f90dbf31d48891cbbce0d0fc56d8b7488 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 20 Dec 2024 06:18:43 +1000 Subject: [PATCH 08/15] fix segv in smb2_set_password_from_file if smb2->user==NULL Signed-off-by: Ronnie Sahlberg --- lib/init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/init.c b/lib/init.c index 8f4e32bf..8aa98829 100644 --- a/lib/init.c +++ b/lib/init.c @@ -545,7 +545,10 @@ void smb2_set_password_from_file(struct smb2_context *smb2) #else name = getenv("NTLM_USER_FILE"); #endif - if (name == NULL) { + if (name == NULL || smb2->user == NULL) { +#ifdef _MSC_UWP + free(name); +#endif return; } fh = fopen(name, "r"); From 180bc38b1f03aa1358c3d22cada168cb66d501b8 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 20 Dec 2024 06:27:00 +1000 Subject: [PATCH 09/15] check result of strdup when connecting share Signed-off-by: Ronnie Sahlberg --- lib/libsmb2.c | 6 ++++++ tests/test_0103_ls_basic_valgrind_malloc_error.sh | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/libsmb2.c b/lib/libsmb2.c index f841fcc8..bfcc8568 100644 --- a/lib/libsmb2.c +++ b/lib/libsmb2.c @@ -1046,11 +1046,17 @@ smb2_connect_share_async(struct smb2_context *smb2, return -EINVAL; } smb2->server = strdup(server); + if (smb2->server == NULL) { + return -ENOMEM; + } if (smb2->share) { free(discard_const(smb2->share)); } smb2->share = strdup(share); + if (smb2->share == NULL) { + return -ENOMEM; + } if (user) { smb2_set_user(smb2, user); diff --git a/tests/test_0103_ls_basic_valgrind_malloc_error.sh b/tests/test_0103_ls_basic_valgrind_malloc_error.sh index 783b009c..5ce875c8 100755 --- a/tests/test_0103_ls_basic_valgrind_malloc_error.sh +++ b/tests/test_0103_ls_basic_valgrind_malloc_error.sh @@ -12,7 +12,7 @@ for IDX in `seq 1 $NUM_CALLS`; do echo -n "Testing prog_ls on root of share with socket failure at #${IDX} ..." #ALLOC_FAIL=${IDX} libtool --mode=execute valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=77 ./prog_ls "${TESTURL}/" # >/dev/null 2>valgrind.out #expr $? "==" "77" >/dev/null && failure - ALLOC_FAIL=${IDX} ./prog_ls "${TESTURL}/" # >/dev/null 2>valgrind.out + ALLOC_FAIL=${IDX} ./prog_ls "${TESTURL}/" 2>&1 # >/dev/null 2>valgrind.out echo $? success done From 8954af99a0b10b8812ac79d74a69aa7d6dccfacd Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 20 Dec 2024 06:34:37 +1000 Subject: [PATCH 10/15] verify we have a share name when connecting a share Signed-off-by: Ronnie Sahlberg --- lib/libsmb2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/libsmb2.c b/lib/libsmb2.c index bfcc8568..928af5d2 100644 --- a/lib/libsmb2.c +++ b/lib/libsmb2.c @@ -1045,6 +1045,10 @@ smb2_connect_share_async(struct smb2_context *smb2, smb2_set_error(smb2, "No server name provided"); return -EINVAL; } + if (share == NULL) { + smb2_set_error(smb2, "No share name provided"); + return -EINVAL; + } smb2->server = strdup(server); if (smb2->server == NULL) { return -ENOMEM; From 80347b382bafa8b20c5e688f637108d315cce99f Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 20 Dec 2024 06:44:03 +1000 Subject: [PATCH 11/15] ensure we have a username when connecting a share Signed-off-by: Ronnie Sahlberg --- lib/libsmb2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/libsmb2.c b/lib/libsmb2.c index 928af5d2..606d7674 100644 --- a/lib/libsmb2.c +++ b/lib/libsmb2.c @@ -1082,6 +1082,10 @@ smb2_connect_share_async(struct smb2_context *smb2, smb2_set_error(smb2, "Failed to strdup(share)"); return -ENOMEM; } + if (smb2->user == NULL) { + smb2_set_error(smb2, "smb2->user is NULL"); + return -ENOMEM; + } c_data->user = strdup(smb2->user); if (c_data->user == NULL) { free_c_data(smb2, c_data); From b074bf8ab71aa75e165217cbfa513e5c126fbf2b Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 21 Dec 2024 01:33:49 +1000 Subject: [PATCH 12/15] fix aditional null pointers due to malloc failures Signed-off-by: Ronnie Sahlberg --- lib/ntlmssp.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/ntlmssp.c b/lib/ntlmssp.c index 91d38533..d309362d 100644 --- a/lib/ntlmssp.c +++ b/lib/ntlmssp.c @@ -169,17 +169,32 @@ ntlmssp_init_context(const char *user, if (user) { auth_data->user = strdup(user); + if (auth_data->user == NULL) { + goto failed; + } } if (password) { auth_data->password = strdup(password); + if (auth_data->password == NULL) { + goto failed; + } } if (domain) { auth_data->domain = strdup(domain); + if (auth_data->domain == NULL) { + goto failed; + } } if (workstation) { auth_data->workstation = strdup(workstation); + if (auth_data->workstation == NULL) { + goto failed; + } } auth_data->client_challenge = malloc(8); + if (auth_data->client_challenge == NULL) { + goto failed; + } memcpy(auth_data->client_challenge, client_challenge, 8); auth_data->is_authenticated = 0; memset(auth_data->exported_session_key, 0, SMB2_KEY_SIZE); @@ -188,6 +203,13 @@ ntlmssp_init_context(const char *user, auth_data->wintime = smb2_timeval_to_win(&tv); return auth_data; + failed: + free(auth_data->user); + free(auth_data->password); + free(auth_data->domain); + free(auth_data->workstation); + free(auth_data->client_challenge); + return NULL; } void @@ -226,6 +248,9 @@ encoder(const void *buffer, size_t size, void *ptr) free(tmp); } + if (auth_data->buf == NULL) { + return -1; + } memcpy(auth_data->buf + auth_data->len, buffer, size); auth_data->len += size; @@ -353,6 +378,10 @@ NTOWFv2(const char *user, const char *password, const char *domain, struct smb2_utf16 *utf16_userdomain = NULL; unsigned char ntlm_hash[16]; + if (user == NULL || password == NULL) { + return -1; + } + /* ntlm:F638EDF864C4805DC65D9BF2BB77E4C0 */ if ((strlen(password) == 37) && (strncmp(password, "ntlm:", 5) == 0)) { if (ntlm_convert_password_hash(password + 5, ntlm_hash) < 0) { From b0f456d61c08898fa92fd819449c3cc7c0ef2158 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 21 Dec 2024 02:21:20 +1000 Subject: [PATCH 13/15] cleanup test_0103 This test will be the blueprint for all additional tests of this type. Check if the application crashes and terminates by a signal or if there are memory leaks when malloc fails. Signed-off-by: Ronnie Sahlberg --- tests/test_0103_ls_basic_valgrind_malloc_error.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/test_0103_ls_basic_valgrind_malloc_error.sh b/tests/test_0103_ls_basic_valgrind_malloc_error.sh index 5ce875c8..ef5fa10a 100755 --- a/tests/test_0103_ls_basic_valgrind_malloc_error.sh +++ b/tests/test_0103_ls_basic_valgrind_malloc_error.sh @@ -9,11 +9,16 @@ NUM_CALLS=`libtool --mode=execute ltrace -l \* ./prog_ls "${TESTURL}/" 2>&1 >/de echo "Num" $NUM_CALLS for IDX in `seq 1 $NUM_CALLS`; do - echo -n "Testing prog_ls on root of share with socket failure at #${IDX} ..." - #ALLOC_FAIL=${IDX} libtool --mode=execute valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=77 ./prog_ls "${TESTURL}/" # >/dev/null 2>valgrind.out - #expr $? "==" "77" >/dev/null && failure - ALLOC_FAIL=${IDX} ./prog_ls "${TESTURL}/" 2>&1 # >/dev/null 2>valgrind.out - echo $? + # check for failing due to a signal (segv/abrt/...) + echo -n "Testing prog_ls for crashes at #${IDX} ..." + ALLOC_FAIL=${IDX} ./prog_ls "${TESTURL}/" 2>&1 >/dev/null 2>valgrind.out + expr $? ">=" "128" >/dev/null && failure + success + + # check for memory leaks in error paths + echo -n "Testing prog_ls for memory leaks at #${IDX} ..." + ALLOC_FAIL=${IDX} libtool --mode=execute valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=77 ./prog_ls "${TESTURL}/" >/dev/null 2>valgrind.out + expr $? "==" "77" >/dev/null && failure success done From 9f86f288df5858d8fad5a67dad69262146033b52 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 21 Dec 2024 02:25:05 +1000 Subject: [PATCH 14/15] tests: exclude known failures for prog_ls crashes Signed-off-by: Ronnie Sahlberg --- tests/prog_ls.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/prog_ls.c b/tests/prog_ls.c index 80a5bafc..5cdcd5d1 100644 --- a/tests/prog_ls.c +++ b/tests/prog_ls.c @@ -83,9 +83,13 @@ int main(int argc, char *argv[]) alloc_fail = atoi(getenv("ALLOC_FAIL")); } /* https://bugzilla.redhat.com/show_bug.cgi?id=2333389 */ - //if (alloc_fail == 1) { - // alloc_fail = -1; - //} + /* skip these test as they are known failures and have been reported */ + if (alloc_fail == 2) { + alloc_fail = -1; + } + if (alloc_fail == 18) { + alloc_fail = -1; + } real_malloc = dlsym(RTLD_NEXT, "malloc"); real_calloc = dlsym(RTLD_NEXT, "calloc"); From 2a5e83ae4b78905249849e3ef0e0aaafa65d2cec Mon Sep 17 00:00:00 2001 From: briandodge Date: Mon, 11 Nov 2024 07:11:26 -0500 Subject: [PATCH 15/15] add krb5 cred handle passing and release mechanism for proxying --- include/libsmb2-private.h | 13 +++++++++++-- include/smb2/libsmb2.h | 23 ++++++++++++++++++++++ lib/init.c | 41 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/include/libsmb2-private.h b/include/libsmb2-private.h index 99d35332..8b51ada9 100644 --- a/include/libsmb2-private.h +++ b/include/libsmb2-private.h @@ -23,6 +23,10 @@ extern "C" { #endif +#ifdef HAVE_LIBKRB5 +#include "krb5-wrapper.h" +#endif + #define MIN(a,b) (((a)<(b))?(a):(b)) #ifndef discard_const @@ -121,7 +125,7 @@ struct sync_cb_data { int status; void *ptr; }; - + struct smb2_context { t_socket fd; @@ -181,6 +185,11 @@ struct smb2_context { uint16_t cypher; uint8_t preauthhash[SMB2_PREAUTH_HASH_SIZE]; + +#ifdef HAVE_LIBKRB5 + /* for delegation of client creds to proxy-client */ + gss_cred_id_t cred_handle; +#endif /* * For handling received smb3 encrypted blobs */ @@ -286,7 +295,7 @@ struct smb2_pdu { /* pointer to the unmarshalled payload in a reply */ void *payload; - + /* callback that frees the any additional memory allocated in the payload. * Or null if no additional memory needs to be freed. */ diff --git a/include/smb2/libsmb2.h b/include/smb2/libsmb2.h index c96e040d..51a62704 100644 --- a/include/smb2/libsmb2.h +++ b/include/smb2/libsmb2.h @@ -369,6 +369,13 @@ void smb2_set_authentication(struct smb2_context *smb2, int val); * Default is to try to authenticate as the current user. */ void smb2_set_user(struct smb2_context *smb2, const char *user); + +/* + * Get the username associated with a context. + * returns NULL if none + */ +const char *smb2_get_user(struct smb2_context *smb2); + /* * Set the password that we will try to authenticate as. * This function is only needed when libsmb2 is built --without-libkrb5 @@ -417,6 +424,12 @@ void smb2_set_password_from_file(struct smb2_context *smb2); * This function is only needed when libsmb2 is built --without-libkrb5 */ void smb2_set_domain(struct smb2_context *smb2, const char *domain); + +/* + * Get the domain associated with a context. + * returns NULL if none + */ +const char *smb2_get_domain(struct smb2_context *smb2); /* * Set the workstation when authenticating. * This function is only needed when libsmb2 is built --without-libkrb5 @@ -434,6 +447,13 @@ void smb2_set_opaque(struct smb2_context *smb2, void *opaque); */ void *smb2_get_opaque(struct smb2_context *smb2); +/* + * copy credential handle from one context to another (and set + * it NULL in source context) + * returns 0 if handle transferred, + * or -1 if not (no handle or no context, or not applicable) + */ +int smb2_delegate_credentials(struct smb2_context *in, struct smb2_context *out); /* * Sets the client_guid for this context. @@ -1278,6 +1298,9 @@ struct smb2_server { uint32_t max_write_size; int signing_enabled; int allow_anonymous; + /* this can be set non-0 to delegate client authentication to + * another client and allow any authentication to this server */ + int proxy_authentication; /* saved from negotiate to be used in validate negotiate info */ uint32_t capabilities; uint32_t security_mode; diff --git a/lib/init.c b/lib/init.c index 8aa98829..96d86383 100644 --- a/lib/init.c +++ b/lib/init.c @@ -378,6 +378,13 @@ void smb2_destroy_context(struct smb2_context *smb2) free(discard_const(smb2->workstation)); free(smb2->enc); +#ifdef HAVE_LIBKRB5 + if (smb2->cred_handle) { + OM_uint32 min; + (void) gss_release_cred(&min, &smb2->cred_handle); + smb2->cred_handle = NULL; + } +#endif if (smb2->connect_data) { free_c_data(smb2, smb2->connect_data); /* sets smb2->connect_data to NULL */ } @@ -617,6 +624,14 @@ void smb2_set_user(struct smb2_context *smb2, const char *user) #endif } +const char *smb2_get_user(struct smb2_context *smb2) +{ + if (smb2 && smb2->user) { + return smb2->user; + } + return NULL; +} + void smb2_set_password(struct smb2_context *smb2, const char *password) { if (smb2->password) { @@ -637,6 +652,14 @@ void smb2_set_domain(struct smb2_context *smb2, const char *domain) smb2->domain = strdup(domain); } +const char *smb2_get_domain(struct smb2_context *smb2) +{ + if (smb2 && smb2->domain) { + return smb2->domain; + } + return NULL; +} + void smb2_set_workstation(struct smb2_context *smb2, const char *workstation) { if (smb2->workstation) { @@ -706,3 +729,21 @@ void smb2_set_oplock_or_lease_break_callback(struct smb2_context *smb2, smb2->oplock_or_lease_break_cb = cb; } +#ifdef HAVE_LIBKRB5 +int smb2_delegate_credentials(struct smb2_context *in, struct smb2_context *out) +{ + if (in && out && in->cred_handle) { + out->cred_handle = in->cred_handle; + in->cred_handle = NULL; + return 0; + } else { + return -1; + } +} +#else +int smb2_delegate_credentials(struct smb2_context *in, struct smb2_context *out) +{ + return -1; +} +#endif +