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