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