Signed-off-by: Hans Leidekker hans@codeweavers.com --- dlls/msv1_0/Makefile.in | 3 +- dlls/msv1_0/main.c | 31 ++++++- dlls/msv1_0/msv1_0.spec | 2 +- dlls/msv1_0/unixlib.c | 185 ++++++++++++++++++++++++++++++++++++++++ dlls/msv1_0/unixlib.h | 97 +++++++++++++++++++++ 5 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 dlls/msv1_0/unixlib.c create mode 100644 dlls/msv1_0/unixlib.h
diff --git a/dlls/msv1_0/Makefile.in b/dlls/msv1_0/Makefile.in index 155ce593ab1..21a9c61e317 100644 --- a/dlls/msv1_0/Makefile.in +++ b/dlls/msv1_0/Makefile.in @@ -3,4 +3,5 @@ MODULE = msv1_0.dll EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ - main.c + main.c \ + unixlib.c diff --git a/dlls/msv1_0/main.c b/dlls/msv1_0/main.c index d3480c563f0..1b143ebf3bd 100644 --- a/dlls/msv1_0/main.c +++ b/dlls/msv1_0/main.c @@ -32,9 +32,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
+static HINSTANCE instance; static ULONG ntlm_package_id; static LSA_DISPATCH_TABLE lsa_dispatch;
+const struct ntlm_funcs *ntlm_funcs = NULL; + #define NTLM_CAPS \ ( SECPKG_FLAG_INTEGRITY \ | SECPKG_FLAG_PRIVACY \ @@ -75,6 +78,12 @@ static NTSTATUS NTAPI ntlm_LsaApInitializePackage( ULONG package_id, LSA_DISPATC TRACE( "%08x, %p, %s, %s, %p\n", package_id, dispatch, debugstr_as(database), debugstr_as(confidentiality), package_name );
+ if (!ntlm_funcs && __wine_init_unix_lib( instance, DLL_PROCESS_ATTACH, NULL, &ntlm_funcs )) + { + ERR( "no NTLM support, expect problems\n" ); + return STATUS_UNSUCCESSFUL; + } + if (!(str = dispatch->AllocateLsaHeap( sizeof(*str) + sizeof("NTLM" )))) return STATUS_NO_MEMORY; ptr = (char *)(str + 1); memcpy( ptr, "NTLM", sizeof("NTLM") ); @@ -90,7 +99,13 @@ static NTSTATUS NTAPI ntlm_LsaApInitializePackage( ULONG package_id, LSA_DISPATC static NTSTATUS NTAPI ntlm_SpInitialize( ULONG_PTR package_id, SECPKG_PARAMETERS *params, LSA_SECPKG_FUNCTION_TABLE *lsa_function_table ) { - FIXME( "%lu, %p, %p\n", package_id, params, lsa_function_table ); + TRACE( "%lu, %p, %p\n", package_id, params, lsa_function_table ); + + if (!ntlm_funcs && __wine_init_unix_lib( instance, DLL_PROCESS_ATTACH, NULL, &ntlm_funcs )) + { + ERR( "no NTLM support, expect problems\n" ); + return STATUS_UNSUCCESSFUL; + } return STATUS_SUCCESS; }
@@ -186,3 +201,17 @@ NTSTATUS NTAPI SpUserModeInitialize( ULONG lsa_version, ULONG *package_version, *table_count = 1; return STATUS_SUCCESS; } + +BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + instance = hinst; + DisableThreadLibraryCalls( hinst ); + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/dlls/msv1_0/msv1_0.spec b/dlls/msv1_0/msv1_0.spec index f751ed40521..9dc2eefae5e 100644 --- a/dlls/msv1_0/msv1_0.spec +++ b/dlls/msv1_0/msv1_0.spec @@ -1,4 +1,4 @@ -@ stub DllMain +@ stdcall -private DllMain(long long ptr) @ stub LsaApCallPackage @ stub LsaApCallPackagePassthrough @ stub LsaApCallPackageUntrusted diff --git a/dlls/msv1_0/unixlib.c b/dlls/msv1_0/unixlib.c new file mode 100644 index 00000000000..098b921e985 --- /dev/null +++ b/dlls/msv1_0/unixlib.c @@ -0,0 +1,185 @@ +/* + * Unix interface for ntlm_auth + * + * Copyright 2005, 2006 Kai Blin + * Copyright 2021 Hans Leidekker for CodeWeavers + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/wait.h> +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" +#include "winbase.h" +#include "sspi.h" + +#include "wine/debug.h" +#include "unixlib.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ntlm); +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +static void CDECL ntlm_cleanup( struct ntlm_ctx *ctx ) +{ + if (!ctx || (ctx->mode != MODE_CLIENT && ctx->mode != MODE_SERVER)) return; + ctx->mode = MODE_INVALID; + + /* closing stdin will terminate ntlm_auth */ + close( ctx->pipe_out ); + close( ctx->pipe_in ); + + if (ctx->pid > 0) /* reap child */ + { + pid_t ret; + do { + ret = waitpid( ctx->pid, NULL, 0 ); + } while (ret < 0 && errno == EINTR); + } + + RtlFreeHeap( GetProcessHeap(), 0, ctx->com_buf ); + RtlFreeHeap( GetProcessHeap(), 0, ctx ); +} + +static SECURITY_STATUS CDECL ntlm_fork( char **argv, struct ntlm_ctx **ret_ctx ) +{ + int pipe_in[2], pipe_out[2]; + struct ntlm_ctx *ctx; + +#ifdef HAVE_PIPE2 + if (pipe2( pipe_in, O_CLOEXEC ) < 0) +#endif + { + if (pipe( pipe_in ) < 0 ) return SEC_E_INTERNAL_ERROR; + fcntl( pipe_in[0], F_SETFD, FD_CLOEXEC ); + fcntl( pipe_in[1], F_SETFD, FD_CLOEXEC ); + } +#ifdef HAVE_PIPE2 + if (pipe2( pipe_out, O_CLOEXEC ) < 0) +#endif + { + if (pipe( pipe_out ) < 0) + { + close( pipe_in[0] ); + close( pipe_in[1] ); + return SEC_E_INTERNAL_ERROR; + } + fcntl( pipe_out[0], F_SETFD, FD_CLOEXEC ); + fcntl( pipe_out[1], F_SETFD, FD_CLOEXEC ); + } + + if (!(ctx = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ctx) ))) + { + close( pipe_in[0] ); + close( pipe_in[1] ); + close( pipe_out[0] ); + close( pipe_out[1] ); + return SEC_E_INSUFFICIENT_MEMORY; + } + + if (!(ctx->pid = fork())) /* child */ + { + dup2( pipe_out[0], 0 ); + close( pipe_out[0] ); + close( pipe_out[1] ); + + dup2( pipe_in[1], 1 ); + close( pipe_in[0] ); + close( pipe_in[1] ); + + execvp( argv[0], argv ); + + write( 1, "BH\n", 3 ); + _exit( 1 ); + } + else + { + ctx->pipe_in = pipe_in[0]; + close( pipe_in[1] ); + ctx->pipe_out = pipe_out[1]; + close( pipe_out[0] ); + *ret_ctx = ctx; + } + + return SEC_E_OK; +} + +#define NTLM_AUTH_MAJOR_VERSION 3 +#define NTLM_AUTH_MINOR_VERSION 0 +#define NTLM_AUTH_MICRO_VERSION 25 + +static BOOL check_version( void ) +{ + struct ntlm_ctx *ctx; + char *argv[3], buf[80]; + BOOL ret = FALSE; + int len; + + argv[0] = (char *)"ntlm_auth"; + argv[1] = (char *)"--version"; + argv[2] = NULL; + if (ntlm_fork( argv, &ctx ) != SEC_E_OK) return FALSE; + + if ((len = read( ctx->pipe_in, buf, sizeof(buf) - 1 )) > 8) + { + char *newline; + int major = 0, minor = 0, micro = 0; + + if ((newline = memchr( buf, '\n', len ))) *newline = 0; + else buf[len] = 0; + + if (sscanf( buf, "Version %d.%d.%d", &major, &minor, µ ) == 3) + { + if (((major > NTLM_AUTH_MAJOR_VERSION) || + (major == NTLM_AUTH_MAJOR_VERSION && minor > NTLM_AUTH_MINOR_VERSION) || + (major == NTLM_AUTH_MAJOR_VERSION && minor == NTLM_AUTH_MINOR_VERSION && + micro >= NTLM_AUTH_MICRO_VERSION))) + { + TRACE( "detected ntlm_auth version %d.%d.%d\n", major, minor, micro ); + ret = TRUE; + } + } + } + + if (!ret) ERR_(winediag)( "ntlm_auth was not found or is outdated. " + "Make sure that ntlm_auth >= %d.%d.%d is in your path. " + "Usually, you can find it in the winbind package of your distribution.\n", + NTLM_AUTH_MAJOR_VERSION, NTLM_AUTH_MINOR_VERSION, NTLM_AUTH_MICRO_VERSION ); + ntlm_cleanup( ctx ); + return ret; +} + +static const struct ntlm_funcs funcs = +{ + ntlm_cleanup, + ntlm_fork, +}; + +NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out ) +{ + if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS; + if (!check_version()) return STATUS_DLL_NOT_FOUND; + *(const struct ntlm_funcs **)ptr_out = &funcs; + return STATUS_SUCCESS; +} diff --git a/dlls/msv1_0/unixlib.h b/dlls/msv1_0/unixlib.h new file mode 100644 index 00000000000..c0dd4ca1456 --- /dev/null +++ b/dlls/msv1_0/unixlib.h @@ -0,0 +1,97 @@ +/* + * Copyright 2005, 2006 Kai Blin + * Copyright 2021 Hans Leidekker for CodeWeavers + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <sys/types.h> + +enum sign_direction +{ + SIGN_SEND, + SIGN_RECV, +}; + +enum mode +{ + MODE_INVALID = -1, + MODE_CLIENT, + MODE_SERVER, +}; + +struct ntlm_cred +{ + enum mode mode; + char *username_arg; + char *domain_arg; + char *password; + int password_len; + int no_cached_credentials; /* don't try to use cached Samba credentials */ +}; + +struct arc4_info +{ + char x; + char y; + char state[256]; +}; + +#define FLAG_NEGOTIATE_SIGN 0x00000010 +#define FLAG_NEGOTIATE_SEAL 0x00000020 +#define FLAG_NEGOTIATE_ALWAYS_SIGN 0x00008000 +#define FLAG_NEGOTIATE_NTLM2 0x00080000 +#define FLAG_NEGOTIATE_KEY_EXCHANGE 0x40000000 + +struct ntlm_ctx +{ + enum mode mode; + pid_t pid; + unsigned int attrs; + int pipe_in; + int pipe_out; + char *com_buf; + unsigned int com_buf_size; + unsigned int com_buf_offset; + char session_key[16]; + unsigned int flags; + struct + { + struct + { + unsigned int seq_no; + struct arc4_info arc4info; + } ntlm; + struct + { + char send_sign_key[16]; + char send_seal_key[16]; + char recv_sign_key[16]; + char recv_seal_key[16]; + unsigned int send_seq_no; + unsigned int recv_seq_no; + struct arc4_info send_arc4info; + struct arc4_info recv_arc4info; + } ntlm2; + } crypt; +}; + +struct ntlm_funcs +{ + void (CDECL *cleanup)( struct ntlm_ctx * ); + SECURITY_STATUS (CDECL *fork)( char **, struct ntlm_ctx ** ); +}; + +extern const struct ntlm_funcs *ntlm_funcs;