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