2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2007 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 #define LDAP_OPT_URLLIST_PROC 0x4e816d
35 #define LDAP_OPT_URLLIST_PARAMS 0x4e816e
37 static const LDAPAPIFeatureInfo features[] = {
38 #ifdef LDAP_API_FEATURE_X_OPENLDAP
39 { /* OpenLDAP Extensions API Feature */
40 LDAP_FEATURE_INFO_VERSION,
42 LDAP_API_FEATURE_X_OPENLDAP
46 #ifdef LDAP_API_FEATURE_THREAD_SAFE
47 { /* Basic Thread Safe */
48 LDAP_FEATURE_INFO_VERSION,
50 LDAP_API_FEATURE_THREAD_SAFE
53 #ifdef LDAP_API_FEATURE_SESSION_THREAD_SAFE
54 { /* Session Thread Safe */
55 LDAP_FEATURE_INFO_VERSION,
56 "SESSION_THREAD_SAFE",
57 LDAP_API_FEATURE_SESSION_THREAD_SAFE
60 #ifdef LDAP_API_FEATURE_OPERATION_THREAD_SAFE
61 { /* Operation Thread Safe */
62 LDAP_FEATURE_INFO_VERSION,
63 "OPERATION_THREAD_SAFE",
64 LDAP_API_FEATURE_OPERATION_THREAD_SAFE
67 #ifdef LDAP_API_FEATURE_X_OPENLDAP_REENTRANT
68 { /* OpenLDAP Reentrant */
69 LDAP_FEATURE_INFO_VERSION,
70 "X_OPENLDAP_REENTRANT",
71 LDAP_API_FEATURE_X_OPENLDAP_REENTRANT
74 #if defined( LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE ) && \
75 defined( LDAP_THREAD_SAFE )
76 { /* OpenLDAP Thread Safe */
77 LDAP_FEATURE_INFO_VERSION,
78 "X_OPENLDAP_THREAD_SAFE",
79 LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE
82 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
84 LDAP_FEATURE_INFO_VERSION,
85 "X_OPENLDAP_V2_REFERRALS",
86 LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
98 struct ldapoptions *lo;
100 /* Get pointer to global option structure */
101 lo = LDAP_INT_GLOBAL_OPT();
103 return LDAP_NO_MEMORY;
106 if( lo->ldo_valid != LDAP_INITIALIZED ) {
107 ldap_int_initialize(lo, NULL);
111 assert( LDAP_VALID( ld ) );
113 if( !LDAP_VALID( ld ) ) {
114 return LDAP_OPT_ERROR;
117 lo = &ld->ld_options;
120 if(outvalue == NULL) {
121 /* no place to get to */
122 return LDAP_OPT_ERROR;
126 case LDAP_OPT_API_INFO: {
127 struct ldapapiinfo *info = (struct ldapapiinfo *) outvalue;
130 /* outvalue must point to an apiinfo structure */
131 return LDAP_OPT_ERROR;
134 if(info->ldapai_info_version != LDAP_API_INFO_VERSION) {
135 /* api info version mismatch */
136 info->ldapai_info_version = LDAP_API_INFO_VERSION;
137 return LDAP_OPT_ERROR;
140 info->ldapai_api_version = LDAP_API_VERSION;
141 info->ldapai_protocol_version = LDAP_VERSION_MAX;
143 if(features[0].ldapaif_name == NULL) {
144 info->ldapai_extensions = NULL;
147 info->ldapai_extensions = LDAP_MALLOC(sizeof(char *) *
148 sizeof(features)/sizeof(LDAPAPIFeatureInfo));
150 for(i=0; features[i].ldapaif_name != NULL; i++) {
151 info->ldapai_extensions[i] =
152 LDAP_STRDUP(features[i].ldapaif_name);
155 info->ldapai_extensions[i] = NULL;
158 info->ldapai_vendor_name = LDAP_STRDUP(LDAP_VENDOR_NAME);
159 info->ldapai_vendor_version = LDAP_VENDOR_VERSION;
161 return LDAP_OPT_SUCCESS;
165 if( ld == NULL || ld->ld_sb == NULL ) {
170 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, outvalue );
171 return LDAP_OPT_SUCCESS;
173 case LDAP_OPT_SOCKBUF:
174 if( ld == NULL ) break;
175 *(Sockbuf **)outvalue = ld->ld_sb;
176 return LDAP_OPT_SUCCESS;
178 case LDAP_OPT_TIMEOUT:
179 *(struct timeval *) outvalue = lo->ldo_tm_api;
180 return LDAP_OPT_SUCCESS;
182 case LDAP_OPT_NETWORK_TIMEOUT:
183 *(struct timeval *) outvalue = lo->ldo_tm_net;
184 return LDAP_OPT_SUCCESS;
187 * (int *) outvalue = lo->ldo_deref;
188 return LDAP_OPT_SUCCESS;
190 case LDAP_OPT_SIZELIMIT:
191 * (int *) outvalue = lo->ldo_sizelimit;
192 return LDAP_OPT_SUCCESS;
194 case LDAP_OPT_TIMELIMIT:
195 * (int *) outvalue = lo->ldo_timelimit;
196 return LDAP_OPT_SUCCESS;
198 case LDAP_OPT_REFERRALS:
199 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_REFERRALS);
200 return LDAP_OPT_SUCCESS;
202 case LDAP_OPT_RESTART:
203 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_RESTART);
204 return LDAP_OPT_SUCCESS;
206 case LDAP_OPT_PROTOCOL_VERSION:
207 * (int *) outvalue = lo->ldo_version;
208 return LDAP_OPT_SUCCESS;
210 case LDAP_OPT_SERVER_CONTROLS:
211 * (LDAPControl ***) outvalue =
212 ldap_controls_dup( lo->ldo_sctrls );
214 return LDAP_OPT_SUCCESS;
216 case LDAP_OPT_CLIENT_CONTROLS:
217 * (LDAPControl ***) outvalue =
218 ldap_controls_dup( lo->ldo_cctrls );
220 return LDAP_OPT_SUCCESS;
222 case LDAP_OPT_HOST_NAME:
223 * (char **) outvalue = ldap_url_list2hosts(lo->ldo_defludp);
224 return LDAP_OPT_SUCCESS;
227 * (char **) outvalue = ldap_url_list2urls(lo->ldo_defludp);
228 return LDAP_OPT_SUCCESS;
230 case LDAP_OPT_DEFBASE:
231 if( lo->ldo_defbase == NULL ) {
232 * (char **) outvalue = NULL;
234 * (char **) outvalue = LDAP_STRDUP(lo->ldo_defbase);
237 return LDAP_OPT_SUCCESS;
239 case LDAP_OPT_CONNECT_ASYNC:
240 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_CONNECT_ASYNC);
241 return LDAP_OPT_SUCCESS;
243 case LDAP_OPT_RESULT_CODE:
248 * (int *) outvalue = ld->ld_errno;
249 return LDAP_OPT_SUCCESS;
251 case LDAP_OPT_DIAGNOSTIC_MESSAGE:
257 if( ld->ld_error == NULL ) {
258 * (char **) outvalue = NULL;
260 * (char **) outvalue = LDAP_STRDUP(ld->ld_error);
263 return LDAP_OPT_SUCCESS;
265 case LDAP_OPT_MATCHED_DN:
271 if( ld->ld_matched == NULL ) {
272 * (char **) outvalue = NULL;
274 * (char **) outvalue = LDAP_STRDUP( ld->ld_matched );
277 return LDAP_OPT_SUCCESS;
279 case LDAP_OPT_REFERRAL_URLS:
285 if( ld->ld_referrals == NULL ) {
286 * (char ***) outvalue = NULL;
288 * (char ***) outvalue = ldap_value_dup(ld->ld_referrals);
291 return LDAP_OPT_SUCCESS;
293 case LDAP_OPT_API_FEATURE_INFO: {
294 LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue;
297 if(info == NULL) return LDAP_OPT_ERROR;
299 if(info->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) {
300 /* api info version mismatch */
301 info->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
302 return LDAP_OPT_ERROR;
305 if(info->ldapaif_name == NULL) return LDAP_OPT_ERROR;
307 for(i=0; features[i].ldapaif_name != NULL; i++) {
308 if(!strcmp(info->ldapaif_name, features[i].ldapaif_name)) {
309 info->ldapaif_version =
310 features[i].ldapaif_version;
311 return LDAP_OPT_SUCCESS;
317 case LDAP_OPT_DEBUG_LEVEL:
318 * (int *) outvalue = lo->ldo_debug;
319 return LDAP_OPT_SUCCESS;
323 if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
324 return LDAP_OPT_SUCCESS;
327 #ifdef HAVE_CYRUS_SASL
328 if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
329 return LDAP_OPT_SUCCESS;
336 return LDAP_OPT_ERROR;
343 LDAP_CONST void *invalue)
345 struct ldapoptions *lo;
348 /* Get pointer to global option structure */
349 lo = LDAP_INT_GLOBAL_OPT();
351 return LDAP_NO_MEMORY;
355 * The architecture to turn on debugging has a chicken and egg
356 * problem. Thus, we introduce a fix here.
359 if (option == LDAP_OPT_DEBUG_LEVEL) {
360 dbglvl = (int *) invalue;
363 if( lo->ldo_valid != LDAP_INITIALIZED ) {
364 ldap_int_initialize(lo, dbglvl);
368 assert( LDAP_VALID( ld ) );
370 if( !LDAP_VALID( ld ) ) {
371 return LDAP_OPT_ERROR;
374 lo = &ld->ld_options;
378 case LDAP_OPT_REFERRALS:
379 if(invalue == LDAP_OPT_OFF) {
380 LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS);
382 LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS);
384 return LDAP_OPT_SUCCESS;
386 case LDAP_OPT_RESTART:
387 if(invalue == LDAP_OPT_OFF) {
388 LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART);
390 LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
392 return LDAP_OPT_SUCCESS;
394 case LDAP_OPT_CONNECT_ASYNC:
395 if(invalue == LDAP_OPT_OFF) {
396 LDAP_BOOL_CLR(lo, LDAP_BOOL_CONNECT_ASYNC);
398 LDAP_BOOL_SET(lo, LDAP_BOOL_CONNECT_ASYNC);
400 return LDAP_OPT_SUCCESS;
403 /* options which can withstand invalue == NULL */
405 case LDAP_OPT_SERVER_CONTROLS: {
406 LDAPControl *const *controls =
407 (LDAPControl *const *) invalue;
410 ldap_controls_free( lo->ldo_sctrls );
412 if( controls == NULL || *controls == NULL ) {
413 lo->ldo_sctrls = NULL;
414 return LDAP_OPT_SUCCESS;
417 lo->ldo_sctrls = ldap_controls_dup( controls );
419 if(lo->ldo_sctrls == NULL) {
420 /* memory allocation error ? */
423 } return LDAP_OPT_SUCCESS;
425 case LDAP_OPT_CLIENT_CONTROLS: {
426 LDAPControl *const *controls =
427 (LDAPControl *const *) invalue;
430 ldap_controls_free( lo->ldo_cctrls );
432 if( controls == NULL || *controls == NULL ) {
433 lo->ldo_cctrls = NULL;
434 return LDAP_OPT_SUCCESS;
437 lo->ldo_cctrls = ldap_controls_dup( controls );
439 if(lo->ldo_cctrls == NULL) {
440 /* memory allocation error ? */
443 } return LDAP_OPT_SUCCESS;
446 case LDAP_OPT_HOST_NAME: {
447 const char *host = (const char *) invalue;
448 LDAPURLDesc *ludlist = NULL;
449 int rc = LDAP_OPT_SUCCESS;
452 rc = ldap_url_parsehosts( &ludlist, host,
453 lo->ldo_defport ? lo->ldo_defport : LDAP_PORT );
455 } else if(ld == NULL) {
457 * must want global default returned
458 * to initial condition.
460 rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL,
461 LDAP_PVT_URL_PARSE_NOEMPTY_HOST
462 | LDAP_PVT_URL_PARSE_DEF_PORT );
466 * must want the session default
467 * updated to the current global default
469 ludlist = ldap_url_duplist(
470 ldap_int_global_options.ldo_defludp);
475 if (rc == LDAP_OPT_SUCCESS) {
476 if (lo->ldo_defludp != NULL)
477 ldap_free_urllist(lo->ldo_defludp);
478 lo->ldo_defludp = ludlist;
484 const char *urls = (const char *) invalue;
485 LDAPURLDesc *ludlist = NULL;
486 int rc = LDAP_OPT_SUCCESS;
489 rc = ldap_url_parselist_ext(&ludlist, urls, NULL,
490 LDAP_PVT_URL_PARSE_NOEMPTY_HOST
491 | LDAP_PVT_URL_PARSE_DEF_PORT );
492 } else if(ld == NULL) {
494 * must want global default returned
495 * to initial condition.
497 rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL,
498 LDAP_PVT_URL_PARSE_NOEMPTY_HOST
499 | LDAP_PVT_URL_PARSE_DEF_PORT );
503 * must want the session default
504 * updated to the current global default
506 ludlist = ldap_url_duplist(
507 ldap_int_global_options.ldo_defludp);
509 rc = LDAP_URL_ERR_MEM;
513 case LDAP_URL_SUCCESS: /* Success */
517 case LDAP_URL_ERR_MEM: /* can't allocate memory space */
521 case LDAP_URL_ERR_PARAM: /* parameter is bad */
522 case LDAP_URL_ERR_BADSCHEME: /* URL doesn't begin with "ldap[si]://" */
523 case LDAP_URL_ERR_BADENCLOSURE: /* URL is missing trailing ">" */
524 case LDAP_URL_ERR_BADURL: /* URL is bad */
525 case LDAP_URL_ERR_BADHOST: /* host port is bad */
526 case LDAP_URL_ERR_BADATTRS: /* bad (or missing) attributes */
527 case LDAP_URL_ERR_BADSCOPE: /* scope string is invalid (or missing) */
528 case LDAP_URL_ERR_BADFILTER: /* bad or missing filter */
529 case LDAP_URL_ERR_BADEXTS: /* bad or missing extensions */
530 rc = LDAP_PARAM_ERROR;
534 if (rc == LDAP_SUCCESS) {
535 if (lo->ldo_defludp != NULL)
536 ldap_free_urllist(lo->ldo_defludp);
537 lo->ldo_defludp = ludlist;
542 case LDAP_OPT_DEFBASE: {
543 const char *newbase = (const char *) invalue;
544 char *defbase = NULL;
546 if ( newbase != NULL ) {
547 defbase = LDAP_STRDUP( newbase );
548 if ( defbase == NULL ) return LDAP_NO_MEMORY;
550 } else if ( ld != NULL ) {
551 defbase = LDAP_STRDUP( ldap_int_global_options.ldo_defbase );
552 if ( defbase == NULL ) return LDAP_NO_MEMORY;
555 if ( lo->ldo_defbase != NULL )
556 LDAP_FREE( lo->ldo_defbase );
557 lo->ldo_defbase = defbase;
558 } return LDAP_OPT_SUCCESS;
560 case LDAP_OPT_DIAGNOSTIC_MESSAGE: {
561 const char *err = (const char *) invalue;
564 /* need a struct ldap */
565 return LDAP_OPT_ERROR;
569 LDAP_FREE(ld->ld_error);
574 ld->ld_error = LDAP_STRDUP(err);
576 } return LDAP_OPT_SUCCESS;
578 case LDAP_OPT_MATCHED_DN: {
579 const char *matched = (const char *) invalue;
582 /* need a struct ldap */
583 return LDAP_OPT_ERROR;
586 if( ld->ld_matched ) {
587 LDAP_FREE(ld->ld_matched);
588 ld->ld_matched = NULL;
592 ld->ld_matched = LDAP_STRDUP( matched );
594 } return LDAP_OPT_SUCCESS;
596 case LDAP_OPT_REFERRAL_URLS: {
597 char *const *referrals = (char *const *) invalue;
600 /* need a struct ldap */
601 return LDAP_OPT_ERROR;
604 if( ld->ld_referrals ) {
605 LDAP_VFREE(ld->ld_referrals);
609 ld->ld_referrals = ldap_value_dup(referrals);
611 } return LDAP_OPT_SUCCESS;
613 /* Only accessed from inside this function by ldap_set_rebind_proc() */
614 case LDAP_OPT_REBIND_PROC: {
615 lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue;
616 } return LDAP_OPT_SUCCESS;
617 case LDAP_OPT_REBIND_PARAMS: {
618 lo->ldo_rebind_params = (void *)invalue;
619 } return LDAP_OPT_SUCCESS;
621 /* Only accessed from inside this function by ldap_set_nextref_proc() */
622 case LDAP_OPT_NEXTREF_PROC: {
623 lo->ldo_nextref_proc = (LDAP_NEXTREF_PROC *)invalue;
624 } return LDAP_OPT_SUCCESS;
625 case LDAP_OPT_NEXTREF_PARAMS: {
626 lo->ldo_nextref_params = (void *)invalue;
627 } return LDAP_OPT_SUCCESS;
629 /* Only accessed from inside this function by ldap_set_urllist_proc() */
630 case LDAP_OPT_URLLIST_PROC: {
631 lo->ldo_urllist_proc = (LDAP_URLLIST_PROC *)invalue;
632 } return LDAP_OPT_SUCCESS;
633 case LDAP_OPT_URLLIST_PARAMS: {
634 lo->ldo_urllist_params = (void *)invalue;
635 } return LDAP_OPT_SUCCESS;
637 /* read-only options */
638 case LDAP_OPT_API_INFO:
640 case LDAP_OPT_SOCKBUF:
641 case LDAP_OPT_API_FEATURE_INFO:
642 return LDAP_OPT_ERROR;
644 /* options which cannot withstand invalue == NULL */
646 case LDAP_OPT_SIZELIMIT:
647 case LDAP_OPT_TIMELIMIT:
648 case LDAP_OPT_PROTOCOL_VERSION:
649 case LDAP_OPT_RESULT_CODE:
650 case LDAP_OPT_DEBUG_LEVEL:
651 case LDAP_OPT_TIMEOUT:
652 case LDAP_OPT_NETWORK_TIMEOUT:
653 if(invalue == NULL) {
654 /* no place to set from */
655 return LDAP_OPT_ERROR;
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;
669 return LDAP_OPT_ERROR;
672 /* options which cannot withstand invalue == NULL */
676 /* FIXME: check value for protocol compliance? */
677 lo->ldo_deref = * (const int *) invalue;
678 return LDAP_OPT_SUCCESS;
680 case LDAP_OPT_SIZELIMIT:
681 /* FIXME: check value for protocol compliance? */
682 lo->ldo_sizelimit = * (const int *) invalue;
683 return LDAP_OPT_SUCCESS;
685 case LDAP_OPT_TIMELIMIT:
686 /* FIXME: check value for protocol compliance? */
687 lo->ldo_timelimit = * (const int *) invalue;
688 return LDAP_OPT_SUCCESS;
690 case LDAP_OPT_TIMEOUT: {
691 const struct timeval *tv =
692 (const struct timeval *) invalue;
694 lo->ldo_tm_api = *tv;
695 } return LDAP_OPT_SUCCESS;
697 case LDAP_OPT_NETWORK_TIMEOUT: {
698 const struct timeval *tv =
699 (const struct timeval *) invalue;
701 lo->ldo_tm_net = *tv;
702 } return LDAP_OPT_SUCCESS;
704 case LDAP_OPT_PROTOCOL_VERSION: {
705 int vers = * (const int *) invalue;
706 if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) {
710 lo->ldo_version = vers;
711 } return LDAP_OPT_SUCCESS;
713 case LDAP_OPT_RESULT_CODE: {
714 int err = * (const int *) invalue;
717 /* need a struct ldap */
722 } return LDAP_OPT_SUCCESS;
724 case LDAP_OPT_DEBUG_LEVEL:
725 lo->ldo_debug = * (const int *) invalue;
726 return LDAP_OPT_SUCCESS;
728 return LDAP_OPT_ERROR;
732 ldap_set_rebind_proc( LDAP *ld, LDAP_REBIND_PROC *proc, void *params )
735 rc = ldap_set_option( ld, LDAP_OPT_REBIND_PROC, (void *)proc );
736 if( rc != LDAP_OPT_SUCCESS ) return rc;
738 rc = ldap_set_option( ld, LDAP_OPT_REBIND_PARAMS, (void *)params );
743 ldap_set_nextref_proc( LDAP *ld, LDAP_NEXTREF_PROC *proc, void *params )
746 rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PROC, (void *)proc );
747 if( rc != LDAP_OPT_SUCCESS ) return rc;
749 rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PARAMS, (void *)params );
754 ldap_set_urllist_proc( LDAP *ld, LDAP_URLLIST_PROC *proc, void *params )
757 rc = ldap_set_option( ld, LDAP_OPT_URLLIST_PROC, (void *)proc );
758 if( rc != LDAP_OPT_SUCCESS ) return rc;
760 rc = ldap_set_option( ld, LDAP_OPT_URLLIST_PARAMS, (void *)params );