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