wbemprox: Implement StdRegProv.CreateKey.
[wine.git] / dlls / wldap32 / init.c
blobfdb79084b502b8819007e64d6d3e7a6d54323da3
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"
34 #include "winldap_private.h"
35 #include "wldap32.h"
36 #include "wine/debug.h"
38 #ifdef HAVE_LDAP
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;
46 unsigned int i = 0;
48 str = strdupU( hostnames );
49 if (!str) return NULL;
51 p = str;
52 while (isspace( *p )) p++;
53 if (*p) i++;
55 while (*p)
57 if (isspace( *p ))
59 while (isspace( *p )) p++;
60 if (*p) i++;
62 p++;
65 if (!(res = heap_alloc( (i + 1) * sizeof(char *) )))
67 heap_free( str );
68 return NULL;
71 p = str;
72 while (isspace( *p )) p++;
74 q = p;
75 i = 0;
77 while (*p)
79 if (p[1] != '\0')
81 if (isspace( *p ))
83 *p = '\0'; p++;
84 res[i] = strdupU( q );
85 if (!res[i]) goto oom;
86 i++;
88 while (isspace( *p )) p++;
89 q = p;
92 else
94 res[i] = strdupU( q );
95 if (!res[i]) goto oom;
96 i++;
98 p++;
100 res[i] = NULL;
102 heap_free( str );
103 return res;
105 oom:
106 while (i > 0) strfreeU( res[--i] );
108 heap_free( res );
109 heap_free( str );
111 return NULL;
114 /* Determine if a URL starts with a known LDAP scheme */
115 static BOOL has_ldap_scheme( char *url )
117 return !strncasecmp( url, "ldap://", 7 ) ||
118 !strncasecmp( url, "ldaps://", 8 ) ||
119 !strncasecmp( url, "ldapi://", 8 ) ||
120 !strncasecmp( url, "cldap://", 8 );
123 /* Flatten an array of hostnames into a space separated string of URLs.
124 * Prepend a given scheme and append a given port number to each hostname
125 * if necessary.
127 static char *join_hostnames( const char *scheme, char **hostnames, ULONG portnumber )
129 char *res, *p, *q, **v;
130 unsigned int i = 0, size = 0;
131 static const char sep[] = " ", fmt[] = ":%d";
132 char port[7];
134 sprintf( port, fmt, portnumber );
136 for (v = hostnames; *v; v++)
138 if (!has_ldap_scheme( *v ))
140 size += strlen( scheme );
141 q = *v;
143 else
144 /* skip past colon in scheme prefix */
145 q = strchr( *v, '/' );
147 size += strlen( *v );
149 if (!strchr( q, ':' ))
150 size += strlen( port );
152 i++;
155 size += (i - 1) * strlen( sep );
156 if (!(res = heap_alloc( size + 1 ))) return NULL;
158 p = res;
159 for (v = hostnames; *v; v++)
161 if (v != hostnames)
163 strcpy( p, sep );
164 p += strlen( sep );
167 if (!has_ldap_scheme( *v ))
169 strcpy( p, scheme );
170 p += strlen( scheme );
171 q = *v;
173 else
174 /* skip past colon in scheme prefix */
175 q = strchr( *v, '/' );
177 strcpy( p, *v );
178 p += strlen( *v );
180 if (!strchr( q, ':' ))
182 strcpy( p, port );
183 p += strlen( port );
186 return res;
189 static char *urlify_hostnames( const char *scheme, char *hostnames, ULONG port )
191 char *url = NULL, **strarray;
193 strarray = split_hostnames( hostnames );
194 if (strarray)
195 url = join_hostnames( scheme, strarray, port );
196 else
197 return NULL;
199 strarrayfreeU( strarray );
200 return url;
202 #endif
204 WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
206 #ifdef HAVE_LDAP
207 static LDAP *create_context( const char *url )
209 LDAP *ld;
210 int version = LDAP_VERSION3;
211 if (ldap_initialize( &ld, url ) != LDAP_SUCCESS) return NULL;
212 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
213 return ld;
215 #endif
217 /***********************************************************************
218 * cldap_openA (WLDAP32.@)
220 * See cldap_openW.
222 WLDAP32_LDAP * CDECL cldap_openA( PCHAR hostname, ULONG portnumber )
224 #ifdef HAVE_LDAP
225 WLDAP32_LDAP *ld = NULL;
226 WCHAR *hostnameW = NULL;
228 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
230 if (hostname) {
231 hostnameW = strAtoW( hostname );
232 if (!hostnameW) goto exit;
235 ld = cldap_openW( hostnameW, portnumber );
237 exit:
238 strfreeW( hostnameW );
239 return ld;
241 #else
242 return NULL;
243 #endif
246 /***********************************************************************
247 * cldap_openW (WLDAP32.@)
249 * Initialize an LDAP context and create a UDP connection.
251 * PARAMS
252 * hostname [I] Name of the host to connect to.
253 * portnumber [I] Port number to use.
255 * RETURNS
256 * Success: Pointer to an LDAP context.
257 * Failure: NULL
259 * NOTES
260 * The hostname string can be a space separated string of hostnames,
261 * in which case the LDAP runtime will try to connect to the hosts
262 * in order, until a connection can be made. A hostname may have a
263 * trailing port number (separated from the hostname by a ':'), which
264 * will take precedence over the port number supplied as a parameter
265 * to this function.
267 WLDAP32_LDAP * CDECL cldap_openW( PWCHAR hostname, ULONG portnumber )
269 #ifdef HAVE_LDAP
270 LDAP *ld = NULL;
271 char *hostnameU = NULL, *url = NULL;
273 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
275 if (hostname) {
276 hostnameU = strWtoU( hostname );
277 if (!hostnameU) goto exit;
279 else {
280 hostnameU = strWtoU( defaulthost );
281 if (!hostnameU) goto exit;
284 url = urlify_hostnames( "cldap://", hostnameU, portnumber );
285 if (!url) goto exit;
287 ld = create_context( url );
289 exit:
290 strfreeU( hostnameU );
291 strfreeU( url );
292 return ld;
294 #else
295 return NULL;
296 #endif
299 /***********************************************************************
300 * ldap_connect (WLDAP32.@)
302 * Connect to an LDAP server.
304 * PARAMS
305 * ld [I] Pointer to an LDAP context.
306 * timeout [I] Pointer to an l_timeval structure specifying the
307 * timeout in seconds.
309 * RETURNS
310 * Success: LDAP_SUCCESS
311 * Failure: An LDAP error code.
313 * NOTES
314 * The timeout parameter may be NULL in which case a default timeout
315 * value will be used.
317 ULONG CDECL ldap_connect( WLDAP32_LDAP *ld, struct l_timeval *timeout )
319 TRACE( "(%p, %p)\n", ld, timeout );
321 if (!ld) return WLDAP32_LDAP_PARAM_ERROR;
322 return WLDAP32_LDAP_SUCCESS; /* FIXME: do something, e.g. ping the host */
325 /***********************************************************************
326 * ldap_initA (WLDAP32.@)
328 * See ldap_initW.
330 WLDAP32_LDAP * CDECL ldap_initA( const PCHAR hostname, ULONG portnumber )
332 #ifdef HAVE_LDAP
333 WLDAP32_LDAP *ld = NULL;
334 WCHAR *hostnameW = NULL;
336 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
338 if (hostname) {
339 hostnameW = strAtoW( hostname );
340 if (!hostnameW) goto exit;
343 ld = ldap_initW( hostnameW, portnumber );
345 exit:
346 strfreeW( hostnameW );
347 return ld;
349 #else
350 return NULL;
351 #endif
354 /***********************************************************************
355 * ldap_initW (WLDAP32.@)
357 * Initialize an LDAP context and create a TCP connection.
359 * PARAMS
360 * hostname [I] Name of the host to connect to.
361 * portnumber [I] Port number to use.
363 * RETURNS
364 * Success: Pointer to an LDAP context.
365 * Failure: NULL
367 * NOTES
368 * The hostname string can be a space separated string of hostnames,
369 * in which case the LDAP runtime will try to connect to the hosts
370 * in order, until a connection can be made. A hostname may have a
371 * trailing port number (separated from the hostname by a ':'), which
372 * will take precedence over the port number supplied as a parameter
373 * to this function. The connection will not be made until the first
374 * LDAP function that needs it is called.
376 WLDAP32_LDAP * CDECL ldap_initW( const PWCHAR hostname, ULONG portnumber )
378 #ifdef HAVE_LDAP
379 LDAP *ld = NULL;
380 char *hostnameU = NULL, *url = NULL;
382 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
384 if (hostname) {
385 hostnameU = strWtoU( hostname );
386 if (!hostnameU) goto exit;
388 else {
389 hostnameU = strWtoU( defaulthost );
390 if (!hostnameU) goto exit;
393 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
394 if (!url) goto exit;
396 ld = create_context( url );
398 exit:
399 strfreeU( hostnameU );
400 strfreeU( url );
401 return ld;
403 #else
404 return NULL;
405 #endif
408 /***********************************************************************
409 * ldap_openA (WLDAP32.@)
411 * See ldap_openW.
413 WLDAP32_LDAP * CDECL ldap_openA( PCHAR hostname, ULONG portnumber )
415 #ifdef HAVE_LDAP
416 WLDAP32_LDAP *ld = NULL;
417 WCHAR *hostnameW = NULL;
419 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
421 if (hostname) {
422 hostnameW = strAtoW( hostname );
423 if (!hostnameW) goto exit;
426 ld = ldap_openW( hostnameW, portnumber );
428 exit:
429 strfreeW( hostnameW );
430 return ld;
432 #else
433 return NULL;
434 #endif
437 /***********************************************************************
438 * ldap_openW (WLDAP32.@)
440 * Initialize an LDAP context and create a TCP connection.
442 * PARAMS
443 * hostname [I] Name of the host to connect to.
444 * portnumber [I] Port number to use.
446 * RETURNS
447 * Success: Pointer to an LDAP context.
448 * Failure: NULL
450 * NOTES
451 * The hostname string can be a space separated string of hostnames,
452 * in which case the LDAP runtime will try to connect to the hosts
453 * in order, until a connection can be made. A hostname may have a
454 * trailing port number (separated from the hostname by a ':'), which
455 * will take precedence over the port number supplied as a parameter
456 * to this function.
458 WLDAP32_LDAP * CDECL ldap_openW( PWCHAR hostname, ULONG portnumber )
460 #ifdef HAVE_LDAP
461 LDAP *ld = NULL;
462 char *hostnameU = NULL, *url = NULL;
464 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
466 if (hostname) {
467 hostnameU = strWtoU( hostname );
468 if (!hostnameU) goto exit;
470 else {
471 hostnameU = strWtoU( defaulthost );
472 if (!hostnameU) goto exit;
475 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
476 if (!url) goto exit;
478 ld = create_context( url );
480 exit:
481 strfreeU( hostnameU );
482 strfreeU( url );
483 return ld;
485 #else
486 return NULL;
487 #endif
490 /***********************************************************************
491 * ldap_sslinitA (WLDAP32.@)
493 * See ldap_sslinitW.
495 WLDAP32_LDAP * CDECL ldap_sslinitA( PCHAR hostname, ULONG portnumber, int secure )
497 #ifdef HAVE_LDAP
498 WLDAP32_LDAP *ld;
499 WCHAR *hostnameW = NULL;
501 TRACE( "(%s, %d, 0x%08x)\n", debugstr_a(hostname), portnumber, secure );
503 if (hostname) {
504 hostnameW = strAtoW( hostname );
505 if (!hostnameW) return NULL;
508 ld = ldap_sslinitW( hostnameW, portnumber, secure );
510 strfreeW( hostnameW );
511 return ld;
513 #else
514 return NULL;
515 #endif
518 /***********************************************************************
519 * ldap_sslinitW (WLDAP32.@)
521 * Initialize an LDAP context and create a secure TCP connection.
523 * PARAMS
524 * hostname [I] Name of the host to connect to.
525 * portnumber [I] Port number to use.
526 * secure [I] Ask the server to create an SSL connection.
528 * RETURNS
529 * Success: Pointer to an LDAP context.
530 * Failure: NULL
532 * NOTES
533 * The hostname string can be a space separated string of hostnames,
534 * in which case the LDAP runtime will try to connect to the hosts
535 * in order, until a connection can be made. A hostname may have a
536 * trailing port number (separated from the hostname by a ':'), which
537 * will take precedence over the port number supplied as a parameter
538 * to this function. The connection will not be made until the first
539 * LDAP function that needs it is called.
541 WLDAP32_LDAP * CDECL ldap_sslinitW( PWCHAR hostname, ULONG portnumber, int secure )
543 #ifdef HAVE_LDAP
544 WLDAP32_LDAP *ld = NULL;
545 char *hostnameU = NULL, *url = NULL;
547 TRACE( "(%s, %d, 0x%08x)\n", debugstr_w(hostname), portnumber, secure );
549 if (hostname) {
550 hostnameU = strWtoU( hostname );
551 if (!hostnameU) goto exit;
553 else {
554 hostnameU = strWtoU( defaulthost );
555 if (!hostnameU) goto exit;
558 if (secure)
559 url = urlify_hostnames( "ldaps://", hostnameU, portnumber );
560 else
561 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
563 if (!url) goto exit;
564 ldap_initialize( &ld, url );
566 exit:
567 strfreeU( hostnameU );
568 strfreeU( url );
569 return ld;
571 #else
572 return NULL;
573 #endif
576 /***********************************************************************
577 * ldap_start_tls_sA (WLDAP32.@)
579 * See ldap_start_tls_sW.
581 ULONG CDECL ldap_start_tls_sA( WLDAP32_LDAP *ld, PULONG retval, WLDAP32_LDAPMessage **result,
582 PLDAPControlA *serverctrls, PLDAPControlA *clientctrls )
584 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
585 #ifdef HAVE_LDAP
586 LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
588 ret = WLDAP32_LDAP_NO_MEMORY;
590 TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
592 if (!ld) return ~0u;
594 if (serverctrls) {
595 serverctrlsW = controlarrayAtoW( serverctrls );
596 if (!serverctrlsW) goto exit;
598 if (clientctrls) {
599 clientctrlsW = controlarrayAtoW( clientctrls );
600 if (!clientctrlsW) goto exit;
603 ret = ldap_start_tls_sW( ld, retval, result, serverctrlsW, clientctrlsW );
605 exit:
606 controlarrayfreeW( serverctrlsW );
607 controlarrayfreeW( clientctrlsW );
609 #endif
610 return ret;
613 /***********************************************************************
614 * ldap_start_tls_s (WLDAP32.@)
616 * Start TLS encryption on an LDAP connection.
618 * PARAMS
619 * ld [I] Pointer to an LDAP context.
620 * retval [I] Return value from the server.
621 * result [I] Response message from the server.
622 * serverctrls [I] Array of LDAP server controls.
623 * clientctrls [I] Array of LDAP client controls.
625 * RETURNS
626 * Success: LDAP_SUCCESS
627 * Failure: An LDAP error code.
629 * NOTES
630 * LDAP function that needs it is called.
632 ULONG CDECL ldap_start_tls_sW( WLDAP32_LDAP *ld, PULONG retval, WLDAP32_LDAPMessage **result,
633 PLDAPControlW *serverctrls, PLDAPControlW *clientctrls )
635 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
636 #ifdef HAVE_LDAP
637 LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
639 ret = WLDAP32_LDAP_NO_MEMORY;
641 TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
643 if (!ld) return ~0u;
645 if (serverctrls) {
646 serverctrlsU = controlarrayWtoU( serverctrls );
647 if (!serverctrlsU) goto exit;
649 if (clientctrls) {
650 clientctrlsU = controlarrayWtoU( clientctrls );
651 if (!clientctrlsU) goto exit;
654 ret = map_error( ldap_start_tls_s( ld, serverctrlsU, clientctrlsU ));
656 exit:
657 controlarrayfreeU( serverctrlsU );
658 controlarrayfreeU( clientctrlsU );
660 #endif
661 return ret;
664 /***********************************************************************
665 * ldap_startup (WLDAP32.@)
667 ULONG CDECL ldap_startup( PLDAP_VERSION_INFO version, HANDLE *instance )
669 TRACE( "(%p, %p)\n", version, instance );
670 return WLDAP32_LDAP_SUCCESS;
673 /***********************************************************************
674 * ldap_stop_tls_s (WLDAP32.@)
676 * Stop TLS encryption on an LDAP connection.
678 * PARAMS
679 * ld [I] Pointer to an LDAP context.
681 * RETURNS
682 * Success: TRUE
683 * Failure: FALSE
685 BOOLEAN CDECL ldap_stop_tls_s( WLDAP32_LDAP *ld )
687 TRACE( "(%p)\n", ld );
688 return TRUE; /* FIXME: find a way to stop tls on a connection */