secur32: dispatcher for ntlm_auth

Kai Blin blin at gmx.net
Tue Sep 27 07:34:37 CDT 2005


ntlm_auth takes care of the messy details of the NTLM and Negotiate
protocols for wine's SSPI implementation. The dispatcher will assume
that ntlm_auth is in the path of the user running wine. For client side
authentication, no setup is needed on the wine side.

Fixed reaping the child process when the NegoHelper allocation fails.

Made the communication buffer part of the helper, so it's not
reallocated and freed on every call of the helper.

Fixed buffer resizing when growing the buffer mutiple times.

Changelog:
Kai Blin  <blin at gmx.net>
A dispatcher for running ntlm_auth.

-- 
Kai Blin, (blin at gmx dot net)
-------------- next part --------------
? dlls/secur32/dispatcher.c
? dlls/secur32/ntlm.c.new
Index: dlls/secur32/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/secur32/Makefile.in,v
retrieving revision 1.7
diff -u -3 -r1.7 Makefile.in
--- dlls/secur32/Makefile.in	21 Sep 2005 11:43:52 -0000	1.7
+++ dlls/secur32/Makefile.in	27 Sep 2005 12:31:50 -0000
@@ -8,6 +8,7 @@
 
 C_SRCS = \
 	base64_codec.c \
+	dispatcher.c \
 	negotiate.c \
 	ntlm.c \
 	schannel.c \
Index: dlls/secur32/secur32_priv.h
===================================================================
RCS file: /home/wine/wine/dlls/secur32/secur32_priv.h,v
retrieving revision 1.6
diff -u -3 -r1.6 secur32_priv.h
--- dlls/secur32/secur32_priv.h	21 Sep 2005 11:43:52 -0000	1.6
+++ dlls/secur32/secur32_priv.h	27 Sep 2005 12:31:51 -0000
@@ -21,6 +21,7 @@
 #ifndef __SECUR32_PRIV_H__
 #define __SECUR32_PRIV_H__
 
+#include <sys/types.h>
 #include "wine/list.h"
 
 /* Memory allocation functions for memory accessible by callers of secur32.
@@ -51,6 +52,26 @@
     SecureProvider *provider;
 } SecurePackage;
 
+typedef enum _helper_mode {
+    NTLM_SERVER,
+    NTLM_CLIENT,
+    NEGO_SERVER,
+    NEGO_CLIENT,
+    NUM_HELPER_MODES
+} HelperMode;
+
+typedef struct _NegoHelper {
+    pid_t helper_pid;
+    HelperMode mode;
+    SEC_CHAR *password;
+    int pwlen;
+    int pipe_in;
+    int pipe_out;
+    int version;
+    char *com_buf;
+    int com_buf_size;
+} NegoHelper, *PNegoHelper;
+
 /* Allocates space for and initializes a new provider.  If fnTableA or fnTableW
  * is non-NULL, assumes the provider is built-in (and is thus already loaded.)
  * Otherwise moduleName must not be NULL.
@@ -86,6 +107,17 @@
 void SECUR32_initNegotiateSP(void);
 void SECUR32_initNTLMSP(void);
 
+/* Functions from dispatcher.c used elsewhere in the code */
+SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog,
+        char * const argv[]);
+
+SECURITY_STATUS run_helper(PNegoHelper helper, unsigned char *buffer,
+        unsigned int max_buflen, int *buflen);
+
+void cleanup_helper(PNegoHelper helper);
+
+void check_version(PNegoHelper helper);
+
 /* Functions from base64_codec.c used elsewhere */
 SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf, 
         int max_len, int *out_len);
--- /dev/null	2005-09-25 11:55:57.285025368 +0200
+++ dlls/secur32/dispatcher.c	2005-09-27 14:31:14.975516448 +0200
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2005 Kai Blin
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * A dispatcher to run ntlm_auth for wine's sspi module.
+ */
+
+#include "config.h"
+#include <stdarg.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif 
+#include <stdlib.h>
+#include <fcntl.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "sspi.h"
+#include "secur32_priv.h"
+#include "wine/debug.h"
+
+#define INITIAL_BUFFER_SIZE 200
+
+WINE_DEFAULT_DEBUG_CHANNEL(secur32);
+
+SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog,
+        char* const argv[])
+{
+    int pipe_in[2];
+    int pipe_out[2];
+    int i;
+    pid_t helper_pid;
+    
+    TRACE("%s ", debugstr_a(prog));
+    for(i = 0; argv[i] != NULL; ++i)
+    {
+        TRACE("%s ", debugstr_a(argv[i]));
+    }
+    TRACE("\n");           
+        
+    if( pipe(pipe_in) < 0 )
+    {
+        return SEC_E_INTERNAL_ERROR;
+    }
+    
+    if( pipe(pipe_out) < 0 )
+    {
+        close(pipe_in[0]);
+        close(pipe_in[1]);
+        return SEC_E_INTERNAL_ERROR;
+    }
+
+    helper_pid = fork();
+
+    if(helper_pid == -1)
+    {
+        close(pipe_in[0]);
+        close(pipe_in[1]);
+        close(pipe_out[0]);
+        close(pipe_out[1]);
+        return SEC_E_INTERNAL_ERROR;
+    }
+
+    if(helper_pid == 0)
+    {
+        /* We're in the child now */
+        close(0);
+        close(1);
+        
+        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(prog, argv);
+
+        /* Whoops, we shouldn't get here. Big badaboom.*/
+        write(STDOUT_FILENO, "BH\n", 3);
+        exit(0x302);
+        
+    }
+    else 
+    {
+        PNegoHelper helper = HeapAlloc(GetProcessHeap(),0, sizeof(NegoHelper));
+        
+        if (helper == NULL)
+        {
+            close(pipe_in[0]);
+            close(pipe_in[1]);
+            close(pipe_out[0]);
+            close(pipe_out[1]);
+            waitpid(helper_pid, NULL, 0);
+            return SEC_E_INSUFFICIENT_MEMORY;
+        }
+
+        *new_helper = helper;
+        
+        helper->helper_pid = helper_pid;
+        helper->version = -1;
+        helper->password = NULL;
+        helper->com_buf = NULL;
+        helper->com_buf_size = 0;
+        helper->pipe_in = pipe_in[0];
+        close(pipe_in[1]);
+        helper->pipe_out = pipe_out[1];
+        close(pipe_out[0]);
+    }
+
+    return SEC_E_OK;
+}
+
+SECURITY_STATUS run_helper(PNegoHelper helper, unsigned char *buffer,
+        unsigned int max_buflen, int *buflen)
+{
+    int new_size;
+    int old_size = (helper->com_buf_size > 0)?helper->com_buf_size:INITIAL_BUFFER_SIZE;
+    char *newline;
+    char *in_buffer;
+    int ret;
+        
+    TRACE("In helper: sending %s\n", debugstr_a(buffer));
+
+    /* buffer + '\n' */
+    write(helper->pipe_out, buffer, lstrlenA(buffer));
+    write(helper->pipe_out, "\n", 1);
+
+    if(helper->com_buf == NULL)
+      helper->com_buf = HeapAlloc(GetProcessHeap(), 0, INITIAL_BUFFER_SIZE);
+
+    in_buffer = helper->com_buf;
+
+    if((ret = read(helper->pipe_in, in_buffer, old_size)) <= 0)
+    {
+        HeapFree(GetProcessHeap(), 0, helper->com_buf);
+        return SEC_E_INTERNAL_ERROR;
+    }
+    newline = memchr(in_buffer, '\n', ret);
+
+    while(newline == NULL)
+    {
+        new_size = old_size + INITIAL_BUFFER_SIZE;
+        /* increment buffer size in INITIAL_BUFFER_SIZE steps */
+        in_buffer = HeapReAlloc(GetProcessHeap(), 0, helper->com_buf, new_size);
+        if((ret = read(helper->pipe_in, in_buffer + old_size, 
+                    new_size - old_size)) < 0)
+        {
+            HeapFree(GetProcessHeap(), 0, helper->com_buf);
+            return SEC_E_INTERNAL_ERROR;
+        }
+        TRACE("Resizing buffer!\n");        
+        newline = memchr(in_buffer, '\n', old_size + ret);
+        old_size = new_size;
+    }
+    
+    *newline = 0;
+    TRACE("In helper: recieved %s\n", debugstr_a(in_buffer));
+    *buflen = lstrlenA(in_buffer);
+
+    if( *buflen > max_buflen)
+    {   
+        ERR("Buffer size too small(%d given, %d required) dropping data!\n",
+                max_buflen, *buflen);
+        HeapFree(GetProcessHeap(), 0, helper->com_buf);
+        return SEC_E_BUFFER_TOO_SMALL;
+    }
+
+    if( *buflen < 2 )
+    {
+        HeapFree(GetProcessHeap(), 0, helper->com_buf);
+        return SEC_E_ILLEGAL_MESSAGE;
+    }
+
+    if( (*buflen <= 3) && (strncmp(in_buffer, "BH", 2) == 0))
+    {
+        HeapFree(GetProcessHeap(), 0, helper->com_buf);
+        return SEC_E_INTERNAL_ERROR;
+    }
+
+    /* We only get ERR if the input size is too big. On a GENSEC error,
+     * ntlm_auth will return BH */
+    if(strncmp(in_buffer, "ERR", 3) == 0)
+    {
+        HeapFree(GetProcessHeap(), 0, helper->com_buf);
+        return SEC_E_INVALID_TOKEN;
+    }
+
+    memcpy(buffer, in_buffer, *buflen);
+    
+    helper->com_buf_size = old_size;
+    return SEC_E_OK;
+}
+
+void cleanup_helper(PNegoHelper helper)
+{
+
+    TRACE("Killing helper %p\n", helper);
+    if( (helper == NULL) || (helper->helper_pid == 0))
+        return;
+      
+    HeapFree(GetProcessHeap(), 0, helper->password);
+    HeapFree(GetProcessHeap(), 0, helper->com_buf);
+
+    /* closing stdin will terminate ntlm_auth */
+    close(helper->pipe_out);
+    close(helper->pipe_in);
+
+    waitpid(helper->helper_pid, NULL, 0);
+
+    helper->helper_pid = 0;
+    HeapFree(GetProcessHeap(), 0, helper);
+}
+
+void check_version(PNegoHelper helper)
+{
+    char temp[80];
+    char *newline;
+
+    TRACE("Checking version of helper\n");
+    if(helper != NULL)
+    {
+        read(helper->pipe_in, temp, sizeof(temp)-1);
+        if((newline = strchr(temp, '\n')) != NULL)
+            *newline = '\0';
+            
+        TRACE("Exact version is %s\n", debugstr_a(temp));
+        if(strncmp(temp+8, "3.9", 3) == 0)
+        {
+            helper->version = 4;
+        }
+        else if(strncmp(temp+8, "3.0", 3) == 0)
+        {
+            helper->version = 3;
+        }
+        else
+        {
+            TRACE("Unknown version!\n");
+            helper->version = -1;
+        }
+    }
+}


More information about the wine-patches mailing list