2 * WLDAP32 - LDAP support for Wine
4 * Copyright 2005 Hans Leidekker
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
34 #include "winldap_private.h"
36 #include "wine/debug.h"
39 /* Should eventually be determined by the algorithm documented on MSDN. */
40 static const WCHAR defaulthost
[] = { 'l','o','c','a','l','h','o','s','t',0 };
42 /* Split a space separated string of hostnames into a string array */
43 static char **split_hostnames( const char *hostnames
)
45 char **res
, *str
, *p
, *q
;
48 str
= strdupU( hostnames
);
49 if (!str
) return NULL
;
52 while (isspace( *p
)) p
++;
59 while (isspace( *p
)) p
++;
65 res
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(char *) );
68 HeapFree( GetProcessHeap(), 0, str
);
73 while (isspace( *p
)) p
++;
85 res
[i
] = strdupU( q
);
86 if (!res
[i
]) goto oom
;
89 while (isspace( *p
)) p
++;
95 res
[i
] = strdupU( q
);
96 if (!res
[i
]) goto oom
;
103 HeapFree( GetProcessHeap(), 0, str
);
107 while (i
> 0) strfreeU( res
[--i
] );
109 HeapFree( GetProcessHeap(), 0, res
);
110 HeapFree( GetProcessHeap(), 0, str
);
115 /* Determine if a URL starts with a known LDAP scheme */
116 static BOOL
has_ldap_scheme( char *url
)
118 return !strncasecmp( url
, "ldap://", 7 ) ||
119 !strncasecmp( url
, "ldaps://", 8 ) ||
120 !strncasecmp( url
, "ldapi://", 8 ) ||
121 !strncasecmp( url
, "cldap://", 8 );
124 /* Flatten an array of hostnames into a space separated string of URLs.
125 * Prepend a given scheme and append a given port number to each hostname
128 static char *join_hostnames( const char *scheme
, char **hostnames
, ULONG portnumber
)
130 char *res
, *p
, *q
, **v
;
131 unsigned int i
= 0, size
= 0;
132 static const char sep
[] = " ", fmt
[] = ":%d";
135 sprintf( port
, fmt
, portnumber
);
137 for (v
= hostnames
; *v
; v
++)
139 if (!has_ldap_scheme( *v
))
141 size
+= strlen( scheme
);
145 /* skip past colon in scheme prefix */
146 q
= strchr( *v
, '/' );
148 size
+= strlen( *v
);
150 if (!strchr( q
, ':' ))
151 size
+= strlen( port
);
156 size
+= (i
- 1) * strlen( sep
);
158 res
= HeapAlloc( GetProcessHeap(), 0, size
+ 1 );
159 if (!res
) return NULL
;
162 for (v
= hostnames
; *v
; v
++)
170 if (!has_ldap_scheme( *v
))
173 p
+= strlen( scheme
);
177 /* skip past colon in scheme prefix */
178 q
= strchr( *v
, '/' );
183 if (!strchr( q
, ':' ))
192 static char *urlify_hostnames( const char *scheme
, char *hostnames
, ULONG port
)
194 char *url
= NULL
, **strarray
;
196 strarray
= split_hostnames( hostnames
);
198 url
= join_hostnames( scheme
, strarray
, port
);
202 strarrayfreeU( strarray
);
207 WINE_DEFAULT_DEBUG_CHANNEL(wldap32
);
209 /***********************************************************************
210 * cldap_openA (WLDAP32.@)
214 WLDAP32_LDAP
* CDECL
cldap_openA( PCHAR hostname
, ULONG portnumber
)
217 WLDAP32_LDAP
*ld
= NULL
;
218 WCHAR
*hostnameW
= NULL
;
220 TRACE( "(%s, %d)\n", debugstr_a(hostname
), portnumber
);
223 hostnameW
= strAtoW( hostname
);
224 if (!hostnameW
) goto exit
;
227 ld
= cldap_openW( hostnameW
, portnumber
);
230 strfreeW( hostnameW
);
238 /***********************************************************************
239 * cldap_openW (WLDAP32.@)
241 * Initialize an LDAP context and create a UDP connection.
244 * hostname [I] Name of the host to connect to.
245 * portnumber [I] Port number to use.
248 * Success: Pointer to an LDAP context.
252 * The hostname string can be a space separated string of hostnames,
253 * in which case the LDAP runtime will try to connect to the hosts
254 * in order, until a connection can be made. A hostname may have a
255 * trailing port number (separated from the hostname by a ':'), which
256 * will take precedence over the port number supplied as a parameter
259 WLDAP32_LDAP
* CDECL
cldap_openW( PWCHAR hostname
, ULONG portnumber
)
263 char *hostnameU
= NULL
, *url
= NULL
;
265 TRACE( "(%s, %d)\n", debugstr_w(hostname
), portnumber
);
268 hostnameU
= strWtoU( hostname
);
269 if (!hostnameU
) goto exit
;
272 hostnameU
= strWtoU( defaulthost
);
273 if (!hostnameU
) goto exit
;
276 url
= urlify_hostnames( "cldap://", hostnameU
, portnumber
);
279 ldap_initialize( &ld
, url
);
282 strfreeU( hostnameU
);
291 /***********************************************************************
292 * ldap_connect (WLDAP32.@)
294 * Connect to an LDAP server.
297 * ld [I] Pointer to an LDAP context.
298 * timeout [I] Pointer to an l_timeval structure specifying the
299 * timeout in seconds.
302 * Success: LDAP_SUCCESS
303 * Failure: An LDAP error code.
306 * The timeout parameter may be NULL in which case a default timeout
307 * value will be used.
309 ULONG CDECL
ldap_connect( WLDAP32_LDAP
*ld
, struct l_timeval
*timeout
)
311 TRACE( "(%p, %p)\n", ld
, timeout
);
313 if (!ld
) return WLDAP32_LDAP_PARAM_ERROR
;
314 return WLDAP32_LDAP_SUCCESS
; /* FIXME: do something, e.g. ping the host */
317 /***********************************************************************
318 * ldap_initA (WLDAP32.@)
322 WLDAP32_LDAP
* CDECL
ldap_initA( const PCHAR hostname
, ULONG portnumber
)
325 WLDAP32_LDAP
*ld
= NULL
;
326 WCHAR
*hostnameW
= NULL
;
328 TRACE( "(%s, %d)\n", debugstr_a(hostname
), portnumber
);
331 hostnameW
= strAtoW( hostname
);
332 if (!hostnameW
) goto exit
;
335 ld
= ldap_initW( hostnameW
, portnumber
);
338 strfreeW( hostnameW
);
346 /***********************************************************************
347 * ldap_initW (WLDAP32.@)
349 * Initialize an LDAP context and create a TCP connection.
352 * hostname [I] Name of the host to connect to.
353 * portnumber [I] Port number to use.
356 * Success: Pointer to an LDAP context.
360 * The hostname string can be a space separated string of hostnames,
361 * in which case the LDAP runtime will try to connect to the hosts
362 * in order, until a connection can be made. A hostname may have a
363 * trailing port number (separated from the hostname by a ':'), which
364 * will take precedence over the port number supplied as a parameter
365 * to this function. The connection will not be made until the first
366 * LDAP function that needs it is called.
368 WLDAP32_LDAP
* CDECL
ldap_initW( const PWCHAR hostname
, ULONG portnumber
)
372 char *hostnameU
= NULL
, *url
= NULL
;
374 TRACE( "(%s, %d)\n", debugstr_w(hostname
), portnumber
);
377 hostnameU
= strWtoU( hostname
);
378 if (!hostnameU
) goto exit
;
381 hostnameU
= strWtoU( defaulthost
);
382 if (!hostnameU
) goto exit
;
385 url
= urlify_hostnames( "ldap://", hostnameU
, portnumber
);
388 ldap_initialize( &ld
, url
);
391 strfreeU( hostnameU
);
400 /***********************************************************************
401 * ldap_openA (WLDAP32.@)
405 WLDAP32_LDAP
* CDECL
ldap_openA( PCHAR hostname
, ULONG portnumber
)
408 WLDAP32_LDAP
*ld
= NULL
;
409 WCHAR
*hostnameW
= NULL
;
411 TRACE( "(%s, %d)\n", debugstr_a(hostname
), portnumber
);
414 hostnameW
= strAtoW( hostname
);
415 if (!hostnameW
) goto exit
;
418 ld
= ldap_openW( hostnameW
, portnumber
);
421 strfreeW( hostnameW
);
429 /***********************************************************************
430 * ldap_openW (WLDAP32.@)
432 * Initialize an LDAP context and create a TCP connection.
435 * hostname [I] Name of the host to connect to.
436 * portnumber [I] Port number to use.
439 * Success: Pointer to an LDAP context.
443 * The hostname string can be a space separated string of hostnames,
444 * in which case the LDAP runtime will try to connect to the hosts
445 * in order, until a connection can be made. A hostname may have a
446 * trailing port number (separated from the hostname by a ':'), which
447 * will take precedence over the port number supplied as a parameter
450 WLDAP32_LDAP
* CDECL
ldap_openW( PWCHAR hostname
, ULONG portnumber
)
454 char *hostnameU
= NULL
, *url
= NULL
;
456 TRACE( "(%s, %d)\n", debugstr_w(hostname
), portnumber
);
459 hostnameU
= strWtoU( hostname
);
460 if (!hostnameU
) goto exit
;
463 hostnameU
= strWtoU( defaulthost
);
464 if (!hostnameU
) goto exit
;
467 url
= urlify_hostnames( "ldap://", hostnameU
, portnumber
);
470 ldap_initialize( &ld
, url
);
473 strfreeU( hostnameU
);
482 /***********************************************************************
483 * ldap_sslinitA (WLDAP32.@)
487 WLDAP32_LDAP
* CDECL
ldap_sslinitA( PCHAR hostname
, ULONG portnumber
, int secure
)
491 WCHAR
*hostnameW
= NULL
;
493 TRACE( "(%s, %d, 0x%08x)\n", debugstr_a(hostname
), portnumber
, secure
);
496 hostnameW
= strAtoW( hostname
);
497 if (!hostnameW
) return NULL
;
500 ld
= ldap_sslinitW( hostnameW
, portnumber
, secure
);
502 strfreeW( hostnameW
);
510 /***********************************************************************
511 * ldap_sslinitW (WLDAP32.@)
513 * Initialize an LDAP context and create a secure TCP connection.
516 * hostname [I] Name of the host to connect to.
517 * portnumber [I] Port number to use.
518 * secure [I] Ask the server to create an SSL connection.
521 * Success: Pointer to an LDAP context.
525 * The hostname string can be a space separated string of hostnames,
526 * in which case the LDAP runtime will try to connect to the hosts
527 * in order, until a connection can be made. A hostname may have a
528 * trailing port number (separated from the hostname by a ':'), which
529 * will take precedence over the port number supplied as a parameter
530 * to this function. The connection will not be made until the first
531 * LDAP function that needs it is called.
533 WLDAP32_LDAP
* CDECL
ldap_sslinitW( PWCHAR hostname
, ULONG portnumber
, int secure
)
536 WLDAP32_LDAP
*ld
= NULL
;
537 char *hostnameU
= NULL
, *url
= NULL
;
539 TRACE( "(%s, %d, 0x%08x)\n", debugstr_w(hostname
), portnumber
, secure
);
542 hostnameU
= strWtoU( hostname
);
543 if (!hostnameU
) goto exit
;
546 hostnameU
= strWtoU( defaulthost
);
547 if (!hostnameU
) goto exit
;
551 url
= urlify_hostnames( "ldaps://", hostnameU
, portnumber
);
553 url
= urlify_hostnames( "ldap://", hostnameU
, portnumber
);
556 ldap_initialize( &ld
, url
);
559 strfreeU( hostnameU
);
568 /***********************************************************************
569 * ldap_start_tls_sA (WLDAP32.@)
571 * See ldap_start_tls_sW.
573 ULONG CDECL
ldap_start_tls_sA( WLDAP32_LDAP
*ld
, PULONG retval
, WLDAP32_LDAPMessage
**result
,
574 PLDAPControlA
*serverctrls
, PLDAPControlA
*clientctrls
)
576 ULONG ret
= WLDAP32_LDAP_NOT_SUPPORTED
;
578 LDAPControlW
**serverctrlsW
= NULL
, **clientctrlsW
= NULL
;
580 ret
= WLDAP32_LDAP_NO_MEMORY
;
582 TRACE( "(%p, %p, %p, %p, %p)\n", ld
, retval
, result
, serverctrls
, clientctrls
);
587 serverctrlsW
= controlarrayAtoW( serverctrls
);
588 if (!serverctrlsW
) goto exit
;
591 clientctrlsW
= controlarrayAtoW( clientctrls
);
592 if (!clientctrlsW
) goto exit
;
595 ret
= ldap_start_tls_sW( ld
, retval
, result
, serverctrlsW
, clientctrlsW
);
598 controlarrayfreeW( serverctrlsW
);
599 controlarrayfreeW( clientctrlsW
);
605 /***********************************************************************
606 * ldap_start_tls_s (WLDAP32.@)
608 * Start TLS encryption on an LDAP connection.
611 * ld [I] Pointer to an LDAP context.
612 * retval [I] Return value from the server.
613 * result [I] Response message from the server.
614 * serverctrls [I] Array of LDAP server controls.
615 * clientctrls [I] Array of LDAP client controls.
618 * Success: LDAP_SUCCESS
619 * Failure: An LDAP error code.
622 * LDAP function that needs it is called.
624 ULONG CDECL
ldap_start_tls_sW( WLDAP32_LDAP
*ld
, PULONG retval
, WLDAP32_LDAPMessage
**result
,
625 PLDAPControlW
*serverctrls
, PLDAPControlW
*clientctrls
)
627 ULONG ret
= WLDAP32_LDAP_NOT_SUPPORTED
;
629 LDAPControl
**serverctrlsU
= NULL
, **clientctrlsU
= NULL
;
631 ret
= WLDAP32_LDAP_NO_MEMORY
;
633 TRACE( "(%p, %p, %p, %p, %p)\n", ld
, retval
, result
, serverctrls
, clientctrls
);
638 serverctrlsU
= controlarrayWtoU( serverctrls
);
639 if (!serverctrlsU
) goto exit
;
642 clientctrlsU
= controlarrayWtoU( clientctrls
);
643 if (!clientctrlsU
) goto exit
;
646 ret
= map_error( ldap_start_tls_s( ld
, serverctrlsU
, clientctrlsU
));
649 controlarrayfreeU( serverctrlsU
);
650 controlarrayfreeU( clientctrlsU
);
656 /***********************************************************************
657 * ldap_startup (WLDAP32.@)
659 ULONG CDECL
ldap_startup( PLDAP_VERSION_INFO version
, HANDLE
*instance
)
661 TRACE( "(%p, %p)\n", version
, instance
);
662 return WLDAP32_LDAP_SUCCESS
;
665 /***********************************************************************
666 * ldap_stop_tls_s (WLDAP32.@)
668 * Stop TLS encryption on an LDAP connection.
671 * ld [I] Pointer to an LDAP context.
677 BOOLEAN CDECL
ldap_stop_tls_s( WLDAP32_LDAP
*ld
)
679 TRACE( "(%p)\n", ld
);
680 return TRUE
; /* FIXME: find a way to stop tls on a connection */