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