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
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
;
41 str
= strdup( hostnames
);
42 if (!str
) return NULL
;
45 while (isspace( *p
)) p
++;
52 while (isspace( *p
)) p
++;
58 if (!(res
= malloc( (i
+ 1) * sizeof(char *) )))
65 while (isspace( *p
)) p
++;
78 if (!res
[i
]) goto oom
;
81 while (isspace( *p
)) p
++;
88 if (!res
[i
]) goto oom
;
99 while (i
> 0) free( res
[--i
] );
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
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
[] = " ";
125 sprintf( port
, ":%lu", portnumber
);
127 for (v
= hostnames
; *v
; v
++)
129 if (!has_ldap_scheme( *v
))
131 size
+= strlen( scheme
);
135 /* skip past colon in scheme prefix */
136 q
= strchr( *v
, '/' );
138 size
+= strlen( *v
);
140 if (!strchr( q
, ':' ))
141 size
+= strlen( port
);
146 size
+= (i
- 1) * strlen( sep
);
147 if (!(res
= malloc( size
+ 1 ))) return NULL
;
150 for (v
= hostnames
; *v
; v
++)
158 if (!has_ldap_scheme( *v
))
161 p
+= strlen( scheme
);
165 /* skip past colon in scheme prefix */
166 q
= strchr( *v
, '/' );
171 if (!strchr( q
, ':' ))
180 static char *urlify_hostnames( const char *scheme
, char *hostnames
, ULONG port
)
182 char *url
= NULL
, **strarray
;
184 strarray
= split_hostnames( hostnames
);
186 url
= join_hostnames( scheme
, strarray
, port
);
190 strarrayfreeU( strarray
);
194 static LDAP
*create_context( const char *url
)
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
);
209 /***********************************************************************
210 * cldap_openA (WLDAP32.@)
212 LDAP
* CDECL
cldap_openA( char *hostname
, ULONG portnumber
)
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
);
227 /***********************************************************************
228 * cldap_openW (WLDAP32.@)
230 LDAP
* CDECL
cldap_openW( WCHAR
*hostname
, ULONG portnumber
)
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
);
248 /***********************************************************************
249 * ldap_connect (WLDAP32.@)
251 ULONG CDECL
WLDAP32_ldap_connect( LDAP
*ld
, struct l_timeval
*timeout
)
253 VERIFYSERVERCERT
*cert_callback
= CERT_CALLBACK(ld
);
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
);
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" );
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
)
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
);
308 /***********************************************************************
309 * ldap_initW (WLDAP32.@)
311 LDAP
* CDECL
ldap_initW( const PWCHAR hostname
, ULONG portnumber
)
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
);
329 /***********************************************************************
330 * ldap_openA (WLDAP32.@)
332 LDAP
* CDECL
ldap_openA( char *hostname
, ULONG portnumber
)
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
);
347 /***********************************************************************
348 * ldap_openW (WLDAP32.@)
350 LDAP
* CDECL
ldap_openW( WCHAR
*hostname
, ULONG portnumber
)
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
);
368 /***********************************************************************
369 * ldap_sslinitA (WLDAP32.@)
371 LDAP
* CDECL
ldap_sslinitA( char *hostname
, ULONG portnumber
, int secure
)
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
);
386 /***********************************************************************
387 * ldap_sslinitW (WLDAP32.@)
389 LDAP
* CDECL
ldap_sslinitW( WCHAR
*hostname
, ULONG portnumber
, int secure
)
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
;
399 url
= urlify_hostnames( "ldaps://", hostnameU
, portnumber
);
401 url
= urlify_hostnames( "ldap://", hostnameU
, portnumber
);
404 ld
= create_context( url
);
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
);
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
);
431 controlarrayfreeW( serverctrlsW
);
432 controlarrayfreeW( clientctrlsW
);
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
);
448 FIXME( "result message not supported\n" );
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
) );
461 controlarrayfreeU( serverctrlsU
);
462 controlarrayfreeU( clientctrlsU
);
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 */