]> git.sur5r.net Git - openldap/blob - libraries/libldap/options.c
45ec0e5f75e2480a9aa086a63b685c9676ed8ffa
[openldap] / libraries / libldap / options.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include <ac/stdlib.h>
12
13 #include <ac/socket.h>
14 #include <ac/string.h>
15 #include <ac/time.h>
16
17 #include "ldap-int.h"
18
19 #define LDAP_OPT_REBIND_PROC 0x4e814d
20 #define LDAP_OPT_REBIND_PARAMS 0x4e814e
21
22 static const LDAPAPIFeatureInfo features[] = {
23 #ifdef LDAP_API_FEATURE_X_OPENLDAP
24         {       /* OpenLDAP Extensions API Feature */
25                 LDAP_FEATURE_INFO_VERSION,
26                 "X_OPENLDAP",
27                 LDAP_API_FEATURE_X_OPENLDAP
28         },
29 #endif
30
31 #ifdef LDAP_API_FEATURE_THREAD_SAFE
32         {       /* Basic Thread Safe */
33                 LDAP_FEATURE_INFO_VERSION,
34                 "THREAD_SAFE",
35                 LDAP_API_FEATURE_THREAD_SAFE
36         },
37 #endif
38 #ifdef LDAP_API_FEATURE_SESSION_THREAD_SAFE
39         {       /* Session Thread Safe */
40                 LDAP_FEATURE_INFO_VERSION,
41                 "SESSION_THREAD_SAFE",
42                 LDAP_API_FEATURE_SESSION_THREAD_SAFE
43         },
44 #endif
45 #ifdef LDAP_API_FEATURE_OPERATION_THREAD_SAFE
46         {       /* Operation Thread Safe */
47                 LDAP_FEATURE_INFO_VERSION,
48                 "OPERATION_THREAD_SAFE",
49                 LDAP_API_FEATURE_OPERATION_THREAD_SAFE
50         },
51 #endif
52 #ifdef LDAP_API_FEATURE_X_OPENLDAP_REENTRANT
53         {       /* OpenLDAP Reentrant */
54                 LDAP_FEATURE_INFO_VERSION,
55                 "X_OPENLDAP_REENTRANT",
56                 LDAP_API_FEATURE_X_OPENLDAP_REENTRANT
57         },
58 #endif
59 #if defined( LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE ) && \
60         defined( LDAP_THREAD_SAFE )
61         {       /* OpenLDAP Thread Safe */
62                 LDAP_FEATURE_INFO_VERSION,
63                 "X_OPENLDAP_THREAD_SAFE",
64                 LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE
65         },
66 #endif
67 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
68         {       /* V2 Referrals */
69                 LDAP_FEATURE_INFO_VERSION,
70                 "X_OPENLDAP_V2_REFERRALS",
71                 LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
72         },
73 #endif
74         {0, NULL, 0}
75 };
76
77 int
78 ldap_get_option(
79         LDAP    *ld,
80         int             option,
81         void    *outvalue)
82 {
83         struct ldapoptions *lo;
84
85         /* Get pointer to global option structure */
86         lo = LDAP_INT_GLOBAL_OPT();   
87         if (NULL == lo) {
88                 return LDAP_NO_MEMORY;
89         }
90
91         if( lo->ldo_valid != LDAP_INITIALIZED ) {
92                 ldap_int_initialize(lo, NULL);
93         }
94
95         if(ld != NULL) {
96                 assert( LDAP_VALID( ld ) );
97
98                 if( !LDAP_VALID( ld ) ) {
99                         return LDAP_OPT_ERROR;
100                 }
101
102                 lo = &ld->ld_options;
103         }
104
105         if(outvalue == NULL) {
106                 /* no place to get to */
107                 return LDAP_OPT_ERROR;
108         }
109
110         switch(option) {
111         case LDAP_OPT_API_INFO: {
112                         struct ldapapiinfo *info = (struct ldapapiinfo *) outvalue;
113
114                         if(info == NULL) {
115                                 /* outvalue must point to an apiinfo structure */
116                                 return LDAP_OPT_ERROR;
117                         }
118
119                         if(info->ldapai_info_version != LDAP_API_INFO_VERSION) {
120                                 /* api info version mismatch */
121                                 info->ldapai_info_version = LDAP_API_INFO_VERSION;
122                                 return LDAP_OPT_ERROR;
123                         }
124
125                         info->ldapai_api_version = LDAP_API_VERSION;
126                         info->ldapai_api_version = LDAP_API_VERSION;
127                         info->ldapai_protocol_version = LDAP_VERSION_MAX;
128
129                         if(features[0].ldapaif_name == NULL) {
130                                 info->ldapai_extensions = NULL;
131                         } else {
132                                 int i;
133                                 info->ldapai_extensions = LDAP_MALLOC(sizeof(char *) *
134                                         sizeof(features)/sizeof(LDAPAPIFeatureInfo));
135
136                                 for(i=0; features[i].ldapaif_name != NULL; i++) {
137                                         info->ldapai_extensions[i] =
138                                                 LDAP_STRDUP(features[i].ldapaif_name);
139                                 }
140
141                                 info->ldapai_extensions[i] = NULL;
142                         }
143
144                         info->ldapai_vendor_name = LDAP_STRDUP(LDAP_VENDOR_NAME);
145                         info->ldapai_vendor_version = LDAP_VENDOR_VERSION;
146
147                         return LDAP_OPT_SUCCESS;
148                 } break;
149
150         case LDAP_OPT_DESC:
151                 if( ld == NULL || ld->ld_sb == NULL ) {
152                         /* bad param */
153                         break;
154                 } 
155
156                 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, outvalue );
157                 return LDAP_OPT_SUCCESS;
158
159         case LDAP_OPT_TIMEOUT:
160                 /* the caller has to free outvalue ! */
161                 if ( ldap_int_timeval_dup( outvalue, lo->ldo_tm_api) != 0 ) {
162                         return LDAP_OPT_ERROR;
163                 }
164                 return LDAP_OPT_SUCCESS;
165                 
166         case LDAP_OPT_NETWORK_TIMEOUT:
167                 /* the caller has to free outvalue ! */
168                 if ( ldap_int_timeval_dup( outvalue, lo->ldo_tm_net ) != 0 ) {
169                         return LDAP_OPT_ERROR;
170                 }
171                 return LDAP_OPT_SUCCESS;
172
173         case LDAP_OPT_DEREF:
174                 * (int *) outvalue = lo->ldo_deref;
175                 return LDAP_OPT_SUCCESS;
176
177         case LDAP_OPT_SIZELIMIT:
178                 * (int *) outvalue = lo->ldo_sizelimit;
179                 return LDAP_OPT_SUCCESS;
180
181         case LDAP_OPT_TIMELIMIT:
182                 * (int *) outvalue = lo->ldo_timelimit;
183                 return LDAP_OPT_SUCCESS;
184
185         case LDAP_OPT_REFERRALS:
186                 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_REFERRALS);
187                 return LDAP_OPT_SUCCESS;
188                 
189         case LDAP_OPT_RESTART:
190                 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_RESTART);
191                 return LDAP_OPT_SUCCESS;
192
193         case LDAP_OPT_PROTOCOL_VERSION:
194                 * (int *) outvalue = lo->ldo_version;
195                 return LDAP_OPT_SUCCESS;
196
197         case LDAP_OPT_SERVER_CONTROLS:
198                 * (LDAPControl ***) outvalue =
199                         ldap_controls_dup( lo->ldo_sctrls );
200
201                 return LDAP_OPT_SUCCESS;
202
203         case LDAP_OPT_CLIENT_CONTROLS:
204                 * (LDAPControl ***) outvalue =
205                         ldap_controls_dup( lo->ldo_cctrls );
206
207                 return LDAP_OPT_SUCCESS;
208
209         case LDAP_OPT_HOST_NAME:
210                 * (char **) outvalue = ldap_url_list2hosts(lo->ldo_defludp);
211                 return LDAP_OPT_SUCCESS;
212
213         case LDAP_OPT_URI:
214                 * (char **) outvalue = ldap_url_list2urls(lo->ldo_defludp);
215                 return LDAP_OPT_SUCCESS;
216
217         case LDAP_OPT_ERROR_NUMBER:
218                 if(ld == NULL) {
219                         /* bad param */
220                         break;
221                 } 
222                 * (int *) outvalue = ld->ld_errno;
223                 return LDAP_OPT_SUCCESS;
224
225         case LDAP_OPT_ERROR_STRING:
226                 if(ld == NULL) {
227                         /* bad param */
228                         break;
229                 } 
230
231                 if( ld->ld_error == NULL ) {
232                         * (char **) outvalue = NULL;
233                 } else {
234                         * (char **) outvalue = LDAP_STRDUP(ld->ld_error);
235                 }
236
237                 return LDAP_OPT_SUCCESS;
238
239         case LDAP_OPT_MATCHED_DN:
240                 if(ld == NULL) {
241                         /* bad param */
242                         break;
243                 } 
244
245                 if( ld->ld_matched == NULL ) {
246                         * (char **) outvalue = NULL;
247                 } else {
248                         * (char **) outvalue = LDAP_STRDUP(ld->ld_matched);
249                 }
250
251                 return LDAP_OPT_SUCCESS;
252
253         case LDAP_OPT_REFERRAL_URLS:
254                 if(ld == NULL) {
255                         /* bad param */
256                         break;
257                 } 
258
259                 if( ld->ld_referrals == NULL ) {
260                         * (char ***) outvalue = NULL;
261                 } else {
262                         * (char ***) outvalue = ldap_value_dup(ld->ld_referrals);
263                 }
264
265                 return LDAP_OPT_SUCCESS;
266
267         case LDAP_OPT_API_FEATURE_INFO: {
268                         LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue;
269                         int i;
270
271                         if(info == NULL) return LDAP_OPT_ERROR;
272
273                         if(info->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) {
274                                 /* api info version mismatch */
275                                 info->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
276                                 return LDAP_OPT_ERROR;
277                         }
278
279                         if(info->ldapaif_name == NULL) return LDAP_OPT_ERROR;
280
281                         for(i=0; features[i].ldapaif_name != NULL; i++) {
282                                 if(!strcmp(info->ldapaif_name, features[i].ldapaif_name)) {
283                                         info->ldapaif_version =
284                                                 features[i].ldapaif_version;
285                                         return LDAP_OPT_SUCCESS;
286                                 }
287                         }
288                 }
289                 break;
290
291         case LDAP_OPT_DEBUG_LEVEL:
292                 * (int *) outvalue = lo->ldo_debug;
293                 return LDAP_OPT_SUCCESS;
294
295         default:
296 #ifdef HAVE_TLS
297                 if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
298                         return LDAP_OPT_SUCCESS;
299                 }
300 #endif
301 #ifdef HAVE_CYRUS_SASL
302                 if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
303                         return LDAP_OPT_SUCCESS;
304                 }
305 #endif
306                 /* bad param */
307                 break;
308         }
309
310         return LDAP_OPT_ERROR;
311 }
312
313 int
314 ldap_set_option(
315         LDAP    *ld,
316         int             option,
317         LDAP_CONST void *invalue)
318 {
319         struct ldapoptions *lo;
320         int *dbglvl = NULL;
321
322         /* Get pointer to global option structure */
323         lo = LDAP_INT_GLOBAL_OPT();
324         if (lo == NULL) {
325                 return LDAP_NO_MEMORY;
326         }
327
328         /*
329          * The architecture to turn on debugging has a chicken and egg
330          * problem. Thus, we introduce a fix here.
331          */
332
333         if (option == LDAP_OPT_DEBUG_LEVEL) {
334                 dbglvl = (int *) invalue;
335         }
336
337         if( lo->ldo_valid != LDAP_INITIALIZED ) {
338                 ldap_int_initialize(lo, dbglvl);
339         }
340
341         if(ld != NULL) {
342                 assert( LDAP_VALID( ld ) );
343
344                 if( !LDAP_VALID( ld ) ) {
345                         return LDAP_OPT_ERROR;
346                 }
347
348                 lo = &ld->ld_options;
349         }
350
351         switch(option) {
352         case LDAP_OPT_REFERRALS:
353                 if(invalue == LDAP_OPT_OFF) {
354                         LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS);
355                 } else {
356                         LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS);
357                 }
358                 return LDAP_OPT_SUCCESS;
359
360         case LDAP_OPT_RESTART:
361                 if(invalue == LDAP_OPT_OFF) {
362                         LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART);
363                 } else {
364                         LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
365                 }
366                 return LDAP_OPT_SUCCESS;
367         }
368
369         /* options which can withstand invalue == NULL */
370         switch ( option ) {
371         case LDAP_OPT_SERVER_CONTROLS: {
372                         LDAPControl *const *controls =
373                                 (LDAPControl *const *) invalue;
374
375                         ldap_controls_free( lo->ldo_sctrls );
376
377                         if( controls == NULL || *controls == NULL ) {
378                                 lo->ldo_sctrls = NULL;
379                                 return LDAP_OPT_SUCCESS;
380                         }
381                                 
382                         lo->ldo_sctrls = ldap_controls_dup( controls );
383
384                         if(lo->ldo_sctrls == NULL) {
385                                 /* memory allocation error ? */
386                                 break;
387                         }
388                 } return LDAP_OPT_SUCCESS;
389
390         case LDAP_OPT_CLIENT_CONTROLS: {
391                         LDAPControl *const *controls =
392                                 (LDAPControl *const *) invalue;
393
394                         ldap_controls_free( lo->ldo_cctrls );
395
396                         if( controls == NULL || *controls == NULL ) {
397                                 lo->ldo_cctrls = NULL;
398                                 return LDAP_OPT_SUCCESS;
399                         }
400                                 
401                         lo->ldo_cctrls = ldap_controls_dup( controls );
402
403                         if(lo->ldo_cctrls == NULL) {
404                                 /* memory allocation error ? */
405                                 break;
406                         }
407                 } return LDAP_OPT_SUCCESS;
408
409         case LDAP_OPT_TIMEOUT: {
410                         const struct timeval *tv = 
411                                 (const struct timeval *) invalue;
412
413                         if ( lo->ldo_tm_api != NULL ) {
414                                 LDAP_FREE( lo->ldo_tm_api );
415                                 lo->ldo_tm_api = NULL;
416                         }
417
418                         if ( ldap_int_timeval_dup( &lo->ldo_tm_api, tv ) != 0 ) {
419                                 return LDAP_OPT_ERROR;
420                         }
421                 } return LDAP_OPT_SUCCESS;
422
423         case LDAP_OPT_NETWORK_TIMEOUT: {
424                         const struct timeval *tv = 
425                                 (const struct timeval *) invalue;
426
427                         if ( lo->ldo_tm_net != NULL ) {
428                                 LDAP_FREE( lo->ldo_tm_net );
429                                 lo->ldo_tm_net = NULL;
430                         }
431
432                         if ( ldap_int_timeval_dup( &lo->ldo_tm_net, tv ) != 0 ) {
433                                 return LDAP_OPT_ERROR;
434                         }
435                 } return LDAP_OPT_SUCCESS;
436
437         /* Only accessed from inside this function by ldap_set_rebind_proc() */
438         case LDAP_OPT_REBIND_PROC: {
439                         lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue;              
440                 } return LDAP_OPT_SUCCESS;
441         case LDAP_OPT_REBIND_PARAMS: {
442                         lo->ldo_rebind_params = (void *)invalue;                
443                 } return LDAP_OPT_SUCCESS;
444         }
445
446         if(invalue == NULL) {
447                 /* no place to set from */
448                 return LDAP_OPT_ERROR;
449         }
450
451         /* options which cannot withstand invalue == NULL */
452
453         switch(option) {
454         case LDAP_OPT_API_INFO:
455         case LDAP_OPT_DESC:
456                 /* READ ONLY */
457                 break;
458
459         case LDAP_OPT_DEREF:
460                 lo->ldo_deref = * (const int *) invalue;
461                 return LDAP_OPT_SUCCESS;
462
463         case LDAP_OPT_SIZELIMIT:
464                 lo->ldo_sizelimit = * (const int *) invalue;
465                 return LDAP_OPT_SUCCESS;
466
467         case LDAP_OPT_TIMELIMIT:
468                 lo->ldo_timelimit = * (const int *) invalue;
469                 return LDAP_OPT_SUCCESS;
470
471         case LDAP_OPT_PROTOCOL_VERSION: {
472                         int vers = * (const int *) invalue;
473                         if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) {
474                                 /* not supported */
475                                 break;
476                         }
477                         lo->ldo_version = vers;
478                 } return LDAP_OPT_SUCCESS;
479
480
481         case LDAP_OPT_HOST_NAME: {
482                         const char *host = (const char *) invalue;
483                         LDAPURLDesc *ludlist = NULL;
484                         int rc = LDAP_OPT_SUCCESS;
485
486                         if(host != NULL) {
487                                 rc = ldap_url_parsehosts( &ludlist, host,
488                                         lo->ldo_defport ? lo->ldo_defport : LDAP_PORT );
489
490                         } else if(ld == NULL) {
491                                 /*
492                                  * must want global default returned
493                                  * to initial condition.
494                                  */
495                                 rc = ldap_url_parselist(&ludlist, "ldap://localhost/");
496
497                         } else {
498                                 /*
499                                  * must want the session default
500                                  *   updated to the current global default
501                                  */
502                                 ludlist = ldap_url_duplist(
503                                         ldap_int_global_options.ldo_defludp);
504                                 if (ludlist == NULL)
505                                         rc = LDAP_NO_MEMORY;
506                         }
507
508                         if (rc == LDAP_OPT_SUCCESS) {
509                                 if (lo->ldo_defludp != NULL)
510                                         ldap_free_urllist(lo->ldo_defludp);
511                                 lo->ldo_defludp = ludlist;
512                         }
513                         return rc;
514                 }
515
516         case LDAP_OPT_URI: {
517                         const char *urls = (const char *) invalue;
518                         LDAPURLDesc *ludlist = NULL;
519                         int rc = LDAP_OPT_SUCCESS;
520
521                         if(urls != NULL) {
522                                 rc = ldap_url_parselist(&ludlist, urls);
523
524                         } else if(ld == NULL) {
525                                 /*
526                                  * must want global default returned
527                                  * to initial condition.
528                                  */
529                                 rc = ldap_url_parselist(&ludlist, "ldap://localhost/");
530
531                         } else {
532                                 /*
533                                  * must want the session default
534                                  *   updated to the current global default
535                                  */
536                                 ludlist = ldap_url_duplist(
537                                         ldap_int_global_options.ldo_defludp);
538                                 if (ludlist == NULL)
539                                         rc = LDAP_NO_MEMORY;
540                         }
541
542                         if (rc == LDAP_OPT_SUCCESS) {
543                                 if (lo->ldo_defludp != NULL)
544                                         ldap_free_urllist(lo->ldo_defludp);
545                                 lo->ldo_defludp = ludlist;
546                         }
547                         return rc;
548                 }
549
550         case LDAP_OPT_ERROR_NUMBER: {
551                         int err = * (const int *) invalue;
552
553                         if(ld == NULL) {
554                                 /* need a struct ldap */
555                                 break;
556                         }
557
558                         ld->ld_errno = err;
559                 } return LDAP_OPT_SUCCESS;
560
561         case LDAP_OPT_ERROR_STRING: {
562                         const char *err = (const char *) invalue;
563
564                         if(ld == NULL) {
565                                 /* need a struct ldap */
566                                 break;
567                         }
568
569                         if( ld->ld_error ) {
570                                 LDAP_FREE(ld->ld_error);
571                         }
572
573                         ld->ld_error = LDAP_STRDUP(err);
574                 } return LDAP_OPT_SUCCESS;
575
576         case LDAP_OPT_MATCHED_DN: {
577                         const char *err = (const char *) invalue;
578
579                         if(ld == NULL) {
580                                 /* need a struct ldap */
581                                 break;
582                         }
583
584                         if( ld->ld_matched ) {
585                                 LDAP_FREE(ld->ld_matched);
586                         }
587
588                         ld->ld_matched = LDAP_STRDUP(err);
589                 } return LDAP_OPT_SUCCESS;
590
591         case LDAP_OPT_REFERRAL_URLS: {
592                         char *const *referrals = (char *const *) invalue;
593                         
594                         if(ld == NULL) {
595                                 /* need a struct ldap */
596                                 break;
597                         }
598
599                         if( ld->ld_referrals ) {
600                                 LDAP_VFREE(ld->ld_referrals);
601                         }
602
603                         ld->ld_referrals = ldap_value_dup(referrals);
604                 } return LDAP_OPT_SUCCESS;
605
606         case LDAP_OPT_API_FEATURE_INFO:
607                 /* read-only */
608                 break;
609
610         case LDAP_OPT_DEBUG_LEVEL:
611                 lo->ldo_debug = * (const int *) invalue;
612                 return LDAP_OPT_SUCCESS;
613
614         default:
615 #ifdef HAVE_TLS
616                 if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 )
617                         return LDAP_OPT_SUCCESS;
618 #endif
619 #ifdef HAVE_CYRUS_SASL
620                 if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 )
621                         return LDAP_OPT_SUCCESS;
622 #endif
623                 /* bad param */
624                 break;
625         }
626         return LDAP_OPT_ERROR;
627 }
628
629 int
630 ldap_set_rebind_proc( LDAP *ld, LDAP_REBIND_PROC *proc, void *params )
631 {
632         int rc;
633         rc = ldap_set_option( ld, LDAP_OPT_REBIND_PROC, (void *)proc );
634         if( rc != LDAP_OPT_SUCCESS ) return rc;
635
636         rc = ldap_set_option( ld, LDAP_OPT_REBIND_PARAMS, (void *)params );
637         return rc;
638 }