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