crypt32: Store CERT_KEY_CONTEXT in a platform independent way.
[wine.git] / dlls / wldap32 / init.c
blobafaef3b52f2e76c39878cb9dfc8e6d5e3abbe798
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 WLDAP32_LDAP *create_context( const char *url )
210 WLDAP32_LDAP *ld;
211 int version = LDAP_VERSION3;
213 ld = heap_alloc_zero( sizeof( *ld ));
214 if (!ld) return NULL;
215 if (ldap_initialize( &ld->ld, url ) != LDAP_SUCCESS)
217 heap_free( ld );
218 return NULL;
220 ldap_set_option( ld->ld, LDAP_OPT_PROTOCOL_VERSION, &version );
221 return ld;
223 #endif
225 /***********************************************************************
226 * cldap_openA (WLDAP32.@)
228 * See cldap_openW.
230 WLDAP32_LDAP * CDECL cldap_openA( PCHAR hostname, ULONG portnumber )
232 #ifdef HAVE_LDAP
233 WLDAP32_LDAP *ld = NULL;
234 WCHAR *hostnameW = NULL;
236 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
238 if (hostname) {
239 hostnameW = strAtoW( hostname );
240 if (!hostnameW) goto exit;
243 ld = cldap_openW( hostnameW, portnumber );
245 exit:
246 strfreeW( hostnameW );
247 return ld;
249 #else
250 return NULL;
251 #endif
254 /***********************************************************************
255 * cldap_openW (WLDAP32.@)
257 * Initialize an LDAP context and create a UDP connection.
259 * PARAMS
260 * hostname [I] Name of the host to connect to.
261 * portnumber [I] Port number to use.
263 * RETURNS
264 * Success: Pointer to an LDAP context.
265 * Failure: NULL
267 * NOTES
268 * The hostname string can be a space separated string of hostnames,
269 * in which case the LDAP runtime will try to connect to the hosts
270 * in order, until a connection can be made. A hostname may have a
271 * trailing port number (separated from the hostname by a ':'), which
272 * will take precedence over the port number supplied as a parameter
273 * to this function.
275 WLDAP32_LDAP * CDECL cldap_openW( PWCHAR hostname, ULONG portnumber )
277 #ifdef HAVE_LDAP
278 WLDAP32_LDAP *ld = NULL;
279 char *hostnameU = NULL, *url = NULL;
281 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
283 if (hostname) {
284 hostnameU = strWtoU( hostname );
285 if (!hostnameU) goto exit;
287 else {
288 hostnameU = strWtoU( defaulthost );
289 if (!hostnameU) goto exit;
292 url = urlify_hostnames( "cldap://", hostnameU, portnumber );
293 if (!url) goto exit;
295 ld = create_context( url );
297 exit:
298 strfreeU( hostnameU );
299 strfreeU( url );
300 return ld;
302 #else
303 return NULL;
304 #endif
307 /***********************************************************************
308 * ldap_connect (WLDAP32.@)
310 * Connect to an LDAP server.
312 * PARAMS
313 * ld [I] Pointer to an LDAP context.
314 * timeout [I] Pointer to an l_timeval structure specifying the
315 * timeout in seconds.
317 * RETURNS
318 * Success: LDAP_SUCCESS
319 * Failure: An LDAP error code.
321 * NOTES
322 * The timeout parameter may be NULL in which case a default timeout
323 * value will be used.
325 ULONG CDECL ldap_connect( WLDAP32_LDAP *ld, struct l_timeval *timeout )
327 TRACE( "(%p, %p)\n", ld, timeout );
329 if (!ld) return WLDAP32_LDAP_PARAM_ERROR;
330 return WLDAP32_LDAP_SUCCESS; /* FIXME: do something, e.g. ping the host */
333 /***********************************************************************
334 * ldap_initA (WLDAP32.@)
336 * See ldap_initW.
338 WLDAP32_LDAP * CDECL ldap_initA( const PCHAR hostname, ULONG portnumber )
340 #ifdef HAVE_LDAP
341 WLDAP32_LDAP *ld = NULL;
342 WCHAR *hostnameW = NULL;
344 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
346 if (hostname) {
347 hostnameW = strAtoW( hostname );
348 if (!hostnameW) goto exit;
351 ld = ldap_initW( hostnameW, portnumber );
353 exit:
354 strfreeW( hostnameW );
355 return ld;
357 #else
358 return NULL;
359 #endif
362 /***********************************************************************
363 * ldap_initW (WLDAP32.@)
365 * Initialize an LDAP context and create a TCP connection.
367 * PARAMS
368 * hostname [I] Name of the host to connect to.
369 * portnumber [I] Port number to use.
371 * RETURNS
372 * Success: Pointer to an LDAP context.
373 * Failure: NULL
375 * NOTES
376 * The hostname string can be a space separated string of hostnames,
377 * in which case the LDAP runtime will try to connect to the hosts
378 * in order, until a connection can be made. A hostname may have a
379 * trailing port number (separated from the hostname by a ':'), which
380 * will take precedence over the port number supplied as a parameter
381 * to this function. The connection will not be made until the first
382 * LDAP function that needs it is called.
384 WLDAP32_LDAP * CDECL ldap_initW( const PWCHAR hostname, ULONG portnumber )
386 #ifdef HAVE_LDAP
387 WLDAP32_LDAP *ld = NULL;
388 char *hostnameU = NULL, *url = NULL;
390 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
392 if (hostname) {
393 hostnameU = strWtoU( hostname );
394 if (!hostnameU) goto exit;
396 else {
397 hostnameU = strWtoU( defaulthost );
398 if (!hostnameU) goto exit;
401 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
402 if (!url) goto exit;
404 ld = create_context( url );
406 exit:
407 strfreeU( hostnameU );
408 strfreeU( url );
409 return ld;
411 #else
412 return NULL;
413 #endif
416 /***********************************************************************
417 * ldap_openA (WLDAP32.@)
419 * See ldap_openW.
421 WLDAP32_LDAP * CDECL ldap_openA( PCHAR hostname, ULONG portnumber )
423 #ifdef HAVE_LDAP
424 WLDAP32_LDAP *ld = NULL;
425 WCHAR *hostnameW = NULL;
427 TRACE( "(%s, %d)\n", debugstr_a(hostname), portnumber );
429 if (hostname) {
430 hostnameW = strAtoW( hostname );
431 if (!hostnameW) goto exit;
434 ld = ldap_openW( hostnameW, portnumber );
436 exit:
437 strfreeW( hostnameW );
438 return ld;
440 #else
441 return NULL;
442 #endif
445 /***********************************************************************
446 * ldap_openW (WLDAP32.@)
448 * Initialize an LDAP context and create a TCP connection.
450 * PARAMS
451 * hostname [I] Name of the host to connect to.
452 * portnumber [I] Port number to use.
454 * RETURNS
455 * Success: Pointer to an LDAP context.
456 * Failure: NULL
458 * NOTES
459 * The hostname string can be a space separated string of hostnames,
460 * in which case the LDAP runtime will try to connect to the hosts
461 * in order, until a connection can be made. A hostname may have a
462 * trailing port number (separated from the hostname by a ':'), which
463 * will take precedence over the port number supplied as a parameter
464 * to this function.
466 WLDAP32_LDAP * CDECL ldap_openW( PWCHAR hostname, ULONG portnumber )
468 #ifdef HAVE_LDAP
469 WLDAP32_LDAP *ld = NULL;
470 char *hostnameU = NULL, *url = NULL;
472 TRACE( "(%s, %d)\n", debugstr_w(hostname), portnumber );
474 if (hostname) {
475 hostnameU = strWtoU( hostname );
476 if (!hostnameU) goto exit;
478 else {
479 hostnameU = strWtoU( defaulthost );
480 if (!hostnameU) goto exit;
483 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
484 if (!url) goto exit;
486 ld = create_context( url );
488 exit:
489 strfreeU( hostnameU );
490 strfreeU( url );
491 return ld;
493 #else
494 return NULL;
495 #endif
498 /***********************************************************************
499 * ldap_sslinitA (WLDAP32.@)
501 * See ldap_sslinitW.
503 WLDAP32_LDAP * CDECL ldap_sslinitA( PCHAR hostname, ULONG portnumber, int secure )
505 #ifdef HAVE_LDAP
506 WLDAP32_LDAP *ld;
507 WCHAR *hostnameW = NULL;
509 TRACE( "(%s, %d, 0x%08x)\n", debugstr_a(hostname), portnumber, secure );
511 if (hostname) {
512 hostnameW = strAtoW( hostname );
513 if (!hostnameW) return NULL;
516 ld = ldap_sslinitW( hostnameW, portnumber, secure );
518 strfreeW( hostnameW );
519 return ld;
521 #else
522 return NULL;
523 #endif
526 /***********************************************************************
527 * ldap_sslinitW (WLDAP32.@)
529 * Initialize an LDAP context and create a secure TCP connection.
531 * PARAMS
532 * hostname [I] Name of the host to connect to.
533 * portnumber [I] Port number to use.
534 * secure [I] Ask the server to create an SSL connection.
536 * RETURNS
537 * Success: Pointer to an LDAP context.
538 * Failure: NULL
540 * NOTES
541 * The hostname string can be a space separated string of hostnames,
542 * in which case the LDAP runtime will try to connect to the hosts
543 * in order, until a connection can be made. A hostname may have a
544 * trailing port number (separated from the hostname by a ':'), which
545 * will take precedence over the port number supplied as a parameter
546 * to this function. The connection will not be made until the first
547 * LDAP function that needs it is called.
549 WLDAP32_LDAP * CDECL ldap_sslinitW( PWCHAR hostname, ULONG portnumber, int secure )
551 #ifdef HAVE_LDAP
552 WLDAP32_LDAP *ld = NULL;
553 char *hostnameU = NULL, *url = NULL;
555 TRACE( "(%s, %d, 0x%08x)\n", debugstr_w(hostname), portnumber, secure );
557 if (hostname) {
558 hostnameU = strWtoU( hostname );
559 if (!hostnameU) goto exit;
561 else {
562 hostnameU = strWtoU( defaulthost );
563 if (!hostnameU) goto exit;
566 if (secure)
567 url = urlify_hostnames( "ldaps://", hostnameU, portnumber );
568 else
569 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
571 if (!url) goto exit;
572 ldap_initialize( &ld->ld, url );
574 exit:
575 strfreeU( hostnameU );
576 strfreeU( url );
577 return ld;
579 #else
580 return NULL;
581 #endif
584 /***********************************************************************
585 * ldap_start_tls_sA (WLDAP32.@)
587 * See ldap_start_tls_sW.
589 ULONG CDECL ldap_start_tls_sA( WLDAP32_LDAP *ld, PULONG retval, WLDAP32_LDAPMessage **result,
590 PLDAPControlA *serverctrls, PLDAPControlA *clientctrls )
592 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
593 #ifdef HAVE_LDAP
594 LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
596 ret = WLDAP32_LDAP_NO_MEMORY;
598 TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
600 if (!ld) return ~0u;
602 if (serverctrls) {
603 serverctrlsW = controlarrayAtoW( serverctrls );
604 if (!serverctrlsW) goto exit;
606 if (clientctrls) {
607 clientctrlsW = controlarrayAtoW( clientctrls );
608 if (!clientctrlsW) goto exit;
611 ret = ldap_start_tls_sW( ld, retval, result, serverctrlsW, clientctrlsW );
613 exit:
614 controlarrayfreeW( serverctrlsW );
615 controlarrayfreeW( clientctrlsW );
617 #endif
618 return ret;
621 /***********************************************************************
622 * ldap_start_tls_s (WLDAP32.@)
624 * Start TLS encryption on an LDAP connection.
626 * PARAMS
627 * ld [I] Pointer to an LDAP context.
628 * retval [I] Return value from the server.
629 * result [I] Response message from the server.
630 * serverctrls [I] Array of LDAP server controls.
631 * clientctrls [I] Array of LDAP client controls.
633 * RETURNS
634 * Success: LDAP_SUCCESS
635 * Failure: An LDAP error code.
637 * NOTES
638 * LDAP function that needs it is called.
640 ULONG CDECL ldap_start_tls_sW( WLDAP32_LDAP *ld, PULONG retval, WLDAP32_LDAPMessage **result,
641 PLDAPControlW *serverctrls, PLDAPControlW *clientctrls )
643 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
644 #ifdef HAVE_LDAP
645 LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
647 ret = WLDAP32_LDAP_NO_MEMORY;
649 TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
651 if (!ld) return ~0u;
653 if (serverctrls) {
654 serverctrlsU = controlarrayWtoU( serverctrls );
655 if (!serverctrlsU) goto exit;
657 if (clientctrls) {
658 clientctrlsU = controlarrayWtoU( clientctrls );
659 if (!clientctrlsU) goto exit;
662 ret = map_error( ldap_start_tls_s( ld->ld, serverctrlsU, clientctrlsU ));
664 exit:
665 controlarrayfreeU( serverctrlsU );
666 controlarrayfreeU( clientctrlsU );
668 #endif
669 return ret;
672 /***********************************************************************
673 * ldap_startup (WLDAP32.@)
675 ULONG CDECL ldap_startup( PLDAP_VERSION_INFO version, HANDLE *instance )
677 TRACE( "(%p, %p)\n", version, instance );
678 return WLDAP32_LDAP_SUCCESS;
681 /***********************************************************************
682 * ldap_stop_tls_s (WLDAP32.@)
684 * Stop TLS encryption on an LDAP connection.
686 * PARAMS
687 * ld [I] Pointer to an LDAP context.
689 * RETURNS
690 * Success: TRUE
691 * Failure: FALSE
693 BOOLEAN CDECL ldap_stop_tls_s( WLDAP32_LDAP *ld )
695 TRACE( "(%p)\n", ld );
696 return TRUE; /* FIXME: find a way to stop tls on a connection */