Better stick to the PSDK types.
[wine] / dlls / wldap32 / init.c
1 /*
2  * WLDAP32 - LDAP support for Wine
3  *
4  * Copyright 2005 Hans Leidekker
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "wine/port.h"
24 #include "wine/debug.h"
25
26 #include <stdio.h>
27 #include <stdarg.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32
33 #ifdef HAVE_LDAP_H
34 #include <ldap.h>
35 #else
36 #define LDAP_SUCCESS        0x00
37 #define LDAP_NOT_SUPPORTED  0x5c
38 #endif
39
40 #include "winldap_private.h"
41 #include "wldap32.h"
42
43 #ifdef HAVE_LDAP
44 /* Should eventually be determined by the algorithm documented on MSDN. */
45 static const WCHAR defaulthost[] = { 'l','o','c','a','l','h','o','s','t',0 };
46
47 /* Split a space separated string of hostnames into a string array */
48 static char **split_hostnames( const char *hostnames )
49 {
50     char **res, *str, *p, *q;
51     unsigned int i = 0;
52
53     str = strdupU( hostnames );
54     if (!str) return NULL;
55
56     p = str;
57     while (isspace( *p )) p++;
58     if (*p) i++;
59
60     while (*p)
61     {
62         if (isspace( *p ))
63         {
64             while (isspace( *p )) p++;
65             if (*p) i++;
66         }
67         p++;
68     }
69
70     res = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(char *) );
71     if (!res)
72     {
73         HeapFree( GetProcessHeap(), 0, str );
74         return NULL;
75     }
76
77     p = str;
78     while (isspace( *p )) p++;
79
80     q = p;
81     i = 0;
82     
83     while (*p)
84     {
85         if (p[1] != '\0')
86         {
87             if (isspace( *p ))
88             {
89                 *p = '\0'; p++;
90                 res[i] = strdupU( q );
91                 if (!res[i]) goto oom;
92                 i++;
93             
94                 while (isspace( *p )) p++;
95                 q = p;
96             }
97         }
98         else
99         {
100             res[i] = strdupU( q );
101             if (!res[i]) goto oom;
102             i++;
103         }
104         p++;
105     }
106     res[i] = NULL;
107
108     HeapFree( GetProcessHeap(), 0, str );
109     return res;
110
111 oom:
112     for (--i; i >= 0; i--)
113         strfreeU( res[i] );
114
115     HeapFree( GetProcessHeap(), 0, res );
116     HeapFree( GetProcessHeap(), 0, str );
117
118     return NULL;
119 }
120
121 /* Determine if a URL starts with a known LDAP scheme */
122 static int has_ldap_scheme( char *url )
123 {
124     if (!strncasecmp( url, "ldap://", 7 ) || 
125         !strncasecmp( url, "ldaps://", 8 ) ||
126         !strncasecmp( url, "ldapi://", 8 ) ||
127         !strncasecmp( url, "cldap://", 8 )) return 1;
128     return 0;
129 }
130
131 /* Flatten an array of hostnames into a space separated string of URLs.
132  * Prepend a given scheme and append a given portnumber to each hostname
133  * if necessary.
134  */
135 static char *join_hostnames( char *scheme, char **hostnames, ULONG portnumber )
136 {
137     char *res, *p, *q, **v;
138     unsigned int i = 0, size = 0; 
139     static const char sep[] = " ", fmt[] = ":%ld";
140     char port[6];
141
142     sprintf( port, fmt, portnumber ); 
143
144     for (v = hostnames; *v; v++)
145     {
146         if (!has_ldap_scheme( *v ))
147         {
148             size += strlen( scheme );
149             q = *v;
150         }
151         else
152             /* skip past colon in scheme prefix */
153             q = strchr( *v, '/' );
154
155         size += strlen( *v );
156
157         if (!strchr( q, ':' )) 
158             size += strlen( port );
159
160         i++;
161     }
162
163     size += (i - 1) * strlen( sep );
164  
165     res = HeapAlloc( GetProcessHeap(), 0, size + 1 );
166     if (!res) return NULL;
167
168     p = res;
169     for (v = hostnames; *v; v++)
170     {
171         if (v != hostnames)
172         {
173             strcpy( p, sep );
174             p += strlen( sep );
175         }
176
177         if (!has_ldap_scheme( *v ))
178         {
179             strcpy( p, scheme );
180             p += strlen( scheme );
181             q = *v;
182         }
183         else
184             /* skip past colon in scheme prefix */
185             q = strchr( *v, '/' );
186
187         strcpy( p, *v );
188         p += strlen( *v );
189
190         if (!strchr( q, ':' ))
191         {
192             strcpy( p, port );
193             p += strlen( port );
194         }
195     }
196     return res;
197 }
198
199 static char *urlify_hostnames( char *scheme, char *hostnames, ULONG port )
200 {
201     char *url, **strarray;
202
203     strarray = split_hostnames( hostnames );
204     url = join_hostnames( scheme, strarray, port );
205     strarrayfreeU( strarray );
206
207     return url;
208 }
209 #endif
210
211 WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
212
213 WLDAP32_LDAP *cldap_openA( PCHAR hostname, ULONG portnumber )
214 {
215 #ifdef HAVE_LDAP
216     WLDAP32_LDAP *ld = NULL;
217     WCHAR *hostnameW = NULL;
218
219     TRACE( "(%s, %ld)\n", debugstr_a(hostname), portnumber );
220
221     if (hostname) {
222         hostnameW = strAtoW( hostname );
223         if (!hostnameW) goto exit;
224     }
225
226     ld = cldap_openW( hostnameW, portnumber );
227
228 exit:
229     strfreeW( hostnameW );
230     return ld;
231
232 #endif
233     return NULL;
234 }
235
236 WLDAP32_LDAP *cldap_openW( PWCHAR hostname, ULONG portnumber )
237 {
238 #ifdef HAVE_LDAP
239     LDAP *ld = NULL;
240     char *hostnameU = NULL, *url = NULL;
241
242     TRACE( "(%s, %ld)\n", debugstr_w(hostname), portnumber );
243
244     if (hostname) {
245         hostnameU = strWtoU( hostname );
246         if (!hostnameU) goto exit;
247     }
248     else {
249         hostnameU = strWtoU( defaulthost );
250         if (!hostnameU) goto exit;
251     }
252
253     url = urlify_hostnames( "cldap://", hostnameU, portnumber );
254     if (!url) goto exit;
255
256     ldap_initialize( &ld, url );
257
258 exit:
259     strfreeU( hostnameU );
260     strfreeU( url );
261     return ld;
262
263 #endif
264     return NULL;
265 }
266
267 ULONG ldap_connect( WLDAP32_LDAP *ld, struct l_timeval *timeout )
268 {
269     TRACE( "(%p, %p)\n", ld, timeout );
270
271     if (!ld || !timeout) return WLDAP32_LDAP_PARAM_ERROR;
272     return LDAP_SUCCESS; /* FIXME: do something, e.g. ping the host */
273 }
274
275 WLDAP32_LDAP *ldap_initA( PCHAR hostname, ULONG portnumber )
276 {
277 #ifdef HAVE_LDAP
278     WLDAP32_LDAP *ld = NULL;
279     WCHAR *hostnameW = NULL;
280
281     TRACE( "(%s, %ld)\n", debugstr_a(hostname), portnumber );
282
283     if (hostname) {
284         hostnameW = strAtoW( hostname );
285         if (!hostnameW) goto exit;
286     }
287
288     ld = ldap_initW( hostnameW, portnumber );
289
290 exit:
291     strfreeW( hostnameW );
292     return ld;
293
294 #endif
295     return NULL;
296 }
297
298 WLDAP32_LDAP *ldap_initW( PWCHAR hostname, ULONG portnumber )
299 {
300 #ifdef HAVE_LDAP
301     LDAP *ld = NULL;
302     char *hostnameU = NULL, *url = NULL;
303
304     TRACE( "(%s, %ld)\n", debugstr_w(hostname), portnumber );
305
306     if (hostname) {
307         hostnameU = strWtoU( hostname );
308         if (!hostnameU) goto exit;
309     }
310     else {
311         hostnameU = strWtoU( defaulthost );
312         if (!hostnameU) goto exit;
313     }
314
315     url = urlify_hostnames( "ldap://", hostnameU, portnumber );
316     if (!url) goto exit;
317
318     ldap_initialize( &ld, url );
319
320 exit:
321     strfreeU( hostnameU );
322     strfreeU( url );
323     return ld;
324
325 #endif
326     return NULL;
327 }
328
329 WLDAP32_LDAP *ldap_openA( PCHAR hostname, ULONG portnumber )
330 {
331 #ifdef HAVE_LDAP
332     WLDAP32_LDAP *ld = NULL;
333     WCHAR *hostnameW = NULL;
334
335     TRACE( "(%s, %ld)\n", debugstr_a(hostname), portnumber );
336
337     if (hostname) {
338         hostnameW = strAtoW( hostname );
339         if (!hostnameW) goto exit;
340     }
341
342     ld = ldap_openW( hostnameW, portnumber );
343
344 exit:
345     strfreeW( hostnameW );
346     return ld;
347
348 #endif
349     return NULL;
350 }
351
352 WLDAP32_LDAP *ldap_openW( PWCHAR hostname, ULONG portnumber )
353 {
354 #ifdef HAVE_LDAP
355     LDAP *ld = NULL;
356     char *hostnameU = NULL, *url = NULL;
357
358     TRACE( "(%s, %ld)\n", debugstr_w(hostname), portnumber );
359
360     if (hostname) {
361         hostnameU = strWtoU( hostname );
362         if (!hostnameU) goto exit;
363     }
364     else {
365         hostnameU = strWtoU( defaulthost );
366         if (!hostnameU) goto exit;
367     }
368
369     url = urlify_hostnames( "ldap://", hostnameU, portnumber );
370     if (!url) goto exit;
371
372     ldap_initialize( &ld, url );
373
374 exit:
375     strfreeU( hostnameU );
376     strfreeU( url );
377     return ld;
378
379 #endif
380     return NULL;
381 }
382
383 WLDAP32_LDAP *ldap_sslinitA( PCHAR hostname, ULONG portnumber, int secure )
384 {
385 #ifdef HAVE_LDAP
386     WLDAP32_LDAP *ld;
387     WCHAR *hostnameW = NULL;
388
389     TRACE( "(%s, %ld, 0x%08x)\n", debugstr_a(hostname), portnumber, secure );
390
391     if (hostname) {
392         hostnameW = strAtoW( hostname );
393         if (!hostnameW) return NULL;
394     }
395
396     ld  = ldap_sslinitW( hostnameW, portnumber, secure );
397
398     strfreeW( hostnameW );
399     return ld;
400
401 #endif
402     return NULL;
403 }
404
405 WLDAP32_LDAP *ldap_sslinitW( PWCHAR hostname, ULONG portnumber, int secure )
406 {
407 #ifdef HAVE_LDAP
408     WLDAP32_LDAP *ld;
409     char *hostnameU = NULL, *url = NULL;
410
411     TRACE( "(%s, %ld, 0x%08x)\n", debugstr_w(hostname), portnumber, secure );
412
413     if (hostname) {
414         hostnameU = strWtoU( hostname );
415         if (!hostnameU) goto exit;
416     }
417     else {
418         hostnameU = strWtoU( defaulthost );
419         if (!hostnameU) goto exit;
420     }
421
422     if (secure)
423         url = urlify_hostnames( "ldaps://", hostnameU, portnumber );
424     else
425         url = urlify_hostnames( "ldap://", hostnameU, portnumber );
426
427     if (!url) goto exit;
428     ldap_initialize( &ld, url );
429
430 exit:
431     strfreeU( hostnameU );
432     strfreeU( url );
433     return ld;
434
435 #endif
436     return NULL;
437 }
438
439 ULONG ldap_start_tls_sA( WLDAP32_LDAP *ld, PULONG retval, WLDAP32_LDAPMessage **result,
440     PLDAPControlA *serverctrls, PLDAPControlA *clientctrls )
441 {
442     ULONG ret = LDAP_NOT_SUPPORTED;
443 #ifdef HAVE_LDAP
444     LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
445
446     ret = WLDAP32_LDAP_NO_MEMORY;
447
448     TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
449
450     if (!ld) return ~0UL;
451
452     if (serverctrls) {
453         serverctrlsW = controlarrayAtoW( serverctrls );
454         if (!serverctrlsW) goto exit;
455     }
456     if (clientctrls) {
457         clientctrlsW = controlarrayAtoW( clientctrls );
458         if (!clientctrlsW) goto exit;
459     }
460
461     ret = ldap_start_tls_sW( ld, retval, result, serverctrlsW, clientctrlsW );
462
463 exit:
464     controlarrayfreeW( serverctrlsW );
465     controlarrayfreeW( clientctrlsW );
466
467 #endif
468     return ret;
469 }
470
471 ULONG ldap_start_tls_sW( WLDAP32_LDAP *ld, PULONG retval, WLDAP32_LDAPMessage **result,
472     PLDAPControlW *serverctrls, PLDAPControlW *clientctrls )
473 {
474     ULONG ret = LDAP_NOT_SUPPORTED;
475 #ifdef HAVE_LDAP
476     LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
477
478     ret = WLDAP32_LDAP_NO_MEMORY;
479
480     TRACE( "(%p, %p, %p, %p, %p)\n", ld, retval, result, serverctrls, clientctrls );
481
482     if (!ld) return ~0UL;
483
484     if (serverctrls) {
485         serverctrlsU = controlarrayWtoU( serverctrls );
486         if (!serverctrlsU) goto exit;
487     }
488     if (clientctrls) {
489         clientctrlsU = controlarrayWtoU( clientctrls );
490         if (!clientctrlsU) goto exit;
491     }
492
493     ret = ldap_start_tls_s( ld, serverctrlsU, clientctrlsU );
494
495 exit:
496     controlarrayfreeU( serverctrlsU );
497     controlarrayfreeU( clientctrlsU );
498
499 #endif
500     return ret;
501 }
502
503 ULONG ldap_startup( PLDAP_VERSION_INFO version, HANDLE *instance )
504 {
505     TRACE( "(%p, %p)\n", version, instance );
506     return LDAP_SUCCESS;
507 }
508
509 BOOLEAN ldap_stop_tls_s( WLDAP32_LDAP *ld )
510 {
511     TRACE( "(%p)\n", ld );
512     return 0; /* FIXME: find a way to stop tls on a connection */
513 }