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