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