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
29 #include "wine/debug.h"
30 #include "winldap_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(wldap32
);
34 /* Split a space separated string of hostnames into a string array */
35 static char **split_hostnames( const char *hostnames
)
37 char **res
, *str
, *p
, *q
;
40 str
= strdupU( hostnames
);
41 if (!str
) return NULL
;
44 while (isspace( *p
)) p
++;
51 while (isspace( *p
)) p
++;
57 if (!(res
= malloc( (i
+ 1) * sizeof(char *) )))
64 while (isspace( *p
)) p
++;
76 res
[i
] = strdupU( q
);
77 if (!res
[i
]) goto oom
;
80 while (isspace( *p
)) p
++;
86 res
[i
] = strdupU( q
);
87 if (!res
[i
]) goto oom
;
98 while (i
> 0) free( res
[--i
] );
104 /* Determine if a URL starts with a known LDAP scheme */
105 static BOOL
has_ldap_scheme( char *url
)
107 return !_strnicmp( url
, "ldap://", 7 ) ||
108 !_strnicmp( url
, "ldaps://", 8 ) ||
109 !_strnicmp( url
, "ldapi://", 8 ) ||
110 !_strnicmp( url
, "cldap://", 8 );
113 /* Flatten an array of hostnames into a space separated string of URLs.
114 * Prepend a given scheme and append a given port number to each hostname
117 static char *join_hostnames( const char *scheme
, char **hostnames
, ULONG portnumber
)
119 char *res
, *p
, *q
, **v
;
120 unsigned int i
= 0, size
= 0;
121 static const char sep
[] = " ", fmt
[] = ":%d";
124 sprintf( port
, fmt
, portnumber
);
126 for (v
= hostnames
; *v
; v
++)
128 if (!has_ldap_scheme( *v
))
130 size
+= strlen( scheme
);
134 /* skip past colon in scheme prefix */
135 q
= strchr( *v
, '/' );
137 size
+= strlen( *v
);
139 if (!strchr( q
, ':' ))
140 size
+= strlen( port
);
145 size
+= (i
- 1) * strlen( sep
);
146 if (!(res
= malloc( size
+ 1 ))) return NULL
;
149 for (v
= hostnames
; *v
; v
++)
157 if (!has_ldap_scheme( *v
))
160 p
+= strlen( scheme
);
164 /* skip past colon in scheme prefix */
165 q
= strchr( *v
, '/' );
170 if (!strchr( q
, ':' ))
179 static char *urlify_hostnames( const char *scheme
, char *hostnames
, ULONG port
)
181 char *url
= NULL
, **strarray
;
183 strarray
= split_hostnames( hostnames
);
185 url
= join_hostnames( scheme
, strarray
, port
);
189 strarrayfreeU( strarray
);
194 static LDAP
*create_context( const char *url
)
197 int version
= LDAP_VERSION3
;
198 struct ldap_initialize_params params
;
200 if (!(ld
= calloc( 1, sizeof( *ld
)))) return NULL
;
201 params
.ld
= &CTX(ld
);
203 if (map_error( LDAP_CALL( ldap_initialize
, ¶ms
)) == LDAP_SUCCESS
)
205 struct ldap_set_option_params opt_params
= { CTX(ld
), LDAP_OPT_PROTOCOL_VERSION
, &version
};
206 LDAP_CALL( ldap_set_option
, &opt_params
);
213 /***********************************************************************
214 * cldap_openA (WLDAP32.@)
218 LDAP
* CDECL
cldap_openA( char *hostname
, ULONG portnumber
)
221 WCHAR
*hostnameW
= NULL
;
223 TRACE( "(%s, %d)\n", debugstr_a(hostname
), portnumber
);
225 if (hostname
&& !(hostnameW
= strAtoW( hostname
))) return NULL
;
227 ld
= cldap_openW( hostnameW
, portnumber
);
233 /***********************************************************************
234 * cldap_openW (WLDAP32.@)
236 * Initialize an LDAP context and create a UDP connection.
239 * hostname [I] Name of the host to connect to.
240 * portnumber [I] Port number to use.
243 * Success: Pointer to an LDAP context.
247 * The hostname string can be a space separated string of hostnames,
248 * in which case the LDAP runtime will try to connect to the hosts
249 * in order, until a connection can be made. A hostname may have a
250 * trailing port number (separated from the hostname by a ':'), which
251 * will take precedence over the port number supplied as a parameter
254 LDAP
* CDECL
cldap_openW( WCHAR
*hostname
, ULONG portnumber
)
257 char *hostnameU
, *url
= NULL
;
259 TRACE( "(%s, %d)\n", debugstr_w(hostname
), portnumber
);
261 if (!(hostnameU
= strWtoU( hostname
? hostname
: L
"localhost" ))) return NULL
;
262 if (!(url
= urlify_hostnames( "cldap://", hostnameU
, portnumber
))) goto exit
;
264 ld
= create_context( url
);
272 /***********************************************************************
273 * ldap_connect (WLDAP32.@)
275 * Connect to an LDAP server.
278 * ld [I] Pointer to an LDAP context.
279 * timeout [I] Pointer to an l_timeval structure specifying the
280 * timeout in seconds.
283 * Success: LDAP_SUCCESS
284 * Failure: An LDAP error code.
287 * The timeout parameter may be NULL in which case a default timeout
288 * value will be used.
290 ULONG CDECL
ldap_connect( LDAP
*ld
, struct l_timeval
*timeout
)
292 TRACE( "(%p, %p)\n", ld
, timeout
);
294 if (!ld
) return LDAP_PARAM_ERROR
;
295 return LDAP_SUCCESS
; /* FIXME: do something, e.g. ping the host */
298 /***********************************************************************
299 * ldap_initA (WLDAP32.@)
303 LDAP
* CDECL
ldap_initA( const PCHAR hostname
, ULONG portnumber
)
306 WCHAR
*hostnameW
= NULL
;
308 TRACE( "(%s, %d)\n", debugstr_a(hostname
), portnumber
);
310 if (hostname
&& !(hostnameW
= strAtoW( hostname
))) return NULL
;
312 ld
= ldap_initW( hostnameW
, portnumber
);
318 /***********************************************************************
319 * ldap_initW (WLDAP32.@)
321 * Initialize an LDAP context and create a TCP connection.
324 * hostname [I] Name of the host to connect to.
325 * portnumber [I] Port number to use.
328 * Success: Pointer to an LDAP context.
332 * The hostname string can be a space separated string of hostnames,
333 * in which case the LDAP runtime will try to connect to the hosts
334 * in order, until a connection can be made. A hostname may have a
335 * trailing port number (separated from the hostname by a ':'), which
336 * will take precedence over the port number supplied as a parameter
337 * to this function. The connection will not be made until the first
338 * LDAP function that needs it is called.
340 LDAP
* CDECL
ldap_initW( const PWCHAR hostname
, ULONG portnumber
)
343 char *hostnameU
, *url
= NULL
;
345 TRACE( "(%s, %d)\n", debugstr_w(hostname
), portnumber
);
347 if (!(hostnameU
= strWtoU( hostname
? hostname
: L
"localhost" ))) return NULL
;
348 if (!(url
= urlify_hostnames( "ldap://", hostnameU
, portnumber
))) goto exit
;
350 ld
= create_context( url
);
358 /***********************************************************************
359 * ldap_openA (WLDAP32.@)
363 LDAP
* CDECL
ldap_openA( char *hostname
, ULONG portnumber
)
366 WCHAR
*hostnameW
= NULL
;
368 TRACE( "(%s, %d)\n", debugstr_a(hostname
), portnumber
);
370 if (hostname
&& !(hostnameW
= strAtoW( hostname
))) return NULL
;
372 ld
= ldap_openW( hostnameW
, portnumber
);
378 /***********************************************************************
379 * ldap_openW (WLDAP32.@)
381 * Initialize an LDAP context and create a TCP connection.
384 * hostname [I] Name of the host to connect to.
385 * portnumber [I] Port number to use.
388 * Success: Pointer to an LDAP context.
392 * The hostname string can be a space separated string of hostnames,
393 * in which case the LDAP runtime will try to connect to the hosts
394 * in order, until a connection can be made. A hostname may have a
395 * trailing port number (separated from the hostname by a ':'), which
396 * will take precedence over the port number supplied as a parameter
399 LDAP
* CDECL
ldap_openW( WCHAR
*hostname
, ULONG portnumber
)
402 char *hostnameU
, *url
= NULL
;
404 TRACE( "(%s, %d)\n", debugstr_w(hostname
), portnumber
);
406 if (!(hostnameU
= strWtoU( hostname
? hostname
: L
"localhost" ))) return NULL
;
407 if (!(url
= urlify_hostnames( "ldap://", hostnameU
, portnumber
))) goto exit
;
409 ld
= create_context( url
);
417 /***********************************************************************
418 * ldap_sslinitA (WLDAP32.@)
422 LDAP
* CDECL
ldap_sslinitA( char *hostname
, ULONG portnumber
, int secure
)
425 WCHAR
*hostnameW
= NULL
;
427 TRACE( "(%s, %d, 0x%08x)\n", debugstr_a(hostname
), portnumber
, secure
);
429 if (hostname
&& !(hostnameW
= strAtoW( hostname
))) return NULL
;
431 ld
= ldap_sslinitW( hostnameW
, portnumber
, secure
);
437 /***********************************************************************
438 * ldap_sslinitW (WLDAP32.@)
440 * Initialize an LDAP context and create a secure TCP connection.
443 * hostname [I] Name of the host to connect to.
444 * portnumber [I] Port number to use.
445 * secure [I] Ask the server to create an SSL connection.
448 * Success: Pointer to an LDAP context.
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. The connection will not be made until the first
458 * LDAP function that needs it is called.
460 LDAP
* CDECL
ldap_sslinitW( WCHAR
*hostname
, ULONG portnumber
, int secure
)
463 char *hostnameU
, *url
= NULL
;
465 TRACE( "(%s, %d, 0x%08x)\n", debugstr_w(hostname
), portnumber
, secure
);
467 if (!(hostnameU
= strWtoU( hostname
? hostname
: L
"localhost" ))) return NULL
;
470 url
= urlify_hostnames( "ldaps://", hostnameU
, portnumber
);
472 url
= urlify_hostnames( "ldap://", hostnameU
, portnumber
);
475 ld
= create_context( url
);
483 /***********************************************************************
484 * ldap_start_tls_sA (WLDAP32.@)
486 * See ldap_start_tls_sW.
488 ULONG CDECL
ldap_start_tls_sA( LDAP
*ld
, ULONG
*retval
, LDAPMessage
**result
, LDAPControlA
**serverctrls
,
489 LDAPControlA
**clientctrls
)
491 ULONG ret
= LDAP_NO_MEMORY
;
492 LDAPControlW
**serverctrlsW
= NULL
, **clientctrlsW
= NULL
;
494 TRACE( "(%p, %p, %p, %p, %p)\n", ld
, retval
, result
, serverctrls
, clientctrls
);
498 if (serverctrls
&& !(serverctrlsW
= controlarrayAtoW( serverctrls
))) goto exit
;
499 if (clientctrls
&& !(clientctrlsW
= controlarrayAtoW( clientctrls
))) goto exit
;
501 ret
= ldap_start_tls_sW( ld
, retval
, result
, serverctrlsW
, clientctrlsW
);
504 controlarrayfreeW( serverctrlsW
);
505 controlarrayfreeW( clientctrlsW
);
509 /***********************************************************************
510 * ldap_start_tls_s (WLDAP32.@)
512 * Start TLS encryption on an LDAP connection.
515 * ld [I] Pointer to an LDAP context.
516 * retval [I] Return value from the server.
517 * result [I] Response message from the server.
518 * serverctrls [I] Array of LDAP server controls.
519 * clientctrls [I] Array of LDAP client controls.
522 * Success: LDAP_SUCCESS
523 * Failure: An LDAP error code.
526 * LDAP function that needs it is called.
528 ULONG CDECL
ldap_start_tls_sW( LDAP
*ld
, ULONG
*retval
, LDAPMessage
**result
, LDAPControlW
**serverctrls
,
529 LDAPControlW
**clientctrls
)
531 ULONG ret
= LDAP_NO_MEMORY
;
532 LDAPControlU
**serverctrlsU
= NULL
, **clientctrlsU
= NULL
;
534 TRACE( "(%p, %p, %p, %p, %p)\n", ld
, retval
, result
, serverctrls
, clientctrls
);
537 FIXME( "result message not supported\n" );
543 if (serverctrls
&& !(serverctrlsU
= controlarrayWtoU( serverctrls
))) goto exit
;
544 if (clientctrls
&& !(clientctrlsU
= controlarrayWtoU( clientctrls
))) goto exit
;
547 struct ldap_start_tls_s_params params
= { CTX(ld
), serverctrlsU
, clientctrlsU
};
548 ret
= map_error( LDAP_CALL( ldap_start_tls_s
, ¶ms
));
552 controlarrayfreeU( serverctrlsU
);
553 controlarrayfreeU( clientctrlsU
);
557 /***********************************************************************
558 * ldap_startup (WLDAP32.@)
560 ULONG CDECL
ldap_startup( LDAP_VERSION_INFO
*version
, HANDLE
*instance
)
562 TRACE( "(%p, %p)\n", version
, instance
);
566 /***********************************************************************
567 * ldap_stop_tls_s (WLDAP32.@)
569 * Stop TLS encryption on an LDAP connection.
572 * ld [I] Pointer to an LDAP context.
578 BOOLEAN CDECL
ldap_stop_tls_s( LDAP
*ld
)
580 TRACE( "(%p)\n", ld
);
581 return TRUE
; /* FIXME: find a way to stop tls on a connection */