[PATCH 2/5] wldap32: Move support for ber functions to the Unix library.

Hans Leidekker hans at codeweavers.com
Wed Apr 14 02:40:26 CDT 2021


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/wldap32/ber.c             | 348 ++++++++++++++-------------------
 dlls/wldap32/libldap.c         | 260 ++++++++++++++++++++++++
 dlls/wldap32/libldap.h         |  28 +++
 dlls/wldap32/misc.c            |  28 ++-
 dlls/wldap32/winldap_private.h |  22 +++
 include/winber.h               |   6 +
 6 files changed, 477 insertions(+), 215 deletions(-)

diff --git a/dlls/wldap32/ber.c b/dlls/wldap32/ber.c
index 7f39b9cfe17..ae5e9292e04 100644
--- a/dlls/wldap32/ber.c
+++ b/dlls/wldap32/ber.c
@@ -18,24 +18,16 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include "config.h"
-
 #include <stdarg.h>
-#ifdef HAVE_LDAP_H
-#include <ldap.h>
-#endif
-
 #include "windef.h"
 #include "winbase.h"
-#include "winldap_private.h"
-#include "wldap32.h"
+#include "winnls.h"
+
 #include "wine/debug.h"
+#include "wine/heap.h"
+#include "winldap_private.h"
 
-#ifdef HAVE_LDAP
 WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
-#endif
-
-#define WLDAP32_LBER_ERROR (~0U)
 
 /***********************************************************************
  *      ber_alloc_t     (WLDAP32.@)
@@ -52,13 +44,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
  * NOTES
  *  Free the berelement structure with ber_free.
  */
-WLDAP32_BerElement * CDECL WLDAP32_ber_alloc_t( INT options )
+WLDAP32_BerElement * CDECL WLDAP32_ber_alloc_t( int options )
 {
-#ifdef HAVE_LDAP
-    return ber_alloc_t( options );
-#else
-    return NULL;
-#endif
+    WLDAP32_BerElement *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    if (!(ret->opaque = ldap_funcs->ber_alloc_t( options )))
+    {
+        heap_free( ret );
+        return NULL;
+    }
+    return ret;
 }
 
 
@@ -98,7 +94,7 @@ BERVAL * CDECL WLDAP32_ber_bvdup( BERVAL *berval )
  *  Use this function only to free an array of berval structures
  *  returned by a call to ber_scanf with a 'V' in the format string.
  */
-void CDECL WLDAP32_ber_bvecfree( PBERVAL *berval )
+void CDECL WLDAP32_ber_bvecfree( BERVAL **berval )
 {
     bvarrayfreeW( berval );
 }
@@ -142,26 +138,9 @@ void CDECL WLDAP32_ber_bvfree( BERVAL *berval )
  * NOTES
  *  len and cookie should be passed to ber_next_element.
  */
-ULONG CDECL WLDAP32_ber_first_element( WLDAP32_BerElement *berelement, ULONG *ret_len, CHAR **opaque )
+ULONG CDECL WLDAP32_ber_first_element( WLDAP32_BerElement *ber, ULONG *len, char **opaque )
 {
-#ifdef HAVE_LDAP
-    ber_len_t len;
-    ber_tag_t ret;
-
-    if ((ret = ber_first_element( berelement, &len, opaque )) != LBER_ERROR)
-    {
-        if (len > ~0u)
-        {
-            ERR( "len too large\n" );
-            return WLDAP32_LBER_ERROR;
-        }
-        *ret_len = len;
-    }
-    return ret;
-
-#else
-    return WLDAP32_LBER_ERROR;
-#endif
+    return ldap_funcs->ber_first_element( ber->opaque, len, opaque );
 }
 
 
@@ -181,23 +160,18 @@ ULONG CDECL WLDAP32_ber_first_element( WLDAP32_BerElement *berelement, ULONG *re
  * NOTES
  *  Free the berval structure with ber_bvfree.
  */
-INT CDECL WLDAP32_ber_flatten( WLDAP32_BerElement *berelement, PBERVAL *berval )
+int CDECL WLDAP32_ber_flatten( WLDAP32_BerElement *ber, BERVAL **berval )
 {
-#ifdef HAVE_LDAP
-    struct berval *bervalU;
+    struct bervalU *bervalU;
     struct WLDAP32_berval *bervalW;
 
-    if (ber_flatten( berelement, &bervalU )) return WLDAP32_LBER_ERROR;
+    if (ldap_funcs->ber_flatten( ber->opaque, &bervalU )) return WLDAP32_LBER_ERROR;
 
-    bervalW = bervalUtoW( bervalU );
-    ber_bvfree( bervalU );
+    if (!(bervalW = bervalUtoW( bervalU ))) return WLDAP32_LBER_ERROR;
+    ldap_funcs->ber_bvfree( bervalU );
     if (!bervalW) return WLDAP32_LBER_ERROR;
     *berval = bervalW;
     return 0;
-
-#else
-    return WLDAP32_LBER_ERROR;
-#endif
 }
 
 
@@ -217,11 +191,10 @@ INT CDECL WLDAP32_ber_flatten( WLDAP32_BerElement *berelement, PBERVAL *berval )
  *  Set buf to 0 if the berelement was allocated with ldap_first_attribute
  *  or ldap_next_attribute, otherwise set it to 1.
  */
-void CDECL WLDAP32_ber_free( WLDAP32_BerElement *berelement, INT buf )
+void CDECL WLDAP32_ber_free( WLDAP32_BerElement *ber, int freebuf )
 {
-#ifdef HAVE_LDAP
-    ber_free( berelement, buf );
-#endif
+    ldap_funcs->ber_free( ber->opaque, freebuf );
+    heap_free( ber );
 }
 
 
@@ -242,17 +215,22 @@ void CDECL WLDAP32_ber_free( WLDAP32_BerElement *berelement, INT buf )
  */
 WLDAP32_BerElement * CDECL WLDAP32_ber_init( BERVAL *berval )
 {
-#ifdef HAVE_LDAP
-    struct berval *bervalU;
+    struct bervalU *bervalU;
     WLDAP32_BerElement *ret;
 
-    if (!(bervalU = bervalWtoU( berval ))) return NULL;
-    ret = ber_init( bervalU );
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    if (!(bervalU = bervalWtoU( berval )))
+    {
+        heap_free( ret );
+        return NULL;
+    }
+    if (!(ret->opaque = ldap_funcs->ber_init( bervalU )))
+    {
+        heap_free( ret );
+        ret = NULL;
+    }
     heap_free( bervalU );
     return ret;
-#else
-    return NULL;
-#endif
 }
 
 
@@ -274,26 +252,9 @@ WLDAP32_BerElement * CDECL WLDAP32_ber_init( BERVAL *berval )
  *  len and cookie are initialized by ber_first_element and should
  *  be passed on in subsequent calls to ber_next_element.
  */
-ULONG CDECL WLDAP32_ber_next_element( WLDAP32_BerElement *berelement, ULONG *ret_len, CHAR *opaque )
+ULONG CDECL WLDAP32_ber_next_element( WLDAP32_BerElement *ber, ULONG *len, char *opaque )
 {
-#ifdef HAVE_LDAP
-    ber_len_t len;
-    ber_tag_t ret;
-
-    if ((ret = ber_next_element( berelement, &len, opaque )) != LBER_ERROR)
-    {
-        if (len > ~0u)
-        {
-            ERR( "len too large\n" );
-            return WLDAP32_LBER_ERROR;
-        }
-        *ret_len = len;
-    }
-    return ret;
-
-#else
-    return WLDAP32_LBER_ERROR;
-#endif
+    return ldap_funcs->ber_next_element( ber->opaque, len, opaque );
 }
 
 
@@ -310,26 +271,9 @@ ULONG CDECL WLDAP32_ber_next_element( WLDAP32_BerElement *berelement, ULONG *ret
  *  Success: Tag of the next element.
  *  Failure: LBER_DEFAULT (no more data).
  */
-ULONG CDECL WLDAP32_ber_peek_tag( WLDAP32_BerElement *berelement, ULONG *ret_len )
+ULONG CDECL WLDAP32_ber_peek_tag( WLDAP32_BerElement *ber, ULONG *len )
 {
-#ifdef HAVE_LDAP
-    ber_len_t len;
-    ber_tag_t ret;
-
-    if ((ret = ber_peek_tag( berelement, &len )) != LBER_ERROR)
-    {
-        if (len > ~0u)
-        {
-            ERR( "len too large\n" );
-            return WLDAP32_LBER_ERROR;
-        }
-        *ret_len = len;
-    }
-    return ret;
-
-#else
-    return WLDAP32_LBER_ERROR;
-#endif
+    return ldap_funcs->ber_peek_tag( ber->opaque, len );
 }
 
 
@@ -346,26 +290,9 @@ ULONG CDECL WLDAP32_ber_peek_tag( WLDAP32_BerElement *berelement, ULONG *ret_len
  *  Success: Tag of the next element.
  *  Failure: LBER_DEFAULT (no more data).
  */
-ULONG CDECL WLDAP32_ber_skip_tag( WLDAP32_BerElement *berelement, ULONG *ret_len )
+ULONG CDECL WLDAP32_ber_skip_tag( WLDAP32_BerElement *ber, ULONG *len )
 {
-#ifdef HAVE_LDAP
-    ber_len_t len;
-    ber_tag_t ret;
-
-    if ((ret = ber_skip_tag( berelement, &len )) != LBER_ERROR)
-    {
-        if (len > ~0u)
-        {
-            ERR( "len too large\n" );
-            return WLDAP32_LBER_ERROR;
-        }
-        *ret_len = len;
-    }
-    return ret;
-
-#else
-    return WLDAP32_LBER_ERROR;
-#endif
+    return ldap_funcs->ber_skip_tag( ber->opaque, len );
 }
 
 
@@ -380,16 +307,15 @@ ULONG CDECL WLDAP32_ber_skip_tag( WLDAP32_BerElement *berelement, ULONG *ret_len
  *  ...        [I]   Values to encode.
  *
  * RETURNS
- *  Success: Non-negative number. 
+ *  Success: Non-negative number.
  *  Failure: LBER_ERROR
  *
  * NOTES
  *  berelement must have been allocated with ber_alloc_t. This function
  *  can be called multiple times to append data.
  */
-INT WINAPIV WLDAP32_ber_printf( WLDAP32_BerElement *berelement, PCHAR fmt, ... )
+int WINAPIV WLDAP32_ber_printf( WLDAP32_BerElement *ber, char *fmt, ... )
 {
-#ifdef HAVE_LDAP
     __ms_va_list list;
     int ret = 0;
     char new_fmt[2];
@@ -399,63 +325,64 @@ INT WINAPIV WLDAP32_ber_printf( WLDAP32_BerElement *berelement, PCHAR fmt, ... )
     while (*fmt)
     {
         new_fmt[0] = *fmt++;
-        switch(new_fmt[0])
+        switch (new_fmt[0])
         {
         case 'b':
         case 'e':
         case 'i':
-            {
-                int i = va_arg( list, int );
-                ret = ber_printf( berelement, new_fmt, i );
-                break;
-            }
+        {
+            int i = va_arg( list, int );
+            ret = ldap_funcs->ber_printf( ber->opaque, new_fmt, i );
+            break;
+        }
         case 'o':
         case 's':
-            {
-                char *str = va_arg( list, char * );
-                ret = ber_printf( berelement, new_fmt, str );
-                break;
-            }
+        {
+            char *str = va_arg( list, char * );
+            ret = ldap_funcs->ber_printf( ber->opaque, new_fmt, str );
+            break;
+        }
         case 't':
-            {
-                unsigned int tag = va_arg( list, unsigned int );
-                ret = ber_printf( berelement, new_fmt, tag );
-                break;
-            }
+        {
+            unsigned int tag = va_arg( list, unsigned int );
+            ret = ldap_funcs->ber_printf( ber->opaque, new_fmt, tag );
+            break;
+        }
         case 'v':
-            {
-                char **array = va_arg( list, char ** );
-                ret = ber_printf( berelement, new_fmt, array );
-                break;
-            }
+        {
+            char **array = va_arg( list, char ** );
+            ret = ldap_funcs->ber_printf( ber->opaque, new_fmt, array );
+            break;
+        }
         case 'V':
+        {
+            struct WLDAP32_berval **array = va_arg( list, struct WLDAP32_berval ** );
+            struct bervalU **arrayU;
+            if (!(arrayU = bvarrayWtoU( array )))
             {
-                struct WLDAP32_berval **array = va_arg( list, struct WLDAP32_berval ** );
-                struct berval **arrayU;
-                if (!(arrayU = bvarrayWtoU( array )))
-                {
-                    ret = -1;
-                    break;
-                }
-                ret = ber_printf( berelement, new_fmt, arrayU );
-                bvarrayfreeU( arrayU );
+                ret = -1;
                 break;
             }
+            ret = ldap_funcs->ber_printf( ber->opaque, new_fmt, arrayU );
+            bvarrayfreeU( arrayU );
+            break;
+        }
         case 'X':
-            {
-                char *str = va_arg( list, char * );
-                int len = va_arg( list, int );
-                new_fmt[0] = 'B';  /* 'X' is deprecated */
-                ret = ber_printf( berelement, new_fmt, str, len );
-                break;
-            }
+        {
+            char *str = va_arg( list, char * );
+            int len = va_arg( list, int );
+            new_fmt[0] = 'B';  /* 'X' is deprecated */
+            ret = ldap_funcs->ber_printf( ber->opaque, new_fmt, str, len );
+            break;
+        }
         case 'n':
         case '{':
         case '}':
         case '[':
         case ']':
-            ret = ber_printf( berelement, new_fmt );
+            ret = ldap_funcs->ber_printf( ber->opaque, new_fmt );
             break;
+
         default:
             FIXME( "Unknown format '%c'\n", new_fmt[0] );
             ret = -1;
@@ -465,9 +392,6 @@ INT WINAPIV WLDAP32_ber_printf( WLDAP32_BerElement *berelement, PCHAR fmt, ... )
     }
     __ms_va_end( list );
     return ret;
-#else
-    return WLDAP32_LBER_ERROR;
-#endif
 }
 
 
@@ -482,16 +406,15 @@ INT WINAPIV WLDAP32_ber_printf( WLDAP32_BerElement *berelement, PCHAR fmt, ... )
  *  ...        [I]   Pointers to values to be decoded.
  *
  * RETURNS
- *  Success: Non-negative number. 
+ *  Success: Non-negative number.
  *  Failure: LBER_ERROR
  *
  * NOTES
  *  berelement must have been allocated with ber_init. This function
  *  can be called multiple times to decode data.
  */
-INT WINAPIV WLDAP32_ber_scanf( WLDAP32_BerElement *berelement, PCHAR fmt, ... )
+int WINAPIV WLDAP32_ber_scanf( WLDAP32_BerElement *ber, char *fmt, ... )
 {
-#ifdef HAVE_LDAP
     __ms_va_list list;
     int ret = 0;
     char new_fmt[2];
@@ -501,65 +424,81 @@ INT WINAPIV WLDAP32_ber_scanf( WLDAP32_BerElement *berelement, PCHAR fmt, ... )
     while (*fmt)
     {
         new_fmt[0] = *fmt++;
-        switch(new_fmt[0])
+        switch (new_fmt[0])
         {
         case 'a':
-            {
-                char **ptr = va_arg( list, char ** );
-                ret = ber_scanf( berelement, new_fmt, ptr );
-                break;
-            }
+        {
+            char *str, **ptr = va_arg( list, char ** );
+            if ((ret = ldap_funcs->ber_scanf( ber->opaque, new_fmt, &str )) == -1) break;
+            *ptr = strdupU( str );
+            ldap_funcs->ldap_memfree( str );
+            break;
+        }
         case 'b':
         case 'e':
         case 'i':
-            {
-                int *i = va_arg( list, int * );
-                ret = ber_scanf( berelement, new_fmt, i );
-                break;
-            }
+        {
+            int *i = va_arg( list, int * );
+            ret = ldap_funcs->ber_scanf( ber->opaque, new_fmt, i );
+            break;
+        }
         case 't':
-            {
-                unsigned int *tag = va_arg( list, unsigned int * );
-                ret = ber_scanf( berelement, new_fmt, tag );
-                break;
-            }
+        {
+            unsigned int *tag = va_arg( list, unsigned int * );
+            ret = ldap_funcs->ber_scanf( ber->opaque, new_fmt, tag );
+            break;
+        }
         case 'v':
+        {
+            char *str, **arrayU, **ptr, ***array = va_arg( list, char *** );
+            if ((ret = ldap_funcs->ber_scanf( ber->opaque, new_fmt, &arrayU )) == -1) break;
+            *array = strarrayUtoU( arrayU );
+            ptr = arrayU;
+            while ((str = *ptr))
             {
-                char ***array = va_arg( list, char *** );
-                ret = ber_scanf( berelement, new_fmt, array );
-                break;
+                ldap_funcs->ldap_memfree( str );
+                ptr++;
             }
+            ldap_funcs->ldap_memfree( arrayU );
+            break;
+        }
         case 'B':
-            {
-                char **str = va_arg( list, char ** );
-                int *len = va_arg( list, int * );
-                ret = ber_scanf( berelement, new_fmt, str, len );
-                break;
-            }
+        {
+            char *strU, **str = va_arg( list, char ** );
+            int *len = va_arg( list, int * );
+            if ((ret = ldap_funcs->ber_scanf( ber->opaque, new_fmt, &strU, len )) == -1) break;
+            *str = heap_alloc( *len );
+            memcpy( *str, strU, *len );
+            ldap_funcs->ldap_memfree( strU );
+            break;
+        }
         case 'O':
-            {
-                struct berval **ptr = va_arg( list, struct berval ** );
-                ret = ber_scanf( berelement, new_fmt, ptr );
-                break;
-            }
+        {
+            struct WLDAP32_berval **berval = va_arg( list, struct WLDAP32_berval ** );
+            struct bervalU *bervalU;
+            if ((ret = ldap_funcs->ber_scanf( ber->opaque, new_fmt, &bervalU )) == -1) break;
+            *berval = bervalUtoW( bervalU );
+            ldap_funcs->ber_bvfree( bervalU );
+            break;
+        }
         case 'V':
-            {
-                struct WLDAP32_berval **arrayW, ***array = va_arg( list, struct WLDAP32_berval *** );
-                struct berval **arrayU;
-                if ((ret = ber_scanf( berelement, new_fmt, &arrayU )) == -1) break;
-                if ((arrayW = bvarrayUtoW( arrayU ))) *array = arrayW;
-                else ret = -1;
-                bvarrayfreeU( arrayU );
-                break;
-            }
+        {
+            struct WLDAP32_berval ***array = va_arg( list, struct WLDAP32_berval *** );
+            struct bervalU **arrayU;
+            if ((ret = ldap_funcs->ber_scanf( ber->opaque, new_fmt, &arrayU )) == -1) break;
+            *array = bvarrayUtoW( arrayU );
+            ldap_funcs->ber_bvecfree( arrayU );
+            break;
+        }
         case 'n':
         case 'x':
         case '{':
         case '}':
         case '[':
         case ']':
-            ret = ber_scanf( berelement, new_fmt );
+            ret = ldap_funcs->ber_scanf( ber->opaque, new_fmt );
             break;
+
         default:
             FIXME( "Unknown format '%c'\n", new_fmt[0] );
             ret = -1;
@@ -569,7 +508,4 @@ INT WINAPIV WLDAP32_ber_scanf( WLDAP32_BerElement *berelement, PCHAR fmt, ... )
     }
     __ms_va_end( list );
     return ret;
-#else
-    return WLDAP32_LBER_ERROR;
-#endif
 }
diff --git a/dlls/wldap32/libldap.c b/dlls/wldap32/libldap.c
index 0372206062a..3436cffc4a1 100644
--- a/dlls/wldap32/libldap.c
+++ b/dlls/wldap32/libldap.c
@@ -42,6 +42,8 @@
 #include "wine/debug.h"
 #include "winldap_private.h"
 
+WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
+
 C_ASSERT( sizeof(BerValueU) == sizeof(BerValue) );
 C_ASSERT( sizeof(LDAPModU) == sizeof(LDAPMod) );
 C_ASSERT( sizeof(LDAPControlU) == sizeof(LDAPControl) );
@@ -50,6 +52,246 @@ C_ASSERT( sizeof(LDAPVLVInfoU) == sizeof(LDAPVLVInfo) );
 
 static LDAPMod *nullattrs[] = { NULL };
 
+void * CDECL wrap_ber_alloc_t( int options )
+{
+    return ber_alloc_t( options );
+}
+
+void CDECL wrap_ber_bvecfree( struct bervalU **berval )
+{
+    ber_bvecfree( (struct berval **)berval );
+}
+
+void CDECL wrap_ber_bvfree( struct bervalU *berval )
+{
+    ber_bvfree( (struct berval *)berval );
+}
+
+unsigned int CDECL wrap_ber_first_element( void *ber, ULONG *ret_len, char **last )
+{
+    ber_len_t len;
+    ber_tag_t ret;
+
+    if ((ret = ber_first_element( ber, &len, last )) == LBER_ERROR) return WLDAP32_LBER_ERROR;
+    if (ret > ~0u)
+    {
+        ERR( "ret too large\n" );
+        return WLDAP32_LBER_ERROR;
+    }
+    if (len > ~0u)
+    {
+        ERR( "len too large\n" );
+        return WLDAP32_LBER_ERROR;
+    }
+
+    *ret_len = len;
+    return ret;
+}
+
+int CDECL wrap_ber_flatten( void *ber, struct bervalU **berval )
+{
+    return ber_flatten( ber, (struct berval **)berval );
+}
+
+void CDECL wrap_ber_free( void *ber, int freebuf )
+{
+    ber_free( ber, freebuf );
+}
+
+void * CDECL wrap_ber_init( struct bervalU *berval )
+{
+    return ber_init( (struct berval *)berval );
+}
+
+unsigned int CDECL wrap_ber_next_element( void *ber, unsigned int *ret_len, char *last )
+{
+    ber_len_t len;
+    ber_tag_t ret;
+
+    if ((ret = ber_next_element( ber, &len, last )) == LBER_ERROR) return WLDAP32_LBER_ERROR;
+    if (ret > ~0u)
+    {
+        ERR( "ret too large\n" );
+        return WLDAP32_LBER_ERROR;
+    }
+    if (len > ~0u)
+    {
+        ERR( "len too large\n" );
+        return WLDAP32_LBER_ERROR;
+    }
+
+    *ret_len = len;
+    return ret;
+}
+
+unsigned int CDECL wrap_ber_peek_tag( void *ber, unsigned int *ret_len )
+{
+    ber_len_t len;
+    ber_tag_t ret;
+
+    if ((ret = ber_peek_tag( ber, &len )) == LBER_ERROR) return WLDAP32_LBER_ERROR;
+    if (len > ~0u)
+    {
+        ERR( "len too large\n" );
+        return WLDAP32_LBER_ERROR;
+    }
+
+    *ret_len = len;
+    return ret;
+}
+
+unsigned int CDECL wrap_ber_skip_tag( void *ber, unsigned int *ret_len )
+{
+    ber_len_t len;
+    ber_tag_t ret;
+
+    if ((ret = ber_skip_tag( ber, &len )) == LBER_ERROR) return WLDAP32_LBER_ERROR;
+    if (len > ~0u)
+    {
+        ERR( "len too large\n" );
+        return WLDAP32_LBER_ERROR;
+    }
+
+    *ret_len = len;
+    return ret;
+}
+
+int WINAPIV wrap_ber_printf( void *ber, char *fmt, ... )
+{
+    int ret;
+    __ms_va_list args;
+
+    assert( strlen(fmt) == 1 );
+
+    __ms_va_start( args, fmt );
+    switch (fmt[0])
+    {
+    case 'b':
+    case 'e':
+    case 'i':
+    {
+        int i = va_arg( args, int );
+        ret = ber_printf( ber, fmt, i );
+        break;
+    }
+    case 'o':
+    case 's':
+    {
+        char *str = va_arg( args, char * );
+        ret = ber_printf( ber, fmt, str );
+        break;
+    }
+    case 't':
+    {
+        unsigned int tag = va_arg( args, unsigned int );
+        ret = ber_printf( ber, fmt, tag );
+        break;
+    }
+    case 'v':
+    {
+        char **array = va_arg( args, char ** );
+        ret = ber_printf( ber, fmt, array );
+        break;
+    }
+    case 'V':
+    {
+        struct berval **array = va_arg( args, struct berval ** );
+        ret = ber_printf( ber, fmt, array );
+        break;
+    }
+    case 'B':
+    {
+        char *str = va_arg( args, char * );
+        int len = va_arg( args, int );
+        ret = ber_printf( ber, fmt, str, len );
+        break;
+    }
+    case 'n':
+    case '{':
+    case '}':
+    case '[':
+    case ']':
+        ret = ber_printf( ber, fmt );
+        break;
+
+    default:
+        assert( 0 );
+    }
+    __ms_va_end( args );
+    return ret;
+}
+
+int WINAPIV wrap_ber_scanf( void *ber, char *fmt, ... )
+{
+    int ret;
+    __ms_va_list args;
+
+    assert( strlen(fmt) == 1 );
+
+    __ms_va_start( args, fmt );
+    switch (fmt[0])
+    {
+    case 'a':
+    {
+        char **str = va_arg( args, char ** );
+        ret = ber_scanf( ber, fmt, str );
+        break;
+    }
+    case 'b':
+    case 'e':
+    case 'i':
+    {
+        int *i = va_arg( args, int * );
+        ret = ber_scanf( ber, fmt, i );
+        break;
+    }
+    case 't':
+    {
+        unsigned int *tag = va_arg( args, unsigned int * );
+        ret = ber_scanf( ber, fmt, tag );
+        break;
+    }
+    case 'v':
+    {
+        char ***array = va_arg( args, char *** );
+        ret = ber_scanf( ber, fmt, array );
+        break;
+    }
+    case 'B':
+    {
+        char **str = va_arg( args, char ** );
+        int *len = va_arg( args, int * );
+        ret = ber_scanf( ber, fmt, str, len );
+        break;
+    }
+    case 'O':
+    {
+        struct berval **berval = va_arg( args, struct berval ** );
+        ret = ber_scanf( ber, fmt, berval );
+        break;
+    }
+    case 'V':
+    {
+        struct berval ***array = va_arg( args, struct berval *** );
+        ret = ber_scanf( ber, fmt, array );
+        break;
+    }
+    case 'n':
+    case 'x':
+    case '{':
+    case '}':
+    case '[':
+    case ']':
+        ret = ber_scanf( ber, fmt );
+        break;
+
+    default:
+        assert( 0 );
+    }
+    __ms_va_end( args );
+    return ret;
+}
+
 int CDECL wrap_ldap_add_ext( void *ld, char *dn, LDAPModU **attrs, LDAPControlU **serverctrls,
                              LDAPControlU **clientctrls, ULONG *msg )
 {
@@ -65,10 +307,28 @@ int CDECL wrap_ldap_add_ext_s( void *ld, char *dn, LDAPModU **attrs, LDAPControl
                            (LDAPControl **)clientctrls );
 }
 
+void CDECL wrap_ldap_memfree( void *ptr )
+{
+    return ldap_memfree( ptr );
+}
+
 static const struct ldap_funcs funcs =
 {
+    wrap_ber_alloc_t,
+    wrap_ber_bvecfree,
+    wrap_ber_bvfree,
+    wrap_ber_first_element,
+    wrap_ber_flatten,
+    wrap_ber_free,
+    wrap_ber_init,
+    wrap_ber_next_element,
+    wrap_ber_peek_tag,
+    wrap_ber_skip_tag,
+    wrap_ber_printf,
+    wrap_ber_scanf,
     wrap_ldap_add_ext,
     wrap_ldap_add_ext_s,
+    wrap_ldap_memfree,
 };
 
 NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
diff --git a/dlls/wldap32/libldap.h b/dlls/wldap32/libldap.h
index d9d833cdcb8..4ca90d298a0 100644
--- a/dlls/wldap32/libldap.h
+++ b/dlls/wldap32/libldap.h
@@ -60,13 +60,41 @@ typedef struct
     void           *ldvlv_extradata;
 } LDAPVLVInfoU;
 
+extern void * CDECL wrap_ber_alloc_t(int) DECLSPEC_HIDDEN;
+extern void CDECL wrap_ber_bvecfree(struct bervalU **) DECLSPEC_HIDDEN;
+extern void CDECL wrap_ber_bvfree(struct bervalU *) DECLSPEC_HIDDEN;
+extern unsigned int CDECL wrap_ber_first_element(void *, unsigned int *, char **) DECLSPEC_HIDDEN;
+extern int CDECL wrap_ber_flatten(void *, struct bervalU **) DECLSPEC_HIDDEN;
+extern void CDECL wrap_ber_free(void *, int) DECLSPEC_HIDDEN;
+extern void * CDECL wrap_ber_init(struct bervalU *) DECLSPEC_HIDDEN;
+extern unsigned int CDECL wrap_ber_next_element(void *, unsigned int *, char *) DECLSPEC_HIDDEN;
+extern unsigned int CDECL wrap_ber_peek_tag(void *, unsigned int *) DECLSPEC_HIDDEN;
+extern unsigned int CDECL wrap_ber_skip_tag(void *, unsigned int *) DECLSPEC_HIDDEN;
+extern int WINAPIV wrap_ber_printf(void *, char *, ...) DECLSPEC_HIDDEN;
+extern int WINAPIV wrap_ber_scanf(void *, char *, ...) DECLSPEC_HIDDEN;
+
 extern int CDECL wrap_ldap_add_ext(void *, char *, LDAPModU **, LDAPControlU **, LDAPControlU **, ULONG *) DECLSPEC_HIDDEN;
 extern int CDECL wrap_ldap_add_ext_s(void *, char *, LDAPModU **, LDAPControlU **, LDAPControlU **) DECLSPEC_HIDDEN;
+extern void CDECL wrap_ldap_memfree(void *) DECLSPEC_HIDDEN;
 
 struct ldap_funcs
 {
+    void * (CDECL *ber_alloc_t)(int);
+    void (CDECL *ber_bvecfree)(struct bervalU **);
+    void (CDECL *ber_bvfree)(struct bervalU *);
+    unsigned int (CDECL *ber_first_element)(void *, unsigned int *, char **);
+    int (CDECL *ber_flatten)(void *, struct bervalU **);
+    void (CDECL *ber_free)(void *, int);
+    void * (CDECL *ber_init)(struct bervalU *);
+    unsigned int (CDECL *ber_next_element)(void *, unsigned int *, char *);
+    unsigned int (CDECL *ber_peek_tag)(void *, unsigned int *);
+    unsigned int (CDECL *ber_skip_tag)(void *, unsigned int *);
+    int (WINAPIV *ber_printf)(void *, char *, ...);
+    int (WINAPIV *ber_scanf)(void *, char *, ...);
+
     int (CDECL *ldap_add_ext)(void *, char *, LDAPModU **, LDAPControlU **, LDAPControlU **, ULONG *);
     int (CDECL *ldap_add_ext_s)(void *, char *, LDAPModU **, LDAPControlU **, LDAPControlU **);
+    void (CDECL *ldap_memfree)(void *);
 };
 
 extern const struct ldap_funcs *ldap_funcs;
diff --git a/dlls/wldap32/misc.c b/dlls/wldap32/misc.c
index 39642960955..dd1a1ef3f12 100644
--- a/dlls/wldap32/misc.c
+++ b/dlls/wldap32/misc.c
@@ -328,15 +328,22 @@ PWCHAR CDECL ldap_first_attributeW( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry
 {
     PWCHAR ret = NULL;
 #ifdef HAVE_LDAP
+    BerElement *berU;
     char *retU;
 
     TRACE( "(%p, %p, %p)\n", ld, entry, ptr );
 
     if (!ld || !entry) return NULL;
-    retU = ldap_first_attribute( ld->ld, entry, ptr );
 
-    ret = strUtoW( retU );
-    ldap_memfree( retU );
+    retU = ldap_first_attribute( ld->ld, entry, &berU );
+    if (retU)
+    {
+        WLDAP32_BerElement *ber = heap_alloc( sizeof(*ber) );
+        ber->opaque = (char *)berU;
+        *ptr = ber;
+        ret = strUtoW( retU );
+        ldap_memfree( retU );
+    }
 
 #endif
     return ret;
@@ -487,19 +494,22 @@ PCHAR CDECL ldap_next_attributeA( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry,
  *  When done iterating and when ptr != NULL, call ber_free( ptr, 0 ).
  */
 PWCHAR CDECL ldap_next_attributeW( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry,
-    WLDAP32_BerElement *ptr )
+    WLDAP32_BerElement *ber )
 {
     PWCHAR ret = NULL;
 #ifdef HAVE_LDAP
     char *retU;
 
-    TRACE( "(%p, %p, %p)\n", ld, entry, ptr );
+    TRACE( "(%p, %p, %p)\n", ld, entry, ber );
 
-    if (!ld || !entry || !ptr) return NULL;
-    retU = ldap_next_attribute( ld->ld, entry, ptr );
+    if (!ld || !entry) return NULL;
 
-    ret = strUtoW( retU );
-    ldap_memfree( retU );
+    retU = ldap_next_attribute( ld->ld, entry, (BerElement *)ber->opaque );
+    if (retU)
+    {
+        ret = strUtoW( retU );
+        ldap_memfree( retU );
+    }
 
 #endif
     return ret;
diff --git a/dlls/wldap32/winldap_private.h b/dlls/wldap32/winldap_private.h
index d0583c61f50..22e981cb26d 100644
--- a/dlls/wldap32/winldap_private.h
+++ b/dlls/wldap32/winldap_private.h
@@ -27,6 +27,8 @@
 #include "winnls.h"
 #include "libldap.h"
 
+#define WLDAP32_LBER_ERROR (~0L)
+
 typedef enum {
     WLDAP32_LDAP_SUCCESS                 =   0x00,
     WLDAP32_LDAP_UNWILLING_TO_PERFORM    =   0x35,
@@ -1187,6 +1189,26 @@ static inline WCHAR **strarrayUtoW( char **strarray )
     return strarrayW;
 }
 
+static inline char **strarrayUtoU( char **strarray )
+{
+    char **strarrayU = NULL;
+    DWORD size;
+
+    if (strarray)
+    {
+        size = sizeof(char *) * (strarraylenU( strarray ) + 1);
+        if ((strarrayU = RtlAllocateHeap( GetProcessHeap(), 0, size )))
+        {
+            char **p = strarray;
+            char **q = strarrayU;
+
+            while (*p) *q++ = strdupU( *p++ );
+            *q = NULL;
+        }
+    }
+    return strarrayU;
+}
+
 static inline LDAPControlW *controlUtoW( const LDAPControlU *control )
 {
     LDAPControlW *controlW;
diff --git a/include/winber.h b/include/winber.h
index 40ab0f40ed8..372cc321269 100644
--- a/include/winber.h
+++ b/include/winber.h
@@ -27,11 +27,17 @@ typedef unsigned int ber_tag_t;
 typedef unsigned int ber_len_t;
 
 BerElement * CDECL ber_alloc_t( int );
+BERVAL * CDECL ber_bvdup( BERVAL * );
+void CDECL ber_bvecfree( BERVAL ** );
 void CDECL ber_bvfree( BERVAL * );
+ULONG CDECL ber_first_element( BerElement *, ULONG *, char ** );
 int CDECL ber_flatten( BerElement *, BERVAL ** );
 void CDECL ber_free( BerElement *, int );
 BerElement * CDECL ber_init( BERVAL * );
+ULONG CDECL ber_next_element( BerElement *, ULONG *, char ** );
+ULONG CDECL ber_peek_tag( BerElement *, ULONG * );
 int WINAPIV ber_printf( BerElement *, char *, ... );
 ULONG WINAPIV ber_scanf( BerElement *, char *, ... );
+ULONG CDECL ber_skip_tag( BerElement *, ULONG * );
 
 #endif /* __WINE_WINBER_H */
-- 
2.30.2




More information about the wine-devel mailing list