]> git.sur5r.net Git - openldap/blob - libraries/libldap/options.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / libraries / libldap / options.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2013 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                 if(ld == NULL) {
371                         /* bad param */
372                         break;
373                 } 
374                 * (int *) outvalue = ld->ld_ldcrefcnt;
375                 rc = LDAP_OPT_SUCCESS;
376                 break;
377
378         case LDAP_OPT_X_KEEPALIVE_IDLE:
379                 * (int *) outvalue = lo->ldo_keepalive_idle;
380                 rc = LDAP_OPT_SUCCESS;
381                 break;
382
383         case LDAP_OPT_X_KEEPALIVE_PROBES:
384                 * (int *) outvalue = lo->ldo_keepalive_probes;
385                 rc = LDAP_OPT_SUCCESS;
386                 break;
387
388         case LDAP_OPT_X_KEEPALIVE_INTERVAL:
389                 * (int *) outvalue = lo->ldo_keepalive_interval;
390                 rc = LDAP_OPT_SUCCESS;
391                 break;
392
393         default:
394 #ifdef HAVE_TLS
395                 if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
396                         rc = LDAP_OPT_SUCCESS;
397                         break;
398                 }
399 #endif
400 #ifdef HAVE_CYRUS_SASL
401                 if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
402                         rc = LDAP_OPT_SUCCESS;
403                         break;
404                 }
405 #endif
406 #ifdef HAVE_GSSAPI
407                 if ( ldap_int_gssapi_get_option( ld, option, outvalue ) == 0 ) {
408                         rc = LDAP_OPT_SUCCESS;
409                         break;
410                 }
411 #endif
412                 /* bad param */
413                 break;
414         }
415
416         LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
417         return ( rc );
418 }
419
420 int
421 ldap_set_option(
422         LDAP    *ld,
423         int             option,
424         LDAP_CONST void *invalue)
425 {
426         struct ldapoptions *lo;
427         int *dbglvl = NULL;
428         int rc = LDAP_OPT_ERROR;
429
430         /* Get pointer to global option structure */
431         lo = LDAP_INT_GLOBAL_OPT();
432         if (lo == NULL) {
433                 return LDAP_NO_MEMORY;
434         }
435
436         /*
437          * The architecture to turn on debugging has a chicken and egg
438          * problem. Thus, we introduce a fix here.
439          */
440
441         if (option == LDAP_OPT_DEBUG_LEVEL) {
442                 dbglvl = (int *) invalue;
443         }
444
445         if( lo->ldo_valid != LDAP_INITIALIZED ) {
446                 ldap_int_initialize(lo, dbglvl);
447         }
448
449         if(ld != NULL) {
450                 assert( LDAP_VALID( ld ) );
451
452                 if( !LDAP_VALID( ld ) ) {
453                         return LDAP_OPT_ERROR;
454                 }
455
456                 lo = &ld->ld_options;
457         }
458
459         LDAP_MUTEX_LOCK( &lo->ldo_mutex );
460
461         switch ( option ) {
462
463         /* options with boolean values */
464         case LDAP_OPT_REFERRALS:
465                 if(invalue == LDAP_OPT_OFF) {
466                         LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS);
467                 } else {
468                         LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS);
469                 }
470                 rc = LDAP_OPT_SUCCESS;
471                 break;
472
473         case LDAP_OPT_RESTART:
474                 if(invalue == LDAP_OPT_OFF) {
475                         LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART);
476                 } else {
477                         LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
478                 }
479                 rc = LDAP_OPT_SUCCESS;
480                 break;
481
482         case LDAP_OPT_CONNECT_ASYNC:
483                 if(invalue == LDAP_OPT_OFF) {
484                         LDAP_BOOL_CLR(lo, LDAP_BOOL_CONNECT_ASYNC);
485                 } else {
486                         LDAP_BOOL_SET(lo, LDAP_BOOL_CONNECT_ASYNC);
487                 }
488                 rc = LDAP_OPT_SUCCESS;
489                 break;
490
491         /* options which can withstand invalue == NULL */
492         case LDAP_OPT_SERVER_CONTROLS: {
493                         LDAPControl *const *controls =
494                                 (LDAPControl *const *) invalue;
495
496                         if( lo->ldo_sctrls )
497                                 ldap_controls_free( lo->ldo_sctrls );
498
499                         if( controls == NULL || *controls == NULL ) {
500                                 lo->ldo_sctrls = NULL;
501                                 rc = LDAP_OPT_SUCCESS;
502                                 break;
503                         }
504                                 
505                         lo->ldo_sctrls = ldap_controls_dup( controls );
506
507                         if(lo->ldo_sctrls == NULL) {
508                                 /* memory allocation error ? */
509                                 break;  /* LDAP_OPT_ERROR */
510                         }
511                 }
512                 rc = LDAP_OPT_SUCCESS;
513                 break;
514
515         case LDAP_OPT_CLIENT_CONTROLS: {
516                         LDAPControl *const *controls =
517                                 (LDAPControl *const *) invalue;
518
519                         if( lo->ldo_cctrls )
520                                 ldap_controls_free( lo->ldo_cctrls );
521
522                         if( controls == NULL || *controls == NULL ) {
523                                 lo->ldo_cctrls = NULL;
524                                 rc = LDAP_OPT_SUCCESS;
525                                 break;
526                         }
527                                 
528                         lo->ldo_cctrls = ldap_controls_dup( controls );
529
530                         if(lo->ldo_cctrls == NULL) {
531                                 /* memory allocation error ? */
532                                 break;  /* LDAP_OPT_ERROR */
533                         }
534                 }
535                 rc = LDAP_OPT_SUCCESS;
536                 break;
537
538
539         case LDAP_OPT_HOST_NAME: {
540                         const char *host = (const char *) invalue;
541                         LDAPURLDesc *ludlist = NULL;
542                         rc = LDAP_OPT_SUCCESS;
543
544                         if(host != NULL) {
545                                 rc = ldap_url_parsehosts( &ludlist, host,
546                                         lo->ldo_defport ? lo->ldo_defport : LDAP_PORT );
547
548                         } else if(ld == NULL) {
549                                 /*
550                                  * must want global default returned
551                                  * to initial condition.
552                                  */
553                                 rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL,
554                                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
555                                         | LDAP_PVT_URL_PARSE_DEF_PORT );
556
557                         } else {
558                                 /*
559                                  * must want the session default
560                                  *   updated to the current global default
561                                  */
562                                 ludlist = ldap_url_duplist(
563                                         ldap_int_global_options.ldo_defludp);
564                                 if (ludlist == NULL)
565                                         rc = LDAP_NO_MEMORY;
566                         }
567
568                         if (rc == LDAP_OPT_SUCCESS) {
569                                 if (lo->ldo_defludp != NULL)
570                                         ldap_free_urllist(lo->ldo_defludp);
571                                 lo->ldo_defludp = ludlist;
572                         }
573                         break;
574                 }
575
576         case LDAP_OPT_URI: {
577                         const char *urls = (const char *) invalue;
578                         LDAPURLDesc *ludlist = NULL;
579                         rc = LDAP_OPT_SUCCESS;
580
581                         if(urls != NULL) {
582                                 rc = ldap_url_parselist_ext(&ludlist, urls, NULL,
583                                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
584                                         | LDAP_PVT_URL_PARSE_DEF_PORT );
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_URL_ERR_MEM;
603                         }
604
605                         switch (rc) {
606                         case LDAP_URL_SUCCESS:          /* Success */
607                                 rc = LDAP_SUCCESS;
608                                 break;
609
610                         case LDAP_URL_ERR_MEM:          /* can't allocate memory space */
611                                 rc = LDAP_NO_MEMORY;
612                                 break;
613
614                         case LDAP_URL_ERR_PARAM:        /* parameter is bad */
615                         case LDAP_URL_ERR_BADSCHEME:    /* URL doesn't begin with "ldap[si]://" */
616                         case LDAP_URL_ERR_BADENCLOSURE: /* URL is missing trailing ">" */
617                         case LDAP_URL_ERR_BADURL:       /* URL is bad */
618                         case LDAP_URL_ERR_BADHOST:      /* host port is bad */
619                         case LDAP_URL_ERR_BADATTRS:     /* bad (or missing) attributes */
620                         case LDAP_URL_ERR_BADSCOPE:     /* scope string is invalid (or missing) */
621                         case LDAP_URL_ERR_BADFILTER:    /* bad or missing filter */
622                         case LDAP_URL_ERR_BADEXTS:      /* bad or missing extensions */
623                                 rc = LDAP_PARAM_ERROR;
624                                 break;
625                         }
626
627                         if (rc == LDAP_SUCCESS) {
628                                 if (lo->ldo_defludp != NULL)
629                                         ldap_free_urllist(lo->ldo_defludp);
630                                 lo->ldo_defludp = ludlist;
631                         }
632                         break;
633                 }
634
635         case LDAP_OPT_DEFBASE: {
636                         const char *newbase = (const char *) invalue;
637                         char *defbase = NULL;
638
639                         if ( newbase != NULL ) {
640                                 defbase = LDAP_STRDUP( newbase );
641                                 if ( defbase == NULL ) {
642                                         rc = LDAP_NO_MEMORY;
643                                         break;
644                                 }
645
646                         } else if ( ld != NULL ) {
647                                 defbase = LDAP_STRDUP( ldap_int_global_options.ldo_defbase );
648                                 if ( defbase == NULL ) {
649                                         rc = LDAP_NO_MEMORY;
650                                         break;
651                                 }
652                         }
653                         
654                         if ( lo->ldo_defbase != NULL )
655                                 LDAP_FREE( lo->ldo_defbase );
656                         lo->ldo_defbase = defbase;
657                 }
658                 rc = LDAP_OPT_SUCCESS;
659                 break;
660
661         case LDAP_OPT_DIAGNOSTIC_MESSAGE: {
662                         const char *err = (const char *) invalue;
663
664                         if(ld == NULL) {
665                                 /* need a struct ldap */
666                                 break;  /* LDAP_OPT_ERROR */
667                         }
668
669                         if( ld->ld_error ) {
670                                 LDAP_FREE(ld->ld_error);
671                                 ld->ld_error = NULL;
672                         }
673
674                         if ( err ) {
675                                 ld->ld_error = LDAP_STRDUP(err);
676                         }
677                 }
678                 rc = LDAP_OPT_SUCCESS;
679                 break;
680
681         case LDAP_OPT_MATCHED_DN: {
682                         const char *matched = (const char *) invalue;
683
684                         if (ld == NULL) {
685                                 /* need a struct ldap */
686                                 break;  /* LDAP_OPT_ERROR */
687                         }
688
689                         if( ld->ld_matched ) {
690                                 LDAP_FREE(ld->ld_matched);
691                                 ld->ld_matched = NULL;
692                         }
693
694                         if ( matched ) {
695                                 ld->ld_matched = LDAP_STRDUP( matched );
696                         }
697                 }
698                 rc = LDAP_OPT_SUCCESS;
699                 break;
700
701         case LDAP_OPT_REFERRAL_URLS: {
702                         char *const *referrals = (char *const *) invalue;
703                         
704                         if(ld == NULL) {
705                                 /* need a struct ldap */
706                                 break;  /* LDAP_OPT_ERROR */
707                         }
708
709                         if( ld->ld_referrals ) {
710                                 LDAP_VFREE(ld->ld_referrals);
711                         }
712
713                         if ( referrals ) {
714                                 ld->ld_referrals = ldap_value_dup(referrals);
715                         }
716                 }
717                 rc = LDAP_OPT_SUCCESS;
718                 break;
719
720         /* Only accessed from inside this function by ldap_set_rebind_proc() */
721         case LDAP_OPT_REBIND_PROC: {
722                         lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue;              
723                 }
724                 rc = LDAP_OPT_SUCCESS;
725                 break;
726         case LDAP_OPT_REBIND_PARAMS: {
727                         lo->ldo_rebind_params = (void *)invalue;                
728                 }
729                 rc = LDAP_OPT_SUCCESS;
730                 break;
731
732         /* Only accessed from inside this function by ldap_set_nextref_proc() */
733         case LDAP_OPT_NEXTREF_PROC: {
734                         lo->ldo_nextref_proc = (LDAP_NEXTREF_PROC *)invalue;            
735                 }
736                 rc = LDAP_OPT_SUCCESS;
737                 break;
738         case LDAP_OPT_NEXTREF_PARAMS: {
739                         lo->ldo_nextref_params = (void *)invalue;               
740                 }
741                 rc = LDAP_OPT_SUCCESS;
742                 break;
743
744         /* Only accessed from inside this function by ldap_set_urllist_proc() */
745         case LDAP_OPT_URLLIST_PROC: {
746                         lo->ldo_urllist_proc = (LDAP_URLLIST_PROC *)invalue;            
747                 }
748                 rc = LDAP_OPT_SUCCESS;
749                 break;
750         case LDAP_OPT_URLLIST_PARAMS: {
751                         lo->ldo_urllist_params = (void *)invalue;               
752                 }
753                 rc = LDAP_OPT_SUCCESS;
754                 break;
755
756         /* read-only options */
757         case LDAP_OPT_API_INFO:
758         case LDAP_OPT_DESC:
759         case LDAP_OPT_SOCKBUF:
760         case LDAP_OPT_API_FEATURE_INFO:
761                 break;  /* LDAP_OPT_ERROR */
762
763         /* options which cannot withstand invalue == NULL */
764         case LDAP_OPT_DEREF:
765         case LDAP_OPT_SIZELIMIT:
766         case LDAP_OPT_TIMELIMIT:
767         case LDAP_OPT_PROTOCOL_VERSION:
768         case LDAP_OPT_RESULT_CODE:
769         case LDAP_OPT_DEBUG_LEVEL:
770         case LDAP_OPT_TIMEOUT:
771         case LDAP_OPT_NETWORK_TIMEOUT:
772         case LDAP_OPT_CONNECT_CB:
773         case LDAP_OPT_X_KEEPALIVE_IDLE:
774         case LDAP_OPT_X_KEEPALIVE_PROBES :
775         case LDAP_OPT_X_KEEPALIVE_INTERVAL :
776                 if(invalue == NULL) {
777                         /* no place to set from */
778                         LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
779                         return ( LDAP_OPT_ERROR );
780                 }
781                 break;
782
783         default:
784 #ifdef HAVE_TLS
785                 if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 ) {
786                         LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
787                         return ( LDAP_OPT_SUCCESS );
788                 }
789 #endif
790 #ifdef HAVE_CYRUS_SASL
791                 if ( ldap_int_sasl_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_GSSAPI
797                 if ( ldap_int_gssapi_set_option( ld, option, (void *)invalue ) == 0 ) {
798                         LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
799                         return ( LDAP_OPT_SUCCESS );
800                 }
801 #endif
802                 /* bad param */
803                 break;  /* LDAP_OPT_ERROR */
804         }
805
806         /* options which cannot withstand invalue == NULL */
807
808         switch(option) {
809         case LDAP_OPT_DEREF:
810                 /* FIXME: check value for protocol compliance? */
811                 lo->ldo_deref = * (const int *) invalue;
812                 rc = LDAP_OPT_SUCCESS;
813                 break;
814
815         case LDAP_OPT_SIZELIMIT:
816                 /* FIXME: check value for protocol compliance? */
817                 lo->ldo_sizelimit = * (const int *) invalue;
818                 rc = LDAP_OPT_SUCCESS;
819                 break;
820
821         case LDAP_OPT_TIMELIMIT:
822                 /* FIXME: check value for protocol compliance? */
823                 lo->ldo_timelimit = * (const int *) invalue;
824                 rc = LDAP_OPT_SUCCESS;
825                 break;
826
827         case LDAP_OPT_TIMEOUT: {
828                         const struct timeval *tv = 
829                                 (const struct timeval *) invalue;
830
831                         lo->ldo_tm_api = *tv;
832                 }
833                 rc = LDAP_OPT_SUCCESS;
834                 break;
835
836         case LDAP_OPT_NETWORK_TIMEOUT: {
837                         const struct timeval *tv = 
838                                 (const struct timeval *) invalue;
839
840                         lo->ldo_tm_net = *tv;
841                 }
842                 rc = LDAP_OPT_SUCCESS;
843                 break;
844
845         case LDAP_OPT_PROTOCOL_VERSION: {
846                         int vers = * (const int *) invalue;
847                         if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) {
848                                 /* not supported */
849                                 break;
850                         }
851                         lo->ldo_version = vers;
852                 }
853                 rc = LDAP_OPT_SUCCESS;
854                 break;
855
856         case LDAP_OPT_RESULT_CODE: {
857                         int err = * (const int *) invalue;
858
859                         if(ld == NULL) {
860                                 /* need a struct ldap */
861                                 break;
862                         }
863
864                         ld->ld_errno = err;
865                 }
866                 rc = LDAP_OPT_SUCCESS;
867                 break;
868
869         case LDAP_OPT_DEBUG_LEVEL:
870                 lo->ldo_debug = * (const int *) invalue;
871                 rc = LDAP_OPT_SUCCESS;
872                 break;
873
874         case LDAP_OPT_CONNECT_CB:
875                 {
876                         /* setting pushes the callback */
877                         ldaplist *ll;
878                         ll = LDAP_MALLOC( sizeof( *ll ));
879                         ll->ll_data = (void *)invalue;
880                         ll->ll_next = lo->ldo_conn_cbs;
881                         lo->ldo_conn_cbs = ll;
882                 }
883                 rc = LDAP_OPT_SUCCESS;
884                 break;
885         case LDAP_OPT_X_KEEPALIVE_IDLE:
886                 lo->ldo_keepalive_idle = * (const int *) invalue;
887                 rc = LDAP_OPT_SUCCESS;
888                 break;
889         case LDAP_OPT_X_KEEPALIVE_PROBES :
890                 lo->ldo_keepalive_probes = * (const int *) invalue;
891                 rc = LDAP_OPT_SUCCESS;
892                 break;
893         case LDAP_OPT_X_KEEPALIVE_INTERVAL :
894                 lo->ldo_keepalive_interval = * (const int *) invalue;
895                 rc = LDAP_OPT_SUCCESS;
896                 break;
897         
898         }
899         LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
900         return ( rc );
901 }
902
903 int
904 ldap_set_rebind_proc( LDAP *ld, LDAP_REBIND_PROC *proc, void *params )
905 {
906         int rc;
907         rc = ldap_set_option( ld, LDAP_OPT_REBIND_PROC, (void *)proc );
908         if( rc != LDAP_OPT_SUCCESS ) return rc;
909
910         rc = ldap_set_option( ld, LDAP_OPT_REBIND_PARAMS, (void *)params );
911         return rc;
912 }
913
914 int
915 ldap_set_nextref_proc( LDAP *ld, LDAP_NEXTREF_PROC *proc, void *params )
916 {
917         int rc;
918         rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PROC, (void *)proc );
919         if( rc != LDAP_OPT_SUCCESS ) return rc;
920
921         rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PARAMS, (void *)params );
922         return rc;
923 }
924
925 int
926 ldap_set_urllist_proc( LDAP *ld, LDAP_URLLIST_PROC *proc, void *params )
927 {
928         int rc;
929         rc = ldap_set_option( ld, LDAP_OPT_URLLIST_PROC, (void *)proc );
930         if( rc != LDAP_OPT_SUCCESS ) return rc;
931
932         rc = ldap_set_option( ld, LDAP_OPT_URLLIST_PARAMS, (void *)params );
933         return rc;
934 }