Home | History | Annotate | Line # | Download | only in libldap
      1 /*	$NetBSD: options.c,v 1.4 2025/09/05 21:16:21 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2024 The OpenLDAP Foundation.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted only as authorized by the OpenLDAP
     11  * Public License.
     12  *
     13  * A copy of this license is available in the file LICENSE in the
     14  * top-level directory of the distribution or, alternatively, at
     15  * <http://www.OpenLDAP.org/license.html>.
     16  */
     17 
     18 #include <sys/cdefs.h>
     19 __RCSID("$NetBSD: options.c,v 1.4 2025/09/05 21:16:21 christos Exp $");
     20 
     21 #include "portable.h"
     22 
     23 #include <stdio.h>
     24 
     25 #include <ac/stdlib.h>
     26 
     27 #include <ac/socket.h>
     28 #include <ac/string.h>
     29 #include <ac/time.h>
     30 
     31 #include "ldap-int.h"
     32 
     33 #define LDAP_OPT_REBIND_PROC 0x4e814d
     34 #define LDAP_OPT_REBIND_PARAMS 0x4e814e
     35 
     36 #define LDAP_OPT_NEXTREF_PROC 0x4e815d
     37 #define LDAP_OPT_NEXTREF_PARAMS 0x4e815e
     38 
     39 #define LDAP_OPT_URLLIST_PROC 0x4e816d
     40 #define LDAP_OPT_URLLIST_PARAMS 0x4e816e
     41 
     42 static const LDAPAPIFeatureInfo features[] = {
     43 #ifdef LDAP_API_FEATURE_X_OPENLDAP
     44 	{	/* OpenLDAP Extensions API Feature */
     45 		LDAP_FEATURE_INFO_VERSION,
     46 		"X_OPENLDAP",
     47 		LDAP_API_FEATURE_X_OPENLDAP
     48 	},
     49 #endif
     50 
     51 #ifdef LDAP_API_FEATURE_THREAD_SAFE
     52 	{	/* Basic Thread Safe */
     53 		LDAP_FEATURE_INFO_VERSION,
     54 		"THREAD_SAFE",
     55 		LDAP_API_FEATURE_THREAD_SAFE
     56 	},
     57 #endif
     58 #ifdef LDAP_API_FEATURE_SESSION_THREAD_SAFE
     59 	{	/* Session Thread Safe */
     60 		LDAP_FEATURE_INFO_VERSION,
     61 		"SESSION_THREAD_SAFE",
     62 		LDAP_API_FEATURE_SESSION_THREAD_SAFE
     63 	},
     64 #endif
     65 #ifdef LDAP_API_FEATURE_OPERATION_THREAD_SAFE
     66 	{	/* Operation Thread Safe */
     67 		LDAP_FEATURE_INFO_VERSION,
     68 		"OPERATION_THREAD_SAFE",
     69 		LDAP_API_FEATURE_OPERATION_THREAD_SAFE
     70 	},
     71 #endif
     72 #ifdef LDAP_API_FEATURE_X_OPENLDAP_REENTRANT
     73 	{	/* OpenLDAP Reentrant */
     74 		LDAP_FEATURE_INFO_VERSION,
     75 		"X_OPENLDAP_REENTRANT",
     76 		LDAP_API_FEATURE_X_OPENLDAP_REENTRANT
     77 	},
     78 #endif
     79 #ifdef LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE
     80 	{	/* OpenLDAP Thread Safe */
     81 		LDAP_FEATURE_INFO_VERSION,
     82 		"X_OPENLDAP_THREAD_SAFE",
     83 		LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE
     84 	},
     85 #endif
     86 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
     87 	{	/* V2 Referrals */
     88 		LDAP_FEATURE_INFO_VERSION,
     89 		"X_OPENLDAP_V2_REFERRALS",
     90 		LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
     91 	},
     92 #endif
     93 	{0, NULL, 0}
     94 };
     95 
     96 int
     97 ldap_get_option(
     98 	LDAP	*ld,
     99 	int		option,
    100 	void	*outvalue)
    101 {
    102 	struct ldapoptions *lo;
    103 	int rc = LDAP_OPT_ERROR;
    104 
    105 	/* Get pointer to global option structure */
    106 	lo = LDAP_INT_GLOBAL_OPT();
    107 	if (NULL == lo)	{
    108 		return LDAP_NO_MEMORY;
    109 	}
    110 
    111 	if( lo->ldo_valid != LDAP_INITIALIZED ) {
    112 		ldap_int_initialize(lo, NULL);
    113 		if ( lo->ldo_valid != LDAP_INITIALIZED )
    114 			return LDAP_LOCAL_ERROR;
    115 	}
    116 
    117 	if(ld != NULL) {
    118 		if( !LDAP_VALID( ld ) ) {
    119 			return LDAP_OPT_ERROR;
    120 		}
    121 
    122 		lo = &ld->ld_options;
    123 	}
    124 
    125 	if(outvalue == NULL) {
    126 		/* no place to get to */
    127 		return LDAP_OPT_ERROR;
    128 	}
    129 
    130 	LDAP_MUTEX_LOCK( &lo->ldo_mutex );
    131 
    132 	switch(option) {
    133 	case LDAP_OPT_API_INFO: {
    134 			struct ldapapiinfo *info = (struct ldapapiinfo *) outvalue;
    135 
    136 			if(info == NULL) {
    137 				/* outvalue must point to an apiinfo structure */
    138 				break;	/* LDAP_OPT_ERROR */
    139 			}
    140 
    141 			if(info->ldapai_info_version != LDAP_API_INFO_VERSION) {
    142 				/* api info version mismatch */
    143 				info->ldapai_info_version = LDAP_API_INFO_VERSION;
    144 				break;	/* LDAP_OPT_ERROR */
    145 			}
    146 
    147 			info->ldapai_api_version = LDAP_API_VERSION;
    148 			info->ldapai_protocol_version = LDAP_VERSION_MAX;
    149 
    150 			if(features[0].ldapaif_name == NULL) {
    151 				info->ldapai_extensions = NULL;
    152 			} else {
    153 				int i;
    154 				info->ldapai_extensions = LDAP_MALLOC(sizeof(char *) *
    155 					sizeof(features)/sizeof(LDAPAPIFeatureInfo));
    156 				if ( info->ldapai_extensions == NULL ) {
    157 					rc = LDAP_NO_MEMORY;
    158 					break;
    159 				}
    160 
    161 				for(i=0; features[i].ldapaif_name != NULL; i++) {
    162 					info->ldapai_extensions[i] =
    163 						LDAP_STRDUP(features[i].ldapaif_name);
    164 					if ( info->ldapai_extensions[i] == NULL ) {
    165 						rc = LDAP_NO_MEMORY;
    166 						break;
    167 					}
    168 				}
    169 				if ( features[i].ldapaif_name != NULL ) {
    170 					break; /* LDAP_NO_MEMORY */
    171 				}
    172 
    173 				info->ldapai_extensions[i] = NULL;
    174 			}
    175 
    176 			info->ldapai_vendor_name = LDAP_STRDUP(LDAP_VENDOR_NAME);
    177 			info->ldapai_vendor_version = LDAP_VENDOR_VERSION;
    178 
    179 			rc = LDAP_OPT_SUCCESS;
    180 			break;
    181 		} break;
    182 
    183 	case LDAP_OPT_DESC:
    184 		if( ld == NULL || ld->ld_sb == NULL ) {
    185 			/* bad param */
    186 			break;
    187 		}
    188 
    189 		ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, outvalue );
    190 		rc = LDAP_OPT_SUCCESS;
    191 		break;
    192 
    193 	case LDAP_OPT_SOCKBUF:
    194 		if( ld == NULL ) break;
    195 		*(Sockbuf **)outvalue = ld->ld_sb;
    196 		rc = LDAP_OPT_SUCCESS;
    197 		break;
    198 
    199 	case LDAP_OPT_TIMEOUT:
    200 		/* the caller has to free outvalue ! */
    201 		if ( lo->ldo_tm_api.tv_sec < 0 ) {
    202 			*(void **)outvalue = NULL;
    203 		} else if ( ldap_int_timeval_dup( outvalue, &lo->ldo_tm_api ) != 0 ) {
    204 			break;	/* LDAP_OPT_ERROR */
    205 		}
    206 		rc = LDAP_OPT_SUCCESS;
    207 		break;
    208 
    209 	case LDAP_OPT_NETWORK_TIMEOUT:
    210 		/* the caller has to free outvalue ! */
    211 		if ( lo->ldo_tm_net.tv_sec < 0 ) {
    212 			*(void **)outvalue = NULL;
    213 		} else if ( ldap_int_timeval_dup( outvalue, &lo->ldo_tm_net ) != 0 ) {
    214 			break;	/* LDAP_OPT_ERROR */
    215 		}
    216 		rc = LDAP_OPT_SUCCESS;
    217 		break;
    218 
    219 	case LDAP_OPT_DEREF:
    220 		* (int *) outvalue = lo->ldo_deref;
    221 		rc = LDAP_OPT_SUCCESS;
    222 		break;
    223 
    224 	case LDAP_OPT_SIZELIMIT:
    225 		* (int *) outvalue = lo->ldo_sizelimit;
    226 		rc = LDAP_OPT_SUCCESS;
    227 		break;
    228 
    229 	case LDAP_OPT_TIMELIMIT:
    230 		* (int *) outvalue = lo->ldo_timelimit;
    231 		rc = LDAP_OPT_SUCCESS;
    232 		break;
    233 
    234 	case LDAP_OPT_REFERRALS:
    235 		* (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_REFERRALS);
    236 		rc = LDAP_OPT_SUCCESS;
    237 		break;
    238 
    239 	case LDAP_OPT_RESTART:
    240 		* (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_RESTART);
    241 		rc = LDAP_OPT_SUCCESS;
    242 		break;
    243 
    244 	case LDAP_OPT_PROTOCOL_VERSION:
    245 		* (int *) outvalue = lo->ldo_version;
    246 		rc = LDAP_OPT_SUCCESS;
    247 		break;
    248 
    249 	case LDAP_OPT_SERVER_CONTROLS:
    250 		* (LDAPControl ***) outvalue =
    251 			ldap_controls_dup( lo->ldo_sctrls );
    252 		rc = LDAP_OPT_SUCCESS;
    253 		break;
    254 
    255 	case LDAP_OPT_CLIENT_CONTROLS:
    256 		* (LDAPControl ***) outvalue =
    257 			ldap_controls_dup( lo->ldo_cctrls );
    258 		rc = LDAP_OPT_SUCCESS;
    259 		break;
    260 
    261 	case LDAP_OPT_HOST_NAME:
    262 		* (char **) outvalue = ldap_url_list2hosts(lo->ldo_defludp);
    263 		rc = LDAP_OPT_SUCCESS;
    264 		break;
    265 
    266 	case LDAP_OPT_SOCKET_BIND_ADDRESSES:
    267 		if ( lo->ldo_local_ip_addrs.local_ip_addrs == NULL ) {
    268 			* (void **) outvalue = NULL;
    269 		}
    270 		else {
    271 			* (char **) outvalue =
    272 				LDAP_STRDUP( lo->ldo_local_ip_addrs.local_ip_addrs );
    273 		}
    274 		rc = LDAP_OPT_SUCCESS;
    275 		break;
    276 
    277 	case LDAP_OPT_URI:
    278 		* (char **) outvalue = ldap_url_list2urls(lo->ldo_defludp);
    279 		rc = LDAP_OPT_SUCCESS;
    280 		break;
    281 
    282 	case LDAP_OPT_DEFBASE:
    283 		if( lo->ldo_defbase == NULL ) {
    284 			* (char **) outvalue = NULL;
    285 		} else {
    286 			* (char **) outvalue = LDAP_STRDUP(lo->ldo_defbase);
    287 		}
    288 		rc = LDAP_OPT_SUCCESS;
    289 		break;
    290 
    291 	case LDAP_OPT_CONNECT_ASYNC:
    292 		* (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_CONNECT_ASYNC);
    293 		rc = LDAP_OPT_SUCCESS;
    294 		break;
    295 
    296 	case LDAP_OPT_CONNECT_CB:
    297 		{
    298 			/* Getting deletes the specified callback */
    299 			ldaplist **ll = &lo->ldo_conn_cbs;
    300 			for (;*ll;ll = &(*ll)->ll_next) {
    301 				if ((*ll)->ll_data == outvalue) {
    302 					ldaplist *lc = *ll;
    303 					*ll = lc->ll_next;
    304 					LDAP_FREE(lc);
    305 					break;
    306 				}
    307 			}
    308 		}
    309 		rc = LDAP_OPT_SUCCESS;
    310 		break;
    311 
    312 	case LDAP_OPT_RESULT_CODE:
    313 		if(ld == NULL) {
    314 			/* bad param */
    315 			break;
    316 		}
    317 		* (int *) outvalue = ld->ld_errno;
    318 		rc = LDAP_OPT_SUCCESS;
    319 		break;
    320 
    321 	case LDAP_OPT_DIAGNOSTIC_MESSAGE:
    322 		if(ld == NULL) {
    323 			/* bad param */
    324 			break;
    325 		}
    326 
    327 		if( ld->ld_error == NULL ) {
    328 			* (char **) outvalue = NULL;
    329 		} else {
    330 			* (char **) outvalue = LDAP_STRDUP(ld->ld_error);
    331 		}
    332 		rc = LDAP_OPT_SUCCESS;
    333 		break;
    334 
    335 	case LDAP_OPT_MATCHED_DN:
    336 		if(ld == NULL) {
    337 			/* bad param */
    338 			break;
    339 		}
    340 
    341 		if( ld->ld_matched == NULL ) {
    342 			* (char **) outvalue = NULL;
    343 		} else {
    344 			* (char **) outvalue = LDAP_STRDUP( ld->ld_matched );
    345 		}
    346 		rc = LDAP_OPT_SUCCESS;
    347 		break;
    348 
    349 	case LDAP_OPT_REFERRAL_URLS:
    350 		if(ld == NULL) {
    351 			/* bad param */
    352 			break;
    353 		}
    354 
    355 		if( ld->ld_referrals == NULL ) {
    356 			* (char ***) outvalue = NULL;
    357 		} else {
    358 			* (char ***) outvalue = ldap_value_dup(ld->ld_referrals);
    359 		}
    360 		rc = LDAP_OPT_SUCCESS;
    361 		break;
    362 
    363 	case LDAP_OPT_API_FEATURE_INFO: {
    364 			LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue;
    365 			int i;
    366 
    367 			if(info == NULL)
    368 				break;	/* LDAP_OPT_ERROR */
    369 
    370 			if(info->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) {
    371 				/* api info version mismatch */
    372 				info->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
    373 				break;	/* LDAP_OPT_ERROR */
    374 			}
    375 
    376 			if(info->ldapaif_name == NULL)
    377 				break;	/* LDAP_OPT_ERROR */
    378 
    379 			for(i=0; features[i].ldapaif_name != NULL; i++) {
    380 				if(!strcmp(info->ldapaif_name, features[i].ldapaif_name)) {
    381 					info->ldapaif_version =
    382 						features[i].ldapaif_version;
    383 					rc = LDAP_OPT_SUCCESS;
    384 					break;
    385 				}
    386 			}
    387 		}
    388 		break;
    389 
    390 	case LDAP_OPT_DEBUG_LEVEL:
    391 		* (int *) outvalue = lo->ldo_debug;
    392 		rc = LDAP_OPT_SUCCESS;
    393 		break;
    394 
    395 	case LDAP_OPT_SESSION_REFCNT:
    396 		if(ld == NULL) {
    397 			/* bad param */
    398 			break;
    399 		}
    400 		LDAP_MUTEX_LOCK( &ld->ld_ldcmutex );
    401 		* (int *) outvalue = ld->ld_ldcrefcnt;
    402 		LDAP_MUTEX_UNLOCK( &ld->ld_ldcmutex );
    403 		rc = LDAP_OPT_SUCCESS;
    404 		break;
    405 
    406 	case LDAP_OPT_KEEPCONN:
    407 		* (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_KEEPCONN);
    408 		rc = LDAP_OPT_SUCCESS;
    409 		break;
    410 
    411 	case LDAP_OPT_X_KEEPALIVE_IDLE:
    412 		* (int *) outvalue = lo->ldo_keepalive_idle;
    413 		rc = LDAP_OPT_SUCCESS;
    414 		break;
    415 
    416 	case LDAP_OPT_X_KEEPALIVE_PROBES:
    417 		* (int *) outvalue = lo->ldo_keepalive_probes;
    418 		rc = LDAP_OPT_SUCCESS;
    419 		break;
    420 
    421 	case LDAP_OPT_X_KEEPALIVE_INTERVAL:
    422 		* (int *) outvalue = lo->ldo_keepalive_interval;
    423 		rc = LDAP_OPT_SUCCESS;
    424 		break;
    425 
    426 	case LDAP_OPT_TCP_USER_TIMEOUT:
    427 		* (unsigned int *) outvalue = lo->ldo_tcp_user_timeout;
    428 		rc = LDAP_OPT_SUCCESS;
    429 		break;
    430 
    431 	default:
    432 #ifdef HAVE_TLS
    433 		if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
    434 			rc = LDAP_OPT_SUCCESS;
    435 			break;
    436 		}
    437 #endif
    438 #ifdef HAVE_CYRUS_SASL
    439 		if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
    440 			rc = LDAP_OPT_SUCCESS;
    441 			break;
    442 		}
    443 #endif
    444 #ifdef HAVE_GSSAPI
    445 		if ( ldap_int_gssapi_get_option( ld, option, outvalue ) == 0 ) {
    446 			rc = LDAP_OPT_SUCCESS;
    447 			break;
    448 		}
    449 #endif
    450 		/* bad param */
    451 		break;
    452 	}
    453 
    454 	LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
    455 	return ( rc );
    456 }
    457 
    458 int
    459 ldap_set_option(
    460 	LDAP	*ld,
    461 	int		option,
    462 	LDAP_CONST void	*invalue)
    463 {
    464 	struct ldapoptions *lo;
    465 	int *dbglvl = NULL;
    466 	int rc = LDAP_OPT_ERROR;
    467 
    468 	/* Get pointer to global option structure */
    469 	lo = LDAP_INT_GLOBAL_OPT();
    470 	if (lo == NULL)	{
    471 		return LDAP_NO_MEMORY;
    472 	}
    473 
    474 	/*
    475 	 * The architecture to turn on debugging has a chicken and egg
    476 	 * problem. Thus, we introduce a fix here.
    477 	 */
    478 
    479 	if (option == LDAP_OPT_DEBUG_LEVEL) {
    480 		dbglvl = (int *) invalue;
    481 	}
    482 
    483 	if( lo->ldo_valid != LDAP_INITIALIZED ) {
    484 		ldap_int_initialize(lo, dbglvl);
    485 		if ( lo->ldo_valid != LDAP_INITIALIZED )
    486 			return LDAP_LOCAL_ERROR;
    487 	}
    488 
    489 	if(ld != NULL) {
    490 		assert( LDAP_VALID( ld ) );
    491 
    492 		if( !LDAP_VALID( ld ) ) {
    493 			return LDAP_OPT_ERROR;
    494 		}
    495 
    496 		lo = &ld->ld_options;
    497 	}
    498 
    499 	LDAP_MUTEX_LOCK( &lo->ldo_mutex );
    500 
    501 	switch ( option ) {
    502 
    503 	/* options with boolean values */
    504 	case LDAP_OPT_REFERRALS:
    505 		if(invalue == LDAP_OPT_OFF) {
    506 			LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS);
    507 		} else {
    508 			LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS);
    509 		}
    510 		rc = LDAP_OPT_SUCCESS;
    511 		break;
    512 
    513 	case LDAP_OPT_RESTART:
    514 		if(invalue == LDAP_OPT_OFF) {
    515 			LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART);
    516 		} else {
    517 			LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
    518 		}
    519 		rc = LDAP_OPT_SUCCESS;
    520 		break;
    521 
    522 	case LDAP_OPT_CONNECT_ASYNC:
    523 		if(invalue == LDAP_OPT_OFF) {
    524 			LDAP_BOOL_CLR(lo, LDAP_BOOL_CONNECT_ASYNC);
    525 		} else {
    526 			LDAP_BOOL_SET(lo, LDAP_BOOL_CONNECT_ASYNC);
    527 		}
    528 		rc = LDAP_OPT_SUCCESS;
    529 		break;
    530 
    531 	case LDAP_OPT_KEEPCONN:
    532 		if(invalue == LDAP_OPT_OFF) {
    533 			LDAP_BOOL_CLR(lo, LDAP_BOOL_KEEPCONN);
    534 		} else {
    535 			LDAP_BOOL_SET(lo, LDAP_BOOL_KEEPCONN);
    536 		}
    537 		rc = LDAP_OPT_SUCCESS;
    538 		break;
    539 	/* options which can withstand invalue == NULL */
    540 	case LDAP_OPT_SERVER_CONTROLS: {
    541 			LDAPControl *const *controls =
    542 				(LDAPControl *const *) invalue;
    543 
    544 			if( lo->ldo_sctrls )
    545 				ldap_controls_free( lo->ldo_sctrls );
    546 
    547 			if( controls == NULL || *controls == NULL ) {
    548 				lo->ldo_sctrls = NULL;
    549 				rc = LDAP_OPT_SUCCESS;
    550 				break;
    551 			}
    552 
    553 			lo->ldo_sctrls = ldap_controls_dup( controls );
    554 
    555 			if(lo->ldo_sctrls == NULL) {
    556 				/* memory allocation error ? */
    557 				break;	/* LDAP_OPT_ERROR */
    558 			}
    559 		}
    560 		rc = LDAP_OPT_SUCCESS;
    561 		break;
    562 
    563 	case LDAP_OPT_CLIENT_CONTROLS: {
    564 			LDAPControl *const *controls =
    565 				(LDAPControl *const *) invalue;
    566 
    567 			if( lo->ldo_cctrls )
    568 				ldap_controls_free( lo->ldo_cctrls );
    569 
    570 			if( controls == NULL || *controls == NULL ) {
    571 				lo->ldo_cctrls = NULL;
    572 				rc = LDAP_OPT_SUCCESS;
    573 				break;
    574 			}
    575 
    576 			lo->ldo_cctrls = ldap_controls_dup( controls );
    577 
    578 			if(lo->ldo_cctrls == NULL) {
    579 				/* memory allocation error ? */
    580 				break;	/* LDAP_OPT_ERROR */
    581 			}
    582 		}
    583 		rc = LDAP_OPT_SUCCESS;
    584 		break;
    585 
    586 
    587 	case LDAP_OPT_HOST_NAME: {
    588 			const char *host = (const char *) invalue;
    589 			LDAPURLDesc *ludlist = NULL;
    590 			rc = LDAP_OPT_SUCCESS;
    591 
    592 			if(host != NULL) {
    593 				rc = ldap_url_parsehosts( &ludlist, host,
    594 					lo->ldo_defport ? lo->ldo_defport : LDAP_PORT );
    595 
    596 			} else if(ld == NULL) {
    597 				/*
    598 				 * must want global default returned
    599 				 * to initial condition.
    600 				 */
    601 				rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL,
    602 					LDAP_PVT_URL_PARSE_NOEMPTY_HOST
    603 					| LDAP_PVT_URL_PARSE_DEF_PORT );
    604 
    605 			} else {
    606 				/*
    607 				 * must want the session default
    608 				 *   updated to the current global default
    609 				 */
    610 				ludlist = ldap_url_duplist(
    611 					ldap_int_global_options.ldo_defludp);
    612 				if (ludlist == NULL)
    613 					rc = LDAP_NO_MEMORY;
    614 			}
    615 
    616 			if (rc == LDAP_OPT_SUCCESS) {
    617 				if (lo->ldo_defludp != NULL)
    618 					ldap_free_urllist(lo->ldo_defludp);
    619 				lo->ldo_defludp = ludlist;
    620 			}
    621 			break;
    622 		}
    623 
    624 	case LDAP_OPT_SOCKET_BIND_ADDRESSES: {
    625 			const char *source_ip = (const char *) invalue;
    626 			char **source_ip_lst = NULL;
    627 
    628 			ldapsourceip temp_source_ip;
    629 			memset( &temp_source_ip, 0, sizeof( ldapsourceip ) );
    630 			rc = LDAP_OPT_SUCCESS;
    631 			if( source_ip == NULL ) {
    632 				if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ) {
    633 					LDAP_FREE( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs );
    634 					memset( &ld->ld_options.ldo_local_ip_addrs, 0,
    635 						sizeof( ldapsourceip ) );
    636 				}
    637 			}
    638 			else {
    639 				source_ip_lst = ldap_str2charray( source_ip, " " );
    640 
    641 				if ( source_ip_lst == NULL )
    642 					rc =  LDAP_NO_MEMORY;
    643 
    644 				if( rc == LDAP_OPT_SUCCESS ) {
    645 					rc = ldap_validate_and_fill_sourceip ( source_ip_lst,
    646 						&temp_source_ip );
    647 					ldap_charray_free( source_ip_lst );
    648 				}
    649 				if ( rc == LDAP_OPT_SUCCESS ) {
    650 					if ( lo->ldo_local_ip_addrs.local_ip_addrs != NULL ) {
    651 						LDAP_FREE( lo->ldo_local_ip_addrs.local_ip_addrs );
    652 						lo->ldo_local_ip_addrs.local_ip_addrs = NULL;
    653 					}
    654 					lo->ldo_local_ip_addrs = temp_source_ip;
    655 					lo->ldo_local_ip_addrs.local_ip_addrs = LDAP_STRDUP( source_ip );
    656 				}
    657 			}
    658 			break;
    659 		}
    660 
    661 	case LDAP_OPT_URI: {
    662 			const char *urls = (const char *) invalue;
    663 			LDAPURLDesc *ludlist = NULL;
    664 			rc = LDAP_OPT_SUCCESS;
    665 
    666 			if(urls != NULL) {
    667 				rc = ldap_url_parselist_ext(&ludlist, urls, NULL,
    668 					LDAP_PVT_URL_PARSE_NOEMPTY_HOST
    669 					| LDAP_PVT_URL_PARSE_DEF_PORT );
    670 			} else if(ld == NULL) {
    671 				/*
    672 				 * must want global default returned
    673 				 * to initial condition.
    674 				 */
    675 				rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL,
    676 					LDAP_PVT_URL_PARSE_NOEMPTY_HOST
    677 					| LDAP_PVT_URL_PARSE_DEF_PORT );
    678 
    679 			} else {
    680 				/*
    681 				 * must want the session default
    682 				 *   updated to the current global default
    683 				 */
    684 				ludlist = ldap_url_duplist(
    685 					ldap_int_global_options.ldo_defludp);
    686 				if (ludlist == NULL)
    687 					rc = LDAP_URL_ERR_MEM;
    688 			}
    689 
    690 			switch (rc) {
    691 			case LDAP_URL_SUCCESS:		/* Success */
    692 				rc = LDAP_SUCCESS;
    693 				break;
    694 
    695 			case LDAP_URL_ERR_MEM:		/* can't allocate memory space */
    696 				rc = LDAP_NO_MEMORY;
    697 				break;
    698 
    699 			case LDAP_URL_ERR_PARAM:	/* parameter is bad */
    700 			case LDAP_URL_ERR_BADSCHEME:	/* URL doesn't begin with "ldap[si]://" */
    701 			case LDAP_URL_ERR_BADENCLOSURE:	/* URL is missing trailing ">" */
    702 			case LDAP_URL_ERR_BADURL:	/* URL is bad */
    703 			case LDAP_URL_ERR_BADHOST:	/* host port is bad */
    704 			case LDAP_URL_ERR_BADATTRS:	/* bad (or missing) attributes */
    705 			case LDAP_URL_ERR_BADSCOPE:	/* scope string is invalid (or missing) */
    706 			case LDAP_URL_ERR_BADFILTER:	/* bad or missing filter */
    707 			case LDAP_URL_ERR_BADEXTS:	/* bad or missing extensions */
    708 				rc = LDAP_PARAM_ERROR;
    709 				break;
    710 			}
    711 
    712 			if (rc == LDAP_SUCCESS) {
    713 				if (lo->ldo_defludp != NULL)
    714 					ldap_free_urllist(lo->ldo_defludp);
    715 				lo->ldo_defludp = ludlist;
    716 			}
    717 			break;
    718 		}
    719 
    720 	case LDAP_OPT_DEFBASE: {
    721 			const char *newbase = (const char *) invalue;
    722 			char *defbase = NULL;
    723 
    724 			if ( newbase != NULL ) {
    725 				defbase = LDAP_STRDUP( newbase );
    726 				if ( defbase == NULL ) {
    727 					rc = LDAP_NO_MEMORY;
    728 					break;
    729 				}
    730 
    731 			} else if ( ld != NULL ) {
    732 				defbase = LDAP_STRDUP( ldap_int_global_options.ldo_defbase );
    733 				if ( defbase == NULL ) {
    734 					rc = LDAP_NO_MEMORY;
    735 					break;
    736 				}
    737 			}
    738 
    739 			if ( lo->ldo_defbase != NULL )
    740 				LDAP_FREE( lo->ldo_defbase );
    741 			lo->ldo_defbase = defbase;
    742 		}
    743 		rc = LDAP_OPT_SUCCESS;
    744 		break;
    745 
    746 	case LDAP_OPT_DIAGNOSTIC_MESSAGE: {
    747 			const char *err = (const char *) invalue;
    748 
    749 			if(ld == NULL) {
    750 				/* need a struct ldap */
    751 				break;	/* LDAP_OPT_ERROR */
    752 			}
    753 
    754 			if( ld->ld_error ) {
    755 				LDAP_FREE(ld->ld_error);
    756 				ld->ld_error = NULL;
    757 			}
    758 
    759 			if ( err ) {
    760 				ld->ld_error = LDAP_STRDUP(err);
    761 			}
    762 		}
    763 		rc = LDAP_OPT_SUCCESS;
    764 		break;
    765 
    766 	case LDAP_OPT_MATCHED_DN: {
    767 			const char *matched = (const char *) invalue;
    768 
    769 			if (ld == NULL) {
    770 				/* need a struct ldap */
    771 				break;	/* LDAP_OPT_ERROR */
    772 			}
    773 
    774 			if( ld->ld_matched ) {
    775 				LDAP_FREE(ld->ld_matched);
    776 				ld->ld_matched = NULL;
    777 			}
    778 
    779 			if ( matched ) {
    780 				ld->ld_matched = LDAP_STRDUP( matched );
    781 			}
    782 		}
    783 		rc = LDAP_OPT_SUCCESS;
    784 		break;
    785 
    786 	case LDAP_OPT_REFERRAL_URLS: {
    787 			char *const *referrals = (char *const *) invalue;
    788 
    789 			if(ld == NULL) {
    790 				/* need a struct ldap */
    791 				break;	/* LDAP_OPT_ERROR */
    792 			}
    793 
    794 			if( ld->ld_referrals ) {
    795 				LDAP_VFREE(ld->ld_referrals);
    796 			}
    797 
    798 			if ( referrals ) {
    799 				ld->ld_referrals = ldap_value_dup(referrals);
    800 			}
    801 		}
    802 		rc = LDAP_OPT_SUCCESS;
    803 		break;
    804 
    805 	/* Only accessed from inside this function by ldap_set_rebind_proc() */
    806 	case LDAP_OPT_REBIND_PROC: {
    807 			lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue;
    808 		}
    809 		rc = LDAP_OPT_SUCCESS;
    810 		break;
    811 	case LDAP_OPT_REBIND_PARAMS: {
    812 			lo->ldo_rebind_params = (void *)invalue;
    813 		}
    814 		rc = LDAP_OPT_SUCCESS;
    815 		break;
    816 
    817 	/* Only accessed from inside this function by ldap_set_nextref_proc() */
    818 	case LDAP_OPT_NEXTREF_PROC: {
    819 			lo->ldo_nextref_proc = (LDAP_NEXTREF_PROC *)invalue;
    820 		}
    821 		rc = LDAP_OPT_SUCCESS;
    822 		break;
    823 	case LDAP_OPT_NEXTREF_PARAMS: {
    824 			lo->ldo_nextref_params = (void *)invalue;
    825 		}
    826 		rc = LDAP_OPT_SUCCESS;
    827 		break;
    828 
    829 	/* Only accessed from inside this function by ldap_set_urllist_proc() */
    830 	case LDAP_OPT_URLLIST_PROC: {
    831 			lo->ldo_urllist_proc = (LDAP_URLLIST_PROC *)invalue;
    832 		}
    833 		rc = LDAP_OPT_SUCCESS;
    834 		break;
    835 	case LDAP_OPT_URLLIST_PARAMS: {
    836 			lo->ldo_urllist_params = (void *)invalue;
    837 		}
    838 		rc = LDAP_OPT_SUCCESS;
    839 		break;
    840 
    841 	/* read-only options */
    842 	case LDAP_OPT_API_INFO:
    843 	case LDAP_OPT_DESC:
    844 	case LDAP_OPT_SOCKBUF:
    845 	case LDAP_OPT_API_FEATURE_INFO:
    846 		break;	/* LDAP_OPT_ERROR */
    847 
    848 	/* options which cannot withstand invalue == NULL */
    849 	case LDAP_OPT_DEREF:
    850 	case LDAP_OPT_SIZELIMIT:
    851 	case LDAP_OPT_TIMELIMIT:
    852 	case LDAP_OPT_PROTOCOL_VERSION:
    853 	case LDAP_OPT_RESULT_CODE:
    854 	case LDAP_OPT_DEBUG_LEVEL:
    855 	case LDAP_OPT_TIMEOUT:
    856 	case LDAP_OPT_NETWORK_TIMEOUT:
    857 	case LDAP_OPT_CONNECT_CB:
    858 	case LDAP_OPT_X_KEEPALIVE_IDLE:
    859 	case LDAP_OPT_X_KEEPALIVE_PROBES :
    860 	case LDAP_OPT_X_KEEPALIVE_INTERVAL :
    861 	case LDAP_OPT_TCP_USER_TIMEOUT:
    862 		if(invalue == NULL) {
    863 			/* no place to set from */
    864 			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
    865 			return ( LDAP_OPT_ERROR );
    866 		}
    867 		break;
    868 
    869 	default:
    870 #ifdef HAVE_TLS
    871 		if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 ) {
    872 			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
    873 			return ( LDAP_OPT_SUCCESS );
    874 		}
    875 #endif
    876 #ifdef HAVE_CYRUS_SASL
    877 		if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 ) {
    878 			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
    879 			return ( LDAP_OPT_SUCCESS );
    880 		}
    881 #endif
    882 #ifdef HAVE_GSSAPI
    883 		if ( ldap_int_gssapi_set_option( ld, option, (void *)invalue ) == 0 ) {
    884 			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
    885 			return ( LDAP_OPT_SUCCESS );
    886 		}
    887 #endif
    888 		/* bad param */
    889 		break;	/* LDAP_OPT_ERROR */
    890 	}
    891 
    892 	/* options which cannot withstand invalue == NULL */
    893 
    894 	switch(option) {
    895 	case LDAP_OPT_DEREF:
    896 		/* FIXME: check value for protocol compliance? */
    897 		lo->ldo_deref = * (const int *) invalue;
    898 		rc = LDAP_OPT_SUCCESS;
    899 		break;
    900 
    901 	case LDAP_OPT_SIZELIMIT:
    902 		/* FIXME: check value for protocol compliance? */
    903 		lo->ldo_sizelimit = * (const int *) invalue;
    904 		rc = LDAP_OPT_SUCCESS;
    905 		break;
    906 
    907 	case LDAP_OPT_TIMELIMIT:
    908 		/* FIXME: check value for protocol compliance? */
    909 		lo->ldo_timelimit = * (const int *) invalue;
    910 		rc = LDAP_OPT_SUCCESS;
    911 		break;
    912 
    913 	case LDAP_OPT_TIMEOUT: {
    914 			const struct timeval *tv =
    915 				(const struct timeval *) invalue;
    916 
    917 			lo->ldo_tm_api = *tv;
    918 		}
    919 		rc = LDAP_OPT_SUCCESS;
    920 		break;
    921 
    922 	case LDAP_OPT_NETWORK_TIMEOUT: {
    923 			const struct timeval *tv =
    924 				(const struct timeval *) invalue;
    925 
    926 			lo->ldo_tm_net = *tv;
    927 		}
    928 		rc = LDAP_OPT_SUCCESS;
    929 		break;
    930 
    931 	case LDAP_OPT_PROTOCOL_VERSION: {
    932 			int vers = * (const int *) invalue;
    933 			if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) {
    934 				/* not supported */
    935 				break;
    936 			}
    937 			lo->ldo_version = vers;
    938 		}
    939 		rc = LDAP_OPT_SUCCESS;
    940 		break;
    941 
    942 	case LDAP_OPT_RESULT_CODE: {
    943 			int err = * (const int *) invalue;
    944 
    945 			if(ld == NULL) {
    946 				/* need a struct ldap */
    947 				break;
    948 			}
    949 
    950 			ld->ld_errno = err;
    951 		}
    952 		rc = LDAP_OPT_SUCCESS;
    953 		break;
    954 
    955 	case LDAP_OPT_DEBUG_LEVEL:
    956 		lo->ldo_debug = * (const int *) invalue;
    957 		rc = LDAP_OPT_SUCCESS;
    958 		break;
    959 
    960 	case LDAP_OPT_CONNECT_CB:
    961 		{
    962 			/* setting pushes the callback */
    963 			ldaplist *ll;
    964 			ll = LDAP_MALLOC( sizeof( *ll ));
    965 			if ( ll == NULL ) {
    966 				rc = LDAP_NO_MEMORY;
    967 				break;
    968 			}
    969 
    970 			ll->ll_data = (void *)invalue;
    971 			ll->ll_next = lo->ldo_conn_cbs;
    972 			lo->ldo_conn_cbs = ll;
    973 		}
    974 		rc = LDAP_OPT_SUCCESS;
    975 		break;
    976 	case LDAP_OPT_X_KEEPALIVE_IDLE:
    977 		lo->ldo_keepalive_idle = * (const int *) invalue;
    978 		rc = LDAP_OPT_SUCCESS;
    979 		break;
    980 	case LDAP_OPT_X_KEEPALIVE_PROBES :
    981 		lo->ldo_keepalive_probes = * (const int *) invalue;
    982 		rc = LDAP_OPT_SUCCESS;
    983 		break;
    984 	case LDAP_OPT_X_KEEPALIVE_INTERVAL :
    985 		lo->ldo_keepalive_interval = * (const int *) invalue;
    986 		rc = LDAP_OPT_SUCCESS;
    987 		break;
    988 	case LDAP_OPT_TCP_USER_TIMEOUT:
    989 		lo->ldo_tcp_user_timeout = * (const unsigned int *) invalue;
    990 		rc = LDAP_OPT_SUCCESS;
    991 		break;
    992 
    993 	}
    994 	LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
    995 	return ( rc );
    996 }
    997 
    998 int
    999 ldap_set_rebind_proc( LDAP *ld, LDAP_REBIND_PROC *proc, void *params )
   1000 {
   1001 	int rc;
   1002 	rc = ldap_set_option( ld, LDAP_OPT_REBIND_PROC, (void *)proc );
   1003 	if( rc != LDAP_OPT_SUCCESS ) return rc;
   1004 
   1005 	rc = ldap_set_option( ld, LDAP_OPT_REBIND_PARAMS, (void *)params );
   1006 	return rc;
   1007 }
   1008 
   1009 int
   1010 ldap_set_nextref_proc( LDAP *ld, LDAP_NEXTREF_PROC *proc, void *params )
   1011 {
   1012 	int rc;
   1013 	rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PROC, (void *)proc );
   1014 	if( rc != LDAP_OPT_SUCCESS ) return rc;
   1015 
   1016 	rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PARAMS, (void *)params );
   1017 	return rc;
   1018 }
   1019 
   1020 int
   1021 ldap_set_urllist_proc( LDAP *ld, LDAP_URLLIST_PROC *proc, void *params )
   1022 {
   1023 	int rc;
   1024 	rc = ldap_set_option( ld, LDAP_OPT_URLLIST_PROC, (void *)proc );
   1025 	if( rc != LDAP_OPT_SUCCESS ) return rc;
   1026 
   1027 	rc = ldap_set_option( ld, LDAP_OPT_URLLIST_PARAMS, (void *)params );
   1028 	return rc;
   1029 }
   1030