]> git.sur5r.net Git - openldap/blob - libraries/libldap/options.c
Fix up restart code for EINTR
[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_API_FEATURE_INFO: {
254                         LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue;
255                         int i;
256
257                         if(info == NULL) return LDAP_OPT_ERROR;
258
259                         if(info->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) {
260                                 /* api info version mismatch */
261                                 info->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
262                                 return LDAP_OPT_ERROR;
263                         }
264
265                         if(info->ldapaif_name == NULL) return LDAP_OPT_ERROR;
266
267                         for(i=0; features[i].ldapaif_name != NULL; i++) {
268                                 if(!strcmp(info->ldapaif_name, features[i].ldapaif_name)) {
269                                         info->ldapaif_version =
270                                                 features[i].ldapaif_version;
271                                         return LDAP_OPT_SUCCESS;
272                                 }
273                         }
274                 }
275                 break;
276
277         case LDAP_OPT_DEBUG_LEVEL:
278                 * (int *) outvalue = lo->ldo_debug;
279                 return LDAP_OPT_SUCCESS;
280
281         default:
282 #ifdef HAVE_TLS
283                 if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
284                         return LDAP_OPT_SUCCESS;
285                 }
286 #endif
287 #ifdef HAVE_CYRUS_SASL
288                 if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
289                         return LDAP_OPT_SUCCESS;
290                 }
291 #endif
292                 /* bad param */
293                 break;
294         }
295
296         return LDAP_OPT_ERROR;
297 }
298
299 int
300 ldap_set_option(
301         LDAP    *ld,
302         int             option,
303         LDAP_CONST void *invalue)
304 {
305         struct ldapoptions *lo;
306         int *dbglvl = NULL;
307
308         /* Get pointer to global option structure */
309         lo = LDAP_INT_GLOBAL_OPT();
310         if (lo == NULL) {
311                 return LDAP_NO_MEMORY;
312         }
313
314         /*
315          * The architecture to turn on debugging has a chicken and egg
316          * problem. Thus, we introduce a fix here.
317          */
318
319         if (option == LDAP_OPT_DEBUG_LEVEL)
320             dbglvl = (int *) invalue;
321
322         if( lo->ldo_valid != LDAP_INITIALIZED ) {
323                 ldap_int_initialize(lo, dbglvl);
324         }
325
326         if(ld != NULL) {
327                 assert( LDAP_VALID( ld ) );
328
329                 if( !LDAP_VALID( ld ) ) {
330                         return LDAP_OPT_ERROR;
331                 }
332
333                 lo = &ld->ld_options;
334         }
335
336         switch(option) {
337         case LDAP_OPT_REFERRALS:
338                 if(invalue == LDAP_OPT_OFF) {
339                         LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS);
340                 } else {
341                         LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS);
342                 }
343                 return LDAP_OPT_SUCCESS;
344
345         case LDAP_OPT_RESTART:
346                 if(invalue == LDAP_OPT_OFF) {
347                         LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART);
348                 } else {
349                         LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
350                 }
351                 return LDAP_OPT_SUCCESS;
352         }
353
354         /* options which can withstand invalue == NULL */
355         switch ( option ) {
356         case LDAP_OPT_SERVER_CONTROLS: {
357                         LDAPControl *const *controls =
358                                 (LDAPControl *const *) invalue;
359
360                         ldap_controls_free( lo->ldo_sctrls );
361
362                         if( controls == NULL || *controls == NULL ) {
363                                 lo->ldo_sctrls = NULL;
364                                 return LDAP_OPT_SUCCESS;
365                         }
366                                 
367                         lo->ldo_sctrls = ldap_controls_dup( controls );
368
369                         if(lo->ldo_sctrls == NULL) {
370                                 /* memory allocation error ? */
371                                 break;
372                         }
373                 } return LDAP_OPT_SUCCESS;
374
375         case LDAP_OPT_CLIENT_CONTROLS: {
376                         LDAPControl *const *controls =
377                                 (LDAPControl *const *) invalue;
378
379                         ldap_controls_free( lo->ldo_cctrls );
380
381                         if( controls == NULL || *controls == NULL ) {
382                                 lo->ldo_cctrls = NULL;
383                                 return LDAP_OPT_SUCCESS;
384                         }
385                                 
386                         lo->ldo_cctrls = ldap_controls_dup( controls );
387
388                         if(lo->ldo_cctrls == NULL) {
389                                 /* memory allocation error ? */
390                                 break;
391                         }
392                 } return LDAP_OPT_SUCCESS;
393
394         case LDAP_OPT_TIMEOUT: {
395                         const struct timeval *tv = 
396                                 (const struct timeval *) invalue;
397
398                         if ( lo->ldo_tm_api != NULL ) {
399                                 LDAP_FREE( lo->ldo_tm_api );
400                                 lo->ldo_tm_api = NULL;
401                         }
402
403                         if ( ldap_int_timeval_dup( &lo->ldo_tm_api, tv ) != 0 ) {
404                                 return LDAP_OPT_ERROR;
405                         }
406                 } return LDAP_OPT_SUCCESS;
407
408         case LDAP_OPT_NETWORK_TIMEOUT: {
409                         const struct timeval *tv = 
410                                 (const struct timeval *) invalue;
411
412                         if ( lo->ldo_tm_net != NULL ) {
413                                 LDAP_FREE( lo->ldo_tm_net );
414                                 lo->ldo_tm_net = NULL;
415                         }
416
417                         if ( ldap_int_timeval_dup( &lo->ldo_tm_net, tv ) != 0 ) {
418                                 return LDAP_OPT_ERROR;
419                         }
420                 } return LDAP_OPT_SUCCESS;
421
422         /* Only accessed from inside this function by ldap_set_rebind_proc() */
423         case LDAP_OPT_REBIND_PROC: {
424                         lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue;              
425                 } return LDAP_OPT_SUCCESS;
426         case LDAP_OPT_REBIND_PARAMS: {
427                         lo->ldo_rebind_params = (void *)invalue;                
428                 } return LDAP_OPT_SUCCESS;
429         }
430
431         if(invalue == NULL) {
432                 /* no place to set from */
433                 return LDAP_OPT_ERROR;
434         }
435
436         /* options which cannot withstand invalue == NULL */
437
438         switch(option) {
439         case LDAP_OPT_API_INFO:
440         case LDAP_OPT_DESC:
441                 /* READ ONLY */
442                 break;
443
444         case LDAP_OPT_DEREF:
445                 lo->ldo_deref = * (const int *) invalue;
446                 return LDAP_OPT_SUCCESS;
447
448         case LDAP_OPT_SIZELIMIT:
449                 lo->ldo_sizelimit = * (const int *) invalue;
450                 return LDAP_OPT_SUCCESS;
451
452         case LDAP_OPT_TIMELIMIT:
453                 lo->ldo_timelimit = * (const int *) invalue;
454                 return LDAP_OPT_SUCCESS;
455
456         case LDAP_OPT_PROTOCOL_VERSION: {
457                         int vers = * (const int *) invalue;
458                         if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) {
459                                 /* not supported */
460                                 break;
461                         }
462                         lo->ldo_version = vers;
463                 } return LDAP_OPT_SUCCESS;
464
465
466         case LDAP_OPT_HOST_NAME: {
467                         const char *host = (const char *) invalue;
468                         LDAPURLDesc *ludlist = NULL;
469                         int rc = LDAP_OPT_SUCCESS;
470
471                         if(host != NULL) {
472                                 rc = ldap_url_parsehosts( &ludlist, host,
473                                         lo->ldo_defport ? lo->ldo_defport : LDAP_PORT );
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( ld, option, (void *)invalue ) == 0 )
587                 return LDAP_OPT_SUCCESS;
588 #endif
589 #ifdef HAVE_CYRUS_SASL
590                 if ( ldap_int_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 int
600 ldap_set_rebind_proc( LDAP *ld, LDAP_REBIND_PROC *proc, void *params )
601 {
602         int rc;
603         rc = ldap_set_option( ld, LDAP_OPT_REBIND_PROC, (void *)proc );
604         if( rc != LDAP_OPT_SUCCESS ) return rc;
605
606         rc = ldap_set_option( ld, LDAP_OPT_REBIND_PARAMS, (void *)params );
607         return rc;
608 }