msi/tests: Remove workarounds for Windows 2000.
[wine.git] / dlls / wldap32 / init.c
blobd3508e33ef6f826985a30f3a49518baacb4d851c
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdio.h>
25 #include <stdarg.h>
26 #ifdef HAVE_LDAP_H
27 #include <ldap.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winnls.h"
33 #include "winternl.h"
35 #include "winldap_private.h"
36 #include "wldap32.h"
37 #include "wine/debug.h"
39 #ifdef HAVE_LDAP
40 /* Should eventually be determined by the algorithm documented on MSDN. */
41 static const WCHAR defaulthost[] = { 'l','o','c','a','l','h','o','s','t',0 };
43 /* Split a space separated string of hostnames into a string array */
44 static char **split_hostnames( const char *hostnames )
46 char **res, *str, *p, *q;
47 unsigned int i = 0;
49 str = strdupU( hostnames );
50 if (!str) return NULL;
52 p = str;
53 while (isspace( *p )) p++;
54 if (*p) i++;
56 while (*p)
58 if (isspace( *p ))
60 while (isspace( *p )) p++;
61 if (*p) i++;
63 p++;
66 if (!(res = heap_alloc( (i + 1) * sizeof(char *) )))
68 heap_free( str );
69 return NULL;
72 p = str;
73 while (isspace( *p )) p++;
75 q = p;
76 i = 0;
78 while (*p)
80 if (p[1] != '\0')
82 if (isspace( *p ))
84 *p = '\0'; p++;
85 res[i] = strdupU( q );
86 if (!res[i]) goto oom;
87 i++;
89 while (isspace( *p )) p++;
90 q = p;
93 else
95 res[i] = strdupU( q );
96 if (!res[i]) goto oom;
97 i++;
99 p++;
101 res[i] = NULL;
103 heap_free( str );
104 return res;
106 oom:
107 while (i > 0) strfreeU( res[--i] );
109 heap_free( res );
110 heap_free( str );
112 return NULL;
115 /* Determine if a URL starts with a known LDAP scheme */
116 static BOOL has_ldap_scheme( char *url )
118 return !_strnicmp( url, "ldap://", 7 ) ||
119 !_strnicmp( url, "ldaps://", 8 ) ||
120 !_strnicmp( url, "ldapi://", 8 ) ||
121 !_strnicmp( 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
126 * if necessary.
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";
133 char port[7];
135 sprintf( port, fmt, portnumber );
137 for (v = hostnames; *v; v++)
139 if (!has_ldap_scheme( *v ))
141 size += strlen( scheme );
142 q = *v;
144 else
145 /* skip past colon in scheme prefix */
146 q = strchr( *v, '/' );
148 size += strlen( *v );
150 if (!strchr( q, ':' ))
151 size += strlen( port );
153 i++;
156 size += (i - 1) * strlen( sep );
157 if (!(res = heap_alloc( size + 1 ))) return NULL;
159 p = res;
160 for (v = hostnames; *v; v++)
162 if (v != hostnames)
164 strcpy( p, sep );
165 p += strlen( sep );
168 if (!has_ldap_scheme( *v ))
170 strcpy( p, scheme );
171 p += strlen( scheme );
172 q = *v;
174 else
175 /* skip past colon in scheme prefix */
176 q = strchr( *v, '/' );
178 strcpy( p, *v );
179 p += strlen( *v );
181 if (!strchr( q, ':' ))
183 strcpy( p, port );
184 p += strlen( port );
187 return res;
190 static char *urlify_hostnames( const char *scheme, char *hostnames, ULONG port )
192 char *url = NULL, **strarray;
194 strarray = split_hostnames( hostnames );
195 if (strarray)
196 url = join_hostnames( scheme, strarray, port );
197 else
198 return NULL;
200 strarrayfreeU( strarray );
201 return url;
203 #endif
205 WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
207 #ifdef HAVE_LDAP
208 static LDAP *create_context( const char *url )
210 LDAP *ld;
211 int version = LDAP_VERSION3;
212 if (ldap_initialize( &ld, url ) != LDAP_SUCCESS) return NULL;
213 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
214 return ld;
216 #endif
218 /***********************************************************************
219 * cldap_openA (WLDAP32.@)
221 * See cldap_openW.
223 WLDAP32_LDAP * CDECL cldap_openA( PCHAR hostname, ULONG portnumber )
225 #ifdef HAVE_LDAP
226 WLDAP32_LDAP *ld = NULL;
227 WCHAR *hostnameW = NULL;
229 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
231 if (hostname) {
232 hostnameW = strAtoW( hostname );
233 if (!hostnameW) goto exit;
236 ld = cldap_openW( hostnameW, portnumber );
238 exit:
239 strfreeW( hostnameW );
240 return ld;
242 #else
243 return NULL;
244 #endif
247 /***********************************************************************
248 * cldap_openW (WLDAP32.@)
250 * Initialize an LDAP context and create a UDP connection.
252 * PARAMS
253 * hostname [I] Name of the host to connect to.
254 * portnumber [I] Port number to use.
256 * RETURNS
257 * Success: Pointer to an LDAP context.
258 * Failure: NULL
260 * NOTES
261 * The hostname string can be a space separated string of hostnames,
262 * in which case the LDAP runtime will try to connect to the hosts
263 * in order, until a connection can be made. A hostname may have a
264 * trailing port number (separated from the hostname by a ':'), which
265 * will take precedence over the port number supplied as a parameter
266 * to this function.
268 WLDAP32_LDAP * CDECL cldap_openW( PWCHAR hostname, ULONG portnumber )
270 #ifdef HAVE_LDAP
271 LDAP *ld = NULL;
272 char *hostnameU = NULL, *url = NULL;
274 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
276 if (hostname) {
277 hostnameU = strWtoU( hostname );
278 if (!hostnameU) goto exit;
280 else {
281 hostnameU = strWtoU( defaulthost );
282 if (!hostnameU) goto exit;
285 url = urlify_hostnames( "cldap://", hostnameU, portnumber );
286 if (!url) goto exit;
288 ld = create_context( url );
290 exit:
291 strfreeU( hostnameU );
292 strfreeU( url );
293 return ld;
295 #else
296 return NULL;
297 #endif
300 /***********************************************************************
301 * ldap_connect (WLDAP32.@)
303 * Connect to an LDAP server.
305 * PARAMS
306 * ld [I] Pointer to an LDAP context.
307 * timeout [I] Pointer to an l_timeval structure specifying the
308 * timeout in seconds.
310 * RETURNS
311 * Success: LDAP_SUCCESS
312 * Failure: An LDAP error code.
314 * NOTES
315 * The timeout parameter may be NULL in which case a default timeout
316 * value will be used.
318 ULONG CDECL ldap_connect( WLDAP32_LDAP *ld, struct l_timeval *timeout )
320 TRACE( "(%p, %p)\n", ld, timeout );
322 if (!ld) return WLDAP32_LDAP_PARAM_ERROR;
323 return WLDAP32_LDAP_SUCCESS; /* FIXME: do something, e.g. ping the host */
326 /***********************************************************************
327 * ldap_initA (WLDAP32.@)
329 * See ldap_initW.
331 WLDAP32_LDAP * CDECL ldap_initA( const PCHAR hostname, ULONG portnumber )
333 #ifdef HAVE_LDAP
334 WLDAP32_LDAP *ld = NULL;
335 WCHAR *hostnameW = NULL;
337 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
339 if (hostname) {
340 hostnameW = strAtoW( hostname );
341 if (!hostnameW) goto exit;
344 ld = ldap_initW( hostnameW, portnumber );
346 exit:
347 strfreeW( hostnameW );
348 return ld;
350 #else
351 return NULL;
352 #endif
355 /***********************************************************************
356 * ldap_initW (WLDAP32.@)
358 * Initialize an LDAP context and create a TCP connection.
360 * PARAMS
361 * hostname [I] Name of the host to connect to.
362 * portnumber [I] Port number to use.
364 * RETURNS
365 * Success: Pointer to an LDAP context.
366 * Failure: NULL
368 * NOTES
369 * The hostname string can be a space separated string of hostnames,
370 * in which case the LDAP runtime will try to connect to the hosts
371 * in order, until a connection can be made. A hostname may have a
372 * trailing port number (separated from the hostname by a ':'), which
373 * will take precedence over the port number supplied as a parameter
374 * to this function. The connection will not be made until the first
375 * LDAP function that needs it is called.
377 WLDAP32_LDAP * CDECL ldap_initW( const PWCHAR hostname, ULONG portnumber )
379 #ifdef HAVE_LDAP
380 LDAP *ld = NULL;
381 char *hostnameU = NULL, *url = NULL;
383 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
385 if (hostname) {
386 hostnameU = strWtoU( hostname );
387 if (!hostnameU) goto exit;
389 else {
390 hostnameU = strWtoU( defaulthost );
391 if (!hostnameU) goto exit;
394 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
395 if (!url) goto exit;
397 ld = create_context( url );
399 exit:
400 strfreeU( hostnameU );
401 strfreeU( url );
402 return ld;
404 #else
405 return NULL;
406 #endif
409 /***********************************************************************
410 * ldap_openA (WLDAP32.@)
412 * See ldap_openW.
414 WLDAP32_LDAP * CDECL ldap_openA( PCHAR hostname, ULONG portnumber )
416 #ifdef HAVE_LDAP
417 WLDAP32_LDAP *ld = NULL;
418 WCHAR *hostnameW = NULL;
420 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
422 if (hostname) {
423 hostnameW = strAtoW( hostname );
424 if (!hostnameW) goto exit;
427 ld = ldap_openW( hostnameW, portnumber );
429 exit:
430 strfreeW( hostnameW );
431 return ld;
433 #else
434 return NULL;
435 #endif
438 /***********************************************************************
439 * ldap_openW (WLDAP32.@)
441 * Initialize an LDAP context and create a TCP connection.
443 * PARAMS
444 * hostname [I] Name of the host to connect to.
445 * portnumber [I] Port number to use.
447 * RETURNS
448 * Success: Pointer to an LDAP context.
449 * Failure: NULL
451 * NOTES
452 * The hostname string can be a space separated string of hostnames,
453 * in which case the LDAP runtime will try to connect to the hosts
454 * in order, until a connection can be made. A hostname may have a
455 * trailing port number (separated from the hostname by a ':'), which
456 * will take precedence over the port number supplied as a parameter
457 * to this function.
459 WLDAP32_LDAP * CDECL ldap_openW( PWCHAR hostname, ULONG portnumber )
461 #ifdef HAVE_LDAP
462 LDAP *ld = NULL;
463 char *hostnameU = NULL, *url = NULL;
465 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
467 if (hostname) {
468 hostnameU = strWtoU( hostname );
469 if (!hostnameU) goto exit;
471 else {
472 hostnameU = strWtoU( defaulthost );
473 if (!hostnameU) goto exit;
476 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
477 if (!url) goto exit;
479 ld = create_context( url );
481 exit:
482 strfreeU( hostnameU );
483 strfreeU( url );
484 return ld;
486 #else
487 return NULL;
488 #endif
491 /***********************************************************************
492 * ldap_sslinitA (WLDAP32.@)
494 * See ldap_sslinitW.
496 WLDAP32_LDAP * CDECL ldap_sslinitA( PCHAR hostname, ULONG portnumber, int secure )
498 #ifdef HAVE_LDAP
499 WLDAP32_LDAP *ld;
500 WCHAR *hostnameW = NULL;
502 TRACE( "(%s, %d, 0x%08x)\n", debugstr_a(hostname), portnumber, secure );
504 if (hostname) {
505 hostnameW = strAtoW( hostname );
506 if (!hostnameW) return NULL;
509 ld = ldap_sslinitW( hostnameW, portnumber, secure );
511 strfreeW( hostnameW );
512 return ld;
514 #else
515 return NULL;
516 #endif
519 /***********************************************************************
520 * ldap_sslinitW (WLDAP32.@)
522 * Initialize an LDAP context and create a secure TCP connection.
524 * PARAMS
525 * hostname [I] Name of the host to connect to.
526 * portnumber [I] Port number to use.
527 * secure [I] Ask the server to create an SSL connection.
529 * RETURNS
530 * Success: Pointer to an LDAP context.
531 * Failure: NULL
533 * NOTES
534 * The hostname string can be a space separated string of hostnames,
535 * in which case the LDAP runtime will try to connect to the hosts
536 * in order, until a connection can be made. A hostname may have a
537 * trailing port number (separated from the hostname by a ':'), which
538 * will take precedence over the port number supplied as a parameter
539 * to this function. The connection will not be made until the first
540 * LDAP function that needs it is called.
542 WLDAP32_LDAP * CDECL ldap_sslinitW( PWCHAR hostname, ULONG portnumber, int secure )
544 #ifdef HAVE_LDAP
545 WLDAP32_LDAP *ld = NULL;
546 char *hostnameU = NULL, *url = NULL;
548 TRACE( "(%s, %d, 0x%08x)\n", debugstr_w(hostname), portnumber, secure );
550 if (hostname) {
551 hostnameU = strWtoU( hostname );
552 if (!hostnameU) goto exit;
554 else {
555 hostnameU = strWtoU( defaulthost );
556 if (!hostnameU) goto exit;
559 if (secure)
560 url = urlify_hostnames( "ldaps://", hostnameU, portnumber );
561 else
562 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
564 if (!url) goto exit;
565 ldap_initialize( &ld, url );
567 exit:
568 strfreeU( hostnameU );
569 strfreeU( url );
570 return ld;
572 #else
573 return NULL;
574 #endif
577 /***********************************************************************
578 * ldap_start_tls_sA (WLDAP32.@)
580 * See ldap_start_tls_sW.
582 ULONG CDECL ldap_start_tls_sA( WLDAP32_LDAP *ld, PULONG retval, WLDAP32_LDAPMessage **result,
583 PLDAPControlA *serverctrls, PLDAPControlA *clientctrls )
585 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
586 #ifdef HAVE_LDAP
587 LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
589 ret = WLDAP32_LDAP_NO_MEMORY;
591 TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
593 if (!ld) return ~0u;
595 if (serverctrls) {
596 serverctrlsW = controlarrayAtoW( serverctrls );
597 if (!serverctrlsW) goto exit;
599 if (clientctrls) {
600 clientctrlsW = controlarrayAtoW( clientctrls );
601 if (!clientctrlsW) goto exit;
604 ret = ldap_start_tls_sW( ld, retval, result, serverctrlsW, clientctrlsW );
606 exit:
607 controlarrayfreeW( serverctrlsW );
608 controlarrayfreeW( clientctrlsW );
610 #endif
611 return ret;
614 /***********************************************************************
615 * ldap_start_tls_s (WLDAP32.@)
617 * Start TLS encryption on an LDAP connection.
619 * PARAMS
620 * ld [I] Pointer to an LDAP context.
621 * retval [I] Return value from the server.
622 * result [I] Response message from the server.
623 * serverctrls [I] Array of LDAP server controls.
624 * clientctrls [I] Array of LDAP client controls.
626 * RETURNS
627 * Success: LDAP_SUCCESS
628 * Failure: An LDAP error code.
630 * NOTES
631 * LDAP function that needs it is called.
633 ULONG CDECL ldap_start_tls_sW( WLDAP32_LDAP *ld, PULONG retval, WLDAP32_LDAPMessage **result,
634 PLDAPControlW *serverctrls, PLDAPControlW *clientctrls )
636 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
637 #ifdef HAVE_LDAP
638 LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
640 ret = WLDAP32_LDAP_NO_MEMORY;
642 TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
644 if (!ld) return ~0u;
646 if (serverctrls) {
647 serverctrlsU = controlarrayWtoU( serverctrls );
648 if (!serverctrlsU) goto exit;
650 if (clientctrls) {
651 clientctrlsU = controlarrayWtoU( clientctrls );
652 if (!clientctrlsU) goto exit;
655 ret = map_error( ldap_start_tls_s( ld, serverctrlsU, clientctrlsU ));
657 exit:
658 controlarrayfreeU( serverctrlsU );
659 controlarrayfreeU( clientctrlsU );
661 #endif
662 return ret;
665 /***********************************************************************
666 * ldap_startup (WLDAP32.@)
668 ULONG CDECL ldap_startup( PLDAP_VERSION_INFO version, HANDLE *instance )
670 TRACE( "(%p, %p)\n", version, instance );
671 return WLDAP32_LDAP_SUCCESS;
674 /***********************************************************************
675 * ldap_stop_tls_s (WLDAP32.@)
677 * Stop TLS encryption on an LDAP connection.
679 * PARAMS
680 * ld [I] Pointer to an LDAP context.
682 * RETURNS
683 * Success: TRUE
684 * Failure: FALSE
686 BOOLEAN CDECL ldap_stop_tls_s( WLDAP32_LDAP *ld )
688 TRACE( "(%p)\n", ld );
689 return TRUE; /* FIXME: find a way to stop tls on a connection */