]> git.sur5r.net Git - openldap/blob - libraries/libldap/open.c
stdlib.h should be included as <ac/stdlib.h>
[openldap] / libraries / libldap / open.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1995 Regents of the University of Michigan.
8  *  All rights reserved.
9  *
10  *  open.c
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16 #include <limits.h>
17
18 #include <ac/stdlib.h>
19
20 #include <ac/param.h>
21 #include <ac/socket.h>
22 #include <ac/string.h>
23 #include <ac/time.h>
24
25 #include "ldap-int.h"
26
27 int ldap_open_defconn( LDAP *ld )
28 {
29         ld->ld_defconn = ldap_new_connection( ld,
30                 ld->ld_options.ldo_defludp, 1, 1, NULL );
31
32         if( ld->ld_defconn == NULL ) {
33                 ld->ld_errno = LDAP_SERVER_DOWN;
34                 return -1;
35         }
36
37         ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */
38         return 0;
39 }
40
41 /*
42  * ldap_open - initialize and connect to an ldap server.  A magic cookie to
43  * be used for future communication is returned on success, NULL on failure.
44  * "host" may be a space-separated list of hosts or IP addresses
45  *
46  * Example:
47  *      LDAP    *ld;
48  *      ld = ldap_open( hostname, port );
49  */
50
51 LDAP *
52 ldap_open( LDAP_CONST char *host, int port )
53 {
54         int rc;
55         LDAP            *ld;
56
57         Debug( LDAP_DEBUG_TRACE, "ldap_open(%s, %d)\n",
58                 host, port, 0 );
59
60         ld = ldap_init( host, port );
61         if ( ld == NULL ) {
62                 return( NULL );
63         }
64
65         rc = ldap_open_defconn( ld );
66
67         if( rc < 0 ) {
68                 ldap_ld_free( ld, 0, NULL, NULL );
69                 ld = NULL;
70         }
71
72         Debug( LDAP_DEBUG_TRACE, "ldap_open: %s\n",
73                 ld == NULL ? "succeeded" : "failed", 0, 0 );
74
75         return ld;
76 }
77
78
79
80 int
81 ldap_create( LDAP **ldp )
82 {
83         LDAP                    *ld;
84         struct ldapoptions      *gopts;
85
86         *ldp = NULL;
87         /* Get pointer to global option structure */
88         if ( (gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
89                 return LDAP_NO_MEMORY;
90         }
91
92         /* Initialize the global options, if not already done. */
93         if( gopts->ldo_valid != LDAP_INITIALIZED ) {
94                 ldap_int_initialize(gopts, NULL);
95         }
96
97         Debug( LDAP_DEBUG_TRACE, "ldap_create\n", 0, 0, 0 );
98
99 #ifdef HAVE_WINSOCK2
100 {       WORD wVersionRequested;
101         WSADATA wsaData;
102  
103         wVersionRequested = MAKEWORD( 2, 0 );
104         if ( WSAStartup( wVersionRequested, &wsaData ) != 0 ) {
105                 /* Tell the user that we couldn't find a usable */
106                 /* WinSock DLL.                                  */
107                 return LDAP_LOCAL_ERROR;
108         }
109  
110         /* Confirm that the WinSock DLL supports 2.0.*/
111         /* Note that if the DLL supports versions greater    */
112         /* than 2.0 in addition to 2.0, it will still return */
113         /* 2.0 in wVersion since that is the version we      */
114         /* requested.                                        */
115  
116         if ( LOBYTE( wsaData.wVersion ) != 2 ||
117                 HIBYTE( wsaData.wVersion ) != 0 )
118         {
119             /* Tell the user that we couldn't find a usable */
120             /* WinSock DLL.                                  */
121             WSACleanup( );
122             return LDAP_LOCAL_ERROR; 
123         }
124 }       /* The WinSock DLL is acceptable. Proceed. */
125
126 #elif HAVE_WINSOCK
127 {       WSADATA wsaData;
128         if ( WSAStartup( 0x0101, &wsaData ) != 0 ) {
129             return LDAP_LOCAL_ERROR;
130         }
131 }
132 #endif
133
134         if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
135             WSACleanup( );
136                 return( LDAP_NO_MEMORY );
137         }
138    
139         /* copy the global options */
140         AC_MEMCPY(&ld->ld_options, gopts, sizeof(ld->ld_options));
141
142         ld->ld_valid = LDAP_VALID_SESSION;
143
144         /* but not pointers to malloc'ed items */
145         ld->ld_options.ldo_sctrls = NULL;
146         ld->ld_options.ldo_cctrls = NULL;
147
148 #ifdef HAVE_CYRUS_SASL
149         ld->ld_options.ldo_def_sasl_mech = gopts->ldo_def_sasl_mech
150                 ? LDAP_STRDUP( gopts->ldo_def_sasl_mech ) : NULL;
151         ld->ld_options.ldo_def_sasl_realm = gopts->ldo_def_sasl_realm
152                 ? LDAP_STRDUP( gopts->ldo_def_sasl_realm ) : NULL;
153         ld->ld_options.ldo_def_sasl_authcid = gopts->ldo_def_sasl_authcid
154                 ? LDAP_STRDUP( gopts->ldo_def_sasl_authcid ) : NULL;
155         ld->ld_options.ldo_def_sasl_authzid = gopts->ldo_def_sasl_authzid
156                 ? LDAP_STRDUP( gopts->ldo_def_sasl_authzid ) : NULL;
157 #endif
158
159         ld->ld_options.ldo_defludp = ldap_url_duplist(gopts->ldo_defludp);
160
161         if ( ld->ld_options.ldo_defludp == NULL ) {
162                 LDAP_FREE( (char*)ld );
163             WSACleanup( );
164                 return LDAP_NO_MEMORY;
165         }
166
167         if (( ld->ld_selectinfo = ldap_new_select_info()) == NULL ) {
168                 ldap_free_urllist( ld->ld_options.ldo_defludp );
169                 LDAP_FREE( (char*) ld );
170             WSACleanup( );
171                 return LDAP_NO_MEMORY;
172         }
173
174         ld->ld_lberoptions = LBER_USE_DER;
175
176         ld->ld_sb = ber_sockbuf_alloc( );
177         if ( ld->ld_sb == NULL ) {
178                 ldap_free_urllist( ld->ld_options.ldo_defludp );
179                 LDAP_FREE( (char*) ld );
180                 WSACleanup( );
181                 return LDAP_NO_MEMORY;
182         }
183
184         *ldp = ld;
185         return LDAP_SUCCESS;
186 }
187
188 /*
189  * ldap_init - initialize the LDAP library.  A magic cookie to be used for
190  * future communication is returned on success, NULL on failure.
191  * "host" may be a space-separated list of hosts or IP addresses
192  *
193  * Example:
194  *      LDAP    *ld;
195  *      ld = ldap_init( host, port );
196  */
197 LDAP *
198 ldap_init( LDAP_CONST char *defhost, int defport )
199 {
200         LDAP *ld;
201         int rc;
202
203         rc = ldap_create(&ld);
204         if ( rc != LDAP_SUCCESS )
205                 return NULL;
206
207         if (defport != 0)
208                 ld->ld_options.ldo_defport = defport;
209
210         if (defhost != NULL) {
211                 rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, defhost);
212                 if ( rc != LDAP_SUCCESS ) {
213                         ldap_ld_free(ld, 1, NULL, NULL);
214                         return NULL;
215                 }
216         }
217
218         return( ld );
219 }
220
221
222 int
223 ldap_initialize( LDAP **ldp, LDAP_CONST char *url )
224 {
225         int rc;
226         LDAP *ld;
227
228         *ldp = NULL;
229         rc = ldap_create(&ld);
230         if ( rc != LDAP_SUCCESS )
231                 return rc;
232
233         if (url != NULL) {
234                 rc = ldap_set_option(ld, LDAP_OPT_URI, url);
235                 if ( rc != LDAP_SUCCESS ) {
236                         ldap_ld_free(ld, 1, NULL, NULL);
237                         return rc;
238                 }
239 #ifdef LDAP_CONNECTIONLESS
240                 if (ldap_is_ldapc_url(url))
241                         LDAP_IS_UDP(ld) = 1;
242 #endif
243         }
244
245         *ldp = ld;
246         return LDAP_SUCCESS;
247 }
248
249 int
250 ldap_int_open_connection(
251         LDAP *ld,
252         LDAPConn *conn,
253         LDAPURLDesc *srv,
254         int async )
255 {
256         int rc = -1;
257 #ifdef HAVE_CYRUS_SASL
258         char *sasl_host = NULL;
259         int sasl_ssf = 0;
260 #endif
261         char *host;
262         int port, proto;
263         long addr;
264
265         Debug( LDAP_DEBUG_TRACE, "ldap_int_open_connection\n", 0, 0, 0 );
266
267         switch ( proto = ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) {
268                 case LDAP_PROTO_TCP:
269                         port = srv->lud_port;
270
271                         addr = 0;
272                         if ( srv->lud_host == NULL || *srv->lud_host == 0 ) {
273                                 host = NULL;
274                                 addr = htonl( INADDR_LOOPBACK );
275                         } else {
276                                 host = srv->lud_host;
277                         }
278
279                         rc = ldap_connect_to_host( ld, conn->lconn_sb,
280                                 proto, host, addr, port, async );
281
282                         if ( rc == -1 ) return rc;
283
284 #ifdef LDAP_DEBUG
285                         ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
286                                 LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" );
287 #endif
288                         ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp,
289                                 LBER_SBIOD_LEVEL_PROVIDER, NULL );
290
291 #ifdef HAVE_CYRUS_SASL
292                         sasl_host = ldap_host_connected_to( conn->lconn_sb );
293 #endif
294                         break;
295 #ifdef LDAP_CONNECTIONLESS
296                 case LDAP_PROTO_UDP:
297                         port = srv->lud_port;
298
299                         addr = 0;
300                         if ( srv->lud_host == NULL || *srv->lud_host == 0 ) {
301                                 host = NULL;
302                                 addr = htonl( INADDR_LOOPBACK );
303                         } else {
304                                 host = srv->lud_host;
305                         }
306                         LDAP_IS_UDP(ld) = 1;
307                         rc = ldap_connect_to_host( ld, conn->lconn_sb,
308                                 proto, host, addr, port, async );
309
310                         if ( rc == -1 ) return rc;
311 #ifdef LDAP_DEBUG
312                         ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
313                                 LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" );
314 #endif
315                         ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp,
316                                 LBER_SBIOD_LEVEL_PROVIDER, NULL );
317                         break;
318 #endif
319                 case LDAP_PROTO_IPC:
320 #ifdef LDAP_PF_LOCAL
321                         /* only IPC mechanism supported is PF_LOCAL (PF_UNIX) */
322                         rc = ldap_connect_to_path( ld, conn->lconn_sb,
323                                 srv->lud_host, async );
324                         if ( rc == -1 ) return rc;
325 #ifdef LDAP_DEBUG
326                         ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
327                                 LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
328 #endif
329                         ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd,
330                                 LBER_SBIOD_LEVEL_PROVIDER, NULL );
331
332 #ifdef HAVE_CYRUS_SASL
333                         sasl_host = ldap_host_connected_to( conn->lconn_sb );
334                         sasl_ssf = LDAP_PVT_SASL_LOCAL_SSF;
335 #endif
336                         break;
337 #endif /* LDAP_PF_LOCAL */
338                 default:
339                         return -1;
340                         break;
341         }
342
343         ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead,
344                 LBER_SBIOD_LEVEL_PROVIDER, NULL );
345
346 #ifdef LDAP_DEBUG
347         ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
348                 INT_MAX, (void *)"ldap_" );
349 #endif
350
351 #ifdef LDAP_CONNECTIONLESS
352         if( proto == LDAP_PROTO_UDP )
353                 return 0;
354 #endif
355
356 #ifdef HAVE_CYRUS_SASL
357         /* establish Cyrus SASL context prior to starting TLS so
358                 that SASL EXTERNAL might be used */
359         if( sasl_host != NULL ) {
360                 ldap_int_sasl_open( ld, conn, sasl_host, sasl_ssf );
361                 LDAP_FREE( sasl_host );
362         }
363 #endif
364
365 #ifdef HAVE_TLS
366         if (ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
367                 strcmp( srv->lud_scheme, "ldaps" ) == 0 )
368         {
369                 ++conn->lconn_refcnt;   /* avoid premature free */
370
371                 rc = ldap_int_tls_start( ld, conn, srv );
372
373                 --conn->lconn_refcnt;
374
375                 if (rc != LDAP_SUCCESS) {
376                         return -1;
377                 }
378         }
379 #endif
380
381 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
382         if ( conn->lconn_krbinstance == NULL ) {
383                 char *c;
384                 conn->lconn_krbinstance = ldap_host_connected_to( conn->lconn_sb );
385
386                 if( conn->lconn_krbinstance != NULL && 
387                     ( c = strchr( conn->lconn_krbinstance, '.' )) != NULL ) {
388                         *c = '\0';
389                 }
390         }
391 #endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND */
392
393         return( 0 );
394 }
395
396
397 int ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp )
398 {
399         int rc;
400         LDAPConn *c;
401         LDAPRequest *lr;
402
403         rc = ldap_create( ldp );
404         if( rc != LDAP_SUCCESS ) {
405                 *ldp = NULL;
406                 return( rc );
407         }
408
409         /* Make it appear that a search request, msgid 0, was sent */
410         lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ));
411         if( lr == NULL ) {
412                 ldap_unbind( *ldp );
413                 *ldp = NULL;
414                 return( LDAP_NO_MEMORY );
415         }
416         memset(lr, 0, sizeof( LDAPRequest ));
417         lr->lr_msgid = 0;
418         lr->lr_status = LDAP_REQST_INPROGRESS;
419         lr->lr_res_errno = LDAP_SUCCESS;
420         (*ldp)->ld_requests = lr;
421
422         /* Attach the passed socket as the *LDAP's connection */
423         c = ldap_new_connection( *ldp, NULL, 1, 0, NULL);
424         if( c == NULL ) {
425                 ldap_unbind( *ldp );
426                 *ldp = NULL;
427                 return( LDAP_NO_MEMORY );
428         }
429         ber_sockbuf_ctrl( c->lconn_sb, LBER_SB_OPT_SET_FD, fdp );
430 #ifdef LDAP_DEBUG
431         ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_debug,
432                 LBER_SBIOD_LEVEL_PROVIDER, (void *)"int_" );
433 #endif
434         ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_tcp,
435           LBER_SBIOD_LEVEL_PROVIDER, NULL );
436         (*ldp)->ld_defconn = c;
437
438         /* Add the connection to the *LDAP's select pool */
439         ldap_mark_select_read( *ldp, c->lconn_sb );
440         ldap_mark_select_write( *ldp, c->lconn_sb );
441
442         /* Make this connection an LDAP V3 protocol connection */
443         rc = LDAP_VERSION3;
444         ldap_set_option( *ldp, LDAP_OPT_PROTOCOL_VERSION, &rc );
445
446         return( LDAP_SUCCESS );
447 }