]> git.sur5r.net Git - openldap/blob - libraries/libldap/options.c
ITS#3168: Add LDAP_OPT_SOCKBUF
[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_SOCKBUF:
169                 if( ld == NULL ) break;
170                 outvalue = ld->ld_sb;
171                 return LDAP_OPT_SUCCESS;
172
173         case LDAP_OPT_TIMEOUT:
174                 /* the caller has to free outvalue ! */
175                 if ( ldap_int_timeval_dup( outvalue, lo->ldo_tm_api) != 0 ) {
176                         return LDAP_OPT_ERROR;
177                 }
178                 return LDAP_OPT_SUCCESS;
179                 
180         case LDAP_OPT_NETWORK_TIMEOUT:
181                 /* the caller has to free outvalue ! */
182                 if ( ldap_int_timeval_dup( outvalue, lo->ldo_tm_net ) != 0 ) {
183                         return LDAP_OPT_ERROR;
184                 }
185                 return LDAP_OPT_SUCCESS;
186
187         case LDAP_OPT_DEREF:
188                 * (int *) outvalue = lo->ldo_deref;
189                 return LDAP_OPT_SUCCESS;
190
191         case LDAP_OPT_SIZELIMIT:
192                 * (int *) outvalue = lo->ldo_sizelimit;
193                 return LDAP_OPT_SUCCESS;
194
195         case LDAP_OPT_TIMELIMIT:
196                 * (int *) outvalue = lo->ldo_timelimit;
197                 return LDAP_OPT_SUCCESS;
198
199         case LDAP_OPT_REFERRALS:
200                 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_REFERRALS);
201                 return LDAP_OPT_SUCCESS;
202                 
203         case LDAP_OPT_RESTART:
204                 * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_RESTART);
205                 return LDAP_OPT_SUCCESS;
206
207         case LDAP_OPT_PROTOCOL_VERSION:
208                 * (int *) outvalue = lo->ldo_version;
209                 return LDAP_OPT_SUCCESS;
210
211         case LDAP_OPT_SERVER_CONTROLS:
212                 * (LDAPControl ***) outvalue =
213                         ldap_controls_dup( lo->ldo_sctrls );
214
215                 return LDAP_OPT_SUCCESS;
216
217         case LDAP_OPT_CLIENT_CONTROLS:
218                 * (LDAPControl ***) outvalue =
219                         ldap_controls_dup( lo->ldo_cctrls );
220
221                 return LDAP_OPT_SUCCESS;
222
223         case LDAP_OPT_HOST_NAME:
224                 * (char **) outvalue = ldap_url_list2hosts(lo->ldo_defludp);
225                 return LDAP_OPT_SUCCESS;
226
227         case LDAP_OPT_URI:
228                 * (char **) outvalue = ldap_url_list2urls(lo->ldo_defludp);
229                 return LDAP_OPT_SUCCESS;
230
231         case LDAP_OPT_ERROR_NUMBER:
232                 if(ld == NULL) {
233                         /* bad param */
234                         break;
235                 } 
236                 * (int *) outvalue = ld->ld_errno;
237                 return LDAP_OPT_SUCCESS;
238
239         case LDAP_OPT_ERROR_STRING:
240                 if(ld == NULL) {
241                         /* bad param */
242                         break;
243                 } 
244
245                 if( ld->ld_error == NULL ) {
246                         * (char **) outvalue = NULL;
247                 } else {
248                         * (char **) outvalue = LDAP_STRDUP(ld->ld_error);
249                 }
250
251                 return LDAP_OPT_SUCCESS;
252
253         case LDAP_OPT_MATCHED_DN:
254                 if(ld == NULL) {
255                         /* bad param */
256                         break;
257                 } 
258
259                 if( ld->ld_matched == NULL ) {
260                         * (char **) outvalue = NULL;
261                 } else {
262                         * (char **) outvalue = LDAP_STRDUP(ld->ld_matched);
263                 }
264
265                 return LDAP_OPT_SUCCESS;
266
267         case LDAP_OPT_REFERRAL_URLS:
268                 if(ld == NULL) {
269                         /* bad param */
270                         break;
271                 } 
272
273                 if( ld->ld_referrals == NULL ) {
274                         * (char ***) outvalue = NULL;
275                 } else {
276                         * (char ***) outvalue = ldap_value_dup(ld->ld_referrals);
277                 }
278
279                 return LDAP_OPT_SUCCESS;
280
281         case LDAP_OPT_API_FEATURE_INFO: {
282                         LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue;
283                         int i;
284
285                         if(info == NULL) return LDAP_OPT_ERROR;
286
287                         if(info->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) {
288                                 /* api info version mismatch */
289                                 info->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
290                                 return LDAP_OPT_ERROR;
291                         }
292
293                         if(info->ldapaif_name == NULL) return LDAP_OPT_ERROR;
294
295                         for(i=0; features[i].ldapaif_name != NULL; i++) {
296                                 if(!strcmp(info->ldapaif_name, features[i].ldapaif_name)) {
297                                         info->ldapaif_version =
298                                                 features[i].ldapaif_version;
299                                         return LDAP_OPT_SUCCESS;
300                                 }
301                         }
302                 }
303                 break;
304
305         case LDAP_OPT_DEBUG_LEVEL:
306                 * (int *) outvalue = lo->ldo_debug;
307                 return LDAP_OPT_SUCCESS;
308
309         default:
310 #ifdef HAVE_TLS
311                 if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
312                         return LDAP_OPT_SUCCESS;
313                 }
314 #endif
315 #ifdef HAVE_CYRUS_SASL
316                 if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
317                         return LDAP_OPT_SUCCESS;
318                 }
319 #endif
320                 /* bad param */
321                 break;
322         }
323
324         return LDAP_OPT_ERROR;
325 }
326
327 int
328 ldap_set_option(
329         LDAP    *ld,
330         int             option,
331         LDAP_CONST void *invalue)
332 {
333         struct ldapoptions *lo;
334         int *dbglvl = NULL;
335
336         /* Get pointer to global option structure */
337         lo = LDAP_INT_GLOBAL_OPT();
338         if (lo == NULL) {
339                 return LDAP_NO_MEMORY;
340         }
341
342         /*
343          * The architecture to turn on debugging has a chicken and egg
344          * problem. Thus, we introduce a fix here.
345          */
346
347         if (option == LDAP_OPT_DEBUG_LEVEL) {
348                 dbglvl = (int *) invalue;
349         }
350
351         if( lo->ldo_valid != LDAP_INITIALIZED ) {
352                 ldap_int_initialize(lo, dbglvl);
353         }
354
355         if(ld != NULL) {
356                 assert( LDAP_VALID( ld ) );
357
358                 if( !LDAP_VALID( ld ) ) {
359                         return LDAP_OPT_ERROR;
360                 }
361
362                 lo = &ld->ld_options;
363         }
364
365         switch(option) {
366         case LDAP_OPT_REFERRALS:
367                 if(invalue == LDAP_OPT_OFF) {
368                         LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS);
369                 } else {
370                         LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS);
371                 }
372                 return LDAP_OPT_SUCCESS;
373
374         case LDAP_OPT_RESTART:
375                 if(invalue == LDAP_OPT_OFF) {
376                         LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART);
377                 } else {
378                         LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
379                 }
380                 return LDAP_OPT_SUCCESS;
381         }
382
383         /* options which can withstand invalue == NULL */
384         switch ( option ) {
385         case LDAP_OPT_SERVER_CONTROLS: {
386                         LDAPControl *const *controls =
387                                 (LDAPControl *const *) invalue;
388
389                         ldap_controls_free( lo->ldo_sctrls );
390
391                         if( controls == NULL || *controls == NULL ) {
392                                 lo->ldo_sctrls = NULL;
393                                 return LDAP_OPT_SUCCESS;
394                         }
395                                 
396                         lo->ldo_sctrls = ldap_controls_dup( controls );
397
398                         if(lo->ldo_sctrls == NULL) {
399                                 /* memory allocation error ? */
400                                 break;
401                         }
402                 } return LDAP_OPT_SUCCESS;
403
404         case LDAP_OPT_CLIENT_CONTROLS: {
405                         LDAPControl *const *controls =
406                                 (LDAPControl *const *) invalue;
407
408                         ldap_controls_free( lo->ldo_cctrls );
409
410                         if( controls == NULL || *controls == NULL ) {
411                                 lo->ldo_cctrls = NULL;
412                                 return LDAP_OPT_SUCCESS;
413                         }
414                                 
415                         lo->ldo_cctrls = ldap_controls_dup( controls );
416
417                         if(lo->ldo_cctrls == NULL) {
418                                 /* memory allocation error ? */
419                                 break;
420                         }
421                 } return LDAP_OPT_SUCCESS;
422
423         case LDAP_OPT_TIMEOUT: {
424                         const struct timeval *tv = 
425                                 (const struct timeval *) invalue;
426
427                         if ( lo->ldo_tm_api != NULL ) {
428                                 LDAP_FREE( lo->ldo_tm_api );
429                                 lo->ldo_tm_api = NULL;
430                         }
431
432                         if ( ldap_int_timeval_dup( &lo->ldo_tm_api, tv ) != 0 ) {
433                                 return LDAP_OPT_ERROR;
434                         }
435                 } return LDAP_OPT_SUCCESS;
436
437         case LDAP_OPT_NETWORK_TIMEOUT: {
438                         const struct timeval *tv = 
439                                 (const struct timeval *) invalue;
440
441                         if ( lo->ldo_tm_net != NULL ) {
442                                 LDAP_FREE( lo->ldo_tm_net );
443                                 lo->ldo_tm_net = NULL;
444                         }
445
446                         if ( ldap_int_timeval_dup( &lo->ldo_tm_net, tv ) != 0 ) {
447                                 return LDAP_OPT_ERROR;
448                         }
449                 } return LDAP_OPT_SUCCESS;
450
451         /* Only accessed from inside this function by ldap_set_rebind_proc() */
452         case LDAP_OPT_REBIND_PROC: {
453                         lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue;              
454                 } return LDAP_OPT_SUCCESS;
455         case LDAP_OPT_REBIND_PARAMS: {
456                         lo->ldo_rebind_params = (void *)invalue;                
457                 } return LDAP_OPT_SUCCESS;
458         }
459
460         if(invalue == NULL) {
461                 /* no place to set from */
462                 return LDAP_OPT_ERROR;
463         }
464
465         /* options which cannot withstand invalue == NULL */
466
467         switch(option) {
468         case LDAP_OPT_API_INFO:
469         case LDAP_OPT_DESC:
470                 /* READ ONLY */
471                 break;
472
473         case LDAP_OPT_DEREF:
474                 lo->ldo_deref = * (const int *) invalue;
475                 return LDAP_OPT_SUCCESS;
476
477         case LDAP_OPT_SIZELIMIT:
478                 lo->ldo_sizelimit = * (const int *) invalue;
479                 return LDAP_OPT_SUCCESS;
480
481         case LDAP_OPT_TIMELIMIT:
482                 lo->ldo_timelimit = * (const int *) invalue;
483                 return LDAP_OPT_SUCCESS;
484
485         case LDAP_OPT_PROTOCOL_VERSION: {
486                         int vers = * (const int *) invalue;
487                         if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) {
488                                 /* not supported */
489                                 break;
490                         }
491                         lo->ldo_version = vers;
492                 } return LDAP_OPT_SUCCESS;
493
494
495         case LDAP_OPT_HOST_NAME: {
496                         const char *host = (const char *) invalue;
497                         LDAPURLDesc *ludlist = NULL;
498                         int rc = LDAP_OPT_SUCCESS;
499
500                         if(host != NULL) {
501                                 rc = ldap_url_parsehosts( &ludlist, host,
502                                         lo->ldo_defport ? lo->ldo_defport : LDAP_PORT );
503
504                         } else if(ld == NULL) {
505                                 /*
506                                  * must want global default returned
507                                  * to initial condition.
508                                  */
509                                 rc = ldap_url_parselist(&ludlist, "ldap://localhost/");
510
511                         } else {
512                                 /*
513                                  * must want the session default
514                                  *   updated to the current global default
515                                  */
516                                 ludlist = ldap_url_duplist(
517                                         ldap_int_global_options.ldo_defludp);
518                                 if (ludlist == NULL)
519                                         rc = LDAP_NO_MEMORY;
520                         }
521
522                         if (rc == LDAP_OPT_SUCCESS) {
523                                 if (lo->ldo_defludp != NULL)
524                                         ldap_free_urllist(lo->ldo_defludp);
525                                 lo->ldo_defludp = ludlist;
526                         }
527                         return rc;
528                 }
529
530         case LDAP_OPT_URI: {
531                         const char *urls = (const char *) invalue;
532                         LDAPURLDesc *ludlist = NULL;
533                         int rc = LDAP_OPT_SUCCESS;
534
535                         if(urls != NULL) {
536                                 rc = ldap_url_parselist(&ludlist, urls);
537                         } else if(ld == NULL) {
538                                 /*
539                                  * must want global default returned
540                                  * to initial condition.
541                                  */
542                                 rc = ldap_url_parselist(&ludlist, "ldap://localhost/");
543
544                         } else {
545                                 /*
546                                  * must want the session default
547                                  *   updated to the current global default
548                                  */
549                                 ludlist = ldap_url_duplist(
550                                         ldap_int_global_options.ldo_defludp);
551                                 if (ludlist == NULL)
552                                         rc = LDAP_NO_MEMORY;
553                         }
554
555                         switch (rc) {
556                         case LDAP_URL_SUCCESS:          /* Success */
557                                 rc = LDAP_SUCCESS;
558                                 break;
559
560                         case LDAP_URL_ERR_MEM:          /* can't allocate memory space */
561                                 rc = LDAP_NO_MEMORY;
562                                 break;
563
564                         case LDAP_URL_ERR_PARAM:        /* parameter is bad */
565                         case LDAP_URL_ERR_BADSCHEME:    /* URL doesn't begin with "ldap[si]://" */
566                         case LDAP_URL_ERR_BADENCLOSURE: /* URL is missing trailing ">" */
567                         case LDAP_URL_ERR_BADURL:       /* URL is bad */
568                         case LDAP_URL_ERR_BADHOST:      /* host port is bad */
569                         case LDAP_URL_ERR_BADATTRS:     /* bad (or missing) attributes */
570                         case LDAP_URL_ERR_BADSCOPE:     /* scope string is invalid (or missing) */
571                         case LDAP_URL_ERR_BADFILTER:    /* bad or missing filter */
572                         case LDAP_URL_ERR_BADEXTS:      /* bad or missing extensions */
573                                 rc = LDAP_PARAM_ERROR;
574                                 break;
575                         }
576
577                         if (rc == LDAP_OPT_SUCCESS) {
578                                 if (lo->ldo_defludp != NULL)
579                                         ldap_free_urllist(lo->ldo_defludp);
580                                 lo->ldo_defludp = ludlist;
581                         }
582                         return rc;
583                 }
584
585         case LDAP_OPT_ERROR_NUMBER: {
586                         int err = * (const int *) invalue;
587
588                         if(ld == NULL) {
589                                 /* need a struct ldap */
590                                 break;
591                         }
592
593                         ld->ld_errno = err;
594                 } return LDAP_OPT_SUCCESS;
595
596         case LDAP_OPT_ERROR_STRING: {
597                         const char *err = (const char *) invalue;
598
599                         if(ld == NULL) {
600                                 /* need a struct ldap */
601                                 break;
602                         }
603
604                         if( ld->ld_error ) {
605                                 LDAP_FREE(ld->ld_error);
606                         }
607
608                         ld->ld_error = LDAP_STRDUP(err);
609                 } return LDAP_OPT_SUCCESS;
610
611         case LDAP_OPT_MATCHED_DN: {
612                         const char *err = (const char *) invalue;
613
614                         if(ld == NULL) {
615                                 /* need a struct ldap */
616                                 break;
617                         }
618
619                         if( ld->ld_matched ) {
620                                 LDAP_FREE(ld->ld_matched);
621                         }
622
623                         ld->ld_matched = LDAP_STRDUP(err);
624                 } return LDAP_OPT_SUCCESS;
625
626         case LDAP_OPT_REFERRAL_URLS: {
627                         char *const *referrals = (char *const *) invalue;
628                         
629                         if(ld == NULL) {
630                                 /* need a struct ldap */
631                                 break;
632                         }
633
634                         if( ld->ld_referrals ) {
635                                 LDAP_VFREE(ld->ld_referrals);
636                         }
637
638                         ld->ld_referrals = ldap_value_dup(referrals);
639                 } return LDAP_OPT_SUCCESS;
640
641         case LDAP_OPT_API_FEATURE_INFO:
642                 /* read-only */
643                 break;
644
645         case LDAP_OPT_DEBUG_LEVEL:
646                 lo->ldo_debug = * (const int *) invalue;
647                 return LDAP_OPT_SUCCESS;
648
649         default:
650 #ifdef HAVE_TLS
651                 if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 )
652                         return LDAP_OPT_SUCCESS;
653 #endif
654 #ifdef HAVE_CYRUS_SASL
655                 if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 )
656                         return LDAP_OPT_SUCCESS;
657 #endif
658                 /* bad param */
659                 break;
660         }
661         return LDAP_OPT_ERROR;
662 }
663
664 int
665 ldap_set_rebind_proc( LDAP *ld, LDAP_REBIND_PROC *proc, void *params )
666 {
667         int rc;
668         rc = ldap_set_option( ld, LDAP_OPT_REBIND_PROC, (void *)proc );
669         if( rc != LDAP_OPT_SUCCESS ) return rc;
670
671         rc = ldap_set_option( ld, LDAP_OPT_REBIND_PARAMS, (void *)params );
672         return rc;
673 }