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