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