libsmb2-6.2/0000775000175000017500000000000014732155517012017 5ustar polpypolpylibsmb2-6.2/packaging/0000775000175000017500000000000014732155517013743 5ustar polpypolpylibsmb2-6.2/packaging/RPM/0000775000175000017500000000000014732155517014401 5ustar polpypolpylibsmb2-6.2/packaging/RPM/libsmb2.spec.in0000664000175000017500000000637214732155517017224 0ustar polpypolpyName: libsmb2 Summary: SMB2/3 client library Vendor: Ronnie Sahlberg Packager: ronniesahlberg@gmail.com Version: @VERSION@ Release: 1 Epoch: 0 License: GNU LGPL version 2.1 Group: System Environment/Libraries URL: http://www.github.com/sahlberg/libsmb2 Source: libsmb2-%{version}.tar.gz Provides: lib = %{version} Prefix: /usr BuildRoot: %{_tmppath}/%{name}-%{version}-root %description Libsmb2 is a SMB2/3 client library ####################################################################### %prep %setup -q # setup the init script and sysconfig file %setup -T -D -n libsmb2-%{version} -q %build ## check for ccache if ccache -h >/dev/null 2>&1 ; then CC="ccache gcc" else CC="gcc" fi export CC ## always run autogen.sh aclocal autoheader autoconf libtoolize -c -f -i automake --add-missing CFLAGS="$RPM_OPT_FLAGS $EXTRA -O2 -D_GNU_SOURCE" %configure %install # Clean up in case there is trash left from a previous build rm -rf $RPM_BUILD_ROOT # Create the target build directory hierarchy make DESTDIR=$RPM_BUILD_ROOT install # Remove "*.old" files find $RPM_BUILD_ROOT -name "*.old" -exec rm -f {} \; %clean rm -rf $RPM_BUILD_ROOT ####################################################################### ## Files section ## ####################################################################### %files %defattr(-,root,root) %{_libdir}/libsmb2.so* %package devel Summary: Development libraries for LibSMB2 Group: Development %description devel development libraries for LibSMB2 %files devel %defattr(-,root,root) %{_includedir}/smb2/libsmb2.h %{_includedir}/smb2/libsmb2-raw.h %{_includedir}/smb2/libsmb2-dcerpc.h %{_includedir}/smb2/libsmb2-dcerpc-lsa.h %{_includedir}/smb2/libsmb2-dcerpc-srvsvc.h %{_includedir}/smb2/smb2.h %{_includedir}/smb2/smb2-errors.h %{_libdir}/libsmb2.a %{_libdir}/pkgconfig/libsmb2.pc %changelog * Mon Dec 16 2024 : Version 6.1.0 - Fix return code for smb2-ls on failure - Fix memory errors in smb2_opendir() - Add a macro te test for the version of the share-enum api * Wed Dec 11 2024 : Version 6.0.0 - Major rewrites to DCE-RPC - Initial support for building servers * Mon Jan 17 2022 : Version 4.0.0 - Add support for SMB3 encryption - Add support for Anonymous NTLMSSP logins - Add support for readlink. - Add API to notify application of changes to which filehandles are used by libsmb2. - Add support for Big Endian DCERPC and allow it to be controlled from the URL. - Add support for 3.1.1 signing - Add support for PS2(EE) and PS3 - Fixes to UCS2 when compose characters are used. - Various MacOS fixes - Fix a few NULL dereferences * Mon Jun 10 2019 : Version 3.0.0 - ESP32 support - Support specifying the port number in an SMB URL. - Add creation time to smb_stat - Abort all commands when the context is destroyed. - Free all file and directory handles when the context is destroyed. - Fix handling of O_TRUNC - Add more error codes. - Add support for SMB2_IOCTL - Handle DCE/RPC fragment reassembly for IOCTL(). * Sat Jul 7 2018 : Version 2.0.0 - SMB2/3 signing - Kerberos authentication - Builtin NTLMSSP authentication for when libkrb5 is not available - Share enumeration - CMake support - Various bugfixes * Sun Mar 5 2017 : Version 1.0.0 - Initial version libsmb2-6.2/packaging/RPM/makerpms.sh0000775000175000017500000000572614732155517016571 0ustar polpypolpy#!/bin/sh # # makerpms.sh - build RPM packages from the git sources # # Copyright (C) John H Terpstra 1998-2002 # Copyright (C) Gerald (Jerry) Carter 2003 # Copyright (C) Jim McDonough 2007 # Copyright (C) Andrew Tridgell 2007 # Copyright (C) Michael Adam 2008-2009 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 3 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, see . # # # The following allows environment variables to override the target directories # the alternative is to have a file in your home directory called .rpmmacros # containing the following: # %_topdir /home/mylogin/redhat # # Note: Under this directory rpm expects to find the same directories that are under the # /usr/src/redhat directory # EXTRA_OPTIONS="$1" DIRNAME=$(dirname $0) TOPDIR=${DIRNAME}/../.. SPECDIR=`rpm --eval %_specdir` SRCDIR=`rpm --eval %_sourcedir` SPECFILE="libsmb2.spec" SPECFILE_IN="libsmb2.spec.in" RPMBUILD="rpmbuild" # We use tags and determine the version, as follows: # libsmb2-0.9.1 (First release of 0.9). # libsmb2-0.9.23 (23rd minor release of the 112 version) # # If we're not directly on a tag, this is a devel release; we append # .0...devel to the release. TAG=`git describe` case "$TAG" in libsmb2-*) TAG=${TAG##libsmb2-} case "$TAG" in *-*-g*) # 0.9-168-ge6cf0e8 # Not exactly on tag: devel version. VERSION=`echo "$TAG" | sed 's/\([^-]\+\)-\([0-9]\+\)-\(g[0-9a-f]\+\)/\1.0.\2.\3.devel/'` ;; *) # An actual release version VERSION=$TAG ;; esac ;; *) echo Invalid tag "$TAG" >&2 exit 1 ;; esac sed -e s/@VERSION@/$VERSION/g \ < ${DIRNAME}/${SPECFILE_IN} \ > ${DIRNAME}/${SPECFILE} VERSION=$(grep ^Version ${DIRNAME}/${SPECFILE} | sed -e 's/^Version:\ \+//') if echo | gzip -c --rsyncable - > /dev/null 2>&1 ; then GZIP="gzip -9 --rsyncable" else GZIP="gzip -9" fi pushd ${TOPDIR} echo -n "Creating libsmb2-${VERSION}.tar.gz ... " mkdir -p "${SRCDIR}" git archive --prefix=libsmb2-${VERSION}/ HEAD | ${GZIP} > ${SRCDIR}/libsmb2-${VERSION}.tar.gz RC=$? popd echo "Done." if [ $RC -ne 0 ]; then echo "Build failed!" exit 1 fi # At this point the SPECDIR and SRCDIR variables must have a value! ## ## copy additional source files ## mkdir -p ${SPECDIR} cp -p ${DIRNAME}/${SPECFILE} ${SPECDIR} ## ## Build ## echo "$(basename $0): Getting Ready to build release package" ${RPMBUILD} -ba --clean --rmsource ${EXTRA_OPTIONS} ${SPECDIR}/${SPECFILE} || exit 1 echo "$(basename $0): Done." exit 0 libsmb2-6.2/utils/0000775000175000017500000000000014732155517013157 5ustar polpypolpylibsmb2-6.2/utils/smb2-cp.c0000664000175000017500000001433514732155517014574 0ustar polpypolpy/* Copyright (C) by Ronnie Sahlberg 2024 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #define _FILE_OFFSET_BITS 64 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) #include #endif #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #ifdef __AROS__ #include "asprintf.h" #endif struct file_context { int is_smb2; int fd; struct smb2_context *smb2; struct smb2fh *smb2fh; struct smb2_url *url; }; void usage(void) { fprintf(stderr, "Usage: smb2-cp \n"); fprintf(stderr, ", can either be a local file or " "an smb2 URL.\n"); exit(0); } static void free_file_context(struct file_context *file_context) { if (file_context->fd != -1) { close(file_context->fd); } if (file_context->smb2fh != NULL) { smb2_close(file_context->smb2, file_context->smb2fh); } if (file_context->smb2 != NULL) { smb2_destroy_context(file_context->smb2); } smb2_destroy_url(file_context->url); free(file_context); } static int fstat_file(struct file_context *fc, struct stat *st) { if (fc->is_smb2 == 0) { return fstat(fc->fd, st); } else { int res; struct smb2_stat_64 smb2_st; res = smb2_fstat(fc->smb2, fc->smb2fh, &smb2_st); st->st_dev = 0; st->st_ino = (ino_t)smb2_st.smb2_ino; #ifndef WIN32 st->st_mode = 0; st->st_nlink = (nlink_t)smb2_st.smb2_nlink; st->st_blksize = 4096; st->st_blocks = (smb2_st.smb2_size + 4096 - 1) % 4096; #endif st->st_uid = 0; st->st_gid = 0; st->st_rdev = 0; st->st_size = (off_t)smb2_st.smb2_size; st->st_atime = smb2_st.smb2_atime; st->st_mtime = smb2_st.smb2_mtime; st->st_ctime = smb2_st.smb2_ctime; return res; } } static ssize_t file_pread(struct file_context *fc, uint8_t *buf, size_t count, off_t off) { if (fc->is_smb2 == 0) { lseek(fc->fd, off, SEEK_SET); return read(fc->fd, buf, count); } else { return smb2_pread(fc->smb2, fc->smb2fh, buf, count, off); } } static ssize_t file_pwrite(struct file_context *fc, uint8_t *buf, size_t count, off_t off) { if (fc->is_smb2 == 0) { lseek(fc->fd, off, SEEK_SET); return write(fc->fd, buf, count); } else { return smb2_pwrite(fc->smb2, fc->smb2fh, buf, count, off); } } static struct file_context * open_file(const char *url, int flags) { struct file_context *file_context; file_context = malloc(sizeof(struct file_context)); if (file_context == NULL) { fprintf(stderr, "Failed to malloc file_context\n"); return NULL; } file_context->is_smb2 = 0; file_context->fd = -1; file_context->smb2 = NULL; file_context->smb2fh = NULL; file_context->url = NULL; if (strncmp(url, "smb://", 6)) { file_context->is_smb2 = 0; file_context->fd = open(url, flags, 0660); if (file_context->fd == -1) { fprintf(stderr, "Failed to open %s\n", url); free_file_context(file_context); return NULL; } return file_context; } file_context->is_smb2 = 1; file_context->smb2 = smb2_init_context(); if (file_context->smb2 == NULL) { fprintf(stderr, "failed to init context\n"); free_file_context(file_context); return NULL; } file_context->url = smb2_parse_url(file_context->smb2, url); if (file_context->url == NULL) { fprintf(stderr, "%s\n", smb2_get_error(file_context->smb2)); free_file_context(file_context); return NULL; } if (smb2_connect_share(file_context->smb2, file_context->url->server, file_context->url->share, file_context->url->user) != 0) { fprintf(stderr, "Failed to mount smb2 share : %s\n", smb2_get_error(file_context->smb2)); free_file_context(file_context); return NULL; } file_context->smb2fh = smb2_open(file_context->smb2, file_context->url->path, flags); if (file_context->smb2fh == NULL) { fprintf(stderr, "Failed to open file %s: %s\n", file_context->url->path, smb2_get_error(file_context->smb2)); free_file_context(file_context); return NULL; } return file_context; } #define BUFSIZE 1024*1024 static uint8_t buf[BUFSIZE]; int main(int argc, char *argv[]) { struct stat st; struct file_context *src; struct file_context *dst; off_t off; ssize_t count; #ifdef WIN32 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { printf("Failed to start Winsock2\n"); return 10; } #endif #ifdef AROS aros_init_socket(); #endif if (argc != 3) { usage(); } src = open_file(argv[1], O_RDONLY); if (src == NULL) { fprintf(stderr, "Failed to open %s\n", argv[1]); return 10; } dst = open_file(argv[2], O_WRONLY|O_CREAT|O_TRUNC); if (dst == NULL) { fprintf(stderr, "Failed to open %s\n", argv[2]); free_file_context(src); return 10; } if (fstat_file(src, &st) != 0) { fprintf(stderr, "Failed to fstat source file\n"); free_file_context(src); free_file_context(dst); return 10; } off = 0; while (off < st.st_size) { count = (size_t)(st.st_size - off); if (count > BUFSIZE) { count = BUFSIZE; } count = file_pread(src, buf, count, off); if (count < 0) { fprintf(stderr, "Failed to read from source file\n"); free_file_context(src); free_file_context(dst); return 10; } count = file_pwrite(dst, buf, count, off); if (count < 0) { fprintf(stderr, "Failed to write to dest file\n"); free_file_context(src); free_file_context(dst); return 10; } off += count; } printf("copied %d bytes\n", (int)off); free_file_context(src); free_file_context(dst); return 0; } libsmb2-6.2/utils/Makefile.am0000664000175000017500000000040714732155517015214 0ustar polpypolpynoinst_PROGRAMS = smb2-cp smb2-ls AM_CPPFLAGS = \ -I$(abs_top_srcdir)/include \ -I$(abs_top_srcdir)/include/smb2 \ "-D_U_=__attribute__((unused))" \ -Wall -Werror COMMON_LIBS = ../lib/libsmb2.la smb2_ls_LDADD = $(COMMON_LIBS) smb2_cp_LDADD = $(COMMON_LIBS) libsmb2-6.2/utils/smb2-ls.c0000664000175000017500000001170314732155517014604 0ustar polpypolpy/* -*- 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; } libsmb2-6.2/libsmb2.pc.in0000664000175000017500000000044714732155517014307 0ustar polpypolpy# libsmb2 pkg-config file prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libsmb2 Description: libsmb2 is a client library for accessing SMB shares over a network. Version: @VERSION@ Requires: Conflicts: Libs: -L${libdir} -lsmb2 Cflags: -I${includedir} libsmb2-6.2/component.mk0000664000175000017500000000016214732155517014351 0ustar polpypolpy COMPONENT_SRCDIRS=lib COMPONENT_PRIV_INCLUDEDIRS=lib include/esp COMPONENT_ADD_INCLUDEDIRS=include include/smb2 libsmb2-6.2/examples/0000775000175000017500000000000014732155517013635 5ustar polpypolpylibsmb2-6.2/examples/smb2-ftruncate-sync.c0000664000175000017500000000620514732155517017612 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-ftruncate-sync \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct smb2fh *fh; if (argc < 3) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } fh = smb2_open(smb2, url->path, O_RDWR); if (fh == NULL) { printf("smb2_open failed. %s\n", smb2_get_error(smb2)); exit(10); } if (smb2_ftruncate(smb2, fh, strtoll(argv[2], NULL, 10)) < 0) { printf("smb2_ftruncate failed. %s\n", smb2_get_error(smb2)); smb2_close(smb2, fh); exit(10); } smb2_close(smb2, fh); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-cat-sync.c0000664000175000017500000000715514732155517016373 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #include #if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) #include #endif #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #define MAXBUF 16 * 1024 * 1024 uint8_t buf[MAXBUF]; uint32_t pos; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-cat-sync \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct smb2fh *fh; int count, rc = 0; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } fh = smb2_open(smb2, url->path, O_RDONLY); if (fh == NULL) { printf("smb2_open failed. %s\n", smb2_get_error(smb2)); exit(10); } while ((count = smb2_pread(smb2, fh, buf, MAXBUF, pos)) != 0) { if (count == -EAGAIN) { continue; } if (count < 0) { fprintf(stderr, "Failed to read file. %s\n", smb2_get_error(smb2)); rc = 1; break; } write(STDOUT_FILENO, buf, count); pos += count; }; smb2_close(smb2, fh); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return rc; } libsmb2-6.2/examples/smb2-ls-async.c0000664000175000017500000001315614732155517016401 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #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 #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) struct pollfd { int fd; short events; short revents; }; int poll(struct pollfd *fds, unsigned int nfds, int timo); #endif int is_finished; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-ls-async \n\n" "URL format: " "smb://[@]>[:]//\n"); exit(1); } void dc_cb(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { is_finished = 1; } void od_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2dir *dir = command_data; struct smb2dirent *ent; if (status) { printf("failed to create/open directory (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } while ((ent = smb2_readdir(smb2, dir))) { char *type; time_t t; 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; } t = (time_t)ent->st.smb2_mtime; printf("%-20s %-9s %15"PRIu64" %s\n", ent->name, type, ent->st.smb2_size, asctime(localtime(&t))); } smb2_closedir(smb2, dir); smb2_disconnect_share_async(smb2, dc_cb, NULL); } void cf_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { if (status) { printf("failed to connect share (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } if (smb2_opendir_async(smb2, private_data, od_cb, NULL) < 0) { printf("Failed to call opendir_async()\n"); exit(10); } } static int cfd = -1; void fd_cb(struct smb2_context *smb2, int fd, int cmd) { if (cmd == SMB2_ADD_FD) { cfd = fd; } if (cmd == SMB2_DEL_FD) { cfd = -1; } } static int cevents = 0; void events_cb(struct smb2_context *smb2, int fd, int events) { cevents = events; } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct pollfd pfd; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } smb2_fd_event_callbacks(smb2, fd_cb, events_cb); url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED); if (smb2_connect_share_async(smb2, url->server, url->share, url->user, cf_cb, (void *)url->path) != 0) { printf("smb2_connect_share failed. %s\n", smb2_get_error(smb2)); exit(10); } while (!is_finished) { pfd.fd = cfd; pfd.events = cevents; if (poll(&pfd, 1, 1000) < 0) { printf("Poll failed"); exit(10); } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { printf("smb2_service failed with : %s\n", smb2_get_error(smb2)); break; } } smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-put-async.c0000664000175000017500000001250314732155517016566 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #include #if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) #include #endif #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) struct pollfd { int fd; short events; short revents; }; int poll(struct pollfd *fds, unsigned int nfds, int timo); #endif uint8_t buf[256 * 1024]; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-put-async \n\n" "URL format: " "smb://[@]>[:]//\n"); exit(1); } struct cb_data { int is_finished; int fd; struct smb2fh *fh; uint32_t pos; }; void write_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct cb_data *data = private_data; int count; if (status < 0) { printf("failed to write to share (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } if (status == 0) { data->is_finished = 1; return; } printf("write_cb:%d\n", status); data->pos += status; count = read(data->fd, buf, 1024); if (count <= 0) { exit(10); } if (smb2_pwrite_async(smb2, data->fh, buf, count, data->pos, write_cb, data) < 0) { printf("smb2_write_async failed. %s\n", smb2_get_error(smb2)); exit(10); }; } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct cb_data data; struct pollfd pfd; int count; data.is_finished = 0; data.pos = 0; if (argc < 2) { usage(); } data.fd = open(argv[1], O_RDONLY); if (data.fd == -1) { printf("Failed to open local file %s (%s)\n", argv[1], strerror(errno)); exit(10); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[2]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } data.fh = smb2_open(smb2, url->path, O_WRONLY|O_CREAT); if (data.fh == NULL) { printf("smb2_open failed. %s\n", smb2_get_error(smb2)); exit(10); } count = read(data.fd, buf, 1024); if (count <= 0) { exit(10); } if (smb2_pwrite_async(smb2, data.fh, buf, count, data.pos, write_cb, &data) < 0) { printf("smb2_write_async failed. %s\n", smb2_get_error(smb2)); exit(10); }; while (!data.is_finished) { pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { printf("Poll failed"); exit(10); } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { printf("smb2_service failed with : %s\n", smb2_get_error(smb2)); break; } } close(data.fd); smb2_close(smb2, data.fh); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-CMD-FIND.c0000664000175000017500000003030114732155517015760 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2022 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int is_finished; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-CMD-FIND \n\n" "URL format: " "smb://[@]>[:]/\n"); exit(1); } struct app_data { smb2_file_id file_id; uint32_t index_1, index_2; const char *name_1, *name_2; }; void qd_3_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2_query_directory_reply *rep = command_data; struct app_data *data = private_data; struct smb2_iovec vec; struct smb2_fileidfulldirectoryinformation fs; if (status) { printf("Restarting scan of directory using SMB2_INDEX_SPECIFIED failed (%s) %s\n", strerror(-status), smb2_get_error(smb2)); printf("ERROR: server does not support SMB2_INDEX_SPECIFIED\n"); exit(10); } printf("Third scan of directory done.\n"); vec.buf = rep->output_buffer; vec.len = rep->output_buffer_length; if (smb2_decode_fileidfulldirectoryinformation(smb2, &fs, &vec)) { printf("Failed to decode directory entry\n"); printf("ERROR: restarting the scan using SMB2_RESTART_SCAN broken\n"); exit(10); } printf("Index of first entry after restarting the scan at the second index: 0x%08x\n", fs.file_index); printf("Name of first entry after restarting the scan at the second index %s\n", fs.name); if (strcmp(fs.name, data->name_2)) { printf("ERROR: restarting the scan using SMB2_INDEX_SPECIFIED did not return the expected second entry.\n"); printf("ERROR: server does not support SMB2_INDEX_SPECIFIED.\n"); exit(10); } } void qd_2_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2_query_directory_reply *rep = command_data; struct smb2_query_directory_request req; struct smb2_pdu *pdu; struct app_data *data = private_data; struct smb2_iovec vec; struct smb2_fileidfulldirectoryinformation fs; if (status) { printf("Restarting scan of directory using SMB2_RESTART_SCAN failed (%s) %s\n", strerror(-status), smb2_get_error(smb2)); printf("ERROR: server does not support SMB2_RESTART_SCAN\n"); exit(10); } printf("Second scan of directory done.\n"); vec.buf = rep->output_buffer; vec.len = rep->output_buffer_length; if (smb2_decode_fileidfulldirectoryinformation(smb2, &fs, &vec)) { printf("Failed to decode directory entry\n"); printf("ERROR: restarting the scan using SMB2_RESTART_SCAN broken\n"); exit(10); } printf("Index of first entry after restarting the scan: 0x%08x\n", fs.file_index); printf("Name of first entry after restarting the scan %s\n", fs.name); if (strcmp(fs.name, data->name_1)) { printf("ERROR: restarting the scan using SMB2_RESTART_SCAN did not return the name of the first entry.\n"); exit(10); } printf("Try restarting scan at the second entry using SMB2_INDEX_SPECIFIED\n"); memset(&req, 0, sizeof(struct smb2_query_directory_request)); req.file_information_class = SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION; req.flags = SMB2_INDEX_SPECIFIED; req.file_index = data->index_2; memcpy(req.file_id, data->file_id, SMB2_FD_SIZE); req.output_buffer_length = 8 * 1024; req.name = "*"; pdu = smb2_cmd_query_directory_async(smb2, &req, qd_2_cb, data); if (pdu == NULL) { printf("Failed to queue QUERY_DIRECTORY\n"); exit(10); } smb2_queue_pdu(smb2, pdu); } void qd_1_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2_query_directory_reply *rep = command_data; struct smb2_query_directory_request req; struct smb2_pdu *pdu; struct app_data *data = private_data; struct smb2_iovec vec, tmp_vec; struct smb2_fileidfulldirectoryinformation fs; uint32_t offset = 0; if (status) { printf("failed to query directory (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } printf("Initial scan of directory done.\n"); vec.buf = rep->output_buffer; vec.len = rep->output_buffer_length; tmp_vec.buf = &vec.buf[offset]; tmp_vec.len = vec.len - offset; if (smb2_decode_fileidfulldirectoryinformation(smb2, &fs, &tmp_vec)) { printf("Failed to decode directory entry\n"); exit(10); } data->name_1 = strdup(fs.name); data->index_1 = fs.file_index; printf("First file in directory: %s\n", data->name_1); printf("Index of first file in directory: 0x%08x\n", fs.file_index); offset += fs.next_entry_offset; tmp_vec.buf = &vec.buf[offset]; tmp_vec.len = vec.len - offset; if (smb2_decode_fileidfulldirectoryinformation(smb2, &fs, &tmp_vec)) { printf("Failed to decode directory entry\n"); exit(10); } data->name_2 = strdup(fs.name); data->index_2 = fs.file_index; printf("Second file in directory: %s\n", data->name_2); printf("Index of second file in directory: 0x%08x\n", fs.file_index); if (data->index_1 == data->index_2) { printf("ERROR: broken server returns same file_index for first two entries in the directory\n"); printf("ERROR: This server does not support SMB2_INDEX_SPECIFIED queries\n"); } printf("Try restarting scan of directory using SMB2_RESTART_SCAN\n"); memset(&req, 0, sizeof(struct smb2_query_directory_request)); req.file_information_class = SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION; req.flags = SMB2_RESTART_SCANS; memcpy(req.file_id, data->file_id, SMB2_FD_SIZE); req.output_buffer_length = 8 * 1024; req.name = "*"; pdu = smb2_cmd_query_directory_async(smb2, &req, qd_2_cb, data); if (pdu == NULL) { printf("Failed to queue QUERY_DIRECTORY\n"); exit(10); } smb2_queue_pdu(smb2, pdu); } void cr_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2_create_reply *rep = command_data; struct smb2_query_directory_request req; struct smb2_pdu *pdu; struct app_data *data = private_data; if (status) { printf("failed to open root of share (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } printf("Opened root of the share\n"); memcpy(data->file_id, rep->file_id, SMB2_FD_SIZE); memset(&req, 0, sizeof(struct smb2_query_directory_request)); req.file_information_class = SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION; req.flags = 0; memcpy(req.file_id, data->file_id, SMB2_FD_SIZE); req.output_buffer_length = 8 * 1024; req.name = "*"; printf("Performing initial scan of directory\n"); pdu = smb2_cmd_query_directory_async(smb2, &req, qd_1_cb, data); if (pdu == NULL) { printf("Failed to queue QUERY_DIRECTORY\n"); exit(10); } smb2_queue_pdu(smb2, pdu); } void cf_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2_create_request cr_req; struct smb2_pdu *pdu; struct add_data *data = private_data; if (status) { printf("failed to connect share (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } /* CREATE command */ memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.file_attributes = SMB2_FILE_ATTRIBUTE_DIRECTORY; cr_req.desired_access = SMB2_FILE_LIST_DIRECTORY | SMB2_FILE_READ_ATTRIBUTES; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = SMB2_FILE_DIRECTORY_FILE; cr_req.name = ""; pdu = smb2_cmd_create_async(smb2, &cr_req, cr_cb, data); if (pdu == NULL) { fprintf(stderr, "Failed to create create command\n"); exit(10); } smb2_queue_pdu(smb2, pdu); } static int cfd = -1; void fd_cb(struct smb2_context *smb2, int fd, int cmd) { if (cmd == SMB2_ADD_FD) { cfd = fd; } if (cmd == SMB2_DEL_FD) { cfd = -1; } } static int cevents = 0; void events_cb(struct smb2_context *smb2, int fd, int events) { cevents = events; } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct pollfd pfd; struct app_data data; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } smb2_fd_event_callbacks(smb2, fd_cb, events_cb); url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED); if (smb2_connect_share_async(smb2, url->server, url->share, url->user, cf_cb, &data) != 0) { printf("smb2_connect_share failed. %s\n", smb2_get_error(smb2)); exit(10); } while (!is_finished) { pfd.fd = cfd; pfd.events = cevents; if (poll(&pfd, 1, 1000) < 0) { printf("Poll failed"); exit(10); } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { printf("smb2_service failed with : %s\n", smb2_get_error(smb2)); break; } } smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-stat-sync.c0000664000175000017500000000726414732155517016600 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-stat-sync \n\n" "URL format: " "smb://[@]>[:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct smb2_stat_64 st; time_t t; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } if (smb2_stat(smb2, url->path, &st) < 0) { printf("smb2_stat failed. %s\n", smb2_get_error(smb2)); exit(10); } switch (st.smb2_type) { case SMB2_TYPE_FILE: printf("Type:FILE\n"); break; case SMB2_TYPE_DIRECTORY: printf("Type:DIRECTORY\n"); break; default: printf("Type:unknown\n"); break; } printf("Size:%"PRIu64"\n", st.smb2_size); printf("Inode:0x%"PRIx64"\n", st.smb2_ino); printf("Links:%"PRIu32"\n", st.smb2_nlink); t = (time_t)st.smb2_atime; printf("Atime:%s", asctime(localtime(&t))); t = (time_t)st.smb2_mtime; printf("Mtime:%s", asctime(localtime(&t))); t = (time_t)st.smb2_ctime; printf("Ctime:%s", asctime(localtime(&t))); t = (time_t)st.smb2_btime; printf("Btime:%s", asctime(localtime(&t))); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-cat-async.c0000664000175000017500000001316314732155517016530 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) #include #endif #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) struct pollfd { int fd; short events; short revents; }; int poll(struct pollfd *fds, unsigned int nfds, int timo); #endif int is_finished; uint8_t buf[256 * 1024]; uint32_t pos; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-cat-async \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } void dc_cb(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { is_finished = 1; } void cl_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { smb2_disconnect_share_async(smb2, dc_cb, NULL); } void pr_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2fh *fh = private_data; if (status < 0) { printf("failed to read file (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } if (status == 0) { if (smb2_close_async(smb2, fh, cl_cb, NULL) < 0) { printf("Failed to call smb2_close_async()\n"); exit(10); } return; } write(STDOUT_FILENO, buf, status); pos += status; if (smb2_pread_async(smb2, fh, buf, 102400, pos, pr_cb, fh) < 0) { printf("Failed to call smb2_pread_async()\n"); exit(10); } } void of_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2fh *fh = command_data; if (status) { printf("failed to open file (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } if (smb2_pread_async(smb2, fh, buf, 102400, 0, pr_cb, fh) < 0) { printf("Failed to call smb2_pread_async()\n"); exit(10); } } void cf_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { if (status) { printf("failed to connect share (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } if (smb2_open_async(smb2, private_data, O_RDONLY, of_cb, NULL) < 0) { printf("Failed to call smb2_open_async()\n"); exit(10); } } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct pollfd pfd; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED); if (smb2_connect_share_async(smb2, url->server, url->share, url->user, cf_cb, (void *)url->path) != 0) { printf("smb2_connect_share failed. %s\n", smb2_get_error(smb2)); exit(10); } while (!is_finished) { pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { printf("Poll failed"); exit(10); } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { printf("smb2_service failed with : %s\n", smb2_get_error(smb2)); break; } } smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/picow/0000775000175000017500000000000014732155517014756 5ustar polpypolpylibsmb2-6.2/examples/picow/main.cpp0000664000175000017500000000643314732155517016414 0ustar polpypolpy#include "pico/cyw43_arch.h" #include "pico/stdio.h" #include "pico/stdlib.h" #include "FreeRTOS.h" #include "task.h" #include "smb2.h" #include "libsmb2.h" int smb2_ls_sync(char* user_url) { struct smb2_context *smb2; struct smb2_url *url; struct smb2dir *dir; struct smb2dirent *ent; char link[1024]; smb2 = smb2_init_context(); if (smb2 == NULL) { printf("Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, user_url); if (url == NULL) { printf("Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } dir = smb2_opendir(smb2, url->path); if (dir == NULL) { printf("smb2_opendir failed. %s\n", smb2_get_error(smb2)); exit(10); } while ((ent = smb2_readdir(smb2, dir))) { const 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 %15u\n", ent->name, type, ent->st.smb2_size); if (ent->st.smb2_type == SMB2_TYPE_LINK) { char buf[256]; if (url->path && url->path[0]) { sprintf(link, "%s/%s", url->path, ent->name); } else { sprintf(link, "%s", ent->name); } smb2_readlink(smb2, link, buf, 256); printf(" -> [%s]\n", buf); } } smb2_closedir(smb2, dir); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } static void main_task(__unused void *params) { if (cyw43_arch_init()) { printf("Failed to initialise Pico W\n"); return; } cyw43_arch_enable_sta_mode(); printf("Connecting to WiFi...\n"); if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { printf("Failed to connect.\n"); return; } ip4_addr_t *address = &(cyw43_state.netif[0].ip_addr); printf("Connected to %s as %d.%d.%d.%d as host %s\n", WIFI_SSID, ip4_addr1_16(address), ip4_addr2_16(address), ip4_addr3_16(address), ip4_addr4_16(address), cyw43_state.netif[0].hostname); smb2_ls_sync(SMB2_URL); vTaskDelete(NULL); } int main(void) { TaskHandle_t task; stdio_init_all(); xTaskCreate(main_task, "MainThread", configMINIMAL_STACK_SIZE, NULL, 1, &task); vTaskStartScheduler(); return 0; } libsmb2-6.2/examples/picow/CMakeLists.txt0000664000175000017500000000454314732155517017524 0ustar polpypolpycmake_minimum_required(VERSION 3.24) # Some user configuration needed below # Get the Pico SDK from https://github.com/raspberrypi/pico-sdk.git tested on TAG 1.4.0 # Get FreeRTOS from https://github.com/FreeRTOS/FreeRTOS-Kernel.git tested on TAG V10.5.0 # Replace the /path/to's below with appropriate paths # Something like /home/me/dve/github/pico_sdk, but wherever you put the pico-sdk or freertos-kernel set(PICO_SDK_PATH /path/to/pick-sdk) set(FREERTOS_KERNEL_PATH /path/to/freertos-kernel) set(LIBSMB2_PATH ${CMAKE_CURRENT_LIST_DIR}/../..) # Replace with the name of your WiFi (SSID) and the password to join that WiFi set(WIFI_SSID ssid_name) set(WIFI_PASSWORD wifi_name) # Put in the URL of the server/share you want to see the directory of set(SMB2_URL smb://myserver.lan/myshare) # No other configuration needed, below this # Name the project and prepare it to be a pico_w project, using FreeRTOS and lwip set(PROJECT_NAME libsmb2-picow-ls) set(PICO_BOARD pico_w) include(${PICO_SDK_PATH}/pico_sdk_init.cmake) include(${FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake) project(${PROJECT_NAME} C CXX ASM) pico_sdk_init() # Add a couple of definitions that all projects/libraries can/should use add_definitions(-DPICO_PLATFORM=${PICO_PLATFORM}) add_definitions(-DHAVE_CONFIG_H) # Build libsmb2 as a library add_subdirectory(${LIBSMB2_PATH} libsmb2) # The example set(PROJECT_NAME smb2-ls-sync) project(${PROJECT_NAME} C CXX ASM) # Application, including in the FreeRTOS-Kernel add_executable(${PROJECT_NAME} main.cpp) # Build the app include_directories( ${CMAKE_CURRENT_LIST_DIR} ${FREERTOS_KERNEL_PATH}/include ${LIBSMB2_PATH}/include ${LIBSMB2_PATH}/include/smb2 ${LIBSMB2_PATH}/include/picow ) pico_enable_stdio_usb(${PROJECT_NAME} 1) pico_enable_stdio_uart(${PROJECT_NAME} 0) pico_enable_stdio_semihosting(${PROJECT_NAME} ENABLED) target_compile_definitions(${PROJECT_NAME} PRIVATE WIFI_SSID=\"${WIFI_SSID}\" WIFI_PASSWORD=\"${WIFI_PASSWORD}\" SMB2_URL=\"${SMB2_URL}\" NO_SYS=0 # don't want NO_SYS (generally this would be in your lwipopts.h) ) target_link_libraries(${PROJECT_NAME} pico_cyw43_arch_lwip_sys_freertos FreeRTOS-Kernel pico_stdlib libsmb2 FreeRTOS-Kernel-Heap4 ) pico_add_extra_outputs(${PROJECT_NAME}) libsmb2-6.2/examples/picow/README.md0000664000175000017500000000041314732155517016233 0ustar polpypolpy# Pico W sample This is the smb-ls-sync.c example adapted to run on a Pico W. You will need the Pico-SDK and FreeRTOS-Kernel installed for this to work. See the CMakeLists.txt file - there's some user configuration needed before the sample can be compiled and run. libsmb2-6.2/examples/picow/smb-ls-sync.c0000664000175000017500000000000014732155517017257 0ustar polpypolpylibsmb2-6.2/examples/smb2-lseek-sync.c0000664000175000017500000000713314732155517016723 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2020 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-lseek-sync \n\n" "URL format: " "smb://[@]>[:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct smb2fh *fh; struct smb2_stat_64 st; int64_t pos; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } fh = smb2_open(smb2, url->path, O_RDONLY); if (fh == NULL) { printf("smb2_open failed. %s\n", smb2_get_error(smb2)); exit(10); } if (smb2_fstat(smb2, fh, &st) < 0) { printf("smb2_fstat failed. %s\n", smb2_get_error(smb2)); exit(10); } printf("SIZE:%"PRIu64"\n", st.smb2_size); pos = smb2_lseek(smb2, fh, st.smb2_size, SEEK_SET, NULL); printf("SEEK_SET to eof:%"PRIu64"\n", pos); pos = smb2_lseek(smb2, fh, 0, SEEK_SET, NULL); printf("SEEK_SET to bof:%"PRIu64"\n", pos); pos = smb2_lseek(smb2, fh, 0, SEEK_END, NULL); if (pos < 0) { printf("%s\n", smb2_get_error(smb2)); } printf("SEEK_END with offset == 0 :%"PRIu64"\n", pos); smb2_close(smb2, fh); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-raw-fsstat-async.c0000664000175000017500000003056714732155517020063 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2017 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int info_level; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-raw-fsstat-async \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } struct sync_cb_data { int is_finished; int status; void *ptr; }; static int wait_for_reply(struct smb2_context *smb2, struct sync_cb_data *cb_data) { while (!cb_data->is_finished) { struct pollfd pfd; pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { fprintf(stderr, "Poll failed"); return -1; } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { fprintf(stderr, "smb2_service failed with : " "%s\n", smb2_get_error(smb2)); return -1; } } return 0; } static void generic_status_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; cb_data->is_finished = 1; cb_data->status = status; cb_data->ptr = command_data; } struct stat_cb_data { smb2_command_cb cb; void *cb_data; uint32_t status; }; static void stat_cb_3(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct stat_cb_data *stat_data = private_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } stat_data->cb(smb2, -nterror_to_errno(stat_data->status), 0, stat_data->cb_data); free(stat_data); } static void stat_cb_2(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct stat_cb_data *stat_data = private_data; struct smb2_query_info_reply *rep = command_data; struct smb2_file_fs_size_info *fs_size; struct smb2_file_fs_device_info *fs_dev; struct smb2_file_fs_control_info *fs_ct; struct smb2_file_fs_full_size_info *fs_full_size; struct smb2_file_fs_volume_info *fs_vol; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } if (stat_data->status != SMB2_STATUS_SUCCESS) { return; } switch (info_level) { case SMB2_FILE_FS_VOLUME_INFORMATION: fs_vol = rep->output_buffer; printf("VolumeSerialNumber: 0x%0x\n", fs_vol->volume_serial_number); printf("VolumeLabel: %s\n", fs_vol->volume_label); break; case SMB2_FILE_FS_SIZE_INFORMATION: fs_size = rep->output_buffer; printf("TotalAllocationUnits: %" PRIu64 "\n", fs_size->total_allocation_units); printf("AvailableAllocationUnits: %" PRIu64 "\n", fs_size->available_allocation_units); printf("SectorsPerAllocationUnit: %u\n", fs_size->sectors_per_allocation_unit); printf("BytesPerSector: %u\n", fs_size->bytes_per_sector); break; case SMB2_FILE_FS_DEVICE_INFORMATION: fs_dev = rep->output_buffer; printf("DeviceType: %u\n", fs_dev->device_type); printf("Characteristics: 0x%08x\n", fs_dev->characteristics); break; case SMB2_FILE_FS_CONTROL_INFORMATION: fs_ct = rep->output_buffer; printf("FreeSpaceStartFiltering: %" PRIu64 "\n", fs_ct->free_space_start_filtering); printf("FreeSpaceThreshold: %" PRIu64 "\n", fs_ct->free_space_threshold); printf("FreeSpaceStopFiltering: %" PRIu64 "\n", fs_ct->free_space_stop_filtering); printf("DefaultQuotaThreshold: %" PRIu64 "\n", fs_ct->default_quota_threshold); printf("DefaultQuotaLimit: %" PRIu64 "\n", fs_ct->default_quota_limit); printf("Characteristics: 0x%08x\n", fs_ct->file_system_control_flags); break; case SMB2_FILE_FS_FULL_SIZE_INFORMATION: fs_full_size = rep->output_buffer; printf("TotalAllocationUnits: %" PRIu64 "\n", fs_full_size->total_allocation_units); printf("CallerAvailableAllocationUnits: %" PRIu64 "\n", fs_full_size->caller_available_allocation_units); printf("ActualAvailableAllocationUnits: %" PRIu64 "\n", fs_full_size->actual_available_allocation_units); printf("SectorsPerAllocationUnit: %u\n", fs_full_size->sectors_per_allocation_unit); printf("BytesPerSector: %u\n", fs_full_size->bytes_per_sector); break; } } static void stat_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct stat_cb_data *stat_data = private_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } } int send_compound_stat(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data) { struct stat_cb_data *stat_data; struct smb2_create_request cr_req; struct smb2_query_info_request qi_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; stat_data = malloc(sizeof(struct stat_cb_data)); if (stat_data == NULL) { fprintf(stderr, "Failed to allocate create_data"); return -1; } memset(stat_data, 0, sizeof(struct stat_cb_data)); stat_data->cb = cb; stat_data->cb_data = cb_data; /* CREATE command */ memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; cr_req.file_attributes = 0; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = 0; cr_req.name = path; pdu = smb2_cmd_create_async(smb2, &cr_req, stat_cb_1, stat_data); if (pdu == NULL) { fprintf(stderr, "Failed to create create command\n"); free(stat_data); return -1; } /* QUERY INFO command */ memset(&qi_req, 0, sizeof(struct smb2_query_info_request)); qi_req.info_type = SMB2_0_INFO_FILESYSTEM; qi_req.file_info_class = info_level; qi_req.output_buffer_length = 65535; qi_req.additional_information = 0; qi_req.flags = 0; memcpy(qi_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_query_info_async(smb2, &qi_req, stat_cb_2, stat_data); if (next_pdu == NULL) { fprintf(stderr, "Failed to create query command\n"); free(stat_data); smb2_free_pdu(smb2, pdu); return -1; } smb2_add_compound_pdu(smb2, pdu, next_pdu); /* CLOSE command */ memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, stat_cb_3, stat_data); if (next_pdu == NULL) { fprintf(stderr, "Failed to create CLOSE command\n"); free(stat_data); smb2_free_pdu(smb2, pdu); return -1; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct sync_cb_data cb_data; struct smb2_file_all_info *fs; if (argc < 3) { usage(); } if (!strncmp(argv[2], "0x", 2)) { info_level = strtol(argv[2], NULL, 16); } else { info_level = strtol(argv[2], NULL, 10); } switch (info_level) { case SMB2_FILE_FS_VOLUME_INFORMATION: printf("InfoLevel:%d FileFsVolmeInformation\n", info_level); break; case SMB2_FILE_FS_SIZE_INFORMATION: printf("InfoLevel:%d FileFsSizeInformation\n", info_level); break; case SMB2_FILE_FS_DEVICE_INFORMATION: printf("InfoLevel:%d FileFsDeviceInformation\n", info_level); break; case SMB2_FILE_FS_CONTROL_INFORMATION: printf("InfoLevel:%d FileFsControlInformation\n", info_level); break; case SMB2_FILE_FS_FULL_SIZE_INFORMATION: printf("InfoLevel:%d FileFsFullSizeInformation\n", info_level); break; } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } if (url->user) { smb2_set_user(smb2, url->user); } 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)); exit(10); } memset(&cb_data, 0, sizeof(cb_data)); if (send_compound_stat(smb2, url->path, generic_status_cb, &cb_data) != 0) { printf("sending compound stat failed. %s\n", smb2_get_error(smb2)); exit(10); } if (wait_for_reply(smb2, &cb_data) < 0) { printf("failed waiting for a reply. %s\n", smb2_get_error(smb2)); exit(10); } if (cb_data.status != 0) { printf("Compound command sequence returned error 0x%08x\n", cb_data.status); exit(10); } fs = cb_data.ptr; smb2_free_data(smb2, fs); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-raw-stat-async.c0000664000175000017500000003653114732155517017527 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2017 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-raw-stat-async \n\n" "URL format: " "smb://[@]>[:]//\n"); exit(1); } struct sync_cb_data { int is_finished; int status; void *ptr; }; static int wait_for_reply(struct smb2_context *smb2, struct sync_cb_data *cb_data) { while (!cb_data->is_finished) { struct pollfd pfd; pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { fprintf(stderr, "Poll failed"); return -1; } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { fprintf(stderr, "smb2_service failed with : " "%s\n", smb2_get_error(smb2)); return -1; } } return 0; } static void generic_status_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; cb_data->is_finished = 1; cb_data->status = status; cb_data->ptr = command_data; } struct stat_cb_data { smb2_command_cb cb; void *cb_data; uint32_t status; struct smb2_file_all_info *fs; }; static void stat_cb_3(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct stat_cb_data *stat_data = private_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } stat_data->cb(smb2, -nterror_to_errno(stat_data->status), stat_data->fs, stat_data->cb_data); free(stat_data); } static void stat_cb_2(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct stat_cb_data *stat_data = private_data; struct smb2_query_info_reply *rep = command_data; struct smb2_file_all_info *fs = rep->output_buffer; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } if (stat_data->status != SMB2_STATUS_SUCCESS) { return; } /* Remember the fs structure so we can pass it back to the caller */ stat_data->fs = fs; } static void stat_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct stat_cb_data *stat_data = private_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } } int send_compound_stat(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data) { struct stat_cb_data *stat_data; struct smb2_create_request cr_req; struct smb2_query_info_request qi_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; stat_data = malloc(sizeof(struct stat_cb_data)); if (stat_data == NULL) { fprintf(stderr, "Failed to allocate create_data"); return -1; } memset(stat_data, 0, sizeof(struct stat_cb_data)); stat_data->cb = cb; stat_data->cb_data = cb_data; /* CREATE command */ memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; cr_req.file_attributes = 0; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = 0; cr_req.name = path; pdu = smb2_cmd_create_async(smb2, &cr_req, stat_cb_1, stat_data); if (pdu == NULL) { fprintf(stderr, "Failed to create create command\n"); free(stat_data); return -1; } /* QUERY INFO command */ memset(&qi_req, 0, sizeof(struct smb2_query_info_request)); qi_req.info_type = SMB2_0_INFO_FILE; qi_req.file_info_class = SMB2_FILE_ALL_INFORMATION; qi_req.output_buffer_length = 65535; qi_req.additional_information = 0; qi_req.flags = 0; memcpy(qi_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_query_info_async(smb2, &qi_req, stat_cb_2, stat_data); if (next_pdu == NULL) { fprintf(stderr, "Failed to create query command\n"); free(stat_data); smb2_free_pdu(smb2, pdu); return -1; } smb2_add_compound_pdu(smb2, pdu, next_pdu); /* CLOSE command */ memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, stat_cb_3, stat_data); if (next_pdu == NULL) { fprintf(stderr, "Failed to create CLOSE command\n"); free(stat_data); smb2_free_pdu(smb2, pdu); return -1; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct sync_cb_data cb_data; struct smb2_file_all_info *fs; time_t t; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } if (url->user) { smb2_set_user(smb2, url->user); } 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)); exit(10); } memset(&cb_data, 0, sizeof(cb_data)); if (send_compound_stat(smb2, url->path, generic_status_cb, &cb_data) != 0) { printf("sending compound stat failed. %s\n", smb2_get_error(smb2)); exit(10); } if (wait_for_reply(smb2, &cb_data) < 0) { printf("failed waiting for a reply. %s\n", smb2_get_error(smb2)); exit(10); } if (cb_data.status != 0) { printf("Compound command sequence returned error 0x%08x\n", cb_data.status); exit(10); } fs = cb_data.ptr; /* Print the file_all_info structure */ printf("Attributes: "); if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_READONLY) { printf("READONLY "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_HIDDEN) { printf("HIDDEN "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_SYSTEM) { printf("SYSTEM "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) { printf("DIRECTORY "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_ARCHIVE) { printf("ARCHIVE "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_NORMAL) { printf("NORMAL "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_TEMPORARY) { printf("TMP "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_SPARSE_FILE) { printf("SPARSE "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) { printf("REPARSE "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_COMPRESSED) { printf("COMPRESSED "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_OFFLINE) { printf("OFFLINE "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) { printf("NOT_CONTENT_INDEXED "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_ENCRYPTED) { printf("ENCRYPTED "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_INTEGRITY_STREAM) { printf("INTEGRITY_STREAM "); } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_NO_SCRUB_DATA) { printf("NO_SCRUB_DATA "); } printf("\n"); t = fs->basic.creation_time.tv_sec; printf("Creation Time: %s", asctime(localtime(&t))); t = fs->basic.last_access_time.tv_sec; printf("Last Access Time: %s", asctime(localtime(&t))); t = fs->basic.last_write_time.tv_sec; printf("Last Write Time: %s", asctime(localtime(&t))); t = fs->basic.change_time.tv_sec; printf("Change Time: %s", asctime(localtime(&t))); printf("Allocation Size: %" PRIu64 "\n", fs->standard.allocation_size); printf("End Of File: %" PRIu64 "\n", fs->standard.end_of_file); printf("Number Of Links: %d\n", fs->standard.number_of_links); printf("Delete Pending: %s\n", fs->standard.delete_pending ? "YES" : "NO"); printf("Directory: %s\n", fs->standard.directory ? "YES" : "NO"); printf("Index Number: 0x%016" PRIx64 "\n", fs->index_number); printf("EA Size : %d\n", fs->ea_size); printf("Access Flags: "); if (fs->standard.directory) { if (fs->access_flags & SMB2_FILE_LIST_DIRECTORY) { printf("LIST_DIRECTORY "); } if (fs->access_flags & SMB2_FILE_ADD_FILE) { printf("ADD_FILE "); } if (fs->access_flags & SMB2_FILE_ADD_SUBDIRECTORY) { printf("ADD_SUBDIRECTORY "); } if (fs->access_flags & SMB2_FILE_TRAVERSE) { printf("TRAVERSE "); } } else { if (fs->access_flags & SMB2_FILE_READ_DATA) { printf("READ_DATA "); } if (fs->access_flags & SMB2_FILE_WRITE_DATA) { printf("WRITE_DATA "); } if (fs->access_flags & SMB2_FILE_APPEND_DATA) { printf("APPEND_DATA "); } if (fs->access_flags & SMB2_FILE_EXECUTE) { printf("FILE_EXECUTE "); } } if (fs->access_flags & SMB2_FILE_READ_EA) { printf("READ_EA "); } if (fs->access_flags & SMB2_FILE_WRITE_EA) { printf("WRITE_EA "); } if (fs->access_flags & SMB2_FILE_READ_ATTRIBUTES) { printf("READ_ATTRIBUTES "); } if (fs->access_flags & SMB2_FILE_WRITE_ATTRIBUTES) { printf("WRITE_ATTRIBUTES "); } if (fs->access_flags & SMB2_FILE_DELETE_CHILD) { printf("DELETE_CHILD "); } if (fs->access_flags & SMB2_DELETE) { printf("DELETE "); } if (fs->access_flags & SMB2_READ_CONTROL) { printf("READ_CONTROL "); } if (fs->access_flags & SMB2_WRITE_DACL) { printf("WRITE_DACL "); } if (fs->access_flags & SMB2_WRITE_OWNER) { printf("WRITE_OWNER "); } if (fs->access_flags & SMB2_SYNCHRONIZE) { printf("SYNCHRONIZE "); } if (fs->access_flags & SMB2_ACCESS_SYSTEM_SECURITY) { printf("ACCESS_SYSTEM_SECURITY "); } if (fs->access_flags & SMB2_MAXIMUM_ALLOWED) { printf("MAXIMUM_ALLOWED "); } if (fs->access_flags & SMB2_GENERIC_ALL) { printf("GENERIC_ALL "); } if (fs->access_flags & SMB2_GENERIC_EXECUTE) { printf("GENERIC_EXECUTE "); } if (fs->access_flags & SMB2_GENERIC_WRITE) { printf("GENERIC_WRITE "); } if (fs->access_flags & SMB2_GENERIC_READ) { printf("GENERIC_READ "); } printf("\n"); printf("Current Byte Offset: %" PRIu64 "\n", fs->current_byte_offset); printf("Mode: "); if (fs->access_flags & SMB2_FILE_WRITE_THROUGH) { printf("WRITE_THROUGH "); } if (fs->access_flags & SMB2_FILE_SEQUENTIAL_ONLY) { printf("SEQUENTIAL_ONLY "); } if (fs->access_flags & SMB2_FILE_NO_INTERMEDIATE_BUFFERING) { printf("NO_INTERMEDIATE_BUFFERING "); } if (fs->access_flags & SMB2_FILE_SYNCHRONOUS_IO_ALERT) { printf("SYNCHRONOUS_IO_ALERT "); } if (fs->access_flags & SMB2_FILE_SYNCHRONOUS_IO_NONALERT) { printf("SYNCHRONOUS_IO_NONALERT "); } if (fs->access_flags & SMB2_FILE_DELETE_ON_CLOSE) { printf("DELETE_ON_CLOSE "); } printf("\n"); printf("Alignment Requirement: %d\n", fs->alignment_requirement); printf("Name: %s\n", fs->name); smb2_free_data(smb2, fs); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-truncate-sync.c0000664000175000017500000000557714732155517017457 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-truncate-sync \n\n" "URL format: " "smb://[@]>[:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; if (argc < 3) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } if (smb2_truncate(smb2, url->path, strtoll(argv[2], NULL, 10)) < 0) { printf("smb2_truncate failed. %s\n", smb2_get_error(smb2)); exit(10); } smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/Makefile.am0000664000175000017500000000253614732155517015677 0ustar polpypolpynoinst_PROGRAMS = smb2-cat-async smb2-cat-sync \ smb2-ftruncate-sync \ smb2-ls-async \ smb2-put-async \ smb2-put-sync \ smb2-raw-fsstat-async \ smb2-raw-getsd-async \ smb2-raw-stat-async \ smb2-readlink \ smb2-lsa-lookupsids \ smb2-lseek-sync \ smb2-share-enum \ smb2-share-info \ smb2-stat-sync \ smb2-statvfs-sync \ smb2-truncate-sync \ smb2-rename-sync \ smb2-CMD-FIND \ smb2-server-sync AM_CPPFLAGS = \ -I$(abs_top_srcdir)/include \ -I$(abs_top_srcdir)/include/smb2 \ "-D_U_=__attribute__((unused))" \ -Wall -Werror COMMON_LIBS = ../lib/libsmb2.la smb2_cat_async_LDADD = $(COMMON_LIBS) smb2_cat_sync_LDADD = $(COMMON_LIBS) smb2_ftruncate_sync_LDADD = $(COMMON_LIBS) smb2_ls_async_LDADD = $(COMMON_LIBS) smb2_put_async_LDADD = $(COMMON_LIBS) smb2_put_sync_LDADD = $(COMMON_LIBS) smb2_raw_fsstat_async_LDADD = $(COMMON_LIBS) smb2_raw_getsd_async_LDADD = $(COMMON_LIBS) smb2_raw_stat_async_LDADD = $(COMMON_LIBS) smb2_readlink_LDADD = $(COMMON_LIBS) smb2_lsa_lookupsids_LDADD = $(COMMON_LIBS) smb2_lseek_sync_LDADD = $(COMMON_LIBS) smb2_share_enum_LDADD = $(COMMON_LIBS) smb2_share_info_LDADD = $(COMMON_LIBS) smb2_stat_sync_LDADD = $(COMMON_LIBS) smb2_statvfs_sync_LDADD = $(COMMON_LIBS) smb2_truncate_sync_LDADD = $(COMMON_LIBS) smb2_rename_sync_LDADD = $(COMMON_LIBS) smb2_CMD_FIND_LDADD = $(COMMON_LIBS) smb2_server_sync_LDADD = $(COMMON_LIBS) libsmb2-6.2/examples/smb2-rename-sync.c0000664000175000017500000000570014732155517017065 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2022 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-rename-sync \n\n" "URL format: " "smb://[@]>[:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; if (argc < 4) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } printf("Renaming %s -> %s\n", argv[2], argv[3]); if (smb2_rename(smb2, argv[2], argv[3]) < 0) { printf("smb2_rename failed. %s\n", smb2_get_error(smb2)); exit(10); } smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-raw-getsd-async.c0000664000175000017500000003023214732155517017652 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2017 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-raw-getsd-async \n\n" "URL format: " "smb://[@]>[:]//\n"); exit(1); } struct sync_cb_data { int is_finished; int status; void *ptr; }; static int wait_for_reply(struct smb2_context *smb2, struct sync_cb_data *cb_data) { while (!cb_data->is_finished) { struct pollfd pfd; pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { fprintf(stderr, "Poll failed"); return -1; } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { fprintf(stderr, "smb2_service failed with : " "%s\n", smb2_get_error(smb2)); return -1; } } return 0; } static void generic_status_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; cb_data->is_finished = 1; cb_data->status = status; cb_data->ptr = command_data; } struct stat_cb_data { smb2_command_cb cb; void *cb_data; uint32_t status; struct smb2_security_descriptor *sd; }; static void stat_cb_3(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct stat_cb_data *stat_data = private_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } stat_data->cb(smb2, -nterror_to_errno(stat_data->status), stat_data->sd, stat_data->cb_data); free(stat_data); } static void stat_cb_2(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct stat_cb_data *stat_data = private_data; struct smb2_query_info_reply *rep = command_data; struct smb2_security_descriptor *sd = rep->output_buffer; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } if (stat_data->status != SMB2_STATUS_SUCCESS) { return; } /* Remember the sd structure so we can pass it back to the caller */ stat_data->sd = sd; } static void stat_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct stat_cb_data *stat_data = private_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } } static int send_compound_stat(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data) { struct stat_cb_data *stat_data; struct smb2_create_request cr_req; struct smb2_query_info_request qi_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; stat_data = malloc(sizeof(struct stat_cb_data)); if (stat_data == NULL) { fprintf(stderr, "Failed to allocate create_data"); return -1; } memset(stat_data, 0, sizeof(struct stat_cb_data)); stat_data->cb = cb; stat_data->cb_data = cb_data; /* CREATE command */ memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_READ_CONTROL; cr_req.file_attributes = 0; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = 0; cr_req.name = path; pdu = smb2_cmd_create_async(smb2, &cr_req, stat_cb_1, stat_data); if (pdu == NULL) { fprintf(stderr, "Failed to create create command\n"); free(stat_data); return -1; } /* QUERY INFO command */ memset(&qi_req, 0, sizeof(struct smb2_query_info_request)); qi_req.info_type = SMB2_0_INFO_SECURITY; qi_req.output_buffer_length = 65535; qi_req.additional_information = SMB2_OWNER_SECURITY_INFORMATION | SMB2_GROUP_SECURITY_INFORMATION | SMB2_DACL_SECURITY_INFORMATION; memcpy(qi_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_query_info_async(smb2, &qi_req, stat_cb_2, stat_data); if (next_pdu == NULL) { fprintf(stderr, "Failed to create query command\n"); free(stat_data); smb2_free_pdu(smb2, pdu); return -1; } smb2_add_compound_pdu(smb2, pdu, next_pdu); /* CLOSE command */ memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, stat_cb_3, stat_data); if (next_pdu == NULL) { fprintf(stderr, "Failed to create close command\n"); free(stat_data); smb2_free_pdu(smb2, pdu); return -1; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } static void print_sid(struct smb2_sid *sid) { int i; uint64_t ia = 0; if (sid == NULL) { printf("No SID"); return; } printf("S-1"); for(i = 0; i < SID_ID_AUTH_LEN; i++) { ia <<= 8; ia |= sid->id_auth[i]; } if (ia <= 0xffffffff) { printf("-%" PRIu64, ia); } else { printf("-0x%012" PRIx64, ia); } for (i = 0; i < sid->sub_auth_count; i++) { printf("-%u", sid->sub_auth[i]); } } static void print_ace(struct smb2_ace *ace) { printf("ACE: "); printf("Type:%d ", ace->ace_type); printf("Flags:0x%02x ", ace->ace_flags); switch (ace->ace_type) { case SMB2_ACCESS_ALLOWED_ACE_TYPE: case SMB2_ACCESS_DENIED_ACE_TYPE: case SMB2_SYSTEM_AUDIT_ACE_TYPE: case SMB2_SYSTEM_MANDATORY_LABEL_ACE_TYPE: printf("Mask:0x%08x ", ace->mask); print_sid(ace->sid); break; default: printf("can't print this type"); } printf("\n"); } static void print_acl(struct smb2_acl *acl) { struct smb2_ace *ace; printf("Revision: %d\n", acl->revision); printf("Ace count: %d\n", acl->ace_count); for (ace = acl->aces; ace; ace = ace->next) { print_ace(ace); } }; static void print_security_descriptor(struct smb2_security_descriptor *sd) { printf("Revision: %d\n", sd->revision); printf("Control: (0x%08x) ", sd->control); if (sd->control & SMB2_SD_CONTROL_SR) { printf("SR "); } if (sd->control & SMB2_SD_CONTROL_RM) { printf("RM "); } if (sd->control & SMB2_SD_CONTROL_PS) { printf("PS "); } if (sd->control & SMB2_SD_CONTROL_PD) { printf("PD "); } if (sd->control & SMB2_SD_CONTROL_SI) { printf("SI "); } if (sd->control & SMB2_SD_CONTROL_DI) { printf("DI "); } if (sd->control & SMB2_SD_CONTROL_SC) { printf("SC "); } if (sd->control & SMB2_SD_CONTROL_DC) { printf("DC "); } if (sd->control & SMB2_SD_CONTROL_DT) { printf("DT "); } if (sd->control & SMB2_SD_CONTROL_SS) { printf("SS "); } if (sd->control & SMB2_SD_CONTROL_SD) { printf("SD "); } if (sd->control & SMB2_SD_CONTROL_SP) { printf("SP "); } if (sd->control & SMB2_SD_CONTROL_DD) { printf("DD "); } if (sd->control & SMB2_SD_CONTROL_DP) { printf("DP "); } if (sd->control & SMB2_SD_CONTROL_GD) { printf("GD "); } if (sd->control & SMB2_SD_CONTROL_OD) { printf("OD "); } printf("\n"); if (sd->owner) { printf("Owner SID: "); print_sid(sd->owner); printf("\n"); } if (sd->group) { printf("Group SID: "); print_sid(sd->group); printf("\n"); } if (sd->dacl) { printf("DACL:\n"); print_acl(sd->dacl); } } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct sync_cb_data cb_data; struct smb2_security_descriptor *sd; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } memset(&cb_data, 0, sizeof(cb_data)); if (send_compound_stat(smb2, url->path, generic_status_cb, &cb_data) != 0) { printf("sending compound stat failed. %s\n", smb2_get_error(smb2)); exit(10); } if (wait_for_reply(smb2, &cb_data) < 0) { printf("failed waiting for a reply. %s\n", smb2_get_error(smb2)); exit(10); } if (cb_data.status != 0) { printf("Compound command sequence returned error 0x%08x\n", cb_data.status); exit(10); } sd = cb_data.ptr; print_security_descriptor(sd); smb2_free_data(smb2, sd); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-share-info.c0000664000175000017500000001520114732155517016674 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2020 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-dcerpc.h" #include "libsmb2-dcerpc-srvsvc.h" #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) #endif int is_finished; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-share-info \n\n" "URL format: " "smb://[@][:]/share\n"); exit(1); } void si_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct srvsvc_NetrShareGetInfo_rep *rep = command_data; free(cb_data); if (status) { printf("failed to get info for share (%s) %s\n", strerror(-status), dcerpc_get_error(dce)); exit(10); } printf("%-20s %-20s", rep->InfoStruct.ShareInfo1.netname.utf8, rep->InfoStruct.ShareInfo1.remark.utf8); if ((rep->InfoStruct.ShareInfo1.type & 3) == SHARE_TYPE_DISKTREE) { printf(" DISKTREE"); } if ((rep->InfoStruct.ShareInfo1.type & 3) == SHARE_TYPE_PRINTQ) { printf(" PRINTQ"); } if ((rep->InfoStruct.ShareInfo1.type & 3) == SHARE_TYPE_DEVICE) { printf(" DEVICE"); } if ((rep->InfoStruct.ShareInfo1.type & 3) == SHARE_TYPE_IPC) { printf(" IPC"); } if (rep->InfoStruct.ShareInfo1.type & SHARE_TYPE_TEMPORARY) { printf(" TEMPORARY"); } if (rep->InfoStruct.ShareInfo1.type & SHARE_TYPE_HIDDEN) { printf(" HIDDEN"); } printf("\n"); dcerpc_free_data(dce, rep); is_finished = 1; } void co_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct srvsvc_NetrShareGetInfo_req *si_req; struct smb2_url *url = cb_data; char *server; if (status != SMB2_STATUS_SUCCESS) { printf("failed to connect to SRVSVC (%s) %s\n", strerror(-status), dcerpc_get_error(dce)); exit(10); } si_req = calloc(1, sizeof(struct srvsvc_NetrShareGetInfo_req)); if (si_req == NULL) { printf("failed to allocate srvsvc_NetrShareGetInfo_req\n"); exit(10); } server = malloc(strlen(url->server) + 3); if (server == NULL) { printf("failed to allocate ServerName\n"); exit(10); } sprintf(server, "\\\\%s", url->server); si_req->ServerName.utf8 = server; si_req->NetName.utf8 = url->share; si_req->Level = 1; if (dcerpc_call_async(dce, SRVSVC_NETRSHAREGETINFO, srvsvc_NetrShareGetInfo_req_coder, si_req, srvsvc_NetrShareGetInfo_rep_coder, sizeof(struct srvsvc_NetrShareGetInfo_rep), si_cb, si_req) != 0) { printf("dcerpc_call_async failed with %s\n", dcerpc_get_error(dce)); free(si_req); exit(10); } free(server); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct dcerpc_context *dce; struct smb2_url *url; struct pollfd pfd; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } if (url->user) { smb2_set_user(smb2, url->user); } smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED); if (smb2_connect_share(smb2, url->server, "IPC$", NULL) < 0) { printf("Failed to connect to IPC$. %s\n", smb2_get_error(smb2)); exit(10); } dce = dcerpc_create_context(smb2); if (dce == NULL) { printf("Failed to create dce context. %s\n", smb2_get_error(smb2)); exit(10); } if (dcerpc_connect_context_async(dce, "srvsvc", &srvsvc_interface, co_cb, url) != 0) { printf("Failed to connect dce context. %s\n", smb2_get_error(smb2)); exit(10); } while (!is_finished) { pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { printf("Poll failed"); exit(10); } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { printf("smb2_service failed with : %s\n", smb2_get_error(smb2)); break; } } dcerpc_destroy_context(dce); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-statvfs-sync.c0000664000175000017500000000625314732155517017314 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 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. */ #define _GNU_SOURCE #include #include #if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) #include #endif #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-statvfs-sync \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct smb2_statvfs vfs; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } if (smb2_statvfs(smb2, url->path, &vfs) < 0) { printf("smb2_statvfs failed. %s\n", smb2_get_error(smb2)); exit(10); } printf("Blocksize:%d\n", vfs.f_bsize); printf("Blocks:%"PRIu64"\n", vfs.f_blocks); printf("Free:%"PRIu64"\n", vfs.f_bfree); printf("Avail:%"PRIu64"\n", vfs.f_bavail); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-server-sync.c0000664000175000017500000004050714732155517017130 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2024 by Brian Dodge 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #define PAD_TO_32BIT(len) ((len + 0x03) & 0xfffffffc) #define PAD_TO_64BIT(len) ((len + 0x07) & 0xfffffff8) static int fill_file_info(struct smb2_context *smb2, uint8_t info_type, uint8_t file_info_class, void **out_info) { uint8_t *info = NULL; int len = 0; switch (info_type) { case SMB2_0_INFO_FILE: switch (file_info_class) { case SMB2_FILE_BASIC_INFORMATION: { struct smb2_file_basic_info *fs; len = sizeof(struct smb2_file_basic_info); fs = malloc(len); if (!fs) { return -1; } memset(fs, 0, len); fs->file_attributes = 0; info = (uint8_t*)fs; break; } case SMB2_FILE_STANDARD_INFORMATION: { struct smb2_file_standard_info *fs; len = sizeof(struct smb2_file_standard_info); fs = malloc(len); if (!fs) { return -1; } memset(fs, 0, len); fs->allocation_size = 32; fs->end_of_file = 32; fs->number_of_links = 0; fs->delete_pending = 0; fs->directory = 0; info = (uint8_t*)fs; break; } case SMB2_FILE_RENAME_INFORMATION: break; case SMB2_FILE_ALL_INFORMATION: { struct smb2_file_all_info *fs; len = sizeof(struct smb2_file_all_info); fs = malloc(len); if (!fs) { return -1; } memset(fs, 0, len); fs->basic.file_attributes = 0; fs->standard.allocation_size = 32; fs->standard.end_of_file = 32; fs->standard.number_of_links = 0; fs->standard.delete_pending = 0; fs->standard.directory = 0; fs->index_number = 1; fs->ea_size = 0; fs->access_flags = 0xFFFFFFFF; fs->current_byte_offset = 0; fs->mode = 0; fs->alignment_requirement = 0; fs->name = (uint8_t*)"junk.txt"; info = (uint8_t*)fs; break; } case SMB2_FILE_NETWORK_OPEN_INFORMATION: { struct smb2_file_network_open_info *fs; len = sizeof(struct smb2_file_network_open_info); fs = malloc(len); if (!fs) { return -1; } memset(fs, 0, len); fs->file_attributes = 0; fs->allocation_size = 32; fs->end_of_file = 32; info = (uint8_t*)fs; break; } case SMB2_FILE_END_OF_FILE_INFORMATION: break; default: break; } break; case SMB2_0_INFO_FILESYSTEM: switch (file_info_class) { case SMB2_FILE_FS_VOLUME_INFORMATION: break; case SMB2_FILE_FS_SIZE_INFORMATION: { struct smb2_file_fs_size_info *fs; len = sizeof(struct smb2_file_fs_size_info); fs = malloc(len); if (!fs) { return -1; } fs->total_allocation_units = 0x100000; fs->available_allocation_units = 0x10000; fs->sectors_per_allocation_unit = 1; fs->bytes_per_sector = 512; info = (uint8_t*)fs; break; } case SMB2_FILE_FS_DEVICE_INFORMATION: { struct smb2_file_fs_device_info *fs; len = sizeof(struct smb2_file_fs_device_info); fs = malloc(len); if (!fs) { return -1; } fs->device_type = FILE_DEVICE_DISK; fs->characteristics = 0; info = (uint8_t*)fs; break; } case SMB2_FILE_FS_ATTRIBUTE_INFORMATION: { struct smb2_file_fs_attribute_info *fs; len = sizeof(struct smb2_file_fs_attribute_info); fs = malloc(len); if (!fs) { return -1; } fs->filesystem_attributes = 0x2; //FILE_CASE_PRESERVED_NAMES; fs->maximum_component_name_length = 0x100; fs->filesystem_name = (uint8_t*)"Sotero"; fs->filesystem_name_length = strlen((char*)fs->filesystem_name); info = (uint8_t*)fs; break; } case SMB2_FILE_FS_CONTROL_INFORMATION: break; case SMB2_FILE_FS_FULL_SIZE_INFORMATION: break; case SMB2_FILE_FS_SECTOR_SIZE_INFORMATION: break; default: break; } break; case SMB2_0_INFO_SECURITY: break; case SMB2_0_INFO_QUOTA: break; default: return 0; } *out_info = info; return len; } static int fill_dir_info(struct smb2_context *smb2, uint8_t **out_info) { static const char *files[] = { "junk.txt", "crap.bin" }; struct smb2_fileidbothdirectoryinformation *fsb; struct smb2_utf16 *fname = NULL; uint8_t *info; uint32_t fname_len; int len; int nfiles = sizeof(files)/sizeof(files[0]); int n; len = 0; for (n = 0; n < nfiles; n++) { len += PAD_TO_64BIT(sizeof(struct smb2_fileidbothdirectoryinformation) + 2 * strlen(files[n])); } info = malloc(len); if (!info) { //smb2_set_error(smb2, "can not alloc dir info", smb2_get_error(smb2)); return -ENOMEM; } memset(info, 0, len); len = 0; for (n = 0; n < nfiles; n++) { fname_len = 0; fname = smb2_utf8_to_utf16(files[n]); if (fname == NULL) { //smb2_set_error(smb2, "Could not convert name into UTF-16"); return -EINVAL; } fname_len = 2 * fname->len; fsb = (struct smb2_fileidbothdirectoryinformation *)(info + len); fsb->file_index = n; fsb->file_name_length = fname_len; fsb->short_name_length = sizeof(fsb->short_name); if (fsb->short_name_length > fname_len) { fsb->short_name_length = fname_len; } memcpy(fsb->short_name, fname->val, fsb->short_name_length); fsb->name = files[n]; len += PAD_TO_64BIT(sizeof(struct smb2_fileidbothdirectoryinformation)); free(fname); } *out_info = info; return len; } static int session_handler(struct smb2_server *srvr, struct smb2_context *smb2) { printf("Selected dialect %04x\n", smb2_get_dialect(smb2)); return 0; } static int authorize_handler(struct smb2_server *srvr, struct smb2_context *smb2, const char *user, const char *domain, const char *workstation) { if (user) { smb2_set_user(smb2, user); smb2_set_password_from_file(smb2); return 0; } return -1; } static int logoff_handler(struct smb2_server *srvr, struct smb2_context *smb2) { return 0; } static int tree_connect_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_tree_connect_request *req, struct smb2_tree_connect_reply *rep) { rep->share_type = SMB2_SHARE_TYPE_DISK; rep->maximal_access = 0x101f01ff; if (req->path && req->path_length) { int ei = (req->path_length / 2) - 4; if (ei >= 0) { if (req->path[ei] == 'I' && req->path[ei + 3] == '$') { rep->share_type = SMB2_SHARE_TYPE_PIPE; rep->maximal_access = 0x1f00a9; } } } rep->share_flags = 0; rep->capabilities = 0; return 0; } static int tree_disconnect_handler(struct smb2_server *srvr, struct smb2_context *smb2, const uint32_t tree_id) { return 0; } static int create_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_create_request *req, struct smb2_create_reply *rep) { rep->file_attributes = SMB2_FILE_ATTRIBUTE_NORMAL; return 0; } static int close_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_close_request *req, struct smb2_close_reply *rep) { memset(rep, 0, sizeof(*rep)); return 0; } static int flush_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_flush_request *req) { return 0; } static int read_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_read_request *req, struct smb2_read_reply *rep) { if (req->offset > 32) { rep->data = NULL; rep->data_length = 0; rep->data_remaining = 0; return 0; } rep->data_offset = req->offset; rep->data_length = 32; rep->data_remaining = 0; rep->data = malloc(rep->data_length); if (!rep->data) { return -ENOMEM; } for (uint32_t i = 0; i < rep->data_length; i++) { rep->data[i] = ('A' + i) & 0xff; } return 0; } static int write_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_write_request *req, struct smb2_write_reply *rep) { rep->count = req->length; rep->remaining = 0; return 0; } static int lock_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_lock_request *req) { return 0; } int ioctl_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_ioctl_request *req, struct smb2_ioctl_reply *rep) { memset(rep, 0, sizeof(*rep)); rep->ctl_code = req->ctl_code; memcpy(rep->file_id, req->file_id, SMB2_FD_SIZE); switch(rep->ctl_code) { case SMB2_FSCTL_VALIDATE_NEGOTIATE_INFO: break; default: return 1; } return 0; } static int cancel_handler(struct smb2_server *srvr, struct smb2_context *smb2) { return 0; } static int echo_handler(struct smb2_server *srvr, struct smb2_context *smb2) { return 0; } static int query_directory_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_query_directory_request *req, struct smb2_query_directory_reply *rep) { static int rets; if (rets++ == 0) { rep->output_buffer_length = fill_dir_info(smb2, &rep->output_buffer); } else { rep->output_buffer_length = 0; rep->output_buffer = NULL; rets = 0; } return 0; } static int query_info_handler(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_query_info_request *req, struct smb2_query_info_reply *rep) { rep->output_buffer_length = fill_file_info(smb2, req->info_type, req->file_info_class, &rep->output_buffer); return rep->output_buffer_length > 0 ? 0 : -1; } struct smb2_server_request_handlers test_handlers = { NULL, authorize_handler, session_handler, logoff_handler, tree_connect_handler, tree_disconnect_handler, create_handler, close_handler, flush_handler, read_handler, write_handler, NULL, NULL, lock_handler, ioctl_handler, cancel_handler, echo_handler, query_directory_handler, NULL, query_info_handler, NULL }; struct smb2_server server; int usage(void) { fprintf(stderr, "Usage:\n" "smbsever [port]\n\n"); exit(1); } void on_smb2_error(struct smb2_context *smb2, const char *error_string) { if (error_string) { fprintf(stderr, "%p: %s\n", smb2, error_string); } } void on_new_client(struct smb2_context *smb2, void *cb_data) { struct smb2_context **pctx = (struct smb2_context **)cb_data; printf("New connection: %p\n", smb2); /* setup client context */ smb2_set_version(smb2, SMB2_VERSION_ANY); // smb2_set_version(smb2, SMB2_VERSION_0210); smb2_register_error_callback(smb2, on_smb2_error); *pctx = smb2; } int main(int argc, char **argv) { struct smb2_context *smb2 = NULL; int err; if (argc < 2) { usage(); } memset(&server, 0, sizeof(server)); server.handlers = &test_handlers; server.signing_enabled = 1; server.allow_anonymous = 1; server.port = strtoul(argv[1], NULL, 0); err = smb2_serve_port(&server, 1, on_new_client, (void *)&smb2); if (err) { fprintf(stderr, "smb2_serv_port failed %d\n", err); exit(err); } if (smb2) { fprintf(stderr, "client error %s\n", smb2_get_error(smb2)); } return 0; } libsmb2-6.2/examples/CMakeLists.txt0000664000175000017500000000137214732155517016400 0ustar polpypolpylist(APPEND CORE_LIBRARIES ${POPT_LIBRARY}) set(SOURCES smb2-cat-async smb2-cat-sync smb2-ftruncate-sync smb2-ls-async smb2-put-async smb2-put-sync smb2-raw-stat-async smb2-raw-getsd-async smb2-readlink smb2-lsa-lookupsids smb2-lseek-sync smb2-share-enum smb2-share-info smb2-stat-sync smb2-truncate-sync smb2-CMD-FIND smb2-server-sync) foreach(TARGET ${SOURCES}) add_executable(${TARGET} ${TARGET}.c) target_link_libraries(${TARGET} smb2 ${CORE_LIBRARIES}) add_dependencies(${TARGET} smb2) endforeach() add_definitions(-Werror "-D_U_=__attribute__((unused))") libsmb2-6.2/examples/smb2-readlink.c0000664000175000017500000000567614732155517016451 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2019 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" int usage(void) { fprintf(stderr, "Usage:\n" "smb2-readlink \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; char buf[256]; int rc; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } rc = smb2_readlink(smb2, url->path, buf, 256); if (rc == 0) { printf("Link:%s\n", buf); } else { printf("Error: %s (%s)\n", smb2_get_error(smb2), strerror(-rc)); } smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-share-enum.c0000664000175000017500000001517714732155517016721 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) #include #endif #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) struct pollfd { int fd; short events; short revents; }; int poll(struct pollfd *fds, unsigned int nfds, int timo); #endif int is_finished; int level; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-share-enum [-l level] \n\n" "URL format: " "smb://[@][:]/\n"); exit(1); } void se_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct srvsvc_NetrShareEnum_rep *rep = command_data; int i; if (status) { printf("failed to enumerate shares (%s) %s\n", strerror(-status), smb2_get_error(smb2)); exit(10); } /* We always only use Level1 for netshare enum */ switch (level) { case SHARE_INFO_0: printf("Number of shares:%d\n", rep->ses.ShareInfo.Level0.EntriesRead); for (i = 0; i < rep->ses.ShareInfo.Level0.EntriesRead; i++) { printf("%-20s\n", rep->ses.ShareInfo.Level0.Buffer->share_info_0[i].netname.utf8); } break; case SHARE_INFO_1: printf("Number of shares:%d\n", rep->ses.ShareInfo.Level1.EntriesRead); for (i = 0; i < rep->ses.ShareInfo.Level1.EntriesRead; i++) { printf("%-20s %-20s", rep->ses.ShareInfo.Level1.Buffer->share_info_1[i].netname.utf8, rep->ses.ShareInfo.Level1.Buffer->share_info_1[i].remark.utf8); if ((rep->ses.ShareInfo.Level1.Buffer->share_info_1[i].type & 3) == SHARE_TYPE_DISKTREE) { printf(" DISKTREE"); } if ((rep->ses.ShareInfo.Level1.Buffer->share_info_1[i].type & 3) == SHARE_TYPE_PRINTQ) { printf(" PRINTQ"); } if ((rep->ses.ShareInfo.Level1.Buffer->share_info_1[i].type & 3) == SHARE_TYPE_DEVICE) { printf(" DEVICE"); } if ((rep->ses.ShareInfo.Level1.Buffer->share_info_1[i].type & 3) == SHARE_TYPE_IPC) { printf(" IPC"); } if (rep->ses.ShareInfo.Level1.Buffer->share_info_1[i].type & SHARE_TYPE_TEMPORARY) { printf(" TEMPORARY"); } if (rep->ses.ShareInfo.Level1.Buffer->share_info_1[i].type & SHARE_TYPE_HIDDEN) { printf(" HIDDEN"); } printf("\n"); } break; } smb2_free_data(smb2, rep); is_finished = 1; } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct pollfd pfd; int opt; while ((opt = getopt(argc, argv, "l:")) != -1) { switch (opt) { case 'l': level = atoi(optarg); break; default: /* '?' */ usage(); } } if (optind >= argc) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } switch (level) { case SHARE_INFO_0: case SHARE_INFO_1: break; default: fprintf(stderr, "level must be 0/1\n"); exit(0); } url = smb2_parse_url(smb2, argv[optind]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } if (url->user) { smb2_set_user(smb2, url->user); } smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED); if (smb2_connect_share(smb2, url->server, "IPC$", NULL) < 0) { printf("Failed to connect to IPC$. %s\n", smb2_get_error(smb2)); exit(10); } if (smb2_share_enum_async(smb2, level, se_cb, NULL) != 0) { printf("smb2_share_enum failed. %s\n", smb2_get_error(smb2)); exit(10); } while (!is_finished) { pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { printf("Poll failed"); exit(10); } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { printf("smb2_service failed with : %s\n", smb2_get_error(smb2)); break; } } smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-put-sync.c0000664000175000017500000000667114732155517016436 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #include #if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) #include #endif #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" uint8_t buf[256 * 1024]; uint32_t pos; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-put-sync \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct smb2fh *fh; int count; int fd; if (argc < 2) { usage(); } fd = open(argv[1], O_RDONLY); if (fd == -1) { printf("Failed to open local file %s (%s)\n", argv[1], strerror(errno)); exit(10); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[2]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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)); exit(10); } fh = smb2_open(smb2, url->path, O_WRONLY|O_CREAT); if (fh == NULL) { printf("smb2_open failed. %s\n", smb2_get_error(smb2)); exit(10); } while ((count = read(fd, buf, 1024)) > 0) { smb2_write(smb2, fh, buf, count); }; close(fd); smb2_close(smb2, fh); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/examples/smb2-lsa-lookupsids.c0000664000175000017500000002352114732155517017616 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2020 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-dcerpc.h" #include "libsmb2-dcerpc-lsa.h" #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) #endif int is_finished; struct ndr_context_handle PolicyHandle; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-lsa-lookupsids \n\n" "URL format: " "smb://[@][:]/share\n"); exit(1); } void print_sid(RPC_SID *sid) { int i; uint64_t ia = 0; printf("S-%d-", sid->Revision); for (i = 0; i < 6; i++) { ia <<= 8; ia |= sid->IdentifierAuthority[i]; } printf("%ld", ia); for (i = 0; i < sid->SubAuthorityCount; i++) { printf("-%d", sid->SubAuthority[i]); } } void cl_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct lsa_close_rep *rep = command_data; if (status) { dcerpc_free_data(dce, rep); printf("failed to close policy handle (%s) %s\n", strerror(-status), dcerpc_get_error(dce)); exit(10); } dcerpc_free_data(dce, rep); is_finished = 1; } void ls_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct lsa_lookupsids2_rep *rep = command_data; struct lsa_close_req cl_req; int i; if (status) { dcerpc_free_data(dce, rep); printf("failed to lookup sids (%s) %s\n", strerror(-status), dcerpc_get_error(dce)); exit(10); } printf("ReferencedDomains\n"); printf(" Entries:%d\n", rep->ReferencedDomains.Entries); printf(" MaxEntries:%d\n", rep->ReferencedDomains.MaxEntries); for(i = 0; i < rep->ReferencedDomains.Entries; i++) { printf(" Name:%s SID:", rep->ReferencedDomains.Domains[i].Name); print_sid(&rep->ReferencedDomains.Domains[i].Sid); printf("\n"); } printf("TranslatedNames\n"); printf(" Entries:%d\n", rep->TranslatedNames.Entries); for(i = 0; i < rep->TranslatedNames.Entries; i++) { printf(" Name:%s DomainIndex:%d\n", rep->TranslatedNames.Names[i].Name, rep->TranslatedNames.Names[i].DomainIndex); } memcpy(&cl_req.PolicyHandle, &PolicyHandle, sizeof(struct ndr_context_handle)); dcerpc_free_data(dce, rep); if (dcerpc_call_async(dce, LSA_CLOSE, lsa_Close_req_coder, &cl_req, lsa_Close_rep_coder, sizeof(struct lsa_close_rep), cl_cb, NULL) != 0) { printf("dcerpc_call_async failed with %s\n", dcerpc_get_error(dce)); exit(10); } } void op_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct lsa_openpolicy2_rep *rep = command_data; struct lsa_lookupsids2_req ls_req; PRPC_SID sid, *sids; int num_sids; uint32_t sa[2]; if (status) { dcerpc_free_data(dce, rep); printf("failed to get policy handle (%s) %s\n", strerror(-status), dcerpc_get_error(dce)); exit(10); } memcpy(&PolicyHandle, &rep->PolicyHandle, sizeof(struct ndr_context_handle)); memcpy(&ls_req.PolicyHandle, &PolicyHandle, sizeof(struct ndr_context_handle)); sid = malloc(sizeof(*sid) + 2 * sizeof(uint32_t)); if (sid == NULL) { printf("failed to allocate SID\n"); exit(10); } sid->Revision = 1; sid->SubAuthorityCount = 2; memcpy(sid->IdentifierAuthority, NT_SID_AUTHORITY, 6); sid->SubAuthority = &sa[0]; sid->SubAuthority[0] = 32; sid->SubAuthority[1] = 544; num_sids = 2; sids = malloc(num_sids * sizeof(PRPC_SID)); if (sids == NULL) { printf("failed to allocate SIDs\n"); exit(10); } ls_req.SidEnumBuffer.Entries = num_sids; ls_req.SidEnumBuffer.SidInfo = sids; ls_req.SidEnumBuffer.SidInfo[0] = sid; ls_req.SidEnumBuffer.SidInfo[1] = sid; ls_req.TranslatedNames.Entries = 0; ls_req.TranslatedNames.Names = NULL; ls_req.LookupLevel = LsapLookupWksta; dcerpc_free_data(dce, rep); if (dcerpc_call_async(dce, LSA_LOOKUPSIDS2, lsa_LookupSids2_req_coder, &ls_req, lsa_LookupSids2_rep_coder, sizeof(struct lsa_lookupsids2_rep), ls_cb, NULL) != 0) { printf("dcerpc_call_async failed with %s\n", dcerpc_get_error(dce)); exit(10); } free(sid); free(sids); } void co_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct lsa_openpolicy2_req op_req; struct smb2_url *url = cb_data; if (status != SMB2_STATUS_SUCCESS) { printf("failed to connect to LSA (%s) %s\n", strerror(-status), dcerpc_get_error(dce)); exit(10); } op_req.SystemName = malloc(strlen(url->server) + 3); if (op_req.SystemName == NULL) { printf("failed to allocate SystemName\n"); exit(10); } sprintf(op_req.SystemName, "\\\\%s", url->server); op_req.ObjectAttributes.Length = 24; op_req.DesiredAccess = POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION; if (dcerpc_call_async(dce, LSA_OPENPOLICY2, lsa_OpenPolicy2_req_coder, &op_req, lsa_OpenPolicy2_rep_coder, sizeof(struct lsa_openpolicy2_rep), op_cb, NULL) != 0) { printf("dcerpc_call_async failed with %s\n", dcerpc_get_error(dce)); exit(10); } free(op_req.SystemName); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct dcerpc_context *dce; struct smb2_url *url; struct pollfd pfd; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } if (url->user) { smb2_set_user(smb2, url->user); } smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED); if (smb2_connect_share(smb2, url->server, "IPC$", NULL) < 0) { printf("Failed to connect to IPC$. %s\n", smb2_get_error(smb2)); exit(10); } dce = dcerpc_create_context(smb2); if (dce == NULL) { printf("Failed to create dce context. %s\n", smb2_get_error(smb2)); exit(10); } if (dcerpc_connect_context_async(dce, "lsarpc", &lsa_interface, co_cb, url) != 0) { printf("Failed to connect dce context. %s\n", smb2_get_error(smb2)); exit(10); } while (!is_finished) { pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { printf("Poll failed"); exit(10); } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { printf("smb2_service failed with : %s\n", smb2_get_error(smb2)); break; } } dcerpc_destroy_context(dce); smb2_disconnect_share(smb2); smb2_destroy_url(url); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/Xbox 360/0000775000175000017500000000000014732155517013230 5ustar polpypolpylibsmb2-6.2/Xbox 360/libsmb2.vcxproj0000664000175000017500000004263314732155517016207 0ustar polpypolpy CodeAnalysis Xbox 360 Debug Xbox 360 Profile Xbox 360 Profile_FastCap Xbox 360 Release Xbox 360 Release_LTCG Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4} Xbox360Proj StaticLibrary MultiByte StaticLibrary MultiByte StaticLibrary MultiByte StaticLibrary MultiByte StaticLibrary MultiByte true StaticLibrary true MultiByte $(OutDir)$(ProjectName).lib $(OutDir)$(ProjectName).lib $(OutDir)$(ProjectName).lib $(OutDir)$(ProjectName).lib $(OutDir)$(ProjectName).lib $(OutDir)$(ProjectName).lib NotUsing Level3 ProgramDatabase Disabled false true false $(OutDir)$(ProjectName).pch MultiThreadedDebug _DEBUG;_XBOX;_LIB;NEED_POLL;NEED_GETPID;NEED_GETLOGIN_R;NEED_RANDOM;NEED_SRANDOM;NEED_GETADDRINFO;NEED_FREEADDRINFO;XBOX_360_PLATFORM;HAVE_CONFIG_H;_U_=/**/ Callcap CompileAsC ..\include\;..\include\smb2;..\include\xbox 360 AnySuitable true true NotUsing Level4 ProgramDatabase Disabled false true AnalyzeOnly false $(OutDir)$(ProjectName).pch MultiThreadedDebug _DEBUG;_XBOX;_LIB Callcap true Level3 NotUsing Full true false true ProgramDatabase Size false $(OutDir)$(ProjectName).pch MultiThreaded NDEBUG;_XBOX;PROFILE;_LIB Callcap true false xapilib.lib true Level3 NotUsing Full true false true ProgramDatabase Fastcap Size false $(OutDir)$(ProjectName).pch MultiThreaded NDEBUG;_XBOX;PROFILE;FASTCAP;_LIB true false true Level3 NotUsing Full true true ProgramDatabase Size false false $(OutDir)$(ProjectName).pch MultiThreaded NDEBUG;_XBOX;_LIB;NEED_POLL;NEED_GETPID;NEED_GETLOGIN_R;NEED_RANDOM;NEED_SRANDOM;NEED_GETADDRINFO;NEED_FREEADDRINFO;XBOX_360_PLATFORM;HAVE_CONFIG_H;_U_=/**/ ..\include\;..\include\smb2;..\include\xbox 360 CompileAsC AnySuitable true true true true Level3 NotUsing Full true true ProgramDatabase Size false false $(OutDir)$(ProjectName).pch MultiThreaded NDEBUG;_XBOX;LTCG;_LIB;NEED_POLL;NEED_GETPID;NEED_GETLOGIN_R;NEED_RANDOM;NEED_SRANDOM;NEED_GETADDRINFO;NEED_FREEADDRINFO;XBOX_360_PLATFORM;HAVE_CONFIG_H;_U_=/**/ true ..\include\;..\include\smb2;..\include\xbox 360 CompileAsC true true true libsmb2-6.2/Xbox 360/libsmb2.vcxproj.filters0000664000175000017500000002064214732155517017652 0ustar polpypolpy include lib lib lib lib lib lib lib {028f1ea9-92cf-4908-a035-80459a8cf956} {28810bac-fb60-4810-8ce9-1d5c989d4c75} {8f3e89d9-a92f-4650-a970-3af5fddd92fe} {6c01c6cd-316c-4bff-82ea-f611e60057e9} include\smb2 include\smb2 include\smb2 include\smb2 include\smb2 include\smb2 include\smb2 include include include lib lib lib lib lib lib lib lib lib lib lib include include\xbox 360 lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib lib libsmb2-6.2/Xbox 360/libsmb2.sln0000664000175000017500000000346414732155517015307 0ustar polpypolpy Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsmb2", "libsmb2.vcxproj", "{B2F1D3EE-7D56-4862-9286-5937E1A554A4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CodeAnalysis|Xbox 360 = CodeAnalysis|Xbox 360 Debug|Xbox 360 = Debug|Xbox 360 Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360 Profile|Xbox 360 = Profile|Xbox 360 Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360 Release|Xbox 360 = Release|Xbox 360 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.CodeAnalysis|Xbox 360.ActiveCfg = CodeAnalysis|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.CodeAnalysis|Xbox 360.Build.0 = CodeAnalysis|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Profile|Xbox 360.Build.0 = Profile|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 {B2F1D3EE-7D56-4862-9286-5937E1A554A4}.Release|Xbox 360.Build.0 = Release|Xbox 360 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal libsmb2-6.2/.gitignore0000664000175000017500000000046014732155517014007 0ustar polpypolpy.* *.in *.la *.a *.lo *.o *.obj *.lib *.dll *.ilk *.pdb *.ex? *-stamp Makefile aclocal.m4 ar-lib autom4te.cache build/ compile config.guess config.h.in config.h.in~ config.log config.status config.sub configure depcomp install-sh m4/ missing stamp-h1 libsmb2.pc libtool ltmain.sh lib/ps2/imports.c *.bak libsmb2-6.2/tests/0000775000175000017500000000000014732155517013161 5ustar polpypolpylibsmb2-6.2/tests/prog_rmdir.c0000664000175000017500000000600514732155517015472 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #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" "prog_rmdir \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; int rc = 0; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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; } if (smb2_rmdir(smb2, url->path)) { printf("smb2_rmdir failed. %s\n", smb2_get_error(smb2)); goto out_disconnect; } out_disconnect: smb2_disconnect_share(smb2); out_context: smb2_destroy_url(url); smb2_destroy_context(smb2); return rc; } libsmb2-6.2/tests/smb2-dcerpc-coder-test.c0000664000175000017500000007155014732155517017505 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2020 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-dcerpc.h" #include "libsmb2-dcerpc-lsa.h" #include "libsmb2-dcerpc-srvsvc.h" #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) #endif void dcerpc_set_tctx(struct dcerpc_context *ctx, int tctx); void dcerpc_set_endian(struct dcerpc_pdu *pdu, int little_endian); int is_finished; struct ndr_context_handle PolicyHandle; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-dcerpc-coder-test\n\n"); exit(1); } typedef int (*compare_func)(void *ptr1, void *ptr2); static void test_dcerpc_coder(struct dcerpc_context *dce, char *method, dcerpc_coder coder, compare_func cmp, void *req, int req_size, int expected_offset, uint8_t *expected_data, int print_buf, int endian) { struct dcerpc_pdu *pdu1, *pdu2; struct smb2_iovec iov; static unsigned char buf[65536]; int offset; int i; char *req2 = NULL; printf("Test codec for %s\n", method); /* Encode */ pdu1 = dcerpc_allocate_pdu(dce, DCERPC_ENCODE, req_size); iov.len = 65536; iov.buf = buf; memset(iov.buf, 0, iov.len); offset = 0; dcerpc_set_endian(pdu1, endian); if (dcerpc_ptr_coder(dce, pdu1, &iov, &offset, req, PTR_REF, coder)) { printf("Encoding failed\n"); exit(20); } if (offset != expected_offset) { printf("Encoding failed 0. Offset/Expected mismatch. %d/%d\n", offset, expected_offset); printf("\n"); exit(20); } if (print_buf) { printf("offset:%d expected:%d\n", offset, expected_offset); for (i = 0; i < offset; i++) { if (i % 8 == 0) printf("[0x%02x] ", i); printf("0x%02x, ", iov.buf[i]); if (i % 8 == 7) printf("\n"); } printf("\n"); } /* Fake unque pointers. different implementations implement them differently and I don't want to have to modify buffers that I take from genuine network traffic. */ { int o; for (o = 0; o < offset; o+= 8) { if (!memcmp(&buf[o], "UptrrtpU", 8)) { memcpy(&buf[o], &expected_data[o], 8); } } } //int expected_offset, uint8_t *expected_data, if (memcmp(iov.buf, expected_data, expected_offset)) { printf("Encoding failed 1. Data Mismatch\n"); for (i = 0; i < expected_offset; i++) { if (iov.buf[i] != expected_data[i]) { printf("[0x%02x]: Expected:0x%02x Got:0x%02x\n", i, expected_data[i], iov.buf[i]); } } exit(20); } /* Decode it again */ req2 = calloc(1, req_size); pdu2 = dcerpc_allocate_pdu(dce, DCERPC_DECODE, req_size); offset = 0; dcerpc_set_endian(pdu2, endian); if (dcerpc_ptr_coder(dce, pdu2, &iov, &offset, req2, PTR_REF, coder)) { printf("Encoding failed\n"); exit(20); } if (offset != expected_offset) { printf("Encoding failed 2. Offset/Expected mismatch. %d/%d\n", offset, expected_offset); exit(20); } cmp(req, req2); dcerpc_free_pdu(dce, pdu1); dcerpc_free_pdu(dce, pdu2); free(req2); } static int compare_utf16(void *ptr1, void *ptr2) { struct dcerpc_utf16 *s1 = ptr1; struct dcerpc_utf16 *s2 = ptr2; if (strcmp(s1->utf8, s2->utf8)) { printf("Compare ->utf8 failed %s != %s\n", s1->utf8, s2->utf8); exit(20); } return 0; } static void test_utf16_ndr32_le(struct dcerpc_context *dce) { struct dcerpc_utf16 s1; unsigned char buf[] = { 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x00, 0x00 }; s1.utf8 = "\\\\win16-1"; dcerpc_set_tctx(dce, 0); /* NDR32 */ test_dcerpc_coder(dce, "dcerpc_utf16 NDR32 LE", dcerpc_utf16z_coder, compare_utf16, &s1, sizeof(s1), sizeof(buf), buf, 0, 1); } static void test_utf16_ndr32_be(struct dcerpc_context *dce) { struct dcerpc_utf16 s1; unsigned char buf[] = { 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x00 }; s1.utf8 = "\\\\win16-1"; dcerpc_set_tctx(dce, 0); /* NDR32 */ test_dcerpc_coder(dce, "dcerpc_utf16 NDR32 BE", dcerpc_utf16z_coder, compare_utf16, &s1, sizeof(s1), sizeof(buf), buf, 0, 0); } static void test_utf16_ndr64_le(struct dcerpc_context *dce) { struct dcerpc_utf16 s1; unsigned char buf[] = { 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x00, 0x00 }; s1.utf8 = "\\\\win16-1"; dcerpc_set_tctx(dce, 1); /* NDR64 */ test_dcerpc_coder(dce, "dcerpc_utf16 NDR64 LE", dcerpc_utf16z_coder, compare_utf16, &s1, sizeof(s1), sizeof(buf), buf, 0, 1); } /* struct srvsvc_SHARE_INFO_1 { struct dcerpc_utf16 netname; uint32_t type; struct dcerpc_utf16 remark; }; int srvsvc_SHARE_INFO_1_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) */ static int compare_SHARE_INFO_1(void *ptr1, void *ptr2) { struct srvsvc_SHARE_INFO_1 *s1 = ptr1; struct srvsvc_SHARE_INFO_1 *s2 = ptr2; if (strcmp(s1->netname.utf8, s2->netname.utf8)) { printf("Compare ->netname failed %s != %s\n", s1->netname.utf8, s2->netname.utf8); exit(20); } if (s1->type != s2->type) { printf("Compare ->type failed 0x%08x != 0x%08x\n", s1->type, s2->type); exit(20); } if (strcmp(s1->remark.utf8, s2->remark.utf8)) { printf("Compare ->remark failed %s != %s\n", s1->remark.utf8, s2->remark.utf8); exit(20); } return 0; } static void test_SHARE_INFO_1_ndr32_le(struct dcerpc_context *dce) { struct srvsvc_SHARE_INFO_1 s1; unsigned char buf[] = { 0x55, 0x70, 0x74, 0x72, 0x03, 0x00, 0x00, 0x80, 0x55, 0x70, 0x74, 0x72, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x49, 0x00, 0x50, 0x00, 0x43, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x49, 0x00, 0x50, 0x00, 0x43, 0x00, 0x00, 0x00 }; s1.netname.utf8 = "IPC$"; s1.type = 0x80000003; s1.remark.utf8 = "Remote IPC"; dcerpc_set_tctx(dce, 0); /* NDR32 */ test_dcerpc_coder(dce, "dcerpc_SHARE_INFO_1 NDR32 LE", srvsvc_SHARE_INFO_1_coder, compare_SHARE_INFO_1, &s1, sizeof(s1), sizeof(buf), buf, 0, 1); } static int compare_SHARE_INFO_1_CONTAINER(void *ptr1, void *ptr2) { struct srvsvc_SHARE_INFO_1_CONTAINER *s1 = ptr1; struct srvsvc_SHARE_INFO_1_CONTAINER *s2 = ptr2; int i; if (s1->EntriesRead != s2->EntriesRead) { printf("Compare EntriesRead failed %d != %d\n", s1->EntriesRead, s2->EntriesRead); exit(20); } for (i = 0; i < 10; i++) { if (strcmp(s1->Buffer->share_info_1[i].netname.utf8, s2->Buffer->share_info_1[i].netname.utf8)) { printf("Compare ->netname failed %s != %s\n", s1->Buffer->share_info_1[i].netname.utf8, s2->Buffer->share_info_1[i].netname.utf8); exit(20); } if (s1->Buffer->share_info_1[i].type != s2->Buffer->share_info_1[i].type) { printf("Compare ->type failed %d != %d\n", s1->Buffer->share_info_1[i].type, s2->Buffer->share_info_1[i].type); exit(20); } if (strcmp(s1->Buffer->share_info_1[i].remark.utf8, s2->Buffer->share_info_1[i].remark.utf8)) { printf("Compare ->remark failed %s != %s\n", s1->Buffer->share_info_1[i].remark.utf8, s2->Buffer->share_info_1[i].remark.utf8); exit(20); } } return 0; } static void test_SHARE_INFO_1_CONTAINER_ndr32_le(struct dcerpc_context *dce) { struct srvsvc_SHARE_INFO_1_carray ca; struct srvsvc_SHARE_INFO_1_CONTAINER s1; struct srvsvc_SHARE_INFO_1 si[10]; unsigned char buf[] = { /*000*/ 0x0a, 0x00, 0x00, 0x00, 0x55, 0x70, 0x74, 0x72, 0x0a, 0x00, 0x00, 0x00, 0x55, 0x70, 0x74, 0x72, /*010*/ 0x00, 0x00, 0x00, 0x80, 0x55, 0x70, 0x74, 0x72, 0x55, 0x70, 0x74, 0x72, 0x00, 0x00, 0x00, 0x00, /*020*/ 0x55, 0x70, 0x74, 0x72, 0x55, 0x70, 0x74, 0x72, 0x00, 0x00, 0x00, 0x80, 0x55, 0x70, 0x74, 0x72, /*030*/ 0x55, 0x70, 0x74, 0x72, 0x00, 0x00, 0x00, 0x00, 0x55, 0x70, 0x74, 0x72, 0x55, 0x70, 0x74, 0x72, /*040*/ 0x00, 0x00, 0x00, 0x00, 0x55, 0x70, 0x74, 0x72, 0x55, 0x70, 0x74, 0x72, 0x03, 0x00, 0x00, 0x80, /*050*/ 0x55, 0x70, 0x74, 0x72, 0x55, 0x70, 0x74, 0x72, 0x00, 0x00, 0x00, 0x00, 0x55, 0x70, 0x74, 0x72, /*060*/ 0x55, 0x70, 0x74, 0x72, 0x00, 0x00, 0x00, 0x00, 0x55, 0x70, 0x74, 0x72, 0x55, 0x70, 0x74, 0x72, /*070*/ 0x00, 0x00, 0x00, 0x00, 0x55, 0x70, 0x74, 0x72, 0x55, 0x70, 0x74, 0x72, 0x00, 0x00, 0x00, 0x00, /*080*/ 0x55, 0x70, 0x74, 0x72, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x44, 0x00, 0x4d, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x43, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x65, 0x00, 0x66, 0x00, 0x61, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x20, 0x00, 0x73, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x44, 0x00, 0x46, 0x00, 0x53, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x72, 0x00, 0x79, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x49, 0x00, 0x50, 0x00, 0x43, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x49, 0x00, 0x50, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x53, 0x00, 0x63, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x63, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; s1.EntriesRead = 10; s1.Buffer = &ca; s1.Buffer->max_count = 10; s1.Buffer->share_info_1 = &si[0]; si[0].netname.utf8 = "ADMIN$"; si[0].type = 0x80000000; si[0].remark.utf8 = "Remote Admin"; si[1].netname.utf8 = "C"; si[1].type = 0x00000000; si[1].remark.utf8 = ""; si[2].netname.utf8 = "C$"; si[2].type = 0x80000000; si[2].remark.utf8 = "Default share"; si[3].netname.utf8 = "DFS-Standalone"; si[3].type = 0x00000000; si[3].remark.utf8 = ""; si[4].netname.utf8 = "Encrypted"; si[4].type = 0x00000000; si[4].remark.utf8 = ""; si[5].netname.utf8 = "IPC$"; si[5].type = 0x80000003; si[5].remark.utf8 = "Remote IPC"; si[6].netname.utf8 = "NFS"; si[6].type = 0x00000000; si[6].remark.utf8 = ""; si[7].netname.utf8 = "Scratch"; si[7].type = 0x00000000; si[7].remark.utf8 = ""; si[8].netname.utf8 = "Share"; si[8].type = 0x00000000; si[8].remark.utf8 = ""; si[9].netname.utf8 = "Users"; si[9].type = 0x00000000; si[9].remark.utf8 = ""; dcerpc_set_tctx(dce, 0); /* NDR32 */ test_dcerpc_coder(dce, "dcerpc_SHARE_INFO_1_CONTAINER NDR32 LE", srvsvc_SHARE_INFO_1_CONTAINER_coder, compare_SHARE_INFO_1_CONTAINER, &s1, sizeof(s1), sizeof(buf), buf, 0, 1); } static void test_SHARE_INFO_1_CONTAINER_ndr64_le(struct dcerpc_context *dce) { struct srvsvc_SHARE_INFO_1_carray ca; struct srvsvc_SHARE_INFO_1_CONTAINER s1; struct srvsvc_SHARE_INFO_1 si[10]; unsigned char buf[] = { 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x44, 0x00, 0x4d, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x65, 0x00, 0x66, 0x00, 0x61, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x20, 0x00, 0x73, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x46, 0x00, 0x53, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x72, 0x00, 0x79, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x50, 0x00, 0x43, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x49, 0x00, 0x50, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x63, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x63, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; s1.EntriesRead = 10; s1.Buffer = &ca; s1.Buffer->max_count = 10; s1.Buffer->share_info_1 = &si[0]; si[0].netname.utf8 = "ADMIN$"; si[0].type = 0x80000000; si[0].remark.utf8 = "Remote Admin"; si[1].netname.utf8 = "C"; si[1].type = 0x00000000; si[1].remark.utf8 = ""; si[2].netname.utf8 = "C$"; si[2].type = 0x80000000; si[2].remark.utf8 = "Default share"; si[3].netname.utf8 = "DFS-Standalone"; si[3].type = 0x00000000; si[3].remark.utf8 = ""; si[4].netname.utf8 = "Encrypted"; si[4].type = 0x00000000; si[4].remark.utf8 = ""; si[5].netname.utf8 = "IPC$"; si[5].type = 0x80000003; si[5].remark.utf8 = "Remote IPC"; si[6].netname.utf8 = "NFS"; si[6].type = 0x00000000; si[6].remark.utf8 = ""; si[7].netname.utf8 = "Scratch"; si[7].type = 0x00000000; si[7].remark.utf8 = ""; si[8].netname.utf8 = "Share"; si[8].type = 0x00000000; si[8].remark.utf8 = ""; si[9].netname.utf8 = "Users"; si[9].type = 0x00000000; si[9].remark.utf8 = ""; dcerpc_set_tctx(dce, 1); /* NDR64 */ test_dcerpc_coder(dce, "dcerpc_SHARE_INFO_1_CONTAINER NDR64 LE", srvsvc_SHARE_INFO_1_CONTAINER_coder, compare_SHARE_INFO_1_CONTAINER, &s1, sizeof(s1), sizeof(buf), buf, 0, 1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct dcerpc_context *dce; char ph[16] = "abcdefghij012345"; if (argc != 1) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } dce = dcerpc_create_context(smb2); if (dce == NULL) { printf("Failed to create dce context. %s\n", smb2_get_error(smb2)); exit(10); } PolicyHandle.context_handle_attributes = 0; memcpy(&PolicyHandle.context_handle_uuid, ph, 16); test_utf16_ndr32_le(dce); test_utf16_ndr32_be(dce); test_utf16_ndr64_le(dce); test_SHARE_INFO_1_ndr32_le(dce); test_SHARE_INFO_1_CONTAINER_ndr32_le(dce); test_SHARE_INFO_1_CONTAINER_ndr64_le(dce); dcerpc_destroy_context(dce); smb2_destroy_context(smb2); return 0; } libsmb2-6.2/tests/ld_sockerr.c0000664000175000017500000000324714732155517015462 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2024 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include int readv_close = -1; int (*real_readv)(int fd, const struct iovec *iov, int iovcnt); ssize_t readv(int fd, const struct iovec *iov, int iovcnt) { static int call_idx = 0; call_idx++; if (call_idx == readv_close) { /* write some garbage */ write(fd, &call_idx, sizeof(call_idx)); errno = EBADF; return -1; } return real_readv(fd, iov, iovcnt); } static void __attribute__((constructor)) _init(void) { /* Close the socket at this call to readv */ if (getenv("READV_CLOSE") != NULL) { readv_close = atoi(getenv("READV_CLOSE")); } real_readv = dlsym(RTLD_NEXT, "readv"); } libsmb2-6.2/tests/test_0200_mkdir.sh0000775000175000017500000000044714732155517016333 0ustar polpypolpy#!/bin/sh . ./functions.sh echo "basic mkdir test" echo -n "Testing prog_mkdir on root of share ... " ./prog_mkdir "${TESTURL}/testdir" > /dev/null || failure success echo -n "Testing prog_rmdir on root of share ... " ./prog_rmdir "${TESTURL}/testdir" > /dev/null || failure success exit 0 libsmb2-6.2/tests/test_0210_cp_basic.sh0000775000175000017500000000114314732155517016763 0ustar polpypolpy#!/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 libsmb2-6.2/tests/test_0300_cat_basic.sh0000775000175000017500000000033414732155517017131 0ustar polpypolpy#!/bin/sh . ./functions.sh echo "basic cat test" ../utils/smb2-cp ./prog_cat.c "${TESTURL}/CAT" echo -n "Testing prog_cat on root of share/CAT ... " ./prog_cat "${TESTURL}/CAT" > /dev/null || failure success exit 0 libsmb2-6.2/tests/prog_mkdir.c0000664000175000017500000000604314732155517015465 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #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" "prog_mkdir \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; int rc = 0; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } 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; } smb2_rmdir(smb2, url->path); if (smb2_mkdir(smb2, url->path)) { printf("smb2_mkdir failed. %s\n", smb2_get_error(smb2)); goto out_disconnect; } out_disconnect: smb2_disconnect_share(smb2); out_context: smb2_destroy_url(url); smb2_destroy_context(smb2); return rc; } libsmb2-6.2/tests/test_900_dcerpc.sh0000775000175000017500000000015514732155517016410 0ustar polpypolpy#!/bin/sh . ./functions.sh echo "DCE/RPC coder tests" ./smb2-dcerpc-coder-test || failure success exit 0 libsmb2-6.2/tests/test_0101_ls_basic_valgrind.sh0000775000175000017500000000146414732155517020672 0ustar polpypolpy#!/bin/sh . ./functions.sh 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 ./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 ./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 ./prog_ls "${TESTURL}/testdir" >/dev/null 2>&1 || failure ./prog_rmdir "${TESTURL}/testdir" > /dev/null success exit 0 libsmb2-6.2/tests/test_0100_ls_basic.sh0000775000175000017500000000105014732155517016772 0ustar polpypolpy#!/bin/sh . ./functions.sh echo "basic ls test" echo -n "Testing prog_ls on root of share ... " ./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 ./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 ./prog_ls "${TESTURL}/testdir" >/dev/null || failure ./prog_rmdir "${TESTURL}/testdir" > /dev/null success exit 0 libsmb2-6.2/tests/prog_cat.c0000664000175000017500000001361514732155517015131 0ustar polpypolpy/* -*- 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. */ #define _GNU_SOURCE #include #if !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) #include #endif #include #include #include #include #include #include #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) struct pollfd { int fd; short events; short revents; }; int poll(struct pollfd *fds, unsigned int nfds, int timo); #endif int is_finished = 0; uint8_t buf[256 * 1024]; uint32_t pos; int usage(void) { fprintf(stderr, "Usage:\n" "smb2-cat-async \n\n" "URL format: " "smb://[@][:]//\n"); exit(1); } void dc_cb(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { is_finished = 1; } void cl_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { smb2_disconnect_share_async(smb2, dc_cb, NULL); } void pr_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2fh *fh = private_data; if (status < 0) { printf("failed to read file (%s) %s\n", strerror(-status), smb2_get_error(smb2)); is_finished = 1; return; } if (status == 0) { if (smb2_close_async(smb2, fh, cl_cb, NULL) < 0) { printf("Failed to call smb2_close_async()\n"); is_finished = 1; } return; } write(STDOUT_FILENO, buf, status); pos += status; if (smb2_pread_async(smb2, fh, buf, 102400, pos, pr_cb, fh) < 0) { printf("Failed to call smb2_pread_async()\n"); is_finished = 1; return; } } void of_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2fh *fh = command_data; if (status) { printf("failed to open file (%s) %s\n", strerror(-status), smb2_get_error(smb2)); is_finished = 1; return; } if (smb2_pread_async(smb2, fh, buf, 102400, 0, pr_cb, fh) < 0) { printf("Failed to call smb2_pread_async()\n"); is_finished = 1; return; } } void cf_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { if (status) { printf("failed to connect share (%s) %s\n", strerror(-status), smb2_get_error(smb2)); is_finished = 1; return; } if (smb2_open_async(smb2, private_data, O_RDONLY, of_cb, NULL) < 0) { printf("Failed to call smb2_open_async()\n"); is_finished = 1; return; } } int main(int argc, char *argv[]) { struct smb2_context *smb2; struct smb2_url *url; struct pollfd pfd; int rc = 0; if (argc < 2) { usage(); } smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); exit(0); } url = smb2_parse_url(smb2, argv[1]); if (url == NULL) { fprintf(stderr, "Failed to parse url: %s\n", smb2_get_error(smb2)); exit(0); } smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED); if (smb2_connect_share_async(smb2, url->server, url->share, url->user, cf_cb, (void *)url->path) != 0) { printf("smb2_connect_share failed. %s\n", smb2_get_error(smb2)); goto finished; } while (!is_finished) { pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { printf("Poll failed"); goto finished; } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { printf("smb2_service failed with : %s\n", smb2_get_error(smb2)); goto finished; } } finished: smb2_destroy_url(url); smb2_destroy_context(smb2); return rc; } libsmb2-6.2/tests/README0000664000175000017500000000142614732155517014044 0ustar polpypolpyTo run the test you need an SMB server that exports a share and two configurations files: 1, ./tests/NTLM =============== This file contains the username to password mapping you need to authenticate to the server with NTLM. Example: $ cat tests/NTLM win16-1:Administrator:mypassword $ 2, tests/setup.local ==================== This file sets two environment variables the tests need, NTLM_USER_FILE and TESTURL. Example: $ cat tests/setup.local TESTURL=smb://Administrator@win16-1/Share NTLM_USER_FILE=`pwd`/NTLM $ A good idea is to use a special share/subdirectory on the server so that the tests do not overwrite/corrupt/delete important files. Create a dedicated share on the server that is only used for testing and be prepared that any data in this share can be randomly deleted. libsmb2-6.2/tests/Makefile.am0000664000175000017500000000147114732155517015220 0ustar polpypolpyAM_CPPFLAGS = -I${srcdir}/../include -I${srcdir}/../include/smb2 \ "-D_U_=__attribute__((unused))" \ "-D_R_(A,B)=__attribute__((format(printf,A,B)))" AM_CFLAGS = $(WARN_CFLAGS) LDADD = ../lib/libsmb2.la noinst_PROGRAMS = prog_ls prog_mkdir prog_rmdir prog_cat \ smb2-dcerpc-coder-test EXTRA_PROGRAMS = ld_sockerr CLEANFILES = ld_sockerr.o ld_sockerr.so ld_sockerr_SOURCES = ld_sockerr.c ld_sockerr_CFLAGS = $(AM_CFLAGS) -fPIC bin_SCRIPTS = ld_sockerr.so ld_sockerr.o: ld_sockerr-ld_sockerr.o $(LIBTOOL) --mode=link $(CC) -o $@ $^ ld_sockerr.so: ld_sockerr.o $(CC) -shared -o ld_sockerr.so ld_sockerr.o -ldl T = `ls test_*.sh` test: $(noinst_PROGRAMS) $(bin_SCRIPTS) for TEST in $(T); do \ echo "Running $$TEST"; \ echo "--------------"; \ sh $$TEST || exit 1; \ echo "--------------"; \ echo; \ done libsmb2-6.2/tests/ntlmssp_generate_blob.c0000664000175000017500000001110614732155517017674 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #include #include #include #include #include #include "libsmb2.h" #include "smb2.h" #include "../lib/ntlmssp.h" time_t timestamp = 1559429385; unsigned char security_blob[] = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x38, 0x00, 0x00, 0x00, 0x05, 0x02, 0x8a, 0xa2, 0x02, 0x2b, 0xb9, 0x85, 0x51, 0xa1, 0x4a, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x58, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x43, 0x00, 0x02, 0x00, 0x08, 0x00, 0x58, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x43, 0x00, 0x01, 0x00, 0x08, 0x00, 0x58, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x43, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x78, 0x00, 0x62, 0x00, 0x6d, 0x00, 0x63, 0x00, 0x07, 0x00, 0x08, 0x00, 0x36, 0x78, 0xf0, 0x50, 0xc1, 0x18, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x00}; char client_challenge[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; unsigned char expected_blob[] = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x72, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x16, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x08, 0xa0, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x23, 0x62, 0x8c, 0xb8, 0x79, 0xfb, 0x73, 0x3f, 0x9a, 0x20, 0xc7, 0xaa, 0xb8, 0x17, 0xbc, 0x45, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x96, 0x1b, 0xfb, 0x56, 0x51, 0x7c, 0xdb, 0x5b, 0x52, 0x62, 0x64, 0x92, 0x81, 0xf3, 0x01, 0x7e, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4a, 0xb2, 0x4e, 0xcc, 0x18, 0xd5, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x58, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x43, 0x00, 0x01, 0x00, 0x08, 0x00, 0x58, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x43, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x78, 0x00, 0x62, 0x00, 0x6d, 0x00, 0x63, 0x00, 0x07, 0x00, 0x08, 0x00, 0x36, 0x78, 0xf0, 0x50, 0xc1, 0x18, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int main(int argc, char *argv[]) { struct smb2_session_setup_request req; struct smb2_context *smb2; void *auth_data; int i; smb2 = smb2_init_context(); if (smb2 == NULL) { fprintf(stderr, "Failed to init context\n"); return -1; } printf("size of security blob:%d\n", sizeof(security_blob)); /* Session setup request. */ memset(&req, 0, sizeof(struct smb2_session_setup_request)); req.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; auth_data = ntlmssp_init_context("Username", "Password", "Domain", "Workstation", client_challenge); if (auth_data == NULL) { smb2_destroy_context(smb2); fprintf(stderr, "Failed to init auth_data\n"); return -1; } if (ntlmssp_generate_blob(NULL, smb2, timestamp, auth_data, security_blob, sizeof(security_blob), &req.security_buffer, &req.security_buffer_length) < 0) { smb2_destroy_context(smb2); return -1; } printf("Size of generated blob: %d\n", req.security_buffer_length); for (i = 0; i < req.security_buffer_length; i++) { printf("0x%02x ", req.security_buffer[i]); if (i%8 == 7) { printf("\n"); } } printf("\n"); if (memcmp(req.security_buffer, expected_blob, sizeof(expected_blob))) { smb2_destroy_context(smb2); fprintf(stderr, "Generated blob does not match expected blob\n"); return -1; } smb2_destroy_context(smb2); return 0; } libsmb2-6.2/tests/test_0212_cp_valgrind_socket_error.sh0000775000175000017500000000235714732155517022303 0ustar polpypolpy#!/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 libsmb2-6.2/tests/aes128ccm-test.c0000664000175000017500000000730514732155517015775 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #include #include #include #include #include #include "lib/aes128ccm.h" void test_1(void) { unsigned char key[16] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f}; unsigned char nonce[7] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; unsigned char aad[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; unsigned char p[4] = {0x20, 0x21, 0x22, 0x23}; int mlen = 4; unsigned char exp[8] = {0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d}; unsigned char buf[1024]; int i, rc; memcpy(buf, p, sizeof(p)); aes128ccm_encrypt(key, nonce, sizeof(nonce), aad, sizeof(aad), buf, sizeof(p), &buf[sizeof(p)], mlen); printf("Expected:\n"); for (i = 0; i < sizeof(p) + mlen; i++) { printf("%02x ", exp[i]); } printf("\n"); printf("Got:\n"); for (i = 0; i < sizeof(p) + mlen; i++) { printf("%02x ", buf[i]); } printf("\n"); rc = aes128ccm_decrypt(key, nonce, sizeof(nonce), aad, sizeof(aad), buf, sizeof(p), &buf[sizeof(p)], mlen); printf("it ran rc : %d\n", rc); if (rc) exit(10); printf("Got:\n"); for (i = 0; i < sizeof(p); i++) { printf("%02x ", buf[i]); } printf("\n"); printf("Decrypted correct: %d\n", memcmp(p, &buf[0], sizeof(p))); if (memcmp(p, &buf[0], sizeof(p))) exit(10); } void test_2(void) { unsigned char key[16] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f}; unsigned char nonce[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b}; unsigned char aad[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13}; unsigned char p[] = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; int mlen = 8; unsigned char exp[] = {0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51}; unsigned char buf[1024]; int i, rc; memcpy(buf, p, sizeof(p)); aes128ccm_encrypt(key, nonce, sizeof(nonce), aad, sizeof(aad), buf, sizeof(p), &buf[sizeof(p)], mlen); printf("Expected:\n"); for (i = 0; i < sizeof(p) + mlen; i++) { printf("%02x ", exp[i]); } printf("\n"); printf("Got:\n"); for (i = 0; i < sizeof(p) + mlen; i++) { printf("%02x ", buf[i]); } printf("\n"); rc = aes128ccm_decrypt(key, nonce, sizeof(nonce), aad, sizeof(aad), buf, sizeof(p), &buf[sizeof(p)], mlen); printf("it ran rc : %d\n", rc); if (rc) exit(10); printf("Got:\n"); for (i = 0; i < sizeof(p); i++) { printf("%02x ", buf[i]); } printf("\n"); printf("Decrypted correct: %d\n", memcmp(p, &buf[0], sizeof(p))); if (memcmp(p, &buf[0], sizeof(p))) exit(10); } int main(int argc, char *argv[]) { test_1(); test_2(); return 0; } libsmb2-6.2/tests/test_0211_cp_valgrind.sh0000775000175000017500000000156714732155517017523 0ustar polpypolpy#!/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 libsmb2-6.2/tests/test_0201_mkdir_valgrind.sh0000775000175000017500000000066714732155517020226 0ustar polpypolpy#!/bin/sh . ./functions.sh echo "mkdir test with valgrind" echo -n "Testing mkdir on root of share ... " libtool --mode=execute valgrind --leak-check=full --error-exitcode=1 ./prog_mkdir "${TESTURL}/testdir" >/dev/null 2>&1 || failure success echo -n "Testing rmdir on root of share ... " libtool --mode=execute valgrind --leak-check=full --error-exitcode=1 ./prog_rmdir "${TESTURL}/testdir" >/dev/null 2>&1 || failure success exit 0 libsmb2-6.2/tests/prog_ls.c0000664000175000017500000001373114732155517014777 0ustar polpypolpy/* -*- 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" #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) { 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 (getenv("ALLOC_FAIL") != NULL) { alloc_fail = atoi(getenv("ALLOC_FAIL")); } /* https://bugzilla.redhat.com/show_bug.cgi?id=2333389 */ /* 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"); printf("Alloc fail at %d\n", alloc_fail); 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; } libsmb2-6.2/tests/test_0302_cat_valgrind_socket_error.sh0000775000175000017500000000111514732155517022437 0ustar polpypolpy#!/bin/sh . ./functions.sh echo "basic cat test with valgrind and session errors" ../utils/smb2-cp ./prog_cat.c "${TESTURL}/CAT" NUM_CALLS=`libtool --mode=execute strace ./prog_cat "${TESTURL}/CAT" 2>&1 >/dev/null | grep readv |wc -l` for IDX in `seq 1 $NUM_CALLS`; do echo -n "Testing prog_cat 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=1 ./prog_cat "${TESTURL}/CAT" >/dev/null 2>valgrind.out || failure success done exit 0 libsmb2-6.2/tests/functions.sh0000775000175000017500000000013614732155517015530 0ustar polpypolpy. ./setup.local success() { echo "[OK]" } failure() { echo "[FAILED]" exit 1 } libsmb2-6.2/tests/test_0301_cat_valgrind.sh0000775000175000017500000000046314732155517017662 0ustar polpypolpy#!/bin/sh . ./functions.sh echo "basic cat test with valgrind" ../utils/smb2-cp ./prog_cat.c "${TESTURL}/CAT" echo -n "Testing prog_cat on root of share/CAT ... " libtool --mode=execute valgrind --leak-check=full --error-exitcode=1 ./prog_cat "${TESTURL}/CAT" >/dev/null 2>&1 || failure success exit 0 libsmb2-6.2/tests/test_0103_ls_basic_valgrind_malloc_error.sh0000775000175000017500000000161714732155517023434 0ustar polpypolpy#!/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 # 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 exit 0 libsmb2-6.2/tests/test_0102_ls_basic_socket_error.sh0000775000175000017500000000106414732155517021562 0ustar polpypolpy#!/bin/sh . ./functions.sh echo "basic ls test with valgrind and session errors" 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 ./prog_ls "${TESTURL}/" >/dev/null 2>valgrind.out expr $? "==" "77" >/dev/null && failure success done exit 0 libsmb2-6.2/README0000664000175000017500000003670514732155517012712 0ustar polpypolpyLibsmb2 is a userspace client/server library for accessing or serving SMB2/SMB3 shares on a network. It is high performance and fully async. It supports both zero-copy for SMB READ/WRITE commands as well as compounded commands. Libsmb2 is distributed under the LGPLv2.1 licence. API === Libsmb2 implements three different APIs for accessing remote SMB shares : 1, High level synchronous posix-like API: This is a simple API for accessing a share. The functions in this API are modelled to be be similar to the corresponding POSIX functions. This API is described in libsmb2.h 2, High level async posix-like API: This is a high performance, fully non-blocking and async API. The functions in this API are modelled to be be similar to the corresponding POSIX functions. This is the recommended API. This API is described in libsmb2.h 3, Low level async RAW API: This is a low level API that provides direct access to the SMB2 PDUs and data structures. This API is described in libsmb2-raw.h Libsmb2 implements a synchronous API for running an SMB server. You could run an async server if you implement the main loop yourself however SMB URL Format ============== The SMB URL format is currently a small subset of the URL format that is defined/used by the Samba project. The goal is to eventually support the full URL format, thus making URLs interchangeable between Samba utilities and Libsmb2 but we are not there yet. smb://[;][@][:]/[/path][?arg=val[&arg=val]*] is either a hostname, an IPv4 or an IPv6 address. Arguments supported by libsmb2 are : sec= : Mechanism to use to authenticate to the server. Default is any available mech, but can be overridden by : krb5: Use Kerberos using credentials from kinit. krb5cc: Use Kerberos using credentials from credentials cache. ntlmssp : Only use NTLMSSP vers= : Which SMB version to negotiate: 2: Negotiate any version of SMB2 3: Negotiate any version of SMB3 2.02, 2.10, 3.00, 3.02, 3.1.1 : negotiate a specific version. Default is to negotiate any SMB2 or SMB3 version. seal : Enable SMB3 encryption. sign : Require SMB2/3 signing. timeout : Timeout in seconds when to cancel a command. Default it 0: No timeout. ndr32 : DCERPC: only offer NDR32 transfer syntax. (default) ndr64 : DCERPC: only offer NDR64 transfer syntax. ndr3264 : DCERPC: offer both NRD32 and NDR64 transfer syntax. le : DCERPC: send PDUs in Little-Endian format be : DCERPC: send PDUs in Big-Endian format NOTE:- When using krb5cc mode use smb2_set_domain() and smb2_set_password() in the examples and applications SMB Server ========== There is an example server implementation in examples/smb2-server-sync.c. The library server function is handed an array of function pointers that the library will call for each client command. It is up to your implementation to fill out and return replies for each according to your use. The example simulates a disk with a few files. Your handler will be also be called to pre-authenticate users as part of ntlmssp (krb authenticaton not yet implemented). Your application will also be called-back each time a client connect to allow your to configure the context prior to negotiation. Authentication ============== Libsmb2 provides has builtin support for NTLMSSP username/password authentication. It can also, optionally, be built with (MIT) Kerberos authentication. Libsmb2 will try to build with Kerberos if these libraries are present. You can force a build without Kerberos support by using the flag --without-libkrb5 to configure. In this case only NTLMSSP authentication will be available. MIT KERBEROS ============ Authentication is implemented using MIT Kerberos and it supports both KRB5 for authentication against Active Directory as well as NTLMSSP (optional). MIT Kerberos can be configured to also provide NTLMSSP authentication, as an alternative to the builtin NTLMSSP implementation using an external mech plugin. To use this Kerberos/NTLMSSP module you will need to build and install GSS-NTLMSSP from [https://github.com/simo5/gss-ntlmssp] If you are uncertain you can skip this module and just use the NTLMSSP module that is provided by libsmb2. NTLM Authentication ------------------- NTLM credentials are stored in a text file of the form : DOMAIN:USERNAME:PASSWORD with one line per username. You need to set up the environment variable NTLM_USER_FILE to point to this file. You need one entry in this file for each local user account you want to be able to use libsmb2 for accessing a remote share. By default, NTLM authentication will use the username for the current process. This can be overridden by specifying a different username in the SMB URL : smb://guest@server/share?sec=ntlmssp KRB5 Authentication ------------------- Kerberos authentication can be used when the linux workstation as well as the file server are part of Active Directory. You should be able to authenticate to the file server using krb5 by specifying sec=krb5 in the URL : smb://server/share?sec=krb5 The application needs to set the username, password and the domain fqdn in the context using smb2_set_user(), smb2_set_password() and smb2_set_domain() respectively. NTLM Credentials ================ This applies to both the builtin NTLMSSP implementation as well as when using Kerberos with the NTLMSSP mech plugin. NTLM credentials are stored in a text file of the form : DOMAIN:USERNAME:PASSWORD with one line per username. You need to set up the environment variable NTLM_USER_FILE to point to this file. You need one entry in this file for each local user account you want to be able to use libsmb2 for accessing a remote share. By default, NTLM authentication will use the username for the current process. This can be overridden by specifying a different username in the SMB URL : smb://guest@server/share?sec=ntlmssp Alternatively you can provide the username and password from your application by calling : smb2_set_user(smb2, ); smb2_set_password(smb2, ); (For server, you don't need to set the user, as that is supplied by the client) SMB2/3 SIGNING ============== Signing is supported with KRB5, with the builtin ntlmssp support and with gss-ntlmssp mech plugin. SMB3 Encryption =============== Encryption is only supported with KRB5 or with the builtin ntlmssp support. Encryption is not supported when the gss-ntlmssp mech plugin is used. Encryption can be enabled either using the "seal" URL argument or by calling smb3_set_seal(smb2, 1); BUILDING LIBSMB2 =============== Windows --------------------------- You have to install CMake (https://cmake.org/) and Visual Studio (https://www.visualstudio.com/) to build libsmb2 for Windows (including Universal Windows Platform). Please follow the next steps to build shared library: mkdir build cd build cmake -G "Visual Studio 15 2017" .. cmake --build . --config RelWithDebInfo Static library: mkdir build cd build cmake -G "Visual Studio 15 2017" -DBUILD_SHARED_LIBS=0 .. cmake --build . --config RelWithDebInfo macOS, iOS, tvOS, watchOS --------------------------- You can use AMSMB2 (https://github.com/amosavian/AMSMB2) universal framework which incorporates precompiled libsmb2 for Apple devices. It is written in Swift but can be used in both Swift and Objective-C codes. If you want to rebuild libsmb2 in AMSMB2, please follow these steps: git clone https://github.com/amosavian/AMSMB2 cd AMSMB2/buildtools ./build.sh Precompiled binaries don't include Kerberos support by default. If you want build libraries with Kerberos support, execute this script instead: ./build-with-krb5.sh ESP32 ----- libsmb2 is pre-configured for the ESP32 micro-controller using the esp-idf toolchain (Arduino is not supported). Simply clone this project in the 'components' directory of the ESP32 project and it will automatically be included in the build process. Raspberry Pi Pico W (RP2040) ---------------------------- libsmb2 will compile on the RP2040 using gcc-arm-none-eabi, the pico-sdk and FreeRTOS-Kernel. In examples/picow is a CMakeLists.txt that can be edited to point at the pico-sdk and FreeRTOS-Kernel, and will then build libsmb2 and a sample - this can be used as a starting point. Inside include/picow are some configuration files for lwip, FreeRTOS and any applications built with libsmb2. These can also be used as a starting point and adjusted as needed for your applications. The only define needed for libsmb2 on the RP2040, other than the RP2040 defines such as PICO_BOARD=pico_w, is PICO_PLATFORM. Playstation 2 ------------ EE, Emotion-Engine, is the main CPU for the PS2. To compile libsmb2 for the PS2 EE, first install the PS2 toolchain and PS2 SDK and set it up. To build libsmb2.a, a version of libsmb2 for the EE tcpip stack: $ make -f Makefile.platform clean $ make -f Makefile.platform ps2_ee_install EE Using IOP Stack, It´s a different of EE version for when the LWIP stack is running on the IOP (libsmb2_rpc and linking with -lps2ips) To build libsmb2_rpc.a, a version of libsmb2 for ee with IOP tcpip stack: $ make -f Makefile.platform clean $ make -f Makefile.platform ps2_rpc_install IOP, IO-Processor is the secondary CPU for the PS2. The library is been used to build smb2man.irx module but it doesn´t comes with the library installed, To install libsmb2 for the PS2 IOP and smb2man.irx, first install the PS2 toolchain and PS2SDK and set it up. Then to build libsmb2, run $ make -f Makefile.platform clean $ make -f Makefile.platform ps2_iop_install $ make -f Makefile.platform clean $ make -f Makefile.platform ps2_irx_install PlayStation 3 ------------- PPU, PowerPC, is the main CPU for the PS3. To compile libsmb2 for the PS3 PPU, first install the PS3 toolchain and PSL1GHT SDK and set it up. Then to build libsmb2, run $ cd lib $ make -f Makefile.PS3_PPU install The process will copy the resulting libsmb2.a and the include/smb2 headers to your PSL1GHT SDK portlibs folder. PlayStation Vita ------------- ARM® Cortex™ - A9 core (4 core), is the main CPU for the PSVITA. To compile libsmb2 for the PSVITA, first install the VitaSDK using vdpm Then to build libsmb2, run $ make vita_install -f Makefile.platform The process will copy the resulting libsmb2.a and the include/smb2 headers to your VitaSDK libs folder. PlayStation 4 ------------- x86_64 is the main CPU for the PS4. To compile libsmb2 for the PS4 PPU, first install the PS4 toolchain and OpenOrbis SDK and set it up. Then to build libsmb2, run $ make -f Makefile.platform ps4_install The process will copy the resulting libsmb2.a and the include/smb2 headers to your OpenOrbis SDK include folder. Nintendo 3DS ------------- Nintendo 3DS CPU is a ARM11 MPCore variant. To compile libsmb2 for the Nintendo 3DS, first install the devkitPro with libctru to set it up. Then to build libsmb2, run $ make -f Makefile.platform 3ds_install The process will copy the resulting libsmb2.a and the include/smb2 headers to your devkitPro 3ds portlibs folder. Nintendo Switch ------------- Nintendo Switch CPU is a Custom Nvidia Tegra X1. To compile libsmb2 for the Nintendo Switch, first install the devkitPro with libnx to set it up. Then to build libsmb2, run $ cd lib $ make -f Makefile.platform switch_install The process will copy the resulting libsmb2.a and the include/smb2 headers to your devkitPro switch portlibs folder. Nintendo Wii ------------- Nintendo Wii CPU is a Broadway PowerPC processor. To compile libsmb2 for the Nintendo Wii, first install the devkitPro with libogc using pacman to set it up. Then to build libsmb2, run $ make -f Makefile.platform wii_install The process will copy the resulting libsmb2.a and the include/smb2 headers to your devkitPro wii portlibs folder. Nintendo Gamecube ------------- Nintendo GameCube CPU is a IBM "Gekko" PowerPC CPU. To compile libsmb2 for the Gamecube, first install the devkitPro with libogc using pacman to set it up. Then to build libsmb2, run $ make -f Makefile.platform gc_install The process will copy the resulting libsmb2.a and the include/smb2 headers to your devkitPro gamecube portlibs folder. Nintendo DS ------------- Nintendo DS CPU is both ARM7TDMI and ARM946E-S. To compile libsmb2 for the Nintendo DS, first install the devkitPro with libnds using pacman to set it up. Then to build libsmb2, run $ cd lib $ make -f Makefile.platform ds_install The process will copy the resulting libsmb29.a and the include/smb2 headers to your devkitPro ds portlibs folder on: lib/arm9. Nintendo WII-U ------------- Nintendo Wii-U CPU is a IBM "Espresso" PowerPC-based 45 nm, with 4 cores and a clock speed of 1.24 GHz. To compile libsmb2 for the Nintendo WII-U, first install the devkitPro with libwut using pacman to set it up. Then to build libsmb2, run $ cd lib $ make -f Makefile.platform wiiu_install The process will copy the resulting libsmb2.a and the include/smb2 headers to your devkitPro wiiu portlibs folder. Amiga (AmigaOS) ---------------------- AmigaOS is Operating system which the main processor is a Microprocessor PowerPC. There are 3 versions: AmigaOS4(Makefile.AMIGA) AmigaOS3(Makefile.AMIGA_OS3) AmigaAROS(Makefile.AMIGA_AROS) To compile libsmb2 for the AmigaOS, you need to set newlib.library V53.40 or newer (or V53.30 as included in 4.1 FE) and filesysbox.library 54.4 or newer to set it up. Then to build libsmb2, choose the makefile acording your AmigaOS system and hit $ cd lib $ make -f Makefile.YOUR_AMIGA_OS_USED clean install The process will copy the resulting libsmb2.a and the include/smb2 headers in the bin folder inside of the lib folder NOTE: Amiga AROS is a Open Source version of AmigaOS, So do not build this version unless you are using the AmigaAROS. Dreamcast (KallistiOS) ---------------------- Hitachi SH4 in little-endian mode is the main CPU for the Dreamcast. To compile libsmb2 for the Dreamcast, first install the KOS toolchain and and set it up. Then to build libsmb2, run $ cd lib $ make -f Makefile.platform clean dc_install The process will copy the resulting libsmb2.a and the include/smb2 headers to your KallistiOS toolchain install location addons folder. NOTE: There is not yet a kos-ports entry for libsmb2 but once a versioned release that includes Dreamcast support is created installing from kos-ports will become the preferred method of installation. Xbox (Xbox XDK) ---------------------- Xbox CPU is a custom Intel Pentium III Coppermine-based processor which only supports litlle endian values. To compile libsmb2 for the Xbox, first install the Xbox XDK(with all features), Microsoft Visual C++ 2003 Professional and Windows XP. Then to build libsmb2, go to Xbox folder and open the provided .sln file, Then hit the green button to build: The process will result a libsmb2.lib. So you can copy the include files and the .lib file to your Xbox project. Xbox 360 (Xbox 360 SDK) ---------------------- Xbox 360 CPU is a PPC(PowerPC) Xenon which only supports only big endian values. To compile libsmb2 for the Xbox 360, first install the Xbox 360 SDK(with all features), Microsoft Visual C++ 2010 Ultimate and Windows XP(Recommended) or Windows 7. Then to build libsmb2, go to Xbox 360 folder and open the provided .sln file, Then hit the green button to build: The process will result a libsmb2.lib. So you can copy the include files and the .lib file to your Xbox 360 project. NOTE: Both ports was based on XBMC-360 port by BDC(Brent De Cartet) and now being updated to libsmb2 standards to best performance. libsmb2-6.2/include/0000775000175000017500000000000014732155517013442 5ustar polpypolpylibsmb2-6.2/include/smb2/0000775000175000017500000000000014732155517014305 5ustar polpypolpylibsmb2-6.2/include/smb2/libsmb2-dcerpc-lsa.h0000664000175000017500000001333314732155517020026 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2020 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef _LIBSMB2_DCERPC_LSA_H_ #define _LIBSMB2_DCERPC_LSA_H_ #ifdef __cplusplus extern "C" { #endif #define LSA_CLOSE 0x00 #define LSA_OPENPOLICY2 0x2c #define LSA_LOOKUPSIDS2 0x39 /* Access Mask. LSA specific flags. */ #define POLICY_VIEW_LOCAL_INFORMATION 0x00000001 #define POLICY_VIEW_AUDIT_INFORMATION 0x00000002 #define POLICY_GET_PRIVATE_INFORMATION 0x00000004 #define POLICY_TRUST_ADMIN 0x00000008 #define POLICY_CREATE_ACCOUNT 0x00000010 #define POLICY_CREATE_SECRET 0x00000020 #define POLICY_CREATE_PRIVILEGE 0x00000040 #define POLICY_SET_DEFAULT_QUOTA_LIMITS 0x00000080 #define POLICY_SET_AUDIT_REQUIREMENTS 0x00000100 #define POLICY_AUDIT_LOG_ADMIN 0x00000200 #define POLICY_SERVER_ADMIN 0x00000400 #define POLICY_LOOKUP_NAMES 0x00000800 #define POLICY_NOTIFICATION 0x00001000 extern unsigned char NT_SID_AUTHORITY[6]; typedef struct RPC_SID { uint8_t Revision; uint8_t SubAuthorityCount; uint8_t IdentifierAuthority[6]; uint32_t *SubAuthority; } RPC_SID, *PRPC_SID; typedef struct _LSAPR_TRANSLATED_NAME_EX { uint32_t Use; char *Name; uint32_t DomainIndex; uint32_t Flags; } LSAPR_TRANSLATED_NAME_EX, *PLSAPR_TRANSLATED_NAME_EX; typedef struct _LSAPR_TRANSLATED_NAMES_EX { uint32_t Entries; LSAPR_TRANSLATED_NAME_EX *Names; } LSAPR_TRANSLATED_NAMES_EX, *PLSAPR_TRANSLATED_NAMES_EX; typedef struct _SID_ENUM_BUFFER { uint32_t Entries; PRPC_SID *SidInfo; } LSAPR_SID_ENUM_BUFFER, *PLSAPR_SID_ENUM_BUFFER; typedef enum _LSAP_LOOKUP_LEVEL { LsapLookupWksta = 1, LsapLookupPDC, LsapLookupTDL, LsapLookupGC, LsapLookupXForestReferral, LsapLookupXForestResolve, LsapLookupRODCReferralToFullDC } LSAP_LOOKUP_LEVEL, *PLSAP_LOOKUP_LEVEL; typedef struct _LSAPR_TRUST_INFORMATION { char *Name; RPC_SID Sid; } LSAPR_TRUST_INFORMATION, *PLSAPR_TRUST_INFORMATION; typedef struct _LSAPR_REFERENCED_DOMAIN_LIST { uint32_t Entries; LSAPR_TRUST_INFORMATION *Domains; uint32_t MaxEntries; /* must be ignored */ } LSAPR_REFERENCED_DOMAIN_LIST, *PLSAPR_REFERENCED_DOMAIN_LIST; /* For OPENPOLICY2: RootDirectory MUST be zero. Everything else is ignored. */ typedef struct _LSAPR_OBJECT_ATTRIBUTES { uint32_t Length; unsigned char *RootDirectory; void *ObjectName; uint32_t Attributes; void *SecurityDescriptor; void *SecurityQualityOfService; } LSAPR_OBJECT_ATTRIBUTES, *PLSAPR_OBJECT_ATTRIBUTES; struct lsa_close_req { struct ndr_context_handle PolicyHandle; }; struct lsa_close_rep { uint32_t status; struct ndr_context_handle PolicyHandle; }; struct lsa_openpolicy2_req { char *SystemName; LSAPR_OBJECT_ATTRIBUTES ObjectAttributes; uint32_t DesiredAccess; }; struct lsa_openpolicy2_rep { uint32_t status; struct ndr_context_handle PolicyHandle; }; struct lsa_lookupsids2_req { struct ndr_context_handle PolicyHandle; LSAPR_SID_ENUM_BUFFER SidEnumBuffer; LSAPR_TRANSLATED_NAMES_EX TranslatedNames; LSAP_LOOKUP_LEVEL LookupLevel; }; struct lsa_lookupsids2_rep { uint32_t status; LSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains; LSAPR_TRANSLATED_NAMES_EX TranslatedNames; uint32_t MappedCount; }; int lsa_Close_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int lsa_Close_req_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int lsa_LookupSids2_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int lsa_LookupSids2_req_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int lsa_OpenPolicy2_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int lsa_OpenPolicy2_req_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int lsa_RPC_SID_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); #ifdef __cplusplus } #endif #endif /* !_LIBSMB2_DCERPC_LSA_H_ */ libsmb2-6.2/include/smb2/smb2.h0000664000175000017500000011115714732155517015327 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef _SMB2_H_ #define _SMB2_H_ #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef __cplusplus extern "C" { #endif struct smb2_timeval { time_t tv_sec; long tv_usec; }; #define SMB2_ERROR_REPLY_SIZE 9 struct smb2_error_reply { uint8_t error_context_count; uint32_t byte_count; uint8_t *error_data; }; #define SMB2_FLAGS_SERVER_TO_REDIR 0x00000001 #define SMB2_FLAGS_ASYNC_COMMAND 0x00000002 #define SMB2_FLAGS_RELATED_OPERATIONS 0x00000004 #define SMB2_FLAGS_SIGNED 0x00000008 #define SMB2_FLAGS_PRIORITY_MASK 0x00000070 #define SMB2_FLAGS_DFS_OPERATIONS 0x10000000 #define SMB2_FLAGS_REPLAY_OPERATION 0x20000000 enum smb2_command { SMB2_NEGOTIATE = 0, SMB2_SESSION_SETUP = 1, SMB2_LOGOFF = 2, SMB2_TREE_CONNECT = 3, SMB2_TREE_DISCONNECT = 4, SMB2_CREATE = 5, SMB2_CLOSE = 6, SMB2_FLUSH = 7, SMB2_READ = 8, SMB2_WRITE = 9, SMB2_LOCK = 10, SMB2_IOCTL = 11, SMB2_CANCEL = 12, SMB2_ECHO = 13, SMB2_QUERY_DIRECTORY = 14, SMB2_CHANGE_NOTIFY = 15, SMB2_QUERY_INFO = 16, SMB2_SET_INFO = 17, SMB2_OPLOCK_BREAK = 18, SMB1_NEGOTIATE = 114, }; /* * SMB2 NEGOTIATE */ #define SMB2_NEGOTIATE_SIGNING_ENABLED 0x0001 #define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x0002 #define SMB2_GLOBAL_CAP_DFS 0x00000001 #define SMB2_GLOBAL_CAP_LEASING 0x00000002 #define SMB2_GLOBAL_CAP_LARGE_MTU 0x00000004 #define SMB2_GLOBAL_CAP_MULTI_CHANNEL 0x00000008 #define SMB2_GLOBAL_CAP_PERSISTENT_HANDLES 0x00000010 #define SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020 #define SMB2_GLOBAL_CAP_ENCRYPTION 0x00000040 #define SMB2_PREAUTH_INTEGRITY_CAP 0x0001 #define SMB2_ENCRYPTION_CAP 0x0002 #define SMB2_COMPRESSION_CAP 0x0003 #define SMB2_NETNAME_NEGOTIATE_CONTEXT_ID 0x0005 #define SMB2_TRANSPORT_CAP 0x0006 #define SMB2_RDMA_TRANSFORM_CAP 0x0007 #define SMB2_SIGNING_CAP 0x0008 #define SMB2_CONTEXTTYPE_RESERVED 0x0100 #define SMB2_HASH_SHA_512 0x0001 #define SMB2_PREAUTH_HASH_SIZE 64 #define SMB2_ENCRYPTION_AES_128_CCM 0x0001 #define SMB2_ENCRYPTION_AES_128_GCM 0x0002 #define SMB2_NEGOTIATE_MAX_DIALECTS 10 #define SMB2_NEGOTIATE_REQUEST_SIZE 36 #define SMB2_GUID_SIZE 16 typedef uint8_t smb2_guid[SMB2_GUID_SIZE]; struct smb2_negotiate_request { uint16_t dialect_count; uint16_t security_mode; uint32_t capabilities; smb2_guid client_guid; uint32_t negotiate_context_offset; uint16_t negotiate_context_count; uint16_t dialects[SMB2_NEGOTIATE_MAX_DIALECTS]; }; #define SMB2_NEGOTIATE_REPLY_SIZE 65 struct smb2_negotiate_reply { uint16_t security_mode; uint16_t dialect_revision; uint16_t cypher; smb2_guid server_guid; uint32_t capabilities; uint32_t max_transact_size; uint32_t max_read_size; uint32_t max_write_size; uint64_t system_time; uint64_t server_start_time; uint32_t negotiate_context_offset; uint16_t negotiate_context_count; uint16_t security_buffer_length; uint16_t security_buffer_offset; uint8_t *security_buffer; }; /* session setup flags */ #define SMB2_SESSION_FLAG_BINDING 0x01 /* session setup capabilities */ #define SMB2_GLOBAL_CAP_DFS 0x00000001 #define SMB2_GLOBAL_CAP_UNUSED1 0x00000002 #define SMB2_GLOBAL_CAP_UNUSED2 0x00000004 #define SMB2_GLOBAL_CAP_UNUSED4 0x00000008 #define SMB2_SESSION_SETUP_REQUEST_SIZE 25 struct smb2_session_setup_request { uint8_t flags; uint8_t security_mode; uint32_t capabilities; uint32_t channel; uint64_t previous_session_id; uint16_t security_buffer_length; uint8_t *security_buffer; }; #define SMB2_SESSION_FLAG_IS_GUEST 0x0001 #define SMB2_SESSION_FLAG_IS_NULL 0x0002 #define SMB2_SESSION_FLAG_IS_ENCRYPT_DATA 0x0004 #define SMB2_SESSION_SETUP_REPLY_SIZE 9 struct smb2_session_setup_reply { uint16_t session_flags; uint16_t security_buffer_length; uint16_t security_buffer_offset; uint8_t *security_buffer; }; #define SMB2_TREE_CONNECT_REQUEST_SIZE 9 #define SMB2_SHAREFLAG_CLUSTER_RECONNECT 0x0001 struct smb2_tree_connect_request { uint16_t flags; uint16_t path_offset; uint16_t path_length; uint16_t *path; }; #define SMB2_SHARE_TYPE_DISK 0x01 #define SMB2_SHARE_TYPE_PIPE 0x02 #define SMB2_SHARE_TYPE_PRINT 0x03 #define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000 #define SMB2_SHAREFLAG_DFS 0x00000001 #define SMB2_SHAREFLAG_DFS_ROOT 0x00000002 #define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010 #define SMB2_SHAREFLAG_VDO_CACHING 0x00000020 #define SMB2_SHAREFLAG_NO_CACHING 0x00000030 #define SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS 0x00000100 #define SMB2_SHAREFLAG_FORCE_SHARED_DELETE 0x00000200 #define SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING 0x00000400 #define SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM 0x00000800 #define SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCK 0x00001000 #define SMB2_SHAREFLAG_ENABLE_HASH_V1 0x00002000 #define SMB2_SHAREFLAG_ENABLE_HASH_V2 0x00004000 #define SMB2_SHAREFLAG_ENCRYPT_DATA 0x00008000 #define SMB2_SHARE_CAP_DFS 0x00000008 #define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY 0x00000010 #define SMB2_SHARE_CAP_SCALEOUT 0x00000020 #define SMB2_SHARE_CAP_CLUSTER 0x00000040 #define SMB2_SHARE_CAP_ASYMMETRIC 0x00000080 #define SMB2_TREE_CONNECT_REPLY_SIZE 16 struct smb2_tree_connect_reply { uint8_t share_type; uint32_t share_flags; uint32_t capabilities; uint32_t maximal_access; }; #define SMB2_CREATE_REQUEST_SIZE 57 #define SMB2_OPLOCK_LEVEL_NONE 0x00 #define SMB2_OPLOCK_LEVEL_II 0x01 #define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 #define SMB2_OPLOCK_LEVEL_BATCH 0x09 #define SMB2_OPLOCK_LEVEL_LEASE 0xff #define SMB2_CREATE_REQUEST_LEASE_SIZE 32 #define SMB2_IMPERSONATION_ANONYMOUS 0x00000000 #define SMB2_IMPERSONATION_IDENTIFICATION 0x00000001 #define SMB2_IMPERSONATION_IMPERSONATION 0x00000002 #define SMB2_IMPERSONATION_DELEGATE 0x00000003 /* Access mask common to all objects */ #define SMB2_FILE_READ_EA 0x00000008 #define SMB2_FILE_WRITE_EA 0x00000010 #define SMB2_FILE_DELETE_CHILD 0x00000040 #define SMB2_FILE_READ_ATTRIBUTES 0x00000080 #define SMB2_FILE_WRITE_ATTRIBUTES 0x00000100 #define SMB2_DELETE 0x00010000 #define SMB2_READ_CONTROL 0x00020000 #define SMB2_WRITE_DACL 0x00040000 #define SMB2_WRITE_OWNER 0x00080000 #define SMB2_SYNCHRONIZE 0x00100000 #define SMB2_ACCESS_SYSTEM_SECURITY 0x01000000 #define SMB2_MAXIMUM_ALLOWED 0x02000000 #define SMB2_GENERIC_ALL 0x10000000 #define SMB2_GENERIC_EXECUTE 0x20000000 #define SMB2_GENERIC_WRITE 0x40000000 #define SMB2_GENERIC_READ 0x80000000 /* Access mask unique for file/pipe/printer */ #define SMB2_FILE_READ_DATA 0x00000001 #define SMB2_FILE_WRITE_DATA 0x00000002 #define SMB2_FILE_APPEND_DATA 0x00000004 #define SMB2_FILE_EXECUTE 0x00000020 /* Access mask unique for directories */ #define SMB2_FILE_LIST_DIRECTORY 0x00000001 #define SMB2_FILE_ADD_FILE 0x00000002 #define SMB2_FILE_ADD_SUBDIRECTORY 0x00000004 #define SMB2_FILE_TRAVERSE 0x00000020 /* File attributes */ #define SMB2_FILE_ATTRIBUTE_READONLY 0x00000001 #define SMB2_FILE_ATTRIBUTE_HIDDEN 0x00000002 #define SMB2_FILE_ATTRIBUTE_SYSTEM 0x00000004 #define SMB2_FILE_ATTRIBUTE_DIRECTORY 0x00000010 #define SMB2_FILE_ATTRIBUTE_ARCHIVE 0x00000020 #define SMB2_FILE_ATTRIBUTE_NORMAL 0x00000080 #define SMB2_FILE_ATTRIBUTE_TEMPORARY 0x00000100 #define SMB2_FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 #define SMB2_FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 #define SMB2_FILE_ATTRIBUTE_COMPRESSED 0x00000800 #define SMB2_FILE_ATTRIBUTE_OFFLINE 0x00001000 #define SMB2_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 #define SMB2_FILE_ATTRIBUTE_ENCRYPTED 0x00004000 #define SMB2_FILE_ATTRIBUTE_INTEGRITY_STREAM 0x00008000 #define SMB2_FILE_ATTRIBUTE_NO_SCRUB_DATA 0x00020000 /* Share access */ #define SMB2_FILE_SHARE_READ 0x00000001 #define SMB2_FILE_SHARE_WRITE 0x00000002 #define SMB2_FILE_SHARE_DELETE 0x00000004 /* Create disposition */ #define SMB2_FILE_SUPERSEDE 0x00000000 #define SMB2_FILE_OPEN 0x00000001 #define SMB2_FILE_CREATE 0x00000002 #define SMB2_FILE_OPEN_IF 0x00000003 #define SMB2_FILE_OVERWRITE 0x00000004 #define SMB2_FILE_OVERWRITE_IF 0x00000005 /* Create options */ #define SMB2_FILE_DIRECTORY_FILE 0x00000001 #define SMB2_FILE_WRITE_THROUGH 0x00000002 #define SMB2_FILE_SEQUENTIAL_ONLY 0x00000004 #define SMB2_FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 #define SMB2_FILE_SYNCHRONOUS_IO_ALERT 0x00000010 #define SMB2_FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 #define SMB2_FILE_NON_DIRECTORY_FILE 0x00000040 #define SMB2_FILE_COMPLETE_IF_OPLOCKED 0x00000100 #define SMB2_FILE_NO_EA_KNOWLEDGE 0x00000200 #define SMB2_FILE_RANDOM_ACCESS 0x00000800 #define SMB2_FILE_DELETE_ON_CLOSE 0x00001000 #define SMB2_FILE_OPEN_BY_FILE_ID 0x00002000 #define SMB2_FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 #define SMB2_FILE_NO_COMPRESSION 0x00008000 #define SMB2_FILE_OPEN_REMOTE_INSTANCE 0x00000400 #define SMB2_FILE_OPEN_REQUIRING_OPLOCK 0x00010000 #define SMB2_FILE_DISALLOW_EXCLUSIVE 0x00020000 #define SMB2_FILE_RESERVE_OPFILTER 0x00100000 #define SMB2_FILE_OPEN_REPARSE_POINT 0x00200000 #define SMB2_FILE_OPEN_NO_RECALL 0x00400000 #define SMB2_FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 struct smb2_create_request { uint8_t security_flags; uint8_t requested_oplock_level; uint32_t impersonation_level; uint64_t smb_create_flags; uint32_t desired_access; uint32_t file_attributes; uint32_t share_access; uint32_t create_disposition; uint32_t create_options; uint16_t name_offset; uint16_t name_length; const char *name; /* name in UTF8 */ uint32_t create_context_offset; uint32_t create_context_length; uint8_t *create_context; }; #define SMB2_CREATE_REPLY_SIZE 89 #define SMB2_FD_SIZE 16 typedef uint8_t smb2_file_id[SMB2_FD_SIZE]; #define SMB2_LEASE_KEY_SIZE 16 typedef uint8_t smb2_lease_key[SMB2_LEASE_KEY_SIZE]; struct smb2fh; smb2_file_id *smb2_get_file_id(struct smb2fh *fh); /* * This creates a new smb2fh based on fileid. * Free it with smb2_close_async() */ struct smb2_context; struct smb2fh *smb2_fh_from_file_id(struct smb2_context *smb2, smb2_file_id *fileid); struct smb2_create_reply { uint8_t oplock_level; uint8_t flags; uint32_t create_action; uint64_t creation_time; uint64_t last_access_time; uint64_t last_write_time; uint64_t change_time; uint64_t allocation_size; uint64_t end_of_file; uint32_t file_attributes; smb2_file_id file_id; uint32_t create_context_length; uint32_t create_context_offset; uint8_t *create_context; }; #define SMB2_CLOSE_REQUEST_SIZE 24 #define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB 0x0001 struct smb2_close_request { uint16_t flags; smb2_file_id file_id; }; #define SMB2_CLOSE_REPLY_SIZE 60 struct smb2_close_reply { uint16_t flags; uint64_t creation_time; uint64_t last_access_time; uint64_t last_write_time; uint64_t change_time; uint64_t allocation_size; uint64_t end_of_file; uint32_t file_attributes; }; #define SMB2_FLUSH_REQUEST_SIZE 24 struct smb2_flush_request { smb2_file_id file_id; }; #define SMB2_LOGFF_REQUEST_SIZE 4 struct smb2_logoff_request { uint16_t reserved; }; #define SMB2_ECHO_REQUEST_SIZE 4 struct smb2_echo_request { uint16_t reserved; }; #define SMB2_FLUSH_REPLY_SIZE 4 #define SMB2_QUERY_DIRECTORY_REQUEST_SIZE 33 /* File information class */ #define SMB2_FILE_DIRECTORY_INFORMATION 0x01 #define SMB2_FILE_FULL_DIRECTORY_INFORMATION 0x02 #define SMB2_FILE_BOTH_DIRECTORY_INFORMATION 0x03 #define SMB2_FILE_ID_BOTH_DIRECTORY_INFORMATION 0x25 #define SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION 0x26 /* query flags */ #define SMB2_RESTART_SCANS 0x01 #define SMB2_RETURN_SINGLE_ENTRY 0x02 #define SMB2_INDEX_SPECIFIED 0x04 #define SMB2_REOPEN 0x10 #define SMB2_FILEID_FULL_DIRECTORY_INFORMATION_SIZE 80 /* Structure for SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION. * This is also used as the dirent content. */ struct smb2_fileidfulldirectoryinformation { uint32_t next_entry_offset; uint32_t file_index; struct smb2_timeval creation_time; struct smb2_timeval last_access_time; struct smb2_timeval last_write_time; struct smb2_timeval change_time; uint64_t end_of_file; uint64_t allocation_size; uint32_t file_attributes; uint32_t file_name_length; uint32_t ea_size; uint64_t file_id; const char *name; /* or "reserved" for replys */ }; #define SMB2_FILEID_BOTH_DIRECTORY_INFORMATION_SIZE 104 /* Structure for SMB2_FILE_ID_BOTH_DIRECTORY_INFORMATION. */ struct smb2_fileidbothdirectoryinformation { uint32_t next_entry_offset; uint32_t file_index; struct smb2_timeval creation_time; struct smb2_timeval last_access_time; struct smb2_timeval last_write_time; struct smb2_timeval change_time; uint64_t end_of_file; uint64_t allocation_size; uint32_t file_attributes; uint32_t file_name_length; uint32_t ea_size; uint8_t short_name_length; uint8_t short_name[24]; uint64_t file_id; const char *name; /* or "reserved" for replys */ }; struct smb2_iovec; int smb2_decode_fileidfulldirectoryinformation( struct smb2_context *smb2, struct smb2_fileidfulldirectoryinformation *fs, struct smb2_iovec *vec); struct smb2_query_directory_request { uint8_t file_information_class; uint8_t flags; uint32_t file_index; smb2_file_id file_id; uint32_t output_buffer_length; uint16_t file_name_offset; uint16_t file_name_length; const char *name; /* name in UTF8 */ }; #define SMB2_QUERY_DIRECTORY_REPLY_SIZE 9 struct smb2_query_directory_reply { uint16_t output_buffer_offset; uint32_t output_buffer_length; uint8_t *output_buffer; }; #define SMB2_READ_REQUEST_SIZE 49 #define SMB2_READFLAG_READ_UNBUFFERED 0x01 #define SMB2_CHANNEL_NONE 0x00000000 #define SMB2_CHANNEL_RDMA_V1 0x00000001 #define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000002 struct smb2_read_request { uint8_t flags; uint32_t length; uint64_t offset; uint8_t *buf; smb2_file_id file_id; uint32_t minimum_count; uint32_t channel; uint32_t remaining_bytes; uint16_t read_channel_info_offset; uint16_t read_channel_info_length; uint8_t *read_channel_info; }; #define SMB2_READ_REPLY_SIZE 17 struct smb2_read_reply { uint8_t data_offset; uint32_t data_length; uint32_t data_remaining; uint8_t *data; }; #define SMB2_QUERY_INFO_REQUEST_SIZE 41 /* info type */ #define SMB2_0_INFO_FILE 0x01 #define SMB2_0_INFO_FILESYSTEM 0x02 #define SMB2_0_INFO_SECURITY 0x03 #define SMB2_0_INFO_QUOTA 0x04 /* File information class : for SMB2_0_INFO_FILE */ #define SMB2_FILE_DIRECTORY_INFORMATION 0x01 #define SMB2_FILE_FULL_DIRECTORY_INFORMATION 0x02 #define SMB2_FILE_BOTH_DIRECTORY_INFORMATION 0x03 #define SMB2_FILE_BASIC_INFORMATION 0x04 #define SMB2_FILE_STANDARD_INFORMATION 0x05 #define SMB2_FILE_INTERNAL_INFORMATION 0x06 #define SMB2_FILE_EA_INFORMATION 0x07 #define SMB2_FILE_ACCESS_INFORMATION 0x08 #define SMB2_FILE_NAME_INFORMATION 0x09 #define SMB2_FILE_RENAME_INFORMATION 0x0A #define SMB2_FILE_LINK_INFORMATION 0x0B #define SMB2_FILE_NAMES_INFORMATION 0x0C #define SMB2_FILE_DISPOSITION_INFORMATION 0x0D #define SMB2_FILE_POSITION_INFORMATION 0x0E #define SMB2_FILE_FULL_EA_INFORMATION 0x0F #define SMB2_FILE_MODE_INFORMATION 0x10 #define SMB2_FILE_ALIGNMENT_INFORMATION 0x11 #define SMB2_FILE_ALL_INFORMATION 0x12 #define SMB2_FILE_END_OF_FILE_INFORMATION 0x14 #define SMB2_FILE_ALTERNATE_NAME_INFORMATION 0x15 #define SMB2_FILE_OBJECT_ID_INFORMATION 0x1D #define SMB2_FILE_ATTRIBUTE_TAG_INFORMATION 0x23 #define SMB2_FILE_NORMALIZED_NAME_INFORMATION 0x30 #define SMB2_FILE_ID_INFORMATION 0x3B #define SMB2_FILE_STREAM_INFORMATION 0x16 #define SMB2_FILE_PIPE_INFORMATION 0x17 #define SMB2_FILE_PIPE_LOCAL_INFORMATION 0x18 #define SMB2_FILE_PIPE_REMOTE_INFORMATION 0x19 #define SMB2_FILE_MAILSLOT_QUERY_INFORMATION 0x1A #define SMB2_FILE_MAILSLOT_SET_INFORMATION 0x1B #define SMB2_FILE_COMPRESSION_INFORMATION 0x1C #define SMB2_FILE_OBJECT_ID_INFORMATION 0x1D #define SMB2_FILE_QUOTA_INFORMATION 0x20 #define SMB2_FILE_REPARSE_POINT_INFORMATION 0x21 #define SMB2_FILE_NETWORK_OPEN_INFORMATION 0x22 /* Filesystem information class : for SMB2_0_INFO_FILESYSTEM */ #define SMB2_FILE_FS_VOLUME_INFORMATION 1 #define SMB2_FILE_FS_SIZE_INFORMATION 3 #define SMB2_FILE_FS_DEVICE_INFORMATION 4 #define SMB2_FILE_FS_ATTRIBUTE_INFORMATION 5 #define SMB2_FILE_FS_CONTROL_INFORMATION 6 #define SMB2_FILE_FS_FULL_SIZE_INFORMATION 7 #define SMB2_FILE_FS_OBJECT_ID_INFORMATION 8 #define SMB2_FILE_FS_SECTOR_SIZE_INFORMATION 11 #define SMB2_FILE_INFO_CLASS_RESERVED 0x40 /* additional info */ #define SMB2_OWNER_SECURITY_INFORMATION 0x00000001 #define SMB2_GROUP_SECURITY_INFORMATION 0x00000002 #define SMB2_DACL_SECURITY_INFORMATION 0x00000004 #define SMB2_SACL_SECURITY_INFORMATION 0x00000008 #define SMB2_LABEL_SECURITY_INFORMATION 0x00000010 #define SMB2_ATTRIBUTE_SECURITY_INFORMATION 0x00000020 #define SMB2_SCOPE_SECURITY_INFORMATION 0x00000040 #define SMB2_BACKUP_SECURITY_INFORMATION 0x00010000 /* flags */ #define SL_RESTART_SCAN 0x00000001 #define SL_RETURN_SINGLE_ENTRY 0x00000002 #define SL_INDEX_SPECIFIED 0x00000004 /* * FILE_BASIC_INFORMATION */ struct smb2_file_basic_info { struct smb2_timeval creation_time; struct smb2_timeval last_access_time; struct smb2_timeval last_write_time; struct smb2_timeval change_time; uint32_t file_attributes; }; /* * FILE_STANDARD_INFORMATION */ struct smb2_file_standard_info { uint64_t allocation_size; uint64_t end_of_file; uint32_t number_of_links; uint8_t delete_pending; uint8_t directory; }; /* * FILE_POSITION_INFORMATION */ struct smb2_file_position_info { uint64_t current_byte_offset; }; /* * FILE_ALL_INFORMATION. */ struct smb2_file_all_info { struct smb2_file_basic_info basic; struct smb2_file_standard_info standard; uint64_t index_number; uint32_t ea_size; uint32_t access_flags; uint64_t current_byte_offset; uint32_t mode; uint32_t alignment_requirement; const uint8_t *name; }; struct smb2_query_info_request { uint8_t info_type; uint8_t file_info_class; uint32_t output_buffer_length; uint16_t input_buffer_offset; uint32_t input_buffer_length; uint8_t *input_buffer; uint32_t additional_information; uint32_t flags; smb2_file_id file_id; const uint8_t *input; }; /* * FILE_END_OF_FILE_INFORMATION. */ struct smb2_file_end_of_file_info { uint64_t end_of_file; }; /* * FILE_DISPOSITION_INFORMATION. */ struct smb2_file_disposition_info { uint8_t delete_pending; }; /* * SMB2_FILE_RENAME_INFORMATION. */ struct smb2_file_rename_info { uint8_t replace_if_exist; const uint8_t* file_name; }; /* * FILE_NETWORK_OPEN_INFORMATION */ struct smb2_file_network_open_info { struct smb2_timeval creation_time; struct smb2_timeval last_access_time; struct smb2_timeval last_write_time; struct smb2_timeval change_time; uint64_t allocation_size; uint64_t end_of_file; uint32_t file_attributes; }; #define SMB2_SET_INFO_REQUEST_SIZE 33 struct smb2_set_info_request { uint8_t info_type; uint8_t file_info_class; uint32_t buffer_length; uint16_t buffer_offset; uint32_t additional_information; smb2_file_id file_id; void *input_data; }; #define SMB2_SET_INFO_REPLY_SIZE 2 /* * SID */ #define SID_ID_AUTH_LEN 6 #ifdef _MSC_VER #pragma warning(push) #pragma warning( disable : 4200 ) /* Silence c4200 warning. */ #endif struct smb2_sid { uint8_t revision; uint8_t sub_auth_count; uint8_t id_auth[SID_ID_AUTH_LEN]; uint32_t sub_auth[0]; }; #ifdef _MSC_VER #pragma warning(pop) #endif /* * ACE */ /* ace type */ #define SMB2_ACCESS_ALLOWED_ACE_TYPE 0x00 #define SMB2_ACCESS_DENIED_ACE_TYPE 0x01 #define SMB2_SYSTEM_AUDIT_ACE_TYPE 0x02 /* * Reserved for future use * #define SMB2_SYSTEM_ALARM_ACE_TYPE 0x03 */ #define SMB2_ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05 #define SMB2_ACCESS_DENIED_OBJECT_ACE_TYPE 0x06 #define SMB2_SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07 /* * Reserved for future use * #define SMB2_SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08 */ #define SMB2_ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x09 #define SMB2_ACCESS_DENIED_CALLBACK_ACE_TYPE 0x10 #define SMB2_SYSTEM_MANDATORY_LABEL_ACE_TYPE 0x11 #define SMB2_SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE 0x12 #define SMB2_SYSTEM_SCOPED_POLICY_ID_ACE_TYPE 0x13 /* ace flags */ #define SMB2_OBJECT_INHERIT_ACE 0x01 #define SMB2_CONTAINER_INHERIT_ACE 0x02 #define SMB2_NO_PROPAGATE_INHERIT_ACE 0x04 #define SMB2_INHERIT_ONLY_ACE 0x08 #define SMB2_INHERITED_ACE 0x10 #define SMB2_SUCCESSFUL_ACCESS_ACE_FLAG 0x40 #define SMB2_FAILED_ACCESS_ACE_FLAG 0x80 #define SMB2_OBJECT_TYPE_SIZE 16 struct smb2_ace { struct smb2_ace *next; uint8_t ace_type; uint8_t ace_flags; uint16_t ace_size; /* Which fields are valid depends on the ace type */ uint32_t mask; uint32_t flags; struct smb2_sid *sid; uint8_t object_type[SMB2_OBJECT_TYPE_SIZE]; uint8_t inherited_object_type[SMB2_OBJECT_TYPE_SIZE]; /* ApplicationData/AttributeData. Used by * SMB2_ACCESS_ALLOWED_CALLBACK_ACE_TYPE, * SMB2_DENIED_ALLOWED_CALLBACK_ACE_TYPE, * SMB2_SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE */ size_t ad_len; char *ad_data; /* raw blob, used for unknown ACE types */ size_t raw_len; char *raw_data; }; /* * ACL */ #define SMB2_ACL_REVISION 0x02 #define SMB2_ACL_REVISION_DS 0x04 struct smb2_acl { uint8_t revision; uint16_t ace_count; struct smb2_ace *aces; }; /* * SECURITY_DESCRIPTOR */ /* Security descriptor control flags */ #define SMB2_SD_CONTROL_OD 0x0001 #define SMB2_SD_CONTROL_GD 0x0002 #define SMB2_SD_CONTROL_DP 0x0004 #define SMB2_SD_CONTROL_DD 0x0008 #define SMB2_SD_CONTROL_SP 0x0010 #define SMB2_SD_CONTROL_SD 0x0020 #define SMB2_SD_CONTROL_SS 0x0040 #define SMB2_SD_CONTROL_DT 0x0080 #define SMB2_SD_CONTROL_DC 0x0100 #define SMB2_SD_CONTROL_SC 0x0200 #define SMB2_SD_CONTROL_DI 0x0400 #define SMB2_SD_CONTROL_SI 0x0800 #define SMB2_SD_CONTROL_PD 0x1000 #define SMB2_SD_CONTROL_PS 0x2000 #define SMB2_SD_CONTROL_RM 0x4000 #define SMB2_SD_CONTROL_SR 0x8000 struct smb2_security_descriptor { uint8_t revision; uint16_t control; struct smb2_sid *owner; struct smb2_sid *group; struct smb2_acl *dacl; }; struct smb2_file_fs_volume_info { struct smb2_timeval creation_time; uint32_t volume_serial_number; uint32_t volume_label_length; uint8_t supports_objects; uint8_t reserved; const uint8_t *volume_label; }; struct smb2_file_fs_size_info { uint64_t total_allocation_units; uint64_t available_allocation_units; uint32_t sectors_per_allocation_unit; uint32_t bytes_per_sector; }; struct smb2_file_fs_attribute_info { uint32_t filesystem_attributes; uint32_t maximum_component_name_length; uint32_t filesystem_name_length; const uint8_t *filesystem_name; }; /* Device type */ #define FILE_DEVICE_CD_ROM 0x00000002 #define FILE_DEVICE_DISK 0x00000007 /* Characteristics */ #define FILE_REMOVABLE_MEDIA 0x00000001 #define FILE_READ_ONLY_DEVICE 0x00000002 #define FILE_FLOPPY_DISKETTE 0x00000004 #define FILE_WRITE_ONCE_MEDIA 0x00000008 #define FILE_REMOTE_DEVICE 0x00000010 #define FILE_DEVICE_IS_MOUNTED 0x00000020 #define FILE_VIRTUAL_VOLUME 0x00000040 #define FILE_DEVICE_SECURE_OPEN 0x00000100 #define FILE_CHARACTERISTIC_TS_DEVICE 0x00001000 #define FILE_CHARACTERISTIC_WEBDAV_DEVICE 0x00002000 #define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000 #define FILE_PORTABLE_DEVICE 0x00040000 struct smb2_file_fs_device_info { uint32_t device_type; uint32_t characteristics; }; /* File System Control Flags */ #define FILE_VC_QUOTA_TRACK 0x00000001 #define FILE_VC_QUOTA_ENFORCE 0x00000002 #define FILE_VC_CONTENT_INDEX_DISABLED 0x00000008 #define FILE_VC_LOG_QUOTA_THRESHOLD 0x00000010 #define FILE_VC_LOG_QUOTA_LIMIT 0x00000020 #define FILE_VC_LOG_VOLUME_THRESHOLD 0x00000040 #define FILE_VC_LOG_VOLUME_LIMIT 0x00000080 #define FILE_VC_QUOTAS_INCOMPLETE 0x00000100 #define FILE_VC_QUOTAS_REBUILDING 0x00000200 struct smb2_file_fs_control_info { uint64_t free_space_start_filtering; uint64_t free_space_threshold; uint64_t free_space_stop_filtering; uint64_t default_quota_threshold; uint64_t default_quota_limit; uint32_t file_system_control_flags; }; struct smb2_file_fs_full_size_info { uint64_t total_allocation_units; uint64_t caller_available_allocation_units; uint64_t actual_available_allocation_units; uint32_t sectors_per_allocation_unit; uint32_t bytes_per_sector; }; struct smb2_file_fs_object_id_info { smb2_guid object_id; uint8_t extended_info[48]; }; /* Flags */ #define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001 #define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002 #define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004 #define SSINFO_FLAGS_TRIM_ENABLED 0x00000008 struct smb2_file_fs_sector_size_info { uint32_t logical_bytes_per_sector; uint32_t physical_bytes_per_sector_for_atomicity; uint32_t physical_bytes_per_sector_for_performance; uint32_t file_system_effective_physical_bytes_per_sector_for_atomicity; uint32_t flags; uint32_t byte_offset_for_sector_alignment; uint32_t byte_offset_for_partition_alignment; }; #define SMB2_QUERY_INFO_REPLY_SIZE 9 struct smb2_query_info_reply { uint16_t output_buffer_offset; uint32_t output_buffer_length; void *output_buffer; }; #define SMB2_IOCTL_REQUEST_SIZE 57 /* CtlCode */ #define SMB2_FSCTL_DFS_GET_REFERRALS 0x00060194 #define SMB2_FSCTL_PIPE_PEEK 0x0011400C #define SMB2_FSCTL_PIPE_WAIT 0x00110018 #define SMB2_FSCTL_PIPE_TRANSCEIVE 0x0011C017 #define SMB2_FSCTL_SRV_COPYCHUNK 0x001440F2 #define SMB2_FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064 #define SMB2_FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078 #define SMB2_FSCTL_SRV_READ_HASH 0x001441bb #define SMB2_FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2 #define SMB2_FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 #define SMB2_FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC #define SMB2_FSCTL_SET_REPARSE_POINT 0x000900A4 #define SMB2_FSCTL_GET_REPARSE_POINT 0X000900A8 #define SMB2_FSCTL_DFS_GET_REFERRALS_EX 0x000601B0 #define SMB2_FSCTL_FILE_LEVEL_TRIM 0x00098208 #define SMB2_FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 /* Flags */ #define SMB2_0_IOCTL_IS_FSCTL 0x00000001 #define SMB2_SYMLINK_FLAG_RELATIVE 0x00000001 struct smb2_symlink_reparse_buffer { uint32_t flags; char *subname; char *printname; }; #define SMB2_REPARSE_TAG_SYMLINK 0xa000000c /* * Reparse_data_buffer */ struct smb2_reparse_data_buffer { uint32_t reparse_tag; uint16_t reparse_data_length; union { struct smb2_symlink_reparse_buffer symlink; }; }; struct smb2_ioctl_request { uint32_t ctl_code; smb2_file_id file_id; uint32_t input_offset; uint32_t input_count; uint32_t max_input_response; uint32_t output_offset; uint32_t output_count; uint32_t max_output_response; uint32_t flags; void *input; }; #define SMB2_IOCTL_REPLY_SIZE 49 struct smb2_ioctl_reply { uint32_t ctl_code; smb2_file_id file_id; uint32_t input_offset; uint32_t input_count; uint32_t output_offset; uint32_t output_count; uint32_t flags; void *output; }; #define SMB2_IOCTL_VALIDIATE_NEGOTIATE_INFO_SIZE 24 struct smb2_ioctl_validate_negotiate_info { uint32_t capabilities; uint8_t guid[16]; uint16_t security_mode; uint16_t dialect; }; #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_SIZE 0x00000008 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_CREATION 0x00000040 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_EA 0x00000080 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_SECURITY 0x00000100 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 #define SMB2_CHANGE_NOTIIFY_FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 #define SMB2_CHANGE_NOTIFY_WATCH_TREE 0x0001 #define SMB2_CHANGE_NOTIFY_REQUEST_SIZE 32 struct smb2_change_notify_request { uint16_t flags; uint32_t output_buffer_length; smb2_file_id file_id; uint32_t completion_filter; }; #define SMB2_CHANGE_NOTIFY_REPLY_SIZE 9 struct smb2_change_notify_reply { uint16_t output_buffer_offset; uint32_t output_buffer_length; uint8_t *output; }; #define SMB2_OPLOCK_LEVEL_NONE 0x00 #define SMB2_OPLOCK_LEVEL_II 0x01 #define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 #define SMB2_OPLOCK_BREAK_NOTIFICATION_SIZE 24 struct smb2_oplock_break_notification { uint8_t oplock_level; smb2_file_id file_id; }; #define SMB2_OPLOCK_BREAK_ACKNOWLEDGE_SIZE 24 struct smb2_oplock_break_acknowledgement { uint8_t oplock_level; smb2_file_id file_id; }; #define SMB2_OPLOCK_BREAK_REPLY_SIZE 24 struct smb2_oplock_break_reply { uint8_t oplock_level; smb2_file_id file_id; }; #define SMB2_LEASE_NONE 0x00 #define SMB2_LEASE_READ_CACHING 0x01 #define SMB2_LEASE_HANDLE_CACHING 0x02 #define SMB2_LEASE_WRITE_CACHING 0x04 #define SMB2_BREAK_TYPE_OPLOCK_NOTIFICATION 0x01 #define SMB2_BREAK_TYPE_OPLOCK_RESPONSE 0x02 #define SMB2_BREAK_TYPE_OPLOCK_ACKNOWLEDGE 0x03 #define SMB2_BREAK_TYPE_LEASE_NOTIFICATION 0x04 #define SMB2_BREAK_TYPE_LEASE_RESPONSE 0x05 #define SMB2_BREAK_TYPE_LEASE_ACKNOWLEDGE 0x06 #define SMB2_LEASE_BREAK_NOTIFICATION_SIZE 44 struct smb2_lease_break_notification { uint16_t new_epoch; uint32_t flags; smb2_lease_key lease_key; uint32_t current_lease_state; uint32_t new_lease_state; uint32_t break_reason; uint32_t access_mask_hint; uint32_t share_mask_hint; }; #define SMB2_LEASE_BREAK_ACKNOWLEDGE_SIZE 36 struct smb2_lease_break_acknowledgement { uint32_t flags; smb2_lease_key lease_key; uint32_t lease_state; uint64_t lease_duration; }; #define SMB2_LEASE_BREAK_REPLY_SIZE 36 struct smb2_lease_break_reply { uint32_t flags; smb2_lease_key lease_key; uint32_t lease_state; uint64_t lease_duration; }; /* note that for oplocks, notifications (request) and responses (reply) * come from the server, while acknowledgements come from the client */ struct smb2_oplock_or_lease_break_reply { uint16_t struct_size; int break_type; union { struct smb2_oplock_break_notification oplock; struct smb2_oplock_break_reply oplockrep; struct smb2_lease_break_notification lease; struct smb2_lease_break_reply leaserep; } lock; }; struct smb2_oplock_or_lease_break_request { uint16_t struct_size; int break_type; union { struct smb2_oplock_break_acknowledgement oplock; struct smb2_lease_break_acknowledgement lease; } lock; }; #define SMB2_WRITE_REQUEST_SIZE 49 #define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001 #define SMB2_WRITEFLAG_WRITE_UNBUFFERED 0x00000002 struct smb2_write_request { uint16_t data_offset; uint32_t length; uint64_t offset; const uint8_t* buf; smb2_file_id file_id; uint32_t channel; uint32_t remaining_bytes; uint16_t write_channel_info_offset; uint16_t write_channel_info_length; uint8_t *write_channel_info; uint32_t flags; }; #define SMB2_WRITE_REPLY_SIZE 17 struct smb2_write_reply { uint32_t count; uint32_t remaining; }; #define SMB2_LOCK_ELEMENT_SIZE 24 struct smb2_lock_element { uint64_t offset; uint64_t length; uint32_t flags; uint32_t reserved; }; /* Note that this size includes 1 lock element */ #define SMB2_LOCK_REQUEST_SIZE 48 struct smb2_lock_request { uint16_t lock_count; uint8_t lock_sequence_number; uint32_t lock_sequence_index; smb2_file_id file_id; struct smb2_lock_element *locks; }; #define SMB2_LOCK_REPLY_SIZE 4 #define SMB2_ECHO_REQUEST_SIZE 4 #define SMB2_ECHO_REPLY_SIZE 4 #define SMB2_CANCEL_REQUEST_SIZE 4 #define SMB2_LOGOFF_REQUEST_SIZE 4 #define SMB2_LOGOFF_REPLY_SIZE 4 #define SMB2_TREE_DISCONNECT_REQUEST_SIZE 4 #define SMB2_TREE_DISCONNECT_REPLY_SIZE 4 #define SMB_ENCRYPTION_AES128_CCM 0x0001 #ifdef __cplusplus } #endif #endif /* !_SMB2_H_ */ libsmb2-6.2/include/smb2/libsmb2-dcerpc-srvsvc.h0000664000175000017500000001303714732155517020576 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef _LIBSMB2_DCERPC_SRVSVC_H_ #define _LIBSMB2_DCERPC_SRVSVC_H_ #ifdef __cplusplus extern "C" { #endif #include #define SRVSVC_NETRSHAREENUM 0x0f #define SRVSVC_NETRSHAREGETINFO 0x10 struct dcerpc_context; struct dcerpc_pdu; /* Low 2 bits desctibe the type */ #define SHARE_TYPE_DISKTREE 0 #define SHARE_TYPE_PRINTQ 1 #define SHARE_TYPE_DEVICE 2 #define SHARE_TYPE_IPC 3 #define SHARE_TYPE_TEMPORARY 0x40000000 #define SHARE_TYPE_HIDDEN 0x80000000 enum SHARE_INFO_enum { SHARE_INFO_0 = 0, SHARE_INFO_1 = 1, }; struct srvsvc_SHARE_INFO_0 { struct dcerpc_utf16 netname; }; int srvsvc_SHARE_INFO_0_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); struct srvsvc_SHARE_INFO_0_carray { uint32_t max_count; struct srvsvc_SHARE_INFO_0 *share_info_0; }; struct srvsvc_SHARE_INFO_0_CONTAINER { uint32_t EntriesRead; struct srvsvc_SHARE_INFO_0_carray *Buffer; }; struct srvsvc_SHARE_INFO_1 { struct dcerpc_utf16 netname; uint32_t type; struct dcerpc_utf16 remark; }; int srvsvc_SHARE_INFO_1_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); struct srvsvc_SHARE_INFO_1_carray { uint32_t max_count; struct srvsvc_SHARE_INFO_1 *share_info_1; }; struct srvsvc_SHARE_INFO_1_CONTAINER { uint32_t EntriesRead; struct srvsvc_SHARE_INFO_1_carray *Buffer; }; int srvsvc_SHARE_INFO_1_CONTAINER_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); struct srvsvc_SHARE_ENUM_UNION { uint32_t Level; union { struct srvsvc_SHARE_INFO_0_CONTAINER Level0; struct srvsvc_SHARE_INFO_1_CONTAINER Level1; }; }; struct srvsvc_SHARE_ENUM_STRUCT { uint32_t Level; struct srvsvc_SHARE_ENUM_UNION ShareInfo; }; struct srvsvc_NetrShareEnum_req { struct dcerpc_utf16 ServerName; struct srvsvc_SHARE_ENUM_STRUCT ses; uint32_t PreferedMaximumLength; uint32_t ResumeHandle; }; struct srvsvc_NetrShareEnum_rep { uint32_t status; struct srvsvc_SHARE_ENUM_STRUCT ses; uint32_t total_entries; uint32_t resume_handle; }; struct srvsvc_SHARE_INFO { uint32_t level; union { struct srvsvc_SHARE_INFO_1 ShareInfo1; }; }; struct srvsvc_NetrShareGetInfo_req { struct dcerpc_utf16 ServerName; struct dcerpc_utf16 NetName; uint32_t Level; }; struct srvsvc_NetrShareGetInfo_rep { uint32_t status; struct srvsvc_SHARE_INFO InfoStruct; }; struct srvsvc_rep { uint32_t status; }; /* * Async share_enum() * This function only works when connected to the IPC$ share. * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. Command_data is struct srvsvc_NetrShareEnum_rep * * This pointer must be freed using smb2_free_data(). * -errno : An error occurred. */ int smb2_share_enum_async(struct smb2_context *smb2, enum SHARE_INFO_enum level, smb2_command_cb cb, void *cb_data); int srvsvc_NetrShareEnum_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int srvsvc_NetrShareEnum_req_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int srvsvc_NetrShareGetInfo_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int srvsvc_NetrShareGetInfo_req_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); #ifdef __cplusplus } #endif #endif /* !_LIBSMB2_DCERPC_SRVSVC_H_ */ libsmb2-6.2/include/smb2/libsmb2.h0000664000175000017500000012123314732155517016012 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef _LIBSMB2_H_ #define _LIBSMB2_H_ #ifdef __cplusplus extern "C" { #endif #define LIBSMB2_SHARE_ENUM_V2 1 struct smb2_iovec { uint8_t *buf; size_t len; void (*free)(void *); }; struct smb2_context; /* * Generic callback for completion of smb2_*_async(). * command_data depends on status. */ typedef void (*smb2_command_cb)(struct smb2_context *smb2, int status, void *command_data, void *cb_data); /* * callback for getting error information when errors are set * command_data depends on status. */ typedef void (*smb2_error_cb)(struct smb2_context *smb2, const char *error_string); /* * callback for server accepting a new connection */ typedef int (*smb2_accepted_cb)(const int fd, void *cb_data); /* * callback when a new connection is made to setup context */ typedef void (*smb2_client_connection)(struct smb2_context *smb2, void *cb_data); /* * callback when a server notifies of an oplock or lease break * the type of break is determined from the stuct_size in the request * (notification) passed in. the app can set the new oplock level * or new lease state for the acknowledgement that will be sent back */ typedef void (*smb2_oplock_or_lease_break_cb)(struct smb2_context *smb2, int status, struct smb2_oplock_or_lease_break_reply *rep, uint8_t *new_oplock_level, uint32_t *new_lease_state); /* Stat structure */ #define SMB2_TYPE_FILE 0x00000000 #define SMB2_TYPE_DIRECTORY 0x00000001 #define SMB2_TYPE_LINK 0x00000002 struct smb2_stat_64 { uint32_t smb2_type; uint32_t smb2_nlink; uint64_t smb2_ino; uint64_t smb2_size; uint64_t smb2_atime; uint64_t smb2_atime_nsec; uint64_t smb2_mtime; uint64_t smb2_mtime_nsec; uint64_t smb2_ctime; uint64_t smb2_ctime_nsec; uint64_t smb2_btime; uint64_t smb2_btime_nsec; }; struct smb2_statvfs { uint32_t f_bsize; uint32_t f_frsize; uint64_t f_blocks; uint64_t f_bfree; uint64_t f_bavail; uint32_t f_files; uint32_t f_ffree; uint32_t f_favail; uint32_t f_fsid; uint32_t f_flag; uint32_t f_namemax; }; struct smb2dirent { const char *name; struct smb2_stat_64 st; }; #if defined(_WINDOWS) #ifdef __USE_WINSOCK__ #include #else #include #include #endif #elif defined(_XBOX) #include #include #endif #if defined(_WINDOWS) || defined(_XBOX) typedef SOCKET t_socket; #else typedef int t_socket; #endif /* * Create an SMB2 context. * Function returns * NULL : Failed to create a context. * *smb2 : A pointer to an smb2 context. */ struct smb2_context *smb2_init_context(void); /* * Close an SMB2 context * * closes socket if open, and clears keys but leave * context allocated. the context will be destroyed * at a time later when it won't be in-use */ void smb2_close_context(struct smb2_context *smb2); /* * Destroy an smb2 context. * * Any open "struct smb2fh" will automatically be freed. You can not reference * any "struct smb2fh" after the context is destroyed. * Any open "struct smb2dir" will automatically be freed. You can not reference * any "struct smb2dir" after the context is destroyed. * Any pending async commands will be aborted with -ECONNRESET. */ void smb2_destroy_context(struct smb2_context *smb2); /* * Get the list of currently allocated contexts */ struct smb2_context *smb2_active_contexts(void); /* * Determine of the context is currently active. This lets * code know if the context was destroyed in a callback for example */ int smb2_context_active(struct smb2_context *smb2); /* * EVENT SYSTEM INTEGRATION * ======================== * The following functions are used to integrate libsmb2 in an event * system. * * The simplest way is by using smb2_get_fd() and smb2_which_events() * in every loop of the event system to detect which fd to use (it can change) * and which events should be waited for. * This is very simple to use but has the drawback of the overhead having to * call these two functions for every loop. * * This is suitable for trivial apps where you roll your event system * using select() or poll(). * * See for example smb2-cat-async.c for an example on how to use these * two functions in an event loop. */ /* * Returns the file descriptor that libsmb2 uses. */ t_socket smb2_get_fd(struct smb2_context *smb2); /* * Returns which events that we need to poll for for the smb2 file descriptor. */ int smb2_which_events(struct smb2_context *smb2); /* * Returns file descriptors that libsmb2 use or is trying to connect to * * This function should be used when trying to connect with more than one * addresses in parallel, cf. rfc8305: Happy Eyeballs. * * The timeout, in ms, is valid during the socket connection step. The caller * should call smb2_service_fd() with fd = -1 when the timeout is reached. * This will trigger a new socket connection on the next resolved address. All * connecting fds will be closed when the first fd is connected. The timeout * will be -1 (infinite) once connected or if there is no next addresses to * connect to. */ const t_socket * smb2_get_fds(struct smb2_context *smb2, size_t *fd_count, int *timeout); /* * A much more scalable way to use smb2_fd_event_callbacks() to register * callbacks for libsmb2 to call anytime a filedescriptor is changed or when * the events we are waiting for changes. * This way libsmb2 will do callbacks back into the application to inform * when fd or events change. * * This is suitable when you want to plug libsmb2 into a more sophisticated * eventsystem or if you use epoll() or similar. * * See for smb2-ls-async.c for a trivial example of using these callbacks. */ #define SMB2_ADD_FD 0 #define SMB2_DEL_FD 1 typedef void (*smb2_change_fd_cb)(struct smb2_context *smb2, t_socket fd, int cmd); typedef void (*smb2_change_events_cb)(struct smb2_context *smb2, t_socket fd, int events); void smb2_fd_event_callbacks(struct smb2_context *smb2, smb2_change_fd_cb change_fd, smb2_change_events_cb change_events); /* * Called to process the events when events become available for the smb2 * file descriptor. * * Returns: * 0 : Success * <0 : Unrecoverable failure. At this point the context can no longer be * used and must be freed by calling smb2_destroy_context(). * */ int smb2_service(struct smb2_context *smb2, int revents); /* * Called to process the events when events become available for the smb2 * file descriptor. * * Behave like smb2_service() with some differences: * - must be called with a fd returned by smb2_get_fd() or smb2_get_fds(), * - passing -1 as fd will trigger a new connection attempt on the next * resolved address, cf. smb2_get_fds(). * * Returns: * 0 : Success * <0 : Unrecoverable failure. At this point the context can no longer be * used and must be freed by calling smb2_destroy_context(). * */ int smb2_service_fd(struct smb2_context *smb2, t_socket fd, int revents); /* * Set the timeout in seconds after which a command will be aborted with * SMB2_STATUS_IO_TIMEOUT. * If you use timeouts with the async API you must make sure to call * smb2_service() at least once every second. * * Default is 0: No timeout. */ void smb2_set_timeout(struct smb2_context *smb2, int seconds); /* * Set passthrough-enable. Passthrough allows command packers * and unpackers to keep the extra data on complex commands * in its on-the-wire format without any interpretation. this * is useful for proxy use cases where there might be no need * to fully parse things like query-info replies or ioctl * requests. If passthrough is not set, any command that * that is processed that can't interpret the data will fail * Most client use case will not need this * * Default is 0: no-passthrough */ void smb2_set_passthrough(struct smb2_context *smb2, int passthrough); /* * Get the current passthrough setting */ void smb2_get_passthrough(struct smb2_context *smb2, int *passthrough); /* * Set which version of SMB to negotiate. * Default is to let the server pick the version. */ enum smb2_negotiate_version { SMB2_VERSION_ANY = 0, SMB2_VERSION_ANY2 = 2, SMB2_VERSION_ANY3 = 3, SMB2_VERSION_0202 = 0x0202, SMB2_VERSION_0210 = 0x0210, SMB2_VERSION_0300 = 0x0300, SMB2_VERSION_0302 = 0x0302, SMB2_VERSION_0311 = 0x0311, }; #define SMB2_VERSION_WILDCARD 0x02FF void smb2_set_version(struct smb2_context *smb2, enum smb2_negotiate_version version); /* * Sets which version libsmb2 uses. */ #define LIBSMB2_MAJOR_VERSION 4 #define LIBSMB2_MINOR_VERSION 0 #define LIBSMB2_PATCH_VERSION 0 struct smb2_libversion { uint8_t major_version; uint8_t minor_version; uint8_t patch_version; }; /* * Gets the libsmb2 version being linked while used. * This function will be available on 5.x * @param struct smb2_libversion */ void smb2_get_libsmb2Version(struct smb2_libversion *smb2_ver); /* * gets the (currently) negotiated dialect */ uint16_t smb2_get_dialect(struct smb2_context *smb2); /* * Set the security mode for the connection. * This is a combination of the flags SMB2_NEGOTIATE_SIGNING_ENABLED * and SMB2_NEGOTIATE_SIGNING_REQUIRED * Default is 0. */ void smb2_set_security_mode(struct smb2_context *smb2, uint16_t security_mode); /* * Set whether smb3 encryption should be used or not. * 0 : disable encryption. This is the default. * !0 : enable encryption. */ void smb2_set_seal(struct smb2_context *smb2, int val); /* * Set whether smb2 signing should be required or not * 0 : do not require signing. This is the default. * !0 : require signing. */ void smb2_set_sign(struct smb2_context *smb2, int val); /* * Set authentication method. * SMB2_SEC_UNDEFINED (use KRB if available or NTLM if not) * SMB2_SEC_NTLMSSP * SMB2_SEC_KRB5 */ void smb2_set_authentication(struct smb2_context *smb2, int val); /* * Set the username that we will try to authenticate as. * 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 */ void smb2_set_password(struct smb2_context *smb2, const char *password); /* * Convert a win timestamp to a unix timeval */ void smb2_win_to_timeval(uint64_t smb2_time, struct smb2_timeval *tv); /* * Convert unit timeval to a win timestamp */ time_t smb2_timeval_to_win(struct smb2_timeval *tv); /* * set the context error string */ void smb2_set_error(struct smb2_context *smb2, const char *error_string, ...); /* * Register an error callback, so any calls to smb2_set_error will call this * function with the error string generated */ void smb2_register_error_callback(struct smb2_context *smb, smb2_error_cb error_cb); /* * register for oplock or lease break callbacks */ void smb2_set_oplock_or_lease_break_callback(struct smb2_context *smb2, smb2_oplock_or_lease_break_cb cb); /* * Set the smb2 context passworkd from a file (see NTLM_USER_FILE) * depends on user/domain being already set in smb2 context */ #if !defined(_XBOX) && !defined(_IOP) && !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) void smb2_set_password_from_file(struct smb2_context *smb2); #endif /* * Set the domain when authenticating. * 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 */ void smb2_set_workstation(struct smb2_context *smb2, const char *workstation); /* * Sets the address to some user defined object. May be used to make * additional context data available in the async callbacks. */ void smb2_set_opaque(struct smb2_context *smb2, void *opaque); /* * Returns the opaque pointer set with smb2_set_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. */ void smb2_set_client_guid(struct smb2_context *smb2, const uint8_t guid[SMB2_GUID_SIZE]); /* * Returns the client_guid for this context. */ const char *smb2_get_client_guid(struct smb2_context *smb2); /* * Asynchronous call to connect a TCP connection to the server * * Returns: * 0 if the call was initiated and a connection will be attempted. Result of * the connection will be reported through the callback function. * <0 if there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Connection was successful. Command_data is NULL. * * -errno : Failed to establish the connection. Command_data is NULL. */ int smb2_connect_async(struct smb2_context *smb2, const char *server, smb2_command_cb cb, void *cb_data); /* * Async call to connect to a share. * On unix, if user is NULL then default to the current user. * * Returns: * 0 if the call was initiated and a connection will be attempted. Result of * the connection will be reported through the callback function. * -errno if there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Connection was successful. Command_data is NULL. * * -errno : Failed to connect to the share. Command_data is NULL. */ int smb2_connect_share_async(struct smb2_context *smb2, const char *server, const char *share, const char *user, smb2_command_cb cb, void *cb_data); /* * Sync call to connect to a share. * On unix, if user is NULL then default to the current user. * * Returns: * 0 : Connected to the share successfully. * -errno : Failure. */ int smb2_connect_share(struct smb2_context *smb2, const char *server, const char *share, const char *user); /* * Async call to disconnect from a share/ * * Returns: * 0 if the call was initiated and a connection will be attempted. Result of * the disconnect will be reported through the callback function. * -errno if there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Connection was successful. Command_data is NULL. * * -errno : Failed to disconnect the share. Command_data is NULL. */ int smb2_disconnect_share_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); /* * Sync call to disconnect from a share/ * * Returns: * 0 : Disconnected from the share successfully. * -errno : Failure. */ int smb2_disconnect_share(struct smb2_context *smb2); /* * Select a tree id that was previously connected. Sets the tree_id * in the context to be used for subsequent requests * * Returns: * 0 : OK * -errno : tree wasn't connected */ int smb2_select_tree_id(struct smb2_context *smb2, uint32_t tree_id); struct smb2_pdu; /* * Get/Set the tree id of a pdu * * Returns: * 0 : OK * -errno : tree wasn't connected | no pdu | no context */ int smb2_get_tree_id_for_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu, uint32_t *tree_id); int smb2_set_tree_id_for_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu, uint32_t tree_id); /* * This function returns a description of the last encountered error. */ const char *smb2_get_error(struct smb2_context *smb2); int smb2_get_nterror(struct smb2_context *smb2); struct smb2_url { const char *domain; const char *user; const char *server; const char *share; const char *path; }; /* Convert an smb2/nt error code into a string */ const char *nterror_to_str(uint32_t status); /* Convert an smb2/nt error code into an errno value */ int nterror_to_errno(uint32_t status); /* * This function is used to parse an SMB2 URL into as smb2_url structure. * SMB2 URL format: * smb2://[@]// * where has the format: * [:]. * * Function will return a pointer to an iscsi smb2 structure if successful, * or it will return NULL and set smb2_get_error() accordingly if there was * a problem with the URL. * * The returned structure is freed by calling smb2_destroy_url() */ struct smb2_url *smb2_parse_url(struct smb2_context *smb2, const char *url); void smb2_destroy_url(struct smb2_url *url); /* * The functions are used when creating compound low level commands. * The general pattern for compound chains is * 1, pdu = smb2_cmd_*_async(smb2, ...) * * 2, next = smb2_cmd_*_async(smb2, ...) * 3, smb2_add_compound_pdu(smb2, pdu, next); * * 4, next = smb2_cmd_*_async(smb2, ...) * 5, smb2_add_compound_pdu(smb2, pdu, next); * ... * *, smb2_queue_pdu(smb2, pdu); * * See libsmb2.c and smb2-raw-stat-async.c for examples on how to use * this interface. */ void smb2_add_compound_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_pdu *next_pdu); void smb2_free_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu); void smb2_queue_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_pdu_is_compound(struct smb2_context *smb2); /* * OPENDIR */ struct smb2dir; /* * Async opendir() * * Returns * 0 : The operation was initiated. Result of the operation will be reported * through the callback function. * <0 : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * Command_data is struct smb2dir. * This structure is freed using smb2_closedir(). * -errno : An error occurred. * Command_data is NULL. */ int smb2_opendir_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data); /* * Sync opendir() * * Returns NULL on failure. */ struct smb2dir *smb2_opendir(struct smb2_context *smb2, const char *path); /* * closedir() */ /* * smb2_closedir() never blocks, thus no async version is needed. */ void smb2_closedir(struct smb2_context *smb2, struct smb2dir *smb2dir); /* * readdir() */ /* * smb2_readdir() never blocks, thus no async version is needed. */ struct smb2dirent *smb2_readdir(struct smb2_context *smb2, struct smb2dir *smb2dir); /* * rewinddir() */ /* * smb2_rewinddir() never blocks, thus no async version is needed. */ void smb2_rewinddir(struct smb2_context *smb2, struct smb2dir *smb2dir); /* * telldir() */ /* * smb2_telldir() never blocks, thus no async version is needed. */ long smb2_telldir(struct smb2_context *smb2, struct smb2dir *smb2dir); /* * seekdir() */ /* * smb2_seekdir() never blocks, thus no async version is needed. */ void smb2_seekdir(struct smb2_context *smb2, struct smb2dir *smb2dir, long loc); /* * OPEN */ struct smb2fh; /* * Async open() * * Opens or creates a file. * Supported flags are: * O_RDONLY * O_WRONLY * O_RDWR * O_SYNC * O_CREAT * O_EXCL * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * Command_data is struct smb2fh. * This structure is freed using smb2_close(). * -errno : An error occurred. * Command_data is NULL. */ int smb2_open_async_with_oplock_or_lease(struct smb2_context *smb2, const char *path, int flags, uint8_t oplock_level, uint32_t lease_state, smb2_lease_key lease_key, smb2_command_cb cb, void *cb_data); int smb2_open_async(struct smb2_context *smb2, const char *path, int flags, smb2_command_cb cb, void *cb_data); /* * Sync open() * * Returns NULL on failure. */ struct smb2fh *smb2_open(struct smb2_context *smb2, const char *path, int flags); /* * CLOSE */ /* * Async close() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. * * Command_data is always NULL. */ int smb2_close_async(struct smb2_context *smb2, struct smb2fh *fh, smb2_command_cb cb, void *cb_data); /* * Sync close() */ int smb2_close(struct smb2_context *smb2, struct smb2fh *fh); /* * FSYNC */ /* * Async fsync() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. * * Command_data is always NULL. */ int smb2_fsync_async(struct smb2_context *smb2, struct smb2fh *fh, smb2_command_cb cb, void *cb_data); /* * Sync fsync() */ int smb2_fsync(struct smb2_context *smb2, struct smb2fh *fh); /* * GetMaxReadWriteSize * SMB2 servers have a maximum size for read/write data that they support. */ uint32_t smb2_get_max_read_size(struct smb2_context *smb2); uint32_t smb2_get_max_write_size(struct smb2_context *smb2); struct smb2_read_cb_data { struct smb2fh *fh; uint8_t *buf; uint32_t count; uint64_t offset; }; struct smb2_write_cb_data { struct smb2fh *fh; const uint8_t *buf; uint32_t count; uint64_t offset; }; /* * PREAD */ /* * Async pread() * Use smb2_get_max_read_size to discover the maximum data size that the * server supports. * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * >=0 : Number of bytes read. * -errno : An error occurred. * * Command_data is struct smb2_read_cb_data, which holds the arguments * that were given to smb2_pread_async. * This structure is automatically freed. */ int smb2_pread_async(struct smb2_context *smb2, struct smb2fh *fh, uint8_t *buf, uint32_t count, uint64_t offset, smb2_command_cb cb, void *cb_data); /* * Sync pread() * Use smb2_get_max_read_size to discover the maximum data size that the * server supports. */ int smb2_pread(struct smb2_context *smb2, struct smb2fh *fh, uint8_t *buf, uint32_t count, uint64_t offset); /* * PWRITE */ /* * Async pwrite() * Use smb2_get_max_write_size to discover the maximum data size that the * server supports. * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * >=0 : Number of bytes written. * -errno : An error occurred. * * Command_data is struct smb2_write_cb_data, which holds the arguments * that were given to smb2_pwrite_async. * This structure is automatically freed. */ int smb2_pwrite_async(struct smb2_context *smb2, struct smb2fh *fh, const uint8_t *buf, uint32_t count, uint64_t offset, smb2_command_cb cb, void *cb_data); /* * Sync pwrite() * Use smb2_get_max_write_size to discover the maximum data size that the * server supports. */ int smb2_pwrite(struct smb2_context *smb2, struct smb2fh *fh, const uint8_t *buf, uint32_t count, uint64_t offset); /* * READ */ /* * Async read() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * >=0 : Number of bytes read. * -errno : An error occurred. * * Command_data is struct smb2_read_cb_data, which holds the arguments * that were given to smb2_read_async. offset denotes the offset in the file * at which the read took place. * This structure is automatically freed. */ int smb2_read_async(struct smb2_context *smb2, struct smb2fh *fh, uint8_t *buf, uint32_t count, smb2_command_cb cb, void *cb_data); /* * Sync read() */ int smb2_read(struct smb2_context *smb2, struct smb2fh *fh, uint8_t *buf, uint32_t count); /* * WRITE */ /* * Async write() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * >=0 : Number of bytes written. * -errno : An error occurred. * * Command_data is struct smb2_write_cb_data, which holds the arguments * that were given to smb2_write_async. offset denotes the offset in the file * at which the write took place. * This structure is automatically freed. */ int smb2_write_async(struct smb2_context *smb2, struct smb2fh *fh, const uint8_t *buf, uint32_t count, smb2_command_cb cb, void *cb_data); /* * Sync write() */ int smb2_write(struct smb2_context *smb2, struct smb2fh *fh, const uint8_t *buf, uint32_t count); /* * Sync lseek() */ /* * smb2_seek() SEEK_SET and SEEK_CUR are fully supported. * SEEK_END only returns the end-of-file from the original open. * (it will not call fstat to discover the current file size and will not block) */ int64_t smb2_lseek(struct smb2_context *smb2, struct smb2fh *fh, int64_t offset, int whence, uint64_t *current_offset); /* * UNLINK */ /* * Async unlink() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. * * Command_data is always NULL. */ int smb2_unlink_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data); /* * Sync unlink() */ int smb2_unlink(struct smb2_context *smb2, const char *path); /* * RMDIR */ /* * Async rmdir() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. * * Command_data is always NULL. */ int smb2_rmdir_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data); /* * Sync rmdir() */ int smb2_rmdir(struct smb2_context *smb2, const char *path); /* * MKDIR */ /* * Async mkdir() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. * * Command_data is always NULL. */ int smb2_mkdir_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data); /* * Sync mkdir() */ int smb2_mkdir(struct smb2_context *smb2, const char *path); /* * STATVFS */ /* * Async statvfs() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. Command_data is struct smb2_statvfs * -errno : An error occurred. */ int smb2_statvfs_async(struct smb2_context *smb2, const char *path, struct smb2_statvfs *statvfs, smb2_command_cb cb, void *cb_data); /* * Sync statvfs() */ int smb2_statvfs(struct smb2_context *smb2, const char *path, struct smb2_statvfs *statvfs); /* * FSTAT */ /* * Async fstat() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. Command_data is struct smb2_stat_64 * -errno : An error occurred. */ int smb2_fstat_async(struct smb2_context *smb2, struct smb2fh *fh, struct smb2_stat_64 *st, smb2_command_cb cb, void *cb_data); /* * Sync fstat() */ int smb2_fstat(struct smb2_context *smb2, struct smb2fh *fh, struct smb2_stat_64 *st); /* * Async stat() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. Command_data is struct smb2_stat_64 * -errno : An error occurred. */ int smb2_stat_async(struct smb2_context *smb2, const char *path, struct smb2_stat_64 *st, smb2_command_cb cb, void *cb_data); /* * Sync stat() */ int smb2_stat(struct smb2_context *smb2, const char *path, struct smb2_stat_64 *st); /* * Async rename() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. */ int smb2_rename_async(struct smb2_context *smb2, const char *oldpath, const char *newpath, smb2_command_cb cb, void *cb_data); /* * Sync rename() */ int smb2_rename(struct smb2_context *smb2, const char *oldpath, const char *newpath); /* * Async truncate() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. */ int smb2_truncate_async(struct smb2_context *smb2, const char *path, uint64_t length, smb2_command_cb cb, void *cb_data); /* * Sync truncate() * Function returns * 0 : Success * -errno : An error occurred. */ int smb2_truncate(struct smb2_context *smb2, const char *path, uint64_t length); /* * Async ftruncate() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. */ int smb2_ftruncate_async(struct smb2_context *smb2, struct smb2fh *fh, uint64_t length, smb2_command_cb cb, void *cb_data); /* * Sync ftruncate() * Function returns * 0 : Success * -errno : An error occurred. */ int smb2_ftruncate(struct smb2_context *smb2, struct smb2fh *fh, uint64_t length); /* * READLINK */ /* * Async readlink() * * Returns * 0 : The operation was initiated. The link content will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. Command_data is the link content. * -errno : An error occurred. */ int smb2_readlink_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data); /* * Sync readlink() */ int smb2_readlink(struct smb2_context *smb2, const char *path, char *buf, uint32_t bufsiz); /* * Async echo() * * Returns * 0 : The operation was initiated. Result of the operation will be * reported through the callback function. * -errno : There was an error. The callback function will not be invoked. * * When the callback is invoked, status indicates the result: * 0 : Success. * -errno : An error occurred. */ int smb2_echo_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); /* * Sync echo() * * Returns: * 0 : successfully send the message and received a reply. * -errno : Failure. */ int smb2_echo(struct smb2_context *smb2); /* Utilities that help by being public */ /* SMB's UTF-16 is always in Little Endian */ struct smb2_utf16 { int len; uint16_t val[1]; }; /* Returns a string converted to UTF-16 format. Use free() to release * the utf16 string. */ struct smb2_utf16 *smb2_utf8_to_utf16(const char *utf8); /* Returns a string converted to UTF8 format. Use free() to release * the utf8 string. */ const char *smb2_utf16_to_utf8(const uint16_t *str, size_t len); /************* Server-side API **********************************************/ struct smb2_server; /* pdu handlers in general take the request from the client, and return * < 0 on error, and the library should create an error reply * == 0 on OK, and the library should use the reply struct (if needed) to create a reply * > 0 if the handler created and queued a reply itself */ struct smb2_server_request_handlers { int (*destruction_event)(struct smb2_server *srvr, struct smb2_context *smb2); int (*authorize_user)(struct smb2_server *srvr, struct smb2_context *smb2, const char *user, const char *domain, const char *workstation); int (*session_established)(struct smb2_server *srvr, struct smb2_context *smb2); int (*logoff_cmd)(struct smb2_server *srvr, struct smb2_context *smb2); int (*tree_connect_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_tree_connect_request *req, struct smb2_tree_connect_reply *rep); int (*tree_disconnect_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, const uint32_t tree_id); int (*create_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_create_request *req, struct smb2_create_reply *rep); int (*close_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_close_request *req, struct smb2_close_reply *rep); int (*flush_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_flush_request *req); int (*read_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_read_request *req, struct smb2_read_reply *rep); int (*write_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_write_request *req, struct smb2_write_reply *rep); int (*oplock_break_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_oplock_break_acknowledgement *req); int (*lease_break_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_lease_break_acknowledgement *req); int (*lock_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_lock_request *req); int (*ioctl_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_ioctl_request *req, struct smb2_ioctl_reply *rep); int (*cancel_cmd)(struct smb2_server *srvr, struct smb2_context *smb2); int (*echo_cmd)(struct smb2_server *srvr, struct smb2_context *smb2); int (*query_directory_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_query_directory_request *req, struct smb2_query_directory_reply *rep); int (*change_notify_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_change_notify_request *req, struct smb2_change_notify_reply *rep); int (*query_info_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_query_info_request *req, struct smb2_query_info_reply *rep); int (*set_info_cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_set_info_request *req); /* int (*oplock_break cmd)(struct smb2_server *srvr, struct smb2_context *smb2, struct smb2_oplock_break_request *req); */ }; struct smb2_server { uint8_t guid[16]; char hostname[128]; char domain[128]; int fd; uint16_t port; uint64_t session_counter; struct smb2_server_request_handlers *handlers; uint32_t max_transact_size; uint32_t max_read_size; 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; }; int smb2_bind_and_listen(const uint16_t port, const int max_connections, int *out_fd); int smb2_accept_connection_async(const int fd, const int to_msecs, smb2_accepted_cb cb, void *cb_data); int smb2_serve_port_async(const int fd, const int to_msecs, struct smb2_context **out_smb2); /* * Sync serve port() * * Returns * 0 : The server is complete by exiting its loop normally (shouldnt happen) * -errno : There was an error causing server loop to exit */ int smb2_serve_port(struct smb2_server *server, const int max_connections, smb2_client_connection cb, void *cb_data); /* * Some symbols have moved over to a different header file to allow better * separation between dcerpc and smb2, so we need to include this header * here to retain compatibility for apps that depend on those symbols. */ #include #ifdef __cplusplus } #endif #endif /* !_LIBSMB2_H_ */ libsmb2-6.2/include/smb2/smb2-errors.h0000664000175000017500000010414414732155517016637 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ /* * NTSTATUS fields */ #define SMB2_STATUS_SEVERITY_MASK 0xc0000000 #define SMB2_STATUS_SEVERITY_SUCCESS 0x00000000 #define SMB2_STATUS_SEVERITY_INFO 0x40000000 #define SMB2_STATUS_SEVERITY_WARNING 0x80000000 #define SMB2_STATUS_SEVERITY_ERROR 0xc0000000 #define SMB2_STATUS_CUSTOMER_MASK 0x20000000 #define SMB2_STATUS_FACILITY_MASK 0x0fff0000 #define SMB2_STATUS_CODE_MASK 0x0000ffff /* Error codes */ #define SMB2_STATUS_SUCCESS 0x00000000 #define SMB2_STATUS_SHUTDOWN 0xffffffff #define SMB2_STATUS_PENDING 0x00000103 #define SMB2_STATUS_SMB_BAD_FID 0x00060001 #define SMB2_STATUS_NO_MORE_FILES 0x80000006 #define SMB2_STATUS_UNSUCCESSFUL 0xC0000001 #define SMB2_STATUS_NOT_IMPLEMENTED 0xC0000002 #define SMB2_STATUS_INVALID_INFO_CLASS 0xC0000003 #define SMB2_STATUS_INFO_LENGTH_MISMATCH 0xC0000004 #define SMB2_STATUS_ACCESS_VIOLATION 0xC0000005 #define SMB2_STATUS_IN_PAGE_ERROR 0xC0000006 #define SMB2_STATUS_PAGEFILE_QUOTA 0xC0000007 #define SMB2_STATUS_INVALID_HANDLE 0xC0000008 #define SMB2_STATUS_BAD_INITIAL_STACK 0xC0000009 #define SMB2_STATUS_BAD_INITIAL_PC 0xC000000A #define SMB2_STATUS_INVALID_CID 0xC000000B #define SMB2_STATUS_TIMER_NOT_CANCELED 0xC000000C #define SMB2_STATUS_INVALID_PARAMETER 0xC000000D #define SMB2_STATUS_NO_SUCH_DEVICE 0xC000000E #define SMB2_STATUS_NO_SUCH_FILE 0xC000000F #define SMB2_STATUS_INVALID_DEVICE_REQUEST 0xC0000010 #define SMB2_STATUS_END_OF_FILE 0xC0000011 #define SMB2_STATUS_WRONG_VOLUME 0xC0000012 #define SMB2_STATUS_NO_MEDIA_IN_DEVICE 0xC0000013 #define SMB2_STATUS_UNRECOGNIZED_MEDIA 0xC0000014 #define SMB2_STATUS_NONEXISTENT_SECTOR 0xC0000015 #define SMB2_STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 #define SMB2_STATUS_NO_MEMORY 0xC0000017 #define SMB2_STATUS_CONFLICTING_ADDRESSES 0xC0000018 #define SMB2_STATUS_NOT_MAPPED_VIEW 0xC0000019 #define SMB2_STATUS_UNABLE_TO_FREE_VM 0xC000001A #define SMB2_STATUS_UNABLE_TO_DELETE_SECTION 0xC000001B #define SMB2_STATUS_INVALID_SYSTEM_SERVICE 0xC000001C #define SMB2_STATUS_ILLEGAL_INSTRUCTION 0xC000001D #define SMB2_STATUS_INVALID_LOCK_SEQUENCE 0xC000001E #define SMB2_STATUS_INVALID_VIEW_SIZE 0xC000001F #define SMB2_STATUS_INVALID_FILE_FOR_SECTION 0xC0000020 #define SMB2_STATUS_ALREADY_COMMITTED 0xC0000021 #define SMB2_STATUS_ACCESS_DENIED 0xC0000022 #define SMB2_STATUS_BUFFER_TOO_SMALL 0xC0000023 #define SMB2_STATUS_OBJECT_TYPE_MISMATCH 0xC0000024 #define SMB2_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025 #define SMB2_STATUS_INVALID_DISPOSITION 0xC0000026 #define SMB2_STATUS_UNWIND 0xC0000027 #define SMB2_STATUS_BAD_STACK 0xC0000028 #define SMB2_STATUS_INVALID_UNWIND_TARGET 0xC0000029 #define SMB2_STATUS_NOT_LOCKED 0xC000002A #define SMB2_STATUS_PARITY_ERROR 0xC000002B #define SMB2_STATUS_UNABLE_TO_DECOMMIT_VM 0xC000002C #define SMB2_STATUS_NOT_COMMITTED 0xC000002D #define SMB2_STATUS_INVALID_PORT_ATTRIBUTES 0xC000002E #define SMB2_STATUS_PORT_MESSAGE_TOO_LONG 0xC000002F #define SMB2_STATUS_INVALID_PARAMETER_MIX 0xC0000030 #define SMB2_STATUS_INVALID_QUOTA_LOWER 0xC0000031 #define SMB2_STATUS_DISK_CORRUPT_ERROR 0xC0000032 #define SMB2_STATUS_OBJECT_NAME_INVALID 0xC0000033 #define SMB2_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034 #define SMB2_STATUS_OBJECT_NAME_COLLISION 0xC0000035 #define SMB2_STATUS_HANDLE_NOT_WAITABLE 0xC0000036 #define SMB2_STATUS_PORT_DISCONNECTED 0xC0000037 #define SMB2_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000038 #define SMB2_STATUS_OBJECT_PATH_INVALID 0xC0000039 #define SMB2_STATUS_OBJECT_PATH_NOT_FOUND 0xC000003A #define SMB2_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC000003B #define SMB2_STATUS_DATA_OVERRUN 0xC000003C #define SMB2_STATUS_DATA_LATE_ERROR 0xC000003D #define SMB2_STATUS_DATA_ERROR 0xC000003E #define SMB2_STATUS_CRC_ERROR 0xC000003F #define SMB2_STATUS_SECTION_TOO_BIG 0xC0000040 #define SMB2_STATUS_PORT_CONNECTION_REFUSED 0xC0000041 #define SMB2_STATUS_INVALID_PORT_HANDLE 0xC0000042 #define SMB2_STATUS_SHARING_VIOLATION 0xC0000043 #define SMB2_STATUS_QUOTA_EXCEEDED 0xC0000044 #define SMB2_STATUS_INVALID_PAGE_PROTECTION 0xC0000045 #define SMB2_STATUS_MUTANT_NOT_OWNED 0xC0000046 #define SMB2_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000047 #define SMB2_STATUS_PORT_ALREADY_SET 0xC0000048 #define SMB2_STATUS_SECTION_NOT_IMAGE 0xC0000049 #define SMB2_STATUS_SUSPEND_COUNT_EXCEEDED 0xC000004A #define SMB2_STATUS_THREAD_IS_TERMINATING 0xC000004B #define SMB2_STATUS_BAD_WORKING_SET_LIMIT 0xC000004C #define SMB2_STATUS_INCOMPATIBLE_FILE_MAP 0xC000004D #define SMB2_STATUS_SECTION_PROTECTION 0xC000004E #define SMB2_STATUS_EAS_NOT_SUPPORTED 0xC000004F #define SMB2_STATUS_EA_TOO_LARGE 0xC0000050 #define SMB2_STATUS_NONEXISTENT_EA_ENTRY 0xC0000051 #define SMB2_STATUS_NO_EAS_ON_FILE 0xC0000052 #define SMB2_STATUS_EA_CORRUPT_ERROR 0xC0000053 #define SMB2_STATUS_FILE_LOCK_CONFLICT 0xC0000054 #define SMB2_STATUS_LOCK_NOT_GRANTED 0xC0000055 #define SMB2_STATUS_DELETE_PENDING 0xC0000056 #define SMB2_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000057 #define SMB2_STATUS_UNKNOWN_REVISION 0xC0000058 #define SMB2_STATUS_REVISION_MISMATCH 0xC0000059 #define SMB2_STATUS_INVALID_OWNER 0xC000005A #define SMB2_STATUS_INVALID_PRIMARY_GROUP 0xC000005B #define SMB2_STATUS_NO_IMPERSONATION_TOKEN 0xC000005C #define SMB2_STATUS_CANT_DISABLE_MANDATORY 0xC000005D #define SMB2_STATUS_NO_LOGON_SERVERS 0xC000005E #define SMB2_STATUS_NO_SUCH_LOGON_SESSION 0xC000005F #define SMB2_STATUS_NO_SUCH_PRIVILEGE 0xC0000060 #define SMB2_STATUS_PRIVILEGE_NOT_HELD 0xC0000061 #define SMB2_STATUS_INVALID_ACCOUNT_NAME 0xC0000062 #define SMB2_STATUS_USER_EXISTS 0xC0000063 #define SMB2_STATUS_NO_SUCH_USER 0xC0000064 #define SMB2_STATUS_GROUP_EXISTS 0xC0000065 #define SMB2_STATUS_NO_SUCH_GROUP 0xC0000066 #define SMB2_STATUS_MEMBER_IN_GROUP 0xC0000067 #define SMB2_STATUS_MEMBER_NOT_IN_GROUP 0xC0000068 #define SMB2_STATUS_LAST_ADMIN 0xC0000069 #define SMB2_STATUS_WRONG_PASSWORD 0xC000006A #define SMB2_STATUS_ILL_FORMED_PASSWORD 0xC000006B #define SMB2_STATUS_PASSWORD_RESTRICTION 0xC000006C #define SMB2_STATUS_LOGON_FAILURE 0xC000006D #define SMB2_STATUS_ACCOUNT_RESTRICTION 0xC000006E #define SMB2_STATUS_INVALID_LOGON_HOURS 0xC000006F #define SMB2_STATUS_INVALID_WORKSTATION 0xC0000070 #define SMB2_STATUS_PASSWORD_EXPIRED 0xC0000071 #define SMB2_STATUS_ACCOUNT_DISABLED 0xC0000072 #define SMB2_STATUS_NONE_MAPPED 0xC0000073 #define SMB2_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000074 #define SMB2_STATUS_LUIDS_EXHAUSTED 0xC0000075 #define SMB2_STATUS_INVALID_SUB_AUTHORITY 0xC0000076 #define SMB2_STATUS_INVALID_ACL 0xC0000077 #define SMB2_STATUS_INVALID_SID 0xC0000078 #define SMB2_STATUS_INVALID_SECURITY_DESCR 0xC0000079 #define SMB2_STATUS_PROCEDURE_NOT_FOUND 0xC000007A #define SMB2_STATUS_INVALID_IMAGE_FORMAT 0xC000007B #define SMB2_STATUS_NO_TOKEN 0xC000007C #define SMB2_STATUS_BAD_INHERITANCE_ACL 0xC000007D #define SMB2_STATUS_RANGE_NOT_LOCKED 0xC000007E #define SMB2_STATUS_DISK_FULL 0xC000007F #define SMB2_STATUS_SERVER_DISABLED 0xC0000080 #define SMB2_STATUS_SERVER_NOT_DISABLED 0xC0000081 #define SMB2_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000082 #define SMB2_STATUS_GUIDS_EXHAUSTED 0xC0000083 #define SMB2_STATUS_INVALID_ID_AUTHORITY 0xC0000084 #define SMB2_STATUS_AGENTS_EXHAUSTED 0xC0000085 #define SMB2_STATUS_INVALID_VOLUME_LABEL 0xC0000086 #define SMB2_STATUS_SECTION_NOT_EXTENDED 0xC0000087 #define SMB2_STATUS_NOT_MAPPED_DATA 0xC0000088 #define SMB2_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000089 #define SMB2_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC000008A #define SMB2_STATUS_RESOURCE_NAME_NOT_FOUND 0xC000008B #define SMB2_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008C #define SMB2_STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D #define SMB2_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E #define SMB2_STATUS_FLOAT_INEXACT_RESULT 0xC000008F #define SMB2_STATUS_FLOAT_INVALID_OPERATION 0xC0000090 #define SMB2_STATUS_FLOAT_OVERFLOW 0xC0000091 #define SMB2_STATUS_FLOAT_STACK_CHECK 0xC0000092 #define SMB2_STATUS_FLOAT_UNDERFLOW 0xC0000093 #define SMB2_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094 #define SMB2_STATUS_INTEGER_OVERFLOW 0xC0000095 #define SMB2_STATUS_PRIVILEGED_INSTRUCTION 0xC0000096 #define SMB2_STATUS_TOO_MANY_PAGING_FILES 0xC0000097 #define SMB2_STATUS_FILE_INVALID 0xC0000098 #define SMB2_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000099 #define SMB2_STATUS_INSUFFICIENT_RESOURCES 0xC000009A #define SMB2_STATUS_DFS_EXIT_PATH_FOUND 0xC000009B #define SMB2_STATUS_DEVICE_DATA_ERROR 0xC000009C #define SMB2_STATUS_DEVICE_NOT_CONNECTED 0xC000009D #define SMB2_STATUS_DEVICE_POWER_FAILURE 0xC000009E #define SMB2_STATUS_FREE_VM_NOT_AT_BASE 0xC000009F #define SMB2_STATUS_MEMORY_NOT_ALLOCATED 0xC00000A0 #define SMB2_STATUS_WORKING_SET_QUOTA 0xC00000A1 #define SMB2_STATUS_MEDIA_WRITE_PROTECTED 0xC00000A2 #define SMB2_STATUS_DEVICE_NOT_READY 0xC00000A3 #define SMB2_STATUS_INVALID_GROUP_ATTRIBUTES 0xC00000A4 #define SMB2_STATUS_BAD_IMPERSONATION_LEVEL 0xC00000A5 #define SMB2_STATUS_CANT_OPEN_ANONYMOUS 0xC00000A6 #define SMB2_STATUS_BAD_VALIDATION_CLASS 0xC00000A7 #define SMB2_STATUS_BAD_TOKEN_TYPE 0xC00000A8 #define SMB2_STATUS_BAD_MASTER_BOOT_RECORD 0xC00000A9 #define SMB2_STATUS_INSTRUCTION_MISALIGNMENT 0xC00000AA #define SMB2_STATUS_INSTANCE_NOT_AVAILABLE 0xC00000AB #define SMB2_STATUS_PIPE_NOT_AVAILABLE 0xC00000AC #define SMB2_STATUS_INVALID_PIPE_STATE 0xC00000AD #define SMB2_STATUS_PIPE_BUSY 0xC00000AE #define SMB2_STATUS_ILLEGAL_FUNCTION 0xC00000AF #define SMB2_STATUS_PIPE_DISCONNECTED 0xC00000B0 #define SMB2_STATUS_PIPE_CLOSING 0xC00000B1 #define SMB2_STATUS_PIPE_CONNECTED 0xC00000B2 #define SMB2_STATUS_PIPE_LISTENING 0xC00000B3 #define SMB2_STATUS_INVALID_READ_MODE 0xC00000B4 #define SMB2_STATUS_IO_TIMEOUT 0xC00000B5 #define SMB2_STATUS_FILE_FORCED_CLOSED 0xC00000B6 #define SMB2_STATUS_PROFILING_NOT_STARTED 0xC00000B7 #define SMB2_STATUS_PROFILING_NOT_STOPPED 0xC00000B8 #define SMB2_STATUS_COULD_NOT_INTERPRET 0xC00000B9 #define SMB2_STATUS_FILE_IS_A_DIRECTORY 0xC00000BA #define SMB2_STATUS_NOT_SUPPORTED 0xC00000BB #define SMB2_STATUS_REMOTE_NOT_LISTENING 0xC00000BC #define SMB2_STATUS_DUPLICATE_NAME 0xC00000BD #define SMB2_STATUS_BAD_NETWORK_PATH 0xC00000BE #define SMB2_STATUS_NETWORK_BUSY 0xC00000BF #define SMB2_STATUS_DEVICE_DOES_NOT_EXIST 0xC00000C0 #define SMB2_STATUS_TOO_MANY_COMMANDS 0xC00000C1 #define SMB2_STATUS_ADAPTER_HARDWARE_ERROR 0xC00000C2 #define SMB2_STATUS_INVALID_NETWORK_RESPONSE 0xC00000C3 #define SMB2_STATUS_UNEXPECTED_NETWORK_ERROR 0xC00000C4 #define SMB2_STATUS_BAD_REMOTE_ADAPTER 0xC00000C5 #define SMB2_STATUS_PRINT_QUEUE_FULL 0xC00000C6 #define SMB2_STATUS_NO_SPOOL_SPACE 0xC00000C7 #define SMB2_STATUS_PRINT_CANCELLED 0xC00000C8 #define SMB2_STATUS_NETWORK_NAME_DELETED 0xC00000C9 #define SMB2_STATUS_NETWORK_ACCESS_DENIED 0xC00000CA #define SMB2_STATUS_BAD_DEVICE_TYPE 0xC00000CB #define SMB2_STATUS_BAD_NETWORK_NAME 0xC00000CC #define SMB2_STATUS_TOO_MANY_NAMES 0xC00000CD #define SMB2_STATUS_TOO_MANY_SESSIONS 0xC00000CE #define SMB2_STATUS_SHARING_PAUSED 0xC00000CF #define SMB2_STATUS_REQUEST_NOT_ACCEPTED 0xC00000D0 #define SMB2_STATUS_REDIRECTOR_PAUSED 0xC00000D1 #define SMB2_STATUS_NET_WRITE_FAULT 0xC00000D2 #define SMB2_STATUS_PROFILING_AT_LIMIT 0xC00000D3 #define SMB2_STATUS_NOT_SAME_DEVICE 0xC00000D4 #define SMB2_STATUS_FILE_RENAMED 0xC00000D5 #define SMB2_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC00000D6 #define SMB2_STATUS_NO_SECURITY_ON_OBJECT 0xC00000D7 #define SMB2_STATUS_CANT_WAIT 0xC00000D8 #define SMB2_STATUS_PIPE_EMPTY 0xC00000D9 #define SMB2_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC00000DA #define SMB2_STATUS_CANT_TERMINATE_SELF 0xC00000DB #define SMB2_STATUS_INVALID_SERVER_STATE 0xC00000DC #define SMB2_STATUS_INVALID_DOMAIN_STATE 0xC00000DD #define SMB2_STATUS_INVALID_DOMAIN_ROLE 0xC00000DE #define SMB2_STATUS_NO_SUCH_DOMAIN 0xC00000DF #define SMB2_STATUS_DOMAIN_EXISTS 0xC00000E0 #define SMB2_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC00000E1 #define SMB2_STATUS_OPLOCK_NOT_GRANTED 0xC00000E2 #define SMB2_STATUS_INVALID_OPLOCK_PROTOCOL 0xC00000E3 #define SMB2_STATUS_INTERNAL_DB_CORRUPTION 0xC00000E4 #define SMB2_STATUS_INTERNAL_ERROR 0xC00000E5 #define SMB2_STATUS_GENERIC_NOT_MAPPED 0xC00000E6 #define SMB2_STATUS_BAD_DESCRIPTOR_FORMAT 0xC00000E7 #define SMB2_STATUS_INVALID_USER_BUFFER 0xC00000E8 #define SMB2_STATUS_UNEXPECTED_IO_ERROR 0xC00000E9 #define SMB2_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC00000EA #define SMB2_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC00000EB #define SMB2_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC00000EC #define SMB2_STATUS_NOT_LOGON_PROCESS 0xC00000ED #define SMB2_STATUS_LOGON_SESSION_EXISTS 0xC00000EE #define SMB2_STATUS_INVALID_PARAMETER_1 0xC00000EF #define SMB2_STATUS_INVALID_PARAMETER_2 0xC00000F0 #define SMB2_STATUS_INVALID_PARAMETER_3 0xC00000F1 #define SMB2_STATUS_INVALID_PARAMETER_4 0xC00000F2 #define SMB2_STATUS_INVALID_PARAMETER_5 0xC00000F3 #define SMB2_STATUS_INVALID_PARAMETER_6 0xC00000F4 #define SMB2_STATUS_INVALID_PARAMETER_7 0xC00000F5 #define SMB2_STATUS_INVALID_PARAMETER_8 0xC00000F6 #define SMB2_STATUS_INVALID_PARAMETER_9 0xC00000F7 #define SMB2_STATUS_INVALID_PARAMETER_10 0xC00000F8 #define SMB2_STATUS_INVALID_PARAMETER_11 0xC00000F9 #define SMB2_STATUS_INVALID_PARAMETER_12 0xC00000FA #define SMB2_STATUS_REDIRECTOR_NOT_STARTED 0xC00000FB #define SMB2_STATUS_REDIRECTOR_STARTED 0xC00000FC #define SMB2_STATUS_STACK_OVERFLOW 0xC00000FD #define SMB2_STATUS_NO_SUCH_PACKAGE 0xC00000FE #define SMB2_STATUS_BAD_FUNCTION_TABLE 0xC00000FF #define SMB2_STATUS_DIRECTORY_NOT_EMPTY 0xC0000101 #define SMB2_STATUS_FILE_CORRUPT_ERROR 0xC0000102 #define SMB2_STATUS_NOT_A_DIRECTORY 0xC0000103 #define SMB2_STATUS_BAD_LOGON_SESSION_STATE 0xC0000104 #define SMB2_STATUS_LOGON_SESSION_COLLISION 0xC0000105 #define SMB2_STATUS_NAME_TOO_LONG 0xC0000106 #define SMB2_STATUS_FILES_OPEN 0xC0000107 #define SMB2_STATUS_CONNECTION_IN_USE 0xC0000108 #define SMB2_STATUS_MESSAGE_NOT_FOUND 0xC0000109 #define SMB2_STATUS_PROCESS_IS_TERMINATING 0xC000010A #define SMB2_STATUS_INVALID_LOGON_TYPE 0xC000010B #define SMB2_STATUS_NO_GUID_TRANSLATION 0xC000010C #define SMB2_STATUS_CANNOT_IMPERSONATE 0xC000010D #define SMB2_STATUS_IMAGE_ALREADY_LOADED 0xC000010E #define SMB2_STATUS_ABIOS_NOT_PRESENT 0xC000010F #define SMB2_STATUS_ABIOS_LID_NOT_EXIST 0xC0000110 #define SMB2_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000111 #define SMB2_STATUS_ABIOS_NOT_LID_OWNER 0xC0000112 #define SMB2_STATUS_ABIOS_INVALID_COMMAND 0xC0000113 #define SMB2_STATUS_ABIOS_INVALID_LID 0xC0000114 #define SMB2_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000115 #define SMB2_STATUS_ABIOS_INVALID_SELECTOR 0xC0000116 #define SMB2_STATUS_NO_LDT 0xC0000117 #define SMB2_STATUS_INVALID_LDT_SIZE 0xC0000118 #define SMB2_STATUS_INVALID_LDT_OFFSET 0xC0000119 #define SMB2_STATUS_INVALID_LDT_DESCRIPTOR 0xC000011A #define SMB2_STATUS_INVALID_IMAGE_NE_FORMAT 0xC000011B #define SMB2_STATUS_RXACT_INVALID_STATE 0xC000011C #define SMB2_STATUS_RXACT_COMMIT_FAILURE 0xC000011D #define SMB2_STATUS_MAPPED_FILE_SIZE_ZERO 0xC000011E #define SMB2_STATUS_TOO_MANY_OPENED_FILES 0xC000011F #define SMB2_STATUS_CANCELLED 0xC0000120 #define SMB2_STATUS_CANNOT_DELETE 0xC0000121 #define SMB2_STATUS_INVALID_COMPUTER_NAME 0xC0000122 #define SMB2_STATUS_FILE_DELETED 0xC0000123 #define SMB2_STATUS_SPECIAL_ACCOUNT 0xC0000124 #define SMB2_STATUS_SPECIAL_GROUP 0xC0000125 #define SMB2_STATUS_SPECIAL_USER 0xC0000126 #define SMB2_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000127 #define SMB2_STATUS_FILE_CLOSED 0xC0000128 #define SMB2_STATUS_TOO_MANY_THREADS 0xC0000129 #define SMB2_STATUS_THREAD_NOT_IN_PROCESS 0xC000012A #define SMB2_STATUS_TOKEN_ALREADY_IN_USE 0xC000012B #define SMB2_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC000012C #define SMB2_STATUS_COMMITMENT_LIMIT 0xC000012D #define SMB2_STATUS_INVALID_IMAGE_LE_FORMAT 0xC000012E #define SMB2_STATUS_INVALID_IMAGE_NOT_MZ 0xC000012F #define SMB2_STATUS_INVALID_IMAGE_PROTECT 0xC0000130 #define SMB2_STATUS_INVALID_IMAGE_WIN_16 0xC0000131 #define SMB2_STATUS_LOGON_SERVER_CONFLICT 0xC0000132 #define SMB2_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000133 #define SMB2_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000134 #define SMB2_STATUS_DLL_NOT_FOUND 0xC0000135 #define SMB2_STATUS_OPEN_FAILED 0xC0000136 #define SMB2_STATUS_IO_PRIVILEGE_FAILED 0xC0000137 #define SMB2_STATUS_ORDINAL_NOT_FOUND 0xC0000138 #define SMB2_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000139 #define SMB2_STATUS_CONTROL_C_EXIT 0xC000013A #define SMB2_STATUS_LOCAL_DISCONNECT 0xC000013B #define SMB2_STATUS_REMOTE_DISCONNECT 0xC000013C #define SMB2_STATUS_REMOTE_RESOURCES 0xC000013D #define SMB2_STATUS_LINK_FAILED 0xC000013E #define SMB2_STATUS_LINK_TIMEOUT 0xC000013F #define SMB2_STATUS_INVALID_CONNECTION 0xC0000140 #define SMB2_STATUS_INVALID_ADDRESS 0xC0000141 #define SMB2_STATUS_DLL_INIT_FAILED 0xC0000142 #define SMB2_STATUS_MISSING_SYSTEMFILE 0xC0000143 #define SMB2_STATUS_UNHANDLED_EXCEPTION 0xC0000144 #define SMB2_STATUS_APP_INIT_FAILURE 0xC0000145 #define SMB2_STATUS_PAGEFILE_CREATE_FAILED 0xC0000146 #define SMB2_STATUS_NO_PAGEFILE 0xC0000147 #define SMB2_STATUS_INVALID_LEVEL 0xC0000148 #define SMB2_STATUS_WRONG_PASSWORD_CORE 0xC0000149 #define SMB2_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC000014A #define SMB2_STATUS_PIPE_BROKEN 0xC000014B #define SMB2_STATUS_REGISTRY_CORRUPT 0xC000014C #define SMB2_STATUS_REGISTRY_IO_FAILED 0xC000014D #define SMB2_STATUS_NO_EVENT_PAIR 0xC000014E #define SMB2_STATUS_UNRECOGNIZED_VOLUME 0xC000014F #define SMB2_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000150 #define SMB2_STATUS_NO_SUCH_ALIAS 0xC0000151 #define SMB2_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000152 #define SMB2_STATUS_MEMBER_IN_ALIAS 0xC0000153 #define SMB2_STATUS_ALIAS_EXISTS 0xC0000154 #define SMB2_STATUS_LOGON_NOT_GRANTED 0xC0000155 #define SMB2_STATUS_TOO_MANY_SECRETS 0xC0000156 #define SMB2_STATUS_SECRET_TOO_LONG 0xC0000157 #define SMB2_STATUS_INTERNAL_DB_ERROR 0xC0000158 #define SMB2_STATUS_FULLSCREEN_MODE 0xC0000159 #define SMB2_STATUS_TOO_MANY_CONTEXT_IDS 0xC000015A #define SMB2_STATUS_LOGON_TYPE_NOT_GRANTED 0xC000015B #define SMB2_STATUS_NOT_REGISTRY_FILE 0xC000015C #define SMB2_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC000015D #define SMB2_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC000015E #define SMB2_STATUS_FT_MISSING_MEMBER 0xC000015F #define SMB2_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000160 #define SMB2_STATUS_ILLEGAL_CHARACTER 0xC0000161 #define SMB2_STATUS_UNMAPPABLE_CHARACTER 0xC0000162 #define SMB2_STATUS_UNDEFINED_CHARACTER 0xC0000163 #define SMB2_STATUS_FLOPPY_VOLUME 0xC0000164 #define SMB2_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000165 #define SMB2_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000166 #define SMB2_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000167 #define SMB2_STATUS_FLOPPY_BAD_REGISTERS 0xC0000168 #define SMB2_STATUS_DISK_RECALIBRATE_FAILED 0xC0000169 #define SMB2_STATUS_DISK_OPERATION_FAILED 0xC000016A #define SMB2_STATUS_DISK_RESET_FAILED 0xC000016B #define SMB2_STATUS_SHARED_IRQ_BUSY 0xC000016C #define SMB2_STATUS_FT_ORPHANING 0xC000016D #define SMB2_STATUS_PARTITION_FAILURE 0xC0000172 #define SMB2_STATUS_INVALID_BLOCK_LENGTH 0xC0000173 #define SMB2_STATUS_DEVICE_NOT_PARTITIONED 0xC0000174 #define SMB2_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000175 #define SMB2_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000176 #define SMB2_STATUS_EOM_OVERFLOW 0xC0000177 #define SMB2_STATUS_NO_MEDIA 0xC0000178 #define SMB2_STATUS_NO_SUCH_MEMBER 0xC000017A #define SMB2_STATUS_INVALID_MEMBER 0xC000017B #define SMB2_STATUS_KEY_DELETED 0xC000017C #define SMB2_STATUS_NO_LOG_SPACE 0xC000017D #define SMB2_STATUS_TOO_MANY_SIDS 0xC000017E #define SMB2_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC000017F #define SMB2_STATUS_KEY_HAS_CHILDREN 0xC0000180 #define SMB2_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000181 #define SMB2_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000182 #define SMB2_STATUS_DRIVER_INTERNAL_ERROR 0xC0000183 #define SMB2_STATUS_INVALID_DEVICE_STATE 0xC0000184 #define SMB2_STATUS_IO_DEVICE_ERROR 0xC0000185 #define SMB2_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000186 #define SMB2_STATUS_BACKUP_CONTROLLER 0xC0000187 #define SMB2_STATUS_LOG_FILE_FULL 0xC0000188 #define SMB2_STATUS_TOO_LATE 0xC0000189 #define SMB2_STATUS_NO_TRUST_LSA_SECRET 0xC000018A #define SMB2_STATUS_NO_TRUST_SAM_ACCOUNT 0xC000018B #define SMB2_STATUS_TRUSTED_DOMAIN_FAILURE 0xC000018C #define SMB2_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC000018D #define SMB2_STATUS_EVENTLOG_FILE_CORRUPT 0xC000018E #define SMB2_STATUS_EVENTLOG_CANT_START 0xC000018F #define SMB2_STATUS_TRUST_FAILURE 0xC0000190 #define SMB2_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000191 #define SMB2_STATUS_NETLOGON_NOT_STARTED 0xC0000192 #define SMB2_STATUS_ACCOUNT_EXPIRED 0xC0000193 #define SMB2_STATUS_POSSIBLE_DEADLOCK 0xC0000194 #define SMB2_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000195 #define SMB2_STATUS_REMOTE_SESSION_LIMIT 0xC0000196 #define SMB2_STATUS_EVENTLOG_FILE_CHANGED 0xC0000197 #define SMB2_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000198 #define SMB2_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000199 #define SMB2_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC000019A #define SMB2_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC000019B #define SMB2_STATUS_FS_DRIVER_REQUIRED 0xC000019C #define SMB2_STATUS_NO_USER_SESSION_KEY 0xC0000202 #define SMB2_STATUS_USER_SESSION_DELETED 0xC0000203 #define SMB2_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000204 #define SMB2_STATUS_INSUFF_SERVER_RESOURCES 0xC0000205 #define SMB2_STATUS_INVALID_BUFFER_SIZE 0xC0000206 #define SMB2_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000207 #define SMB2_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000208 #define SMB2_STATUS_TOO_MANY_ADDRESSES 0xC0000209 #define SMB2_STATUS_ADDRESS_ALREADY_EXISTS 0xC000020A #define SMB2_STATUS_ADDRESS_CLOSED 0xC000020B #define SMB2_STATUS_CONNECTION_DISCONNECTED 0xC000020C #define SMB2_STATUS_CONNECTION_RESET 0xC000020D #define SMB2_STATUS_TOO_MANY_NODES 0xC000020E #define SMB2_STATUS_TRANSACTION_ABORTED 0xC000020F #define SMB2_STATUS_TRANSACTION_TIMED_OUT 0xC0000210 #define SMB2_STATUS_TRANSACTION_NO_RELEASE 0xC0000211 #define SMB2_STATUS_TRANSACTION_NO_MATCH 0xC0000212 #define SMB2_STATUS_TRANSACTION_RESPONDED 0xC0000213 #define SMB2_STATUS_TRANSACTION_INVALID_ID 0xC0000214 #define SMB2_STATUS_TRANSACTION_INVALID_TYPE 0xC0000215 #define SMB2_STATUS_NOT_SERVER_SESSION 0xC0000216 #define SMB2_STATUS_NOT_CLIENT_SESSION 0xC0000217 #define SMB2_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000218 #define SMB2_STATUS_DEBUG_ATTACH_FAILED 0xC0000219 #define SMB2_STATUS_SYSTEM_PROCESS_TERMINATED 0xC000021A #define SMB2_STATUS_DATA_NOT_ACCEPTED 0xC000021B #define SMB2_STATUS_NO_BROWSER_SERVERS_FOUND 0xC000021C #define SMB2_STATUS_VDM_HARD_ERROR 0xC000021D #define SMB2_STATUS_DRIVER_CANCEL_TIMEOUT 0xC000021E #define SMB2_STATUS_REPLY_MESSAGE_MISMATCH 0xC000021F #define SMB2_STATUS_MAPPED_ALIGNMENT 0xC0000220 #define SMB2_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000221 #define SMB2_STATUS_LOST_WRITEBEHIND_DATA 0xC0000222 #define SMB2_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000223 #define SMB2_STATUS_PASSWORD_MUST_CHANGE 0xC0000224 #define SMB2_STATUS_NOT_FOUND 0xC0000225 #define SMB2_STATUS_NOT_TINY_STREAM 0xC0000226 #define SMB2_STATUS_RECOVERY_FAILURE 0xC0000227 #define SMB2_STATUS_STACK_OVERFLOW_READ 0xC0000228 #define SMB2_STATUS_FAIL_CHECK 0xC0000229 #define SMB2_STATUS_DUPLICATE_OBJECTID 0xC000022A #define SMB2_STATUS_OBJECTID_EXISTS 0xC000022B #define SMB2_STATUS_CONVERT_TO_LARGE 0xC000022C #define SMB2_STATUS_RETRY 0xC000022D #define SMB2_STATUS_FOUND_OUT_OF_SCOPE 0xC000022E #define SMB2_STATUS_ALLOCATE_BUCKET 0xC000022F #define SMB2_STATUS_PROPSET_NOT_FOUND 0xC0000230 #define SMB2_STATUS_MARSHALL_OVERFLOW 0xC0000231 #define SMB2_STATUS_INVALID_VARIANT 0xC0000232 #define SMB2_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000233 #define SMB2_STATUS_ACCOUNT_LOCKED_OUT 0xC0000234 #define SMB2_STATUS_HANDLE_NOT_CLOSABLE 0xC0000235 #define SMB2_STATUS_CONNECTION_REFUSED 0xC0000236 #define SMB2_STATUS_GRACEFUL_DISCONNECT 0xC0000237 #define SMB2_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000238 #define SMB2_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000239 #define SMB2_STATUS_CONNECTION_INVALID 0xC000023A #define SMB2_STATUS_CONNECTION_ACTIVE 0xC000023B #define SMB2_STATUS_NETWORK_UNREACHABLE 0xC000023C #define SMB2_STATUS_HOST_UNREACHABLE 0xC000023D #define SMB2_STATUS_PROTOCOL_UNREACHABLE 0xC000023E #define SMB2_STATUS_PORT_UNREACHABLE 0xC000023F #define SMB2_STATUS_REQUEST_ABORTED 0xC0000240 #define SMB2_STATUS_CONNECTION_ABORTED 0xC0000241 #define SMB2_STATUS_BAD_COMPRESSION_BUFFER 0xC0000242 #define SMB2_STATUS_USER_MAPPED_FILE 0xC0000243 #define SMB2_STATUS_AUDIT_FAILED 0xC0000244 #define SMB2_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000245 #define SMB2_STATUS_CONNECTION_COUNT_LIMIT 0xC0000246 #define SMB2_STATUS_LOGIN_TIME_RESTRICTION 0xC0000247 #define SMB2_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000248 #define SMB2_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000249 #define SMB2_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000250 #define SMB2_STATUS_BAD_DLL_ENTRYPOINT 0xC0000251 #define SMB2_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000252 #define SMB2_STATUS_LPC_REPLY_LOST 0xC0000253 #define SMB2_STATUS_IP_ADDRESS_CONFLICT1 0xC0000254 #define SMB2_STATUS_IP_ADDRESS_CONFLICT2 0xC0000255 #define SMB2_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000256 #define SMB2_STATUS_PATH_NOT_COVERED 0xC0000257 #define SMB2_STATUS_NO_CALLBACK_ACTIVE 0xC0000258 #define SMB2_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000259 #define SMB2_STATUS_PWD_TOO_SHORT 0xC000025A #define SMB2_STATUS_PWD_TOO_RECENT 0xC000025B #define SMB2_STATUS_PWD_HISTORY_CONFLICT 0xC000025C #define SMB2_STATUS_PLUGPLAY_NO_DEVICE 0xC000025E #define SMB2_STATUS_UNSUPPORTED_COMPRESSION 0xC000025F #define SMB2_STATUS_INVALID_HW_PROFILE 0xC0000260 #define SMB2_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000261 #define SMB2_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000262 #define SMB2_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000263 #define SMB2_STATUS_RESOURCE_NOT_OWNED 0xC0000264 #define SMB2_STATUS_TOO_MANY_LINKS 0xC0000265 #define SMB2_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000266 #define SMB2_STATUS_FILE_IS_OFFLINE 0xC0000267 #define SMB2_STATUS_VOLUME_DISMOUNTED 0xC000026E #define SMB2_STATUS_NOT_A_REPARSE_POINT 0xC0000275 #define SMB2_STATUS_SERVER_UNAVAILABLE 0xC0000466 /* Warning codes */ #define SMB2_STATUS_STOPPED_ON_SYMLINK 0x8000002d libsmb2-6.2/include/smb2/libsmb2-dcerpc.h0000664000175000017500000001365114732155517017254 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef _LIBSMB2_DCERPC_H_ #define _LIBSMB2_DCERPC_H_ #ifdef __cplusplus extern "C" { #endif /* Data representation */ /* Integer */ #define DCERPC_DR_BIG_ENDIAN 0x00 #define DCERPC_DR_LITTLE_ENDIAN 0x10 /* Character */ #define DCERPC_DR_ASCII 0x00 #define DCERPC_DR_EBCDIC 0x01 struct dcerpc_context; struct dcerpc_pdu; /* Encoder/Decoder for a DCERPC object */ typedef int (*dcerpc_coder)(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); enum ptr_type { PTR_REF = 0, PTR_UNIQUE = 1, PTR_FULL = 2 }; typedef struct dcerpc_uuid { uint32_t v1; uint16_t v2; uint16_t v3; uint8_t v4[8]; } dcerpc_uuid_t; typedef struct p_syntax_id { dcerpc_uuid_t uuid; uint16_t vers; uint16_t vers_minor; } p_syntax_id_t; struct ndr_transfer_syntax { dcerpc_uuid_t uuid; uint16_t vers; }; struct ndr_context_handle { uint32_t context_handle_attributes; dcerpc_uuid_t context_handle_uuid; }; struct dcerpc_utf16 { uint32_t max_count; /* internal use only */ uint32_t offset; /* internal use only */ uint32_t actual_count; /* internal use only */ struct smb2_utf16 *utf16; /* internal use only */ const char *utf8; }; struct dcerpc_carray { uint32_t max_count; uint8_t *data; }; extern p_syntax_id_t lsa_interface; extern p_syntax_id_t srvsvc_interface; typedef void (*dcerpc_cb)(struct dcerpc_context *dce, int status, void *command_data, void *cb_data); struct dcerpc_context *dcerpc_create_context(struct smb2_context *smb2); void dcerpc_free_data(struct dcerpc_context *dce, void *data); const char *dcerpc_get_error(struct dcerpc_context *dce); int dcerpc_connect_context_async(struct dcerpc_context *dce, const char *path, p_syntax_id_t *syntax, dcerpc_cb cb, void *cb_data); void dcerpc_destroy_context(struct dcerpc_context *dce); struct smb2_context *dcerpc_get_smb2_context(struct dcerpc_context *dce); void *dcerpc_get_pdu_payload(struct dcerpc_pdu *pdu); int dcerpc_open_async(struct dcerpc_context *dce, dcerpc_cb cb, void *cb_data); int dcerpc_call_async(struct dcerpc_context *dce, int opnum, dcerpc_coder req_coder, void *req, dcerpc_coder rep_coder, int rep_size, dcerpc_cb cb, void *cb_data); int dcerpc_do_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, dcerpc_coder coder); int dcerpc_ptr_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, enum ptr_type type, dcerpc_coder coder); int dcerpc_carray_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, int elem_size, dcerpc_coder coder); int dcerpc_uint8_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int dcerpc_uint16_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int dcerpc_uint32_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int dcerpc_uint3264_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int dcerpc_conformance_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int dcerpc_utf16_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int dcerpc_utf16z_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int dcerpc_context_handle_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); int dcerpc_uuid_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, dcerpc_uuid_t *uuid); int dcerpc_uint8_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr); #define DCERPC_DECODE 0 #define DCERPC_ENCODE 1 struct dcerpc_pdu *dcerpc_allocate_pdu(struct dcerpc_context *dce, int direction, int payload_size); void dcerpc_free_pdu(struct dcerpc_context *dce, struct dcerpc_pdu *pdu); #ifdef __cplusplus } #endif #endif /* !_LIBSMB2_DCERPC_H_ */ libsmb2-6.2/include/smb2/libsmb2-raw.h0000664000175000017500000004536314732155517016612 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef _LIBSMB2_RAW_H_ #define _LIBSMB2_RAW_H_ #ifdef __cplusplus extern "C" { #endif /* * Low level RAW SMB2 interface */ /* * Magic file Id used for compound commands. */ extern const smb2_file_id compound_file_id; /* * This function is used to free the data returned by the query functions. */ void smb2_free_data(struct smb2_context *smb2, void *ptr); /* * Asynchronous SMB2 Negotiate * pdu : If the call was initiated and a connection will be attempted. * Result of the negotiate will be reported through the callback * function. * NULL : If there was an error. The callback function will not be invoked. * * Returns: * * Callback parameters : * status can be either of : * 0 : Negotiate was successful. * Command_data is a struct smb2_negotiate_reply. * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_negotiate_async(struct smb2_context *smb2, struct smb2_negotiate_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_negotiate_reply_async(struct smb2_context *smb2, struct smb2_negotiate_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Session Setup * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the session setup will be reported through the callback * function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Session setup was successful. * Command_data is a struct smb2_session_setup_reply. * * !0 : Status is NT status code. */ struct smb2_pdu *smb2_cmd_session_setup_async(struct smb2_context *smb2, struct smb2_session_setup_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_session_setup_reply_async(struct smb2_context *smb2, struct smb2_session_setup_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Tree Connect * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the tree connect will be reported through the callback * function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Tree Connect was successful. * Command_data is a struct smb2_tree_connect_reply. * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_tree_connect_async(struct smb2_context *smb2, struct smb2_tree_connect_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_tree_connect_reply_async(struct smb2_context *smb2, struct smb2_tree_connect_reply *rep, uint32_t tree_id, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Tree Disconnect * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the tree connect will be reported through the callback * function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Tree Disconnect was successful. * * !0 : Status is NT status code. * * Command_data is always NULL. */ struct smb2_pdu *smb2_cmd_tree_disconnect_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_tree_disconnect_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Create * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the create will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Create was successful. * Command_data is a struct smb2_create_reply. * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_create_async(struct smb2_context *smb2, struct smb2_create_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_create_reply_async(struct smb2_context *smb2, struct smb2_create_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Close * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the close will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Close was successful. * Command_data is a struct smb2_close_reply. * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_close_async(struct smb2_context *smb2, struct smb2_close_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_close_reply_async(struct smb2_context *smb2, struct smb2_close_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Read * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the read will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Read was successful. * * !0 : Status is NT status code. * * command_data is always NULL. */ struct smb2_pdu *smb2_cmd_read_async(struct smb2_context *smb2, struct smb2_read_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_read_reply_async(struct smb2_context *smb2, struct smb2_read_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Write * * use pass_buf_ownerhip non-0 to allow the request's buf to be * freed along with the pdu when it is freed, use 0 to retain * req->buf * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the write will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Write was successful. * * !0 : Status is NT status code. * * command_data is always NULL. */ struct smb2_pdu *smb2_cmd_write_async(struct smb2_context *smb2, struct smb2_write_request *req, int pass_buf_ownership, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_write_reply_async(struct smb2_context *smb2, struct smb2_write_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Query Directory * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the QD will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Query was successful. * Command_data is a struct smb2_query_directory_reply. * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_query_directory_async(struct smb2_context *smb2, struct smb2_query_directory_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_query_directory_reply_async(struct smb2_context *smb2, struct smb2_query_directory_request *req, struct smb2_query_directory_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Change Notify * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the close will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Close was successful. * Command_data is a struct smb2_close_reply. * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_change_notify_async(struct smb2_context *smb2, struct smb2_change_notify_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_change_notify_reply_async(struct smb2_context *smb2, struct smb2_change_notify_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Query Info * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the QI will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Query was successful. * Command_data is a struct struct smb2_query_info_reply * * This structure contains a pointer to the requested data * structure in ->output_buffer. * Output_buffer must be freed by calling smb2_free_data() * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_query_info_async(struct smb2_context *smb2, struct smb2_query_info_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_query_info_reply_async(struct smb2_context *smb2, struct smb2_query_info_request *req, struct smb2_query_info_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Set Info * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the QI will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Query was successful. * Command_data is a struct struct smb2_query_info_reply * * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_set_info_async(struct smb2_context *smb2, struct smb2_set_info_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_set_info_reply_async(struct smb2_context *smb2, struct smb2_set_info_request *req, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Ioctl * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the Ioctl will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Query was successful. * Command_data is a struct struct smb2_ioctl_reply * * This structure contains a pointer to the requested data * structure in ->output. * Output must be freed by calling smb2_free_data() * * !0 : Status is NT status code. Command_data is NULL. */ struct smb2_pdu *smb2_cmd_ioctl_async(struct smb2_context *smb2, struct smb2_ioctl_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_ioctl_reply_async(struct smb2_context *smb2, struct smb2_ioctl_reply *rep, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Echo * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the echo will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Echo was successful. * * !0 : Status is NT status code. * * command_data is always NULL. */ struct smb2_pdu *smb2_cmd_echo_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_echo_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Lock * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the logoff will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Lock was successful. * * !0 : Status is NT status code. * * command_data is always NULL. */ struct smb2_pdu *smb2_cmd_lock_async(struct smb2_context *smb2, struct smb2_lock_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_lock_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Logoff * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the logoff will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Logoff was successful. * * !0 : Status is NT status code. * * command_data is always NULL. */ struct smb2_pdu *smb2_cmd_logoff_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_logoff_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 Flush * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the flush will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : Flush was successful. * * !0 : Status is NT status code. * * command_data is always NULL. */ struct smb2_pdu *smb2_cmd_flush_async(struct smb2_context *smb2, struct smb2_flush_request *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_flush_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data); /* * Asynchronous SMB2 oplock-break; * * Returns: * pdu : If the call was initiated and a connection will be attempted. * Result of the flush will be reported through the callback function. * NULL : If there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * 0 : successful. * * !0 : Status is NT status code. * * command_data is always NULL. */ struct smb2_pdu *smb2_cmd_oplock_break_async(struct smb2_context *smb2, struct smb2_oplock_break_acknowledgement *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_oplock_break_reply_async(struct smb2_context *smb2, struct smb2_oplock_break_reply *rep, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_oplock_break_notification_async(struct smb2_context *smb2, struct smb2_oplock_break_notification *rep, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_lease_break_async(struct smb2_context *smb2, struct smb2_lease_break_acknowledgement *req, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_lease_break_reply_async(struct smb2_context *smb2, struct smb2_lease_break_reply *rep, smb2_command_cb cb, void *cb_data); struct smb2_pdu *smb2_cmd_lease_break_notification_async(struct smb2_context *smb2, struct smb2_lease_break_notification *req, smb2_command_cb cb, void *cb_data); /* * */ struct smb2_pdu *smb2_cmd_error_reply_async(struct smb2_context *smb2, struct smb2_error_reply *rep, uint8_t causing_command, int status, smb2_command_cb cb, void *cb_data); #ifdef __cplusplus } #endif #endif /* !_LIBSMB2_RAW_H_ */ libsmb2-6.2/include/slist.h0000664000175000017500000000350314732155517014752 0ustar polpypolpy/* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef __smb2_slist_h__ #define __smb2_slist_h__ #define SMB2_LIST_ADD(list, item) \ do { \ (item)->next = (*list); \ (*list) = (item); \ } while (0); #define SMB2_LIST_ADD_END(list, item) \ if ((*list) == NULL) { \ SMB2_LIST_ADD((list), (item)); \ } else { \ void *head = (*list); \ while ((*list)->next) \ (*list) = (*list)->next; \ (*list)->next = (item); \ (item)->next = NULL; \ (*list) = head; \ } #define SMB2_LIST_REMOVE(list, item) \ if ((*list) == (item)) { \ (*list) = (item)->next; \ } else { \ void *head = (*list); \ while ((*list)->next && (*list)->next != (item)) \ (*list) = (*list)->next; \ if ((*list)->next != NULL) { \ (*list)->next = (*list)->next->next; \ } \ (*list) = head; \ } #define SMB2_LIST_LENGTH(list, length) \ do { \ (length) = 0; \ void *head = (*list); \ while ((*list)) { \ (*list) = (*list)->next; \ (length)++; \ } \ (*list) = head; \ } while (0); #endif /* __smb2_slist_h__ */ libsmb2-6.2/include/esp/0000775000175000017500000000000014732155517014231 5ustar polpypolpylibsmb2-6.2/include/esp/config.h0000664000175000017500000001001114732155517015640 0ustar polpypolpy/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether or not TCP sockets should be allowed to linger after closure */ #define CONFIGURE_OPTION_TCP_LINGER 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Whether we use gssapi_krb5 or not */ /* #undef HAVE_LIBKRB5 */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Whether we have linger */ #define HAVE_LINGER 1 /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_TCP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Whether sockaddr struct has sa_len */ /* #undef HAVE_SOCKADDR_LEN */ /* Whether we have sockaddr_Storage */ #define HAVE_SOCKADDR_STORAGE 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_ERRNO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FCNTL_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_POLL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TIME_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UIO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UNISTD_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS__IOVEC_H */ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libsmb2" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "ronniesahlberg@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsmb2" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsmb2 4.0.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsmb2" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.0.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.0" libsmb2-6.2/include/asprintf.h0000664000175000017500000000260214732155517015441 0ustar polpypolpy #ifndef _ASPRINTF_H_ #define _ASPRINTF_H_ #if !defined(__AROS__) && !defined(__ps2sdk_iop__) #include #endif #include #include #include #ifdef _XBOX #define inline __inline #endif #ifndef _XBOX #ifndef _vscprintf /* For some reason, MSVC fails to honour this #ifndef. */ /* Hence function renamed to _vscprintf_so(). */ static inline int _vscprintf_so(const char * format, va_list pargs) { int retval; va_list argcopy; va_copy(argcopy, pargs); retval = vsnprintf(NULL, 0, format, argcopy); va_end(argcopy); return retval; } #endif /* _vscprintf */ #endif #ifndef vasprintf static inline int vasprintf(char **strp, const char *fmt, va_list ap) { #ifdef _XBOX int len = _vscprintf(fmt, ap); #else int len = _vscprintf_so(fmt, ap); #endif char *str; int r; if (len == -1) return -1; str = malloc((size_t)len + 1); if (!str) return -1; #ifdef _XBOX r = _vsnprintf(str, len + 1, fmt, ap); /* "secure" version of vsprintf */ #else r = vsnprintf(str, len + 1, fmt, ap); /* "secure" version of vsprintf */ #endif if (r == -1) return free(str), -1; *strp = str; return r; } #endif /* vasprintf */ #ifndef asprintf static inline int asprintf(char *strp[], const char *fmt, ...) { int r; va_list ap; va_start(ap, fmt); r = vasprintf(strp, fmt, ap); va_end(ap); return r; } #endif /* asprintf */ #endif /* ! _ASPRINTF_H_ */ libsmb2-6.2/include/module.modulemap0000664000175000017500000000072614732155517016641 0ustar polpypolpymodule SMB2 [system] [extern_c] { module LibSMB2 { header "apple/config.h" header "smb2/smb2-errors.h" header "smb2/smb2.h" header "smb2/libsmb2.h" header "smb2/libsmb2-dcerpc.h" header "smb2/libsmb2-dcerpc-lsa.h" header "smb2/libsmb2-dcerpc-srvsvc.h" } module Internal { header "libsmb2-private.h" } explicit module Raw { header "smb2/libsmb2-raw.h" } export SMB2 } libsmb2-6.2/include/ps3/0000775000175000017500000000000014732155517014147 5ustar polpypolpylibsmb2-6.2/include/ps3/config.h0000664000175000017500000001005214732155517015563 0ustar polpypolpy/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether or not TCP sockets should be allowed to linger after closure */ #define CONFIGURE_OPTION_TCP_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ARPA_INET_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_DLFCN_H */ /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_INTTYPES_H */ /* Whether we use gssapi_krb5 or not */ /* #undef HAVE_LIBKRB5 */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Whether we have linger */ #define HAVE_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETDB_H */ /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_TCP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Whether sockaddr struct has sa_len */ /* #undef HAVE_SOCKADDR_LEN */ /* Whether we have sockaddr_Storage */ /* #undef HAVE_SOCKADDR_STORAGE */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_STRINGS_H */ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_ERRNO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FCNTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_IOCTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKET_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_STAT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TIME_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UIO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UNISTD_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS__IOVEC_H */ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libsmb2" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "ronniesahlberg@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsmb2" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsmb2 4.0.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsmb2" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.0.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.0" libsmb2-6.2/include/picow/0000775000175000017500000000000014732155517014563 5ustar polpypolpylibsmb2-6.2/include/picow/config.h0000664000175000017500000001005514732155517016202 0ustar polpypolpy/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether or not TCP sockets should be allowed to linger after closure */ #define CONFIGURE_OPTION_TCP_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ARPA_INET_H */ /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ERRNO_H */ /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_INTTYPES_H */ /* Whether we use gssapi_krb5 or not */ /* #undef HAVE_LIBKRB5 */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Whether we have linger */ /* #undef HAVE_LINGER */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETDB_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IN_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_TCP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Whether sockaddr struct has sa_len */ /* #undef HAVE_SOCKADDR_LEN */ /* Whether we have sockaddr_Storage */ #define HAVE_SOCKADDR_STORAGE 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_STRINGS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_STRING_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_ERRNO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FCNTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_IOCTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKET_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TIME_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UIO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UNISTD_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS__IOVEC_H */ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libsmb2" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "ronniesahlberg@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsmb2" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsmb2 4.0.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsmb2" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.0.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.0" libsmb2-6.2/include/picow/lwipopts_examples_common.h0000664000175000017500000000653114732155517022070 0ustar polpypolpy#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H #define _LWIPOPTS_EXAMPLE_COMMONH_H // Common settings used in most of the pico_w examples // (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) // allow override in some examples #ifndef NO_SYS #define NO_SYS 1 #endif // allow override in some examples #ifndef LWIP_SOCKET #define LWIP_SOCKET 1 #endif #if PICO_CYW43_ARCH_POLL #define MEM_LIBC_MALLOC 1 #else // MEM_LIBC_MALLOC is incompatible with non polling versions #define MEM_LIBC_MALLOC 0 #endif #define MEM_ALIGNMENT 4 #define MEM_SIZE 4000 #define MEMP_NUM_TCP_SEG 32 #define MEMP_NUM_ARP_QUEUE 10 #define PBUF_POOL_SIZE 24 #define LWIP_ARP 1 #define LWIP_ETHERNET 1 #define LWIP_ICMP 1 #define LWIP_RAW 1 #define TCP_WND (8 * TCP_MSS) #define TCP_MSS 1460 #define TCP_SND_BUF (8 * TCP_MSS) #define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) #define LWIP_NETIF_STATUS_CALLBACK 1 #define LWIP_NETIF_LINK_CALLBACK 1 #define LWIP_NETIF_HOSTNAME 1 #define LWIP_NETCONN 0 #define MEM_STATS 0 #define SYS_STATS 0 #define MEMP_STATS 0 #define LINK_STATS 0 // #define ETH_PAD_SIZE 2 #define LWIP_CHKSUM_ALGORITHM 3 #define LWIP_DHCP 1 #define LWIP_IPV4 1 #define LWIP_TCP 1 #define LWIP_UDP 1 #define LWIP_DNS 1 #define LWIP_TCP_KEEPALIVE 1 #define LWIP_NETIF_TX_SINGLE_PBUF 1 #define DHCP_DOES_ARP_CHECK 0 #define LWIP_DHCP_DOES_ACD_CHECK 0 #ifndef NDEBUG #define LWIP_DEBUG 1 #define LWIP_STATS 1 #define LWIP_STATS_DISPLAY 1 #endif #define ETHARP_DEBUG LWIP_DBG_OFF #define NETIF_DEBUG LWIP_DBG_OFF #define PBUF_DEBUG LWIP_DBG_OFF #define API_LIB_DEBUG LWIP_DBG_OFF #define API_MSG_DEBUG LWIP_DBG_OFF #define SOCKETS_DEBUG LWIP_DBG_OFF #define ICMP_DEBUG LWIP_DBG_OFF #define INET_DEBUG LWIP_DBG_OFF #define IP_DEBUG LWIP_DBG_OFF #define IP_REASS_DEBUG LWIP_DBG_OFF #define RAW_DEBUG LWIP_DBG_OFF #define MEM_DEBUG LWIP_DBG_OFF #define MEMP_DEBUG LWIP_DBG_OFF #define SYS_DEBUG LWIP_DBG_OFF #define TCP_DEBUG LWIP_DBG_OFF #define TCP_INPUT_DEBUG LWIP_DBG_OFF #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF #define TCP_RTO_DEBUG LWIP_DBG_OFF #define TCP_CWND_DEBUG LWIP_DBG_OFF #define TCP_WND_DEBUG LWIP_DBG_OFF #define TCP_FR_DEBUG LWIP_DBG_OFF #define TCP_QLEN_DEBUG LWIP_DBG_OFF #define TCP_RST_DEBUG LWIP_DBG_OFF #define UDP_DEBUG LWIP_DBG_OFF #define TCPIP_DEBUG LWIP_DBG_OFF #define PPP_DEBUG LWIP_DBG_OFF #define SLIP_DEBUG LWIP_DBG_OFF #define DHCP_DEBUG LWIP_DBG_OFF #endif /* __LWIPOPTS_H__ */ libsmb2-6.2/include/picow/lwipopts.h0000664000175000017500000000136714732155517016624 0ustar polpypolpy#ifndef _LWIPOPTS_H #define _LWIPOPTS_H // Generally you would define your own explicit list of lwIP options // (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html) // // This example uses a common include to avoid repetition #include "lwipopts_examples_common.h" #define LWIP_SO_RCVBUF 1 #define LWIP_TIMEVAL_PRIVATE 0 #if !NO_SYS #define TCPIP_THREAD_STACKSIZE 1024 #define DEFAULT_THREAD_STACKSIZE 1024 #define DEFAULT_RAW_RECVMBOX_SIZE 8 #define TCPIP_MBOX_SIZE 8 //#define LWIP_TIMEVAL_PRIVATE 0 #define DEFAULT_UDP_RECVMBOX_SIZE TCPIP_MBOX_SIZE #define DEFAULT_TCP_RECVMBOX_SIZE TCPIP_MBOX_SIZE #define DEFAULT_ACCEPTMBOX_SIZE TCPIP_MBOX_SIZE // not necessary, can be done either way #define LWIP_TCPIP_CORE_LOCKING_INPUT 1 #endif #endif libsmb2-6.2/include/picow/FreeRTOSConfig.h0000664000175000017500000001351214732155517017455 0ustar polpypolpy/* * FreeRTOS V202111.00 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * http://www.FreeRTOS.org * http://aws.amazon.com/freertos * * 1 tab == 4 spaces! */ #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H /*----------------------------------------------------------- * Application specific definitions. * * These definitions should be adjusted for your particular hardware and * application requirements. * * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. * * See http://www.freertos.org/a00110.html *----------------------------------------------------------*/ /* Scheduler Related */ #define configUSE_PREEMPTION 1 #define configUSE_TICKLESS_IDLE 0 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMAX_PRIORITIES 32 #define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 2048 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 /* Synchronization Related */ #define configUSE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_APPLICATION_TASK_TAG 0 #define configUSE_COUNTING_SEMAPHORES 1 #define configQUEUE_REGISTRY_SIZE 8 #define configUSE_QUEUE_SETS 1 #define configUSE_TIME_SLICING 1 #define configUSE_NEWLIB_REENTRANT 0 // todo need this for lwip FreeRTOS sys_arch to compile #define configENABLE_BACKWARD_COMPATIBILITY 1 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 /* System */ #define configSTACK_DEPTH_TYPE uint32_t #define configMESSAGE_BUFFER_LENGTH_TYPE size_t /* Memory allocation related definitions. */ #define configSUPPORT_STATIC_ALLOCATION 0 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configTOTAL_HEAP_SIZE (128*1024) #define configAPPLICATION_ALLOCATED_HEAP 0 /* Hook function related definitions. */ #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 /* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 0 #define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 0 /* Co-routine related definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES 1 /* Software timer related definitions. */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH 1024 /* Interrupt nesting behaviour configuration. */ /* #define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] #define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application] #define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application] */ #if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS /* SMP port only */ #define configNUM_CORES 2 #define configTICK_CORE 0 #define configRUN_MULTIPLE_PRIORITIES 1 #define configUSE_CORE_AFFINITY 1 #endif /* RP2040 specific */ #define configSUPPORT_PICO_SYNC_INTEROP 1 #define configSUPPORT_PICO_TIME_INTEROP 1 #include /* Define to trap errors during development. */ #define configASSERT(x) assert(x) /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_uxTaskGetStackHighWaterMark 1 #define INCLUDE_xTaskGetIdleTaskHandle 1 #define INCLUDE_eTaskGetState 1 #define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTaskAbortDelay 1 #define INCLUDE_xTaskGetHandle 1 #define INCLUDE_xTaskResumeFromISR 1 #define INCLUDE_xQueueGetMutexHolder 1 /* A header file that defines trace macro can be included here. */ #endif /* FREERTOS_CONFIG_H */ libsmb2-6.2/include/picow/README.md0000664000175000017500000000044014732155517016040 0ustar polpypolpy# Pico W config files These files should be seen as samples and you can start with these or use your own. They are here so that the examples/picow sample will compile and build. These have not been tuned in any way, other than to let libsmb2 compile with the Pico W, FreeRTOS and lwip. libsmb2-6.2/include/portable-endian.h0000664000175000017500000002177314732155517016671 0ustar polpypolpy// "License": Public Domain // I, Mathias Panzenbck, place this file hereby into the public domain. Use it at your own risk for whatever you like. // In case there are jurisdictions that don't support putting things in the public domain you can also consider it to // be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it // an example on how to get the endian conversion functions on different platforms. #ifndef PORTABLE_ENDIAN_H__ #define PORTABLE_ENDIAN_H__ #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) && !defined(_XBOX) #define __WINDOWS__ #endif #if defined(__PS2__) || defined(PICO_PLATFORM) #ifndef _LITTLE_ENDIAN #define _LITTLE_ENDIAN LITTLE_ENDIAN #endif #if defined(_EE) || defined(PICO_PLATFORM) #include #ifdef PICO_PLATFORM #include "lwip/def.h" #endif #endif #define be16toh(x) PP_NTOHS(x) #define htobe16(x) PP_HTONS(x) #define htole16(x) (x) #define le16toh(x) (x) #define be32toh(x) PP_NTOHL(x) #define htobe32(x) PP_HTONL(x) #define htole32(x) (x) #define le32toh(x) (x) #define htobe64(x) be64toh(x) #define htole64(x) (x) #define le64toh(x) (x) #elif defined(__DREAMCAST__) #include #define be16toh(x) __builtin_bswap16(x) #define htobe16(x) __builtin_bswap16(x) #define htole16(x) (x) #define le16toh(x) (x) #define be32toh(x) __builtin_bswap32(x) #define htobe32(x) __builtin_bswap32(x) #define htole32(x) (x) #define le32toh(x) (x) #define be64toh(x) __builtin_bswap64(x) #define htobe64(x) __builtin_bswap64(x) #define htole64(x) (x) #define le64toh(x) (x) #elif defined(__linux__) || defined(__CYGWIN__) || defined(ESP_PLATFORM) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) #if defined(__linux__) || defined(__CYGWIN__) || defined(PS4_PLATFORM) || defined(ESP_PLATFORM) #include /* Include byteswap.h on linux since it might not be automatically included in some cases (e.g. alpine / musl) */ #if defined(__linux__) #include #endif #else #include #endif /* These 4 #defines may be needed with older esp-idf environments */ #ifndef _LITTLE_ENDIAN #define _LITTLE_ENDIAN LITTLE_ENDIAN #endif #ifndef __bswap16 #define __bswap16 __bswap_16 #endif #ifndef __bswap32 #define __bswap32 __bswap_32 #endif #ifndef __bswap64 #define __bswap64 __bswap_64 #endif #ifndef be16toh #define be16toh(x) betoh16(x) #endif #ifndef le16toh #define le16toh(x) letoh16(x) #endif #ifndef be32toh #define be32toh(x) betoh32(x) #endif #ifndef le32toh #define le32toh(x) letoh32(x) #endif #ifndef be64toh #define be64toh(x) betoh64(x) #endif #ifndef le64toh #define le64toh(x) letoh64(x) #endif #elif defined(__APPLE__) #include #define htobe16(x) OSSwapHostToBigInt16(x) #define htole16(x) OSSwapHostToLittleInt16(x) #define be16toh(x) OSSwapBigToHostInt16(x) #define le16toh(x) OSSwapLittleToHostInt16(x) #define htobe32(x) OSSwapHostToBigInt32(x) #define htole32(x) OSSwapHostToLittleInt32(x) #define be32toh(x) OSSwapBigToHostInt32(x) #define le32toh(x) OSSwapLittleToHostInt32(x) #define htobe64(x) OSSwapHostToBigInt64(x) #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) #define __BYTE_ORDER BYTE_ORDER #define __BIG_ENDIAN BIG_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN #define __PDP_ENDIAN PDP_ENDIAN #elif defined(PS3_PPU_PLATFORM) #define htobe16(x) (x) #define htole16(x) __builtin_bswap16(x) #define be16toh(x) (x) #define le16toh(x) __builtin_bswap16(x) #define htobe32(x) (x) #define htole32(x) __builtin_bswap32(x) #define be32toh(x) (x) #define le32toh(x) __builtin_bswap32(x) #define htobe64(x) (x) #define htole64(x) __builtin_bswap64(x) #define be64toh(x) (x) #define le64toh(x) __builtin_bswap64(x) #elif defined(__SWITCH__) || defined(__N3DS__) || defined(__WII__) || defined(__GC__) || defined(__WIIU__) || defined(__NDS__) #include #define htobe16(x) __bswap16(x) #define htole16(x) (x) #define be16toh(x) __bswap16(x) #define le16toh(x) (x) #define htobe32(x) __bswap32(x) #define htole32(x) (x) #define be32toh(x) __bswap32(x) #define le32toh(x) (x) #define htobe64(x) __bswap64(x) #define htole64(x) (x) #define be64toh(x) __bswap64(x) #define le64toh(x) (x) #elif defined(__WINDOWS__) || defined(_XBOX) #ifdef _XBOX #include #else #include #endif #if defined(_MSC_VER) #include #define htobe16(x) _byteswap_ushort(x) #define htole16(x) (x) #define be16toh(x) _byteswap_ushort(x) #define le16toh(x) (x) #define htobe32(x) _byteswap_ulong(x) #define htole32(x) (x) #define be32toh(x) _byteswap_ulong(x) #define le32toh(x) (x) #define htobe64(x) _byteswap_uint64(x) #define htole64(x) (x) #define be64toh(x) _byteswap_uint64(x) #define le64toh(x) (x) #ifndef __BYTE_ORDER #define __BYTE_ORDER BYTE_ORDER #endif #ifndef __BIG_ENDIAN #define __BIG_ENDIAN BIG_ENDIAN #endif #ifndef __LITTLE_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN #endif #ifndef __PDP_ENDIAN #define __PDP_ENDIAN PDP_ENDIAN #endif #elif defined(__GNUC__) || defined(__clang__) #define htobe16(x) __builtin_bswap16(x) #define htole16(x) (x) #define be16toh(x) __builtin_bswap16(x) #define le16toh(x) (x) #define htobe32(x) __builtin_bswap32(x) #define htole32(x) (x) #define be32toh(x) __builtin_bswap32(x) #define le32toh(x) (x) #define htobe64(x) __builtin_bswap64(x) #define htole64(x) (x) #define be64toh(x) __builtin_bswap64(x) #define le64toh(x) (x) #else #error platform not supported #endif #elif defined(__amigaos4__) || defined(__AMIGA__) #if defined(__NEWLIB__) #include #ifndef __bswap16 #define __bswap16(x) __builtin_bswap16(x) #endif #ifndef __bswap32 #define __bswap32(x) __builtin_bswap32(x) #endif #ifndef __bswap64 #define __bswap64(x) __builtin_bswap64(x) #endif #define htobe16(x) (x) #define htole16(x) __bswap16(x) #define be16toh(x) (x) #define le16toh(x) __bswap16(x) #define htobe32(x) (x) #define htole32(x) __bswap32(x) #define be32toh(x) (x) #define le32toh(x) __bswap32(x) #define htobe64(x) (x) #define htole64(x) __bswap64(x) #define be64toh(x) (x) #define le64toh(x) __bswap64(x) #elif defined(__GNUC__) #define htobe16(x) (x) #define htole16(x) __builtin_bswap16(x) #define be16toh(x) (x) #define le16toh(x) __builtin_bswap16(x) #define htobe32(x) (x) #define htole32(x) __builtin_bswap32(x) #define be32toh(x) (x) #define le32toh(x) __builtin_bswap32(x) #define htobe64(x) (x) #define htole64(x) __builtin_bswap64(x) #define be64toh(x) (x) #define le64toh(x) __builtin_bswap64(x) #else #error platform not supported #endif #elif defined(__AROS__) #include #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 8)) #define __bswap16(x) __builtin_bswap16(x) #define __bswap32(x) __builtin_bswap32(x) #define __bswap64(x) __builtin_bswap64(x) #else #define __bswap16(x) ((((uint16_t)(x) & 0xFF00) >> 8) | \ (((uint16_t)(x) & 0x00FF) << 8)) #define __bswap32(x) ((((uint32_t)(x) & 0xFF000000) >> 24) | \ (((uint32_t)(x) & 0x00FF0000) >> 8) | \ (((uint32_t)(x) & 0x0000FF00) << 8) | \ (((uint32_t)(x) & 0x000000FF) << 24)) #define __bswap64(x) ((((uint64_t)(x) & 0xFF00000000000000) >> 56) | \ (((uint64_t)(x) & 0x00FF000000000000) >> 40) | \ (((uint64_t)(x) & 0x0000FF0000000000) >> 24) | \ (((uint64_t)(x) & 0x000000FF00000000) >> 8) | \ (((uint64_t)(x) & 0x00000000FF000000) << 8) | \ (((uint64_t)(x) & 0x0000000000FF0000) << 24) | \ (((uint64_t)(x) & 0x000000000000FF00) << 40) | \ (((uint64_t)(x) & 0x00000000000000FF) << 56)) #endif #if _BYTE_ORDER == _LITTLE_ENDIAN #define htobe16(x) __bswap16(x) #define htole16(x) (x) #define be16toh(x) __bswap16(x) #define le16toh(x) (x) #define htobe32(x) __bswap32(x) #define htole32(x) (x) #define be32toh(x) __bswap32(x) #define le32toh(x) (x) #define htobe64(x) __bswap64(x) #define htole64(x) (x) #define be64toh(x) __bswap64(x) #define le64toh(x) (x) #else #define htobe16(x) (x) #define htole16(x) __bswap16(x) #define be16toh(x) (x) #define le16toh(x) __bswap16(x) #define htobe32(x) (x) #define htole32(x) __bswap32(x) #define be32toh(x) (x) #define le32toh(x) __bswap32(x) #define htobe64(x) (x) #define htole64(x) __bswap64(x) #define be64toh(x) (x) #define le64toh(x) __bswap64(x) #endif #elif defined(__GNUC__) || defined(__clang__) #ifdef __vita__ #include #endif #define htobe16(x) __builtin_bswap16(x) #define htole16(x) (x) #define be16toh(x) __builtin_bswap16(x) #define le16toh(x) (x) #define htobe32(x) __builtin_bswap32(x) #define htole32(x) (x) #define be32toh(x) __builtin_bswap32(x) #define le32toh(x) (x) #define htobe64(x) __builtin_bswap64(x) #define htole64(x) (x) #define be64toh(x) __builtin_bswap64(x) #define le64toh(x) (x) #else #error platform not supported #endif #endif libsmb2-6.2/include/libsmb2-private.h0000664000175000017500000006252014732155517016622 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef _LIBSMB2_PRIVATE_H_ #define _LIBSMB2_PRIVATE_H_ #ifdef __cplusplus extern "C" { #endif #ifdef HAVE_LIBKRB5 #if __APPLE__ #import #else #include #endif /* __APPLE__ */ #endif /* HAVE_LIBKRB5 */ #define MIN(a,b) (((a)<(b))?(a):(b)) #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) #endif #define MAX_ERROR_SIZE 256 #define PAD_TO_32BIT(len) ((len + 0x03) & 0xfffffffc) #define PAD_TO_64BIT(len) ((len + 0x07) & 0xfffffff8) #define SMB2_SPL_SIZE 4 #define SMB2_HEADER_SIZE 64 #define SMB2_SIGNATURE_SIZE 16 #define SMB2_KEY_SIZE 16 #define SMB2_MAX_VECTORS 256 struct smb2_io_vectors { size_t num_done; size_t total_size; int niov; struct smb2_iovec iov[SMB2_MAX_VECTORS]; }; struct smb2_async { uint64_t async_id; }; struct smb2_sync { uint32_t process_id; uint32_t tree_id; }; struct smb2_header { uint8_t protocol_id[4]; uint16_t struct_size; uint16_t credit_charge; uint32_t status; uint16_t command; uint16_t credit_request_response; uint32_t flags; uint32_t next_command; uint64_t message_id; union { struct smb2_async async; struct smb2_sync sync; }; uint64_t session_id; uint8_t signature[16]; }; /* States that we transition when we read data back from the server for * normal SMB2/3 : * 1: SMB2_RECV_SPL SPL * 2: SMB2_RECV_HEADER SMB2 Header * 3: SMB2_RECV_FIXED The fixed part of the payload. * 4: SMB2_RECV_VARIABLE Optional variable part of the payload. * 5: SMB2_RECV_PAD Optional padding * * 2-5 will be repeated for compound commands. * 4-5 are optional and may or may not be present depending on the * type of command. * * States for SMB3 encryption: * 1: SMB2_RECV_SPL SPL * 2: SMB2_RECV_HEADER SMB3 Transform Header * 3: SMB2_RECV_TRFM encrypted payload */ enum smb2_recv_state { SMB2_RECV_SPL = 0, SMB2_RECV_HEADER, SMB2_RECV_FIXED, SMB2_RECV_VARIABLE, SMB2_RECV_PAD, SMB2_RECV_TRFM, }; enum smb2_sec { SMB2_SEC_UNDEFINED = 0, SMB2_SEC_NTLMSSP, SMB2_SEC_KRB5, }; /* current tree id stack, note: index 0 in the stack is not used */ #define SMB2_MAX_TREE_NESTING 32 #define smb2_tree_id(smb2) (((smb2)->tree_id_cur >= 0)?smb2->tree_id[(smb2)->tree_id_cur]:0xdeadbeef) #define MAX_CREDITS 1024 #define SMB2_SALT_SIZE 32 struct sync_cb_data { int is_finished; int status; void *ptr; }; struct smb2_context { t_socket fd; struct smb2_server *owning_server; t_socket *connecting_fds; size_t connecting_fds_count; struct addrinfo *addrinfos; const struct addrinfo *next_addrinfo; int timeout; enum smb2_sec sec; uint16_t security_mode; uint32_t capabilities; int use_cached_creds; enum smb2_negotiate_version version; const char *server; const char *share; const char *user; /* Only used with --without-libkrb5 */ const char *password; const char *domain; const char *workstation; char client_challenge[8]; void *opaque; smb2_error_cb error_cb; smb2_command_cb connect_cb; void *connect_data; struct sync_cb_data connect_cb_data; int credits; char client_guid[16]; uint32_t tree_id[SMB2_MAX_TREE_NESTING]; int tree_id_top; int tree_id_cur; uint64_t message_id; uint64_t session_id; uint8_t *session_key; uint8_t session_key_size; uint8_t seal:1; uint8_t sign:1; uint8_t signing_key[SMB2_KEY_SIZE]; uint8_t serverin_key[SMB2_KEY_SIZE]; uint8_t serverout_key[SMB2_KEY_SIZE]; uint8_t salt[SMB2_SALT_SIZE]; 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 */ unsigned char *enc; size_t enc_len; int enc_pos; /* * For sending PDUs */ struct smb2_pdu *outqueue; struct smb2_pdu *waitqueue; /* * For receiving PDUs */ struct smb2_io_vectors in; enum smb2_recv_state recv_state; /* SPL for the (compound) command we are currently reading */ uint32_t spl; /* buffer to avoid having to malloc the header */ uint8_t header[SMB2_HEADER_SIZE]; struct smb2_header hdr; /* Offset into smb2->in where the payload for the current PDU starts */ size_t payload_offset; /* Pointer to the current PDU that we are receiving the reply for. * Only valid once the full smb2 header has been received. */ struct smb2_pdu *pdu; /* pointer to the pdu to read AFTER the current one is completed * (if this context is a server) */ struct smb2_pdu *next_pdu; /* flag indicated command packers/unpackers can pass "extra" * content without trying to decode or encode it. this is * useful for proxies and applies only to the commands with * complex data: query-info, query-directory, ioctl, and * create (contexts). the command fixed part is always * de/en-coded regardless of this setting */ int passthrough; /* for oplock/lease breaks, inform the app */ smb2_oplock_or_lease_break_cb oplock_or_lease_break_cb; /* oplock state, needed to discriminate between notification or response */ int oplock_break_count; /* last file_id in a create-reply, for "related requests" */ smb2_file_id last_file_id; /* Server capabilities */ uint8_t supports_multi_credit; uint32_t max_transact_size; uint32_t max_read_size; uint32_t max_write_size; uint16_t dialect; char error_string[MAX_ERROR_SIZE]; int nterror; /* Open filehandles */ struct smb2fh *fhs; /* Open dirhandles */ struct smb2dir *dirs; /* callbacks for the eventsystem */ int events; smb2_change_fd_cb change_fd; smb2_change_events_cb change_events; /* dcerpc settings */ uint8_t ndr; int endianness; /* to maintain lists of contexts for server used */ struct smb2_context *next; }; /* * Callback for freeing a payload. */ typedef void (*smb2_free_payload)(struct smb2_context *smb2, void *payload); #define SMB2_MAX_PDU_SIZE 16*1024*1024 struct smb2_pdu { struct smb2_pdu *next; struct smb2_header header; struct smb2_pdu *next_compound; smb2_command_cb cb; void *cb_data; /* buffer to avoid having to malloc the headers */ uint8_t hdr[SMB2_HEADER_SIZE]; /* 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. */ smb2_free_payload free_payload; /* For sending/receiving * out contains at least two vectors: * [0] 64 bytes for the smb header * [1+] command and and extra parameters * * in contains at least one vector: * [0+] command and and extra parameters */ struct smb2_io_vectors out; struct smb2_io_vectors in; /* Data we need to retain between request/reply for QUERY INFO */ uint8_t info_type; uint8_t file_info_class; /* For encrypted PDUs */ uint8_t seal:1; uint32_t crypt_len; unsigned char *crypt; time_t timeout; }; struct smb2_dirent_internal { struct smb2_dirent_internal *next; struct smb2dirent dirent; }; struct smb2dir { struct smb2dir *next; smb2_command_cb cb; void (*free_cb_data)(void *); void *cb_data; smb2_file_id file_id; struct smb2_dirent_internal *entries; struct smb2_dirent_internal *current_entry; int index; }; #define smb2_is_server(ctx) ((ctx)->owning_server != NULL) void smb2_set_nterror(struct smb2_context *smb2, int nterror, const char *error_string, ...); void smb2_close_connecting_fds(struct smb2_context *smb2); void *smb2_alloc_init(struct smb2_context *smb2, size_t size); void *smb2_alloc_data(struct smb2_context *smb2, void *memctx, size_t size); struct smb2_iovec *smb2_add_iovector(struct smb2_context *smb2, struct smb2_io_vectors *v, uint8_t *buf, size_t len, void (*free)(void *)); int smb2_pad_to_64bit(struct smb2_context *smb2, struct smb2_io_vectors *v); int smb2_connect_tree_id(struct smb2_context *smb2, uint32_t tree_id); int smb2_disconnect_tree_id(struct smb2_context *smb2, uint32_t tree_id); struct smb2_pdu *smb2_allocate_pdu(struct smb2_context *smb2, enum smb2_command command, smb2_command_cb cb, void *cb_data); int smb2_process_payload_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_payload_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_get_fixed_size(struct smb2_context *smb2, struct smb2_pdu *pdu); struct smb2_pdu *smb2_find_pdu(struct smb2_context *smb2, uint64_t message_id); void smb2_free_iovector(struct smb2_context *smb2, struct smb2_io_vectors *v); void smb2_oplock_break_notify(struct smb2_context *smb2, int status, void *command_data, void *cb_data); int smb2_decode_header(struct smb2_context *smb2, struct smb2_iovec *iov, struct smb2_header *hdr); int smb2_calc_signature(struct smb2_context *smb2, uint8_t *signature, struct smb2_iovec *iov, size_t niov); int smb2_set_uint8(struct smb2_iovec *iov, int offset, uint8_t value); int smb2_set_uint16(struct smb2_iovec *iov, int offset, uint16_t value); int smb2_set_uint32(struct smb2_iovec *iov, int offset, uint32_t value); int smb2_set_uint64(struct smb2_iovec *iov, int offset, uint64_t value); int smb2_get_uint8(struct smb2_iovec *iov, int offset, uint8_t *value); int smb2_get_uint16(struct smb2_iovec *iov, int offset, uint16_t *value); int smb2_get_uint32(struct smb2_iovec *iov, int offset, uint32_t *value); int smb2_get_uint64(struct smb2_iovec *iov, int offset, uint64_t *value); int smb2_process_error_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_error_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_negotiate_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_negotiate_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_negotiate_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_negotiate_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_session_setup_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_session_setup_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_session_setup_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_session_setup_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_tree_connect_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_tree_connect_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_tree_connect_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_create_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_create_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_create_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_create_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_query_directory_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_query_directory_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_query_directory_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_query_directory_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_change_notify_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_change_notify_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_change_notify_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_query_info_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_query_info_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_query_info_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_query_info_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_close_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_close_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_set_info_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_set_info_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_set_info_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_tree_disconnect_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_tree_disconnect_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_logoff_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_logoff_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_lock_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_lock_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_lock_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_oplock_break_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_oplock_break_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_oplock_break_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_oplock_break_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_echo_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_echo_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_flush_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_flush_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_read_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_read_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_read_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_read_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_write_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_write_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_write_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_ioctl_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_ioctl_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_ioctl_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_process_ioctl_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_decode_file_basic_info(struct smb2_context *smb2, void *memctx, struct smb2_file_basic_info *fs, struct smb2_iovec *vec); int smb2_encode_file_basic_info(struct smb2_context *smb2, struct smb2_file_basic_info *fs, struct smb2_iovec *vec); int smb2_decode_file_standard_info(struct smb2_context *smb2, void *memctx, struct smb2_file_standard_info *fs, struct smb2_iovec *vec); int smb2_encode_file_standard_info(struct smb2_context *smb2, struct smb2_file_standard_info *fs, struct smb2_iovec *vec); int smb2_decode_file_position_info(struct smb2_context *smb2, void *memctx, struct smb2_file_position_info *fs, struct smb2_iovec *vec); int smb2_encode_file_position_info(struct smb2_context *smb2, struct smb2_file_position_info *fs, struct smb2_iovec *vec); int smb2_decode_file_all_info(struct smb2_context *smb2, void *memctx, struct smb2_file_all_info *fs, struct smb2_iovec *vec); int smb2_encode_file_all_info(struct smb2_context *smb2, struct smb2_file_all_info *fs, struct smb2_iovec *vec); int smb2_decode_file_network_open_info(struct smb2_context *smb2, void *memctx, struct smb2_file_network_open_info *fs, struct smb2_iovec *vec); int smb2_encode_file_network_open_info(struct smb2_context *smb2, struct smb2_file_network_open_info *fs, struct smb2_iovec *vec); int smb2_decode_security_descriptor(struct smb2_context *smb2, void *memctx, struct smb2_security_descriptor *sd, struct smb2_iovec *vec); int smb2_decode_file_fs_volume_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_volume_info *fs, struct smb2_iovec *vec); int smb2_encode_file_fs_volume_info(struct smb2_context *smb2, struct smb2_file_fs_volume_info *fs, struct smb2_iovec *vec); int smb2_decode_file_fs_size_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_size_info *fs, struct smb2_iovec *vec); int smb2_encode_file_fs_size_info(struct smb2_context *smb2, struct smb2_file_fs_size_info *fs, struct smb2_iovec *vec); int smb2_decode_file_fs_device_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_device_info *fs, struct smb2_iovec *vec); int smb2_encode_file_fs_device_info(struct smb2_context *smb2, struct smb2_file_fs_device_info *fs, struct smb2_iovec *vec); int smb2_decode_file_fs_attribute_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_attribute_info *fs, struct smb2_iovec *vec); int smb2_encode_file_fs_attribute_info(struct smb2_context *smb2, struct smb2_file_fs_attribute_info *fs, struct smb2_iovec *vec); int smb2_decode_file_fs_control_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_control_info *fs, struct smb2_iovec *vec); int smb2_encode_file_fs_control_info(struct smb2_context *smb2, struct smb2_file_fs_control_info *fs, struct smb2_iovec *vec); int smb2_decode_file_fs_full_size_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_full_size_info *fs, struct smb2_iovec *vec); int smb2_encode_file_fs_full_size_info(struct smb2_context *smb2, struct smb2_file_fs_full_size_info *fs, struct smb2_iovec *vec); int smb2_decode_file_fs_object_id_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_object_id_info *fs, struct smb2_iovec *vec); int smb2_encode_file_fs_object_id_info(struct smb2_context *smb2, struct smb2_file_fs_object_id_info *fs, struct smb2_iovec *vec); int smb2_decode_file_fs_sector_size_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_sector_size_info *fs, struct smb2_iovec *vec); int smb2_encode_file_fs_sector_size_info(struct smb2_context *smb2, struct smb2_file_fs_sector_size_info *fs, struct smb2_iovec *vec); int smb2_decode_reparse_data_buffer(struct smb2_context *smb2, void *memctx, struct smb2_reparse_data_buffer *rp, struct smb2_iovec *vec); void smb2_free_all_fhs(struct smb2_context *smb2); void smb2_free_all_dirs(struct smb2_context *smb2); int smb2_read_from_buf(struct smb2_context *smb2); void smb2_change_events(struct smb2_context *smb2, t_socket fd, int events); void smb2_timeout_pdus(struct smb2_context *smb2); struct dcerpc_context; int dcerpc_set_uint8(struct dcerpc_context *ctx, struct smb2_iovec *iov, int *offset, uint8_t value); struct dcerpc_pdu; int dcerpc_pdu_direction(struct dcerpc_pdu *pdu); int dcerpc_align_3264(struct dcerpc_context *ctx, int offset); struct connect_data; /* defined in libsmb2.c */ void free_c_data(struct smb2_context*, struct connect_data*); /* defined in libsmb2.c */ #ifdef __cplusplus } #endif #endif /* !_LIBSMB2_PRIVATE_H_ */ libsmb2-6.2/include/apple/0000775000175000017500000000000014732155517014543 5ustar polpypolpylibsmb2-6.2/include/apple/config.h0000664000175000017500000000776114732155517016174 0ustar polpypolpy/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether or not TCP sockets should be allowed to linger after closure */ #define CONFIGURE_OPTION_TCP_LINGER 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_GSSAPI_GSSAPI_H 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Whether we use gssapi_krb5 or not */ /* #undef HAVE_LIBKRB5 */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Whether we have linger */ #define HAVE_LINGER 1 /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_TCP_H 1 /* Define to 1 if you have the header file. */ #define HAVE_POLL_H 1 /* Whether sockaddr struct has sa_len */ #define HAVE_SOCKADDR_LEN 1 /* Whether we have sockaddr_Storage */ #define HAVE_SOCKADDR_STORAGE 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_FCNTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_POLL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS__IOVEC_H */ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libsmb2" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "ronniesahlberg@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsmb2" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsmb2 4.0.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsmb2" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.0.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.0" libsmb2-6.2/include/ps2/0000775000175000017500000000000014732155517014146 5ustar polpypolpylibsmb2-6.2/include/ps2/config.h0000664000175000017500000001005314732155517015563 0ustar polpypolpy/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether or not TCP sockets should be allowed to linger after closure */ #define CONFIGURE_OPTION_TCP_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ARPA_INET_H */ /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_FCNTL_H */ /* Define to 1 if you have the header file. */ #define HAVE_GSSAPI_GSSAPI_H 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Whether we use gssapi_krb5 or not */ /* #undef HAVE_LIBKRB5 */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Whether we have linger */ #define HAVE_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETDB_H 1 */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IN_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_TCP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Whether sockaddr struct has sa_len */ /* #undef HAVE_SOCKADDR_LEN */ /* Whether we have sockaddr_Storage */ #define HAVE_SOCKADDR_STORAGE 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_STDLIB_H */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_ERRNO_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_FCNTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKET_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_STAT_H 1 */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UIO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UNISTD_H 1 */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS__IOVEC_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_TIME_H 1 */ /* Define to 1 if you have the header file. */ /* #undef HAVE_UNISTD_H 1 */ /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libsmb2" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "ronniesahlberg@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsmb2" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsmb2 4.0.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsmb2" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.0.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.0" libsmb2-6.2/include/Makefile.am0000664000175000017500000000045614732155517015503 0ustar polpypolpysmb2dir = $(includedir)/smb2 dist_smb2_HEADERS = \ smb2/libsmb2.h \ smb2/libsmb2-dcerpc.h \ smb2/libsmb2-dcerpc-lsa.h \ smb2/libsmb2-dcerpc-srvsvc.h \ smb2/libsmb2-raw.h \ smb2/smb2.h \ smb2/smb2-errors.h dist_noinst_HEADERS = \ asprintf.h \ libsmb2-private.h \ portable-endian.h \ slist.h libsmb2-6.2/include/xbox 360/0000775000175000017500000000000014732155517014713 5ustar polpypolpylibsmb2-6.2/include/xbox 360/config.h0000664000175000017500000001006314732155517016331 0ustar polpypolpy/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether or not TCP sockets should be allowed to linger after closure */ #define CONFIGURE_OPTION_TCP_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ARPA_INET_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_DLFCN_H */ /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_INTTYPES_H */ /* Whether we use gssapi_krb5 or not */ /* #undef HAVE_LIBKRB5 */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Whether we have linger */ #define HAVE_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETDB_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IN_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_TCP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Whether sockaddr struct has sa_len */ /* #undef HAVE_SOCKADDR_LEN */ /* Whether we have sockaddr_Storage */ /* #undef HAVE_SOCKADDR_STORAGE */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_STRINGS_H 1 */ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_ERRNO_H 1 */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FCNTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_IOCTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKET_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TIME_H 1 */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UIO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UNISTD_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS__IOVEC_H */ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UNISTD_H */ /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libsmb2" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "ronniesahlberg@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsmb2" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsmb2 4.0.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsmb2" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.0.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.0" libsmb2-6.2/include/xbox/0000775000175000017500000000000014732155517014422 5ustar polpypolpylibsmb2-6.2/include/xbox/config.h0000664000175000017500000001005514732155517016041 0ustar polpypolpy/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether or not TCP sockets should be allowed to linger after closure */ #define CONFIGURE_OPTION_TCP_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ARPA_INET_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_DLFCN_H */ /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_INTTYPES_H */ /* Whether we use gssapi_krb5 or not */ /* #undef HAVE_LIBKRB5 */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Whether we have linger */ #define HAVE_LINGER 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETDB_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IN_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_TCP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Whether sockaddr struct has sa_len */ /* #undef HAVE_SOCKADDR_LEN */ /* Whether we have sockaddr_Storage */ #define HAVE_SOCKADDR_STORAGE 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_STDINT_H */ /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_STRINGS_H */ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_ERRNO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FCNTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_IOCTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKET_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TIME_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UIO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UNISTD_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS__IOVEC_H */ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UNISTD_H */ /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libsmb2" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "ronniesahlberg@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsmb2" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsmb2 4.0.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsmb2" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.0.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.0" libsmb2-6.2/include/amiga_os/0000775000175000017500000000000014732155517015221 5ustar polpypolpylibsmb2-6.2/include/amiga_os/config.h0000664000175000017500000001000014732155517016626 0ustar polpypolpy/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether or not TCP sockets should be allowed to linger after closure */ #define CONFIGURE_OPTION_TCP_LINGER 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Whether we use gssapi_krb5 or not */ /* #undef HAVE_LIBKRB5 */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Whether we have linger */ /* #undef HAVE_LINGER */ /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_TCP_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Whether sockaddr struct has sa_len */ #define HAVE_SOCKADDR_LEN 1 /* Whether we have sockaddr_Storage */ /* #undef HAVE_SOCKADDR_STORAGE */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_FCNTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS__IOVEC_H */ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libsmb2" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "ronniesahlberg@gmail.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsmb2" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsmb2 4.0.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsmb2" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.0.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.0" libsmb2-6.2/Makefile.platform0000664000175000017500000000734314732155517015311 0ustar polpypolpy# -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- # # Copyright (C) 2024 by André Guilherme # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, see . .PHONY: gc_all gc_install nds_all nds_install wii_all wii_install 3ds_all 3ds_install wiiu_all wiiu_install switch_all switch_install dc_all dc_install ps2_ee_all ps2_ee_install ps2_ips_all ps2_ips_install ps2_iop_all ps2_iop_install ps4_all ps4_install gc_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/GameCube.cmake" cmake --build build gc_install: gc_all cmake --build build --target install nds_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/NDS.cmake" cmake --build build nds_install: nds_all cmake --build build --target install wii_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Wii.cmake" cmake --build build wii_install: wii_all cmake --build build --target install 3ds_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake" cmake --build build 3ds_install: 3ds_all cmake --build build --target install wiiu_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/WiiU.cmake" cmake --build build wiiu_install: wiiu_all cmake --build build --target install switch_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Switch.cmake" cmake --build build switch_install: switch_all cmake --build build --target install dc_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${KOS_CMAKE_TOOLCHAIN}" "-DCMAKE_INSTALL_PREFIX=${KOS_BASE}/addons/" "-DCMAKE_PREFIX_PATH=${KOS_BASE}/addons/" cmake --build build dc_install: dc_all cmake --build build --target install ps2_ee_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${PS2DEV}/share/ps2dev.cmake" "-DCMAKE_INSTALL_PREFIX=${PS2SDK}/ports" "-DCMAKE_PREFIX_PATH=${PS2SDK}/ports" cmake --build build ps2_ee_install: ps2_ee_all cmake --build build --target install ps2_rpc_all: cmake -S . -B build -DPS2RPC=1 "-DCMAKE_TOOLCHAIN_FILE=${PS2DEV}/share/ps2dev.cmake" "-DCMAKE_INSTALL_PREFIX=${PS2SDK}/ports" "-DCMAKE_INSTALL_PREFIX=${PS2SDK}/ports" cmake --build build ps2_rpc_install: ps2_rpc_all cmake --build build --target install ps2_iop_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${PS2DEV}/share/ps2dev_iop.cmake" "-DCMAKE_INSTALL_PREFIX=${PS2SDK}/ports_iop" "-DCMAKE_INSTALL_PREFIX=${PS2SDK}/ports_iop" cmake --build build ps2_iop_install: ps2_iop_all cmake --build build --target install ps2_irx_all: cmake -S . -B build -DBUILD_IRX=1 "-DCMAKE_TOOLCHAIN_FILE=${PS2DEV}/share/ps2dev_iop.cmake" cmake --build build ps2_irx_install: ps2_irx_all cmake --build build --target install ps4_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=/opt/pacbrew/ps4/openorbis/cmake/ps4.cmake" "-DCMAKE_INSTALL_PREFIX=/opt/pacbrew/ps4/openorbis/" "-DCMAKE_PREFIX_PATH=/opt/pacbrew/ps4/openorbis/" cmake --build build vita_all: cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${VITASDK}/share/vita.toolchain.cmake" cmake --build build vita_install: vita_all cmake --build build --target install ps4_install: ps4_all cmake --build build --target install clean: rm -rf build libsmb2-6.2/cmake/0000775000175000017500000000000014732155517013077 5ustar polpypolpylibsmb2-6.2/cmake/config.h.cmake0000664000175000017500000001047214732155517015600 0ustar polpypolpy/* config.h.cmake */ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ARPA_INET_H "@HAVE_ARPA_INET_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DLFCN_H "@HAVE_DLFCN_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_FCNTL_H "@HAVE_FCNTL_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_FCNTL_H "@HAVE_SYS_FCNTL_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_GSSAPI_GSSAPI_H "@HAVE_GSSAPI_GSSAPI_H@" /* Whether we use gssapi_krb5 or not */ #cmakedefine HAVE_LIBKRB5 "@HAVE_LIBKRB5@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_INTTYPES_H "@HAVE_INTTYPES_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETDB_H "@HAVE_NETDB_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_IN_H "@HAVE_NETINET_IN_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_TCP_H "@HAVE_NETINET_TCP_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_POLL_H "@HAVE_POLL_H@" /* Whether sockaddr struct has sa_len */ #cmakedefine HAVE_SOCKADDR_LEN "@HAVE_SOCKADDR_LEN@" /* Whether we have sockaddr_Storage */ #cmakedefine HAVE_SOCKADDR_STORAGE "@HAVE_SOCKADDR_STORAGE@" /* Whether we have linger */ #cmakedefine HAVE_LINGER "@HAVE_LINGER@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDINT_H "@HAVE_STDINT_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDIO_H "@HAVE_STDIO_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDLIB_H "@HAVE_STDLIB_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRINGS_H "@HAVE_STRINGS_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRING_H "@HAVE_STRING_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_IOCTL_H "@HAVE_SYS_IOCTL_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_POLL_H "@HAVE_SYS_POLL_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SOCKET_H "@HAVE_SYS_SOCKET_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H "@HAVE_SYS_STAT_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H "@HAVE_SYS_TYPES_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_UIO_H "@HAVE_SYS_UIO_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS__IOVEC_H "@HAVE_SYS__IOVEC_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TIME_H "@HAVE_TIME_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TIME_H "@HAVE_SYS_TIME_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H "@HAVE_UNISTD_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_UNISTD_H "@HAVE_SYS_UNISTD_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ERRNO_H "@HAVE_ERRNO_H@" /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_ERRNO_H "@HAVE_SYS_ERRNO_H@" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #cmakedefine STDC_HEADERS "@STDC_HEADERS@" /* Name of package */ #cmakedefine PACKAGE "@PACKAGE@" /* Define to the address where bug reports for this package should be sent. */ #cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" /* Define to the full name of this package. */ #cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" /* Define to the full name and version of this package. */ #cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" /* Define to the one symbol short name of this package. */ #cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@" /* Define to the home page for this package. */ #cmakedefine PACKAGE_URL "@PACKAGE_URL@" /* Define to the version of this package. */ #cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" /* Version number of package */ #cmakedefine VERSION "@VERSION@" libsmb2-6.2/cmake/ConfigureChecks.cmake0000664000175000017500000000474214732155517017152 0ustar polpypolpyif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") include(CheckIncludeFiles) else() include(CheckIncludeFile) 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) if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") check_include_files("sys/types.h;netinet/tcp.h" HAVE_NETINET_TCP_H) else() check_include_file("netinet/tcp.h" HAVE_NETINET_TCP_H) endif() check_include_file("poll.h" HAVE_POLL_H) check_include_file("stdint.h" HAVE_STDINT_H) check_include_file("stdio.h" HAVE_STDIO_H) check_include_file("stdlib.h" HAVE_STDLIB_H) check_include_file("strings.h" HAVE_STRINGS_H) check_include_file("string.h" HAVE_STRING_H) check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H) if(NOT PS4) check_include_file("sys/poll.h" HAVE_SYS_POLL_H) endif() check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H) check_include_file("sys/stat.h" HAVE_SYS_STAT_H) check_include_file("sys/types.h" HAVE_SYS_TYPES_H) check_include_file("sys/uio.h" HAVE_SYS_UIO_H) check_include_file("sys/_iovec.h" HAVE_SYS__IOVEC_H) check_include_file("sys/time.h" HAVE_SYS_TIME_H) check_include_file("sys/unistd.h" HAVE_SYS_UNISTD_H) if(NOT PS4) check_include_file("sys/errno.h" HAVE_SYS_ERRNO_H) endif() check_include_file("time.h" HAVE_TIME_H) check_include_file("unistd.h" HAVE_UNISTD_H) check_include_file("errno.h" HAVE_ERRNO_H) check_include_file("stddef.h" STDC_HEADERS) include(CheckStructHasMember) check_struct_has_member("struct sockaddr" sa_len sys/socket.h HAVE_SOCKADDR_LEN) check_struct_has_member("struct sockaddr_storage" ss_family sys/socket.h HAVE_SOCKADDR_STORAGE) if(CMAKE_SYSTEM_NAME MATCHES NintendoGameCube OR CMAKE_SYSTEM_NAME MATCHES NintendoWii) check_struct_has_member("struct linger" l_linger network.h HAVE_LINGER) else() check_struct_has_member("struct linger" l_linger sys/socket.h HAVE_LINGER) endif() include(CheckCCompilerFlag) if(CMAKE_COMPILER_IS_GNUCC) check_c_compiler_flag(-Wall C_ACCEPTS_WALL) if(C_ACCEPTS_WALL) add_definitions(-Wall) endif() endif() # We always want 64 bit file offsets add_definitions(-D_FILE_OFFSET_BITS=64) configure_file(cmake/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) add_definitions(-DHAVE_CONFIG_H) libsmb2-6.2/cmake/FindSMB2.cmake0000664000175000017500000000175414732155517015414 0ustar polpypolpy#.rst: # FindSMB2 # ------- # Finds the libsmb2 library # # This will will define the following variables:: # # SMB2_FOUND - system has libsmb2 # SMB2_INCLUDE_DIRS - the libsmb2 include directory # SMB2_LIBRARIES - the libsmb2 libraries # SMB2_DEFINITIONS - the libsmb2 compile definitions if(PKG_CONFIG_FOUND) pkg_check_modules(PC_SMB2 libsmb2 QUIET) endif() find_path(SMB2_INCLUDE_DIR smb2/libsmb2.h PATHS ${PC_SMB2_INCLUDEDIR}) set(SMB2_VERSION ${PC_SMB2_VERSION}) include(FindPackageHandleStandardArgs) find_library(SMB2_LIBRARY NAMES smb2 PATHS ${PC_SMB2_LIBDIR}) find_package_handle_standard_args(SMB2 REQUIRED_VARS SMB2_LIBRARY SMB2_INCLUDE_DIR VERSION_VAR SMB2_VERSION) if(SMB2_FOUND) set(SMB2_LIBRARIES ${SMB2_LIBRARY}) set(SMB2_INCLUDE_DIRS ${SMB2_INCLUDE_DIR}) set(SMB2_DEFINITIONS -DHAVE_LIBSMB2=1) endif() mark_as_advanced(SMB2_INCLUDE_DIR SMB2_LIBRARY) libsmb2-6.2/cmake/libsmb2.pc.cmake0000664000175000017500000000052414732155517016035 0ustar polpypolpy# libsmb2 pkg-config file prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=@INSTALL_LIB_DIR@ includedir=@INSTALL_INC_DIR@ Name: libsmb2 Description: libsmb2 is a client library for accessing SMB shares over a network. Version: @PROJECT_VERSION@ Requires: Conflicts: Libs: -L${libdir} -lsmb2 Cflags: -I${includedir} libsmb2-6.2/cmake/Modules/0000775000175000017500000000000014732155517014507 5ustar polpypolpylibsmb2-6.2/cmake/Modules/FindLibKrb5.cmake0000664000175000017500000000213614732155517017546 0ustar polpypolpy# - Try to find Krb5 headers and libraries # # Usage of this module as follows: # # find_package(LibKrb5) # # Variables used by this module, they can change the default behaviour and need # to be set before calling find_package: # # LibKrb5_ROOT_DIR Set this variable to the root installation of # libKrb5 if the module has problems finding the # proper installation path. # # Variables defined by this module: # # LibKrb5_FOUND System has Krb5 libraries and headers # LibKrb5_LIBRARY The Krb5 library # LibKrb5_INCLUDE_DIR The location of Krb5 headers find_path(LibKrb5_ROOT_DIR NAMES include/krb5.h ) find_library(LibKrb5_LIBRARY NAMES krb5 HINTS ${LibKrb5_ROOT_DIR}/lib ) find_path(LibKrb5_INCLUDE_DIR NAMES krb5.h HINTS ${LibKrb5_ROOT_DIR}/include ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LibKrb5 DEFAULT_MSG LibKrb5_LIBRARY LibKrb5_INCLUDE_DIR ) mark_as_advanced( LibKrb5_ROOT_DIR LibKrb5_LIBRARY LibKrb5_INCLUDE_DIR )libsmb2-6.2/cmake/Modules/FindGSSAPI.cmake0000664000175000017500000000144214732155517017301 0ustar polpypolpy#.rst: # FindGSSAPI # ------- # Finds the gssapi library # # This will will define the following variables:: # # GSSAPI_FOUND - system has gssapi # GSSAPI_INCLUDE_DIRS - the gssapi include directory # GSSAPI_LIBRARIES - the gssapi libraries find_library(GSSAPI_LIBRARY NAMES gssapi_krb5) find_path(GSSAPI_INCLUDE_DIR NAMES gssapi.h gssapi/gssapi.h) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GSSAPI REQUIRED_VARS GSSAPI_LIBRARY GSSAPI_INCLUDE_DIR) if (GSSAPI_LIBRARY AND GSSAPI_INCLUDE_DIRS) set(GSSAPI_FOUND TRUE) endif () if(GSSAPI_FOUND) set(GSSAPI_LIBRARIES ${GSSAPI_LIBRARY}) set(GSSAPI_INCLUDE_DIRS ${GSSAPI_INCLUDE_DIR}) endif() mark_as_advanced(GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIRS) libsmb2-6.2/Makefile.am0000664000175000017500000000040614732155517014053 0ustar polpypolpyif ENABLE_EXAMPLES MAYBE_EXAMPLES = examples endif SUBDIRS = include lib utils . $(MAYBE_EXAMPLES) ACLOCAL_AMFLAGS = -I m4 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsmb2.pc EXTRA_DIST = \ libsmb2.pc.in test: $(SUBDIRS) cd tests; make test libsmb2-6.2/COPYING0000664000175000017500000000157714732155517013064 0ustar polpypolpyLibsmb2 components fall under two separate licences The lib and include directories =============================== The smb2 client library itself, i.e. the lib and include directories, is licenced under GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. A copy of LGPL 2.1 is included in the file LICENCE-LGPL-2.1.txt but can also be downloaded from http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html This is the licence that applies to the libsmb2 library and its use. The examples directory ====================== The example applications using this library, i.e. the examples directory, is licenced under 2-Clause BSD License. These are executable applications that link with the libsmb2 library. To avoid any confusion, every source file also contain a licence boilerplate. libsmb2-6.2/LICENCE-LGPL-2.1.txt0000664000175000017500000006364214732155517014667 0ustar polpypolpy GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libsmb2-6.2/CMakeLists.txt0000664000175000017500000002345514732155517014570 0ustar polpypolpyif(NOT ESP_PLATFORM) if(CMAKE_SYSTEM_NAME MATCHES NintendoSwitch OR CMAKE_SYSTEM_NAME MATCHES Nintendo3DS OR CMAKE_SYSTEM_NAME MATCHES Dreamcast OR CMAKE_SYSTEM_NAME MATCHES NintendoGameCube OR CMAKE_SYSTEM_NAME MATCHES NintendoDS OR CMAKE_SYSTEM_NAME MATCHES NintendoWii OR CMAKE_SYSTEM_NAME MATCHES CafeOS) cmake_minimum_required(VERSION 3.13) elseif(VITA) cmake_minimum_required(VERSION 3.2) elseif(PICO_BOARD) cmake_minimum_required(VERSION 3.12) message(STATUS "Configuring libsmb2 for ${PICO_BOARD}") else() cmake_minimum_required(VERSION 3.5) endif() if(NOT IOP AND BUILD_IRX) project(smb2man LANGUAGES C VERSION 2.3.0 ) set(VERSION 2.3.0) set(PACKAGE "smb2man") set(PACKAGE_BUGREPORT "ronniesahlberg@gmail.com or andregui17@outlook.com") set(PACKAGE_NAME "smb2man") set(PACKAGE_VERSION "${VERSION}") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE}") set(PACKAGE_URL "https://github.com/sahlberg/libsmb2") elseif(PICO_BOARD) project(libsmb2 C CXX ASM) else() project(libsmb2 LANGUAGES C VERSION 6.1.0 ) set(VERSION 6.1.0) set(PACKAGE "libsmb2") set(PACKAGE_BUGREPORT "ronniesahlberg@gmail.com") set(PACKAGE_NAME "libsmb2") set(PACKAGE_VERSION "${VERSION}") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE}") set(PACKAGE_URL "https://github.com/sahlberg/libsmb2") endif() configure_file(libsmb2.pc.in libsmb2.pc @ONLY) endif() if(NOT ESP_PLATFORM) set(SOVERSION 1 CACHE STRING "" FORCE) if(NOT IOP AND NOT BUILD_IRX) set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Installation directory for libraries") set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/cmake/libsmb2" CACHE PATH "Installation directory for cmake (.cmake) files") endif() if(CMAKE_SYSTEM_NAME MATCHES NintendoSwitch OR CMAKE_SYSTEM_NAME MATCHES Nintendo3DS OR PS4 OR PS2 OR VITA OR CMAKE_SYSTEM_NAME MATCHES Dreamcast OR CMAKE_SYSTEM_NAME MATCHES NintendoGameCube OR CMAKE_SYSTEM_NAME MATCHES NintendoDS OR CMAKE_SYSTEM_NAME MATCHES NintendoWii OR CMAKE_SYSTEM_NAME MATCHES CafeOS) option(BUILD_SHARED_LIBS "Build shared libraries" OFF) else() 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) if (ENABLE_LIBKRB5) find_package(LibKrb5) endif() elseif(IOS) if (ENABLE_GSSAPI) find_package(GSSAPI) endif() endif() if(NOT ESP_PLATFORM) include(cmake/ConfigureChecks.cmake) endif() if(PICO_BOARD) include_directories(libsmb2 STATIC ${PICO_SDK_PATH}/lib/lwip/src/include ${PICO_SDK_PATH}/src/rp2_common/pico_lwip/include lib include include/smb2 include/picow ) elseif(ESP_PLATFORM) set(COMPONENT_ADD_INCLUDEDIRS "lib" include include/smb2 include/esp ) else() include_directories(${CMAKE_CURRENT_BINARY_DIR} include include/smb2 ) endif() if(CMAKE_SYSTEM_NAME MATCHES Linux) if (ENABLE_LIBKRB5) set(core_DEPENDS ${LIBKRB5_LIBRARY} CACHE STRING "" FORCE) endif() elseif(IOS) if (ENABLE_GSSAPI) set(core_DEPENDS ${GSSAPI_LIBRARIES} CACHE STRING "" FORCE) endif() endif() if(MSVC AND BUILD_SHARED_LIBS) # If we are building dll with msvc, then generate a def file according to the syms file set(SYMS_FILE_PATH "${PROJECT_SOURCE_DIR}/lib/libsmb2.syms") set(DEF_FILE_PATH "${PROJECT_BINARY_DIR}/lib/libsmb2.def") file(READ ${SYMS_FILE_PATH} EXPORT_SYMBOLS) file(WRITE ${DEF_FILE_PATH} "LIBRARY smb2\nEXPORTS\n\n${EXPORT_SYMBOLS}") # Pass def file to the linker set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEF:${DEF_FILE_PATH}") endif() if(CMAKE_SYSTEM_NAME MATCHES Windows) list(APPEND CORE_LIBRARIES ws2_32.lib) add_definitions(-DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS -DHAVE_LINGER -DNEED_GETLOGIN_R -DNEED_GETPID -DNEED_RANDOM -DNEED_SRANDOM) elseif(CMAKE_SYSTEM_NAME MATCHES NintendoSwitch) add_definitions(-DARM11 -DSWITCH -D__SWITCH__ -DNEED_READV -DNEED_WRITEV -DNEED_GETLOGIN_R) set(ARCH "-march=armv8-a -mtp=soft -fPIE") set(CMAKE_C_FLAGS "-g -Wall -O2 -ffast-math ${ARCH}") set(CMAKE_C_FLAGS "-Wno-unused-variable") set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -std=gnu11") set(CMAKE_C_LDFLAGS "${CMAKE_C_FLAGS} -specs=switch.specs -g ${ARCH} -Wl,-Map,$(notdir $*.map)") add_compile_options("${CMAKE_C_FLAGS} ${CMAKE_LDFLAGS}") elseif(CMAKE_SYSTEM_NAME MATCHES Nintendo3DS) add_definitions(-DARM11 -D_3DS -D__3DS__ -DNEED_READV -DNEED_WRITEV -DNEED_GETLOGIN_R) set(ARCH "-march=armv6k -mfloat-abi=hard -mtune=mpcore -mtp=soft -fPIE") set(CMAKE_C_FLAGS "-Wno-unused-variable -g -Wall -O2 -mword-relocations -fomit-frame-pointer -ffast-math ${ARCH}") set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -std=gnu11") set(CMAKE_C_LDFLAGS "${CMAKE_C_FLAGS} -specs=3dsx.specs -g ${ARCH} -Wl,-Map,$(notdir $*.map)") add_compile_options("${CMAKE_C_FLAGS} ${CMAKE_LDFLAGS}") elseif(CMAKE_SYSTEM_NAME MATCHES NintendoDS) add_definitions(-DARM9 -D__NDS__ -DNEED_READV -DHAVE_SOCKADDR_STORAGE -DNEED_WRITEV -DNEED_GETLOGIN_R -DNEED_GETADDRINFO -DNEED_FREEADDRINFO -DNEED_POLL) set(CMAKE_C_FLAGS "-Wno-format -Wpointer-arith") set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -std=gnu11") set(CMAKE_C_LDFLAGS "${CMAKE_C_FLAGS} -specs=ds_arm9.specs -g") add_compile_options("${CMAKE_C_FLAGS} ${CMAKE_LDFLAGS}") elseif(CMAKE_SYSTEM_NAME MATCHES NintendoGameCube) add_definitions(-DGEKKO -D__GC__ -DNEED_READV -DNEED_WRITEV -DNEED_GETLOGIN_R -DNEED_GETADDRINFO -DNEED_FREEADDRINFO -DNEED_POLL) set(CMAKE_C_FLAGS "-g") #-O3 -Wall add_compile_options("${CMAKE_C_FLAGS}") elseif(CMAKE_SYSTEM_NAME MATCHES NintendoWii) add_definitions(-DGEKKO -D__WII__ -DNEED_READV -DNEED_WRITEV -DNEED_GETLOGIN_R -DNEED_GETADDRINFO -DNEED_FREEADDRINFO -DNEED_POLL) set(CMAKE_C_FLAGS "-g") #-O3 -Wall add_compile_options("${CMAKE_C_FLAGS}") elseif(CMAKE_SYSTEM_NAME MATCHES CafeOS) add_definitions(-D__WIIU__ -DNEED_READV -DNEED_WRITEV -DNEED_GETLOGIN_R) set(CMAKE_C_FLAGS "-g") #-O3 -Wall add_compile_options("${CMAKE_C_FLAGS}") elseif(PS4) add_definitions(-DPS4_PLATFORM) set(CMAKE_C_FLAGS "-funwind-tables") #-fuse-init-array -emit-llvm broken... set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") add_compile_options("${CMAKE_C_FLAGS}") elseif(EE) add_definitions(-DNEED_BE64TOH -DNEED_POLL -DNEED_WRITEV -DNEED_READV -DNEED_GETLOGIN_R) if(EE AND PS2RPC) add_definitions(-DPS2RPC) endif() elseif(IOP) add_definitions(-DHAVE_CONFIG_H -DNEED_BE64TOH -DNEED_STRDUP -DNEED_READV -DNEED_WRITEV -DNEED_POLL -DNEED_GETPID -DNEED_RANDOM -DNEED_SRANDOM -DNEED_GETLOGIN_R -DHAVE_STRING_H -DHAVE_SYS_FCNTL_H) if(IOP AND BUILD_IRX) add_definitions(-D__ps2sdk_iop__) if(DEBUG) add_definitions(-DDEBUG) endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fno-builtin") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s") endif() set(CMAKE_C_FLAGS "-Wall") include_directories(${CMAKE_CURRENT_BINARY_DIR} include/ps2) add_compile_options("${CMAKE_C_FLAGS}") elseif(VITA) add_definitions(-DNEED_READV -DNEED_WRITEV -DNEED_GETLOGIN_R) elseif(PICO_BOARD) add_definitions(-DNEED_BE64TOH -DNEED_POLL -DNEED_GETLOGIN_R) elseif(ESP_PLATFORM) if(NOT CMAKE_BUILD_EARLY_EXPANSION) add_definitions(-DHAVE_CONFIG_H) endif() add_definitions(-DNEED_READV -DNEED_WRITEV -DNEED_GETLOGIN_R -DNEED_RANDOM -DNEED_SRANDOM) elseif(CMAKE_SYSTEM_NAME MATCHES Dreamcast) add_definitions(-DNEED_WRITEV -DNEED_READV -DHAVE_CONFIG_H -DNEED_GETLOGIN_R) elseif(CMAKE_SYSTEM_NAME STREQUAL Solaris) find_library(SOCKET_LIBRARY socket) find_library(NSL_LIBRARY nsl) list(APPEND CORE_LIBRARIES ${SOCKET_LIBRARY} ${NSL_LIBRARY}) endif() if(ENABLE_EXAMPLES) add_subdirectory(examples) endif() add_subdirectory(lib) if(NOT PICO_BOARD OR ESP_PLATFORM) include(CMakePackageConfigHelpers) write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/libsmb2-config-version.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion) if(NOT IOP AND NOT BUILD_IRX) configure_file(cmake/libsmb2.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libsmb2.pc @ONLY) install(DIRECTORY include/smb2 DESTINATION ${INSTALL_INC_DIR}) install(FILES cmake/FindSMB2.cmake ${CMAKE_CURRENT_BINARY_DIR}/libsmb2-config-version.cmake DESTINATION ${INSTALL_CMAKE_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libsmb2.pc DESTINATION ${INSTALL_PKGCONFIG_DIR}) endif() endif() libsmb2-6.2/bootstrap0000664000175000017500000000003214732155517013752 0ustar polpypolpy#!/bin/sh autoreconf -vif libsmb2-6.2/Xbox/0000775000175000017500000000000014732155517012737 5ustar polpypolpylibsmb2-6.2/Xbox/libsmb2.sln0000664000175000017500000000265614732155517015020 0ustar polpypolpyMicrosoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsmb2", "libsmb2.vcproj", "{7326DFF9-17C3-478F-9EAB-15FC697DC053}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Profile = Profile Profile_FastCap = Profile_FastCap Release = Release Release_LTCG = Release_LTCG EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Debug.ActiveCfg = Debug|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Debug.Build.0 = Debug|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Profile.ActiveCfg = Profile|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Profile.Build.0 = Profile|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Profile_FastCap.ActiveCfg = Profile_FastCap|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Profile_FastCap.Build.0 = Profile_FastCap|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Release.ActiveCfg = Release|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Release.Build.0 = Release|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Release_LTCG.ActiveCfg = Release_LTCG|Xbox {7326DFF9-17C3-478F-9EAB-15FC697DC053}.Release_LTCG.Build.0 = Release_LTCG|Xbox EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal libsmb2-6.2/Xbox/libsmb2.vcproj0000664000175000017500000002663114732155517015526 0ustar polpypolpy libsmb2-6.2/lib/0000775000175000017500000000000014732155517012565 5ustar polpypolpylibsmb2-6.2/lib/smb2-data-security-descriptor.c0000664000175000017500000002654614732155517020541 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2017 by Ronnie Sahlberg Portions of this code are copyright 2017 to Primary Data Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "slist.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static struct smb2_sid * decode_sid(struct smb2_context *smb2, void *memctx, struct smb2_iovec *v) { struct smb2_sid *sid; uint8_t revision, sub_auth_count; int i; if (v->len < 8) { smb2_set_error(smb2, "SID must be at least 8 bytes"); return NULL; } smb2_get_uint8(v, 0, &revision); if (revision != 1) { smb2_set_error(smb2, "can not decode sid with " "revision %d", revision); return NULL; } smb2_get_uint8(v, 1, &sub_auth_count); if (v->len < 8 + sub_auth_count * sizeof(uint32_t)) { smb2_set_error(smb2, "SID is bigger than the buffer"); return NULL; } sid = smb2_alloc_data(smb2, memctx, offsetof(struct smb2_sid, sub_auth) + sub_auth_count * sizeof(uint32_t)); if (sid == NULL) { smb2_set_error(smb2, "failed to allocate sid."); return NULL; } sid->revision = revision; sid->sub_auth_count = sub_auth_count; memcpy(&sid->id_auth[0], &v->buf[2], SID_ID_AUTH_LEN); for (i = 0; i < sub_auth_count; i++) { smb2_get_uint32(v, 8 + i * sizeof(uint32_t), &sid->sub_auth[i]); } v->len -= 8 + sub_auth_count * sizeof(uint32_t); v->buf += 8 + sub_auth_count * sizeof(uint32_t); return sid; } static struct smb2_ace * decode_ace(struct smb2_context *smb2, void *memctx, struct smb2_iovec *vec) { struct smb2_iovec v = *vec; uint8_t ace_type, ace_flags; uint16_t ace_size; struct smb2_ace *ace; if (v.len < 4) { smb2_set_error(smb2, "not enough data for ace header."); return NULL; } smb2_get_uint8(&v, 0, &ace_type); smb2_get_uint8(&v, 1, &ace_flags); smb2_get_uint16(&v, 2, &ace_size); ace = smb2_alloc_data(smb2, memctx, sizeof(struct smb2_ace)); if (ace == NULL) { smb2_set_error(smb2, "failed to allocate ace."); return NULL; } ace->ace_type = ace_type; ace->ace_flags = ace_flags; ace->ace_size = ace_size; /* Skip past the header */ if (ace_size < 4) { smb2_set_error(smb2, "not enough data for ace data."); return NULL; } if (v.len < ace_size) { smb2_set_error(smb2, "not enough data for ace data."); return NULL; } v.len -= 4; v.buf = &v.buf[4]; /* decode the content of the ace */ /* TODO: have a default case where we just keep the raw blob */ switch (ace_type) { case SMB2_ACCESS_ALLOWED_ACE_TYPE: case SMB2_ACCESS_DENIED_ACE_TYPE: case SMB2_SYSTEM_AUDIT_ACE_TYPE: case SMB2_SYSTEM_MANDATORY_LABEL_ACE_TYPE: case SMB2_SYSTEM_SCOPED_POLICY_ID_ACE_TYPE: smb2_get_uint32(&v, 0, &ace->mask); if (v.len < 4) { smb2_set_error(smb2, "not enough data for ace data."); return NULL; } v.len -= 4; v.buf = &v.buf[4]; ace->sid = decode_sid(smb2, memctx, &v); break; case SMB2_ACCESS_ALLOWED_OBJECT_ACE_TYPE: case SMB2_ACCESS_DENIED_OBJECT_ACE_TYPE: case SMB2_SYSTEM_AUDIT_OBJECT_ACE_TYPE: if (v.len < 40) { smb2_set_error(smb2, "not enough data for ace data."); return NULL; } smb2_get_uint32(&v, 0, &ace->mask); v.len -= 4; v.buf = &v.buf[4]; smb2_get_uint32(&v, 0, &ace->flags); v.len -= 4; v.buf = &v.buf[4]; memcpy(ace->object_type, v.buf, SMB2_OBJECT_TYPE_SIZE); v.len -= SMB2_OBJECT_TYPE_SIZE; v.buf = &v.buf[SMB2_OBJECT_TYPE_SIZE]; memcpy(ace->inherited_object_type, v.buf, SMB2_OBJECT_TYPE_SIZE); v.len -= SMB2_OBJECT_TYPE_SIZE; v.buf = &v.buf[SMB2_OBJECT_TYPE_SIZE]; ace->sid = decode_sid(smb2, memctx, &v); break; case SMB2_ACCESS_ALLOWED_CALLBACK_ACE_TYPE: case SMB2_ACCESS_DENIED_CALLBACK_ACE_TYPE: case SMB2_SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE: smb2_get_uint32(&v, 0, &ace->mask); if (v.len < 4) { smb2_set_error(smb2, "not enough data for ace data."); return NULL; } v.len -= 4; v.buf = &v.buf[4]; ace->sid = decode_sid(smb2, memctx, &v); ace->ad_len = v.len; ace->ad_data = smb2_alloc_data(smb2, memctx, ace->ad_len); if (ace->ad_data == NULL) { return NULL; } memcpy(ace->ad_data, v.buf, v.len); break; default: ace->raw_len = v.len; ace->raw_data = smb2_alloc_data(smb2, memctx, ace->raw_len); if (ace->raw_data == NULL) { return NULL; } memcpy(ace->raw_data, v.buf, v.len); } return ace; } static struct smb2_acl * decode_acl(struct smb2_context *smb2, void *memctx, struct smb2_iovec *vec) { struct smb2_iovec v = *vec; struct smb2_acl *acl; uint8_t revision; uint16_t acl_size, ace_count; int i; if (v.len < 8) { smb2_set_error(smb2, "not enough data for acl header."); return NULL; } smb2_get_uint8(&v, 0, &revision); smb2_get_uint16(&v, 2, &acl_size); smb2_get_uint16(&v, 4, &ace_count); switch (revision) { case SMB2_ACL_REVISION: case SMB2_ACL_REVISION_DS: break; default: smb2_set_error(smb2, "can not decode acl with " "revision %d", revision); return NULL; } if (v.len > acl_size) { v.len = acl_size; } if (v.len < acl_size) { smb2_set_error(smb2, "not enough data for acl"); return NULL; } acl = smb2_alloc_data(smb2, memctx, sizeof(struct smb2_acl)); if (acl == NULL) { smb2_set_error(smb2, "failed to allocate acl."); return NULL; } acl->revision = revision; acl->ace_count = ace_count; /* Skip past the ACL header to the first ace. */ v.len -= 8; v.buf = &v.buf[8]; for (i = 0; i < ace_count; i++) { struct smb2_ace *ace = decode_ace(smb2, memctx, &v); if (ace == NULL) { smb2_set_error(smb2, "failed to decode ace # %d: %s", i, smb2_get_error(smb2)); return NULL; } /* skip to the next ace */ if (ace->ace_size > v.len) { smb2_set_error(smb2, "not enough data for ace %s", smb2_get_error(smb2)); return NULL; } v.len -= ace->ace_size; v.buf = &v.buf[ace->ace_size]; SMB2_LIST_ADD_END(&acl->aces, ace); } return acl; } int smb2_decode_security_descriptor(struct smb2_context *smb2, void *memctx, struct smb2_security_descriptor *sd, struct smb2_iovec *vec) { struct smb2_iovec v; uint32_t offset_owner, offset_group, offset_sacl, offset_dacl; if (vec->len < 20) { return -1; } v.buf = &vec->buf[0]; v.len = 20; smb2_get_uint8(&v, 0, &sd->revision); if (sd->revision != 1) { smb2_set_error(smb2, "can not decode security descriptor with " "revision %d", sd->revision); return -1; } smb2_get_uint16(&v, 2, &sd->control); smb2_get_uint32(&v, 4, &offset_owner); smb2_get_uint32(&v, 8, &offset_group); smb2_get_uint32(&v, 12, &offset_sacl); smb2_get_uint32(&v, 16, &offset_dacl); /* Owner */ if (offset_owner > 0 && offset_owner + 2 + SID_ID_AUTH_LEN < vec->len) { v.buf = &vec->buf[offset_owner]; v.len = vec->len - offset_owner; sd->owner = decode_sid(smb2, memctx, &v); if (sd->owner == NULL) { smb2_set_error(smb2, "failed to decode owner sid: %s", smb2_get_error(smb2)); return -1; } } /* Group */ if (offset_group > 0 && offset_group + 2 + SID_ID_AUTH_LEN < vec->len) { v.buf = &vec->buf[offset_group]; v.len = vec->len - offset_group; sd->group = decode_sid(smb2, sd, &v); if (sd->group == NULL) { smb2_set_error(smb2, "failed to decode group sid: %s", smb2_get_error(smb2)); return -1; } } /* DACL */ if (offset_dacl > 0 && offset_dacl + 8 <= vec->len) { v.buf = &vec->buf[offset_dacl]; v.len = vec->len - offset_dacl; sd->dacl = decode_acl(smb2, sd, &v); if (sd->dacl == NULL) { smb2_set_error(smb2, "failed to decode dacl: %s", smb2_get_error(smb2)); return -1; } } return 0; } libsmb2-6.2/lib/hmac-md5.h0000664000175000017500000000114514732155517014332 0ustar polpypolpy/* From RFC1204 HMAC-MD5 */ #ifndef HMAC_MD5_H #define HMAC_MD5_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_STDINT_H #include #endif #if (__BYTE_ORDER == __BIG_ENDIAN) || defined(XBOX_360_PLATFORM) # define WORDS_BIGENDIAN 1 #endif #if !defined(__PS2__) && !defined(PICO_PLATFORM) typedef uint32_t UWORD32; #endif #ifdef __cplusplus extern "C" { #endif void smb2_hmac_md5(unsigned char *text, int text_len, unsigned char *key, unsigned int key_len, unsigned char *digest); #ifdef __cplusplus } #endif #endif /* !HMAC_MD5_H */ libsmb2-6.2/lib/dcerpc-srvsvc.c0000664000175000017500000003341014732155517015516 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-dcerpc.h" #include "libsmb2-dcerpc-srvsvc.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" #define SRVSVC_UUID 0x4b324fc8, 0x1670, 0x01d3, {0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88} int dcerpc_get_cr(struct dcerpc_pdu *pdu); p_syntax_id_t srvsvc_interface = { {SRVSVC_UUID}, 3, 0 }; /* * SRVSVC BEGIN: DEFINITIONS FROM SRVSVC.IDL * [MS-SRVS].pdf */ /* * typedef struct _SHARE_INFO_0 { * [string] wchar_t * shi0_netname; * } SHARE_INFO_0, *PSHARE_INFO_0, *LPSHARE_INFO_0; */ int srvsvc_SHARE_INFO_0_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_SHARE_INFO_0 *nsi1 = ptr; if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &nsi1->netname, PTR_UNIQUE, dcerpc_utf16z_coder)) { return -1; } return 0; } /* * [size_is(EntriesRead)] LPSHARE_INFO_0 Buffer; */ static int srvsvc_SHARE_INFO_0_carray_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { return dcerpc_carray_coder(ctx, pdu, iov, offset, ptr, sizeof(struct srvsvc_SHARE_INFO_0), srvsvc_SHARE_INFO_0_coder); } /* * typedef struct _SHARE_INFO_0_CONTAINER { * DWORD EntriesRead; * [size_is(EntriesRead)] LPSHARE_INFO_0 Buffer; * } SHARE_INFO_0_CONTAINER; */ int srvsvc_SHARE_INFO_0_CONTAINER_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_SHARE_INFO_0_CONTAINER *ctr = ptr; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &ctr->EntriesRead)) { return -1; } if (dcerpc_pdu_direction(pdu) == DCERPC_DECODE) { if (ctr->Buffer == NULL) { ctr->Buffer = smb2_alloc_data( dcerpc_get_smb2_context(dce), dcerpc_get_pdu_payload(pdu), sizeof(struct srvsvc_SHARE_INFO_0_carray)); } } if (dcerpc_ptr_coder(dce, pdu, iov, offset, ctr->Buffer, PTR_UNIQUE, srvsvc_SHARE_INFO_0_carray_coder)) { return -1; } return 0; } /* * typedef struct _SHARE_INFO_1 { * [string] wchar_t *netname; * DWORD shi1_type; * [string] wchar_t *remark; * } SHARE_INFO_1, *PSHARE_INFO_1, *LPSHARE_INFO_1; */ int srvsvc_SHARE_INFO_1_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_SHARE_INFO_1 *nsi1 = ptr; if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &nsi1->netname, PTR_UNIQUE, dcerpc_utf16z_coder)) { return -1; } if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &nsi1->type)) { return -1; } if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &nsi1->remark, PTR_UNIQUE, dcerpc_utf16z_coder)) { return -1; } return 0; } /* * [size_is(EntriesRead)] LPSHARE_INFO_1 Buffer; */ static int srvsvc_SHARE_INFO_1_carray_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { return dcerpc_carray_coder(ctx, pdu, iov, offset, ptr, sizeof(struct srvsvc_SHARE_INFO_1), srvsvc_SHARE_INFO_1_coder); } /* * typedef struct _SHARE_INFO_1_CONTAINER { * DWORD EntriesRead; * [size_is(EntriesRead)] LPSHARE_INFO_1 Buffer; * } SHARE_INFO_1_CONTAINER; */ int srvsvc_SHARE_INFO_1_CONTAINER_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_SHARE_INFO_1_CONTAINER *ctr = ptr; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &ctr->EntriesRead)) { return -1; } if (dcerpc_pdu_direction(pdu) == DCERPC_DECODE) { if (ctr->Buffer == NULL) { ctr->Buffer = smb2_alloc_data( dcerpc_get_smb2_context(dce), dcerpc_get_pdu_payload(pdu), sizeof(struct srvsvc_SHARE_INFO_1_carray)); } } if (dcerpc_ptr_coder(dce, pdu, iov, offset, ctr->Buffer, PTR_UNIQUE, srvsvc_SHARE_INFO_1_carray_coder)) { return -1; } return 0; } /* * typedef [switch_type(DWORD)] union _SHARE_ENUM_UNION { * [case(0)] SHARE_INFO_0_CONTAINER* Level0; * [case(1)] SHARE_INFO_1_CONTAINER* Level1; * [case(2)] SHARE_INFO_2_CONTAINER* Level2; * [case(501)] SHARE_INFO_501_CONTAINER* Level501; * [case(502)] SHARE_INFO_502_CONTAINER* Level502; * [case(503)] SHARE_INFO_503_CONTAINER* Level503; * } SHARE_ENUM_UNION; */ static int srvsvc_SHARE_ENUM_UNION_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_SHARE_ENUM_UNION *ctr = ptr; uint64_t p; p = ctr->Level; if (dcerpc_uint3264_coder(ctx, pdu, iov, offset, &p)) { return -1; } ctr->Level = (uint32_t)p; switch (ctr->Level) { case 0: if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &ctr->Level0, PTR_UNIQUE, srvsvc_SHARE_INFO_0_CONTAINER_coder)) { return -1; } break; case 1: if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &ctr->Level1, PTR_UNIQUE, srvsvc_SHARE_INFO_1_CONTAINER_coder)) { return -1; } break; }; return 0; } /* * typedef struct _SHARE_ENUM_STRUCT { * DWORD Level; * [switch_is(Level)] SHARE_ENUM_UNION ShareInfo; * } SHARE_ENUM_STRUCT, *PSHARE_ENUM_STRUCT, *LPSHARE_ENUM_STRUCT; */ int srvsvc_SHARE_ENUM_STRUCT_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_SHARE_ENUM_STRUCT *ses = ptr; if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &ses->Level)) { return -1; } if (srvsvc_SHARE_ENUM_UNION_coder(ctx, pdu, iov, offset, &ses->ShareInfo)) { return -1; } return 0; } /***************** * Function: 0x0f * NET_API_STATUS NetrShareEnum ( * [in,string,unique] SRVSVC_HANDLE ServerName, * [in,out] LPSHARE_ENUM_STRUCT InfoStruct, * [in] DWORD PreferedMaximumLength, * [out] DWORD * TotalEntries, * [in,out,unique] DWORD * ResumeHandle * ); */ int srvsvc_NetrShareEnum_req_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_NetrShareEnum_req *req = ptr; if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &req->ServerName, PTR_UNIQUE, dcerpc_utf16z_coder)) { return -1; } if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &req->ses, PTR_REF, srvsvc_SHARE_ENUM_STRUCT_coder)) { return -1; } if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &req->PreferedMaximumLength, PTR_REF, dcerpc_uint32_coder)) { return -1; } if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &req->ResumeHandle, PTR_UNIQUE, dcerpc_uint32_coder)) { return -1; } return 0; } int srvsvc_NetrShareEnum_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_NetrShareEnum_rep *rep = ptr; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &rep->ses, PTR_REF, srvsvc_SHARE_ENUM_STRUCT_coder)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, &rep->total_entries, PTR_REF, dcerpc_uint32_coder)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, &rep->resume_handle, PTR_UNIQUE, dcerpc_uint32_coder)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &rep->status)) { return -1; } return 0; } /* * typedef [switch_type(unsigned long)] union _SHARE_INFO { * [case(0)] LPSHARE_INFO_0 ShareInfo0; * [case(1)] LPSHARE_INFO_1 ShareInfo1; * [case(2)] LPSHARE_INFO_2 ShareInfo2; * [case(502)] LPSHARE_INFO_502_I ShareInfo502; * [case(1004)] LPSHARE_INFO_1004 ShareInfo1004; * [case(1006)] LPSHARE_INFO_1006 ShareInfo1006; * [case(1501)] LPSHARE_INFO_1501_I ShareInfo1501; * [default]; * [case(1005)] LPSHARE_INFO_1005 ShareInfo1005; * [case(501)] LPSHARE_INFO_501 ShareInfo501; * [case(503)] LPSHARE_INFO_503_I ShareInfo503; * } SHARE_INFO, *PSHARE_INFO, *LPSHARE_INFO; */ static int srvsvc_SHARE_INFO_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_SHARE_INFO *info = ptr; uint64_t p; p = info->level; if (dcerpc_uint3264_coder(ctx, pdu, iov, offset, &p)) { return -1; } info->level = (uint32_t)p; switch (info->level) { case 1: if (dcerpc_ptr_coder(ctx, pdu, iov, offset, &info->ShareInfo1, PTR_UNIQUE, srvsvc_SHARE_INFO_1_coder)) { return -1; } break; }; return 0; } /****************** * Function: 0x10 * NET_API_STATUS NetrShareGetInfo ( * [in,string,unique] SRVSVC_HANDLE ServerName, * [in,string] WCHAR * NetName, * [in] DWORD Level, * [out, switch_is(Level)] LPSHARE_INFO InfoStruct */ int srvsvc_NetrShareGetInfo_req_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_NetrShareGetInfo_req *req = ptr; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &req->ServerName, PTR_UNIQUE, dcerpc_utf16z_coder)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, discard_const(&req->NetName), PTR_REF, dcerpc_utf16z_coder)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &req->Level)) { return -1; } return 0; } int srvsvc_NetrShareGetInfo_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct srvsvc_NetrShareGetInfo_rep *rep = ptr; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &rep->InfoStruct, PTR_REF, srvsvc_SHARE_INFO_coder)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &rep->status)) { return -1; } return 0; } libsmb2-6.2/lib/smb3-seal.c0000664000175000017500000001076514732155517014530 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2019 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif #ifdef HAVE_SYS__IOVEC_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "portable-endian.h" #include "aes128ccm.h" #include "slist.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" #include "smb3-seal.h" static const char xfer[4] = {0xFD, 'S', 'M', 'B'}; int smb3_encrypt_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_pdu *tmp_pdu; uint32_t spl, u32; int i; uint16_t u16; if (!smb2->seal) { return 0; } if (!pdu->seal) { return 0; } spl = 52; /* transform header */ for (tmp_pdu = pdu; tmp_pdu; tmp_pdu = tmp_pdu->next_compound) { for (i = 0; i < tmp_pdu->out.niov; i++) { spl += (uint32_t)tmp_pdu->out.iov[i].len; } } pdu->crypt = calloc(spl, sizeof(uint8_t)); if (pdu->crypt == NULL) { pdu->seal = 0; return -1; } memcpy(&pdu->crypt[0], xfer, 4); for (i = 20; i < 31; i++) { pdu->crypt[i] = random()&0xff; } u32 = htole32(spl - 52); memcpy(&pdu->crypt[36], &u32, 4); u16 = htole16(SMB_ENCRYPTION_AES128_CCM); memcpy(&pdu->crypt[42], &u16, 2); memcpy(&pdu->crypt[44], &smb2->session_id, 8); spl = 52; /* transform header */ for (tmp_pdu = pdu; tmp_pdu; tmp_pdu = tmp_pdu->next_compound) { for (i = 0; i < tmp_pdu->out.niov; i++) { memcpy(&pdu->crypt[spl], tmp_pdu->out.iov[i].buf, tmp_pdu->out.iov[i].len); spl += (uint32_t)tmp_pdu->out.iov[i].len; } } aes128ccm_encrypt(smb2->serverin_key, &pdu->crypt[20], 11, &pdu->crypt[20], 32, &pdu->crypt[52], spl - 52, &pdu->crypt[4], 16); pdu->crypt_len = spl; return 0; } int smb3_decrypt_pdu(struct smb2_context *smb2) { int rc; if (aes128ccm_decrypt(smb2->serverout_key, &smb2->in.iov[smb2->in.niov - 2].buf[20], 11, &smb2->in.iov[smb2->in.niov - 2].buf[20], 32, &smb2->in.iov[smb2->in.niov - 1].buf[0], smb2->in.iov[smb2->in.niov - 1].len, &smb2->in.iov[smb2->in.niov - 2].buf[4], 16)) { smb2_set_error(smb2, "Failed to decrypt PDU"); return -1; } if (smb2->in.num_done == 0) { smb2->enc = smb2->in.iov[smb2->in.niov - 1].buf; smb2->enc_len = smb2->in.iov[smb2->in.niov - 1].len; smb2->enc_pos = 0; smb2->in.iov[smb2->in.niov - 1].free = NULL; smb2_free_iovector(smb2, &smb2->in); smb2->spl = (uint32_t)smb2->enc_len; smb2->recv_state = SMB2_RECV_HEADER; smb2_add_iovector(smb2, &smb2->in, &smb2->header[0], SMB2_HEADER_SIZE, NULL); } rc = smb2_read_from_buf(smb2); free(smb2->enc); smb2->enc = NULL; return rc; } libsmb2-6.2/lib/sha224-256.c0000664000175000017500000004254614732155517014261 0ustar polpypolpy/*************************** sha224-256.c ***************************/ /********************* See RFC 4634 for details *********************/ /* * Description: * This file implements the Secure Hash Signature Standard * algorithms as defined in the National Institute of Standards * and Technology Federal Information Processing Standards * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 * published on August 1, 2002, and the FIPS PUB 180-2 Change * Notice published on February 28, 2004. * * A combined document showing all algorithms is available at * http://csrc.nist.gov/publications/fips/ * fips180-2/fips180-2withchangenotice.pdf * * The SHA-224 and SHA-256 algorithms produce 224-bit and 256-bit * message digests for a given data stream. It should take about * 2**n steps to find a message with the same digest as a given * message and 2**(n/2) to find any two messages with the same * digest, when n is the digest size in bits. Therefore, this * algorithm can serve as a means of providing a * "fingerprint" for a message. * * Portability Issues: * SHA-224 and SHA-256 are defined in terms of 32-bit "words". * This code uses (included via "sha.h") to define 32 * and 8 bit unsigned integer types. If your C compiler does not * support 32 bit unsigned integers, this code is not * appropriate. * * Caveats: * SHA-224 and SHA-256 are designed to work with messages less * than 2^64 bits long. This implementation uses SHA224/256Input() * to hash the bits that are a multiple of the size of an 8-bit * character, and then uses SHA224/256FinalBits() to hash the * final few bits of the input. */ #include "compat.h" #include "sha.h" #include "sha-private.h" /* Define the SHA shift, rotate left and rotate right macro */ #define SHA256_SHR(bits,word) ((word) >> (bits)) #define SHA256_ROTL(bits,word) \ (((word) << (bits)) | ((word) >> (32-(bits)))) #define SHA256_ROTR(bits,word) \ (((word) >> (bits)) | ((word) << (32-(bits)))) /* Define the SHA SIGMA and sigma macros */ #define SHA256_SIGMA0(word) \ (SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word)) #define SHA256_SIGMA1(word) \ (SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word)) #define SHA256_sigma0(word) \ (SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word)) #define SHA256_sigma1(word) \ (SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word)) /* * add "length" to the length */ #define SHA224_256AddLength(context, length) \ (addTemp = (context)->Length_Low, (context)->Corrupted = \ (((context)->Length_Low += (length)) < addTemp) && \ (++(context)->Length_High == 0) ? 1 : 0) /* Local Function Prototypes */ static void SHA224_256Finalize (SHA256Context * context, uint8_t Pad_Byte); static void SHA224_256PadMessage (SHA256Context * context, uint8_t Pad_Byte); static void SHA224_256ProcessMessageBlock (SHA256Context * context); static int SHA224_256Reset (SHA256Context * context, uint32_t * H0); static int SHA224_256ResultN (SHA256Context * context, uint8_t Message_Digest[], int HashSize); /* Initial Hash Values: FIPS-180-2 section 5.3.2 */ static uint32_t SHA256_H0[SHA256HashSize / 4] = { 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 }; #if defined(USE_SHA224) && USE_SHA224 /* Initial Hash Values: FIPS-180-2 Change Notice 1 */ static uint32_t SHA224_H0[SHA256HashSize / 4] = { 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 }; /* * SHA224Reset * * Description: * This function will initialize the SHA384Context in preparation * for computing a new SHA224 message digest. * * Parameters: * context: [in/out] * The context to reset. * * Returns: * sha Error Code. */ int SHA224Reset (SHA224Context * context) { return SHA224_256Reset (context, SHA224_H0); } /* * SHA224Input * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */ int SHA224Input (SHA224Context * context, const uint8_t * message_array, size_t length) { return SHA256Input (context, message_array, length); } /* * SHA224FinalBits * * Description: * This function will add in any final bits of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_bits: [in] * The final bits of the message, in the upper portion of the * byte. (Use 0b###00000 instead of 0b00000### to input the * three bits ###.) * length: [in] * The number of bits in message_bits, between 1 and 7. * * Returns: * sha Error Code. */ int SHA224FinalBits (SHA224Context * context, const uint8_t message_bits, size_t length) { return SHA256FinalBits (context, message_bits, length); } /* * SHA224Result * * Description: * This function will return the 224-bit message * digest into the Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 28th element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA hash. * Message_Digest: [out] * Where the digest is returned. * * Returns: * sha Error Code. */ int SHA224Result (SHA224Context * context, uint8_t Message_Digest[SHA224HashSize]) { return SHA224_256ResultN (context, Message_Digest, SHA224HashSize); } #endif /* defined(USE_SHA224) && USE_SHA224 */ /* * SHA256Reset * * Description: * This function will initialize the SHA256Context in preparation * for computing a new SHA256 message digest. * * Parameters: * context: [in/out] * The context to reset. * * Returns: * sha Error Code. */ int SHA256Reset (SHA256Context * context) { return SHA224_256Reset (context, SHA256_H0); } /* * SHA256Input * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. */ int SHA256Input (SHA256Context * context, const uint8_t * message_array, size_t length) { uint32_t addTemp; if (!length) return shaSuccess; if (!context || !message_array) return shaNull; if (context->Computed) { context->Corrupted = shaStateError; return shaStateError; } if (context->Corrupted) return context->Corrupted; while (length-- && !context->Corrupted) { context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF); if (!SHA224_256AddLength (context, 8) && (context->Message_Block_Index == SHA256_Message_Block_Size)) SHA224_256ProcessMessageBlock (context); message_array++; } return shaSuccess; } /* * SHA256FinalBits * * Description: * This function will add in any final bits of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_bits: [in] * The final bits of the message, in the upper portion of the * byte. (Use 0b###00000 instead of 0b00000### to input the * three bits ###.) * length: [in] * The number of bits in message_bits, between 1 and 7. * * Returns: * sha Error Code. */ int SHA256FinalBits (SHA256Context * context, const uint8_t message_bits, size_t length) { uint32_t addTemp; uint8_t masks[8] = { /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE }; uint8_t markbit[8] = { /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 }; if (!length) return shaSuccess; if (!context) return shaNull; if ((context->Computed) || (length >= 8) || (length == 0)) { context->Corrupted = shaStateError; return shaStateError; } if (context->Corrupted) return context->Corrupted; SHA224_256AddLength (context, (uint32_t)length); SHA224_256Finalize (context, (uint8_t) ((message_bits & masks[length]) | markbit[length])); return shaSuccess; } /* * SHA256Result * * Description: * This function will return the 256-bit message * digest into the Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 32nd element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA hash. * Message_Digest: [out] * Where the digest is returned. * * Returns: * sha Error Code. */ int SHA256Result (SHA256Context * context, uint8_t Message_Digest[SHA256HashSize]) { return SHA224_256ResultN (context, Message_Digest, SHA256HashSize); } /* * SHA224_256Finalize * * Description: * This helper function finishes off the digest calculations. * * Parameters: * context: [in/out] * The SHA context to update * Pad_Byte: [in] * The last byte to add to the digest before the 0-padding * and length. This will contain the last bits of the message * followed by another single bit. If the message was an * exact multiple of 8-bits long, Pad_Byte will be 0x80. * * Returns: * sha Error Code. */ static void SHA224_256Finalize (SHA256Context * context, uint8_t Pad_Byte) { int i; SHA224_256PadMessage (context, Pad_Byte); /* message may be sensitive, so clear it out */ for (i = 0; i < SHA256_Message_Block_Size; ++i) context->Message_Block[i] = 0; context->Length_Low = 0; /* and clear length */ context->Length_High = 0; context->Computed = 1; } /* * SHA224_256PadMessage * * Description: * According to the standard, the message must be padded to an * even 512 bits. The first padding bit must be a '1'. The * last 64 bits represent the length of the original message. * All bits in between should be 0. This helper function will pad * the message according to those rules by filling the * Message_Block array accordingly. When it returns, it can be * assumed that the message digest has been computed. * * Parameters: * context: [in/out] * The context to pad * Pad_Byte: [in] * The last byte to add to the digest before the 0-padding * and length. This will contain the last bits of the message * followed by another single bit. If the message was an * exact multiple of 8-bits long, Pad_Byte will be 0x80. * * Returns: * Nothing. */ static void SHA224_256PadMessage (SHA256Context * context, uint8_t Pad_Byte) { /* * Check to see if the current message block is too small to hold * the initial padding bits and length. If so, we will pad the * block, process it, and then continue padding into a second * block. */ if (context->Message_Block_Index >= (SHA256_Message_Block_Size - 8)) { context->Message_Block[context->Message_Block_Index++] = Pad_Byte; while (context->Message_Block_Index < SHA256_Message_Block_Size) context->Message_Block[context->Message_Block_Index++] = 0; SHA224_256ProcessMessageBlock (context); } else context->Message_Block[context->Message_Block_Index++] = Pad_Byte; while (context->Message_Block_Index < (SHA256_Message_Block_Size - 8)) context->Message_Block[context->Message_Block_Index++] = 0; /* * Store the message length as the last 8 octets */ context->Message_Block[56] = (uint8_t) (context->Length_High >> 24); context->Message_Block[57] = (uint8_t) (context->Length_High >> 16); context->Message_Block[58] = (uint8_t) (context->Length_High >> 8); context->Message_Block[59] = (uint8_t) (context->Length_High); context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24); context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16); context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8); context->Message_Block[63] = (uint8_t) (context->Length_Low); SHA224_256ProcessMessageBlock (context); } /* * SHA224_256ProcessMessageBlock * * Description: * This function will process the next 512 bits of the message * stored in the Message_Block array. * * Parameters: * context: [in/out] * The SHA context to update * * Returns: * Nothing. * * Comments: * Many of the variable names in this code, especially the * single character names, were used because those were the * names used in the publication. */ static void SHA224_256ProcessMessageBlock (SHA256Context * context) { /* Constants defined in FIPS-180-2, section 4.2.2 */ static const uint32_t K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; int t, t4; /* Loop counter */ uint32_t temp1, temp2; /* Temporary word value */ uint32_t W[64]; /* Word sequence */ uint32_t A, B, C, D, E, F, G, H; /* Word buffers */ /* * Initialize the first 16 words in the array W */ for (t = t4 = 0; t < 16; t++, t4 += 4) W[t] = (((uint32_t) context->Message_Block[t4]) << 24) | (((uint32_t) context->Message_Block[t4 + 1]) << 16) | (((uint32_t) context->Message_Block[t4 + 2]) << 8) | (((uint32_t) context->Message_Block[t4 + 3])); for (t = 16; t < 64; t++) W[t] = SHA256_sigma1 (W[t - 2]) + W[t - 7] + SHA256_sigma0 (W[t - 15]) + W[t - 16]; A = context->Intermediate_Hash[0]; B = context->Intermediate_Hash[1]; C = context->Intermediate_Hash[2]; D = context->Intermediate_Hash[3]; E = context->Intermediate_Hash[4]; F = context->Intermediate_Hash[5]; G = context->Intermediate_Hash[6]; H = context->Intermediate_Hash[7]; for (t = 0; t < 64; t++) { temp1 = H + SHA256_SIGMA1 (E) + SHA_Ch (E, F, G) + K[t] + W[t]; temp2 = SHA256_SIGMA0 (A) + SHA_Maj (A, B, C); H = G; G = F; F = E; E = D + temp1; D = C; C = B; B = A; A = temp1 + temp2; } context->Intermediate_Hash[0] += A; context->Intermediate_Hash[1] += B; context->Intermediate_Hash[2] += C; context->Intermediate_Hash[3] += D; context->Intermediate_Hash[4] += E; context->Intermediate_Hash[5] += F; context->Intermediate_Hash[6] += G; context->Intermediate_Hash[7] += H; context->Message_Block_Index = 0; } /* * SHA224_256Reset * * Description: * This helper function will initialize the SHA256Context in * preparation for computing a new SHA256 message digest. * * Parameters: * context: [in/out] * The context to reset. * H0 * The initial hash value to use. * * Returns: * sha Error Code. */ static int SHA224_256Reset (SHA256Context * context, uint32_t * H0) { if (!context) return shaNull; context->Length_Low = 0; context->Length_High = 0; context->Message_Block_Index = 0; context->Intermediate_Hash[0] = H0[0]; context->Intermediate_Hash[1] = H0[1]; context->Intermediate_Hash[2] = H0[2]; context->Intermediate_Hash[3] = H0[3]; context->Intermediate_Hash[4] = H0[4]; context->Intermediate_Hash[5] = H0[5]; context->Intermediate_Hash[6] = H0[6]; context->Intermediate_Hash[7] = H0[7]; context->Computed = 0; context->Corrupted = 0; return shaSuccess; } /* * SHA224_256ResultN * * Description: * This helper function will return the 224-bit or 256-bit message * digest into the Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 28th/32nd element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA hash. * Message_Digest: [out] * Where the digest is returned. * HashSize: [in] * The size of the hash, either 28 or 32. * * Returns: * sha Error Code. */ static int SHA224_256ResultN (SHA256Context * context, uint8_t Message_Digest[], int HashSize) { int i; if (!context || !Message_Digest) return shaNull; if (context->Corrupted) return context->Corrupted; if (!context->Computed) SHA224_256Finalize (context, 0x80); for (i = 0; i < HashSize; ++i) Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03))); return shaSuccess; } libsmb2-6.2/lib/smb3-seal.h0000664000175000017500000000225014732155517014523 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #ifndef _SMB3_SEAL_H_ #define _SMB3_SEAL_H_ /* Copyright (C) 2019 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef __cplusplus extern "C" { #endif int smb3_encrypt_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb3_decrypt_pdu(struct smb2_context *smb2); #ifdef __cplusplus } #endif #endif /* _SMB3_SEAL_H_ */ libsmb2-6.2/lib/smb2-signing.c0000664000175000017500000001716514732155517015242 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include "compat.h" #include "smb2-signing.h" #define EBC 1 #define CBC 1 #include "aes.h" #include "sha.h" #include "sha-private.h" #define AES128_KEY_LEN 16 #define AES_BLOCK_SIZE 16 static int aes_cmac_shift_left(uint8_t data[AES128_KEY_LEN]) { int i = 0; int cin = 0; int cout = 0; for (i = AES128_KEY_LEN - 1; i >= 0; i--) { cout = ((int) data[i] & 0x80) >> 7; data[i] = (data[i] << 1) | cin; cin = cout; } return cout; } static void aes_cmac_xor( uint8_t data[AES128_KEY_LEN], const uint8_t value[AES128_KEY_LEN] ) { int i = 0; for (i = 0; i < AES128_KEY_LEN; i++) { data[i] ^= value[i]; } } static void aes_cmac_sub_keys( uint8_t key[AES128_KEY_LEN], uint8_t sub_key1[AES128_KEY_LEN], uint8_t sub_key2[AES128_KEY_LEN] ) { uint8_t zero[AES128_KEY_LEN] = {0}; static const uint8_t rb[AES128_KEY_LEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x87}; AES128_ECB_encrypt(zero, key, sub_key1); if (aes_cmac_shift_left(sub_key1)) { aes_cmac_xor(sub_key1, rb); } memcpy(sub_key2, sub_key1, AES128_KEY_LEN); if (aes_cmac_shift_left(sub_key2)) { aes_cmac_xor(sub_key2, rb); } } void smb3_aes_cmac_128(uint8_t key[AES128_KEY_LEN], uint8_t * msg, uint64_t msg_len, uint8_t mac[AES128_KEY_LEN] ) { uint8_t sub_key1[AES128_KEY_LEN] = {0}; uint8_t sub_key2[AES128_KEY_LEN] = {0}; uint8_t scratch[AES128_KEY_LEN] = {0}; uint64_t n = (msg_len + AES128_KEY_LEN - 1) / AES128_KEY_LEN; uint64_t rem = msg_len % AES128_KEY_LEN; uint64_t i = 0; int is_last_block_complete = n != 0 && rem == 0; if (n == 0) { n = 1; } aes_cmac_sub_keys(key, sub_key1, sub_key2); memset(mac, 0, AES128_KEY_LEN); for (i = 0; i < n - 1; i++) { aes_cmac_xor(mac, &msg[i*AES128_KEY_LEN]); AES128_ECB_encrypt(mac, key, scratch); memcpy(mac, scratch, AES128_KEY_LEN); } if (is_last_block_complete) { memcpy(scratch, &msg[i*AES128_KEY_LEN], AES128_KEY_LEN); aes_cmac_xor(scratch, sub_key1); } else { memcpy(scratch, &msg[i*AES128_KEY_LEN], (size_t)rem); scratch[rem] = 0x80; memset(&scratch[rem + 1], 0, AES128_KEY_LEN - ((size_t)rem + 1)); aes_cmac_xor(scratch, sub_key2); } aes_cmac_xor(mac, scratch); AES128_ECB_encrypt(mac, key, scratch); memcpy(mac, scratch, AES128_KEY_LEN); } int smb2_calc_signature(struct smb2_context *smb2, uint8_t *signature, struct smb2_iovec *iov, size_t niov) { /* Clear the smb2 header signature field field */ memset(iov[0].buf + 48, 0, 16); if (smb2->dialect > SMB2_VERSION_0210) { size_t i = 0; size_t len = 0, offset = 0; uint8_t aes_mac[AES_BLOCK_SIZE]; /* combine the buffers into one */ uint8_t *msg = NULL; for (i=0; i < niov; i++) { len += iov[i].len; } msg = (uint8_t *) malloc(len); if (msg == NULL) { smb2_set_error(smb2, "Failed to allocate buffer for " "signature calculation"); return -1; } for (i=0; i < niov; i++) { memcpy(msg + offset, iov[i].buf, iov[i].len); offset += iov[i].len; } smb3_aes_cmac_128(smb2->signing_key, msg, offset, aes_mac); free(msg); memcpy(&signature[0], aes_mac, SMB2_SIGNATURE_SIZE); } else { HMACContext ctx; uint8_t digest[USHAMaxHashSize]; size_t i; hmacReset(&ctx, SHA256, &smb2->signing_key[0], SMB2_KEY_SIZE); for (i=0; i < niov; i++) { hmacInput(&ctx, iov[i].buf, iov[i].len); } hmacResult(&ctx, digest); memcpy(&signature[0], digest, SMB2_SIGNATURE_SIZE); } return 0; } int smb2_pdu_add_signature(struct smb2_context *smb2, struct smb2_pdu *pdu ) { struct smb2_header *hdr = NULL; uint8_t signature[16] = {0}; struct smb2_iovec *iov = NULL; int niov; if (pdu->header.command == SMB2_SESSION_SETUP) { /* the first session setup response with ok status * is the first signed message */ if (pdu->header.status != 0 || !(pdu->header.flags & SMB2_FLAGS_SERVER_TO_REDIR)) { return 0; } } if (pdu->out.niov < 2) { smb2_set_error(smb2, "Too few vectors to sign"); return -1; } if (pdu->out.iov[0].len != SMB2_HEADER_SIZE) { smb2_set_error(smb2, "First vector is not same size as smb2 " "header"); return -1; } if (smb2->session_id == 0) { return 0; /* DO NOT sign the PDU if session id is 0 */ } if (smb2->session_key_size == 0) { return -1; } hdr = &pdu->header; /* Set the flag before calculating signature */ iov = &pdu->out.iov[0]; niov = pdu->out.niov; hdr->flags |= SMB2_FLAGS_SIGNED; smb2_set_uint32(iov, 16, hdr->flags); /* sign the pdu and store the signature in pdu->header.signature * if pdu is signed then add SMB2_FLAGS_SIGNED to pdu->header.flags */ if (smb2_calc_signature(smb2, signature, iov, niov) < 0) { return -1; } memcpy(&(hdr->signature[0]), signature, SMB2_SIGNATURE_SIZE); memcpy(iov->buf + 48, hdr->signature, 16); return 0; } int smb2_pdu_check_signature(struct smb2_context *smb2, struct smb2_pdu *pdu ) { return 0; } libsmb2-6.2/lib/md4.h0000664000175000017500000000274514732155517013432 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #ifndef _MD4_H_ #define _MD4_H_ /* From RFC1320 */ /* MD4.H - header file for MD4C.C */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD4 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ /* MD4 context. */ typedef struct { uint32_t state[4]; /* state (ABCD) */ uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } MD4_CTX; void MD4Init(MD4_CTX *); void MD4Update(MD4_CTX *, unsigned char *, unsigned int); void MD4Final(unsigned char [16], MD4_CTX *); #endif /* _MD4_H_ */ libsmb2-6.2/lib/unicode.c0000664000175000017500000002523014732155517014361 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef STDC_HEADERS #include #endif #include "compat.h" #include "portable-endian.h" #include #include #include "libsmb2-private.h" /* Count number of leading 1 bits in the char */ static int l1(char c) { int i = 0; while (c & 0x80) { i++; c <<= 1; } return i; } /* Validates that utf8 points to a valid utf8 codepoint. * Will update **utf8 to point at the next character in the string. * return 1 if the encoding is valid and requires one UTF-16 code unit, * 2 if the encoding is valid and requires two UTF-16 code units * -1 if it's invalid. * If the encoding is valid the codepoint will be returned in *cp. */ static int validate_utf8_cp(const char **utf8, uint16_t *ret) { int c = *(*utf8)++; int l, l_tmp; uint32_t cp; l = l_tmp = l1(c); switch (l) { case 0: /* 7-bit ascii is always ok */ *ret = c & 0x7f; return 1; case 1: /* 10.. .... can never start a new codepoint */ return -1; case 2: case 3: case 4: cp = c & (0x7f >> l); /* 2, 3 and 4 byte sequences must always be followed by exactly * 1, 2 or 3 chars matching 10.. .... */ while(--l_tmp) { c = *(*utf8)++; if (l1(c) != 1) { return -1; } cp <<= 6; cp |= (c & 0x3f); } /* Check for overlong sequences */ switch (l) { case 2: if (cp < 0x80) return -1; break; case 3: if (cp < 0x800) return -1; break; case 4: if (cp < 0x10000) return -1; break; default: break; } /* Write the code point in either one or two UTC-16 code units */ if (cp < 0xd800 || (cp - 0xe000) < 0x2000) { /* Single UTF-16 code unit */ *ret = cp; return 1; } else if (cp < 0xe000) { /* invalid unicode range */ return -1; } else if (cp < 0x110000) { cp -= 0x10000; *ret = 0xd800 | (cp >> 10); *(ret+1) = 0xdc00 | (cp & 0x3ff) ; return 2; } else { /* invalid unicode range */ return -1; } } return -1; } /* Validate that the given string is properly formatted UTF8. * Returns >=0 if valid UTF8 and -1 if not. */ static int validate_utf8_str(const char *utf8) { const char *u = utf8; int i = 0; int cp_length; uint16_t cp[2]; while (*u) { cp_length = validate_utf8_cp(&u, cp); if (cp_length < 0) { return -1; } i += cp_length; } return i; } /* Convert a UTF8 string into UTF-16LE */ struct smb2_utf16 * smb2_utf8_to_utf16(const char *utf8) { struct smb2_utf16 *utf16; int i, len; len = validate_utf8_str(utf8); if (len < 0) { return NULL; } utf16 = (struct smb2_utf16 *)(malloc(offsetof(struct smb2_utf16, val) + 2 * len)); if (utf16 == NULL) { return NULL; } utf16->len = len; i = 0; while (i < len) { switch(validate_utf8_cp(&utf8, &utf16->val[i])) { case 1: utf16->val[i] = htole16(utf16->val[i]); i += 1; break; case 2: utf16->val[i] = htole16(utf16->val[i]); utf16->val[i+1] = htole16(utf16->val[i+1]); i += 2; break; default: /* Won't happen since we wouldn't have gotten here if the UTF-8 string was invalid */ break; } } return utf16; } static int utf16_size(const uint16_t *utf16, size_t utf16_len) { int length = 0; const uint16_t *utf16_end = utf16 + utf16_len; while (utf16 < utf16_end) { uint32_t code = le16toh(*utf16++); if (code < 0x80) { length += 1; /* One UTF-16 code unit maps to one UTF-8 code unit */ } else if (code < 0x800) { length += 2; /* One UTF-16 code unit maps to two UTF-8 code units */ } else if (code < 0xd800 || code - 0xe000 < 0x2000) { length += 3; } else if (code < 0xdc00) { /* Surrogate pair */ uint32_t trail; if (utf16 == utf16_end) { /* It's possible the stream ends with a leading code unit, which is an error */ return length + 3; /* Replacement char */ } trail = le16toh(*utf16); if (trail - 0xdc00 < 0x400) { /* Check that 0xdc00 <= trail < 0xe000 */ code = 0x10000 + ((code & 0x3ff) << 10) + (trail & 0x3ff); if (code < 0x10000) { length += 3; /* Two UTF-16 code units map to three UTF-8 code units */ } else { length += 4; /* Two UTF-16 code units map to four UTF-8 code units */ } utf16++; } else { /* Invalid trailing code unit. It's still valid on its own though so only the first unit gets replaced */ length += 3; /* Replacement char */ } } else { /* 0xdc00 <= code < 0xe00, which makes code a trailing code unit without a leading one, which is invalid */ length += 3; /* Replacement char */ } } return length; } /* * Convert a UTF-16LE string into UTF8 */ const char * smb2_utf16_to_utf8(const uint16_t *utf16, size_t utf16_len) { int utf8_len = 1; char *str, *tmp; const uint16_t *utf16_end; /* How many bytes do we need for utf8 ? */ utf8_len += utf16_size(utf16, utf16_len); str = tmp = (char*)malloc(utf8_len); if (str == NULL) { return NULL; } str[utf8_len - 1] = 0; utf16_end = utf16 + utf16_len; while (utf16 < utf16_end) { uint32_t code = le16toh(*utf16++); if (code < 0x80) { *tmp++ = code; /* One UTF-16 code unit maps to one UTF-8 code unit */ } else if (code < 0x800) { *tmp++ = 0xc0 | (code >> 6); /* One UTF-16 code unit maps to two UTF-8 code units */ *tmp++ = 0x80 | ((code ) & 0x3f); } else if (code < 0xD800 || code - 0xe000 < 0x2000) { *tmp++ = 0xe0 | (code >> 12); /* All other values where we only have one UTF-16 code unit map to 3 UTF-8 code units */ *tmp++ = 0x80 | ((code >> 6) & 0x3f); *tmp++ = 0x80 | ((code ) & 0x3f); } else if (code < 0xdc00) { /* Surrogate pair */ uint32_t trail; if (utf16 == utf16_end) { /* It's possible the stream ends with a leading code unit, which is an error */ *tmp++ = 0xef; *tmp++ = 0xbf; *tmp++ = 0xbd; /* Replacement char */ return str; } trail = le16toh(*utf16); if (trail - 0xdc00 < 0x400) { /* Check that 0xdc00 <= trail < 0xe000 */ code = 0x10000 + ((code & 0x3ff) << 10) + (trail & 0x3ff); if (code < 0x10000) { *tmp++ = 0xe0 | (code >> 12); *tmp++ = 0x80 | ((code >> 6) & 0x3f); *tmp++ = 0x80 | ((code ) & 0x3f); } else { *tmp++ = 0xF0 | (code >> 18); *tmp++ = 0x80 | ((code >> 12) & 0x3F); *tmp++ = 0x80 | ((code >> 6) & 0x3F); *tmp++ = 0x80 | (code & 0x3F); } utf16++; } else { /* Invalid trailing code unit. It's still valid on its own though so only the first unit gets replaced */ *tmp++ = 0xef; *tmp++ = 0xbf; *tmp++ = 0xbd; /* Replacement char */ } } else { /* 0xdc00 <= code < 0xe00, which makes code a trailing code unit without a leading one, which is invalid */ *tmp++ = 0xef; *tmp++ = 0xbf; *tmp++ = 0xbd; /* Replacement char */ } } return str; } libsmb2-6.2/lib/smb2-data-reparse-point.c0000664000175000017500000000711414732155517017274 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" int smb2_decode_reparse_data_buffer(struct smb2_context *smb2, void *memctx, struct smb2_reparse_data_buffer *rp, struct smb2_iovec *vec) { uint16_t suboffset, sublen, printoffset, printlen; const char *tmp; if (vec->len < 8) { return -1; } smb2_get_uint32(vec, 0, &rp->reparse_tag); smb2_get_uint16(vec, 4, &rp->reparse_data_length); if ((uint16_t)vec->len < rp->reparse_data_length + 8) { return -1; } switch (rp->reparse_tag) { case SMB2_REPARSE_TAG_SYMLINK: if (vec->len < 20) { return -1; } smb2_get_uint32(vec, 16, &rp->symlink.flags); smb2_get_uint16(vec, 8, &suboffset); smb2_get_uint16(vec, 10, &sublen); if (suboffset + sublen + 12 > rp->reparse_data_length) { return -1; } tmp = smb2_utf16_to_utf8((uint16_t *)(&vec->buf[suboffset + 20]), sublen / 2); rp->symlink.subname = smb2_alloc_data(smb2, rp, strlen(tmp) + 1); if (rp->symlink.subname == NULL) { free(discard_const(tmp)); return -1; } strcpy(rp->symlink.subname, tmp); free(discard_const(tmp)); smb2_get_uint16(vec, 12, &printoffset); smb2_get_uint16(vec, 14, &printlen); if (printoffset + printlen + 12 > rp->reparse_data_length) { return -1; } tmp = smb2_utf16_to_utf8((uint16_t *)(&vec->buf[printoffset + 20]), printlen / 2); rp->symlink.printname = smb2_alloc_data(smb2, rp, strlen(tmp) + 1); if (rp->symlink.printname == NULL) { free(discard_const(tmp)); return -1; } strcpy(rp->symlink.printname, tmp); free(discard_const(tmp)); } return 0; } libsmb2-6.2/lib/asn1-ber.c0000664000175000017500000005331014732155517014343 0ustar polpypolpy/* ber_type:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg Copyright (C) 2024 by André Guilherme This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include #include "compat.h" #include "asn1-ber.h" int asn1ber_next_byte(struct asn1ber_context *actx, uint8_t *outb) { if (!actx || !actx->src || actx->src_tail >= actx->src_count) { return -1; } actx->src_tail++; *outb = actx->src[actx->src_tail - 1]; return 0; } int asn1ber_out_byte(struct asn1ber_context *actx, uint8_t inb) { if (!actx || !actx->dst || actx->dst_head >= actx->dst_size) { return -1; } actx->dst[actx->dst_head++] = inb; return 0; } int asn1ber_save_out_state(struct asn1ber_context *actx, int *out_pos) { if (!out_pos || !actx || !actx->dst || actx->dst_head >= actx->dst_size) { return -1; } *out_pos = actx->dst_head; return 0; } int asn1ber_annotate_length(struct asn1ber_context *actx, int out_pos, int reserved) { uint32_t bytes_made; uint32_t lenbytes; int result; if (!actx || !actx->dst || actx->dst_head >= actx->dst_size) { return -1; } /* bytes added since out_pos snap-shot */ bytes_made = actx->dst_head - out_pos; bytes_made -= reserved; actx->dst_head = out_pos; /* encode length in bytes as ber at out pos */ result = asn1ber_ber_from_length(actx, bytes_made, &lenbytes); if (result) { return result; } /* if reserved more than needed, move new contents left over unused reserved */ if (reserved > (int)lenbytes) { memmove(actx->dst + actx->dst_head, actx->dst + out_pos + reserved, bytes_made); } /* restore head to new end */ actx->dst_head+= bytes_made; return 0; } int asn1ber_length_from_ber(struct asn1ber_context *actx, uint32_t *len) { int result; uint8_t b = 0; uint32_t val; result = asn1ber_next_byte(actx, &b); if (result) { return result; } if (b & 0x80) { uint32_t vallen; val = 0; /* length is number of bytes of length, not actual length */ vallen = b & 0x7F; if (vallen > 4) { actx->last_error = -E2BIG; return -1; } while (vallen > 0) { result = asn1ber_next_byte(actx, &b); if (result) { return result; } val <<= 8; val |= (uint32_t)b; vallen--; } } else { /* simple small len */ val = (uint32_t)b; } *len = val; return 0; } int ber_typecode_from_ber(struct asn1ber_context *actx, ber_type_t *typecode) { int result; uint8_t b = 0; result = asn1ber_next_byte(actx, &b); if (result) { return result; } if ((b & 0x1F) != 0x1F) /* not [IMPLICIT] */ { *typecode = b; return 0; } result = asn1ber_next_byte(actx, &b); if (result) { return result; } if (b >= 0x30) { b -= 0x30; } *typecode = (ber_type_t)b; return 0; } int ber_typelen_from_ber(struct asn1ber_context *actx, ber_type_t *typecode, uint32_t *len) { int result; result = ber_typecode_from_ber(actx, typecode); if (result) { return result; } return asn1ber_length_from_ber(actx, len); } int asn1ber_request_from_ber(struct asn1ber_context *actx, ber_type_t *opcode, uint32_t *len) { int result; result = ber_typelen_from_ber(actx, opcode, len); if (result) { return result; } return 0; } int asn1ber_struct_from_ber(struct asn1ber_context *actx, uint32_t *len) { int result; ber_type_t typecode; result = ber_typelen_from_ber(actx, &typecode, len); if (result) { return result; } if (typecode != asnSTRUCT) { actx->last_error = -EINVAL; return -1; } return 0; } int asn1ber_null_from_ber(struct asn1ber_context *actx, uint32_t *len) { int result; ber_type_t typecode; result = ber_typelen_from_ber(actx, &typecode, len); if (result) { return result; } if (typecode != asnNULL) { actx->last_error = -EINVAL; return -1; } return 0; } int asn1ber_int32_from_ber(struct asn1ber_context *actx, int32_t *val) { int result; int ival; uint8_t vallen; uint8_t b = 0; *val = 0; /* TYPE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } switch ((ber_type_t)b) { case BER_INTEGER: case BER_COUNTER: break; default: actx->last_error = -EINVAL; return -1; } /* LENGTH */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } vallen = b; if (vallen > 4) { *val = 0; actx->last_error = -E2BIG; return -1; } if (vallen == 0) { *val = 0; actx->last_error = -E2BIG; return -1; } /* VALUE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } if (b & 0x80) { ival = -1; } else { ival = 0; } ival <<= 8; ival |= (int32_t)(uint32_t)b; vallen--; while (vallen > 0) { result = asn1ber_next_byte(actx, &b); if (result) { return result; } ival <<= 8; ival |= (int32_t)(uint32_t)b; vallen--; } *val = ival; return 0; } int asn1ber_uint32_from_ber(struct asn1ber_context *actx, uint32_t *val) { int result; uint32_t uval; uint8_t vallen; uint8_t b = 0; *val = 0; /* TYPE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } switch ((ber_type_t)b) { case BER_BOOLEAN: case BER_IPADDRESS: case BER_COUNTER: case BER_UNSIGNED: case BER_TIMETICKS: case BER_NSAPADDRESS: case BER_UNSIGNED32: case BER_ENUMERATED: break; default: actx->last_error = -EINVAL; return -1; } /* LENGTH */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } vallen = b; if (vallen > 4) { *val = 0; actx->last_error = -E2BIG; return -1; } if (vallen == 0) { *val = 0; actx->last_error = -E2BIG; return -1; } /* VALUE */ uval = 0; while (vallen > 0) { result = asn1ber_next_byte(actx, &b); if (result) { return result; } uval <<= 8; uval |= (uint32_t)b; vallen--; } *val = uval; return 0; } int asn1ber_int64_from_ber(struct asn1ber_context *actx, int64_t *val) { int result; int64_t ival; uint8_t vallen; uint8_t b = 0; *val = 0; /* TYPE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } switch ((ber_type_t)b) { case BER_INTEGER64: break; default: actx->last_error = -EINVAL; return -1; } /* LENGTH */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } vallen = b; if (vallen > 8) { *val = 0; actx->last_error = -E2BIG; return -1; } if (vallen == 0) { *val = 0; actx->last_error = -E2BIG; return -1; } /* VALUE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } if (b & 0x80) { ival = -1; } else { ival = 0; } ival <<= 8; ival |= (int32_t)(uint32_t)b; vallen--; while (vallen > 0) { result = asn1ber_next_byte(actx, &b); if (result) { return result; } ival <<= 8; ival |= (int64_t)(uint32_t)b; vallen--; } *val = ival; return 0; } int asn1ber_uint64_from_ber(struct asn1ber_context *actx, uint64_t *val) { int result; uint64_t uval; uint8_t vallen; uint8_t b = 0; *val = 0; /* TYPE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } switch ((ber_type_t)b) { case BER_UNSIGNED64: case BER_COUNTER64: break; default: actx->last_error = -EINVAL; return -1; } /* LENGTH */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } vallen = b; if (vallen > 8) { *val = 0; actx->last_error = -E2BIG; return -1; } if (vallen == 0) { *val = 0; actx->last_error = -E2BIG; return -1; } /* VALUE */ uval = 0; while (vallen > 0) { result = asn1ber_next_byte(actx, &b); if (result) { return result; } uval <<= 8; uval |= (uint64_t)b; vallen--; } *val = uval; return 0; } int asn1ber_oid_from_ber(struct asn1ber_context *actx, struct asn1ber_oid_value *oid) { int result; int i; uint16_t oval; uint32_t vallen; uint8_t b = 0; oid->length = 0; /* TYPE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } if ((ber_type_t)b != BER_OBJECT_ID) { actx->last_error = -EINVAL; return -1; } /* LENGTH */ result = asn1ber_length_from_ber(actx, &vallen); if (result) { return result; } if (vallen > BER_MAX_OID_ELEMENTS) { actx->last_error = -E2BIG; return -1; } if (vallen == 0) { actx->last_error = -E2BIG; return -1; } /* VALUE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } /* ** first byte is specially encoded */ oval = (beroid_type_t)b; ((beroid_type_t*)(oid->elements))[0] = oval / 40; ((beroid_type_t*)(oid->elements))[1] = oval - (((beroid_type_t *)(oid->elements))[0] * 40); vallen--; /* ** next bytes are oid types ber encoded */ i = 2; while (vallen > 0 && i < BER_MAX_OID_ELEMENTS) { result = asn1ber_next_byte(actx, &b); if (result) { return result; } oval = (beroid_type_t)(b & 0x7F); while ((b & 0x80) && (vallen > 0)) { result = asn1ber_next_byte(actx, &b); if (result) { return result; } oval <<= 7; oval |= (beroid_type_t)(b & 0x7F); } ((beroid_type_t*)(oid->elements))[i++] = oval; vallen--; } if (vallen != 0) { actx->last_error = -E2BIG; return -1; } oid->length = i; return 0; } int asn1ber_bytes_from_ber(struct asn1ber_context *actx, uint8_t *val, uint32_t maxlen, uint32_t *lenout) { int result; size_t i; uint32_t vallen; uint8_t b = 0; /* TYPE */ result = asn1ber_next_byte(actx, &b); if (result) { return result; } if ((ber_type_t)b != asnOCTET_STRING) { actx->last_error = -EINVAL; return -1; } /* LENGTH */ result = asn1ber_length_from_ber(actx, &vallen); if (result) { return result; } if (vallen > maxlen) { actx->last_error = -E2BIG; return -1; } if (vallen == 0) { *val = 0; *lenout = 0; return 0; } /* VALUE */ for (i = 0; vallen > 0; vallen--) { result = asn1ber_next_byte(actx, &b); if (result) { return result; } val[i++] = b; } /* convenience 0 terminate */ if (i < maxlen) { val[i] = 0; } *lenout = i; return 0; } int asn1ber_string_from_ber(struct asn1ber_context *actx, char *val, uint32_t maxlen, uint32_t *lenout) { return asn1ber_bytes_from_ber(actx, (uint8_t *)val, maxlen, lenout); } int asn1ber_ber_from_length(struct asn1ber_context *actx, uint32_t lenin, uint32_t *lenout) { int result; int outlen = 0; if (lenin < 128) { result = asn1ber_out_byte(actx, (const uint8_t)lenin); if (result) { return result; } outlen++; } else { uint32_t lenbytesneeded; uint32_t lenbytes; for (lenbytesneeded = 0, lenbytes = lenin; lenbytes; lenbytesneeded++) { lenbytes >>= 8; } result = asn1ber_out_byte(actx, (const uint8_t)(0x80 | lenbytesneeded)); if (result) { return result; } outlen++; while (lenbytesneeded > 0) { result = asn1ber_out_byte(actx, (const uint8_t)(lenin >> (8 * (lenbytesneeded - 1)))); if (result) { return result; } lenbytesneeded--; outlen++; } } *lenout = outlen; return 0; } int asn1ber_ber_reserve_length(struct asn1ber_context *actx, uint32_t len) { int result; while (len-- > 0) { result = asn1ber_out_byte(actx, 0); if (result) { return result; } } return 0; } int asn1ber_ber_from_typecode(struct asn1ber_context *actx, const ber_type_t typecode) { return asn1ber_out_byte(actx, (const uint8_t)typecode); } int asn1ber_ber_from_typelen(struct asn1ber_context *actx, const ber_type_t typecode, const uint32_t lenin, uint32_t *lenout) { int result; uint32_t outlen; result = asn1ber_out_byte(actx, (const uint8_t)typecode); if (result) { return result; } result = asn1ber_ber_from_length(actx, lenin, &outlen); if (result) { return result; } *lenout = outlen + 1; return 0; } int asn1ber_ber_from_int32(struct asn1ber_context *actx, const ber_type_t type, const int32_t val) { uint32_t bytesneeded; uint32_t bytes; int result; if (val == 0) { bytesneeded = 1; } else if (val < 0) { for (bytes = (uint32_t)val, bytesneeded = 4; bytes; bytesneeded--) { if ((bytes & 0xFF800000) != 0xFF800000) { break; } } } else { for (bytes = (uint32_t)val, bytesneeded = 4; bytes; bytesneeded--) { if ((bytes & 0xFF000000) != 0) { break; } bytes <<= 8; } } result = asn1ber_ber_from_typelen(actx, type, bytesneeded, &bytes); if (result) { return result; } while (bytesneeded > 0) { result = asn1ber_out_byte(actx, (const uint8_t)(val >> (8 * (bytesneeded - 1)))); if (result) { return result; } bytesneeded--; } return result; } int asn1ber_ber_from_uint32(struct asn1ber_context *actx, const ber_type_t type, const uint32_t val) { uint32_t bytesneeded; uint32_t bytes; int result; for (bytes = val, bytesneeded = 4; bytes; bytesneeded--) { if ((bytes & 0xFF000000) != 0) { break; } bytes <<= 8; } result = asn1ber_ber_from_typelen(actx, type, bytesneeded, &bytes); if (result) { return result; } while (bytesneeded > 0) { result = asn1ber_out_byte(actx, (const uint8_t)(val >> (8 * (bytesneeded - 1)))); if (result) { return result; } bytesneeded--; } return result; } int asn1ber_ber_from_int64(struct asn1ber_context *actx, const ber_type_t type, const int64_t val) { uint32_t bytesneeded; uint32_t bytesout; uint64_t bytes; int result; if (val == 0) { bytesneeded = 1; } else if (val < 0) { for (bytes = (uint64_t)val, bytesneeded = 8; bytes; bytesneeded--) { if ((bytes & 0xFF80000000000000) != 0xFF80000000000000) { break; } } } else { for (bytes = (uint64_t)val, bytesneeded = 8; bytes; bytesneeded--) { if ((bytes & 0xFF00000000000000) != 0) { break; } bytes <<= 8; } } result = asn1ber_ber_from_typelen(actx, type, bytesneeded, &bytesout); if (result) { return result; } while (bytesneeded > 0) { result = asn1ber_out_byte(actx, (const uint8_t)(val >> (8 * (bytesneeded - 1)))); if (result) { return result; } bytesneeded--; } return result; } int asn1ber_ber_from_uint64(struct asn1ber_context *actx, const ber_type_t type, const uint64_t val) { uint32_t bytesneeded; uint32_t bytesout; uint64_t bytes; int result; for (bytes = val, bytesneeded = 4; bytes; bytesneeded--) { if ((bytes & 0xFF00000000000000) != 0) { break; } bytes <<= 8; } result = asn1ber_ber_from_typelen(actx, type, bytesneeded, &bytesout); if (result) { return result; } while (bytesneeded > 0) { result = asn1ber_out_byte(actx, (const uint8_t)(val >> (8 * (bytesneeded - 1)))); if (result) { return result; } bytesneeded--; } return result; } static int asn1ber_ber_from_single_oid(struct asn1ber_context *actx, beroid_type_t oidb) { int result; uint8_t a, b, c, d, e; a = (unsigned char)(oidb & 0x7F); oidb >>= 7; b = (unsigned char)(oidb & 0x7F); oidb >>= 7; c = (unsigned char)(oidb & 0x7F); oidb >>= 7; d = (unsigned char)(oidb & 0x7F); oidb >>= 7; e = (unsigned char)(oidb & 0x7F); if (e) { result = asn1ber_out_byte(actx, (e | 0x80)); if (result) { return result; } } if (d || e) { result = asn1ber_out_byte(actx, (d | 0x80)); if (result) { return result; } } if (c || d || e) { result = asn1ber_out_byte(actx, (c | 0x80)); if (result) { return result; } } if (b || c || d || e) { result = asn1ber_out_byte(actx, (b | 0x80)); if (result) { return result; } } result = asn1ber_out_byte(actx, a); return result; } int asn1ber_ber_from_oid(struct asn1ber_context *actx, const struct asn1ber_oid_value *oid) { int lenpos; int reserve; int oiddex; int result; if (! oid) { actx->last_error = -EINVAL; return 1; } if (oid->length >= BER_MAX_OID_ELEMENTS) { actx->last_error = -E2BIG; return 1; } result = asn1ber_ber_from_typecode(actx, BER_OBJECT_ID); if (result) { return result; } if (BER_MAX_OID_ELEMENTS > 127) { reserve = 5; } else { reserve = 1; } /* save position for back annotating */ asn1ber_save_out_state(actx, &lenpos); /* put in expected length bytes */ result = asn1ber_ber_reserve_length(actx, reserve); if (result) { return result; } if (oid->length > 1) { if (((beroid_type_t*)(oid->elements))[0] < 40) { result = asn1ber_ber_from_single_oid(actx, ((beroid_type_t *)(oid->elements))[0] * 40 + ((beroid_type_t *)(oid->elements))[1]); if (result) { return result; } oiddex = 2; } else { oiddex = 0; } } else { oiddex = 0; } while (oiddex < oid->length) { result = asn1ber_ber_from_single_oid(actx, ((beroid_type_t *)(oid->elements))[oiddex]); if (result) { return result; } oiddex++; } /* back annotate length byte(s) */ result = asn1ber_annotate_length(actx, lenpos, reserve); return result; } int asn1ber_ber_from_bytes(struct asn1ber_context *actx, const ber_type_t type, const uint8_t *val, uint32_t len) { uint32_t outlen; uint32_t outdex; int result; result = asn1ber_ber_from_typelen(actx, type, len, &outlen); if (result) { return result; } for (outdex = 0; outdex < len; outdex++) { result = asn1ber_out_byte(actx, val[outdex]); if (result) { return result; } } return result; } int asn1ber_ber_from_string(struct asn1ber_context *actx, const char *val, uint32_t len) { return asn1ber_ber_from_bytes(actx, BER_OCTET_STRING, (uint8_t*)val, len); } libsmb2-6.2/lib/usha.c0000664000175000017500000001631114732155517013673 0ustar polpypolpy/**************************** usha.c ****************************/ /******************** See RFC 4634 for details ******************/ /* * Description: * This file implements a unified interface to the SHA algorithms. */ #include "compat.h" #include "sha.h" /* * USHAReset * * Description: * This function will initialize the SHA Context in preparation * for computing a new SHA message digest. * * Parameters: * context: [in/out] * The context to reset. * whichSha: [in] * Selects which SHA reset to call * * Returns: * sha Error Code. * */ int USHAReset (USHAContext * ctx, enum SHAversion whichSha) { if (ctx) { ctx->whichSha = whichSha; switch (whichSha) { #if defined(USE_SHA1) && USE_SHA1 case SHA1: return SHA1Reset ((SHA1Context *) & ctx->ctx); #endif #if defined(USE_SHA224) && USE_SHA224 case SHA224: return SHA224Reset ((SHA224Context *) & ctx->ctx); #endif case SHA256: return SHA256Reset ((SHA256Context *) & ctx->ctx); #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 case SHA384: return SHA384Reset ((SHA384Context *) & ctx->ctx); case SHA512: return SHA512Reset ((SHA512Context *) & ctx->ctx); #endif default: return shaBadParam; } } else { return shaNull; } } /* * USHAInput * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */ int USHAInput (USHAContext * ctx, const uint8_t * bytes, size_t bytecount) { if (ctx) { switch (ctx->whichSha) { #if defined(USE_SHA1) && USE_SHA1 case SHA1: return SHA1Input ((SHA1Context *) & ctx->ctx, bytes, bytecount); #endif #if defined(USE_SHA224) && USE_SHA224 case SHA224: return SHA224Input ((SHA224Context *) & ctx->ctx, bytes, bytecount); #endif case SHA256: return SHA256Input ((SHA256Context *) & ctx->ctx, bytes, bytecount); #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 case SHA384: return SHA384Input ((SHA384Context *) & ctx->ctx, bytes, bytecount); case SHA512: return SHA512Input ((SHA512Context *) & ctx->ctx, bytes, bytecount); #endif default: return shaBadParam; } } else { return shaNull; } } /* * USHAFinalBits * * Description: * This function will add in any final bits of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_bits: [in] * The final bits of the message, in the upper portion of the * byte. (Use 0b###00000 instead of 0b00000### to input the * three bits ###.) * length: [in] * The number of bits in message_bits, between 1 and 7. * * Returns: * sha Error Code. */ int USHAFinalBits (USHAContext * ctx, const uint8_t bits, size_t bitcount) { if (ctx) { switch (ctx->whichSha) { #if defined(USE_SHA1) && USE_SHA1 case SHA1: return SHA1FinalBits ((SHA1Context *) & ctx->ctx, bits, bitcount); #endif #if defined(USE_SHA224) && USE_SHA224 case SHA224: return SHA224FinalBits ((SHA224Context *) & ctx->ctx, bits, bitcount); #endif case SHA256: return SHA256FinalBits ((SHA256Context *) & ctx->ctx, bits, bitcount); #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 case SHA384: return SHA384FinalBits ((SHA384Context *) & ctx->ctx, bits, bitcount); case SHA512: return SHA512FinalBits ((SHA512Context *) & ctx->ctx, bits, bitcount); #endif default: return shaBadParam; } } else { return shaNull; } } /* * USHAResult * * Description: * This function will return the 160-bit message digest into the * Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 19th element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA-1 hash. * Message_Digest: [out] * Where the digest is returned. * * Returns: * sha Error Code. * */ int USHAResult (USHAContext * ctx, uint8_t Message_Digest[USHAMaxHashSize]) { if (ctx) { switch (ctx->whichSha) { #if defined(USE_SHA1) && USE_SHA1 case SHA1: return SHA1Result ((SHA1Context *) & ctx->ctx, Message_Digest); #endif #if defined(USE_SHA224) && USE_SHA224 case SHA224: return SHA224Result ((SHA224Context *) & ctx->ctx, Message_Digest); #endif case SHA256: return SHA256Result ((SHA256Context *) & ctx->ctx, Message_Digest); #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 case SHA384: return SHA384Result ((SHA384Context *) & ctx->ctx, Message_Digest); case SHA512: return SHA512Result ((SHA512Context *) & ctx->ctx, Message_Digest); #endif default: return shaBadParam; } } else { return shaNull; } } /* * USHABlockSize * * Description: * This function will return the blocksize for the given SHA * algorithm. * * Parameters: * whichSha: * which SHA algorithm to query * * Returns: * block size * */ int USHABlockSize (enum SHAversion whichSha) { switch (whichSha) { #if defined(USE_SHA1) && USE_SHA1 case SHA1: return SHA1_Message_Block_Size; #endif #if defined(USE_SHA224) && USE_SHA224 case SHA224: return SHA224_Message_Block_Size; #endif case SHA256: return SHA256_Message_Block_Size; #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 case SHA384: return SHA384_Message_Block_Size; case SHA512: return SHA512_Message_Block_Size; #endif default: return SHA512_Message_Block_Size; } } /* * USHAHashSize * * Description: * This function will return the hashsize for the given SHA * algorithm. * * Parameters: * whichSha: * which SHA algorithm to query * * Returns: * hash size * */ int USHAHashSize (enum SHAversion whichSha) { switch (whichSha) { #if defined(USE_SHA1) && USE_SHA1 case SHA1: return SHA1HashSize; #endif #if defined(USE_SHA224) && USE_SHA224 case SHA224: return SHA224HashSize; #endif case SHA256: return SHA256HashSize; #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 case SHA384: return SHA384HashSize; case SHA512: return SHA512HashSize; #endif default: return SHA512HashSize; } } /* * USHAHashSizeBits * * Description: * This function will return the hashsize for the given SHA * algorithm, expressed in bits. * * Parameters: * whichSha: * which SHA algorithm to query * * Returns: * hash size in bits * */ int USHAHashSizeBits (enum SHAversion whichSha) { switch (whichSha) { #if defined(USE_SHA1) && USE_SHA1 case SHA1: return SHA1HashSizeBits; #endif #if defined(USE_SHA224) && USE_SHA224 case SHA224: return SHA224HashSizeBits; #endif case SHA256: return SHA256HashSizeBits; #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 case SHA384: return SHA384HashSizeBits; case SHA512: return SHA512HashSizeBits; #endif default: return SHA512HashSizeBits; } } libsmb2-6.2/lib/Makefile.AMIGA0000664000175000017500000000305614732155517015046 0ustar polpypolpyCC = ppc-amigaos-gcc AR = ppc-amigaos-ar RANLIB = ppc-amigaos-ranlib STRIP = ppc-amigaos-strip OPTIMIZE = -O2 DEBUG = -gstabs WARNINGS = -Wall -Werror -Wwrite-strings INCLUDES = -I. -I../include -I../include/smb2 -I../include/amiga_os DEFINES = -DHAVE_CONFIG_H "-D_U_=__attribute__((unused))" -DHAVE_ADDRINFO -DNEED_POLL -DNEED_GETADDRINFO -DNEED_FREEADDRINFO -DNEED_GETLOGIN_R -DHAVE_LINGER CFLAGS = $(OPTIMIZE) $(DEBUG) $(WARNINGS) $(INCLUDES) $(DEFINES) STRIPFLAGS = -R.comment --strip-unneeded-rel-relocs SRCS = aes.c aes128ccm.c alloc.c dcerpc.c dcerpc-lsa.c dcerpc-srvsvc.c \ errors.c init.c hmac.c hmac-md5.c libsmb2.c md4c.c \ md5.c ntlmssp.c pdu.c sha1.c sha224-256.c sha384-512.c \ smb2-cmd-close.c smb2-cmd-create.c smb2-cmd-echo.c smb2-cmd-error.c \ smb2-cmd-flush.c smb2-cmd-ioctl.c smb2-cmd-logoff.c \ smb2-cmd-negotiate.c smb2-cmd-query-directory.c smb2-cmd-query-info.c \ smb2-cmd-read.c smb2-cmd-session-setup.c smb2-cmd-set-info.c \ smb2-cmd-tree-connect.c smb2-cmd-tree-disconnect.c smb2-cmd-write.c \ smb2-data-file-info.c smb2-data-filesystem-info.c \ smb2-data-security-descriptor.c smb2-data-reparse-point.c \ smb2-share-enum.c smb3-seal.c smb2-signing.c socket.c sync.c \ timestamps.c unicode.c usha.c compat.c OBJS = $(addprefix obj/,$(SRCS:.c=.o)) .PHONY: all all: bin/libsmb2.a obj/%.o: %.c @mkdir -p $(dir $@) $(CC) $(CFLAGS) -c -o $@ $< bin/libsmb2.a: $(OBJS) @mkdir -p $(dir $@) $(AR) -crv $@ $^ $(RANLIB) $@ .PHONY: clean clean: rm -rf bin obj libsmb2-6.2/lib/spnego-wrapper.h0000664000175000017500000000367214732155517015717 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #ifndef SPEGNO_WRAPPER_H #define SPEGNO_WRAPPER_H 1 /* Copyright (C) 2024 by Brian Dodge Copyright (C) 2024 by André Guilherme This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef __cplusplus extern "C" { #endif #define SPNEGO_MECHANISM_KRB5 (0x0001) #define SPNEGO_MECHANISM_NTLMSSP (0x0002) int smb2_spnego_create_negotiate_reply_blob(struct smb2_context *smb2, void **neg_init_token); int smb2_spnego_wrap_gssapi(struct smb2_context *smb2, const uint8_t *ntlmssp_token, const int token_len, void **blob); int smb2_spnego_wrap_ntlmssp_challenge(struct smb2_context *smb2, const uint8_t *ntlmssp_token, const int token_len, void **neg_targ_token); int smb2_spnego_wrap_authenticate_result(struct smb2_context *smb2, const int authorized_ok, void **blob); int smb2_spnego_unwrap_blob(struct smb2_context *smb2, const uint8_t *spnego, const int spnego_len, uint8_t **response_token, uint32_t *mechanisms); #ifdef __cplusplus } #endif #endif /* SPEGNO_WRAPPER_H */ libsmb2-6.2/lib/smb2-cmd-error.c0000664000175000017500000001003414732155517015462 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_error_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_error_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_ERROR_REPLY_SIZE; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate error buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_ERROR_REPLY_SIZE); smb2_set_uint8(iov, 2, rep->error_context_count); smb2_set_uint32(iov, 4, rep->byte_count); /* TODO - handle error data? */ return 0; } struct smb2_pdu * smb2_cmd_error_reply_async(struct smb2_context *smb2, struct smb2_error_reply *rep, uint8_t causing_command, int status, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, causing_command, cb, cb_data); if (pdu == NULL) { return NULL; } pdu->header.status = status; if (smb2_encode_error_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_error_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_error_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_ERROR_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Error " "reply. Expected %d, got %d", SMB2_ERROR_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate error reply"); return -1; } pdu->payload = rep; smb2_get_uint8(iov, 2, &rep->error_context_count); smb2_get_uint32(iov, 4, &rep->byte_count); return rep->byte_count; } int smb2_process_error_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_error_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; rep->error_data = &iov->buf[0]; return 0; } libsmb2-6.2/lib/sync.c0000664000175000017500000005175114732155517013716 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include #ifdef HAVE_SYS_POLL_H #include #endif #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "compat.h" #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" static int wait_for_reply(struct smb2_context *smb2, struct sync_cb_data *cb_data) { time_t t = time(NULL); while (!cb_data->is_finished) { struct pollfd pfd; memset(&pfd, 0, sizeof(struct pollfd)); pfd.fd = smb2_get_fd(smb2); pfd.events = smb2_which_events(smb2); if (poll(&pfd, 1, 1000) < 0) { smb2_set_error(smb2, "Poll failed"); return -1; } if (smb2->timeout) { smb2_timeout_pdus(smb2); } if (!SMB2_VALID_SOCKET(smb2->fd) && ((time(NULL) - t) > (smb2->timeout))) { smb2_set_error(smb2, "Timeout expired and no connection exists\n"); return -1; } if (pfd.revents == 0) { continue; } if (smb2_service(smb2, pfd.revents) < 0) { smb2_set_error(smb2, "smb2_service failed with : " "%s\n", smb2_get_error(smb2)); return -1; } } return 0; } static void connect_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; if (cb_data->status == SMB2_STATUS_CANCELLED) { if (cb_data != &smb2->connect_cb_data) { free(cb_data); } return; } cb_data->is_finished = 1; cb_data->status = status; } /* * Connect to the server and mount the share. */ int smb2_connect_share(struct smb2_context *smb2, const char *server, const char *share, const char *user) { struct sync_cb_data *cb_data; int rc = 0; cb_data = &smb2->connect_cb_data; rc = smb2_connect_share_async(smb2, server, share, user, connect_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: return rc; } /* * Disconnect from share */ int smb2_disconnect_share(struct smb2_context *smb2) { struct sync_cb_data *cb_data; int rc = 0; cb_data = &smb2->connect_cb_data; rc = smb2_disconnect_share_async(smb2, connect_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: return rc; } /* * opendir() */ static void opendir_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; if (status == SMB2_STATUS_SHUTDOWN) { return; } if (cb_data->status == SMB2_STATUS_CANCELLED) { return; } if (status) { cb_data->status = status; } cb_data->is_finished = 1; cb_data->ptr = command_data; } struct smb2dir *smb2_opendir(struct smb2_context *smb2, const char *path) { struct sync_cb_data *cb_data; struct smb2dir *dir; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return NULL; } if (smb2_opendir_async(smb2, path, opendir_cb, cb_data) != 0) { smb2_set_error(smb2, "smb2_opendir_async failed"); free(cb_data); return NULL; } if (wait_for_reply(smb2, cb_data) < 0) { cb_data->status = SMB2_STATUS_CANCELLED; free(cb_data); return NULL; } dir = cb_data->ptr; if (dir) { /* Give ownership of cb_data to dir. It will be freed when dir is freed */ dir->free_cb_data = free; } else { free(cb_data); } return dir; } /* * open() */ static void open_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; if (cb_data->status == SMB2_STATUS_CANCELLED) { free(cb_data); return; } cb_data->is_finished = 1; cb_data->ptr = command_data; } struct smb2fh *smb2_open(struct smb2_context *smb2, const char *path, int flags) { struct sync_cb_data *cb_data; void *ptr; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return NULL; } if (smb2_open_async(smb2, path, flags, open_cb, cb_data) != 0) { smb2_set_error(smb2, "smb2_open_async failed"); free(cb_data); return NULL; } if (wait_for_reply(smb2, cb_data) < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return NULL; } ptr = cb_data->ptr; free(cb_data); return ptr; } /* * close() */ static void close_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { 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; } cb_data->is_finished = 1; cb_data->status = status; } int smb2_close(struct smb2_context *smb2, struct smb2fh *fh) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_close_async(smb2, fh, close_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; goto out; } rc = cb_data->status; out: free(cb_data); return rc; } /* * fsync() */ static void fsync_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; if (cb_data->status == SMB2_STATUS_CANCELLED) { free(cb_data); return; } cb_data->is_finished = 1; cb_data->status = status; } int smb2_fsync(struct smb2_context *smb2, struct smb2fh *fh) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_fsync_async(smb2, fh, fsync_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } /* * pread() */ static void generic_status_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; if (cb_data->status == SMB2_STATUS_CANCELLED) { free(cb_data); return; } cb_data->is_finished = 1; cb_data->status = status; } int smb2_pread(struct smb2_context *smb2, struct smb2fh *fh, uint8_t *buf, uint32_t count, uint64_t offset) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_pread_async(smb2, fh, buf, count, offset, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_pwrite(struct smb2_context *smb2, struct smb2fh *fh, const uint8_t *buf, uint32_t count, uint64_t offset) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_pwrite_async(smb2, fh, buf, count, offset, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_read(struct smb2_context *smb2, struct smb2fh *fh, uint8_t *buf, uint32_t count) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_read_async(smb2, fh, buf, count, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_write(struct smb2_context *smb2, struct smb2fh *fh, const uint8_t *buf, uint32_t count) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_write_async(smb2, fh, buf, count, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_unlink(struct smb2_context *smb2, const char *path) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_unlink_async(smb2, path, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_rmdir(struct smb2_context *smb2, const char *path) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_rmdir_async(smb2, path, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_mkdir(struct smb2_context *smb2, const char *path) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_mkdir_async(smb2, path, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_fstat(struct smb2_context *smb2, struct smb2fh *fh, struct smb2_stat_64 *st) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_fstat_async(smb2, fh, st, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_stat(struct smb2_context *smb2, const char *path, struct smb2_stat_64 *st) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_stat_async(smb2, path, st, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_rename(struct smb2_context *smb2, const char *oldpath, const char *newpath) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_rename_async(smb2, oldpath, newpath, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_statvfs(struct smb2_context *smb2, const char *path, struct smb2_statvfs *st) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_statvfs_async(smb2, path, st, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_truncate(struct smb2_context *smb2, const char *path, uint64_t length) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_truncate_async(smb2, path, length, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } int smb2_ftruncate(struct smb2_context *smb2, struct smb2fh *fh, uint64_t length) { struct sync_cb_data *cb_data; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_ftruncate_async(smb2, fh, length, generic_status_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } struct readlink_cb_data { char *buf; int len; }; static void readlink_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; struct readlink_cb_data *rl_data = cb_data->ptr; if (cb_data->status == SMB2_STATUS_CANCELLED) { free(cb_data); return; } cb_data->is_finished = 1; cb_data->status = status; strncpy(rl_data->buf, command_data, rl_data->len); } int smb2_readlink(struct smb2_context *smb2, const char *path, char *buf, uint32_t len) { struct sync_cb_data *cb_data; struct readlink_cb_data rl_data _U_; int rc = 0; cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rl_data.buf = buf; rl_data.len = len; cb_data->ptr = &rl_data; rc = smb2_readlink_async(smb2, path, readlink_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } static void echo_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct sync_cb_data *cb_data = private_data; if (cb_data->status == SMB2_STATUS_CANCELLED) { free(cb_data); return; } cb_data->is_finished = 1; cb_data->status = status; } /* * Send SMB2_ECHO command to the server */ int smb2_echo(struct smb2_context *smb2) { struct sync_cb_data *cb_data; int rc = 0; if (SMB2_VALID_SOCKET(smb2->fd)) { smb2_set_error(smb2, "Not Connected to Server"); return -ENOMEM; } cb_data = calloc(1, sizeof(struct sync_cb_data)); if (cb_data == NULL) { smb2_set_error(smb2, "Failed to allocate sync_cb_data"); return -ENOMEM; } rc = smb2_echo_async(smb2, echo_cb, cb_data); if (rc < 0) { goto out; } rc = wait_for_reply(smb2, cb_data); if (rc < 0) { cb_data->status = SMB2_STATUS_CANCELLED; return rc; } rc = cb_data->status; out: free(cb_data); return rc; } libsmb2-6.2/lib/libsmb2.syms0000664000175000017500000000540314732155517015036 0ustar polpypolpycompound_file_id dcerpc_allocate_pdu dcerpc_call_async dcerpc_connect_context_async dcerpc_context_handle_coder dcerpc_create_context dcerpc_destroy_context dcerpc_do_coder dcerpc_free_data dcerpc_free_pdu dcerpc_get_error dcerpc_set_endian dcerpc_set_tctx dcerpc_get_cr dcerpc_ptr_coder dcerpc_utf16_coder dcerpc_utf16z_coder nterror_to_str nterror_to_errno smb2_add_compound_pdu smb2_close smb2_close_async smb2_closedir smb2_close_context smb2_cmd_close_async smb2_cmd_create_async smb2_cmd_echo_async smb2_cmd_logoff_async smb2_cmd_negotiate_async smb2_cmd_query_directory_async smb2_cmd_query_info_async smb2_cmd_session_setup_async smb2_cmd_set_info_async smb2_cmd_tree_connect_async smb2_cmd_tree_disconnect_async smb2_connect_async smb2_connect_share smb2_connect_share_async smb2_connect_tree_id smb2_context_active smb2_decode_fileidfulldirectoryinformation smb2_destroy_context smb2_destroy_url smb2_disconnect_share smb2_disconnect_share_async smb2_disconnect_tree_id smb2_fd_event_callbacks smb2_fh_from_file_id smb2_free_data smb2_free_pdu smb2_fstat smb2_fstat_async smb2_fsync smb2_fsync_async smb2_ftruncate smb2_ftruncate_async smb2_get_client_guid smb2_get_dialect smb2_get_error smb2_get_fd smb2_get_fds smb2_get_file_id smb2_get_tree_id_for_pdu smb2_get_max_read_size smb2_get_max_write_size smb2_get_opaque smb2_get_passthrough smb2_init_context smb2_mkdir smb2_mkdir_async smb2_share_enum_async smb2_open smb2_open_async smb2_opendir smb2_opendir_async smb2_parse_url smb2_pdu_is_compound smb2_pread smb2_pread_async smb2_pwrite smb2_pwrite_async smb2_queue_pdu smb2_read smb2_read_async smb2_readdir smb2_register_error_callback smb2_rewinddir smb2_readlink smb2_readlink_async smb2_rmdir smb2_rmdir_async smb2_lseek smb2_seekdir smb2_select_tree_id smb2_serve_port smb2_service smb2_service_fd smb2_set_authentication smb2_set_security_mode smb2_set_version smb2_set_user smb2_set_passthrough smb2_set_password smb2_set_password_from_file smb2_set_domain smb2_set_error smb2_set_tree_id_for_pdu smb2_set_workstation smb2_set_opaque smb2_set_seal smb2_set_sign smb2_set_timeout smb2_stat smb2_stat_async smb2_statvfs smb2_statvfs_async smb2_telldir smb2_timeval_to_win smb2_truncate smb2_truncate_async smb2_rename smb2_rename_async smb2_unlink smb2_unlink_async smb2_utf8_to_utf16 smb2_utf16_to_utf8 smb2_which_events smb2_win_to_timeval smb2_write smb2_write_async smb2_echo smb2_echo_async srvsvc_interface srvsvc_NetrShareEnum_rep_coder srvsvc_NetrShareEnum_req_coder srvsvc_NetrShareGetInfo_rep_coder srvsvc_NetrShareGetInfo_req_coder srvsvc_SHARE_INFO_1_coder srvsvc_SHARE_INFO_1_CONTAINER_coder NT_SID_AUTHORITY lsa_interface lsa_Close_rep_coder lsa_Close_req_coder lsa_LookupSids2_rep_coder lsa_LookupSids2_req_coder lsa_OpenPolicy2_rep_coder lsa_OpenPolicy2_req_coder lsa_RPC_SID_coder libsmb2-6.2/lib/md5.c0000664000175000017500000001663414732155517013430 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. * * Changed so as no longer to depend on Colin Plumb's `usual.h' header * definitions; now uses stuff from dpkg's config.h. * - Ian Jackson . * Still in the public domain. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_SYS_TYPES_H #include #endif #include "compat.h" #include "md5.h" #ifdef WORDS_BIGENDIAN void byteSwap(UWORD32 *buf, unsigned words) { md5byte *p = (md5byte *)buf; do { *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]); p += 4; } while (--words); } #else #define byteSwap(buf,words) #endif /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bytes[0] = 0; ctx->bytes[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) { UWORD32 t; /* Update byte count */ t = ctx->bytes[0]; if ((ctx->bytes[0] = t + len) < t) ctx->bytes[1]++; /* Carry from low to high */ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ if (t > len) { memcpy((md5byte *)ctx->in + 64 - t, buf, len); return; } /* First chunk is an odd size */ memcpy((md5byte *)ctx->in + 64 - t, buf, t); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += t; len -= t; /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(md5byte digest[16], struct MD5Context *ctx) { int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ md5byte *p = (md5byte *)ctx->in + count; /* Set the first char of padding to 0x80. There is always room. */ *p++ = 0x80; /* Bytes of padding needed to make 56 bytes (-8..55) */ count = 56 - 1 - count; if (count < 0) { /* Padding forces an extra block */ memset(p, 0, count + 8); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); p = (md5byte *)ctx->in; count = 56; } memset(p, 0, count); byteSwap(ctx->in, 14); /* Append length in bits and transform */ ctx->in[14] = ctx->bytes[0] << 3; ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; MD5Transform(ctx->buf, ctx->in); byteSwap(ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } #ifndef ASM_MD5 /* The four core functions - F1 is optimized somewhat */ #if 0 #define F1(x, y, z) (x & y | ~x & z) #else #define F1(x, y, z) (z ^ (x & (y ^ z))) #endif #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f,w,x,y,z,in,s) \ (w += f(x,y,z) + in, w = (w<>(32-s)) + x) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { register UWORD32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } #endif libsmb2-6.2/lib/Makefile.PS3_PPU0000664000175000017500000000573314732155517015365 0ustar polpypolpy#--------------------------------------------------------------------------------- # Clear the implicit built in rules #--------------------------------------------------------------------------------- .SUFFIXES: #--------------------------------------------------------------------------------- ifeq ($(strip $(PSL1GHT)),) $(error "Please set PSL1GHT in your environment. export PSL1GHT=") endif include $(PSL1GHT)/ppu_rules #--------------------------------------------------------------------------------- ifeq ($(strip $(PLATFORM)),) #--------------------------------------------------------------------------------- export BASEDIR := $(CURDIR) export DEPS := $(BASEDIR)/deps export LIBS := $(BASEDIR)/lib #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LIBDIR := $(LIBS)/$(PLATFORM) export DEPSDIR := $(DEPS)/$(PLATFORM) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- TARGET := libsmb2 BUILD := build SOURCE := ../lib INCLUDE := ../include ../include/ps3 ../include/smb2 DATA := data LIBS := MACHDEP := -DPS3_PPU_PLATFORM -DHAVE_CONFIG_H -DNEED_READV -DNEED_WRITEV -DNEED_GETLOGIN_R -DNEED_RANDOM -DNEED_SRANDOM -DNEED_GETADDRINFO -DNEED_FREEADDRINFO -D_U_=/**/ CFLAGS += -O2 -Wall -mcpu=cell $(MACHDEP) -fno-strict-aliasing $(INCLUDES) LD := ppu-ld ifneq ($(BUILD),$(notdir $(CURDIR))) export OUTPUT := $(CURDIR)/$(TARGET) export VPATH := $(foreach dir,$(SOURCE),$(CURDIR)/$(dir)) \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) export BUILDDIR := $(CURDIR)/$(BUILD) export DEPSDIR := $(BUILDDIR) CFILES := $(foreach dir,$(SOURCE),$(notdir $(wildcard $(dir)/*.c))) CXXFILES := $(foreach dir,$(SOURCE),$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCE),$(notdir $(wildcard $(dir)/*.S))) BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.bin))) export OFILES := $(CFILES:.c=.o) \ $(CXXFILES:.cpp=.o) \ $(SFILES:.S=.o) \ $(BINFILES:.bin=.bin.o) export BINFILES := $(BINFILES:.bin=.bin.h) export INCLUDES = $(foreach dir,$(INCLUDE),-I$(CURDIR)/$(dir)) \ -I$(CURDIR)/$(BUILD) -I$(PSL1GHT)/ppu/include -I$(PORTLIBS)/include .PHONY: $(BUILD) install clean shader $(BUILD): @[ -d $@ ] || mkdir -p $@ @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.PS3_PPU install: $(BUILD) ifeq ($(PORTLIBS),) @echo "$PORTLIBS is not set. Can not install libsmb2." @exit 1 endif @echo Copying... @[ -d $(PORTLIBS)/include/smb2 ] || mkdir -p $(PORTLIBS)/include/smb2 @cp -frv ../include/smb2/*.h $(PORTLIBS)/include/smb2 @cp -frv *.a $(PORTLIBS)/lib @echo Done! clean: @echo Clean... @rm -rf $(BUILD) $(OUTPUT).elf $(OUTPUT).self $(OUTPUT).a else DEPENDS := $(OFILES:.o=.d) $(OUTPUT).a: $(OFILES) $(OFILES): $(BINFILES) $(VCGFILES) $(VSAFILES) -include $(DEPENDS) endif libsmb2-6.2/lib/socket.c0000664000175000017500000014007714732155517014232 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif #ifdef HAVE_SYS__IOVEC_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_SYS_FCNTL_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include "compat.h" #include "slist.h" #include "smb2.h" #include "libsmb2.h" #include "smb3-seal.h" #include "libsmb2-private.h" #include "portable-endian.h" #include #define MAX_URL_SIZE 1024 /* Timeout in ms between 2 consecutive socket connection. * The rfc8305 recommends a timeout of 250ms and a minimum timeout of 100ms. * Since the smb is most likely used on local network, use an aggressive * timeout of 100ms. */ #define HAPPY_EYEBALLS_TIMEOUT 100 #if !defined(HAVE_LINGER) struct linger { int l_onoff; /* Linger active */ int l_linger; /* How long to linger for */ }; #endif static int smb2_connect_async_next_addr(struct smb2_context *smb2, const struct addrinfo *base); void smb2_close_connecting_fds(struct smb2_context *smb2) { size_t i; for (i = 0; i < smb2->connecting_fds_count; ++i) { t_socket fd = smb2->connecting_fds[i]; /* Don't close the connected fd */ if (fd == smb2->fd || !SMB2_VALID_SOCKET(fd)) continue; if (smb2->change_fd) { smb2->change_fd(smb2, fd, SMB2_DEL_FD); } close(fd); } free(smb2->connecting_fds); smb2->connecting_fds = NULL; smb2->connecting_fds_count = 0; if (smb2->addrinfos != NULL) { freeaddrinfo(smb2->addrinfos); smb2->addrinfos = NULL; } smb2->next_addrinfo = NULL; } static int smb2_get_credit_charge(struct smb2_context *smb2, struct smb2_pdu *pdu) { int credits = 0; while (pdu) { credits += pdu->header.credit_charge; pdu = pdu->next_compound; } return credits; } int smb2_which_events(struct smb2_context *smb2) { int events = SMB2_VALID_SOCKET(smb2->fd) ? POLLIN : POLLOUT; if (smb2->outqueue != NULL && smb2_get_credit_charge(smb2, smb2->outqueue) <= smb2->credits) { events |= POLLOUT; } return events; } t_socket smb2_get_fd(struct smb2_context *smb2) { if (SMB2_VALID_SOCKET(smb2->fd)) { return smb2->fd; } else if (smb2->connecting_fds_count > 0) { return smb2->connecting_fds[0]; } else { return -1; } } const t_socket * smb2_get_fds(struct smb2_context *smb2, size_t *fd_count, int *timeout) { if (SMB2_VALID_SOCKET(smb2->fd)) { *fd_count = 1; *timeout = -1; return &smb2->fd; } else { *fd_count = smb2->connecting_fds_count; *timeout = smb2->next_addrinfo != NULL ? HAPPY_EYEBALLS_TIMEOUT : -1; return smb2->connecting_fds; } } static int smb2_write_to_socket(struct smb2_context *smb2) { struct smb2_pdu *pdu; if (!SMB2_VALID_SOCKET(smb2->fd)) { smb2_set_error(smb2, "trying to write but not connected"); return -1; } while ((pdu = smb2->outqueue) != NULL) { struct iovec iov[SMB2_MAX_VECTORS] _U_; struct iovec *tmpiov; struct smb2_pdu *tmp_pdu; size_t num_done = pdu->out.num_done; int i, niov = 1; ssize_t count; uint32_t spl = 0, tmp_spl, credit_charge = 0; for (tmp_pdu = pdu; tmp_pdu; tmp_pdu = tmp_pdu->next_compound) { credit_charge += pdu->header.credit_charge; } if (smb2->dialect > SMB2_VERSION_0202) { if (credit_charge > (uint32_t)smb2->credits) { return 0; } } if (pdu->seal) { niov = 2; spl = pdu->crypt_len; iov[1].iov_base = pdu->crypt; iov[1].iov_len = pdu->crypt_len; } else { /* Copy all the vectors from all PDUs in the * compound set. */ for (tmp_pdu = pdu; tmp_pdu; tmp_pdu = tmp_pdu->next_compound) { for (i = 0; i < tmp_pdu->out.niov; i++, niov++) { iov[niov].iov_base = tmp_pdu->out.iov[i].buf; #if defined(_WIN32) || defined(_XBOX) iov[niov].iov_len = (unsigned long)tmp_pdu->out.iov[i].len; #else iov[niov].iov_len = (size_t)tmp_pdu->out.iov[i].len; #endif spl += (uint32_t)tmp_pdu->out.iov[i].len; } } } /* Add the SPL vector as the first vector */ tmp_spl = htobe32(spl); iov[0].iov_base = &tmp_spl; iov[0].iov_len = SMB2_SPL_SIZE; tmpiov = iov; /* Skip the vectors we have already written */ while (num_done >= tmpiov->iov_len) { num_done -= tmpiov->iov_len; tmpiov++; niov--; } /* Adjust the first vector to send */ tmpiov->iov_base = (char *)tmpiov->iov_base + num_done; #if defined(_WIN32) || defined(_XBOX) tmpiov->iov_len -= (unsigned long)num_done; #else tmpiov->iov_len -= (size_t)num_done; #endif count = writev(smb2->fd, tmpiov, niov); if (count == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return 0; } smb2_set_error(smb2, "Error when writing to " "socket :%d %s", errno, smb2_get_error(smb2)); return -1; } pdu->out.num_done += (size_t)count; if (pdu->out.num_done == SMB2_SPL_SIZE + spl) { SMB2_LIST_REMOVE(&smb2->outqueue, pdu); smb2_change_events(smb2, smb2->fd, smb2_which_events(smb2)); while (pdu) { tmp_pdu = pdu->next_compound; /* As we have now sent all the PDUs we * can remove the chaining. * On the receive side we will treat all * PDUs as individual PDUs. */ pdu->next_compound = NULL; smb2->credits -= pdu->header.credit_charge; if (!smb2_is_server(smb2)) { /* queue requests we send to correlate replies with */ SMB2_LIST_ADD_END(&smb2->waitqueue, pdu); } else { smb2->credits += pdu->header.credit_request_response; /* no longer need this reply we've sent */ smb2_free_pdu(smb2, pdu); } pdu = tmp_pdu; } } } return 0; } typedef ssize_t (*read_func)(struct smb2_context *smb2, const struct iovec *iov, int iovcnt); static int smb2_read_data(struct smb2_context *smb2, read_func func, int has_xfrmhdr) { struct iovec iov[SMB2_MAX_VECTORS] _U_; struct iovec *tmpiov; int i, niov, is_chained; size_t num_done; size_t iov_offset = 0; static char smb3tfrm[4] = {0xFD, 'S', 'M', 'B'}; struct smb2_pdu *pdu = smb2->pdu; ssize_t count; int len; read_more_data: num_done = smb2->in.num_done; /* Copy all the current vectors to our work vector */ niov = smb2->in.niov; for (i = 0; i < niov; i++) { iov[i].iov_base = smb2->in.iov[i].buf; #if defined(_WIN32) || defined(_XBOX) iov[i].iov_len = (unsigned long)smb2->in.iov[i].len; #else iov[i].iov_len = (size_t)smb2->in.iov[i].len; #endif } tmpiov = iov; /* Skip the vectors we have already read */ while (num_done >= tmpiov->iov_len) { num_done -= tmpiov->iov_len; tmpiov++; niov--; } /* Adjust the first vector to read */ tmpiov->iov_base = (char *)tmpiov->iov_base + num_done; #if defined(_WIN32) || defined(_XBOX) tmpiov->iov_len -= (unsigned long)num_done; #else tmpiov->iov_len -= (size_t)num_done; #endif /* Read into our trimmed iovectors */ count = func(smb2, tmpiov, niov); if (count < 0) { #if defined(_WIN32) || defined(_XBOX) int err = WSAGetLastError(); if (err == WSAEINTR || err == WSAEWOULDBLOCK) { #else int err = errno; if (err == EINTR || err == EAGAIN || err == EWOULDBLOCK) { #endif return 0; } smb2_set_error(smb2, "Read from socket failed, " "errno:%d. Closing socket.", err); return -1; } if (count == 0) { /* remote side has closed the socket. */ smb2_set_error(smb2, "Read from socket failed, " "remote closed connection."); return -1; } smb2->in.num_done += (size_t)count; if (smb2->in.num_done < smb2->in.total_size) { goto read_more_data; } /* At this point we have all the data we need for the current phase */ switch (smb2->recv_state) { case SMB2_RECV_SPL: smb2->spl = be32toh(smb2->spl); smb2->recv_state = SMB2_RECV_HEADER; smb2_add_iovector(smb2, &smb2->in, &smb2->header[0], SMB2_HEADER_SIZE, NULL); goto read_more_data; case SMB2_RECV_HEADER: if (!memcmp(smb2->in.iov[smb2->in.niov - 1].buf, smb3tfrm, 4)) { smb2->in.iov[smb2->in.niov - 1].len = 52; len = smb2->spl - 52; smb2->in.total_size -= 12; smb2_add_iovector(smb2, &smb2->in, malloc(len), len, free); memcpy(smb2->in.iov[smb2->in.niov - 1].buf, &smb2->in.iov[smb2->in.niov - 2].buf[52], 12); smb2->recv_state = SMB2_RECV_TRFM; goto read_more_data; } if (smb2_decode_header(smb2, &smb2->in.iov[smb2->in.niov - 1], &smb2->hdr) != 0) { smb2_set_error(smb2, "Failed to decode smb2 " "header: %s", smb2_get_error(smb2)); return -1; } /* if serving, and this is an smb1 negotiate, just short-circuit and flush * any remaining data on input and call the callback */ if (smb2_is_server(smb2) && smb2->hdr.command == SMB1_NEGOTIATE) { uint8_t flusher[32]; struct iovec fiov; fiov.iov_base = (char *)flusher; fiov.iov_len = sizeof(flusher); do { count = func(smb2, &fiov, 1); if (count < 0) { #if defined(_WIN32) || defined(_XBOX) int err = WSAGetLastError(); if (err == WSAEINTR || err == WSAEWOULDBLOCK) { #else int err = errno; if (err == EINTR || err == EAGAIN || err == EWOULDBLOCK) { #endif count = 0; } } } while (count > 0); /* put on wait queue so queue_pdu doesn't complain */ SMB2_LIST_ADD_END(&smb2->waitqueue, pdu); smb2->in.num_done = 0; pdu->cb(smb2, smb2->hdr.status, pdu->payload, pdu->cb_data); smb2->pdu = NULL; smb2->pdu = smb2->next_pdu; smb2->next_pdu = NULL; return 0; } /* Record the offset for the start of payload data. */ smb2->payload_offset = smb2->in.num_done; if (!smb2_is_server(smb2)) { smb2->credits += smb2->hdr.credit_request_response; } if (!smb2_is_server(smb2) && !(smb2->hdr.flags & SMB2_FLAGS_SERVER_TO_REDIR)) { smb2_set_error(smb2, "received non-reply"); return -1; } else if (smb2_is_server(smb2) && (smb2->hdr.flags & SMB2_FLAGS_SERVER_TO_REDIR)) { smb2_set_error(smb2, "received non-request"); return -1; } if (smb2->hdr.status == SMB2_STATUS_PENDING) { /* Pending. Just treat the rest of the data as * padding then check for and skip processing below. * We will eventually receive a proper reply for this * request sometime later. */ len = smb2->spl - smb2->in.num_done; /* If we don't have a transform header we are reading * straight from the socket, and not a buffer, * so we need to take the SPL size into account. */ if (!has_xfrmhdr) { len += SMB2_SPL_SIZE; } /* Add padding before the next PDU */ smb2->recv_state = SMB2_RECV_PAD; smb2_add_iovector(smb2, &smb2->in, malloc(len), len, free); goto read_more_data; } if (smb2_is_server(smb2)) { pdu = smb2->pdu; if (!pdu) { smb2_set_error(smb2, "no pdu for request"); return -ENOMEM; } /* set the pdu header's message id to the request's id and * the tree id to the request's tree id */ pdu->header.message_id = smb2->hdr.message_id; if (!(smb2->hdr.flags & SMB2_FLAGS_ASYNC_COMMAND)) { pdu->header.sync.tree_id = smb2->hdr.sync.tree_id; } /* if the session is properly opened then we could get * any request from the client, so use the headers command * not the pdus command for the rest of input */ if (pdu->header.command > SMB2_SESSION_SETUP) { pdu->header.command = smb2->hdr.command; } } else { if (smb2->hdr.command != SMB2_OPLOCK_BREAK) { if (smb2->pdu) { smb2_free_pdu(smb2, smb2->pdu); smb2->pdu = NULL; } pdu = smb2->pdu = smb2_find_pdu(smb2, smb2->hdr.message_id); if (pdu == NULL) { smb2_set_error(smb2, "no matching PDU found"); return -1; } SMB2_LIST_REMOVE(&smb2->waitqueue, pdu); } else { /* oplock and lease break notifications won't have a pdu */ pdu = smb2->pdu; if (!pdu) { pdu = smb2->pdu = smb2_allocate_pdu(smb2, SMB2_OPLOCK_BREAK, smb2_oplock_break_notify, NULL); } if (pdu == NULL) { smb2_set_error(smb2, "can not alloc pdu"); return -1; } } } len = smb2_get_fixed_size(smb2, pdu); if (((int)len) < 0) { smb2_set_error(smb2, "can not determine fixed size"); return -1; } smb2->recv_state = SMB2_RECV_FIXED; smb2_add_iovector(smb2, &smb2->in, malloc(len & 0xfffe), len & 0xfffe, free); goto read_more_data; case SMB2_RECV_FIXED: len = smb2_process_payload_fixed(smb2, pdu); if (len < 0) { smb2_set_error(smb2, "Failed to parse fixed part of " "command payload. %s", smb2_get_error(smb2)); return -1; } /* Add application provided iovectors */ if (len) { for (i = 0; i < pdu->in.niov; i++) { size_t num = pdu->in.iov[i].len; if (num > (size_t)len) { num = (size_t)len; } smb2_add_iovector(smb2, &smb2->in, pdu->in.iov[i].buf, num, NULL); len -= num; if (len == 0) { smb2->recv_state = SMB2_RECV_VARIABLE; goto read_more_data; } } if (len > 0) { smb2->recv_state = SMB2_RECV_VARIABLE; smb2_add_iovector(smb2, &smb2->in, malloc(len), len, free); goto read_more_data; } } /* Check for padding */ if (smb2->hdr.next_command) { len = smb2->hdr.next_command - (SMB2_HEADER_SIZE + smb2->in.num_done - smb2->payload_offset); } else { len = smb2->spl + SMB2_SPL_SIZE - smb2->in.num_done; /* * We never read the SPL when handling decrypted * payloads. */ if (smb2->enc) { len -= SMB2_SPL_SIZE; } } if (len < 0) { smb2_set_error(smb2, "Negative number of PAD bytes " "encountered during PDU decode of" "fixed payload"); return -1; } if (len > 0) { /* Add padding before the next PDU */ smb2->recv_state = SMB2_RECV_PAD; smb2_add_iovector(smb2, &smb2->in, malloc(len), len, free); goto read_more_data; } /* If len == 0 it means there is no padding and we are finished * reading this PDU */ break; case SMB2_RECV_VARIABLE: if (smb2_process_payload_variable(smb2, pdu) < 0) { smb2_set_error(smb2, "Failed to parse variable part of " "command payload. %s", smb2_get_error(smb2)); return -1; } /* Check for padding */ if (smb2->hdr.next_command) { len = smb2->hdr.next_command - (SMB2_HEADER_SIZE + smb2->in.num_done - smb2->payload_offset); } else { len = smb2->spl + SMB2_SPL_SIZE - smb2->in.num_done; /* * We never read the SPL when handling decrypted * payloads. */ if (smb2->enc) { len -= SMB2_SPL_SIZE; } } if (len < 0) { smb2_set_error(smb2, "Negative number of PAD bytes " "encountered during PDU decode of" "variable payload"); return -1; } if (len > 0) { /* Add padding before the next PDU */ smb2->recv_state = SMB2_RECV_PAD; smb2_add_iovector(smb2, &smb2->in, malloc(len), len, free); goto read_more_data; } /* If len == 0 it means there is no padding and we are finished * reading this PDU */ break; case SMB2_RECV_PAD: /* We are finished reading all the data and padding for this * PDU. Break out of the switch and invoke the callback. */ break; case SMB2_RECV_TRFM: /* We are finished reading the full payload for the * encrypted packet. */ smb2->in.num_done = 0; if (smb3_decrypt_pdu(smb2)) { smb2_set_error(smb2, "Failed to decrypyt pdu"); return -1; } /* We are all done now with this PDU. Reset num_done to 0 * and restart with a new SPL for the next chain. */ return 0; } if (smb2->in.niov < 2) { smb2_set_error(smb2, "Too few io vectors in received PDU."); return -1; } if (smb2->hdr.status == SMB2_STATUS_PENDING) { /* This was a pending command. Just ignore it and proceed * to read the next chain. */ if (smb2->passthrough) { pdu = smb2_find_pdu(smb2, smb2->hdr.message_id); if (pdu == NULL) { smb2_set_error(smb2, "no matching PDU found"); return -1; } else { /* need to pass all pdus through note we do not free * the pdu or delist the request */ pdu->cb(smb2, smb2->hdr.status, pdu->payload, pdu->cb_data); } } smb2->in.num_done = 0; return 0; } /* We don't yet have the signing key until later, once session * setup has completed, so we can not yet verify the signature * of the final leg of session setup. */ if (smb2->sign && (smb2->hdr.flags & SMB2_FLAGS_SIGNED) && (smb2->hdr.command != SMB2_SESSION_SETUP) ) { uint8_t signature[16] _U_; memcpy(&signature[0], &smb2->in.iov[1 + iov_offset].buf[48], 16); if (smb2_calc_signature(smb2, &smb2->in.iov[1 + iov_offset].buf[48], &smb2->in.iov[1 + iov_offset], smb2->in.niov - 1 - iov_offset) < 0) { smb2_set_error(smb2, "Signature calc failed."); return -1; } if (memcmp(&signature[0], &smb2->in.iov[1 + iov_offset].buf[48], 16)) { smb2_set_error(smb2, "Wrong signature in received " "PDU"); return -1; } } is_chained = smb2->hdr.next_command; if (smb2_is_server(smb2)) { /* queue requests to correlate our replies we send back later */ SMB2_LIST_ADD_END(&smb2->waitqueue, pdu); pdu->cb(smb2, smb2->hdr.status, pdu->payload, pdu->cb_data); smb2->pdu = smb2->next_pdu; smb2->next_pdu = NULL; } else { pdu->cb(smb2, smb2->hdr.status, pdu->payload, pdu->cb_data); smb2_free_pdu(smb2, pdu); smb2->pdu = NULL; } if (is_chained) { /* Record at which iov we ended in this loop so we know where to start in the next */ iov_offset = smb2->in.niov - 1; smb2->recv_state = SMB2_RECV_HEADER; smb2_add_iovector(smb2, &smb2->in, &smb2->header[0], SMB2_HEADER_SIZE, NULL); goto read_more_data; } /* We are all done now with this chain. Reset num_done to 0 * and restart with a new SPL for the next chain. */ smb2->in.num_done = 0; return 0; } static ssize_t smb2_readv_from_socket(struct smb2_context *smb2, const struct iovec *iov, int iovcnt) { ssize_t rc = readv(smb2->fd, (struct iovec*) iov, iovcnt); return rc; } static int smb2_read_from_socket(struct smb2_context *smb2) { /* initialize the input vectors to the spl and the header * which are both static data in the smb2 context. * additional vectors will be added when we can map this to * the corresponding pdu. */ if (smb2->in.num_done == 0) { smb2->recv_state = SMB2_RECV_SPL; smb2->spl = 0; smb2_free_iovector(smb2, &smb2->in); smb2_add_iovector(smb2, &smb2->in, (uint8_t *)&smb2->spl, SMB2_SPL_SIZE, NULL); } return smb2_read_data(smb2, smb2_readv_from_socket, 0); } static ssize_t smb2_readv_from_buf(struct smb2_context *smb2, const struct iovec *iov, int iovcnt) { size_t i, len; ssize_t count = 0; for (i=0;(int)i smb2->enc_len - smb2->enc_pos) { len = smb2->enc_len - smb2->enc_pos; } memcpy(iov[i].iov_base, &smb2->enc[smb2->enc_pos], len); smb2->enc_pos += (int)len; count += len; } return count; } int smb2_read_from_buf(struct smb2_context *smb2) { return smb2_read_data(smb2, smb2_readv_from_buf, 1); } static void smb2_close_connecting_fd(struct smb2_context *smb2, t_socket fd) { size_t i; close(fd); /* Remove the fd from the connecting_fds array */ for (i = 0; i < smb2->connecting_fds_count; ++i) { if (fd == smb2->connecting_fds[i]) { memmove(&smb2->connecting_fds[i], &smb2->connecting_fds[i + 1], smb2->connecting_fds_count - i - 1); smb2->connecting_fds_count--; return; } } } int smb2_service_fd(struct smb2_context *smb2, t_socket fd, int revents) { int ret = 0; if (!SMB2_VALID_SOCKET(fd)) { /* Connect to a new addr in parallel */ if (smb2->next_addrinfo != NULL) { int err = smb2_connect_async_next_addr(smb2, smb2->next_addrinfo); return err == 0 ? 0 : -1; } goto out; } else if (fd != smb2->fd) { int fd_found = 0; size_t i; for (i = 0; i < smb2->connecting_fds_count; ++i) { if (fd == smb2->connecting_fds[i]) { fd_found = 1; break; } } if (fd_found == 0) { /* Not an error, this can happen if more than one * connecting fds had POLLOUT events. In that case, * only the first one is connected and all other FDs * are dropped. */ return 0; } } if (revents & POLLERR) { int err = 0; socklen_t err_size = sizeof(err); if (!SMB2_VALID_SOCKET(smb2->fd) && smb2->next_addrinfo != NULL) { /* Connecting fd failed, try to connect to the next addr */ smb2_close_connecting_fd(smb2, fd); err = smb2_connect_async_next_addr(smb2, smb2->next_addrinfo); /* error already set by connect_async_ai() */ if (err == 0) { return 0; } } else if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &err_size) != 0 || err != 0) { if (err == 0) { err = errno; } smb2_set_error(smb2, "smb2_service: socket error " "%s(%d).", strerror(err), err); } else { smb2_set_error(smb2, "smb2_service: POLLERR, " "Unknown socket error."); } if (smb2->connect_cb) { smb2->connect_cb(smb2, err, NULL, smb2->connect_data); smb2->connect_cb = NULL; } ret = -1; goto out; } if (revents & POLLHUP) { smb2_set_error(smb2, "smb2_service: POLLHUP, " "socket error."); ret = -1; goto out; } if (!SMB2_VALID_SOCKET(smb2->fd) && revents & POLLOUT) { int err = 0; socklen_t err_size = sizeof(err); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &err_size) != 0 || err != 0) { if (err == 0) { err = errno; } if (smb2->next_addrinfo != NULL) { /* Connecting fd failed, try to connect to the next addr */ smb2_close_connecting_fd(smb2, fd); err = smb2_connect_async_next_addr(smb2, smb2->next_addrinfo); /* error already set by connect_async_ai() */ if (err == 0) { return 0; } } else { smb2_set_error(smb2, "smb2_service: socket error " "%s(%d) while connecting.", strerror(err), err); } if (smb2->connect_cb) { smb2->connect_cb(smb2, err, NULL, smb2->connect_data); smb2->connect_cb = NULL; } ret = -1; goto out; } smb2->fd = fd; smb2_close_connecting_fds(smb2); smb2_change_events(smb2, smb2->fd, smb2_which_events(smb2)); if (smb2->connect_cb) { smb2->connect_cb(smb2, 0, NULL, smb2->connect_data); smb2->connect_cb = NULL; } goto out; } if (revents & POLLIN) { if (smb2_read_from_socket(smb2) != 0) { ret = -1; goto out; } } if (revents & POLLOUT && smb2->outqueue != NULL) { if (smb2_write_to_socket(smb2) != 0) { ret = -1; goto out; } } out: if (smb2->timeout) { smb2_timeout_pdus(smb2); } return ret; } int smb2_service(struct smb2_context *smb2, int revents) { if (smb2->connecting_fds_count > 0) { return smb2_service_fd(smb2, smb2->connecting_fds[0], revents); } else { return smb2_service_fd(smb2, smb2->fd, revents); } } static void set_nonblocking(t_socket fd) { #if defined(WIN32) || defined(_XBOX) unsigned long opt = 1; ioctlsocket(fd, FIONBIO, &opt); #elif (defined(__AMIGA__) || defined(__AROS__)) && !defined(__amigaos4__) && !defined(__amigaos3__) unsigned long opt = 0; IoctlSocket(fd, FIONBIO, (char *)&opt); #else unsigned v; v = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, v | O_NONBLOCK); #endif } static int set_tcp_sockopt(t_socket sockfd, int optname, int value) { int level; #if !defined(SOL_TCP) struct protoent *buf; if ((buf = getprotobyname("tcp")) != NULL) { level = buf->p_proto; } else { return -1; } #else level = SOL_TCP; #endif return setsockopt(sockfd, level, optname, (char *)&value, sizeof(value)); } static int connect_async_ai(struct smb2_context *smb2, const struct addrinfo *ai, int *fd_out) { int family; t_socket fd; socklen_t socksize; struct sockaddr_storage ss; #if 0 == CONFIGURE_OPTION_TCP_LINGER int const yes = 1; struct linger const lin = { 1, 0 }; /* if l_linger is zero, sends RST after FIN */ #endif #ifdef _XBOX BOOL bBroadcast = TRUE; #endif memset(&ss, 0, sizeof(ss)); switch (ai->ai_family) { case AF_INET: socksize = sizeof(struct sockaddr_in); memcpy(&ss, ai->ai_addr, socksize); #ifdef HAVE_SOCK_SIN_LEN ((struct sockaddr_in *)&ss)->sin_len = socksize; #endif break; #ifdef AF_INET6 case AF_INET6: #if !defined(PICO_PLATFORM) || defined(LWIP_INETV6) socksize = sizeof(struct sockaddr_in6); memcpy(&ss, ai->ai_addr, socksize); #ifdef HAVE_SOCK_SIN_LEN ((struct sockaddr_in6 *)&ss)->sin6_len = socksize; #endif #endif break; #endif default: smb2_set_error(smb2, "Unknown address family :%d. " "Only IPv4/IPv6 supported so far.", ai->ai_family); return -EINVAL; } family = ai->ai_family; fd = socket(family, SOCK_STREAM, 0); if (!SMB2_VALID_SOCKET(fd)) { smb2_set_error(smb2, "Failed to open smb2 socket. " "Errno:%s(%d).", strerror(errno), errno); return -EIO; } #ifdef _XBOX if(setsockopt(fd, SOL_SOCKET, 0x5801, (PCSTR)&bBroadcast, sizeof(BOOL) ) != 0 ) { #if 0 return 0; #endif } if(setsockopt(fd, SOL_SOCKET, 0x5802, (PCSTR)&bBroadcast, sizeof(BOOL)) != 0) { #if 0 return 0; #endif } #endif set_nonblocking(fd); set_tcp_sockopt(fd, TCP_NODELAY, 1); #if 0 == CONFIGURE_OPTION_TCP_LINGER setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*)&yes, sizeof yes); setsockopt(fd, SOL_SOCKET, SO_LINGER, (const void*)&lin, sizeof lin); #endif if (connect(fd, (struct sockaddr *)&ss, socksize) != 0 #ifndef _MSC_VER && errno != EINPROGRESS) { #else && WSAGetLastError() != WSAEWOULDBLOCK) { #endif smb2_set_error(smb2, "Connect failed with errno : " "%s(%d)", strerror(errno), errno); close(fd); return -EIO; } *fd_out = (int)fd; return 0; } static int smb2_connect_async_next_addr(struct smb2_context *smb2, const struct addrinfo *base) { int err = -1; const struct addrinfo *ai; for (ai = base; ai != NULL; ai = ai->ai_next) { int fd; err = connect_async_ai(smb2, ai, &fd); if (err == 0) { /* clear the error that could be set by a previous ai * connection */ smb2_set_error(smb2, ""); smb2->connecting_fds[smb2->connecting_fds_count++] = fd; if (smb2->change_fd) { smb2->change_fd(smb2, fd, SMB2_ADD_FD); smb2_change_events(smb2, fd, POLLOUT); } smb2->next_addrinfo = ai->ai_next; break; } } return err; } /* Copied from FFmpeg: libavformat/network.c */ static void interleave_addrinfo(struct addrinfo *base) { struct addrinfo **next = &base->ai_next; while (*next) { struct addrinfo *cur = *next; /* Iterate forward until we find an entry of a different family. */ if (cur->ai_family == base->ai_family) { next = &cur->ai_next; continue; } if (cur == base->ai_next) { /* ** If the first one following base is of a different family, just ** move base forward one step and continue. */ base = cur; next = &base->ai_next; continue; } /* Unchain cur from the rest of the list from its current spot. */ *next = cur->ai_next; /* Hook in cur directly after base. */ cur->ai_next = base->ai_next; base->ai_next = cur; /* ** Restart with a new base. We know that before moving the cur element, ** everything between the previous base and cur had the same family, ** different from cur->ai_family. Therefore, we can keep next pointing ** where it was, and continue from there with base at the one after ** cur. */ base = cur->ai_next; } } int smb2_connect_async(struct smb2_context *smb2, const char *server, smb2_command_cb cb, void *private_data) { char *addr, *host, *port; int err; size_t addr_count = 0; const struct addrinfo *ai; if (SMB2_VALID_SOCKET(smb2->fd)) { smb2_set_error(smb2, "Trying to connect but already " "connected."); return -EINVAL; } addr = strdup(server); if (addr == NULL) { smb2_set_error(smb2, "Out-of-memory: " "Failed to strdup server address."); return -ENOMEM; } host = addr; port = host; /* ipv6 in [...] form ? */ if (host[0] == '[') { char *str; host++; str = strchr(host, ']'); if (str == NULL) { free(addr); smb2_set_error(smb2, "Invalid address:%s " "Missing ']' in IPv6 address", server); return -EINVAL; } *str = 0; port = str + 1; } port = strchr(port, ':'); if (port != NULL) { *port++ = 0; } else { port = (char*)"445"; } /* is it a hostname ? */ err = getaddrinfo(host, port, NULL, &smb2->addrinfos); if (err != 0) { free(addr); #if defined(_WINDOWS) || defined(_XBOX) if (err == WSANOTINITIALISED) { smb2_set_error(smb2, "Winsock was not initialized. " "Please call WSAStartup()."); return -WSANOTINITIALISED; } else #endif { smb2_set_error(smb2, "Invalid address:%s " "Can not resolve into IPv4/v6.", server); } switch (err) { case EAI_AGAIN: return -EAGAIN; case EAI_NONAME: #ifdef EAI_NODATA #if EAI_NODATA != EAI_NONAME /* Equal in MSVC */ case EAI_NODATA: #endif #endif case EAI_SERVICE: case EAI_FAIL: #ifdef EAI_ADDRFAMILY /* Not available in MSVC */ case EAI_ADDRFAMILY: #endif return -EIO; case EAI_MEMORY: return -ENOMEM; #ifdef EAI_SYSTEM /* Not available in MSVC */ case EAI_SYSTEM: return -errno; #endif default: return -EINVAL; } } free(addr); interleave_addrinfo(smb2->addrinfos); /* Allocate connecting fds array */ for (ai = smb2->addrinfos; ai != NULL; ai = ai->ai_next) addr_count++; smb2->connecting_fds = malloc(sizeof(t_socket) * addr_count); if (smb2->connecting_fds == NULL) { freeaddrinfo(smb2->addrinfos); smb2->addrinfos = NULL; return -ENOMEM; } err = smb2_connect_async_next_addr(smb2, smb2->addrinfos); if (err == 0) { smb2->connect_cb = cb; smb2->connect_data = private_data; } else { free(smb2->connecting_fds); smb2->connecting_fds = NULL; freeaddrinfo(smb2->addrinfos); smb2->addrinfos = NULL; smb2->next_addrinfo = NULL; } return err; } int smb2_bind_and_listen(const uint16_t port, const int max_connections, int *out_fd) { t_socket fd; socklen_t socksize; struct sockaddr_in serv_addr; *out_fd = -1; fd = socket(AF_INET, SOCK_STREAM, 0); if (!SMB2_VALID_SOCKET(fd)) { return -EIO; } set_nonblocking(fd); set_tcp_sockopt(fd, TCP_NODELAY, 1); serv_addr.sin_port = htons(port); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; socksize = sizeof(serv_addr); if (bind(fd, (struct sockaddr *)&serv_addr, socksize) != 0 #ifndef _MSC_VER && errno != EINPROGRESS) { #else && WSAGetLastError() != WSAEWOULDBLOCK) { #endif close(fd); return -EIO; } if (listen(fd, max_connections) != 0) { close(fd); return -EIO; } *out_fd = (int)fd; return 0; } int smb2_accept_connection_async(const int fd, const int to_msec, smb2_accepted_cb cb, void *cb_data) { int err = -1; struct sockaddr_in client_addr; socklen_t socklen; t_socket clientfd; struct pollfd pfd; #if 0 == CONFIGURE_OPTION_TCP_LINGER int const yes = 1; struct linger const lin = { 1, 0 }; /* if l_linger is zero, sends RST after FIN */ #endif if (!SMB2_VALID_SOCKET(fd)) { return -EINVAL; } memset(&pfd, 0, sizeof(struct pollfd)); pfd.fd = fd; pfd.events = POLLIN; err = poll(&pfd, 1, to_msec); if (err > 0) { socklen = sizeof(client_addr); clientfd = accept(fd, (struct sockaddr *)&client_addr, &socklen); if (clientfd >= 0) { set_nonblocking(clientfd); set_tcp_sockopt(clientfd, TCP_NODELAY, 1); #if 0 == CONFIGURE_OPTION_TCP_LINGER setsockopt(clientfd, SOL_SOCKET, SO_REUSEADDR, (const void*)&yes, sizeof yes); setsockopt(clientfd, SOL_SOCKET, SO_LINGER, (const void*)&lin, sizeof lin); #endif err = cb(clientfd, cb_data); } else { err = -EIO; } } return err; } void smb2_change_events(struct smb2_context *smb2, t_socket fd, int events) { if (smb2->events == events) { return; } if (smb2->change_events) { smb2->change_events(smb2, fd, events); smb2->events = events; } } libsmb2-6.2/lib/smb2-cmd-ioctl.c0000664000175000017500000003376714732155517015465 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_ioctl_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_ioctl_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_IOCTL_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate ioctl buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_IOCTL_REQUEST_SIZE); smb2_set_uint32(iov, 4, req->ctl_code); memcpy(iov->buf + 8, req->file_id, SMB2_FD_SIZE); smb2_set_uint32(iov, 24, SMB2_HEADER_SIZE + (SMB2_IOCTL_REQUEST_SIZE & 0xfffffffe)); smb2_set_uint32(iov, 28, req->input_count); smb2_set_uint32(iov, 32, 0); /* Max input response */ smb2_set_uint32(iov, 44, 65535); /* Max output response */ smb2_set_uint32(iov, 48, req->flags); if (req->input_count) { iov = smb2_add_iovector(smb2, &pdu->out, req->input, req->input_count, NULL); } return 0; } struct smb2_pdu * smb2_cmd_ioctl_async(struct smb2_context *smb2, struct smb2_ioctl_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_IOCTL, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_ioctl_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_ioctl_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_ioctl_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov, *ioctlv; len = SMB2_IOCTL_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate ioctl reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); ioctlv = NULL; if (rep->output_count) { switch (rep->ctl_code) { case SMB2_FSCTL_VALIDATE_NEGOTIATE_INFO: /* even when passthrough is set we transcode this one */ len = SMB2_IOCTL_VALIDIATE_NEGOTIATE_INFO_SIZE; break; default: if (smb2->passthrough) { /* assume the replys output is already coded */ len = rep->output_count; } else { smb2_set_error(smb2, "No handling of code %d", rep->ctl_code); len = 0; return -1; } break; } buf = malloc(PAD_TO_64BIT(len)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate ioctl output"); return -1; } memset(buf, 0, rep->output_count); ioctlv = smb2_add_iovector(smb2, &pdu->out, buf, len, free); switch (rep->ctl_code) { case SMB2_FSCTL_VALIDATE_NEGOTIATE_INFO: { struct smb2_ioctl_validate_negotiate_info *info = (struct smb2_ioctl_validate_negotiate_info *) rep->output; smb2_set_uint32(ioctlv, 0, info->capabilities); memcpy(&ioctlv->buf[4], info->guid, 16); smb2_set_uint16(ioctlv, 20, info->security_mode); smb2_set_uint16(ioctlv, 22, info->dialect); break; } default: if (smb2->passthrough) { memcpy(buf, rep->output, rep->output_count); ioctlv->len = rep->output_count; } else { /* this is already checked above */ return -1; } break; } } smb2_set_uint16(iov, 0, SMB2_IOCTL_REPLY_SIZE); smb2_set_uint32(iov, 4, rep->ctl_code); memcpy(iov->buf + 8, rep->file_id, SMB2_FD_SIZE); smb2_set_uint32(iov, 24, SMB2_HEADER_SIZE + (SMB2_IOCTL_REPLY_SIZE & 0xfffffffe)); smb2_set_uint32(iov, 28, rep->input_count); smb2_set_uint32(iov, 32, SMB2_HEADER_SIZE + (SMB2_IOCTL_REPLY_SIZE & 0xfffffffe) + PAD_TO_64BIT(rep->input_count)); smb2_set_uint32(iov, 36, len); smb2_set_uint32(iov, 40, rep->flags); return 0; } struct smb2_pdu * smb2_cmd_ioctl_reply_async(struct smb2_context *smb2, struct smb2_ioctl_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_IOCTL, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_ioctl_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } #define IOV_OFFSET (rep->output_offset - SMB2_HEADER_SIZE - \ (SMB2_IOCTL_REPLY_SIZE & 0xfffe)) int smb2_process_ioctl_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_ioctl_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_IOCTL_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Ioctl " "reply. Expected %d, got %d", SMB2_IOCTL_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate ioctl reply"); return -1; } pdu->payload = rep; smb2_get_uint32(iov, 4, &rep->ctl_code); memcpy(rep->file_id, iov->buf + 8, SMB2_FD_SIZE); smb2_get_uint32(iov, 32, &rep->output_offset); smb2_get_uint32(iov, 36, &rep->output_count); smb2_get_uint32(iov, 40, &rep->flags); if (rep->output_count == 0) { return 0; } if (rep->output_offset < SMB2_HEADER_SIZE + (SMB2_IOCTL_REPLY_SIZE & 0xfffe)) { smb2_set_error(smb2, "Output buffer overlaps with " "Ioctl reply header"); pdu->payload = NULL; free(rep); return -1; } /* Return the amount of data that the output buffer will take up. * Including any padding before the output buffer itself. */ return IOV_OFFSET + rep->output_count; } int smb2_process_ioctl_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_ioctl_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; struct smb2_iovec vec; void *ptr; if (rep->output_count > iov->len - IOV_OFFSET) { return -EINVAL; } vec.buf = &iov->buf[IOV_OFFSET]; vec.len = iov->len - IOV_OFFSET; switch (rep->ctl_code) { case SMB2_FSCTL_GET_REPARSE_POINT: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_reparse_data_buffer)); if (smb2_decode_reparse_data_buffer(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode reparse " "data buffer. %s", smb2_get_error(smb2)); return -1; } break; default: ptr = smb2_alloc_init(smb2, rep->output_count); if (ptr == NULL) { return -ENOMEM; } memcpy(ptr, &iov->buf[IOV_OFFSET], iov->len - IOV_OFFSET); } rep->output = ptr; return 0; } #define IOVREQ_OFFSET (req->input_offset - SMB2_HEADER_SIZE - \ (SMB2_IOCTL_REQUEST_SIZE & 0xfffe)) int smb2_process_ioctl_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_ioctl_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_IOCTL_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Ioctl " "request. Expected %d, got %d", SMB2_IOCTL_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate ioctl request"); return -1; } pdu->payload = req; smb2_get_uint32(iov, 4, &req->ctl_code); memcpy(req->file_id, iov->buf + 8, SMB2_FD_SIZE); smb2_get_uint32(iov, 24, &req->input_offset); smb2_get_uint32(iov, 28, &req->input_count); smb2_get_uint32(iov, 32, &req->max_input_response); smb2_get_uint32(iov, 40, &req->output_offset); smb2_get_uint32(iov, 44, &req->output_count); smb2_get_uint32(iov, 48, &req->max_output_response); smb2_get_uint32(iov, 52, &req->flags); if (req->input_count == 0) { return 0; } if (req->input_offset < SMB2_HEADER_SIZE + (SMB2_IOCTL_REQUEST_SIZE & 0xfffe)) { smb2_set_error(smb2, "Output buffer overlaps with " "Ioctl request header"); pdu->payload = NULL; free(req); return -1; } /* Return the amount of data that the input buffer will take up. * Including any padding before the input buffer itself. */ return IOVREQ_OFFSET + req->input_count; } int smb2_process_ioctl_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_ioctl_request *req = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; struct smb2_iovec vec; void *ptr = NULL; struct smb2_ioctl_validate_negotiate_info *info; /* this one is handled locally regardless of proxy or not */ ptr = smb2_alloc_init(smb2, sizeof(struct smb2_ioctl_validate_negotiate_info)); info = ptr; if (req->input_count > iov->len - IOVREQ_OFFSET) { return -EINVAL; } vec.buf = &iov->buf[IOVREQ_OFFSET]; vec.len = iov->len - IOVREQ_OFFSET; switch (req->ctl_code) { case SMB2_FSCTL_VALIDATE_NEGOTIATE_INFO: smb2_get_uint32(&vec, 0, &info->capabilities); memcpy(info->guid, &vec.buf[4], 16); smb2_get_uint16(&vec, 20, &info->security_mode); smb2_get_uint16(&vec, 22, &info->dialect); req->input_count = sizeof(struct smb2_ioctl_validate_negotiate_info); break; default: if (smb2->passthrough) { /* dont know how to handle this, let user decode it */ ptr = vec.buf; req->input_count = vec.len; } else { smb2_set_error(smb2, "No handling for ioctl req %x", req->ctl_code); } break; } req->input = ptr; return 0; } libsmb2-6.2/lib/Makefile.AMIGA_OS30000664000175000017500000000370514732155517015533 0ustar polpypolpyCC = m68k-amigaos-gcc AR = m68k-amigaos-ar RANLIB = m68k-amigaos-ranlib STRIP = m68k-amigaos-strip OPTIMIZE = -O2 -noixemul -fno-common -fomit-frame-pointer DEBUG = -g WARNINGS = -Wall -Wno-pointer-sign -Wno-discarded-qualifiers -Werror INCLUDES = -I. -I../include -I../include/smb2 -I../include/amiga_os DEFINES = -DHAVE_CONFIG_H "-D_U_=__attribute__((unused))" -DNEED_POLL -DNEED_GETADDRINFO -DNEED_FREEADDRINFO -DNEED_GETLOGIN_R -DHAVE_LINGER -DHAVE_ADDRINFO -D__amigaos3__ CFLAGS = $(OPTIMIZE) $(DEBUG) $(WARNINGS) $(INCLUDES) $(DEFINES) STRIPFLAGS = -R.comment SRCS = aes.c aes128ccm.c alloc.c dcerpc.c dcerpc-lsa.c dcerpc-srvsvc.c \ errors.c init.c hmac.c hmac-md5.c libsmb2.c md4c.c \ md5.c ntlmssp.c pdu.c sha1.c sha224-256.c sha384-512.c \ smb2-cmd-close.c smb2-cmd-create.c smb2-cmd-echo.c smb2-cmd-error.c \ smb2-cmd-flush.c smb2-cmd-ioctl.c smb2-cmd-logoff.c \ smb2-cmd-negotiate.c smb2-cmd-query-directory.c smb2-cmd-query-info.c \ smb2-cmd-read.c smb2-cmd-session-setup.c smb2-cmd-set-info.c \ smb2-cmd-tree-connect.c smb2-cmd-tree-disconnect.c smb2-cmd-write.c \ smb2-data-file-info.c smb2-data-filesystem-info.c \ smb2-data-security-descriptor.c smb2-data-reparse-point.c \ smb2-share-enum.c smb3-seal.c smb2-signing.c socket.c sync.c \ timestamps.c unicode.c usha.c compat.c ARCH_000 = -mcpu=68000 -mtune=68000 OBJS_000 = $(addprefix obj/68000/,$(SRCS:.c=.o)) ARCH_020 = -mcpu=68020 -mtune=68020-60 OBJS_020 = $(addprefix obj/68020/,$(SRCS:.c=.o)) .PHONY: all all: bin/libsmb2.a.000 bin/libsmb2.a.020 obj/68000/%.o: %.c @mkdir -p $(dir $@) $(CC) $(ARCH_000) $(CFLAGS) -c -o $@ $< obj/68020/%.o: %.c @mkdir -p $(dir $@) $(CC) $(ARCH_020) $(CFLAGS) -c -o $@ $< bin/libsmb2.a.000: $(OBJS_000) @mkdir -p $(dir $@) $(AR) -crv $@ $^ $(RANLIB) $@ bin/libsmb2.a.020: $(OBJS_020) @mkdir -p $(dir $@) $(AR) -crv $@ $^ $(RANLIB) $@ .PHONY: clean clean: rm -rf bin obj libsmb2-6.2/lib/spnego-wrapper.c0000664000175000017500000004705014732155517015710 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2024 by Brian Dodge Copyright (C) 2024 by André Guilherme This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" #include "asn1-ber.h" #include "spnego-wrapper.h" static const struct asn1ber_oid_value oid_gss_mech_spnego = { 7, { 1, 3, 6, 1, 5, 5, 2 } }; static const struct asn1ber_oid_value oid_spnego_mech_krb5 = { 7, { 1, 2, 840, 113554, 1, 2, 2 } }; static const struct asn1ber_oid_value oid_spnego_mech_ntlmssp = { 10, { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 } }; static int oid_compare(const struct asn1ber_oid_value *a, const struct asn1ber_oid_value *b) { int i; if (!a || !b || !a->length || !b->length || a->length != b->length) { return -1; } for (i = 0; i < a->length; i++) { if (a->elements[i] < b->elements[i]) { return -1; } if (a->elements[i] > b->elements[i]) { return 1; } } return 0; } int smb2_spnego_create_negotiate_reply_blob(struct smb2_context *smb2, void **neg_init_token) { struct asn1ber_context asn_encoder; uint8_t *neg_init; int alloc_len; int pos[6]; alloc_len = 5 * sizeof oid_gss_mech_spnego; neg_init = calloc(1, alloc_len); if (neg_init == NULL) { smb2_set_error(smb2, "Failed to allocate negotiate token init"); return 0; } memset(&asn_encoder, 0, sizeof(asn_encoder)); asn_encoder.dst = neg_init; asn_encoder.dst_size = alloc_len; asn_encoder.dst_head = 0; asn1ber_ber_from_typecode(&asn_encoder, asnCONSTRUCTOR | asnAPPLICATION); /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[0]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* insert top level oid */ asn1ber_ber_from_oid(&asn_encoder, &oid_gss_mech_spnego); asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(0)); /* save location of length of sub mechanisms */ asn1ber_save_out_state(&asn_encoder, &pos[1]); asn1ber_ber_reserve_length(&asn_encoder, 5); asn1ber_ber_from_typecode(&asn_encoder, asnSTRUCT); /* save location of length of mechanism struct */ asn1ber_save_out_state(&asn_encoder, &pos[2]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* constructed */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(0)); /* save location of length of mechanism sequence */ asn1ber_save_out_state(&asn_encoder, &pos[3]); asn1ber_ber_reserve_length(&asn_encoder, 5); asn1ber_ber_from_typecode(&asn_encoder, ASN1_SEQUENCE(0)); /* save location of length of mechanism struct */ asn1ber_save_out_state(&asn_encoder, &pos[4]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* for each negotiable mechanism */ /* insert mechanism oids */ asn1ber_ber_from_oid(&asn_encoder, &oid_spnego_mech_ntlmssp); #ifdef HAVE_LIBKRB5 /* insert mechanism oids */ asn1ber_ber_from_oid(&asn_encoder, &oid_spnego_mech_krb5); #endif asn1ber_annotate_length(&asn_encoder, pos[4], 5); asn1ber_annotate_length(&asn_encoder, pos[3], 5); asn1ber_annotate_length(&asn_encoder, pos[2], 5); asn1ber_annotate_length(&asn_encoder, pos[1], 5); asn1ber_annotate_length(&asn_encoder, pos[0], 5); *neg_init_token = neg_init; return asn_encoder.dst_head; } int smb2_spnego_wrap_gssapi(struct smb2_context *smb2, const uint8_t *ntlmssp_token, const int token_len, void **blob) { struct asn1ber_context asn_encoder; uint8_t *neg_init; int alloc_len; int pos[8]; alloc_len = 256 + 4 * token_len; neg_init = calloc(1, alloc_len); if (neg_init == NULL) { smb2_set_error(smb2, "Failed to allocate spnego wrapper"); return 0; } memset(&asn_encoder, 0, sizeof(asn_encoder)); asn_encoder.dst = neg_init; asn_encoder.dst_size = alloc_len; asn_encoder.dst_head = 0; /* blob */ asn1ber_ber_from_typecode(&asn_encoder, asnCONSTRUCTOR | asnAPPLICATION); /* 60 ZZ */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[0]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* gss-spnego mech oid */ asn1ber_ber_from_oid(&asn_encoder, &oid_gss_mech_spnego); /* context 0 */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(0)); /* A0 XX */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[1]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* sequence 0 */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_SEQUENCE(0)); /* 30 YY */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[2]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* context 0 mech types */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(0)); /* A0 zz */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[3]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* sequence 0 of mech types */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_SEQUENCE(0)); /* 30 xx */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[4]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* ntlmssp mech oid */ asn1ber_ber_from_oid(&asn_encoder, &oid_spnego_mech_ntlmssp); /* end sequenuce of mech types */ asn1ber_annotate_length(&asn_encoder, pos[4], 5); /* end mech types */ asn1ber_annotate_length(&asn_encoder, pos[3], 5); /* context 2 mech token */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(2)); /* A2 yy */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[3]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* ntlmssp token */ asn1ber_ber_from_typecode(&asn_encoder, asnOCTET_STRING); /* 04 nn */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[4]); asn1ber_ber_reserve_length(&asn_encoder, 5); memcpy(asn_encoder.dst + asn_encoder.dst_head, ntlmssp_token, token_len); asn_encoder.dst_head += token_len; asn1ber_annotate_length(&asn_encoder, pos[4], 5); asn1ber_annotate_length(&asn_encoder, pos[3], 5); asn1ber_annotate_length(&asn_encoder, pos[2], 5); asn1ber_annotate_length(&asn_encoder, pos[1], 5); asn1ber_annotate_length(&asn_encoder, pos[0], 5); *blob = neg_init; return asn_encoder.dst_head; } int smb2_spnego_wrap_ntlmssp_challenge(struct smb2_context *smb2, const uint8_t *ntlmssp_token, const int token_len, void **neg_init_token) { struct asn1ber_context asn_encoder; uint8_t *neg_init; int alloc_len; int pos[6]; uint8_t neg_result = 1; alloc_len = 64 + 2 * token_len; neg_init = calloc(1, alloc_len); if (neg_init == NULL) { smb2_set_error(smb2, "Failed to allocate spnego wrapper"); return 0; } memset(&asn_encoder, 0, sizeof(asn_encoder)); asn_encoder.dst = neg_init; asn_encoder.dst_size = alloc_len; asn_encoder.dst_head = 0; asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(1)); /* A1 XX */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[0]); asn1ber_ber_reserve_length(&asn_encoder, 5); asn1ber_ber_from_typecode(&asn_encoder, ASN1_SEQUENCE(0)); /* 30 YY */ /* save location of sub length */ asn1ber_save_out_state(&asn_encoder, &pos[1]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* negTokenTarg */ /* negResult: accept-incomplete */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(0)); /* A0 ZZ */ /* save location of length */ asn1ber_save_out_state(&asn_encoder, &pos[2]); asn1ber_ber_reserve_length(&asn_encoder, 1); asn1ber_ber_from_bytes(&asn_encoder, asnENUMERATED, &neg_result, sizeof(neg_result)); /* 0A 01 01 */ asn1ber_annotate_length(&asn_encoder, pos[2], 1); /* supportedMech */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(1)); /* A1 ZZ */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[2]); asn1ber_ber_reserve_length(&asn_encoder, 1); asn1ber_ber_from_oid(&asn_encoder, &oid_spnego_mech_ntlmssp); asn1ber_annotate_length(&asn_encoder, pos[2], 1); /* ntlm service provider */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(2)); /* A2 ZZ */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[2]); asn1ber_ber_reserve_length(&asn_encoder, 5); asn1ber_ber_from_typecode(&asn_encoder, asnOCTET_STRING); /* 04 zz */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[3]); asn1ber_ber_reserve_length(&asn_encoder, 5); memcpy(asn_encoder.dst + asn_encoder.dst_head, ntlmssp_token, token_len); asn_encoder.dst_head += token_len; asn1ber_annotate_length(&asn_encoder, pos[3], 5); asn1ber_annotate_length(&asn_encoder, pos[2], 5); asn1ber_annotate_length(&asn_encoder, pos[1], 5); asn1ber_annotate_length(&asn_encoder, pos[0], 5); *neg_init_token = neg_init; return asn_encoder.dst_head; } int smb2_spnego_wrap_authenticate_result(struct smb2_context *smb2, const int authorized_ok, void **blob) { struct asn1ber_context asn_encoder; uint8_t *neg_targ; int alloc_len; int pos[6]; uint8_t result_code = 3; /* accept-fail */ alloc_len = 128; neg_targ = calloc(1, alloc_len); if (neg_targ == NULL) { smb2_set_error(smb2, "Failed to allocate spnego wrapper"); return -ENOMEM; } if (authorized_ok) { result_code = 0 /* accept-completed */; } memset(&asn_encoder, 0, sizeof(asn_encoder)); asn_encoder.dst = neg_targ; asn_encoder.dst_size = alloc_len; asn_encoder.dst_head = 0; asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(1)); /* A1 XX */ /* save location of total length */ asn1ber_save_out_state(&asn_encoder, &pos[0]); asn1ber_ber_reserve_length(&asn_encoder, 5); asn1ber_ber_from_typecode(&asn_encoder, ASN1_SEQUENCE(0)); /* 30 YY */ /* save location of sub length */ asn1ber_save_out_state(&asn_encoder, &pos[1]); asn1ber_ber_reserve_length(&asn_encoder, 5); /* negTokenTarg */ /* negResult: accept-incomplete */ asn1ber_ber_from_typecode(&asn_encoder, ASN1_CONTEXT(0)); /* A0 ZZ */ /* save location of length */ asn1ber_save_out_state(&asn_encoder, &pos[2]); asn1ber_ber_reserve_length(&asn_encoder, 1); asn1ber_ber_from_bytes(&asn_encoder, asnENUMERATED, &result_code, 1); /* 0A 01 Value */ asn1ber_annotate_length(&asn_encoder, pos[2], 1); asn1ber_annotate_length(&asn_encoder, pos[1], 5); asn1ber_annotate_length(&asn_encoder, pos[0], 5); *blob = neg_targ; return asn_encoder.dst_head; } #define require_typecode(ctx, expected, label) \ ret = ber_typecode_from_ber(ctx, (ber_type_t*)&typecode); \ if (ret || (typecode != (expected))) { \ goto label; \ } #define require_typeandlen(ctx, expected, minimum, label) \ ret = ber_typelen_from_ber(ctx, (ber_type_t*)&typecode, &typelen); \ if (ret || (typecode != (expected)) || (typelen < (minimum))) { \ fail_line = __LINE__; \ goto label; \ } #define require_noerr(errcode, label) \ if (errcode) { \ fail_line = __LINE__; \ goto label; \ } int smb2_spnego_unwrap_targ(struct smb2_context *smb2, const uint8_t *spnego, const int spnego_len, uint8_t **token, uint32_t *mechanisms) { struct asn1ber_context asn_decoder; struct asn1ber_oid_value oid; uint32_t typecode; uint32_t typelen; int objpos; int token_len = 0; int sequence_len = 0; int fail_line = 0; int ret; memset(&asn_decoder, 0, sizeof(asn_decoder)); asn_decoder.src = discard_const(spnego); asn_decoder.src_count = spnego_len; asn_decoder.src_tail = 0; require_typeandlen(&asn_decoder, ASN1_CONTEXT(1), 14, fail); require_typeandlen(&asn_decoder, ASN1_SEQUENCE(0), 12, fail); sequence_len = typelen; while (sequence_len > 2) { objpos = asn_decoder.src_tail; ret = ber_typelen_from_ber(&asn_decoder, (ber_type_t*)&typecode, &typelen); require_noerr(ret, fail); switch (typecode) { case ASN1_CONTEXT(0): ret = asn1ber_uint32_from_ber(&asn_decoder, mechanisms); require_noerr(ret, fail); break; case ASN1_CONTEXT(1): /* supported mechanism */ ret = asn1ber_oid_from_ber(&asn_decoder, &oid); require_noerr(ret, fail); case ASN1_CONTEXT(2): /* response token */ require_typeandlen(&asn_decoder, asnOCTET_STRING, 8, fail); *token = asn_decoder.src + asn_decoder.src_tail; token_len = typelen; break; } sequence_len -= (asn_decoder.src_tail - objpos); if (token_len) { break; } } return token_len; fail: smb2_set_error(smb2, "bad spnego at line %d, spengo offset %d", fail_line, asn_decoder.src_tail); return -EINVAL; } int smb2_spnego_unwrap_gssapi(struct smb2_context *smb2, const uint8_t *spnego, const int spnego_len, uint8_t **token, uint32_t *mechanisms) { struct asn1ber_context asn_decoder; struct asn1ber_oid_value oid; uint32_t typecode; uint32_t typelen; int decode_pos; int mech_bytes; uint32_t mechs = 0; int fail_line; int ret; memset(&asn_decoder, 0, sizeof(asn_decoder)); asn_decoder.src = discard_const(spnego); asn_decoder.src_count = spnego_len; asn_decoder.src_tail = 0; require_typeandlen(&asn_decoder, asnCONSTRUCTOR | asnAPPLICATION, 32, fail); /* gss-spnego mech oid */ ret = asn1ber_oid_from_ber(&asn_decoder, &oid); require_noerr(ret, fail); require_noerr(oid.length != oid_gss_mech_spnego.length, fail); require_noerr(oid_compare(&oid, &oid_gss_mech_spnego), fail); /* context 0 */ require_typeandlen(&asn_decoder, ASN1_CONTEXT(0), 10, fail); require_typeandlen(&asn_decoder, ASN1_SEQUENCE(0), 8, fail); require_typeandlen(&asn_decoder, ASN1_CONTEXT(0), 10, fail); require_typeandlen(&asn_decoder, ASN1_SEQUENCE(0), 8, fail); mech_bytes = typelen; /* sequence of mechanism types */ while (mech_bytes > 0) { decode_pos = asn_decoder.src_tail; ret = asn1ber_oid_from_ber(&asn_decoder, &oid); require_noerr(ret, fail); mech_bytes -= (asn_decoder.src_tail - decode_pos); if (!oid_compare(&oid, &oid_spnego_mech_krb5)) { mechs |= SPNEGO_MECHANISM_KRB5; } else if (!oid_compare(&oid, &oid_spnego_mech_ntlmssp)) { mechs |= SPNEGO_MECHANISM_NTLMSSP; } } /* mech token */ require_typeandlen(&asn_decoder, asnOCTET_STRING, 7, fail); *token = asn_decoder.src + asn_decoder.src_tail; if (mechanisms) { *mechanisms = mechs; } return typelen; fail: smb2_set_error(smb2, "bad spnego at line %d, spengo offset %d", fail_line, asn_decoder.src_tail); return -EINVAL; } int smb2_spnego_unwrap_blob(struct smb2_context *smb2, const uint8_t *spnego, const int spnego_len, uint8_t **token, uint32_t *mechanisms) { uint8_t typecode; if (token) { *token = NULL; } if (!spnego || !token || spnego_len < 7) { return -EINVAL; } /* if not wrapped, just return raw token */ if (spnego_len > 7 && !memcmp(spnego, "NTLMSSP", 8)) { *token = discard_const(spnego); return spnego_len; } /* peek at first byte of spnego and dispatch */ typecode = spnego[0]; if (typecode == (asnCONSTRUCTOR | asnAPPLICATION)) { /* 0x60 - a GSS-API blob */ return smb2_spnego_unwrap_gssapi(smb2, spnego, spnego_len, token, mechanisms); } else if (typecode == ASN1_CONTEXT(0) || typecode == ASN1_CONTEXT(1) || typecode == ASN1_CONTEXT(2)) { /* 0xAx - a raw spnego blob */ return smb2_spnego_unwrap_targ(smb2, spnego, spnego_len, token, mechanisms); } return -EINVAL; } libsmb2-6.2/lib/smb2-cmd-negotiate.c0000664000175000017500000005223314732155517016317 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_preauth_context(struct smb2_context *smb2, struct smb2_pdu *pdu) { uint8_t *buf; int len, i, data_len; struct smb2_iovec *iov; /* Preauth integrity capability */ data_len = 38; len = 8 + PAD_TO_64BIT(38); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate preauth context"); return -1; } memset(buf, 0, len); iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_PREAUTH_INTEGRITY_CAP); smb2_set_uint16(iov, 2, data_len); smb2_set_uint16(iov, 8, 1); smb2_set_uint16(iov, 10, 32); smb2_set_uint16(iov, 12, SMB2_HASH_SHA_512); for (i = 0; i < SMB2_SALT_SIZE; i++) { smb2_set_uint8(iov, 14 + i, smb2->salt[i]); } return 0; } static int smb2_encode_encryption_context(struct smb2_context *smb2, struct smb2_pdu *pdu) { uint8_t *buf; int len, data_len; struct smb2_iovec *iov; data_len = PAD_TO_64BIT(4); len = 8 + data_len; len = PAD_TO_64BIT(len); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate encryption context"); return -1; } memset(buf, 0, len); iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_ENCRYPTION_CAP); smb2_set_uint16(iov, 2, data_len); smb2_set_uint16(iov, 8, 1); smb2_set_uint16(iov, 10, SMB2_ENCRYPTION_AES_128_CCM); return 0; } static int smb2_encode_negotiate_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_negotiate_request *req) { uint8_t *buf; int i, len; struct smb2_iovec *iov; len = SMB2_NEGOTIATE_REQUEST_SIZE + req->dialect_count * sizeof(uint16_t); len = PAD_TO_32BIT(len); if (smb2->version == SMB2_VERSION_ANY || smb2->version == SMB2_VERSION_ANY3 || smb2->version == SMB2_VERSION_0311) { /* Negotiate contexts are aligned at 64bit boundaries */ if (len & 0x04) { len += 4; } } buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate negotiate buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); if (smb2->version == SMB2_VERSION_ANY || smb2->version == SMB2_VERSION_ANY3 || smb2->version == SMB2_VERSION_0311) { req->negotiate_context_offset = len + SMB2_HEADER_SIZE; if (smb2_encode_preauth_context(smb2, pdu)) { return -1; } req->negotiate_context_count++; if (smb2_encode_encryption_context(smb2, pdu)) { return -1; } req->negotiate_context_count++; } smb2_set_uint16(iov, 0, SMB2_NEGOTIATE_REQUEST_SIZE); smb2_set_uint16(iov, 2, req->dialect_count); smb2_set_uint16(iov, 4, req->security_mode); smb2_set_uint32(iov, 8, req->capabilities); memcpy(iov->buf + 12, req->client_guid, SMB2_GUID_SIZE); smb2_set_uint32(iov, 28, req->negotiate_context_offset); smb2_set_uint16(iov, 32, req->negotiate_context_count); for (i = 0; i < req->dialect_count; i++) { smb2_set_uint16(iov, 36 + i * sizeof(uint16_t), req->dialects[i]); } return 0; } struct smb2_pdu * smb2_cmd_negotiate_async(struct smb2_context *smb2, struct smb2_negotiate_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_NEGOTIATE, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_negotiate_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_negotiate_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_negotiate_reply *rep) { uint8_t *buf; int len, seclen; struct smb2_iovec *iov; len = SMB2_NEGOTIATE_REPLY_SIZE & 0xfffe; len = PAD_TO_32BIT(len); if (smb2->dialect == SMB2_VERSION_ANY || smb2->dialect == SMB2_VERSION_ANY3 || smb2->dialect == SMB2_VERSION_0311) { /* Negotiate contexts are aligned at 64bit boundaries */ if (len & 0x04) { len += 4; } } buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate negotiate reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); if (rep->security_buffer_length) { seclen = rep->security_buffer_length; seclen = PAD_TO_64BIT(len); /* Security buffer */ buf = malloc(seclen); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate secbuf"); return -1; } memcpy(buf, rep->security_buffer, rep->security_buffer_length); memset(buf + rep->security_buffer_length, 0, seclen - rep->security_buffer_length); smb2_add_iovector(smb2, &pdu->out, buf, len, free); } if (smb2->dialect == SMB2_VERSION_ANY || smb2->dialect == SMB2_VERSION_ANY3 || smb2->dialect == SMB2_VERSION_0311) { if (smb2_encode_preauth_context(smb2, pdu)) { return -1; } rep->negotiate_context_count++; if (smb2_encode_encryption_context(smb2, pdu)) { return -1; } rep->negotiate_context_count++; } smb2_set_uint16(iov, 0, SMB2_NEGOTIATE_REPLY_SIZE); smb2_set_uint16(iov, 2, rep->security_mode); smb2_set_uint16(iov, 4, rep->dialect_revision); smb2_set_uint16(iov, 6, rep->negotiate_context_count); memcpy(iov->buf + 8, rep->server_guid, SMB2_GUID_SIZE); smb2_set_uint32(iov, 24, rep->capabilities); smb2_set_uint32(iov, 28, rep->max_transact_size); smb2_set_uint32(iov, 32, rep->max_read_size); smb2_set_uint32(iov, 36, rep->max_write_size); smb2_set_uint64(iov, 40, rep->system_time); smb2_set_uint64(iov, 48, rep->server_start_time); rep->security_buffer_offset = len + SMB2_HEADER_SIZE; smb2_set_uint16(iov, 56, rep->security_buffer_offset); smb2_set_uint16(iov, 58, rep->security_buffer_length); rep->negotiate_context_offset = len + seclen + SMB2_HEADER_SIZE; smb2_set_uint32(iov, 60, rep->negotiate_context_offset); return 0; } struct smb2_pdu * smb2_cmd_negotiate_reply_async(struct smb2_context *smb2, struct smb2_negotiate_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_NEGOTIATE, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_negotiate_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } #define IOV_OFFSET (rep->security_buffer_offset - SMB2_HEADER_SIZE - \ (SMB2_NEGOTIATE_REPLY_SIZE & 0xfffe)) static int smb2_parse_encryption_context(struct smb2_context *smb2, struct smb2_negotiate_reply *rep, struct smb2_iovec *iov, int offset) { smb2_get_uint16(iov, offset, &rep->cypher); return 0; } static int smb2_parse_negotiate_contexts(struct smb2_context *smb2, struct smb2_negotiate_reply *rep, struct smb2_iovec *iov, int offset, int count) { uint16_t type, len; while (count--) { if (offset > (int)iov->len) { smb2_set_error(smb2, "Bad len in negotiate context\n"); return -1; } smb2_get_uint16(iov, offset, &type); smb2_get_uint16(iov, offset + 2, &len); switch (type) { case SMB2_PREAUTH_INTEGRITY_CAP: break; case SMB2_ENCRYPTION_CAP: if (smb2_parse_encryption_context(smb2, rep, iov, offset + 8)) { return -1; } break; case SMB2_SIGNING_CAP: case SMB2_COMPRESSION_CAP: case SMB2_NETNAME_NEGOTIATE_CONTEXT_ID: case SMB2_TRANSPORT_CAP: case SMB2_RDMA_TRANSFORM_CAP: break; default: smb2_set_error(smb2, "Unknown negotiate context " "type 0x%04x", type); return -1; } offset += PAD_TO_64BIT(len + 8); } return 0; } int smb2_process_negotiate_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_negotiate_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_NEGOTIATE_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Negotiate " "reply. Expected %d, got %d", SMB2_NEGOTIATE_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate negotiate reply"); return -1; } pdu->payload = rep; smb2_get_uint16(iov, 2, &rep->security_mode); smb2_get_uint16(iov, 4, &rep->dialect_revision); memcpy(rep->server_guid, iov->buf + 8, SMB2_GUID_SIZE); smb2_get_uint32(iov, 24, &rep->capabilities); smb2_get_uint32(iov, 28, &rep->max_transact_size); smb2_get_uint32(iov, 32, &rep->max_read_size); smb2_get_uint32(iov, 36, &rep->max_write_size); smb2_get_uint64(iov, 40, &rep->system_time); smb2_get_uint64(iov, 48, &rep->server_start_time); smb2_get_uint16(iov, 56, &rep->security_buffer_offset); smb2_get_uint16(iov, 58, &rep->security_buffer_length); if (rep->security_buffer_length && (rep->security_buffer_offset + rep->security_buffer_length > (uint16_t)smb2->spl)) { smb2_set_error(smb2, "Security buffer extends beyond end of " "PDU"); pdu->payload = NULL; free(rep); return -1; } smb2_get_uint16(iov, 6, &rep->negotiate_context_count); smb2_get_uint32(iov, 60, &rep->negotiate_context_offset); if (rep->security_buffer_length == 0) { return 0; } if (rep->security_buffer_offset < SMB2_HEADER_SIZE + (SMB2_NEGOTIATE_REPLY_SIZE & 0xfffe)) { smb2_set_error(smb2, "Security buffer overlaps with " "negotiate reply header"); pdu->payload = NULL; free(rep); return -1; } /* * In SMB3.1.1 and later we have negotiate contexts at the end of the * blob but we can not compute how big they are from just * looking at the smb2 header of the fixed part of the negotiate reply * so just return all the remaining data as the variable size. * The contexts are technically where padding should be. */ if (rep->dialect_revision >= SMB2_VERSION_0311) { return smb2->spl - SMB2_HEADER_SIZE - (SMB2_NEGOTIATE_REPLY_SIZE & 0xfffe); } else { return IOV_OFFSET + rep->security_buffer_length; } } int smb2_process_negotiate_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_negotiate_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; int offset; rep->security_buffer = &iov->buf[IOV_OFFSET]; if (rep->dialect_revision < SMB2_VERSION_0311 || !rep->negotiate_context_count) { return 0; } offset = rep->negotiate_context_offset - SMB2_HEADER_SIZE - (SMB2_NEGOTIATE_REPLY_SIZE & 0xfffe); if (offset < 0 || offset > (int)iov->len) { return -1; } if (smb2_parse_negotiate_contexts(smb2, rep, iov, offset, rep->negotiate_context_count)) { return -1; } return 0; } #define IOVREQ_OFFSET (req->security_buffer_offset - SMB2_HEADER_SIZE - \ (SMB2_NEGOTIATE_REQUEST_SIZE & 0xfffe)) int smb2_process_negotiate_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_negotiate_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_NEGOTIATE_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Negotiate " "request. Expected %d, got %d", SMB2_NEGOTIATE_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate negotiate request"); return -1; } pdu->payload = req; smb2_get_uint16(iov, 2, &req->dialect_count); smb2_get_uint16(iov, 4, &req->security_mode); /* 2 bytes reserved */ smb2_get_uint32(iov, 8, &req->capabilities); memcpy(req->client_guid, iov->buf + 12, SMB2_GUID_SIZE); smb2_get_uint32(iov, 28, &req->negotiate_context_offset); smb2_get_uint16(iov, 32, &req->negotiate_context_count); /* * In SMB3.1.1 and later we have negotiate contexts at the end of the * blob but we can not compute how big they are from just * looking at the smb2 header of the fixed part of the negotiate reply * so just return all the remaining data as the variable size. * The contexts are technically where padding should be. */ if (req->negotiate_context_count > 0) { return smb2->spl - SMB2_HEADER_SIZE - (SMB2_NEGOTIATE_REQUEST_SIZE & 0xfffe); } else { return req->dialect_count * sizeof(uint16_t); } } static int smb2_parse_encryption_request_context(struct smb2_context *smb2, struct smb2_negotiate_request *req, struct smb2_iovec *iov, int offset, int len) { return 0; } static int smb2_parse_netname_request_context(struct smb2_context *smb2, struct smb2_negotiate_request *req, struct smb2_iovec *iov, int offset, int len) { char netname[128]; char *client; memcpy(netname, iov->buf + offset, len); client = discard_const(smb2_utf16_to_utf8((uint16_t *)netname, len)); free(client); return 0; } static int smb2_parse_negotiate_request_contexts(struct smb2_context *smb2, struct smb2_negotiate_request *req, struct smb2_iovec *iov, int offset, int count) { uint16_t type, len; while (count--) { smb2_get_uint16(iov, offset, &type); smb2_get_uint16(iov, offset + 2, &len); if (offset > (int)iov->len) { smb2_set_error(smb2, "Bad len in negotiate context"); return -1; } switch (type) { case SMB2_PREAUTH_INTEGRITY_CAP: break; case SMB2_ENCRYPTION_CAP: if (smb2_parse_encryption_request_context(smb2, req, iov, offset + 8, len)) { return -1; } break; case SMB2_NETNAME_NEGOTIATE_CONTEXT_ID: if (smb2_parse_netname_request_context(smb2, req, iov, offset + 8, len)) { return -1; } break; case SMB2_SIGNING_CAP: case SMB2_COMPRESSION_CAP: case SMB2_TRANSPORT_CAP: case SMB2_RDMA_TRANSFORM_CAP: break; case SMB2_CONTEXTTYPE_RESERVED: /* used by samba for "posix extension cap" */ break; default: smb2_set_error(smb2, "Unknown negotiate context " "type 0x%04x", type); return -1; } offset += PAD_TO_64BIT(len + 8); } return 0; } int smb2_process_negotiate_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_negotiate_request *req = (struct smb2_negotiate_request*)pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; int offset; int has_0311 = 0; uint32_t d; for (d = 0; d < req->dialect_count && d < SMB2_NEGOTIATE_MAX_DIALECTS; d++) { smb2_get_uint16(iov, d * 2, &req->dialects[d]); if (req->dialects[d] == 0x0311) { has_0311 = 1; } } if (!req->negotiate_context_count) { return 0; } /* if dialects array does not contain 0311, there should be no interpretation of * negotiate contexts (its the client start time in non-0311 dialects) */ if (!has_0311) { return 0; } offset = req->negotiate_context_offset - SMB2_HEADER_SIZE - (SMB2_NEGOTIATE_REQUEST_SIZE & 0xfffe); if (offset < 0 || offset > (int)iov->len) { return -1; } if (smb2_parse_negotiate_request_contexts(smb2, req, iov, offset, req->negotiate_context_count)) { return -1; } return 0; } libsmb2-6.2/lib/smb2-cmd-logoff.c0000664000175000017500000001100214732155517015601 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_logoff_request(struct smb2_context *smb2, struct smb2_pdu *pdu) { uint8_t *buf; int len; struct smb2_iovec *iov; len = SMB2_LOGOFF_REQUEST_SIZE; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate logoff buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_LOGOFF_REQUEST_SIZE); return 0; } struct smb2_pdu * smb2_cmd_logoff_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_LOGOFF, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_logoff_request(smb2, pdu)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_logoff_reply(struct smb2_context *smb2, struct smb2_pdu *pdu) { uint8_t *buf; int len; struct smb2_iovec *iov; len = SMB2_LOGOFF_REPLY_SIZE; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate logoff reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_LOGOFF_REPLY_SIZE); return 0; } struct smb2_pdu * smb2_cmd_logoff_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_LOGOFF, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_logoff_reply(smb2, pdu)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_logoff_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { return 0; } int smb2_process_logoff_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_logoff_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_ECHO_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of logoff " "request. Expected %d, got %d", SMB2_ECHO_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate echo request"); return -1; } pdu->payload = req; return 0; } libsmb2-6.2/lib/md4c.c0000664000175000017500000002060314732155517013561 0ustar polpypolpy/* From RFC1320 */ /* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */ /* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD4 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STDINT_H #include #endif #include "compat.h" #include "md4.h" /* Constants for MD4Transform routine. */ #define S11 3 #define S12 7 #define S13 11 #define S14 19 #define S21 3 #define S22 5 #define S23 9 #define S24 13 #define S31 3 #define S32 9 #define S33 11 #define S34 15 static void MD4Transform(uint32_t [4], unsigned char [64]); static void Encode(unsigned char *, uint32_t *, unsigned int); static void Decode(uint32_t *, unsigned char *, unsigned int); static void MD4_memcpy(unsigned char *, unsigned char *, unsigned int); static void MD4_memset(unsigned char *, int, unsigned int); static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* F, G and H are basic MD4 functions. */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) /* ROTATE_LEFT rotates x left n bits. */ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) /* FF, GG and HH are transformations for rounds 1, 2 and 3 */ /* Rotation is separate from addition to prevent recomputation */ #define FF(a, b, c, d, x, s) { \ (a) += F ((b), (c), (d)) + (x); \ (a) = ROTATE_LEFT ((a), (s)); \ } #define GG(a, b, c, d, x, s) { \ (a) += G ((b), (c), (d)) + (x) + (uint32_t)0x5a827999; \ (a) = ROTATE_LEFT ((a), (s)); \ } #define HH(a, b, c, d, x, s) { \ (a) += H ((b), (c), (d)) + (x) + (uint32_t)0x6ed9eba1; \ (a) = ROTATE_LEFT ((a), (s)); \ } /* MD4 initialization. Begins an MD4 operation, writing a new context. */ void MD4Init(MD4_CTX *context) { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; context->state[2] = 0x98badcfe; context->state[3] = 0x10325476; } /* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */ void MD4Update(MD4_CTX *context, unsigned char *input, unsigned int inputLen) { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int)((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((uint32_t)inputLen << 3)) < ((uint32_t)inputLen << 3)) context->count[1]++; context->count[1] += ((uint32_t)inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { MD4_memcpy ((unsigned char *)&context->buffer[index], (unsigned char *)input, partLen); MD4Transform (context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) MD4Transform (context->state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ MD4_memcpy ((unsigned char *)&context->buffer[index], (unsigned char *)&input[i], inputLen-i); } /* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */ void MD4Final(unsigned char digest[16], MD4_CTX *context) { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ Encode (bits, context->count, 8); /* Pad out to 56 mod 64. */ index = (unsigned int)((context->count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); MD4Update (context, PADDING, padLen); /* Append length (before padding) */ MD4Update (context, bits, 8); /* Store state in digest */ Encode (digest, context->state, 16); /* Zeroize sensitive information. */ MD4_memset ((unsigned char *)context, 0, sizeof (*context)); } /* MD4 basic transformation. Transforms state based on block. */ static void MD4Transform(uint32_t state[4], unsigned char block[64]) { uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode (x, block, 64); /* Round 1 */ FF (a, b, c, d, x[ 0], S11); /* 1 */ FF (d, a, b, c, x[ 1], S12); /* 2 */ FF (c, d, a, b, x[ 2], S13); /* 3 */ FF (b, c, d, a, x[ 3], S14); /* 4 */ FF (a, b, c, d, x[ 4], S11); /* 5 */ FF (d, a, b, c, x[ 5], S12); /* 6 */ FF (c, d, a, b, x[ 6], S13); /* 7 */ FF (b, c, d, a, x[ 7], S14); /* 8 */ FF (a, b, c, d, x[ 8], S11); /* 9 */ FF (d, a, b, c, x[ 9], S12); /* 10 */ FF (c, d, a, b, x[10], S13); /* 11 */ FF (b, c, d, a, x[11], S14); /* 12 */ FF (a, b, c, d, x[12], S11); /* 13 */ FF (d, a, b, c, x[13], S12); /* 14 */ FF (c, d, a, b, x[14], S13); /* 15 */ FF (b, c, d, a, x[15], S14); /* 16 */ /* Round 2 */ GG (a, b, c, d, x[ 0], S21); /* 17 */ GG (d, a, b, c, x[ 4], S22); /* 18 */ GG (c, d, a, b, x[ 8], S23); /* 19 */ GG (b, c, d, a, x[12], S24); /* 20 */ GG (a, b, c, d, x[ 1], S21); /* 21 */ GG (d, a, b, c, x[ 5], S22); /* 22 */ GG (c, d, a, b, x[ 9], S23); /* 23 */ GG (b, c, d, a, x[13], S24); /* 24 */ GG (a, b, c, d, x[ 2], S21); /* 25 */ GG (d, a, b, c, x[ 6], S22); /* 26 */ GG (c, d, a, b, x[10], S23); /* 27 */ GG (b, c, d, a, x[14], S24); /* 28 */ GG (a, b, c, d, x[ 3], S21); /* 29 */ GG (d, a, b, c, x[ 7], S22); /* 30 */ GG (c, d, a, b, x[11], S23); /* 31 */ GG (b, c, d, a, x[15], S24); /* 32 */ /* Round 3 */ HH (a, b, c, d, x[ 0], S31); /* 33 */ HH (d, a, b, c, x[ 8], S32); /* 34 */ HH (c, d, a, b, x[ 4], S33); /* 35 */ HH (b, c, d, a, x[12], S34); /* 36 */ HH (a, b, c, d, x[ 2], S31); /* 37 */ HH (d, a, b, c, x[10], S32); /* 38 */ HH (c, d, a, b, x[ 6], S33); /* 39 */ HH (b, c, d, a, x[14], S34); /* 40 */ HH (a, b, c, d, x[ 1], S31); /* 41 */ HH (d, a, b, c, x[ 9], S32); /* 42 */ HH (c, d, a, b, x[ 5], S33); /* 43 */ HH (b, c, d, a, x[13], S34); /* 44 */ HH (a, b, c, d, x[ 3], S31); /* 45 */ HH (d, a, b, c, x[11], S32); /* 46 */ HH (c, d, a, b, x[ 7], S33); /* 47 */ HH (b, c, d, a, x[15], S34); /* 48 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ MD4_memset ((unsigned char *)x, 0, sizeof (x)); } /* Encodes input (uint32_t) into output (unsigned char). Assumes len is a multiple of 4. */ static void Encode(unsigned char *output, uint32_t *input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char)(input[i] & 0xff); output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (uint32_t). Assumes len is a multiple of 4. */ static void Decode(uint32_t *output, unsigned char *input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); } /* Note: Replace "for loop" with standard memcpy if possible. */ static void MD4_memcpy(unsigned char *output, unsigned char *input, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } /* Note: Replace "for loop" with standard memset if possible. */ static void MD4_memset(unsigned char *output, int value, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) ((char *)output)[i] = (char)value; } libsmb2-6.2/lib/smb2-cmd-close.c0000664000175000017500000001503514732155517015444 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_close_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_close_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_CLOSE_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate close buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_CLOSE_REQUEST_SIZE); smb2_set_uint16(iov, 2, req->flags); memcpy(iov->buf + 8, req->file_id, SMB2_FD_SIZE); return 0; } struct smb2_pdu * smb2_cmd_close_async(struct smb2_context *smb2, struct smb2_close_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_CLOSE, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_close_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_close_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_close_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_CLOSE_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate close reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_CLOSE_REPLY_SIZE); smb2_set_uint16(iov, 2, rep->flags); smb2_set_uint64(iov, 4, rep->creation_time); smb2_set_uint64(iov, 12, rep->last_access_time); smb2_set_uint64(iov, 20, rep->last_write_time); smb2_set_uint64(iov, 28, rep->change_time); smb2_set_uint64(iov, 36, rep->allocation_size); smb2_set_uint64(iov, 44, rep->end_of_file); smb2_set_uint32(iov, 52, rep->file_attributes); return 0; } struct smb2_pdu * smb2_cmd_close_reply_async(struct smb2_context *smb2, struct smb2_close_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_CLOSE, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_close_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_close_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_close_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_CLOSE_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Close " "reply. Expected %d, got %d", SMB2_CLOSE_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate close reply"); return -1; } pdu->payload = rep; smb2_get_uint16(iov, 2, &rep->flags); smb2_get_uint64(iov, 8, &rep->creation_time); smb2_get_uint64(iov, 16, &rep->last_access_time); smb2_get_uint64(iov, 24, &rep->last_write_time); smb2_get_uint64(iov, 32, &rep->change_time); smb2_get_uint64(iov, 40, &rep->allocation_size); smb2_get_uint64(iov, 48, &rep->end_of_file); smb2_get_uint32(iov, 56, &rep->file_attributes); return 0; } int smb2_process_close_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_close_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_CLOSE_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Close " "request. Expected %d, got %d", SMB2_CLOSE_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate close request"); return -1; } pdu->payload = req; smb2_get_uint16(iov, 2, &req->flags); memcpy(req->file_id, iov->buf + 8, SMB2_FD_SIZE); return 0; } libsmb2-6.2/lib/ps2/0000775000175000017500000000000014766406304013271 5ustar polpypolpylibsmb2-6.2/lib/ps2/TODO0000664000175000017500000000036314732155517013763 0ustar polpypolpyTODO: * Tweak libsmb2 to make the irx smaller * Add a keeaplive devctl that will try to smb2_echo() all connected shares. * Setting up the logging and getting the network to work only works half the time. Do we need to re-try a few times? libsmb2-6.2/lib/ps2/imports.lst0000664000175000017500000000213014732155517015506 0ustar polpypolpyioman_IMPORTS_start I_AddDrv I_DelDrv ioman_IMPORTS_end ps2ip_IMPORTS_start I_lwip_recv I_lwip_send I_lwip_close I_lwip_fcntl I_lwip_freeaddrinfo I_lwip_getaddrinfo I_lwip_getsockopt I_lwip_shutdown I_lwip_socket I_lwip_connect I_lwip_select I_inet_addr I_lwip_setsockopt I_lwip_bind I_lwip_accept I_lwip_listen ps2ip_IMPORTS_end intrman_IMPORTS_start I_CpuSuspendIntr I_CpuResumeIntr intrman_IMPORTS_end sifman_IMPORTS_start I_sceSifSetDma I_sceSifDmaStat sifman_IMPORTS_end thbase_IMPORTS_start I_DelayThread I_CreateThread I_StartThread I_DeleteThread I_USec2SysClock I_SysClock2USec I_SetAlarm I_iSetAlarm I_CancelAlarm I_GetSystemTime thbase_IMPORTS_end sysmem_IMPORTS_start I_AllocSysMemory I_FreeSysMemory sysmem_IMPORTS_end thsemap_IMPORTS_start I_CreateSema I_WaitSema I_SignalSema I_iSignalSema I_DeleteSema thsemap_IMPORTS_end sysclib_IMPORTS_start I_look_ctype_table I_memset I_memcpy I_memcmp I_memmove I_strcpy I_strcat I_strchr I_strrchr I_strncmp I_strncpy I_strcmp I_strlen I_strtol I_sprintf I_toupper sysclib_IMPORTS_end stdio_IMPORTS_start I_printf I_putchar I_puts stdio_IMPORTS_end libsmb2-6.2/lib/ps2/ps2smb2.h0000664000175000017500000000105514732155517014733 0ustar polpypolpy/** * @file * PS2SMB2 definitions. */ #ifndef __PS2SMB2_H__ #define __PS2SMB2_H__ #define SMB2_PATH_MAX 1024 /* * DEVCTL commands */ #define SMB2_DEVCTL_CONNECT 0xC0DE0001 #define SMB2_DEVCTL_DISCONNECT_ALL 0xC0DE0002 /* * I/O structures for DEVCTL commands */ #define SMB2_MAX_NAME_LEN 32 typedef struct { char name[SMB2_MAX_NAME_LEN]; char username[32]; char password[32]; char url[256]; } smb2Connect_in_t; typedef struct { void *ctx; } smb2Connect_out_t; typedef struct { void *ctx; } smb2Disconnect_in_t; #endif /* __PS2SMB2_H__ */ libsmb2-6.2/lib/ps2/smb2_fio.c0000664000175000017500000004120514732155517015137 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* SMB2MAN Ronnie Sahlberg 2021 André Guilherme 2023-2024 Based on SMBMAN: Copyright 2009-2010, jimmikaelkael Licenced under Academic Free License version 3.0 */ #include "types.h" #include "defs.h" #include "irx.h" #include "intrman.h" #include "iomanX.h" #include "io_common.h" #include "sifman.h" #include "stdio.h" #include "sysclib.h" #include "thbase.h" #include "thsemap.h" #include "errno.h" #include "ps2smb2.h" #include "smb2_fio.h" #include "loadcore.h" #include #include #include #include /* Uncomment to enable debug logging */ /*#define DEBUG*/ #ifdef DEBUG #define SMB2_LOG_URL "smb://10.10.10.11/PS2SMB/ps2.log" #define SMB2_LOG_USER "user" #define SMB2_LOG_PASSWORD "password" struct smb2_context *log_smb2; struct smb2fh *log_fh; char log_buf[1024]; #define SMB2LOG(...) \ { \ int l; \ if (log_fh) { \ l = sprintf(log_buf, __VA_ARGS__); \ smb2_write(log_smb2, log_fh, (const u8 *)log_buf, l); \ } \ } #else #define SMB2LOG(...) #endif void free(void *); void *malloc(int); int smb2man_io_sema; static char *smb2_curdir; /* * Linked list of all connected shares. * Each share is presented as smb:/ */ struct smb2_share_list { struct smb2_share_list *next; char name[SMB2_MAX_NAME_LEN]; struct smb2_context *smb2; }; struct smb2_share_list *shares; #define smb2_io_lock() WaitSema(smb2man_io_sema) #define smb2_io_unlock() SignalSema(smb2man_io_sema) /* * Takes a path of the form / and returns the context that * represents and return the path within that share as **remainder. */ static struct smb2_context *find_context(char *path, char **remainder) { char *tmp; struct smb2_share_list *share = shares; tmp = strchr(path, '/'); if (tmp == NULL) { return NULL; } *tmp++ = 0; if (*remainder) { *remainder = tmp; } while (share) { if (strcmp(share->name, path)) { return share->smb2; } share = share->next; } return NULL; } static char *prepare_path(const char *path) { int i, len; char *p, *p2; len = strlen(path) + 1 + (smb2_curdir ? strlen(smb2_curdir) + 1 : 0); p = malloc(len); if (p == NULL) { return NULL; } p[0] = 0; if (smb2_curdir) { strcat(p, smb2_curdir); strcat(p, "/"); } strcat(p, path); for (i = strlen(p) - 1; i > 0; i--) { if (p[i] == '\\') { p[i] = '/'; } } /* strip trailing /. */ if (strlen(p) > 2) { p2 = p + strlen(p) - 2; if (!strcmp(p2, "/.")) { *p2 = 0; } } /* strip trailing /.. */ if (strlen(p) > 3) { p2 = p + strlen(p) - 3; if (!strcmp(p2, "/..")) { *p2 = 0; p2 = strrchr(p, '/'); if (p2 == NULL) { free(p); return NULL; } *p2 = 0; } } return p; } static int smb2_Connect(smb2Connect_in_t *in, smb2Connect_out_t *out) { struct smb2_share_list *share; struct smb2_url *url; int rc; if (out) { out->ctx = NULL; } #ifdef DEBUG if (log_smb2 == NULL) { log_smb2 = smb2_init_context(); smb2_set_timeout(log_smb2, 30); url = smb2_parse_url(log_smb2, SMB2_LOG_URL); smb2_set_password(log_smb2, SMB2_LOG_PASSWORD); if (smb2_connect_share(log_smb2, url->server, url->share, SMB2_LOG_USER)) { return -EIO; } log_fh = smb2_open(log_smb2, url->path, O_RDWR | O_CREAT); smb2_ftruncate(log_smb2, log_fh, 0); smb2_destroy_url(url); SMB2LOG("Logging started\n"); } #endif SMB2LOG("smb2_Connect: Try to connect %s as smb:/%s\n", in->url, in->name); share = malloc(sizeof(struct smb2_share_list)); if (share == NULL) { SMB2LOG("Failed to malloc share\n"); return -ENOMEM; } memset(share, 0, sizeof(struct smb2_share_list)); share->next = shares; strcpy(share->name, in->name); share->smb2 = smb2_init_context(); smb2_set_timeout(share->smb2, 30); if (share->smb2 == NULL) { SMB2LOG("Failed to initialize smb2 context\n"); free(share); return -ENOMEM; } url = smb2_parse_url(share->smb2, in->url); if (url == NULL) { SMB2LOG("Failed to parse URL: %s\n", in->url); free(share); return -EINVAL; } smb2_set_password(share->smb2, in->password); rc = smb2_connect_share(share->smb2, url->server, url->share, in->username); smb2_destroy_url(url); if (rc) { smb2_destroy_context(share->smb2); free(share); SMB2LOG("Failed to connect to share: %s %s\n", in->url, smb2_get_error(share->smb2)); return -EIO; } shares = share; if (out) { out->ctx = share->smb2; } SMB2LOG("Connected to share %s\n", in->url); return 0; } int SMB2_devctl(iop_file_t *f, const char *devname, int cmd, void *arg, unsigned int arglen, void *bufp, unsigned int buflen) { int r = 0; SMB2LOG("SMB2_devctl cmd:%d\n", cmd); smb2_io_lock(); switch (cmd) { case SMB2_DEVCTL_CONNECT: r = smb2_Connect((smb2Connect_in_t *)arg, (smb2Connect_out_t *)bufp); break; default: r = -EINVAL; } smb2_io_unlock(); return r; } struct dir_fh { struct smb2_context *smb2; struct smb2dir *fh; int is_root; struct smb2_share_list *shares; }; struct file_fh { struct smb2_context *smb2; struct smb2fh *fh; }; int SMB2_open(iop_file_t *f, const char *filename, int flags, int mode) { char *path = NULL, *p; struct smb2_context *smb2; struct file_fh *ffh = NULL; int rc = 0; SMB2LOG("SMB2_OPEN %s flags:%x\n", filename, flags); /* no writing, yet */ if (flags != O_RDONLY) { return -EROFS; } if (!filename) return -ENOENT; path = prepare_path(filename); if (path == NULL) { return -ENOMEM; } smb2 = find_context(path, &p); if (smb2 == NULL) { rc = -ENOENT; goto out; } ffh = malloc(sizeof(struct file_fh)); if (ffh == NULL) { rc = -ENOMEM; goto out; } smb2_io_lock(); ffh->smb2 = smb2; ffh->fh = smb2_open(smb2, p, flags); smb2_io_unlock(); if (ffh->fh == NULL) { rc = -EINVAL; goto out; } f->privdata = ffh; out: if (rc) { free(ffh); } free(path); return rc; } int SMB2_close(iop_file_t *f) { SMB2LOG("SMB2_CLOSE\n"); struct file_fh *ffh = f->privdata; if (ffh == NULL) { return -EBADF; } smb2_io_lock(); smb2_close(ffh->smb2, ffh->fh); smb2_io_unlock(); free(ffh); f->privdata = NULL; return 0; } int SMB2_dopen(iop_file_t *f, const char *dirname) { char *path = NULL, *p; struct smb2_context *smb2; struct dir_fh *dfh = NULL; int rc = 0; SMB2LOG("SMB2_DOPEN %s\n", dirname); if (!dirname) return -ENOENT; path = prepare_path(dirname); if (path == NULL) { return -ENOMEM; } /* TODO: * If path[0] == 0 then we are at the virtual root and should return * all the shares that are mounted. */ smb2 = find_context(path, &p); if (smb2 == NULL) { rc = -ENOENT; goto out; } dfh = malloc(sizeof(struct dir_fh)); if (dfh == NULL) { rc = -ENOMEM; goto out; } dfh->smb2 = smb2; if (p[0]) { dfh->is_root = false; smb2_io_lock(); dfh->fh = smb2_opendir(smb2, p); smb2_io_unlock(); } else { dfh->is_root = true; dfh->shares = shares; } if (dfh->fh == NULL) { rc = -EINVAL; goto out; } f->privdata = dfh; out: if (rc) { free(dfh); } free(path); return rc; } int SMB2_dclose(iop_file_t *f) { struct dir_fh *dfh = f->privdata; if (dfh == NULL) { return -EBADF; } if (!dfh->is_root) { smb2_closedir(dfh->smb2, dfh->fh); } free(dfh); f->privdata = NULL; return 0; } static void FileTimeToDate(u64 t, u8 *datetime) { u8 daysPerMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int i; u64 time; u16 years, days; u8 leapdays, months, hours, minutes, seconds; time = t / 10000000; /* convert to seconds from 100-nanosecond intervals */ years = (u16)(time / ((u64)60 * 60 * 24 * 365)); /* hurray for interger division */ time -= years * ((u64)60 * 60 * 24 * 365); /* truncate off the years */ leapdays = (years / 4) - (years / 100) + (years / 400); years += 1601; /* add base year from FILETIME struct; */ days = (u16)(time / (60 * 60 * 24)); time -= (u32)days * (60 * 60 * 24); days -= leapdays; if ((years % 4) == 0 && ((years % 100) != 0 || (years % 400) == 0)) daysPerMonth[1]++; months = 0; for (i = 0; i < 12; i++) { if (days > daysPerMonth[i]) { days -= daysPerMonth[i]; months++; } else break; } if (months >= 12) { months -= 12; years++; } hours = (u8)(time / (60 * 60)); time -= (u16)hours * (60 * 60); minutes = (u8)(time / 60); time -= minutes * 60; seconds = (u8)(time); datetime[0] = 0; datetime[1] = seconds; datetime[2] = minutes; datetime[3] = hours; datetime[4] = days + 1; datetime[5] = months + 1; datetime[6] = (u8)(years & 0xFF); datetime[7] = (u8)((years >> 8) & 0xFF); } static void smb2_statFiller(struct smb2_stat_64 *st, iox_stat_t *stat) { FileTimeToDate(st->smb2_ctime, stat->ctime); FileTimeToDate(st->smb2_atime, stat->atime); FileTimeToDate(st->smb2_mtime, stat->mtime); stat->size = (int)(st->smb2_size & 0xffffffff); stat->hisize = (int)((st->smb2_size >> 32) & 0xffffffff); stat->mode = (st->smb2_type == SMB2_TYPE_DIRECTORY) ? FIO_S_IFDIR : FIO_S_IFREG; } int SMB2_dread(iop_file_t *f, iox_dirent_t *dirent) { struct dir_fh *dfh = f->privdata; struct smb2dirent *de; if (dfh == NULL) { return -EBADF; } if (!dfh->is_root) { de = smb2_readdir(dfh->smb2, dfh->fh); if (de == NULL) { return 0; } } else { if (dfh->shares == NULL) { return 0; } memset(&dirent->stat, 0, sizeof(iox_stat_t)); strncpy(dirent->name, dfh->shares->name, 256); dirent->stat.mode = FIO_S_IFDIR; dfh->shares = dfh->shares->next; return 1; } SMB2LOG("SMB2_DREAD %s\n", de->name); strncpy(dirent->name, de->name, 256); smb2_statFiller(&de->st, &dirent->stat); return 1; } int SMB2_getstat(iop_file_t *f, const char *filename, iox_stat_t *stat) { char *path = NULL, *p; struct smb2_context *smb2; struct smb2_stat_64 st; int rc = 0; SMB2LOG("SMB2_GETSTAT %s\n", filename); if (!filename) return -ENOENT; path = prepare_path(filename); if (path == NULL) { return -ENOMEM; } smb2 = find_context(path, &p); if (smb2 == NULL) { rc = -ENOENT; goto out; } memset((void *)stat, 0, sizeof(iox_stat_t)); smb2_io_lock(); rc = smb2_stat(smb2, p, &st); smb2_io_unlock(); if (rc) { goto out; } smb2_statFiller(&st, stat); out: free(path); return rc; } s64 SMB2_lseek64(iop_file_t *f, s64 pos, int whence) { struct file_fh *ffh = f->privdata; int rc = 0; SMB2LOG("SMB2_LSEEK64 pos:%d whence:%d\n", (int)pos, whence); rc = smb2_lseek(ffh->smb2, ffh->fh, pos, whence, NULL); return rc; } int SMB2_lseek(iop_file_t *f, int pos, int where) { return (int)SMB2_lseek64(f, pos, where); } int SMB2_read(iop_file_t *f, void *buf, int size) { struct file_fh *ffh = f->privdata; int rc; SMB2LOG("SMB2_READ len:%d\n", size); if (ffh == NULL) { return -EBADF; } smb2_io_lock(); rc = smb2_read(ffh->smb2, ffh->fh, buf, size); smb2_io_unlock(); return rc; } int SMB2_write(iop_file_t *f, void *buf, int size) { struct file_fh *ffh = f->privdata; int rc; SMB2LOG("SMB2_write %d\n", size); smb2_io_lock(); rc = smb2_write(ffh->smb2, ffh->fh, buf, size); smb2_io_unlock(); return rc; } int SMB2_mkdir(iop_file_t *f, const char *dirname, int mode) { char *path = NULL, *p; struct smb2_context *smb2; int rc; SMB2LOG("SMB2_mkdir %s\n", dirname); if (!dirname) return -ENOENT; path = prepare_path(dirname); if (path == NULL) { return -ENOMEM; } smb2 = find_context(path, &p); if (smb2 == NULL) { rc = -ENOENT; goto out; } smb2_io_lock(); rc = smb2_mkdir(smb2, p); smb2_io_unlock(); out: free(path); return rc; } int SMB2_rmdir(iop_file_t *f, const char *dirname) { char *path = NULL, *p; struct smb2_context *smb2; int rc; SMB2LOG("SMB2_rmdir %s\n", dirname); if (!dirname) return -ENOENT; path = prepare_path(dirname); if (path == NULL) { return -ENOMEM; } smb2 = find_context(path, &p); if (smb2 == NULL) { rc = -ENOENT; goto out; } smb2_io_lock(); rc = smb2_rmdir(smb2, p); smb2_io_unlock(); out: free(path); return rc; } int SMB2_remove(iop_file_t *f, const char *filename) { char *path = NULL, *p; struct smb2_context *smb2; int rc; SMB2LOG("SMB2_remove %s\n", filename); if (!filename) return -ENOENT; path = prepare_path(filename); if (path == NULL) { return -ENOMEM; } smb2 = find_context(path, &p); if (smb2 == NULL) { rc = -ENOENT; goto out; } smb2_io_lock(); rc = smb2_unlink(smb2, p); smb2_io_unlock(); out: free(path); return rc; } int SMB2_rename(iop_file_t *f, const char *oldname, const char *newname) { char *oldpath = NULL, *newpath = NULL, *oldp, *newp; struct smb2_context *oldsmb2, *newsmb2; int rc = 0; SMB2LOG("SMB2_rename %s -> %s\n", oldname, newname); oldpath = prepare_path(oldname); if (oldpath == NULL) { rc = -ENOMEM; goto out; } oldsmb2 = find_context(oldpath, &oldp); if (oldsmb2 == NULL) { rc = -ENOENT; goto out; } newpath = prepare_path(newname); if (newpath == NULL) { rc = -ENOMEM; goto out; } newsmb2 = find_context(newpath, &newp); if (newsmb2 == NULL) { rc = -ENOENT; goto out; } if (newsmb2 != oldsmb2) { rc = -EINVAL; goto out; } smb2_io_lock(); rc = smb2_rename(oldsmb2, oldp, newp); smb2_io_unlock(); out: free(oldpath); free(newpath); return rc; } int SMB2_dummy(void) { SMB2LOG("SMB2_dummy\n"); return -EIO; } int SMB2_chdir(iop_file_t *f, const char *dirname) { char *path; SMB2LOG("SMB2_chdir %s\n", dirname); if (!dirname) return -ENOENT; path = prepare_path(dirname); if (path == NULL) { return -ENOMEM; } free(smb2_curdir); smb2_curdir = path; return 0; } int SMB2_deinit(iop_device_t *dev) { SMB2LOG("SMB2_deinit\n"); DeleteSema(smb2man_io_sema); return 0; } int SMB2_init(iop_device_t *dev) { SMB2LOG("SMB2_init\n"); smb2man_io_sema = CreateMutex(IOP_MUTEX_UNLOCKED); return 0; } static iop_device_ops_t smb2man_ops = { &SMB2_init, &SMB2_deinit, (void *)&SMB2_dummy, &SMB2_open, &SMB2_close, &SMB2_read, &SMB2_write, &SMB2_lseek, (void *)&SMB2_dummy, &SMB2_remove, &SMB2_mkdir, &SMB2_rmdir, &SMB2_dopen, &SMB2_dclose, &SMB2_dread, &SMB2_getstat, (void *)&SMB2_dummy, &SMB2_rename, &SMB2_chdir, (void *)&SMB2_dummy, (void *)&SMB2_dummy, (void *)&SMB2_dummy, &SMB2_lseek64, &SMB2_devctl, (void *)&SMB2_dummy, (void *)&SMB2_dummy, (void *)&SMB2_dummy}; static iop_device_t smb2dev = { "smb", IOP_DT_FS | IOP_DT_FSEXT, 1, "SMB", &smb2man_ops}; int SMB2_initdev(void) { DelDrv(smb2dev.name); if (AddDrv((iop_device_t *)&smb2dev)) return MODULE_NO_RESIDENT_END; return MODULE_RESIDENT_END; } libsmb2-6.2/lib/ps2/smb2man.c0000664000175000017500000000242314732155517014775 0ustar polpypolpy/* SMB2MAN Ronnie Sahlberg 2021 André Guilherme 2023-2024 Based on SMBMAN: Copyright 2009-2010, jimmikaelkael Licenced under Academic Free License version 3.0 */ #include "types.h" #include "defs.h" #include "intrman.h" #include "irx.h" #include "iomanX.h" #include "loadcore.h" #include "stdio.h" #include "sysclib.h" #include "sysmem.h" #include "smb2_fio.h" #define MODNAME "smb2man" #define VER_MAJOR 2 #define VER_MINOR 2 IRX_ID(MODNAME, VER_MAJOR, VER_MINOR); int _start(int argc, char *argv[]) { (void)argc; (void)argv; printf("%s version 0x%01x%02x - Copyright(c) 2021 Ronnie Sahlberg, Copyright(c) 2023-2024 André Guilherme, Copyright(c) 2024-Present PS2DEV \n", MODNAME, VER_MAJOR, VER_MINOR); return SMB2_initdev(); } void *malloc(int size) { void *result; int OldState; CpuSuspendIntr(&OldState); result = AllocSysMemory(ALLOC_FIRST, size, NULL); CpuResumeIntr(OldState); return result; } void free(void *ptr) { int OldState; CpuSuspendIntr(&OldState); FreeSysMemory(ptr); CpuResumeIntr(OldState); } void *calloc(size_t nmemb, size_t size) { size_t s = nmemb * size; void *ptr; ptr = malloc(s); memset(ptr, 0, s); return ptr; }libsmb2-6.2/lib/ps2/smb2_fio.h0000664000175000017500000000046314732155517015145 0ustar polpypolpy/* SMB2MAN Ronnie Sahlberg 2021 André Guilherme 2023-2024 Based on SMBMAN: Copyright 2009-2010, jimmikaelkael Licenced under Academic Free License version 3.0 */ #ifndef __SMB2_FIO_H__ #define __SMB2_FIO_H__ int SMB2_initdev(void); #endif libsmb2-6.2/lib/sha.h0000664000175000017500000002317014732155517013514 0ustar polpypolpy/**************************** sha.h ****************************/ /******************* See RFC 4634 for details ******************/ #ifndef _SHA_H_ #define _SHA_H_ #ifndef USE_SHA1 #define USE_SHA1 0 #endif #ifndef USE_SHA224 #define USE_SHA224 0 #endif #ifndef USE_SHA384_SHA512 #define USE_SHA384_SHA512 1 #endif /* * Description: * This file implements the Secure Hash Signature Standard * algorithms as defined in the National Institute of Standards * and Technology Federal Information Processing Standards * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 * published on August 1, 2002, and the FIPS PUB 180-2 Change * Notice published on February 28, 2004. * * A combined document showing all algorithms is available at * http://csrc.nist.gov/publications/fips/ * fips180-2/fips180-2withchangenotice.pdf * * The five hashes are defined in these sizes: * SHA-1 20 byte / 160 bit * SHA-224 28 byte / 224 bit * SHA-256 32 byte / 256 bit * SHA-384 48 byte / 384 bit * SHA-512 64 byte / 512 bit */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif /* * If you do not have the ISO standard stdint.h header file, then you * must typedef the following: * name meaning * uint64_t unsigned 64 bit integer * uint32_t unsigned 32 bit integer * uint8_t unsigned 8 bit integer (i.e., unsigned char) * int_least16_t integer of >= 16 bits * */ #ifndef _SHA_enum_ #define _SHA_enum_ /* * All SHA functions return one of these values. */ enum { shaSuccess = 0, shaNull, /* Null pointer parameter */ shaInputTooLong, /* input data too long */ shaStateError, /* called Input after FinalBits or Result */ shaBadParam /* passed a bad parameter */ }; #endif /* _SHA_enum_ */ /* * These constants hold size information for each of the SHA * hashing operations */ enum { #if defined(USE_SHA1) && USE_SHA1 SHA1_Message_Block_Size = 64, SHA1HashSize = 20, SHA1HashSizeBits = 160, #endif #if defined(USE_SHA224) && USE_SHA224 SHA224_Message_Block_Size = 64, SHA224HashSize = 28, SHA224HashSizeBits = 224, #endif #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 SHA384_Message_Block_Size = 128, SHA384HashSize = 48, SHA384HashSizeBits = 384, #endif SHA256_Message_Block_Size = 64, SHA512_Message_Block_Size = 128, USHA_Max_Message_Block_Size = SHA512_Message_Block_Size, SHA256HashSize = 32, SHA512HashSize = 64, USHAMaxHashSize = SHA512HashSize, SHA256HashSizeBits = 256, SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits }; /* * These constants are used in the USHA (unified sha) functions. */ typedef enum SHAversion { #if defined(USE_SHA1) && USE_SHA1 SHA1, #endif #if defined(USE_SHA224) && USE_SHA224 SHA224, #endif #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 SHA384, SHA512, #endif SHA256 } SHAversion; #if defined(USE_SHA1) && USE_SHA1 /* * This structure will hold context information for the SHA-1 * hashing operation. */ typedef struct SHA1Context { uint32_t Intermediate_Hash[SHA1HashSize / 4]; /* Message Digest */ uint32_t Length_Low; /* Message length in bits */ uint32_t Length_High; /* Message length in bits */ int_least16_t Message_Block_Index; /* Message_Block array index */ /* 512-bit message blocks */ uint8_t Message_Block[SHA1_Message_Block_Size]; int Computed; /* Is the digest computed? */ int Corrupted; /* Is the digest corrupted? */ } SHA1Context; #endif /* * This structure will hold context information for the SHA-256 * hashing operation. */ typedef struct SHA256Context { uint32_t Intermediate_Hash[SHA256HashSize / 4]; /* Message Digest */ uint32_t Length_Low; /* Message length in bits */ uint32_t Length_High; /* Message length in bits */ int_least16_t Message_Block_Index; /* Message_Block array index */ /* 512-bit message blocks */ uint8_t Message_Block[SHA256_Message_Block_Size]; int Computed; /* Is the digest computed? */ int Corrupted; /* Is the digest corrupted? */ } SHA256Context; /* * This structure will hold context information for the SHA-512 * hashing operation. */ typedef struct SHA512Context { #ifdef USE_32BIT_ONLY uint32_t Intermediate_Hash[SHA512HashSize / 4]; /* Message Digest */ uint32_t Length[4]; /* Message length in bits */ #else /* !USE_32BIT_ONLY */ uint64_t Intermediate_Hash[SHA512HashSize / 8]; /* Message Digest */ uint64_t Length_Low, Length_High; /* Message length in bits */ #endif /* USE_32BIT_ONLY */ int_least16_t Message_Block_Index; /* Message_Block array index */ /* 1024-bit message blocks */ uint8_t Message_Block[SHA512_Message_Block_Size]; int Computed; /* Is the digest computed? */ int Corrupted; /* Is the digest corrupted? */ } SHA512Context; #if defined(USE_SHA224) && USE_SHA224 /* * This structure will hold context information for the SHA-224 * hashing operation. It uses the SHA-256 structure for computation. */ typedef struct SHA256Context SHA224Context; #endif #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 /* * This structure will hold context information for the SHA-384 * hashing operation. It uses the SHA-512 structure for computation. */ typedef struct SHA512Context SHA384Context; #endif /* * This structure holds context information for all SHA * hashing operations. */ typedef struct USHAContext { SHAversion whichSha; /* which SHA is being used */ union { #if defined(USE_SHA1) && USE_SHA1 SHA1Context sha1Context; #endif #if defined(USE_SHA224) && USE_SHA224 SHA224Context sha224Context; #endif SHA256Context sha256Context; #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 SHA384Context sha384Context; SHA512Context sha512Context; #endif } ctx; } USHAContext; /* * This structure will hold context information for the HMAC * keyed hashing operation. */ typedef struct HMACContext { SHAversion whichSha; /* which SHA is being used */ int hashSize; /* hash size of SHA being used */ int blockSize; /* block size of SHA being used */ USHAContext shaContext; /* SHA context */ unsigned char k_opad[USHA_Max_Message_Block_Size]; /* outer padding - key XORd with opad */ } HMACContext; /* * Function Prototypes */ #if defined(USE_SHA1) && USE_SHA1 /* SHA-1 */ extern int SHA1Reset (SHA1Context *); extern int SHA1Input (SHA1Context *, const uint8_t * bytes, size_t bytecount); extern int SHA1FinalBits (SHA1Context *, const uint8_t bits, size_t bitcount); extern int SHA1Result (SHA1Context *, uint8_t Message_Digest[SHA1HashSize]); #endif #if defined(USE_SHA224) && USE_SHA224 /* SHA-224 */ extern int SHA224Reset (SHA224Context *); extern int SHA224Input (SHA224Context *, const uint8_t * bytes, size_t bytecount); extern int SHA224FinalBits (SHA224Context *, const uint8_t bits, size_t bitcount); extern int SHA224Result (SHA224Context *, uint8_t Message_Digest[SHA224HashSize]); #endif /* SHA-256 */ extern int SHA256Reset (SHA256Context *); extern int SHA256Input (SHA256Context *, const uint8_t * bytes, size_t bytecount); extern int SHA256FinalBits (SHA256Context *, const uint8_t bits, size_t bitcount); extern int SHA256Result (SHA256Context *, uint8_t Message_Digest[SHA256HashSize]); #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 /* SHA-384 */ extern int SHA384Reset (SHA384Context *); extern int SHA384Input (SHA384Context *, const uint8_t * bytes, size_t bytecount); extern int SHA384FinalBits (SHA384Context *, const uint8_t bits, size_t bitcount); extern int SHA384Result (SHA384Context *, uint8_t Message_Digest[SHA384HashSize]); /* SHA-512 */ extern int SHA512Reset (SHA512Context *); extern int SHA512Input (SHA512Context *, const uint8_t * bytes, size_t bytecount); extern int SHA512FinalBits (SHA512Context *, const uint8_t bits, size_t bitcount); extern int SHA512Result (SHA512Context *, uint8_t Message_Digest[SHA512HashSize]); #endif /* Unified SHA functions, chosen by whichSha */ extern int USHAReset (USHAContext *, SHAversion whichSha); extern int USHAInput (USHAContext *, const uint8_t * bytes, size_t bytecount); extern int USHAFinalBits (USHAContext *, const uint8_t bits, size_t bitcount); extern int USHAResult (USHAContext *, uint8_t Message_Digest[USHAMaxHashSize]); extern int USHABlockSize (enum SHAversion whichSha); extern int USHAHashSize (enum SHAversion whichSha); extern int USHAHashSizeBits (enum SHAversion whichSha); /* * HMAC Keyed-Hashing for Message Authentication, RFC2104, * for all SHAs. * This interface allows a fixed-length text input to be used. */ extern int hmac (SHAversion whichSha, /* which SHA algorithm to use */ const unsigned char *text, /* pointer to data stream */ size_t text_len, /* length of data stream */ const unsigned char *key, /* pointer to authentication key */ size_t key_len, /* length of authentication key */ uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ /* * HMAC Keyed-Hashing for Message Authentication, RFC2104, * for all SHAs. * This interface allows any length of text input to be used. */ extern int hmacReset (HMACContext * ctx, enum SHAversion whichSha, const unsigned char *key, size_t key_len); extern int hmacInput (HMACContext * ctx, const unsigned char *text, size_t text_len); extern int hmacFinalBits (HMACContext * ctx, const uint8_t bits, size_t bitcount); extern int hmacResult (HMACContext * ctx, uint8_t *digest); #endif /* _SHA_H_ */ libsmb2-6.2/lib/hmac.c0000664000175000017500000001405714732155517013650 0ustar polpypolpy/**************************** hmac.c ****************************/ /******************** See RFC 4634 for details ******************/ /* * Description: * This file implements the HMAC algorithm (Keyed-Hashing for * Message Authentication, RFC2104), expressed in terms of the * various SHA algorithms. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include "compat.h" #include "sha.h" /* * hmac * * Description: * This function will compute an HMAC message digest. * * Parameters: * whichSha: [in] * One of SHA1, SHA224, SHA256, SHA384, SHA512 * key: [in] * The secret shared key. * key_len: [in] * The length of the secret shared key. * message_array: [in] * An array of characters representing the message. * length: [in] * The length of the message in message_array * digest: [out] * Where the digest is returned. * NOTE: The length of the digest is determined by * the value of whichSha. * * Returns: * sha Error Code. * */ int hmac (SHAversion whichSha, const unsigned char *text, size_t text_len, const unsigned char *key, size_t key_len, uint8_t digest[USHAMaxHashSize]) { HMACContext ctx; return hmacReset (&ctx, whichSha, key, key_len) || hmacInput (&ctx, text, text_len) || hmacResult (&ctx, digest); } /* * hmacReset * * Description: * This function will initialize the hmacContext in preparation * for computing a new HMAC message digest. * * Parameters: * context: [in/out] * The context to reset. * whichSha: [in] * One of SHA1, SHA224, SHA256, SHA384, SHA512 * key: [in] * The secret shared key. * key_len: [in] * The length of the secret shared key. * * Returns: * sha Error Code. * */ int hmacReset (HMACContext * ctx, enum SHAversion whichSha, const unsigned char *key, size_t key_len) { int i, blocksize, hashsize; /* inner padding - key XORd with ipad */ unsigned char k_ipad[USHA_Max_Message_Block_Size]; /* temporary buffer when keylen > blocksize */ unsigned char tempkey[USHAMaxHashSize]; if (!ctx) return shaNull; blocksize = ctx->blockSize = USHABlockSize (whichSha); hashsize = ctx->hashSize = USHAHashSize (whichSha); ctx->whichSha = whichSha; /* * If key is longer than the hash blocksize, * reset it to key = HASH(key). */ if (key_len > (size_t)blocksize) { USHAContext tctx; int err = USHAReset (&tctx, whichSha) || USHAInput (&tctx, key, key_len) || USHAResult (&tctx, tempkey); if (err != shaSuccess) return err; key = tempkey; key_len = hashsize; } /* * The HMAC transform looks like: * * SHA(K XOR opad, SHA(K XOR ipad, text)) * * where K is an n byte key. * ipad is the byte 0x36 repeated blocksize times * opad is the byte 0x5c repeated blocksize times * and text is the data being protected. */ /* store key into the pads, XOR'd with ipad and opad values */ for (i = 0; i < (int)key_len; i++) { k_ipad[i] = key[i] ^ 0x36; ctx->k_opad[i] = key[i] ^ 0x5c; } /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ for (; i < blocksize; i++) { k_ipad[i] = 0x36; ctx->k_opad[i] = 0x5c; } /* perform inner hash */ /* init context for 1st pass */ return USHAReset (&ctx->shaContext, whichSha) || /* and start with inner pad */ USHAInput (&ctx->shaContext, k_ipad, blocksize); } /* * hmacInput * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The HMAC context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */ int hmacInput (HMACContext * ctx, const unsigned char *text, size_t text_len) { if (!ctx) return shaNull; /* then text of datagram */ return USHAInput (&ctx->shaContext, text, text_len); } /* * HMACFinalBits * * Description: * This function will add in any final bits of the message. * * Parameters: * context: [in/out] * The HMAC context to update * message_bits: [in] * The final bits of the message, in the upper portion of the * byte. (Use 0b###00000 instead of 0b00000### to input the * three bits ###.) * length: [in] * The number of bits in message_bits, between 1 and 7. * * Returns: * sha Error Code. */ int hmacFinalBits (HMACContext * ctx, const uint8_t bits, size_t bitcount) { if (!ctx) return shaNull; /* then final bits of datagram */ return USHAFinalBits (&ctx->shaContext, bits, bitcount); } /* * HMACResult * * Description: * This function will return the N-byte message digest into the * Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the Nth element. * * Parameters: * context: [in/out] * The context to use to calculate the HMAC hash. * digest: [out] * Where the digest is returned. * NOTE 2: The length of the hash is determined by the value of * whichSha that was passed to hmacReset(). * * Returns: * sha Error Code. * */ int hmacResult (HMACContext * ctx, uint8_t * digest) { if (!ctx) return shaNull; /* finish up 1st pass */ /* (Use digest here as a temporary buffer.) */ return USHAResult (&ctx->shaContext, digest) || /* perform outer SHA */ /* init context for 2nd pass */ USHAReset (&ctx->shaContext, ctx->whichSha) || /* start with outer pad */ USHAInput (&ctx->shaContext, ctx->k_opad, ctx->blockSize) || /* then results of 1st hash */ USHAInput (&ctx->shaContext, digest, ctx->hashSize) || /* finish up 2nd pass */ USHAResult (&ctx->shaContext, digest); } libsmb2-6.2/lib/smb2-cmd-set-info.c0000664000175000017500000002657014732155517016071 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_set_info_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_set_info_request *req) { int i, len; uint16_t ch; uint8_t *buf; struct smb2_iovec *iov; struct smb2_file_end_of_file_info *eofi; struct smb2_file_disposition_info *fdi; struct smb2_file_rename_info *rni; struct smb2_utf16 *name; len = SMB2_SET_INFO_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate set info buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_SET_INFO_REQUEST_SIZE); smb2_set_uint8(iov, 2, req->info_type); smb2_set_uint8(iov, 3, req->file_info_class); smb2_set_uint16(iov,8, SMB2_HEADER_SIZE + 32); /* buffer offset */ smb2_set_uint32(iov,12, req->additional_information); memcpy(iov->buf + 16, req->file_id, SMB2_FD_SIZE); if (smb2->passthrough) { if (req->buffer_length) { buf = malloc(PAD_TO_32BIT(req->buffer_length)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate set " "info data buffer"); return -1; } memcpy(buf, req->input_data, req->buffer_length); smb2_add_iovector(smb2, &pdu->out, buf, req->buffer_length, free); } smb2_set_uint32(iov, 4, req->buffer_length); smb2_set_uint16(iov, 8, req->buffer_offset); return 0; } switch (req->info_type) { case SMB2_0_INFO_FILE: switch (req->file_info_class) { case SMB2_FILE_BASIC_INFORMATION: len = 40; smb2_set_uint32(iov, 4, len); /* buffer length */ buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate set " "info data buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_encode_file_basic_info(smb2, req->input_data, iov); break; case SMB2_FILE_END_OF_FILE_INFORMATION: len = 8; smb2_set_uint32(iov, 4, len); /* buffer length */ buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate set " "info data buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); eofi = req->input_data; smb2_set_uint64(iov, 0, eofi->end_of_file); break; case SMB2_FILE_RENAME_INFORMATION: rni = req->input_data; name = smb2_utf8_to_utf16((char *)(rni->file_name)); if (name == NULL) { smb2_set_error(smb2, "Could not convert name into UTF-16"); return -1; } /* Convert '/' to '\' */ for (i = 0; i < name->len; i++) { smb2_get_uint16(iov, i * 2, &ch); if (ch == 0x002f) { smb2_set_uint16(iov, i * 2, 0x005c); } } len = 20 + name->len * 2; smb2_set_uint32(iov, 4, len); /* buffer length */ buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate set " "info data buffer"); free(name); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint8(iov, 0, rni->replace_if_exist); smb2_set_uint64(iov, 8, 0u); smb2_set_uint32(iov, 16, name->len * 2); memcpy(iov->buf + 20, name->val, name->len * 2); free(name); break; case SMB2_FILE_DISPOSITION_INFORMATION: len = 1; smb2_set_uint32(iov, 4, len); /* buffer length */ buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate set " "info data buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); fdi = req->input_data; smb2_set_uint8(iov, 0, fdi->delete_pending); break; default: smb2_set_error(smb2, "Can not enccode info_type/" "info_class %d/%d yet", req->info_type, req->file_info_class); return -1; } break; default: smb2_set_error(smb2, "Can not encode file info_type %d yet", req->info_type); return -1; } return 0; } struct smb2_pdu * smb2_cmd_set_info_async(struct smb2_context *smb2, struct smb2_set_info_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_SET_INFO, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_set_info_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_set_info_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_set_info_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_SET_INFO_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate set info buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_SET_INFO_REPLY_SIZE); return 0; } struct smb2_pdu * smb2_cmd_set_info_reply_async(struct smb2_context *smb2, struct smb2_set_info_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_SET_INFO, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_set_info_reply(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_set_info_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { return 0; } int smb2_process_set_info_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_set_info_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_SET_INFO_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of set " "info request. Expected %d, got %d", SMB2_SET_INFO_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate set-info request"); return -1; } pdu->payload = req; smb2_get_uint8(iov, 2, &req->info_type); smb2_get_uint8(iov, 3, &req->file_info_class); smb2_get_uint32(iov, 4, &req->buffer_length); smb2_get_uint16(iov, 8, &req->buffer_offset); smb2_get_uint32(iov, 12, &req->additional_information); memcpy(req->file_id, iov->buf + 16, SMB2_FD_SIZE); return req->buffer_length; } int smb2_process_set_info_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_set_info_request *req = (struct smb2_set_info_request*)pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; if (!smb2->passthrough) { smb2_set_error(smb2, "can not interpret set-info buffers yet"); return -1; } req->input_data = iov->buf; return 0; } libsmb2-6.2/lib/libsmb2.c0000664000175000017500000042567714732155517014310 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg Portions of this code are copyright 2017 to Primary Data Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include #include #ifdef HAVE_SYS_POLL_H #include #endif #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_SYS_FCNTL_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #if defined(_WIN32) || defined(_XBOX) || defined(__AROS__) #include "asprintf.h" #endif #include "compat.h" #include "sha.h" #include "sha-private.h" #include "slist.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" #include "portable-endian.h" #include "ntlmssp.h" #ifdef HAVE_LIBKRB5 #include "krb5-wrapper.h" #endif #include "spnego-wrapper.h" #if defined(ESP_PLATFORM) #define DEFAULT_OUTPUT_BUFFER_LENGTH 512 #elif defined(__PS2__) #define DEFAULT_OUTPUT_BUFFER_LENGTH 4096 #else #define DEFAULT_OUTPUT_BUFFER_LENGTH 0xffff #endif /* strings used to derive SMB signing and encryption keys */ static const char SMBSigningKey[] = "SMBSigningKey"; static const char SMBC2SCipherKey[] = "SMBC2SCipherKey"; static const char SMBS2CCipherKey[] = "SMBS2CCipherKey"; static const char SMB2AESCMAC[] = "SMB2AESCMAC"; static const char SmbSign[] = "SmbSign"; static const char SMB2AESCCM[] = "SMB2AESCCM"; static const char ServerOut[] = "ServerOut"; static const char ServerIn[] = "ServerIn "; /* The following strings will be used for deriving other keys */ #if 0 static const char SMB2APP[] = "SMB2APP"; static const char SmbRpc[] = "SmbRpc"; static const char SMBAppKey[] = "SMBAppKey"; #endif const smb2_file_id compound_file_id = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; struct connect_data { smb2_command_cb cb; void *cb_data; const char *server; const char *share; const char *user; /* UNC for the share in utf8 as well as utf16 formats */ char *utf8_unc; struct smb2_utf16 *utf16_unc; void *auth_data; /* if context is being served by our server */ struct smb2_server *server_context; }; struct smb2fh { struct smb2fh *next; smb2_command_cb cb; void *cb_data; smb2_file_id file_id; int64_t offset; int64_t end_of_file; }; void smb2_close_context(struct smb2_context *smb2) { if (smb2 == NULL) { return; } if (SMB2_VALID_SOCKET(smb2->fd)) { if (smb2->change_fd) { smb2->change_fd(smb2, smb2->fd, SMB2_DEL_FD); } close(smb2->fd); smb2->fd = SMB2_INVALID_SOCKET; } smb2->message_id = 0; smb2->session_id = 0; smb2->tree_id_top = 0; smb2->tree_id_cur = 0; smb2->tree_id[0] = 0xdeadbeef; memset(smb2->signing_key, 0, SMB2_KEY_SIZE); if (smb2->session_key) { free(smb2->session_key); smb2->session_key = NULL; } smb2->session_key_size = 0; } static int send_session_setup_request(struct smb2_context *smb2, struct connect_data *c_data, unsigned char *buf, int len); static void free_smb2dir(struct smb2_context *smb2, struct smb2dir *dir) { SMB2_LIST_REMOVE(&smb2->dirs, dir); while (dir->entries) { struct smb2_dirent_internal *e = dir->entries->next; free(discard_const(dir->entries->dirent.name)); free(dir->entries); dir->entries = e; } if (dir->free_cb_data) { dir->free_cb_data(dir->cb_data); } free(dir); } void smb2_free_all_dirs(struct smb2_context *smb2) { while (smb2->dirs) { free_smb2dir(smb2, smb2->dirs); } } void smb2_seekdir(struct smb2_context *smb2, struct smb2dir *dir, long loc) { if (dir == NULL){ return; } dir->current_entry = dir->entries; dir->index = 0; while (dir->current_entry && loc--) { dir->current_entry = dir->current_entry->next; dir->index++; } } long smb2_telldir(struct smb2_context *smb2, struct smb2dir *dir) { if (dir == NULL) { return -EINVAL; } return dir->index; } void smb2_rewinddir(struct smb2_context *smb2, struct smb2dir *dir) { if (dir == NULL) { return; } dir->current_entry = dir->entries; dir->index = 0; } struct smb2dirent * smb2_readdir(struct smb2_context *smb2, struct smb2dir *dir) { struct smb2dirent *ent; if ((dir == NULL) || (dir->current_entry == NULL)) { return NULL; } ent = &dir->current_entry->dirent; dir->current_entry = dir->current_entry->next; dir->index++; return ent; } void smb2_closedir(struct smb2_context *smb2, struct smb2dir *dir) { if ((smb2 == NULL) || (dir == NULL)) { return; } free_smb2dir(smb2, dir); } static int decode_dirents(struct smb2_context *smb2, struct smb2dir *dir, struct smb2_iovec *vec) { struct smb2_dirent_internal *ent; struct smb2_fileidfulldirectoryinformation fs; uint32_t offset = 0; do { struct smb2_iovec tmp_vec _U_; /* Make sure we do not go beyond end of vector */ if (offset >= vec->len) { smb2_set_error(smb2, "Malformed query reply."); return -1; } ent = calloc(1, sizeof(struct smb2_dirent_internal)); if (ent == NULL) { smb2_set_error(smb2, "Failed to allocate " "dirent_internal"); return -1; } SMB2_LIST_ADD(&dir->entries, ent); tmp_vec.buf = &vec->buf[offset]; tmp_vec.len = vec->len - offset; smb2_decode_fileidfulldirectoryinformation(smb2, &fs, &tmp_vec); /* steal the name */ ent->dirent.name = fs.name; ent->dirent.st.smb2_type = SMB2_TYPE_FILE; if (fs.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) { ent->dirent.st.smb2_type = SMB2_TYPE_DIRECTORY; } if (fs.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) { ent->dirent.st.smb2_type = SMB2_TYPE_LINK; } ent->dirent.st.smb2_nlink = 0; ent->dirent.st.smb2_ino = fs.file_id; ent->dirent.st.smb2_size = fs.end_of_file; ent->dirent.st.smb2_atime = fs.last_access_time.tv_sec; ent->dirent.st.smb2_atime_nsec = fs.last_access_time.tv_usec * 1000; ent->dirent.st.smb2_mtime = fs.last_write_time.tv_sec; ent->dirent.st.smb2_mtime_nsec = fs.last_write_time.tv_usec * 1000; ent->dirent.st.smb2_ctime = fs.change_time.tv_sec; ent->dirent.st.smb2_ctime_nsec = fs.change_time.tv_usec * 1000; ent->dirent.st.smb2_btime = fs.creation_time.tv_sec; ent->dirent.st.smb2_btime_nsec = fs.creation_time.tv_usec * 1000; offset += fs.next_entry_offset; } while (fs.next_entry_offset); return 0; } static void od_close_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2dir *dir = private_data; if (status != SMB2_STATUS_SUCCESS) { dir->cb(smb2, -nterror_to_errno(status), NULL, dir->cb_data); free_smb2dir(smb2, dir); return; } dir->current_entry = dir->entries; dir->index = 0; /* dir will be freed in smb2_closedir() */ dir->cb(smb2, 0, dir, dir->cb_data); } static void query_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2dir *dir = private_data; struct smb2_query_directory_reply *rep = command_data; if (status == SMB2_STATUS_SUCCESS) { struct smb2_iovec vec _U_; struct smb2_query_directory_request req; struct smb2_pdu *pdu; vec.buf = rep->output_buffer; vec.len = rep->output_buffer_length; if (decode_dirents(smb2, dir, &vec) < 0) { dir->cb(smb2, -ENOMEM, NULL, dir->cb_data); free_smb2dir(smb2, dir); return; } /* We need to get more data */ memset(&req, 0, sizeof(struct smb2_query_directory_request)); req.file_information_class = SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION; req.flags = 0; memcpy(req.file_id, dir->file_id, SMB2_FD_SIZE); req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH; req.name = "*"; pdu = smb2_cmd_query_directory_async(smb2, &req, query_cb, dir); if (pdu == NULL) { dir->cb(smb2, -ENOMEM, NULL, dir->cb_data); free_smb2dir(smb2, dir); return; } smb2_queue_pdu(smb2, pdu); return; } if (status == SMB2_STATUS_NO_MORE_FILES) { struct smb2_close_request req; struct smb2_pdu *pdu; /* We have all the data */ memset(&req, 0, sizeof(struct smb2_close_request)); req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(req.file_id, dir->file_id, SMB2_FD_SIZE); pdu = smb2_cmd_close_async(smb2, &req, od_close_cb, dir); if (pdu == NULL) { dir->cb(smb2, -ENOMEM, NULL, dir->cb_data); free_smb2dir(smb2, dir); return; } smb2_queue_pdu(smb2, pdu); return; } smb2_set_nterror(smb2, status, "Query directory failed with (0x%08x) %s. %s", status, nterror_to_str(status), smb2_get_error(smb2)); dir->cb(smb2, -nterror_to_errno(status), NULL, dir->cb_data); free_smb2dir(smb2, dir); } static void opendir_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2dir *dir = private_data; struct smb2_create_reply *rep = command_data; struct smb2_query_directory_request req; struct smb2_pdu *pdu; if (status != SMB2_STATUS_SUCCESS) { smb2_set_nterror(smb2, status, "Opendir failed with (0x%08x) %s.", status, nterror_to_str(status)); dir->cb(smb2, -nterror_to_errno(status), NULL, dir->cb_data); free_smb2dir(smb2, dir); return; } memcpy(dir->file_id, rep->file_id, SMB2_FD_SIZE); memset(&req, 0, sizeof(struct smb2_query_directory_request)); req.file_information_class = SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION; req.flags = 0; memcpy(req.file_id, dir->file_id, SMB2_FD_SIZE); req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH; req.name = "*"; pdu = smb2_cmd_query_directory_async(smb2, &req, query_cb, dir); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create query command."); dir->cb(smb2, -ENOMEM, NULL, dir->cb_data); free_smb2dir(smb2, dir); return; } smb2_queue_pdu(smb2, pdu); } int smb2_opendir_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data) { struct smb2_create_request req; struct smb2dir *dir; struct smb2_pdu *pdu; if (smb2 == NULL) { return -EINVAL; } if (path == NULL) { path = ""; } dir = calloc(1, sizeof(struct smb2dir)); if (dir == NULL) { smb2_set_error(smb2, "Failed to allocate smb2dir."); return -EINVAL; } SMB2_LIST_ADD(&smb2->dirs, dir); dir->cb = cb; dir->cb_data = cb_data; memset(&req, 0, sizeof(struct smb2_create_request)); req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; req.desired_access = SMB2_FILE_LIST_DIRECTORY | SMB2_FILE_READ_ATTRIBUTES; req.file_attributes = SMB2_FILE_ATTRIBUTE_DIRECTORY; req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; req.create_disposition = SMB2_FILE_OPEN; req.create_options = SMB2_FILE_DIRECTORY_FILE; req.name = path; pdu = smb2_cmd_create_async(smb2, &req, opendir_cb, dir); if (pdu == NULL) { free_smb2dir(smb2, dir); smb2_set_error(smb2, "Failed to create opendir command."); return -EINVAL; } smb2_queue_pdu(smb2, pdu); return 0; } extern void free_c_data(struct smb2_context *smb2, struct connect_data *c_data) { if (c_data->auth_data) { if (smb2->sec == SMB2_SEC_NTLMSSP) { ntlmssp_destroy_context(c_data->auth_data); } #ifdef HAVE_LIBKRB5 else { krb5_free_auth_data(c_data->auth_data); } #endif } if (smb2->connect_data == c_data) { smb2->connect_data = NULL; /* to prevent double-free in smb2_destroy_context */ } free(c_data->utf8_unc); free(c_data->utf16_unc); free(discard_const(c_data->server)); free(discard_const(c_data->share)); free(discard_const(c_data->user)); free(c_data); } static void tree_connect_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct connect_data *c_data = private_data; if (status != SMB2_STATUS_SUCCESS) { smb2_close_context(smb2); smb2_set_nterror(smb2, status, "Tree Connect failed with (0x%08x) %s. %s", status, nterror_to_str(status), smb2_get_error(smb2)); c_data->cb(smb2, -nterror_to_errno(status), NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } c_data->cb(smb2, 0, NULL, c_data->cb_data); free_c_data(smb2, c_data); } void smb2_derive_key( uint8_t *derivation_key, uint32_t derivation_key_len, const char *label, uint32_t label_len, const char *context, uint32_t context_len, uint8_t derived_key[SMB2_KEY_SIZE] ) { unsigned char nul = 0; const uint32_t counter = htobe32(1); const uint32_t keylen = htobe32(SMB2_KEY_SIZE * 8); uint8_t input_key[SMB2_KEY_SIZE] = {0}; HMACContext ctx; uint8_t digest[USHAMaxHashSize]; memcpy(input_key, derivation_key, MIN(sizeof(input_key), derivation_key_len)); hmacReset(&ctx, SHA256, input_key, sizeof(input_key)); hmacInput(&ctx, (unsigned char *)&counter, sizeof(counter)); hmacInput(&ctx, (unsigned char *)label, label_len); hmacInput(&ctx, &nul, 1); hmacInput(&ctx, (unsigned char *)context, context_len); hmacInput(&ctx, (unsigned char *)&keylen, sizeof(keylen)); hmacResult(&ctx, digest); memcpy(derived_key, digest, SMB2_KEY_SIZE); } /* MS-SMB2 3.2.5.2 */ static void smb3_init_preauth_hash(struct smb2_context *smb2) { memset(&smb2->preauthhash[0], 0, SMB2_PREAUTH_HASH_SIZE); } /* MS-SMB2 3.2.5.2 */ static int smb3_update_preauth_hash(struct smb2_context *smb2, int niov, struct smb2_iovec *iov) { int i; USHAContext tctx; USHAReset(&tctx, SHA512); USHAInput(&tctx, smb2->preauthhash, SMB2_PREAUTH_HASH_SIZE); for (i = 0; i < niov; i++) { USHAInput(&tctx, iov[i].buf, iov[i].len); } USHAResult(&tctx, smb2->preauthhash); return 0; } static void smb2_create_signing_key(struct smb2_context *smb2) { /* Derive the signing key from session key * This is based on negotiated protocol */ if (smb2->dialect == SMB2_VERSION_0202 || smb2->dialect == SMB2_VERSION_0210) { /* For SMB2 session key is the signing key */ memcpy(smb2->signing_key, smb2->session_key, MIN(smb2->session_key_size, SMB2_KEY_SIZE)); } else if (smb2->dialect <= SMB2_VERSION_0302) { smb2_derive_key(smb2->session_key, smb2->session_key_size, SMB2AESCMAC, sizeof(SMB2AESCMAC), SmbSign, sizeof(SmbSign), smb2->signing_key); smb2_derive_key(smb2->session_key, smb2->session_key_size, SMB2AESCCM, sizeof(SMB2AESCCM), ServerIn, sizeof(ServerIn), smb2->serverin_key); smb2_derive_key(smb2->session_key, smb2->session_key_size, SMB2AESCCM, sizeof(SMB2AESCCM), ServerOut, sizeof(ServerOut), smb2->serverout_key); } else if (smb2->dialect > SMB2_VERSION_0302) { smb2_derive_key(smb2->session_key, smb2->session_key_size, SMBSigningKey, sizeof(SMBSigningKey), (char *)smb2->preauthhash, SMB2_PREAUTH_HASH_SIZE, smb2->signing_key); smb2_derive_key(smb2->session_key, smb2->session_key_size, SMBC2SCipherKey, sizeof(SMBC2SCipherKey), (char *)smb2->preauthhash, SMB2_PREAUTH_HASH_SIZE, smb2->serverin_key); smb2_derive_key(smb2->session_key, smb2->session_key_size, SMBS2CCipherKey, sizeof(SMBS2CCipherKey), (char *)smb2->preauthhash, SMB2_PREAUTH_HASH_SIZE, smb2->serverout_key); } } static void session_setup_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct connect_data *c_data = private_data; struct smb2_session_setup_reply *rep = command_data; struct smb2_tree_connect_request req; struct smb2_pdu *pdu; int ret; if (status == SMB2_STATUS_MORE_PROCESSING_REQUIRED && rep->security_buffer) { smb3_update_preauth_hash(smb2, smb2->in.niov - 1, &smb2->in.iov[1]); if ((ret = send_session_setup_request( smb2, c_data, rep->security_buffer, rep->security_buffer_length)) < 0) { smb2_close_context(smb2); c_data->cb(smb2, ret, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } return; } else if (status != SMB2_STATUS_SUCCESS) { smb2_close_context(smb2); smb2_set_nterror(smb2, status, "Session setup failed with (0x%08x) %s", status, nterror_to_str(status)); c_data->cb(smb2, -nterror_to_errno(status), NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } if (rep->session_flags & SMB2_SESSION_FLAG_IS_ENCRYPT_DATA) { smb2->seal = 1; smb2->sign = 0; } #ifdef HAVE_LIBKRB5 if (smb2->sec == SMB2_SEC_KRB5) { /* For NTLM the status will be * SMB2_STATUS_MORE_PROCESSING_REQUIRED and a second call to * gss_init_sec_context will complete the gss session. * But for krb5 a second call to gss_init_sec_context is * required if GSS_C_MUTUAL_FLAG is set. * * At this point SMB2 layer reported success already, so we * ignore krb5 errors. */ krb5_session_request(smb2, c_data->auth_data, rep->security_buffer, rep->security_buffer_length); } #endif if (smb2->sign || smb2->seal || smb2->dialect == SMB2_VERSION_0311) { uint8_t zero_key[SMB2_KEY_SIZE] = {0}; int have_valid_session_key = 1; if (smb2->sec == SMB2_SEC_NTLMSSP) { if (ntlmssp_get_session_key(c_data->auth_data, &smb2->session_key, &smb2->session_key_size) < 0) { have_valid_session_key = 0; } } #ifdef HAVE_LIBKRB5 else { if (krb5_session_get_session_key(smb2, c_data->auth_data) < 0) { have_valid_session_key = 0; } } #endif /* check if the session key is proper */ if (smb2->session_key == NULL || memcmp(smb2->session_key, zero_key, SMB2_KEY_SIZE) == 0) { have_valid_session_key = 0; } if (smb2->sign && have_valid_session_key == 0) { smb2_close_context(smb2); smb2_set_error(smb2, "Signing required by server. Session " "Key is not available %s", smb2_get_error(smb2)); c_data->cb(smb2, -EACCES, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } smb2_create_signing_key(smb2); if (smb2->hdr.flags & SMB2_FLAGS_SIGNED) { uint8_t signature[16] _U_; memcpy(&signature[0], &smb2->in.iov[1].buf[48], 16); if (smb2_calc_signature(smb2, &smb2->in.iov[1].buf[48], &smb2->in.iov[1], smb2->in.niov - 1) < 0) { c_data->cb(smb2, -EINVAL, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } if (memcmp(&signature[0], &smb2->in.iov[1].buf[48], 16)) { smb2_set_error(smb2, "Wrong signature in received " "PDU"); c_data->cb(smb2, -EINVAL, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } } } memset(&req, 0, sizeof(struct smb2_tree_connect_request)); req.flags = 0; req.path_length = 2 * c_data->utf16_unc->len; req.path = c_data->utf16_unc->val; if (!smb2->passthrough) { pdu = smb2_cmd_tree_connect_async(smb2, &req, tree_connect_cb, c_data); if (pdu == NULL) { smb2_close_context(smb2); c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } smb2_queue_pdu(smb2, pdu); } else { /* if user wants raw data she probably doesnt want us to * do an implicit tree-connect, so just end here */ c_data->cb(smb2, 0, NULL, c_data->cb_data); free_c_data(smb2, c_data); } } /* Returns 0 for success and -errno for failure */ static int send_session_setup_request(struct smb2_context *smb2, struct connect_data *c_data, unsigned char *buf, int len) { struct smb2_pdu *pdu; struct smb2_session_setup_request req; /* Session setup request. */ memset(&req, 0, sizeof(struct smb2_session_setup_request)); req.security_mode = (uint8_t)smb2->security_mode; if (smb2->sec == SMB2_SEC_NTLMSSP) { /*ntlmssp_set_spnego_wrapping(c_data->auth_data, 1);*/ if (ntlmssp_generate_blob(NULL, smb2, time(NULL), c_data->auth_data, buf, len, &req.security_buffer, &req.security_buffer_length) < 0) { smb2_close_context(smb2); return -1; } } #ifdef HAVE_LIBKRB5 else { if (krb5_session_request(smb2, c_data->auth_data, buf, len) < 0) { smb2_close_context(smb2); return -1; } req.security_buffer_length = krb5_get_output_token_length(c_data->auth_data); req.security_buffer = krb5_get_output_token_buffer(c_data->auth_data); } #endif pdu = smb2_cmd_session_setup_async(smb2, &req, session_setup_cb, c_data); if (pdu == NULL) { smb2_close_context(smb2); return -ENOMEM; } smb2_queue_pdu(smb2, pdu); smb3_update_preauth_hash(smb2, pdu->out.niov, &pdu->out.iov[0]); return 0; } static void negotiate_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct connect_data *c_data = private_data; struct smb2_negotiate_reply *rep = command_data; int ret; smb3_update_preauth_hash(smb2, smb2->in.niov - 1, &smb2->in.iov[1]); if (status != SMB2_STATUS_SUCCESS) { smb2_close_context(smb2); smb2_set_nterror(smb2, status, "Negotiate failed with (0x%08x) %s. %s", status, nterror_to_str(status), smb2_get_error(smb2)); /* calls connect_cb */ c_data->cb(smb2, -nterror_to_errno(status), NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } /* update the context with the server capabilities */ if (rep->dialect_revision > SMB2_VERSION_0202) { if (rep->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) { smb2->supports_multi_credit = 1; } } smb2->max_transact_size = rep->max_transact_size; smb2->max_read_size = rep->max_read_size; smb2->max_write_size = rep->max_write_size; smb2->dialect = rep->dialect_revision; smb2->cypher = rep->cypher; if (smb2->seal && (smb2->dialect == SMB2_VERSION_0300 || smb2->dialect == SMB2_VERSION_0302)) { if(!(rep->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) { smb2_set_error(smb2, "Encryption requested but server " "does not support encryption."); smb2_close_context(smb2); c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } } if (smb2->sign && !(rep->security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED)) { smb2_set_error(smb2, "Signing requested but server " "does not support signing."); smb2_close_context(smb2); c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } if (rep->security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { smb2->sign = 1; } if (smb2->seal) { smb2->sign = 0; } if (smb2->sec == SMB2_SEC_NTLMSSP) { c_data->auth_data = ntlmssp_init_context(smb2->user, smb2->password, smb2->domain, smb2->workstation, smb2->client_challenge); } #ifdef HAVE_LIBKRB5 else { c_data->auth_data = krb5_negotiate_reply(smb2, c_data->server, smb2->domain, c_data->user, smb2->password); } #endif if (c_data->auth_data == NULL) { smb2_close_context(smb2); c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } if ((ret = send_session_setup_request(smb2, c_data, NULL, 0)) < 0) { smb2_close_context(smb2); c_data->cb(smb2, ret, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } } static void connect_cb(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct connect_data *c_data = private_data; struct smb2_negotiate_request req; struct smb2_pdu *pdu; if (status != 0) { smb2_set_error(smb2, "Socket connect failed with %d", status); c_data->cb(smb2, -status, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } memset(&req, 0, sizeof(struct smb2_negotiate_request)); req.capabilities = SMB2_GLOBAL_CAP_LARGE_MTU; if (smb2->version == SMB2_VERSION_ANY || smb2->version == SMB2_VERSION_ANY3 || smb2->version == SMB2_VERSION_0300 || smb2->version == SMB2_VERSION_0302 || smb2->version == SMB2_VERSION_0311) { req.capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; } req.security_mode = smb2->security_mode; switch (smb2->version) { case SMB2_VERSION_ANY: req.dialect_count = 5; req.dialects[0] = SMB2_VERSION_0202; req.dialects[1] = SMB2_VERSION_0210; req.dialects[2] = SMB2_VERSION_0300; req.dialects[3] = SMB2_VERSION_0302; req.dialects[4] = SMB2_VERSION_0311; break; case SMB2_VERSION_ANY2: req.dialect_count = 2; req.dialects[0] = SMB2_VERSION_0202; req.dialects[1] = SMB2_VERSION_0210; break; case SMB2_VERSION_ANY3: req.dialect_count = 3; req.dialects[0] = SMB2_VERSION_0300; req.dialects[1] = SMB2_VERSION_0302; req.dialects[2] = SMB2_VERSION_0311; break; case SMB2_VERSION_0202: case SMB2_VERSION_0210: case SMB2_VERSION_0300: case SMB2_VERSION_0302: case SMB2_VERSION_0311: req.dialect_count = 1; req.dialects[0] = smb2->version; break; } memcpy(req.client_guid, smb2_get_client_guid(smb2), SMB2_GUID_SIZE); if (smb2->sec == SMB2_SEC_UNDEFINED) { #ifdef HAVE_LIBKRB5 smb2->sec = SMB2_SEC_KRB5; #else smb2->sec = SMB2_SEC_NTLMSSP; #endif } smb3_init_preauth_hash(smb2); pdu = smb2_cmd_negotiate_async(smb2, &req, negotiate_cb, c_data); if (pdu == NULL) { c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data); free_c_data(smb2, c_data); return; } smb2_queue_pdu(smb2, pdu); smb3_update_preauth_hash(smb2, pdu->out.niov, &pdu->out.iov[0]); } int smb2_connect_share_async(struct smb2_context *smb2, const char *server, const char *share, const char *user, smb2_command_cb cb, void *cb_data) { struct connect_data *c_data; int err; if (smb2 == NULL) { return -EINVAL; } if (smb2->server != NULL) { free(discard_const(smb2->server)); smb2->server = NULL; } if (server == NULL) { 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; } 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); } c_data = calloc(1, sizeof(struct connect_data)); if (c_data == NULL) { smb2_set_error(smb2, "Failed to allocate connect_data"); return -ENOMEM; } c_data->server = strdup(smb2->server); if (c_data->server == NULL) { free_c_data(smb2, c_data); smb2_set_error(smb2, "Failed to strdup(server)"); return -ENOMEM; } c_data->share = strdup(smb2->share); if (c_data->share == NULL) { free_c_data(smb2, c_data); 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); smb2_set_error(smb2, "Failed to strdup(user)"); return -ENOMEM; } if (asprintf(&c_data->utf8_unc, "\\\\%s\\%s", c_data->server, c_data->share) < 0) { free_c_data(smb2, c_data); smb2_set_error(smb2, "Failed to allocate unc string."); return -ENOMEM; } c_data->utf16_unc = smb2_utf8_to_utf16(c_data->utf8_unc); if (c_data->utf16_unc == NULL) { smb2_set_error(smb2, "Count not convert UNC:[%s] into UTF-16", c_data->utf8_unc); free_c_data(smb2, c_data); return -ENOMEM; } c_data->cb = cb; c_data->cb_data = cb_data; err = smb2_connect_async(smb2, server, connect_cb, c_data); if (err != 0) { free_c_data(smb2, c_data); return err; } return 0; } static void free_smb2fh(struct smb2_context *smb2, struct smb2fh *fh) { SMB2_LIST_REMOVE(&smb2->fhs, fh); free(fh); } void smb2_free_all_fhs(struct smb2_context *smb2) { while (smb2->fhs) { free_smb2fh(smb2, smb2->fhs); } } static void open_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2fh *fh = private_data; struct smb2_create_reply *rep = command_data; if (status != SMB2_STATUS_SUCCESS) { smb2_set_nterror(smb2, status, "Open failed with (0x%08x) %s.", status, nterror_to_str(status)); fh->cb(smb2, -nterror_to_errno(status), NULL, fh->cb_data); free_smb2fh(smb2, fh); return; } memcpy(fh->file_id, rep->file_id, SMB2_FD_SIZE); fh->end_of_file = rep->end_of_file; fh->cb(smb2, 0, fh, fh->cb_data); } int smb2_open_async_with_oplock_or_lease(struct smb2_context *smb2, const char *path, int flags, uint8_t oplock_level, uint32_t lease_state, smb2_lease_key lease_key, smb2_command_cb cb, void *cb_data) { struct smb2fh *fh; struct smb2_create_request req; struct smb2_pdu *pdu; struct smb2_iovec iov; uint32_t desired_access = 0; uint32_t create_disposition = 0; uint32_t create_options = 0; uint32_t file_attributes = 0; if (smb2 == NULL) { return -EINVAL; } fh = calloc(1, sizeof(struct smb2fh)); if (fh == NULL) { smb2_set_error(smb2, "Failed to allocate smbfh"); return -ENOMEM; } SMB2_LIST_ADD(&smb2->fhs, fh); fh->cb = cb; fh->cb_data = cb_data; /* Create disposition */ if (flags & O_CREAT) { if (flags & O_EXCL) { create_disposition = SMB2_FILE_CREATE; } else if(flags & O_TRUNC) { create_disposition = SMB2_FILE_OVERWRITE_IF; } else { create_disposition = SMB2_FILE_OPEN_IF; } } else { if (flags & O_TRUNC) { create_disposition = SMB2_FILE_OVERWRITE; } else { create_disposition = SMB2_FILE_OPEN; } } /* desired access */ switch (flags & O_ACCMODE) { case O_RDWR: case O_WRONLY: desired_access |= SMB2_FILE_WRITE_DATA | SMB2_FILE_WRITE_EA | SMB2_FILE_WRITE_ATTRIBUTES; if ((flags & O_ACCMODE) == O_WRONLY) break; case O_RDONLY: desired_access |= SMB2_FILE_READ_DATA | SMB2_FILE_READ_EA | SMB2_FILE_READ_ATTRIBUTES; break; } /* create options */ create_options |= SMB2_FILE_NON_DIRECTORY_FILE; if (flags & O_SYNC) { desired_access |= SMB2_SYNCHRONIZE; create_options |= SMB2_FILE_NO_INTERMEDIATE_BUFFERING; } memset(&req, 0, sizeof(struct smb2_create_request)); req.requested_oplock_level = oplock_level; req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; req.desired_access = desired_access; req.file_attributes = file_attributes; req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; req.create_disposition = create_disposition; req.create_options = create_options; req.name = path; if (lease_state && lease_key) { req.create_context_length = SMB2_CREATE_REQUEST_LEASE_SIZE + 24; req.create_context = calloc(1, SMB2_CREATE_REQUEST_LEASE_SIZE + 24); iov.buf = req.create_context; iov.len = req.create_context_length; smb2_set_uint32(&iov, 0, 0); /* chain offset */ smb2_set_uint16(&iov, 4, 16); /* tag offset */ smb2_set_uint16(&iov, 6, 4); /* tag length lo */ smb2_set_uint16(&iov, 8, 0); /* tag length up */ smb2_set_uint16(&iov, 10, 24); /* data offset */ smb2_set_uint16(&iov, 12, SMB2_CREATE_REQUEST_LEASE_SIZE); smb2_set_uint32(&iov, 16, htobe32(0x52714c73)); memcpy(iov.buf + 24, lease_key, SMB2_LEASE_KEY_SIZE); smb2_set_uint32(&iov, 40, lease_state); } pdu = smb2_cmd_create_async(smb2, &req, open_cb, fh); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create create command"); free_smb2fh(smb2, fh); return -ENOMEM; } if (req.create_context && req.create_context_length) { free(req.create_context); } smb2_queue_pdu(smb2, pdu); return 0; } int smb2_open_async(struct smb2_context *smb2, const char *path, int flags, smb2_command_cb cb, void *cb_data) { return smb2_open_async_with_oplock_or_lease(smb2, path, flags, SMB2_OPLOCK_LEVEL_NONE, 0, NULL, cb, cb_data); } static void close_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2fh *fh = private_data; if (status != SMB2_STATUS_SUCCESS) { smb2_set_nterror(smb2, status, "Close failed with (0x%08x) %s", status, nterror_to_str(status)); fh->cb(smb2, -nterror_to_errno(status), NULL, fh->cb_data); free_smb2fh(smb2, fh); return; } fh->cb(smb2, 0, NULL, fh->cb_data); free_smb2fh(smb2, fh); } int smb2_close_async(struct smb2_context *smb2, struct smb2fh *fh, smb2_command_cb cb, void *cb_data) { struct smb2_close_request req; struct smb2_pdu *pdu; if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } fh->cb = cb; fh->cb_data = cb_data; memset(&req, 0, sizeof(struct smb2_close_request)); req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE); pdu = smb2_cmd_close_async(smb2, &req, close_cb, fh); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create close command"); return -ENOMEM; } smb2_queue_pdu(smb2, pdu); return 0; } static void fsync_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct smb2fh *fh = private_data; if (status != SMB2_STATUS_SUCCESS) { smb2_set_nterror(smb2, status, "Flush failed with (0x%08x) %s", status, nterror_to_str(status)); fh->cb(smb2, -nterror_to_errno(status), NULL, fh->cb_data); return; } fh->cb(smb2, 0, NULL, fh->cb_data); } int smb2_fsync_async(struct smb2_context *smb2, struct smb2fh *fh, smb2_command_cb cb, void *cb_data) { struct smb2_flush_request req; struct smb2_pdu *pdu; if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } fh->cb = cb; fh->cb_data = cb_data; memset(&req, 0, sizeof(struct smb2_flush_request)); memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE); pdu = smb2_cmd_flush_async(smb2, &req, fsync_cb, fh); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create flush command"); return -ENOMEM; } smb2_queue_pdu(smb2, pdu); return 0; } struct read_data { smb2_command_cb cb; void *cb_data; struct smb2_read_cb_data read_cb_data; }; static void read_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct read_data *rd = private_data; struct smb2_read_reply *rep = command_data; if (status && status != SMB2_STATUS_END_OF_FILE) { smb2_set_nterror(smb2, status, "Read/Write failed with (0x%08x) %s", status, nterror_to_str(status)); rd->cb(smb2, -nterror_to_errno(status), &rd->read_cb_data, rd->cb_data); free(rd); return; } if (status == SMB2_STATUS_SUCCESS) { rd->read_cb_data.fh->offset = rd->read_cb_data.offset + rep->data_length; } rd->cb(smb2, rep->data_length, &rd->read_cb_data, rd->cb_data); free(rd); } int smb2_pread_async(struct smb2_context *smb2, struct smb2fh *fh, uint8_t *buf, uint32_t count, uint64_t offset, smb2_command_cb cb, void *cb_data) { struct smb2_read_request req; struct read_data *rd; struct smb2_pdu *pdu; int needed_credits; if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } rd = calloc(1, sizeof(struct read_data)); if (rd == NULL) { smb2_set_error(smb2, "Failed to allocate read_data"); return -ENOMEM; } rd->cb = cb; rd->cb_data = cb_data; rd->read_cb_data.fh = fh; rd->read_cb_data.buf = buf; rd->read_cb_data.count = count; rd->read_cb_data.offset = offset; if (count > smb2->max_read_size) { count = smb2->max_read_size; } needed_credits = (count - 1) / 65536 + 1; if (smb2->dialect > SMB2_VERSION_0202) { if (needed_credits > MAX_CREDITS - 16) { count = (MAX_CREDITS - 16) * 65536; } needed_credits = (count - 1) / 65536 + 1; if (needed_credits > smb2->credits) { count = smb2->credits * 65536; } } else { if (count > 65536) { count = 65536; } } needed_credits = (count - 1) / 65536 + 1; memset(&req, 0, sizeof(struct smb2_read_request)); req.flags = 0; req.length = count; req.offset = offset; req.buf = buf; memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE); req.minimum_count = 0; req.channel = SMB2_CHANNEL_NONE; req.remaining_bytes = 0; pdu = smb2_cmd_read_async(smb2, &req, read_cb, rd); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create read command"); return -EINVAL; } smb2_queue_pdu(smb2, pdu); return 0; } int smb2_read_async(struct smb2_context *smb2, struct smb2fh *fh, uint8_t *buf, uint32_t count, smb2_command_cb cb, void *cb_data) { if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } return smb2_pread_async(smb2, fh, buf, count, fh->offset, cb, cb_data); } struct write_data { smb2_command_cb cb; void *cb_data; struct smb2_write_cb_data write_cb_data; }; static void write_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct write_data *wd = private_data; struct smb2_write_reply *rep = command_data; if (status && status != SMB2_STATUS_END_OF_FILE) { smb2_set_nterror(smb2, status, "Read/Write failed with (0x%08x) %s", status, nterror_to_str(status)); wd->cb(smb2, -nterror_to_errno(status), &wd->write_cb_data, wd->cb_data); free(wd); return; } if (status == SMB2_STATUS_SUCCESS) { wd->write_cb_data.fh->offset = wd->write_cb_data.offset + rep->count; } wd->cb(smb2, rep->count, &wd->write_cb_data, wd->cb_data); free(wd); } int smb2_pwrite_async(struct smb2_context *smb2, struct smb2fh *fh, const uint8_t *buf, uint32_t count, uint64_t offset, smb2_command_cb cb, void *cb_data) { struct smb2_write_request req; struct write_data *wr; struct smb2_pdu *pdu; int needed_credits; if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } wr = calloc(1, sizeof(struct write_data)); if (wr == NULL) { smb2_set_error(smb2, "Failed to allocate write_data"); return -ENOMEM; } wr->cb = cb; wr->cb_data = cb_data; wr->write_cb_data.fh = fh; wr->write_cb_data.buf = buf; wr->write_cb_data.count = count; wr->write_cb_data.offset = offset; if (count > smb2->max_write_size) { count = smb2->max_write_size; } needed_credits = (count - 1) / 65536 + 1; if (smb2->dialect > SMB2_VERSION_0202) { if (needed_credits > MAX_CREDITS - 16) { count = (MAX_CREDITS - 16) * 65536; } needed_credits = (count - 1) / 65536 + 1; if (needed_credits > smb2->credits) { count = smb2->credits * 65536; } } else { if (count > 65536) { count = 65536; } } needed_credits = (count - 1) / 65536 + 1; memset(&req, 0, sizeof(struct smb2_write_request)); req.length = count; req.offset = offset; req.buf = buf; memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE); req.channel = SMB2_CHANNEL_NONE; req.remaining_bytes = 0; req.flags = 0; pdu = smb2_cmd_write_async(smb2, &req, 0, write_cb, wr); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create write command"); return -EINVAL; } smb2_queue_pdu(smb2, pdu); return 0; } int smb2_write_async(struct smb2_context *smb2, struct smb2fh *fh, const uint8_t *buf, uint32_t count, smb2_command_cb cb, void *cb_data) { if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } return smb2_pwrite_async(smb2, fh, buf, count, fh->offset, cb, cb_data); } int64_t smb2_lseek(struct smb2_context *smb2, struct smb2fh *fh, int64_t offset, int whence, uint64_t *current_offset) { if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } switch(whence) { case SEEK_SET: if (offset < 0) { smb2_set_error(smb2, "Lseek() offset would become" "negative"); return -EINVAL; } fh->offset = offset; if (current_offset) { *current_offset = fh->offset; } return fh->offset; case SEEK_CUR: if (fh->offset + offset < 0) { smb2_set_error(smb2, "Lseek() offset would become" "negative"); return -EINVAL; } fh->offset += offset; if (current_offset) { *current_offset = fh->offset; } return fh->offset; case SEEK_END: fh->offset = fh->end_of_file; if (fh->offset + offset < 0) { smb2_set_error(smb2, "Lseek() offset would become" "negative"); return -EINVAL; } fh->offset += offset; if (current_offset) { *current_offset = fh->offset; } return fh->offset; default: smb2_set_error(smb2, "Invalid whence(%d) for lseek", whence); return -EINVAL; } } struct create_cb_data { smb2_command_cb cb; void *cb_data; }; static void create_cb_2(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct create_cb_data *create_data = private_data; if (status != SMB2_STATUS_SUCCESS) { status = -nterror_to_errno(status); } create_data->cb(smb2, status, NULL, create_data->cb_data); free(create_data); } static void create_cb_1(struct smb2_context *smb2, int status, void *command_data, void *private_data) { if (status != SMB2_STATUS_SUCCESS) { smb2_set_error(smb2, "Create failed with status %d. %s", status, smb2_get_error(smb2)); return; } } static int smb2_unlink_internal(struct smb2_context *smb2, const char *path, int is_dir, smb2_command_cb cb, void *cb_data) { struct create_cb_data *create_data; struct smb2_create_request cr_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; if (smb2 == NULL) { return -EINVAL; } create_data = calloc(1, sizeof(struct create_cb_data)); if (create_data == NULL) { smb2_set_error(smb2, "Failed to allocate create_data"); return -ENOMEM; } create_data->cb = cb; create_data->cb_data = cb_data; memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_DELETE; if (is_dir) { cr_req.file_attributes = SMB2_FILE_ATTRIBUTE_DIRECTORY; } else { cr_req.file_attributes = SMB2_FILE_ATTRIBUTE_NORMAL; } cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE | SMB2_FILE_SHARE_DELETE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = SMB2_FILE_DELETE_ON_CLOSE; cr_req.name = path; pdu = smb2_cmd_create_async(smb2, &cr_req, create_cb_1, create_data); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create create command"); return -ENOMEM; } memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, create_cb_2, create_data); if (next_pdu == NULL) { smb2_set_error(smb2, "Failed to create close command"); smb2_free_pdu(smb2, pdu); free(create_data); return -ENOMEM; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } int smb2_unlink_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data) { return smb2_unlink_internal(smb2, path, 0, cb, cb_data); } int smb2_rmdir_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data) { return smb2_unlink_internal(smb2, path, 1, cb, cb_data); } int smb2_mkdir_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data) { struct create_cb_data *create_data; struct smb2_create_request cr_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; if (smb2 == NULL) { return -EINVAL; } create_data = calloc(1, sizeof(struct create_cb_data)); if (create_data == NULL) { smb2_set_error(smb2, "Failed to allocate create_data"); return -ENOMEM; } create_data->cb = cb; create_data->cb_data = cb_data; memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_FILE_READ_ATTRIBUTES; cr_req.file_attributes = SMB2_FILE_ATTRIBUTE_DIRECTORY; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; cr_req.create_disposition = SMB2_FILE_CREATE; cr_req.create_options = SMB2_FILE_DIRECTORY_FILE; cr_req.name = path; pdu = smb2_cmd_create_async(smb2, &cr_req, create_cb_1, create_data); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create create command"); return -ENOMEM; } memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, create_cb_2, create_data); if (next_pdu == NULL) { smb2_set_error(smb2, "Failed to create close command"); smb2_free_pdu(smb2, pdu); free(create_data); return -ENOMEM; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } struct stat_cb_data { smb2_command_cb cb; void *cb_data; uint32_t status; uint8_t info_type; uint8_t file_info_class; void *st; }; static void fstat_cb_1(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct stat_cb_data *stat_data = private_data; struct smb2_query_info_reply *rep = command_data; struct smb2_file_all_info *fs = rep->output_buffer; struct smb2_stat_64 *st = stat_data->st; if (status != SMB2_STATUS_SUCCESS) { stat_data->cb(smb2, -nterror_to_errno(status), NULL, stat_data->cb_data); free(stat_data); return; } st->smb2_type = SMB2_TYPE_FILE; if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) { st->smb2_type = SMB2_TYPE_DIRECTORY; } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) { st->smb2_type = SMB2_TYPE_LINK; } st->smb2_nlink = fs->standard.number_of_links; st->smb2_ino = fs->index_number; st->smb2_size = fs->standard.end_of_file; st->smb2_atime = fs->basic.last_access_time.tv_sec; st->smb2_atime_nsec = fs->basic.last_access_time.tv_usec * 1000; st->smb2_mtime = fs->basic.last_write_time.tv_sec; st->smb2_mtime_nsec = fs->basic.last_write_time.tv_usec * 1000; st->smb2_ctime = fs->basic.change_time.tv_sec; st->smb2_ctime_nsec = fs->basic.change_time.tv_usec * 1000; st->smb2_btime = fs->basic.creation_time.tv_sec; st->smb2_btime_nsec = fs->basic.creation_time.tv_usec * 1000; smb2_free_data(smb2, fs); stat_data->cb(smb2, 0, st, stat_data->cb_data); free(stat_data); } int smb2_fstat_async(struct smb2_context *smb2, struct smb2fh *fh, struct smb2_stat_64 *st, smb2_command_cb cb, void *cb_data) { struct stat_cb_data *stat_data; struct smb2_query_info_request req; struct smb2_pdu *pdu; if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } stat_data = calloc(1, sizeof(struct stat_cb_data)); if (stat_data == NULL) { smb2_set_error(smb2, "Failed to allocate stat_data"); return -ENOMEM; } stat_data->cb = cb; stat_data->cb_data = cb_data; stat_data->st = st; memset(&req, 0, sizeof(struct smb2_query_info_request)); req.info_type = SMB2_0_INFO_FILE; req.file_info_class = SMB2_FILE_ALL_INFORMATION; req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH; req.additional_information = 0; req.flags = 0; memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE); pdu = smb2_cmd_query_info_async(smb2, &req, fstat_cb_1, stat_data); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create query command"); free(stat_data); return -ENOMEM; } smb2_queue_pdu(smb2, pdu); return 0; } static void getinfo_cb_3(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct stat_cb_data *stat_data = private_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } stat_data->cb(smb2, -nterror_to_errno(stat_data->status), stat_data->st, stat_data->cb_data); free(stat_data); } static void getinfo_cb_2(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct stat_cb_data *stat_data = private_data; struct smb2_query_info_reply *rep = command_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } if (stat_data->status != SMB2_STATUS_SUCCESS) { return; } if (stat_data->info_type == SMB2_0_INFO_FILE && stat_data->file_info_class == SMB2_FILE_ALL_INFORMATION) { struct smb2_stat_64 *st = stat_data->st; struct smb2_file_all_info *fs = rep->output_buffer; st->smb2_type = SMB2_TYPE_FILE; if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) { st->smb2_type = SMB2_TYPE_DIRECTORY; } if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) { st->smb2_type = SMB2_TYPE_LINK; } st->smb2_nlink = fs->standard.number_of_links; st->smb2_ino = fs->index_number; st->smb2_size = fs->standard.end_of_file; st->smb2_atime = fs->basic.last_access_time.tv_sec; st->smb2_atime_nsec = fs->basic.last_access_time.tv_usec * 1000; st->smb2_mtime = fs->basic.last_write_time.tv_sec; st->smb2_mtime_nsec = fs->basic.last_write_time.tv_usec * 1000; st->smb2_ctime = fs->basic.change_time.tv_sec; st->smb2_ctime_nsec = fs->basic.change_time.tv_usec * 1000; st->smb2_btime = fs->basic.creation_time.tv_sec; st->smb2_btime_nsec = fs->basic.creation_time.tv_usec * 1000; } else if (stat_data->info_type == SMB2_0_INFO_FILESYSTEM && stat_data->file_info_class == SMB2_FILE_FS_FULL_SIZE_INFORMATION) { struct smb2_statvfs *statvfs = stat_data->st; struct smb2_file_fs_full_size_info *vfs = rep->output_buffer; memset(statvfs, 0, sizeof(struct smb2_statvfs)); statvfs->f_bsize = statvfs->f_frsize = vfs->bytes_per_sector * vfs->sectors_per_allocation_unit; statvfs->f_blocks = vfs->total_allocation_units; statvfs->f_bfree = statvfs->f_bavail = vfs->caller_available_allocation_units; } smb2_free_data(smb2, rep->output_buffer); } static void getinfo_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct stat_cb_data *stat_data = private_data; if (stat_data->status == SMB2_STATUS_SUCCESS) { stat_data->status = status; } } static int smb2_getinfo_async(struct smb2_context *smb2, const char *path, uint8_t info_type, uint8_t file_info_class, void *st, smb2_command_cb cb, void *cb_data) { struct stat_cb_data *stat_data; struct smb2_create_request cr_req; struct smb2_query_info_request qi_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; if (smb2 == NULL) { return -EINVAL; } stat_data = calloc(1, sizeof(struct stat_cb_data)); if (stat_data == NULL) { smb2_set_error(smb2, "Failed to allocate create_data"); return -1; } stat_data->cb = cb; stat_data->cb_data = cb_data; stat_data->info_type = info_type; stat_data->file_info_class = file_info_class; stat_data->st = st; /* CREATE command */ memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; cr_req.file_attributes = 0; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = 0; cr_req.name = path; pdu = smb2_cmd_create_async(smb2, &cr_req, getinfo_cb_1, stat_data); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create create command"); free(stat_data); return -1; } /* QUERY INFO command */ memset(&qi_req, 0, sizeof(struct smb2_query_info_request)); qi_req.info_type = info_type; qi_req.file_info_class = file_info_class; qi_req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH; qi_req.additional_information = 0; qi_req.flags = 0; memcpy(qi_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_query_info_async(smb2, &qi_req, getinfo_cb_2, stat_data); if (next_pdu == NULL) { smb2_set_error(smb2, "Failed to create query command"); free(stat_data); smb2_free_pdu(smb2, pdu); return -1; } smb2_add_compound_pdu(smb2, pdu, next_pdu); /* CLOSE command */ memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, getinfo_cb_3, stat_data); if (next_pdu == NULL) { stat_data->cb(smb2, -ENOMEM, NULL, stat_data->cb_data); free(stat_data); smb2_free_pdu(smb2, pdu); return -1; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } int smb2_stat_async(struct smb2_context *smb2, const char *path, struct smb2_stat_64 *st, smb2_command_cb cb, void *cb_data) { return smb2_getinfo_async(smb2, path, SMB2_0_INFO_FILE, SMB2_FILE_ALL_INFORMATION, st, cb, cb_data); } int smb2_statvfs_async(struct smb2_context *smb2, const char *path, struct smb2_statvfs *statvfs, smb2_command_cb cb, void *cb_data) { return smb2_getinfo_async(smb2, path, SMB2_0_INFO_FILESYSTEM, SMB2_FILE_FS_FULL_SIZE_INFORMATION, statvfs, cb, cb_data); } struct trunc_cb_data { smb2_command_cb cb; void *cb_data; uint32_t status; uint64_t length; }; static void trunc_cb_3(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct trunc_cb_data *trunc_data = private_data; if (trunc_data->status == SMB2_STATUS_SUCCESS) { trunc_data->status = status; } trunc_data->cb(smb2, -nterror_to_errno(trunc_data->status), NULL, trunc_data->cb_data); free(trunc_data); } static void trunc_cb_2(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct trunc_cb_data *trunc_data = private_data; if (trunc_data->status == SMB2_STATUS_SUCCESS) { trunc_data->status = status; } } static void trunc_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct trunc_cb_data *trunc_data = private_data; if (trunc_data->status == SMB2_STATUS_SUCCESS) { trunc_data->status = status; } } int smb2_truncate_async(struct smb2_context *smb2, const char *path, uint64_t length, smb2_command_cb cb, void *cb_data) { struct trunc_cb_data *trunc_data; struct smb2_create_request cr_req; struct smb2_set_info_request si_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; struct smb2_file_end_of_file_info eofi _U_; if (smb2 == NULL) { return -EINVAL; } trunc_data = calloc(1, sizeof(struct trunc_cb_data)); if (trunc_data == NULL) { smb2_set_error(smb2, "Failed to allocate trunc_data"); return -ENOMEM; } trunc_data->cb = cb; trunc_data->cb_data = cb_data; trunc_data->length = length; /* CREATE command */ memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_GENERIC_WRITE; cr_req.file_attributes = 0; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = 0; cr_req.name = path; pdu = smb2_cmd_create_async(smb2, &cr_req, trunc_cb_1, trunc_data); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create create command"); free(trunc_data); return -EINVAL; } /* SET INFO command */ eofi.end_of_file = length; memset(&si_req, 0, sizeof(struct smb2_set_info_request)); si_req.info_type = SMB2_0_INFO_FILE; si_req.file_info_class = SMB2_FILE_END_OF_FILE_INFORMATION; si_req.additional_information = 0; memcpy(si_req.file_id, compound_file_id, SMB2_FD_SIZE); si_req.input_data = &eofi; next_pdu = smb2_cmd_set_info_async(smb2, &si_req, trunc_cb_2, trunc_data); if (next_pdu == NULL) { smb2_set_error(smb2, "Failed to create set command. %s", smb2_get_error(smb2)); free(trunc_data); smb2_free_pdu(smb2, pdu); return -EINVAL; } smb2_add_compound_pdu(smb2, pdu, next_pdu); /* CLOSE command */ memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, trunc_cb_3, trunc_data); if (next_pdu == NULL) { trunc_data->cb(smb2, -ENOMEM, NULL, trunc_data->cb_data); free(trunc_data); smb2_free_pdu(smb2, pdu); return -EINVAL; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } struct rename_cb_data { uint8_t *newpath; smb2_command_cb cb; void *cb_data; uint32_t status; }; static void free_rename_data(struct rename_cb_data *rename_data) { free(rename_data->newpath); free(rename_data); } static void rename_cb_3(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct rename_cb_data *rename_data = private_data; if (rename_data->status == SMB2_STATUS_SUCCESS) { rename_data->status = status; } rename_data->cb(smb2, -nterror_to_errno(rename_data->status), NULL, rename_data->cb_data); free_rename_data(rename_data); } static void rename_cb_2(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct rename_cb_data *rename_data = private_data; if (rename_data->status == SMB2_STATUS_SUCCESS) { rename_data->status = status; } } static void rename_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct rename_cb_data *rename_data = private_data; if (rename_data->status == SMB2_STATUS_SUCCESS) { rename_data->status = status; } } int smb2_rename_async(struct smb2_context *smb2, const char *oldpath, const char *newpath, smb2_command_cb cb, void *cb_data) { struct rename_cb_data *rename_data; struct smb2_create_request cr_req; struct smb2_set_info_request si_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; struct smb2_file_rename_info rn_info _U_; uint8_t *ptr; if (smb2 == NULL) { return -EINVAL; } rename_data = calloc(1, sizeof(struct rename_cb_data)); if (rename_data == NULL) { smb2_set_error(smb2, "Failed to allocate rename_data"); return -ENOMEM; } rename_data->cb = cb; rename_data->cb_data = cb_data; rename_data->newpath = (uint8_t *)strdup(newpath); if (rename_data->newpath == NULL) { free_rename_data(rename_data); smb2_set_error(smb2, "Failed to allocate rename_data->newpath"); return -ENOMEM; } for (ptr = rename_data->newpath; *ptr; ptr++) { if (*ptr == '/') { *ptr = '\\'; } } /* CREATE command */ memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_GENERIC_READ | SMB2_FILE_READ_ATTRIBUTES | SMB2_DELETE; cr_req.file_attributes = 0; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE | SMB2_FILE_SHARE_DELETE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = 0; cr_req.name = oldpath; pdu = smb2_cmd_create_async(smb2, &cr_req, rename_cb_1, rename_data); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create create command"); free_rename_data(rename_data); return -EINVAL; } /* SET INFO command */ rn_info.replace_if_exist = 0; rn_info.file_name = rename_data->newpath; memset(&si_req, 0, sizeof(struct smb2_set_info_request)); si_req.info_type = SMB2_0_INFO_FILE; si_req.file_info_class = SMB2_FILE_RENAME_INFORMATION; si_req.additional_information = 0; memcpy(si_req.file_id, compound_file_id, SMB2_FD_SIZE); si_req.input_data = &rn_info; next_pdu = smb2_cmd_set_info_async(smb2, &si_req, rename_cb_2, rename_data); if (next_pdu == NULL) { smb2_set_error(smb2, "Failed to create set command. %s", smb2_get_error(smb2)); free_rename_data(rename_data); smb2_free_pdu(smb2, pdu); return -EINVAL; } smb2_add_compound_pdu(smb2, pdu, next_pdu); /* CLOSE command */ memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, rename_cb_3, rename_data); if (next_pdu == NULL) { rename_data->cb(smb2, -ENOMEM, NULL, rename_data->cb_data); free_rename_data(rename_data); smb2_free_pdu(smb2, pdu); return -EINVAL; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } static void ftrunc_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct create_cb_data *cb_data = private_data; cb_data->cb(smb2, -nterror_to_errno(status), NULL, cb_data->cb_data); free(cb_data); } int smb2_ftruncate_async(struct smb2_context *smb2, struct smb2fh *fh, uint64_t length, smb2_command_cb cb, void *cb_data) { struct create_cb_data *create_data; struct smb2_set_info_request req; struct smb2_file_end_of_file_info eofi _U_; struct smb2_pdu *pdu; if (smb2 == NULL) { return -EINVAL; } if (fh == NULL) { smb2_set_error(smb2, "File handle was NULL"); return -EINVAL; } create_data = calloc(1, sizeof(struct create_cb_data)); if (create_data == NULL) { smb2_set_error(smb2, "Failed to allocate create_data"); return -ENOMEM; } create_data->cb = cb; create_data->cb_data = cb_data; eofi.end_of_file = length; memset(&req, 0, sizeof(struct smb2_set_info_request)); req.info_type = SMB2_0_INFO_FILE; req.file_info_class = SMB2_FILE_END_OF_FILE_INFORMATION; req.additional_information = 0; memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE); req.input_data = &eofi; pdu = smb2_cmd_set_info_async(smb2, &req, ftrunc_cb_1, create_data); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create set info command"); return -ENOMEM; } smb2_queue_pdu(smb2, pdu); return 0; } struct readlink_cb_data { smb2_command_cb cb; void *cb_data; uint32_t status; struct smb2_reparse_data_buffer *reparse; }; static void readlink_cb_3(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct readlink_cb_data *cb_data = private_data; struct smb2_reparse_data_buffer *rp = cb_data->reparse; char *target = (char*)""; if (rp) { switch (rp->reparse_tag) { case SMB2_REPARSE_TAG_SYMLINK: target = rp->symlink.subname; } } cb_data->cb(smb2, -nterror_to_errno(cb_data->status), target, cb_data->cb_data); smb2_free_data(smb2, rp); free(cb_data); } static void readlink_cb_2(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct readlink_cb_data *cb_data = private_data; struct smb2_ioctl_reply *rep = command_data; if (cb_data->status == SMB2_STATUS_SUCCESS) { cb_data->status = status; } if (status == SMB2_STATUS_NOT_A_REPARSE_POINT) { smb2_set_error(smb2, "Not a reparse point"); } if (status == SMB2_STATUS_SUCCESS) { cb_data->reparse = rep->output; } } static void readlink_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct readlink_cb_data *cb_data = private_data; if (status != SMB2_STATUS_SUCCESS) { smb2_set_nterror(smb2, status, "%s", nterror_to_str(status)); } cb_data->status = status; } int smb2_readlink_async(struct smb2_context *smb2, const char *path, smb2_command_cb cb, void *cb_data) { struct readlink_cb_data *readlink_data; struct smb2_create_request cr_req; struct smb2_ioctl_request io_req; struct smb2_close_request cl_req; struct smb2_pdu *pdu, *next_pdu; if (smb2 == NULL) { return -EINVAL; } readlink_data = calloc(1, sizeof(struct readlink_cb_data)); if (readlink_data == NULL) { smb2_set_error(smb2, "Failed to allocate readlink_data"); return -ENOMEM; } readlink_data->cb = cb; readlink_data->cb_data = cb_data; /* CREATE command */ memset(&cr_req, 0, sizeof(struct smb2_create_request)); cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; cr_req.desired_access = SMB2_FILE_READ_ATTRIBUTES; cr_req.file_attributes = 0; cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE | SMB2_FILE_SHARE_DELETE; cr_req.create_disposition = SMB2_FILE_OPEN; cr_req.create_options = SMB2_FILE_OPEN_REPARSE_POINT; cr_req.name = path; pdu = smb2_cmd_create_async(smb2, &cr_req, readlink_cb_1, readlink_data); if (pdu == NULL) { smb2_set_error(smb2, "Failed to create create command"); free(readlink_data); return -EINVAL; } /* IOCTL command */ memset(&io_req, 0, sizeof(struct smb2_ioctl_request)); io_req.ctl_code = SMB2_FSCTL_GET_REPARSE_POINT; memcpy(io_req.file_id, compound_file_id, SMB2_FD_SIZE); io_req.input_count = 0; io_req.input = NULL; io_req.flags = SMB2_0_IOCTL_IS_FSCTL; next_pdu = smb2_cmd_ioctl_async(smb2, &io_req, readlink_cb_2, readlink_data); if (next_pdu == NULL) { free(readlink_data); smb2_free_pdu(smb2, pdu); return -EINVAL; } smb2_add_compound_pdu(smb2, pdu, next_pdu); /* CLOSE command */ memset(&cl_req, 0, sizeof(struct smb2_close_request)); cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE); next_pdu = smb2_cmd_close_async(smb2, &cl_req, readlink_cb_3, readlink_data); if (next_pdu == NULL) { free(readlink_data); smb2_free_pdu(smb2, pdu); return -EINVAL; } smb2_add_compound_pdu(smb2, pdu, next_pdu); smb2_queue_pdu(smb2, pdu); return 0; } struct disconnect_data { smb2_command_cb cb; void *cb_data; }; static void disconnect_cb_2(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct disconnect_data *dc_data = private_data; dc_data->cb(smb2, 0, NULL, dc_data->cb_data); free(dc_data); if (smb2->change_fd) { smb2->change_fd(smb2, smb2->fd, SMB2_DEL_FD); } close(smb2->fd); smb2->fd = SMB2_INVALID_SOCKET; } static void disconnect_cb_1(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct disconnect_data *dc_data = private_data; struct smb2_pdu *pdu; if (status != SMB2_STATUS_SUCCESS) { smb2_set_nterror(smb2, status, "%s", nterror_to_str(status)); dc_data->cb(smb2, -ENOMEM, NULL, dc_data->cb_data); free(dc_data); return; } pdu = smb2_cmd_logoff_async(smb2, disconnect_cb_2, dc_data); if (pdu == NULL) { dc_data->cb(smb2, -ENOMEM, NULL, dc_data->cb_data); free(dc_data); return; } smb2_queue_pdu(smb2, pdu); } int smb2_disconnect_share_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct disconnect_data *dc_data; struct smb2_pdu *pdu; if (smb2 == NULL) { return -EINVAL; } if (!SMB2_VALID_SOCKET(smb2->fd)) { smb2_set_error(smb2, "connection is alreeady disconnected or was never connected"); return -EINVAL; } dc_data = calloc(1, sizeof(struct disconnect_data)); if (dc_data == NULL) { smb2_set_error(smb2, "Failed to allocate disconnect_data"); return -ENOMEM; } dc_data->cb = cb; dc_data->cb_data = cb_data; pdu = smb2_cmd_tree_disconnect_async(smb2, disconnect_cb_1, dc_data); if (pdu == NULL) { free(dc_data); return -ENOMEM; } smb2_queue_pdu(smb2, pdu); return 0; } struct echo_data { smb2_command_cb cb; void *cb_data; }; static void echo_cb(struct smb2_context *smb2, int status, void *command_data _U_, void *private_data) { struct echo_data *cb_data = private_data; cb_data->cb(smb2, -nterror_to_errno(status), NULL, cb_data->cb_data); free(cb_data); } int smb2_echo_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct echo_data *echo_data; struct smb2_pdu *pdu; if (smb2 == NULL) { return -EINVAL; } echo_data = calloc(1, sizeof(struct echo_data)); if (echo_data == NULL) { smb2_set_error(smb2, "Failed to allocate echo_data"); return -ENOMEM; } echo_data->cb = cb; echo_data->cb_data = cb_data; pdu = smb2_cmd_echo_async(smb2, echo_cb, echo_data); if (pdu == NULL) { free(echo_data); return -ENOMEM; } smb2_queue_pdu(smb2, pdu); return 0; } uint32_t smb2_get_max_read_size(struct smb2_context *smb2) { return smb2->max_read_size; } uint32_t smb2_get_max_write_size(struct smb2_context *smb2) { return smb2->max_write_size; } smb2_file_id * smb2_get_file_id(struct smb2fh *fh) { return &fh->file_id; } struct smb2fh * smb2_fh_from_file_id(struct smb2_context *smb2, smb2_file_id *fileid) { struct smb2fh *fh; fh = calloc(1, sizeof(struct smb2fh)); if (fh == NULL) { return NULL; } memcpy(fh->file_id, fileid, SMB2_FD_SIZE); SMB2_LIST_ADD(&smb2->fhs, fh); return fh; } void smb2_fd_event_callbacks(struct smb2_context *smb2, smb2_change_fd_cb change_fd, smb2_change_events_cb change_events) { smb2->change_fd = change_fd; smb2->change_events = change_events; } void smb2_oplock_break_notify(struct smb2_context *smb2, int status, void *command_data, void *cb_data) { struct smb2_oplock_or_lease_break_reply *rep; struct smb2_oplock_break_reply rep_oplock; struct smb2_lease_break_reply rep_lease; struct smb2_pdu *pdu = NULL; uint8_t new_oplock_level; uint32_t new_lease_state; rep= command_data; if (smb2->oplock_or_lease_break_cb) { smb2->oplock_or_lease_break_cb(smb2, status, rep, &new_oplock_level, &new_lease_state); } /* for passthrough case assume the app callback will do everything needed */ if (!smb2->passthrough) { if (status) { return; } else switch (rep->break_type) { case SMB2_BREAK_TYPE_OPLOCK_NOTIFICATION: memset(&rep_oplock, 0, sizeof(rep_oplock)); rep_oplock.oplock_level = new_oplock_level; memcpy(rep_oplock.file_id, rep->lock.oplock.file_id, SMB2_FD_SIZE); pdu = smb2_cmd_oplock_break_reply_async(smb2, &rep_oplock, NULL, cb_data); break; case SMB2_BREAK_TYPE_OPLOCK_RESPONSE: break; case SMB2_BREAK_TYPE_LEASE_NOTIFICATION: memset(&rep_lease, 0, sizeof(rep_oplock)); rep_lease.flags = rep->lock.lease.flags; rep_lease.lease_state = new_lease_state; memcpy(rep_lease.lease_key, rep->lock.lease.lease_key, SMB2_LEASE_KEY_SIZE); pdu = smb2_cmd_lease_break_reply_async(smb2, &rep_lease, NULL, cb_data); break; case SMB2_BREAK_TYPE_LEASE_RESPONSE: break; default: smb2_set_error(smb2, "Bad oplock/lease break request %s", smb2_get_error(smb2)); return; } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } } /*************************** server handlers *************************************************************/ static void smb2_logoff_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_pdu *pdu = NULL; struct smb2_error_reply err; int ret = -EINVAL; if (server->handlers && server->handlers->logoff_cmd) { ret = server->handlers->logoff_cmd(server, smb2); } if (!ret) { pdu = smb2_cmd_logoff_reply_async(smb2, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_LOGOFF, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_tree_connect_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_tree_connect_request *req = command_data; struct smb2_tree_connect_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&rep, 0, sizeof(rep)); if (server->handlers && server->handlers->tree_connect_cmd) { ret = server->handlers->tree_connect_cmd(server, smb2, req, &rep); } if (!ret) { pdu = smb2_cmd_tree_connect_reply_async(smb2, &rep, 0, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_TREE_CONNECT, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_tree_disconnect_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_pdu *pdu = NULL; struct smb2_error_reply err; uint32_t tree_id = smb2->hdr.sync.tree_id; int ret = -1; if (server->handlers && server->handlers->tree_disconnect_cmd) { ret = server->handlers->tree_disconnect_cmd(server, smb2, smb2_tree_id(smb2)); } if (!ret) { pdu = smb2_cmd_tree_disconnect_reply_async(smb2, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_TREE_DISCONNECT, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } smb2_disconnect_tree_id(smb2, tree_id); } static void smb2_create_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_create_request *req = command_data; struct smb2_create_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&rep, 0, sizeof(rep)); if (server->handlers && server->handlers->create_cmd) { ret = server->handlers->create_cmd(server, smb2, req, &rep); } if (!ret) { pdu = smb2_cmd_create_reply_async(smb2, &rep, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_CREATE, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (req->name) { smb2_free_data(smb2, discard_const(req->name)); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_close_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_close_request *req = command_data; struct smb2_close_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&rep, 0, sizeof(rep)); if (server->handlers && server->handlers->close_cmd) { ret = server->handlers->close_cmd(server, smb2, req, &rep); } if (!ret) { pdu = smb2_cmd_close_reply_async(smb2, &rep, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_CLOSE, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_flush_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_flush_request *req = command_data; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; if (server->handlers && server->handlers->flush_cmd) { ret = server->handlers->flush_cmd(server, smb2, req); } if (!ret) { pdu = smb2_cmd_flush_reply_async(smb2, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_FLUSH, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_read_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_read_request *req = command_data; struct smb2_read_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&rep, 0, sizeof(rep)); if (server->handlers && server->handlers->read_cmd) { ret = server->handlers->read_cmd(server, smb2, req, &rep); } if (!ret) { pdu = smb2_cmd_read_reply_async(smb2, &rep, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_READ, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_write_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_write_request *req = command_data; struct smb2_write_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&rep, 0, sizeof(rep)); if (server->handlers && server->handlers->write_cmd) { ret = server->handlers->write_cmd(server, smb2, req, &rep); } if (!ret) { pdu = smb2_cmd_write_reply_async(smb2, &rep, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_WRITE, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_oplock_break_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_oplock_or_lease_break_request *req = command_data; struct smb2_oplock_break_reply rep_oplock; struct smb2_lease_break_reply rep_lease; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; if (req->struct_size == SMB2_OPLOCK_BREAK_NOTIFICATION_SIZE) { if (server->handlers && server->handlers->oplock_break_cmd) { ret = server->handlers->oplock_break_cmd(server, smb2, &req->lock.oplock); if (!ret) { memset(&rep_oplock, 0, sizeof(rep_oplock)); pdu = smb2_cmd_oplock_break_reply_async(smb2, &rep_oplock, NULL, cb_data); } } } else if ((req->struct_size == SMB2_LEASE_BREAK_NOTIFICATION_SIZE) | (req->struct_size == SMB2_LEASE_BREAK_REPLY_SIZE)) { if (server->handlers && server->handlers->lease_break_cmd) { ret = server->handlers->lease_break_cmd(server, smb2, &req->lock.lease); if (!ret) { memset(&rep_lease, 0, sizeof(rep_lease)); pdu = smb2_cmd_lease_break_reply_async(smb2, &rep_lease, NULL, cb_data); } } } if(ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_LOCK, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_lock_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_lock_request *req = command_data; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; if (server->handlers && server->handlers->lock_cmd) { ret = server->handlers->lock_cmd(server, smb2, req); } if (!ret) { pdu = smb2_cmd_lock_reply_async(smb2, NULL, cb_data); } else if(ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_LOCK, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_ioctl_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_ioctl_request *req = command_data; struct smb2_ioctl_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; struct smb2_ioctl_validate_negotiate_info out_info; int ret = -1; memset(&rep, 0, sizeof(rep)); rep.ctl_code = req->ctl_code; memcpy(rep.file_id, req->file_id, SMB2_FD_SIZE); if (req->ctl_code == SMB2_FSCTL_VALIDATE_NEGOTIATE_INFO) { /* this one only needs local handling ever */ /* in_info = (struct smb2_ioctl_validate_negotiate_info *)req->input; */ out_info.capabilities = smb2->capabilities; out_info.security_mode = smb2->security_mode; memcpy(out_info.guid, server->guid, 16); out_info.dialect = smb2->dialect; rep.output = (uint8_t*)&out_info; rep.output_count = sizeof(out_info); pdu = smb2_cmd_ioctl_reply_async(smb2, &rep, NULL, cb_data); } else { if (server->handlers && server->handlers->ioctl_cmd) { ret = server->handlers->ioctl_cmd(server, smb2, req, &rep); } if (!ret) { pdu = smb2_cmd_ioctl_reply_async(smb2, &rep, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_IOCTL, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_cancel_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; if (server->handlers && server->handlers->cancel_cmd) { ret = server->handlers->cancel_cmd(server, smb2); } if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_CANCEL, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_echo_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; if (server->handlers && server->handlers->echo_cmd) { ret = server->handlers->echo_cmd(server, smb2); } if (!ret) { pdu = smb2_cmd_echo_reply_async(smb2, NULL, cb_data); } else if (ret < 0) { memset(&err, 0, sizeof(err)); pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_ECHO, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_query_directory_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_query_directory_request *req = command_data; struct smb2_query_directory_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&rep, 0, sizeof(rep)); memset(&err, 0, sizeof(err)); if (server->handlers && server->handlers->query_directory_cmd) { ret = server->handlers->query_directory_cmd(server, smb2, req, &rep); } if (ret < 0) { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_QUERY_DIRECTORY, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } else if (!ret) { if (rep.output_buffer_length == 0) { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_QUERY_DIRECTORY, SMB2_STATUS_NO_MORE_FILES, NULL, cb_data); } else if (rep.output_buffer_length < 0) { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_QUERY_DIRECTORY, SMB2_STATUS_NOT_SUPPORTED, NULL, cb_data); } else { pdu = smb2_cmd_query_directory_reply_async(smb2, req, &rep, NULL, cb_data); } } if (req->name) { smb2_free_data(smb2, discard_const(req->name)); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_change_notify_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_change_notify_request *req = command_data; struct smb2_change_notify_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&rep, 0, sizeof(rep)); memset(&err, 0, sizeof(err)); if (server->handlers && server->handlers->change_notify_cmd) { ret = server->handlers->change_notify_cmd(server, smb2, req, &rep); } if (ret < 0) { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_CHANGE_NOTIFY, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } else if (!ret) { pdu = smb2_cmd_change_notify_reply_async(smb2, &rep, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_query_info_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_query_info_request *req = command_data; struct smb2_query_info_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&rep, 0, sizeof(rep)); memset(&err, 0, sizeof(err)); if (server->handlers && server->handlers->query_info_cmd) { ret = server->handlers->query_info_cmd(server, smb2, req, &rep); } if (ret < 0) { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_QUERY_INFO, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } else if (!ret) { if (rep.output_buffer_length == 0) { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_QUERY_INFO, SMB2_STATUS_NOT_SUPPORTED, NULL, cb_data); } else if (rep.output_buffer_length < 0) { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_QUERY_INFO, SMB2_STATUS_INVALID_INFO_CLASS, NULL, cb_data); } else { pdu = smb2_cmd_query_info_reply_async(smb2, req, &rep, NULL, cb_data); } } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_set_info_request_cb(struct smb2_server *server, struct smb2_context *smb2, void *command_data, void *cb_data) { struct smb2_set_info_request *req = command_data; struct smb2_error_reply err; struct smb2_pdu *pdu = NULL; int ret = -1; memset(&err, 0, sizeof(err)); if (server->handlers && server->handlers->set_info_cmd) { ret = server->handlers->set_info_cmd(server, smb2, req); } if (ret < 0) { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_SET_INFO, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } else if (!ret) { pdu = smb2_cmd_set_info_reply_async(smb2, req, NULL, cb_data); } if (pdu != NULL) { smb2_queue_pdu(smb2, pdu); } } static void smb2_session_setup_request_cb(struct smb2_context *smb2, int status, void *command_data, void *cb_data); static void smb2_general_client_request_cb(struct smb2_context *smb2, int status, void *command_data, void *cb_data) { struct connect_data *c_data = cb_data; struct smb2_server *server = c_data->server_context; if (!smb2->pdu) { smb2_set_error(smb2, "No pdu for general client request"); smb2_close_context(smb2); return; } if (status == SMB2_STATUS_CANCELLED) { return; } switch (smb2->pdu->header.command) { case SMB2_LOGOFF: smb2_logoff_request_cb(server, smb2, command_data, cb_data); /* alloc a pdu for next session setup request */ smb2->next_pdu = smb2_allocate_pdu(smb2, SMB2_TREE_CONNECT, smb2_session_setup_request_cb, cb_data); if (!smb2->next_pdu) { smb2_set_error(smb2, "can not alloc pdu for authorization session setup request"); smb2_close_context(smb2); } /* note special case */ return; case SMB2_TREE_CONNECT: smb2_tree_connect_request_cb(server, smb2, command_data, cb_data); break; case SMB2_TREE_DISCONNECT: smb2_tree_disconnect_request_cb(server, smb2, command_data, cb_data); break; case SMB2_CREATE: smb2_create_request_cb(server, smb2, command_data, cb_data); break; case SMB2_CLOSE: smb2_close_request_cb(server, smb2, command_data, cb_data); break; case SMB2_FLUSH: smb2_flush_request_cb(server, smb2, command_data, cb_data); break; case SMB2_READ: smb2_read_request_cb(server, smb2, command_data, cb_data); break; case SMB2_WRITE: smb2_write_request_cb(server, smb2, command_data, cb_data); break; case SMB2_OPLOCK_BREAK: smb2_oplock_break_request_cb(server, smb2, command_data, cb_data); break; case SMB2_LOCK: smb2_lock_request_cb(server, smb2, command_data, cb_data); break; case SMB2_IOCTL: smb2_ioctl_request_cb(server, smb2, command_data, cb_data); break; case SMB2_CANCEL: smb2_cancel_request_cb(server, smb2, command_data, cb_data); break; case SMB2_ECHO: smb2_echo_request_cb(server, smb2, command_data, cb_data); break; case SMB2_QUERY_DIRECTORY: smb2_query_directory_request_cb(server, smb2, command_data, cb_data); break; case SMB2_CHANGE_NOTIFY: smb2_change_notify_request_cb(server, smb2, command_data, cb_data); break; case SMB2_QUERY_INFO: smb2_query_info_request_cb(server, smb2, command_data, cb_data); break; case SMB2_SET_INFO: smb2_set_info_request_cb(server, smb2, command_data, cb_data); break; default: smb2_set_error(smb2, "Client request %d not implemented %s", smb2->pdu->header.command, smb2_get_error(smb2)); break; } /* alloc a pdu for next request. note that we dont really expect a tree connect, its just to * allow pdu reading to know to allow for any command above negotiate and session-setup */ smb2->next_pdu = smb2_allocate_pdu(smb2, SMB2_TREE_CONNECT, smb2_general_client_request_cb, cb_data); if (!smb2->next_pdu) { smb2_set_error(smb2, "can not alloc pdu for authorization session setup request"); smb2_close_context(smb2); } } #include "smb2-signing.h" static void smb2_session_setup_request_cb(struct smb2_context *smb2, int status, void *command_data, void *cb_data) { struct connect_data *c_data = cb_data; struct smb2_server *server = c_data->server_context; struct smb2_session_setup_request *req = command_data; struct smb2_session_setup_reply rep; struct smb2_pdu *pdu; struct smb2_error_reply err; uint32_t message_type; int more_processing_needed = 0; uint8_t *response_token; int response_length; int is_spnego_wrapped; int have_valid_session_key = 1; int ret; if (status) { return; } rep.security_buffer_length = 0; rep.security_buffer_offset = 0; rep.session_flags = 0; /* req->flags; */ smb3_update_preauth_hash(smb2, smb2->in.niov - 1, &smb2->in.iov[1]); memset(&err, 0, sizeof(err)); pdu = NULL; if (smb2->sec == SMB2_SEC_NTLMSSP) { if (ntlmssp_get_message_type(smb2, req->security_buffer, req->security_buffer_length, &message_type, &response_token, &response_length, &is_spnego_wrapped) < 0) { smb2_set_error(smb2, "No message type in NTLMSSP %s", smb2_get_error(smb2)); smb2_close_context(smb2); return; } /* set error code in header - more processing required if negotiate req not auth req */ if (message_type == NEGOTIATE_MESSAGE) { if (c_data->auth_data) { ntlmssp_destroy_context(c_data->auth_data); } c_data->auth_data = ntlmssp_init_context( "", "", "", server->hostname, smb2->client_challenge ); if (!c_data->auth_data) { smb2_set_error(smb2, "can not init auth data %s", smb2_get_error(smb2)); smb2_close_context(smb2); return; } smb2->connect_data = c_data; /* alloc a pdu for next request */ smb2->next_pdu = smb2_allocate_pdu(smb2, SMB2_SESSION_SETUP, smb2_session_setup_request_cb, cb_data); more_processing_needed = 1; smb2->session_id = server->session_counter++; } else if (message_type == AUTHENTICATION_MESSAGE) { /* alloc a pdu for next request (not really required to get tree connect) */ smb2->next_pdu = smb2_allocate_pdu(smb2, SMB2_TREE_CONNECT, smb2_general_client_request_cb, cb_data); } else { smb2_set_error(smb2, "Unexpected ntlmssp msg code %08X", message_type); smb2_close_context(smb2); return; } if (ntlmssp_generate_blob(server, smb2, 0, c_data->auth_data, req->security_buffer, req->security_buffer_length, &rep.security_buffer, &rep.security_buffer_length) < 0) { smb2_close_context(smb2); return; } if (message_type == AUTHENTICATION_MESSAGE) { if (!ntlmssp_get_authenticated(c_data->auth_data)) { smb2_set_error(smb2, "Authentication failed: %s", smb2_get_error(smb2)); #if 0 smb2_close_context(smb2); return; #else pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_SESSION_SETUP, SMB2_STATUS_LOGON_FAILURE, NULL, cb_data); smb2_free_pdu(smb2, smb2->next_pdu); smb2->next_pdu = smb2_allocate_pdu(smb2, SMB2_SESSION_SETUP, smb2_session_setup_request_cb, cb_data); more_processing_needed = 0; #endif } if (ntlmssp_get_session_key(c_data->auth_data, &smb2->session_key, &smb2->session_key_size) < 0) { have_valid_session_key = 0; } } } #ifdef HAVE_LIBKRB5 else { /* TODO: */ have_valid_session_key = 0; } #endif if (smb2->sign && have_valid_session_key == 0) { smb2_close_context(smb2); smb2_set_error(smb2, "Signing required by server. Session " "Key is not available %s", smb2_get_error(smb2)); return; } if (smb2->sign) { /* Derive the signing key from session key * This is based on negotiated protocol */ smb2_create_signing_key(smb2); } if (server->allow_anonymous && ((smb2->user == NULL || smb2->user[0] == '\0')|| (smb2->password == NULL || smb2->password[0] == '\0'))) { rep.session_flags |= SMB2_SESSION_FLAG_IS_GUEST; } if (!pdu) { pdu = smb2_cmd_session_setup_reply_async(smb2, &rep, NULL, cb_data); if (pdu == NULL) { return; } if (more_processing_needed) { pdu->header.status = SMB2_STATUS_MORE_PROCESSING_REQUIRED; } else { if (server->handlers && server->handlers->session_established) { ret = server->handlers->session_established(server, smb2); if (ret) { smb2_set_error(smb2, "server session start handler failed"); smb2_close_context(smb2); return; } } else { pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_SESSION_SETUP, SMB2_STATUS_NOT_IMPLEMENTED, NULL, cb_data); } } } if (!smb2->next_pdu) { smb2_set_error(smb2, "can not alloc pdu for authorization session setup request"); smb2_close_context(smb2); return; } smb2_queue_pdu(smb2, pdu); smb3_update_preauth_hash(smb2, pdu->out.niov, &pdu->out.iov[0]); } static void smb2_negotiate_request_cb(struct smb2_context *smb2, int status, void *command_data, void *cb_data) { struct connect_data *c_data = cb_data; struct smb2_server *server = c_data->server_context; struct smb2_negotiate_request *req = command_data; struct smb2_negotiate_reply rep; struct smb2_error_reply err; struct smb2_pdu *pdu; uint16_t dialects[SMB2_NEGOTIATE_MAX_DIALECTS]; int dialect_count; int d; int dialect_index; struct smb2_timeval now; /*void *auth_data;*/ memset(&rep, 0, sizeof(rep)); memset(&err, 0, sizeof(err)); smb2_set_error(smb2, ""); /* negotiate highest version in request dialects */ switch (smb2->version) { case SMB2_VERSION_ANY: dialect_count = 5; dialects[0] = SMB2_VERSION_0202; dialects[1] = SMB2_VERSION_0210; dialects[2] = SMB2_VERSION_0300; dialects[3] = SMB2_VERSION_0302; dialects[4] = SMB2_VERSION_0311; break; case SMB2_VERSION_ANY2: dialect_count = 2; dialects[0] = SMB2_VERSION_0202; dialects[1] = SMB2_VERSION_0210; break; case SMB2_VERSION_ANY3: dialect_count = 3; dialects[0] = SMB2_VERSION_0300; dialects[1] = SMB2_VERSION_0302; dialects[2] = SMB2_VERSION_0311; break; case SMB2_VERSION_0202: case SMB2_VERSION_0210: case SMB2_VERSION_0300: case SMB2_VERSION_0302: case SMB2_VERSION_0311: default: dialect_count = 1; dialects[0] = smb2->version; break; } if (req && smb2->pdu->header.command != SMB1_NEGOTIATE) { if (req->dialect_count == 0) { /* windows does this crap */ /* alloc a pdu for another negotiate request */ smb2->next_pdu = smb2_allocate_pdu(smb2, SMB2_NEGOTIATE, smb2_negotiate_request_cb, cb_data); if (!smb2->next_pdu) { smb2_set_error(smb2, "can not alloc pdu for second negotiate request"); smb2_close_context(smb2); } pdu = smb2_cmd_error_reply_async(smb2, &err, SMB2_NEGOTIATE, SMB2_STATUS_INVALID_PARAMETER, NULL, cb_data); if (pdu == NULL) { return; } smb2_queue_pdu(smb2, pdu); return; } smb2->dialect = 0; for (dialect_index = req->dialect_count - 1; dialect_index >= 0; dialect_index--) { for (d = dialect_count - 1; d >= 0; d--) { if (dialects[d] == req->dialects[dialect_index]) { smb2->dialect = dialects[d]; break; } } if (smb2->dialect != 0) { break; } } if (dialect_index < 0) { smb2_set_error(smb2, "No common dialects for protocol"); smb2_close_context(smb2); return; } smb2_set_client_guid(smb2, req->client_guid); } else { /* sn smb1-negotiate, list all dialects */ smb2->dialect = SMB2_VERSION_WILDCARD; } smb3_init_preauth_hash(smb2); smb3_update_preauth_hash(smb2, smb2->in.niov - 1, &smb2->in.iov[1]); if (req) { rep.capabilities = SMB2_GLOBAL_CAP_LARGE_MTU; if (smb2->version == SMB2_VERSION_ANY || smb2->version == SMB2_VERSION_ANY3 || smb2->version == SMB2_VERSION_0300 || smb2->version == SMB2_VERSION_0302 || smb2->version == SMB2_VERSION_0311) { rep.capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; } /* update the context with the client capabilities */ if (smb2->dialect > SMB2_VERSION_0202) { if (req->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) { smb2->supports_multi_credit = 1; } } if (smb2->seal && (smb2->dialect == SMB2_VERSION_0300 || smb2->dialect == SMB2_VERSION_0302)) { if(!(req->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) { smb2_set_error(smb2, "Encryption requested but client " "does not support encryption."); smb2_close_context(smb2); return; } } if (smb2->sign && !(req->security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED)) { smb2_set_error(smb2, "Signing required but client " "does not support signing."); smb2_close_context(smb2); return; } if (req->security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { smb2->sign = 1; } if (!server->allow_anonymous || (smb2->password && smb2->password[0])) { if (server->signing_enabled) { if (req->security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED && smb2->dialect == SMB2_VERSION_0210) { /* smb2.1 requires signing if enabled on both sides * regardless of what the flags say */ smb2->sign = 1; } if (req->security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED && smb2->dialect >= SMB2_VERSION_0311) { /* smb3.1.1 requires signing if enabled on both sides * regardless of what the flags say */ smb2->sign = 1; } } } if (smb2->seal) { smb2->sign = 0; } } rep.security_mode = (server->signing_enabled ? SMB2_NEGOTIATE_SIGNING_ENABLED : 0)| (smb2->sign ? SMB2_NEGOTIATE_SIGNING_REQUIRED : 0); memcpy(rep.server_guid, server->guid, 16); /* TODO */ rep.max_transact_size = smb2->max_transact_size;; rep.max_read_size = smb2->max_read_size; rep.max_write_size = smb2->max_write_size; rep.dialect_revision = smb2->dialect; rep.cypher = smb2->cypher; /* remember negotiated capabilites and security mode */ smb2->capabilities = rep.capabilities; smb2->security_mode = rep.security_mode; now.tv_sec = time(NULL); now.tv_usec = 0; rep.system_time = smb2_timeval_to_win(&now); now.tv_sec = 0; rep.server_start_time = smb2_timeval_to_win(&now); smb2->sec = SMB2_SEC_NTLMSSP; if (smb2->sec == SMB2_SEC_UNDEFINED) { #ifdef HAVE_LIBKRB5 smb2->sec = SMB2_SEC_KRB5; #else smb2->sec = SMB2_SEC_NTLMSSP; #endif } rep.security_buffer_length = smb2_spnego_create_negotiate_reply_blob( smb2, (void*)&rep.security_buffer); pdu = smb2_cmd_negotiate_reply_async(smb2, &rep, NULL, cb_data); if (rep.security_buffer) { free(rep.security_buffer); } if (pdu == NULL) { return; } smb2_queue_pdu(smb2, pdu); smb3_update_preauth_hash(smb2, pdu->out.niov, &pdu->out.iov[0]); if (req) { /* alloc a pdu for session request */ smb2->next_pdu = smb2_allocate_pdu(smb2, SMB2_SESSION_SETUP, smb2_session_setup_request_cb, cb_data); if (!smb2->next_pdu) { smb2_set_error(smb2, "can not alloc pdu for session setup request"); smb2_close_context(smb2); } } else { /* alloc a pdu for another negotiate request */ smb2->next_pdu = smb2_allocate_pdu(smb2, SMB2_NEGOTIATE, smb2_negotiate_request_cb, cb_data); if (!smb2->next_pdu) { smb2_set_error(smb2, "can not alloc pdu for second negotiate request"); smb2_close_context(smb2); } } } static int accept_cb(const int fd, void *cb_data) { int err = -1; struct smb2_context **psmb2 = (struct smb2_context**)cb_data; struct smb2_context *smb2; if (!psmb2) { return -EINVAL; } *psmb2 = NULL; smb2 = smb2_init_context(); if (smb2 == NULL) { err = -ENOMEM; } else { *psmb2 = smb2; /* put client fd into connecting fd array (todo? for now just set fd) */ smb2->fd = fd; err = 0; } return err; } int smb2_serve_port_async(const int fd, const int to_msecs, struct smb2_context **smb2) { int err = -1; err = smb2_accept_connection_async(fd, to_msecs, accept_cb, smb2); return err; } int smb2_serve_port(struct smb2_server *server, const int max_connections, smb2_client_connection cb, void *cb_data) { struct smb2_context *smb2; struct connect_data *c_data = cb_data; fd_set rfds, wfds; int maxfd; int ready; short events; struct timeval timeout; int err = -1; static const char *default_domain = "WORKGROUP"; if (!server->max_transact_size) { server->max_transact_size = 0x100000; server->max_read_size = 0x100000; server->max_write_size = 0x100000; } if (!server->guid[0]) { memcpy(server->guid, "libsmb2-srvrguid", 16); } if (!server->hostname[0]) { gethostname(server->hostname, sizeof(server->hostname)); } if (!server->domain[0]) { strncpy(server->domain, default_domain, MIN(sizeof(server->domain),strlen(default_domain) + 1)); } err = smb2_bind_and_listen(server->port, max_connections, &server->fd); if (err != 0) { return err; } server->session_counter = 0x1234; do { /* select on the file descriptors of all active client connections and our server socket for the first readable event */ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(server->fd, &rfds); maxfd = server->fd; for (smb2 = smb2_active_contexts(); smb2; smb2 = smb2->next) { if (SMB2_VALID_SOCKET(smb2_get_fd(smb2))) { events = smb2_which_events(smb2); if (events) { if (events & POLLIN) { FD_SET(smb2_get_fd(smb2), &rfds); } if (events & POLLOUT) { FD_SET(smb2_get_fd(smb2), &wfds); } if (smb2_get_fd(smb2) > (t_socket)maxfd) { maxfd = smb2_get_fd(smb2); } } } } /* 100ms select timeout to allow period pdu timeouts */ timeout.tv_sec = 0; timeout.tv_usec = 100000; ready = select( maxfd + 1, &rfds, &wfds, NULL, (timeout.tv_sec > 0 || timeout.tv_usec >= 0) ? &timeout : NULL ); if (ready > 0) { time_t t = time(NULL); /* for each client context ready to read, process that context */ for (smb2 = smb2_active_contexts(); smb2; smb2 = smb2->next) { if (SMB2_VALID_SOCKET(smb2_get_fd(smb2)) && FD_ISSET(smb2_get_fd(smb2), &rfds)) { if (smb2_service(smb2, POLLIN) < 0) { smb2_set_error(smb2, "smb2_service (in) failed with : " "%s", smb2_get_error(smb2)); smb2_close_context(smb2); } err = 0; } if (SMB2_VALID_SOCKET(smb2_get_fd(smb2)) && FD_ISSET(smb2_get_fd(smb2), &wfds)) { if (smb2_service(smb2, POLLOUT) < 0) { smb2_set_error(smb2, "smb2_service (out) failed with : " "%s", smb2_get_error(smb2)); smb2_close_context(smb2); } } if (!SMB2_VALID_SOCKET(smb2->fd) && ((time(NULL) - t) > (smb2->timeout))) { smb2_set_error(smb2, "Timeout expired and no connection exists\n"); smb2_close_context(smb2); } if (smb2->timeout) { smb2_timeout_pdus(smb2); } } if (FD_ISSET(server->fd, &rfds)) { smb2 = NULL; err = smb2_serve_port_async(server->fd, 10, &smb2); if (!err && smb2) { c_data = calloc(1, sizeof(struct connect_data)); if (c_data == NULL) { smb2_set_error(smb2, "Failed to allocate connect_data"); smb2_close_context(smb2); } c_data->server_context = server; smb2->connect_data = c_data; /* alloc a pdu for first server request */ smb2->pdu = smb2_allocate_pdu(smb2, SMB2_NEGOTIATE, smb2_negotiate_request_cb, c_data); if (!smb2->pdu) { smb2_set_error(smb2, "can not alloc pdu for request"); smb2_close_context(smb2); } /* got a new smb2 context with a connection, enlist it and tell user */ smb2->owning_server = server; smb2->max_transact_size = server->max_transact_size; smb2->max_read_size = server->max_read_size; smb2->max_write_size = server->max_write_size; if (cb) { cb(smb2, cb_data); } } else if (err) { break; } } /* cull connection-less clients here, one per iteration (since active list changes on destroy)*/ for (smb2 = smb2_active_contexts(); smb2; smb2 = smb2->next) { if (smb2_is_server(smb2)) { if (!SMB2_VALID_SOCKET(smb2_get_fd(smb2))) { if (server->handlers && server->handlers->destruction_event) { server->handlers->destruction_event(server, smb2); } smb2_destroy_context(smb2); break; } } /* client connections are destroyed when they timeout or get disconnected */ } } } while (err == 0); close(server->fd); server->fd = -1; while (smb2_active_contexts()) { smb2 = smb2_active_contexts(); smb2_destroy_context(smb2); } return err; } libsmb2-6.2/lib/ntlmssp.h0000664000175000017500000000473414732155517014446 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #ifndef _GSSAPI_WRAPPER_H_ #define _GSSAPI_WRAPPER_H_ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef __cplusplus extern "C" { #endif #define NEGOTIATE_MESSAGE 0x00000001 #define CHALLENGE_MESSAGE 0x00000002 #define AUTHENTICATION_MESSAGE 0x00000003 struct auth_data; struct auth_data * ntlmssp_init_context(const char *user, const char *password, const char *domain, const char *workstation, const char *client_challenge); void ntlmssp_destroy_context(struct auth_data *auth); void ntlmssp_set_spnego_wrapping(struct auth_data *auth, int wrap); int ntlmssp_get_spnego_wrapping(struct auth_data *auth); int ntlmssp_get_message_type(struct smb2_context *smb2, uint8_t *ntlmssp_buffer, int len, uint32_t *message_type, uint8_t **ntlmssp_ptr, int *ntlmssp_len, int *is_wrapped); int ntlmssp_generate_blob(struct smb2_server *server, struct smb2_context *smb2, time_t t, struct auth_data *auth_data, unsigned char *input_buf, int input_len, unsigned char **output_buf, uint16_t *output_len); int ntlmssp_authenticate_blob(struct smb2_server *server, struct smb2_context *smb2, struct auth_data *auth_data, unsigned char *input_buf, int input_len); int ntlmssp_get_authenticated(struct auth_data *auth); int ntlmssp_get_session_key(struct auth_data *auth, uint8_t **key, uint8_t *key_size); #ifdef __cplusplus } #endif #endif /* _GSSAPI_WRAPPER_H_ */ libsmb2-6.2/lib/Makefile.am0000664000175000017500000000304214732155517014620 0ustar polpypolpyAM_CFLAGS=$(WARN_CFLAGS) lib_LTLIBRARIES = libsmb2.la libsmb2_la_CPPFLAGS = -I$(abs_top_srcdir)/include \ -I$(abs_top_srcdir)/include/smb2 \ "-D_U_=__attribute__((unused))" libsmb2_la_SOURCES = \ aes.h \ aes.c \ aes128ccm.h \ aes128ccm.c \ alloc.c \ asn1-ber.c \ compat.c \ compat.h \ dcerpc.c \ dcerpc-lsa.c \ dcerpc-srvsvc.c \ errors.c \ init.c \ hmac.c \ hmac-md5.h \ hmac-md5.c \ krb5-wrapper.h \ krb5-wrapper.c \ libsmb2.c \ md4.h \ md4c.c \ md5.h \ md5.c \ ntlmssp.h \ ntlmssp.c \ pdu.c \ sha.h \ sha-private.h \ sha1.c \ sha224-256.c \ sha384-512.c \ smb2-cmd-close.c \ smb2-cmd-create.c \ smb2-cmd-echo.c \ smb2-cmd-error.c \ smb2-cmd-flush.c \ smb2-cmd-ioctl.c \ smb2-cmd-lock.c \ smb2-cmd-logoff.c \ smb2-cmd-negotiate.c \ smb2-cmd-notify-change.c \ smb2-cmd-oplock-break.c \ smb2-cmd-query-directory.c \ smb2-cmd-query-info.c \ smb2-cmd-read.c \ smb2-cmd-session-setup.c \ smb2-cmd-set-info.c \ smb2-cmd-tree-connect.c \ smb2-cmd-tree-disconnect.c \ smb2-cmd-write.c \ smb2-data-file-info.c \ smb2-data-filesystem-info.c \ smb2-data-reparse-point.c \ smb2-data-security-descriptor.c \ smb2-share-enum.c \ smb3-seal.h \ smb3-seal.c \ smb2-signing.h \ smb2-signing.c \ socket.c \ spnego-wrapper.c \ sync.c \ timestamps.c \ unicode.c \ usha.c SOCURRENT=6 SOREVISION=1 SOAGE=0 libsmb2_la_LDFLAGS = \ -version-info $(SOCURRENT):$(SOREVISION):$(SOAGE) -bindir $(bindir) \ -no-undefined -export-symbols ${srcdir}/libsmb2.syms $(MAYBE_LIBKRB5) dist_noinst_DATA = libsmb2.syms libsmb2-6.2/lib/asn1-ber.h0000664000175000017500000001461514732155517014355 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #ifndef _ASN1_BER_H_ #define _ASN1_BER_H_ /* Copyright (C) 2018 by Ronnie Sahlberg and 2024 by Brian Dodge Copyright (C) 2024 by André Guilherme This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STDINT_H #include #endif #ifdef __cplusplus extern "C" { #endif #define BER_MAX_OID_ELEMENTS (32) typedef uint32_t beroid_type_t; /* Notes: BER = ASN.1 Basic Encoding Rules defined in ITU-TX.690 * https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */ /** ASN.1 Type Tags in BER per X.208 */ #define asnUNIVERSAL (0x0) #define asnBOOLEAN (0x1) #define asnINTEGER (0x2) #define asnBIT_STRING (0x3) #define asnOCTET_STRING (0x4) #define asnNULL (0x5) #define asnOBJECT_ID (0x6) #define asnENUMERATED (0xA) #define asnSEQUENCE (0x10) #define asnSET (0x11) #define asnPRINTABLE_STR (0x13) #define asnUTC_TIME (0x17) /** ASN.1 Type Class in BER per X.690 */ #define asnEXTENSION_ID (0x1F) #define asnCONSTRUCTOR (0x20) #define asnSTRUCT (0x30) #define asnAPPLICATION (0x40) #define asnCONTEXT_SPECIFIC (0x80) #define asnPRIVATE (0xC0) typedef enum { /** SNMP Basic Types per ASN.1 BER */ BER_BOOLEAN = (asnBOOLEAN), BER_INTEGER = (asnINTEGER), BER_BIT_STRING = (asnBIT_STRING), BER_OCTET_STRING = (asnOCTET_STRING), BER_NULL = (asnNULL), BER_OBJECT_ID = (asnOBJECT_ID), BER_ENUMERATED = (asnENUMERATED), BER_SEQUENCE = (asnSEQUENCE), BER_SETOF = (asnSET), BER_PRINTABLE_STR = (asnPRINTABLE_STR), BER_UTC_TIME = (asnUTC_TIME), /** BER Types as per RFC-1442, pre-formatted per BER */ BER_IPADDRESS = (asnAPPLICATION | 0x0), BER_COUNTER = (asnAPPLICATION | 0x1), BER_GAUGE = (asnAPPLICATION | 0x2), BER_UNSIGNED = (asnAPPLICATION | 0x2), BER_TIMETICKS = (asnAPPLICATION | 0x3), BER_OPAQUE = (asnAPPLICATION | 0x4), BER_NSAPADDRESS = (asnAPPLICATION | 0x5), BER_COUNTER64 = (asnAPPLICATION | 0x6), BER_UNSIGNED32 = (asnAPPLICATION | 0x7), BER_FLOAT = (asnAPPLICATION | 0x8), BER_DOUBLE = (asnAPPLICATION | 0x9), /** BER Types per RFC3781 = (Next gen SMI) */ BER_INTEGER64 = (asnAPPLICATION | 0xA), BER_UNSIGNED64 = (asnAPPLICATION | 0xB), BER_FLOAT32 = (asnAPPLICATION | 0xC), BER_FLOAT64 = (asnAPPLICATION | 0xD), BER_FLOAT128 = (asnAPPLICATION | 0xE) } ber_type_t; #define ASN1_SEQUENCE(n) (asnSTRUCT | (n)) #define ASN1_CONTEXT(n) (asnCONTEXT_SPECIFIC | asnCONSTRUCTOR | (n)) #define ASN1_CONTEXT_SIMPLE(n) (asnCONTEXT_SPECIFIC | (n)) #define ASN1_PRIVATE (asnPRIVATE) struct asn1ber_context { uint8_t *src; int src_count; int src_tail; uint8_t *dst; int dst_size; int dst_head; int last_error; }; struct asn1ber_oid_value { int length; beroid_type_t elements[BER_MAX_OID_ELEMENTS]; }; int asn1ber_save_out_state(struct asn1ber_context *actx, int *out_pos); int asn1ber_annotate_length(struct asn1ber_context *actx, int out_pos, int reserved); int asn1ber_length_from_ber(struct asn1ber_context *actx, uint32_t *len); int ber_typecode_from_ber(struct asn1ber_context *actx, ber_type_t *typecode); int ber_typelen_from_ber(struct asn1ber_context *actx, ber_type_t *typecode, uint32_t *len); int asn1ber_request_from_ber(struct asn1ber_context *actx, ber_type_t *opcode, uint32_t *len); int asn1ber_struct_from_ber(struct asn1ber_context *actx, uint32_t *len); int asn1ber_null_from_ber(struct asn1ber_context *actx, uint32_t *len); int asn1ber_int32_from_ber(struct asn1ber_context *actx, int32_t *val); int asn1ber_uint32_from_ber(struct asn1ber_context *actx, uint32_t *val); int asn1ber_int64_from_ber(struct asn1ber_context *actx, int64_t *val); int asn1ber_uint64_from_ber(struct asn1ber_context *actx, uint64_t *val); int asn1ber_oid_from_ber(struct asn1ber_context *actx, struct asn1ber_oid_value *oid); int asn1ber_bytes_from_ber(struct asn1ber_context *actx, uint8_t *val, uint32_t maxlen, uint32_t *lenout); int asn1ber_string_from_ber(struct asn1ber_context *actx, char *val, uint32_t maxlen, uint32_t *lenout); int asn1ber_ber_from_length(struct asn1ber_context *actx, uint32_t lenin, uint32_t *lenout); int asn1ber_ber_reserve_length(struct asn1ber_context *actx, uint32_t len); int asn1ber_ber_from_typecode(struct asn1ber_context *actx, const ber_type_t typecode); int asn1ber_ber_from_typelen(struct asn1ber_context *actx, const ber_type_t typecode, const uint32_t lenin, uint32_t *lenout); int asn1ber_ber_from_int32(struct asn1ber_context *actx, const ber_type_t type, const int32_t val); int asn1ber_ber_from_uint32(struct asn1ber_context *actx, const ber_type_t type, const uint32_t val); int asn1ber_ber_from_int64(struct asn1ber_context *actx, const ber_type_t type, const int64_t val); int asn1ber_ber_from_uint64(struct asn1ber_context *actx, const ber_type_t type, const uint64_t val); int asn1ber_ber_from_oid(struct asn1ber_context *actx, const struct asn1ber_oid_value *oid); int asn1ber_ber_from_bytes(struct asn1ber_context *actx, const ber_type_t type, const uint8_t *val, uint32_t len); int asn1ber_ber_from_string(struct asn1ber_context *actx, const char *val, uint32_t len); #ifdef __cplusplus } #endif #endif /* ASN1_BER_H_ */ libsmb2-6.2/lib/hmac-md5.c0000664000175000017500000000534414732155517014332 0ustar polpypolpy/* From RFC2104 */ /* ** Function: hmac_md5 */ #ifdef HAVE_STRINGS_H #include #endif #include "compat.h" #include "md5.h" /* * unsigned char* text; pointer to data stream/ * int text_len; length of data stream * unsigned char* key; pointer to authentication key * int key_len; length of authentication key * caddr_t digest; caller digest to be filled in */ void smb2_hmac_md5(unsigned char *text, int text_len, unsigned char *key, unsigned int key_len, unsigned char *digest) { struct MD5Context context; unsigned char k_ipad[65]; /* inner padding - * key XORd with ipad */ unsigned char k_opad[65]; /* outer padding - * key XORd with opad */ unsigned char tk[16]; int i; /* if key is longer than 64 bytes reset it to key=MD5(key) */ if (key_len > 64) { struct MD5Context tctx; MD5Init(&tctx); MD5Update(&tctx, key, key_len); MD5Final(tk, &tctx); key = tk; key_len = 16; } /* * the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * and text is the data being protected */ /* start out by storing key in pads */ memset(k_ipad, 0, sizeof k_ipad); memset(k_opad, 0, sizeof k_opad); memmove(k_ipad, key, key_len); memmove(k_opad, key, key_len); /* XOR key with ipad and opad values */ for (i=0; i<64; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; } /* * perform inner MD5 */ MD5Init(&context); /* init context for 1st * pass */ MD5Update(&context, k_ipad, 64); /* start with inner pad */ MD5Update(&context, text, text_len); /* then text of datagram */ MD5Final(digest, &context); /* finish up 1st pass */ /* * perform outer MD5 */ MD5Init(&context); /* init context for 2nd * pass */ MD5Update(&context, k_opad, 64); /* start with outer pad */ MD5Update(&context, digest, 16); /* then results of 1st * hash */ MD5Final(digest, &context); /* finish up 2nd pass */ } libsmb2-6.2/lib/smb2-cmd-tree-connect.c0000664000175000017500000001752414732155517016732 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_tree_connect_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_tree_connect_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_TREE_CONNECT_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate tree connect setup " "buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_TREE_CONNECT_REQUEST_SIZE); smb2_set_uint16(iov, 2, req->flags); /* path offset */ smb2_set_uint16(iov, 4, SMB2_HEADER_SIZE + len); smb2_set_uint16(iov, 6, req->path_length); /* Path */ buf = malloc(req->path_length); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate tcon path"); return -1; } memcpy(buf, req->path, req->path_length); iov = smb2_add_iovector(smb2, &pdu->out, buf, req->path_length, free); return 0; } struct smb2_pdu * smb2_cmd_tree_connect_async(struct smb2_context *smb2, struct smb2_tree_connect_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_TREE_CONNECT, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_tree_connect_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_tree_connect_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_tree_connect_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_TREE_CONNECT_REPLY_SIZE; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate tree connect reply " "buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_TREE_CONNECT_REPLY_SIZE); smb2_set_uint8(iov, 2, rep->share_type); smb2_set_uint8(iov, 3, 0); smb2_set_uint32(iov, 4, rep->share_flags); smb2_set_uint32(iov, 8, rep->capabilities); smb2_set_uint32(iov, 12, rep->maximal_access); return 0; } struct smb2_pdu * smb2_cmd_tree_connect_reply_async(struct smb2_context *smb2, struct smb2_tree_connect_reply *rep, uint32_t tree_id, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; static uint32_t s_tree_id = 0xfeedface; pdu = smb2_allocate_pdu(smb2, SMB2_TREE_CONNECT, cb, cb_data); if (pdu == NULL) { return NULL; } if (!tree_id) { /* invent a tree-id and use it while tree connected */ tree_id = s_tree_id++; } smb2_connect_tree_id(smb2, tree_id); pdu->header.sync.tree_id = smb2_tree_id(smb2); if (smb2_encode_tree_connect_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_tree_connect_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_tree_connect_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_TREE_CONNECT_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Tree Connect " "reply. Expected %d, got %d", SMB2_TREE_CONNECT_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate tcon reply"); return -1; } pdu->payload = rep; smb2_connect_tree_id(smb2, smb2->hdr.sync.tree_id); smb2_get_uint8(iov, 2, &rep->share_type); smb2_get_uint32(iov, 4, &rep->share_flags); smb2_get_uint32(iov, 8, &rep->capabilities); smb2_get_uint32(iov, 12, &rep->maximal_access); if (!smb2->seal) smb2->seal = !!(rep->share_flags & SMB2_SHAREFLAG_ENCRYPT_DATA); return 0; } int smb2_process_tree_connect_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_tree_connect_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_TREE_CONNECT_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Tree Connect " "request. Expected %d, got %d", SMB2_TREE_CONNECT_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate tcon request"); return -1; } pdu->payload = req; smb2_get_uint16(iov, 2, &req->flags); smb2_get_uint16(iov, 4, &req->path_offset); smb2_get_uint16(iov, 6, &req->path_length); return req->path_length; } int smb2_process_tree_connect_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_tree_connect_request *req = (struct smb2_tree_connect_request*)pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; req->path = (uint16_t*)iov->buf; return 0; } libsmb2-6.2/lib/aes.c0000664000175000017500000004461314732155517013511 0ustar polpypolpy/* From https://github.com/bitdust/tiny-AES128-C * Licenced as Public Domain */ /* This is an implementation of the AES128 algorithm, specifically ECB and CBC mode. The implementation is verified against the test vectors in: National Institute of Standards and Technology Special Publication 800-38A 2001 ED ECB-AES128 ---------- plain-text: 6bc1bee22e409f96e93d7e117393172a ae2d8a571e03ac9c9eb76fac45af8e51 30c81c46a35ce411e5fbc1191a0a52ef f69f2445df4f9b17ad2b417be66c3710 key: 2b7e151628aed2a6abf7158809cf4f3c resulting cipher 3ad77bb40d7a3660a89ecaf32466ef97 f5d3d58503b9699de785895a96fdbaaf 43b1cd7f598ece23881b00e3ed030688 7b0c785e27e8ad3f8223207104725dd4 NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) You should pad the end of the string with zeros if this is not the case. */ /*****************************************************************************/ /* Includes: */ /*****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STDINT_H #include #endif #include "compat.h" #include // CBC mode, for memset #include "aes.h" /*****************************************************************************/ /* Defines: */ /*****************************************************************************/ // The number of columns comprising a state in AES. This is a constant in AES. Value=4 #define Nb 4 // The number of 32 bit words in a key. #define Nk 4 // Key length in bytes [128 bit] #define KEYLEN 16 // The number of rounds in AES Cipher. #define Nr 10 // jcallan@github points out that declaring Multiply as a function // reduces code size considerably with the Keil ARM compiler. // See this link for more information: https://github.com/kokke/tiny-AES128-C/pull/3 #ifndef MULTIPLY_AS_A_FUNCTION #define MULTIPLY_AS_A_FUNCTION 0 #endif // state - array holding the intermediate results during decryption. typedef uint8_t state_t[4][4]; // The lookup-tables are marked const so they can be placed in read-only storage instead of RAM // The numbers below can be computed dynamically trading ROM for RAM - // This can be useful in (embedded) bootloader applications, where ROM is often limited. static const uint8_t sbox[256] = { //0 1 2 3 4 5 6 7 8 9 A B C D E F 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; static const uint8_t rsbox[256] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; // The round constant word array, Rcon[i], contains the values given by // x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) // Note that i starts at 1, not 0). static const uint8_t Rcon[255] = { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb }; /*****************************************************************************/ /* Private functions: */ /*****************************************************************************/ static uint8_t getSBoxValue(uint8_t num) { return sbox[num]; } static uint8_t getSBoxInvert(uint8_t num) { return rsbox[num]; } // This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. static void KeyExpansion(const uint8_t* Key, uint8_t* roundKey) { uint32_t i, j, k; uint8_t tempa[4]; // Used for the column/row operations // The first round key is the key itself. for(i = 0; i < Nk; ++i) { roundKey[(i * 4) + 0] = Key[(i * 4) + 0]; roundKey[(i * 4) + 1] = Key[(i * 4) + 1]; roundKey[(i * 4) + 2] = Key[(i * 4) + 2]; roundKey[(i * 4) + 3] = Key[(i * 4) + 3]; } // All other round keys are found from the previous round keys. for(; (i < (Nb * (Nr + 1))); ++i) { for(j = 0; j < 4; ++j) { tempa[j]=roundKey[(i-1) * 4 + j]; } if (i % Nk == 0) { // This function rotates the 4 bytes in a word to the left once. // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] // Function RotWord() { k = tempa[0]; tempa[0] = tempa[1]; tempa[1] = tempa[2]; tempa[2] = tempa[3]; tempa[3] = k; } // SubWord() is a function that takes a four-byte input word and // applies the S-box to each of the four bytes to produce an output word. // Function Subword() { tempa[0] = getSBoxValue(tempa[0]); tempa[1] = getSBoxValue(tempa[1]); tempa[2] = getSBoxValue(tempa[2]); tempa[3] = getSBoxValue(tempa[3]); } tempa[0] = tempa[0] ^ Rcon[i/Nk]; } else if (Nk > 6 && i % Nk == 4) { // Function Subword() { tempa[0] = getSBoxValue(tempa[0]); tempa[1] = getSBoxValue(tempa[1]); tempa[2] = getSBoxValue(tempa[2]); tempa[3] = getSBoxValue(tempa[3]); } } roundKey[i * 4 + 0] = roundKey[(i - Nk) * 4 + 0] ^ tempa[0]; roundKey[i * 4 + 1] = roundKey[(i - Nk) * 4 + 1] ^ tempa[1]; roundKey[i * 4 + 2] = roundKey[(i - Nk) * 4 + 2] ^ tempa[2]; roundKey[i * 4 + 3] = roundKey[(i - Nk) * 4 + 3] ^ tempa[3]; } } // This function adds the round key to state. // The round key is added to the state by an XOR function. static void AddRoundKey(uint8_t* roundKey, state_t* state, uint8_t round) { uint8_t i,j; for(i=0;i<4;++i) { for(j = 0; j < 4; ++j) { (*state)[i][j] ^= roundKey[round * Nb * 4 + i * Nb + j]; } } } // The SubBytes Function Substitutes the values in the // state matrix with values in an S-box. static void SubBytes(state_t* state) { uint8_t i, j; for(i = 0; i < 4; ++i) { for(j = 0; j < 4; ++j) { (*state)[j][i] = getSBoxValue((*state)[j][i]); } } } // The ShiftRows() function shifts the rows in the state to the left. // Each row is shifted with different offset. // Offset = Row number. So the first row is not shifted. static void ShiftRows(state_t* state) { uint8_t temp; // Rotate first row 1 columns to left temp = (*state)[0][1]; (*state)[0][1] = (*state)[1][1]; (*state)[1][1] = (*state)[2][1]; (*state)[2][1] = (*state)[3][1]; (*state)[3][1] = temp; // Rotate second row 2 columns to left temp = (*state)[0][2]; (*state)[0][2] = (*state)[2][2]; (*state)[2][2] = temp; temp = (*state)[1][2]; (*state)[1][2] = (*state)[3][2]; (*state)[3][2] = temp; // Rotate third row 3 columns to left temp = (*state)[0][3]; (*state)[0][3] = (*state)[3][3]; (*state)[3][3] = (*state)[2][3]; (*state)[2][3] = (*state)[1][3]; (*state)[1][3] = temp; } static uint8_t xtime(uint8_t x) { return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); } // MixColumns function mixes the columns of the state matrix static void MixColumns(state_t* state) { uint8_t i; uint8_t Tmp,Tm,t; for(i = 0; i < 4; ++i) { t = (*state)[i][0]; Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; } } // Multiply is used to multiply numbers in the field GF(2^8) #if MULTIPLY_AS_A_FUNCTION static uint8_t Multiply(uint8_t x, uint8_t y) { return (((y & 1) * x) ^ ((y>>1 & 1) * xtime(x)) ^ ((y>>2 & 1) * xtime(xtime(x))) ^ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); } #else #define Multiply(x, y) \ ( ((y & 1) * x) ^ \ ((y>>1 & 1) * xtime(x)) ^ \ ((y>>2 & 1) * xtime(xtime(x))) ^ \ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ #endif // MixColumns function mixes the columns of the state matrix. // The method used to multiply may be difficult to understand for the inexperienced. // Please use the references to gain more information. static void InvMixColumns(state_t* state) { int i; uint8_t a,b,c,d; for(i=0;i<4;++i) { a = (*state)[i][0]; b = (*state)[i][1]; c = (*state)[i][2]; d = (*state)[i][3]; (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); } } // The SubBytes Function Substitutes the values in the // state matrix with values in an S-box. static void InvSubBytes(state_t* state) { uint8_t i,j; for(i=0;i<4;++i) { for(j=0;j<4;++j) { (*state)[j][i] = getSBoxInvert((*state)[j][i]); } } } static void InvShiftRows(state_t* state) { uint8_t temp; // Rotate first row 1 columns to right temp=(*state)[3][1]; (*state)[3][1]=(*state)[2][1]; (*state)[2][1]=(*state)[1][1]; (*state)[1][1]=(*state)[0][1]; (*state)[0][1]=temp; // Rotate second row 2 columns to right temp=(*state)[0][2]; (*state)[0][2]=(*state)[2][2]; (*state)[2][2]=temp; temp=(*state)[1][2]; (*state)[1][2]=(*state)[3][2]; (*state)[3][2]=temp; // Rotate third row 3 columns to right temp=(*state)[0][3]; (*state)[0][3]=(*state)[1][3]; (*state)[1][3]=(*state)[2][3]; (*state)[2][3]=(*state)[3][3]; (*state)[3][3]=temp; } // Cipher is the main function that encrypts the PlainText. static void Cipher(uint8_t* roundKey, state_t* state) { uint8_t round = 0; // Add the First round key to the state before starting the rounds. AddRoundKey(roundKey, state, 0); // There will be Nr rounds. // The first Nr-1 rounds are identical. // These Nr-1 rounds are executed in the loop below. for(round = 1; round < Nr; ++round) { SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(roundKey, state, round); } // The last round is given below. // The MixColumns function is not here in the last round. SubBytes(state); ShiftRows(state); AddRoundKey(roundKey, state, Nr); } static void InvCipher(uint8_t* roundKey, state_t* state) { uint8_t round=0; // Add the First round key to the state before starting the rounds. AddRoundKey(roundKey, state, Nr); // There will be Nr rounds. // The first Nr-1 rounds are identical. // These Nr-1 rounds are executed in the loop below. for(round=Nr-1;round>0;round--) { InvShiftRows(state); InvSubBytes(state); AddRoundKey(roundKey, state, round); InvMixColumns(state); } // The last round is given below. // The MixColumns function is not here in the last round. InvShiftRows(state); InvSubBytes(state); AddRoundKey(roundKey, state, 0); } static void BlockCopy(uint8_t* output, uint8_t* input) { uint8_t i; for (i=0;i #endif // #define the macros below to 1/0 to enable/disable the mode of operation. // // CBC enables AES128 encryption in CBC-mode of operation and handles 0-padding. // ECB enables the basic ECB 16-byte block algorithm. Both can be enabled simultaneously. // The #ifndef-guard allows it to be configured before #include'ing or at compile time. #ifndef CBC #define CBC 0 #endif #ifndef ECB #define ECB 1 #endif #if defined(ECB) && ECB void AES128_ECB_encrypt(uint8_t* input, const uint8_t* key, uint8_t *output); void AES128_ECB_decrypt(uint8_t* input, const uint8_t* key, uint8_t *output); #endif // #if defined(ECB) && ECB #if defined(CBC) && CBC void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, uint8_t* iv); void AES128_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, uint8_t* iv); #endif // #if defined(CBC) && CBC #endif //_AES_H_ libsmb2-6.2/lib/init.c0000664000175000017500000005143614732155517013705 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg Portions of this code are copyright 2017 to Primary Data Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include #include #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_SYS_ERRNO_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" #include "slist.h" #define MAX_URL_SIZE 1024 /* This is a list of all allocated contexts so servers can iterate over each * it should probably be moved to the server context and a callback registered * here to tell the server when a context is destroyed, but this works */ static struct smb2_context *active_contexts; static int smb2_parse_args(struct smb2_context *smb2, const char *args) { while (args && *args != 0) { char *next, *value; next = strchr(args, '&'); if (next) { *(next++) = '\0'; } value = strchr(args, '='); if (value) { *(value++) = '\0'; } if (!strcmp(args, "seal")) { smb2->seal = 1; } else if (!strcmp(args, "sign")) { smb2->sign = 1; } else if (!strcmp(args, "ndr3264")) { smb2->ndr = 0; } else if (!strcmp(args, "ndr32")) { smb2->ndr = 1; } else if (!strcmp(args, "ndr64")) { smb2->ndr = 2; } else if (!strcmp(args, "le")) { smb2->endianness = 0; } else if (!strcmp(args, "be")) { smb2->endianness = 1; } else if (!strcmp(args, "sec")) { if(!strcmp(value, "krb5")) { smb2->sec = SMB2_SEC_KRB5; } else if(!strcmp(value, "krb5cc")) { smb2->sec = SMB2_SEC_KRB5; smb2->use_cached_creds = 1; } else if (!strcmp(value, "ntlmssp")) { smb2->sec = SMB2_SEC_NTLMSSP; } else { smb2_set_error(smb2, "Unknown sec= argument: " "%s", value); return -1; } } else if (!strcmp(args, "vers")) { if(!strcmp(value, "2")) { smb2->version = SMB2_VERSION_ANY2; } else if(!strcmp(value, "3")) { smb2->version = SMB2_VERSION_ANY3; } else if(!strcmp(value, "2.02")) { smb2->version = SMB2_VERSION_0202; } else if(!strcmp(value, "2.10")) { smb2->version = SMB2_VERSION_0210; } else if(!strcmp(value, "3.0") || !strcmp(value, "3.00")) { smb2->version = SMB2_VERSION_0300; } else if(!strcmp(value, "3.02")) { smb2->version = SMB2_VERSION_0302; } else if(!strcmp(value, "3.1.1")) { smb2->version = SMB2_VERSION_0311; } else { smb2_set_error(smb2, "Unknown vers= argument: " "%s", value); return -1; } } else if (!strcmp(args, "timeout")) { smb2->timeout = (int)strtol(value, NULL, 10); } else { smb2_set_error(smb2, "Unknown argument: %s", args); return -1; } args = next; } if (smb2->seal) { switch (smb2->version) { case SMB2_VERSION_ANY: smb2->version = SMB2_VERSION_ANY3; break; case SMB2_VERSION_ANY3: case SMB2_VERSION_0300: case SMB2_VERSION_0302: case SMB2_VERSION_0311: break; default: smb2_set_error(smb2, "Can only use seal with SMB3"); return -1; } } return 0; } struct smb2_url *smb2_parse_url(struct smb2_context *smb2, const char *url) { struct smb2_url *u; char *ptr, *tmp, str[MAX_URL_SIZE]; char *args; char *shared_folder; size_t len_shared_folder; if (strncmp(url, "smb://", 6)) { smb2_set_error(smb2, "URL does not start with 'smb://'"); return NULL; } if (strlen(url + 6) >= MAX_URL_SIZE) { smb2_set_error(smb2, "URL is too long"); return NULL; } strncpy(str, url + 6, MAX_URL_SIZE); args = strchr(str, '?'); if (args) { *(args++) = '\0'; if (smb2_parse_args(smb2, args) != 0) { return NULL; } } u = calloc(1, sizeof(struct smb2_url)); if (u == NULL) { smb2_set_error(smb2, "Failed to allocate smb2_url"); return NULL; } ptr = str; shared_folder = strchr(ptr, '/'); if (!shared_folder) { smb2_set_error(smb2, "Wrong URL format"); return NULL; } len_shared_folder = strlen(shared_folder); /* domain */ if ((tmp = strchr(ptr, ';')) != NULL && strlen(tmp) > len_shared_folder) { *(tmp++) = '\0'; u->domain = strdup(ptr); ptr = tmp; } /* user */ if ((tmp = strchr(ptr, '@')) != NULL && strlen(tmp) > len_shared_folder) { *(tmp++) = '\0'; u->user = strdup(ptr); ptr = tmp; } /* server */ if ((tmp = strchr(ptr, '/')) != NULL) { *(tmp++) = '\0'; u->server = strdup(ptr); ptr = tmp; } /* Do we just have a share or do we have both a share and an object */ tmp = strchr(ptr, '/'); /* We only have a share */ if (tmp == NULL) { u->share = strdup(ptr); return u; } /* we have both share and object path */ *(tmp++) = '\0'; u->share = strdup(ptr); u->path = strdup(tmp); return u; } void smb2_destroy_url(struct smb2_url *url) { if (url == NULL) { return; } free(discard_const(url->domain)); free(discard_const(url->user)); free(discard_const(url->server)); free(discard_const(url->share)); free(discard_const(url->path)); free(url); } struct smb2_context *smb2_init_context(void) { struct smb2_context *smb2; char buf[1024] _U_; int i, ret; static int ctr; srandom((unsigned)time(NULL) ^ getpid() ^ ctr++); smb2 = calloc(1, sizeof(struct smb2_context)); if (smb2 == NULL) { return NULL; } ret = getlogin_r(buf, sizeof(buf)); smb2_set_user(smb2, ret == 0 ? buf : "Guest"); smb2->fd = SMB2_INVALID_SOCKET; smb2->connecting_fds = NULL; smb2->connecting_fds_count = 0; smb2->addrinfos = NULL; smb2->next_addrinfo = NULL; smb2->sec = SMB2_SEC_UNDEFINED; smb2->version = SMB2_VERSION_ANY; smb2->ndr = 1; for (i = 0; i < 8; i++) { smb2->client_challenge[i] = random() & 0xff; } for (i = 0; i < SMB2_SALT_SIZE; i++) { smb2->salt[i] = random() & 0xff; } snprintf(smb2->client_guid, 16, "libsmb2-%d", (int)random()); smb2->session_key = NULL; SMB2_LIST_ADD(&active_contexts, smb2); return smb2; } void smb2_destroy_context(struct smb2_context *smb2) { if (smb2 == NULL) { return; } if (SMB2_VALID_SOCKET(smb2->fd)) { if (smb2->change_fd) { smb2->change_fd(smb2, smb2->fd, SMB2_DEL_FD); } close(smb2->fd); smb2->fd = SMB2_INVALID_SOCKET; } else { smb2_close_connecting_fds(smb2); } while (smb2->outqueue) { struct smb2_pdu *pdu = smb2->outqueue; smb2->outqueue = pdu->next; if (pdu->cb) { pdu->cb(smb2, SMB2_STATUS_SHUTDOWN, NULL, pdu->cb_data); } smb2_free_pdu(smb2, pdu); } if (smb2->pdu) { struct smb2_pdu *pdu = smb2->pdu; if (pdu->cb) { pdu->cb(smb2, SMB2_STATUS_SHUTDOWN, NULL, pdu->cb_data); } smb2_free_pdu(smb2, smb2->pdu); } while (smb2->waitqueue) { struct smb2_pdu *pdu = smb2->waitqueue; smb2->waitqueue = pdu->next; if (pdu->cb) { pdu->cb(smb2, SMB2_STATUS_SHUTDOWN, NULL, pdu->cb_data); } if (pdu == smb2->pdu) { smb2->pdu = NULL; } smb2_free_pdu(smb2, pdu); } smb2_free_iovector(smb2, &smb2->in); if (smb2->fhs) { smb2_free_all_fhs(smb2); } if (smb2->dirs) { smb2_free_all_dirs(smb2); } if (smb2->connect_cb) { smb2->connect_cb(smb2, SMB2_STATUS_CANCELLED, NULL, smb2->connect_data); smb2->connect_cb = NULL; } free(smb2->session_key); smb2->session_key = NULL; free(discard_const(smb2->user)); free(discard_const(smb2->server)); free(discard_const(smb2->share)); free(discard_const(smb2->password)); free(discard_const(smb2->domain)); 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 */ } SMB2_LIST_REMOVE(&active_contexts, smb2); free(smb2); } struct smb2_context *smb2_active_contexts(void) { return active_contexts; } int smb2_context_active(struct smb2_context *smb2) { struct smb2_context *context = active_contexts; while (context) { if (smb2 == context) { return 1; } context = context->next; } return 0; } void smb2_free_iovector(struct smb2_context *smb2, struct smb2_io_vectors *v) { int i; for (i = 0; i < v->niov; i++) { if (v->iov[i].free) { v->iov[i].free(v->iov[i].buf); } } v->niov = 0; v->total_size = 0; v->num_done = 0; } struct smb2_iovec *smb2_add_iovector(struct smb2_context *smb2, struct smb2_io_vectors *v, uint8_t *buf, size_t len, void (*free)(void *)) { struct smb2_iovec *iov = &v->iov[v->niov]; v->iov[v->niov].buf = buf; v->iov[v->niov].len = len; v->iov[v->niov].free = free; v->total_size += len; v->niov++; return iov; } #ifndef _IOP static void smb2_set_error_string(struct smb2_context *smb2, const char * error_string, va_list args) { char errstr[MAX_ERROR_SIZE] = {0}; #ifdef _XBOX if (_vsnprintf(errstr, MAX_ERROR_SIZE, error_string, args) < 0) { #else if (vsnprintf(errstr, MAX_ERROR_SIZE, error_string, args) < 0) { #endif strncpy(errstr, "could not format error string!", MAX_ERROR_SIZE); } strncpy(smb2->error_string, errstr, MAX_ERROR_SIZE); } #endif /* _IOP */ void smb2_set_error(struct smb2_context *smb2, const char *error_string, ...) { #ifndef _IOP va_list ap; if (!smb2) return; if (!error_string || !*error_string) smb2->nterror = 0; va_start(ap, error_string); smb2_set_error_string(smb2, error_string, ap); va_end(ap); if(smb2->error_cb) { smb2->error_cb(smb2, smb2_get_error(smb2)); } #endif } void smb2_register_error_callback(struct smb2_context *smb2, smb2_error_cb error_cb) { smb2->error_cb = error_cb; } void smb2_set_nterror(struct smb2_context *smb2, int nterror, const char *error_string, ...) { if (!smb2) return; #ifndef _IOP { va_list ap; va_start(ap, error_string); smb2_set_error_string(smb2, error_string, ap); va_end(ap); } #endif smb2->nterror = nterror; } const char *smb2_get_error(struct smb2_context *smb2) { return smb2 ? smb2->error_string : ""; } int smb2_get_nterror(struct smb2_context *smb2) { return smb2 ? smb2->nterror : 0; } void smb2_set_client_guid(struct smb2_context *smb2, const uint8_t guid[SMB2_GUID_SIZE]) { memcpy(smb2->client_guid, guid, SMB2_GUID_SIZE); } const char *smb2_get_client_guid(struct smb2_context *smb2) { return smb2->client_guid; } uint16_t smb2_get_dialect(struct smb2_context *smb2) { return smb2->dialect; } void smb2_set_security_mode(struct smb2_context *smb2, uint16_t security_mode) { smb2->security_mode = security_mode; } #if !defined(_XBOX) && !defined(_IOP) && !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) void smb2_set_password_from_file(struct smb2_context *smb2) { char *name = NULL; FILE *fh; char buf[256]; char *domain, *user, *password; int finished; #ifdef _MSC_UWP /* GetEnvironmentVariable is not available for UWP up to 10.0.16299 SDK */ #if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3) uint32_t name_len = GetEnvironmentVariableA("NTLM_USER_FILE", NULL, 0); if (name_len > 0) { name = (char*)malloc(name_len + 1); if (name == NULL) { return; } GetEnvironmentVariableA("NTLM_USER_FILE", name, name_len); } #endif #else name = getenv("NTLM_USER_FILE"); #endif if (name == NULL || smb2->user == NULL) { #ifdef _MSC_UWP free(name); #endif return; } fh = fopen(name, "r"); #ifdef _MSC_UWP free(name); #endif if (!fh) { return; } smb2_set_password(smb2, NULL); while (!feof(fh)) { if (fgets(buf, 256, fh) == NULL) { break; } buf[255] = 0; finished = 0; while (!finished) { switch (buf[strlen(buf) - 1]) { case '\n': buf[strlen(buf) - 1] = 0; default: finished = 1; } if (strlen(buf) == 0) { break; } } if (buf[0] == 0) { break; } domain = buf; user = strchr(domain, ':'); if (user == NULL) { continue; } *user++ = 0; password = strchr(user, ':'); if (password == NULL) { continue; } *password++ = 0; if (strcmp(user, smb2->user)) { continue; } smb2_set_password(smb2, password); } fclose(fh); } #endif /* !_IOP */ void smb2_set_user(struct smb2_context *smb2, const char *user) { if (smb2->user) { free(discard_const(smb2->user)); smb2->user = NULL; } if (user == NULL) { return; } smb2->user = strdup(user); #if !defined(_XBOX) && !defined(_IOP) && !defined(__amigaos4__) && !defined(__AMIGA__) && !defined(__AROS__) smb2_set_password_from_file(smb2); #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) { free(discard_const(smb2->password)); smb2->password = NULL; } if (password == NULL) { return; } smb2->password = strdup(password); } void smb2_set_domain(struct smb2_context *smb2, const char *domain) { if (smb2->domain) { free(discard_const(smb2->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) { free(discard_const(smb2->workstation)); } smb2->workstation = strdup(workstation); } void smb2_set_opaque(struct smb2_context *smb2, void *opaque) { smb2->opaque = opaque; } void *smb2_get_opaque(struct smb2_context *smb2) { return smb2->opaque; } void smb2_set_seal(struct smb2_context *smb2, int val) { smb2->seal = val; } void smb2_set_sign(struct smb2_context *smb2, int val) { smb2->sign = val; } void smb2_set_authentication(struct smb2_context *smb2, int val) { smb2->sec = (enum smb2_sec)val; } void smb2_set_timeout(struct smb2_context *smb2, int seconds) { smb2->timeout = seconds; } void smb2_set_version(struct smb2_context *smb2, enum smb2_negotiate_version version) { smb2->version = version; } void smb2_get_libsmb2Version(struct smb2_libversion *smb2_ver) { smb2_ver->major_version = LIBSMB2_MAJOR_VERSION; smb2_ver->minor_version = LIBSMB2_MINOR_VERSION; smb2_ver->patch_version = LIBSMB2_MAJOR_VERSION; } void smb2_set_passthrough(struct smb2_context *smb2, int passthrough) { smb2->passthrough = passthrough; } void smb2_get_passthrough(struct smb2_context *smb2, int *passthrough) { *passthrough = smb2->passthrough; } void smb2_set_oplock_or_lease_break_callback(struct smb2_context *smb2, smb2_oplock_or_lease_break_cb cb) { 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 libsmb2-6.2/lib/smb2-cmd-lock.c0000664000175000017500000002143114732155517015264 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Brian Dodge This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_lock_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_lock_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; struct smb2_lock_element *elements; uint32_t u32; int i; uint32_t offset; len = SMB2_LOCK_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate lock buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_LOCK_REQUEST_SIZE); smb2_set_uint16(iov, 2, req->lock_count); u32 = (req->lock_sequence_number << 28) | req->lock_sequence_index; smb2_set_uint32(iov, 4, u32); memcpy(iov->buf + 8, req->file_id, SMB2_FD_SIZE); elements = req->locks; if (req->lock_count && req->locks) { smb2_set_uint64(iov, 24, elements->offset); smb2_set_uint64(iov, 24 + 8, elements->length); smb2_set_uint32(iov, 24 + 16, elements->flags); elements++; } if ((req->lock_count > 1) && req->locks) { len = PAD_TO_64BIT(SMB2_LOCK_ELEMENT_SIZE * req->lock_count); buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate locks buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); for (i = 0, offset = 0; i < req->lock_count; i++) { smb2_set_uint64(iov, offset, elements->offset); smb2_set_uint64(iov, offset + 8, elements->length); smb2_set_uint32(iov, offset + 16, elements->flags); offset += SMB2_LOCK_ELEMENT_SIZE; elements++; } } return 0; } struct smb2_pdu * smb2_cmd_lock_async(struct smb2_context *smb2, struct smb2_lock_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_LOCK, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_lock_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_lock_reply(struct smb2_context *smb2, struct smb2_pdu *pdu) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_LOCK_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate lock buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_LOCK_REPLY_SIZE); return 0; } struct smb2_pdu * smb2_cmd_lock_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_LOCK, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_lock_reply(smb2, pdu)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_lock_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_LOCK_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of lock " "reply. Expected %d, got %d", SMB2_LOCK_REPLY_SIZE, (int)iov->len); return -1; } return 0; } static int smb2_parse_locks(struct smb2_context *smb2, struct smb2_iovec *iov, uint32_t offset, int count, void *locks) { struct smb2_lock_element *elements; if (!iov || !locks) { return -1; } elements = (struct smb2_lock_element *)locks; while (count-- > 0) { smb2_get_uint64(iov, offset + 0, &elements->offset); smb2_get_uint64(iov, offset + 8, &elements->length); smb2_get_uint32(iov, offset + 16, &elements->flags); offset += SMB2_LOCK_ELEMENT_SIZE; elements++; } return 0; } int smb2_process_lock_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_lock_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; void *ptr; uint32_t u32; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_LOCK_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of lock " "request. Expected %d, got %d", SMB2_LOCK_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate lock request"); return -1; } pdu->payload = req; smb2_get_uint16(iov, 2, &req->lock_count); smb2_get_uint32(iov, 4, &u32); req->lock_sequence_number = u32 >> 28; req->lock_sequence_index = u32 & 0x0FFFFFFF; memcpy(req->file_id, iov->buf + 8, SMB2_FD_SIZE); if (req->lock_count < 1) { smb2_set_error(smb2, "Lock request must have at least one lock."); pdu->payload = NULL; free(req); return -1; } ptr = smb2_alloc_init(smb2, req->lock_count * SMB2_LOCK_ELEMENT_SIZE); if (!ptr) { smb2_set_error(smb2, "can not alloc lock buffer."); pdu->payload = NULL; free(req); return -1; } req->locks = ptr; /* the fixed size includes 1 lock (the most common use) so * there is no more data in that case */ if (req->lock_count > 0) { struct smb2_iovec vec; vec.buf = iov->buf + 24; vec.len = iov->len - 24; smb2_parse_locks(smb2, &vec, 0, 1, ptr); } return SMB2_LOCK_ELEMENT_SIZE * (req->lock_count - 1); } int smb2_process_lock_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_lock_request *req = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; /* parse remaining locks, there is already one parsed */ return smb2_parse_locks(smb2, iov, 0, req->lock_count - 1, (uint8_t*)(req->locks + 1)); } libsmb2-6.2/lib/dcerpc.c0000664000175000017500000016504114732155517014200 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include "portable-endian.h" #include #include "compat.h" #include #include "smb2.h" #include "libsmb2.h" #include "libsmb2-dcerpc.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) struct dcerpc_deferred_pointer { dcerpc_coder coder; void *ptr; }; #define MAX_DEFERRED_PTR 1024 #define NDR32_UUID 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60} #define NDR64_UUID 0x71710533, 0xbeba, 0x4937, {0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36} /* * NDR64 is only supported for LITTLE_ENDIAN encodings: * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/b1af93c7-f988-4a1a-ac74-063179942f32 */ p_syntax_id_t ndr32_syntax = { {NDR32_UUID}, 2, 0 }; p_syntax_id_t ndr64_syntax = { {NDR64_UUID}, 1, 0 }; struct dcerpc_context { struct smb2_context *smb2; const char *path; p_syntax_id_t *syntax; smb2_file_id file_id; uint8_t tctx_id; /* 0:NDR32 1:NDR64 */ uint8_t packed_drep[4]; uint32_t call_id; }; struct dcerpc_header { uint8_t rpc_vers; uint8_t rpc_vers_minor; uint8_t PTYPE; uint8_t pfc_flags; uint8_t packed_drep[4]; uint16_t frag_length; uint16_t auth_length; uint32_t call_id; }; struct p_cont_elem_t { uint16_t p_cont_id; uint8_t n_transfer_syn; /* number of items */ uint8_t reserved; /* alignment pad, m.b.z. */ p_syntax_id_t *abstract_syntax; /* transfer syntax list */ p_syntax_id_t **transfer_syntaxes; }; struct dcerpc_bind_pdu { uint16_t max_xmit_frag; uint16_t max_recv_frag; uint32_t assoc_group_id; /* presentation context list */ uint8_t n_context_elem; /* number of items */ //u_int8 reserved; /* alignment pad, m.b.z. */ //u_short reserved2; /* alignment pad, m.b.z. */ struct p_cont_elem_t *p_cont_elem; //p_cont_elem_t [size_is(n_cont_elem)] p_cont_elem[]; //p_syntax_id_t *abstract_syntax; }; #define ACK_RESULT_ACCEPTANCE 0 #define ACK_RESULT_USER_REJECTION 1 #define ACK_RESULT_PROVIDER_REJECTION 2 #define ACK_REASON_REASON_NOT_SPECIFIED 0 #define ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED 1 #define ACK_REASON_PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED 2 #define ACK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED 4 struct dcerpc_bind_context_results { uint16_t ack_result; uint16_t ack_reason; dcerpc_uuid_t uuid; uint32_t syntax_version; }; #define MAX_ACK_RESULTS 4 struct dcerpc_bind_ack_pdu { uint16_t max_xmit_frag; uint16_t max_recv_frag; uint32_t assoc_group_id; /* presentation context list */ uint8_t num_results; struct dcerpc_bind_context_results results[MAX_ACK_RESULTS]; }; struct dcerpc_request_pdu { uint32_t alloc_hint; uint16_t context_id; uint16_t opnum; /* optional field for request, only present if the PFC_OBJECT_UUID * field is non-zero */ /* dcerpc_uuid_t object; 24:16 object UID */ /* stub data, 8-octet aligned . . . */ }; struct dcerpc_response_pdu { uint32_t alloc_hint; uint16_t context_id; uint8_t cancel_count; uint8_t reserved; /* stub data, 8-octet aligned . . . */ }; /* PDU Types */ #define PDU_TYPE_REQUEST 0 #define PDU_TYPE_PING 1 #define PDU_TYPE_RESPONSE 2 #define PDU_TYPE_FAULT 3 #define PDU_TYPE_WORKING 4 #define PDU_TYPE_NOCALL 5 #define PDU_TYPE_REJECT 6 #define PDU_TYPE_ACK 7 #define PDU_TYPE_CL_CANCEL 8 #define PDU_TYPE_FACK 9 #define PDU_TYPE_CANCEL_ACK 10 #define PDU_TYPE_BIND 11 #define PDU_TYPE_BIND_ACK 12 #define PDU_TYPE_BIND_NAK 13 #define PDU_TYPE_ALTER_CONTEXT 14 #define PDU_TYPE_ALTER_CONTEXT_RESP 15 #define PDU_TYPE_SHUTDOWN 17 #define PDU_TYPE_CO_CANCEL 18 #define PDU_TYPE_ORPHANED 19 /* Flags */ #define PFC_FIRST_FRAG 0x01 #define PFC_LAST_FRAG 0x02 #define PFC_PENDING_CANCEL 0x04 #define PFC_RESERVED_1 0x08 #define PFC_CONC_MPX 0x10 #define PFC_DID_NOT_EXECUTE 0x20 #define PFC_MAYBE 0x40 #define PFC_OBJECT_UUID 0x80 #define NSE_BUF_SIZE 128*1024 struct dcerpc_cb_data { struct dcerpc_context *dce; dcerpc_cb cb; void *cb_data; }; struct dcerpc_pdu { struct dcerpc_header hdr; union { struct dcerpc_bind_pdu bind; struct dcerpc_bind_ack_pdu bind_ack; struct dcerpc_request_pdu req; struct dcerpc_response_pdu rsp; }; /* optional authentication verifier */ /* following fields present iff auth_length != 0 */ #if 0 auth_verifier_co_t auth_verifier; #endif struct dcerpc_context *dce; dcerpc_cb cb; void *cb_data; dcerpc_coder coder; int decode_size; void *payload; int top_level; uint64_t ptr_id; int cur_ptr; int max_ptr; struct dcerpc_deferred_pointer ptrs[MAX_DEFERRED_PTR]; int direction; /* All items are parsed twice, first to handle the conformance * fields and a second time to handle the data itself. * During the first run we also check what the maximum alignment * of the fields are. */ int is_conformance_run; int max_alignment; }; int dcerpc_set_uint8(struct dcerpc_context *ctx, struct smb2_iovec *iov, int *offset, uint8_t value) { if (*offset + sizeof(uint8_t) > iov->len) { return -1; } *(uint8_t *)(iov->buf + *offset) = value; *offset += 1; return 0; } static int dcerpc_set_uint16(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, uint16_t value) { *offset = (*offset + 1) & ~1; if (*offset + sizeof(uint16_t) > iov->len) { return -1; } if (!(pdu->hdr.packed_drep[0] & DCERPC_DR_LITTLE_ENDIAN)) { *(uint16_t *)(iov->buf + *offset) = htobe16(value); } else { *(uint16_t *)(iov->buf + *offset) = htole16(value); } *offset += 2; return 0; } static int dcerpc_set_uint32(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, uint32_t value) { *offset = (*offset + 3) & ~3; if (*offset + sizeof(uint32_t) > iov->len) { return -1; } if (!(pdu->hdr.packed_drep[0] & DCERPC_DR_LITTLE_ENDIAN)) { *(uint32_t *)(iov->buf + *offset) = htobe32(value); } else { *(uint32_t *)(iov->buf + *offset) = htole32(value); } *offset += 4; return 0; } static int dcerpc_set_uint64(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, uint64_t value) { *offset = (*offset + 7) & ~7; if (*offset + sizeof(uint64_t) > iov->len) { return -1; } if (!(pdu->hdr.packed_drep[0] & DCERPC_DR_LITTLE_ENDIAN)) { *(uint64_t *)(iov->buf + *offset) = htobe64(value); } else { *(uint64_t *)(iov->buf + *offset) = htole64(value); } *offset += 8; return 0; } static int dcerpc_get_uint8(struct dcerpc_context *ctx, struct smb2_iovec *iov, int *offset, uint8_t *value) { if (*offset + sizeof(uint8_t) > iov->len) { return -1; } *value = iov->buf[*offset]; *offset += 1; return 0; } static int dcerpc_get_uint16(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, uint16_t *value) { uint16_t val; *offset = (*offset + 1) & ~1; if (*offset + sizeof(uint16_t) > iov->len) { return -1; } if (!(pdu->hdr.packed_drep[0] & DCERPC_DR_LITTLE_ENDIAN)) { val = be16toh(*(uint16_t *)(iov->buf + *offset)); } else { val = le16toh(*(uint16_t *)(iov->buf + *offset)); } *value = val; *offset += 2; return 0; } static int dcerpc_get_uint32(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, uint32_t *value) { uint32_t val; *offset = (*offset + 3) & ~3; if (*offset + sizeof(uint32_t) > iov->len) { return -1; } if (!(pdu->hdr.packed_drep[0] & DCERPC_DR_LITTLE_ENDIAN)) { val = be32toh(*(uint32_t *)(iov->buf + *offset)); } else { val = le32toh(*(uint32_t *)(iov->buf + *offset)); } *value = val; *offset += 4; return 0; } static int dcerpc_get_uint64(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, uint64_t *value) { uint64_t val; *offset = (*offset + 7) & ~7; if (*offset + sizeof(uint64_t) > iov->len) { return -1; } if (!(pdu->hdr.packed_drep[0] & DCERPC_DR_LITTLE_ENDIAN)) { val = be64toh(*(uint64_t *)(iov->buf + *offset)); } else { val = le64toh(*(uint64_t *)(iov->buf + *offset)); } *value = val; *offset += 8; return 0; } int dcerpc_uint64_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { if (pdu->is_conformance_run) { if (pdu->max_alignment < 8) { pdu->max_alignment = 8; } return 0; } if (pdu->direction == DCERPC_DECODE) { return dcerpc_get_uint64(ctx, pdu, iov, offset, ptr); } else { return dcerpc_set_uint64(ctx, pdu, iov, offset, *(uint32_t *)ptr); } } struct smb2_context * dcerpc_get_smb2_context(struct dcerpc_context *dce) { return dce->smb2; } void * dcerpc_get_pdu_payload(struct dcerpc_pdu *pdu) { return pdu->payload; } struct dcerpc_context * dcerpc_create_context(struct smb2_context *smb2) { struct dcerpc_context *ctx; ctx = calloc(1, sizeof(struct dcerpc_context)); if (ctx == NULL) { smb2_set_error(smb2, "Failed to allocate dcercp context."); return NULL; } ctx->smb2 = smb2; ctx->packed_drep[0] |= DCERPC_DR_LITTLE_ENDIAN; return ctx; } int dcerpc_connect_context_async(struct dcerpc_context *dce, const char *path, p_syntax_id_t *syntax, dcerpc_cb cb, void *cb_data) { dce->call_id = 2; dce->path = strdup(path); if (dce->path == NULL) { smb2_set_error(dce->smb2, "Failed to allocate path for " "dcercp context."); return -ENOMEM; } dce->syntax = syntax; dce->packed_drep[0] = DCERPC_DR_ASCII; if (!dce->smb2->endianness) { dce->packed_drep[0] |= DCERPC_DR_LITTLE_ENDIAN; } if (dcerpc_open_async(dce, cb, cb_data) != 0) { return -1; } return 0; } void dcerpc_destroy_context(struct dcerpc_context *dce) { if (dce == NULL) { return; } free(discard_const(dce->path)); free(dce); } void dcerpc_free_pdu(struct dcerpc_context *dce, struct dcerpc_pdu *pdu) { if (pdu == NULL) { return; } if (pdu->payload) { smb2_free_data(dce->smb2, pdu->payload); } free(pdu); } struct dcerpc_pdu * dcerpc_allocate_pdu(struct dcerpc_context *dce, int direction, int payload_size) { struct dcerpc_pdu *pdu; pdu = calloc(1, sizeof(struct dcerpc_pdu)); if (pdu == NULL) { smb2_set_error(dce->smb2, "Failed to allocate DCERPC PDU"); return NULL; } pdu->dce = dce; pdu->hdr.call_id = dce->call_id++; pdu->direction = direction; pdu->top_level = 1; pdu->payload = smb2_alloc_init(dce->smb2, payload_size); if (pdu->payload == NULL) { smb2_set_error(dce->smb2, "Failed to allocate PDU Payload"); dcerpc_free_pdu(dce, pdu); return NULL; } return pdu; } static void dcerpc_add_deferred_pointer(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, dcerpc_coder coder, void *ptr) { pdu->ptrs[pdu->max_ptr].coder = coder; pdu->ptrs[pdu->max_ptr].ptr = ptr; pdu->max_ptr++; } int dcerpc_do_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, dcerpc_coder coder) { pdu->max_alignment = 1; pdu->is_conformance_run = 1; if (coder(ctx, pdu, iov, offset, ptr)) { return -1; } *offset = (*offset + (pdu->max_alignment - 1)) & ~(pdu->max_alignment - 1); pdu->is_conformance_run = 0; if (coder(ctx, pdu, iov, offset, ptr)) { return -1; } return 0; } static int dcerpc_process_deferred_pointers(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset) { struct dcerpc_deferred_pointer *dp; int idx; while (pdu->cur_ptr != pdu->max_ptr) { idx = pdu->cur_ptr++; dp = &pdu->ptrs[idx]; if (dcerpc_do_coder(ctx, pdu, iov, offset, dp->ptr, dp->coder)) { return -1; } } return 0; } int dcerpc_uint32_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { if (pdu->is_conformance_run) { if (pdu->max_alignment < 4) { pdu->max_alignment = 4; } return 0; } if (pdu->direction == DCERPC_DECODE) { return dcerpc_get_uint32(ctx, pdu, iov, offset, ptr); } else { return dcerpc_set_uint32(ctx, pdu, iov, offset, *(uint32_t *)ptr); } } int dcerpc_uint16_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { if (pdu->is_conformance_run) { if (pdu->max_alignment < 2) { pdu->max_alignment = 2; } return 0; } if (pdu->direction == DCERPC_DECODE) { return dcerpc_get_uint16(ctx, pdu, iov, offset, ptr); } else { return dcerpc_set_uint16(ctx, pdu, iov, offset, *(uint16_t *)ptr); } } int dcerpc_uint8_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { if (pdu->is_conformance_run) { if (pdu->max_alignment < 1) { pdu->max_alignment = 1; } return 0; } if (pdu->direction == DCERPC_DECODE) { return dcerpc_get_uint8(ctx, iov, offset, ptr); } else { return dcerpc_set_uint8(ctx, iov, offset, *(uint8_t *)ptr); } return 0; } /* Encode words that vary in size depending on the transport syntax */ int dcerpc_uint3264_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { uint32_t u32 = 0; uint64_t val = *(uint64_t *)ptr; if (pdu->is_conformance_run) { if (ctx->tctx_id) { if (pdu->max_alignment < 8) { pdu->max_alignment = 8; } } else { if (pdu->max_alignment < 4) { pdu->max_alignment = 4; } } return 0; } if (pdu->direction == DCERPC_DECODE) { if (ctx->tctx_id) { if (dcerpc_get_uint64(ctx, pdu, iov, offset, ptr)) { return -1; } } else { if (dcerpc_get_uint32(ctx, pdu, iov, offset, &u32)) { return -1; } *(uint64_t *)ptr = u32; } } else { if (ctx->tctx_id) { if (dcerpc_set_uint64(ctx, pdu, iov, offset, val)) { return -1; } } else { if (dcerpc_set_uint32(ctx, pdu, iov, offset, (uint32_t)val)) { return -1; } } } return 0; } int dcerpc_conformance_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { uint32_t u32 = 0; uint64_t val = *(uint64_t *)ptr; if (!pdu->is_conformance_run) { return 0; } if (pdu->direction == DCERPC_DECODE) { if (ctx->tctx_id) { if (dcerpc_get_uint64(ctx, pdu, iov, offset, ptr)) { return -1; } } else { if (dcerpc_get_uint32(ctx, pdu, iov, offset, &u32)) { return -1; } *(uint64_t *)ptr = u32; } } else { if (ctx->tctx_id) { if (dcerpc_set_uint64(ctx, pdu, iov, offset, val)) { return -1; } } else { if (dcerpc_set_uint32(ctx, pdu, iov, offset, val)) { return -1; } } } return 0; } #define RPTR 0x5270747272747052 #define UPTR 0x5570747272747055 static int dcerpc_encode_ptr(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, enum ptr_type type, dcerpc_coder coder) { int top_level = pdu->top_level; uint64_t val; if (pdu->is_conformance_run) { if (dce->tctx_id) { if (pdu->max_alignment < 8) { pdu->max_alignment = 8; } } else { if (pdu->max_alignment < 4) { pdu->max_alignment = 4; } } return 0; } switch (type) { case PTR_REF: if (pdu->top_level) { pdu->top_level = 0; if (dcerpc_do_coder(dce, pdu, iov, offset, ptr, coder)) { return -1; } pdu->top_level = top_level; goto out; } val = RPTR; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } dcerpc_add_deferred_pointer(dce, pdu, (dcerpc_coder)coder, ptr); break; case PTR_FULL: if (ptr == NULL) { val = 0; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } goto out; } pdu->ptr_id++; val = pdu->ptr_id; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } if (pdu->top_level) { pdu->top_level = 0; if (dcerpc_do_coder(dce, pdu, iov, offset, ptr, coder)) { return -1; } pdu->top_level = top_level; } else { dcerpc_add_deferred_pointer(dce, pdu, (dcerpc_coder)coder, ptr); } break; case PTR_UNIQUE: if (ptr == NULL) { val = 0; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } goto out; } val = UPTR; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } if (pdu->top_level) { pdu->top_level = 0; if (dcerpc_do_coder(dce, pdu, iov, offset, ptr, coder)) { return -1; } pdu->top_level = top_level; } else { dcerpc_add_deferred_pointer(dce, pdu, (dcerpc_coder)coder, ptr); } break; } out: if (pdu->top_level) { pdu->top_level = 0; if (dcerpc_process_deferred_pointers(dce, pdu, iov, offset)) { return -1; } pdu->top_level = top_level; } return 0; } /* TODO conformance split * during the conformance run we need to do the alignment in all the coders, even for the coders that do not have any conformance data. */ static int dcerpc_decode_ptr(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, enum ptr_type type, dcerpc_coder coder) { int top_level = pdu->top_level; uint64_t p; if (pdu->is_conformance_run) { if (!(type==PTR_REF && pdu->top_level)) { if (dce->tctx_id) { if (pdu->max_alignment < 8) { pdu->max_alignment = 8; } } else { if (pdu->max_alignment < 4) { pdu->max_alignment = 4; } } } return 0; } switch (type) { case PTR_REF: if (pdu->top_level) { pdu->top_level = 0; if (dcerpc_do_coder(dce, pdu, iov, offset, ptr, coder)) { return -1; } pdu->top_level = top_level; goto out; } if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &p)) { return -1; } dcerpc_add_deferred_pointer(dce, pdu, (dcerpc_coder)coder, ptr); break; case PTR_UNIQUE: if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &p)) { return -1; } if (p == 0 || ptr == NULL) { return 0; } if (pdu->top_level) { pdu->top_level = 0; if (dcerpc_do_coder(dce, pdu, iov, offset, ptr, coder)) { return -1; } pdu->top_level = top_level; } else { dcerpc_add_deferred_pointer(dce, pdu, (dcerpc_coder)coder, ptr); } break; case PTR_FULL: /* not implemented yet */ break; } out: if (pdu->top_level) { pdu->top_level = 0; if (dcerpc_process_deferred_pointers(dce, pdu, iov, offset)) { return -1; } pdu->top_level = top_level; } return 0; } int dcerpc_carray_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, int elem_size, dcerpc_coder coder) { struct dcerpc_carray *carray = ptr; int i; uint64_t p; /* Conformance */ p = carray->max_count; if (dcerpc_conformance_coder(ctx, pdu, iov, offset, &p)) { return -1; } carray->max_count = p; if (dcerpc_pdu_direction(pdu) == DCERPC_DECODE) { if (carray->max_count && carray->data == NULL) { carray->data = smb2_alloc_data( dcerpc_get_smb2_context(ctx), dcerpc_get_pdu_payload(pdu), carray->max_count * elem_size); if (carray->data == NULL) { return -1; } } } /* Data */ for (i = 0; i < p; i++) { if (coder(ctx, pdu, iov, offset, &carray->data[i * elem_size])) { return -1; } } return 0; } int dcerpc_ptr_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, enum ptr_type type, dcerpc_coder coder) { if (pdu->direction == DCERPC_DECODE) { return dcerpc_decode_ptr(dce, pdu, iov, offset, ptr, type, coder); } else { return dcerpc_encode_ptr(dce, pdu, iov, offset, ptr, type, coder); } } static int dcerpc_encode_utf16(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, int nult) { struct dcerpc_utf16 *s = ptr; int i; uint64_t val; uint16_t zero = 0; /* Conformance part */ if (pdu->is_conformance_run) { if (s->utf8 == NULL) { s->utf8 = ""; } s->utf16 = smb2_utf8_to_utf16(s->utf8); if (s->utf16 == NULL) { return -1; } if (nult) { val = s->utf16->len + 1; } else { val = s->utf16->len; } s->actual_count = (uint32_t)val; if (!nult) { if (val & 0x01) val++; } s->max_count = (uint32_t)val; s->offset = 0; val = s->max_count; if (dcerpc_conformance_coder(ctx, pdu, iov, offset, &val)) { return -1; } val = s->offset; if (dcerpc_conformance_coder(ctx, pdu, iov, offset, &val)) { return -1; } val = s->actual_count; if (dcerpc_conformance_coder(ctx, pdu, iov, offset, &val)) { return -1; } if (pdu->max_alignment < 2) { pdu->max_alignment = 2; } return 0; } /* Data part */ for (i = 0; i < s->utf16->len; i++) { if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &s->utf16->val[i])) { return -1; } } if (nult) { if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &zero)) { return -1; } } free(s->utf16); return 0; } static int dcerpc_decode_utf16(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr, int nult) { struct dcerpc_utf16 *s = ptr; uint64_t val; /* Any fundament of this? */ char *str; const char *tmp; /* Conformance part */ if (pdu->is_conformance_run) { if (dcerpc_conformance_coder(ctx, pdu, iov, offset, &val)) { return -1; } s->max_count = (uint32_t)val; if (dcerpc_conformance_coder(ctx, pdu, iov, offset, &val)) { return -1; } s->offset = (uint32_t)val; if (dcerpc_conformance_coder(ctx, pdu, iov, offset, &val)) { return -1; } s->actual_count = (uint32_t)val; if (pdu->max_alignment < 2) { pdu->max_alignment = 2; } return 0; } /* Data part */ if (*offset + s->actual_count * 2 > iov->len) { return -1; } if (!(pdu->hdr.packed_drep[0] & DCERPC_DR_LITTLE_ENDIAN)) { int i, o; uint16_t v; for (i = 0; i < s->actual_count; i++) { o = *offset + i *2; if (dcerpc_get_uint16(ctx, pdu, iov, &o, &v)) { return -1; } *(uint16_t *)&iov->buf[*offset + i * 2] = v; } } tmp = smb2_utf16_to_utf8((uint16_t *)(&iov->buf[*offset]), (size_t)s->actual_count); *offset += (int)s->actual_count * 2; str = smb2_alloc_data(ctx->smb2, pdu->payload, strlen(tmp) + 1); if (str == NULL) { free(discard_const(tmp)); return -1; } strcat(str, tmp); free(discard_const(tmp)); s->utf8 = str; return 0; } /* Handle \0 terminated utf16 strings */ /* ptr is char ** */ int dcerpc_utf16z_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { if (pdu->direction == DCERPC_DECODE) { return dcerpc_decode_utf16(ctx, pdu, iov, offset, ptr, 1); } else { return dcerpc_encode_utf16(ctx, pdu, iov, offset, ptr, 1); } } /* Handle utf16 strings that are NOT \0 terminated */ int dcerpc_utf16_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { if (pdu->direction == DCERPC_DECODE) { return dcerpc_decode_utf16(ctx, pdu, iov, offset, ptr, 0); } else { return dcerpc_encode_utf16(ctx, pdu, iov, offset, ptr, 0); } } int dcerpc_header_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, struct dcerpc_header *hdr) { /* Major Version */ if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &hdr->rpc_vers)) { return -1; } /* Minor Version */ if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &hdr->rpc_vers_minor)) { return -1; } /* Packet Type */ if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &hdr->PTYPE)) { return -1; } /* Flags */ if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &hdr->pfc_flags)) { return -1; } /* Data Representation */ if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &hdr->packed_drep[0])) { return -1; } if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &hdr->packed_drep[1])) { return -1; } if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &hdr->packed_drep[2])) { return -1; } if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &hdr->packed_drep[3])) { return -1; } /* Fragment len */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &hdr->frag_length)) { return -1; } /* Auth len */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &hdr->auth_length)) { return -1; } /* Call id */ if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &hdr->call_id)) { return -1; } return 0; } int dcerpc_uuid_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, dcerpc_uuid_t *uuid) { int i; if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &uuid->v1)) { return -1; } if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &uuid->v2)) { return -1; } if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &uuid->v3)) { return -1; } for (i = 0; i < 8; i++) { if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &uuid->v4[i])) { return -1; } } return 0; } /********************** * typedef struct ndr_context_handle { * unsigned32 context_handle_attributes; * dcerpc_uuid_t context_handle_uuid; * } ndr_context_handle; **********************/ int dcerpc_context_handle_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct ndr_context_handle *handle = ptr; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &handle->context_handle_attributes)) { return -1; } if (dcerpc_uuid_coder(dce, pdu, iov, offset, &handle->context_handle_uuid)) { return -1; } return 0; } static int dcerpc_bind_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct dcerpc_bind_pdu *bind, struct smb2_iovec *iov, int *offset) { int oo, i, j; uint16_t v; /* Max Xmit Frag */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &bind->max_xmit_frag)) { return -1; } /* Max Recv Frag */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &bind->max_recv_frag)) { return -1; } /* Association Group */ if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &bind->assoc_group_id)) { return -1; } /* Number Of Context Items */ if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &bind->n_context_elem)) { return -1; } *offset += 3; //qqq TODO allocate p_cont_elem on decode for (i = 0; i < bind->n_context_elem; i++) { if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &pdu->bind.p_cont_elem[i].p_cont_id)) { return -1; } if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &pdu->bind.p_cont_elem[i].n_transfer_syn)) { return -1; } *offset += 1; /* Abstract Syntax */ //qqq TODO allocate abstract_syntax on decode if (dcerpc_uuid_coder(ctx, pdu, iov, offset, &pdu->bind.p_cont_elem[i].abstract_syntax->uuid)) { return -1; } if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &pdu->bind.p_cont_elem[i].abstract_syntax->vers)) { return -1; } //qqq TODO allocate transfer_syntaxes on decode for (j = 0; j < pdu->bind.p_cont_elem[i].n_transfer_syn; j++) { if (dcerpc_uuid_coder(ctx, pdu, iov, offset, &pdu->bind.p_cont_elem[i].transfer_syntaxes[j]->uuid)) { return -1; } if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &pdu->bind.p_cont_elem[i].transfer_syntaxes[j]->vers)) { return -1; } } } /* Fixup fragment length */ oo = 8; v = *offset; if (dcerpc_uint16_coder(ctx, pdu, iov, &oo, &v)) { return -1; } return 0; } static int dcerpc_request_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct dcerpc_request_pdu *req, struct smb2_iovec *iov, int *offset) { /* Alloc Hint */ if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &req->alloc_hint)) { return -1; } /* Context ID */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &req->context_id)) { return -1; } /* Opnum */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &req->opnum)) { return -1; } return 0; } static int dcerpc_bind_ack_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct dcerpc_bind_ack_pdu *bind_ack, struct smb2_iovec *iov, int *offset) { int i; uint16_t sec_addr_len; /* Max Xmit Frag */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &bind_ack->max_xmit_frag)) { return -1; } /* Max Recv Frag */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &bind_ack->max_recv_frag)) { return -1; } /* Association Group */ if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &bind_ack->assoc_group_id)) { return -1; } /* Secondary Address Length */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &sec_addr_len)) { return -1; } /* Skip the secondary address and realign to 32bit */ /* TODO: we need to handle the encode case. * it is something like "\\PIPE\\srvsvc" */ *offset += sec_addr_len; *offset = (*offset + 3) & ~3; /* Number Of Results */ if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &bind_ack->num_results)) { return -1; } *offset += 3; for (i = 0; i < bind_ack->num_results; i++) { if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &bind_ack->results[i].ack_result)) { return -1; } if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &bind_ack->results[i].ack_reason)) { return -1; } if (dcerpc_uuid_coder(ctx, pdu, iov, offset, &bind_ack->results[i].uuid)) { return -1; } if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &bind_ack->results[i].syntax_version)) { return -1; } } return 0; } static int dcerpc_response_coder(struct dcerpc_context *ctx, struct dcerpc_response_pdu *rsp, struct smb2_iovec *iov, int *offset) { #ifndef _MSC_VER struct dcerpc_pdu *pdu = container_of(rsp, struct dcerpc_pdu, rsp); #else const char* __mptr = (const char*)rsp; struct dcerpc_pdu *pdu = (struct dcerpc_pdu*)((char *)__mptr - offsetof(struct dcerpc_pdu, rsp)); #endif /* !_MSC_VER */ if (*offset < 0) { return -1; } /* Alloc Hint */ if (dcerpc_uint32_coder(ctx, pdu, iov, offset, &rsp->alloc_hint)) { return -1; } if (rsp->alloc_hint > 16*1024*1024) { smb2_set_error(ctx->smb2, "DCERPC RESPONSE alloc_hint out " "of range."); return -1; } /* Context Id */ if (dcerpc_uint16_coder(ctx, pdu, iov, offset, &rsp->context_id)) { return -1; } /* Cancel Count */ if (dcerpc_uint8_coder(ctx, pdu, iov, offset, &rsp->cancel_count)) { return -1; } *offset += 1; /* decode the blob */ pdu->top_level = 1; if (pdu->coder(ctx, pdu, iov, offset, pdu->payload) < 0) { return -1; } *offset += rsp->alloc_hint; return 0; } static int dcerpc_pdu_coder(struct dcerpc_context *ctx, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset) { if (dcerpc_header_coder(ctx, pdu, iov, offset, &pdu->hdr)) { return -1; } switch (pdu->hdr.PTYPE) { case PDU_TYPE_BIND: if (dcerpc_bind_coder(ctx, pdu, &pdu->bind, iov, offset)) { return -1; } break; case PDU_TYPE_BIND_ACK: if (dcerpc_bind_ack_coder(ctx, pdu, &pdu->bind_ack, iov, offset)) { return -1; } break; case PDU_TYPE_REQUEST: if (dcerpc_request_coder(ctx, pdu, &pdu->req, iov, offset)) { return -1; } break; case PDU_TYPE_RESPONSE: if (dcerpc_response_coder(ctx, &pdu->rsp, iov, offset)) { return -1; } break; default: smb2_set_error(ctx->smb2, "DCERPC No decoder for PDU type %d", pdu->hdr.PTYPE); return -1; } return 0; } static void dce_unfragment_ioctl(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov) { int offset = 0; int unfragment_len; struct dcerpc_header hdr, next_hdr; struct smb2_iovec tmpiov _U_; int o; o = 0; if (dcerpc_header_coder(dce, pdu, iov, &o, &hdr)) { return; } if (hdr.rpc_vers != 5 || hdr.rpc_vers_minor != 0 || hdr.PTYPE != PDU_TYPE_RESPONSE) { return; } if (hdr.pfc_flags & PFC_LAST_FRAG) { return; } offset += hdr.frag_length; unfragment_len = hdr.frag_length; do { /* We must have at least a DCERPC header plus a * RESPONSE header */ if (iov->len - offset < 24) { return; } tmpiov.buf = iov->buf + offset; tmpiov.len = iov->len - offset; o = 0; if (dcerpc_header_coder(dce, pdu, &tmpiov, &o, &next_hdr)) { return; } memmove(iov->buf + unfragment_len, iov->buf + offset + 24, next_hdr.frag_length - 24); unfragment_len += next_hdr.frag_length - 24; offset += next_hdr.frag_length; hdr.frag_length += next_hdr.frag_length; if (next_hdr.pfc_flags & PFC_LAST_FRAG) { hdr.pfc_flags |= PFC_LAST_FRAG; } o = 0; if (dcerpc_header_coder(dce, pdu, iov, &o, &hdr)) { return; } } while (!(next_hdr.pfc_flags & PFC_LAST_FRAG)); iov->len = unfragment_len; } static void dcerpc_send_pdu_cb_and_free(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, int status, void *command_data) { dcerpc_cb pdu_cb = pdu->cb; void *pdu_cb_data = pdu->cb_data; dcerpc_free_pdu(dce, pdu); pdu_cb(dce, status, command_data, pdu_cb_data); } static void dcerpc_call_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct dcerpc_pdu *pdu = private_data; struct dcerpc_context *dce = pdu->dce; struct smb2_iovec iov _U_; struct smb2_ioctl_reply *rep = command_data; void *payload; int offset = 0; pdu->direction = DCERPC_DECODE; if (status != SMB2_STATUS_SUCCESS) { dcerpc_send_pdu_cb_and_free(dce, pdu, -nterror_to_errno(status), NULL); return; } smb2_free_data(dce->smb2, pdu->payload); pdu->payload = NULL; pdu->payload = smb2_alloc_init(dce->smb2, pdu->decode_size); if (pdu->payload == NULL) { dcerpc_send_pdu_cb_and_free(dce, pdu, -ENOMEM, NULL); return; } iov.buf = rep->output; iov.len = rep->output_count; iov.free = NULL; dce_unfragment_ioctl(dce, pdu, &iov); if (dcerpc_pdu_coder(dce, pdu, &iov, &offset)) { smb2_free_data(dce->smb2, rep->output); dcerpc_send_pdu_cb_and_free(dce, pdu, -EINVAL, NULL); return; } smb2_free_data(dce->smb2, rep->output); if (pdu->hdr.PTYPE != PDU_TYPE_RESPONSE) { smb2_set_error(dce->smb2, "DCERPC response was not a RESPONSE"); dcerpc_send_pdu_cb_and_free(dce, pdu, -EINVAL, NULL); return; } payload = pdu->payload; pdu->payload = NULL; dcerpc_send_pdu_cb_and_free(dce, pdu, 0, payload); } int dcerpc_call_async(struct dcerpc_context *dce, int opnum, dcerpc_coder encoder, void *ptr, dcerpc_coder decoder, int decode_size, dcerpc_cb cb, void *cb_data) { struct dcerpc_pdu *pdu; struct smb2_pdu *smb2_pdu; struct smb2_ioctl_request req; struct smb2_iovec iov _U_; int offset = 0, o; uint32_t v; pdu = dcerpc_allocate_pdu(dce, DCERPC_ENCODE, NSE_BUF_SIZE); if (pdu == NULL) { return -ENOMEM; } pdu->hdr.rpc_vers = 5; pdu->hdr.rpc_vers_minor = 0; pdu->hdr.PTYPE = PDU_TYPE_REQUEST; pdu->hdr.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG; pdu->hdr.packed_drep[0] = dce->packed_drep[0]; pdu->hdr.frag_length = 0; pdu->hdr.auth_length = 0; pdu->req.alloc_hint = 0; pdu->req.context_id = dce->tctx_id; pdu->req.opnum = opnum; pdu->coder = decoder; pdu->decode_size = decode_size; pdu->cb = cb; pdu->cb_data = cb_data; iov.buf = pdu->payload; iov.len = NSE_BUF_SIZE; iov.free = NULL; if (dcerpc_pdu_coder(dce, pdu, &iov, &offset)) { dcerpc_free_pdu(dce, pdu); return -ENOMEM; } /* encode the blob */ pdu->top_level = 1; if (encoder(dce, pdu, &iov, &offset, ptr)) { return -1; } iov.len = offset; /* Fixup frag_length and alloc_hint */ o = 8; if (dcerpc_set_uint16(dce, pdu, &iov, &o, offset)) { return -1; } o = 16; v = offset - 24; if (dcerpc_uint32_coder(dce, pdu, &iov, &o, &v)) { return -1; } memset(&req, 0, sizeof(struct smb2_ioctl_request)); req.ctl_code = SMB2_FSCTL_PIPE_TRANSCEIVE; memcpy(req.file_id, dce->file_id, SMB2_FD_SIZE); req.input_count = (uint32_t)iov.len; req.input = iov.buf; req.flags = SMB2_0_IOCTL_IS_FSCTL; smb2_pdu = smb2_cmd_ioctl_async(dce->smb2, &req, dcerpc_call_cb, pdu); if (smb2_pdu == NULL) { dcerpc_free_pdu(dce, pdu); return -ENOMEM; } smb2_queue_pdu(dce->smb2, smb2_pdu); return 0; } static void dcerpc_bind_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct dcerpc_cb_data *data = cb_data; if (status != SMB2_STATUS_SUCCESS) { data->cb(dce, status, NULL, data->cb_data); free(data); return; } data->cb(dce, 0, NULL, data->cb_data); free(data); } static void smb2_bind_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct dcerpc_pdu *pdu = private_data; struct dcerpc_context *dce = pdu->dce; struct smb2_iovec iov _U_; struct smb2_ioctl_reply *rep = command_data; int i; int offset = 0; pdu->direction = DCERPC_DECODE; if (status != SMB2_STATUS_SUCCESS) { dcerpc_send_pdu_cb_and_free(dce, pdu, -nterror_to_errno(status), NULL); return; } iov.buf = rep->output; iov.len = rep->output_count; iov.free = NULL; if (dcerpc_pdu_coder(dce, pdu, &iov, &offset)) { smb2_free_data(dce->smb2, rep->output); dcerpc_send_pdu_cb_and_free(dce, pdu, -EINVAL, NULL); return; } smb2_free_data(dce->smb2, rep->output); if (pdu->hdr.PTYPE != PDU_TYPE_BIND_ACK) { smb2_set_error(dce->smb2, "DCERPC response was not a BIND_ACK"); dcerpc_send_pdu_cb_and_free(dce, pdu, -EINVAL, NULL); return; } if (pdu->bind_ack.num_results < 1) { smb2_set_error(smb2, "No results in BIND ACK"); dcerpc_send_pdu_cb_and_free(dce, pdu, -EINVAL, NULL); return; } for (i = 0; i < pdu->bind_ack.num_results; i++) { if (pdu->bind_ack.results[i].ack_result != ACK_RESULT_ACCEPTANCE) { continue; } switch (smb2->ndr) { case 0: dce->tctx_id = i; break; case 1: dce->tctx_id = 0; break; case 2: dce->tctx_id = 1; break; } break; } if (i == pdu->bind_ack.num_results) { smb2_set_error(smb2, "Bind rejected all contexts"); dcerpc_send_pdu_cb_and_free(dce, pdu, -EINVAL, NULL); return; } dcerpc_send_pdu_cb_and_free(dce, pdu, 0, NULL); } static int dcerpc_bind_async(struct dcerpc_context *dce, dcerpc_cb cb, void *cb_data) { struct dcerpc_pdu *pdu; struct smb2_pdu *smb2_pdu; struct smb2_ioctl_request req; struct smb2_iovec iov _U_; int offset = 0; struct p_cont_elem_t *pce; pdu = dcerpc_allocate_pdu(dce, DCERPC_ENCODE, NSE_BUF_SIZE); if (pdu == NULL) { return -ENOMEM; } pdu->hdr.rpc_vers = 5; pdu->hdr.rpc_vers_minor = 0; pdu->hdr.PTYPE = PDU_TYPE_BIND; pdu->hdr.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG; pdu->hdr.packed_drep[0] = dce->packed_drep[0]; pdu->hdr.frag_length = 0; pdu->hdr.auth_length = 0; pdu->bind.max_xmit_frag = 32768; pdu->bind.max_recv_frag = 32768; pdu->bind.assoc_group_id = 0; pdu->bind.n_context_elem = dce->smb2->ndr ? 1 : 2; pdu->bind.p_cont_elem = smb2_alloc_data(dce->smb2, pdu->payload, pdu->bind.n_context_elem * sizeof(struct p_cont_elem_t)); pce = pdu->bind.p_cont_elem; if (dce->smb2->ndr == 0 || dce->smb2->ndr == 1) { pce->p_cont_id = 0; pce->n_transfer_syn = 1; pce->abstract_syntax = dce->syntax; pce->transfer_syntaxes = smb2_alloc_data( dce->smb2, pdu->payload, pce->n_transfer_syn * sizeof(struct p_cont_elem_t *)); pce->transfer_syntaxes[0] = &ndr32_syntax; pce++; } if (dce->smb2->ndr == 0 || dce->smb2->ndr == 2) { pce->p_cont_id = 1; pce->n_transfer_syn = 1; pce->abstract_syntax = dce->syntax; pce->transfer_syntaxes = smb2_alloc_data( dce->smb2, pdu->payload, pce->n_transfer_syn * sizeof(struct p_cont_elem_t *)); pce->transfer_syntaxes[0] = &ndr64_syntax; } pdu->cb = cb; pdu->cb_data = cb_data; iov.buf = pdu->payload; iov.len = NSE_BUF_SIZE; iov.free = NULL; if (dcerpc_pdu_coder(dce, pdu, &iov, &offset)) { dcerpc_free_pdu(dce, pdu); return -ENOMEM; } iov.len = offset; memset(&req, 0, sizeof(struct smb2_ioctl_request)); req.ctl_code = SMB2_FSCTL_PIPE_TRANSCEIVE; memcpy(req.file_id, dce->file_id, SMB2_FD_SIZE); req.input_count = (uint32_t)iov.len; req.input = iov.buf; req.flags = SMB2_0_IOCTL_IS_FSCTL; smb2_pdu = smb2_cmd_ioctl_async(dce->smb2, &req, smb2_bind_cb, pdu); if (smb2_pdu == NULL) { dcerpc_free_pdu(dce, pdu); return -ENOMEM; } smb2_queue_pdu(dce->smb2, smb2_pdu); return 0; } static void smb2_open_cb(struct smb2_context *smb2, int status, void *command_data, void *private_data) { struct dcerpc_cb_data *data = private_data; struct smb2_create_reply *rep = command_data; struct dcerpc_context *dce = data->dce; if (status != SMB2_STATUS_SUCCESS) { data->cb(dce, -nterror_to_errno(status), NULL, data->cb_data); free(data); return; } memcpy(dce->file_id, rep->file_id, SMB2_FD_SIZE); status = dcerpc_bind_async(dce, dcerpc_bind_cb, data); if (status) { data->cb(dce, status, NULL, data->cb_data); free(data); return; } return; } int dcerpc_open_async(struct dcerpc_context *dce, dcerpc_cb cb, void *cb_data) { struct smb2_create_request req; struct smb2_pdu *pdu; struct dcerpc_cb_data *data; data = calloc(1, sizeof(struct dcerpc_cb_data)); if (data == NULL) { smb2_set_error(dce->smb2, "Failed to allocate dcerpc callback " "data"); return -ENOMEM; } data->dce = dce; data->cb = cb; data->cb_data = cb_data; memset(&req, 0, sizeof(struct smb2_create_request)); req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE; req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; req.desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA | SMB2_FILE_READ_EA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_EA | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_READ_CONTROL | SMB2_SYNCHRONIZE; req.file_attributes = 0; req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE | SMB2_FILE_SHARE_DELETE; req.create_disposition = SMB2_FILE_OPEN; req.create_options = 0; req.name = dce->path; pdu = smb2_cmd_create_async(dce->smb2, &req, smb2_open_cb, data); if (pdu == NULL) { free(data); return -ENOMEM; } smb2_queue_pdu(dce->smb2, pdu); return 0; } const char * dcerpc_get_error(struct dcerpc_context *dce) { return smb2_get_error(dcerpc_get_smb2_context(dce)); } void dcerpc_free_data(struct dcerpc_context *dce, void *data) { smb2_free_data(dcerpc_get_smb2_context(dce), data); } int dcerpc_pdu_direction(struct dcerpc_pdu *pdu) { return pdu->direction; } int dcerpc_align_3264(struct dcerpc_context *ctx, int offset) { if (offset < 0) { return offset; } if (ctx->tctx_id) { offset = (offset + 7) & ~7; } else { offset = (offset + 3) & ~3; } return offset; } /* Used for testing. Override/force the transfer syntax. */ void dcerpc_set_tctx(struct dcerpc_context *ctx, int tctx) { ctx->tctx_id = tctx; } /* Used for testing. Override/force the transfer syntax. */ void dcerpc_set_endian(struct dcerpc_pdu *pdu, int little_endian) { if (little_endian) { pdu->hdr.packed_drep[0] |= DCERPC_DR_LITTLE_ENDIAN; } else { pdu->hdr.packed_drep[0] &= ~DCERPC_DR_LITTLE_ENDIAN; } } int dcerpc_get_cr(struct dcerpc_pdu *pdu) { return pdu->is_conformance_run; } libsmb2-6.2/lib/timestamps.c0000664000175000017500000000320614732155517015120 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef STDC_HEADERS #include #endif #include "compat.h" #include "portable-endian.h" #include #include #include "libsmb2-private.h" time_t smb2_timeval_to_win(struct smb2_timeval *tv) { return (tv->tv_sec * 10000000) + 116444736000000000 + tv->tv_usec * 10; } void smb2_win_to_timeval(uint64_t smb2_time, struct smb2_timeval *tv) { tv->tv_usec = (smb2_time / 10) % 1000000; tv->tv_sec = (smb2_time - 116444736000000000) / 10000000; } libsmb2-6.2/lib/smb2-cmd-query-directory.c0000664000175000017500000005406114732155517017510 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" int smb2_decode_fileidfulldirectoryinformation( struct smb2_context *smb2, struct smb2_fileidfulldirectoryinformation *fs, struct smb2_iovec *vec) { uint32_t name_len; uint64_t t; /* Make sure the name fits before end of vector. * As the name is the final part of this blob this guarantees * that all other fields also fit within the remainder of the * vector. */ smb2_get_uint32(vec, 60, &name_len); if (name_len > 80 + name_len || 80 + name_len > vec->len) { smb2_set_error(smb2, "Malformed name in query.\n"); return -1; } smb2_get_uint32(vec, 0, &fs->next_entry_offset); smb2_get_uint32(vec, 4, &fs->file_index); smb2_get_uint64(vec, 40, &fs->end_of_file); smb2_get_uint64(vec, 48, &fs->allocation_size); smb2_get_uint32(vec, 56, &fs->file_attributes); smb2_get_uint32(vec, 64, &fs->ea_size); smb2_get_uint64(vec, 72, &fs->file_id); fs->name = smb2_utf16_to_utf8((uint16_t *)&vec->buf[80], name_len / 2); smb2_get_uint64(vec, 8, &t); smb2_win_to_timeval(t, &fs->creation_time); smb2_get_uint64(vec, 16, &t); smb2_win_to_timeval(t, &fs->last_access_time); smb2_get_uint64(vec, 24, &t); smb2_win_to_timeval(t, &fs->last_write_time); smb2_get_uint64(vec, 32, &t); smb2_win_to_timeval(t, &fs->change_time); return 0; } static int smb2_encode_query_directory_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_query_directory_request *req) { int len; uint8_t *buf; struct smb2_utf16 *name = NULL; struct smb2_iovec *iov; len = SMB2_QUERY_DIRECTORY_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate query buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); /* Name */ if (req->name && req->name[0]) { name = smb2_utf8_to_utf16(req->name); if (name == NULL) { smb2_set_error(smb2, "Could not convert name into UTF-16"); return -1; } smb2_set_uint16(iov, 26, 2 * name->len); } smb2_set_uint16(iov, 0, SMB2_QUERY_DIRECTORY_REQUEST_SIZE); smb2_set_uint8(iov, 2, req->file_information_class); smb2_set_uint8(iov, 3, req->flags); smb2_set_uint32(iov, 4, req->file_index); memcpy(iov->buf + 8, req->file_id, SMB2_FD_SIZE); smb2_set_uint16(iov, 24, SMB2_HEADER_SIZE + 32); smb2_set_uint32(iov, 28, req->output_buffer_length); /* Name */ if (name) { buf = malloc(2 * name->len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate qdir name"); free(name); return -1; } memcpy(buf, &name->val[0], 2 * name->len); iov = smb2_add_iovector(smb2, &pdu->out, buf, 2 * name->len, free); } free(name); return 0; } struct smb2_pdu * smb2_cmd_query_directory_async(struct smb2_context *smb2, struct smb2_query_directory_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_QUERY_DIRECTORY, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_query_directory_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } /* Adjust credit charge for large payloads */ if (smb2->supports_multi_credit) { pdu->header.credit_charge = (req->output_buffer_length - 1) / 65536 + 1; /* 3.1.5.2 of [MS-SMB2] */ } return pdu; } static int smb2_encode_query_directory_reply(struct smb2_context *smb2, uint8_t info_class, uint8_t flags, uint32_t room, struct smb2_pdu *pdu, struct smb2_query_directory_reply *rep) { int len; int fslen; uint8_t *buf; struct smb2_utf16 *name = NULL; struct smb2_fileidbothdirectoryinformation *fs; struct smb2_iovec *iov; uint32_t fs_size; uint32_t fname_len; int offset; int in_offset; int in_remain; len = SMB2_QUERY_DIRECTORY_REPLY_SIZE & 0xfffe; len = PAD_TO_32BIT(len); buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate query reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); fslen = rep->output_buffer_length; rep->output_buffer_offset = len + SMB2_HEADER_SIZE; if (rep->output_buffer) { if (!smb2->passthrough) { rep->output_buffer_length = 0; in_offset = 0; in_remain = fslen; do { fs = (struct smb2_fileidbothdirectoryinformation*)(rep->output_buffer + in_offset); fname_len = 0; if (fs->name && fs->name[0]) { name = smb2_utf8_to_utf16(fs->name); if (name == NULL) { smb2_set_error(smb2, "Could not convert name into UTF-16"); return -1; } fname_len = 2 * name->len; free(name); } switch (info_class) { case SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION: fs_size = PAD_TO_32BIT(SMB2_FILEID_FULL_DIRECTORY_INFORMATION_SIZE + fname_len); break; case SMB2_FILE_ID_BOTH_DIRECTORY_INFORMATION: fs_size = PAD_TO_32BIT(SMB2_FILEID_BOTH_DIRECTORY_INFORMATION_SIZE + fname_len); break; default: fs_size = 0; break; } rep->output_buffer_length += fs_size; in_offset += PAD_TO_64BIT(sizeof(struct smb2_fileidbothdirectoryinformation)); in_remain -= PAD_TO_64BIT(sizeof(struct smb2_fileidbothdirectoryinformation)); } while (in_remain >= sizeof(struct smb2_fileidbothdirectoryinformation)); } } smb2_set_uint16(iov, 0, SMB2_QUERY_DIRECTORY_REPLY_SIZE); smb2_set_uint16(iov, 2, rep->output_buffer_offset); smb2_set_uint32(iov, 4, rep->output_buffer_length); if (rep->output_buffer_length == 0) { return 0; } len = rep->output_buffer_length; len = PAD_TO_32BIT(len); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate output buf"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); in_offset = 0; in_remain = fslen; offset = 0; if (smb2->passthrough) { memcpy(buf, rep->output_buffer, rep->output_buffer_length); memset(buf + rep->output_buffer_length, 0, len - rep->output_buffer_length); iov->len = rep->output_buffer_length; } else { do { fs = (struct smb2_fileidbothdirectoryinformation*)(rep->output_buffer + in_offset); fname_len = 0; if (fs->name && fs->name[0]) { name = smb2_utf8_to_utf16(fs->name); if (name == NULL) { smb2_set_error(smb2, "Could not convert name into UTF-16"); return -1; } fname_len = 2 * name->len; } switch (info_class) { case SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION: fs_size = PAD_TO_32BIT(SMB2_FILEID_FULL_DIRECTORY_INFORMATION_SIZE + fname_len); break; case SMB2_FILE_ID_BOTH_DIRECTORY_INFORMATION: fs_size = PAD_TO_32BIT(SMB2_FILEID_BOTH_DIRECTORY_INFORMATION_SIZE + fname_len); break; default: fs_size = 0; break; } in_offset += PAD_TO_64BIT(sizeof(struct smb2_fileidbothdirectoryinformation)); in_remain -= PAD_TO_64BIT(sizeof(struct smb2_fileidbothdirectoryinformation)); if (in_remain >= SMB2_FILEID_BOTH_DIRECTORY_INFORMATION_SIZE) { smb2_set_uint32(iov, offset + 0, offset + fs_size); } else { smb2_set_uint32(iov, offset + 0, 0); } switch (info_class) { case SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION: fs_size = PAD_TO_32BIT(SMB2_FILEID_FULL_DIRECTORY_INFORMATION_SIZE + fname_len); smb2_set_uint32(iov, offset + 4, fs->file_index); smb2_set_uint64(iov, offset + 8, smb2_timeval_to_win(&fs->creation_time)); smb2_set_uint64(iov, offset + 16, smb2_timeval_to_win(&fs->last_access_time)); smb2_set_uint64(iov, offset + 24, smb2_timeval_to_win(&fs->last_write_time)); smb2_set_uint64(iov, offset + 32, smb2_timeval_to_win(&fs->change_time)); smb2_set_uint64(iov, offset + 40, fs->end_of_file); smb2_set_uint64(iov, offset + 48, fs->allocation_size); smb2_set_uint32(iov, offset + 56, fs->file_attributes); smb2_set_uint32(iov, offset + 60, fname_len); smb2_set_uint32(iov, offset + 64, fs->ea_size); smb2_set_uint32(iov, offset + 68, 0); /* reserved */ smb2_set_uint64(iov, offset + 72, fs->file_id); if (name && fname_len > 0) { memcpy(buf + offset + SMB2_FILEID_FULL_DIRECTORY_INFORMATION_SIZE, &name->val[0], fname_len); } break; case SMB2_FILE_ID_BOTH_DIRECTORY_INFORMATION: fs_size = PAD_TO_32BIT(SMB2_FILEID_BOTH_DIRECTORY_INFORMATION_SIZE + fname_len); smb2_set_uint32(iov, offset + 4, fs->file_index); smb2_set_uint64(iov, offset + 8, smb2_timeval_to_win(&fs->creation_time)); smb2_set_uint64(iov, offset + 16, smb2_timeval_to_win(&fs->last_access_time)); smb2_set_uint64(iov, offset + 24, smb2_timeval_to_win(&fs->last_write_time)); smb2_set_uint64(iov, offset + 32, smb2_timeval_to_win(&fs->change_time)); smb2_set_uint64(iov, offset + 40, fs->end_of_file); smb2_set_uint64(iov, offset + 48, fs->allocation_size); smb2_set_uint32(iov, offset + 56, fs->file_attributes); smb2_set_uint32(iov, offset + 60, fname_len); smb2_set_uint32(iov, offset + 64, fs->ea_size); smb2_set_uint8(iov, offset + 68, fs->short_name_length); smb2_set_uint8(iov, offset + 69, 0); /* reserved */ memcpy(iov->buf + offset + 70, fs->short_name, sizeof(fs->short_name)); smb2_set_uint16(iov, offset + 94, 0); /* reserved */ smb2_set_uint64(iov, offset + 96, fs->file_id); if (name && fname_len > 0) { memcpy(buf + offset + SMB2_FILEID_BOTH_DIRECTORY_INFORMATION_SIZE, &name->val[0], fname_len); } break; default: break; } if (name) { free(name); } offset += fs_size; } while (in_remain >= sizeof(struct smb2_fileidbothdirectoryinformation)); } return 0; } struct smb2_pdu * smb2_cmd_query_directory_reply_async(struct smb2_context *smb2, struct smb2_query_directory_request *req, struct smb2_query_directory_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_QUERY_DIRECTORY, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_query_directory_reply(smb2, req->file_information_class, req->flags, req->output_buffer_length, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } #define IOV_OFFSET (rep->output_buffer_offset - SMB2_HEADER_SIZE - \ (SMB2_QUERY_DIRECTORY_REPLY_SIZE & 0xfffe)) int smb2_process_query_directory_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_query_directory_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_QUERY_DIRECTORY_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Query Dir " "reply. Expected %d, got %d", SMB2_QUERY_DIRECTORY_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate query dir reply"); return -1; } pdu->payload = rep; smb2_get_uint16(iov, 2, &rep->output_buffer_offset); smb2_get_uint32(iov, 4, &rep->output_buffer_length); if (rep->output_buffer_length && (rep->output_buffer_offset + rep->output_buffer_length > smb2->spl)) { smb2_set_error(smb2, "Output buffer extends beyond end of " "PDU"); free(rep); return -1; } if (rep->output_buffer_length == 0) { return 0; } if (rep->output_buffer_offset < SMB2_HEADER_SIZE + (SMB2_QUERY_INFO_REPLY_SIZE & 0xfffe)) { smb2_set_error(smb2, "Output buffer overlaps with " "Query Dir reply header"); free(rep); return -1; } /* Return the amount of data that the output buffer will take up. * Including any padding before the output buffer itself. */ return IOV_OFFSET + rep->output_buffer_length; } int smb2_process_query_directory_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_query_directory_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; rep->output_buffer = &iov->buf[IOV_OFFSET]; return 0; } #define IOVREQ_OFFSET (req->file_name_offset - SMB2_HEADER_SIZE - \ (SMB2_QUERY_DIRECTORY_REQUEST_SIZE & 0xfffe)) int smb2_process_query_directory_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_query_directory_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_QUERY_DIRECTORY_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Query Dir " "request. Expected %d, got %d", SMB2_QUERY_DIRECTORY_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate query dir request"); return -1; } pdu->payload = req; smb2_get_uint8(iov, 2, &req->file_information_class); smb2_get_uint8(iov, 3, &req->flags); smb2_get_uint32(iov, 4, &req->file_index); memcpy(req->file_id, &iov->buf[8], SMB2_FD_SIZE); smb2_get_uint16(iov, 24, &req->file_name_offset); smb2_get_uint16(iov, 26, &req->file_name_length); smb2_get_uint32(iov, 28, &req->output_buffer_length); if (req->file_name_length && (req->file_name_offset + req->file_name_length > (uint16_t)smb2->spl)) { smb2_set_error(smb2, "Filename extends beyond end of " "PDU"); free(req); return -1; } if (req->file_name_length == 0) { return 0; } if (req->file_name_offset < SMB2_HEADER_SIZE + (SMB2_QUERY_DIRECTORY_REQUEST_SIZE & 0xfffe)) { smb2_set_error(smb2, "Name buffer overlaps with " "Query Dir request header"); free(req); return -1; } /* Return the amount of data that the name will take up. * Including any padding before the name itself. */ return IOVREQ_OFFSET + req->file_name_length; } int smb2_process_query_directory_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_query_directory_request *req = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; void *ptr; int name_byte_len; if (req->file_name_length > 0) { req->name = smb2_utf16_to_utf8((uint16_t*)&iov->buf[IOVREQ_OFFSET], req->file_name_length / 2); if (req->name) { name_byte_len = strlen(req->name) + 1; ptr = smb2_alloc_init(smb2, name_byte_len); if (ptr) { memcpy(ptr, req->name, name_byte_len); } free(discard_const(req->name)); req->name = ptr; if (!ptr) { smb2_set_error(smb2, "can not alloc name buffer"); return -1; } } else { smb2_set_error(smb2, "can not convert name to utf8"); return -1; } } return 0; } libsmb2-6.2/lib/smb2-signing.h0000664000175000017500000000254614732155517015244 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #ifndef _SMB2_SIGNING_H_ #define _SMB2_SIGNING_H_ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef __cplusplus extern "C" { #endif #include "slist.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" int smb2_pdu_add_signature(struct smb2_context *smb2, struct smb2_pdu *pdu); int smb2_pdu_check_signature(struct smb2_context *smb2, struct smb2_pdu *pdu); #ifdef __cplusplus } #endif #endif /* _SMB2_SIGNING_H_ */ libsmb2-6.2/lib/smb2-cmd-create.c0000664000175000017500000004215114732155517015601 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" #define CCX_OFFSET() \ PAD_TO_64BIT(SMB2_HEADER_SIZE + (SMB2_CREATE_REQUEST_SIZE & 0xfffe) \ + (req->name_length ? req->name_length : 1)); static int smb2_encode_create_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_create_request *req) { int i, len; uint8_t *buf; uint16_t ch; struct smb2_utf16 *name = NULL; uint32_t name_byte_len = 0; struct smb2_iovec *iov; len = SMB2_CREATE_REQUEST_SIZE & 0xfffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate create buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); /* Name */ if (req->name && req->name[0]) { name = smb2_utf8_to_utf16(req->name); if (name == NULL) { smb2_set_error(smb2, "Could not convert name into UTF-16"); return -1; } name_byte_len = 2 * name->len; /* name length */ req->name_length = name_byte_len; smb2_set_uint16(iov, 46, req->name_length); } smb2_set_uint16(iov, 0, SMB2_CREATE_REQUEST_SIZE); smb2_set_uint8(iov, 2, req->security_flags); smb2_set_uint8(iov, 3, req->requested_oplock_level); smb2_set_uint32(iov, 4, req->impersonation_level); smb2_set_uint64(iov, 8, req->smb_create_flags); smb2_set_uint32(iov, 24, req->desired_access); smb2_set_uint32(iov, 28, req->file_attributes); smb2_set_uint32(iov, 32, req->share_access); smb2_set_uint32(iov, 36, req->create_disposition); smb2_set_uint32(iov, 40, req->create_options); /* name offset */ req->name_offset = PAD_TO_32BIT(SMB2_HEADER_SIZE + (SMB2_CREATE_REQUEST_SIZE & 0xfffe)); smb2_set_uint16(iov, 44, req->name_offset); /* context offset */ if (req->create_context_length) { if (req->name_length == 0) { req->create_context_offset = PAD_TO_64BIT(4 + req->name_offset); } else { req->create_context_offset = PAD_TO_64BIT(req->name_length + req->name_offset); } } else { req->create_context_offset = 0; } smb2_set_uint32(iov, 48, req->create_context_offset); smb2_set_uint32(iov, 52, req->create_context_length); /* Name */ if (name) { len = PAD_TO_64BIT(name_byte_len); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate create name"); free(name); return -1; } memcpy(buf, &name->val[0], name_byte_len); memset(buf + name_byte_len, 0, len - name_byte_len); iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); /* Convert '/' to '\' */ for (i = 0; i < name->len; i++) { smb2_get_uint16(iov, i * 2, &ch); if (ch == 0x002f) { smb2_set_uint16(iov, i * 2, 0x005c); } } free(name); } else { /* have to have at least one byte for name even if len is 0 * this code pads out to a 64 bit boundary to place the * create contexts on which they require */ static uint8_t zero[8]; iov = smb2_add_iovector(smb2, &pdu->out, zero, 8, NULL); } /* Create Context: note there is no encoding, we just pass along */ if (req->create_context_length) { len = PAD_TO_64BIT(req->create_context_length); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate create context"); return -1; } memcpy(buf, req->create_context, req->create_context_length); memset(buf + req->create_context_length, 0, len - req->create_context_length); iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); } return 0; } struct smb2_pdu * smb2_cmd_create_async(struct smb2_context *smb2, struct smb2_create_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_CREATE, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_create_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_create_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_create_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_CREATE_REPLY_SIZE & 0xfffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate create buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_CREATE_REPLY_SIZE); smb2_set_uint8(iov, 2, rep->oplock_level); smb2_set_uint8(iov, 3, rep->flags); smb2_set_uint32(iov, 4, rep->create_action); smb2_set_uint64(iov, 8, rep->creation_time); smb2_set_uint64(iov, 16, rep->last_access_time); smb2_set_uint64(iov, 24, rep->last_write_time); smb2_set_uint64(iov, 32, rep->change_time); smb2_set_uint64(iov, 40, rep->allocation_size); smb2_set_uint64(iov, 48, rep->end_of_file); smb2_set_uint32(iov, 56, rep->file_attributes); memcpy(&iov->buf[64], rep->file_id, SMB2_FD_SIZE); rep->create_context_offset = PAD_TO_64BIT((SMB2_CREATE_REPLY_SIZE & 0xfffe) + SMB2_HEADER_SIZE); smb2_set_uint32(iov, 80, rep->create_context_offset); smb2_set_uint32(iov, 84, rep->create_context_length); /* Create Context */ if (rep->create_context_length) { len = PAD_TO_64BIT(rep->create_context_length); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate create context"); return -1; } memcpy(buf, rep->create_context, rep->create_context_length); memset(buf + rep->create_context_length, 0, len - rep->create_context_length); iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); } return 0; } struct smb2_pdu * smb2_cmd_create_reply_async(struct smb2_context *smb2, struct smb2_create_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_CREATE, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_create_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } #define IOV_OFFSET (rep->create_context_offset - SMB2_HEADER_SIZE - \ (SMB2_CREATE_REPLY_SIZE & 0xfffe)) int smb2_process_create_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_create_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_CREATE_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Create. " "Expected %d, got %d", SMB2_CREATE_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate create reply"); return -1; } pdu->payload = rep; smb2_get_uint8(iov, 2, &rep->oplock_level); smb2_get_uint8(iov, 3, &rep->flags); smb2_get_uint32(iov, 4, &rep->create_action); smb2_get_uint64(iov, 8, &rep->creation_time); smb2_get_uint64(iov, 16, &rep->last_access_time); smb2_get_uint64(iov, 24, &rep->last_write_time); smb2_get_uint64(iov, 32, &rep->change_time); smb2_get_uint64(iov, 40, &rep->allocation_size); smb2_get_uint64(iov, 48, &rep->end_of_file); smb2_get_uint32(iov, 56, &rep->file_attributes); memcpy(rep->file_id, iov->buf + 64, SMB2_FD_SIZE); smb2_get_uint32(iov, 80, &rep->create_context_offset); smb2_get_uint32(iov, 84, &rep->create_context_length); if (rep->create_context_length == 0) { return 0; } if (rep->create_context_offset < SMB2_HEADER_SIZE + (SMB2_CREATE_REPLY_SIZE & 0xfffe)) { smb2_set_error(smb2, "Create context overlaps with " "reply header"); pdu->payload = NULL; free(rep); return -1; } /* Return the amount of data that the security buffer will take up. * Including any padding before the security buffer itself. */ return IOV_OFFSET + rep->create_context_length; } int smb2_process_create_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_create_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; struct smb2_iovec vec; vec.buf = iov->buf + IOV_OFFSET; vec.len = iov->len - IOV_OFFSET; rep->create_context = NULL; if (rep->create_context_length) { rep->create_context = vec.buf; } return 0; } #define IOVREQ_OFFSET (req->name_offset - SMB2_HEADER_SIZE - \ (SMB2_CREATE_REQUEST_SIZE & 0xfffe)) int smb2_process_create_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_create_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; int remaining; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_CREATE_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Create " "Request. Expected %d, got %d", SMB2_CREATE_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req== NULL) { smb2_set_error(smb2, "Failed to allocate create request"); return -1; } pdu->payload = req; req->name = ""; /* avoid seg faults if accessed before set */ smb2_get_uint8(iov, 2, &req->security_flags); smb2_get_uint8(iov, 3, &req->requested_oplock_level); smb2_get_uint32(iov, 4, &req->impersonation_level); smb2_get_uint64(iov, 8, &req->smb_create_flags); /* reserved 64bits at 16 */ smb2_get_uint32(iov, 24, &req->desired_access); smb2_get_uint32(iov, 28, &req->file_attributes); smb2_get_uint32(iov, 32, &req->share_access); smb2_get_uint32(iov, 36, &req->create_disposition); smb2_get_uint32(iov, 40, &req->create_options); smb2_get_uint16(iov, 44, &req->name_offset); smb2_get_uint16(iov, 46, &req->name_length); smb2_get_uint32(iov, 48, &req->create_context_offset); smb2_get_uint32(iov, 52, &req->create_context_length); req->name = NULL; if (req->create_context_length == 0 && req->name_length == 0) { return 0; } if (req->name_length > 0) { if (req->name_offset < SMB2_HEADER_SIZE + (SMB2_CREATE_REQUEST_SIZE & 0xfffe)) { smb2_set_error(smb2, "name overlaps with " "request header"); pdu->payload = NULL; free(req); return -1; } } if (req->create_context_length > 0) { if (req->create_context_offset < SMB2_HEADER_SIZE + (SMB2_CREATE_REQUEST_SIZE & 0xfffe)) { smb2_set_error(smb2, "Create context overlaps with " "request header"); pdu->payload = NULL; free(req); return -1; } } /* Return the amount of data that the name will take up. * Including any padding before the name itself, and between name and create contexts */ remaining = IOVREQ_OFFSET; if (req->create_context_offset > req->name_offset) { remaining += PAD_TO_64BIT(req->create_context_offset - req->name_offset); } else { remaining += req->name_length; } remaining += req->create_context_length; return remaining; } int smb2_process_create_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_create_request *req = (struct smb2_create_request*)pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint32_t offset; void *ptr; int name_byte_len; req->name = NULL; if (req->name_length > 0) { req->name = smb2_utf16_to_utf8((const uint16_t*)iov->buf, req->name_length / 2); if (req->name) { name_byte_len = strlen(req->name) + 1; ptr = smb2_alloc_init(smb2, name_byte_len); if (ptr) { memcpy(ptr, req->name, name_byte_len); } free(discard_const(req->name)); req->name = ptr; if (!ptr) { smb2_set_error(smb2, "can not alloc name buffer"); return -1; } } else { smb2_set_error(smb2, "can not convert name to utf8"); return -1; } } /* we dont parse the create contexts but we tack them on in case the * the caller wants to pass them along */ req->create_context = NULL; if (req->create_context_length && req->create_context_offset) { offset = req->create_context_offset - SMB2_HEADER_SIZE - (SMB2_CREATE_REQUEST_SIZE & 0xfffe); req->create_context = iov->buf + offset; } return 0; } libsmb2-6.2/lib/alloc.c0000664000175000017500000000670214732155517014030 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2017 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include #include #include "libsmb2-private.h" #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) struct smb2_alloc_entry { struct smb2_alloc_entry *next; #if 0 /* UNUSED. */ size_t len; #endif char buf[0]; }; struct smb2_alloc_header { struct smb2_alloc_entry *mem; char buf[0]; }; void * smb2_alloc_init(struct smb2_context *smb2, size_t size) { struct smb2_alloc_header *ptr; size += offsetof(struct smb2_alloc_header, buf); ptr = calloc(size, 1); if (ptr == NULL) { return NULL; } return &ptr->buf[0]; } void * smb2_alloc_data(struct smb2_context *smb2, void *memctx, size_t size) { struct smb2_alloc_header *hdr; struct smb2_alloc_entry *ptr; size += offsetof(struct smb2_alloc_entry, buf); ptr = calloc(size, 1); if (ptr == NULL) { smb2_set_error(smb2, "Failed to alloc %zu bytes", size); return NULL; } #ifndef _MSC_VER hdr = container_of(memctx, struct smb2_alloc_header, buf); #else { const char* __mptr = memctx; hdr = (struct smb2_alloc_header*)((char *)__mptr - offsetof(struct smb2_alloc_header, buf)); } #endif /* !_MSC_VER */ ptr->next = hdr->mem; hdr->mem = ptr; return &ptr->buf[0]; } void smb2_free_data(struct smb2_context *smb2, void *ptr) { struct smb2_alloc_header *hdr; struct smb2_alloc_entry *ent; if (ptr == NULL) { return; } #ifndef _MSC_VER hdr = container_of(ptr, struct smb2_alloc_header, buf); #else { const char* __mptr = ptr; hdr = (struct smb2_alloc_header*)((char *)__mptr - offsetof(struct smb2_alloc_header, buf)); } #endif /* !_MSC_VER */ while ((ent = hdr->mem)) { hdr->mem = ent->next; free(ent); } free(hdr); } libsmb2-6.2/lib/Makefile.AMIGA_AROS0000664000175000017500000000351614732155517015673 0ustar polpypolpyCPU ?= i386 CC = $(CPU)-aros-gcc AR = $(CPU)-aros-ar RANLIB = $(CPU)-aros-ranlib STRIP = $(CPU)-aros-strip OPTIMIZE = -O2 -fno-common -fomit-frame-pointer DEBUG = -g WARNINGS = -Wall -Werror INCLUDES = -I. -I../include -I../include/smb2 -I../include/amiga_os DEFINES = -DHAVE_CONFIG_H "-D_U_=__attribute__((unused))" -DNEED_POLL -DNEED_GETADDRINFO -DNEED_FREEADDRINFO -DNEED_GETLOGIN_R -DHAVE_LINGER -DHAVE_ADDRINFO ifeq (x86_64,$(CPU)) # Fixes duplicate member th_off/th_x2 errors in # on x86_64 ABIv11 target. DEFINES += -D__BSD_VISIBLE endif CFLAGS = -std=gnu99 $(OPTIMIZE) $(DEBUG) $(WARNINGS) $(INCLUDES) $(DEFINES) LIBS = -lnet ifneq (,$(SYSROOT)) CFLAGS := --sysroot=$(SYSROOT) $(CFLAGS) LDFLAGS := --sysroot=$(SYSROOT) $(LDFLAGS) endif SRCS = aes.c aes128ccm.c alloc.c dcerpc.c dcerpc-lsa.c dcerpc-srvsvc.c \ errors.c init.c hmac.c hmac-md5.c libsmb2.c md4c.c \ md5.c ntlmssp.c pdu.c sha1.c sha224-256.c sha384-512.c \ smb2-cmd-close.c smb2-cmd-create.c smb2-cmd-echo.c smb2-cmd-error.c \ smb2-cmd-flush.c smb2-cmd-ioctl.c smb2-cmd-logoff.c \ smb2-cmd-negotiate.c smb2-cmd-query-directory.c smb2-cmd-query-info.c \ smb2-cmd-read.c smb2-cmd-session-setup.c smb2-cmd-set-info.c \ smb2-cmd-tree-connect.c smb2-cmd-tree-disconnect.c smb2-cmd-write.c \ smb2-data-file-info.c smb2-data-filesystem-info.c \ smb2-data-security-descriptor.c smb2-data-reparse-point.c \ smb2-share-enum.c smb3-seal.c smb2-signing.c socket.c sync.c \ timestamps.c unicode.c usha.c compat.c OBJS = $(addprefix obj/$(CPU)/,$(SRCS:.c=.o)) .PHONY: all all: bin/libsmb2.a.$(CPU) obj/$(CPU)/%.o: %.c @mkdir -p $(dir $@) $(CC) $(CFLAGS) -c -o $@ $< bin/libsmb2.a.$(CPU): $(OBJS) @mkdir -p $(dir $@) $(AR) -crv $@ $^ $(RANLIB) $@ .PHONY: clean clean: rm -rf bin obj libsmb2-6.2/lib/smb2-data-filesystem-info.c0000664000175000017500000002757314732155517017634 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" int smb2_decode_file_fs_volume_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_volume_info *fs, struct smb2_iovec *vec) { uint64_t t; const char *name; smb2_get_uint64(vec, 0, &t); smb2_win_to_timeval(t, &fs->creation_time); smb2_get_uint32(vec, 8, &fs->volume_serial_number); smb2_get_uint32(vec, 12, &fs->volume_label_length); smb2_get_uint8(vec, 16, &fs->supports_objects); smb2_get_uint8(vec, 17, &fs->reserved); name = smb2_utf16_to_utf8((uint16_t *)&vec->buf[18], fs->volume_label_length / 2); fs->volume_label = smb2_alloc_data(smb2, memctx, strlen(name) + 1); if (fs->volume_label == NULL) { free(discard_const(name)); return -1; } strcpy(discard_const(fs->volume_label), name); free(discard_const(name)); return 0; } int smb2_encode_file_fs_volume_info(struct smb2_context *smb2, struct smb2_file_fs_volume_info *fs, struct smb2_iovec *vec) { uint64_t t; struct smb2_utf16 *name; t = smb2_timeval_to_win(&fs->creation_time); smb2_set_uint64(vec, 0, t); smb2_set_uint32(vec, 8, fs->volume_serial_number); smb2_set_uint8(vec, 16, fs->supports_objects); smb2_set_uint8(vec, 17, fs->reserved); name = smb2_utf8_to_utf16((char*)fs->volume_label); smb2_set_uint32(vec, 12, 2 * name->len); memcpy(&vec->buf[18], name->val, 2 * name->len); vec->len += 2 * name->len; free(name); return 0; } int smb2_decode_file_fs_size_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_size_info *fs, struct smb2_iovec *vec) { if (vec->len < 24) { return -1; } smb2_get_uint64(vec, 0, &fs->total_allocation_units); smb2_get_uint64(vec, 8, &fs->available_allocation_units); smb2_get_uint32(vec, 16, &fs->sectors_per_allocation_unit); smb2_get_uint32(vec, 20, &fs->bytes_per_sector); return 0; } int smb2_encode_file_fs_size_info(struct smb2_context *smb2, struct smb2_file_fs_size_info *fs, struct smb2_iovec *vec) { if (vec->len < 24) { return -1; } smb2_set_uint64(vec, 0, fs->total_allocation_units); smb2_set_uint64(vec, 8, fs->available_allocation_units); smb2_set_uint32(vec, 16, fs->sectors_per_allocation_unit); smb2_set_uint32(vec, 20, fs->bytes_per_sector); return 0; } int smb2_decode_file_fs_device_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_device_info *fs, struct smb2_iovec *vec) { if (vec->len < 8) { return -1; } smb2_get_uint32(vec, 0, &fs->device_type); smb2_get_uint32(vec, 4, &fs->characteristics); return 0; } int smb2_encode_file_fs_device_info(struct smb2_context *smb2, struct smb2_file_fs_device_info *fs, struct smb2_iovec *vec) { if (vec->len < 8) { return -1; } smb2_set_uint32(vec, 0, fs->device_type); smb2_set_uint32(vec, 4, fs->characteristics); return 0; } int smb2_decode_file_fs_attribute_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_attribute_info *fs, struct smb2_iovec *vec) { const char *name; uint32_t name_len; if (vec->len < 20) { return -1; } smb2_get_uint32(vec, 0, &fs->filesystem_attributes); smb2_get_uint32(vec, 4, &fs->maximum_component_name_length); smb2_get_uint32(vec, 8, &name_len); if (name_len > 0) { name = smb2_utf16_to_utf8((uint16_t*)&vec->buf[12], name_len / 2); if (!name) { return -1; } fs->filesystem_name = smb2_alloc_data(smb2, memctx, strlen(name) + 1); if (fs->filesystem_name == NULL) { free(discard_const(name)); return -1; } strcpy(discard_const(fs->filesystem_name), name); free(discard_const(name)); } return 0; } int smb2_encode_file_fs_attribute_info(struct smb2_context *smb2, struct smb2_file_fs_attribute_info *fs, struct smb2_iovec *vec) { struct smb2_utf16 *name; if (vec->len < 20) { return -1; } smb2_set_uint32(vec, 0, fs->filesystem_attributes); smb2_set_uint32(vec, 4, fs->maximum_component_name_length); name = smb2_utf8_to_utf16((char*)fs->filesystem_name); smb2_set_uint32(vec, 8, 2 * name->len); memcpy(&vec->buf[12], name->val, 2 * name->len); vec->len += 2 * name->len; free(name); return 0; } int smb2_decode_file_fs_control_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_control_info *fs, struct smb2_iovec *vec) { if (vec->len < 48) { return -1; } smb2_get_uint64(vec, 0, &fs->free_space_start_filtering); smb2_get_uint64(vec, 8, &fs->free_space_threshold); smb2_get_uint64(vec, 16, &fs->free_space_stop_filtering); smb2_get_uint64(vec, 24, &fs->default_quota_threshold); smb2_get_uint64(vec, 32, &fs->default_quota_limit); smb2_get_uint32(vec, 40, &fs->file_system_control_flags); return 0; } int smb2_encode_file_fs_control_info(struct smb2_context *smb2, struct smb2_file_fs_control_info *fs, struct smb2_iovec *vec) { if (vec->len < 48) { return -1; } smb2_set_uint64(vec, 0, fs->free_space_start_filtering); smb2_set_uint64(vec, 8, fs->free_space_threshold); smb2_set_uint64(vec, 16, fs->free_space_stop_filtering); smb2_set_uint64(vec, 24, fs->default_quota_threshold); smb2_set_uint64(vec, 32, fs->default_quota_limit); smb2_set_uint32(vec, 40, fs->file_system_control_flags); return 0; } int smb2_decode_file_fs_full_size_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_full_size_info *fs, struct smb2_iovec *vec) { if (vec->len < 32) { return -1; } smb2_get_uint64(vec, 0, &fs->total_allocation_units); smb2_get_uint64(vec, 8, &fs->caller_available_allocation_units); smb2_get_uint64(vec, 16, &fs->actual_available_allocation_units); smb2_get_uint32(vec, 24, &fs->sectors_per_allocation_unit); smb2_get_uint32(vec, 28, &fs->bytes_per_sector); return 0; } int smb2_encode_file_fs_full_size_info(struct smb2_context *smb2, struct smb2_file_fs_full_size_info *fs, struct smb2_iovec *vec) { if (vec->len < 32) { return -1; } smb2_set_uint64(vec, 0, fs->total_allocation_units); smb2_set_uint64(vec, 8, fs->caller_available_allocation_units); smb2_set_uint64(vec, 16, fs->actual_available_allocation_units); smb2_set_uint32(vec, 24, fs->sectors_per_allocation_unit); smb2_set_uint32(vec, 28, fs->bytes_per_sector); return 0; } int smb2_decode_file_fs_object_id_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_object_id_info *fs, struct smb2_iovec *vec) { if (vec->len < 64) { return -1; } memcpy(fs->object_id, &vec->buf[0], SMB2_GUID_SIZE); memcpy(fs->extended_info, &vec->buf[SMB2_GUID_SIZE], sizeof(fs->extended_info)); return 0; } int smb2_encode_file_fs_object_id_info(struct smb2_context *smb2, struct smb2_file_fs_object_id_info *fs, struct smb2_iovec *vec) { if (vec->len < 64) { return -1; } memcpy(&vec->buf[0], fs->object_id, SMB2_GUID_SIZE); memcpy(&vec->buf[SMB2_GUID_SIZE], fs->extended_info, sizeof(fs->extended_info)); return 0; } int smb2_decode_file_fs_sector_size_info(struct smb2_context *smb2, void *memctx, struct smb2_file_fs_sector_size_info *fs, struct smb2_iovec *vec) { if (vec->len < 28) { return -1; } smb2_get_uint32(vec, 0, &fs->logical_bytes_per_sector); smb2_get_uint32(vec, 4, &fs->physical_bytes_per_sector_for_atomicity); smb2_get_uint32(vec, 8, &fs->physical_bytes_per_sector_for_performance); smb2_get_uint32(vec, 12, &fs->file_system_effective_physical_bytes_per_sector_for_atomicity); smb2_get_uint32(vec, 16, &fs->flags); smb2_get_uint32(vec, 20, &fs->byte_offset_for_sector_alignment); smb2_get_uint32(vec, 24, &fs->byte_offset_for_partition_alignment); return 0; } int smb2_encode_file_fs_sector_size_info(struct smb2_context *smb2, struct smb2_file_fs_sector_size_info *fs, struct smb2_iovec *vec) { if (vec->len < 28) { return -1; } smb2_set_uint32(vec, 0, fs->logical_bytes_per_sector); smb2_set_uint32(vec, 4, fs->physical_bytes_per_sector_for_atomicity); smb2_set_uint32(vec, 8, fs->physical_bytes_per_sector_for_performance); smb2_set_uint32(vec, 12, fs->file_system_effective_physical_bytes_per_sector_for_atomicity); smb2_set_uint32(vec, 16, fs->flags); smb2_set_uint32(vec, 20, fs->byte_offset_for_sector_alignment); smb2_set_uint32(vec, 24, fs->byte_offset_for_partition_alignment); return 0; } libsmb2-6.2/lib/pdu.c0000664000175000017500000010263414732155517013527 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "portable-endian.h" #include "slist.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" #include "smb3-seal.h" #include "smb2-signing.h" int smb2_pad_to_64bit(struct smb2_context *smb2, struct smb2_io_vectors *v) { static uint8_t zero_bytes[7]; int i, len = 0; for (i = 0; i < v->niov; i++) { len += (int)v->iov[i].len; } if ((len & 0x07) == 0) { return 0; } if (smb2_add_iovector(smb2, v, &zero_bytes[0], 8 - (len & 0x07), NULL) == NULL) { return -1; } return 0; } #include struct smb2_pdu * smb2_allocate_pdu(struct smb2_context *smb2, enum smb2_command command, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; struct smb2_header *hdr; char magic[4] = {0xFE, 'S', 'M', 'B'}; pdu = calloc(1, sizeof(struct smb2_pdu)); if (pdu == NULL) { smb2_set_error(smb2, "Failed to allocate pdu"); return NULL; } hdr = &pdu->header; memcpy(hdr->protocol_id, magic, 4); /* ZERO out the signature * Signature calculation happens by zeroing out */ memset(hdr->signature, 0, 16); hdr->struct_size = SMB2_HEADER_SIZE; hdr->command = command; hdr->flags = 0; hdr->sync.process_id = 0xFEFF; if (smb2->dialect == SMB2_VERSION_0202) { hdr->credit_charge = 0; } else if (hdr->command == SMB2_NEGOTIATE) { /* We don't have any credits yet during negprot by * looking at traces. */ hdr->credit_charge = 0; } else { /* Assume the credits for this PDU will be 1. * READ/WRITE/IOCTL/QUERYDIR that consumes more than * 1 credit will adjusted this after it has marshalled the * fixed part of the PDU. */ hdr->credit_charge = 1; } hdr->credit_request_response = MAX_CREDITS - smb2->credits; switch (command) { case SMB2_NEGOTIATE: case SMB2_SESSION_SETUP: case SMB2_LOGOFF: case SMB2_ECHO: /* case SMB2_CANCEL: */ hdr->sync.tree_id = 0; break; case SMB2_TREE_CONNECT: /* [MS-SMB2] 2.2.1.2 */ hdr->sync.tree_id = 0; break; default: hdr->sync.tree_id = smb2_tree_id(smb2); break; } switch (command) { case SMB2_NEGOTIATE: break; default: hdr->session_id = smb2->session_id; } pdu->cb = cb; pdu->cb_data = cb_data; pdu->out.niov = 0; smb2_add_iovector(smb2, &pdu->out, pdu->hdr, SMB2_HEADER_SIZE, NULL); switch (command) { case SMB2_NEGOTIATE: case SMB2_SESSION_SETUP: break; default: if (smb2->seal) { pdu->seal = 1; } } if (smb2->timeout) { pdu->timeout = time(NULL) + smb2->timeout; } return pdu; } int smb2_select_tree_id(struct smb2_context *smb2, uint32_t tree_id) { int i; for ( i = 1; i <= smb2->tree_id_top && i <= SMB2_MAX_TREE_NESTING; i++ ) { if (smb2->tree_id[i] == tree_id) { break; } } if (i <= smb2->tree_id_top) { smb2->tree_id_cur = i; } else { smb2_set_error(smb2, "No connected tree-id %08X to select", tree_id); return -1; } return 0; } int smb2_get_tree_id_for_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu, uint32_t *tree_id) { if (pdu) { switch (pdu->header.command) { case SMB2_NEGOTIATE: case SMB2_SESSION_SETUP: case SMB2_LOGOFF: case SMB2_ECHO: /* case SMB2_CANCEL: */ case SMB2_TREE_CONNECT: *tree_id = 0; return 0; default: break; } } if (smb2->tree_id_top > 0) { *tree_id = smb2->tree_id[smb2->tree_id_cur]; } else { smb2_set_error(smb2, "No tree-id connected"); *tree_id = 0xdeadbeef; return -1; } return 0; } int smb2_set_tree_id_for_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu, uint32_t tree_id) { if (pdu) { if (pdu->header.flags & SMB2_FLAGS_ASYNC_COMMAND) { smb2_set_error(smb2, "no tree id for async pdu"); return 0; } switch (pdu->header.command) { case SMB2_NEGOTIATE: case SMB2_SESSION_SETUP: case SMB2_LOGOFF: case SMB2_ECHO: /* case SMB2_CANCEL: */ break; case SMB2_TREE_CONNECT: break; default: pdu->header.sync.tree_id = tree_id; } return 0; } return -1; } int smb2_connect_tree_id(struct smb2_context *smb2, uint32_t tree_id) { if (smb2->tree_id_top < (SMB2_MAX_TREE_NESTING - 1)) { smb2->tree_id[++smb2->tree_id_top] = tree_id; smb2->tree_id_cur = smb2->tree_id_top; } else { smb2_set_error(smb2, "Tree nesting too deep"); return -1; } return 0; } int smb2_disconnect_tree_id(struct smb2_context *smb2, uint32_t tree_id) { int i, j; if (smb2->tree_id_top > 0) { for ( i = 1; i <= smb2->tree_id_top && i <= SMB2_MAX_TREE_NESTING; i++ ) { if (smb2->tree_id[i] == tree_id) { break; } } if (i <= smb2->tree_id_top) { for (j = i; j < smb2->tree_id_top; j++) { smb2->tree_id[j] = smb2->tree_id[j + 1]; } smb2->tree_id_top--; /* not sure what tree id should be after a disconnect but * this makes sure its not invalid */ if (smb2->tree_id_cur > smb2->tree_id_top) { smb2->tree_id_cur = smb2->tree_id_top; } return 0; } } smb2_set_error(smb2, "No tree-id %08X to remove", tree_id); return -1; } int smb2_pdu_is_compound(struct smb2_context *smb2) { return (smb2) ? (smb2->hdr.next_command != 0) : 0; } void smb2_add_compound_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_pdu *next_pdu) { int i, offset; /* find the last pdu in the chain */ while (pdu->next_compound) { pdu = pdu->next_compound; } pdu->next_compound = next_pdu; /* Fixup the next offset in the header */ for (i = 0, offset = 0; i < pdu->out.niov; i++) { offset += (int)pdu->out.iov[i].len; } pdu->header.next_command = offset; smb2_set_uint32(&pdu->out.iov[0], 20, pdu->header.next_command); /* Fixup flags */ next_pdu->header.flags |= SMB2_FLAGS_RELATED_OPERATIONS; smb2_set_uint32(&next_pdu->out.iov[0], 16, next_pdu->header.flags); } void smb2_free_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu) { if (pdu->next_compound) { smb2_free_pdu(smb2, pdu->next_compound); } smb2_free_iovector(smb2, &pdu->out); smb2_free_iovector(smb2, &pdu->in); if (pdu->free_payload != NULL) { pdu->free_payload(smb2, pdu->payload); } free(pdu->payload); free(pdu->crypt); free(pdu); } int smb2_set_uint8(struct smb2_iovec *iov, int offset, uint8_t value) { if (offset + sizeof(uint8_t) > iov->len) { return -1; } iov->buf[offset] = value; return 0; } int smb2_set_uint16(struct smb2_iovec *iov, int offset, uint16_t value) { if (offset + sizeof(uint16_t) > iov->len) { return -1; } *(uint16_t *)(iov->buf + offset) = htole16(value); return 0; } int smb2_set_uint32(struct smb2_iovec *iov, int offset, uint32_t value) { if (offset + sizeof(uint32_t) > iov->len) { return -1; } *(uint32_t *)(iov->buf + offset) = htole32(value); return 0; } int smb2_set_uint64(struct smb2_iovec *iov, int offset, uint64_t value) { if (offset + sizeof(uint64_t) > iov->len) { return -1; } value = htole64(value); memcpy(iov->buf + offset, &value, 8); return 0; } int smb2_get_uint8(struct smb2_iovec *iov, int offset, uint8_t *value) { if (offset + sizeof(uint8_t) > iov->len) { return -1; } *value = iov->buf[offset]; return 0; } int smb2_get_uint16(struct smb2_iovec *iov, int offset, uint16_t *value) { uint16_t tmp; if (offset + sizeof(uint16_t) > iov->len) { return -1; } memcpy(&tmp, iov->buf + offset, sizeof(uint16_t)); *value = le16toh(tmp); return 0; } int smb2_get_uint32(struct smb2_iovec *iov, int offset, uint32_t *value) { uint32_t tmp; if (offset + sizeof(uint32_t) > iov->len) { return -1; } memcpy(&tmp, iov->buf + offset, sizeof(uint32_t)); *value = le32toh(tmp); return 0; } int smb2_get_uint64(struct smb2_iovec *iov, int offset, uint64_t *value) { uint64_t tmp; if (offset + sizeof(uint64_t) > iov->len) { return -1; } memcpy(&tmp, iov->buf + offset, sizeof(uint64_t)); *value = le64toh(tmp); return 0; } static void smb2_encode_header(struct smb2_context *smb2, struct smb2_iovec *iov, struct smb2_header *hdr) { if (!smb2_is_server(smb2)) { hdr->message_id = smb2->message_id++; if (hdr->credit_charge > 1) { smb2->message_id += (hdr->credit_charge - 1); } } memcpy(iov->buf, hdr->protocol_id, 4); smb2_set_uint16(iov, 4, hdr->struct_size); smb2_set_uint16(iov, 6, hdr->credit_charge); smb2_set_uint32(iov, 8, hdr->status); smb2_set_uint16(iov, 12, hdr->command); smb2_set_uint16(iov, 14, hdr->credit_request_response); smb2_set_uint32(iov, 16, hdr->flags); smb2_set_uint32(iov, 20, hdr->next_command); smb2_set_uint64(iov, 24, hdr->message_id); if (hdr->flags & SMB2_FLAGS_ASYNC_COMMAND) { smb2_set_uint64(iov, 32, hdr->async.async_id); } else { /* printf(">>>>>>>>>> %p %s %d treeid=%08x %08X\n", smb2, (hdr->flags & SMB2_FLAGS_SERVER_TO_REDIR) ? "rep" : "cmd", hdr->command, hdr->sync.tree_id, smb2_tree_id(smb2)); */ smb2_set_uint32(iov, 32, hdr->sync.process_id); smb2_set_uint32(iov, 36, hdr->sync.tree_id); } smb2_set_uint64(iov, 40, hdr->session_id); memcpy(iov->buf + 48, hdr->signature, 16); } int smb2_decode_header(struct smb2_context *smb2, struct smb2_iovec *iov, struct smb2_header *hdr) { static char smb1sign[4] = {0xFF, 'S', 'M', 'B'}; static char smb2sign[4] = {0xFE, 'S', 'M', 'B'}; if (iov->len < SMB2_HEADER_SIZE) { smb2_set_error(smb2, "io vector for header is too small"); return -1; } if (!memcmp(iov->buf, smb1sign, 4)) { /* an SMBv1 request. if it is a negotiate request * allow it through, else ingore */ if (iov->buf[4] == SMB1_NEGOTIATE) { /*printf("Handling SMBv1 Negotiate\n");*/ memset(hdr, 0, sizeof *hdr); hdr->command = SMB1_NEGOTIATE; return 0; } smb2_set_error(smb2, "not handling SMBv1 request"); return -1; } if (memcmp(iov->buf, smb2sign, 4)) { smb2_set_error(smb2, "bad SMB signature in header"); return -1; } memcpy(&hdr->protocol_id, iov->buf, 4); smb2_get_uint16(iov, 4, &hdr->struct_size); smb2_get_uint16(iov, 6, &hdr->credit_charge); smb2_get_uint32(iov, 8, &hdr->status); smb2_get_uint16(iov, 12, &hdr->command); smb2_get_uint16(iov, 14, &hdr->credit_request_response); smb2_get_uint32(iov, 16, &hdr->flags); smb2_get_uint32(iov, 20, &hdr->next_command); smb2_get_uint64(iov, 24, &hdr->message_id); if (hdr->flags & SMB2_FLAGS_ASYNC_COMMAND) { smb2_get_uint64(iov, 32, &hdr->async.async_id); } else { smb2_get_uint32(iov, 32, &hdr->sync.process_id); smb2_get_uint32(iov, 36, &hdr->sync.tree_id); /* printf("<<<<<<<<<<< %p %s %d treeid=%08x %08X\n", smb2, (hdr->flags & SMB2_FLAGS_SERVER_TO_REDIR) ? "rep" : "cmd", hdr->command, hdr->sync.tree_id, smb2_tree_id(smb2)); */ /* for requests, set the context tree id to the header value */ if (!(hdr->flags & SMB2_FLAGS_SERVER_TO_REDIR)) { switch (hdr->command) { case SMB2_NEGOTIATE: case SMB2_SESSION_SETUP: case SMB2_LOGOFF: case SMB2_ECHO: /* case SMB2_CANCEL: */ break; case SMB2_TREE_CONNECT: break; default: /* TODO - care about not having this already connected */ smb2_select_tree_id(smb2, hdr->sync.tree_id); break; } if (smb2_is_server(smb2)) { /* remember message id to format reply */ smb2->message_id = hdr->message_id; } } } smb2_get_uint64(iov, 40, &hdr->session_id); memcpy(&hdr->signature, iov->buf + 48, 16); return 0; } static void smb2_add_to_outqueue(struct smb2_context *smb2, struct smb2_pdu *pdu) { SMB2_LIST_ADD_END(&smb2->outqueue, pdu); smb2_change_events(smb2, smb2->fd, smb2_which_events(smb2)); } struct smb2_pdu * smb2_find_pdu_by_command(struct smb2_context *smb2, uint32_t command) { struct smb2_pdu *pdu; for (pdu = smb2->waitqueue; pdu; pdu = pdu->next) { if (pdu->header.command == command) { break; } } return pdu; } static int smb2_correlate_reply(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_pdu *req_pdu; int ret = 0; /* set reply flag */ pdu->header.flags |= SMB2_FLAGS_SERVER_TO_REDIR; req_pdu = smb2_find_pdu_by_command(smb2, pdu->header.command); if (req_pdu == NULL) { if (pdu->header.command != SMB2_OPLOCK_BREAK) { smb2_set_error(smb2, "no matching request PDU " "found for reply to cmd %d", pdu->header.command); return -1; } else { /* sending an unsolicited break */ pdu->header.message_id = 0xffffffffffffffffULL; pdu->header.sync.tree_id = 0; pdu->header.session_id = 0; } } else { SMB2_LIST_REMOVE(&smb2->waitqueue, req_pdu); pdu->header.credit_request_response = 64 + req_pdu->header.credit_charge; /* replies always have to have the same message-id and tree-id as * the request we sent, so use the request from the wait queue * to make sure that is the case. (exception is tree-connect where * the reply has the new tree-id and request was 0 ) */ pdu->header.message_id = req_pdu->header.message_id; if (pdu->header.command != SMB2_TREE_CONNECT) { pdu->header.sync.tree_id = req_pdu->header.sync.tree_id; } smb2_free_pdu(smb2, req_pdu); } return ret; } void smb2_queue_pdu(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_pdu *p; /* Update all the PDU headers in this chain */ for (p = pdu; p; p = p->next_compound) { if (smb2_is_server(smb2)) { if (!(pdu->header.flags & SMB2_FLAGS_ASYNC_COMMAND)) { smb2_correlate_reply(smb2, p); /* TODO - care about check reply failures? */ } } smb2_encode_header(smb2, &p->out.iov[0], &p->header); if (smb2->sign || (p->header.command == SMB2_TREE_CONNECT && smb2->dialect == SMB2_VERSION_0311 && !smb2->seal)) { if (smb2_pdu_add_signature(smb2, p) < 0) { smb2_set_error(smb2, "Failure to add " "signature. %s", smb2_get_error(smb2)); } } } smb3_encrypt_pdu(smb2, pdu); smb2_add_to_outqueue(smb2, pdu); } struct smb2_pdu * smb2_find_pdu(struct smb2_context *smb2, uint64_t message_id) { struct smb2_pdu *pdu; for (pdu = smb2->waitqueue; pdu; pdu = pdu->next) { if (pdu->header.message_id == message_id) { break; } } return pdu; } static int smb2_is_error_response(struct smb2_context *smb2, struct smb2_pdu *pdu) { if ((smb2->hdr.status & SMB2_STATUS_SEVERITY_MASK) == SMB2_STATUS_SEVERITY_ERROR) { switch (smb2->hdr.status) { case SMB2_STATUS_MORE_PROCESSING_REQUIRED: return 0; default: return 1; } } else if ((smb2->hdr.status & SMB2_STATUS_SEVERITY_MASK) == SMB2_STATUS_SEVERITY_WARNING) { switch(smb2->hdr.status) { case SMB2_STATUS_STOPPED_ON_SYMLINK: return 1; default: return 0; } } return 0; } int smb2_get_fixed_reply_size(struct smb2_context *smb2, struct smb2_pdu *pdu) { if (smb2_is_error_response(smb2, pdu)) { return SMB2_ERROR_REPLY_SIZE & 0xfffe; } switch (pdu->header.command) { case SMB2_NEGOTIATE: return SMB2_NEGOTIATE_REPLY_SIZE; case SMB2_SESSION_SETUP: return SMB2_SESSION_SETUP_REPLY_SIZE; case SMB2_LOGOFF: return SMB2_LOGOFF_REPLY_SIZE; case SMB2_TREE_CONNECT: return SMB2_TREE_CONNECT_REPLY_SIZE; case SMB2_TREE_DISCONNECT: return SMB2_TREE_DISCONNECT_REPLY_SIZE; case SMB2_CREATE: return SMB2_CREATE_REPLY_SIZE; case SMB2_CLOSE: return SMB2_CLOSE_REPLY_SIZE; case SMB2_FLUSH: return SMB2_FLUSH_REPLY_SIZE; case SMB2_READ: return SMB2_READ_REPLY_SIZE; case SMB2_WRITE: return SMB2_WRITE_REPLY_SIZE; case SMB2_LOCK: return SMB2_LOCK_REPLY_SIZE; case SMB2_ECHO: return SMB2_ECHO_REPLY_SIZE; case SMB2_QUERY_DIRECTORY: return SMB2_QUERY_DIRECTORY_REPLY_SIZE; case SMB2_CHANGE_NOTIFY: return SMB2_CHANGE_NOTIFY_REPLY_SIZE; case SMB2_QUERY_INFO: return SMB2_QUERY_INFO_REPLY_SIZE; case SMB2_SET_INFO: return SMB2_SET_INFO_REPLY_SIZE; case SMB2_IOCTL: return SMB2_IOCTL_REPLY_SIZE; case SMB2_OPLOCK_BREAK: /* need to read the struct size to see what * type (oplock or lease) the pdu is */ return sizeof(uint16_t); } return -1; } int smb2_get_fixed_request_size(struct smb2_context *smb2, struct smb2_pdu *pdu) { switch (pdu->header.command) { case SMB2_NEGOTIATE: return SMB2_NEGOTIATE_REQUEST_SIZE; case SMB2_SESSION_SETUP: return SMB2_SESSION_SETUP_REQUEST_SIZE; case SMB2_LOGOFF: return SMB2_LOGOFF_REQUEST_SIZE; case SMB2_TREE_CONNECT: return SMB2_TREE_CONNECT_REQUEST_SIZE; case SMB2_TREE_DISCONNECT: return SMB2_TREE_DISCONNECT_REQUEST_SIZE; case SMB2_CREATE: return SMB2_CREATE_REQUEST_SIZE; case SMB2_CLOSE: return SMB2_CLOSE_REQUEST_SIZE; case SMB2_FLUSH: return SMB2_FLUSH_REQUEST_SIZE; case SMB2_READ: return SMB2_READ_REQUEST_SIZE; case SMB2_WRITE: return SMB2_WRITE_REQUEST_SIZE; case SMB2_LOCK: return SMB2_LOCK_REQUEST_SIZE; case SMB2_CANCEL: return SMB2_CANCEL_REQUEST_SIZE; case SMB2_ECHO: return SMB2_ECHO_REQUEST_SIZE; case SMB2_QUERY_DIRECTORY: return SMB2_QUERY_DIRECTORY_REQUEST_SIZE; case SMB2_CHANGE_NOTIFY: return SMB2_CHANGE_NOTIFY_REQUEST_SIZE; case SMB2_QUERY_INFO: return SMB2_QUERY_INFO_REQUEST_SIZE; case SMB2_SET_INFO: return SMB2_SET_INFO_REQUEST_SIZE; case SMB2_IOCTL: return SMB2_IOCTL_REQUEST_SIZE; case SMB2_OPLOCK_BREAK: /* need to read the struct size to see what * type (oplock or lease) the pdu is */ return sizeof(uint16_t); } return -1; } int smb2_get_fixed_size(struct smb2_context *smb2, struct smb2_pdu *pdu) { if (smb2_is_server(smb2)) { return smb2_get_fixed_request_size(smb2, pdu); } else { return smb2_get_fixed_reply_size(smb2, pdu); } } int smb2_process_reply_payload_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { if (smb2_is_error_response(smb2, pdu)) { return smb2_process_error_fixed(smb2, pdu); } switch (pdu->header.command) { case SMB2_NEGOTIATE: return smb2_process_negotiate_fixed(smb2, pdu); case SMB2_SESSION_SETUP: return smb2_process_session_setup_fixed(smb2, pdu); case SMB2_LOGOFF: return smb2_process_logoff_fixed(smb2, pdu); case SMB2_TREE_CONNECT: return smb2_process_tree_connect_fixed(smb2, pdu); case SMB2_TREE_DISCONNECT: return smb2_process_tree_disconnect_fixed(smb2, pdu); case SMB2_CREATE: return smb2_process_create_fixed(smb2, pdu); case SMB2_CLOSE: return smb2_process_close_fixed(smb2, pdu); case SMB2_FLUSH: return smb2_process_flush_fixed(smb2, pdu); case SMB2_READ: return smb2_process_read_fixed(smb2, pdu); case SMB2_WRITE: return smb2_process_write_fixed(smb2, pdu); case SMB2_ECHO: return smb2_process_echo_fixed(smb2, pdu); case SMB2_LOCK: return smb2_process_lock_fixed(smb2, pdu); case SMB2_QUERY_DIRECTORY: return smb2_process_query_directory_fixed(smb2, pdu); case SMB2_CHANGE_NOTIFY: return smb2_process_change_notify_fixed(smb2, pdu); case SMB2_QUERY_INFO: return smb2_process_query_info_fixed(smb2, pdu); case SMB2_SET_INFO: return smb2_process_set_info_fixed(smb2, pdu); case SMB2_IOCTL: return smb2_process_ioctl_fixed(smb2, pdu); case SMB2_OPLOCK_BREAK: /* notice that op/lease lock breaks can be notification or response here */ return smb2_process_oplock_break_fixed(smb2, pdu); } return 0; } int smb2_process_reply_payload_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { if (smb2_is_error_response(smb2, pdu)) { return smb2_process_error_variable(smb2, pdu); } switch (pdu->header.command) { case SMB2_NEGOTIATE: return smb2_process_negotiate_variable(smb2, pdu); case SMB2_SESSION_SETUP: return smb2_process_session_setup_variable(smb2, pdu); case SMB2_LOGOFF: return 0; case SMB2_TREE_CONNECT: return 0; case SMB2_TREE_DISCONNECT: return 0; case SMB2_CREATE: return smb2_process_create_variable(smb2, pdu); case SMB2_CLOSE: return 0; case SMB2_FLUSH: return 0; case SMB2_READ: return smb2_process_read_variable(smb2, pdu); case SMB2_WRITE: return 0; case SMB2_ECHO: return 0; case SMB2_LOCK: return 0; case SMB2_CANCEL: return 0; case SMB2_QUERY_DIRECTORY: return smb2_process_query_directory_variable(smb2, pdu); case SMB2_CHANGE_NOTIFY: return smb2_process_change_notify_variable(smb2, pdu); case SMB2_QUERY_INFO: return smb2_process_query_info_variable(smb2, pdu); case SMB2_SET_INFO: return 0; case SMB2_IOCTL: return smb2_process_ioctl_variable(smb2, pdu); case SMB2_OPLOCK_BREAK: return smb2_process_oplock_break_variable(smb2, pdu); } return 0; } int smb2_process_request_payload_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { switch (pdu->header.command) { case SMB2_NEGOTIATE: return smb2_process_negotiate_request_fixed(smb2, pdu); case SMB2_SESSION_SETUP: return smb2_process_session_setup_request_fixed(smb2, pdu); case SMB2_LOGOFF: return smb2_process_logoff_request_fixed(smb2, pdu); case SMB2_TREE_CONNECT: return smb2_process_tree_connect_request_fixed(smb2, pdu); case SMB2_TREE_DISCONNECT: return 0; case SMB2_CREATE: return smb2_process_create_request_fixed(smb2, pdu); case SMB2_CLOSE: return smb2_process_close_request_fixed(smb2, pdu); case SMB2_FLUSH: return smb2_process_flush_request_fixed(smb2, pdu); case SMB2_READ: return smb2_process_read_request_fixed(smb2, pdu); case SMB2_WRITE: return smb2_process_write_request_fixed(smb2, pdu); case SMB2_ECHO: return smb2_process_echo_request_fixed(smb2, pdu); case SMB2_LOCK: return smb2_process_lock_request_fixed(smb2, pdu); case SMB2_CANCEL: return 0; case SMB2_QUERY_DIRECTORY: return smb2_process_query_directory_request_fixed(smb2, pdu); case SMB2_CHANGE_NOTIFY: return smb2_process_change_notify_request_fixed(smb2, pdu); case SMB2_QUERY_INFO: return smb2_process_query_info_request_fixed(smb2, pdu); case SMB2_SET_INFO: return smb2_process_set_info_request_fixed(smb2, pdu); case SMB2_IOCTL: return smb2_process_ioctl_request_fixed(smb2, pdu); case SMB2_OPLOCK_BREAK: /* note oplock/lease break from a client is an acknowlegement here */ return smb2_process_oplock_break_request_fixed(smb2, pdu); default: smb2_set_error(smb2, "No handler for fixed request"); return -1; } return 0; } int smb2_process_request_payload_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { switch (pdu->header.command) { case SMB2_NEGOTIATE: return smb2_process_negotiate_request_variable(smb2, pdu); case SMB2_SESSION_SETUP: return smb2_process_session_setup_request_variable(smb2, pdu); case SMB2_LOGOFF: return 0; case SMB2_TREE_CONNECT: return smb2_process_tree_connect_request_variable(smb2, pdu); case SMB2_TREE_DISCONNECT: return 0; case SMB2_CREATE: return smb2_process_create_request_variable(smb2, pdu); case SMB2_CLOSE: return 0; case SMB2_FLUSH: return 0; case SMB2_READ: return smb2_process_read_request_variable(smb2, pdu); case SMB2_WRITE: return smb2_process_write_request_variable(smb2, pdu); case SMB2_LOCK: return smb2_process_lock_request_variable(smb2, pdu); case SMB2_CANCEL: return 0; case SMB2_ECHO: return 0; case SMB2_QUERY_DIRECTORY: return smb2_process_query_directory_request_variable(smb2, pdu); case SMB2_CHANGE_NOTIFY: return 0; case SMB2_QUERY_INFO: return smb2_process_query_info_request_variable(smb2, pdu); case SMB2_SET_INFO: return smb2_process_set_info_request_variable(smb2, pdu); case SMB2_IOCTL: return smb2_process_ioctl_request_variable(smb2, pdu); case SMB2_OPLOCK_BREAK: return smb2_process_oplock_break_request_variable(smb2, pdu); default: smb2_set_error(smb2, "No handler for var request"); } return -1; } int smb2_process_payload_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { if (smb2_is_server(smb2)) { return smb2_process_request_payload_fixed(smb2, pdu); } else { return smb2_process_reply_payload_fixed(smb2, pdu); } } int smb2_process_payload_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { if (smb2_is_server(smb2)) { return smb2_process_request_payload_variable(smb2, pdu); } else { return smb2_process_reply_payload_variable(smb2, pdu); } } void smb2_timeout_pdus(struct smb2_context *smb2) { struct smb2_pdu *pdu, *next; time_t t = time(NULL); pdu = smb2->outqueue; while (pdu) { next = pdu->next; if (pdu->timeout && pdu->timeout < t) { SMB2_LIST_REMOVE(&smb2->outqueue, pdu); pdu->cb(smb2, SMB2_STATUS_IO_TIMEOUT, NULL, pdu->cb_data); smb2_free_pdu(smb2, pdu); } pdu = next; } pdu = smb2->waitqueue; while (pdu) { next = pdu->next; if (pdu->timeout && pdu->timeout < t) { SMB2_LIST_REMOVE(&smb2->waitqueue, pdu); pdu->cb(smb2, SMB2_STATUS_IO_TIMEOUT, NULL, pdu->cb_data); smb2_free_pdu(smb2, pdu); } pdu = next; } } libsmb2-6.2/lib/CMakeLists.txt0000664000175000017500000001512214732155517015326 0ustar polpypolpyif(GSSAPI_FOUND OR LIBKRB5_FOUND) set(KRB5_SOURCE krb5-wrapper.c) endif() if(ESP_PLATFORM) set(COMPONENT_SRCS aes.c aes128ccm.c alloc.c asn1-ber.c compat.c dcerpc.c dcerpc-lsa.c dcerpc-srvsvc.c errors.c init.c hmac.c hmac-md5.c ${KRB5_SOURCE} libsmb2.c md4c.c md5.c ntlmssp.c pdu.c sha1.c sha224-256.c sha384-512.c smb2-cmd-close.c smb2-cmd-create.c smb2-cmd-echo.c smb2-cmd-error.c smb2-cmd-flush.c smb2-cmd-ioctl.c smb2-cmd-lock.c smb2-cmd-logoff.c smb2-cmd-negotiate.c smb2-cmd-notify-change.c smb2-cmd-oplock-break.c smb2-cmd-query-directory.c smb2-cmd-query-info.c smb2-cmd-read.c smb2-cmd-session-setup.c smb2-cmd-set-info.c smb2-cmd-tree-connect.c smb2-cmd-tree-disconnect.c smb2-cmd-write.c smb2-data-file-info.c smb2-data-filesystem-info.c smb2-data-security-descriptor.c smb2-data-reparse-point.c smb2-share-enum.c smb3-seal.c smb2-signing.c socket.c spnego-wrapper.c sync.c timestamps.c unicode.c usha.c ) set(COMPONENT_NAME ".") register_component() elseif(IOP AND BUILD_IRX) set(SOURCES ps2/smb2_fio.c ps2/smb2man.c ps2/imports.c aes.c aes128ccm.c alloc.c asn1-ber.c compat.c dcerpc.c dcerpc-lsa.c dcerpc-srvsvc.c errors.c hmac.c hmac-md5.c init.c ${KRB5_SOURCE} libsmb2.c md4c.c md5.c ntlmssp.c pdu.c sha1.c sha224-256.c sha384-512.c smb2-cmd-close.c smb2-cmd-create.c smb2-cmd-echo.c smb2-cmd-error.c smb2-cmd-flush.c smb2-cmd-ioctl.c smb2-cmd-lock.c smb2-cmd-logoff.c smb2-cmd-negotiate.c smb2-cmd-notify-change.c smb2-cmd-oplock-break.c smb2-cmd-query-directory.c smb2-cmd-query-info.c smb2-cmd-read.c smb2-cmd-session-setup.c smb2-cmd-set-info.c smb2-cmd-tree-connect.c smb2-cmd-tree-disconnect.c smb2-cmd-write.c smb2-data-file-info.c smb2-data-filesystem-info.c smb2-data-security-descriptor.c smb2-data-reparse-point.c smb2-share-enum.c smb3-seal.c smb2-signing.c socket.c spnego-wrapper.c sync.c timestamps.c unicode.c usha.c) BUILD_IOP_IMPORTS(${CMAKE_CURRENT_SOURCE_DIR}/ps2/imports.c ${CMAKE_CURRENT_SOURCE_DIR}/ps2/imports.lst) else() set(SOURCES aes.c aes128ccm.c alloc.c asn1-ber.c compat.c dcerpc.c dcerpc-lsa.c dcerpc-srvsvc.c errors.c hmac.c hmac-md5.c init.c ${KRB5_SOURCE} libsmb2.c md4c.c md5.c ntlmssp.c pdu.c sha1.c sha224-256.c sha384-512.c smb2-cmd-close.c smb2-cmd-create.c smb2-cmd-echo.c smb2-cmd-error.c smb2-cmd-flush.c smb2-cmd-ioctl.c smb2-cmd-lock.c smb2-cmd-logoff.c smb2-cmd-negotiate.c smb2-cmd-notify-change.c smb2-cmd-oplock-break.c smb2-cmd-query-directory.c smb2-cmd-query-info.c smb2-cmd-read.c smb2-cmd-session-setup.c smb2-cmd-set-info.c smb2-cmd-tree-connect.c smb2-cmd-tree-disconnect.c smb2-cmd-write.c smb2-data-file-info.c smb2-data-filesystem-info.c smb2-data-security-descriptor.c smb2-data-reparse-point.c smb2-share-enum.c smb3-seal.c smb2-signing.c socket.c spnego-wrapper.c sync.c timestamps.c unicode.c usha.c) endif() if(NOT ESP_PLATFORM) set(INCLUDE_PATH ../include) set(SMB2_INCLUDE "${INCLUDE_PATH}/smb2") set(HEADERS ${SMB2_INCLUDE}/libsmb2-dcerpc-lsa.h ${SMB2_INCLUDE}/libsmb2-dcerpc-srvsvc.h ${SMB2_INCLUDE}/libsmb2-dcerpc.h ${SMB2_INCLUDE}/libsmb2-raw.h ${SMB2_INCLUDE}/libsmb2.h ${SMB2_INCLUDE}/smb2-errors.h ${SMB2_INCLUDE}/smb2.h) if(EE AND PS2RPC) add_library(smb2_rpc ${SOURCES} ${HEADERS}) target_link_libraries(smb2_rpc PUBLIC ${core_DEPENDS} ${CORE_LIBRARIES}) target_include_directories(smb2_rpc PUBLIC ${INCLUDE_PATH}) set_target_properties(smb2_rpc PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${SOVERSION}) elseif(IOP AND BUILD_IRX) add_executable(smb2man.irx ${SOURCES}) target_link_libraries(smb2man.irx PRIVATE gcc) set_target_properties(smb2man.irx PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${SOVERSION}) add_custom_command(TARGET smb2man.irx POST_BUILD COMMAND md5sum ARGS smb2man.irx) elseif(PICO_BOARD) add_library(libsmb2 STATIC ${SOURCES}) else() add_library(smb2 ${SOURCES} ${HEADERS}) target_link_libraries(smb2 PUBLIC ${core_DEPENDS} ${CORE_LIBRARIES}) target_include_directories(smb2 PUBLIC ${INCLUDE_PATH}) set_target_properties(smb2 PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${SOVERSION}) endif() endif() if(NOT MSVC) add_definitions("-D_U_=__attribute__((unused))") else() add_definitions("-D_U_=") if(CMAKE_SYSTEM_NAME STREQUAL WindowsStore) add_definitions("-D_MSC_UWP") endif() endif() if(NOT PICO_BOARD OR NOT ESP_PLATFORM) if(EE AND PS2RPC) install(TARGETS smb2_rpc EXPORT smb2_rpc RUNTIME DESTINATION bin ARCHIVE DESTINATION lib${LIB_SUFFIX} LIBRARY DESTINATION lib${LIB_SUFFIX}) elseif(IOP AND BUILD_IRX) install(FILES ps2/ps2smb2.h DESTINATION ${PS2SDK}/common/include) install(TARGETS smb2man.irx EXPORT smb2man.irx RUNTIME DESTINATION ${PS2SDK}/ports_iop/irx ARCHIVE DESTINATION smb2man.irx LIBRARY DESTINATION smb2man.irx) else() install(TARGETS smb2 EXPORT smb2 RUNTIME DESTINATION bin ARCHIVE DESTINATION lib${LIB_SUFFIX} LIBRARY DESTINATION lib${LIB_SUFFIX}) endif() endif() libsmb2-6.2/lib/smb2-cmd-flush.c0000664000175000017500000001230714732155517015457 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_flush_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_flush_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_FLUSH_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate flush buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_FLUSH_REQUEST_SIZE); memcpy(iov->buf + 8, req->file_id, SMB2_FD_SIZE); return 0; } struct smb2_pdu * smb2_cmd_flush_async(struct smb2_context *smb2, struct smb2_flush_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_FLUSH, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_flush_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_flush_reply(struct smb2_context *smb2, struct smb2_pdu *pdu) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_FLUSH_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate flush reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_FLUSH_REPLY_SIZE); return 0; } struct smb2_pdu * smb2_cmd_flush_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_FLUSH, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_flush_reply(smb2, pdu)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_flush_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_FLUSH_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of flush " "reply. Expected %d, got %d", SMB2_FLUSH_REPLY_SIZE, (int)iov->len); return -1; } return 0; } int smb2_process_flush_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_flush_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_FLUSH_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of flush " "request. Expected %d, got %d", SMB2_FLUSH_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate flush request"); return -1; } pdu->payload = req; return 0; } libsmb2-6.2/lib/krb5-wrapper.h0000664000175000017500000000522414732155517015262 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ #ifndef _KRB5_WRAPPER_H_ #define _KRB5_WRAPPER_H_ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LIBKRB5 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef __cplusplus extern "C" { #endif #if __APPLE__ #import #else #include static const gss_OID_desc gss_mech_spnego = { 6, "\x2b\x06\x01\x05\x05\x02" }; #endif static const gss_OID_desc spnego_mech_krb5 = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; static const gss_OID_desc spnego_mech_ntlmssp = { 10, "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" }; struct private_auth_data { gss_ctx_id_t context; gss_cred_id_t cred; gss_name_t user_name; gss_name_t target_name; gss_const_OID mech_type; uint32_t req_flags; gss_buffer_desc output_token; char *g_server; }; void krb5_free_auth_data(struct private_auth_data *auth); unsigned char * krb5_get_output_token_buffer(struct private_auth_data *auth_data); int krb5_get_output_token_length(struct private_auth_data *auth_data); struct private_auth_data * krb5_negotiate_reply(struct smb2_context *smb2, const char *server, const char *domain, const char *user_name, const char *password); int krb5_negotiate_request(struct smb2_context *smb2, void **neg_init_token); int krb5_session_get_session_key(struct smb2_context *smb2, struct private_auth_data *auth_data); int krb5_session_request(struct smb2_context *smb2, struct private_auth_data *auth_data, unsigned char *buf, int len); void krb5_set_gss_error(struct smb2_context *smb2, char *func, uint32_t maj, uint32_t min); #ifdef __cplusplus } #endif #endif /* HAVE_LIBKRB5 */ #endif /* _KRB5_WRAPPER_H_ */ libsmb2-6.2/lib/sha1.c0000664000175000017500000003036614732155517013575 0ustar polpypolpy/**************************** sha1.c ****************************/ /******************** See RFC 4634 for details ******************/ /* * Description: * This file implements the Secure Hash Signature Standard * algorithms as defined in the National Institute of Standards * and Technology Federal Information Processing Standards * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 * published on August 1, 2002, and the FIPS PUB 180-2 Change * Notice published on February 28, 2004. * * A combined document showing all algorithms is available at * http://csrc.nist.gov/publications/fips/ * fips180-2/fips180-2withchangenotice.pdf * * The SHA-1 algorithm produces a 160-bit message digest for a * given data stream. It should take about 2**n steps to find a * message with the same digest as a given message and * 2**(n/2) to find any two messages with the same digest, * when n is the digest size in bits. Therefore, this * algorithm can serve as a means of providing a * "fingerprint" for a message. * * Portability Issues: * SHA-1 is defined in terms of 32-bit "words". This code * uses (included via "sha.h") to define 32 and 8 * bit unsigned integer types. If your C compiler does not * support 32 bit unsigned integers, this code is not * appropriate. * * Caveats: * SHA-1 is designed to work with messages less than 2^64 bits * long. This implementation uses SHA1Input() to hash the bits * that are a multiple of the size of an 8-bit character, and then * uses SHA1FinalBits() to hash the final few bits of the input. */ #include "compat.h" #include "sha.h" #include "sha-private.h" #if defined(USE_SHA1) && USE_SHA1 /* * Define the SHA1 circular left shift macro */ #define SHA1_ROTL(bits,word) \ (((word) << (bits)) | ((word) >> (32-(bits)))) /* * add "length" to the length */ #define SHA1AddLength(context, length) \ (addTemp = (context)->Length_Low, \ (context)->Corrupted = \ (((context)->Length_Low += (length)) < addTemp) && \ (++(context)->Length_High == 0) ? 1 : 0) /* Local Function Prototypes */ static void SHA1Finalize (SHA1Context * context, uint8_t Pad_Byte); static void SHA1PadMessage (SHA1Context *, uint8_t Pad_Byte); static void SHA1ProcessMessageBlock (SHA1Context *); /* * SHA1Reset * * Description: * This function will initialize the SHA1Context in preparation * for computing a new SHA1 message digest. * * Parameters: * context: [in/out] * The context to reset. * * Returns: * sha Error Code. * */ int SHA1Reset (SHA1Context * context) { if (!context) return shaNull; context->Length_Low = 0; context->Length_High = 0; context->Message_Block_Index = 0; /* Initial Hash Values: FIPS-180-2 section 5.3.1 */ context->Intermediate_Hash[0] = 0x67452301; context->Intermediate_Hash[1] = 0xEFCDAB89; context->Intermediate_Hash[2] = 0x98BADCFE; context->Intermediate_Hash[3] = 0x10325476; context->Intermediate_Hash[4] = 0xC3D2E1F0; context->Computed = 0; context->Corrupted = 0; return shaSuccess; } /* * SHA1Input * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */ int SHA1Input (SHA1Context * context, const uint8_t * message_array, size_t length) { uint32_t addTemp; if (!length) return shaSuccess; if (!context || !message_array) return shaNull; if (context->Computed) { context->Corrupted = shaStateError; return shaStateError; } if (context->Corrupted) return context->Corrupted; while (length-- && !context->Corrupted) { context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF); if (!SHA1AddLength (context, 8) && (context->Message_Block_Index == SHA1_Message_Block_Size)) SHA1ProcessMessageBlock (context); message_array++; } return shaSuccess; } /* * SHA1FinalBits * * Description: * This function will add in any final bits of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_bits: [in] * The final bits of the message, in the upper portion of the * byte. (Use 0b###00000 instead of 0b00000### to input the * three bits ###.) * length: [in] * The number of bits in message_bits, between 1 and 7. * * Returns: * sha Error Code. */ int SHA1FinalBits (SHA1Context * context, const uint8_t message_bits, size_t length) { uint32_t addTemp; uint8_t masks[8] = { /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE }; uint8_t markbit[8] = { /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 }; if (!length) return shaSuccess; if (!context) return shaNull; if (context->Computed || (length >= 8) || (length == 0)) { context->Corrupted = shaStateError; return shaStateError; } if (context->Corrupted) return context->Corrupted; SHA1AddLength (context, length); SHA1Finalize (context, (uint8_t) ((message_bits & masks[length]) | markbit[length])); return shaSuccess; } /* * SHA1Result * * Description: * This function will return the 160-bit message digest into the * Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 19th element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA-1 hash. * Message_Digest: [out] * Where the digest is returned. * * Returns: * sha Error Code. * */ int SHA1Result (SHA1Context * context, uint8_t Message_Digest[SHA1HashSize]) { int i; if (!context || !Message_Digest) return shaNull; if (context->Corrupted) return context->Corrupted; if (!context->Computed) SHA1Finalize (context, 0x80); for (i = 0; i < SHA1HashSize; ++i) Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03))); return shaSuccess; } /* * SHA1Finalize * * Description: * This helper function finishes off the digest calculations. * * Parameters: * context: [in/out] * The SHA context to update * Pad_Byte: [in] * The last byte to add to the digest before the 0-padding * and length. This will contain the last bits of the message * followed by another single bit. If the message was an * exact multiple of 8-bits long, Pad_Byte will be 0x80. * * Returns: * sha Error Code. * */ static void SHA1Finalize (SHA1Context * context, uint8_t Pad_Byte) { int i; SHA1PadMessage (context, Pad_Byte); /* message may be sensitive, clear it out */ for (i = 0; i < SHA1_Message_Block_Size; ++i) context->Message_Block[i] = 0; context->Length_Low = 0; /* and clear length */ context->Length_High = 0; context->Computed = 1; } /* * SHA1PadMessage * * Description: * According to the standard, the message must be padded to an * even 512 bits. The first padding bit must be a '1'. The last * 64 bits represent the length of the original message. All bits * in between should be 0. This helper function will pad the * message according to those rules by filling the Message_Block * array accordingly. When it returns, it can be assumed that the * message digest has been computed. * * Parameters: * context: [in/out] * The context to pad * Pad_Byte: [in] * The last byte to add to the digest before the 0-padding * and length. This will contain the last bits of the message * followed by another single bit. If the message was an * exact multiple of 8-bits long, Pad_Byte will be 0x80. * * Returns: * Nothing. */ static void SHA1PadMessage (SHA1Context * context, uint8_t Pad_Byte) { /* * Check to see if the current message block is too small to hold * the initial padding bits and length. If so, we will pad the * block, process it, and then continue padding into a second * block. */ if (context->Message_Block_Index >= (SHA1_Message_Block_Size - 8)) { context->Message_Block[context->Message_Block_Index++] = Pad_Byte; while (context->Message_Block_Index < SHA1_Message_Block_Size) context->Message_Block[context->Message_Block_Index++] = 0; SHA1ProcessMessageBlock (context); } else context->Message_Block[context->Message_Block_Index++] = Pad_Byte; while (context->Message_Block_Index < (SHA1_Message_Block_Size - 8)) context->Message_Block[context->Message_Block_Index++] = 0; /* * Store the message length as the last 8 octets */ context->Message_Block[56] = (uint8_t) (context->Length_High >> 24); context->Message_Block[57] = (uint8_t) (context->Length_High >> 16); context->Message_Block[58] = (uint8_t) (context->Length_High >> 8); context->Message_Block[59] = (uint8_t) (context->Length_High); context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24); context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16); context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8); context->Message_Block[63] = (uint8_t) (context->Length_Low); SHA1ProcessMessageBlock (context); } /* * SHA1ProcessMessageBlock * * Description: * This helper function will process the next 512 bits of the * message stored in the Message_Block array. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * Many of the variable names in this code, especially the * single character names, were used because those were the * names used in the publication. */ static void SHA1ProcessMessageBlock (SHA1Context * context) { /* Constants defined in FIPS-180-2, section 4.2.1 */ const uint32_t K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; int t; /* Loop counter */ uint32_t temp; /* Temporary word value */ uint32_t W[80]; /* Word sequence */ uint32_t A, B, C, D, E; /* Word buffers */ /* * Initialize the first 16 words in the array W */ for (t = 0; t < 16; t++) { W[t] = ((uint32_t) context->Message_Block[t * 4]) << 24; W[t] |= ((uint32_t) context->Message_Block[t * 4 + 1]) << 16; W[t] |= ((uint32_t) context->Message_Block[t * 4 + 2]) << 8; W[t] |= ((uint32_t) context->Message_Block[t * 4 + 3]); } for (t = 16; t < 80; t++) W[t] = SHA1_ROTL (1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); A = context->Intermediate_Hash[0]; B = context->Intermediate_Hash[1]; C = context->Intermediate_Hash[2]; D = context->Intermediate_Hash[3]; E = context->Intermediate_Hash[4]; for (t = 0; t < 20; t++) { temp = SHA1_ROTL (5, A) + SHA_Ch (B, C, D) + E + W[t] + K[0]; E = D; D = C; C = SHA1_ROTL (30, B); B = A; A = temp; } for (t = 20; t < 40; t++) { temp = SHA1_ROTL (5, A) + SHA_Parity (B, C, D) + E + W[t] + K[1]; E = D; D = C; C = SHA1_ROTL (30, B); B = A; A = temp; } for (t = 40; t < 60; t++) { temp = SHA1_ROTL (5, A) + SHA_Maj (B, C, D) + E + W[t] + K[2]; E = D; D = C; C = SHA1_ROTL (30, B); B = A; A = temp; } for (t = 60; t < 80; t++) { temp = SHA1_ROTL (5, A) + SHA_Parity (B, C, D) + E + W[t] + K[3]; E = D; D = C; C = SHA1_ROTL (30, B); B = A; A = temp; } context->Intermediate_Hash[0] += A; context->Intermediate_Hash[1] += B; context->Intermediate_Hash[2] += C; context->Intermediate_Hash[3] += D; context->Intermediate_Hash[4] += E; context->Message_Block_Index = 0; } #endif /* defined(USE_SHA1) && USE_SHA1 */ libsmb2-6.2/lib/smb2-share-enum.c0000664000175000017500000001257014732155517015643 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-dcerpc.h" #include "libsmb2-dcerpc-srvsvc.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" struct smb2nse { smb2_command_cb cb; void *cb_data; union { struct srvsvc_NetrShareEnum_req se_req; }; }; static void nse_free(struct smb2nse *nse) { free(discard_const(nse->se_req.ServerName.utf8)); free(nse); } static void srvsvc_ioctl_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct smb2nse *nse = cb_data; struct srvsvc_rep *rep = command_data; struct smb2_context *smb2 = dcerpc_get_smb2_context(dce); if (status != SMB2_STATUS_SUCCESS) { nse->cb(smb2, status, NULL, nse->cb_data); nse_free(nse); dcerpc_destroy_context(dce); return; } nse->cb(smb2, rep->status, rep, nse->cb_data); nse_free(nse); dcerpc_destroy_context(dce); } static void share_enum_bind_cb(struct dcerpc_context *dce, int status, void *command_data, void *cb_data) { struct smb2nse *nse = cb_data; struct smb2_context *smb2 = dcerpc_get_smb2_context(dce); if (status != SMB2_STATUS_SUCCESS) { nse->cb(smb2, status, NULL, nse->cb_data); nse_free(nse); dcerpc_destroy_context(dce); return; } status = dcerpc_call_async(dce, SRVSVC_NETRSHAREENUM, srvsvc_NetrShareEnum_req_coder, &nse->se_req, srvsvc_NetrShareEnum_rep_coder, sizeof(struct srvsvc_NetrShareEnum_rep), srvsvc_ioctl_cb, nse); if (status) { nse->cb(smb2, status, NULL, nse->cb_data); nse_free(nse); dcerpc_destroy_context(dce); return; } } int smb2_share_enum_async(struct smb2_context *smb2, enum SHARE_INFO_enum level, smb2_command_cb cb, void *cb_data) { struct dcerpc_context *dce; struct smb2nse *nse; int rc; char *server; dce = dcerpc_create_context(smb2); if (dce == NULL) { return -ENOMEM; } nse = calloc(1, sizeof(struct smb2nse)); if (nse == NULL) { smb2_set_error(smb2, "Failed to allocate nse"); dcerpc_destroy_context(dce); return -ENOMEM; } nse->cb = cb; nse->cb_data = cb_data; server = malloc(strlen(smb2->server) + 3); if (server == NULL) { free(nse); smb2_set_error(smb2, "Failed to allocate server"); dcerpc_destroy_context(dce); return -ENOMEM; } sprintf(server, "\\\\%s", smb2->server); nse->se_req.ServerName.utf8 = server; switch (level) { case SHARE_INFO_0: nse->se_req.ses.Level = level; nse->se_req.ses.ShareInfo.Level = level; nse->se_req.ses.ShareInfo.Level0.EntriesRead = 0; nse->se_req.ses.ShareInfo.Level0.Buffer = NULL; break; case SHARE_INFO_1: nse->se_req.ses.Level = level; nse->se_req.ses.ShareInfo.Level = level; nse->se_req.ses.ShareInfo.Level1.EntriesRead = 0; nse->se_req.ses.ShareInfo.Level1.Buffer = NULL; break; } nse->se_req.PreferedMaximumLength = 0xffffffff; nse->se_req.ResumeHandle = 0; rc = dcerpc_connect_context_async(dce, "srvsvc", &srvsvc_interface, share_enum_bind_cb, nse); if (rc) { nse_free(nse); dcerpc_destroy_context(dce); return rc; } return 0; } libsmb2-6.2/lib/smb2-cmd-echo.c0000664000175000017500000001171014732155517015251 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_echo_request(struct smb2_context *smb2, struct smb2_pdu *pdu) { uint8_t *buf; int len; struct smb2_iovec *iov; len = SMB2_ECHO_REQUEST_SIZE; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate echo buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_ECHO_REQUEST_SIZE); return 0; } struct smb2_pdu * smb2_cmd_echo_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_ECHO, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_echo_request(smb2, pdu)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_echo_reply(struct smb2_context *smb2, struct smb2_pdu *pdu) { uint8_t *buf; int len; struct smb2_iovec *iov; len = SMB2_ECHO_REPLY_SIZE; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate echo buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_ECHO_REPLY_SIZE); return 0; } struct smb2_pdu * smb2_cmd_echo_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_ECHO, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_echo_reply(smb2, pdu)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_echo_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_ECHO_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of echo " "reply. Expected %d, got %d", SMB2_ECHO_REPLY_SIZE, (int)iov->len); return -1; } return 0; } int smb2_process_echo_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_echo_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_ECHO_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of echo " "request. Expected %d, got %d", SMB2_ECHO_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate echo request"); return -1; } pdu->payload = req; return 0; } libsmb2-6.2/lib/smb2-data-file-info.c0000664000175000017500000002226414732155517016357 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2017 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" int smb2_decode_file_basic_info(struct smb2_context *smb2, void *memctx, struct smb2_file_basic_info *fs, struct smb2_iovec *vec) { uint64_t t; smb2_get_uint64(vec, 0, &t); smb2_win_to_timeval(t, &fs->creation_time); smb2_get_uint64(vec, 8, &t); smb2_win_to_timeval(t, &fs->last_access_time); smb2_get_uint64(vec, 16, &t); smb2_win_to_timeval(t, &fs->last_write_time); smb2_get_uint64(vec, 24, &t); smb2_win_to_timeval(t, &fs->change_time); smb2_get_uint32(vec, 32, &fs->file_attributes); return 0; } static uint64_t smb2_tv_timeval_to_win(struct smb2_timeval *tv){ if (tv->tv_sec == 0 && tv->tv_usec == 0) { return 0; } else if (tv->tv_sec == 0xffffffff && tv->tv_usec == 0xffffffff) { return 0xffffffffffffffffULL; } return smb2_timeval_to_win(tv); } int smb2_encode_file_basic_info(struct smb2_context *smb2, struct smb2_file_basic_info *fs, struct smb2_iovec *vec) { uint64_t t; t = smb2_tv_timeval_to_win(&fs->creation_time); smb2_set_uint64(vec, 0, t); t = smb2_tv_timeval_to_win(&fs->last_access_time); smb2_set_uint64(vec, 8, t); t = smb2_tv_timeval_to_win(&fs->last_write_time); smb2_set_uint64(vec, 16, t); t = smb2_tv_timeval_to_win(&fs->change_time); smb2_set_uint64(vec, 24, t); smb2_set_uint32(vec, 32, fs->file_attributes); smb2_set_uint32(vec, 36, 0); return 40; } int smb2_decode_file_standard_info(struct smb2_context *smb2, void *memctx, struct smb2_file_standard_info *fs, struct smb2_iovec *vec) { smb2_get_uint64(vec, 0, &fs->allocation_size); smb2_get_uint64(vec, 8, &fs->end_of_file); smb2_get_uint32(vec, 16, &fs->number_of_links); smb2_get_uint8(vec, 20, &fs->delete_pending); smb2_get_uint8(vec, 21, &fs->directory); return 0; } int smb2_encode_file_standard_info(struct smb2_context *smb2, struct smb2_file_standard_info *fs, struct smb2_iovec *vec) { smb2_set_uint64(vec, 0, fs->allocation_size); smb2_set_uint64(vec, 8, fs->end_of_file); smb2_set_uint32(vec, 16, fs->number_of_links); smb2_set_uint8(vec, 20, fs->delete_pending); smb2_set_uint8(vec, 21, fs->directory); smb2_set_uint16(vec, 22, 0); return 24; } int smb2_decode_file_position_info(struct smb2_context *smb2, void *memctx, struct smb2_file_position_info *fs, struct smb2_iovec *vec) { smb2_get_uint64(vec, 0, &fs->current_byte_offset); return 0; } int smb2_encode_file_position_info(struct smb2_context *smb2, struct smb2_file_position_info *fs, struct smb2_iovec *vec) { smb2_set_uint64(vec, 0, fs->current_byte_offset); return 8; } int smb2_decode_file_all_info(struct smb2_context *smb2, void *memctx, struct smb2_file_all_info *fs, struct smb2_iovec *vec) { struct smb2_iovec v _U_; uint32_t name_len; const char *name; if (vec->len < 40) { return -1; } v.buf = &vec->buf[0]; v.len = 40; smb2_decode_file_basic_info(smb2, memctx, &fs->basic, &v); if (vec->len < 64) { return -1; } v.buf = &vec->buf[40]; v.len = 24; smb2_decode_file_standard_info(smb2, memctx, &fs->standard, &v); smb2_get_uint64(vec, 64, &fs->index_number); smb2_get_uint32(vec, 72, &fs->ea_size); smb2_get_uint32(vec, 76, &fs->access_flags); smb2_get_uint64(vec, 80, &fs->current_byte_offset); smb2_get_uint32(vec, 88, &fs->mode); smb2_get_uint32(vec, 92, &fs->alignment_requirement); smb2_get_uint32(vec, 96, &name_len); if (name_len > 0) { name = smb2_utf16_to_utf8((uint16_t *)&vec->buf[100], name_len / 2); fs->name = smb2_alloc_data(smb2, memctx, strlen(name) + 1); if (fs->name == NULL) { free(discard_const(name)); return -1; } strcpy(discard_const(fs->name), name); free(discard_const(name)); } else { fs->name = NULL; } return 0; } int smb2_encode_file_all_info(struct smb2_context *smb2, struct smb2_file_all_info *fs, struct smb2_iovec *vec) { struct smb2_iovec v _U_; struct smb2_utf16 *name = NULL; int name_len; if (vec->len < 40) { return -1; } v.buf = &vec->buf[0]; v.len = 40; smb2_encode_file_basic_info(smb2, &fs->basic, &v); if (vec->len < 64) { return -1; } v.buf = &vec->buf[40]; v.len = 24; smb2_encode_file_standard_info(smb2, &fs->standard, &v); smb2_set_uint64(vec, 64, fs->index_number); smb2_set_uint32(vec, 72, fs->ea_size); smb2_set_uint32(vec, 76, fs->access_flags); smb2_set_uint64(vec, 80, fs->current_byte_offset); smb2_set_uint32(vec, 88, fs->mode); smb2_set_uint32(vec, 92, fs->alignment_requirement); if (fs->name) { name = smb2_utf8_to_utf16((const char*)fs->name); if (name) { name_len = 2 * name->len; smb2_set_uint32(vec, 96, name_len); memcpy((uint16_t *)&vec->buf[100], name->val, name_len); free(name); return 100 + name_len; } else { return -1; } } else { smb2_set_uint32(vec, 96, 0); return 100; } } int smb2_decode_file_network_open_info(struct smb2_context *smb2, void *memctx, struct smb2_file_network_open_info *fs, struct smb2_iovec *vec) { uint64_t t; if (vec->len < 56) { return -1; } smb2_get_uint64(vec, 0, &t); smb2_win_to_timeval(t, &fs->creation_time); smb2_get_uint64(vec, 8, &t); smb2_win_to_timeval(t, &fs->last_access_time); smb2_get_uint64(vec, 16, &t); smb2_win_to_timeval(t, &fs->last_write_time); smb2_get_uint64(vec, 24, &t); smb2_win_to_timeval(t, &fs->change_time); smb2_get_uint64(vec, 32, &fs->allocation_size); smb2_get_uint64(vec, 40, &fs->end_of_file); smb2_get_uint32(vec, 48, &fs->file_attributes); return 0; } int smb2_encode_file_network_open_info(struct smb2_context *smb2, struct smb2_file_network_open_info *fs, struct smb2_iovec *vec) { uint64_t t; if (vec->len < 56) { return -1; } t = smb2_tv_timeval_to_win(&fs->creation_time); smb2_set_uint64(vec, 0, t); t = smb2_tv_timeval_to_win(&fs->last_access_time); smb2_set_uint64(vec, 8, t); t = smb2_tv_timeval_to_win(&fs->last_write_time); smb2_set_uint64(vec, 16, t); t = smb2_tv_timeval_to_win(&fs->change_time); smb2_set_uint64(vec, 24, t); smb2_set_uint64(vec, 32, fs->allocation_size); smb2_set_uint64(vec, 40, fs->end_of_file); smb2_set_uint32(vec, 48, fs->file_attributes); return 52; } libsmb2-6.2/lib/compat.h0000664000175000017500000004213214732155517014223 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2020 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifndef _COMPAT_H_ #define _COMPAT_H_ #ifdef __cplusplus extern "C" { #endif #if defined(_XBOX) || defined(_WINDOWS) || defined(__MINGW32__) #if defined(_WINDOWS) || defined(__MINGW32__) #include #ifdef __USE_WINSOCK__ #include #else #include #include #endif #elif defined(_XBOX) #include #include #endif typedef SOCKET t_socket; #ifndef INVALID_SOCKET #define INVALID_SOCKET (t_socket)(~0) #endif #define SMB2_INVALID_SOCKET INVALID_SOCKET #define SMB2_VALID_SOCKET(sock) ((sock) != SMB2_INVALID_SOCKET) #else typedef int t_socket; #define SMB2_VALID_SOCKET(sock) ((sock) >= 0) #define SMB2_INVALID_SOCKET -1 #endif #if defined(_XBOX) || defined(_WINDOWS) || defined(__MINGW32__) #include #include #ifdef __USE_WINSOCK__ #include #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif /* !WIN32_LEAN_AND_MEAN */ #ifdef XBOX_PLATFORM /* MSVC 2003 and Xbox XDK Doesn´t have stdint.h header */ typedef char int8_t; typedef short int16_t; typedef short int_least16_t; typedef int int32_t; typedef long long int64_t; typedef int intptr_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef unsigned int uint_t; typedef unsigned int uintptr_t; #endif #ifndef ENETRESET #define ENETRESET WSAENETRESET #endif #ifndef ECONNREFUSED #define ECONNREFUSED WSAECONNREFUSED #endif #ifndef ETIMEDOUT #define ETIMEDOUT WSAETIMEDOUT #endif #ifndef ECONNRESET #define ECONNRESET WSAECONNRESET #endif #ifndef ENODATA #define ENODATA WSANO_DATA #endif #ifndef ETXTBSY #define ETXTBSY 139 #endif #ifndef ENOLINK #define ENOLINK 121 #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK #endif #ifndef EBADF #define EBADF WSAENOTSOCK #endif #if defined(_XBOX) || defined(__MINGW32__) #define snprintf _snprintf int gethostname(char* name, size_t len); #endif #ifndef EAI_AGAIN #define EAI_AGAIN EAGAIN #endif #ifndef EAI_FAIL #define EAI_FAIL 4 #endif #ifndef EAI_MEMORY #define EAI_MEMORY 6 #endif #ifndef EAI_NONAME #define EAI_NONAME 8 #endif #ifndef EAI_SERVICE #define EAI_SERVICE 9 #endif #if defined(_XBOX) || defined(__USE_WINSOCK__) typedef int socklen_t; #endif #ifndef POLLIN #define POLLIN 0x0001 /* There is data to read */ #endif #ifndef POLLPRI #define POLLPRI 0x0002 /* There is urgent data to read */ #endif #ifndef POLLOUT #define POLLOUT 0x0004 /* Writing now will not block */ #endif #ifndef POLLERR #define POLLERR 0x0008 /* Error condition */ #endif #ifndef POLLHUP #define POLLHUP 0x0010 /* Hung up */ #endif #ifndef SO_ERROR #define SO_ERROR 0x1007 #endif #if defined(_XBOX) || defined(__USE_WINSOCK__) struct sockaddr_storage { #ifdef HAVE_SOCKADDR_SA_LEN unsigned char ss_len; #endif /* HAVE_SOCKADDR_SA_LEN */ unsigned char ss_family; unsigned char fill[127]; }; struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; /* XBOX Defs end */ struct pollfd { t_socket fd; short events; short revents; }; #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif #ifdef _XBOX #define inline __inline #endif #endif typedef SSIZE_T ssize_t; struct iovec { unsigned long iov_len; /* from WSABUF */ void *iov_base; }; #if defined(_XBOX) || defined(__USE_WINSOCK__) int poll(struct pollfd *fds, unsigned int nfds, int timo); #ifdef __USE_WINSOCK__ #define write(fd, buf, maxcount) _write(fd, buf, (unsigned int)maxcount) #define read(fd, buf, maxcount) _read(fd, buf, (unsigned int)maxcount) #endif int smb2_getaddrinfo(const char *node, const char*service, const struct addrinfo *hints, struct addrinfo **res); void smb2_freeaddrinfo(struct addrinfo *res); #define getaddrinfo smb2_getaddrinfo #define freeaddrinfo smb2_freeaddrinfo #else #undef poll #define poll WSAPoll #endif #ifdef __USE_WINSOCK__ ssize_t writev(t_socket fd, const struct iovec* vector, int count); ssize_t readv(t_socket fd, const struct iovec* vector, int count); #else inline int writev(t_socket sock, struct iovec *iov, int nvecs) { DWORD ret; int res = WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL); if (res == 0) { return (int)ret; } return -1; } inline int readv(t_socket sock, struct iovec *iov, int nvecs) { DWORD ret; DWORD flags = 0; int res = WSARecv(sock, (LPWSABUF)iov, nvecs, &ret, &flags, NULL, NULL); if (res == 0) { return (int)ret; } return -1; } #endif #ifdef __USE_WINSOCK__ #define close(x) _close((int)x) #else #define close closesocket #endif void srandom(unsigned int seed); int random(void); int getlogin_r(char *buf, size_t size); int getpid(); #pragma warning( disable : 4090 ) #define strdup _strdup #ifdef _XBOX /* just pretend they are the same so we compile */ #define sockaddr_in6 sockaddr_in #endif #endif /* _XBOX */ #ifdef PICO_PLATFORM #include "lwip/netdb.h" #include "lwip/sockets.h" #ifndef SOL_TCP #define SOL_TCP 6 #endif #define EAI_AGAIN EAGAIN long long int be64toh(long long int x); int getlogin_r(char *buf, size_t size); #endif /* PICO_PLATFORM */ #ifdef __DREAMCAST__ #include #include #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif ssize_t writev(t_socket fd, const struct iovec *iov, int iovcnt); ssize_t readv(t_socket fd, const struct iovec *iov, int iovcnt); int getlogin_r(char *buf, size_t size); #endif /* __DREAMCAST__ */ #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) #include #include #include #include #include #if defined(__amigaos4__) || defined(__AROS__) #include #endif int getlogin_r(char *buf, size_t size); #if !defined(__amigaos4__) && (defined(__AMIGA__) || defined(__AROS__)) #include #undef HAVE_UNISTD_H #define close CloseSocket #undef getaddrinfo #undef freeaddrinfo #endif #define strncpy(a,b,c) strcpy(a,b) #define POLLIN 0x0001 /* There is data to read */ #define POLLPRI 0x0002 /* There is urgent data to read */ #define POLLOUT 0x0004 /* Writing now will not block */ #define POLLERR 0x0008 /* Error condition */ #define POLLHUP 0x0010 /* Hung up */ struct pollfd { int fd; short events; short revents; }; #ifndef HAVE_ADDRINFO struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; #endif int poll(struct pollfd *fds, unsigned int nfds, int timo); int smb2_getaddrinfo(const char *node, const char*service, const struct addrinfo *hints, struct addrinfo **res); void smb2_freeaddrinfo(struct addrinfo *res); #define getaddrinfo smb2_getaddrinfo #define freeaddrinfo smb2_freeaddrinfo #ifndef __amigaos4__ ssize_t writev(t_socket fd, const struct iovec *iov, int iovcnt); ssize_t readv(t_socket fd, const struct iovec *iov, int iovcnt); #endif #if !defined(HAVE_SOCKADDR_STORAGE) /* * RFC 2553: protocol-independent placeholder for socket addresses */ #define _SS_MAXSIZE 128 #define _SS_ALIGNSIZE (sizeof(double)) #define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(unsigned char) * 2) #define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(unsigned char) * 2 - \ _SS_PAD1SIZE - _SS_ALIGNSIZE) struct sockaddr_storage { #ifdef HAVE_SOCKADDR_LEN unsigned char ss_len; /* address length */ unsigned char ss_family; /* address family */ #else unsigned short ss_family; #endif char __ss_pad1[_SS_PAD1SIZE]; double __ss_align; /* force desired structure storage alignment */ char __ss_pad2[_SS_PAD2SIZE]; }; #endif #ifndef EAI_AGAIN #define EAI_AGAIN EAGAIN #endif #ifndef EAI_FAIL #define EAI_FAIL 4 #endif #ifndef EAI_MEMORY #define EAI_MEMORY 6 #endif #ifndef EAI_NONAME #define EAI_NONAME 8 #endif #ifndef EAI_SERVICE #define EAI_SERVICE 9 #endif #endif #ifdef __PS2__ #ifdef _EE #include #else #ifndef __ps2sdk_iop__ #include #endif #include #include #include #endif #ifdef PS2RPC #include #else #include #endif #ifdef _IOP typedef uint32_t UWORD32; typedef size_t ssize_t; #include #endif long long int be64toh(long long int x); #ifdef _IOP char *strdup(const char *s); int gethostname(char *name, size_t len); int random(void); void srandom(unsigned int seed); time_t time(time_t *tloc); int asprintf(char **strp, const char *fmt, ...); #endif int getlogin_r(char *buf, size_t size); #ifdef _IOP int getpid(); #define close(x) lwip_close(x) #define snprintf(format, n, ...) sprintf(format, __VA_ARGS__) #define fcntl(a,b,c) lwip_fcntl(a,b,c) #endif #ifndef POLLIN #define POLLIN 0x0001 /* There is data to read */ #endif #ifndef POLLPRI #define POLLPRI 0x0002 /* There is urgent data to read */ #endif #ifndef POLLOUT #define POLLOUT 0x0004 /* Writing now will not block */ #endif #ifndef POLLERR #define POLLERR 0x0008 /* Error condition */ #endif #ifndef POLLHUP #define POLLHUP 0x0010 /* Hung up */ #endif struct pollfd { int fd; short events; short revents; }; int poll(struct pollfd *fds, unsigned int nfds, int timo); struct iovec { void *iov_base; size_t iov_len; }; #ifdef _IOP #undef connect #define connect(a,b,c) iop_connect(a,b,c) int iop_connect(int sockfd, struct sockaddr *addr, socklen_t addrlen); #define write(a,b,c) lwip_send(a,b,c,MSG_DONTWAIT) #define read(a,b,c) lwip_recv(a,b,c,MSG_DONTWAIT) #endif #ifdef __ps2sdk_iop__ void *malloc(int size); void free(void *ptr); void *calloc(size_t nmemb, size_t size); #endif ssize_t writev(t_socket fd, const struct iovec *iov, int iovcnt); ssize_t readv(t_socket fd, const struct iovec *iov, int iovcnt); #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif #ifndef EAI_AGAIN #define EAI_AGAIN EAGAIN #endif #ifdef _IOP #define strerror(x) "Unknown" #endif /* just pretend they are the same so we compile */ #define sockaddr_in6 sockaddr_in #endif /* __PS2__ */ #ifdef PS3_PPU_PLATFORM #include #include #include int getlogin_r(char *buf, size_t size); void srandom(unsigned int seed); int random(void); #define getaddrinfo smb2_getaddrinfo #define freeaddrinfo smb2_freeaddrinfo #define TCP_NODELAY 1 /* Don't delay send to coalesce packets */ #define EAI_FAIL 4 #define EAI_MEMORY 6 #define EAI_NONAME 8 #define EAI_SERVICE 9 int smb2_getaddrinfo(const char *node, const char*service, const struct addrinfo *hints, struct addrinfo **res); void smb2_freeaddrinfo(struct addrinfo *res); ssize_t writev(t_socket fd, const struct iovec *iov, int iovcnt); ssize_t readv(t_socket fd, const struct iovec *iov, int iovcnt); #define SOL_TCP IPPROTO_TCP #define EAI_AGAIN EAGAIN #if !defined(HAVE_SOCKADDR_STORAGE) /* * RFC 2553: protocol-independent placeholder for socket addresses */ #define _SS_MAXSIZE 128 #define _SS_ALIGNSIZE (sizeof(double)) #define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(unsigned char) * 2) #define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(unsigned char) * 2 - \ _SS_PAD1SIZE - _SS_ALIGNSIZE) struct sockaddr_storage { #ifdef HAVE_SOCKADDR_LEN unsigned char ss_len; /* address length */ unsigned char ss_family; /* address family */ #else unsigned short ss_family; #endif char __ss_pad1[_SS_PAD1SIZE]; double __ss_align; /* force desired structure storage alignment */ char __ss_pad2[_SS_PAD2SIZE]; }; #endif /* just pretend they are the same so we compile */ #define sockaddr_in6 sockaddr_in #endif #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) #ifndef ENODATA #define ENODATA ENOATTR #endif #endif /* PS4_PLATFORM */ #ifdef __vita__ #include int getlogin_r(char *buf, size_t size); ssize_t writev(t_socket fd, const struct iovec *iov, int iovcnt); ssize_t readv(t_socket fd, const struct iovec *iov, int iovcnt); #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif #endif #if defined(__SWITCH__) || defined(__3DS__) || defined(__WII__) || defined(__GC__) || defined(__WIIU__) || defined(__NDS__) #include #if defined(__3DS__) || defined(__WII__) || defined(__GC__) || defined(__WIIU__) || defined(__NDS__) struct iovec { void *iov_base; size_t iov_len; }; #if defined(__WII__) || defined(__GC__) || defined(__NDS__) #ifndef __NDS__ #include #endif #if !defined(HAVE_SOCKADDR_STORAGE) struct sockaddr_storage { #ifdef HAVE_SOCKADDR_SA_LEN unsigned char ss_len; #endif /* HAVE_SOCKADDR_SA_LEN */ unsigned char ss_family; unsigned char fill[127]; }; #endif struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; #endif #define sockaddr_in6 sockaddr_in #else #include #endif #ifndef EAI_AGAIN #define EAI_AGAIN EAGAIN #endif #ifndef EAI_FAIL #define EAI_FAIL 4 #endif #ifndef EAI_MEMORY #define EAI_MEMORY 6 #endif #ifndef EAI_NONAME #define EAI_NONAME 8 #endif #ifndef EAI_SERVICE #define EAI_SERVICE 9 #endif #ifndef POLLIN #define POLLIN 0x0001 /* There is data to read */ #endif #ifndef POLLPRI #define POLLPRI 0x0002 /* There is urgent data to read */ #endif #ifndef POLLOUT #define POLLOUT 0x0004 /* Writing now will not block */ #endif #ifndef POLLERR #define POLLERR 0x0008 /* Error condition */ #endif #ifndef POLLHUP #define POLLHUP 0x0010 /* Hung up */ #endif #ifndef TCP_NODELAY #define TCP_NODELAY 1 /* Don't delay send to coalesce packets */ #endif #ifndef __NDS__ #ifndef IPPROTO_TCP #define IPPROTO_TCP 6 #endif #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif #endif ssize_t writev(int fd, const struct iovec *iov, int iovcnt); ssize_t readv(int fd, const struct iovec *iov, int iovcnt); int getlogin_r(char *buf, size_t size); #if defined(__WII__) || defined(__GC__) || defined(__NDS__) int smb2_getaddrinfo(const char *node, const char*service, const struct addrinfo *hints, struct addrinfo **res); void smb2_freeaddrinfo(struct addrinfo *res); #define getaddrinfo smb2_getaddrinfo #define freeaddrinfo smb2_freeaddrinfo #ifndef __NDS__ #define connect net_connect #define socket net_socket #define setsockopt net_setsockopt s32 getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); #define select net_select #define accept net_accept #define listen net_listen #define bind net_bind #endif struct pollfd { int fd; short events; short revents; }; int poll(struct pollfd *fds, unsigned int nfds, int timo); #endif #endif #ifdef ESP_PLATFORM #include #include #include #ifndef SOL_TCP #define SOL_TCP 6 #endif void srandom(unsigned int seed); long random(void); int getlogin_r(char *buf, size_t size); #endif #ifdef __ANDROID__ #include /* getlogin_r() was added in API 28 */ #if __ANDROID_API__ < 28 int getlogin_r(char *buf, size_t size); #endif #endif /* __ANDROID__ */ #ifndef O_RDONLY #define O_RDONLY 00000000 #endif #ifndef O_WRONLY #define O_WRONLY 00000001 #endif #ifndef O_RDWR #define O_RDWR 00000002 #endif #ifndef O_DSYNC #define O_DSYNC 040000 #endif /* !O_DSYNC */ #ifndef __O_SYNC #define __O_SYNC 020000000 #endif #ifndef O_SYNC #define O_SYNC (__O_SYNC|O_DSYNC) #endif /* !O_SYNC */ #ifndef O_ACCMODE #define O_ACCMODE (O_RDWR|O_WRONLY|O_RDONLY) #endif /* !O_ACCMODE */ #ifndef ENOMEM #define ENOMEM 12 #endif #ifndef EINVAL #define EINVAL 22 #endif #ifdef __cplusplus } #endif #endif /* _COMPAT_H_ */ libsmb2-6.2/lib/smb2-cmd-write.c0000664000175000017500000002344014732155517015470 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_write_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_write_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_WRITE_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate write buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); if (!smb2->supports_multi_credit && req->length > 64 * 1024) { req->length = 64 * 1024; } smb2_set_uint16(iov, 0, SMB2_WRITE_REQUEST_SIZE); smb2_set_uint16(iov, 2, SMB2_HEADER_SIZE + 48); smb2_set_uint32(iov, 4, req->length); smb2_set_uint64(iov, 8, req->offset); memcpy(iov->buf + 16, req->file_id, SMB2_FD_SIZE); smb2_set_uint32(iov, 32, req->channel); smb2_set_uint32(iov, 36, req->remaining_bytes); smb2_set_uint16(iov, 42, req->write_channel_info_length); smb2_set_uint32(iov, 44, req->flags); if (req->write_channel_info_length > 0 && req->write_channel_info != NULL) { if (smb2->passthrough) { req->write_channel_info_offset = (SMB2_READ_REQUEST_SIZE & 0xfffffffe) + SMB2_HEADER_SIZE; smb2_set_uint16(iov, 44, req->write_channel_info_offset); len = PAD_TO_64BIT(req->write_channel_info_length); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate write channel context"); return -1; } memcpy(buf, req->write_channel_info, req->write_channel_info_length); memset(buf + req->write_channel_info_length, 0, len - req->write_channel_info_length); iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); } else { smb2_set_error(smb2, "ChannelInfo not yet implemented"); return -1; } } return 0; } struct smb2_pdu * smb2_cmd_write_async(struct smb2_context *smb2, struct smb2_write_request *req, int pass_buf_ownership, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_WRITE, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_write_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } smb2_add_iovector(smb2, &pdu->out, (uint8_t*)req->buf, req->length, pass_buf_ownership ? free : NULL); /* Adjust credit charge for large payloads */ if (smb2->supports_multi_credit) { pdu->header.credit_charge = (req->length - 1) / 65536 + 1; /* 3.1.5.2 of [MS-SMB2] */ } return pdu; } static int smb2_encode_write_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_write_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_WRITE_REPLY_SIZE; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate write reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_WRITE_REPLY_SIZE); smb2_set_uint32(iov, 4, rep->count); smb2_set_uint32(iov, 8, rep->remaining); return 0; } struct smb2_pdu * smb2_cmd_write_reply_async(struct smb2_context *smb2, struct smb2_write_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_WRITE, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_write_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_write_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_write_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_WRITE_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Write " "reply. Expected %d, got %d", SMB2_WRITE_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate write reply"); return -1; } pdu->payload = rep; smb2_get_uint32(iov, 4, &rep->count); smb2_get_uint32(iov, 8, &rep->remaining); return 0; } #define IOVREQ_OFFSET (req->write_channel_info_length ? (req->write_channel_info_offset - SMB2_HEADER_SIZE - \ (SMB2_WRITE_REQUEST_SIZE & 0xfffe)):0) int smb2_process_write_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_write_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size > SMB2_WRITE_REQUEST_SIZE) { smb2_set_error(smb2, "Unexpected size of Write " "request. Expected %d, got %d", SMB2_WRITE_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate write request"); return -1; } pdu->payload = req; smb2_get_uint16(iov, 2, &req->data_offset); smb2_get_uint32(iov, 4, &req->length); smb2_get_uint64(iov, 8, &req->offset); memcpy(req->file_id, iov->buf + 16, SMB2_FD_SIZE); smb2_get_uint32(iov, 24, &req->channel); smb2_get_uint32(iov, 28, &req->remaining_bytes); smb2_get_uint16(iov, 32, &req->write_channel_info_offset); smb2_get_uint16(iov, 34, &req->write_channel_info_length); req->buf = NULL; if (req->write_channel_info_length) { if (req->write_channel_info_offset < (SMB2_HEADER_SIZE + (SMB2_WRITE_REQUEST_SIZE & 0xfffe))) { smb2_set_error(smb2, "channel info overlaps request"); pdu->payload = NULL; free(req); return -1; } } if (req->length) { return IOVREQ_OFFSET + PAD_TO_64BIT(req->write_channel_info_length) + req->length; } else if (req->write_channel_info_length) { return IOVREQ_OFFSET + req->write_channel_info_length; } else { return 0; } } int smb2_process_write_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_write_request *req = (struct smb2_write_request*)pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; struct smb2_iovec vec = { &iov->buf[IOVREQ_OFFSET], iov->len, NULL }; req->write_channel_info = (uint8_t *)vec.buf; /* 0-copy but app must know this buffer is gone when pdu is freed */ req->buf = &vec.buf[PAD_TO_64BIT(req->write_channel_info_length)]; return 0; } libsmb2-6.2/lib/smb2-cmd-oplock-break.c0000664000175000017500000004117514732155517016714 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Brian Dodge This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_oplock_break_acknowledgement(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_oplock_break_acknowledgement *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_OPLOCK_BREAK_ACKNOWLEDGE_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate oplock request buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_OPLOCK_BREAK_ACKNOWLEDGE_SIZE); smb2_set_uint8(iov, 2, req->oplock_level); memcpy(iov->buf + 8, req->file_id, SMB2_FD_SIZE); return 0; } struct smb2_pdu * smb2_cmd_oplock_break_async(struct smb2_context *smb2, struct smb2_oplock_break_acknowledgement *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_OPLOCK_BREAK, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_oplock_break_acknowledgement(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_oplock_break_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_oplock_break_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; /* this encodes both notifications and responses */ len = SMB2_OPLOCK_BREAK_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate oplock reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_OPLOCK_BREAK_REPLY_SIZE); smb2_set_uint8(iov, 2, rep->oplock_level); memcpy(iov->buf + 8, rep->file_id, SMB2_FD_SIZE); return 0; } struct smb2_pdu * smb2_cmd_oplock_break_reply_async(struct smb2_context *smb2, struct smb2_oplock_break_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_OPLOCK_BREAK, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_oplock_break_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_oplock_break_notification(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_oplock_break_notification *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; /* this encodes both notifications and responses */ len = SMB2_OPLOCK_BREAK_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate oplock reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_OPLOCK_BREAK_REPLY_SIZE); smb2_set_uint8(iov, 2, rep->oplock_level); memcpy(iov->buf + 8, rep->file_id, SMB2_FD_SIZE); return 0; } struct smb2_pdu * smb2_cmd_oplock_break_notification_async(struct smb2_context *smb2, struct smb2_oplock_break_notification *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_OPLOCK_BREAK, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_oplock_break_notification(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_lease_break_acknowledgement(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_lease_break_acknowledgement *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_LEASE_BREAK_ACKNOWLEDGE_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate lease notification buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_LEASE_BREAK_ACKNOWLEDGE_SIZE); smb2_set_uint32(iov, 4, req->flags); memcpy(iov->buf + 8, req->lease_key, SMB2_LEASE_KEY_SIZE); smb2_set_uint32(iov, 4, req->lease_state); smb2_set_uint32(iov, 4, req->lease_duration); return 0; } struct smb2_pdu * smb2_cmd_lease_break_async(struct smb2_context *smb2, struct smb2_lease_break_acknowledgement *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_OPLOCK_BREAK, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_lease_break_acknowledgement(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_lease_break_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_lease_break_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_LEASE_BREAK_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate " "lease-break reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_LEASE_BREAK_REPLY_SIZE); smb2_set_uint32(iov, 4, rep->flags); memcpy(iov->buf + 8, rep->lease_key, SMB2_LEASE_KEY_SIZE); smb2_set_uint32(iov, 24, rep->lease_state); smb2_set_uint32(iov, 28, rep->lease_duration); return 0; } struct smb2_pdu * smb2_cmd_lease_break_reply_async(struct smb2_context *smb2, struct smb2_lease_break_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_OPLOCK_BREAK, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_lease_break_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_lease_break_notification(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_lease_break_notification *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_LEASE_BREAK_NOTIFICATION_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate lease notification buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_LEASE_BREAK_NOTIFICATION_SIZE); smb2_set_uint16(iov, 2, req->new_epoch); smb2_set_uint32(iov, 4, req->flags); memcpy(iov->buf + 8, req->lease_key, SMB2_LEASE_KEY_SIZE); smb2_set_uint32(iov, 4, req->current_lease_state); smb2_set_uint32(iov, 4, req->new_lease_state); smb2_set_uint32(iov, 4, req->break_reason); smb2_set_uint32(iov, 4, req->access_mask_hint); smb2_set_uint32(iov, 4, req->share_mask_hint); return 0; } struct smb2_pdu * smb2_cmd_lease_break_notification_async(struct smb2_context *smb2, struct smb2_lease_break_notification *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_OPLOCK_BREAK, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_lease_break_notification(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_oplock_break_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_oplock_or_lease_break_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate oplock-" "or lease break reply"); return -1; } rep->struct_size = struct_size; pdu->payload = rep; if (struct_size == SMB2_OPLOCK_BREAK_REPLY_SIZE) { /* same size as notification too */ return struct_size - sizeof(uint16_t); } else if (struct_size == SMB2_LEASE_BREAK_NOTIFICATION_SIZE) { return struct_size - sizeof(uint16_t); } else if (struct_size == SMB2_LEASE_BREAK_REPLY_SIZE) { return struct_size - sizeof(uint16_t); } else { smb2_set_error(smb2, "Unexpected size of oplock or " "lease break noiify/reply. Expected " "%d or %d, got %d", SMB2_OPLOCK_BREAK_REPLY_SIZE, SMB2_LEASE_BREAK_REPLY_SIZE, struct_size); pdu->payload = NULL; free(rep); return -1; } return 0; } int smb2_process_oplock_break_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_oplock_or_lease_break_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; /* note the stuct-size has already been read, so offsets are -2 */ if (rep->struct_size == SMB2_OPLOCK_BREAK_NOTIFICATION_SIZE) { /* the oplock notify and response are both the same structure */ if (smb2->hdr.message_id == 0xffffffffffffffffULL) { rep->break_type = SMB2_BREAK_TYPE_OPLOCK_NOTIFICATION; } else { rep->break_type = SMB2_BREAK_TYPE_OPLOCK_RESPONSE; } smb2_get_uint8(iov, 0, &rep->lock.oplock.oplock_level); memcpy(rep->lock.oplock.file_id, iov->buf + 6, SMB2_FD_SIZE); } else if (rep->struct_size == SMB2_LEASE_BREAK_NOTIFICATION_SIZE) { rep->break_type = SMB2_BREAK_TYPE_LEASE_NOTIFICATION; smb2_get_uint16(iov, 0, &rep->lock.lease.new_epoch); smb2_get_uint32(iov, 2, &rep->lock.lease.flags); memcpy(rep->lock.lease.lease_key, iov->buf + 6, SMB2_LEASE_KEY_SIZE); smb2_get_uint32(iov, 22, &rep->lock.lease.current_lease_state); smb2_get_uint32(iov, 26, &rep->lock.lease.new_lease_state); smb2_get_uint32(iov, 30, &rep->lock.lease.break_reason); smb2_get_uint32(iov, 34, &rep->lock.lease.access_mask_hint); smb2_get_uint32(iov, 38, &rep->lock.lease.share_mask_hint); } else if (rep->struct_size == SMB2_LEASE_BREAK_REPLY_SIZE) { rep->break_type = SMB2_BREAK_TYPE_LEASE_RESPONSE; smb2_get_uint32(iov, 2, &rep->lock.leaserep.flags); memcpy(rep->lock.lease.lease_key, iov->buf + 6, SMB2_LEASE_KEY_SIZE); smb2_get_uint32(iov, 22, &rep->lock.leaserep.lease_state); smb2_get_uint64(iov, 26, &rep->lock.leaserep.lease_duration); } else { return -1; } return 0; } int smb2_process_oplock_break_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_oplock_or_lease_break_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate oplock-" "lease-break request"); return -1; } req->struct_size = struct_size; pdu->payload = req; if (struct_size == SMB2_OPLOCK_BREAK_ACKNOWLEDGE_SIZE) { return struct_size - sizeof(uint16_t); } else if (struct_size == SMB2_LEASE_BREAK_ACKNOWLEDGE_SIZE) { return struct_size - sizeof(uint16_t); } else { smb2_set_error(smb2, "Unexpected size of oplock or " "lease break acknowledge. Expected " "%d or %d, got %d", SMB2_OPLOCK_BREAK_ACKNOWLEDGE_SIZE, SMB2_LEASE_BREAK_ACKNOWLEDGE_SIZE, (int)struct_size); pdu->payload = NULL; free(req); return -1; } return 0; } int smb2_process_oplock_break_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_oplock_or_lease_break_request *req = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; /* note the stuct-size has already been read, so offsets are -2 */ if (req->struct_size == SMB2_OPLOCK_BREAK_ACKNOWLEDGE_SIZE) { req->break_type = SMB2_BREAK_TYPE_OPLOCK_ACKNOWLEDGE; smb2_get_uint8(iov, 0, &req->lock.oplock.oplock_level); memcpy(req->lock.oplock.file_id, iov->buf + 6, SMB2_FD_SIZE); } else if (req->struct_size == SMB2_LEASE_BREAK_ACKNOWLEDGE_SIZE) { req->break_type = SMB2_BREAK_TYPE_LEASE_ACKNOWLEDGE; smb2_get_uint32(iov, 2, &req->lock.lease.flags); memcpy(req->lock.lease.lease_key, iov->buf + 6, SMB2_LEASE_KEY_SIZE); smb2_get_uint32(iov, 22, &req->lock.lease.lease_state); smb2_get_uint64(iov, 26, &req->lock.lease.lease_duration); } else { return -1; } return 0; } libsmb2-6.2/lib/dcerpc-lsa.c0000664000175000017500000004660514732155517014761 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2020 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-dcerpc.h" #include "libsmb2-dcerpc-lsa.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" #define LSA_UUID 0x12345778, 0x1234, 0xabcd, {0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab} p_syntax_id_t lsa_interface = { {LSA_UUID}, 0, 0 }; unsigned char NT_SID_AUTHORITY[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 }; /* * typedef struct _RPC_SID { * unsigned char Revision; * unsigned char SubAuthorityCount; * byte IdentifierAuthority[6]; * [size_is(SubAuthorityCount)] uint32_t SubAuthority[]; * } RPC_SID, *PRPC_SID, *PSID; */ int lsa_RPC_SID_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { RPC_SID *sid = ptr; uint64_t count; int i; count = sid->SubAuthorityCount; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &count)) { return -1; } if (dcerpc_uint8_coder(dce, pdu, iov, offset, &sid->Revision)) { return -1; } if (dcerpc_uint8_coder(dce, pdu, iov, offset, &sid->SubAuthorityCount)) { return -1; } for (i = 0; i < 6; i++) { if (dcerpc_uint8_coder(dce, pdu, iov, offset, &sid->IdentifierAuthority[i])) { return -1; } } if (dcerpc_pdu_direction(pdu) == DCERPC_DECODE) { sid->SubAuthority = smb2_alloc_data(dcerpc_get_smb2_context(dce), dcerpc_get_pdu_payload(pdu), (size_t)count * sizeof(uint32_t)); if (sid->SubAuthority == NULL) { return -1; } } for (i = 0; i < count; i++) { if (dcerpc_uint32_coder(dce, pdu, iov, offset, &sid->SubAuthority[i])) { return -1; } } return 0; } static int lsa_PRPC_SID_array_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { PLSAPR_SID_ENUM_BUFFER seb = ptr; uint64_t val; int i; val = seb->Entries; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &val)) { return -1; } if (dcerpc_pdu_direction(pdu) == DCERPC_DECODE) { seb->SidInfo = smb2_alloc_data(dcerpc_get_smb2_context(dce), dcerpc_get_pdu_payload(pdu), (size_t)val * sizeof(PRPC_SID)); if (seb->SidInfo == NULL) { return -1; } for (i = 0; i < val; i++) { seb->SidInfo[i] = smb2_alloc_data(dcerpc_get_smb2_context(dce), dcerpc_get_pdu_payload(pdu), sizeof(RPC_SID)); if (seb->SidInfo[i] == NULL) { return -1; } } } for (i = 0; i < val; i++) { if (dcerpc_ptr_coder(dce, pdu, iov, offset, seb->SidInfo[i], PTR_UNIQUE, lsa_RPC_SID_coder)) { return -1; } } return 0; } /* * typedef struct _LSAPR_SID_ENUM_BUFFER { * [range(0,20480)] uint32_t Entries; * [size_is(Entries)] PRPC_SID SidInfo; * } LSAPR_SID_ENUM_BUFFER, *PLSAPR_SID_ENUM_BUFFER; */ static int lsa_SID_ENUM_BUFFER_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { PLSAPR_SID_ENUM_BUFFER seb = ptr; uint32_t val; val = seb->Entries; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &val)) { return -1; } seb->Entries = val; if (dcerpc_ptr_coder(dce, pdu, iov, offset, seb, PTR_UNIQUE, lsa_PRPC_SID_array_coder)) { return -1; } return 0; } /* * typedef struct _RPC_UNICODE_STRING { * uint16_t Length; * uint16_t MaximumLength; * char *Buffer; * } RPC_UNICODE_STRING, *PRPC_UNICODE_STRING; */ /* ptr is char ** */ int lsa_RPC_UNICODE_STRING_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { uint16_t len, maxlen; /* TODO conformance split * during the conformance run we need to do the alignment in all the coders, even for the coders that do not have any conformance data. that will eliminate the need to manually set the alignment like we do here */ *offset = dcerpc_align_3264(dce, *offset); if (dcerpc_pdu_direction(pdu) == DCERPC_ENCODE) { len = (uint16_t)strlen(*(char **)ptr) * 2; maxlen = (len & 0x02) ? len + 2 : len; } if (dcerpc_uint16_coder(dce, pdu, iov, offset, &len)) { return -1; } if (dcerpc_uint16_coder(dce, pdu, iov, offset, &maxlen)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, ptr, PTR_UNIQUE, dcerpc_utf16_coder)) { return -1; } return 0; } /* * typedef struct _LSAPR_TRANSLATED_NAME_EX { * SID_NAME_USE Use; * RPC_UNICODE_STRING Name; * uint32_t DomainIndex; * uint32_t Flags; * } LSAPR_TRANSLATED_NAME_EX, *PLSAPR_TRANSLATED_NAME_EX; */ static int lsa_TRANSLATED_NAME_EX_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { LSAPR_TRANSLATED_NAME_EX *tn = ptr; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &tn->Use)) { return -1; } if (lsa_RPC_UNICODE_STRING_coder(dce, pdu, iov, offset, &tn->Name)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &tn->DomainIndex)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &tn->Flags)) { return -1; } return 0; } /* * typedef struct _LSAPR_TRANSLATED_NAMES_EX { * [range(0,20480)] unsigned long Entries; * [size_is(Entries)] PLSAPR_TRANSLATED_NAME_EX Names; * } LSAPR_TRANSLATED_NAMES_EX, *PLSAPR_TRANSLATED_NAMES_EX; */ static int TN_array_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { LSAPR_TRANSLATED_NAMES_EX *tn = ptr; uint64_t count; int i; count = tn->Entries; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &count)) { return -1; } if (dcerpc_pdu_direction(pdu) == DCERPC_DECODE) { tn->Names = smb2_alloc_data(dcerpc_get_smb2_context(dce), dcerpc_get_pdu_payload(pdu), (size_t)count * sizeof(LSAPR_TRANSLATED_NAME_EX)); if (tn->Names == NULL) { return -1; } } for (i = 0; i < count; i++) { if (lsa_TRANSLATED_NAME_EX_coder(dce, pdu, iov, offset, &tn->Names[i])) { return -1; } } return 0; } static int lsa_TRANSLATED_NAMES_EX_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { LSAPR_TRANSLATED_NAMES_EX *tn = ptr; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &tn->Entries)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, ptr, PTR_UNIQUE, TN_array_coder)) { return -1; } return 0; } /* * typedef struct _LSAPR_OBJECT_ATTRIBUTES { * unsigned long Length = 0; * unsigned char *RootDirectory = NULL; * PSTRING ObjectName = NULL; * unsigned long Attributes = 0; * PLSAPR_SECURITY_DESCRIPTOR SecurityDescriptor = NULL; * PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService = NULL; * } LSAPR_OBJECT_ATTRIBUTES, *PLSAPR_OBJECT_ATTRIBUTES; */ static int lsa_ObjectAttributes_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { uint32_t len; uint64_t val; /* just encode a fake empty object for OpenPolicy2 */ len = 24; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &len)) { return -1; } val = 0; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } len = 0; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &len)) { return -1; } if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &val)) { return -1; } return 0; } /********************** * Function: 0x00 * NTSTATUS lsa_Close ( * [in,out] ndr_context_handle handle * ); **********************/ int lsa_Close_req_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct lsa_close_req *req = ptr; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &req->PolicyHandle, PTR_REF, dcerpc_context_handle_coder)) { return -1; } return 0; } int lsa_Close_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct lsa_close_rep *rep = ptr; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &rep->PolicyHandle, PTR_REF, dcerpc_context_handle_coder)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &rep->status)) { return -1; } return 0; } /********************** * Function: 0x2c * NTSTATUS LsarOpenPolicy2( * [in,unique,string] wchar_t* SystemName, * [in] PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes, * [in] uint32_t DesiredAccess, * [out] ndr_context_handle PolicyHandle * ); **********************/ int lsa_OpenPolicy2_req_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct lsa_openpolicy2_req *req = ptr; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &req->SystemName, PTR_UNIQUE, dcerpc_utf16z_coder)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, &req->ObjectAttributes, PTR_REF, lsa_ObjectAttributes_coder)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &req->DesiredAccess)) { return -1; } return 0; } int lsa_OpenPolicy2_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct lsa_openpolicy2_rep *rep = ptr; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &rep->PolicyHandle, PTR_REF, dcerpc_context_handle_coder)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &rep->status)) { return -1; } return 0; } /* * typedef struct _LSAPR_TRUST_INFORMATION { * RPC_UNICODE_STRING Name; * PRPC_SID Sid; * } LSAPR_TRUST_INFORMATION, *PLSAPR_TRUST_INFORMATION; */ static int lsa_TRUST_INFORMATION_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { LSAPR_TRUST_INFORMATION *ti = ptr; if (lsa_RPC_UNICODE_STRING_coder(dce, pdu, iov, offset, &ti->Name)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, &ti->Sid, PTR_UNIQUE, lsa_RPC_SID_coder)) { return -1; } return 0; } static int RDL_DOMAINS_array_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { LSAPR_REFERENCED_DOMAIN_LIST *rdl = ptr; uint64_t entries; int i; entries = rdl->Entries; if (dcerpc_uint3264_coder(dce, pdu, iov, offset, &entries)) { return -1; } rdl->Entries = (uint32_t)entries; if (dcerpc_pdu_direction(pdu) == DCERPC_DECODE) { rdl->Domains = smb2_alloc_data(dcerpc_get_smb2_context(dce), dcerpc_get_pdu_payload(pdu), rdl->Entries * sizeof(LSAPR_TRUST_INFORMATION)); if (rdl->Domains == NULL) { return -1; } } for (i = 0; i < entries; i++) { if (lsa_TRUST_INFORMATION_coder(dce, pdu, iov, offset, &rdl->Domains[i])) { return -1; } } return 0; } /* * typedef struct _LSAPR_REFERENCED_DOMAIN_LIST { * uint32_t Entries; * LSAPR_TRUST_INFORMATION *Domains; * uint32_t MaxEntries; must be ignored * } LSAPR_REFERENCED_DOMAIN_LIST, *PLSAPR_REFERENCED_DOMAIN_LIST; */ static int lsa_REFERENCED_DOMAIN_LIST_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { LSAPR_REFERENCED_DOMAIN_LIST *rdl = ptr; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &rdl->Entries)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, ptr, PTR_UNIQUE, RDL_DOMAINS_array_coder)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &rdl->MaxEntries)) { return -1; } return 0; } /********************** * Function: 0x39 * NTSTATUS LsarLookupSids2( * [in] ndr_context_handle PolicyHandle, * [in] PLSAPR_SID_ENUM_BUFFER SidEnumBuffer, * [out] PLSAPR_REFERENCED_DOMAIN_LIST* ReferencedDomains, * [in, out] PLSAPR_TRANSLATED_NAMES_EX TranslatedNames, * [in] LSAP_LOOKUP_LEVEL LookupLevel, * [in, out] unsigned long* MappedCount, * [in] unsigned long LookupOptions, (SHOULD BE 0) * [in] unsigned long ClientRevision * ); *******************/ int lsa_LookupSids2_req_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct lsa_lookupsids2_req *req = (struct lsa_lookupsids2_req*) ptr; uint32_t val; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &req->PolicyHandle, PTR_REF, dcerpc_context_handle_coder)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, &req->SidEnumBuffer, PTR_REF, lsa_SID_ENUM_BUFFER_coder)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, &req->TranslatedNames, PTR_REF, lsa_TRANSLATED_NAMES_EX_coder)) { return -1; } val = req->LookupLevel; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &val)) { return -1; } req->LookupLevel = (LSAP_LOOKUP_LEVEL)val; val = 0; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &val)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &val)) { return -1; } val = 2; if (dcerpc_uint32_coder(dce, pdu, iov, offset, &val)) { return -1; } return 0; } int lsa_LookupSids2_rep_coder(struct dcerpc_context *dce, struct dcerpc_pdu *pdu, struct smb2_iovec *iov, int *offset, void *ptr) { struct lsa_lookupsids2_rep *rep = ptr; if (dcerpc_ptr_coder(dce, pdu, iov, offset, &rep->ReferencedDomains, PTR_UNIQUE, lsa_REFERENCED_DOMAIN_LIST_coder)) { return -1; } if (dcerpc_ptr_coder(dce, pdu, iov, offset, &rep->TranslatedNames, PTR_REF, lsa_TRANSLATED_NAMES_EX_coder)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &rep->MappedCount)) { return -1; } if (dcerpc_uint32_coder(dce, pdu, iov, offset, &rep->status)) { return -1; } return 0; } libsmb2-6.2/lib/compat.c0000664000175000017500000003451214732155517014221 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2020 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #include "compat.h" #if defined(_WINDOWS) || defined(_XBOX) #include #include #ifdef _WINDOWS #define login_num ENXIO #define getpid_num() GetCurrentProcessId() #else #define login_num 0 #define getpid_num() 0 #endif #define smb2_random rand #define smb2_srandom srand #ifdef _XBOX int gethostname(char *name, size_t len) { #ifdef XBOX_PLATFORM strncpy(name, "XBOX", len); #else strncpy(name, "XBOX_360", len); #endif return 0; } #endif #endif #ifdef __DREAMCAST__ #include #include #include #define login_num ENXIO #endif #ifdef ESP_PLATFORM #include #include #include #include #include #include #define login_num ENXIO #define smb2_random esp_random #define smb2_srandom(seed) #endif #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) #ifndef __amigaos4__ #define NEED_READV #define NEED_WRITEV #include #define read(fd, buf, count) recv(fd, buf, count, 0) #define write(fd, buf, count) send(fd, buf, count, 0) #ifndef __AROS__ #define select(nfds, readfds, writefds, exceptfds, timeout) WaitSelect(nfds, readfds, writefds, exceptfds, timeout, NULL) #endif #ifdef libnix StdFileDes *_lx_fhfromfd(int d) { return NULL; } struct MinList __filelist = { (struct MinNode *) &__filelist.mlh_Tail, NULL, (struct MinNode *) &__filelist.mlh_Head }; #endif #endif #define login_num ENXIO #include #include #include #endif #ifdef PICO_PLATFORM #include "lwip/def.h" #include #include #define login_num 1 #endif /* PICO_PLATFORM */ #ifdef __PS2__ #ifdef _EE #include #include #include #include #include #else #include #include #include #include #endif #include #define login_num ENXIO #ifdef _IOP #define getpid_num() 27 static unsigned long int next = 1; int gethostname(char *name, size_t len) { strncpy(name, "PS2", len); return 0; } time_t time(time_t *tloc) { u32 sec, usec; iop_sys_clock_t sys_clock; GetSystemTime(&sys_clock); SysClock2USec(&sys_clock, &sec, &usec); return sec; } int asprintf(char **strp, const char *fmt, ...) { int len; char *str; va_list args; va_start(args, fmt); str = malloc(256); len = sprintf(str, fmt, args); va_end(args); *strp = str; return len; } int errno; int iop_connect(int sockfd, struct sockaddr *addr, socklen_t addrlen) { int rc; int err = 0; socklen_t err_size = sizeof(err); if ((rc = lwip_connect(sockfd, addr, addrlen)) < 0) { if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&err, &err_size) != 0 || err != 0) { errno = err; } } return rc; } #endif #endif /* __PS2__ */ #ifdef __ANDROID__ /* getlogin_r() was added in API 28 */ #if __ANDROID_API__ < 28 #include #define NEED_GETLOGIN_R #define login_num ENXIO #endif #endif #ifdef PS3_PPU_PLATFORM #include #include #include #include #define login_num ENXIO #define smb2_random rand #define smb2_srandom srand #endif /* PS3_PPU_PLATFORM */ #ifdef __vita__ #include #include #include #include #define login_num ENXIO #endif #if defined(__SWITCH__) || defined(__3DS__) || defined(__WII__) || defined(__GC__) || defined(__WIIU__) || defined(__NDS__) #include #include #include #include #include #include #if !defined(__WII__) && !defined(__GC__) #include #endif #if defined(__NDS__) #include #endif #if defined(__SWITCH__) #include #elif defined(__3DS__) #include <3ds/types.h> #elif defined(__WII__) || defined(__GC__) #include #elif defined(__WIIU__) #include #elif defined(__NDS__) #include #endif #define login_num ENXIO #if defined(__WII__) || defined(__GC__) s32 getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { #ifdef __GC__ return net_getsockopt(sockfd, level, optname, optval, (socklen_t)optlen); #else printf("not yet supported"); return 0; #endif } #endif #endif /* __SWITCH__ */ #ifdef NEED_GETADDRINFO int smb2_getaddrinfo(const char *node, const char*service, const struct addrinfo *hints, struct addrinfo **res) { struct sockaddr_in *sin; #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) struct hostent *host; int i, ip[4]; #endif #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) sin = calloc(1, sizeof(struct sockaddr_in)); #else sin = malloc(sizeof(struct sockaddr_in)); #endif #if !defined(_XBOX) && !defined(__NDS__) && !defined(__USE_WINSOCK__) sin->sin_len = sizeof(struct sockaddr_in); #endif sin->sin_family=AF_INET; #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) /* Some error checking would be nice */ if (sscanf(node, "%d.%d.%d.%d", ip, ip+1, ip+2, ip+3) == 4) { for (i = 0; i < 4; i++) { ((char *)&sin->sin_addr.s_addr)[i] = ip[i]; } } else { host = gethostbyname(node); if (host == NULL) { return -1; } if (host->h_addrtype != AF_INET) { return -2; } memcpy(&sin->sin_addr.s_addr, host->h_addr, 4); } sin->sin_port=0; if (service) { sin->sin_port=htons(atoi(service)); } *res = calloc(1, sizeof(struct addrinfo)); #else /* Some error checking would be nice */ sin->sin_addr.s_addr = inet_addr(node); sin->sin_port=0; if (service) { sin->sin_port=htons(atoi(service)); } *res = malloc(sizeof(struct addrinfo)); memset(*res, 0, sizeof(struct addrinfo)); #endif (*res)->ai_family = AF_INET; (*res)->ai_addrlen = sizeof(struct sockaddr_in); (*res)->ai_addr = (struct sockaddr *)sin; return 0; } #endif #ifdef NEED_FREEADDRINFO void smb2_freeaddrinfo(struct addrinfo *res) { free(res->ai_addr); free(res); } #endif #ifdef NEED_RANDOM #ifdef ESP_PLATFORM long random(void) #else int random(void) #endif { #ifdef _IOP next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768; #else return smb2_random(); #endif } #endif #ifdef NEED_SRANDOM void srandom(unsigned int seed) { #ifdef _IOP next = seed; #else smb2_srandom(seed); #endif } #endif #ifdef NEED_GETPID int getpid() { return getpid_num(); }; #endif #ifdef NEED_GETLOGIN_R int getlogin_r(char *buf, size_t size) { return login_num; } #endif #ifdef NEED_WRITEV ssize_t writev(t_socket fd, const struct iovec* vector, int count) { /* Find the total number of bytes to be written. */ size_t bytes = 0; int i; char *buffer; size_t to_copy; char *bp; ssize_t bytes_written; for (i = 0; i < count; ++i) { /* Check for ssize_t overflow. */ if (((ssize_t)-1) - bytes < vector[i].iov_len) { errno = EINVAL; return -1; } bytes += vector[i].iov_len; } buffer = (char *)malloc(bytes); if (buffer == NULL) /* XXX I don't know whether it is acceptable to try writing the data in chunks. Probably not so we just fail here. */ return -1; /* Copy the data into BUFFER. */ to_copy = bytes; bp = buffer; for (i = 0; i < count; ++i) { size_t copy = (vector[i].iov_len < to_copy) ? vector[i].iov_len : to_copy; memcpy((void *)bp, (void *)vector[i].iov_base, copy); bp += copy; to_copy -= copy; if (to_copy == 0) break; } bytes_written = write((int)fd, buffer, bytes); free(buffer); return bytes_written; } #endif #ifdef NEED_READV ssize_t readv(t_socket fd, const struct iovec* vector, int count) { /* Find the total number of bytes to be read. */ size_t bytes = 0; int i; char *buffer; ssize_t bytes_read; char *bp; for (i = 0; i < count; ++i) { /* Check for ssize_t overflow. */ if (((ssize_t)-1) - bytes < vector[i].iov_len) { errno = EINVAL; return -1; } bytes += vector[i].iov_len; } buffer = (char *)malloc(bytes); if (buffer == NULL) return -1; /* Read the data. */ bytes_read = read((int)fd, buffer, bytes); if (bytes_read < 0) { free(buffer); return -1; } /* Copy the data from BUFFER into the memory specified by VECTOR. */ bytes = bytes_read; bp = buffer; for (i = 0; i < count; ++i) { size_t copy = (vector[i].iov_len < bytes) ? vector[i].iov_len : bytes; memcpy((void *)vector[i].iov_base, (void *)bp, copy); bp += copy; bytes -= copy; if (bytes == 0) break; } free(buffer); return bytes_read; } #endif #ifdef NEED_POLL int poll(struct pollfd *fds, unsigned int nfds, int timo) { struct timeval timeout, *toptr; fd_set ifds, ofds, efds, *ip, *op; unsigned int i, maxfd = 0; int rc; FD_ZERO(&ifds); FD_ZERO(&ofds); FD_ZERO(&efds); #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) op = ip = 0; for (i = 0; i < nfds; ++i) { int fd = fds[i].fd; fds[i].revents = 0; if (!SMB2_VALID_SOCKET(fd)) continue; if(fds[i].events & (POLLIN|POLLPRI)) { ip = &ifds; FD_SET(fd, ip); } if(fds[i].events & POLLOUT) { op = &ofds; FD_SET(fd, op); } FD_SET(fd, &efds); if (fd > maxfd) { maxfd = fd; } } #else for (i = 0, op = ip = 0; i < nfds; ++i) { fds[i].revents = 0; if(fds[i].events & (POLLIN|POLLPRI)) { ip = &ifds; FD_SET(fds[i].fd, ip); } if(fds[i].events & POLLOUT) { op = &ofds; FD_SET(fds[i].fd, op); } FD_SET(fds[i].fd, &efds); if (fds[i].fd > (int)maxfd) { maxfd = fds[i].fd; } } #endif #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) if(timo >= 0) { toptr = &timeout; timeout.tv_sec = (unsigned)timo / 1000; timeout.tv_usec = ((unsigned)timo % 1000) * 1000; } #else if(timo < 0) { toptr = NULL; } else { toptr = &timeout; timeout.tv_sec = timo / 1000; timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000; } #endif rc = select(maxfd + 1, ip, op, &efds, toptr); if(rc <= 0) return rc; #if defined(__amigaos4__) || defined(__AMIGA__) || defined(__AROS__) rc = 0; for (i = 0; i < nfds; ++i) { int fd = fds[i].fd; short events = fds[i].events; short revents = 0; if (!SMB2_VALID_SOCKET(fd)) continue; if(events & (POLLIN|POLLPRI) && FD_ISSET(fd, &ifds)) revents |= POLLIN; if(events & POLLOUT && FD_ISSET(fd, &ofds)) revents |= POLLOUT; if(FD_ISSET(fd, &efds)) revents |= POLLHUP; if (revents) { fds[i].revents = revents; rc++; } } #else if(rc > 0) { for (i = 0; i < nfds; ++i) { int fd = fds[i].fd; if(fds[i].events & (POLLIN|POLLPRI) && FD_ISSET(fd, &ifds)) fds[i].revents |= POLLIN; if(fds[i].events & POLLOUT && FD_ISSET(fd, &ofds)) fds[i].revents |= POLLOUT; if(FD_ISSET(fd, &efds)) fds[i].revents |= POLLHUP; } } #endif return rc; } #endif #ifdef NEED_STRDUP char *strdup(const char *s) { char *str; int len; len = strlen(s) + 1; str = malloc(len); if (str == NULL) { #ifndef _IOP errno = ENOMEM; #endif /* !_IOP */ return NULL; } memcpy(str, s, len + 1); return str; } #endif /* NEED_STRDUP */ #ifdef NEED_BE64TOH long long int be64toh(long long int x) { long long int val; val = ntohl(x & 0xffffffff); val <<= 32; val ^= ntohl(x >> 32); return val; } #endif /* NEED_BE64TOH */ libsmb2-6.2/lib/smb2-cmd-tree-disconnect.c0000664000175000017500000001006214732155517017420 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_tree_disconnect_request(struct smb2_context *smb2, struct smb2_pdu *pdu) { uint8_t *buf; int len; struct smb2_iovec *iov; len = 4; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate tree disconnect " "buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_TREE_DISCONNECT_REQUEST_SIZE); return 0; } struct smb2_pdu * smb2_cmd_tree_disconnect_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_TREE_DISCONNECT, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_tree_disconnect_request(smb2, pdu)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_tree_disconnect_reply(struct smb2_context *smb2, struct smb2_pdu *pdu) { uint8_t *buf; int len; struct smb2_iovec *iov; len = SMB2_TREE_DISCONNECT_REPLY_SIZE; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate tree disconnect " "reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_TREE_DISCONNECT_REPLY_SIZE); return 0; } struct smb2_pdu * smb2_cmd_tree_disconnect_reply_async(struct smb2_context *smb2, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_TREE_DISCONNECT, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_tree_disconnect_reply(smb2, pdu)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_tree_disconnect_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { smb2_disconnect_tree_id(smb2, smb2->hdr.sync.tree_id); return 0; } int smb2_process_tree_disconnect_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { return 0; } libsmb2-6.2/lib/krb5-wrapper.c0000664000175000017500000003275514732155517015266 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LIBKRB5 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include #if __APPLE__ #include #else #include #include #endif #include #include "compat.h" #include "slist.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" #include "krb5-wrapper.h" void krb5_free_auth_data(struct private_auth_data *auth) { uint32_t maj, min; /* Delete context */ if (auth->context) { maj = gss_delete_sec_context(&min, &auth->context, &auth->output_token); if (maj != GSS_S_COMPLETE) { /* No logging, yet. Do we care? */ } } gss_release_buffer(&min, &auth->output_token); if (auth->target_name) { gss_release_name(&min, &auth->target_name); } if (auth->user_name) { gss_release_name(&min, &auth->user_name); } free(auth->g_server); free(auth); } static char * display_status(int type, uint32_t err) { gss_buffer_desc text; uint32_t msg_ctx; char *msg, *tmp; uint32_t maj, min; msg = NULL; msg_ctx = 0; do { maj = gss_display_status(&min, err, type, GSS_C_NO_OID, &msg_ctx, &text); if (maj != GSS_S_COMPLETE) { return msg; } tmp = NULL; if (msg) { tmp = msg; min = asprintf(&msg, "%s, %*s", msg, (int)text.length, (char *)text.value); } else { min = asprintf(&msg, "%*s", (int)text.length, (char *)text.value); } if (min == -1) return tmp; free(tmp); gss_release_buffer(&min, &text); } while (msg_ctx != 0); return msg; } void krb5_set_gss_error(struct smb2_context *smb2, char *func, uint32_t maj, uint32_t min) { char *err_maj = display_status(GSS_C_GSS_CODE, maj); char *err_min = display_status(GSS_C_MECH_CODE, min); smb2_set_error(smb2, "%s: (%s, %s)", func, err_maj, err_min); free(err_min); free(err_maj); } struct private_auth_data * krb5_negotiate_reply(struct smb2_context *smb2, const char *server, const char *domain, const char *user_name, const char *password) { struct private_auth_data *auth_data; gss_buffer_desc target = GSS_C_EMPTY_BUFFER; uint32_t maj, min; gss_buffer_desc user; char user_principal[2048]; char *nc_password = NULL; gss_buffer_desc passwd; gss_OID_set_desc mechOidSet; if (smb2->use_cached_creds) { /* Validate the parameters */ if (domain == NULL || password == NULL) { smb2_set_error(smb2, "domain and password must be set while using krb5cc mode"); return NULL; } } auth_data = calloc(1, sizeof(struct private_auth_data)); if (auth_data == NULL) { smb2_set_error(smb2, "Failed to allocate private_auth_data"); return NULL; } auth_data->context = GSS_C_NO_CONTEXT; if (asprintf(&auth_data->g_server, "cifs@%s", server) < 0) { smb2_set_error(smb2, "Failed to allocate server string"); return NULL; } target.value = auth_data->g_server; target.length = strlen(auth_data->g_server); maj = gss_import_name(&min, &target, GSS_C_NT_HOSTBASED_SERVICE, &auth_data->target_name); if (maj != GSS_S_COMPLETE) { krb5_set_gss_error(smb2, "gss_import_name", maj, min); return NULL; } if (smb2->use_cached_creds) { memset(&user_principal[0], 0, 2048); if (sprintf(&user_principal[0], "%s@%s", user_name, domain) < 0) { smb2_set_error(smb2, "Failed to allocate user principal"); return NULL; } user.value = discard_const(user_principal); user.length = strlen(user_principal); } else { user.value = discard_const(user_name); user.length = strlen(user_name); } /* create a name for the user */ maj = gss_import_name(&min, &user, GSS_C_NT_USER_NAME, &auth_data->user_name); if (maj != GSS_S_COMPLETE) { krb5_set_gss_error(smb2, "gss_import_name", maj, min); return NULL; } /* TODO: the proper mechanism (SPNEGO vs NTLM vs KRB5) should be * selected based on the SMB negotiation flags */ #ifdef __APPLE__ auth_data->mech_type = GSS_SPNEGO_MECHANISM; #else auth_data->mech_type = &gss_mech_spnego; #endif auth_data->cred = GSS_C_NO_CREDENTIAL; /* Create creds for the user */ mechOidSet.count = 1; #ifdef __APPLE__ mechOidSet.elements = discard_const(GSS_SPNEGO_MECHANISM); #else mechOidSet.elements = discard_const(&gss_mech_spnego); #endif if (smb2->use_cached_creds) { krb5_error_code ret = 0; const char *cname = NULL; krb5_context krb5_cctx; krb5_ccache krb5_Ccache; /* krb5 cache management */ ret = krb5_init_context(&krb5_cctx); if (ret) { smb2_set_error(smb2, "Failed to initialize krb5 context - %s", krb5_get_error_message(krb5_cctx, ret)); return NULL; } ret = krb5_cc_new_unique(krb5_cctx, "MEMORY", NULL, &krb5_Ccache); if (ret != 0) { smb2_set_error(smb2, "Failed to create krb5 credentials cache - %s", krb5_get_error_message(krb5_cctx, ret)); return NULL; } cname = krb5_cc_get_name(krb5_cctx, krb5_Ccache); if (cname == NULL) { smb2_set_error(smb2, "Failed to retrieve the credentials cache name"); return NULL; } maj = gss_krb5_ccache_name(&min, cname, NULL); if (maj != GSS_S_COMPLETE) { krb5_set_gss_error(smb2, "gss_krb5_ccache_name", maj, min); return NULL; } nc_password = strdup(password); passwd.value = nc_password; passwd.length = strlen(nc_password); maj = gss_acquire_cred_with_password(&min, auth_data->user_name, &passwd, 0, &mechOidSet, GSS_C_INITIATE, &auth_data->cred, NULL, NULL); } else { maj = gss_acquire_cred(&min, auth_data->user_name, 0, &mechOidSet, GSS_C_INITIATE, &auth_data->cred, NULL, NULL); } if (maj != GSS_S_COMPLETE) { krb5_set_gss_error(smb2, "gss_acquire_cred", maj, min); return NULL; } #ifndef __APPLE__ /* gss_set_neg_mechs is not defined on macOS/iOS. */ if (smb2->sec != SMB2_SEC_UNDEFINED) { gss_OID_set_desc wantMech; wantMech.count = 1; if (smb2->sec == SMB2_SEC_KRB5) { wantMech.elements = discard_const(&spnego_mech_krb5); } else if (smb2->sec == SMB2_SEC_NTLMSSP) { wantMech.elements = discard_const(&spnego_mech_ntlmssp); } maj = gss_set_neg_mechs(&min, auth_data->cred, &wantMech); if (GSS_ERROR(maj)) { krb5_set_gss_error(smb2, "gss_set_neg_mechs", maj, min); return NULL; } } #endif if (nc_password) { free(nc_password); nc_password = NULL; } return auth_data; } int krb5_session_get_session_key(struct smb2_context *smb2, struct private_auth_data *auth_data) { /* Get the Session Key */ uint32_t gssMajor, gssMinor; gss_buffer_set_t sessionKey = NULL; gssMajor = gss_inquire_sec_context_by_oid( &gssMinor, auth_data->context, GSS_C_INQ_SSPI_SESSION_KEY, &sessionKey); if (gssMajor != GSS_S_COMPLETE) { krb5_set_gss_error(smb2, "gss_inquire_sec_context_by_oid", gssMajor, gssMinor); return -1; } /* The key is in element 0 and the key type OID is in element 1 */ if (!sessionKey || (sessionKey->count < 1) || !sessionKey->elements[0].value || (0 == sessionKey->elements[0].length)) { smb2_set_error(smb2, "Invalid session key"); return -1; } smb2->session_key = (uint8_t *) malloc(sessionKey->elements[0].length); if (smb2->session_key == NULL) { smb2_set_error(smb2, "Failed to allocate SessionKey"); return -1; } memset(smb2->session_key, 0, sessionKey->elements[0].length); memcpy(smb2->session_key, sessionKey->elements[0].value, sessionKey->elements[0].length); smb2->session_key_size = sessionKey->elements[0].length; gss_release_buffer_set(&gssMinor, &sessionKey); return 0; } int krb5_session_request(struct smb2_context *smb2, struct private_auth_data *auth_data, unsigned char *buf, int len) { uint32_t maj, min; gss_buffer_desc *input_token = NULL; gss_buffer_desc token = GSS_C_EMPTY_BUFFER; if (buf) { /* release the previous token */ gss_release_buffer(&min, &auth_data->output_token); auth_data->output_token.length = 0; auth_data->output_token.value = NULL; token.value = buf; token.length = len; input_token = &token; } /* TODO return -errno instead of just -1 */ /* NOTE: this call is not async, a helper thread should be used if that * is an issue */ auth_data->req_flags = GSS_C_SEQUENCE_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; maj = gss_init_sec_context(&min, auth_data->cred, &auth_data->context, auth_data->target_name, discard_const(auth_data->mech_type), auth_data->req_flags, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, input_token, NULL, &auth_data->output_token, NULL, NULL); /* GSS_C_MUTUAL_FLAG expects the acceptor to send a token so * a second call to gss_init_sec_context is required to complete the session. * A second call is required even if the first call returns GSS_S_COMPLETE */ if (maj & GSS_S_CONTINUE_NEEDED) { return 0; } if (GSS_ERROR(maj)) { krb5_set_gss_error(smb2, "gss_init_sec_context", maj, min); return -1; } return 0; } int krb5_get_output_token_length(struct private_auth_data *auth_data) { return auth_data->output_token.length; } unsigned char * krb5_get_output_token_buffer(struct private_auth_data *auth_data) { return auth_data->output_token.value; } #endif /* HAVE_LIBKRB5 */libsmb2-6.2/lib/smb2-cmd-notify-change.c0000664000175000017500000001745514732155517017102 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Brian Dodge This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_change_notify_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_change_notify_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_CHANGE_NOTIFY_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate " "change-notify buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_CHANGE_NOTIFY_REQUEST_SIZE); smb2_set_uint16(iov, 2, req->flags); smb2_set_uint32(iov, 4, req->output_buffer_length); memcpy(iov->buf + 8, req->file_id, SMB2_FD_SIZE); smb2_set_uint32(iov, 24, req->completion_filter); return 0; } struct smb2_pdu * smb2_cmd_change_notify_async(struct smb2_context *smb2, struct smb2_change_notify_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_CHANGE_NOTIFY, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_change_notify_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_change_notify_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_change_notify_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_CHANGE_NOTIFY_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate " "change-notify reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_CHANGE_NOTIFY_REPLY_SIZE); rep->output_buffer_offset = SMB2_HEADER_SIZE + SMB2_CHANGE_NOTIFY_REQUEST_SIZE; smb2_set_uint16(iov, 2, rep->output_buffer_offset); smb2_set_uint32(iov, 4, rep->output_buffer_length); if (rep->output_buffer_length == 0) { return 0; } len = rep->output_buffer_length; len = PAD_TO_32BIT(len); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate output buf"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); if (smb2->passthrough) { memcpy(buf, rep->output, rep->output_buffer_length); memset(buf + rep->output_buffer_length, 0, len - rep->output_buffer_length); iov->len = rep->output_buffer_length; } else { smb2_set_error(smb2, "Change-notify buffer " "packing not implemented"); return -1; } return 0; } struct smb2_pdu * smb2_cmd_change_notify_reply_async(struct smb2_context *smb2, struct smb2_change_notify_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_CHANGE_NOTIFY, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_change_notify_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_change_notify_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_change_notify_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_CHANGE_NOTIFY_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of change " "notify reply. Expected %d, got %d", SMB2_CHANGE_NOTIFY_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate " "change-notify reply"); return -1; } pdu->payload = rep; smb2_get_uint16(iov, 2, &rep->output_buffer_offset); smb2_get_uint32(iov, 4, &rep->output_buffer_length); return rep->output_buffer_length; } int smb2_process_change_notify_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_change_notify_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; rep->output = (uint8_t *)iov->buf; return 0; } int smb2_process_change_notify_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_change_notify_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_CHANGE_NOTIFY_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of change " "notify request. Expected %d, got %d", SMB2_CHANGE_NOTIFY_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate " "change-notify request"); return -1; } pdu->payload = req; smb2_get_uint16(iov, 2, &req->flags); memcpy(req->file_id, iov->buf + 8, SMB2_FD_SIZE); smb2_get_uint32(iov, 24, &req->completion_filter); return 0; } libsmb2-6.2/lib/smb2-cmd-session-setup.c0000664000175000017500000002420114732155517017153 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_session_setup_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_session_setup_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_SESSION_SETUP_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate session " "setup buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_SESSION_SETUP_REQUEST_SIZE); smb2_set_uint8(iov, 2, req->flags); smb2_set_uint8(iov, 3, req->security_mode); smb2_set_uint32(iov, 4, req->capabilities); smb2_set_uint32(iov, 8, req->channel); smb2_set_uint16(iov, 12, SMB2_HEADER_SIZE + 24); smb2_set_uint16(iov, 14, req->security_buffer_length); smb2_set_uint64(iov, 16, req->previous_session_id); /* Security buffer */ buf = malloc(req->security_buffer_length); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate secbuf"); return -1; } memcpy(buf, req->security_buffer, req->security_buffer_length); iov = smb2_add_iovector(smb2, &pdu->out, buf, req->security_buffer_length, free); return 0; } struct smb2_pdu * smb2_cmd_session_setup_async(struct smb2_context *smb2, struct smb2_session_setup_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_SESSION_SETUP, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_session_setup_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_session_setup_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_session_setup_reply *rep) { uint8_t *buf; int len; struct smb2_iovec *iov; len = SMB2_SESSION_SETUP_REPLY_SIZE & 0xfffe; len = PAD_TO_32BIT(len); buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate session_setup buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_SESSION_SETUP_REPLY_SIZE); smb2_set_uint16(iov, 2, rep->session_flags); rep->security_buffer_offset = len + SMB2_HEADER_SIZE; smb2_set_uint16(iov, 4, rep->security_buffer_offset); smb2_set_uint16(iov, 6, rep->security_buffer_length); if (rep->security_buffer_length) { len = rep->security_buffer_length; len = PAD_TO_32BIT(len); /* Security buffer */ buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate secbuf"); return -1; } memcpy(buf, rep->security_buffer, rep->security_buffer_length); memset(buf + rep->security_buffer_length, 0, len - rep->security_buffer_length); iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); } /* TODO append neg contexts? */ return 0; } struct smb2_pdu * smb2_cmd_session_setup_reply_async(struct smb2_context *smb2, struct smb2_session_setup_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_SESSION_SETUP, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_session_setup_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } #define IOV_OFFSET (rep->security_buffer_offset - SMB2_HEADER_SIZE - \ (SMB2_SESSION_SETUP_REPLY_SIZE & 0xfffe)) int smb2_process_session_setup_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_session_setup_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_SESSION_SETUP_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Session Setup " "reply. Expected %d, got %d", SMB2_SESSION_SETUP_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate session setup reply"); return -1; } pdu->payload = rep; smb2_get_uint16(iov, 2, &rep->session_flags); smb2_get_uint16(iov, 4, &rep->security_buffer_offset); smb2_get_uint16(iov, 6, &rep->security_buffer_length); if (rep->security_buffer_length && (rep->security_buffer_offset + rep->security_buffer_length > (uint16_t)smb2->spl)) { smb2_set_error(smb2, "Security buffer extends beyond end of " "PDU"); pdu->payload = NULL; free(rep); return -1; } /* Update session ID to use for future PDUs */ smb2->session_id = smb2->hdr.session_id; if (rep->security_buffer_length == 0) { return 0; } if (rep->security_buffer_offset < SMB2_HEADER_SIZE + (SMB2_SESSION_SETUP_REPLY_SIZE & 0xfffe)) { smb2_set_error(smb2, "Security buffer overlaps with " "Session Setup reply header"); pdu->payload = NULL; free(rep); return -1; } /* Return the amount of data that the security buffer will take up. * Including any padding before the security buffer itself. */ return IOV_OFFSET + rep->security_buffer_length; } int smb2_process_session_setup_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_session_setup_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; rep->security_buffer = &iov->buf[IOV_OFFSET]; return 0; } int smb2_process_session_setup_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_session_setup_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_SESSION_SETUP_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Session setup " "request. Expected %d, got %d", SMB2_SESSION_SETUP_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate session setup request"); return -1; } pdu->payload = req; smb2_get_uint8(iov, 2, &req->flags); smb2_get_uint8(iov, 3, &req->security_mode); smb2_get_uint32(iov, 4, &req->capabilities); smb2_get_uint32(iov, 8, &req->channel); /* smb2_get_uint16(iov, 12, &req->security_buffer_offset); */ smb2_get_uint16(iov, 14, &req->security_buffer_length); smb2_get_uint64(iov, 18, &req->previous_session_id); return req->security_buffer_length; } int smb2_process_session_setup_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_session_setup_request *req = (struct smb2_session_setup_request*)pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; req->security_buffer = iov->buf; return 0; } libsmb2-6.2/lib/errors.c0000664000175000017500000016075514732155517014263 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "smb2.h" const char *nterror_to_str(uint32_t status) { switch (status) { case SMB2_STATUS_SUCCESS: return "STATUS_SUCCESS"; case SMB2_STATUS_SHUTDOWN: return "STATUS_SHUTDOWN"; case SMB2_STATUS_PENDING: return "STATUS_PENDING"; case SMB2_STATUS_NO_MORE_FILES: return "STATUS_NO_MORE_FILES"; case SMB2_STATUS_UNSUCCESSFUL: return "SMB2_STATUS_UNSUCCESSFUL"; case SMB2_STATUS_NOT_IMPLEMENTED: return "STATUS_NOT_IMPLEMENTED"; case SMB2_STATUS_INVALID_INFO_CLASS: return "SMB2_STATUS_INVALID_INFO_CLASS"; case SMB2_STATUS_INFO_LENGTH_MISMATCH: return "SMB2_STATUS_INFO_LENGTH_MISMATCH"; case SMB2_STATUS_ACCESS_VIOLATION: return "SMB2_STATUS_ACCESS_VIOLATION"; case SMB2_STATUS_IN_PAGE_ERROR: return "SMB2_STATUS_IN_PAGE_ERROR"; case SMB2_STATUS_PAGEFILE_QUOTA: return "SMB2_STATUS_PAGEFILE_QUOTA"; case SMB2_STATUS_INVALID_HANDLE: return "STATUS_INVALID_HANDLE"; case SMB2_STATUS_BAD_INITIAL_STACK: return "SMB2_STATUS_BAD_INITIAL_STACK"; case SMB2_STATUS_BAD_INITIAL_PC: return "SMB2_STATUS_BAD_INITIAL_PC"; case SMB2_STATUS_INVALID_CID: return "SMB2_STATUS_INVALID_CID"; case SMB2_STATUS_TIMER_NOT_CANCELED: return "SMB2_STATUS_TIMER_NOT_CANCELED"; case SMB2_STATUS_INVALID_PARAMETER: return "STATUS_INVALID_PARAMETER"; case SMB2_STATUS_NO_SUCH_DEVICE: return "STATUS_NO_SUCH_DEVICE"; case SMB2_STATUS_NO_SUCH_FILE: return "STATUS_NO_SUCH_FILE"; case SMB2_STATUS_INVALID_DEVICE_REQUEST: return "STATUS_INVALID_DEVICE_REQUEST"; case SMB2_STATUS_END_OF_FILE: return "STATUS_END_OF_FILE"; case SMB2_STATUS_WRONG_VOLUME: return "SMB2_STATUS_WRONG_VOLUME"; case SMB2_STATUS_NO_MEDIA_IN_DEVICE: return "STATUS_NO_MEDIA_IN_DEVICE"; case SMB2_STATUS_UNRECOGNIZED_MEDIA: return "SMB2_STATUS_UNRECOGNIZED_MEDIA"; case SMB2_STATUS_NONEXISTENT_SECTOR: return "SMB2_STATUS_NONEXISTENT_SECTOR"; case SMB2_STATUS_MORE_PROCESSING_REQUIRED: return "STATUS_MORE_PROCESSING_REQUIRED"; case SMB2_STATUS_NO_MEMORY: return "SMB2_STATUS_NO_MEMORY"; case SMB2_STATUS_CONFLICTING_ADDRESSES: return "SMB2_STATUS_CONFLICTING_ADDRESSES"; case SMB2_STATUS_NOT_MAPPED_VIEW: return "SMB2_STATUS_NOT_MAPPED_VIEW"; case SMB2_STATUS_UNABLE_TO_FREE_VM: return "SMB2_STATUS_UNABLE_TO_FREE_VM"; case SMB2_STATUS_UNABLE_TO_DELETE_SECTION: return "SMB2_STATUS_UNABLE_TO_DELETE_SECTION"; case SMB2_STATUS_INVALID_SYSTEM_SERVICE: return "SMB2_STATUS_INVALID_SYSTEM_SERVICE"; case SMB2_STATUS_ILLEGAL_INSTRUCTION: return "SMB2_STATUS_ILLEGAL_INSTRUCTION"; case SMB2_STATUS_INVALID_LOCK_SEQUENCE: return "STATUS_INVALID_LOCK_SEQUENCE"; case SMB2_STATUS_INVALID_VIEW_SIZE: return "STATUS_INVALID_VIEW_SIZE"; case SMB2_STATUS_INVALID_FILE_FOR_SECTION: return "SMB2_STATUS_INVALID_FILE_FOR_SECTION"; case SMB2_STATUS_ALREADY_COMMITTED: return "STATUS_ALREADY_COMMITTED"; case SMB2_STATUS_ACCESS_DENIED: return "STATUS_ACCESS_DENIED"; case SMB2_STATUS_BUFFER_TOO_SMALL: return "SMB2_STATUS_BUFFER_TOO_SMALL"; case SMB2_STATUS_OBJECT_TYPE_MISMATCH: return "STATUS_OBJECT_TYPE_MISMATCH"; case SMB2_STATUS_NONCONTINUABLE_EXCEPTION: return "SMB2_STATUS_NONCONTINUABLE_EXCEPTION"; case SMB2_STATUS_INVALID_DISPOSITION: return "SMB2_STATUS_INVALID_DISPOSITION"; case SMB2_STATUS_UNWIND: return "SMB2_STATUS_UNWIND"; case SMB2_STATUS_BAD_STACK: return "SMB2_STATUS_BAD_STACK"; case SMB2_STATUS_INVALID_UNWIND_TARGET: return "SMB2_STATUS_INVALID_UNWIND_TARGET"; case SMB2_STATUS_NOT_LOCKED: return "SMB2_STATUS_NOT_LOCKED"; case SMB2_STATUS_PARITY_ERROR: return "SMB2_STATUS_PARITY_ERROR"; case SMB2_STATUS_UNABLE_TO_DECOMMIT_VM: return "SMB2_STATUS_UNABLE_TO_DECOMMIT_VM"; case SMB2_STATUS_NOT_COMMITTED: return "SMB2_STATUS_NOT_COMMITTED"; case SMB2_STATUS_INVALID_PORT_ATTRIBUTES: return "SMB2_STATUS_INVALID_PORT_ATTRIBUTES"; case SMB2_STATUS_PORT_MESSAGE_TOO_LONG: return "SMB2_STATUS_PORT_MESSAGE_TOO_LONG"; case SMB2_STATUS_INVALID_PARAMETER_MIX: return "SMB2_STATUS_INVALID_PARAMETER_MIX"; case SMB2_STATUS_INVALID_QUOTA_LOWER: return "SMB2_STATUS_INVALID_QUOTA_LOWER"; case SMB2_STATUS_DISK_CORRUPT_ERROR: return "SMB2_STATUS_DISK_CORRUPT_ERROR"; case SMB2_STATUS_OBJECT_NAME_INVALID: return "STATUS_OBJECT_NAME_INVALID"; case SMB2_STATUS_OBJECT_NAME_NOT_FOUND: return "STATUS_OBJECT_NAME_NOT_FOUND"; case SMB2_STATUS_OBJECT_NAME_COLLISION: return "STATUS_OBJECT_NAME_COLLISION"; case SMB2_STATUS_HANDLE_NOT_WAITABLE: return "SMB2_STATUS_HANDLE_NOT_WAITABLE"; case SMB2_STATUS_PORT_DISCONNECTED: return "STATUS_PORT_DISCONNECTED"; case SMB2_STATUS_DEVICE_ALREADY_ATTACHED: return "SMB2_STATUS_DEVICE_ALREADY_ATTACHED"; case SMB2_STATUS_OBJECT_PATH_INVALID: return "STATUS_OBJECT_PATH_INVALID"; case SMB2_STATUS_OBJECT_PATH_NOT_FOUND: return "STATUS_OBJECT_PATH_NOT_FOUND"; case SMB2_STATUS_OBJECT_PATH_SYNTAX_BAD: return "STATUS_OBJECT_PATH_SYNTAX_BAD"; case SMB2_STATUS_DATA_OVERRUN: return "SMB2_STATUS_DATA_OVERRUN"; case SMB2_STATUS_DATA_LATE_ERROR: return "SMB2_STATUS_DATA_LATE_ERROR"; case SMB2_STATUS_DATA_ERROR: return "STATUS_DATA_ERROR"; case SMB2_STATUS_CRC_ERROR: return "STATUS_CRC_ERROR"; case SMB2_STATUS_SECTION_TOO_BIG: return "STATUS_SECTION_TOO_BIG"; case SMB2_STATUS_PORT_CONNECTION_REFUSED: return "STATUS_PORT_CONNECTION_REFUSED"; case SMB2_STATUS_INVALID_PORT_HANDLE: return "STATUS_INVALID_PORT_HANDLE"; case SMB2_STATUS_SHARING_VIOLATION: return "STATUS_SHARING_VIOLATION"; case SMB2_STATUS_QUOTA_EXCEEDED: return "SMB2_STATUS_QUOTA_EXCEEDED"; case SMB2_STATUS_INVALID_PAGE_PROTECTION: return "SMB2_STATUS_INVALID_PAGE_PROTECTION"; case SMB2_STATUS_MUTANT_NOT_OWNED: return "SMB2_STATUS_MUTANT_NOT_OWNED"; case SMB2_STATUS_SEMAPHORE_LIMIT_EXCEEDED: return "SMB2_STATUS_SEMAPHORE_LIMIT_EXCEEDED"; case SMB2_STATUS_PORT_ALREADY_SET: return "SMB2_STATUS_PORT_ALREADY_SET"; case SMB2_STATUS_SECTION_NOT_IMAGE: return "SMB2_STATUS_SECTION_NOT_IMAGE"; case SMB2_STATUS_SUSPEND_COUNT_EXCEEDED: return "SMB2_STATUS_SUSPEND_COUNT_EXCEEDED"; case SMB2_STATUS_THREAD_IS_TERMINATING: return "STATUS_THREAD_IS_TERMINATING"; case SMB2_STATUS_BAD_WORKING_SET_LIMIT: return "SMB2_STATUS_BAD_WORKING_SET_LIMIT"; case SMB2_STATUS_INCOMPATIBLE_FILE_MAP: return "SMB2_STATUS_INCOMPATIBLE_FILE_MAP"; case SMB2_STATUS_SECTION_PROTECTION: return "SMB2_STATUS_SECTION_PROTECTION"; case SMB2_STATUS_EAS_NOT_SUPPORTED: return "SMB2_STATUS_EAS_NOT_SUPPORTED"; case SMB2_STATUS_EA_TOO_LARGE: return "SMB2_STATUS_EA_TOO_LARGE"; case SMB2_STATUS_NONEXISTENT_EA_ENTRY: return "SMB2_STATUS_NONEXISTENT_EA_ENTRY"; case SMB2_STATUS_NO_EAS_ON_FILE: return "SMB2_STATUS_NO_EAS_ON_FILE"; case SMB2_STATUS_EA_CORRUPT_ERROR: return "SMB2_STATUS_EA_CORRUPT_ERROR"; case SMB2_STATUS_FILE_LOCK_CONFLICT: return "STATUS_FILE_LOCK_CONFLICT"; case SMB2_STATUS_LOCK_NOT_GRANTED: return "STATUS_LOCK_NOT_GRANTED"; case SMB2_STATUS_DELETE_PENDING: return "STATUS_DELETE_PENDING"; case SMB2_STATUS_CTL_FILE_NOT_SUPPORTED: return "SMB2_STATUS_CTL_FILE_NOT_SUPPORTED"; case SMB2_STATUS_UNKNOWN_REVISION: return "SMB2_STATUS_UNKNOWN_REVISION"; case SMB2_STATUS_REVISION_MISMATCH: return "SMB2_STATUS_REVISION_MISMATCH"; case SMB2_STATUS_INVALID_OWNER: return "SMB2_STATUS_INVALID_OWNER"; case SMB2_STATUS_INVALID_PRIMARY_GROUP: return "SMB2_STATUS_INVALID_PRIMARY_GROUP"; case SMB2_STATUS_NO_IMPERSONATION_TOKEN: return "SMB2_STATUS_NO_IMPERSONATION_TOKEN"; case SMB2_STATUS_CANT_DISABLE_MANDATORY: return "SMB2_STATUS_CANT_DISABLE_MANDATORY"; case SMB2_STATUS_NO_LOGON_SERVERS: return "SMB2_STATUS_NO_LOGON_SERVERS"; case SMB2_STATUS_NO_SUCH_LOGON_SESSION: return "SMB2_STATUS_NO_SUCH_LOGON_SESSION"; case SMB2_STATUS_NO_SUCH_PRIVILEGE: return "SMB2_STATUS_NO_SUCH_PRIVILEGE"; case SMB2_STATUS_PRIVILEGE_NOT_HELD: return "STATUS_PRIVILEGE_NOT_HELD"; case SMB2_STATUS_INVALID_ACCOUNT_NAME: return "SMB2_STATUS_INVALID_ACCOUNT_NAME"; case SMB2_STATUS_USER_EXISTS: return "SMB2_STATUS_USER_EXISTS"; case SMB2_STATUS_NO_SUCH_USER: return "SMB2_STATUS_NO_SUCH_USER"; case SMB2_STATUS_GROUP_EXISTS: return "SMB2_STATUS_GROUP_EXISTS"; case SMB2_STATUS_NO_SUCH_GROUP: return "SMB2_STATUS_NO_SUCH_GROUP"; case SMB2_STATUS_MEMBER_IN_GROUP: return "SMB2_STATUS_MEMBER_IN_GROUP"; case SMB2_STATUS_MEMBER_NOT_IN_GROUP: return "SMB2_STATUS_MEMBER_NOT_IN_GROUP"; case SMB2_STATUS_LAST_ADMIN: return "SMB2_STATUS_LAST_ADMIN"; case SMB2_STATUS_WRONG_PASSWORD: return "SMB2_STATUS_WRONG_PASSWORD"; case SMB2_STATUS_ILL_FORMED_PASSWORD: return "SMB2_STATUS_ILL_FORMED_PASSWORD"; case SMB2_STATUS_PASSWORD_RESTRICTION: return "SMB2_STATUS_PASSWORD_RESTRICTION"; case SMB2_STATUS_LOGON_FAILURE: return "STATUS_LOGON_FAILURE"; case SMB2_STATUS_ACCOUNT_RESTRICTION: return "STATUS_ACCOUNT_RESTRICTION"; case SMB2_STATUS_INVALID_LOGON_HOURS: return "STATUS_INVALID_LOGON_HOURS"; case SMB2_STATUS_INVALID_WORKSTATION: return "SMB2_STATUS_INVALID_WORKSTATION"; case SMB2_STATUS_PASSWORD_EXPIRED: return "STATUS_PASSWORD_EXPIRED"; case SMB2_STATUS_ACCOUNT_DISABLED: return "STATUS_ACCOUNT_DISABLED"; case SMB2_STATUS_NONE_MAPPED: return "SMB2_STATUS_NONE_MAPPED"; case SMB2_STATUS_TOO_MANY_LUIDS_REQUESTED: return "SMB2_STATUS_TOO_MANY_LUIDS_REQUESTED"; case SMB2_STATUS_LUIDS_EXHAUSTED: return "SMB2_STATUS_LUIDS_EXHAUSTED"; case SMB2_STATUS_INVALID_SUB_AUTHORITY: return "SMB2_STATUS_INVALID_SUB_AUTHORITY"; case SMB2_STATUS_INVALID_ACL: return "SMB2_STATUS_INVALID_ACL"; case SMB2_STATUS_INVALID_SID: return "SMB2_STATUS_INVALID_SID"; case SMB2_STATUS_INVALID_SECURITY_DESCR: return "SMB2_STATUS_INVALID_SECURITY_DESCR"; case SMB2_STATUS_PROCEDURE_NOT_FOUND: return "SMB2_STATUS_PROCEDURE_NOT_FOUND"; case SMB2_STATUS_INVALID_IMAGE_FORMAT: return "SMB2_STATUS_INVALID_IMAGE_FORMAT"; case SMB2_STATUS_NO_TOKEN: return "SMB2_STATUS_NO_TOKEN"; case SMB2_STATUS_BAD_INHERITANCE_ACL: return "SMB2_STATUS_BAD_INHERITANCE_ACL"; case SMB2_STATUS_RANGE_NOT_LOCKED: return "SMB2_STATUS_RANGE_NOT_LOCKED"; case SMB2_STATUS_DISK_FULL: return "STATUS_DISK_FULL"; case SMB2_STATUS_SERVER_DISABLED: return "SMB2_STATUS_SERVER_DISABLED"; case SMB2_STATUS_SERVER_NOT_DISABLED: return "SMB2_STATUS_SERVER_NOT_DISABLED"; case SMB2_STATUS_TOO_MANY_GUIDS_REQUESTED: return "SMB2_STATUS_TOO_MANY_GUIDS_REQUESTED"; case SMB2_STATUS_GUIDS_EXHAUSTED: return "SMB2_STATUS_GUIDS_EXHAUSTED"; case SMB2_STATUS_INVALID_ID_AUTHORITY: return "SMB2_STATUS_INVALID_ID_AUTHORITY"; case SMB2_STATUS_AGENTS_EXHAUSTED: return "SMB2_STATUS_AGENTS_EXHAUSTED"; case SMB2_STATUS_INVALID_VOLUME_LABEL: return "SMB2_STATUS_INVALID_VOLUME_LABEL"; case SMB2_STATUS_SECTION_NOT_EXTENDED: return "SMB2_STATUS_SECTION_NOT_EXTENDED"; case SMB2_STATUS_NOT_MAPPED_DATA: return "SMB2_STATUS_NOT_MAPPED_DATA"; case SMB2_STATUS_RESOURCE_DATA_NOT_FOUND: return "SMB2_STATUS_RESOURCE_DATA_NOT_FOUND"; case SMB2_STATUS_RESOURCE_TYPE_NOT_FOUND: return "SMB2_STATUS_RESOURCE_TYPE_NOT_FOUND"; case SMB2_STATUS_RESOURCE_NAME_NOT_FOUND: return "SMB2_STATUS_RESOURCE_NAME_NOT_FOUND"; case SMB2_STATUS_ARRAY_BOUNDS_EXCEEDED: return "SMB2_STATUS_ARRAY_BOUNDS_EXCEEDED"; case SMB2_STATUS_FLOAT_DENORMAL_OPERAND: return "SMB2_STATUS_FLOAT_DENORMAL_OPERAND"; case SMB2_STATUS_FLOAT_DIVIDE_BY_ZERO: return "SMB2_STATUS_FLOAT_DIVIDE_BY_ZERO"; case SMB2_STATUS_FLOAT_INEXACT_RESULT: return "SMB2_STATUS_FLOAT_INEXACT_RESULT"; case SMB2_STATUS_FLOAT_INVALID_OPERATION: return "SMB2_STATUS_FLOAT_INVALID_OPERATION"; case SMB2_STATUS_FLOAT_OVERFLOW: return "SMB2_STATUS_FLOAT_OVERFLOW"; case SMB2_STATUS_FLOAT_STACK_CHECK: return "SMB2_STATUS_FLOAT_STACK_CHECK"; case SMB2_STATUS_FLOAT_UNDERFLOW: return "SMB2_STATUS_FLOAT_UNDERFLOW"; case SMB2_STATUS_INTEGER_DIVIDE_BY_ZERO: return "SMB2_STATUS_INTEGER_DIVIDE_BY_ZERO"; case SMB2_STATUS_INTEGER_OVERFLOW: return "SMB2_STATUS_INTEGER_OVERFLOW"; case SMB2_STATUS_PRIVILEGED_INSTRUCTION: return "SMB2_STATUS_PRIVILEGED_INSTRUCTION"; case SMB2_STATUS_TOO_MANY_PAGING_FILES: return "STATUS_TOO_MANY_PAGING_FILES"; case SMB2_STATUS_FILE_INVALID: return "SMB2_STATUS_FILE_INVALID"; case SMB2_STATUS_ALLOTTED_SPACE_EXCEEDED: return "SMB2_STATUS_ALLOTTED_SPACE_EXCEEDED"; case SMB2_STATUS_INSUFFICIENT_RESOURCES: return "SMB2_STATUS_INSUFFICIENT_RESOURCES"; case SMB2_STATUS_DFS_EXIT_PATH_FOUND: return "STATUS_DFS_EXIT_PATH_FOUND"; case SMB2_STATUS_DEVICE_DATA_ERROR: return "STATUS_DEVICE_DATA_ERROR"; case SMB2_STATUS_DEVICE_NOT_CONNECTED: return "SMB2_STATUS_DEVICE_NOT_CONNECTED"; case SMB2_STATUS_DEVICE_POWER_FAILURE: return "SMB2_STATUS_DEVICE_POWER_FAILURE"; case SMB2_STATUS_FREE_VM_NOT_AT_BASE: return "SMB2_STATUS_FREE_VM_NOT_AT_BASE"; case SMB2_STATUS_MEMORY_NOT_ALLOCATED: return "SMB2_STATUS_MEMORY_NOT_ALLOCATED"; case SMB2_STATUS_WORKING_SET_QUOTA: return "SMB2_STATUS_WORKING_SET_QUOTA"; case SMB2_STATUS_MEDIA_WRITE_PROTECTED: return "STATUS_MEDIA_WRITE_PROTECTED"; case SMB2_STATUS_DEVICE_NOT_READY: return "SMB2_STATUS_DEVICE_NOT_READY"; case SMB2_STATUS_INVALID_GROUP_ATTRIBUTES: return "SMB2_STATUS_INVALID_GROUP_ATTRIBUTES"; case SMB2_STATUS_BAD_IMPERSONATION_LEVEL: return "SMB2_STATUS_BAD_IMPERSONATION_LEVEL"; case SMB2_STATUS_CANT_OPEN_ANONYMOUS: return "SMB2_STATUS_CANT_OPEN_ANONYMOUS"; case SMB2_STATUS_BAD_VALIDATION_CLASS: return "SMB2_STATUS_BAD_VALIDATION_CLASS"; case SMB2_STATUS_BAD_TOKEN_TYPE: return "SMB2_STATUS_BAD_TOKEN_TYPE"; case SMB2_STATUS_BAD_MASTER_BOOT_RECORD: return "SMB2_STATUS_BAD_MASTER_BOOT_RECORD"; case SMB2_STATUS_INSTRUCTION_MISALIGNMENT: return "SMB2_STATUS_INSTRUCTION_MISALIGNMENT"; case SMB2_STATUS_INSTANCE_NOT_AVAILABLE: return "SMB2_STATUS_INSTANCE_NOT_AVAILABLE"; case SMB2_STATUS_PIPE_NOT_AVAILABLE: return "SMB2_STATUS_PIPE_NOT_AVAILABLE"; case SMB2_STATUS_INVALID_PIPE_STATE: return "SMB2_STATUS_INVALID_PIPE_STATE"; case SMB2_STATUS_PIPE_BUSY: return "SMB2_STATUS_PIPE_BUSY"; case SMB2_STATUS_ILLEGAL_FUNCTION: return "STATUS_ILLEGAL_FUNCTION"; case SMB2_STATUS_PIPE_DISCONNECTED: return "STATUS_PIPE_DISCONNECTED"; case SMB2_STATUS_PIPE_CLOSING: return "SMB2_STATUS_PIPE_CLOSING"; case SMB2_STATUS_PIPE_CONNECTED: return "SMB2_STATUS_PIPE_CONNECTED"; case SMB2_STATUS_PIPE_LISTENING: return "SMB2_STATUS_PIPE_LISTENING"; case SMB2_STATUS_INVALID_READ_MODE: return "SMB2_STATUS_INVALID_READ_MODE"; case SMB2_STATUS_IO_TIMEOUT: return "SMB2_STATUS_IO_TIMEOUT"; case SMB2_STATUS_FILE_FORCED_CLOSED: return "SMB2_STATUS_FILE_FORCED_CLOSED"; case SMB2_STATUS_PROFILING_NOT_STARTED: return "SMB2_STATUS_PROFILING_NOT_STARTED"; case SMB2_STATUS_PROFILING_NOT_STOPPED: return "SMB2_STATUS_PROFILING_NOT_STOPPED"; case SMB2_STATUS_COULD_NOT_INTERPRET: return "SMB2_STATUS_COULD_NOT_INTERPRET"; case SMB2_STATUS_FILE_IS_A_DIRECTORY: return "STATUS_FILE_IS_A_DIRECTORY"; case SMB2_STATUS_NOT_SUPPORTED: return "SMB2_STATUS_NOT_SUPPORTED"; case SMB2_STATUS_REMOTE_NOT_LISTENING: return "SMB2_STATUS_REMOTE_NOT_LISTENING"; case SMB2_STATUS_DUPLICATE_NAME: return "SMB2_STATUS_DUPLICATE_NAME"; case SMB2_STATUS_BAD_NETWORK_PATH: return "SMB2_STATUS_BAD_NETWORK_PATH"; case SMB2_STATUS_NETWORK_BUSY: return "SMB2_STATUS_NETWORK_BUSY"; case SMB2_STATUS_DEVICE_DOES_NOT_EXIST: return "SMB2_STATUS_DEVICE_DOES_NOT_EXIST"; case SMB2_STATUS_TOO_MANY_COMMANDS: return "SMB2_STATUS_TOO_MANY_COMMANDS"; case SMB2_STATUS_ADAPTER_HARDWARE_ERROR: return "SMB2_STATUS_ADAPTER_HARDWARE_ERROR"; case SMB2_STATUS_INVALID_NETWORK_RESPONSE: return "SMB2_STATUS_INVALID_NETWORK_RESPONSE"; case SMB2_STATUS_UNEXPECTED_NETWORK_ERROR: return "SMB2_STATUS_UNEXPECTED_NETWORK_ERROR"; case SMB2_STATUS_BAD_REMOTE_ADAPTER: return "SMB2_STATUS_BAD_REMOTE_ADAPTER"; case SMB2_STATUS_PRINT_QUEUE_FULL: return "SMB2_STATUS_PRINT_QUEUE_FULL"; case SMB2_STATUS_NO_SPOOL_SPACE: return "SMB2_STATUS_NO_SPOOL_SPACE"; case SMB2_STATUS_PRINT_CANCELLED: return "SMB2_STATUS_PRINT_CANCELLED"; case SMB2_STATUS_NETWORK_NAME_DELETED: return "SMB2_STATUS_NETWORK_NAME_DELETED"; case SMB2_STATUS_NETWORK_ACCESS_DENIED: return "STATUS_NETWORK_ACCESS_DENIED"; case SMB2_STATUS_BAD_DEVICE_TYPE: return "SMB2_STATUS_BAD_DEVICE_TYPE"; case SMB2_STATUS_BAD_NETWORK_NAME: return "STATUS_BAD_NETWORK_NAME"; case SMB2_STATUS_TOO_MANY_NAMES: return "SMB2_STATUS_TOO_MANY_NAMES"; case SMB2_STATUS_TOO_MANY_SESSIONS: return "SMB2_STATUS_TOO_MANY_SESSIONS"; case SMB2_STATUS_SHARING_PAUSED: return "SMB2_STATUS_SHARING_PAUSED"; case SMB2_STATUS_REQUEST_NOT_ACCEPTED: return "SMB2_STATUS_REQUEST_NOT_ACCEPTED"; case SMB2_STATUS_REDIRECTOR_PAUSED: return "SMB2_STATUS_REDIRECTOR_PAUSED"; case SMB2_STATUS_NET_WRITE_FAULT: return "SMB2_STATUS_NET_WRITE_FAULT"; case SMB2_STATUS_PROFILING_AT_LIMIT: return "SMB2_STATUS_PROFILING_AT_LIMIT"; case SMB2_STATUS_NOT_SAME_DEVICE: return "STATUS_NOT_SAME_DEVICE"; case SMB2_STATUS_FILE_RENAMED: return "STATUS_FILE_RENAMED"; case SMB2_STATUS_VIRTUAL_CIRCUIT_CLOSED: return "SMB2_STATUS_VIRTUAL_CIRCUIT_CLOSED"; case SMB2_STATUS_NO_SECURITY_ON_OBJECT: return "SMB2_STATUS_NO_SECURITY_ON_OBJECT"; case SMB2_STATUS_CANT_WAIT: return "SMB2_STATUS_CANT_WAIT"; case SMB2_STATUS_PIPE_EMPTY: return "SMB2_STATUS_PIPE_EMPTY"; case SMB2_STATUS_CANT_ACCESS_DOMAIN_INFO: return "SMB2_STATUS_CANT_ACCESS_DOMAIN_INFO"; case SMB2_STATUS_CANT_TERMINATE_SELF: return "SMB2_STATUS_CANT_TERMINATE_SELF"; case SMB2_STATUS_INVALID_SERVER_STATE: return "SMB2_STATUS_INVALID_SERVER_STATE"; case SMB2_STATUS_INVALID_DOMAIN_STATE: return "SMB2_STATUS_INVALID_DOMAIN_STATE"; case SMB2_STATUS_INVALID_DOMAIN_ROLE: return "SMB2_STATUS_INVALID_DOMAIN_ROLE"; case SMB2_STATUS_NO_SUCH_DOMAIN: return "SMB2_STATUS_NO_SUCH_DOMAIN"; case SMB2_STATUS_DOMAIN_EXISTS: return "SMB2_STATUS_DOMAIN_EXISTS"; case SMB2_STATUS_DOMAIN_LIMIT_EXCEEDED: return "SMB2_STATUS_DOMAIN_LIMIT_EXCEEDED"; case SMB2_STATUS_OPLOCK_NOT_GRANTED: return "SMB2_STATUS_OPLOCK_NOT_GRANTED"; case SMB2_STATUS_INVALID_OPLOCK_PROTOCOL: return "SMB2_STATUS_INVALID_OPLOCK_PROTOCOL"; case SMB2_STATUS_INTERNAL_DB_CORRUPTION: return "SMB2_STATUS_INTERNAL_DB_CORRUPTION"; case SMB2_STATUS_INTERNAL_ERROR: return "SMB2_STATUS_INTERNAL_ERROR"; case SMB2_STATUS_GENERIC_NOT_MAPPED: return "SMB2_STATUS_GENERIC_NOT_MAPPED"; case SMB2_STATUS_BAD_DESCRIPTOR_FORMAT: return "SMB2_STATUS_BAD_DESCRIPTOR_FORMAT"; case SMB2_STATUS_INVALID_USER_BUFFER: return "SMB2_STATUS_INVALID_USER_BUFFER"; case SMB2_STATUS_UNEXPECTED_IO_ERROR: return "SMB2_STATUS_UNEXPECTED_IO_ERROR"; case SMB2_STATUS_UNEXPECTED_MM_CREATE_ERR: return "SMB2_STATUS_UNEXPECTED_MM_CREATE_ERR"; case SMB2_STATUS_UNEXPECTED_MM_MAP_ERROR: return "SMB2_STATUS_UNEXPECTED_MM_MAP_ERROR"; case SMB2_STATUS_UNEXPECTED_MM_EXTEND_ERR: return "SMB2_STATUS_UNEXPECTED_MM_EXTEND_ERR"; case SMB2_STATUS_NOT_LOGON_PROCESS: return "SMB2_STATUS_NOT_LOGON_PROCESS"; case SMB2_STATUS_LOGON_SESSION_EXISTS: return "SMB2_STATUS_LOGON_SESSION_EXISTS"; case SMB2_STATUS_INVALID_PARAMETER_1: return "SMB2_STATUS_INVALID_PARAMETER_1"; case SMB2_STATUS_INVALID_PARAMETER_2: return "SMB2_STATUS_INVALID_PARAMETER_2"; case SMB2_STATUS_INVALID_PARAMETER_3: return "SMB2_STATUS_INVALID_PARAMETER_3"; case SMB2_STATUS_INVALID_PARAMETER_4: return "SMB2_STATUS_INVALID_PARAMETER_4"; case SMB2_STATUS_INVALID_PARAMETER_5: return "SMB2_STATUS_INVALID_PARAMETER_5"; case SMB2_STATUS_INVALID_PARAMETER_6: return "SMB2_STATUS_INVALID_PARAMETER_6"; case SMB2_STATUS_INVALID_PARAMETER_7: return "SMB2_STATUS_INVALID_PARAMETER_7"; case SMB2_STATUS_INVALID_PARAMETER_8: return "SMB2_STATUS_INVALID_PARAMETER_8"; case SMB2_STATUS_INVALID_PARAMETER_9: return "SMB2_STATUS_INVALID_PARAMETER_9"; case SMB2_STATUS_INVALID_PARAMETER_10: return "SMB2_STATUS_INVALID_PARAMETER_10"; case SMB2_STATUS_INVALID_PARAMETER_11: return "SMB2_STATUS_INVALID_PARAMETER_11"; case SMB2_STATUS_INVALID_PARAMETER_12: return "SMB2_STATUS_INVALID_PARAMETER_12"; case SMB2_STATUS_REDIRECTOR_NOT_STARTED: return "STATUS_REDIRECTOR_NOT_STARTED"; case SMB2_STATUS_REDIRECTOR_STARTED: return "SMB2_STATUS_REDIRECTOR_STARTED"; case SMB2_STATUS_STACK_OVERFLOW: return "SMB2_STATUS_STACK_OVERFLOW"; case SMB2_STATUS_NO_SUCH_PACKAGE: return "SMB2_STATUS_NO_SUCH_PACKAGE"; case SMB2_STATUS_BAD_FUNCTION_TABLE: return "SMB2_STATUS_BAD_FUNCTION_TABLE"; case SMB2_STATUS_DIRECTORY_NOT_EMPTY: return "STATUS_DIRECTORY_NOT_EMPTY"; case SMB2_STATUS_FILE_CORRUPT_ERROR: return "SMB2_STATUS_FILE_CORRUPT_ERROR"; case SMB2_STATUS_NOT_A_DIRECTORY: return "STATUS_NOT_A_DIRECTORY"; case SMB2_STATUS_BAD_LOGON_SESSION_STATE: return "SMB2_STATUS_BAD_LOGON_SESSION_STATE"; case SMB2_STATUS_LOGON_SESSION_COLLISION: return "SMB2_STATUS_LOGON_SESSION_COLLISION"; case SMB2_STATUS_NAME_TOO_LONG: return "SMB2_STATUS_NAME_TOO_LONG"; case SMB2_STATUS_FILES_OPEN: return "SMB2_STATUS_FILES_OPEN"; case SMB2_STATUS_CONNECTION_IN_USE: return "SMB2_STATUS_CONNECTION_IN_USE"; case SMB2_STATUS_MESSAGE_NOT_FOUND: return "SMB2_STATUS_MESSAGE_NOT_FOUND"; case SMB2_STATUS_PROCESS_IS_TERMINATING: return "STATUS_PROCESS_IS_TERMINATING"; case SMB2_STATUS_INVALID_LOGON_TYPE: return "SMB2_STATUS_INVALID_LOGON_TYPE"; case SMB2_STATUS_NO_GUID_TRANSLATION: return "SMB2_STATUS_NO_GUID_TRANSLATION"; case SMB2_STATUS_CANNOT_IMPERSONATE: return "SMB2_STATUS_CANNOT_IMPERSONATE"; case SMB2_STATUS_IMAGE_ALREADY_LOADED: return "SMB2_STATUS_IMAGE_ALREADY_LOADED"; case SMB2_STATUS_ABIOS_NOT_PRESENT: return "SMB2_STATUS_ABIOS_NOT_PRESENT"; case SMB2_STATUS_ABIOS_LID_NOT_EXIST: return "SMB2_STATUS_ABIOS_LID_NOT_EXIST"; case SMB2_STATUS_ABIOS_LID_ALREADY_OWNED: return "SMB2_STATUS_ABIOS_LID_ALREADY_OWNED"; case SMB2_STATUS_ABIOS_NOT_LID_OWNER: return "SMB2_STATUS_ABIOS_NOT_LID_OWNER"; case SMB2_STATUS_ABIOS_INVALID_COMMAND: return "SMB2_STATUS_ABIOS_INVALID_COMMAND"; case SMB2_STATUS_ABIOS_INVALID_LID: return "SMB2_STATUS_ABIOS_INVALID_LID"; case SMB2_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE: return "SMB2_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE"; case SMB2_STATUS_ABIOS_INVALID_SELECTOR: return "SMB2_STATUS_ABIOS_INVALID_SELECTOR"; case SMB2_STATUS_NO_LDT: return "SMB2_STATUS_NO_LDT"; case SMB2_STATUS_INVALID_LDT_SIZE: return "SMB2_STATUS_INVALID_LDT_SIZE"; case SMB2_STATUS_INVALID_LDT_OFFSET: return "SMB2_STATUS_INVALID_LDT_OFFSET"; case SMB2_STATUS_INVALID_LDT_DESCRIPTOR: return "SMB2_STATUS_INVALID_LDT_DESCRIPTOR"; case SMB2_STATUS_INVALID_IMAGE_NE_FORMAT: return "SMB2_STATUS_INVALID_IMAGE_NE_FORMAT"; case SMB2_STATUS_RXACT_INVALID_STATE: return "SMB2_STATUS_RXACT_INVALID_STATE"; case SMB2_STATUS_RXACT_COMMIT_FAILURE: return "SMB2_STATUS_RXACT_COMMIT_FAILURE"; case SMB2_STATUS_MAPPED_FILE_SIZE_ZERO: return "SMB2_STATUS_MAPPED_FILE_SIZE_ZERO"; case SMB2_STATUS_TOO_MANY_OPENED_FILES: return "STATUS_TOO_MANY_OPENED_FILES"; case SMB2_STATUS_CANCELLED: return "STATUS_CANCELLED"; case SMB2_STATUS_CANNOT_DELETE: return "STATUS_CANNOT_DELETE"; case SMB2_STATUS_INVALID_COMPUTER_NAME: return "SMB2_STATUS_INVALID_COMPUTER_NAME"; case SMB2_STATUS_FILE_DELETED: return "STATUS_FILE_DELETED"; case SMB2_STATUS_SPECIAL_ACCOUNT: return "SMB2_STATUS_SPECIAL_ACCOUNT"; case SMB2_STATUS_SPECIAL_GROUP: return "SMB2_STATUS_SPECIAL_GROUP"; case SMB2_STATUS_SPECIAL_USER: return "SMB2_STATUS_SPECIAL_USER"; case SMB2_STATUS_MEMBERS_PRIMARY_GROUP: return "SMB2_STATUS_MEMBERS_PRIMARY_GROUP"; case SMB2_STATUS_FILE_CLOSED: return "STATUS_FILE_CLOSED"; case SMB2_STATUS_TOO_MANY_THREADS: return "SMB2_STATUS_TOO_MANY_THREADS"; case SMB2_STATUS_THREAD_NOT_IN_PROCESS: return "SMB2_STATUS_THREAD_NOT_IN_PROCESS"; case SMB2_STATUS_TOKEN_ALREADY_IN_USE: return "SMB2_STATUS_TOKEN_ALREADY_IN_USE"; case SMB2_STATUS_PAGEFILE_QUOTA_EXCEEDED: return "SMB2_STATUS_PAGEFILE_QUOTA_EXCEEDED"; case SMB2_STATUS_COMMITMENT_LIMIT: return "SMB2_STATUS_COMMITMENT_LIMIT"; case SMB2_STATUS_INVALID_IMAGE_LE_FORMAT: return "SMB2_STATUS_INVALID_IMAGE_LE_FORMAT"; case SMB2_STATUS_INVALID_IMAGE_NOT_MZ: return "SMB2_STATUS_INVALID_IMAGE_NOT_MZ"; case SMB2_STATUS_INVALID_IMAGE_PROTECT: return "SMB2_STATUS_INVALID_IMAGE_PROTECT"; case SMB2_STATUS_INVALID_IMAGE_WIN_16: return "SMB2_STATUS_INVALID_IMAGE_WIN_16"; case SMB2_STATUS_LOGON_SERVER_CONFLICT: return "SMB2_STATUS_LOGON_SERVER_CONFLICT"; case SMB2_STATUS_TIME_DIFFERENCE_AT_DC: return "SMB2_STATUS_TIME_DIFFERENCE_AT_DC"; case SMB2_STATUS_SYNCHRONIZATION_REQUIRED: return "SMB2_STATUS_SYNCHRONIZATION_REQUIRED"; case SMB2_STATUS_DLL_NOT_FOUND: return "SMB2_STATUS_DLL_NOT_FOUND"; case SMB2_STATUS_OPEN_FAILED: return "SMB2_STATUS_OPEN_FAILED"; case SMB2_STATUS_IO_PRIVILEGE_FAILED: return "SMB2_STATUS_IO_PRIVILEGE_FAILED"; case SMB2_STATUS_ORDINAL_NOT_FOUND: return "SMB2_STATUS_ORDINAL_NOT_FOUND"; case SMB2_STATUS_ENTRYPOINT_NOT_FOUND: return "SMB2_STATUS_ENTRYPOINT_NOT_FOUND"; case SMB2_STATUS_CONTROL_C_EXIT: return "SMB2_STATUS_CONTROL_C_EXIT"; case SMB2_STATUS_LOCAL_DISCONNECT: return "SMB2_STATUS_LOCAL_DISCONNECT"; case SMB2_STATUS_REMOTE_DISCONNECT: return "SMB2_STATUS_REMOTE_DISCONNECT"; case SMB2_STATUS_REMOTE_RESOURCES: return "SMB2_STATUS_REMOTE_RESOURCES"; case SMB2_STATUS_LINK_FAILED: return "SMB2_STATUS_LINK_FAILED"; case SMB2_STATUS_LINK_TIMEOUT: return "SMB2_STATUS_LINK_TIMEOUT"; case SMB2_STATUS_INVALID_CONNECTION: return "SMB2_STATUS_INVALID_CONNECTION"; case SMB2_STATUS_INVALID_ADDRESS: return "SMB2_STATUS_INVALID_ADDRESS"; case SMB2_STATUS_DLL_INIT_FAILED: return "SMB2_STATUS_DLL_INIT_FAILED"; case SMB2_STATUS_MISSING_SYSTEMFILE: return "SMB2_STATUS_MISSING_SYSTEMFILE"; case SMB2_STATUS_UNHANDLED_EXCEPTION: return "SMB2_STATUS_UNHANDLED_EXCEPTION"; case SMB2_STATUS_APP_INIT_FAILURE: return "SMB2_STATUS_APP_INIT_FAILURE"; case SMB2_STATUS_PAGEFILE_CREATE_FAILED: return "SMB2_STATUS_PAGEFILE_CREATE_FAILED"; case SMB2_STATUS_NO_PAGEFILE: return "SMB2_STATUS_NO_PAGEFILE"; case SMB2_STATUS_INVALID_LEVEL: return "SMB2_STATUS_INVALID_LEVEL"; case SMB2_STATUS_WRONG_PASSWORD_CORE: return "SMB2_STATUS_WRONG_PASSWORD_CORE"; case SMB2_STATUS_ILLEGAL_FLOAT_CONTEXT: return "SMB2_STATUS_ILLEGAL_FLOAT_CONTEXT"; case SMB2_STATUS_PIPE_BROKEN: return "SMB2_STATUS_PIPE_BROKEN"; case SMB2_STATUS_REGISTRY_CORRUPT: return "SMB2_STATUS_REGISTRY_CORRUPT"; case SMB2_STATUS_REGISTRY_IO_FAILED: return "SMB2_STATUS_REGISTRY_IO_FAILED"; case SMB2_STATUS_NO_EVENT_PAIR: return "SMB2_STATUS_NO_EVENT_PAIR"; case SMB2_STATUS_UNRECOGNIZED_VOLUME: return "SMB2_STATUS_UNRECOGNIZED_VOLUME"; case SMB2_STATUS_SERIAL_NO_DEVICE_INITED: return "SMB2_STATUS_SERIAL_NO_DEVICE_INITED"; case SMB2_STATUS_NO_SUCH_ALIAS: return "SMB2_STATUS_NO_SUCH_ALIAS"; case SMB2_STATUS_MEMBER_NOT_IN_ALIAS: return "SMB2_STATUS_MEMBER_NOT_IN_ALIAS"; case SMB2_STATUS_MEMBER_IN_ALIAS: return "SMB2_STATUS_MEMBER_IN_ALIAS"; case SMB2_STATUS_ALIAS_EXISTS: return "SMB2_STATUS_ALIAS_EXISTS"; case SMB2_STATUS_LOGON_NOT_GRANTED: return "SMB2_STATUS_LOGON_NOT_GRANTED"; case SMB2_STATUS_TOO_MANY_SECRETS: return "SMB2_STATUS_TOO_MANY_SECRETS"; case SMB2_STATUS_SECRET_TOO_LONG: return "SMB2_STATUS_SECRET_TOO_LONG"; case SMB2_STATUS_INTERNAL_DB_ERROR: return "SMB2_STATUS_INTERNAL_DB_ERROR"; case SMB2_STATUS_FULLSCREEN_MODE: return "SMB2_STATUS_FULLSCREEN_MODE"; case SMB2_STATUS_TOO_MANY_CONTEXT_IDS: return "SMB2_STATUS_TOO_MANY_CONTEXT_IDS"; case SMB2_STATUS_LOGON_TYPE_NOT_GRANTED: return "SMB2_STATUS_LOGON_TYPE_NOT_GRANTED"; case SMB2_STATUS_NOT_REGISTRY_FILE: return "SMB2_STATUS_NOT_REGISTRY_FILE"; case SMB2_STATUS_NT_CROSS_ENCRYPTION_REQUIRED: return "SMB2_STATUS_NT_CROSS_ENCRYPTION_REQUIRED"; case SMB2_STATUS_DOMAIN_CTRLR_CONFIG_ERROR: return "SMB2_STATUS_DOMAIN_CTRLR_CONFIG_ERROR"; case SMB2_STATUS_FT_MISSING_MEMBER: return "SMB2_STATUS_FT_MISSING_MEMBER"; case SMB2_STATUS_ILL_FORMED_SERVICE_ENTRY: return "SMB2_STATUS_ILL_FORMED_SERVICE_ENTRY"; case SMB2_STATUS_ILLEGAL_CHARACTER: return "SMB2_STATUS_ILLEGAL_CHARACTER"; case SMB2_STATUS_UNMAPPABLE_CHARACTER: return "SMB2_STATUS_UNMAPPABLE_CHARACTER"; case SMB2_STATUS_UNDEFINED_CHARACTER: return "SMB2_STATUS_UNDEFINED_CHARACTER"; case SMB2_STATUS_FLOPPY_VOLUME: return "SMB2_STATUS_FLOPPY_VOLUME"; case SMB2_STATUS_FLOPPY_ID_MARK_NOT_FOUND: return "SMB2_STATUS_FLOPPY_ID_MARK_NOT_FOUND"; case SMB2_STATUS_FLOPPY_WRONG_CYLINDER: return "SMB2_STATUS_FLOPPY_WRONG_CYLINDER"; case SMB2_STATUS_FLOPPY_UNKNOWN_ERROR: return "SMB2_STATUS_FLOPPY_UNKNOWN_ERROR"; case SMB2_STATUS_FLOPPY_BAD_REGISTERS: return "SMB2_STATUS_FLOPPY_BAD_REGISTERS"; case SMB2_STATUS_DISK_RECALIBRATE_FAILED: return "SMB2_STATUS_DISK_RECALIBRATE_FAILED"; case SMB2_STATUS_DISK_OPERATION_FAILED: return "SMB2_STATUS_DISK_OPERATION_FAILED"; case SMB2_STATUS_DISK_RESET_FAILED: return "SMB2_STATUS_DISK_RESET_FAILED"; case SMB2_STATUS_SHARED_IRQ_BUSY: return "SMB2_STATUS_SHARED_IRQ_BUSY"; case SMB2_STATUS_FT_ORPHANING: return "SMB2_STATUS_FT_ORPHANING"; case SMB2_STATUS_PARTITION_FAILURE: return "SMB2_STATUS_PARTITION_FAILURE"; case SMB2_STATUS_INVALID_BLOCK_LENGTH: return "SMB2_STATUS_INVALID_BLOCK_LENGTH"; case SMB2_STATUS_DEVICE_NOT_PARTITIONED: return "SMB2_STATUS_DEVICE_NOT_PARTITIONED"; case SMB2_STATUS_UNABLE_TO_LOCK_MEDIA: return "SMB2_STATUS_UNABLE_TO_LOCK_MEDIA"; case SMB2_STATUS_UNABLE_TO_UNLOAD_MEDIA: return "SMB2_STATUS_UNABLE_TO_UNLOAD_MEDIA"; case SMB2_STATUS_EOM_OVERFLOW: return "SMB2_STATUS_EOM_OVERFLOW"; case SMB2_STATUS_NO_MEDIA: return "SMB2_STATUS_NO_MEDIA"; case SMB2_STATUS_NO_SUCH_MEMBER: return "SMB2_STATUS_NO_SUCH_MEMBER"; case SMB2_STATUS_INVALID_MEMBER: return "SMB2_STATUS_INVALID_MEMBER"; case SMB2_STATUS_KEY_DELETED: return "SMB2_STATUS_KEY_DELETED"; case SMB2_STATUS_NO_LOG_SPACE: return "SMB2_STATUS_NO_LOG_SPACE"; case SMB2_STATUS_TOO_MANY_SIDS: return "SMB2_STATUS_TOO_MANY_SIDS"; case SMB2_STATUS_LM_CROSS_ENCRYPTION_REQUIRED: return "SMB2_STATUS_LM_CROSS_ENCRYPTION_REQUIRED"; case SMB2_STATUS_KEY_HAS_CHILDREN: return "SMB2_STATUS_KEY_HAS_CHILDREN"; case SMB2_STATUS_CHILD_MUST_BE_VOLATILE: return "SMB2_STATUS_CHILD_MUST_BE_VOLATILE"; case SMB2_STATUS_DEVICE_CONFIGURATION_ERROR: return "SMB2_STATUS_DEVICE_CONFIGURATION_ERROR"; case SMB2_STATUS_DRIVER_INTERNAL_ERROR: return "SMB2_STATUS_DRIVER_INTERNAL_ERROR"; case SMB2_STATUS_INVALID_DEVICE_STATE: return "SMB2_STATUS_INVALID_DEVICE_STATE"; case SMB2_STATUS_IO_DEVICE_ERROR: return "SMB2_STATUS_IO_DEVICE_ERROR"; case SMB2_STATUS_DEVICE_PROTOCOL_ERROR: return "SMB2_STATUS_DEVICE_PROTOCOL_ERROR"; case SMB2_STATUS_BACKUP_CONTROLLER: return "SMB2_STATUS_BACKUP_CONTROLLER"; case SMB2_STATUS_LOG_FILE_FULL: return "SMB2_STATUS_LOG_FILE_FULL"; case SMB2_STATUS_TOO_LATE: return "SMB2_STATUS_TOO_LATE"; case SMB2_STATUS_NO_TRUST_LSA_SECRET: return "SMB2_STATUS_NO_TRUST_LSA_SECRET"; case SMB2_STATUS_NO_TRUST_SAM_ACCOUNT: return "SMB2_STATUS_NO_TRUST_SAM_ACCOUNT"; case SMB2_STATUS_TRUSTED_DOMAIN_FAILURE: return "SMB2_STATUS_TRUSTED_DOMAIN_FAILURE"; case SMB2_STATUS_TRUSTED_RELATIONSHIP_FAILURE: return "SMB2_STATUS_TRUSTED_RELATIONSHIP_FAILURE"; case SMB2_STATUS_EVENTLOG_FILE_CORRUPT: return "SMB2_STATUS_EVENTLOG_FILE_CORRUPT"; case SMB2_STATUS_EVENTLOG_CANT_START: return "SMB2_STATUS_EVENTLOG_CANT_START"; case SMB2_STATUS_TRUST_FAILURE: return "SMB2_STATUS_TRUST_FAILURE"; case SMB2_STATUS_MUTANT_LIMIT_EXCEEDED: return "SMB2_STATUS_MUTANT_LIMIT_EXCEEDED"; case SMB2_STATUS_NETLOGON_NOT_STARTED: return "SMB2_STATUS_NETLOGON_NOT_STARTED"; case SMB2_STATUS_ACCOUNT_EXPIRED: return "SMB2_STATUS_ACCOUNT_EXPIRED"; case SMB2_STATUS_POSSIBLE_DEADLOCK: return "SMB2_STATUS_POSSIBLE_DEADLOCK"; case SMB2_STATUS_NETWORK_CREDENTIAL_CONFLICT: return "SMB2_STATUS_NETWORK_CREDENTIAL_CONFLICT"; case SMB2_STATUS_REMOTE_SESSION_LIMIT: return "SMB2_STATUS_REMOTE_SESSION_LIMIT"; case SMB2_STATUS_EVENTLOG_FILE_CHANGED: return "SMB2_STATUS_EVENTLOG_FILE_CHANGED"; case SMB2_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT: return "SMB2_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"; case SMB2_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT: return "SMB2_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT"; case SMB2_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT: return "SMB2_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"; case SMB2_STATUS_DOMAIN_TRUST_INCONSISTENT: return "SMB2_STATUS_DOMAIN_TRUST_INCONSISTENT"; case SMB2_STATUS_FS_DRIVER_REQUIRED: return "SMB2_STATUS_FS_DRIVER_REQUIRED"; case SMB2_STATUS_NO_USER_SESSION_KEY: return "SMB2_STATUS_NO_USER_SESSION_KEY"; case SMB2_STATUS_USER_SESSION_DELETED: return "SMB2_STATUS_USER_SESSION_DELETED"; case SMB2_STATUS_RESOURCE_LANG_NOT_FOUND: return "SMB2_STATUS_RESOURCE_LANG_NOT_FOUND"; case SMB2_STATUS_INSUFF_SERVER_RESOURCES: return "STATUS_INSUFF_SERVER_RESOURCES"; case SMB2_STATUS_INVALID_BUFFER_SIZE: return "SMB2_STATUS_INVALID_BUFFER_SIZE"; case SMB2_STATUS_INVALID_ADDRESS_COMPONENT: return "SMB2_STATUS_INVALID_ADDRESS_COMPONENT"; case SMB2_STATUS_INVALID_ADDRESS_WILDCARD: return "SMB2_STATUS_INVALID_ADDRESS_WILDCARD"; case SMB2_STATUS_TOO_MANY_ADDRESSES: return "SMB2_STATUS_TOO_MANY_ADDRESSES"; case SMB2_STATUS_ADDRESS_ALREADY_EXISTS: return "SMB2_STATUS_ADDRESS_ALREADY_EXISTS"; case SMB2_STATUS_ADDRESS_CLOSED: return "SMB2_STATUS_ADDRESS_CLOSED"; case SMB2_STATUS_CONNECTION_DISCONNECTED: return "SMB2_STATUS_CONNECTION_DISCONNECTED"; case SMB2_STATUS_CONNECTION_RESET: return "SMB2_STATUS_CONNECTION_RESET"; case SMB2_STATUS_TOO_MANY_NODES: return "SMB2_STATUS_TOO_MANY_NODES"; case SMB2_STATUS_TRANSACTION_ABORTED: return "SMB2_STATUS_TRANSACTION_ABORTED"; case SMB2_STATUS_TRANSACTION_TIMED_OUT: return "SMB2_STATUS_TRANSACTION_TIMED_OUT"; case SMB2_STATUS_TRANSACTION_NO_RELEASE: return "SMB2_STATUS_TRANSACTION_NO_RELEASE"; case SMB2_STATUS_TRANSACTION_NO_MATCH: return "SMB2_STATUS_TRANSACTION_NO_MATCH"; case SMB2_STATUS_TRANSACTION_RESPONDED: return "SMB2_STATUS_TRANSACTION_RESPONDED"; case SMB2_STATUS_TRANSACTION_INVALID_ID: return "SMB2_STATUS_TRANSACTION_INVALID_ID"; case SMB2_STATUS_TRANSACTION_INVALID_TYPE: return "SMB2_STATUS_TRANSACTION_INVALID_TYPE"; case SMB2_STATUS_NOT_SERVER_SESSION: return "SMB2_STATUS_NOT_SERVER_SESSION"; case SMB2_STATUS_NOT_CLIENT_SESSION: return "SMB2_STATUS_NOT_CLIENT_SESSION"; case SMB2_STATUS_CANNOT_LOAD_REGISTRY_FILE: return "SMB2_STATUS_CANNOT_LOAD_REGISTRY_FILE"; case SMB2_STATUS_DEBUG_ATTACH_FAILED: return "SMB2_STATUS_DEBUG_ATTACH_FAILED"; case SMB2_STATUS_SYSTEM_PROCESS_TERMINATED: return "SMB2_STATUS_SYSTEM_PROCESS_TERMINATED"; case SMB2_STATUS_DATA_NOT_ACCEPTED: return "SMB2_STATUS_DATA_NOT_ACCEPTED"; case SMB2_STATUS_NO_BROWSER_SERVERS_FOUND: return "SMB2_STATUS_NO_BROWSER_SERVERS_FOUND"; case SMB2_STATUS_VDM_HARD_ERROR: return "SMB2_STATUS_VDM_HARD_ERROR"; case SMB2_STATUS_DRIVER_CANCEL_TIMEOUT: return "SMB2_STATUS_DRIVER_CANCEL_TIMEOUT"; case SMB2_STATUS_REPLY_MESSAGE_MISMATCH: return "SMB2_STATUS_REPLY_MESSAGE_MISMATCH"; case SMB2_STATUS_MAPPED_ALIGNMENT: return "SMB2_STATUS_MAPPED_ALIGNMENT"; case SMB2_STATUS_IMAGE_CHECKSUM_MISMATCH: return "SMB2_STATUS_IMAGE_CHECKSUM_MISMATCH"; case SMB2_STATUS_LOST_WRITEBEHIND_DATA: return "SMB2_STATUS_LOST_WRITEBEHIND_DATA"; case SMB2_STATUS_CLIENT_SERVER_PARAMETERS_INVALID: return "SMB2_STATUS_CLIENT_SERVER_PARAMETERS_INVALID"; case SMB2_STATUS_PASSWORD_MUST_CHANGE: return "SMB2_STATUS_PASSWORD_MUST_CHANGE"; case SMB2_STATUS_NOT_FOUND: return "SMB2_STATUS_NOT_FOUND"; case SMB2_STATUS_NOT_TINY_STREAM: return "SMB2_STATUS_NOT_TINY_STREAM"; case SMB2_STATUS_RECOVERY_FAILURE: return "SMB2_STATUS_RECOVERY_FAILURE"; case SMB2_STATUS_STACK_OVERFLOW_READ: return "SMB2_STATUS_STACK_OVERFLOW_READ"; case SMB2_STATUS_FAIL_CHECK: return "SMB2_STATUS_FAIL_CHECK"; case SMB2_STATUS_DUPLICATE_OBJECTID: return "SMB2_STATUS_DUPLICATE_OBJECTID"; case SMB2_STATUS_OBJECTID_EXISTS: return "SMB2_STATUS_OBJECTID_EXISTS"; case SMB2_STATUS_CONVERT_TO_LARGE: return "SMB2_STATUS_CONVERT_TO_LARGE"; case SMB2_STATUS_RETRY: return "SMB2_STATUS_RETRY"; case SMB2_STATUS_FOUND_OUT_OF_SCOPE: return "SMB2_STATUS_FOUND_OUT_OF_SCOPE"; case SMB2_STATUS_ALLOCATE_BUCKET: return "SMB2_STATUS_ALLOCATE_BUCKET"; case SMB2_STATUS_PROPSET_NOT_FOUND: return "SMB2_STATUS_PROPSET_NOT_FOUND"; case SMB2_STATUS_MARSHALL_OVERFLOW: return "SMB2_STATUS_MARSHALL_OVERFLOW"; case SMB2_STATUS_INVALID_VARIANT: return "SMB2_STATUS_INVALID_VARIANT"; case SMB2_STATUS_DOMAIN_CONTROLLER_NOT_FOUND: return "SMB2_STATUS_DOMAIN_CONTROLLER_NOT_FOUND"; case SMB2_STATUS_ACCOUNT_LOCKED_OUT: return "SMB2_STATUS_ACCOUNT_LOCKED_OUT"; case SMB2_STATUS_HANDLE_NOT_CLOSABLE: return "STATUS_HANDLE_NOT_CLOSABLE"; case SMB2_STATUS_CONNECTION_REFUSED: return "SMB2_STATUS_CONNECTION_REFUSED"; case SMB2_STATUS_GRACEFUL_DISCONNECT: return "SMB2_STATUS_GRACEFUL_DISCONNECT"; case SMB2_STATUS_ADDRESS_ALREADY_ASSOCIATED: return "SMB2_STATUS_ADDRESS_ALREADY_ASSOCIATED"; case SMB2_STATUS_ADDRESS_NOT_ASSOCIATED: return "SMB2_STATUS_ADDRESS_NOT_ASSOCIATED"; case SMB2_STATUS_CONNECTION_INVALID: return "SMB2_STATUS_CONNECTION_INVALID"; case SMB2_STATUS_CONNECTION_ACTIVE: return "SMB2_STATUS_CONNECTION_ACTIVE"; case SMB2_STATUS_NETWORK_UNREACHABLE: return "SMB2_STATUS_NETWORK_UNREACHABLE"; case SMB2_STATUS_HOST_UNREACHABLE: return "SMB2_STATUS_HOST_UNREACHABLE"; case SMB2_STATUS_PROTOCOL_UNREACHABLE: return "SMB2_STATUS_PROTOCOL_UNREACHABLE"; case SMB2_STATUS_PORT_UNREACHABLE: return "SMB2_STATUS_PORT_UNREACHABLE"; case SMB2_STATUS_REQUEST_ABORTED: return "SMB2_STATUS_REQUEST_ABORTED"; case SMB2_STATUS_CONNECTION_ABORTED: return "SMB2_STATUS_CONNECTION_ABORTED"; case SMB2_STATUS_BAD_COMPRESSION_BUFFER: return "SMB2_STATUS_BAD_COMPRESSION_BUFFER"; case SMB2_STATUS_USER_MAPPED_FILE: return "SMB2_STATUS_USER_MAPPED_FILE"; case SMB2_STATUS_AUDIT_FAILED: return "SMB2_STATUS_AUDIT_FAILED"; case SMB2_STATUS_TIMER_RESOLUTION_NOT_SET: return "SMB2_STATUS_TIMER_RESOLUTION_NOT_SET"; case SMB2_STATUS_CONNECTION_COUNT_LIMIT: return "SMB2_STATUS_CONNECTION_COUNT_LIMIT"; case SMB2_STATUS_LOGIN_TIME_RESTRICTION: return "SMB2_STATUS_LOGIN_TIME_RESTRICTION"; case SMB2_STATUS_LOGIN_WKSTA_RESTRICTION: return "SMB2_STATUS_LOGIN_WKSTA_RESTRICTION"; case SMB2_STATUS_IMAGE_MP_UP_MISMATCH: return "SMB2_STATUS_IMAGE_MP_UP_MISMATCH"; case SMB2_STATUS_INSUFFICIENT_LOGON_INFO: return "SMB2_STATUS_INSUFFICIENT_LOGON_INFO"; case SMB2_STATUS_BAD_DLL_ENTRYPOINT: return "SMB2_STATUS_BAD_DLL_ENTRYPOINT"; case SMB2_STATUS_BAD_SERVICE_ENTRYPOINT: return "SMB2_STATUS_BAD_SERVICE_ENTRYPOINT"; case SMB2_STATUS_LPC_REPLY_LOST: return "SMB2_STATUS_LPC_REPLY_LOST"; case SMB2_STATUS_IP_ADDRESS_CONFLICT1: return "SMB2_STATUS_IP_ADDRESS_CONFLICT1"; case SMB2_STATUS_IP_ADDRESS_CONFLICT2: return "SMB2_STATUS_IP_ADDRESS_CONFLICT2"; case SMB2_STATUS_REGISTRY_QUOTA_LIMIT: return "SMB2_STATUS_REGISTRY_QUOTA_LIMIT"; case SMB2_STATUS_PATH_NOT_COVERED: return "SMB2_STATUS_PATH_NOT_COVERED"; case SMB2_STATUS_NO_CALLBACK_ACTIVE: return "SMB2_STATUS_NO_CALLBACK_ACTIVE"; case SMB2_STATUS_LICENSE_QUOTA_EXCEEDED: return "SMB2_STATUS_LICENSE_QUOTA_EXCEEDED"; case SMB2_STATUS_PWD_TOO_SHORT: return "SMB2_STATUS_PWD_TOO_SHORT"; case SMB2_STATUS_PWD_TOO_RECENT: return "SMB2_STATUS_PWD_TOO_RECENT"; case SMB2_STATUS_PWD_HISTORY_CONFLICT: return "SMB2_STATUS_PWD_HISTORY_CONFLICT"; case SMB2_STATUS_PLUGPLAY_NO_DEVICE: return "SMB2_STATUS_PLUGPLAY_NO_DEVICE"; case SMB2_STATUS_UNSUPPORTED_COMPRESSION: return "SMB2_STATUS_UNSUPPORTED_COMPRESSION"; case SMB2_STATUS_INVALID_HW_PROFILE: return "SMB2_STATUS_INVALID_HW_PROFILE"; case SMB2_STATUS_INVALID_PLUGPLAY_DEVICE_PATH: return "SMB2_STATUS_INVALID_PLUGPLAY_DEVICE_PATH"; case SMB2_STATUS_DRIVER_ORDINAL_NOT_FOUND: return "SMB2_STATUS_DRIVER_ORDINAL_NOT_FOUND"; case SMB2_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND: return "SMB2_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND"; case SMB2_STATUS_RESOURCE_NOT_OWNED: return "SMB2_STATUS_RESOURCE_NOT_OWNED"; case SMB2_STATUS_TOO_MANY_LINKS: return "SMB2_STATUS_TOO_MANY_LINKS"; case SMB2_STATUS_QUOTA_LIST_INCONSISTENT: return "SMB2_STATUS_QUOTA_LIST_INCONSISTENT"; case SMB2_STATUS_FILE_IS_OFFLINE: return "SMB2_STATUS_FILE_IS_OFFLINE"; case SMB2_STATUS_VOLUME_DISMOUNTED: return "SMB2_STATUS_VOLUME_DISMOUNTED"; case SMB2_STATUS_NOT_A_REPARSE_POINT: return "STATUS_NOT_A_REPARSE_POINT"; case SMB2_STATUS_STOPPED_ON_SYMLINK: return "SMB2_STATUS_STOPPED_ON_SYMLINK"; default: return "Unknown"; } } int nterror_to_errno(uint32_t status) { switch (status) { case SMB2_STATUS_SUCCESS: case SMB2_STATUS_END_OF_FILE: return 0; case SMB2_STATUS_PENDING: return EAGAIN; 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: case SMB2_STATUS_OBJECT_NAME_NOT_FOUND: case SMB2_STATUS_OBJECT_PATH_INVALID: case SMB2_STATUS_OBJECT_PATH_NOT_FOUND: case SMB2_STATUS_OBJECT_PATH_SYNTAX_BAD: case SMB2_STATUS_DFS_EXIT_PATH_FOUND: case SMB2_STATUS_DELETE_PENDING: case SMB2_STATUS_REDIRECTOR_NOT_STARTED: case SMB2_STATUS_NOT_FOUND: return ENOENT; case SMB2_STATUS_SMB_BAD_FID: case SMB2_STATUS_INVALID_HANDLE: case SMB2_STATUS_OBJECT_TYPE_MISMATCH: case SMB2_STATUS_PORT_DISCONNECTED: case SMB2_STATUS_INVALID_PORT_HANDLE: case SMB2_STATUS_HANDLE_NOT_CLOSABLE: return EBADF; case SMB2_STATUS_MORE_PROCESSING_REQUIRED: return EAGAIN; case SMB2_STATUS_ACCESS_DENIED: case SMB2_STATUS_NETWORK_ACCESS_DENIED: case SMB2_STATUS_ACCOUNT_RESTRICTION: case SMB2_STATUS_INVALID_LOGON_HOURS: case SMB2_STATUS_PASSWORD_EXPIRED: case SMB2_STATUS_ACCOUNT_DISABLED: return EACCES; case SMB2_STATUS_INVALID_LOCK_SEQUENCE: case SMB2_STATUS_INVALID_VIEW_SIZE: case SMB2_STATUS_ALREADY_COMMITTED: case SMB2_STATUS_PORT_CONNECTION_REFUSED: case SMB2_STATUS_THREAD_IS_TERMINATING: case SMB2_STATUS_PRIVILEGE_NOT_HELD: case SMB2_STATUS_FILE_IS_A_DIRECTORY: case SMB2_STATUS_FILE_RENAMED: case SMB2_STATUS_PROCESS_IS_TERMINATING: case SMB2_STATUS_CANNOT_DELETE: case SMB2_STATUS_FILE_DELETED: return EPERM; case SMB2_STATUS_DIRECTORY_NOT_EMPTY: return ENOTEMPTY; case SMB2_STATUS_NO_MORE_FILES: return ENODATA; case SMB2_STATUS_LOGON_FAILURE: return ECONNREFUSED; case SMB2_STATUS_NOT_A_DIRECTORY: return ENOTDIR; case SMB2_STATUS_NOT_IMPLEMENTED: case SMB2_STATUS_INVALID_DEVICE_REQUEST: case SMB2_STATUS_ILLEGAL_FUNCTION: case SMB2_STATUS_INVALID_PARAMETER: case SMB2_STATUS_NOT_SUPPORTED: case SMB2_STATUS_NOT_A_REPARSE_POINT: return EINVAL; case SMB2_STATUS_STOPPED_ON_SYMLINK: return ENOLINK; case SMB2_STATUS_TOO_MANY_OPENED_FILES: return EMFILE; case SMB2_STATUS_SECTION_TOO_BIG: case SMB2_STATUS_TOO_MANY_PAGING_FILES: case SMB2_STATUS_INSUFF_SERVER_RESOURCES: return ENOMEM; case SMB2_STATUS_NOT_SAME_DEVICE: return EXDEV; case SMB2_STATUS_SHARING_VIOLATION: return ETXTBSY; case SMB2_STATUS_FILE_LOCK_CONFLICT: case SMB2_STATUS_LOCK_NOT_GRANTED: return EDEADLK; case SMB2_STATUS_OBJECT_NAME_COLLISION: return EEXIST; case SMB2_STATUS_PIPE_DISCONNECTED: return EPIPE; case SMB2_STATUS_MEDIA_WRITE_PROTECTED: return EROFS; case SMB2_STATUS_NO_MEDIA_IN_DEVICE: return ENODEV; case SMB2_STATUS_DATA_ERROR: case SMB2_STATUS_CRC_ERROR: case SMB2_STATUS_DEVICE_DATA_ERROR: case SMB2_STATUS_IO_DEVICE_ERROR: return EIO; case SMB2_STATUS_DISK_FULL: return ENOSPC; case SMB2_STATUS_CANCELLED: case SMB2_STATUS_FILE_CLOSED: case SMB2_STATUS_VOLUME_DISMOUNTED: case SMB2_STATUS_CONNECTION_DISCONNECTED: case SMB2_STATUS_CONNECTION_RESET: case SMB2_STATUS_CONNECTION_INVALID: case SMB2_STATUS_CONNECTION_ABORTED: case SMB2_STATUS_NETWORK_NAME_DELETED: case SMB2_STATUS_INVALID_NETWORK_RESPONSE: /* ** We return this errno with the intention that caller can ** retry when any of these are received. */ return ENETRESET; case SMB2_STATUS_PATH_NOT_COVERED: /* ** We do not have an errno which can be an equivalent of this ** NT_STATUS code. To handle this, return a code which will not ** be used as we are operating over a network. */ return ENOEXEC; case SMB2_STATUS_IO_TIMEOUT: return ETIMEDOUT; case SMB2_STATUS_INSUFFICIENT_RESOURCES: return EBUSY; case SMB2_STATUS_INTERNAL_ERROR: /* Fall through. */ default: return EIO; } } libsmb2-6.2/lib/smb2-cmd-query-info.c0000664000175000017500000007525014732155517016442 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" int smb2_encode_query_info_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_query_info_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; if (req->input_buffer_length > 0) { smb2_set_error(smb2, "No support for input buffers, yet"); return -1; } len = SMB2_QUERY_INFO_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate query buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(iov, 0, SMB2_QUERY_INFO_REQUEST_SIZE); smb2_set_uint8(iov, 2, req->info_type); smb2_set_uint8(iov, 3, req->file_info_class); smb2_set_uint32(iov,4, req->output_buffer_length); req->input_buffer_offset = SMB2_HEADER_SIZE + (SMB2_QUERY_INFO_REQUEST_SIZE & 0xfffe); smb2_set_uint16(iov,8, req->input_buffer_offset); smb2_set_uint32(iov,12, req->input_buffer_length); smb2_set_uint32(iov,16, req->additional_information); smb2_set_uint32(iov,20, req->flags); memcpy(iov->buf + 24, req->file_id, SMB2_FD_SIZE); /* Remember what we asked for so that we can unmarshall the reply */ pdu->info_type = req->info_type; pdu->file_info_class = req->file_info_class; return 0; } struct smb2_pdu * smb2_cmd_query_info_async(struct smb2_context *smb2, struct smb2_query_info_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_QUERY_INFO, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_query_info_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } static int smb2_encode_query_info_reply(struct smb2_context *smb2, struct smb2_query_info_request *req, struct smb2_pdu *pdu, struct smb2_query_info_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov, *cmdiov; uint32_t created_output_buffer_length; len = SMB2_QUERY_INFO_REPLY_SIZE & 0xfffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate query reply buffer"); return -1; } rep->output_buffer_offset = 0; if (rep->output_buffer_length > 0) { rep->output_buffer_offset = len + SMB2_HEADER_SIZE; } cmdiov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); smb2_set_uint16(cmdiov, 0, SMB2_QUERY_INFO_REPLY_SIZE); smb2_set_uint16(cmdiov, 2, rep->output_buffer_offset); if (rep->output_buffer_length > 0 && rep->output_buffer) { len = rep->output_buffer_length; /* not sure exactly how long the encoding will be, some of them * include variable data so add a whole lot of extra space * TODO - better estimate = sizeof C struct vs sizeof packed data! */ buf = malloc(len + 1024); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate output buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len + 1024, free); created_output_buffer_length = 0; switch (req->info_type) { case SMB2_0_INFO_FILE: switch (req->file_info_class) { case SMB2_FILE_ACCESS_INFORMATION: break; case SMB2_FILE_ALIGNMENT_INFORMATION: break; case SMB2_FILE_ALL_INFORMATION: created_output_buffer_length = smb2_encode_file_all_info(smb2, (struct smb2_file_all_info *)rep->output_buffer, iov); break; case SMB2_FILE_ALTERNATE_NAME_INFORMATION: break; case SMB2_FILE_ATTRIBUTE_TAG_INFORMATION: break; case SMB2_FILE_BASIC_INFORMATION: created_output_buffer_length = smb2_encode_file_basic_info(smb2, (struct smb2_file_basic_info *)rep->output_buffer, iov); break; case SMB2_FILE_COMPRESSION_INFORMATION: break; case SMB2_FILE_EA_INFORMATION: break; case SMB2_FILE_FULL_EA_INFORMATION: break; case SMB2_FILE_ID_INFORMATION: break; case SMB2_FILE_MODE_INFORMATION: break; case SMB2_FILE_NETWORK_OPEN_INFORMATION: created_output_buffer_length = smb2_encode_file_network_open_info(smb2, (struct smb2_file_network_open_info *)rep->output_buffer, iov); break; case SMB2_FILE_NORMALIZED_NAME_INFORMATION: break; case SMB2_FILE_PIPE_INFORMATION: break; case SMB2_FILE_PIPE_LOCAL_INFORMATION: break; case SMB2_FILE_PIPE_REMOTE_INFORMATION: break; case SMB2_FILE_POSITION_INFORMATION: created_output_buffer_length = smb2_encode_file_position_info(smb2, (struct smb2_file_position_info *)rep->output_buffer, iov); break; case SMB2_FILE_STANDARD_INFORMATION: created_output_buffer_length = smb2_encode_file_standard_info(smb2, (struct smb2_file_standard_info *)rep->output_buffer, iov); break; case SMB2_FILE_STREAM_INFORMATION: break; case SMB2_FILE_INFO_CLASS_RESERVED: break; default: break; } break; case SMB2_0_INFO_FILESYSTEM: switch (req->file_info_class) { case SMB2_FILE_FS_ATTRIBUTE_INFORMATION: created_output_buffer_length = smb2_encode_file_fs_attribute_info(smb2, (struct smb2_file_fs_attribute_info *)rep->output_buffer, iov); break; case SMB2_FILE_FS_CONTROL_INFORMATION: created_output_buffer_length = smb2_encode_file_fs_control_info(smb2, (struct smb2_file_fs_control_info *)rep->output_buffer, iov); break; case SMB2_FILE_FS_DEVICE_INFORMATION: created_output_buffer_length = smb2_encode_file_fs_device_info(smb2, (struct smb2_file_fs_device_info *)rep->output_buffer, iov); break; case SMB2_FILE_FS_FULL_SIZE_INFORMATION: created_output_buffer_length = smb2_encode_file_fs_full_size_info(smb2, (struct smb2_file_fs_full_size_info *)rep->output_buffer, iov); break; case SMB2_FILE_FS_OBJECT_ID_INFORMATION: created_output_buffer_length = smb2_encode_file_fs_object_id_info(smb2, (struct smb2_file_fs_object_id_info *)rep->output_buffer, iov); break; case SMB2_FILE_FS_SECTOR_SIZE_INFORMATION: created_output_buffer_length = smb2_encode_file_fs_sector_size_info(smb2, (struct smb2_file_fs_sector_size_info *)rep->output_buffer, iov); break; case SMB2_FILE_FS_SIZE_INFORMATION: created_output_buffer_length = smb2_encode_file_fs_size_info(smb2, (struct smb2_file_fs_size_info *)rep->output_buffer, iov); break; case SMB2_FILE_FS_VOLUME_INFORMATION: created_output_buffer_length = smb2_encode_file_fs_volume_info(smb2, (struct smb2_file_fs_volume_info *)rep->output_buffer, iov); break; default: break; } break; case SMB2_0_INFO_SECURITY: break; case SMB2_0_INFO_QUOTA: break; default: return 0; } if (created_output_buffer_length < 0) { smb2_set_error(smb2, "Bad reply for query info"); return -1; } else if (created_output_buffer_length == 0) { if (smb2->passthrough) { memcpy(buf, rep->output_buffer, rep->output_buffer_length); memset(buf + rep->output_buffer_length, 0, PAD_TO_64BIT(rep->output_buffer_length) - rep->output_buffer_length); /* blob needs 8 byte alignment */ iov->len = PAD_TO_64BIT(rep->output_buffer_length); } else { smb2_set_error(smb2, "No encoding for info_type/" "info_class %d/%d yet", req->info_type, req->file_info_class); } } else { iov->len = PAD_TO_64BIT(created_output_buffer_length); rep->output_buffer_length = created_output_buffer_length; } } smb2_set_uint32(cmdiov, 4, rep->output_buffer_length); return 0; } struct smb2_pdu * smb2_cmd_query_info_reply_async(struct smb2_context *smb2, struct smb2_query_info_request *req, struct smb2_query_info_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_QUERY_INFO, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_query_info_reply(smb2, req, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } #define IOV_OFFSET (rep->output_buffer_offset - SMB2_HEADER_SIZE - \ (SMB2_QUERY_INFO_REPLY_SIZE & 0xfffe)) int smb2_process_query_info_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_query_info_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; uint32_t opl; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_QUERY_INFO_REPLY_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Query Info " "reply. Expected %d, got %d", SMB2_QUERY_INFO_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate query info reply"); return -1; } pdu->payload = rep; smb2_get_uint16(iov, 2, &rep->output_buffer_offset); smb2_get_uint32(iov, 4, &rep->output_buffer_length); opl = rep->output_buffer_offset + rep->output_buffer_length; if (opl < rep->output_buffer_offset) { smb2_set_error(smb2, "Output offset/length wrapped."); pdu->payload = NULL; free(rep); return -1; } if (rep->output_buffer_length) { if (opl > smb2->spl) { smb2_set_error(smb2, "Output buffer extends beyond end of " "PDU"); pdu->payload = NULL; free(rep); return -1; } if (smb2->hdr.next_command && opl > smb2->hdr.next_command) { smb2_set_error(smb2, "Current PDU extends into next " "chained PDU"); pdu->payload = NULL; free(rep); return -1; } } else { /* this can happen "No Info" */ rep->output_buffer = NULL; return 0; } if (rep->output_buffer_offset < SMB2_HEADER_SIZE + (SMB2_QUERY_INFO_REPLY_SIZE & 0xfffe)) { smb2_set_error(smb2, "Output buffer overlaps with " "Query Info reply header"); pdu->payload = NULL; free(rep); return -1; } /* Return the amount of data that the output buffer will take up. * Including any padding before the output buffer itself. */ return IOV_OFFSET + rep->output_buffer_length; } int smb2_process_query_info_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_query_info_reply *rep = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; struct smb2_iovec vec = {&iov->buf[IOV_OFFSET], iov->len - IOV_OFFSET, NULL}; void *ptr = NULL; switch (pdu->info_type) { case SMB2_0_INFO_FILE: switch (pdu->file_info_class) { case SMB2_FILE_ACCESS_INFORMATION: break; case SMB2_FILE_ALIGNMENT_INFORMATION: break; case SMB2_FILE_ALL_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_all_info)); if (smb2_decode_file_all_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "all info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_ALTERNATE_NAME_INFORMATION: break; case SMB2_FILE_ATTRIBUTE_TAG_INFORMATION: break; case SMB2_FILE_BASIC_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_basic_info)); if (smb2_decode_file_basic_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "basic info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_COMPRESSION_INFORMATION: break; case SMB2_FILE_EA_INFORMATION: break; case SMB2_FILE_FULL_EA_INFORMATION: break; case SMB2_FILE_ID_INFORMATION: break; case SMB2_FILE_MODE_INFORMATION: break; case SMB2_FILE_NETWORK_OPEN_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_all_info)); if (smb2_decode_file_network_open_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "network open info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_NORMALIZED_NAME_INFORMATION: break; case SMB2_FILE_PIPE_INFORMATION: break; case SMB2_FILE_PIPE_LOCAL_INFORMATION: break; case SMB2_FILE_PIPE_REMOTE_INFORMATION: break; case SMB2_FILE_POSITION_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_position_info)); if (smb2_decode_file_position_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "positiion info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_STANDARD_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_standard_info)); if (smb2_decode_file_standard_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "standard info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_STREAM_INFORMATION: break; case SMB2_FILE_INFO_CLASS_RESERVED: break; default: break; } break; case SMB2_0_INFO_FILESYSTEM: switch (pdu->file_info_class) { case SMB2_FILE_FS_ATTRIBUTE_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_fs_attribute_info)); if (smb2_decode_file_fs_attribute_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "fs attribute info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_FS_CONTROL_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_fs_control_info)); if (smb2_decode_file_fs_control_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "fs control info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_FS_DEVICE_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_fs_device_info)); if (smb2_decode_file_fs_device_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "fs device info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_FS_FULL_SIZE_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_fs_full_size_info)); if (smb2_decode_file_fs_full_size_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "fs full size info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_FS_OBJECT_ID_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_fs_object_id_info)); if (smb2_decode_file_fs_object_id_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "object id info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_FS_SECTOR_SIZE_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_fs_sector_size_info)); if (smb2_decode_file_fs_sector_size_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "fs sector size info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_FS_SIZE_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_fs_size_info)); if (smb2_decode_file_fs_size_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "fs size info. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_FILE_FS_VOLUME_INFORMATION: ptr = smb2_alloc_init(smb2, sizeof(struct smb2_file_fs_volume_info)); if (smb2_decode_file_fs_volume_info(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode file " "fs volume info. %s", smb2_get_error(smb2)); return -1; } break; default: break; } break; case SMB2_0_INFO_SECURITY: if (smb2->passthrough) { /* TODO - handle encoding of security as needed * for now, just pass-through if indicated */ break; } ptr = smb2_alloc_init(smb2, sizeof(struct smb2_security_descriptor)); if (smb2_decode_security_descriptor(smb2, ptr, ptr, &vec)) { smb2_set_error(smb2, "could not decode security " "descriptor. %s", smb2_get_error(smb2)); return -1; } break; case SMB2_0_INFO_QUOTA: break; default: smb2_set_error(smb2, "Bad info_type %d", pdu->info_type); return -1; } if (!ptr) { if (smb2->passthrough) { ptr = smb2_alloc_init(smb2, rep->output_buffer_length); memcpy(ptr, vec.buf, vec.len); } else { smb2_set_error(smb2, "Can not decode info_type/" "info_class %d/%d yet", pdu->info_type, pdu->file_info_class); return -1; } } rep->output_buffer = ptr; return 0; } #define IOVREQ_OFFSET (req->input_buffer_offset - SMB2_HEADER_SIZE - \ (SMB2_QUERY_INFO_REQUEST_SIZE & 0xfffe)) int smb2_process_query_info_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_query_info_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size != SMB2_QUERY_INFO_REQUEST_SIZE || (struct_size & 0xfffe) != iov->len) { smb2_set_error(smb2, "Unexpected size of Query Info " "request. Expected %d, got %d", SMB2_QUERY_INFO_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate query info request"); return -1; } pdu->payload = req; smb2_get_uint8(iov, 2, &req->info_type); smb2_get_uint8(iov, 3, &req->file_info_class); smb2_get_uint32(iov, 4, &req->output_buffer_length); smb2_get_uint16(iov, 8, &req->input_buffer_offset); smb2_get_uint32(iov, 12, &req->input_buffer_length); smb2_get_uint32(iov, 16, &req->additional_information); smb2_get_uint32(iov, 20, &req->flags); memcpy(req->file_id, iov->buf + 24, SMB2_FD_SIZE); if (req->input_buffer_length == 0) { return 0; } if (req->input_buffer_offset < SMB2_HEADER_SIZE + (SMB2_QUERY_INFO_REQUEST_SIZE & 0xfffe)) { smb2_set_error(smb2, "Input buffer overlaps with " "Query Info request header"); pdu->payload = NULL; free(req); return -1; } return IOVREQ_OFFSET + req->input_buffer_length; } int smb2_process_query_info_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_query_info_request *req = pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; struct smb2_iovec vec = {&iov->buf[IOVREQ_OFFSET], iov->len - IOVREQ_OFFSET, NULL}; req->input = (uint8_t *)vec.buf; return 0; } libsmb2-6.2/lib/sha384-512.c0000664000175000017500000010650014732155517014252 0ustar polpypolpy/*************************** sha384-512.c ***************************/ /********************* See RFC 4634 for details *********************/ /* * Description: * This file implements the Secure Hash Signature Standard * algorithms as defined in the National Institute of Standards * and Technology Federal Information Processing Standards * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 * published on August 1, 2002, and the FIPS PUB 180-2 Change * Notice published on February 28, 2004. * * A combined document showing all algorithms is available at * http://csrc.nist.gov/publications/fips/ * fips180-2/fips180-2withchangenotice.pdf * * The SHA-384 and SHA-512 algorithms produce 384-bit and 512-bit * message digests for a given data stream. It should take about * 2**n steps to find a message with the same digest as a given * message and 2**(n/2) to find any two messages with the same * digest, when n is the digest size in bits. Therefore, this * algorithm can serve as a means of providing a * "fingerprint" for a message. * * Portability Issues: * SHA-384 and SHA-512 are defined in terms of 64-bit "words", * but if USE_32BIT_ONLY is #defined, this code is implemented in * terms of 32-bit "words". This code uses (included * via "sha.h") to define the 64, 32 and 8 bit unsigned integer * types. If your C compiler does not support 64 bit unsigned * integers, and you do not #define USE_32BIT_ONLY, this code is * not appropriate. * * Caveats: * SHA-384 and SHA-512 are designed to work with messages less * than 2^128 bits long. This implementation uses * SHA384/512Input() to hash the bits that are a multiple of the * size of an 8-bit character, and then uses SHA384/256FinalBits() * to hash the final few bits of the input. * */ #include "compat.h" #include "sha.h" #include "sha-private.h" #if defined(USE_SHA384_SHA512) && USE_SHA384_SHA512 #ifdef USE_32BIT_ONLY /* * Define 64-bit arithmetic in terms of 32-bit arithmetic. * Each 64-bit number is represented in a 2-word array. * All macros are defined such that the result is the last parameter. */ /* * Define shift, rotate left and rotate right functions */ #define SHA512_SHR(bits, word, ret) ( \ /* (((uint64_t)((word))) >> (bits)) */ \ (ret)[0] = (((bits) < 32) && ((bits) >= 0)) ? \ ((word)[0] >> (bits)) : 0, \ (ret)[1] = ((bits) > 32) ? ((word)[0] >> ((bits) - 32)) : \ ((bits) == 32) ? (word)[0] : \ ((bits) >= 0) ? \ (((word)[0] << (32 - (bits))) | \ ((word)[1] >> (bits))) : 0 ) #define SHA512_SHL(bits, word, ret) ( \ /* (((uint64_t)(word)) << (bits)) */ \ (ret)[0] = ((bits) > 32) ? ((word)[1] << ((bits) - 32)) : \ ((bits) == 32) ? (word)[1] : \ ((bits) >= 0) ? \ (((word)[0] << (bits)) | \ ((word)[1] >> (32 - (bits)))) : \ 0, \ (ret)[1] = (((bits) < 32) && ((bits) >= 0)) ? \ ((word)[1] << (bits)) : 0 ) /* * Define 64-bit OR */ #define SHA512_OR(word1, word2, ret) ( \ (ret)[0] = (word1)[0] | (word2)[0], \ (ret)[1] = (word1)[1] | (word2)[1] ) /* * Define 64-bit XOR */ #define SHA512_XOR(word1, word2, ret) ( \ (ret)[0] = (word1)[0] ^ (word2)[0], \ (ret)[1] = (word1)[1] ^ (word2)[1] ) /* * Define 64-bit AND */ #define SHA512_AND(word1, word2, ret) ( \ (ret)[0] = (word1)[0] & (word2)[0], \ (ret)[1] = (word1)[1] & (word2)[1] ) /* * Define 64-bit TILDA */ #define SHA512_TILDA(word, ret) \ ( (ret)[0] = ~(word)[0], (ret)[1] = ~(word)[1] ) /* * Define 64-bit ADD */ #define SHA512_ADD(word1, word2, ret) ( \ (ret)[1] = (word1)[1], (ret)[1] += (word2)[1], \ (ret)[0] = (word1)[0] + (word2)[0] + ((ret)[1] < (word1)[1]) ) /* * Add the 4word value in word2 to word1. */ #define SHA512_ADDTO4(word1, word2) ( \ ADDTO4_temp = (word1)[3], \ (word1)[3] += (word2)[3], \ ADDTO4_temp2 = (word1)[2], \ (word1)[2] += (word2)[2] + ((word1)[3] < ADDTO4_temp), \ ADDTO4_temp = (word1)[1], \ (word1)[1] += (word2)[1] + ((word1)[2] < ADDTO4_temp2), \ (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO4_temp) ) /* * Add the 2word value in word2 to word1. */ #define SHA512_ADDTO2(word1, word2) ( \ ADDTO2_temp = (word1)[1], \ (word1)[1] += (word2)[1], \ (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO2_temp) ) /* * SHA rotate ((word >> bits) | (word << (64-bits))) */ #define SHA512_ROTR(bits, word, ret) ( \ SHA512_SHR((bits), (word), ROTR_temp1), \ SHA512_SHL(64-(bits), (word), ROTR_temp2), \ SHA512_OR(ROTR_temp1, ROTR_temp2, (ret)) ) /* * Define the SHA SIGMA and sigma macros * SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word) */ #define SHA512_SIGMA0(word, ret) ( \ SHA512_ROTR(28, (word), SIGMA0_temp1), \ SHA512_ROTR(34, (word), SIGMA0_temp2), \ SHA512_ROTR(39, (word), SIGMA0_temp3), \ SHA512_XOR(SIGMA0_temp2, SIGMA0_temp3, SIGMA0_temp4), \ SHA512_XOR(SIGMA0_temp1, SIGMA0_temp4, (ret)) ) /* * SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word) */ #define SHA512_SIGMA1(word, ret) ( \ SHA512_ROTR(14, (word), SIGMA1_temp1), \ SHA512_ROTR(18, (word), SIGMA1_temp2), \ SHA512_ROTR(41, (word), SIGMA1_temp3), \ SHA512_XOR(SIGMA1_temp2, SIGMA1_temp3, SIGMA1_temp4), \ SHA512_XOR(SIGMA1_temp1, SIGMA1_temp4, (ret)) ) /* * (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) */ #define SHA512_sigma0(word, ret) ( \ SHA512_ROTR( 1, (word), sigma0_temp1), \ SHA512_ROTR( 8, (word), sigma0_temp2), \ SHA512_SHR( 7, (word), sigma0_temp3), \ SHA512_XOR(sigma0_temp2, sigma0_temp3, sigma0_temp4), \ SHA512_XOR(sigma0_temp1, sigma0_temp4, (ret)) ) /* * (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) */ #define SHA512_sigma1(word, ret) ( \ SHA512_ROTR(19, (word), sigma1_temp1), \ SHA512_ROTR(61, (word), sigma1_temp2), \ SHA512_SHR( 6, (word), sigma1_temp3), \ SHA512_XOR(sigma1_temp2, sigma1_temp3, sigma1_temp4), \ SHA512_XOR(sigma1_temp1, sigma1_temp4, (ret)) ) #undef SHA_Ch #undef SHA_Maj #ifndef USE_MODIFIED_MACROS /* * These definitions are the ones used in FIPS-180-2, section 4.1.3 * Ch(x,y,z) ((x & y) ^ (~x & z)) */ #define SHA_Ch(x, y, z, ret) ( \ SHA512_AND(x, y, Ch_temp1), \ SHA512_TILDA(x, Ch_temp2), \ SHA512_AND(Ch_temp2, z, Ch_temp3), \ SHA512_XOR(Ch_temp1, Ch_temp3, (ret)) ) /* * Maj(x,y,z) (((x)&(y)) ^ ((x)&(z)) ^ ((y)&(z))) */ #define SHA_Maj(x, y, z, ret) ( \ SHA512_AND(x, y, Maj_temp1), \ SHA512_AND(x, z, Maj_temp2), \ SHA512_AND(y, z, Maj_temp3), \ SHA512_XOR(Maj_temp2, Maj_temp3, Maj_temp4), \ SHA512_XOR(Maj_temp1, Maj_temp4, (ret)) ) #else /* !USE_32BIT_ONLY */ /* * These definitions are potentially faster equivalents for the ones * used in FIPS-180-2, section 4.1.3. * ((x & y) ^ (~x & z)) becomes * ((x & (y ^ z)) ^ z) */ #define SHA_Ch(x, y, z, ret) ( \ (ret)[0] = (((x)[0] & ((y)[0] ^ (z)[0])) ^ (z)[0]), \ (ret)[1] = (((x)[1] & ((y)[1] ^ (z)[1])) ^ (z)[1]) ) /* * ((x & y) ^ (x & z) ^ (y & z)) becomes * ((x & (y | z)) | (y & z)) */ #define SHA_Maj(x, y, z, ret) ( \ ret[0] = (((x)[0] & ((y)[0] | (z)[0])) | ((y)[0] & (z)[0])), \ ret[1] = (((x)[1] & ((y)[1] | (z)[1])) | ((y)[1] & (z)[1])) ) #endif /* USE_MODIFIED_MACROS */ /* * add "length" to the length */ #define SHA384_512AddLength(context, length) ( \ addTemp[3] = (length), SHA512_ADDTO4((context)->Length, addTemp), \ (context)->Corrupted = (((context)->Length[3] == 0) && \ ((context)->Length[2] == 0) && ((context)->Length[1] == 0) && \ ((context)->Length[0] < 8)) ? 1 : 0 ) /* Local Function Prototypes */ static void SHA384_512Finalize (SHA512Context * context, uint8_t Pad_Byte); static void SHA384_512PadMessage (SHA512Context * context, uint8_t Pad_Byte); static void SHA384_512ProcessMessageBlock (SHA512Context * context); static int SHA384_512Reset (SHA512Context * context, uint32_t H0[]); static int SHA384_512ResultN (SHA512Context * context, uint8_t Message_Digest[], int HashSize); /* Initial Hash Values: FIPS-180-2 sections 5.3.3 and 5.3.4 */ static uint32_t SHA384_H0[SHA512HashSize / 4] = { 0xCBBB9D5D, 0xC1059ED8, 0x629A292A, 0x367CD507, 0x9159015A, 0x3070DD17, 0x152FECD8, 0xF70E5939, 0x67332667, 0xFFC00B31, 0x8EB44A87, 0x68581511, 0xDB0C2E0D, 0x64F98FA7, 0x47B5481D, 0xBEFA4FA4 }; static uint32_t SHA512_H0[SHA512HashSize / 4] = { 0x6A09E667, 0xF3BCC908, 0xBB67AE85, 0x84CAA73B, 0x3C6EF372, 0xFE94F82B, 0xA54FF53A, 0x5F1D36F1, 0x510E527F, 0xADE682D1, 0x9B05688C, 0x2B3E6C1F, 0x1F83D9AB, 0xFB41BD6B, 0x5BE0CD19, 0x137E2179 }; #else /* !USE_32BIT_ONLY */ /* Define the SHA shift, rotate left and rotate right macro */ #define SHA512_SHR(bits,word) (((uint64_t)(word)) >> (bits)) #define SHA512_ROTR(bits,word) ((((uint64_t)(word)) >> (bits)) | \ (((uint64_t)(word)) << (64-(bits)))) /* Define the SHA SIGMA and sigma macros */ #define SHA512_SIGMA0(word) \ (SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word)) #define SHA512_SIGMA1(word) \ (SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word)) #define SHA512_sigma0(word) \ (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) #define SHA512_sigma1(word) \ (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) /* * add "length" to the length */ #define SHA384_512AddLength(context, length) \ (addTemp = context->Length_Low, context->Corrupted = \ ((context->Length_Low += length) < addTemp) && \ (++context->Length_High == 0) ? 1 : 0) /* Local Function Prototypes */ static void SHA384_512Finalize (SHA512Context * context, uint8_t Pad_Byte); static void SHA384_512PadMessage (SHA512Context * context, uint8_t Pad_Byte); static void SHA384_512ProcessMessageBlock (SHA512Context * context); static int SHA384_512Reset (SHA512Context * context, uint64_t H0[]); static int SHA384_512ResultN (SHA512Context * context, uint8_t Message_Digest[], int HashSize); /* Initial Hash Values: FIPS-180-2 sections 5.3.3 and 5.3.4 */ static uint64_t SHA384_H0[] = { 0xCBBB9D5DC1059ED8ll, 0x629A292A367CD507ll, 0x9159015A3070DD17ll, 0x152FECD8F70E5939ll, 0x67332667FFC00B31ll, 0x8EB44A8768581511ll, 0xDB0C2E0D64F98FA7ll, 0x47B5481DBEFA4FA4ll }; static uint64_t SHA512_H0[] = { 0x6A09E667F3BCC908ll, 0xBB67AE8584CAA73Bll, 0x3C6EF372FE94F82Bll, 0xA54FF53A5F1D36F1ll, 0x510E527FADE682D1ll, 0x9B05688C2B3E6C1Fll, 0x1F83D9ABFB41BD6Bll, 0x5BE0CD19137E2179ll }; #endif /* USE_32BIT_ONLY */ /* * SHA384Reset * * Description: * This function will initialize the SHA384Context in preparation * for computing a new SHA384 message digest. * * Parameters: * context: [in/out] * The context to reset. * * Returns: * sha Error Code. * */ int SHA384Reset (SHA384Context * context) { return SHA384_512Reset (context, SHA384_H0); } /* * SHA384Input * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */ int SHA384Input (SHA384Context * context, const uint8_t * message_array, size_t length) { return SHA512Input (context, message_array, length); } /* * SHA384FinalBits * * Description: * This function will add in any final bits of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_bits: [in] * The final bits of the message, in the upper portion of the * byte. (Use 0b###00000 instead of 0b00000### to input the * three bits ###.) * length: [in] * The number of bits in message_bits, between 1 and 7. * * Returns: * sha Error Code. * */ int SHA384FinalBits (SHA384Context * context, const uint8_t message_bits, size_t length) { return SHA512FinalBits (context, message_bits, length); } /* * SHA384Result * * Description: * This function will return the 384-bit message * digest into the Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 48th element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA hash. * Message_Digest: [out] * Where the digest is returned. * * Returns: * sha Error Code. * */ int SHA384Result (SHA384Context * context, uint8_t Message_Digest[SHA384HashSize]) { return SHA384_512ResultN (context, Message_Digest, SHA384HashSize); } /* * SHA512Reset * * Description: * This function will initialize the SHA512Context in preparation * for computing a new SHA512 message digest. * * Parameters: * context: [in/out] * The context to reset. * * Returns: * sha Error Code. * */ int SHA512Reset (SHA512Context * context) { return SHA384_512Reset (context, SHA512_H0); } /* * SHA512Input * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */ int SHA512Input (SHA512Context * context, const uint8_t * message_array, size_t length) { #ifdef USE_32BIT_ONLY /* nothing */ #else uint64_t addTemp; #endif if (!length) return shaSuccess; if (!context || !message_array) return shaNull; if (context->Computed) { context->Corrupted = shaStateError; return shaStateError; } if (context->Corrupted) return context->Corrupted; while (length-- && !context->Corrupted) { context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF); if (!SHA384_512AddLength (context, 8) && (context->Message_Block_Index == SHA512_Message_Block_Size)) SHA384_512ProcessMessageBlock (context); message_array++; } return shaSuccess; } /* * SHA512FinalBits * * Description: * This function will add in any final bits of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_bits: [in] * The final bits of the message, in the upper portion of the * byte. (Use 0b###00000 instead of 0b00000### to input the * three bits ###.) * length: [in] * The number of bits in message_bits, between 1 and 7. * * Returns: * sha Error Code. * */ int SHA512FinalBits (SHA512Context * context, const uint8_t message_bits, size_t length) { #ifdef USE_32BIT_ONLY /* nothing */ #else uint64_t addTemp; #endif uint8_t masks[8] = { /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE }; uint8_t markbit[8] = { /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 }; if (!length) return shaSuccess; if (!context) return shaNull; if ((context->Computed) || (length >= 8) || (length == 0)) { context->Corrupted = shaStateError; return shaStateError; } if (context->Corrupted) return context->Corrupted; SHA384_512AddLength (context, length); SHA384_512Finalize (context, (uint8_t) ((message_bits & masks[length]) | markbit[length])); return shaSuccess; } /* * SHA384_512Finalize * * Description: * This helper function finishes off the digest calculations. * * Parameters: * context: [in/out] * The SHA context to update * Pad_Byte: [in] * The last byte to add to the digest before the 0-padding * and length. This will contain the last bits of the message * followed by another single bit. If the message was an * exact multiple of 8-bits long, Pad_Byte will be 0x80. * * Returns: * sha Error Code. * */ static void SHA384_512Finalize (SHA512Context * context, uint8_t Pad_Byte) { int_least16_t i; SHA384_512PadMessage (context, Pad_Byte); /* message may be sensitive, clear it out */ for (i = 0; i < SHA512_Message_Block_Size; ++i) context->Message_Block[i] = 0; #ifdef USE_32BIT_ONLY /* and clear length */ context->Length[0] = context->Length[1] = 0; context->Length[2] = context->Length[3] = 0; #else /* !USE_32BIT_ONLY */ context->Length_Low = 0; context->Length_High = 0; #endif /* USE_32BIT_ONLY */ context->Computed = 1; } /* * SHA512Result * * Description: * This function will return the 512-bit message * digest into the Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 64th element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA hash. * Message_Digest: [out] * Where the digest is returned. * * Returns: * sha Error Code. * */ int SHA512Result (SHA512Context * context, uint8_t Message_Digest[SHA512HashSize]) { return SHA384_512ResultN (context, Message_Digest, SHA512HashSize); } /* * SHA384_512PadMessage * * Description: * According to the standard, the message must be padded to an * even 1024 bits. The first padding bit must be a '1'. The * last 128 bits represent the length of the original message. * All bits in between should be 0. This helper function will * pad the message according to those rules by filling the * Message_Block array accordingly. When it returns, it can be * assumed that the message digest has been computed. * * Parameters: * context: [in/out] * The context to pad * Pad_Byte: [in] * The last byte to add to the digest before the 0-padding * and length. This will contain the last bits of the message * followed by another single bit. If the message was an * exact multiple of 8-bits long, Pad_Byte will be 0x80. * * Returns: * Nothing. * */ static void SHA384_512PadMessage (SHA512Context * context, uint8_t Pad_Byte) { /* * Check to see if the current message block is too small to hold * the initial padding bits and length. If so, we will pad the * block, process it, and then continue padding into a second * block. */ if (context->Message_Block_Index >= (SHA512_Message_Block_Size - 16)) { context->Message_Block[context->Message_Block_Index++] = Pad_Byte; while (context->Message_Block_Index < SHA512_Message_Block_Size) context->Message_Block[context->Message_Block_Index++] = 0; SHA384_512ProcessMessageBlock (context); } else context->Message_Block[context->Message_Block_Index++] = Pad_Byte; while (context->Message_Block_Index < (SHA512_Message_Block_Size - 16)) context->Message_Block[context->Message_Block_Index++] = 0; /* * Store the message length as the last 16 octets */ #ifdef USE_32BIT_ONLY context->Message_Block[112] = (uint8_t) (context->Length[0] >> 24); context->Message_Block[113] = (uint8_t) (context->Length[0] >> 16); context->Message_Block[114] = (uint8_t) (context->Length[0] >> 8); context->Message_Block[115] = (uint8_t) (context->Length[0]); context->Message_Block[116] = (uint8_t) (context->Length[1] >> 24); context->Message_Block[117] = (uint8_t) (context->Length[1] >> 16); context->Message_Block[118] = (uint8_t) (context->Length[1] >> 8); context->Message_Block[119] = (uint8_t) (context->Length[1]); context->Message_Block[120] = (uint8_t) (context->Length[2] >> 24); context->Message_Block[121] = (uint8_t) (context->Length[2] >> 16); context->Message_Block[122] = (uint8_t) (context->Length[2] >> 8); context->Message_Block[123] = (uint8_t) (context->Length[2]); context->Message_Block[124] = (uint8_t) (context->Length[3] >> 24); context->Message_Block[125] = (uint8_t) (context->Length[3] >> 16); context->Message_Block[126] = (uint8_t) (context->Length[3] >> 8); context->Message_Block[127] = (uint8_t) (context->Length[3]); #else /* !USE_32BIT_ONLY */ context->Message_Block[112] = (uint8_t) (context->Length_High >> 56); context->Message_Block[113] = (uint8_t) (context->Length_High >> 48); context->Message_Block[114] = (uint8_t) (context->Length_High >> 40); context->Message_Block[115] = (uint8_t) (context->Length_High >> 32); context->Message_Block[116] = (uint8_t) (context->Length_High >> 24); context->Message_Block[117] = (uint8_t) (context->Length_High >> 16); context->Message_Block[118] = (uint8_t) (context->Length_High >> 8); context->Message_Block[119] = (uint8_t) (context->Length_High); context->Message_Block[120] = (uint8_t) (context->Length_Low >> 56); context->Message_Block[121] = (uint8_t) (context->Length_Low >> 48); context->Message_Block[122] = (uint8_t) (context->Length_Low >> 40); context->Message_Block[123] = (uint8_t) (context->Length_Low >> 32); context->Message_Block[124] = (uint8_t) (context->Length_Low >> 24); context->Message_Block[125] = (uint8_t) (context->Length_Low >> 16); context->Message_Block[126] = (uint8_t) (context->Length_Low >> 8); context->Message_Block[127] = (uint8_t) (context->Length_Low); #endif /* USE_32BIT_ONLY */ SHA384_512ProcessMessageBlock (context); } /* * SHA384_512ProcessMessageBlock * * Description: * This helper function will process the next 1024 bits of the * message stored in the Message_Block array. * * Parameters: * context: [in/out] * The SHA context to update * * Returns: * Nothing. * * Comments: * Many of the variable names in this code, especially the * single character names, were used because those were the * names used in the publication. * * */ static void SHA384_512ProcessMessageBlock (SHA512Context * context) { /* Constants defined in FIPS-180-2, section 4.2.3 */ #ifdef USE_32BIT_ONLY static const uint32_t K[80 * 2] = { 0x428A2F98, 0xD728AE22, 0x71374491, 0x23EF65CD, 0xB5C0FBCF, 0xEC4D3B2F, 0xE9B5DBA5, 0x8189DBBC, 0x3956C25B, 0xF348B538, 0x59F111F1, 0xB605D019, 0x923F82A4, 0xAF194F9B, 0xAB1C5ED5, 0xDA6D8118, 0xD807AA98, 0xA3030242, 0x12835B01, 0x45706FBE, 0x243185BE, 0x4EE4B28C, 0x550C7DC3, 0xD5FFB4E2, 0x72BE5D74, 0xF27B896F, 0x80DEB1FE, 0x3B1696B1, 0x9BDC06A7, 0x25C71235, 0xC19BF174, 0xCF692694, 0xE49B69C1, 0x9EF14AD2, 0xEFBE4786, 0x384F25E3, 0x0FC19DC6, 0x8B8CD5B5, 0x240CA1CC, 0x77AC9C65, 0x2DE92C6F, 0x592B0275, 0x4A7484AA, 0x6EA6E483, 0x5CB0A9DC, 0xBD41FBD4, 0x76F988DA, 0x831153B5, 0x983E5152, 0xEE66DFAB, 0xA831C66D, 0x2DB43210, 0xB00327C8, 0x98FB213F, 0xBF597FC7, 0xBEEF0EE4, 0xC6E00BF3, 0x3DA88FC2, 0xD5A79147, 0x930AA725, 0x06CA6351, 0xE003826F, 0x14292967, 0x0A0E6E70, 0x27B70A85, 0x46D22FFC, 0x2E1B2138, 0x5C26C926, 0x4D2C6DFC, 0x5AC42AED, 0x53380D13, 0x9D95B3DF, 0x650A7354, 0x8BAF63DE, 0x766A0ABB, 0x3C77B2A8, 0x81C2C92E, 0x47EDAEE6, 0x92722C85, 0x1482353B, 0xA2BFE8A1, 0x4CF10364, 0xA81A664B, 0xBC423001, 0xC24B8B70, 0xD0F89791, 0xC76C51A3, 0x0654BE30, 0xD192E819, 0xD6EF5218, 0xD6990624, 0x5565A910, 0xF40E3585, 0x5771202A, 0x106AA070, 0x32BBD1B8, 0x19A4C116, 0xB8D2D0C8, 0x1E376C08, 0x5141AB53, 0x2748774C, 0xDF8EEB99, 0x34B0BCB5, 0xE19B48A8, 0x391C0CB3, 0xC5C95A63, 0x4ED8AA4A, 0xE3418ACB, 0x5B9CCA4F, 0x7763E373, 0x682E6FF3, 0xD6B2B8A3, 0x748F82EE, 0x5DEFB2FC, 0x78A5636F, 0x43172F60, 0x84C87814, 0xA1F0AB72, 0x8CC70208, 0x1A6439EC, 0x90BEFFFA, 0x23631E28, 0xA4506CEB, 0xDE82BDE9, 0xBEF9A3F7, 0xB2C67915, 0xC67178F2, 0xE372532B, 0xCA273ECE, 0xEA26619C, 0xD186B8C7, 0x21C0C207, 0xEADA7DD6, 0xCDE0EB1E, 0xF57D4F7F, 0xEE6ED178, 0x06F067AA, 0x72176FBA, 0x0A637DC5, 0xA2C898A6, 0x113F9804, 0xBEF90DAE, 0x1B710B35, 0x131C471B, 0x28DB77F5, 0x23047D84, 0x32CAAB7B, 0x40C72493, 0x3C9EBE0A, 0x15C9BEBC, 0x431D67C4, 0x9C100D4C, 0x4CC5D4BE, 0xCB3E42B6, 0x597F299C, 0xFC657E2A, 0x5FCB6FAB, 0x3AD6FAEC, 0x6C44198C, 0x4A475817 }; int t, t2, t8; /* Loop counter */ uint32_t temp1[2], temp2[2], /* Temporary word values */ temp3[2], temp4[2], temp5[2]; uint32_t W[2 * 80]; /* Word sequence */ uint32_t A[2], B[2], C[2], D[2], /* Word buffers */ E[2], F[2], G[2], H[2]; /* Initialize the first 16 words in the array W */ for (t = t2 = t8 = 0; t < 16; t++, t8 += 8) { W[t2++] = ((((uint32_t) context->Message_Block[t8])) << 24) | ((((uint32_t) context->Message_Block[t8 + 1])) << 16) | ((((uint32_t) context->Message_Block[t8 + 2])) << 8) | ((((uint32_t) context->Message_Block[t8 + 3]))); W[t2++] = ((((uint32_t) context->Message_Block[t8 + 4])) << 24) | ((((uint32_t) context->Message_Block[t8 + 5])) << 16) | ((((uint32_t) context->Message_Block[t8 + 6])) << 8) | ((((uint32_t) context->Message_Block[t8 + 7]))); } for (t = 16; t < 80; t++, t2 += 2) { /* W[t] = SHA512_sigma1(W[t-2]) + W[t-7] + SHA512_sigma0(W[t-15]) + W[t-16]; */ uint32_t *Wt2 = &W[t2 - 2 * 2]; uint32_t *Wt7 = &W[t2 - 7 * 2]; uint32_t *Wt15 = &W[t2 - 15 * 2]; uint32_t *Wt16 = &W[t2 - 16 * 2]; SHA512_sigma1 (Wt2, temp1); SHA512_ADD (temp1, Wt7, temp2); SHA512_sigma0 (Wt15, temp1); SHA512_ADD (temp1, Wt16, temp3); SHA512_ADD (temp2, temp3, &W[t2]); } A[0] = context->Intermediate_Hash[0]; A[1] = context->Intermediate_Hash[1]; B[0] = context->Intermediate_Hash[2]; B[1] = context->Intermediate_Hash[3]; C[0] = context->Intermediate_Hash[4]; C[1] = context->Intermediate_Hash[5]; D[0] = context->Intermediate_Hash[6]; D[1] = context->Intermediate_Hash[7]; E[0] = context->Intermediate_Hash[8]; E[1] = context->Intermediate_Hash[9]; F[0] = context->Intermediate_Hash[10]; F[1] = context->Intermediate_Hash[11]; G[0] = context->Intermediate_Hash[12]; G[1] = context->Intermediate_Hash[13]; H[0] = context->Intermediate_Hash[14]; H[1] = context->Intermediate_Hash[15]; for (t = t2 = 0; t < 80; t++, t2 += 2) { #if 0 temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; #endif SHA512_SIGMA1 (E, temp1); SHA512_ADD (H, temp1, temp2); SHA_Ch (E, F, G, temp3); SHA512_ADD (temp2, temp3, temp4); SHA512_ADD (&K[t2], &W[t2], temp5); SHA512_ADD (temp4, temp5, temp1); #if 0 temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C); #endif SHA512_SIGMA0 (A, temp3); SHA_Maj (A, B, C, temp4); SHA512_ADD (temp3, temp4, temp2); H[0] = G[0]; H[1] = G[1]; G[0] = F[0]; G[1] = F[1]; F[0] = E[0]; F[1] = E[1]; SHA512_ADD (D, temp1, E); D[0] = C[0]; D[1] = C[1]; C[0] = B[0]; C[1] = B[1]; B[0] = A[0]; B[1] = A[1]; SHA512_ADD (temp1, temp2, A); } SHA512_ADDTO2 (&context->Intermediate_Hash[0], A); SHA512_ADDTO2 (&context->Intermediate_Hash[2], B); SHA512_ADDTO2 (&context->Intermediate_Hash[4], C); SHA512_ADDTO2 (&context->Intermediate_Hash[6], D); SHA512_ADDTO2 (&context->Intermediate_Hash[8], E); SHA512_ADDTO2 (&context->Intermediate_Hash[10], F); SHA512_ADDTO2 (&context->Intermediate_Hash[12], G); SHA512_ADDTO2 (&context->Intermediate_Hash[14], H); #else /* !USE_32BIT_ONLY */ static const uint64_t K[80] = { 0x428A2F98D728AE22ll, 0x7137449123EF65CDll, 0xB5C0FBCFEC4D3B2Fll, 0xE9B5DBA58189DBBCll, 0x3956C25BF348B538ll, 0x59F111F1B605D019ll, 0x923F82A4AF194F9Bll, 0xAB1C5ED5DA6D8118ll, 0xD807AA98A3030242ll, 0x12835B0145706FBEll, 0x243185BE4EE4B28Cll, 0x550C7DC3D5FFB4E2ll, 0x72BE5D74F27B896Fll, 0x80DEB1FE3B1696B1ll, 0x9BDC06A725C71235ll, 0xC19BF174CF692694ll, 0xE49B69C19EF14AD2ll, 0xEFBE4786384F25E3ll, 0x0FC19DC68B8CD5B5ll, 0x240CA1CC77AC9C65ll, 0x2DE92C6F592B0275ll, 0x4A7484AA6EA6E483ll, 0x5CB0A9DCBD41FBD4ll, 0x76F988DA831153B5ll, 0x983E5152EE66DFABll, 0xA831C66D2DB43210ll, 0xB00327C898FB213Fll, 0xBF597FC7BEEF0EE4ll, 0xC6E00BF33DA88FC2ll, 0xD5A79147930AA725ll, 0x06CA6351E003826Fll, 0x142929670A0E6E70ll, 0x27B70A8546D22FFCll, 0x2E1B21385C26C926ll, 0x4D2C6DFC5AC42AEDll, 0x53380D139D95B3DFll, 0x650A73548BAF63DEll, 0x766A0ABB3C77B2A8ll, 0x81C2C92E47EDAEE6ll, 0x92722C851482353Bll, 0xA2BFE8A14CF10364ll, 0xA81A664BBC423001ll, 0xC24B8B70D0F89791ll, 0xC76C51A30654BE30ll, 0xD192E819D6EF5218ll, 0xD69906245565A910ll, 0xF40E35855771202All, 0x106AA07032BBD1B8ll, 0x19A4C116B8D2D0C8ll, 0x1E376C085141AB53ll, 0x2748774CDF8EEB99ll, 0x34B0BCB5E19B48A8ll, 0x391C0CB3C5C95A63ll, 0x4ED8AA4AE3418ACBll, 0x5B9CCA4F7763E373ll, 0x682E6FF3D6B2B8A3ll, 0x748F82EE5DEFB2FCll, 0x78A5636F43172F60ll, 0x84C87814A1F0AB72ll, 0x8CC702081A6439ECll, 0x90BEFFFA23631E28ll, 0xA4506CEBDE82BDE9ll, 0xBEF9A3F7B2C67915ll, 0xC67178F2E372532Bll, 0xCA273ECEEA26619Cll, 0xD186B8C721C0C207ll, 0xEADA7DD6CDE0EB1Ell, 0xF57D4F7FEE6ED178ll, 0x06F067AA72176FBAll, 0x0A637DC5A2C898A6ll, 0x113F9804BEF90DAEll, 0x1B710B35131C471Bll, 0x28DB77F523047D84ll, 0x32CAAB7B40C72493ll, 0x3C9EBE0A15C9BEBCll, 0x431D67C49C100D4Cll, 0x4CC5D4BECB3E42B6ll, 0x597F299CFC657E2All, 0x5FCB6FAB3AD6FAECll, 0x6C44198C4A475817ll }; int t, t8; /* Loop counter */ uint64_t temp1, temp2; /* Temporary word value */ uint64_t W[80] _U_; /* Word sequence */ uint64_t A, B, C, D, E, F, G, H; /* Word buffers */ /* * Initialize the first 16 words in the array W */ for (t = t8 = 0; t < 16; t++, t8 += 8) W[t] = ((uint64_t) (context->Message_Block[t8]) << 56) | ((uint64_t) (context->Message_Block[t8 + 1]) << 48) | ((uint64_t) (context->Message_Block[t8 + 2]) << 40) | ((uint64_t) (context->Message_Block[t8 + 3]) << 32) | ((uint64_t) (context->Message_Block[t8 + 4]) << 24) | ((uint64_t) (context->Message_Block[t8 + 5]) << 16) | ((uint64_t) (context->Message_Block[t8 + 6]) << 8) | ((uint64_t) (context->Message_Block[t8 + 7])); for (t = 16; t < 80; t++) W[t] = SHA512_sigma1 (W[t - 2]) + W[t - 7] + SHA512_sigma0 (W[t - 15]) + W[t - 16]; A = context->Intermediate_Hash[0]; B = context->Intermediate_Hash[1]; C = context->Intermediate_Hash[2]; D = context->Intermediate_Hash[3]; E = context->Intermediate_Hash[4]; F = context->Intermediate_Hash[5]; G = context->Intermediate_Hash[6]; H = context->Intermediate_Hash[7]; for (t = 0; t < 80; t++) { temp1 = H + SHA512_SIGMA1 (E) + SHA_Ch (E, F, G) + K[t] + W[t]; temp2 = SHA512_SIGMA0 (A) + SHA_Maj (A, B, C); H = G; G = F; F = E; E = D + temp1; D = C; C = B; B = A; A = temp1 + temp2; } context->Intermediate_Hash[0] += A; context->Intermediate_Hash[1] += B; context->Intermediate_Hash[2] += C; context->Intermediate_Hash[3] += D; context->Intermediate_Hash[4] += E; context->Intermediate_Hash[5] += F; context->Intermediate_Hash[6] += G; context->Intermediate_Hash[7] += H; #endif /* USE_32BIT_ONLY */ context->Message_Block_Index = 0; } /* * SHA384_512Reset * * Description: * This helper function will initialize the SHA512Context in * preparation for computing a new SHA384 or SHA512 message * digest. * * Parameters: * context: [in/out] * The context to reset. * H0 * The initial hash value to use. * * Returns: * sha Error Code. * */ #ifdef USE_32BIT_ONLY static int SHA384_512Reset (SHA512Context * context, uint32_t H0[]) #else /* !USE_32BIT_ONLY */ static int SHA384_512Reset (SHA512Context * context, uint64_t H0[]) #endif /* USE_32BIT_ONLY */ { int i; if (!context) return shaNull; context->Message_Block_Index = 0; #ifdef USE_32BIT_ONLY context->Length[0] = context->Length[1] = 0; context->Length[2] = context->Length[3] = 0; for (i = 0; i < SHA512HashSize / 4; i++) context->Intermediate_Hash[i] = H0[i]; #else /* !USE_32BIT_ONLY */ context->Length_High = context->Length_Low = 0; for (i = 0; i < SHA512HashSize / 8; i++) context->Intermediate_Hash[i] = H0[i]; #endif /* USE_32BIT_ONLY */ context->Computed = 0; context->Corrupted = 0; return shaSuccess; } /* * SHA384_512ResultN * * Description: * This helper function will return the 384-bit or 512-bit message * digest into the Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 48th/64th element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA hash. * Message_Digest: [out] * Where the digest is returned. * HashSize: [in] * The size of the hash, either 48 or 64. * * Returns: * sha Error Code. * */ static int SHA384_512ResultN (SHA512Context * context, uint8_t Message_Digest[], int HashSize) { int i; #ifdef USE_32BIT_ONLY int i2; #endif /* USE_32BIT_ONLY */ if (!context || !Message_Digest) return shaNull; if (context->Corrupted) return context->Corrupted; if (!context->Computed) SHA384_512Finalize (context, 0x80); #ifdef USE_32BIT_ONLY for (i = i2 = 0; i < HashSize;) { Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 24); Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 16); Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 8); Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2++]); Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 24); Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 16); Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 8); Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2++]); } #else /* !USE_32BIT_ONLY */ for (i = 0; i < HashSize; ++i) Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i >> 3] >> 8 * (7 - (i % 8))); #endif /* USE_32BIT_ONLY */ return shaSuccess; } #endif libsmb2-6.2/lib/smb2-cmd-read.c0000664000175000017500000002771014732155517015255 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2016 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include "compat.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-private.h" static int smb2_encode_read_request(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_read_request *req) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_READ_REQUEST_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate read buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); if (!smb2->supports_multi_credit && req->length > 64 * 1024) { req->length = 64 * 1024; req->minimum_count = 0; } smb2_set_uint16(iov, 0, SMB2_READ_REQUEST_SIZE); smb2_set_uint8(iov, 3, req->flags); smb2_set_uint32(iov, 4, req->length); smb2_set_uint64(iov, 8, req->offset); memcpy(iov->buf + 16, req->file_id, SMB2_FD_SIZE); smb2_set_uint32(iov, 32, req->minimum_count); smb2_set_uint32(iov, 36, req->channel); smb2_set_uint32(iov, 40, req->remaining_bytes); smb2_set_uint16(iov, 46, req->read_channel_info_length); if (req->read_channel_info_length > 0 && req->read_channel_info != NULL) { if (smb2->passthrough) { req->read_channel_info_offset = (SMB2_READ_REQUEST_SIZE & 0xfffffffe) + SMB2_HEADER_SIZE; smb2_set_uint16(iov, 44, req->read_channel_info_offset); len = PAD_TO_64BIT(req->read_channel_info_length); buf = malloc(len); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate read channel context"); return -1; } memcpy(buf, req->read_channel_info, req->read_channel_info_length); memset(buf + req->read_channel_info_length, 0, len - req->read_channel_info_length); iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); } else { smb2_set_error(smb2, "ChannelInfo not yet implemented"); return -1; } } /* The buffer must contain at least one byte, even if we do not * have any read channel info. */ if (req->read_channel_info_length == 0) { static uint8_t zero; smb2_add_iovector(smb2, &pdu->out, &zero, 1, NULL); } return 0; } struct smb2_pdu * smb2_cmd_read_async(struct smb2_context *smb2, struct smb2_read_request *req, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_READ, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_read_request(smb2, pdu, req)) { smb2_free_pdu(smb2, pdu); return NULL; } /* Add a vector for the buffer that the application gave us */ smb2_add_iovector(smb2, &pdu->in, req->buf, req->length, NULL); if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } /* Adjust credit charge for large payloads */ if (smb2->supports_multi_credit) { pdu->header.credit_charge = (req->length - 1) / 65536 + 1; /* 3.1.5.2 of [MS-SMB2] */ } return pdu; } static int smb2_encode_read_reply(struct smb2_context *smb2, struct smb2_pdu *pdu, struct smb2_read_reply *rep) { int len; uint8_t *buf; struct smb2_iovec *iov; len = SMB2_READ_REPLY_SIZE & 0xfffffffe; buf = calloc(len, sizeof(uint8_t)); if (buf == NULL) { smb2_set_error(smb2, "Failed to allocate read reply buffer"); return -1; } iov = smb2_add_iovector(smb2, &pdu->out, buf, len, free); rep->data_offset = 0; if (rep->data_length && rep->data) { rep->data_offset = (SMB2_READ_REPLY_SIZE & 0xfffffffe) + SMB2_HEADER_SIZE; } smb2_set_uint16(iov, 0, SMB2_READ_REPLY_SIZE); smb2_set_uint8(iov, 2, rep->data_offset); smb2_set_uint32(iov, 4, rep->data_length); smb2_set_uint32(iov, 8, rep->data_remaining); if (rep->data_length > 0 && rep->data) { smb2_add_iovector(smb2, &pdu->out, rep->data, rep->data_length, free); } return 0; } struct smb2_pdu * smb2_cmd_read_reply_async(struct smb2_context *smb2, struct smb2_read_reply *rep, smb2_command_cb cb, void *cb_data) { struct smb2_pdu *pdu; pdu = smb2_allocate_pdu(smb2, SMB2_READ, cb, cb_data); if (pdu == NULL) { return NULL; } if (smb2_encode_read_reply(smb2, pdu, rep)) { smb2_free_pdu(smb2, pdu); return NULL; } if (smb2_pad_to_64bit(smb2, &pdu->out) != 0) { smb2_free_pdu(smb2, pdu); return NULL; } return pdu; } int smb2_process_read_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_read_reply *rep; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size > SMB2_READ_REPLY_SIZE) { smb2_set_error(smb2, "Unexpected size of Read " "reply. Expected %d, got %d", SMB2_READ_REPLY_SIZE, (int)iov->len); return -1; } rep = malloc(sizeof(*rep)); if (rep == NULL) { smb2_set_error(smb2, "Failed to allocate read reply"); return -1; } pdu->payload = rep; smb2_get_uint8(iov, 2, &rep->data_offset); smb2_get_uint32(iov, 4, &rep->data_length); smb2_get_uint32(iov, 8, &rep->data_remaining); rep->data = NULL; if (rep->data_length == 0) { return 0; } if (rep->data_offset != SMB2_HEADER_SIZE + 16) { smb2_set_error(smb2, "Unexpected data offset in Read reply. " "Expected %d, got %d", SMB2_HEADER_SIZE + 16, rep->data_offset); pdu->payload = NULL; free(rep); return -1; } return rep->data_length; } static void free_read_reply(struct smb2_context *smb2, void * payload) { struct smb2_read_reply *rep; if (payload == NULL) { return; } rep = (struct smb2_read_reply*)payload; if (rep->data_length != 0 && rep->data != NULL) { free(rep->data); } } int smb2_process_read_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_read_reply *rep = (struct smb2_read_reply*)pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; if (rep->data) { pdu->free_payload = free_read_reply; memcpy(rep->data, iov->buf, rep->data_length); } else { /* allow app to get data direct from iov to avoid copy */ rep->data = iov->buf; } return 0; } #define IOVREQ_OFFSET ((req->read_channel_info_offset)?(req->read_channel_info_offset - SMB2_HEADER_SIZE - \ (SMB2_READ_REQUEST_SIZE & 0xfffe)):0) int smb2_process_read_request_fixed(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_read_request *req; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; uint16_t struct_size; smb2_get_uint16(iov, 0, &struct_size); if (struct_size > SMB2_READ_REQUEST_SIZE) { smb2_set_error(smb2, "Unexpected size of Read " "request. Expected %d, got %d", SMB2_READ_REQUEST_SIZE, (int)iov->len); return -1; } req = malloc(sizeof(*req)); if (req == NULL) { smb2_set_error(smb2, "Failed to allocate read request"); return -1; } pdu->payload = req; smb2_get_uint8(iov, 3, &req->flags); smb2_get_uint32(iov, 4, &req->length); smb2_get_uint64(iov, 8, &req->offset); memcpy(req->file_id, iov->buf + 16, SMB2_FD_SIZE); smb2_get_uint32(iov, 32, &req->minimum_count); smb2_get_uint32(iov, 36, &req->channel); smb2_get_uint32(iov, 40, &req->remaining_bytes); if (req->read_channel_info_length) { req->read_channel_info_offset = (SMB2_READ_REQUEST_SIZE & 0xfffffffe) + SMB2_HEADER_SIZE; smb2_get_uint16(iov, 44, &req->read_channel_info_offset); } smb2_get_uint16(iov, 46, &req->read_channel_info_length); if (req->length > smb2->max_read_size) { smb2_set_error(smb2, "can not read more than %d bytes", smb2->max_read_size); pdu->payload = NULL; free(req); return -1; } /* provide an iovec to read the data into */ req->buf = malloc(req->length); if (!req->buf) { smb2_set_error(smb2, "can not alloc for read reply data"); pdu->payload = NULL; free(req); return -1; } smb2_add_iovector(smb2, &pdu->in, req->buf, req->length, free); if (req->read_channel_info_length == 0) { return 0; } if (req->read_channel_info_offset < SMB2_HEADER_SIZE + (SMB2_READ_REQUEST_SIZE & 0xfffe)) { smb2_set_error(smb2, "channel info overlaps request", ""); pdu->payload = NULL; free(req); return -1; } return IOVREQ_OFFSET + req->read_channel_info_length; } int smb2_process_read_request_variable(struct smb2_context *smb2, struct smb2_pdu *pdu) { struct smb2_read_request *req = (struct smb2_read_request*)pdu->payload; struct smb2_iovec *iov = &smb2->in.iov[smb2->in.niov - 1]; req->read_channel_info = (uint8_t *)iov->buf; return 0; } libsmb2-6.2/lib/md5.h0000664000175000017500000000335514732155517013431 0ustar polpypolpy/* * This is the header file for the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. * * Changed so as no longer to depend on Colin Plumb's `usual.h' * header definitions; now uses stuff from dpkg's config.h * - Ian Jackson . * Still in the public domain. */ #ifndef MD5_H #define MD5_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_NETINET_IN_H #include #endif #include #include #ifdef HAVE_STDINT_H #include #endif #if !defined(_WIN32) && (__BYTE_ORDER == __BIG_ENDIAN) || defined(XBOX_360_PLATFORM) # define WORDS_BIGENDIAN 1 #endif #if !defined(PS2_IOP_PLATFORM) typedef uint32_t UWORD32; #endif #ifdef __cplusplus extern "C" { #endif #define md5byte unsigned char struct MD5Context { UWORD32 buf[4]; UWORD32 bytes[2]; UWORD32 in[16]; }; void MD5Init(struct MD5Context *context); void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); void MD5Final(unsigned char digest[16], struct MD5Context *context); void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); #ifdef __cplusplus } #endif #endif /* !MD5_H */ libsmb2-6.2/lib/sha-private.h0000664000175000017500000000160414732155517015162 0ustar polpypolpy/*************************** sha-private.h ***************************/ /********************** See RFC 4634 for details *********************/ #ifndef _SHA_PRIVATE__H #define _SHA_PRIVATE__H /* * These definitions are defined in FIPS-180-2, section 4.1. * Ch() and Maj() are defined identically in sections 4.1.1, * 4.1.2 and 4.1.3. * * The definitions used in FIPS-180-2 are as follows: */ #ifndef USE_MODIFIED_MACROS #define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #else /* USE_MODIFIED_MACROS */ /* * The following definitions are equivalent and potentially faster. */ #define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) #define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) #endif /* USE_MODIFIED_MACROS */ #define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) #endif /* _SHA_PRIVATE__H */ libsmb2-6.2/lib/aes128ccm.h0000664000175000017500000000232014732155517014421 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2019 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ void aes128ccm_encrypt(unsigned char *key, unsigned char *nonce, size_t nlen, unsigned char *aad, size_t alen, unsigned char *p, size_t plen, unsigned char *m, size_t mlen); int aes128ccm_decrypt(unsigned char *key, unsigned char *nonce, size_t nlen, unsigned char *aad, size_t alen, unsigned char *p, size_t plen, unsigned char *m, size_t mlen); libsmb2-6.2/lib/ntlmssp.c0000664000175000017500000011656514732155517014447 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2018 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UNISTD_H #include #endif #include #include "portable-endian.h" #include #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "compat.h" #include "slist.h" #include "smb2.h" #include "libsmb2.h" #include "libsmb2-raw.h" #include "libsmb2-private.h" #include "spnego-wrapper.h" #include "md4.h" #include "md5.h" #include "hmac-md5.h" #include "ntlmssp.h" struct auth_data { unsigned char *buf; size_t len; size_t allocated; int neg_result; unsigned char *ntlm_buf; size_t ntlm_len; char *user; char *password; char *domain; char *workstation; uint8_t *client_challenge; uint8_t server_challenge[8]; uint8_t *target_info; int target_info_len; int spnego_wrap; int is_authenticated; time_t wintime; uint8_t exported_session_key[SMB2_KEY_SIZE]; }; #define NTLMSSP_NEGOTIATE_56 0x80000000 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 #define NTLMSSP_NEGOTIATE_128 0x20000000 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 #define NTLMSSP_NEGOTIATE_ANONYMOUS 0x00000800 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 #define NTLMSSP_REQUEST_TARGET 0x00000004 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 void hex_print(const char *blurb, uint8_t *data, int len) { int i; printf("%s\n", blurb); for (i = 0; i < len; i++) { printf("%02X ", data[i]); if (!((i + 1) & 0xf)) { printf("\n"); } } if ((len & 0xf)) { printf("\n"); } printf("\n"); } void ntlmssp_destroy_context(struct auth_data *auth) { free(auth->ntlm_buf); free(auth->buf); free(auth->user); free(auth->password); free(auth->domain); free(auth->workstation); free(auth->client_challenge); free(auth->target_info); free(auth); } struct auth_data * ntlmssp_init_context(const char *user, const char *password, const char *domain, const char *workstation, const char *client_challenge) { struct auth_data *auth_data = NULL; struct smb2_timeval tv; auth_data = calloc(1, sizeof(struct auth_data)); if (auth_data == NULL) { return NULL; } 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); tv.tv_sec = time(NULL); tv.tv_usec = 0; 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 ntlmssp_set_spnego_wrapping(struct auth_data *auth, int wrap) { auth->spnego_wrap = wrap; } int ntlmssp_get_spnego_wrapping(struct auth_data *auth) { return auth->spnego_wrap; } int ntlmssp_get_authenticated(struct auth_data *auth) { return auth ? auth->is_authenticated : 0; } static int encoder(const void *buffer, size_t size, void *ptr) { struct auth_data *auth_data = ptr; if (size + auth_data->len > auth_data->allocated) { unsigned char *tmp = auth_data->buf; auth_data->allocated = 2 * ((size + auth_data->allocated + 256) & ~0xff); auth_data->buf = malloc(auth_data->allocated); if (auth_data->buf == NULL) { free(tmp); return -1; } memcpy(auth_data->buf, tmp, auth_data->len); free(tmp); } if (auth_data->buf == NULL) { return -1; } memcpy(auth_data->buf + auth_data->len, buffer, size); auth_data->len += size; return 0; } static int encode_ntlm_negotiate_message(struct smb2_context *smb2, struct auth_data *auth_data) { unsigned char ntlm[40]; uint32_t flags; uint32_t u32; int ntlm_len = 32; memset(ntlm, 0, sizeof(ntlm)); memcpy(ntlm, "NTLMSSP", 8); u32 = htole32(NEGOTIATE_MESSAGE); memcpy(&ntlm[8], &u32, 4); flags = NTLMSSP_NEGOTIATE_128| NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY| /* NTLMSSP_NEGOTIATE_KEY_EXCH| */ /* NTLMSSP_NEGOTIATE_VERSION| */ /* NTLMSSP_NEGOTIATE_TARGET_INFO| */ /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN| */ NTLMSSP_NEGOTIATE_NTLM| /* Azure netapp server needs this */ NTLMSSP_NEGOTIATE_SEAL| /* NTLMSSP_NEGOTIATE_SIGN| */ NTLMSSP_REQUEST_TARGET| NTLMSSP_NEGOTIATE_OEM| NTLMSSP_NEGOTIATE_UNICODE; u32 = htole32(flags); memcpy(&ntlm[12], &u32, 4); if (flags & NTLMSSP_NEGOTIATE_VERSION) { u32 = 0x1db00106; u32 = htole32(u32); memcpy(&ntlm[32], &u32, 4); u32 = 0x0f000000; u32 = htole32(u32); memcpy(&ntlm[36], &u32, 4); ntlm_len = 40; } if (encoder(&ntlm[0], ntlm_len, auth_data) < 0) { return -1; } return 0; } static int ntlm_decode_challenge_message(struct smb2_context *smb2, struct auth_data *auth_data, unsigned char *buf, size_t len) { if (buf && len > 0) { free(auth_data->ntlm_buf); auth_data->ntlm_len = len; auth_data->ntlm_buf = malloc(auth_data->ntlm_len); if (auth_data->ntlm_buf == NULL) { return -1; } memcpy(auth_data->ntlm_buf, buf, auth_data->ntlm_len); return 0; } return -1; } static int ntlm_convert_password_hash(const char *password, unsigned char password_hash[16]) { int i, hn, ln; struct smb2_utf16 *utf16_password = NULL; utf16_password = smb2_utf8_to_utf16(password); if (utf16_password == NULL) { return -1; } for (i = 0; i < 32; i++) { utf16_password->val[i] = le16toh(utf16_password->val[i]); if (islower((unsigned int) utf16_password->val[i])) { utf16_password->val[i] = toupper((unsigned int) utf16_password->val[i]); } } /* FreeRDP: winpr/libwinpr/sspi/NTLM/ntlm_compute.c */ for (i = 0; i < 32; i += 2) { hn = utf16_password->val[i] > '9' ? utf16_password->val[i] - 'A' + 10 : utf16_password->val[i] - '0'; ln = utf16_password->val[i + 1] > '9' ? utf16_password->val[i + 1] - 'A' + 10 : utf16_password->val[i + 1] - '0'; password_hash[i / 2] = (hn << 4) | ln; } return 0; } static int NTOWFv1(const char *password, unsigned char password_hash[16]) { MD4_CTX ctx; struct smb2_utf16 *utf16_password = NULL; utf16_password = smb2_utf8_to_utf16(password); if (utf16_password == NULL) { return -1; } MD4Init(&ctx); MD4Update(&ctx, (unsigned char *)utf16_password->val, utf16_password->len * 2); MD4Final(password_hash, &ctx); free(utf16_password); return 0; } static int NTOWFv2(const char *user, const char *password, const char *domain, unsigned char ntlmv2_hash[16]) { int64_t i; size_t len; char *userdomain; 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) { return -1; } } else { if (NTOWFv1(password, ntlm_hash) < 0) { return -1; } } len = strlen(user) + 1; if (domain) { len += strlen(domain); } userdomain = malloc(len); if (userdomain == NULL) { return -1; } strcpy(userdomain, user); for (i = strlen(userdomain) - 1; i >= 0; i--) { if (islower((unsigned int) userdomain[i])) { userdomain[i] = toupper((unsigned int) userdomain[i]); } } if (domain) { strcat(userdomain, domain); } utf16_userdomain = smb2_utf8_to_utf16(userdomain); if (utf16_userdomain == NULL) { free(userdomain); return -1; } smb2_hmac_md5((unsigned char *)utf16_userdomain->val, utf16_userdomain->len * 2, ntlm_hash, 16, ntlmv2_hash); free(userdomain); free(utf16_userdomain); return 0; } /* This is not the same temp as in MS-NLMP. This temp has an additional * 16 bytes at the start of the buffer. * Use &auth_data->val[16] if you want the temp from MS-NLMP */ static int encode_temp(struct auth_data *auth_data, uint64_t t, uint8_t *client_challenge, size_t client_challenge_len, uint8_t *server_challenge, uint8_t *server_name, size_t server_name_len) { unsigned char sign[8] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned char zero[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint64_t u64; if (encoder(&zero, 8, auth_data) < 0) { return -1; } if (encoder(server_challenge, 8, auth_data) < 0) { return -1; } if (encoder(sign, 8, auth_data) < 0) { return -1; } u64 = htole64(t); if (encoder(&u64, 8, auth_data) < 0) { return -1; } if (encoder(client_challenge, client_challenge_len, auth_data) < 0) { return -1; } if (encoder(&zero, 4, auth_data) < 0) { return -1; } if (encoder(server_name, server_name_len, auth_data) < 0) { return -1; } if (encoder(&zero, 4, auth_data) < 0) { return -1; } return 0; } static int encode_ntlm_auth(struct smb2_context *smb2, time_t ti, struct auth_data *auth_data, char *server_challenge) { int ret = -1; unsigned char lm_buf[16] _U_; unsigned char *NTChallengeResponse_buf = NULL; unsigned char ResponseKeyNT[16]; struct smb2_utf16 *utf16_domain = NULL; struct smb2_utf16 *utf16_user = NULL; struct smb2_utf16 *utf16_workstation = NULL; unsigned int NTChallengeResponse_len = 0; unsigned char NTProofStr[16]; unsigned char LMStr[16]; time_t t; struct smb2_timeval tv _U_; char *server_name_buf; uint32_t server_name_len; uint32_t u32; uint32_t server_neg_flags; unsigned char key_exch[SMB2_KEY_SIZE]; uint8_t anonymous = 0; tv.tv_sec = ti; tv.tv_usec = 0; t = smb2_timeval_to_win(&tv); if (auth_data->password == NULL) { anonymous = 1; goto encode; } /* * Generate Concatenation of(NTProofStr, temp) */ if (NTOWFv2(auth_data->user, auth_data->password, auth_data->domain, ResponseKeyNT) < 0) { goto finished; } /* Must have at least enough bytes for server name offset */ if (auth_data->ntlm_len < 47) { goto finished; } /* get the server neg flags */ memcpy(&server_neg_flags, &auth_data->ntlm_buf[20], 4); server_neg_flags = le32toh(server_neg_flags); memcpy(&u32, &auth_data->ntlm_buf[40], 4); u32 = le32toh(u32); server_name_len = u32 >> 16; memcpy(&u32, &auth_data->ntlm_buf[44], 4); u32 = le32toh(u32); /* Server name must fit in the buffer */ if (u32 >= auth_data->ntlm_len || (u32 + server_name_len) > auth_data->ntlm_len) { goto finished; } server_name_buf = (char *)&auth_data->ntlm_buf[u32]; if (encode_temp(auth_data, t, auth_data->client_challenge, 8, (uint8_t*)server_challenge, (uint8_t*)server_name_buf, server_name_len) < 0) { return -1; } smb2_hmac_md5(&auth_data->buf[8], (unsigned int)auth_data->len-8, ResponseKeyNT, 16, NTProofStr); memcpy(auth_data->buf, NTProofStr, 16); NTChallengeResponse_buf = auth_data->buf; NTChallengeResponse_len = (unsigned int)auth_data->len; auth_data->buf = NULL; auth_data->len = 0; auth_data->allocated = 0; /* get the NTLMv2 Key-Exchange Key For NTLMv2 - Key Exchange Key is the Session Base Key */ smb2_hmac_md5(NTProofStr, 16, ResponseKeyNT, 16, key_exch); memcpy(auth_data->exported_session_key, key_exch, 16); encode: /* * Generate AUTHENTICATE_MESSAGE */ encoder("NTLMSSP", 8, auth_data); /* message type */ u32 = htole32(AUTHENTICATION_MESSAGE); encoder(&u32, 4, auth_data); /* lm challenge response fields */ if (!anonymous) { memcpy(&lm_buf[0], server_challenge, 8); memcpy(&lm_buf[8], auth_data->client_challenge, 8); smb2_hmac_md5(&lm_buf[0], 16, ResponseKeyNT, 16, LMStr); u32 = htole32(0x00180018); encoder(&u32, 4, auth_data); u32 = 0; encoder(&u32, 4, auth_data); } else { u32 = 0; encoder(&u32, 4, auth_data); encoder(&u32, 4, auth_data); } /* nt challenge response fields */ u32 = htole32((NTChallengeResponse_len<<16)| NTChallengeResponse_len); encoder(&u32, 4, auth_data); u32 = 0; encoder(&u32, 4, auth_data); /* domain name fields */ if (!anonymous && auth_data->domain) { utf16_domain = smb2_utf8_to_utf16(auth_data->domain); if (utf16_domain == NULL) { goto finished; } u32 = utf16_domain->len * 2; u32 = htole32((u32 << 16) | u32); encoder(&u32, 4, auth_data); u32 = 0; encoder(&u32, 4, auth_data); } else { u32 = 0; encoder(&u32, 4, auth_data); encoder(&u32, 4, auth_data); } /* user name fields */ if (!anonymous) { utf16_user = smb2_utf8_to_utf16(auth_data->user); if (utf16_user == NULL) { goto finished; } u32 = utf16_user->len * 2; u32 = htole32((u32 << 16) | u32); encoder(&u32, 4, auth_data); u32 = 0; encoder(&u32, 4, auth_data); } else { u32 = 0; encoder(&u32, 4, auth_data); encoder(&u32, 4, auth_data); } /* workstation name fields */ if (!anonymous && auth_data->workstation) { utf16_workstation = smb2_utf8_to_utf16(auth_data->workstation); if (utf16_workstation == NULL) { goto finished; } u32 = utf16_workstation->len * 2; u32 = htole32((u32 << 16) | u32); encoder(&u32, 4, auth_data); u32 = 0; encoder(&u32, 4, auth_data); } else { u32 = 0; encoder(&u32, 4, auth_data); encoder(&u32, 4, auth_data); } /* encrypted random session key */ u32 = 0; encoder(&u32, 4, auth_data); encoder(&u32, 4, auth_data); /* negotiate flags */ u32 = NTLMSSP_NEGOTIATE_128| NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY| NTLMSSP_NEGOTIATE_ALWAYS_SIGN| NTLMSSP_NEGOTIATE_SIGN| NTLMSSP_REQUEST_TARGET|NTLMSSP_NEGOTIATE_OEM| NTLMSSP_NEGOTIATE_UNICODE; if (anonymous) u32 |= NTLMSSP_NEGOTIATE_ANONYMOUS; else u32 |= NTLMSSP_NEGOTIATE_SEAL; u32 = htole32(u32); encoder(&u32, 4, auth_data); if (!anonymous) { /* append domain */ u32 = htole32((uint32_t)auth_data->len); memcpy(&auth_data->buf[32], &u32, 4); if (utf16_domain) { encoder(utf16_domain->val, utf16_domain->len * 2, auth_data); } /* append user */ u32 = htole32((uint32_t)auth_data->len); memcpy(&auth_data->buf[40], &u32, 4); encoder(utf16_user->val, utf16_user->len * 2, auth_data); /* append workstation */ u32 = htole32((uint32_t)auth_data->len); memcpy(&auth_data->buf[48], &u32, 4); if (utf16_workstation) { encoder(utf16_workstation->val, utf16_workstation->len * 2, auth_data); } /* append LMChallengeResponse */ u32 = htole32((uint32_t)auth_data->len); memcpy(&auth_data->buf[16], &u32, 4); encoder(LMStr, 16, auth_data); encoder(auth_data->client_challenge, 8, auth_data); /* append NTChallengeResponse */ u32 = htole32((uint32_t)auth_data->len); memcpy(&auth_data->buf[24], &u32, 4); encoder(NTChallengeResponse_buf, NTChallengeResponse_len, auth_data); } ret = 0; finished: free(utf16_domain); free(utf16_user); free(utf16_workstation); free(NTChallengeResponse_buf); return ret; } static int encode_ntlm_challenge(struct smb2_context *smb2, struct auth_data *auth_data) { int ret = -1; struct smb2_utf16 *utf16_workstation = NULL; struct smb2_utf16 *utf16_workstation_upper = NULL; uint16_t u16; uint32_t u32; uint64_t u64; uint8_t anonymous = 0; int target_info_pos; int namelen; int cc; char *upper = NULL; /* Generate CHALLENGE_MESSAGE */ encoder("NTLMSSP", 8, auth_data); /* message type */ u32 = htole32(CHALLENGE_MESSAGE); encoder(&u32, 4, auth_data); /* target name fields */ u32 = 0; encoder(&u32, 4, auth_data); encoder(&u32, 4, auth_data); /* negotiate flags */ u32 = NTLMSSP_NEGOTIATE_128| NTLMSSP_NEGOTIATE_TARGET_INFO| NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY| NTLMSSP_NEGOTIATE_ALWAYS_SIGN| NTLMSSP_NEGOTIATE_SIGN| /* NTLMSSP_NEGOTIATE_KEY_EXCH| */ NTLMSSP_REQUEST_TARGET|NTLMSSP_NEGOTIATE_OEM| NTLMSSP_NEGOTIATE_VERSION| NTLMSSP_NEGOTIATE_UNICODE; if (anonymous) u32 |= NTLMSSP_NEGOTIATE_ANONYMOUS; else u32 |= NTLMSSP_NEGOTIATE_SEAL; u32 = htole32(u32); encoder(&u32, 4, auth_data); /* server challenge */ for (cc = 0; cc < 8; cc++) { auth_data->server_challenge[cc] = cc + 1; } encoder(auth_data->server_challenge, 8, auth_data); /* reserved */ u32 = 0; encoder(&u32, 4, auth_data); encoder(&u32, 4, auth_data); /* target into fields */ encoder(&u32, 4, auth_data); encoder(&u32, 4, auth_data); /* version (if we set negotiate version flag */ u32 = htole32(0x00000106); encoder(&u32, 4, auth_data); u32 = htole32(0x0F000000); encoder(&u32, 4, auth_data); /* target name */ if (auth_data->workstation) { int i; namelen = strlen(auth_data->workstation); upper = malloc(namelen + 1); if (!upper) { return -1; } for (i = 0; i < namelen; i++) { upper[i] = toupper(auth_data->workstation[i]); } upper[namelen] = 0; utf16_workstation = smb2_utf8_to_utf16(auth_data->workstation); if (utf16_workstation == NULL) { goto finished; } utf16_workstation_upper = smb2_utf8_to_utf16(upper); if (utf16_workstation_upper == NULL) { goto finished; } u32 = htole32(auth_data->len); memcpy(&auth_data->buf[16], &u32, 4); u32 = utf16_workstation->len * 2; u32 = htole32((u32 << 16) | u32); memcpy(&auth_data->buf[12], &u32, 4); encoder(utf16_workstation_upper->val, utf16_workstation_upper->len * 2, auth_data); } /* target info fields */ target_info_pos = auth_data->len; if (utf16_workstation) { u16 = 0x0002; /* netbios domain */ encoder(&u16, 2, auth_data); u16 = utf16_workstation_upper->len * 2; encoder(&u16, 2, auth_data); encoder(utf16_workstation_upper->val, utf16_workstation_upper->len * 2, auth_data); u16 = 0x0001; /* netbios computer name */ encoder(&u16, 2, auth_data); u16 = utf16_workstation->len * 2; encoder(&u16, 2, auth_data); encoder(utf16_workstation_upper->val, utf16_workstation_upper->len * 2, auth_data); u16 = 0x0004; /* dns domain name */ encoder(&u16, 2, auth_data); u16 = 0; encoder(&u16, 2, auth_data); u16 = 0x0003; /* dns computer name */ encoder(&u16, 2, auth_data); u16 = utf16_workstation->len * 2; encoder(&u16, 2, auth_data); encoder(utf16_workstation->val, utf16_workstation->len * 2, auth_data); } /* target info timestamp */ u16 = 0x0007; encoder(&u16, 2, auth_data); u16 = 8; encoder(&u16, 2, auth_data); u64 = auth_data->wintime; encoder(&u64, 8, auth_data); /* end of info */ u32 = 0; encoder(&u32, 4, auth_data); /* save the target info in auth-data for later */ auth_data->target_info_len = auth_data->len - target_info_pos; auth_data->target_info = malloc(auth_data->target_info_len); memcpy(auth_data->target_info, auth_data->buf + target_info_pos, auth_data->target_info_len); /* back annotate length of target info */ u16 = htole16(auth_data->len - target_info_pos); memcpy(&auth_data->buf[40], &u16, 2); memcpy(&auth_data->buf[42], &u16, 2); u16 = htole16(target_info_pos); memcpy(&auth_data->buf[44], &u16, 2); ret = 0; finished: if (upper) { free(upper); } if (utf16_workstation) { free(utf16_workstation); } if (utf16_workstation_upper) { free(utf16_workstation_upper); } return ret; } int ntlmssp_generate_blob(struct smb2_server *server, struct smb2_context *smb2, time_t t, struct auth_data *auth_data, unsigned char *input_buf, int input_len, unsigned char **output_buf, uint16_t *output_len) { uint32_t cmd; uint8_t *ntlmssp; int ntlmssp_len; uint8_t *spnego_buf; int spnego_len; int is_wrapped; free(auth_data->buf); auth_data->buf = NULL; auth_data->len = 0; auth_data->allocated = 0; if (input_buf == NULL) { if (smb2_is_server(smb2)) { return -1; } encode_ntlm_negotiate_message(smb2, auth_data); if (auth_data->spnego_wrap) { spnego_len = smb2_spnego_wrap_gssapi(smb2, auth_data->buf, auth_data->len, (void*)&spnego_buf); if (spnego_len < 0) { smb2_set_error(smb2, "can not wrap negotiate"); return -1; } free(auth_data->buf); auth_data->buf = spnego_buf; auth_data->len = spnego_len; } } else { if(ntlmssp_get_message_type(smb2, input_buf, input_len, &cmd, &ntlmssp, &ntlmssp_len, &is_wrapped) < 0) { ntlmssp_len = 0; } if (ntlmssp_len < 12) { smb2_set_error(smb2, "no message type in NTLMSSP blob"); return -1; } if (is_wrapped) { auth_data->spnego_wrap = 1; } if (smb2_is_server(smb2)) { if (cmd == NEGOTIATE_MESSAGE) { if (encode_ntlm_challenge(smb2, auth_data)) { smb2_set_error(smb2, "can not encode challenge"); return -1; } if (auth_data->spnego_wrap) { spnego_len = smb2_spnego_wrap_ntlmssp_challenge(smb2, auth_data->buf, auth_data->len, (void*)&spnego_buf); if (spnego_len < 0) { smb2_set_error(smb2, "can not wrap challenge"); return -1; } free(auth_data->buf); auth_data->buf = spnego_buf; auth_data->len = spnego_len; } } else if (cmd == AUTHENTICATION_MESSAGE) { auth_data->is_authenticated = !ntlmssp_authenticate_blob(server, smb2, auth_data, ntlmssp, ntlmssp_len); if (auth_data->spnego_wrap) { spnego_len = smb2_spnego_wrap_authenticate_result(smb2, auth_data->is_authenticated, (void*)&spnego_buf); if (spnego_len < 0) { smb2_set_error(smb2, "can not wrap auth result"); return -1; } free(auth_data->buf); auth_data->buf = spnego_buf; auth_data->len = spnego_len; } } else { return -1; } } else { if (cmd == CHALLENGE_MESSAGE) { if (ntlm_decode_challenge_message(smb2, auth_data, ntlmssp, ntlmssp_len) < 0) { smb2_set_error(smb2, "can not decode challenge"); return -1; } if (encode_ntlm_auth(smb2, t, auth_data, (char *)&auth_data->ntlm_buf[24]) < 0) { smb2_set_error(smb2, "can not encode auth data"); return -1; } /* TODO - spnego wrap auth? */ } else { smb2_set_error(smb2, "Unexpected NTLMSSP message %08X, wanted challenge", cmd); return -1; } } } *output_buf = auth_data->buf; *output_len = (uint16_t)auth_data->len; return 0; } void ntlmssp_get_utf16_field(uint8_t *input_buf, int input_len, int offset, char **result) { uint32_t field_len; uint32_t field_off; uint32_t u32; *result = NULL; if (offset > (input_len - 8)) { return; } memcpy(&u32, &input_buf[offset], 4); field_len = le32toh(u32) >> 16; memcpy(&u32, &input_buf[offset + 4], 4); field_off = le32toh(u32); if (field_len && field_off) { *result = (char*)smb2_utf16_to_utf8((uint16_t*)(input_buf + field_off), field_len / 2); } } int ntlmssp_authenticate_blob(struct smb2_server *server, struct smb2_context *smb2, struct auth_data *auth_data, unsigned char *input_buf, int input_len) { unsigned char ResponseKeyNT[16]; unsigned char NTProofStr[16]; unsigned char key_exch[SMB2_KEY_SIZE]; uint32_t field_len; uint32_t field_off; uint32_t challenge_len; uint8_t *response; uint8_t *temp; uint32_t temp_len; int ret = -1; /* uint32_t negotiate_flags; */ uint32_t u32; if (!input_buf || (input_len < 8) || memcmp(input_buf, "NTLMSSP", 8)) { return -1; } memcpy(&u32, &input_buf[4*2], 4); u32 = le32toh(u32); if (u32 != AUTHENTICATION_MESSAGE) { return -1; } if (auth_data->domain) { free(auth_data->domain); } if (auth_data->user) { free(auth_data->user); } if (auth_data->workstation) { free(auth_data->workstation); } ntlmssp_get_utf16_field(input_buf, input_len, 4*7, &auth_data->domain); ntlmssp_get_utf16_field(input_buf, input_len, 4*9, &auth_data->user); ntlmssp_get_utf16_field(input_buf, input_len, 4*11, &auth_data->workstation); memcpy(&u32, &input_buf[4*15], 4); /* call server handler to get pw for this user */ if (server && server->handlers) { if(server->handlers->authorize_user(server, smb2, auth_data->user, auth_data->domain, auth_data->workstation)) { smb2_set_error(smb2, "server can not authorize %s", auth_data->user); return -1; } if (!smb2->password && !server->allow_anonymous) { smb2_set_error(smb2, "server has no passwd for %s", auth_data->user); return -1; } } /* if no user/pw, and anonymous allowed, do anonymous */ if (!auth_data->user || (auth_data->user[0] == '\0') || !smb2->password || (smb2->password[0] == '\0')) { if (server->allow_anonymous) { return 0; } return -1; } /* negotiate_flags = le32toh(u32); */ /* Lan Man response (we dont even look at, its obsolete) */ /* NTLM response */ memcpy(&u32, &input_buf[4*5], 4); field_len = le32toh(u32) >> 16; memcpy(&u32, &input_buf[4*6], 4); field_off = le32toh(u32); if (field_len == 0 || field_off == 0) { return -1; } if (field_off > (uint32_t)input_len) { return -1; } /* 16 byte NTLMv2 response */ response = input_buf + field_off; challenge_len = field_len - 16; if (challenge_len > 9*4) { temp = input_buf + field_off + 16; temp_len = field_len - 16; if (auth_data->client_challenge) { free(auth_data->client_challenge); } auth_data->client_challenge = malloc(8); memcpy(auth_data->client_challenge, input_buf + field_off + 32, 8); } else { smb2_set_error(smb2, "bad NTLMSSP challenge len %d", challenge_len); return -1; } if (NTOWFv2(auth_data->user, smb2->password, auth_data->domain, ResponseKeyNT) < 0) { return -1; } /* wipe pw out now that its been used */ smb2_set_password(smb2, ""); auth_data->len = 0; if (encoder(auth_data->server_challenge, 8, auth_data)) { return -1; } if (encoder(temp, temp_len, auth_data)) { return -1; } temp = auth_data->buf; temp_len = auth_data->len; smb2_hmac_md5(temp, temp_len, ResponseKeyNT, 16, NTProofStr); memcpy(auth_data->buf, NTProofStr, 16); /* verify ntproof */ if (memcmp(NTProofStr, response, 16)) { smb2_set_error(smb2, "NTLMSSP NTProof != response. Auth failed"); goto fail; } smb2_hmac_md5(NTProofStr, 16, ResponseKeyNT, 16, key_exch); memcpy(auth_data->exported_session_key, key_exch, 16); ret = 0; fail: free(auth_data->buf); auth_data->buf = NULL; auth_data->len = 0; return ret; } int ntlmssp_get_session_key(struct auth_data *auth, uint8_t **key, uint8_t *key_size) { uint8_t *mkey = NULL; if (auth == NULL || key == NULL || key_size == NULL) { return -1; } mkey = (uint8_t *) malloc(SMB2_KEY_SIZE); if (mkey == NULL) { return -1; } memcpy(mkey, auth->exported_session_key, SMB2_KEY_SIZE); *key = mkey; *key_size = SMB2_KEY_SIZE; return 0; } int ntlmssp_get_message_type(struct smb2_context *smb2, uint8_t *buffer, int len, uint32_t *message_type, uint8_t **ntlmssp_ptr, int *ntlmssp_len, int *is_wrapped) { uint8_t *ntlmssp = NULL; uint32_t u32; uint32_t mechanisms; int ntlm_len; if (message_type) { *message_type = 0xFFFFFFFF; } if (ntlmssp_ptr) { *ntlmssp_ptr = NULL; } if (ntlmssp_len) { *ntlmssp_len = 0; } if (!buffer || len < 12) { return -1; } ntlm_len = smb2_spnego_unwrap_blob(smb2, buffer, len, &ntlmssp, &mechanisms); if (ntlm_len < 12 || !ntlmssp) { return -1; } if (ntlmssp != buffer) { if (is_wrapped) { *is_wrapped = 1; } } else { if (is_wrapped) { *is_wrapped = 0; } } memcpy(&u32, ntlmssp + 8, sizeof(uint32_t)); if (message_type) { *message_type = le32toh(u32); } if (ntlmssp_ptr) { *ntlmssp_ptr = ntlmssp; } if (ntlmssp_len) { *ntlmssp_len = ntlm_len; } return 0; } libsmb2-6.2/lib/aes128ccm.c0000664000175000017500000001242414732155517014422 0ustar polpypolpy/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ /* Copyright (C) 2019 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #include #include #include "compat.h" #include "portable-endian.h" #include "aes.h" static void aes_ccm_generate_b0(unsigned char *nonce, size_t nlen, size_t alen, size_t plen, size_t mlen, unsigned char *buf) { uint32_t len; memset(buf, 0, 16); if (alen) { buf[0] |= 0x40; /* Adata */ } buf[0] |= (((mlen - 2) / 2) << 3) & 0x38; /* M' */ buf[0] |= (15 - nlen - 1) & 0x07; /* L' */ len = htobe32((uint32_t)plen); memcpy(&buf[12], &len, 4); memcpy(&buf[1], nonce, nlen); } static inline void bxory(unsigned char *b, unsigned char *y, size_t num) { int i; for(i = 0; i < (int)num; i++) { b[i] = b[i] ^ y[i]; } } static void ccm_generate_T(unsigned char *key, unsigned char *nonce, size_t nlen, unsigned char *aad, size_t alen, unsigned char *p, size_t plen, unsigned char *m, size_t mlen) { unsigned char b[16] _U_, y[16]_U_; uint16_t l; aes_ccm_generate_b0(nonce, nlen, alen, plen, mlen, &b[0]); AES128_ECB_encrypt(b, key, y); /* Create Aad */ if (alen) { /* First block */ memset(b, 0, 16); l = htobe16((uint16_t)alen); memcpy(b, &l, 2); l = (alen > 14) ? 14 : (uint16_t)alen; memcpy(&b[2], aad, l); aad += l; alen -= l; bxory(b, y, 16); AES128_ECB_encrypt(b, key, y); while (alen) { memset(b, 0, 16); l = (alen > 16) ? 16 : (uint16_t)alen; memcpy(b, aad, l); aad += l; alen -= l; bxory(b, y, 16); AES128_ECB_encrypt(b, key, y); } } /* Create Payload */ while (plen) { memset(b, 0, 16); l = (plen > 16) ? 16 : (uint16_t)plen; memcpy(b, p, l); p += l; plen -= l; bxory(b, y, 16); AES128_ECB_encrypt(b, key, y); } memcpy(m, y, mlen); } static void ccm_generate_s(unsigned char *key, unsigned char *nonce, size_t nlen, size_t plen, int i, unsigned char *s) { uint32_t l; memset(s, 0, 16); s[0] |= (15 - nlen - 1) & 0x07; l = htobe32(i); memcpy(&s[12], &l, 4); memcpy(&s[1], nonce, nlen); AES128_ECB_encrypt(s, key, s); } static void aes_ccm_crypt(unsigned char *key, unsigned char *nonce, size_t nlen, unsigned char *p, size_t plen) { int j; size_t l; unsigned char s[16] _U_; j = 0; while (plen) { l = (plen > 16) ? 16 : plen; ccm_generate_s(key, nonce, nlen, plen, j + 1, &s[0]); bxory(&p[j * 16], &s[0], l); j++; plen -= l; } } void aes128ccm_encrypt(unsigned char *key, unsigned char *nonce, size_t nlen, unsigned char *aad, size_t alen, unsigned char *p, size_t plen, unsigned char *m, size_t mlen) { unsigned char s[16] _U_; ccm_generate_T(key, nonce, nlen, aad, alen, p, plen, m, mlen); ccm_generate_s(key, nonce, nlen, plen, 0, &s[0]); bxory(m, &s[0], mlen); aes_ccm_crypt(key, nonce, nlen, p, plen); } int aes128ccm_decrypt(unsigned char *key, unsigned char *nonce, size_t nlen, unsigned char *aad, size_t alen, unsigned char *p, size_t plen, unsigned char *m, size_t mlen) { unsigned char s[16] _U_; unsigned char tmp[16]; aes_ccm_crypt(key, nonce, nlen, p, plen); ccm_generate_T(key, nonce, nlen, aad, alen, p, plen, tmp, mlen); ccm_generate_s(key, nonce, nlen, plen, 0, &s[0]); bxory(tmp, &s[0], mlen); return memcmp(tmp, m, mlen); } libsmb2-6.2/idf_component.yml0000664000175000017500000000027114732155517015366 0ustar polpypolpyversion: "3.0.1" description: Libsmb2 is a userspace client library for accessing SMB2/SMB3 shares on a network url: https://github.com/sahlberg/libsmb2 dependencies: idf: ">=4.2"libsmb2-6.2/.github/0000775000175000017500000000000014732155517013357 5ustar polpypolpylibsmb2-6.2/.github/workflows/0000775000175000017500000000000014732155517015414 5ustar polpypolpylibsmb2-6.2/.github/workflows/ccpp.yml0000664000175000017500000001455314732155517017074 0ustar polpypolpyname: C/C++ CI on: [push, pull_request] jobs: build-linux: name: Linux build runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt update sudo apt install -y libkrb5-dev - name: CMake configure run: | cmake -S . -B build - name: Build (Linux) run: cmake --build build build-windows: name: Windows build runs-on: windows-latest steps: - uses: actions/checkout@v4 - name: CMake configure run: | cmake -G "Visual Studio 17 2022" . - name: Build (MSVC) run: | cmake --build . build-ps2: name: PS2 build runs-on: ubuntu-latest container: ps2dev/ps2dev:latest steps: - name: Install dependencies run: | apk add cmake build-base git zip gawk python3 py3-pip bash - name: git checkout uses: actions/checkout@v4 - name: Compile PS2 EE Side run: | make -f Makefile.platform ps2_ee_all clean - name: Compile PS2 EE RPC Side run: | make -f Makefile.platform ps2_rpc_all clean - name: Compile PS2 IOP Side run: | make -f Makefile.platform ps2_iop_all clean - name: Compile PS2 IRX Side run: | make -f Makefile.platform ps2_irx_all clean build-vita: name: VITA build runs-on: ubuntu-latest container: vitasdk/vitasdk:latest steps: - name: git checkout uses: actions/checkout@v4 - name: Compile VITA run: | make -f Makefile.platform vita_all clean build-ps3-ppu: name: PS3 PPU build runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@v4 - name: Set env vars id: slug run: | echo "sha_name=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_ENV # using pre-compiled sdk - name: Download PSL1GHT Toolchain run: | curl -sL https://github.com/bucanero/ps3toolchain/releases/download/ubuntu-latest-fad3b5fb/ps3dev-ubuntu-latest-2020-08-31.tar.gz | tar xvz -C ./ echo "PS3DEV=${GITHUB_WORKSPACE}/ps3dev" >> $GITHUB_ENV echo "PSL1GHT=${GITHUB_WORKSPACE}/ps3dev" >> $GITHUB_ENV - name: build libsmb2 run: | cd lib make -f Makefile.PS3_PPU clean make -f Makefile.PS3_PPU build-ps4: name: PS4 runs-on: ubuntu-24.04 steps: - name: git checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Create Build Environment run: | sudo apt-get update && \ sudo apt-get install -y pacman-package-manager wget cmake git gettext smpq && \ sudo tee -a /etc/pacman.conf > /dev/null < #include ]) dnl Check if sockaddr_storage struct includes a "ss_family" AC_CHECK_MEMBER([struct sockaddr_storage.ss_family], [ AC_DEFINE([HAVE_SOCKADDR_STORAGE], [1], [Whether we have sockaddr_Storage]) ], [], [ #include #include ]) dnl Check if sockaddr_storage struct includes a "l_linger" AC_CHECK_MEMBER([struct linger.l_linger], [ AC_DEFINE([HAVE_LINGER], [1], [Whether we have linger]) ], [], [ #include #include ]) dnl Output AC_CONFIG_FILES([ Makefile examples/Makefile include/Makefile lib/Makefile tests/Makefile utils/Makefile ]) AC_CONFIG_FILES([libsmb2.pc]) AC_OUTPUT