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