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