2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2005 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
20 #include <ac/stdlib.h>
22 #include <ac/socket.h>
23 #include <ac/string.h>
28 #define LDAP_OPT_REBIND_PROC 0x4e814d
29 #define LDAP_OPT_REBIND_PARAMS 0x4e814e
31 #define LDAP_OPT_NEXTREF_PROC 0x4e815d
32 #define LDAP_OPT_NEXTREF_PARAMS 0x4e815e
34 static const LDAPAPIFeatureInfo features[] = {
35 #ifdef LDAP_API_FEATURE_X_OPENLDAP
36 { /* OpenLDAP Extensions API Feature */
37 LDAP_FEATURE_INFO_VERSION,
39 LDAP_API_FEATURE_X_OPENLDAP
43 #ifdef LDAP_API_FEATURE_THREAD_SAFE
44 { /* Basic Thread Safe */
45 LDAP_FEATURE_INFO_VERSION,
47 LDAP_API_FEATURE_THREAD_SAFE
50 #ifdef LDAP_API_FEATURE_SESSION_THREAD_SAFE
51 { /* Session Thread Safe */
52 LDAP_FEATURE_INFO_VERSION,
53 "SESSION_THREAD_SAFE",
54 LDAP_API_FEATURE_SESSION_THREAD_SAFE
57 #ifdef LDAP_API_FEATURE_OPERATION_THREAD_SAFE
58 { /* Operation Thread Safe */
59 LDAP_FEATURE_INFO_VERSION,
60 "OPERATION_THREAD_SAFE",
61 LDAP_API_FEATURE_OPERATION_THREAD_SAFE
64 #ifdef LDAP_API_FEATURE_X_OPENLDAP_REENTRANT
65 { /* OpenLDAP Reentrant */
66 LDAP_FEATURE_INFO_VERSION,
67 "X_OPENLDAP_REENTRANT",
68 LDAP_API_FEATURE_X_OPENLDAP_REENTRANT
71 #if defined( LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE ) && \
72 defined( LDAP_THREAD_SAFE )
73 { /* OpenLDAP Thread Safe */
74 LDAP_FEATURE_INFO_VERSION,
75 "X_OPENLDAP_THREAD_SAFE",
76 LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE
79 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
81 LDAP_FEATURE_INFO_VERSION,
82 "X_OPENLDAP_V2_REFERRALS",
83 LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
95 struct ldapoptions *lo;
97 /* Get pointer to global option structure */
98 lo = LDAP_INT_GLOBAL_OPT();
100 return LDAP_NO_MEMORY;
103 if( lo->ldo_valid != LDAP_INITIALIZED ) {
104 ldap_int_initialize(lo, NULL);
108 assert( LDAP_VALID( ld ) );
110 if( !LDAP_VALID( ld ) ) {
111 return LDAP_OPT_ERROR;
114 lo = &ld->ld_options;
117 if(outvalue == NULL) {
118 /* no place to get to */
119 return LDAP_OPT_ERROR;
123 case LDAP_OPT_API_INFO: {
124 struct ldapapiinfo *info = (struct ldapapiinfo *) outvalue;
127 /* outvalue must point to an apiinfo structure */
128 return LDAP_OPT_ERROR;
131 if(info->ldapai_info_version != LDAP_API_INFO_VERSION) {
132 /* api info version mismatch */
133 info->ldapai_info_version = LDAP_API_INFO_VERSION;
134 return LDAP_OPT_ERROR;
137 info->ldapai_api_version = LDAP_API_VERSION;
138 info->ldapai_protocol_version = LDAP_VERSION_MAX;
140 if(features[0].ldapaif_name == NULL) {
141 info->ldapai_extensions = NULL;
144 info->ldapai_extensions = LDAP_MALLOC(sizeof(char *) *
145 sizeof(features)/sizeof(LDAPAPIFeatureInfo));
147 for(i=0; features[i].ldapaif_name != NULL; i++) {
148 info->ldapai_extensions[i] =
149 LDAP_STRDUP(features[i].ldapaif_name);
152 info->ldapai_extensions[i] = NULL;
155 info->ldapai_vendor_name = LDAP_STRDUP(LDAP_VENDOR_NAME);
156 info->ldapai_vendor_version = LDAP_VENDOR_VERSION;
158 return LDAP_OPT_SUCCESS;
162 if( ld == NULL || ld->ld_sb == NULL ) {
167 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, outvalue );
168 return LDAP_OPT_SUCCESS;
170 case LDAP_OPT_SOCKBUF:
171 if( ld == NULL ) break;
172 *(Sockbuf **)outvalue = ld->ld_sb;
173 return LDAP_OPT_SUCCESS;
175 case LDAP_OPT_TIMEOUT:
176 /* the caller has to free outvalue ! */
177 if ( ldap_int_timeval_dup( outvalue, lo->ldo_tm_api) != 0 ) {
178 return LDAP_OPT_ERROR;
180 return LDAP_OPT_SUCCESS;
182 case LDAP_OPT_NETWORK_TIMEOUT:
183 /* the caller has to free outvalue ! */
184 if ( ldap_int_timeval_dup( outvalue, lo->ldo_tm_net ) != 0 ) {
185 return LDAP_OPT_ERROR;
187 return LDAP_OPT_SUCCESS;
190 * (int *) outvalue = lo->ldo_deref;
191 return LDAP_OPT_SUCCESS;
193 case LDAP_OPT_SIZELIMIT:
194 * (int *) outvalue = lo->ldo_sizelimit;
195 return LDAP_OPT_SUCCESS;
197 case LDAP_OPT_TIMELIMIT:
198 * (int *) outvalue = lo->ldo_timelimit;
199 return LDAP_OPT_SUCCESS;
201 case LDAP_OPT_REFERRALS:
202 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_REFERRALS);
203 return LDAP_OPT_SUCCESS;
205 case LDAP_OPT_RESTART:
206 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_RESTART);
207 return LDAP_OPT_SUCCESS;
209 case LDAP_OPT_PROTOCOL_VERSION:
210 * (int *) outvalue = lo->ldo_version;
211 return LDAP_OPT_SUCCESS;
213 case LDAP_OPT_SERVER_CONTROLS:
214 * (LDAPControl ***) outvalue =
215 ldap_controls_dup( lo->ldo_sctrls );
217 return LDAP_OPT_SUCCESS;
219 case LDAP_OPT_CLIENT_CONTROLS:
220 * (LDAPControl ***) outvalue =
221 ldap_controls_dup( lo->ldo_cctrls );
223 return LDAP_OPT_SUCCESS;
225 case LDAP_OPT_HOST_NAME:
226 * (char **) outvalue = ldap_url_list2hosts(lo->ldo_defludp);
227 return LDAP_OPT_SUCCESS;
230 * (char **) outvalue = ldap_url_list2urls(lo->ldo_defludp);
231 return LDAP_OPT_SUCCESS;
233 case LDAP_OPT_ERROR_NUMBER:
238 * (int *) outvalue = ld->ld_errno;
239 return LDAP_OPT_SUCCESS;
241 case LDAP_OPT_ERROR_STRING:
247 if( ld->ld_error == NULL ) {
248 * (char **) outvalue = NULL;
250 * (char **) outvalue = LDAP_STRDUP(ld->ld_error);
253 return LDAP_OPT_SUCCESS;
255 case LDAP_OPT_MATCHED_DN:
261 if( ld->ld_matched == NULL ) {
262 * (char **) outvalue = NULL;
264 * (char **) outvalue = LDAP_STRDUP(ld->ld_matched);
267 return LDAP_OPT_SUCCESS;
269 case LDAP_OPT_REFERRAL_URLS:
275 if( ld->ld_referrals == NULL ) {
276 * (char ***) outvalue = NULL;
278 * (char ***) outvalue = ldap_value_dup(ld->ld_referrals);
281 return LDAP_OPT_SUCCESS;
283 case LDAP_OPT_API_FEATURE_INFO: {
284 LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue;
287 if(info == NULL) return LDAP_OPT_ERROR;
289 if(info->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) {
290 /* api info version mismatch */
291 info->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
292 return LDAP_OPT_ERROR;
295 if(info->ldapaif_name == NULL) return LDAP_OPT_ERROR;
297 for(i=0; features[i].ldapaif_name != NULL; i++) {
298 if(!strcmp(info->ldapaif_name, features[i].ldapaif_name)) {
299 info->ldapaif_version =
300 features[i].ldapaif_version;
301 return LDAP_OPT_SUCCESS;
307 case LDAP_OPT_DEBUG_LEVEL:
308 * (int *) outvalue = lo->ldo_debug;
309 return LDAP_OPT_SUCCESS;
313 if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
314 return LDAP_OPT_SUCCESS;
317 #ifdef HAVE_CYRUS_SASL
318 if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
319 return LDAP_OPT_SUCCESS;
326 return LDAP_OPT_ERROR;
333 LDAP_CONST void *invalue)
335 struct ldapoptions *lo;
338 /* Get pointer to global option structure */
339 lo = LDAP_INT_GLOBAL_OPT();
341 return LDAP_NO_MEMORY;
345 * The architecture to turn on debugging has a chicken and egg
346 * problem. Thus, we introduce a fix here.
349 if (option == LDAP_OPT_DEBUG_LEVEL) {
350 dbglvl = (int *) invalue;
353 if( lo->ldo_valid != LDAP_INITIALIZED ) {
354 ldap_int_initialize(lo, dbglvl);
358 assert( LDAP_VALID( ld ) );
360 if( !LDAP_VALID( ld ) ) {
361 return LDAP_OPT_ERROR;
364 lo = &ld->ld_options;
368 case LDAP_OPT_REFERRALS:
369 if(invalue == LDAP_OPT_OFF) {
370 LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS);
372 LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS);
374 return LDAP_OPT_SUCCESS;
376 case LDAP_OPT_RESTART:
377 if(invalue == LDAP_OPT_OFF) {
378 LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART);
380 LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
382 return LDAP_OPT_SUCCESS;
385 /* options which can withstand invalue == NULL */
387 case LDAP_OPT_SERVER_CONTROLS: {
388 LDAPControl *const *controls =
389 (LDAPControl *const *) invalue;
391 ldap_controls_free( lo->ldo_sctrls );
393 if( controls == NULL || *controls == NULL ) {
394 lo->ldo_sctrls = NULL;
395 return LDAP_OPT_SUCCESS;
398 lo->ldo_sctrls = ldap_controls_dup( controls );
400 if(lo->ldo_sctrls == NULL) {
401 /* memory allocation error ? */
404 } return LDAP_OPT_SUCCESS;
406 case LDAP_OPT_CLIENT_CONTROLS: {
407 LDAPControl *const *controls =
408 (LDAPControl *const *) invalue;
410 ldap_controls_free( lo->ldo_cctrls );
412 if( controls == NULL || *controls == NULL ) {
413 lo->ldo_cctrls = NULL;
414 return LDAP_OPT_SUCCESS;
417 lo->ldo_cctrls = ldap_controls_dup( controls );
419 if(lo->ldo_cctrls == NULL) {
420 /* memory allocation error ? */
423 } return LDAP_OPT_SUCCESS;
425 case LDAP_OPT_TIMEOUT: {
426 const struct timeval *tv =
427 (const struct timeval *) invalue;
429 if ( lo->ldo_tm_api != NULL ) {
430 LDAP_FREE( lo->ldo_tm_api );
431 lo->ldo_tm_api = NULL;
434 if ( ldap_int_timeval_dup( &lo->ldo_tm_api, tv ) != 0 ) {
435 return LDAP_OPT_ERROR;
437 } return LDAP_OPT_SUCCESS;
439 case LDAP_OPT_NETWORK_TIMEOUT: {
440 const struct timeval *tv =
441 (const struct timeval *) invalue;
443 if ( lo->ldo_tm_net != NULL ) {
444 LDAP_FREE( lo->ldo_tm_net );
445 lo->ldo_tm_net = NULL;
448 if ( ldap_int_timeval_dup( &lo->ldo_tm_net, tv ) != 0 ) {
449 return LDAP_OPT_ERROR;
451 } return LDAP_OPT_SUCCESS;
453 /* Only accessed from inside this function by ldap_set_rebind_proc() */
454 case LDAP_OPT_REBIND_PROC: {
455 lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue;
456 } return LDAP_OPT_SUCCESS;
457 case LDAP_OPT_REBIND_PARAMS: {
458 lo->ldo_rebind_params = (void *)invalue;
459 } return LDAP_OPT_SUCCESS;
461 /* Only accessed from inside this function by ldap_set_nextref_proc() */
462 case LDAP_OPT_NEXTREF_PROC: {
463 lo->ldo_nextref_proc = (LDAP_NEXTREF_PROC *)invalue;
464 } return LDAP_OPT_SUCCESS;
465 case LDAP_OPT_NEXTREF_PARAMS: {
466 lo->ldo_nextref_params = (void *)invalue;
467 } return LDAP_OPT_SUCCESS;
470 if(invalue == NULL) {
471 /* no place to set from */
472 return LDAP_OPT_ERROR;
475 /* options which cannot withstand invalue == NULL */
478 case LDAP_OPT_API_INFO:
484 lo->ldo_deref = * (const int *) invalue;
485 return LDAP_OPT_SUCCESS;
487 case LDAP_OPT_SIZELIMIT:
488 lo->ldo_sizelimit = * (const int *) invalue;
489 return LDAP_OPT_SUCCESS;
491 case LDAP_OPT_TIMELIMIT:
492 lo->ldo_timelimit = * (const int *) invalue;
493 return LDAP_OPT_SUCCESS;
495 case LDAP_OPT_PROTOCOL_VERSION: {
496 int vers = * (const int *) invalue;
497 if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) {
501 lo->ldo_version = vers;
502 } return LDAP_OPT_SUCCESS;
505 case LDAP_OPT_HOST_NAME: {
506 const char *host = (const char *) invalue;
507 LDAPURLDesc *ludlist = NULL;
508 int rc = LDAP_OPT_SUCCESS;
511 rc = ldap_url_parsehosts( &ludlist, host,
512 lo->ldo_defport ? lo->ldo_defport : LDAP_PORT );
514 } else if(ld == NULL) {
516 * must want global default returned
517 * to initial condition.
519 rc = ldap_url_parselist(&ludlist, "ldap://localhost/");
523 * must want the session default
524 * updated to the current global default
526 ludlist = ldap_url_duplist(
527 ldap_int_global_options.ldo_defludp);
532 if (rc == LDAP_OPT_SUCCESS) {
533 if (lo->ldo_defludp != NULL)
534 ldap_free_urllist(lo->ldo_defludp);
535 lo->ldo_defludp = ludlist;
541 const char *urls = (const char *) invalue;
542 LDAPURLDesc *ludlist = NULL;
543 int rc = LDAP_OPT_SUCCESS;
546 rc = ldap_url_parselist(&ludlist, urls);
547 } else if(ld == NULL) {
549 * must want global default returned
550 * to initial condition.
552 rc = ldap_url_parselist(&ludlist, "ldap://localhost/");
556 * must want the session default
557 * updated to the current global default
559 ludlist = ldap_url_duplist(
560 ldap_int_global_options.ldo_defludp);
566 case LDAP_URL_SUCCESS: /* Success */
570 case LDAP_URL_ERR_MEM: /* can't allocate memory space */
574 case LDAP_URL_ERR_PARAM: /* parameter is bad */
575 case LDAP_URL_ERR_BADSCHEME: /* URL doesn't begin with "ldap[si]://" */
576 case LDAP_URL_ERR_BADENCLOSURE: /* URL is missing trailing ">" */
577 case LDAP_URL_ERR_BADURL: /* URL is bad */
578 case LDAP_URL_ERR_BADHOST: /* host port is bad */
579 case LDAP_URL_ERR_BADATTRS: /* bad (or missing) attributes */
580 case LDAP_URL_ERR_BADSCOPE: /* scope string is invalid (or missing) */
581 case LDAP_URL_ERR_BADFILTER: /* bad or missing filter */
582 case LDAP_URL_ERR_BADEXTS: /* bad or missing extensions */
583 rc = LDAP_PARAM_ERROR;
587 if (rc == LDAP_OPT_SUCCESS) {
588 if (lo->ldo_defludp != NULL)
589 ldap_free_urllist(lo->ldo_defludp);
590 lo->ldo_defludp = ludlist;
595 case LDAP_OPT_ERROR_NUMBER: {
596 int err = * (const int *) invalue;
599 /* need a struct ldap */
604 } return LDAP_OPT_SUCCESS;
606 case LDAP_OPT_ERROR_STRING: {
607 const char *err = (const char *) invalue;
610 /* need a struct ldap */
615 LDAP_FREE(ld->ld_error);
618 ld->ld_error = LDAP_STRDUP(err);
619 } return LDAP_OPT_SUCCESS;
621 case LDAP_OPT_MATCHED_DN: {
622 const char *err = (const char *) invalue;
625 /* need a struct ldap */
629 if( ld->ld_matched ) {
630 LDAP_FREE(ld->ld_matched);
633 ld->ld_matched = LDAP_STRDUP(err);
634 } return LDAP_OPT_SUCCESS;
636 case LDAP_OPT_REFERRAL_URLS: {
637 char *const *referrals = (char *const *) invalue;
640 /* need a struct ldap */
644 if( ld->ld_referrals ) {
645 LDAP_VFREE(ld->ld_referrals);
648 ld->ld_referrals = ldap_value_dup(referrals);
649 } return LDAP_OPT_SUCCESS;
651 case LDAP_OPT_API_FEATURE_INFO:
655 case LDAP_OPT_DEBUG_LEVEL:
656 lo->ldo_debug = * (const int *) invalue;
657 return LDAP_OPT_SUCCESS;
661 if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 )
662 return LDAP_OPT_SUCCESS;
664 #ifdef HAVE_CYRUS_SASL
665 if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 )
666 return LDAP_OPT_SUCCESS;
671 return LDAP_OPT_ERROR;
675 ldap_set_rebind_proc( LDAP *ld, LDAP_REBIND_PROC *proc, void *params )
678 rc = ldap_set_option( ld, LDAP_OPT_REBIND_PROC, (void *)proc );
679 if( rc != LDAP_OPT_SUCCESS ) return rc;
681 rc = ldap_set_option( ld, LDAP_OPT_REBIND_PARAMS, (void *)params );
686 ldap_set_nextref_proc( LDAP *ld, LDAP_NEXTREF_PROC *proc, void *params )
689 rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PROC, (void *)proc );
690 if( rc != LDAP_OPT_SUCCESS ) return rc;
692 rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PARAMS, (void *)params );