dmime: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / wldap32 / init.c
blobc5b11a4de28fe5494692f32a08278c3fdc997322
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 <stdarg.h>
22 #include <stdlib.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "winternl.h"
27 #include "schannel.h"
28 #include "sspi.h"
30 #include "wine/debug.h"
31 #include "winldap_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
35 /* Split a space separated string of hostnames into a string array */
36 static char **split_hostnames( const char *hostnames )
38 char **res, *str, *p, *q;
39 unsigned int i = 0;
41 str = strdup( hostnames );
42 if (!str) return NULL;
44 p = str;
45 while (isspace( *p )) p++;
46 if (*p) i++;
48 while (*p)
50 if (isspace( *p ))
52 while (isspace( *p )) p++;
53 if (*p) i++;
55 p++;
58 if (!(res = malloc( (i + 1) * sizeof(char *) )))
60 free( str );
61 return NULL;
64 p = str;
65 while (isspace( *p )) p++;
67 q = p;
68 i = 0;
70 while (*p)
72 if (p[1] != '\0')
74 if (isspace( *p ))
76 *p = '\0'; p++;
77 res[i] = strdup( q );
78 if (!res[i]) goto oom;
79 i++;
81 while (isspace( *p )) p++;
82 q = p;
85 else
87 res[i] = strdup( q );
88 if (!res[i]) goto oom;
89 i++;
91 p++;
93 res[i] = NULL;
95 free( str );
96 return res;
98 oom:
99 while (i > 0) free( res[--i] );
100 free( res );
101 free( str );
102 return NULL;
105 /* Determine if a URL starts with a known LDAP scheme */
106 static BOOL has_ldap_scheme( char *url )
108 return !_strnicmp( url, "ldap://", 7 ) ||
109 !_strnicmp( url, "ldaps://", 8 ) ||
110 !_strnicmp( url, "ldapi://", 8 ) ||
111 !_strnicmp( url, "cldap://", 8 );
114 /* Flatten an array of hostnames into a space separated string of URLs.
115 * Prepend a given scheme and append a given port number to each hostname
116 * if necessary.
118 static char *join_hostnames( const char *scheme, char **hostnames, ULONG portnumber )
120 char *res, *p, *q, **v;
121 unsigned int i = 0, size = 0;
122 static const char sep[] = " ";
123 char port[7];
125 sprintf( port, ":%lu", portnumber );
127 for (v = hostnames; *v; v++)
129 if (!has_ldap_scheme( *v ))
131 size += strlen( scheme );
132 q = *v;
134 else
135 /* skip past colon in scheme prefix */
136 q = strchr( *v, '/' );
138 size += strlen( *v );
140 if (!strchr( q, ':' ))
141 size += strlen( port );
143 i++;
146 size += (i - 1) * strlen( sep );
147 if (!(res = malloc( size + 1 ))) return NULL;
149 p = res;
150 for (v = hostnames; *v; v++)
152 if (v != hostnames)
154 strcpy( p, sep );
155 p += strlen( sep );
158 if (!has_ldap_scheme( *v ))
160 strcpy( p, scheme );
161 p += strlen( scheme );
162 q = *v;
164 else
165 /* skip past colon in scheme prefix */
166 q = strchr( *v, '/' );
168 strcpy( p, *v );
169 p += strlen( *v );
171 if (!strchr( q, ':' ))
173 strcpy( p, port );
174 p += strlen( port );
177 return res;
180 static char *urlify_hostnames( const char *scheme, char *hostnames, ULONG port )
182 char *url = NULL, **strarray;
184 strarray = split_hostnames( hostnames );
185 if (strarray)
186 url = join_hostnames( scheme, strarray, port );
187 else
188 return NULL;
190 strarrayfreeU( strarray );
191 return url;
194 static LDAP *create_context( const char *url )
196 LDAP *ld;
197 int version = WLDAP32_LDAP_VERSION3;
199 if (!(ld = calloc( 1, sizeof( *ld )))) return NULL;
200 if (map_error( ldap_initialize( &CTX(ld), url ) ) == WLDAP32_LDAP_SUCCESS)
202 ldap_set_option( CTX(ld), WLDAP32_LDAP_OPT_PROTOCOL_VERSION, &version );
203 return ld;
205 free( ld );
206 return NULL;
209 /***********************************************************************
210 * cldap_openA (WLDAP32.@)
212 LDAP * CDECL cldap_openA( char *hostname, ULONG portnumber )
214 LDAP *ld;
215 WCHAR *hostnameW = NULL;
217 TRACE( "(%s, %lu)\n", debugstr_a(hostname), portnumber );
219 if (hostname && !(hostnameW = strAtoW( hostname ))) return NULL;
221 ld = cldap_openW( hostnameW, portnumber );
223 free( hostnameW );
224 return ld;
227 /***********************************************************************
228 * cldap_openW (WLDAP32.@)
230 LDAP * CDECL cldap_openW( WCHAR *hostname, ULONG portnumber )
232 LDAP *ld = NULL;
233 char *hostnameU, *url = NULL;
235 TRACE( "(%s, %lu)\n", debugstr_w(hostname), portnumber );
237 if (!(hostnameU = strWtoU( hostname ? hostname : L"localhost" ))) return NULL;
238 if (!(url = urlify_hostnames( "cldap://", hostnameU, portnumber ))) goto exit;
240 ld = create_context( url );
242 exit:
243 free( hostnameU );
244 free( url );
245 return ld;
248 /***********************************************************************
249 * ldap_connect (WLDAP32.@)
251 ULONG CDECL WLDAP32_ldap_connect( LDAP *ld, struct l_timeval *timeout )
253 VERIFYSERVERCERT *cert_callback = CERT_CALLBACK(ld);
254 int ret;
256 TRACE( "(%p, %p)\n", ld, timeout );
258 if (!ld) return WLDAP32_LDAP_PARAM_ERROR;
259 if (CONNECTED(ld)) return WLDAP32_LDAP_SUCCESS;
261 if (timeout && (timeout->tv_sec || timeout->tv_usec)) FIXME( "ignoring timeout\n" );
262 if ((ret = ldap_connect( CTX(ld) ))) return map_error( ret );
264 if (cert_callback)
266 CtxtHandle *tls_context;
267 const CERT_CONTEXT *cert;
269 if ((ret = ldap_get_option( CTX(ld), LDAP_OPT_X_TLS_SSL_CTX, &tls_context )))
270 return map_error( ret );
272 if (QueryContextAttributesA( tls_context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &cert ) == SEC_E_OK)
274 if (cert_callback( ld, &cert ))
276 TRACE( "accepted\n" );
278 else
280 WARN( "rejected\n" );
281 return WLDAP32_LDAP_SERVER_DOWN;
286 CONNECTED(ld) = TRUE;
287 return WLDAP32_LDAP_SUCCESS;
290 /***********************************************************************
291 * ldap_initA (WLDAP32.@)
293 LDAP * CDECL ldap_initA( const PCHAR hostname, ULONG portnumber )
295 LDAP *ld;
296 WCHAR *hostnameW = NULL;
298 TRACE( "(%s, %lu)\n", debugstr_a(hostname), portnumber );
300 if (hostname && !(hostnameW = strAtoW( hostname ))) return NULL;
302 ld = ldap_initW( hostnameW, portnumber );
304 free( hostnameW );
305 return ld;
308 /***********************************************************************
309 * ldap_initW (WLDAP32.@)
311 LDAP * CDECL ldap_initW( const PWCHAR hostname, ULONG portnumber )
313 LDAP *ld = NULL;
314 char *hostnameU, *url = NULL;
316 TRACE( "(%s, %lu)\n", debugstr_w(hostname), portnumber );
318 if (!(hostnameU = strWtoU( hostname ? hostname : L"localhost" ))) return NULL;
319 if (!(url = urlify_hostnames( "ldap://", hostnameU, portnumber ))) goto exit;
321 ld = create_context( url );
323 exit:
324 free( hostnameU );
325 free( url );
326 return ld;
329 /***********************************************************************
330 * ldap_openA (WLDAP32.@)
332 LDAP * CDECL ldap_openA( char *hostname, ULONG portnumber )
334 LDAP *ld;
335 WCHAR *hostnameW = NULL;
337 TRACE( "(%s, %lu)\n", debugstr_a(hostname), portnumber );
339 if (hostname && !(hostnameW = strAtoW( hostname ))) return NULL;
341 ld = ldap_openW( hostnameW, portnumber );
343 free( hostnameW );
344 return ld;
347 /***********************************************************************
348 * ldap_openW (WLDAP32.@)
350 LDAP * CDECL ldap_openW( WCHAR *hostname, ULONG portnumber )
352 LDAP *ld = NULL;
353 char *hostnameU, *url = NULL;
355 TRACE( "(%s, %lu)\n", debugstr_w(hostname), portnumber );
357 if (!(hostnameU = strWtoU( hostname ? hostname : L"localhost" ))) return NULL;
358 if (!(url = urlify_hostnames( "ldap://", hostnameU, portnumber ))) goto exit;
360 ld = create_context( url );
362 exit:
363 free( hostnameU );
364 free( url );
365 return ld;
368 /***********************************************************************
369 * ldap_sslinitA (WLDAP32.@)
371 LDAP * CDECL ldap_sslinitA( char *hostname, ULONG portnumber, int secure )
373 LDAP *ld;
374 WCHAR *hostnameW = NULL;
376 TRACE( "(%s, %lu, %d)\n", debugstr_a(hostname), portnumber, secure );
378 if (hostname && !(hostnameW = strAtoW( hostname ))) return NULL;
380 ld = ldap_sslinitW( hostnameW, portnumber, secure );
382 free( hostnameW );
383 return ld;
386 /***********************************************************************
387 * ldap_sslinitW (WLDAP32.@)
389 LDAP * CDECL ldap_sslinitW( WCHAR *hostname, ULONG portnumber, int secure )
391 LDAP *ld = NULL;
392 char *hostnameU, *url = NULL;
394 TRACE( "(%s, %lu, %d)\n", debugstr_w(hostname), portnumber, secure );
396 if (!(hostnameU = strWtoU( hostname ? hostname : L"localhost" ))) return NULL;
398 if (secure)
399 url = urlify_hostnames( "ldaps://", hostnameU, portnumber );
400 else
401 url = urlify_hostnames( "ldap://", hostnameU, portnumber );
402 if (!url) goto exit;
404 ld = create_context( url );
406 exit:
407 free( hostnameU );
408 free( url );
409 return ld;
412 /***********************************************************************
413 * ldap_start_tls_sA (WLDAP32.@)
415 ULONG CDECL ldap_start_tls_sA( LDAP *ld, ULONG *retval, LDAPMessage **result, LDAPControlA **serverctrls,
416 LDAPControlA **clientctrls )
418 ULONG ret = WLDAP32_LDAP_NO_MEMORY;
419 LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
421 TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
423 if (!ld) return ~0u;
425 if (serverctrls && !(serverctrlsW = controlarrayAtoW( serverctrls ))) goto exit;
426 if (clientctrls && !(clientctrlsW = controlarrayAtoW( clientctrls ))) goto exit;
428 ret = ldap_start_tls_sW( ld, retval, result, serverctrlsW, clientctrlsW );
430 exit:
431 controlarrayfreeW( serverctrlsW );
432 controlarrayfreeW( clientctrlsW );
433 return ret;
436 /***********************************************************************
437 * ldap_start_tls_s (WLDAP32.@)
439 ULONG CDECL ldap_start_tls_sW( LDAP *ld, ULONG *retval, LDAPMessage **result, LDAPControlW **serverctrls,
440 LDAPControlW **clientctrls )
442 ULONG ret = WLDAP32_LDAP_NO_MEMORY;
443 LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
445 TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
446 if (result)
448 FIXME( "result message not supported\n" );
449 *result = NULL;
452 if (!ld) return ~0u;
453 if (CONNECTED(ld)) return WLDAP32_LDAP_LOCAL_ERROR;
455 if (serverctrls && !(serverctrlsU = controlarrayWtoU( serverctrls ))) goto exit;
456 if (clientctrls && !(clientctrlsU = controlarrayWtoU( clientctrls ))) goto exit;
458 ret = map_error( ldap_start_tls_s( CTX(ld), serverctrlsU, clientctrlsU ) );
460 exit:
461 controlarrayfreeU( serverctrlsU );
462 controlarrayfreeU( clientctrlsU );
463 return ret;
466 /***********************************************************************
467 * ldap_startup (WLDAP32.@)
469 ULONG CDECL ldap_startup( LDAP_VERSION_INFO *version, HANDLE *instance )
471 TRACE( "(%p, %p)\n", version, instance );
472 return WLDAP32_LDAP_SUCCESS;
475 /***********************************************************************
476 * ldap_stop_tls_s (WLDAP32.@)
478 BOOLEAN CDECL ldap_stop_tls_s( LDAP *ld )
480 TRACE( "(%p)\n", ld );
481 return TRUE; /* FIXME: find a way to stop tls on a connection */