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