From 1c5b3f20015f379bbdfa9554fc4c9911062770ea Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Fri, 16 Apr 2021 09:59:18 +0200 Subject: [PATCH] wldap32: Move support for page functions to the Unix library. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/wldap32/ber.c | 2 +- dlls/wldap32/page.c | 281 +++++++++++---------------------- dlls/wldap32/winldap_private.h | 76 +++++++++ 3 files changed, 169 insertions(+), 190 deletions(-) diff --git a/dlls/wldap32/ber.c b/dlls/wldap32/ber.c index ae5e9292e04..c6dca7153a2 100644 --- a/dlls/wldap32/ber.c +++ b/dlls/wldap32/ber.c @@ -413,7 +413,7 @@ int WINAPIV WLDAP32_ber_printf( WLDAP32_BerElement *ber, char *fmt, ... ) * 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 *ber, char *fmt, ... ) +ULONG WINAPIV WLDAP32_ber_scanf( WLDAP32_BerElement *ber, char *fmt, ... ) { __ms_va_list list; int ret = 0; diff --git a/dlls/wldap32/page.c b/dlls/wldap32/page.c index 07f29be0d50..5364280f271 100644 --- a/dlls/wldap32/page.c +++ b/dlls/wldap32/page.c @@ -18,31 +18,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include "wine/port.h" - #include -#ifdef HAVE_LDAP_H -#include -#endif -#ifndef LDAP_MAXINT -#define LDAP_MAXINT 2147483647 -#endif - #include "windef.h" #include "winbase.h" #include "winnls.h" -#include "winldap_private.h" -#include "wldap32.h" #include "wine/debug.h" +#include "wine/heap.h" +#include "winldap_private.h" WINE_DEFAULT_DEBUG_CHANNEL(wldap32); -#ifdef HAVE_LDAP -static struct berval null_cookieU = { 0, NULL }; +#define LDAP_MAXINT (2^31) + static struct WLDAP32_berval null_cookieW = { 0, NULL }; -#endif /*********************************************************************** * ldap_create_page_controlA (WLDAP32.@) @@ -50,84 +39,73 @@ static struct WLDAP32_berval null_cookieW = { 0, NULL }; * See ldap_create_page_controlW. */ ULONG CDECL ldap_create_page_controlA( WLDAP32_LDAP *ld, ULONG pagesize, - struct WLDAP32_berval *cookie, UCHAR critical, PLDAPControlA *control ) + struct WLDAP32_berval *cookie, UCHAR critical, LDAPControlA **control ) { - ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED; -#ifdef HAVE_LDAP + ULONG ret; LDAPControlW *controlW = NULL; - TRACE( "(%p, 0x%08x, %p, 0x%02x, %p)\n", ld, pagesize, cookie, - critical, control ); + TRACE( "(%p, 0x%08x, %p, 0x%02x, %p)\n", ld, pagesize, cookie, critical, control ); - if (!ld || !control || pagesize > LDAP_MAXINT) - return WLDAP32_LDAP_PARAM_ERROR; + if (!ld || !control || pagesize > LDAP_MAXINT) return WLDAP32_LDAP_PARAM_ERROR; ret = ldap_create_page_controlW( ld, pagesize, cookie, critical, &controlW ); - if (ret == LDAP_SUCCESS) + if (ret == WLDAP32_LDAP_SUCCESS) { *control = controlWtoA( controlW ); ldap_control_freeW( controlW ); } - -#endif return ret; } -#ifdef HAVE_LDAP - /* create a page control by hand */ -static ULONG create_page_control( ULONG pagesize, struct berval *cookie, - UCHAR critical, PLDAPControlW *control ) +static ULONG create_page_control( ULONG pagesize, struct WLDAP32_berval *cookie, UCHAR critical, LDAPControlW **control ) { LDAPControlW *ctrl; - BerElement *ber; - ber_tag_t tag; - struct berval *berval; - INT ret, len; + WLDAP32_BerElement *ber; + struct WLDAP32_berval *berval, *vec[2]; + int ret, len; char *val; - ber = ber_alloc_t( LBER_USE_DER ); - if (!ber) return WLDAP32_LDAP_NO_MEMORY; + if (!(ber = WLDAP32_ber_alloc_t( WLDAP32_LBER_USE_DER ))) return WLDAP32_LDAP_NO_MEMORY; + vec[1] = NULL; if (cookie) - tag = ber_printf( ber, "{iO}", (ber_int_t)pagesize, cookie ); + vec[0] = cookie; else - tag = ber_printf( ber, "{iO}", (ber_int_t)pagesize, &null_cookieU ); + vec[0] = &null_cookieW; + len = WLDAP32_ber_printf( ber, (char *)"{iV}", pagesize, vec ); - ret = ber_flatten( ber, &berval ); - ber_free( ber, 1 ); + ret = WLDAP32_ber_flatten( ber, &berval ); + WLDAP32_ber_free( ber, 1 ); - if (tag == LBER_ERROR) - return WLDAP32_LDAP_ENCODING_ERROR; - - if (ret == -1) - return WLDAP32_LDAP_NO_MEMORY; + if (len == WLDAP32_LBER_ERROR) return WLDAP32_LDAP_ENCODING_ERROR; + if (ret == -1) return WLDAP32_LDAP_NO_MEMORY; /* copy the berval so it can be properly freed by the caller */ if (!(val = heap_alloc( berval->bv_len ))) return WLDAP32_LDAP_NO_MEMORY; len = berval->bv_len; memcpy( val, berval->bv_val, len ); - ber_bvfree( berval ); + WLDAP32_ber_bvfree( berval ); - if (!(ctrl = heap_alloc( sizeof(LDAPControlW) ))) + if (!(ctrl = heap_alloc( sizeof(*ctrl) ))) { heap_free( val ); return WLDAP32_LDAP_NO_MEMORY; } - - ctrl->ldctl_oid = strAtoW( LDAP_PAGED_RESULT_OID_STRING ); + if (!(ctrl->ldctl_oid = strAtoW( LDAP_PAGED_RESULT_OID_STRING ))) + { + heap_free( ctrl ); + return WLDAP32_LDAP_NO_MEMORY; + } ctrl->ldctl_value.bv_len = len; ctrl->ldctl_value.bv_val = val; - ctrl->ldctl_iscritical = critical; + ctrl->ldctl_iscritical = critical; *control = ctrl; - return WLDAP32_LDAP_SUCCESS; } -#endif /* HAVE_LDAP */ - /*********************************************************************** * ldap_create_page_controlW (WLDAP32.@) * @@ -146,31 +124,16 @@ static ULONG create_page_control( ULONG pagesize, struct berval *cookie, * Success: LDAP_SUCCESS * Failure: An LDAP error code. */ -ULONG CDECL ldap_create_page_controlW( WLDAP32_LDAP *ld, ULONG pagesize, - struct WLDAP32_berval *cookie, UCHAR critical, PLDAPControlW *control ) +ULONG CDECL ldap_create_page_controlW( WLDAP32_LDAP *ld, ULONG pagesize, struct WLDAP32_berval *cookie, + UCHAR critical, LDAPControlW **control ) { -#ifdef HAVE_LDAP - struct berval *cookieU = NULL; - ULONG ret; + TRACE( "(%p, 0x%08x, %p, 0x%02x, %p)\n", ld, pagesize, cookie, critical, control ); - TRACE( "(%p, 0x%08x, %p, 0x%02x, %p)\n", ld, pagesize, cookie, - critical, control ); - - if (!ld || !control || pagesize > LDAP_MAXINT) - return WLDAP32_LDAP_PARAM_ERROR; - - if (cookie && !(cookieU = bervalWtoU( cookie ))) return WLDAP32_LDAP_NO_MEMORY; - ret = create_page_control( pagesize, cookieU, critical, control ); - heap_free( cookieU ); - return ret; - -#else - return WLDAP32_LDAP_NOT_SUPPORTED; -#endif + if (!ld || !control || pagesize > LDAP_MAXINT) return WLDAP32_LDAP_PARAM_ERROR; + return create_page_control( pagesize, cookie, critical, control ); } -ULONG CDECL ldap_get_next_page( WLDAP32_LDAP *ld, PLDAPSearch search, ULONG pagesize, - ULONG *message ) +ULONG CDECL ldap_get_next_page( WLDAP32_LDAP *ld, LDAPSearch *search, ULONG pagesize, ULONG *message ) { FIXME( "(%p, %p, 0x%08x, %p)\n", ld, search, pagesize, message ); @@ -178,18 +141,16 @@ ULONG CDECL ldap_get_next_page( WLDAP32_LDAP *ld, PLDAPSearch search, ULONG page return WLDAP32_LDAP_NOT_SUPPORTED; } -ULONG CDECL ldap_get_next_page_s( WLDAP32_LDAP *ld, PLDAPSearch search, - struct l_timeval *timeout, ULONG pagesize, ULONG *count, - WLDAP32_LDAPMessage **results ) +ULONG CDECL ldap_get_next_page_s( WLDAP32_LDAP *ld, LDAPSearch *search, struct l_timeval *timeout, ULONG pagesize, + ULONG *count, WLDAP32_LDAPMessage **results ) { -#ifdef HAVE_LDAP ULONG ret; - TRACE( "(%p, %p, %p, %u, %p, %p)\n", ld, search, timeout, - pagesize, count, results ); + TRACE( "(%p, %p, %p, %u, %p, %p)\n", ld, search, timeout, pagesize, count, results ); + if (!ld || !search || !count || !results) return ~0u; - if (search->cookie && search->cookie->bv_len == 0) + if (search->cookie && !search->cookie->bv_len) { /* end of paged results */ *count = 0; @@ -207,22 +168,16 @@ ULONG CDECL ldap_get_next_page_s( WLDAP32_LDAP *ld, PLDAPSearch search, ret = ldap_create_page_controlW( ld, pagesize, search->cookie, 1, &search->serverctrls[0] ); if (ret != WLDAP32_LDAP_SUCCESS) return ret; - ret = ldap_search_ext_sW( ld, search->dn, search->scope, - search->filter, search->attrs, search->attrsonly, + ret = ldap_search_ext_sW( ld, search->dn, search->scope, search->filter, search->attrs, search->attrsonly, search->serverctrls, search->clientctrls, search->timeout.tv_sec ? &search->timeout : NULL, search->sizelimit, results ); if (ret != WLDAP32_LDAP_SUCCESS) return ret; return ldap_get_paged_count( ld, search, count, *results ); - -#endif - return WLDAP32_LDAP_NOT_SUPPORTED; } -ULONG CDECL ldap_get_paged_count( WLDAP32_LDAP *ld, PLDAPSearch search, - ULONG *count, WLDAP32_LDAPMessage *results ) +ULONG CDECL ldap_get_paged_count( WLDAP32_LDAP *ld, LDAPSearch *search, ULONG *count, WLDAP32_LDAPMessage *results ) { -#ifdef HAVE_LDAP ULONG ret; LDAPControlW **server_ctrls = NULL; @@ -249,99 +204,68 @@ ULONG CDECL ldap_get_paged_count( WLDAP32_LDAP *ld, PLDAPSearch search, TRACE("new search->cookie: %s, count %u\n", debugstr_an(search->cookie->bv_val, search->cookie->bv_len), *count); ldap_controls_freeW( server_ctrls ); - return ret; - -#endif - return WLDAP32_LDAP_NOT_SUPPORTED; } /*********************************************************************** * ldap_parse_page_controlA (WLDAP32.@) */ -ULONG CDECL ldap_parse_page_controlA( WLDAP32_LDAP *ld, PLDAPControlA *ctrls, - ULONG *count, struct WLDAP32_berval **cookie ) +ULONG CDECL ldap_parse_page_controlA( WLDAP32_LDAP *ld, LDAPControlA **ctrls, ULONG *count, + struct WLDAP32_berval **cookie ) { - ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED; -#ifdef HAVE_LDAP + ULONG ret; LDAPControlW **ctrlsW = NULL; TRACE( "(%p, %p, %p, %p)\n", ld, ctrls, count, cookie ); - if (!ld || !ctrls || !count || !cookie) - return WLDAP32_LDAP_PARAM_ERROR; - - ctrlsW = controlarrayAtoW( ctrls ); - if (!ctrlsW) return WLDAP32_LDAP_NO_MEMORY; + if (!ld || !ctrls || !count || !cookie) return WLDAP32_LDAP_PARAM_ERROR; + if (!(ctrlsW = controlarrayAtoW( ctrls ))) return WLDAP32_LDAP_NO_MEMORY; ret = ldap_parse_page_controlW( ld, ctrlsW, count, cookie ); controlarrayfreeW( ctrlsW ); - -#endif return ret; } /*********************************************************************** * ldap_parse_page_controlW (WLDAP32.@) */ -ULONG CDECL ldap_parse_page_controlW( WLDAP32_LDAP *ld, PLDAPControlW *ctrls, - ULONG *count, struct WLDAP32_berval **cookie ) +ULONG CDECL ldap_parse_page_controlW( WLDAP32_LDAP *ld, LDAPControlW **ctrls, ULONG *count, + struct WLDAP32_berval **cookie ) { - ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED; -#ifdef HAVE_LDAP + ULONG ret; LDAPControlW *control = NULL; - struct berval *cookieU = NULL, *valueU; - BerElement *ber; - ber_tag_t tag; + WLDAP32_BerElement *ber; + struct WLDAP32_berval *vec[2]; + int tag; ULONG i; TRACE( "(%p, %p, %p, %p)\n", ld, ctrls, count, cookie ); - if (!ld || !ctrls || !count || !cookie) - return WLDAP32_LDAP_PARAM_ERROR; + if (!ld || !ctrls || !count || !cookie) return WLDAP32_LDAP_PARAM_ERROR; for (i = 0; ctrls[i]; i++) { if (!lstrcmpW( LDAP_PAGED_RESULT_OID_STRING_W, ctrls[i]->ldctl_oid )) control = ctrls[i]; } + if (!control) return WLDAP32_LDAP_CONTROL_NOT_FOUND; - if (!control) - return WLDAP32_LDAP_CONTROL_NOT_FOUND; + if (!(ber = WLDAP32_ber_init( &control->ldctl_value ))) return WLDAP32_LDAP_NO_MEMORY; - if (cookie && !(cookieU = bervalWtoU( *cookie ))) - return WLDAP32_LDAP_NO_MEMORY; - - if (!(valueU = bervalWtoU( &control->ldctl_value ))) - { - heap_free( cookieU ); - return WLDAP32_LDAP_NO_MEMORY; - } - - ber = ber_init( valueU ); - heap_free( valueU ); - if (!ber) - { - heap_free( cookieU ); - return WLDAP32_LDAP_NO_MEMORY; - } - - tag = ber_scanf( ber, "{iO}", count, &cookieU ); - if (tag == LBER_ERROR) + vec[0] = *cookie; + vec[1] = 0; + tag = WLDAP32_ber_scanf( ber, (char *)"{iV}", count, vec ); + if (tag == WLDAP32_LBER_ERROR) ret = WLDAP32_LDAP_DECODING_ERROR; else ret = WLDAP32_LDAP_SUCCESS; - heap_free( cookieU ); - ber_free( ber, 1 ); - -#endif + WLDAP32_ber_free( ber, 1 ); return ret; } -ULONG CDECL ldap_search_abandon_page( WLDAP32_LDAP *ld, PLDAPSearch search ) +ULONG CDECL ldap_search_abandon_page( WLDAP32_LDAP *ld, LDAPSearch *search ) { -#ifdef HAVE_LDAP LDAPControlW **ctrls; TRACE( "(%p, %p)\n", ld, search ); @@ -357,91 +281,70 @@ ULONG CDECL ldap_search_abandon_page( WLDAP32_LDAP *ld, PLDAPSearch search ) while (*ctrls) controlfreeW( *ctrls++ ); heap_free( search->serverctrls ); controlarrayfreeW( search->clientctrls ); - if (search->cookie && search->cookie != &null_cookieW) - heap_free( search->cookie ); + if (search->cookie && search->cookie != &null_cookieW) heap_free( search->cookie ); heap_free( search ); return WLDAP32_LDAP_SUCCESS; - -#else - return WLDAP32_LDAP_NOT_SUPPORTED; -#endif } -PLDAPSearch CDECL ldap_search_init_pageA( WLDAP32_LDAP *ld, PCHAR dn, ULONG scope, - PCHAR filter, PCHAR attrs[], ULONG attrsonly, PLDAPControlA *serverctrls, - PLDAPControlA *clientctrls, ULONG timelimit, ULONG sizelimit, PLDAPSortKeyA *sortkeys ) +LDAPSearch * CDECL ldap_search_init_pageA( WLDAP32_LDAP *ld, char *dn, ULONG scope, char *filter, char **attrs, + ULONG attrsonly, LDAPControlA **serverctrls, LDAPControlA **clientctrls, ULONG timelimit, ULONG sizelimit, + LDAPSortKeyA **sortkeys ) { - FIXME( "(%p, %s, 0x%08x, %s, %p, 0x%08x)\n", ld, debugstr_a(dn), - scope, debugstr_a(filter), attrs, attrsonly ); + FIXME( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, 0x%08x, 0x%08x, %p)\n", ld, debugstr_a(dn), scope, + debugstr_a(filter), attrs, attrsonly, serverctrls, clientctrls, timelimit, sizelimit, sortkeys ); return NULL; } -PLDAPSearch CDECL ldap_search_init_pageW( WLDAP32_LDAP *ld, PWCHAR dn, ULONG scope, - PWCHAR filter, PWCHAR attrs[], ULONG attrsonly, PLDAPControlW *serverctrls, - PLDAPControlW *clientctrls, ULONG timelimit, ULONG sizelimit, PLDAPSortKeyW *sortkeys ) +LDAPSearch * CDECL ldap_search_init_pageW( WLDAP32_LDAP *ld, WCHAR *dn, ULONG scope, WCHAR *filter, WCHAR **attrs, + ULONG attrsonly, LDAPControlW **serverctrls, LDAPControlW **clientctrls, ULONG timelimit, ULONG sizelimit, + LDAPSortKeyW **sortkeys ) { -#ifdef HAVE_LDAP LDAPSearch *search; DWORD i, len; - TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, 0x%08x, 0x%08x, %p)\n", - ld, debugstr_w(dn), scope, debugstr_w(filter), attrs, attrsonly, - serverctrls, clientctrls, timelimit, sizelimit, sortkeys ); + TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, 0x%08x, 0x%08x, %p)\n", ld, debugstr_w(dn), scope, + debugstr_w(filter), attrs, attrsonly, serverctrls, clientctrls, timelimit, sizelimit, sortkeys ); - search = heap_alloc_zero( sizeof(*search) ); - if (!search) + if (!(search = heap_alloc_zero( sizeof(*search) ))) { ld->ld_errno = WLDAP32_LDAP_NO_MEMORY; return NULL; } - if (dn) - { - search->dn = strdupW( dn ); - if (!search->dn) goto fail; - } - if (filter) - { - search->filter = strdupW( filter ); - if (!search->filter) goto fail; - } - if (attrs) - { - search->attrs = strarraydupW( attrs ); - if (!search->attrs) goto fail; - } + if (dn && !(search->dn = strdupW( dn ))) goto fail; + if (filter && !(search->filter = strdupW( filter ))) goto fail; + if (attrs && !(search->attrs = strarraydupW( attrs ))) goto fail; len = serverctrls ? controlarraylenW( serverctrls ) : 0; - search->serverctrls = heap_alloc( sizeof(LDAPControl *) * (len + 2) ); - if (!search->serverctrls) goto fail; + if (!(search->serverctrls = heap_alloc( sizeof(LDAPControlW *) * (len + 2) ))) goto fail; search->serverctrls[0] = NULL; /* reserve 0 for page control */ for (i = 0; i < len; i++) { - search->serverctrls[i + 1] = controldupW( serverctrls[i] ); - if (!search->serverctrls[i + 1]) goto fail; + if (!(search->serverctrls[i + 1] = controldupW( serverctrls[i] ))) + { + for (; i > 0; i--) controlfreeW( search->serverctrls[i] ); + goto fail; + } } search->serverctrls[len + 1] = NULL; - if (clientctrls) + if (clientctrls && !(search->clientctrls = controlarraydupW( clientctrls ))) { - search->clientctrls = controlarraydupW( clientctrls ); - if (!search->clientctrls) goto fail; + for (i = 0; i < len; i++) controlfreeW( search->serverctrls[i] ); + goto fail; } - search->scope = scope; - search->attrsonly = attrsonly; - search->timeout.tv_sec = timelimit; + search->scope = scope; + search->attrsonly = attrsonly; + search->timeout.tv_sec = timelimit; search->timeout.tv_usec = 0; - search->sizelimit = sizelimit; - search->cookie = NULL; - + search->sizelimit = sizelimit; + search->cookie = NULL; return search; fail: ldap_search_abandon_page( ld, search ); ld->ld_errno = WLDAP32_LDAP_NO_MEMORY; - -#endif return NULL; } diff --git a/dlls/wldap32/winldap_private.h b/dlls/wldap32/winldap_private.h index 32ed3f5a266..e488db954c8 100644 --- a/dlls/wldap32/winldap_private.h +++ b/dlls/wldap32/winldap_private.h @@ -40,6 +40,8 @@ #define WLDAP32_LDAP_SCOPE_ONELEVEL 0x01 #define WLDAP32_LDAP_SCOPE_SUBTREE 0x02 +#define WLDAP32_LBER_USE_DER 0x01 + typedef enum { WLDAP32_LDAP_SUCCESS = 0x00, WLDAP32_LDAP_UNWILLING_TO_PERFORM = 0x35, @@ -312,6 +314,14 @@ typedef struct ldap_apifeature_infoW int ldapaif_version; } LDAPAPIFeatureInfoW; +WLDAP32_BerElement * CDECL WLDAP32_ber_alloc_t(int); +void CDECL WLDAP32_ber_bvfree(BERVAL *); +int CDECL WLDAP32_ber_flatten(WLDAP32_BerElement *, BERVAL **); +void CDECL WLDAP32_ber_free(WLDAP32_BerElement *, int); +WLDAP32_BerElement * CDECL WLDAP32_ber_init(BERVAL *); +int WINAPIV WLDAP32_ber_printf(WLDAP32_BerElement *, char *, ...); +ULONG WINAPIV WLDAP32_ber_scanf(WLDAP32_BerElement *, char *, ...); + WLDAP32_LDAP * CDECL cldap_openA(PCHAR,ULONG); WLDAP32_LDAP * CDECL cldap_openW(PWCHAR,ULONG); ULONG CDECL WLDAP32_ldap_abandon(WLDAP32_LDAP*,ULONG); @@ -614,6 +624,26 @@ static inline char **strarrayWtoU( WCHAR **strarray ) return strarrayU; } +static inline WCHAR **strarraydupW( WCHAR **strarray ) +{ + WCHAR **strarrayW = NULL; + DWORD size; + + if (strarray) + { + size = sizeof(WCHAR *) * (strarraylenW( strarray ) + 1); + if ((strarrayW = RtlAllocateHeap( GetProcessHeap(), 0, size ))) + { + WCHAR **p = strarray; + WCHAR **q = strarrayW; + + while (*p) *q++ = strdupW( *p++ ); + *q = NULL; + } + } + return strarrayW; +} + static inline char *strWtoA( const WCHAR *str ) { char *ret = NULL; @@ -1161,6 +1191,52 @@ static inline DWORD controlarraylenU( LDAPControlU **controlarray ) return p - controlarray; } +static inline LDAPControlW *controldupW( LDAPControlW *control ) +{ + LDAPControlW *controlW; + DWORD len = control->ldctl_value.bv_len; + char *val = NULL; + + if (control->ldctl_value.bv_val) + { + if (!(val = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return NULL; + memcpy( val, control->ldctl_value.bv_val, len ); + } + + if (!(controlW = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(LDAPControlW) ))) + { + RtlFreeHeap( GetProcessHeap(), 0, val ); + return NULL; + } + + controlW->ldctl_oid = strdupW( control->ldctl_oid ); + controlW->ldctl_value.bv_len = len; + controlW->ldctl_value.bv_val = val; + controlW->ldctl_iscritical = control->ldctl_iscritical; + + return controlW; +} + +static inline LDAPControlW **controlarraydupW( LDAPControlW **controlarray ) +{ + LDAPControlW **controlarrayW = NULL; + DWORD size; + + if (controlarray) + { + size = sizeof(LDAPControlW *) * (controlarraylenW( controlarray ) + 1); + if ((controlarrayW = RtlAllocateHeap( GetProcessHeap(), 0, size ))) + { + LDAPControlW **p = controlarray; + LDAPControlW **q = controlarrayW; + + while (*p) *q++ = controldupW( *p++ ); + *q = NULL; + } + } + return controlarrayW; +} + static inline WCHAR *strUtoW( const char *str ) { WCHAR *ret = NULL;