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