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